diff -drupN a/drivers/soc/sunxi/pm.c b/drivers/soc/sunxi/pm.c --- a/drivers/soc/sunxi/pm.c 1970-01-01 03:00:00.000000000 +0300 +++ b/drivers/soc/sunxi/pm.c 2022-06-12 05:28:14.000000000 +0300 @@ -0,0 +1,546 @@ +/* + * drivers/soc/sunxi/pm.c + * (C) Copyright 2017-2023 + * Allwinner Technology Co., Ltd. + * fanqinghua + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pm.h" +static unsigned long time_to_wakeup_ms; +module_param_named(time_to_wakeup_ms, time_to_wakeup_ms, + ulong, S_IRUGO | S_IWUSR); + +static super_standby_t *super_standby_para; +static unsigned int standby_space_size; +static unsigned int regular_standby_flag ; +static DEFINE_SPINLOCK(data_lock); + +int enable_gpio_wakeup_src(int para) +{ + spin_lock(&data_lock); + super_standby_para->event |= CPUS_WAKEUP_GPIO; + if (para >= AXP_PIN_BASE) { + super_standby_para->gpio_enable_bitmap |= + (WAKEUP_GPIO_AXP((para - AXP_PIN_BASE))); + } else if (para >= SUNXI_PM_BASE) { + super_standby_para->gpio_enable_bitmap |= + (WAKEUP_GPIO_PM((para - SUNXI_PM_BASE))); + } else if (para >= SUNXI_PL_BASE) { + super_standby_para->gpio_enable_bitmap |= + (WAKEUP_GPIO_PL((para - SUNXI_PL_BASE))); + } else if (para >= SUNXI_PH_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('H')); + } else if (para >= SUNXI_PG_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('G')); + } else if (para >= SUNXI_PF_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('F')); + } else if (para >= SUNXI_PE_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('E')); + } else if (para >= SUNXI_PD_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('D')); + } else if (para >= SUNXI_PC_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('C')); + } else if (para >= SUNXI_PB_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('B')); + } else if (para >= SUNXI_PA_BASE) { + super_standby_para->cpux_gpiog_bitmap |= + (WAKEUP_GPIO_GROUP('A')); + } else { + pr_info("cpux need care gpio %d. not support it.\n", + para); + } + spin_unlock(&data_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(enable_gpio_wakeup_src); + +static int sunxi_suspend_valid(suspend_state_t state) +{ + pr_debug("%s\n", __func__); + + if (!((state > PM_SUSPEND_ON) && (state < PM_SUSPEND_MAX))) { + pr_err("state (%d) invalid!\n", state); + return 0; + } + + return 1; +} + +static int __sunxi_suspend_enter(void) +{ + if (regular_standby_flag == 0) { + super_standby_para->event |= CPUS_MEM_WAKEUP; + if (time_to_wakeup_ms > 0) { + super_standby_para->event |= CPUS_WAKEUP_TIMEOUT; + super_standby_para->timeout = time_to_wakeup_ms; + } +#ifdef CONFIG_AW_AXP + if (unlikely(axp_regulator_debug & 0x02)) { + pr_info("power status as follow:"); + axp_regulator_dump(); + } +#endif + pr_info("enter standby, wakesrc:0x%x, timeout: %d\n", + super_standby_para->event, + super_standby_para->timeout); + __dma_flush_area(super_standby_para, standby_space_size); + } + arm_cpuidle_suspend(3); + + return 0; +} + +static int sunxi_suspend_enter(suspend_state_t state) +{ + /* + * This local variable may be calculated with virt_to_phys + * in the function of arisc_query_wakeup_source,so it must + * be located in data section. + */ + static unsigned int wakeup_events; + + if (__sunxi_suspend_enter()) { + pr_err("sunxi suspend failed, need to resume"); + return -1; + } + + arisc_query_wakeup_source(&wakeup_events); + pr_info("platform wakeup, standby wakesource is:0x%x\n", + wakeup_events); + + return 0; +} + +static const struct platform_suspend_ops sunxi_suspend_ops = { + .valid = sunxi_suspend_valid, + .enter = sunxi_suspend_enter, +}; + +static extended_standby_t sun50iw1_superstandby = { + .id = 0x8, + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = 0x0, + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + .cpux_clk_state.exit_pll_en = 0x0, + .cpux_clk_state.pll_change = 0x0, + .cpux_clk_state.bus_change = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x1, + .soc_io_state.io_state[0] = {0x01c208b4, 0x00f0f0ff, 0x00707077}, + .soc_io_state.io_state[1] = {0x01c208b4, 0x000f0f00, 0x00070700}, +}; + +static extended_standby_t sun50iw1_usbstandby = { + .id = 0x2, + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VDD_SYS_BIT) | + BIT(VCC_IO_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .soc_pwr_dm_state.volt[VDD_SYS_BIT] = 980, + .soc_pwr_dm_state.volt[VCC_PLL_BIT] = 2500, + .soc_pwr_dm_state.volt[VCC_IO_BIT] = 3000, + .cpux_clk_state.osc_en = BIT(OSC_LOSC_BIT), + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + .cpux_clk_state.exit_pll_en = 0x0, + .cpux_clk_state.pll_change = 0x0, + .cpux_clk_state.pll_factor[PM_PLL_PERIPH] = { + .factor1 = 1, + .factor2 = 1, + .factor3 = 0, + }, + .cpux_clk_state.bus_change = + BIT(BUS_AHB1) | + BIT(BUS_AHB2) | + BIT(BUS_APB1) | + BIT(BUS_APB2), + .cpux_clk_state.bus_factor[BUS_AHB1] = { + .src = CLK_SRC_LOSC, + .pre_div = 0, + .div_ratio = 0, + }, + .cpux_clk_state.bus_factor[BUS_AHB2] = { + .src = CLK_SRC_AHB1, + .pre_div = 0, + .div_ratio = 0, + }, + .cpux_clk_state.bus_factor[BUS_APB1] = { + .src = CLK_SRC_AHB1, + .pre_div = 0, + .div_ratio = 0, + }, + .cpux_clk_state.bus_factor[BUS_APB2] = { + .src = CLK_SRC_LOSC, + .n = 0, + .m = 0, + }, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x0, + .soc_io_state.io_state[0] = {0x01c208b4, 0x00f0f0ff, 0x00707077}, + .soc_io_state.io_state[1] = {0x01c208b4, 0x000f0f00, 0x00070700}, +}; + +static extended_standby_t sun50iw3_superstandby = { + .id = 0x8, + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = 0x0, + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + .cpux_clk_state.exit_pll_en = 0x0, + .cpux_clk_state.pll_change = 0x0, + .cpux_clk_state.bus_change = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x1, + /* for pf port: set the io to disable state.; */ + .soc_io_state.io_state[0] = {0xd300b0b4, 0x00f0f0ff, 0x00707077}, + .soc_io_state.io_state[1] = {0xd300b0b4, 0x000f0f00, 0x00070700}, +}; + +static extended_standby_t sun50iw3_usbstandby = { + .id = 0x2, + /* note: vcc_io for phy; */ + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VDD_SYS_BIT) | + BIT(VCC_IO_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = + BIT(OSC_LOSC_BIT) | + BIT(OSC_HOSC_BIT) | + BIT(OSC_LDO0_BIT) | + BIT(OSC_LDO1_BIT), + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + /* mean PLL_DRAM is shutdowned & open by dram driver. */ + /* hsic pll can be disabled, + * cpus can change cci400 clk from hsic_pll. + */ + .cpux_clk_state.exit_pll_en = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x0, + /* for pf port: set the io to disable state.; */ + .soc_io_state.io_state[0] = {0xd300b0b4, 0x00f0f0ff, 0x00707077}, + .soc_io_state.io_state[1] = {0xd300b0b4, 0x000f0f00, 0x00070700}, +}; + +static extended_standby_t sun50iw6_superstandby = { + .id = 0x8, + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VDD_SYS_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = 0x0, + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + .cpux_clk_state.exit_pll_en = 0x0, + .cpux_clk_state.pll_change = 0x0, + .cpux_clk_state.bus_change = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x1, + /* for pf port: set the io to disable state.; */ + .soc_io_state.io_state[0] = {0x0300b074, 0x0ffff000, 0x07777000}, + .soc_io_state.io_state[1] = {0x0300b074, 0x00000000, 0x00000000}, +}; + +static extended_standby_t sun50iw6_usbstandby = { + .id = 0x2, + /* note: vcc_io for phy; */ + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VDD_SYS_BIT) | + BIT(VCC_IO_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = + BIT(OSC_LOSC_BIT) | + BIT(OSC_HOSC_BIT) | + BIT(OSC_LDO0_BIT) | + BIT(OSC_LDO1_BIT), + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + /* mean PLL_DRAM is shutdowned & open by dram driver. */ + /* hsic pll can be disabled, + * cpus can change cci400 clk from hsic_pll. + */ + .cpux_clk_state.exit_pll_en = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x0, + /* for pf port: set the io to disable state.; */ + .soc_io_state.io_state[0] = {0x0300b074, 0x0ffff000, 0x07777000}, + .soc_io_state.io_state[1] = {0x0300b074, 0x00000000, 0x00000000}, +}; + +static extended_standby_t sun8iw15_superstandby = { + .id = 0x8, + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = 0x0, + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + .cpux_clk_state.exit_pll_en = 0x0, + .cpux_clk_state.pll_change = 0x0, + .cpux_clk_state.bus_change = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x1, +}; + +static extended_standby_t sun8iw15_usbstandby = { + .id = 0x2, + /* note: vcc_io for phy; */ + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VDD_SYS_BIT) | + BIT(VCC_IO_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = + BIT(OSC_LOSC_BIT) | + BIT(OSC_HOSC_BIT) | + BIT(OSC_LDO0_BIT) | + BIT(OSC_LDO1_BIT), + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + /* mean PLL_DRAM is shutdowned & open by dram driver. */ + /* hsic pll can be disabled, + * cpus can change cci400 clk from hsic_pll. + */ + .cpux_clk_state.exit_pll_en = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x0, +}; + +static extended_standby_t sun8iw17_superstandby = { + .id = 0x8, + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = 0x0, + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + .cpux_clk_state.exit_pll_en = 0x0, + .cpux_clk_state.pll_change = 0x0, + .cpux_clk_state.bus_change = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x1, +}; + +static extended_standby_t sun8iw17_usbstandby = { + .id = 0x2, /* usb1 usb2 usb3 standby */ + /* note: vcc_io for phy; */ + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VDD_SYS_BIT) | + BIT(VCC_IO_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = + BIT(OSC_LOSC_BIT) | + BIT(OSC_HOSC_BIT) | + BIT(OSC_LDO0_BIT) | + BIT(OSC_LDO1_BIT), + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + /* mean PLL_DRAM is shutdowned & open by dram driver. */ + /* hsic pll can be disabled, + * cpus can change cci400 clk from hsic_pll. + */ + .cpux_clk_state.exit_pll_en = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x0, +}; + +static extended_standby_t sun8iw17_usb3standby = { + .id = 1<<0xe, /* usb3 standby (close vdd_sys) */ + /* note: vcc_io for phy; */ + .soc_pwr_dm_state.state = + BIT(VCC_DRAM_BIT) | + BIT(VDD_CPUS_BIT) | + BIT(VCC_LPDDR_BIT) | + BIT(VCC_PL_BIT) | + BIT(VCC_IO_BIT) | + BIT(VCC_PLL_BIT), + .soc_pwr_dm_state.volt[0] = 0x0, + .cpux_clk_state.osc_en = + BIT(OSC_LOSC_BIT) | + BIT(OSC_LDO0_BIT) | + BIT(OSC_LDO1_BIT), + .cpux_clk_state.init_pll_dis = BIT(PM_PLL_DRAM), + /* mean PLL_DRAM is shutdowned & open by dram driver. */ + /* hsic pll can be disabled, + * cpus can change cci400 clk from hsic_pll. + */ + .cpux_clk_state.exit_pll_en = 0x0, + .soc_dram_state.selfresh_flag = 0x1, + .soc_io_state.hold_flag = 0x0, +}; + +static const struct of_device_id pm_of_match[] __initconst = { + { + .compatible = "allwinner,sun50iw1-superstandby", + .data = (extended_standby_t *)&sun50iw1_superstandby, + }, + { + .compatible = "allwinner,sun50iw1-usbstandby", + .data = (extended_standby_t *)&sun50iw1_usbstandby, + }, + { + .compatible = "allwinner,sun50iw3-superstandby", + .data = (extended_standby_t *)&sun50iw3_superstandby, + }, + { + .compatible = "allwinner,sun50iw3-usbstandby", + .data = (extended_standby_t *)&sun50iw3_usbstandby, + }, + { + .compatible = "allwinner,sun50iw6-superstandby", + .data = (extended_standby_t *)&sun50iw6_superstandby, + }, + { + .compatible = "allwinner,sun50iw6-usbstandby", + .data = (extended_standby_t *)&sun50iw6_usbstandby, + }, + { + .compatible = "allwinner,sun8iw15-superstandby", + .data = (extended_standby_t *)&sun8iw15_superstandby, + }, + { + .compatible = "allwinner,sun8iw15-usbstandby", + .data = (extended_standby_t *)&sun8iw15_usbstandby, + }, + { + .compatible = "allwinner,sun8iw17-superstandby", + .data = (extended_standby_t *)&sun8iw17_superstandby, + }, + { + .compatible = "allwinner,sun8iw17-usbstandby", + .data = (extended_standby_t *)&sun8iw17_usbstandby, + }, + { + .compatible = "allwinner,sun8iw17-usb3standby", + .data = (extended_standby_t *)&sun8iw17_usb3standby, + }, + {}, +}; + +static int __init sunxi_suspend_init(void) +{ + struct device_node *np; + const struct of_device_id *matched_np; + const extended_standby_t *extended_standby_info; + extended_standby_t *extend_standby_para; + int ret = 0, standby_stay_cpu = 0; + unsigned int value[3] = { 0, 0, 0 }; + + pr_debug("%s\n", __func__); + + np = of_find_matching_node_and_match(NULL, pm_of_match, + &matched_np); + if (IS_ERR_OR_NULL(np)) { + regular_standby_flag = 1; + goto set_suspend; + } + + extended_standby_info = (extended_standby_t *)matched_np->data; + + ret = of_property_read_u32_array(np, "space1", value, + ARRAY_SIZE(value)); + if (ret) { + pr_err("get standby_space1 err.\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "standby_stay_cpu", &standby_stay_cpu)) { + pr_err("%s: get standby_stay_cpu failed, default to close\ + vcc-cpu when standby!\n", __func__); + standby_stay_cpu = 0; + } + + pr_err("%s, 0x%x, 0x%x, 0x%x\n", __FUNCTION__, + value[0], value[1], value[2]); + super_standby_para = (super_standby_t *)phys_to_virt(value[0]); + super_standby_para->pextended_standby = value[0] + 0x400; + extend_standby_para = + (extended_standby_t *)((char *)super_standby_para + 0x400); + *extend_standby_para = *extended_standby_info; + extend_standby_para->soc_pwr_dm_state.sys_mask = (1 << DM_CPUA) | + (1 << DM_DRAM) | + (1 << DM_SYS) | + (1 << DM_CPUS) | + (1 << DM_LPDDR) | + (1 << DM_PL) | + (1 << DM_PLL) | + (1 << DM_IO); + standby_space_size = value[2]; + super_standby_para->event = 0; + + if (standby_stay_cpu == 1) { + extend_standby_para->soc_pwr_dm_state.state |= + (VDD_CPUA_BIT | VDD_CPUB_BIT); + } + +set_suspend: + suspend_set_ops(&sunxi_suspend_ops); + + return ret; +} +module_init(sunxi_suspend_init); + +static void __exit sunxi_suspend_exit(void) +{ + pr_debug("%s\n", __func__); + suspend_set_ops(NULL); +} +module_exit(sunxi_suspend_exit);