diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-16 12:19:14 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-16 12:19:14 -0400 |
| commit | dc413a90edbe715bebebe859dc072ef73d490d70 (patch) | |
| tree | a6e27ea8a90d61efc1467ca11dee1beb557ee94a | |
| parent | e8a1d70117116c8d96c266f0b99e931717670eaf (diff) | |
| parent | 80d0c649244253d8cb3ba32d708c1431e7ac8fbf (diff) | |
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull ARM SoC-related driver updates from Olof Johansson:
"Various driver updates for platforms and a couple of the small driver
subsystems we merge through our tree:
Among the larger pieces:
- Power management improvements for TI am335x and am437x (RTC
suspend/wake)
- Misc new additions for Amlogic (socinfo updates)
- ZynqMP FPGA manager
- Nvidia improvements for reset/powergate handling
- PMIC wrapper for Mediatek MT8516
- Misc fixes/improvements for ARM SCMI, TEE, NXP i.MX SCU drivers"
* tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (57 commits)
soc: aspeed: fix Kconfig
soc: add aspeed folder and misc drivers
spi: zynqmp: Fix build break
soc: imx: Add generic i.MX8 SoC driver
MAINTAINERS: Update email for Qualcomm SoC maintainer
memory: tegra: Fix a typos for "fdcdwr2" mc client
Revert "ARM: tegra: Restore memory arbitration on resume from LP1 on Tegra30+"
memory: tegra: Replace readl-writel with mc_readl-mc_writel
memory: tegra: Fix integer overflow on tick value calculation
memory: tegra: Fix missed registers values latching
ARM: tegra: cpuidle: Handle tick broadcasting within cpuidle core on Tegra20/30
optee: allow to work without static shared memory
soc/tegra: pmc: Move powergate initialisation to probe
soc/tegra: pmc: Remove reset sysfs entries on error
soc/tegra: pmc: Fix reset sources and levels
soc: amlogic: meson-gx-pwrc-vpu: Add support for G12A
soc: amlogic: meson-gx-pwrc-vpu: Fix power on/off register bitmask
fpga manager: Adding FPGA Manager support for Xilinx zynqmp
dt-bindings: fpga: Add bindings for ZynqMP fpga driver
firmware: xilinx: Add fpga API's
...
71 files changed, 1717 insertions, 434 deletions
diff --git a/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt b/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt new file mode 100644 index 000000000000..3052bf619dd5 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | Devicetree bindings for Zynq Ultrascale MPSoC FPGA Manager. | ||
| 2 | The ZynqMP SoC uses the PCAP (Processor configuration Port) to configure the | ||
| 3 | Programmable Logic (PL). The configuration uses the firmware interface. | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible: should contain "xlnx,zynqmp-pcap-fpga" | ||
| 7 | |||
| 8 | Example for full FPGA configuration: | ||
| 9 | |||
| 10 | fpga-region0 { | ||
| 11 | compatible = "fpga-region"; | ||
| 12 | fpga-mgr = <&zynqmp_pcap>; | ||
| 13 | #address-cells = <0x1>; | ||
| 14 | #size-cells = <0x1>; | ||
| 15 | }; | ||
| 16 | |||
| 17 | firmware { | ||
| 18 | zynqmp_firmware: zynqmp-firmware { | ||
| 19 | compatible = "xlnx,zynqmp-firmware"; | ||
| 20 | method = "smc"; | ||
| 21 | zynqmp_pcap: pcap { | ||
| 22 | compatible = "xlnx,zynqmp-pcap-fpga"; | ||
| 23 | }; | ||
| 24 | }; | ||
| 25 | }; | ||
diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt index 5a2ef1726e2a..7a32404c6114 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt +++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt | |||
| @@ -25,6 +25,7 @@ Required properties in pwrap device node. | |||
| 25 | "mediatek,mt8135-pwrap" for MT8135 SoCs | 25 | "mediatek,mt8135-pwrap" for MT8135 SoCs |
| 26 | "mediatek,mt8173-pwrap" for MT8173 SoCs | 26 | "mediatek,mt8173-pwrap" for MT8173 SoCs |
| 27 | "mediatek,mt8183-pwrap" for MT8183 SoCs | 27 | "mediatek,mt8183-pwrap" for MT8183 SoCs |
| 28 | "mediatek,mt8516-pwrap" for MT8516 SoCs | ||
| 28 | - interrupts: IRQ for pwrap in SOC | 29 | - interrupts: IRQ for pwrap in SOC |
| 29 | - reg-names: Must include the following entries: | 30 | - reg-names: Must include the following entries: |
| 30 | "pwrap": Main registers base | 31 | "pwrap": Main registers base |
diff --git a/Documentation/xilinx/eemi.txt b/Documentation/xilinx/eemi.txt index 0ab686c173be..5f39b4ffdcd4 100644 --- a/Documentation/xilinx/eemi.txt +++ b/Documentation/xilinx/eemi.txt | |||
| @@ -41,8 +41,8 @@ Example of EEMI ops usage: | |||
| 41 | int ret; | 41 | int ret; |
| 42 | 42 | ||
| 43 | eemi_ops = zynqmp_pm_get_eemi_ops(); | 43 | eemi_ops = zynqmp_pm_get_eemi_ops(); |
| 44 | if (!eemi_ops) | 44 | if (IS_ERR(eemi_ops)) |
| 45 | return -ENXIO; | 45 | return PTR_ERR(eemi_ops); |
| 46 | 46 | ||
| 47 | ret = eemi_ops->query_data(qdata, ret_payload); | 47 | ret = eemi_ops->query_data(qdata, ret_payload); |
| 48 | 48 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 5254b352623b..005902ea1450 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -2043,7 +2043,7 @@ W: http://www.armlinux.org.uk/ | |||
| 2043 | S: Maintained | 2043 | S: Maintained |
| 2044 | 2044 | ||
| 2045 | ARM/QUALCOMM SUPPORT | 2045 | ARM/QUALCOMM SUPPORT |
| 2046 | M: Andy Gross <andy.gross@linaro.org> | 2046 | M: Andy Gross <agross@kernel.org> |
| 2047 | M: David Brown <david.brown@linaro.org> | 2047 | M: David Brown <david.brown@linaro.org> |
| 2048 | L: linux-arm-msm@vger.kernel.org | 2048 | L: linux-arm-msm@vger.kernel.org |
| 2049 | S: Maintained | 2049 | S: Maintained |
diff --git a/arch/arm/mach-omap2/pm33xx-core.c b/arch/arm/mach-omap2/pm33xx-core.c index c93b6efd565f..f11442ed3eff 100644 --- a/arch/arm/mach-omap2/pm33xx-core.c +++ b/arch/arm/mach-omap2/pm33xx-core.c | |||
| @@ -10,6 +10,12 @@ | |||
| 10 | #include <asm/suspend.h> | 10 | #include <asm/suspend.h> |
| 11 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
| 12 | #include <linux/platform_data/pm33xx.h> | 12 | #include <linux/platform_data/pm33xx.h> |
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/platform_data/gpio-omap.h> | ||
| 15 | #include <linux/pinctrl/pinmux.h> | ||
| 16 | #include <linux/wkup_m3_ipc.h> | ||
| 17 | #include <linux/of.h> | ||
| 18 | #include <linux/rtc.h> | ||
| 13 | 19 | ||
| 14 | #include "cm33xx.h" | 20 | #include "cm33xx.h" |
| 15 | #include "common.h" | 21 | #include "common.h" |
| @@ -38,6 +44,29 @@ static int am43xx_map_scu(void) | |||
| 38 | return 0; | 44 | return 0; |
| 39 | } | 45 | } |
| 40 | 46 | ||
| 47 | static int am33xx_check_off_mode_enable(void) | ||
| 48 | { | ||
| 49 | if (enable_off_mode) | ||
| 50 | pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); | ||
| 51 | |||
| 52 | /* off mode not supported on am335x so return 0 always */ | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | static int am43xx_check_off_mode_enable(void) | ||
| 57 | { | ||
| 58 | /* | ||
| 59 | * Check for am437x-gp-evm which has the right Hardware design to | ||
| 60 | * support this mode reliably. | ||
| 61 | */ | ||
| 62 | if (of_machine_is_compatible("ti,am437x-gp-evm") && enable_off_mode) | ||
| 63 | return enable_off_mode; | ||
| 64 | else if (enable_off_mode) | ||
| 65 | pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); | ||
| 66 | |||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | |||
| 41 | static int amx3_common_init(void) | 70 | static int amx3_common_init(void) |
| 42 | { | 71 | { |
| 43 | gfx_pwrdm = pwrdm_lookup("gfx_pwrdm"); | 72 | gfx_pwrdm = pwrdm_lookup("gfx_pwrdm"); |
| @@ -141,7 +170,9 @@ static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long), | |||
| 141 | scu_power_mode(scu_base, SCU_PM_POWEROFF); | 170 | scu_power_mode(scu_base, SCU_PM_POWEROFF); |
| 142 | ret = cpu_suspend(args, fn); | 171 | ret = cpu_suspend(args, fn); |
| 143 | scu_power_mode(scu_base, SCU_PM_NORMAL); | 172 | scu_power_mode(scu_base, SCU_PM_NORMAL); |
| 144 | amx3_post_suspend_common(); | 173 | |
| 174 | if (!am43xx_check_off_mode_enable()) | ||
| 175 | amx3_post_suspend_common(); | ||
| 145 | 176 | ||
| 146 | return ret; | 177 | return ret; |
| 147 | } | 178 | } |
| @@ -163,10 +194,48 @@ void __iomem *am43xx_get_rtc_base_addr(void) | |||
| 163 | return omap_hwmod_get_mpu_rt_va(rtc_oh); | 194 | return omap_hwmod_get_mpu_rt_va(rtc_oh); |
| 164 | } | 195 | } |
| 165 | 196 | ||
| 197 | static void am43xx_save_context(void) | ||
| 198 | { | ||
| 199 | } | ||
| 200 | |||
| 201 | static void am33xx_save_context(void) | ||
| 202 | { | ||
| 203 | omap_intc_save_context(); | ||
| 204 | } | ||
| 205 | |||
| 206 | static void am33xx_restore_context(void) | ||
| 207 | { | ||
| 208 | omap_intc_restore_context(); | ||
| 209 | } | ||
| 210 | |||
| 211 | static void am43xx_restore_context(void) | ||
| 212 | { | ||
| 213 | /* | ||
| 214 | * HACK: restore dpll_per_clkdcoldo register contents, to avoid | ||
| 215 | * breaking suspend-resume | ||
| 216 | */ | ||
| 217 | writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14)); | ||
| 218 | } | ||
| 219 | |||
| 220 | static void am43xx_prepare_rtc_suspend(void) | ||
| 221 | { | ||
| 222 | omap_hwmod_enable(rtc_oh); | ||
| 223 | } | ||
| 224 | |||
| 225 | static void am43xx_prepare_rtc_resume(void) | ||
| 226 | { | ||
| 227 | omap_hwmod_idle(rtc_oh); | ||
| 228 | } | ||
| 229 | |||
| 166 | static struct am33xx_pm_platform_data am33xx_ops = { | 230 | static struct am33xx_pm_platform_data am33xx_ops = { |
| 167 | .init = am33xx_suspend_init, | 231 | .init = am33xx_suspend_init, |
| 168 | .soc_suspend = am33xx_suspend, | 232 | .soc_suspend = am33xx_suspend, |
| 169 | .get_sram_addrs = amx3_get_sram_addrs, | 233 | .get_sram_addrs = amx3_get_sram_addrs, |
| 234 | .save_context = am33xx_save_context, | ||
| 235 | .restore_context = am33xx_restore_context, | ||
| 236 | .prepare_rtc_suspend = am43xx_prepare_rtc_suspend, | ||
| 237 | .prepare_rtc_resume = am43xx_prepare_rtc_resume, | ||
| 238 | .check_off_mode_enable = am33xx_check_off_mode_enable, | ||
| 170 | .get_rtc_base_addr = am43xx_get_rtc_base_addr, | 239 | .get_rtc_base_addr = am43xx_get_rtc_base_addr, |
| 171 | }; | 240 | }; |
| 172 | 241 | ||
| @@ -174,6 +243,11 @@ static struct am33xx_pm_platform_data am43xx_ops = { | |||
| 174 | .init = am43xx_suspend_init, | 243 | .init = am43xx_suspend_init, |
| 175 | .soc_suspend = am43xx_suspend, | 244 | .soc_suspend = am43xx_suspend, |
| 176 | .get_sram_addrs = amx3_get_sram_addrs, | 245 | .get_sram_addrs = amx3_get_sram_addrs, |
| 246 | .save_context = am43xx_save_context, | ||
| 247 | .restore_context = am43xx_restore_context, | ||
| 248 | .prepare_rtc_suspend = am43xx_prepare_rtc_suspend, | ||
| 249 | .prepare_rtc_resume = am43xx_prepare_rtc_resume, | ||
| 250 | .check_off_mode_enable = am43xx_check_off_mode_enable, | ||
| 177 | .get_rtc_base_addr = am43xx_get_rtc_base_addr, | 251 | .get_rtc_base_addr = am43xx_get_rtc_base_addr, |
| 178 | }; | 252 | }; |
| 179 | 253 | ||
diff --git a/arch/arm/mach-omap2/sleep43xx.S b/arch/arm/mach-omap2/sleep43xx.S index 5b9343b58fc7..0c1031442571 100644 --- a/arch/arm/mach-omap2/sleep43xx.S +++ b/arch/arm/mach-omap2/sleep43xx.S | |||
| @@ -368,6 +368,9 @@ wait_emif_enable1: | |||
| 368 | mov r1, #AM43XX_EMIF_POWEROFF_DISABLE | 368 | mov r1, #AM43XX_EMIF_POWEROFF_DISABLE |
| 369 | str r1, [r2, #0x0] | 369 | str r1, [r2, #0x0] |
| 370 | 370 | ||
| 371 | ldr r1, [r9, #EMIF_PM_RUN_HW_LEVELING] | ||
| 372 | blx r1 | ||
| 373 | |||
| 371 | #ifdef CONFIG_CACHE_L2X0 | 374 | #ifdef CONFIG_CACHE_L2X0 |
| 372 | ldr r2, l2_cache_base | 375 | ldr r2, l2_cache_base |
| 373 | ldr r0, [r2, #L2X0_CTRL] | 376 | ldr r0, [r2, #L2X0_CTRL] |
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 63e89e75639b..3a06ba263e34 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig | |||
| @@ -10,6 +10,7 @@ menuconfig ARCH_TEGRA | |||
| 10 | select HAVE_ARM_SCU if SMP | 10 | select HAVE_ARM_SCU if SMP |
| 11 | select HAVE_ARM_TWD if SMP | 11 | select HAVE_ARM_TWD if SMP |
| 12 | select PINCTRL | 12 | select PINCTRL |
| 13 | select PM | ||
| 13 | select PM_OPP | 14 | select PM_OPP |
| 14 | select RESET_CONTROLLER | 15 | select RESET_CONTROLLER |
| 15 | select SOC_BUS | 16 | select SOC_BUS |
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 3f24addd7972..6620d61b5ec5 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c | |||
| @@ -61,7 +61,8 @@ static struct cpuidle_driver tegra_idle_driver = { | |||
| 61 | .exit_latency = 5000, | 61 | .exit_latency = 5000, |
| 62 | .target_residency = 10000, | 62 | .target_residency = 10000, |
| 63 | .power_usage = 0, | 63 | .power_usage = 0, |
| 64 | .flags = CPUIDLE_FLAG_COUPLED, | 64 | .flags = CPUIDLE_FLAG_COUPLED | |
| 65 | CPUIDLE_FLAG_TIMER_STOP, | ||
| 65 | .name = "powered-down", | 66 | .name = "powered-down", |
| 66 | .desc = "CPU power gated", | 67 | .desc = "CPU power gated", |
| 67 | }, | 68 | }, |
| @@ -136,12 +137,8 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev, | |||
| 136 | if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready()) | 137 | if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready()) |
| 137 | return false; | 138 | return false; |
| 138 | 139 | ||
| 139 | tick_broadcast_enter(); | ||
| 140 | |||
| 141 | tegra_idle_lp2_last(); | 140 | tegra_idle_lp2_last(); |
| 142 | 141 | ||
| 143 | tick_broadcast_exit(); | ||
| 144 | |||
| 145 | if (cpu_online(1)) | 142 | if (cpu_online(1)) |
| 146 | tegra20_wake_cpu1_from_reset(); | 143 | tegra20_wake_cpu1_from_reset(); |
| 147 | 144 | ||
| @@ -153,14 +150,10 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, | |||
| 153 | struct cpuidle_driver *drv, | 150 | struct cpuidle_driver *drv, |
| 154 | int index) | 151 | int index) |
| 155 | { | 152 | { |
| 156 | tick_broadcast_enter(); | ||
| 157 | |||
| 158 | cpu_suspend(0, tegra20_sleep_cpu_secondary_finish); | 153 | cpu_suspend(0, tegra20_sleep_cpu_secondary_finish); |
| 159 | 154 | ||
| 160 | tegra20_cpu_clear_resettable(); | 155 | tegra20_cpu_clear_resettable(); |
| 161 | 156 | ||
| 162 | tick_broadcast_exit(); | ||
| 163 | |||
| 164 | return true; | 157 | return true; |
| 165 | } | 158 | } |
| 166 | #else | 159 | #else |
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index c1417361e10e..c8fe0447e3a9 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c | |||
| @@ -56,6 +56,7 @@ static struct cpuidle_driver tegra_idle_driver = { | |||
| 56 | .exit_latency = 2000, | 56 | .exit_latency = 2000, |
| 57 | .target_residency = 2200, | 57 | .target_residency = 2200, |
| 58 | .power_usage = 0, | 58 | .power_usage = 0, |
| 59 | .flags = CPUIDLE_FLAG_TIMER_STOP, | ||
| 59 | .name = "powered-down", | 60 | .name = "powered-down", |
| 60 | .desc = "CPU power gated", | 61 | .desc = "CPU power gated", |
| 61 | }, | 62 | }, |
| @@ -76,12 +77,8 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, | |||
| 76 | return false; | 77 | return false; |
| 77 | } | 78 | } |
| 78 | 79 | ||
| 79 | tick_broadcast_enter(); | ||
| 80 | |||
| 81 | tegra_idle_lp2_last(); | 80 | tegra_idle_lp2_last(); |
| 82 | 81 | ||
| 83 | tick_broadcast_exit(); | ||
| 84 | |||
| 85 | return true; | 82 | return true; |
| 86 | } | 83 | } |
| 87 | 84 | ||
| @@ -90,14 +87,10 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, | |||
| 90 | struct cpuidle_driver *drv, | 87 | struct cpuidle_driver *drv, |
| 91 | int index) | 88 | int index) |
| 92 | { | 89 | { |
| 93 | tick_broadcast_enter(); | ||
| 94 | |||
| 95 | smp_wmb(); | 90 | smp_wmb(); |
| 96 | 91 | ||
| 97 | cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); | 92 | cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); |
| 98 | 93 | ||
| 99 | tick_broadcast_exit(); | ||
| 100 | |||
| 101 | return true; | 94 | return true; |
| 102 | } | 95 | } |
| 103 | #else | 96 | #else |
diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h index 4af9e92a216f..ba61db7fe533 100644 --- a/arch/arm/mach-tegra/iomap.h +++ b/arch/arm/mach-tegra/iomap.h | |||
| @@ -79,24 +79,15 @@ | |||
| 79 | #define TEGRA_PMC_BASE 0x7000E400 | 79 | #define TEGRA_PMC_BASE 0x7000E400 |
| 80 | #define TEGRA_PMC_SIZE SZ_256 | 80 | #define TEGRA_PMC_SIZE SZ_256 |
| 81 | 81 | ||
| 82 | #define TEGRA_MC_BASE 0x7000F000 | ||
| 83 | #define TEGRA_MC_SIZE SZ_1K | ||
| 84 | |||
| 85 | #define TEGRA_EMC_BASE 0x7000F400 | 82 | #define TEGRA_EMC_BASE 0x7000F400 |
| 86 | #define TEGRA_EMC_SIZE SZ_1K | 83 | #define TEGRA_EMC_SIZE SZ_1K |
| 87 | 84 | ||
| 88 | #define TEGRA114_MC_BASE 0x70019000 | ||
| 89 | #define TEGRA114_MC_SIZE SZ_4K | ||
| 90 | |||
| 91 | #define TEGRA_EMC0_BASE 0x7001A000 | 85 | #define TEGRA_EMC0_BASE 0x7001A000 |
| 92 | #define TEGRA_EMC0_SIZE SZ_2K | 86 | #define TEGRA_EMC0_SIZE SZ_2K |
| 93 | 87 | ||
| 94 | #define TEGRA_EMC1_BASE 0x7001A800 | 88 | #define TEGRA_EMC1_BASE 0x7001A800 |
| 95 | #define TEGRA_EMC1_SIZE SZ_2K | 89 | #define TEGRA_EMC1_SIZE SZ_2K |
| 96 | 90 | ||
| 97 | #define TEGRA124_MC_BASE 0x70019000 | ||
| 98 | #define TEGRA124_MC_SIZE SZ_4K | ||
| 99 | |||
| 100 | #define TEGRA124_EMC_BASE 0x7001B000 | 91 | #define TEGRA124_EMC_BASE 0x7001B000 |
| 101 | #define TEGRA124_EMC_SIZE SZ_2K | 92 | #define TEGRA124_EMC_SIZE SZ_2K |
| 102 | 93 | ||
diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S index d0b4c486ddbf..7727e005c30e 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S | |||
| @@ -44,8 +44,6 @@ | |||
| 44 | #define EMC_XM2VTTGENPADCTRL 0x310 | 44 | #define EMC_XM2VTTGENPADCTRL 0x310 |
| 45 | #define EMC_XM2VTTGENPADCTRL2 0x314 | 45 | #define EMC_XM2VTTGENPADCTRL2 0x314 |
| 46 | 46 | ||
| 47 | #define MC_EMEM_ARB_CFG 0x90 | ||
| 48 | |||
| 49 | #define PMC_CTRL 0x0 | 47 | #define PMC_CTRL 0x0 |
| 50 | #define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */ | 48 | #define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */ |
| 51 | 49 | ||
| @@ -420,22 +418,6 @@ _pll_m_c_x_done: | |||
| 420 | movweq r0, #:lower16:TEGRA124_EMC_BASE | 418 | movweq r0, #:lower16:TEGRA124_EMC_BASE |
| 421 | movteq r0, #:upper16:TEGRA124_EMC_BASE | 419 | movteq r0, #:upper16:TEGRA124_EMC_BASE |
| 422 | 420 | ||
| 423 | cmp r10, #TEGRA30 | ||
| 424 | moveq r2, #0x20 | ||
| 425 | movweq r4, #:lower16:TEGRA_MC_BASE | ||
| 426 | movteq r4, #:upper16:TEGRA_MC_BASE | ||
| 427 | cmp r10, #TEGRA114 | ||
| 428 | moveq r2, #0x34 | ||
| 429 | movweq r4, #:lower16:TEGRA114_MC_BASE | ||
| 430 | movteq r4, #:upper16:TEGRA114_MC_BASE | ||
| 431 | cmp r10, #TEGRA124 | ||
| 432 | moveq r2, #0x20 | ||
| 433 | movweq r4, #:lower16:TEGRA124_MC_BASE | ||
| 434 | movteq r4, #:upper16:TEGRA124_MC_BASE | ||
| 435 | |||
| 436 | ldr r1, [r5, r2] @ restore MC_EMEM_ARB_CFG | ||
| 437 | str r1, [r4, #MC_EMEM_ARB_CFG] | ||
| 438 | |||
| 439 | exit_self_refresh: | 421 | exit_self_refresh: |
| 440 | ldr r1, [r5, #0xC] @ restore EMC_XM2VTTGENPADCTRL | 422 | ldr r1, [r5, #0xC] @ restore EMC_XM2VTTGENPADCTRL |
| 441 | str r1, [r0, #EMC_XM2VTTGENPADCTRL] | 423 | str r1, [r0, #EMC_XM2VTTGENPADCTRL] |
| @@ -564,7 +546,6 @@ tegra30_sdram_pad_address: | |||
| 564 | .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 | 546 | .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 |
| 565 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 | 547 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 |
| 566 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c | 548 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c |
| 567 | .word TEGRA_MC_BASE + MC_EMEM_ARB_CFG @0x20 | ||
| 568 | tegra30_sdram_pad_address_end: | 549 | tegra30_sdram_pad_address_end: |
| 569 | 550 | ||
| 570 | tegra114_sdram_pad_address: | 551 | tegra114_sdram_pad_address: |
| @@ -581,7 +562,6 @@ tegra114_sdram_pad_address: | |||
| 581 | .word TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL @0x28 | 562 | .word TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL @0x28 |
| 582 | .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL @0x2c | 563 | .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL @0x2c |
| 583 | .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2 @0x30 | 564 | .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2 @0x30 |
| 584 | .word TEGRA114_MC_BASE + MC_EMEM_ARB_CFG @0x34 | ||
| 585 | tegra114_sdram_pad_adress_end: | 565 | tegra114_sdram_pad_adress_end: |
| 586 | 566 | ||
| 587 | tegra124_sdram_pad_address: | 567 | tegra124_sdram_pad_address: |
| @@ -593,7 +573,6 @@ tegra124_sdram_pad_address: | |||
| 593 | .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 | 573 | .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 |
| 594 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 | 574 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 |
| 595 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c | 575 | .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c |
| 596 | .word TEGRA124_MC_BASE + MC_EMEM_ARB_CFG @0x20 | ||
| 597 | tegra124_sdram_pad_address_end: | 576 | tegra124_sdram_pad_address_end: |
| 598 | 577 | ||
| 599 | tegra30_sdram_pad_size: | 578 | tegra30_sdram_pad_size: |
diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c index 084ae286fa23..ac58142301f4 100644 --- a/drivers/bus/tegra-aconnect.c +++ b/drivers/bus/tegra-aconnect.c | |||
| @@ -12,28 +12,38 @@ | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/of_platform.h> | 13 | #include <linux/of_platform.h> |
| 14 | #include <linux/platform_device.h> | 14 | #include <linux/platform_device.h> |
| 15 | #include <linux/pm_clock.h> | ||
| 16 | #include <linux/pm_runtime.h> | 15 | #include <linux/pm_runtime.h> |
| 17 | 16 | ||
| 17 | struct tegra_aconnect { | ||
| 18 | struct clk *ape_clk; | ||
| 19 | struct clk *apb2ape_clk; | ||
| 20 | }; | ||
| 21 | |||
| 18 | static int tegra_aconnect_probe(struct platform_device *pdev) | 22 | static int tegra_aconnect_probe(struct platform_device *pdev) |
| 19 | { | 23 | { |
| 20 | int ret; | 24 | struct tegra_aconnect *aconnect; |
| 21 | 25 | ||
| 22 | if (!pdev->dev.of_node) | 26 | if (!pdev->dev.of_node) |
| 23 | return -EINVAL; | 27 | return -EINVAL; |
| 24 | 28 | ||
| 25 | ret = pm_clk_create(&pdev->dev); | 29 | aconnect = devm_kzalloc(&pdev->dev, sizeof(struct tegra_aconnect), |
| 26 | if (ret) | 30 | GFP_KERNEL); |
| 27 | return ret; | 31 | if (!aconnect) |
| 32 | return -ENOMEM; | ||
| 28 | 33 | ||
| 29 | ret = of_pm_clk_add_clk(&pdev->dev, "ape"); | 34 | aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape"); |
| 30 | if (ret) | 35 | if (IS_ERR(aconnect->ape_clk)) { |
| 31 | goto clk_destroy; | 36 | dev_err(&pdev->dev, "Can't retrieve ape clock\n"); |
| 37 | return PTR_ERR(aconnect->ape_clk); | ||
| 38 | } | ||
| 32 | 39 | ||
| 33 | ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape"); | 40 | aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape"); |
| 34 | if (ret) | 41 | if (IS_ERR(aconnect->apb2ape_clk)) { |
| 35 | goto clk_destroy; | 42 | dev_err(&pdev->dev, "Can't retrieve apb2ape clock\n"); |
| 43 | return PTR_ERR(aconnect->apb2ape_clk); | ||
| 44 | } | ||
| 36 | 45 | ||
| 46 | dev_set_drvdata(&pdev->dev, aconnect); | ||
| 37 | pm_runtime_enable(&pdev->dev); | 47 | pm_runtime_enable(&pdev->dev); |
| 38 | 48 | ||
| 39 | of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); | 49 | of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); |
| @@ -41,35 +51,51 @@ static int tegra_aconnect_probe(struct platform_device *pdev) | |||
| 41 | dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n"); | 51 | dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n"); |
| 42 | 52 | ||
| 43 | return 0; | 53 | return 0; |
| 44 | |||
| 45 | clk_destroy: | ||
| 46 | pm_clk_destroy(&pdev->dev); | ||
| 47 | |||
| 48 | return ret; | ||
| 49 | } | 54 | } |
| 50 | 55 | ||
| 51 | static int tegra_aconnect_remove(struct platform_device *pdev) | 56 | static int tegra_aconnect_remove(struct platform_device *pdev) |
| 52 | { | 57 | { |
| 53 | pm_runtime_disable(&pdev->dev); | 58 | pm_runtime_disable(&pdev->dev); |
| 54 | 59 | ||
| 55 | pm_clk_destroy(&pdev->dev); | ||
| 56 | |||
| 57 | return 0; | 60 | return 0; |
| 58 | } | 61 | } |
| 59 | 62 | ||
| 60 | static int tegra_aconnect_runtime_resume(struct device *dev) | 63 | static int tegra_aconnect_runtime_resume(struct device *dev) |
| 61 | { | 64 | { |
| 62 | return pm_clk_resume(dev); | 65 | struct tegra_aconnect *aconnect = dev_get_drvdata(dev); |
| 66 | int ret; | ||
| 67 | |||
| 68 | ret = clk_prepare_enable(aconnect->ape_clk); | ||
| 69 | if (ret) { | ||
| 70 | dev_err(dev, "ape clk_enable failed: %d\n", ret); | ||
| 71 | return ret; | ||
| 72 | } | ||
| 73 | |||
| 74 | ret = clk_prepare_enable(aconnect->apb2ape_clk); | ||
| 75 | if (ret) { | ||
| 76 | clk_disable_unprepare(aconnect->ape_clk); | ||
| 77 | dev_err(dev, "apb2ape clk_enable failed: %d\n", ret); | ||
| 78 | return ret; | ||
| 79 | } | ||
| 80 | |||
| 81 | return 0; | ||
| 63 | } | 82 | } |
| 64 | 83 | ||
| 65 | static int tegra_aconnect_runtime_suspend(struct device *dev) | 84 | static int tegra_aconnect_runtime_suspend(struct device *dev) |
| 66 | { | 85 | { |
| 67 | return pm_clk_suspend(dev); | 86 | struct tegra_aconnect *aconnect = dev_get_drvdata(dev); |
| 87 | |||
| 88 | clk_disable_unprepare(aconnect->ape_clk); | ||
| 89 | clk_disable_unprepare(aconnect->apb2ape_clk); | ||
| 90 | |||
| 91 | return 0; | ||
| 68 | } | 92 | } |
| 69 | 93 | ||
| 70 | static const struct dev_pm_ops tegra_aconnect_pm_ops = { | 94 | static const struct dev_pm_ops tegra_aconnect_pm_ops = { |
| 71 | SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend, | 95 | SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend, |
| 72 | tegra_aconnect_runtime_resume, NULL) | 96 | tegra_aconnect_runtime_resume, NULL) |
| 97 | SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, | ||
| 98 | pm_runtime_force_resume) | ||
| 73 | }; | 99 | }; |
| 74 | 100 | ||
| 75 | static const struct of_device_id tegra_aconnect_of_match[] = { | 101 | static const struct of_device_id tegra_aconnect_of_match[] = { |
diff --git a/drivers/clk/zynqmp/clkc.c b/drivers/clk/zynqmp/clkc.c index 8febd2431545..a11f93ecbf34 100644 --- a/drivers/clk/zynqmp/clkc.c +++ b/drivers/clk/zynqmp/clkc.c | |||
| @@ -739,8 +739,8 @@ static int zynqmp_clock_probe(struct platform_device *pdev) | |||
| 739 | struct device *dev = &pdev->dev; | 739 | struct device *dev = &pdev->dev; |
| 740 | 740 | ||
| 741 | eemi_ops = zynqmp_pm_get_eemi_ops(); | 741 | eemi_ops = zynqmp_pm_get_eemi_ops(); |
| 742 | if (!eemi_ops) | 742 | if (IS_ERR(eemi_ops)) |
| 743 | return -ENXIO; | 743 | return PTR_ERR(eemi_ops); |
| 744 | 744 | ||
| 745 | ret = zynqmp_clk_setup(dev->of_node); | 745 | ret = zynqmp_clk_setup(dev->of_node); |
| 746 | 746 | ||
diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 8f952f2f1a29..b5bc4c7a8fab 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c | |||
| @@ -654,9 +654,7 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) | |||
| 654 | 654 | ||
| 655 | static int scmi_mailbox_check(struct device_node *np) | 655 | static int scmi_mailbox_check(struct device_node *np) |
| 656 | { | 656 | { |
| 657 | struct of_phandle_args arg; | 657 | return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, NULL); |
| 658 | |||
| 659 | return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg); | ||
| 660 | } | 658 | } |
| 661 | 659 | ||
| 662 | static int scmi_mbox_free_channel(int id, void *p, void *data) | 660 | static int scmi_mbox_free_channel(int id, void *p, void *data) |
| @@ -798,7 +796,9 @@ static int scmi_probe(struct platform_device *pdev) | |||
| 798 | return -EINVAL; | 796 | return -EINVAL; |
| 799 | } | 797 | } |
| 800 | 798 | ||
| 801 | desc = of_match_device(scmi_of_match, dev)->data; | 799 | desc = of_device_get_match_data(dev); |
| 800 | if (!desc) | ||
| 801 | return -EINVAL; | ||
| 802 | 802 | ||
| 803 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); | 803 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); |
| 804 | if (!info) | 804 | if (!info) |
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 1b2e15b3c9ca..802c4ad8e8f9 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o | 2 | obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o imx-scu-irq.o |
| 3 | obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o | 3 | obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o |
diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c new file mode 100644 index 000000000000..043833ad3c1a --- /dev/null +++ b/drivers/firmware/imx/imx-scu-irq.c | |||
| @@ -0,0 +1,168 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Copyright 2019 NXP | ||
| 4 | * | ||
| 5 | * Implementation of the SCU IRQ functions using MU. | ||
| 6 | * | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <dt-bindings/firmware/imx/rsrc.h> | ||
| 10 | #include <linux/firmware/imx/ipc.h> | ||
| 11 | #include <linux/mailbox_client.h> | ||
| 12 | |||
| 13 | #define IMX_SC_IRQ_FUNC_ENABLE 1 | ||
| 14 | #define IMX_SC_IRQ_FUNC_STATUS 2 | ||
| 15 | #define IMX_SC_IRQ_NUM_GROUP 4 | ||
| 16 | |||
| 17 | static u32 mu_resource_id; | ||
| 18 | |||
| 19 | struct imx_sc_msg_irq_get_status { | ||
| 20 | struct imx_sc_rpc_msg hdr; | ||
| 21 | union { | ||
| 22 | struct { | ||
| 23 | u16 resource; | ||
| 24 | u8 group; | ||
| 25 | u8 reserved; | ||
| 26 | } __packed req; | ||
| 27 | struct { | ||
| 28 | u32 status; | ||
| 29 | } resp; | ||
| 30 | } data; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct imx_sc_msg_irq_enable { | ||
| 34 | struct imx_sc_rpc_msg hdr; | ||
| 35 | u32 mask; | ||
| 36 | u16 resource; | ||
| 37 | u8 group; | ||
| 38 | u8 enable; | ||
| 39 | } __packed; | ||
| 40 | |||
| 41 | static struct imx_sc_ipc *imx_sc_irq_ipc_handle; | ||
| 42 | static struct work_struct imx_sc_irq_work; | ||
| 43 | static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain); | ||
| 44 | |||
| 45 | int imx_scu_irq_register_notifier(struct notifier_block *nb) | ||
| 46 | { | ||
| 47 | return atomic_notifier_chain_register( | ||
| 48 | &imx_scu_irq_notifier_chain, nb); | ||
| 49 | } | ||
| 50 | EXPORT_SYMBOL(imx_scu_irq_register_notifier); | ||
| 51 | |||
| 52 | int imx_scu_irq_unregister_notifier(struct notifier_block *nb) | ||
| 53 | { | ||
| 54 | return atomic_notifier_chain_unregister( | ||
| 55 | &imx_scu_irq_notifier_chain, nb); | ||
| 56 | } | ||
| 57 | EXPORT_SYMBOL(imx_scu_irq_unregister_notifier); | ||
| 58 | |||
| 59 | static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group) | ||
| 60 | { | ||
| 61 | return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain, | ||
| 62 | status, (void *)group); | ||
| 63 | } | ||
| 64 | |||
| 65 | static void imx_scu_irq_work_handler(struct work_struct *work) | ||
| 66 | { | ||
| 67 | struct imx_sc_msg_irq_get_status msg; | ||
| 68 | struct imx_sc_rpc_msg *hdr = &msg.hdr; | ||
| 69 | u32 irq_status; | ||
| 70 | int ret; | ||
| 71 | u8 i; | ||
| 72 | |||
| 73 | for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { | ||
| 74 | hdr->ver = IMX_SC_RPC_VERSION; | ||
| 75 | hdr->svc = IMX_SC_RPC_SVC_IRQ; | ||
| 76 | hdr->func = IMX_SC_IRQ_FUNC_STATUS; | ||
| 77 | hdr->size = 2; | ||
| 78 | |||
| 79 | msg.data.req.resource = mu_resource_id; | ||
| 80 | msg.data.req.group = i; | ||
| 81 | |||
| 82 | ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); | ||
| 83 | if (ret) { | ||
| 84 | pr_err("get irq group %d status failed, ret %d\n", | ||
| 85 | i, ret); | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | irq_status = msg.data.resp.status; | ||
| 90 | if (!irq_status) | ||
| 91 | continue; | ||
| 92 | |||
| 93 | imx_scu_irq_notifier_call_chain(irq_status, &i); | ||
| 94 | } | ||
| 95 | } | ||
| 96 | |||
| 97 | int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) | ||
| 98 | { | ||
| 99 | struct imx_sc_msg_irq_enable msg; | ||
| 100 | struct imx_sc_rpc_msg *hdr = &msg.hdr; | ||
| 101 | int ret; | ||
| 102 | |||
| 103 | hdr->ver = IMX_SC_RPC_VERSION; | ||
| 104 | hdr->svc = IMX_SC_RPC_SVC_IRQ; | ||
| 105 | hdr->func = IMX_SC_IRQ_FUNC_ENABLE; | ||
| 106 | hdr->size = 3; | ||
| 107 | |||
| 108 | msg.resource = mu_resource_id; | ||
| 109 | msg.group = group; | ||
| 110 | msg.mask = mask; | ||
| 111 | msg.enable = enable; | ||
| 112 | |||
| 113 | ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); | ||
| 114 | if (ret) | ||
| 115 | pr_err("enable irq failed, group %d, mask %d, ret %d\n", | ||
| 116 | group, mask, ret); | ||
| 117 | |||
| 118 | return ret; | ||
| 119 | } | ||
| 120 | EXPORT_SYMBOL(imx_scu_irq_group_enable); | ||
| 121 | |||
| 122 | static void imx_scu_irq_callback(struct mbox_client *c, void *msg) | ||
| 123 | { | ||
| 124 | schedule_work(&imx_sc_irq_work); | ||
| 125 | } | ||
| 126 | |||
| 127 | int imx_scu_enable_general_irq_channel(struct device *dev) | ||
| 128 | { | ||
| 129 | struct of_phandle_args spec; | ||
| 130 | struct mbox_client *cl; | ||
| 131 | struct mbox_chan *ch; | ||
| 132 | int ret = 0, i = 0; | ||
| 133 | |||
| 134 | ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle); | ||
| 135 | if (ret) | ||
| 136 | return ret; | ||
| 137 | |||
| 138 | cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL); | ||
| 139 | if (!cl) | ||
| 140 | return -ENOMEM; | ||
| 141 | |||
| 142 | cl->dev = dev; | ||
| 143 | cl->rx_callback = imx_scu_irq_callback; | ||
| 144 | |||
| 145 | /* SCU general IRQ uses general interrupt channel 3 */ | ||
| 146 | ch = mbox_request_channel_byname(cl, "gip3"); | ||
| 147 | if (IS_ERR(ch)) { | ||
| 148 | ret = PTR_ERR(ch); | ||
| 149 | dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret); | ||
| 150 | devm_kfree(dev, cl); | ||
| 151 | return ret; | ||
| 152 | } | ||
| 153 | |||
| 154 | INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler); | ||
| 155 | |||
| 156 | if (!of_parse_phandle_with_args(dev->of_node, "mboxes", | ||
| 157 | "#mbox-cells", 0, &spec)) | ||
| 158 | i = of_alias_get_id(spec.np, "mu"); | ||
| 159 | |||
| 160 | /* use mu1 as general mu irq channel if failed */ | ||
| 161 | if (i < 0) | ||
| 162 | i = 1; | ||
| 163 | |||
| 164 | mu_resource_id = IMX_SC_R_MU_0A + i; | ||
| 165 | |||
| 166 | return ret; | ||
| 167 | } | ||
| 168 | EXPORT_SYMBOL(imx_scu_enable_general_irq_channel); | ||
diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 2bb1a19c413f..04a24a863d6e 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/err.h> | 10 | #include <linux/err.h> |
| 11 | #include <linux/firmware/imx/types.h> | 11 | #include <linux/firmware/imx/types.h> |
| 12 | #include <linux/firmware/imx/ipc.h> | 12 | #include <linux/firmware/imx/ipc.h> |
| 13 | #include <linux/firmware/imx/sci.h> | ||
| 13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
| 14 | #include <linux/irq.h> | 15 | #include <linux/irq.h> |
| 15 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
| @@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev) | |||
| 246 | 247 | ||
| 247 | imx_sc_ipc_handle = sc_ipc; | 248 | imx_sc_ipc_handle = sc_ipc; |
| 248 | 249 | ||
| 250 | ret = imx_scu_enable_general_irq_channel(dev); | ||
| 251 | if (ret) | ||
| 252 | dev_warn(dev, | ||
| 253 | "failed to enable general irq channel: %d\n", ret); | ||
| 254 | |||
| 249 | dev_info(dev, "NXP i.MX SCU Initialized\n"); | 255 | dev_info(dev, "NXP i.MX SCU Initialized\n"); |
| 250 | 256 | ||
| 251 | return devm_of_platform_populate(dev); | 257 | return devm_of_platform_populate(dev); |
diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 39a94c7177fc..480cec69e2c9 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c | |||
| @@ -74,7 +74,10 @@ struct imx_sc_pd_range { | |||
| 74 | char *name; | 74 | char *name; |
| 75 | u32 rsrc; | 75 | u32 rsrc; |
| 76 | u8 num; | 76 | u8 num; |
| 77 | |||
| 78 | /* add domain index */ | ||
| 77 | bool postfix; | 79 | bool postfix; |
| 80 | u8 start_from; | ||
| 78 | }; | 81 | }; |
| 79 | 82 | ||
| 80 | struct imx_sc_pd_soc { | 83 | struct imx_sc_pd_soc { |
| @@ -84,71 +87,75 @@ struct imx_sc_pd_soc { | |||
| 84 | 87 | ||
| 85 | static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { | 88 | static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { |
| 86 | /* LSIO SS */ | 89 | /* LSIO SS */ |
| 87 | { "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 }, | 90 | { "pwm", IMX_SC_R_PWM_0, 8, true, 0 }, |
| 88 | { "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 }, | 91 | { "gpio", IMX_SC_R_GPIO_0, 8, true, 0 }, |
| 89 | { "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 }, | 92 | { "gpt", IMX_SC_R_GPT_0, 5, true, 0 }, |
| 90 | { "lsio-kpp", IMX_SC_R_KPP, 1, 0 }, | 93 | { "kpp", IMX_SC_R_KPP, 1, false, 0 }, |
| 91 | { "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 }, | 94 | { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 }, |
| 92 | { "lsio-mu", IMX_SC_R_MU_0A, 14, 1 }, | 95 | { "mu", IMX_SC_R_MU_0A, 14, true, 0 }, |
| 93 | 96 | ||
| 94 | /* CONN SS */ | 97 | /* CONN SS */ |
| 95 | { "con-usb", IMX_SC_R_USB_0, 2, 1 }, | 98 | { "usb", IMX_SC_R_USB_0, 2, true, 0 }, |
| 96 | { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 }, | 99 | { "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 }, |
| 97 | { "con-usb2", IMX_SC_R_USB_2, 1, 0 }, | 100 | { "usb2", IMX_SC_R_USB_2, 1, false, 0 }, |
| 98 | { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 }, | 101 | { "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 }, |
| 99 | { "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 }, | 102 | { "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 }, |
| 100 | { "con-enet", IMX_SC_R_ENET_0, 2, 1 }, | 103 | { "enet", IMX_SC_R_ENET_0, 2, true, 0 }, |
| 101 | { "con-nand", IMX_SC_R_NAND, 1, 0 }, | 104 | { "nand", IMX_SC_R_NAND, 1, false, 0 }, |
| 102 | { "con-mlb", IMX_SC_R_MLB_0, 1, 1 }, | 105 | { "mlb", IMX_SC_R_MLB_0, 1, true, 0 }, |
| 103 | 106 | ||
| 104 | /* Audio DMA SS */ | 107 | /* AUDIO SS */ |
| 105 | { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 }, | 108 | { "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 }, |
| 106 | { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 }, | 109 | { "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 }, |
| 107 | { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 }, | 110 | { "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 }, |
| 108 | { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 }, | 111 | { "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 }, |
| 109 | { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 }, | 112 | { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 }, |
| 110 | { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 }, | 113 | { "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 }, |
| 111 | { "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 }, | 114 | { "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 }, |
| 112 | { "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 }, | 115 | { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 }, |
| 113 | { "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 }, | 116 | { "esai0", IMX_SC_R_ESAI_0, 1, false, 0 }, |
| 114 | { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 }, | 117 | { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 }, |
| 115 | { "adma-sai", IMX_SC_R_SAI_0, 3, 1 }, | 118 | { "sai", IMX_SC_R_SAI_0, 3, true, 0 }, |
| 116 | { "adma-amix", IMX_SC_R_AMIX, 1, 0 }, | 119 | { "amix", IMX_SC_R_AMIX, 1, false, 0 }, |
| 117 | { "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 }, | 120 | { "mqs0", IMX_SC_R_MQS_0, 1, false, 0 }, |
| 118 | { "adma-dsp", IMX_SC_R_DSP, 1, 0 }, | 121 | { "dsp", IMX_SC_R_DSP, 1, false, 0 }, |
| 119 | { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 }, | 122 | { "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 }, |
| 120 | { "adma-can", IMX_SC_R_CAN_0, 3, 1 }, | 123 | |
| 121 | { "adma-ftm", IMX_SC_R_FTM_0, 2, 1 }, | 124 | /* DMA SS */ |
| 122 | { "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 }, | 125 | { "can", IMX_SC_R_CAN_0, 3, true, 0 }, |
| 123 | { "adma-adc", IMX_SC_R_ADC_0, 1, 1 }, | 126 | { "ftm", IMX_SC_R_FTM_0, 2, true, 0 }, |
| 124 | { "adma-lcd", IMX_SC_R_LCD_0, 1, 1 }, | 127 | { "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 }, |
| 125 | { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 }, | 128 | { "adc", IMX_SC_R_ADC_0, 1, true, 0 }, |
| 126 | { "adma-lpuart", IMX_SC_R_UART_0, 4, 1 }, | 129 | { "lcd", IMX_SC_R_LCD_0, 1, true, 0 }, |
| 127 | { "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 }, | 130 | { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 }, |
| 128 | 131 | { "lpuart", IMX_SC_R_UART_0, 4, true, 0 }, | |
| 129 | /* VPU SS */ | 132 | { "lpspi", IMX_SC_R_SPI_0, 4, true, 0 }, |
| 130 | { "vpu", IMX_SC_R_VPU, 1, 0 }, | 133 | |
| 131 | { "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 }, | 134 | /* VPU SS */ |
| 132 | { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 }, | 135 | { "vpu", IMX_SC_R_VPU, 1, false, 0 }, |
| 133 | { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 }, | 136 | { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 }, |
| 137 | { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 }, | ||
| 138 | { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 }, | ||
| 134 | 139 | ||
| 135 | /* GPU SS */ | 140 | /* GPU SS */ |
| 136 | { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 }, | 141 | { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 }, |
| 137 | 142 | ||
| 138 | /* HSIO SS */ | 143 | /* HSIO SS */ |
| 139 | { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 }, | 144 | { "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 }, |
| 140 | { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 }, | 145 | { "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 }, |
| 141 | { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 }, | 146 | { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 }, |
| 147 | |||
| 148 | /* MIPI SS */ | ||
| 149 | { "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 }, | ||
| 150 | { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 }, | ||
| 151 | { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 }, | ||
| 142 | 152 | ||
| 143 | /* MIPI/LVDS SS */ | 153 | /* LVDS SS */ |
| 144 | { "mipi0", IMX_SC_R_MIPI_0, 1, 0 }, | 154 | { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 }, |
| 145 | { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 }, | ||
| 146 | { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 }, | ||
| 147 | { "lvds0", IMX_SC_R_LVDS_0, 1, 0 }, | ||
| 148 | 155 | ||
| 149 | /* DC SS */ | 156 | /* DC SS */ |
| 150 | { "dc0", IMX_SC_R_DC_0, 1, 0 }, | 157 | { "dc0", IMX_SC_R_DC_0, 1, false, 0 }, |
| 151 | { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 }, | 158 | { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 }, |
| 152 | }; | 159 | }; |
| 153 | 160 | ||
| 154 | static const struct imx_sc_pd_soc imx8qxp_scu_pd = { | 161 | static const struct imx_sc_pd_soc imx8qxp_scu_pd = { |
| @@ -236,7 +243,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx, | |||
| 236 | 243 | ||
| 237 | if (pd_ranges->postfix) | 244 | if (pd_ranges->postfix) |
| 238 | snprintf(sc_pd->name, sizeof(sc_pd->name), | 245 | snprintf(sc_pd->name, sizeof(sc_pd->name), |
| 239 | "%s%i", pd_ranges->name, idx); | 246 | "%s%i", pd_ranges->name, pd_ranges->start_from + idx); |
| 240 | else | 247 | else |
| 241 | snprintf(sc_pd->name, sizeof(sc_pd->name), | 248 | snprintf(sc_pd->name, sizeof(sc_pd->name), |
| 242 | "%s", pd_ranges->name); | 249 | "%s", pd_ranges->name); |
diff --git a/drivers/firmware/xilinx/zynqmp-debug.c b/drivers/firmware/xilinx/zynqmp-debug.c index 2771df6df379..c6d0724da4db 100644 --- a/drivers/firmware/xilinx/zynqmp-debug.c +++ b/drivers/firmware/xilinx/zynqmp-debug.c | |||
| @@ -90,9 +90,6 @@ static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret) | |||
| 90 | int ret; | 90 | int ret; |
| 91 | struct zynqmp_pm_query_data qdata = {0}; | 91 | struct zynqmp_pm_query_data qdata = {0}; |
| 92 | 92 | ||
| 93 | if (!eemi_ops) | ||
| 94 | return -ENXIO; | ||
| 95 | |||
| 96 | switch (pm_id) { | 93 | switch (pm_id) { |
| 97 | case PM_GET_API_VERSION: | 94 | case PM_GET_API_VERSION: |
| 98 | ret = eemi_ops->get_api_version(&pm_api_version); | 95 | ret = eemi_ops->get_api_version(&pm_api_version); |
| @@ -163,21 +160,14 @@ static ssize_t zynqmp_pm_debugfs_api_write(struct file *file, | |||
| 163 | 160 | ||
| 164 | strcpy(debugfs_buf, ""); | 161 | strcpy(debugfs_buf, ""); |
| 165 | 162 | ||
| 166 | if (*off != 0 || len == 0) | 163 | if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1) |
| 167 | return -EINVAL; | 164 | return -EINVAL; |
| 168 | 165 | ||
| 169 | kern_buff = kzalloc(len, GFP_KERNEL); | 166 | kern_buff = memdup_user_nul(ptr, len); |
| 170 | if (!kern_buff) | 167 | if (IS_ERR(kern_buff)) |
| 171 | return -ENOMEM; | 168 | return PTR_ERR(kern_buff); |
| 172 | |||
| 173 | tmp_buff = kern_buff; | 169 | tmp_buff = kern_buff; |
| 174 | 170 | ||
| 175 | ret = strncpy_from_user(kern_buff, ptr, len); | ||
| 176 | if (ret < 0) { | ||
| 177 | ret = -EFAULT; | ||
| 178 | goto err; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* Read the API name from a user request */ | 171 | /* Read the API name from a user request */ |
| 182 | pm_api_req = strsep(&kern_buff, " "); | 172 | pm_api_req = strsep(&kern_buff, " "); |
| 183 | 173 | ||
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 98f936125643..fd3d83745208 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c | |||
| @@ -24,6 +24,8 @@ | |||
| 24 | #include <linux/firmware/xlnx-zynqmp.h> | 24 | #include <linux/firmware/xlnx-zynqmp.h> |
| 25 | #include "zynqmp-debug.h" | 25 | #include "zynqmp-debug.h" |
| 26 | 26 | ||
| 27 | static const struct zynqmp_eemi_ops *eemi_ops_tbl; | ||
| 28 | |||
| 27 | static const struct mfd_cell firmware_devs[] = { | 29 | static const struct mfd_cell firmware_devs[] = { |
| 28 | { | 30 | { |
| 29 | .name = "zynqmp_power_controller", | 31 | .name = "zynqmp_power_controller", |
| @@ -538,6 +540,49 @@ static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, | |||
| 538 | } | 540 | } |
| 539 | 541 | ||
| 540 | /** | 542 | /** |
| 543 | * zynqmp_pm_fpga_load - Perform the fpga load | ||
| 544 | * @address: Address to write to | ||
| 545 | * @size: pl bitstream size | ||
| 546 | * @flags: Bitstream type | ||
| 547 | * -XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration | ||
| 548 | * -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration | ||
| 549 | * | ||
| 550 | * This function provides access to pmufw. To transfer | ||
| 551 | * the required bitstream into PL. | ||
| 552 | * | ||
| 553 | * Return: Returns status, either success or error+reason | ||
| 554 | */ | ||
| 555 | static int zynqmp_pm_fpga_load(const u64 address, const u32 size, | ||
| 556 | const u32 flags) | ||
| 557 | { | ||
| 558 | return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address), | ||
| 559 | upper_32_bits(address), size, flags, NULL); | ||
| 560 | } | ||
| 561 | |||
| 562 | /** | ||
| 563 | * zynqmp_pm_fpga_get_status - Read value from PCAP status register | ||
| 564 | * @value: Value to read | ||
| 565 | * | ||
| 566 | * This function provides access to the pmufw to get the PCAP | ||
| 567 | * status | ||
| 568 | * | ||
| 569 | * Return: Returns status, either success or error+reason | ||
| 570 | */ | ||
| 571 | static int zynqmp_pm_fpga_get_status(u32 *value) | ||
| 572 | { | ||
| 573 | u32 ret_payload[PAYLOAD_ARG_CNT]; | ||
| 574 | int ret; | ||
| 575 | |||
| 576 | if (!value) | ||
| 577 | return -EINVAL; | ||
| 578 | |||
| 579 | ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload); | ||
| 580 | *value = ret_payload[1]; | ||
| 581 | |||
| 582 | return ret; | ||
| 583 | } | ||
| 584 | |||
| 585 | /** | ||
| 541 | * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller | 586 | * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller |
| 542 | * master has initialized its own power management | 587 | * master has initialized its own power management |
| 543 | * | 588 | * |
| @@ -640,6 +685,8 @@ static const struct zynqmp_eemi_ops eemi_ops = { | |||
| 640 | .request_node = zynqmp_pm_request_node, | 685 | .request_node = zynqmp_pm_request_node, |
| 641 | .release_node = zynqmp_pm_release_node, | 686 | .release_node = zynqmp_pm_release_node, |
| 642 | .set_requirement = zynqmp_pm_set_requirement, | 687 | .set_requirement = zynqmp_pm_set_requirement, |
| 688 | .fpga_load = zynqmp_pm_fpga_load, | ||
| 689 | .fpga_get_status = zynqmp_pm_fpga_get_status, | ||
| 643 | }; | 690 | }; |
| 644 | 691 | ||
| 645 | /** | 692 | /** |
| @@ -649,7 +696,11 @@ static const struct zynqmp_eemi_ops eemi_ops = { | |||
| 649 | */ | 696 | */ |
| 650 | const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) | 697 | const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) |
| 651 | { | 698 | { |
| 652 | return &eemi_ops; | 699 | if (eemi_ops_tbl) |
| 700 | return eemi_ops_tbl; | ||
| 701 | else | ||
| 702 | return ERR_PTR(-EPROBE_DEFER); | ||
| 703 | |||
| 653 | } | 704 | } |
| 654 | EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); | 705 | EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); |
| 655 | 706 | ||
| @@ -694,6 +745,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) | |||
| 694 | pr_info("%s Trustzone version v%d.%d\n", __func__, | 745 | pr_info("%s Trustzone version v%d.%d\n", __func__, |
| 695 | pm_tz_version >> 16, pm_tz_version & 0xFFFF); | 746 | pm_tz_version >> 16, pm_tz_version & 0xFFFF); |
| 696 | 747 | ||
| 748 | /* Assign eemi_ops_table */ | ||
| 749 | eemi_ops_tbl = &eemi_ops; | ||
| 750 | |||
| 697 | zynqmp_pm_api_debugfs_init(); | 751 | zynqmp_pm_api_debugfs_init(); |
| 698 | 752 | ||
| 699 | ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs, | 753 | ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs, |
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index c20445b867ae..d892f3efcd76 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig | |||
| @@ -204,4 +204,13 @@ config FPGA_DFL_PCI | |||
| 204 | 204 | ||
| 205 | To compile this as a module, choose M here. | 205 | To compile this as a module, choose M here. |
| 206 | 206 | ||
| 207 | config FPGA_MGR_ZYNQMP_FPGA | ||
| 208 | tristate "Xilinx ZynqMP FPGA" | ||
| 209 | depends on ARCH_ZYNQMP || COMPILE_TEST | ||
| 210 | help | ||
| 211 | FPGA manager driver support for Xilinx ZynqMP FPGAs. | ||
| 212 | This driver uses the processor configuration port(PCAP) | ||
| 213 | to configure the programmable logic(PL) through PS | ||
| 214 | on ZynqMP SoC. | ||
| 215 | |||
| 207 | endif # FPGA | 216 | endif # FPGA |
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index c0dd4c82fbdb..312b9371742f 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile | |||
| @@ -17,6 +17,7 @@ obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o | |||
| 17 | obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o | 17 | obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o |
| 18 | obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o | 18 | obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o |
| 19 | obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o | 19 | obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o |
| 20 | obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o | ||
| 20 | obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o | 21 | obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o |
| 21 | obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o | 22 | obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o |
| 22 | 23 | ||
diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c new file mode 100644 index 000000000000..f7cbaadf49ab --- /dev/null +++ b/drivers/fpga/zynqmp-fpga.c | |||
| @@ -0,0 +1,159 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0+ | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2019 Xilinx, Inc. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/dma-mapping.h> | ||
| 7 | #include <linux/fpga/fpga-mgr.h> | ||
| 8 | #include <linux/io.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/of_address.h> | ||
| 12 | #include <linux/string.h> | ||
| 13 | #include <linux/firmware/xlnx-zynqmp.h> | ||
| 14 | |||
| 15 | /* Constant Definitions */ | ||
| 16 | #define IXR_FPGA_DONE_MASK BIT(3) | ||
| 17 | |||
| 18 | /** | ||
| 19 | * struct zynqmp_fpga_priv - Private data structure | ||
| 20 | * @dev: Device data structure | ||
| 21 | * @flags: flags which is used to identify the bitfile type | ||
| 22 | */ | ||
| 23 | struct zynqmp_fpga_priv { | ||
| 24 | struct device *dev; | ||
| 25 | u32 flags; | ||
| 26 | }; | ||
| 27 | |||
| 28 | static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr, | ||
| 29 | struct fpga_image_info *info, | ||
| 30 | const char *buf, size_t size) | ||
| 31 | { | ||
| 32 | struct zynqmp_fpga_priv *priv; | ||
| 33 | |||
| 34 | priv = mgr->priv; | ||
| 35 | priv->flags = info->flags; | ||
| 36 | |||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | |||
| 40 | static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, | ||
| 41 | const char *buf, size_t size) | ||
| 42 | { | ||
| 43 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 44 | struct zynqmp_fpga_priv *priv; | ||
| 45 | dma_addr_t dma_addr; | ||
| 46 | u32 eemi_flags = 0; | ||
| 47 | char *kbuf; | ||
| 48 | int ret; | ||
| 49 | |||
| 50 | if (!eemi_ops || !eemi_ops->fpga_load) | ||
| 51 | return -ENXIO; | ||
| 52 | |||
| 53 | priv = mgr->priv; | ||
| 54 | |||
| 55 | kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL); | ||
| 56 | if (!kbuf) | ||
| 57 | return -ENOMEM; | ||
| 58 | |||
| 59 | memcpy(kbuf, buf, size); | ||
| 60 | |||
| 61 | wmb(); /* ensure all writes are done before initiate FW call */ | ||
| 62 | |||
| 63 | if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG) | ||
| 64 | eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL; | ||
| 65 | |||
| 66 | ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags); | ||
| 67 | |||
| 68 | dma_free_coherent(priv->dev, size, kbuf, dma_addr); | ||
| 69 | |||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr, | ||
| 74 | struct fpga_image_info *info) | ||
| 75 | { | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr) | ||
| 80 | { | ||
| 81 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 82 | u32 status; | ||
| 83 | |||
| 84 | if (!eemi_ops || !eemi_ops->fpga_get_status) | ||
| 85 | return FPGA_MGR_STATE_UNKNOWN; | ||
| 86 | |||
| 87 | eemi_ops->fpga_get_status(&status); | ||
| 88 | if (status & IXR_FPGA_DONE_MASK) | ||
| 89 | return FPGA_MGR_STATE_OPERATING; | ||
| 90 | |||
| 91 | return FPGA_MGR_STATE_UNKNOWN; | ||
| 92 | } | ||
| 93 | |||
| 94 | static const struct fpga_manager_ops zynqmp_fpga_ops = { | ||
| 95 | .state = zynqmp_fpga_ops_state, | ||
| 96 | .write_init = zynqmp_fpga_ops_write_init, | ||
| 97 | .write = zynqmp_fpga_ops_write, | ||
| 98 | .write_complete = zynqmp_fpga_ops_write_complete, | ||
| 99 | }; | ||
| 100 | |||
| 101 | static int zynqmp_fpga_probe(struct platform_device *pdev) | ||
| 102 | { | ||
| 103 | struct device *dev = &pdev->dev; | ||
| 104 | struct zynqmp_fpga_priv *priv; | ||
| 105 | struct fpga_manager *mgr; | ||
| 106 | int ret; | ||
| 107 | |||
| 108 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
| 109 | if (!priv) | ||
| 110 | return -ENOMEM; | ||
| 111 | |||
| 112 | priv->dev = dev; | ||
| 113 | |||
| 114 | mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager", | ||
| 115 | &zynqmp_fpga_ops, priv); | ||
| 116 | if (!mgr) | ||
| 117 | return -ENOMEM; | ||
| 118 | |||
| 119 | platform_set_drvdata(pdev, mgr); | ||
| 120 | |||
| 121 | ret = fpga_mgr_register(mgr); | ||
| 122 | if (ret) { | ||
| 123 | dev_err(dev, "unable to register FPGA manager"); | ||
| 124 | return ret; | ||
| 125 | } | ||
| 126 | |||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int zynqmp_fpga_remove(struct platform_device *pdev) | ||
| 131 | { | ||
| 132 | struct fpga_manager *mgr = platform_get_drvdata(pdev); | ||
| 133 | |||
| 134 | fpga_mgr_unregister(mgr); | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static const struct of_device_id zynqmp_fpga_of_match[] = { | ||
| 140 | { .compatible = "xlnx,zynqmp-pcap-fpga", }, | ||
| 141 | {}, | ||
| 142 | }; | ||
| 143 | |||
| 144 | MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match); | ||
| 145 | |||
| 146 | static struct platform_driver zynqmp_fpga_driver = { | ||
| 147 | .probe = zynqmp_fpga_probe, | ||
| 148 | .remove = zynqmp_fpga_remove, | ||
| 149 | .driver = { | ||
| 150 | .name = "zynqmp_fpga_manager", | ||
| 151 | .of_match_table = of_match_ptr(zynqmp_fpga_of_match), | ||
| 152 | }, | ||
| 153 | }; | ||
| 154 | |||
| 155 | module_platform_driver(zynqmp_fpga_driver); | ||
| 156 | |||
| 157 | MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>"); | ||
| 158 | MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager"); | ||
| 159 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h index 9e9f8037955d..6b71fadb3cfa 100644 --- a/drivers/memory/emif.h +++ b/drivers/memory/emif.h | |||
| @@ -537,6 +537,9 @@ | |||
| 537 | #define MCONNID_SHIFT 0 | 537 | #define MCONNID_SHIFT 0 |
| 538 | #define MCONNID_MASK (0xff << 0) | 538 | #define MCONNID_MASK (0xff << 0) |
| 539 | 539 | ||
| 540 | /* READ_WRITE_LEVELING_CONTROL */ | ||
| 541 | #define RDWRLVLFULL_START 0x80000000 | ||
| 542 | |||
| 540 | /* DDR_PHY_CTRL_1 - EMIF4D */ | 543 | /* DDR_PHY_CTRL_1 - EMIF4D */ |
| 541 | #define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4 | 544 | #define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4 |
| 542 | #define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4) | 545 | #define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4) |
| @@ -598,6 +601,7 @@ extern struct emif_regs_amx3 ti_emif_regs_amx3; | |||
| 598 | 601 | ||
| 599 | void ti_emif_save_context(void); | 602 | void ti_emif_save_context(void); |
| 600 | void ti_emif_restore_context(void); | 603 | void ti_emif_restore_context(void); |
| 604 | void ti_emif_run_hw_leveling(void); | ||
| 601 | void ti_emif_enter_sr(void); | 605 | void ti_emif_enter_sr(void); |
| 602 | void ti_emif_exit_sr(void); | 606 | void ti_emif_exit_sr(void); |
| 603 | void ti_emif_abort_sr(void); | 607 | void ti_emif_abort_sr(void); |
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 0a53598d982f..163b6c69e651 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c | |||
| @@ -51,6 +51,9 @@ | |||
| 51 | #define MC_EMEM_ADR_CFG 0x54 | 51 | #define MC_EMEM_ADR_CFG 0x54 |
| 52 | #define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) | 52 | #define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) |
| 53 | 53 | ||
| 54 | #define MC_TIMING_CONTROL 0xfc | ||
| 55 | #define MC_TIMING_UPDATE BIT(0) | ||
| 56 | |||
| 54 | static const struct of_device_id tegra_mc_of_match[] = { | 57 | static const struct of_device_id tegra_mc_of_match[] = { |
| 55 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | 58 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC |
| 56 | { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc }, | 59 | { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc }, |
| @@ -74,7 +77,7 @@ static const struct of_device_id tegra_mc_of_match[] = { | |||
| 74 | }; | 77 | }; |
| 75 | MODULE_DEVICE_TABLE(of, tegra_mc_of_match); | 78 | MODULE_DEVICE_TABLE(of, tegra_mc_of_match); |
| 76 | 79 | ||
| 77 | static int terga_mc_block_dma_common(struct tegra_mc *mc, | 80 | static int tegra_mc_block_dma_common(struct tegra_mc *mc, |
| 78 | const struct tegra_mc_reset *rst) | 81 | const struct tegra_mc_reset *rst) |
| 79 | { | 82 | { |
| 80 | unsigned long flags; | 83 | unsigned long flags; |
| @@ -90,13 +93,13 @@ static int terga_mc_block_dma_common(struct tegra_mc *mc, | |||
| 90 | return 0; | 93 | return 0; |
| 91 | } | 94 | } |
| 92 | 95 | ||
| 93 | static bool terga_mc_dma_idling_common(struct tegra_mc *mc, | 96 | static bool tegra_mc_dma_idling_common(struct tegra_mc *mc, |
| 94 | const struct tegra_mc_reset *rst) | 97 | const struct tegra_mc_reset *rst) |
| 95 | { | 98 | { |
| 96 | return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0; | 99 | return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0; |
| 97 | } | 100 | } |
| 98 | 101 | ||
| 99 | static int terga_mc_unblock_dma_common(struct tegra_mc *mc, | 102 | static int tegra_mc_unblock_dma_common(struct tegra_mc *mc, |
| 100 | const struct tegra_mc_reset *rst) | 103 | const struct tegra_mc_reset *rst) |
| 101 | { | 104 | { |
| 102 | unsigned long flags; | 105 | unsigned long flags; |
| @@ -112,17 +115,17 @@ static int terga_mc_unblock_dma_common(struct tegra_mc *mc, | |||
| 112 | return 0; | 115 | return 0; |
| 113 | } | 116 | } |
| 114 | 117 | ||
| 115 | static int terga_mc_reset_status_common(struct tegra_mc *mc, | 118 | static int tegra_mc_reset_status_common(struct tegra_mc *mc, |
| 116 | const struct tegra_mc_reset *rst) | 119 | const struct tegra_mc_reset *rst) |
| 117 | { | 120 | { |
| 118 | return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0; | 121 | return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0; |
| 119 | } | 122 | } |
| 120 | 123 | ||
| 121 | const struct tegra_mc_reset_ops terga_mc_reset_ops_common = { | 124 | const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = { |
| 122 | .block_dma = terga_mc_block_dma_common, | 125 | .block_dma = tegra_mc_block_dma_common, |
| 123 | .dma_idling = terga_mc_dma_idling_common, | 126 | .dma_idling = tegra_mc_dma_idling_common, |
| 124 | .unblock_dma = terga_mc_unblock_dma_common, | 127 | .unblock_dma = tegra_mc_unblock_dma_common, |
| 125 | .reset_status = terga_mc_reset_status_common, | 128 | .reset_status = tegra_mc_reset_status_common, |
| 126 | }; | 129 | }; |
| 127 | 130 | ||
| 128 | static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev) | 131 | static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev) |
| @@ -282,25 +285,28 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) | |||
| 282 | u32 value; | 285 | u32 value; |
| 283 | 286 | ||
| 284 | /* compute the number of MC clock cycles per tick */ | 287 | /* compute the number of MC clock cycles per tick */ |
| 285 | tick = mc->tick * clk_get_rate(mc->clk); | 288 | tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); |
| 286 | do_div(tick, NSEC_PER_SEC); | 289 | do_div(tick, NSEC_PER_SEC); |
| 287 | 290 | ||
| 288 | value = readl(mc->regs + MC_EMEM_ARB_CFG); | 291 | value = mc_readl(mc, MC_EMEM_ARB_CFG); |
| 289 | value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; | 292 | value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; |
| 290 | value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); | 293 | value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); |
| 291 | writel(value, mc->regs + MC_EMEM_ARB_CFG); | 294 | mc_writel(mc, value, MC_EMEM_ARB_CFG); |
| 292 | 295 | ||
| 293 | /* write latency allowance defaults */ | 296 | /* write latency allowance defaults */ |
| 294 | for (i = 0; i < mc->soc->num_clients; i++) { | 297 | for (i = 0; i < mc->soc->num_clients; i++) { |
| 295 | const struct tegra_mc_la *la = &mc->soc->clients[i].la; | 298 | const struct tegra_mc_la *la = &mc->soc->clients[i].la; |
| 296 | u32 value; | 299 | u32 value; |
| 297 | 300 | ||
| 298 | value = readl(mc->regs + la->reg); | 301 | value = mc_readl(mc, la->reg); |
| 299 | value &= ~(la->mask << la->shift); | 302 | value &= ~(la->mask << la->shift); |
| 300 | value |= (la->def & la->mask) << la->shift; | 303 | value |= (la->def & la->mask) << la->shift; |
| 301 | writel(value, mc->regs + la->reg); | 304 | mc_writel(mc, value, la->reg); |
| 302 | } | 305 | } |
| 303 | 306 | ||
| 307 | /* latch new values */ | ||
| 308 | mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL); | ||
| 309 | |||
| 304 | return 0; | 310 | return 0; |
| 305 | } | 311 | } |
| 306 | 312 | ||
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index 887a3b07334f..392993955c93 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h | |||
| @@ -35,7 +35,7 @@ static inline void mc_writel(struct tegra_mc *mc, u32 value, | |||
| 35 | writel_relaxed(value, mc->regs + offset); | 35 | writel_relaxed(value, mc->regs + offset); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common; | 38 | extern const struct tegra_mc_reset_ops tegra_mc_reset_ops_common; |
| 39 | 39 | ||
| 40 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC | 40 | #ifdef CONFIG_ARCH_TEGRA_2x_SOC |
| 41 | extern const struct tegra_mc_soc tegra20_mc_soc; | 41 | extern const struct tegra_mc_soc tegra20_mc_soc; |
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index 6560a5101322..62305fafd641 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c | |||
| @@ -572,7 +572,7 @@ static const struct tegra_mc_client tegra114_mc_clients[] = { | |||
| 572 | }, | 572 | }, |
| 573 | }, { | 573 | }, { |
| 574 | .id = 0x34, | 574 | .id = 0x34, |
| 575 | .name = "fdcwr2", | 575 | .name = "fdcdwr2", |
| 576 | .swgroup = TEGRA_SWGROUP_NV, | 576 | .swgroup = TEGRA_SWGROUP_NV, |
| 577 | .smmu = { | 577 | .smmu = { |
| 578 | .reg = 0x22c, | 578 | .reg = 0x22c, |
| @@ -975,7 +975,7 @@ const struct tegra_mc_soc tegra114_mc_soc = { | |||
| 975 | .smmu = &tegra114_smmu_soc, | 975 | .smmu = &tegra114_smmu_soc, |
| 976 | .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | | 976 | .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | |
| 977 | MC_INT_DECERR_EMEM, | 977 | MC_INT_DECERR_EMEM, |
| 978 | .reset_ops = &terga_mc_reset_ops_common, | 978 | .reset_ops = &tegra_mc_reset_ops_common, |
| 979 | .resets = tegra114_mc_resets, | 979 | .resets = tegra114_mc_resets, |
| 980 | .num_resets = ARRAY_SIZE(tegra114_mc_resets), | 980 | .num_resets = ARRAY_SIZE(tegra114_mc_resets), |
| 981 | }; | 981 | }; |
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index b561a1fe7f46..8f8487bda642 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c | |||
| @@ -1074,7 +1074,7 @@ const struct tegra_mc_soc tegra124_mc_soc = { | |||
| 1074 | .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | | 1074 | .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | |
| 1075 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | | 1075 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | |
| 1076 | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, | 1076 | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, |
| 1077 | .reset_ops = &terga_mc_reset_ops_common, | 1077 | .reset_ops = &tegra_mc_reset_ops_common, |
| 1078 | .resets = tegra124_mc_resets, | 1078 | .resets = tegra124_mc_resets, |
| 1079 | .num_resets = ARRAY_SIZE(tegra124_mc_resets), | 1079 | .num_resets = ARRAY_SIZE(tegra124_mc_resets), |
| 1080 | }; | 1080 | }; |
| @@ -1104,7 +1104,7 @@ const struct tegra_mc_soc tegra132_mc_soc = { | |||
| 1104 | .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | | 1104 | .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | |
| 1105 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | | 1105 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | |
| 1106 | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, | 1106 | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, |
| 1107 | .reset_ops = &terga_mc_reset_ops_common, | 1107 | .reset_ops = &tegra_mc_reset_ops_common, |
| 1108 | .resets = tegra124_mc_resets, | 1108 | .resets = tegra124_mc_resets, |
| 1109 | .num_resets = ARRAY_SIZE(tegra124_mc_resets), | 1109 | .num_resets = ARRAY_SIZE(tegra124_mc_resets), |
| 1110 | }; | 1110 | }; |
diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index 7119e532471c..121237b16add 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c | |||
| @@ -198,7 +198,7 @@ static const struct tegra_mc_reset tegra20_mc_resets[] = { | |||
| 198 | TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14), | 198 | TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14), |
| 199 | }; | 199 | }; |
| 200 | 200 | ||
| 201 | static int terga20_mc_hotreset_assert(struct tegra_mc *mc, | 201 | static int tegra20_mc_hotreset_assert(struct tegra_mc *mc, |
| 202 | const struct tegra_mc_reset *rst) | 202 | const struct tegra_mc_reset *rst) |
| 203 | { | 203 | { |
| 204 | unsigned long flags; | 204 | unsigned long flags; |
| @@ -214,7 +214,7 @@ static int terga20_mc_hotreset_assert(struct tegra_mc *mc, | |||
| 214 | return 0; | 214 | return 0; |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | static int terga20_mc_hotreset_deassert(struct tegra_mc *mc, | 217 | static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc, |
| 218 | const struct tegra_mc_reset *rst) | 218 | const struct tegra_mc_reset *rst) |
| 219 | { | 219 | { |
| 220 | unsigned long flags; | 220 | unsigned long flags; |
| @@ -230,7 +230,7 @@ static int terga20_mc_hotreset_deassert(struct tegra_mc *mc, | |||
| 230 | return 0; | 230 | return 0; |
| 231 | } | 231 | } |
| 232 | 232 | ||
| 233 | static int terga20_mc_block_dma(struct tegra_mc *mc, | 233 | static int tegra20_mc_block_dma(struct tegra_mc *mc, |
| 234 | const struct tegra_mc_reset *rst) | 234 | const struct tegra_mc_reset *rst) |
| 235 | { | 235 | { |
| 236 | unsigned long flags; | 236 | unsigned long flags; |
| @@ -246,19 +246,19 @@ static int terga20_mc_block_dma(struct tegra_mc *mc, | |||
| 246 | return 0; | 246 | return 0; |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | static bool terga20_mc_dma_idling(struct tegra_mc *mc, | 249 | static bool tegra20_mc_dma_idling(struct tegra_mc *mc, |
| 250 | const struct tegra_mc_reset *rst) | 250 | const struct tegra_mc_reset *rst) |
| 251 | { | 251 | { |
| 252 | return mc_readl(mc, rst->status) == 0; | 252 | return mc_readl(mc, rst->status) == 0; |
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | static int terga20_mc_reset_status(struct tegra_mc *mc, | 255 | static int tegra20_mc_reset_status(struct tegra_mc *mc, |
| 256 | const struct tegra_mc_reset *rst) | 256 | const struct tegra_mc_reset *rst) |
| 257 | { | 257 | { |
| 258 | return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0; | 258 | return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0; |
| 259 | } | 259 | } |
| 260 | 260 | ||
| 261 | static int terga20_mc_unblock_dma(struct tegra_mc *mc, | 261 | static int tegra20_mc_unblock_dma(struct tegra_mc *mc, |
| 262 | const struct tegra_mc_reset *rst) | 262 | const struct tegra_mc_reset *rst) |
| 263 | { | 263 | { |
| 264 | unsigned long flags; | 264 | unsigned long flags; |
| @@ -274,13 +274,13 @@ static int terga20_mc_unblock_dma(struct tegra_mc *mc, | |||
| 274 | return 0; | 274 | return 0; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | const struct tegra_mc_reset_ops terga20_mc_reset_ops = { | 277 | static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = { |
| 278 | .hotreset_assert = terga20_mc_hotreset_assert, | 278 | .hotreset_assert = tegra20_mc_hotreset_assert, |
| 279 | .hotreset_deassert = terga20_mc_hotreset_deassert, | 279 | .hotreset_deassert = tegra20_mc_hotreset_deassert, |
| 280 | .block_dma = terga20_mc_block_dma, | 280 | .block_dma = tegra20_mc_block_dma, |
| 281 | .dma_idling = terga20_mc_dma_idling, | 281 | .dma_idling = tegra20_mc_dma_idling, |
| 282 | .unblock_dma = terga20_mc_unblock_dma, | 282 | .unblock_dma = tegra20_mc_unblock_dma, |
| 283 | .reset_status = terga20_mc_reset_status, | 283 | .reset_status = tegra20_mc_reset_status, |
| 284 | }; | 284 | }; |
| 285 | 285 | ||
| 286 | const struct tegra_mc_soc tegra20_mc_soc = { | 286 | const struct tegra_mc_soc tegra20_mc_soc = { |
| @@ -290,7 +290,7 @@ const struct tegra_mc_soc tegra20_mc_soc = { | |||
| 290 | .client_id_mask = 0x3f, | 290 | .client_id_mask = 0x3f, |
| 291 | .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | | 291 | .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | |
| 292 | MC_INT_DECERR_EMEM, | 292 | MC_INT_DECERR_EMEM, |
| 293 | .reset_ops = &terga20_mc_reset_ops, | 293 | .reset_ops = &tegra20_mc_reset_ops, |
| 294 | .resets = tegra20_mc_resets, | 294 | .resets = tegra20_mc_resets, |
| 295 | .num_resets = ARRAY_SIZE(tegra20_mc_resets), | 295 | .num_resets = ARRAY_SIZE(tegra20_mc_resets), |
| 296 | }; | 296 | }; |
diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index d00a77160407..aa22cda637eb 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c | |||
| @@ -1132,7 +1132,7 @@ const struct tegra_mc_soc tegra210_mc_soc = { | |||
| 1132 | .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | | 1132 | .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | |
| 1133 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | | 1133 | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | |
| 1134 | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, | 1134 | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, |
| 1135 | .reset_ops = &terga_mc_reset_ops_common, | 1135 | .reset_ops = &tegra_mc_reset_ops_common, |
| 1136 | .resets = tegra210_mc_resets, | 1136 | .resets = tegra210_mc_resets, |
| 1137 | .num_resets = ARRAY_SIZE(tegra210_mc_resets), | 1137 | .num_resets = ARRAY_SIZE(tegra210_mc_resets), |
| 1138 | }; | 1138 | }; |
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index bee5314ed404..c9af0f682ead 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c | |||
| @@ -726,7 +726,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = { | |||
| 726 | }, | 726 | }, |
| 727 | }, { | 727 | }, { |
| 728 | .id = 0x34, | 728 | .id = 0x34, |
| 729 | .name = "fdcwr2", | 729 | .name = "fdcdwr2", |
| 730 | .swgroup = TEGRA_SWGROUP_NV2, | 730 | .swgroup = TEGRA_SWGROUP_NV2, |
| 731 | .smmu = { | 731 | .smmu = { |
| 732 | .reg = 0x22c, | 732 | .reg = 0x22c, |
| @@ -999,7 +999,7 @@ const struct tegra_mc_soc tegra30_mc_soc = { | |||
| 999 | .smmu = &tegra30_smmu_soc, | 999 | .smmu = &tegra30_smmu_soc, |
| 1000 | .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | | 1000 | .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | |
| 1001 | MC_INT_DECERR_EMEM, | 1001 | MC_INT_DECERR_EMEM, |
| 1002 | .reset_ops = &terga_mc_reset_ops_common, | 1002 | .reset_ops = &tegra_mc_reset_ops_common, |
| 1003 | .resets = tegra30_mc_resets, | 1003 | .resets = tegra30_mc_resets, |
| 1004 | .num_resets = ARRAY_SIZE(tegra30_mc_resets), | 1004 | .num_resets = ARRAY_SIZE(tegra30_mc_resets), |
| 1005 | }; | 1005 | }; |
diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c index 2250d03ea17f..ab07aa163138 100644 --- a/drivers/memory/ti-emif-pm.c +++ b/drivers/memory/ti-emif-pm.c | |||
| @@ -138,6 +138,9 @@ static int ti_emif_alloc_sram(struct device *dev, | |||
| 138 | emif_data->pm_functions.exit_sr = | 138 | emif_data->pm_functions.exit_sr = |
| 139 | sram_resume_address(emif_data, | 139 | sram_resume_address(emif_data, |
| 140 | (unsigned long)ti_emif_exit_sr); | 140 | (unsigned long)ti_emif_exit_sr); |
| 141 | emif_data->pm_functions.run_hw_leveling = | ||
| 142 | sram_resume_address(emif_data, | ||
| 143 | (unsigned long)ti_emif_run_hw_leveling); | ||
| 141 | 144 | ||
| 142 | emif_data->pm_data.regs_virt = | 145 | emif_data->pm_data.regs_virt = |
| 143 | (struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt; | 146 | (struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt; |
diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S index a5369181e5c2..d75ae18efa7d 100644 --- a/drivers/memory/ti-emif-sram-pm.S +++ b/drivers/memory/ti-emif-sram-pm.S | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700 | 27 | #define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700 |
| 28 | 28 | ||
| 29 | #define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT | 29 | #define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT |
| 30 | #define EMIF_SDCFG_TYPE_DDR3 0x3 << SDRAM_TYPE_SHIFT | ||
| 30 | #define EMIF_STATUS_READY 0x4 | 31 | #define EMIF_STATUS_READY 0x4 |
| 31 | 32 | ||
| 32 | #define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120 | 33 | #define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120 |
| @@ -245,6 +246,46 @@ emif_skip_restore_extra_regs: | |||
| 245 | ENDPROC(ti_emif_restore_context) | 246 | ENDPROC(ti_emif_restore_context) |
| 246 | 247 | ||
| 247 | /* | 248 | /* |
| 249 | * void ti_emif_run_hw_leveling(void) | ||
| 250 | * | ||
| 251 | * Used during resume to run hardware leveling again and restore the | ||
| 252 | * configuration of the EMIF PHY, only for DDR3. | ||
| 253 | */ | ||
| 254 | ENTRY(ti_emif_run_hw_leveling) | ||
| 255 | adr r4, ti_emif_pm_sram_data | ||
| 256 | ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET] | ||
| 257 | |||
| 258 | ldr r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] | ||
| 259 | orr r3, r3, #RDWRLVLFULL_START | ||
| 260 | ldr r2, [r0, #EMIF_SDRAM_CONFIG] | ||
| 261 | and r2, r2, #SDRAM_TYPE_MASK | ||
| 262 | cmp r2, #EMIF_SDCFG_TYPE_DDR3 | ||
| 263 | bne skip_hwlvl | ||
| 264 | |||
| 265 | str r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] | ||
| 266 | |||
| 267 | /* | ||
| 268 | * If EMIF registers are touched during initial stage of HW | ||
| 269 | * leveling sequence there will be an L3 NOC timeout error issued | ||
| 270 | * as the EMIF will not respond, which is not fatal, but it is | ||
| 271 | * avoidable. This small wait loop is enough time for this condition | ||
| 272 | * to clear, even at worst case of CPU running at max speed of 1Ghz. | ||
| 273 | */ | ||
| 274 | mov r2, #0x2000 | ||
| 275 | 1: | ||
| 276 | subs r2, r2, #0x1 | ||
| 277 | bne 1b | ||
| 278 | |||
| 279 | /* Bit clears when operation is complete */ | ||
| 280 | 2: ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] | ||
| 281 | tst r1, #RDWRLVLFULL_START | ||
| 282 | bne 2b | ||
| 283 | |||
| 284 | skip_hwlvl: | ||
| 285 | mov pc, lr | ||
| 286 | ENDPROC(ti_emif_run_hw_leveling) | ||
| 287 | |||
| 288 | /* | ||
| 248 | * void ti_emif_enter_sr(void) | 289 | * void ti_emif_enter_sr(void) |
| 249 | * | 290 | * |
| 250 | * Programs the EMIF to tell the SDRAM to enter into self-refresh | 291 | * Programs the EMIF to tell the SDRAM to enter into self-refresh |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3209ee020b15..b80cb6af0cb4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -496,30 +496,6 @@ config VEXPRESS_SYSCFG | |||
| 496 | bus. System Configuration interface is one of the possible means | 496 | bus. System Configuration interface is one of the possible means |
| 497 | of generating transactions on this bus. | 497 | of generating transactions on this bus. |
| 498 | 498 | ||
| 499 | config ASPEED_P2A_CTRL | ||
| 500 | depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON | ||
| 501 | tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control" | ||
| 502 | help | ||
| 503 | Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through | ||
| 504 | ioctl()s, the driver also provides an interface for userspace mappings to | ||
| 505 | a pre-defined region. | ||
| 506 | |||
| 507 | config ASPEED_LPC_CTRL | ||
| 508 | depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON | ||
| 509 | tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control" | ||
| 510 | ---help--- | ||
| 511 | Control Aspeed ast2400/2500 HOST LPC to BMC mappings through | ||
| 512 | ioctl()s, the driver also provides a read/write interface to a BMC ram | ||
| 513 | region where the host LPC read/write region can be buffered. | ||
| 514 | |||
| 515 | config ASPEED_LPC_SNOOP | ||
| 516 | tristate "Aspeed ast2500 HOST LPC snoop support" | ||
| 517 | depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON | ||
| 518 | help | ||
| 519 | Provides a driver to control the LPC snoop interface which | ||
| 520 | allows the BMC to listen on and save the data written by | ||
| 521 | the host to an arbitrary LPC I/O port. | ||
| 522 | |||
| 523 | config PCI_ENDPOINT_TEST | 499 | config PCI_ENDPOINT_TEST |
| 524 | depends on PCI | 500 | depends on PCI |
| 525 | select CRC32 | 501 | select CRC32 |
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index c36239573a5c..b9affcdaa3d6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile | |||
| @@ -54,9 +54,6 @@ obj-$(CONFIG_GENWQE) += genwqe/ | |||
| 54 | obj-$(CONFIG_ECHO) += echo/ | 54 | obj-$(CONFIG_ECHO) += echo/ |
| 55 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o | 55 | obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o |
| 56 | obj-$(CONFIG_CXL_BASE) += cxl/ | 56 | obj-$(CONFIG_CXL_BASE) += cxl/ |
| 57 | obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o | ||
| 58 | obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o | ||
| 59 | obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o | ||
| 60 | obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o | 57 | obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o |
| 61 | obj-$(CONFIG_OCXL) += ocxl/ | 58 | obj-$(CONFIG_OCXL) += ocxl/ |
| 62 | obj-y += cardreader/ | 59 | obj-y += cardreader/ |
diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index 490c8fcaec80..5893543918c8 100644 --- a/drivers/nvmem/zynqmp_nvmem.c +++ b/drivers/nvmem/zynqmp_nvmem.c | |||
| @@ -16,6 +16,8 @@ struct zynqmp_nvmem_data { | |||
| 16 | struct nvmem_device *nvmem; | 16 | struct nvmem_device *nvmem; |
| 17 | }; | 17 | }; |
| 18 | 18 | ||
| 19 | static const struct zynqmp_eemi_ops *eemi_ops; | ||
| 20 | |||
| 19 | static int zynqmp_nvmem_read(void *context, unsigned int offset, | 21 | static int zynqmp_nvmem_read(void *context, unsigned int offset, |
| 20 | void *val, size_t bytes) | 22 | void *val, size_t bytes) |
| 21 | { | 23 | { |
| @@ -23,9 +25,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset, | |||
| 23 | int idcode, version; | 25 | int idcode, version; |
| 24 | struct zynqmp_nvmem_data *priv = context; | 26 | struct zynqmp_nvmem_data *priv = context; |
| 25 | 27 | ||
| 26 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | 28 | if (!eemi_ops->get_chipid) |
| 27 | |||
| 28 | if (!eemi_ops || !eemi_ops->get_chipid) | ||
| 29 | return -ENXIO; | 29 | return -ENXIO; |
| 30 | 30 | ||
| 31 | ret = eemi_ops->get_chipid(&idcode, &version); | 31 | ret = eemi_ops->get_chipid(&idcode, &version); |
| @@ -61,6 +61,10 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev) | |||
| 61 | if (!priv) | 61 | if (!priv) |
| 62 | return -ENOMEM; | 62 | return -ENOMEM; |
| 63 | 63 | ||
| 64 | eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 65 | if (IS_ERR(eemi_ops)) | ||
| 66 | return PTR_ERR(eemi_ops); | ||
| 67 | |||
| 64 | priv->dev = dev; | 68 | priv->dev = dev; |
| 65 | econfig.dev = dev; | 69 | econfig.dev = dev; |
| 66 | econfig.reg_read = zynqmp_nvmem_read; | 70 | econfig.reg_read = zynqmp_nvmem_read; |
diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index 2ef1f13aa47b..99e75d92dada 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c | |||
| @@ -79,11 +79,11 @@ static int zynqmp_reset_probe(struct platform_device *pdev) | |||
| 79 | if (!priv) | 79 | if (!priv) |
| 80 | return -ENOMEM; | 80 | return -ENOMEM; |
| 81 | 81 | ||
| 82 | platform_set_drvdata(pdev, priv); | ||
| 83 | |||
| 84 | priv->eemi_ops = zynqmp_pm_get_eemi_ops(); | 82 | priv->eemi_ops = zynqmp_pm_get_eemi_ops(); |
| 85 | if (!priv->eemi_ops) | 83 | if (IS_ERR(priv->eemi_ops)) |
| 86 | return -ENXIO; | 84 | return PTR_ERR(priv->eemi_ops); |
| 85 | |||
| 86 | platform_set_drvdata(pdev, priv); | ||
| 87 | 87 | ||
| 88 | priv->rcdev.ops = &zynqmp_reset_ops; | 88 | priv->rcdev.ops = &zynqmp_reset_ops; |
| 89 | priv->rcdev.owner = THIS_MODULE; | 89 | priv->rcdev.owner = THIS_MODULE; |
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 32994b0dd139..a2941c875a06 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c | |||
| @@ -403,15 +403,12 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) | |||
| 403 | 403 | ||
| 404 | static struct omap_rtc *omap_rtc_power_off_rtc; | 404 | static struct omap_rtc *omap_rtc_power_off_rtc; |
| 405 | 405 | ||
| 406 | /* | 406 | /** |
| 407 | * omap_rtc_poweroff: RTC-controlled power off | 407 | * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC |
| 408 | * | 408 | * generates pmic_pwr_enable control, which can be used to control an external |
| 409 | * The RTC can be used to control an external PMIC via the pmic_power_en pin, | 409 | * PMIC. |
| 410 | * which can be configured to transition to OFF on ALARM2 events. | ||
| 411 | * | ||
| 412 | * Called with local interrupts disabled. | ||
| 413 | */ | 410 | */ |
| 414 | static void omap_rtc_power_off(void) | 411 | int omap_rtc_power_off_program(struct device *dev) |
| 415 | { | 412 | { |
| 416 | struct omap_rtc *rtc = omap_rtc_power_off_rtc; | 413 | struct omap_rtc *rtc = omap_rtc_power_off_rtc; |
| 417 | struct rtc_time tm; | 414 | struct rtc_time tm; |
| @@ -425,6 +422,9 @@ static void omap_rtc_power_off(void) | |||
| 425 | rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); | 422 | rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); |
| 426 | 423 | ||
| 427 | again: | 424 | again: |
| 425 | /* Clear any existing ALARM2 event */ | ||
| 426 | rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2); | ||
| 427 | |||
| 428 | /* set alarm one second from now */ | 428 | /* set alarm one second from now */ |
| 429 | omap_rtc_read_time_raw(rtc, &tm); | 429 | omap_rtc_read_time_raw(rtc, &tm); |
| 430 | seconds = tm.tm_sec; | 430 | seconds = tm.tm_sec; |
| @@ -461,6 +461,39 @@ again: | |||
| 461 | 461 | ||
| 462 | rtc->type->lock(rtc); | 462 | rtc->type->lock(rtc); |
| 463 | 463 | ||
| 464 | return 0; | ||
| 465 | } | ||
| 466 | EXPORT_SYMBOL(omap_rtc_power_off_program); | ||
| 467 | |||
| 468 | /* | ||
| 469 | * omap_rtc_poweroff: RTC-controlled power off | ||
| 470 | * | ||
| 471 | * The RTC can be used to control an external PMIC via the pmic_power_en pin, | ||
| 472 | * which can be configured to transition to OFF on ALARM2 events. | ||
| 473 | * | ||
| 474 | * Notes: | ||
| 475 | * The one-second alarm offset is the shortest offset possible as the alarm | ||
| 476 | * registers must be set before the next timer update and the offset | ||
| 477 | * calculation is too heavy for everything to be done within a single access | ||
| 478 | * period (~15 us). | ||
| 479 | * | ||
| 480 | * Called with local interrupts disabled. | ||
| 481 | */ | ||
| 482 | static void omap_rtc_power_off(void) | ||
| 483 | { | ||
| 484 | struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc; | ||
| 485 | u32 val; | ||
| 486 | |||
| 487 | omap_rtc_power_off_program(rtc->dev.parent); | ||
| 488 | |||
| 489 | /* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */ | ||
| 490 | omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc); | ||
| 491 | val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG); | ||
| 492 | val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) | | ||
| 493 | OMAP_RTC_PMIC_EXT_WKUP_EN(0); | ||
| 494 | rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val); | ||
| 495 | omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc); | ||
| 496 | |||
| 464 | /* | 497 | /* |
| 465 | * Wait for alarm to trigger (within one second) and external PMIC to | 498 | * Wait for alarm to trigger (within one second) and external PMIC to |
| 466 | * power off the system. Add a 500 ms margin for external latencies | 499 | * power off the system. Add a 500 ms margin for external latencies |
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index ae9bf20b26fa..75bdbb2c5140 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig | |||
| @@ -2,6 +2,7 @@ menu "SOC (System On Chip) specific Drivers" | |||
| 2 | 2 | ||
| 3 | source "drivers/soc/actions/Kconfig" | 3 | source "drivers/soc/actions/Kconfig" |
| 4 | source "drivers/soc/amlogic/Kconfig" | 4 | source "drivers/soc/amlogic/Kconfig" |
| 5 | source "drivers/soc/aspeed/Kconfig" | ||
| 5 | source "drivers/soc/atmel/Kconfig" | 6 | source "drivers/soc/atmel/Kconfig" |
| 6 | source "drivers/soc/bcm/Kconfig" | 7 | source "drivers/soc/bcm/Kconfig" |
| 7 | source "drivers/soc/fsl/Kconfig" | 8 | source "drivers/soc/fsl/Kconfig" |
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index c7c1a139ad8d..524ecdc2a9bb 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | obj-$(CONFIG_ARCH_ACTIONS) += actions/ | 6 | obj-$(CONFIG_ARCH_ACTIONS) += actions/ |
| 7 | obj-$(CONFIG_SOC_ASPEED) += aspeed/ | ||
| 7 | obj-$(CONFIG_ARCH_AT91) += atmel/ | 8 | obj-$(CONFIG_ARCH_AT91) += atmel/ |
| 8 | obj-y += bcm/ | 9 | obj-y += bcm/ |
| 9 | obj-$(CONFIG_ARCH_DOVE) += dove/ | 10 | obj-$(CONFIG_ARCH_DOVE) += dove/ |
diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c index 6289965c42e9..511b6856225d 100644 --- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/bitfield.h> | 11 | #include <linux/bitfield.h> |
| 12 | #include <linux/regmap.h> | 12 | #include <linux/regmap.h> |
| 13 | #include <linux/mfd/syscon.h> | 13 | #include <linux/mfd/syscon.h> |
| 14 | #include <linux/of_device.h> | ||
| 14 | #include <linux/reset.h> | 15 | #include <linux/reset.h> |
| 15 | #include <linux/clk.h> | 16 | #include <linux/clk.h> |
| 16 | 17 | ||
| @@ -26,6 +27,7 @@ | |||
| 26 | #define HHI_MEM_PD_REG0 (0x40 << 2) | 27 | #define HHI_MEM_PD_REG0 (0x40 << 2) |
| 27 | #define HHI_VPU_MEM_PD_REG0 (0x41 << 2) | 28 | #define HHI_VPU_MEM_PD_REG0 (0x41 << 2) |
| 28 | #define HHI_VPU_MEM_PD_REG1 (0x42 << 2) | 29 | #define HHI_VPU_MEM_PD_REG1 (0x42 << 2) |
| 30 | #define HHI_VPU_MEM_PD_REG2 (0x4d << 2) | ||
| 29 | 31 | ||
| 30 | struct meson_gx_pwrc_vpu { | 32 | struct meson_gx_pwrc_vpu { |
| 31 | struct generic_pm_domain genpd; | 33 | struct generic_pm_domain genpd; |
| @@ -54,12 +56,55 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) | |||
| 54 | /* Power Down Memories */ | 56 | /* Power Down Memories */ |
| 55 | for (i = 0; i < 32; i += 2) { | 57 | for (i = 0; i < 32; i += 2) { |
| 56 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, | 58 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, |
| 57 | 0x2 << i, 0x3 << i); | 59 | 0x3 << i, 0x3 << i); |
| 58 | udelay(5); | 60 | udelay(5); |
| 59 | } | 61 | } |
| 60 | for (i = 0; i < 32; i += 2) { | 62 | for (i = 0; i < 32; i += 2) { |
| 61 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, | 63 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, |
| 62 | 0x2 << i, 0x3 << i); | 64 | 0x3 << i, 0x3 << i); |
| 65 | udelay(5); | ||
| 66 | } | ||
| 67 | for (i = 8; i < 16; i++) { | ||
| 68 | regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, | ||
| 69 | BIT(i), BIT(i)); | ||
| 70 | udelay(5); | ||
| 71 | } | ||
| 72 | udelay(20); | ||
| 73 | |||
| 74 | regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, | ||
| 75 | GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); | ||
| 76 | |||
| 77 | msleep(20); | ||
| 78 | |||
| 79 | clk_disable_unprepare(pd->vpu_clk); | ||
| 80 | clk_disable_unprepare(pd->vapb_clk); | ||
| 81 | |||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd) | ||
| 86 | { | ||
| 87 | struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); | ||
| 88 | int i; | ||
| 89 | |||
| 90 | regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, | ||
| 91 | GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); | ||
| 92 | udelay(20); | ||
| 93 | |||
| 94 | /* Power Down Memories */ | ||
| 95 | for (i = 0; i < 32; i += 2) { | ||
| 96 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, | ||
| 97 | 0x3 << i, 0x3 << i); | ||
| 98 | udelay(5); | ||
| 99 | } | ||
| 100 | for (i = 0; i < 32; i += 2) { | ||
| 101 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, | ||
| 102 | 0x3 << i, 0x3 << i); | ||
| 103 | udelay(5); | ||
| 104 | } | ||
| 105 | for (i = 0; i < 32; i += 2) { | ||
| 106 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, | ||
| 107 | 0x3 << i, 0x3 << i); | ||
| 63 | udelay(5); | 108 | udelay(5); |
| 64 | } | 109 | } |
| 65 | for (i = 8; i < 16; i++) { | 110 | for (i = 8; i < 16; i++) { |
| @@ -108,13 +153,67 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) | |||
| 108 | /* Power Up Memories */ | 153 | /* Power Up Memories */ |
| 109 | for (i = 0; i < 32; i += 2) { | 154 | for (i = 0; i < 32; i += 2) { |
| 110 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, | 155 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, |
| 111 | 0x2 << i, 0); | 156 | 0x3 << i, 0); |
| 157 | udelay(5); | ||
| 158 | } | ||
| 159 | |||
| 160 | for (i = 0; i < 32; i += 2) { | ||
| 161 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, | ||
| 162 | 0x3 << i, 0); | ||
| 163 | udelay(5); | ||
| 164 | } | ||
| 165 | |||
| 166 | for (i = 8; i < 16; i++) { | ||
| 167 | regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, | ||
| 168 | BIT(i), 0); | ||
| 169 | udelay(5); | ||
| 170 | } | ||
| 171 | udelay(20); | ||
| 172 | |||
| 173 | ret = reset_control_assert(pd->rstc); | ||
| 174 | if (ret) | ||
| 175 | return ret; | ||
| 176 | |||
| 177 | regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, | ||
| 178 | GEN_PWR_VPU_HDMI_ISO, 0); | ||
| 179 | |||
| 180 | ret = reset_control_deassert(pd->rstc); | ||
| 181 | if (ret) | ||
| 182 | return ret; | ||
| 183 | |||
| 184 | ret = meson_gx_pwrc_vpu_setup_clk(pd); | ||
| 185 | if (ret) | ||
| 186 | return ret; | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd) | ||
| 192 | { | ||
| 193 | struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); | ||
| 194 | int ret; | ||
| 195 | int i; | ||
| 196 | |||
| 197 | regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, | ||
| 198 | GEN_PWR_VPU_HDMI, 0); | ||
| 199 | udelay(20); | ||
| 200 | |||
| 201 | /* Power Up Memories */ | ||
| 202 | for (i = 0; i < 32; i += 2) { | ||
| 203 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, | ||
| 204 | 0x3 << i, 0); | ||
| 112 | udelay(5); | 205 | udelay(5); |
| 113 | } | 206 | } |
| 114 | 207 | ||
| 115 | for (i = 0; i < 32; i += 2) { | 208 | for (i = 0; i < 32; i += 2) { |
| 116 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, | 209 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, |
| 117 | 0x2 << i, 0); | 210 | 0x3 << i, 0); |
| 211 | udelay(5); | ||
| 212 | } | ||
| 213 | |||
| 214 | for (i = 0; i < 32; i += 2) { | ||
| 215 | regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, | ||
| 216 | 0x3 << i, 0); | ||
| 118 | udelay(5); | 217 | udelay(5); |
| 119 | } | 218 | } |
| 120 | 219 | ||
| @@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = { | |||
| 160 | }, | 259 | }, |
| 161 | }; | 260 | }; |
| 162 | 261 | ||
| 262 | static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = { | ||
| 263 | .genpd = { | ||
| 264 | .name = "vpu_hdmi", | ||
| 265 | .power_off = meson_g12a_pwrc_vpu_power_off, | ||
| 266 | .power_on = meson_g12a_pwrc_vpu_power_on, | ||
| 267 | }, | ||
| 268 | }; | ||
| 269 | |||
| 163 | static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) | 270 | static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) |
| 164 | { | 271 | { |
| 272 | const struct meson_gx_pwrc_vpu *vpu_pd_match; | ||
| 165 | struct regmap *regmap_ao, *regmap_hhi; | 273 | struct regmap *regmap_ao, *regmap_hhi; |
| 274 | struct meson_gx_pwrc_vpu *vpu_pd; | ||
| 166 | struct reset_control *rstc; | 275 | struct reset_control *rstc; |
| 167 | struct clk *vpu_clk; | 276 | struct clk *vpu_clk; |
| 168 | struct clk *vapb_clk; | 277 | struct clk *vapb_clk; |
| 169 | bool powered_off; | 278 | bool powered_off; |
| 170 | int ret; | 279 | int ret; |
| 171 | 280 | ||
| 281 | vpu_pd_match = of_device_get_match_data(&pdev->dev); | ||
| 282 | if (!vpu_pd_match) { | ||
| 283 | dev_err(&pdev->dev, "failed to get match data\n"); | ||
| 284 | return -ENODEV; | ||
| 285 | } | ||
| 286 | |||
| 287 | vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL); | ||
| 288 | if (!vpu_pd) | ||
| 289 | return -ENOMEM; | ||
| 290 | |||
| 291 | memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd)); | ||
| 292 | |||
| 172 | regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node)); | 293 | regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node)); |
| 173 | if (IS_ERR(regmap_ao)) { | 294 | if (IS_ERR(regmap_ao)) { |
| 174 | dev_err(&pdev->dev, "failed to get regmap\n"); | 295 | dev_err(&pdev->dev, "failed to get regmap\n"); |
| @@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) | |||
| 201 | return PTR_ERR(vapb_clk); | 322 | return PTR_ERR(vapb_clk); |
| 202 | } | 323 | } |
| 203 | 324 | ||
| 204 | vpu_hdmi_pd.regmap_ao = regmap_ao; | 325 | vpu_pd->regmap_ao = regmap_ao; |
| 205 | vpu_hdmi_pd.regmap_hhi = regmap_hhi; | 326 | vpu_pd->regmap_hhi = regmap_hhi; |
| 206 | vpu_hdmi_pd.rstc = rstc; | 327 | vpu_pd->rstc = rstc; |
| 207 | vpu_hdmi_pd.vpu_clk = vpu_clk; | 328 | vpu_pd->vpu_clk = vpu_clk; |
| 208 | vpu_hdmi_pd.vapb_clk = vapb_clk; | 329 | vpu_pd->vapb_clk = vapb_clk; |
| 330 | |||
| 331 | platform_set_drvdata(pdev, vpu_pd); | ||
| 209 | 332 | ||
| 210 | powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); | 333 | powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); |
| 211 | 334 | ||
| 212 | /* If already powered, sync the clock states */ | 335 | /* If already powered, sync the clock states */ |
| 213 | if (!powered_off) { | 336 | if (!powered_off) { |
| 214 | ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd); | 337 | ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd); |
| 215 | if (ret) | 338 | if (ret) |
| 216 | return ret; | 339 | return ret; |
| 217 | } | 340 | } |
| 218 | 341 | ||
| 219 | pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov, | 342 | pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov, |
| 220 | powered_off); | 343 | powered_off); |
| 221 | 344 | ||
| 222 | return of_genpd_add_provider_simple(pdev->dev.of_node, | 345 | return of_genpd_add_provider_simple(pdev->dev.of_node, |
| 223 | &vpu_hdmi_pd.genpd); | 346 | &vpu_pd->genpd); |
| 224 | } | 347 | } |
| 225 | 348 | ||
| 226 | static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev) | 349 | static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev) |
| 227 | { | 350 | { |
| 351 | struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev); | ||
| 228 | bool powered_off; | 352 | bool powered_off; |
| 229 | 353 | ||
| 230 | powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); | 354 | powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); |
| 231 | if (!powered_off) | 355 | if (!powered_off) |
| 232 | meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd); | 356 | vpu_pd->genpd.power_off(&vpu_pd->genpd); |
| 233 | } | 357 | } |
| 234 | 358 | ||
| 235 | static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = { | 359 | static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = { |
| 236 | { .compatible = "amlogic,meson-gx-pwrc-vpu" }, | 360 | { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd }, |
| 361 | { | ||
| 362 | .compatible = "amlogic,meson-g12a-pwrc-vpu", | ||
| 363 | .data = &vpu_hdmi_pd_g12a | ||
| 364 | }, | ||
| 237 | { /* sentinel */ } | 365 | { /* sentinel */ } |
| 238 | }; | 366 | }; |
| 239 | 367 | ||
diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index 37ea0a1c24c8..bca34954518e 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c | |||
| @@ -37,26 +37,34 @@ static const struct meson_gx_soc_id { | |||
| 37 | { "AXG", 0x25 }, | 37 | { "AXG", 0x25 }, |
| 38 | { "GXLX", 0x26 }, | 38 | { "GXLX", 0x26 }, |
| 39 | { "TXHD", 0x27 }, | 39 | { "TXHD", 0x27 }, |
| 40 | { "G12A", 0x28 }, | ||
| 41 | { "G12B", 0x29 }, | ||
| 40 | }; | 42 | }; |
| 41 | 43 | ||
| 42 | static const struct meson_gx_package_id { | 44 | static const struct meson_gx_package_id { |
| 43 | const char *name; | 45 | const char *name; |
| 44 | unsigned int major_id; | 46 | unsigned int major_id; |
| 45 | unsigned int pack_id; | 47 | unsigned int pack_id; |
| 48 | unsigned int pack_mask; | ||
| 46 | } soc_packages[] = { | 49 | } soc_packages[] = { |
| 47 | { "S905", 0x1f, 0 }, | 50 | { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */ |
| 48 | { "S905H", 0x1f, 0x13 }, | 51 | { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */ |
| 49 | { "S905M", 0x1f, 0x20 }, | 52 | { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */ |
| 50 | { "S905D", 0x21, 0 }, | 53 | { "S905D", 0x21, 0, 0xf0 }, |
| 51 | { "S905X", 0x21, 0x80 }, | 54 | { "S905X", 0x21, 0x80, 0xf0 }, |
| 52 | { "S905W", 0x21, 0xa0 }, | 55 | { "S905W", 0x21, 0xa0, 0xf0 }, |
| 53 | { "S905L", 0x21, 0xc0 }, | 56 | { "S905L", 0x21, 0xc0, 0xf0 }, |
| 54 | { "S905M2", 0x21, 0xe0 }, | 57 | { "S905M2", 0x21, 0xe0, 0xf0 }, |
| 55 | { "S912", 0x22, 0 }, | 58 | { "S805X", 0x21, 0x30, 0xf0 }, |
| 56 | { "962X", 0x24, 0x10 }, | 59 | { "S805Y", 0x21, 0xb0, 0xf0 }, |
| 57 | { "962E", 0x24, 0x20 }, | 60 | { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ |
| 58 | { "A113X", 0x25, 0x37 }, | 61 | { "962X", 0x24, 0x10, 0xf0 }, |
| 59 | { "A113D", 0x25, 0x22 }, | 62 | { "962E", 0x24, 0x20, 0xf0 }, |
| 63 | { "A113X", 0x25, 0x37, 0xff }, | ||
| 64 | { "A113D", 0x25, 0x22, 0xff }, | ||
| 65 | { "S905D2", 0x28, 0x10, 0xf0 }, | ||
| 66 | { "S905X2", 0x28, 0x40, 0xf0 }, | ||
| 67 | { "S922X", 0x29, 0x40, 0xf0 }, | ||
| 60 | }; | 68 | }; |
| 61 | 69 | ||
| 62 | static inline unsigned int socinfo_to_major(u32 socinfo) | 70 | static inline unsigned int socinfo_to_major(u32 socinfo) |
| @@ -81,13 +89,14 @@ static inline unsigned int socinfo_to_misc(u32 socinfo) | |||
| 81 | 89 | ||
| 82 | static const char *socinfo_to_package_id(u32 socinfo) | 90 | static const char *socinfo_to_package_id(u32 socinfo) |
| 83 | { | 91 | { |
| 84 | unsigned int pack = socinfo_to_pack(socinfo) & 0xf0; | 92 | unsigned int pack = socinfo_to_pack(socinfo); |
| 85 | unsigned int major = socinfo_to_major(socinfo); | 93 | unsigned int major = socinfo_to_major(socinfo); |
| 86 | int i; | 94 | int i; |
| 87 | 95 | ||
| 88 | for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) { | 96 | for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) { |
| 89 | if (soc_packages[i].major_id == major && | 97 | if (soc_packages[i].major_id == major && |
| 90 | soc_packages[i].pack_id == pack) | 98 | soc_packages[i].pack_id == |
| 99 | (pack & soc_packages[i].pack_mask)) | ||
| 91 | return soc_packages[i].name; | 100 | return soc_packages[i].name; |
| 92 | } | 101 | } |
| 93 | 102 | ||
| @@ -123,8 +132,10 @@ static int __init meson_gx_socinfo_init(void) | |||
| 123 | return -ENODEV; | 132 | return -ENODEV; |
| 124 | 133 | ||
| 125 | /* check if interface is enabled */ | 134 | /* check if interface is enabled */ |
| 126 | if (!of_device_is_available(np)) | 135 | if (!of_device_is_available(np)) { |
| 136 | of_node_put(np); | ||
| 127 | return -ENODEV; | 137 | return -ENODEV; |
| 138 | } | ||
| 128 | 139 | ||
| 129 | /* check if chip-id is available */ | 140 | /* check if chip-id is available */ |
| 130 | if (!of_property_read_bool(np, "amlogic,has-chip-id")) | 141 | if (!of_property_read_bool(np, "amlogic,has-chip-id")) |
diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig new file mode 100644 index 000000000000..765d10191387 --- /dev/null +++ b/drivers/soc/aspeed/Kconfig | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | menu "Aspeed SoC drivers" | ||
| 2 | |||
| 3 | config SOC_ASPEED | ||
| 4 | def_bool y | ||
| 5 | depends on ARCH_ASPEED || COMPILE_TEST | ||
| 6 | |||
| 7 | config ASPEED_LPC_CTRL | ||
| 8 | depends on SOC_ASPEED && REGMAP && MFD_SYSCON | ||
| 9 | tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control" | ||
| 10 | ---help--- | ||
| 11 | Control Aspeed ast2400/2500 HOST LPC to BMC mappings through | ||
| 12 | ioctl()s, the driver also provides a read/write interface to a BMC ram | ||
| 13 | region where the host LPC read/write region can be buffered. | ||
| 14 | |||
| 15 | config ASPEED_LPC_SNOOP | ||
| 16 | tristate "Aspeed ast2500 HOST LPC snoop support" | ||
| 17 | depends on SOC_ASPEED && REGMAP && MFD_SYSCON | ||
| 18 | help | ||
| 19 | Provides a driver to control the LPC snoop interface which | ||
| 20 | allows the BMC to listen on and save the data written by | ||
| 21 | the host to an arbitrary LPC I/O port. | ||
| 22 | |||
| 23 | config ASPEED_P2A_CTRL | ||
| 24 | depends on SOC_ASPEED && REGMAP && MFD_SYSCON | ||
| 25 | tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control" | ||
| 26 | help | ||
| 27 | Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through | ||
| 28 | ioctl()s, the driver also provides an interface for userspace mappings to | ||
| 29 | a pre-defined region. | ||
| 30 | |||
| 31 | endmenu | ||
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile new file mode 100644 index 000000000000..2f7b6da7be79 --- /dev/null +++ b/drivers/soc/aspeed/Makefile | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o | ||
| 2 | obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o | ||
| 3 | obj-$(CONFIG_ASPEED_P2A_CTRL) += aspeed-p2a-ctrl.o | ||
diff --git a/drivers/misc/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c index a024f8042259..a024f8042259 100644 --- a/drivers/misc/aspeed-lpc-ctrl.c +++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c | |||
diff --git a/drivers/misc/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index 2feb4347d67f..2feb4347d67f 100644 --- a/drivers/misc/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c | |||
diff --git a/drivers/misc/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c index b60fbeaffcbd..b60fbeaffcbd 100644 --- a/drivers/misc/aspeed-p2a-ctrl.c +++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c | |||
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index 506a6f3c2b9b..d6b529e06d9a 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile | |||
| @@ -1,2 +1,3 @@ | |||
| 1 | obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o | 1 | obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o |
| 2 | obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o | 2 | obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o |
| 3 | obj-$(CONFIG_ARCH_MXC) += soc-imx8.o | ||
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 29b43651c261..d9231bd3c691 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c | |||
| @@ -406,7 +406,6 @@ static int imx_gpc_probe(struct platform_device *pdev) | |||
| 406 | const struct imx_gpc_dt_data *of_id_data = of_id->data; | 406 | const struct imx_gpc_dt_data *of_id_data = of_id->data; |
| 407 | struct device_node *pgc_node; | 407 | struct device_node *pgc_node; |
| 408 | struct regmap *regmap; | 408 | struct regmap *regmap; |
| 409 | struct resource *res; | ||
| 410 | void __iomem *base; | 409 | void __iomem *base; |
| 411 | int ret; | 410 | int ret; |
| 412 | 411 | ||
| @@ -417,8 +416,7 @@ static int imx_gpc_probe(struct platform_device *pdev) | |||
| 417 | !pgc_node) | 416 | !pgc_node) |
| 418 | return 0; | 417 | return 0; |
| 419 | 418 | ||
| 420 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 419 | base = devm_platform_ioremap_resource(pdev, 0); |
| 421 | base = devm_ioremap_resource(&pdev->dev, res); | ||
| 422 | if (IS_ERR(base)) | 420 | if (IS_ERR(base)) |
| 423 | return PTR_ERR(base); | 421 | return PTR_ERR(base); |
| 424 | 422 | ||
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 176f473127b6..31b8d002d855 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c | |||
| @@ -136,8 +136,8 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, | |||
| 136 | GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; | 136 | GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; |
| 137 | const bool enable_power_control = !on; | 137 | const bool enable_power_control = !on; |
| 138 | const bool has_regulator = !IS_ERR(domain->regulator); | 138 | const bool has_regulator = !IS_ERR(domain->regulator); |
| 139 | unsigned long deadline; | ||
| 140 | int i, ret = 0; | 139 | int i, ret = 0; |
| 140 | u32 pxx_req; | ||
| 141 | 141 | ||
| 142 | regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, | 142 | regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, |
| 143 | domain->bits.map, domain->bits.map); | 143 | domain->bits.map, domain->bits.map); |
| @@ -169,30 +169,19 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, | |||
| 169 | * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait | 169 | * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait |
| 170 | * for PUP_REQ/PDN_REQ bit to be cleared | 170 | * for PUP_REQ/PDN_REQ bit to be cleared |
| 171 | */ | 171 | */ |
| 172 | deadline = jiffies + msecs_to_jiffies(1); | 172 | ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req, |
| 173 | while (true) { | 173 | !(pxx_req & domain->bits.pxx), |
| 174 | u32 pxx_req; | 174 | 0, USEC_PER_MSEC); |
| 175 | 175 | if (ret) { | |
| 176 | regmap_read(domain->regmap, offset, &pxx_req); | 176 | dev_err(domain->dev, "failed to command PGC\n"); |
| 177 | 177 | /* | |
| 178 | if (!(pxx_req & domain->bits.pxx)) | 178 | * If we were in a process of enabling a |
| 179 | break; | 179 | * domain and failed we might as well disable |
| 180 | 180 | * the regulator we just enabled. And if it | |
| 181 | if (time_after(jiffies, deadline)) { | 181 | * was the opposite situation and we failed to |
| 182 | dev_err(domain->dev, "falied to command PGC\n"); | 182 | * power down -- keep the regulator on |
| 183 | ret = -ETIMEDOUT; | 183 | */ |
| 184 | /* | 184 | on = !on; |
| 185 | * If we were in a process of enabling a | ||
| 186 | * domain and failed we might as well disable | ||
| 187 | * the regulator we just enabled. And if it | ||
| 188 | * was the opposite situation and we failed to | ||
| 189 | * power down -- keep the regulator on | ||
| 190 | */ | ||
| 191 | on = !on; | ||
| 192 | break; | ||
| 193 | } | ||
| 194 | |||
| 195 | cpu_relax(); | ||
| 196 | } | 185 | } |
| 197 | 186 | ||
| 198 | if (enable_power_control) | 187 | if (enable_power_control) |
| @@ -574,7 +563,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) | |||
| 574 | struct device *dev = &pdev->dev; | 563 | struct device *dev = &pdev->dev; |
| 575 | struct device_node *pgc_np, *np; | 564 | struct device_node *pgc_np, *np; |
| 576 | struct regmap *regmap; | 565 | struct regmap *regmap; |
| 577 | struct resource *res; | ||
| 578 | void __iomem *base; | 566 | void __iomem *base; |
| 579 | int ret; | 567 | int ret; |
| 580 | 568 | ||
| @@ -584,8 +572,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev) | |||
| 584 | return -EINVAL; | 572 | return -EINVAL; |
| 585 | } | 573 | } |
| 586 | 574 | ||
| 587 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 575 | base = devm_platform_ioremap_resource(pdev, 0); |
| 588 | base = devm_ioremap_resource(dev, res); | ||
| 589 | if (IS_ERR(base)) | 576 | if (IS_ERR(base)) |
| 590 | return PTR_ERR(base); | 577 | return PTR_ERR(base); |
| 591 | 578 | ||
diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c new file mode 100644 index 000000000000..fc6429f9170a --- /dev/null +++ b/drivers/soc/imx/soc-imx8.c | |||
| @@ -0,0 +1,115 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright 2019 NXP. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/init.h> | ||
| 7 | #include <linux/io.h> | ||
| 8 | #include <linux/of_address.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | #include <linux/sys_soc.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | #include <linux/of.h> | ||
| 13 | |||
| 14 | #define REV_B1 0x21 | ||
| 15 | |||
| 16 | #define IMX8MQ_SW_INFO_B1 0x40 | ||
| 17 | #define IMX8MQ_SW_MAGIC_B1 0xff0055aa | ||
| 18 | |||
| 19 | struct imx8_soc_data { | ||
| 20 | char *name; | ||
| 21 | u32 (*soc_revision)(void); | ||
| 22 | }; | ||
| 23 | |||
| 24 | static u32 __init imx8mq_soc_revision(void) | ||
| 25 | { | ||
| 26 | struct device_node *np; | ||
| 27 | void __iomem *ocotp_base; | ||
| 28 | u32 magic; | ||
| 29 | u32 rev = 0; | ||
| 30 | |||
| 31 | np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp"); | ||
| 32 | if (!np) | ||
| 33 | goto out; | ||
| 34 | |||
| 35 | ocotp_base = of_iomap(np, 0); | ||
| 36 | WARN_ON(!ocotp_base); | ||
| 37 | |||
| 38 | magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1); | ||
| 39 | if (magic == IMX8MQ_SW_MAGIC_B1) | ||
| 40 | rev = REV_B1; | ||
| 41 | |||
| 42 | iounmap(ocotp_base); | ||
| 43 | |||
| 44 | out: | ||
| 45 | of_node_put(np); | ||
| 46 | return rev; | ||
| 47 | } | ||
| 48 | |||
| 49 | static const struct imx8_soc_data imx8mq_soc_data = { | ||
| 50 | .name = "i.MX8MQ", | ||
| 51 | .soc_revision = imx8mq_soc_revision, | ||
| 52 | }; | ||
| 53 | |||
| 54 | static const struct of_device_id imx8_soc_match[] = { | ||
| 55 | { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, | ||
| 56 | { } | ||
| 57 | }; | ||
| 58 | |||
| 59 | #define imx8_revision(soc_rev) \ | ||
| 60 | soc_rev ? \ | ||
| 61 | kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ | ||
| 62 | "unknown" | ||
| 63 | |||
| 64 | static int __init imx8_soc_init(void) | ||
| 65 | { | ||
| 66 | struct soc_device_attribute *soc_dev_attr; | ||
| 67 | struct soc_device *soc_dev; | ||
| 68 | struct device_node *root; | ||
| 69 | const struct of_device_id *id; | ||
| 70 | u32 soc_rev = 0; | ||
| 71 | const struct imx8_soc_data *data; | ||
| 72 | int ret; | ||
| 73 | |||
| 74 | soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); | ||
| 75 | if (!soc_dev_attr) | ||
| 76 | return -ENODEV; | ||
| 77 | |||
| 78 | soc_dev_attr->family = "Freescale i.MX"; | ||
| 79 | |||
| 80 | root = of_find_node_by_path("/"); | ||
| 81 | ret = of_property_read_string(root, "model", &soc_dev_attr->machine); | ||
| 82 | if (ret) | ||
| 83 | goto free_soc; | ||
| 84 | |||
| 85 | id = of_match_node(imx8_soc_match, root); | ||
| 86 | if (!id) | ||
| 87 | goto free_soc; | ||
| 88 | |||
| 89 | of_node_put(root); | ||
| 90 | |||
| 91 | data = id->data; | ||
| 92 | if (data) { | ||
| 93 | soc_dev_attr->soc_id = data->name; | ||
| 94 | if (data->soc_revision) | ||
| 95 | soc_rev = data->soc_revision(); | ||
| 96 | } | ||
| 97 | |||
| 98 | soc_dev_attr->revision = imx8_revision(soc_rev); | ||
| 99 | if (!soc_dev_attr->revision) | ||
| 100 | goto free_soc; | ||
| 101 | |||
| 102 | soc_dev = soc_device_register(soc_dev_attr); | ||
| 103 | if (IS_ERR(soc_dev)) | ||
| 104 | goto free_rev; | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | |||
| 108 | free_rev: | ||
| 109 | kfree(soc_dev_attr->revision); | ||
| 110 | free_soc: | ||
| 111 | kfree(soc_dev_attr); | ||
| 112 | of_node_put(root); | ||
| 113 | return -ENODEV; | ||
| 114 | } | ||
| 115 | device_initcall(imx8_soc_init); | ||
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 8236a6c87e19..c4449a163991 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c | |||
| @@ -381,6 +381,10 @@ enum pwrap_regs { | |||
| 381 | PWRAP_EXT_GPS_AUXADC_RDATA_ADDR, | 381 | PWRAP_EXT_GPS_AUXADC_RDATA_ADDR, |
| 382 | PWRAP_GPSINF_0_STA, | 382 | PWRAP_GPSINF_0_STA, |
| 383 | PWRAP_GPSINF_1_STA, | 383 | PWRAP_GPSINF_1_STA, |
| 384 | |||
| 385 | /* MT8516 only regs */ | ||
| 386 | PWRAP_OP_TYPE, | ||
| 387 | PWRAP_MSB_FIRST, | ||
| 384 | }; | 388 | }; |
| 385 | 389 | ||
| 386 | static int mt2701_regs[] = { | 390 | static int mt2701_regs[] = { |
| @@ -852,6 +856,91 @@ static int mt8183_regs[] = { | |||
| 852 | [PWRAP_WACS2_VLDCLR] = 0xC28, | 856 | [PWRAP_WACS2_VLDCLR] = 0xC28, |
| 853 | }; | 857 | }; |
| 854 | 858 | ||
| 859 | static int mt8516_regs[] = { | ||
| 860 | [PWRAP_MUX_SEL] = 0x0, | ||
| 861 | [PWRAP_WRAP_EN] = 0x4, | ||
| 862 | [PWRAP_DIO_EN] = 0x8, | ||
| 863 | [PWRAP_SIDLY] = 0xc, | ||
| 864 | [PWRAP_RDDMY] = 0x10, | ||
| 865 | [PWRAP_SI_CK_CON] = 0x14, | ||
| 866 | [PWRAP_CSHEXT_WRITE] = 0x18, | ||
| 867 | [PWRAP_CSHEXT_READ] = 0x1c, | ||
| 868 | [PWRAP_CSLEXT_START] = 0x20, | ||
| 869 | [PWRAP_CSLEXT_END] = 0x24, | ||
| 870 | [PWRAP_STAUPD_PRD] = 0x28, | ||
| 871 | [PWRAP_STAUPD_GRPEN] = 0x2c, | ||
| 872 | [PWRAP_STAUPD_MAN_TRIG] = 0x40, | ||
| 873 | [PWRAP_STAUPD_STA] = 0x44, | ||
| 874 | [PWRAP_WRAP_STA] = 0x48, | ||
| 875 | [PWRAP_HARB_INIT] = 0x4c, | ||
| 876 | [PWRAP_HARB_HPRIO] = 0x50, | ||
| 877 | [PWRAP_HIPRIO_ARB_EN] = 0x54, | ||
| 878 | [PWRAP_HARB_STA0] = 0x58, | ||
| 879 | [PWRAP_HARB_STA1] = 0x5c, | ||
| 880 | [PWRAP_MAN_EN] = 0x60, | ||
| 881 | [PWRAP_MAN_CMD] = 0x64, | ||
| 882 | [PWRAP_MAN_RDATA] = 0x68, | ||
| 883 | [PWRAP_MAN_VLDCLR] = 0x6c, | ||
| 884 | [PWRAP_WACS0_EN] = 0x70, | ||
| 885 | [PWRAP_INIT_DONE0] = 0x74, | ||
| 886 | [PWRAP_WACS0_CMD] = 0x78, | ||
| 887 | [PWRAP_WACS0_RDATA] = 0x7c, | ||
| 888 | [PWRAP_WACS0_VLDCLR] = 0x80, | ||
| 889 | [PWRAP_WACS1_EN] = 0x84, | ||
| 890 | [PWRAP_INIT_DONE1] = 0x88, | ||
| 891 | [PWRAP_WACS1_CMD] = 0x8c, | ||
| 892 | [PWRAP_WACS1_RDATA] = 0x90, | ||
| 893 | [PWRAP_WACS1_VLDCLR] = 0x94, | ||
| 894 | [PWRAP_WACS2_EN] = 0x98, | ||
| 895 | [PWRAP_INIT_DONE2] = 0x9c, | ||
| 896 | [PWRAP_WACS2_CMD] = 0xa0, | ||
| 897 | [PWRAP_WACS2_RDATA] = 0xa4, | ||
| 898 | [PWRAP_WACS2_VLDCLR] = 0xa8, | ||
| 899 | [PWRAP_INT_EN] = 0xac, | ||
| 900 | [PWRAP_INT_FLG_RAW] = 0xb0, | ||
| 901 | [PWRAP_INT_FLG] = 0xb4, | ||
| 902 | [PWRAP_INT_CLR] = 0xb8, | ||
| 903 | [PWRAP_SIG_ADR] = 0xbc, | ||
| 904 | [PWRAP_SIG_MODE] = 0xc0, | ||
| 905 | [PWRAP_SIG_VALUE] = 0xc4, | ||
| 906 | [PWRAP_SIG_ERRVAL] = 0xc8, | ||
| 907 | [PWRAP_CRC_EN] = 0xcc, | ||
| 908 | [PWRAP_TIMER_EN] = 0xd0, | ||
| 909 | [PWRAP_TIMER_STA] = 0xd4, | ||
| 910 | [PWRAP_WDT_UNIT] = 0xd8, | ||
| 911 | [PWRAP_WDT_SRC_EN] = 0xdc, | ||
| 912 | [PWRAP_WDT_FLG] = 0xe0, | ||
| 913 | [PWRAP_DEBUG_INT_SEL] = 0xe4, | ||
| 914 | [PWRAP_DVFS_ADR0] = 0xe8, | ||
| 915 | [PWRAP_DVFS_WDATA0] = 0xec, | ||
| 916 | [PWRAP_DVFS_ADR1] = 0xf0, | ||
| 917 | [PWRAP_DVFS_WDATA1] = 0xf4, | ||
| 918 | [PWRAP_DVFS_ADR2] = 0xf8, | ||
| 919 | [PWRAP_DVFS_WDATA2] = 0xfc, | ||
| 920 | [PWRAP_DVFS_ADR3] = 0x100, | ||
| 921 | [PWRAP_DVFS_WDATA3] = 0x104, | ||
| 922 | [PWRAP_DVFS_ADR4] = 0x108, | ||
| 923 | [PWRAP_DVFS_WDATA4] = 0x10c, | ||
| 924 | [PWRAP_DVFS_ADR5] = 0x110, | ||
| 925 | [PWRAP_DVFS_WDATA5] = 0x114, | ||
| 926 | [PWRAP_DVFS_ADR6] = 0x118, | ||
| 927 | [PWRAP_DVFS_WDATA6] = 0x11c, | ||
| 928 | [PWRAP_DVFS_ADR7] = 0x120, | ||
| 929 | [PWRAP_DVFS_WDATA7] = 0x124, | ||
| 930 | [PWRAP_SPMINF_STA] = 0x128, | ||
| 931 | [PWRAP_CIPHER_KEY_SEL] = 0x12c, | ||
| 932 | [PWRAP_CIPHER_IV_SEL] = 0x130, | ||
| 933 | [PWRAP_CIPHER_EN] = 0x134, | ||
| 934 | [PWRAP_CIPHER_RDY] = 0x138, | ||
| 935 | [PWRAP_CIPHER_MODE] = 0x13c, | ||
| 936 | [PWRAP_CIPHER_SWRST] = 0x140, | ||
| 937 | [PWRAP_DCM_EN] = 0x144, | ||
| 938 | [PWRAP_DCM_DBC_PRD] = 0x148, | ||
| 939 | [PWRAP_SW_RST] = 0x168, | ||
| 940 | [PWRAP_OP_TYPE] = 0x16c, | ||
| 941 | [PWRAP_MSB_FIRST] = 0x170, | ||
| 942 | }; | ||
| 943 | |||
| 855 | enum pmic_type { | 944 | enum pmic_type { |
| 856 | PMIC_MT6323, | 945 | PMIC_MT6323, |
| 857 | PMIC_MT6351, | 946 | PMIC_MT6351, |
| @@ -869,6 +958,7 @@ enum pwrap_type { | |||
| 869 | PWRAP_MT8135, | 958 | PWRAP_MT8135, |
| 870 | PWRAP_MT8173, | 959 | PWRAP_MT8173, |
| 871 | PWRAP_MT8183, | 960 | PWRAP_MT8183, |
| 961 | PWRAP_MT8516, | ||
| 872 | }; | 962 | }; |
| 873 | 963 | ||
| 874 | struct pmic_wrapper; | 964 | struct pmic_wrapper; |
| @@ -1281,7 +1371,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp) | |||
| 1281 | static int pwrap_init_cipher(struct pmic_wrapper *wrp) | 1371 | static int pwrap_init_cipher(struct pmic_wrapper *wrp) |
| 1282 | { | 1372 | { |
| 1283 | int ret; | 1373 | int ret; |
| 1284 | u32 rdata; | 1374 | u32 rdata = 0; |
| 1285 | 1375 | ||
| 1286 | pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST); | 1376 | pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST); |
| 1287 | pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST); | 1377 | pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST); |
| @@ -1297,6 +1387,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) | |||
| 1297 | case PWRAP_MT6765: | 1387 | case PWRAP_MT6765: |
| 1298 | case PWRAP_MT6797: | 1388 | case PWRAP_MT6797: |
| 1299 | case PWRAP_MT8173: | 1389 | case PWRAP_MT8173: |
| 1390 | case PWRAP_MT8516: | ||
| 1300 | pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); | 1391 | pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); |
| 1301 | break; | 1392 | break; |
| 1302 | case PWRAP_MT7622: | 1393 | case PWRAP_MT7622: |
| @@ -1478,7 +1569,8 @@ static int pwrap_init(struct pmic_wrapper *wrp) | |||
| 1478 | { | 1569 | { |
| 1479 | int ret; | 1570 | int ret; |
| 1480 | 1571 | ||
| 1481 | reset_control_reset(wrp->rstc); | 1572 | if (wrp->rstc) |
| 1573 | reset_control_reset(wrp->rstc); | ||
| 1482 | if (wrp->rstc_bridge) | 1574 | if (wrp->rstc_bridge) |
| 1483 | reset_control_reset(wrp->rstc_bridge); | 1575 | reset_control_reset(wrp->rstc_bridge); |
| 1484 | 1576 | ||
| @@ -1764,6 +1856,18 @@ static const struct pmic_wrapper_type pwrap_mt8183 = { | |||
| 1764 | .init_soc_specific = pwrap_mt8183_init_soc_specific, | 1856 | .init_soc_specific = pwrap_mt8183_init_soc_specific, |
| 1765 | }; | 1857 | }; |
| 1766 | 1858 | ||
| 1859 | static struct pmic_wrapper_type pwrap_mt8516 = { | ||
| 1860 | .regs = mt8516_regs, | ||
| 1861 | .type = PWRAP_MT8516, | ||
| 1862 | .arb_en_all = 0xff, | ||
| 1863 | .int_en_all = ~(u32)(BIT(31) | BIT(2)), | ||
| 1864 | .spi_w = PWRAP_MAN_CMD_SPI_WRITE, | ||
| 1865 | .wdt_src = PWRAP_WDT_SRC_MASK_ALL, | ||
| 1866 | .caps = PWRAP_CAP_DCM, | ||
| 1867 | .init_reg_clock = pwrap_mt2701_init_reg_clock, | ||
| 1868 | .init_soc_specific = NULL, | ||
| 1869 | }; | ||
| 1870 | |||
| 1767 | static const struct of_device_id of_pwrap_match_tbl[] = { | 1871 | static const struct of_device_id of_pwrap_match_tbl[] = { |
| 1768 | { | 1872 | { |
| 1769 | .compatible = "mediatek,mt2701-pwrap", | 1873 | .compatible = "mediatek,mt2701-pwrap", |
| @@ -1787,6 +1891,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = { | |||
| 1787 | .compatible = "mediatek,mt8183-pwrap", | 1891 | .compatible = "mediatek,mt8183-pwrap", |
| 1788 | .data = &pwrap_mt8183, | 1892 | .data = &pwrap_mt8183, |
| 1789 | }, { | 1893 | }, { |
| 1894 | .compatible = "mediatek,mt8516-pwrap", | ||
| 1895 | .data = &pwrap_mt8516, | ||
| 1896 | }, { | ||
| 1790 | /* sentinel */ | 1897 | /* sentinel */ |
| 1791 | } | 1898 | } |
| 1792 | }; | 1899 | }; |
diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index c701b3b010f1..f6c3d17b05c7 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c | |||
| @@ -248,8 +248,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev) | |||
| 248 | } | 248 | } |
| 249 | 249 | ||
| 250 | cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB); | 250 | cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB); |
| 251 | if (IS_ERR_OR_NULL(cmd_db_header)) { | 251 | if (!cmd_db_header) { |
| 252 | ret = PTR_ERR(cmd_db_header); | 252 | ret = -ENOMEM; |
| 253 | cmd_db_header = NULL; | 253 | cmd_db_header = NULL; |
| 254 | return ret; | 254 | return ret; |
| 255 | } | 255 | } |
diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index c239a28e503f..f9e309f0acd3 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c | |||
| @@ -345,8 +345,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) | |||
| 345 | struct qmi_handle *qmi = txn->qmi; | 345 | struct qmi_handle *qmi = txn->qmi; |
| 346 | int ret; | 346 | int ret; |
| 347 | 347 | ||
| 348 | ret = wait_for_completion_interruptible_timeout(&txn->completion, | 348 | ret = wait_for_completion_timeout(&txn->completion, timeout); |
| 349 | timeout); | ||
| 350 | 349 | ||
| 351 | mutex_lock(&qmi->txn_lock); | 350 | mutex_lock(&qmi->txn_lock); |
| 352 | mutex_lock(&txn->lock); | 351 | mutex_lock(&txn->lock); |
| @@ -354,9 +353,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) | |||
| 354 | mutex_unlock(&txn->lock); | 353 | mutex_unlock(&txn->lock); |
| 355 | mutex_unlock(&qmi->txn_lock); | 354 | mutex_unlock(&qmi->txn_lock); |
| 356 | 355 | ||
| 357 | if (ret < 0) | 356 | if (ret == 0) |
| 358 | return ret; | ||
| 359 | else if (ret == 0) | ||
| 360 | return -ETIMEDOUT; | 357 | return -ETIMEDOUT; |
| 361 | else | 358 | else |
| 362 | return txn->result; | 359 | return txn->result; |
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index 7200d762a951..6f5e8be9689c 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c | |||
| @@ -137,6 +137,26 @@ static struct class rmtfs_class = { | |||
| 137 | .name = "rmtfs", | 137 | .name = "rmtfs", |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | static int qcom_rmtfs_mem_mmap(struct file *filep, struct vm_area_struct *vma) | ||
| 141 | { | ||
| 142 | struct qcom_rmtfs_mem *rmtfs_mem = filep->private_data; | ||
| 143 | |||
| 144 | if (vma->vm_end - vma->vm_start > rmtfs_mem->size) { | ||
| 145 | dev_dbg(&rmtfs_mem->dev, | ||
| 146 | "vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n", | ||
| 147 | vma->vm_end, vma->vm_start, | ||
| 148 | (vma->vm_end - vma->vm_start), &rmtfs_mem->size); | ||
| 149 | return -EINVAL; | ||
| 150 | } | ||
| 151 | |||
| 152 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | ||
| 153 | return remap_pfn_range(vma, | ||
| 154 | vma->vm_start, | ||
| 155 | rmtfs_mem->addr >> PAGE_SHIFT, | ||
| 156 | vma->vm_end - vma->vm_start, | ||
| 157 | vma->vm_page_prot); | ||
| 158 | } | ||
| 159 | |||
| 140 | static const struct file_operations qcom_rmtfs_mem_fops = { | 160 | static const struct file_operations qcom_rmtfs_mem_fops = { |
| 141 | .owner = THIS_MODULE, | 161 | .owner = THIS_MODULE, |
| 142 | .open = qcom_rmtfs_mem_open, | 162 | .open = qcom_rmtfs_mem_open, |
| @@ -144,6 +164,7 @@ static const struct file_operations qcom_rmtfs_mem_fops = { | |||
| 144 | .write = qcom_rmtfs_mem_write, | 164 | .write = qcom_rmtfs_mem_write, |
| 145 | .release = qcom_rmtfs_mem_release, | 165 | .release = qcom_rmtfs_mem_release, |
| 146 | .llseek = default_llseek, | 166 | .llseek = default_llseek, |
| 167 | .mmap = qcom_rmtfs_mem_mmap, | ||
| 147 | }; | 168 | }; |
| 148 | 169 | ||
| 149 | static void qcom_rmtfs_mem_release_device(struct device *dev) | 170 | static void qcom_rmtfs_mem_release_device(struct device *dev) |
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 75bd9a83aef0..e278fc11fe5c 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c | |||
| @@ -459,7 +459,7 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg, | |||
| 459 | do { | 459 | do { |
| 460 | slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS, | 460 | slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS, |
| 461 | i, msg->num_cmds, 0); | 461 | i, msg->num_cmds, 0); |
| 462 | if (slot == tcs->num_tcs * tcs->ncpt) | 462 | if (slot >= tcs->num_tcs * tcs->ncpt) |
| 463 | return -ENOMEM; | 463 | return -ENOMEM; |
| 464 | i += tcs->ncpt; | 464 | i += tcs->ncpt; |
| 465 | } while (slot + msg->num_cmds - 1 >= i); | 465 | } while (slot + msg->num_cmds - 1 >= i); |
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 4af96e668a2f..3299cf5365f3 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c | |||
| @@ -335,6 +335,9 @@ static int __init renesas_soc_init(void) | |||
| 335 | /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ | 335 | /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ |
| 336 | if ((product & 0x7fff) == 0x5210) | 336 | if ((product & 0x7fff) == 0x5210) |
| 337 | product ^= 0x11; | 337 | product ^= 0x11; |
| 338 | /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */ | ||
| 339 | if ((product & 0x7fff) == 0x5211) | ||
| 340 | product ^= 0x12; | ||
| 338 | if (soc->id && ((product >> 8) & 0xff) != soc->id) { | 341 | if (soc->id && ((product >> 8) & 0xff) != soc->id) { |
| 339 | pr_warn("SoC mismatch (product = 0x%x)\n", product); | 342 | pr_warn("SoC mismatch (product = 0x%x)\n", product); |
| 340 | return -ENODEV; | 343 | return -ENODEV; |
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c index 96882ffde67e..3b81e1d75a97 100644 --- a/drivers/soc/rockchip/grf.c +++ b/drivers/soc/rockchip/grf.c | |||
| @@ -66,9 +66,11 @@ static const struct rockchip_grf_info rk3228_grf __initconst = { | |||
| 66 | }; | 66 | }; |
| 67 | 67 | ||
| 68 | #define RK3288_GRF_SOC_CON0 0x244 | 68 | #define RK3288_GRF_SOC_CON0 0x244 |
| 69 | #define RK3288_GRF_SOC_CON2 0x24c | ||
| 69 | 70 | ||
| 70 | static const struct rockchip_grf_value rk3288_defaults[] __initconst = { | 71 | static const struct rockchip_grf_value rk3288_defaults[] __initconst = { |
| 71 | { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) }, | 72 | { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) }, |
| 73 | { "pwm select", RK3288_GRF_SOC_CON2, HIWORD_UPDATE(1, 1, 0) }, | ||
| 72 | }; | 74 | }; |
| 73 | 75 | ||
| 74 | static const struct rockchip_grf_info rk3288_grf __initconst = { | 76 | static const struct rockchip_grf_info rk3288_grf __initconst = { |
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 0df258518693..5648e5c09ef5 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c | |||
| @@ -272,6 +272,14 @@ static const char * const tegra30_reset_sources[] = { | |||
| 272 | "WATCHDOG", | 272 | "WATCHDOG", |
| 273 | "SENSOR", | 273 | "SENSOR", |
| 274 | "SW_MAIN", | 274 | "SW_MAIN", |
| 275 | "LP0" | ||
| 276 | }; | ||
| 277 | |||
| 278 | static const char * const tegra210_reset_sources[] = { | ||
| 279 | "POWER_ON_RESET", | ||
| 280 | "WATCHDOG", | ||
| 281 | "SENSOR", | ||
| 282 | "SW_MAIN", | ||
| 275 | "LP0", | 283 | "LP0", |
| 276 | "AOTAG" | 284 | "AOTAG" |
| 277 | }; | 285 | }; |
| @@ -656,10 +664,15 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain) | |||
| 656 | int err; | 664 | int err; |
| 657 | 665 | ||
| 658 | err = tegra_powergate_power_up(pg, true); | 666 | err = tegra_powergate_power_up(pg, true); |
| 659 | if (err) | 667 | if (err) { |
| 660 | dev_err(dev, "failed to turn on PM domain %s: %d\n", | 668 | dev_err(dev, "failed to turn on PM domain %s: %d\n", |
| 661 | pg->genpd.name, err); | 669 | pg->genpd.name, err); |
| 670 | goto out; | ||
| 671 | } | ||
| 672 | |||
| 673 | reset_control_release(pg->reset); | ||
| 662 | 674 | ||
| 675 | out: | ||
| 663 | return err; | 676 | return err; |
| 664 | } | 677 | } |
| 665 | 678 | ||
| @@ -669,10 +682,18 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain) | |||
| 669 | struct device *dev = pg->pmc->dev; | 682 | struct device *dev = pg->pmc->dev; |
| 670 | int err; | 683 | int err; |
| 671 | 684 | ||
| 685 | err = reset_control_acquire(pg->reset); | ||
| 686 | if (err < 0) { | ||
| 687 | pr_err("failed to acquire resets: %d\n", err); | ||
| 688 | return err; | ||
| 689 | } | ||
| 690 | |||
| 672 | err = tegra_powergate_power_down(pg); | 691 | err = tegra_powergate_power_down(pg); |
| 673 | if (err) | 692 | if (err) { |
| 674 | dev_err(dev, "failed to turn off PM domain %s: %d\n", | 693 | dev_err(dev, "failed to turn off PM domain %s: %d\n", |
| 675 | pg->genpd.name, err); | 694 | pg->genpd.name, err); |
| 695 | reset_control_release(pg->reset); | ||
| 696 | } | ||
| 676 | 697 | ||
| 677 | return err; | 698 | return err; |
| 678 | } | 699 | } |
| @@ -937,38 +958,53 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, | |||
| 937 | struct device *dev = pg->pmc->dev; | 958 | struct device *dev = pg->pmc->dev; |
| 938 | int err; | 959 | int err; |
| 939 | 960 | ||
| 940 | pg->reset = of_reset_control_array_get_exclusive(np); | 961 | pg->reset = of_reset_control_array_get_exclusive_released(np); |
| 941 | if (IS_ERR(pg->reset)) { | 962 | if (IS_ERR(pg->reset)) { |
| 942 | err = PTR_ERR(pg->reset); | 963 | err = PTR_ERR(pg->reset); |
| 943 | dev_err(dev, "failed to get device resets: %d\n", err); | 964 | dev_err(dev, "failed to get device resets: %d\n", err); |
| 944 | return err; | 965 | return err; |
| 945 | } | 966 | } |
| 946 | 967 | ||
| 947 | if (off) | 968 | err = reset_control_acquire(pg->reset); |
| 969 | if (err < 0) { | ||
| 970 | pr_err("failed to acquire resets: %d\n", err); | ||
| 971 | goto out; | ||
| 972 | } | ||
| 973 | |||
| 974 | if (off) { | ||
| 948 | err = reset_control_assert(pg->reset); | 975 | err = reset_control_assert(pg->reset); |
| 949 | else | 976 | } else { |
| 950 | err = reset_control_deassert(pg->reset); | 977 | err = reset_control_deassert(pg->reset); |
| 978 | if (err < 0) | ||
| 979 | goto out; | ||
| 951 | 980 | ||
| 952 | if (err) | 981 | reset_control_release(pg->reset); |
| 982 | } | ||
| 983 | |||
| 984 | out: | ||
| 985 | if (err) { | ||
| 986 | reset_control_release(pg->reset); | ||
| 953 | reset_control_put(pg->reset); | 987 | reset_control_put(pg->reset); |
| 988 | } | ||
| 954 | 989 | ||
| 955 | return err; | 990 | return err; |
| 956 | } | 991 | } |
| 957 | 992 | ||
| 958 | static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) | 993 | static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) |
| 959 | { | 994 | { |
| 960 | struct device *dev = pmc->dev; | 995 | struct device *dev = pmc->dev; |
| 961 | struct tegra_powergate *pg; | 996 | struct tegra_powergate *pg; |
| 962 | int id, err; | 997 | int id, err = 0; |
| 963 | bool off; | 998 | bool off; |
| 964 | 999 | ||
| 965 | pg = kzalloc(sizeof(*pg), GFP_KERNEL); | 1000 | pg = kzalloc(sizeof(*pg), GFP_KERNEL); |
| 966 | if (!pg) | 1001 | if (!pg) |
| 967 | return; | 1002 | return -ENOMEM; |
| 968 | 1003 | ||
| 969 | id = tegra_powergate_lookup(pmc, np->name); | 1004 | id = tegra_powergate_lookup(pmc, np->name); |
| 970 | if (id < 0) { | 1005 | if (id < 0) { |
| 971 | dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id); | 1006 | dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id); |
| 1007 | err = -ENODEV; | ||
| 972 | goto free_mem; | 1008 | goto free_mem; |
| 973 | } | 1009 | } |
| 974 | 1010 | ||
| @@ -1021,7 +1057,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) | |||
| 1021 | 1057 | ||
| 1022 | dev_dbg(dev, "added PM domain %s\n", pg->genpd.name); | 1058 | dev_dbg(dev, "added PM domain %s\n", pg->genpd.name); |
| 1023 | 1059 | ||
| 1024 | return; | 1060 | return 0; |
| 1025 | 1061 | ||
| 1026 | remove_genpd: | 1062 | remove_genpd: |
| 1027 | pm_genpd_remove(&pg->genpd); | 1063 | pm_genpd_remove(&pg->genpd); |
| @@ -1040,25 +1076,67 @@ set_available: | |||
| 1040 | 1076 | ||
| 1041 | free_mem: | 1077 | free_mem: |
| 1042 | kfree(pg); | 1078 | kfree(pg); |
| 1079 | |||
| 1080 | return err; | ||
| 1043 | } | 1081 | } |
| 1044 | 1082 | ||
| 1045 | static void tegra_powergate_init(struct tegra_pmc *pmc, | 1083 | static int tegra_powergate_init(struct tegra_pmc *pmc, |
| 1046 | struct device_node *parent) | 1084 | struct device_node *parent) |
| 1047 | { | 1085 | { |
| 1048 | struct device_node *np, *child; | 1086 | struct device_node *np, *child; |
| 1049 | unsigned int i; | 1087 | int err = 0; |
| 1088 | |||
| 1089 | np = of_get_child_by_name(parent, "powergates"); | ||
| 1090 | if (!np) | ||
| 1091 | return 0; | ||
| 1092 | |||
| 1093 | for_each_child_of_node(np, child) { | ||
| 1094 | err = tegra_powergate_add(pmc, child); | ||
| 1095 | if (err < 0) { | ||
| 1096 | of_node_put(child); | ||
| 1097 | break; | ||
| 1098 | } | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | of_node_put(np); | ||
| 1102 | |||
| 1103 | return err; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | static void tegra_powergate_remove(struct generic_pm_domain *genpd) | ||
| 1107 | { | ||
| 1108 | struct tegra_powergate *pg = to_powergate(genpd); | ||
| 1109 | |||
| 1110 | reset_control_put(pg->reset); | ||
| 1111 | |||
| 1112 | while (pg->num_clks--) | ||
| 1113 | clk_put(pg->clks[pg->num_clks]); | ||
| 1114 | |||
| 1115 | kfree(pg->clks); | ||
| 1050 | 1116 | ||
| 1051 | /* Create a bitmap of the available and valid partitions */ | 1117 | set_bit(pg->id, pmc->powergates_available); |
| 1052 | for (i = 0; i < pmc->soc->num_powergates; i++) | 1118 | |
| 1053 | if (pmc->soc->powergates[i]) | 1119 | kfree(pg); |
| 1054 | set_bit(i, pmc->powergates_available); | 1120 | } |
| 1121 | |||
| 1122 | static void tegra_powergate_remove_all(struct device_node *parent) | ||
| 1123 | { | ||
| 1124 | struct generic_pm_domain *genpd; | ||
| 1125 | struct device_node *np, *child; | ||
| 1055 | 1126 | ||
| 1056 | np = of_get_child_by_name(parent, "powergates"); | 1127 | np = of_get_child_by_name(parent, "powergates"); |
| 1057 | if (!np) | 1128 | if (!np) |
| 1058 | return; | 1129 | return; |
| 1059 | 1130 | ||
| 1060 | for_each_child_of_node(np, child) | 1131 | for_each_child_of_node(np, child) { |
| 1061 | tegra_powergate_add(pmc, child); | 1132 | of_genpd_del_provider(child); |
| 1133 | |||
| 1134 | genpd = of_genpd_remove_last(child); | ||
| 1135 | if (IS_ERR(genpd)) | ||
| 1136 | continue; | ||
| 1137 | |||
| 1138 | tegra_powergate_remove(genpd); | ||
| 1139 | } | ||
| 1062 | 1140 | ||
| 1063 | of_node_put(np); | 1141 | of_node_put(np); |
| 1064 | } | 1142 | } |
| @@ -1709,13 +1787,16 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) | |||
| 1709 | static ssize_t reset_reason_show(struct device *dev, | 1787 | static ssize_t reset_reason_show(struct device *dev, |
| 1710 | struct device_attribute *attr, char *buf) | 1788 | struct device_attribute *attr, char *buf) |
| 1711 | { | 1789 | { |
| 1712 | u32 value, rst_src; | 1790 | u32 value; |
| 1713 | 1791 | ||
| 1714 | value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); | 1792 | value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); |
| 1715 | rst_src = (value & pmc->soc->regs->rst_source_mask) >> | 1793 | value &= pmc->soc->regs->rst_source_mask; |
| 1716 | pmc->soc->regs->rst_source_shift; | 1794 | value >>= pmc->soc->regs->rst_source_shift; |
| 1795 | |||
| 1796 | if (WARN_ON(value >= pmc->soc->num_reset_sources)) | ||
| 1797 | return sprintf(buf, "%s\n", "UNKNOWN"); | ||
| 1717 | 1798 | ||
| 1718 | return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]); | 1799 | return sprintf(buf, "%s\n", pmc->soc->reset_sources[value]); |
| 1719 | } | 1800 | } |
| 1720 | 1801 | ||
| 1721 | static DEVICE_ATTR_RO(reset_reason); | 1802 | static DEVICE_ATTR_RO(reset_reason); |
| @@ -1723,13 +1804,16 @@ static DEVICE_ATTR_RO(reset_reason); | |||
| 1723 | static ssize_t reset_level_show(struct device *dev, | 1804 | static ssize_t reset_level_show(struct device *dev, |
| 1724 | struct device_attribute *attr, char *buf) | 1805 | struct device_attribute *attr, char *buf) |
| 1725 | { | 1806 | { |
| 1726 | u32 value, rst_lvl; | 1807 | u32 value; |
| 1727 | 1808 | ||
| 1728 | value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); | 1809 | value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); |
| 1729 | rst_lvl = (value & pmc->soc->regs->rst_level_mask) >> | 1810 | value &= pmc->soc->regs->rst_level_mask; |
| 1730 | pmc->soc->regs->rst_level_shift; | 1811 | value >>= pmc->soc->regs->rst_level_shift; |
| 1731 | 1812 | ||
| 1732 | return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]); | 1813 | if (WARN_ON(value >= pmc->soc->num_reset_levels)) |
| 1814 | return sprintf(buf, "%s\n", "UNKNOWN"); | ||
| 1815 | |||
| 1816 | return sprintf(buf, "%s\n", pmc->soc->reset_levels[value]); | ||
| 1733 | } | 1817 | } |
| 1734 | 1818 | ||
| 1735 | static DEVICE_ATTR_RO(reset_level); | 1819 | static DEVICE_ATTR_RO(reset_level); |
| @@ -1999,7 +2083,7 @@ static int tegra_pmc_probe(struct platform_device *pdev) | |||
| 1999 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | 2083 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { |
| 2000 | err = tegra_powergate_debugfs_init(); | 2084 | err = tegra_powergate_debugfs_init(); |
| 2001 | if (err < 0) | 2085 | if (err < 0) |
| 2002 | return err; | 2086 | goto cleanup_sysfs; |
| 2003 | } | 2087 | } |
| 2004 | 2088 | ||
| 2005 | err = register_restart_handler(&tegra_pmc_restart_handler); | 2089 | err = register_restart_handler(&tegra_pmc_restart_handler); |
| @@ -2013,9 +2097,13 @@ static int tegra_pmc_probe(struct platform_device *pdev) | |||
| 2013 | if (err) | 2097 | if (err) |
| 2014 | goto cleanup_restart_handler; | 2098 | goto cleanup_restart_handler; |
| 2015 | 2099 | ||
| 2100 | err = tegra_powergate_init(pmc, pdev->dev.of_node); | ||
| 2101 | if (err < 0) | ||
| 2102 | goto cleanup_powergates; | ||
| 2103 | |||
| 2016 | err = tegra_pmc_irq_init(pmc); | 2104 | err = tegra_pmc_irq_init(pmc); |
| 2017 | if (err < 0) | 2105 | if (err < 0) |
| 2018 | goto cleanup_restart_handler; | 2106 | goto cleanup_powergates; |
| 2019 | 2107 | ||
| 2020 | mutex_lock(&pmc->powergates_lock); | 2108 | mutex_lock(&pmc->powergates_lock); |
| 2021 | iounmap(pmc->base); | 2109 | iounmap(pmc->base); |
| @@ -2026,10 +2114,15 @@ static int tegra_pmc_probe(struct platform_device *pdev) | |||
| 2026 | 2114 | ||
| 2027 | return 0; | 2115 | return 0; |
| 2028 | 2116 | ||
| 2117 | cleanup_powergates: | ||
| 2118 | tegra_powergate_remove_all(pdev->dev.of_node); | ||
| 2029 | cleanup_restart_handler: | 2119 | cleanup_restart_handler: |
| 2030 | unregister_restart_handler(&tegra_pmc_restart_handler); | 2120 | unregister_restart_handler(&tegra_pmc_restart_handler); |
| 2031 | cleanup_debugfs: | 2121 | cleanup_debugfs: |
| 2032 | debugfs_remove(pmc->debugfs); | 2122 | debugfs_remove(pmc->debugfs); |
| 2123 | cleanup_sysfs: | ||
| 2124 | device_remove_file(&pdev->dev, &dev_attr_reset_reason); | ||
| 2125 | device_remove_file(&pdev->dev, &dev_attr_reset_level); | ||
| 2033 | return err; | 2126 | return err; |
| 2034 | } | 2127 | } |
| 2035 | 2128 | ||
| @@ -2185,7 +2278,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { | |||
| 2185 | .init = tegra20_pmc_init, | 2278 | .init = tegra20_pmc_init, |
| 2186 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2279 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2187 | .reset_sources = tegra30_reset_sources, | 2280 | .reset_sources = tegra30_reset_sources, |
| 2188 | .num_reset_sources = 5, | 2281 | .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), |
| 2189 | .reset_levels = NULL, | 2282 | .reset_levels = NULL, |
| 2190 | .num_reset_levels = 0, | 2283 | .num_reset_levels = 0, |
| 2191 | }; | 2284 | }; |
| @@ -2236,7 +2329,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { | |||
| 2236 | .init = tegra20_pmc_init, | 2329 | .init = tegra20_pmc_init, |
| 2237 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2330 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2238 | .reset_sources = tegra30_reset_sources, | 2331 | .reset_sources = tegra30_reset_sources, |
| 2239 | .num_reset_sources = 5, | 2332 | .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), |
| 2240 | .reset_levels = NULL, | 2333 | .reset_levels = NULL, |
| 2241 | .num_reset_levels = 0, | 2334 | .num_reset_levels = 0, |
| 2242 | }; | 2335 | }; |
| @@ -2347,7 +2440,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { | |||
| 2347 | .init = tegra20_pmc_init, | 2440 | .init = tegra20_pmc_init, |
| 2348 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2441 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2349 | .reset_sources = tegra30_reset_sources, | 2442 | .reset_sources = tegra30_reset_sources, |
| 2350 | .num_reset_sources = 5, | 2443 | .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), |
| 2351 | .reset_levels = NULL, | 2444 | .reset_levels = NULL, |
| 2352 | .num_reset_levels = 0, | 2445 | .num_reset_levels = 0, |
| 2353 | }; | 2446 | }; |
| @@ -2452,8 +2545,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { | |||
| 2452 | .regs = &tegra20_pmc_regs, | 2545 | .regs = &tegra20_pmc_regs, |
| 2453 | .init = tegra20_pmc_init, | 2546 | .init = tegra20_pmc_init, |
| 2454 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, | 2547 | .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, |
| 2455 | .reset_sources = tegra30_reset_sources, | 2548 | .reset_sources = tegra210_reset_sources, |
| 2456 | .num_reset_sources = 5, | 2549 | .num_reset_sources = ARRAY_SIZE(tegra210_reset_sources), |
| 2457 | .reset_levels = NULL, | 2550 | .reset_levels = NULL, |
| 2458 | .num_reset_levels = 0, | 2551 | .num_reset_levels = 0, |
| 2459 | }; | 2552 | }; |
| @@ -2578,9 +2671,9 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { | |||
| 2578 | .init = NULL, | 2671 | .init = NULL, |
| 2579 | .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, | 2672 | .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, |
| 2580 | .reset_sources = tegra186_reset_sources, | 2673 | .reset_sources = tegra186_reset_sources, |
| 2581 | .num_reset_sources = 14, | 2674 | .num_reset_sources = ARRAY_SIZE(tegra186_reset_sources), |
| 2582 | .reset_levels = tegra186_reset_levels, | 2675 | .reset_levels = tegra186_reset_levels, |
| 2583 | .num_reset_levels = 3, | 2676 | .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), |
| 2584 | .num_wake_events = ARRAY_SIZE(tegra186_wake_events), | 2677 | .num_wake_events = ARRAY_SIZE(tegra186_wake_events), |
| 2585 | .wake_events = tegra186_wake_events, | 2678 | .wake_events = tegra186_wake_events, |
| 2586 | }; | 2679 | }; |
| @@ -2719,6 +2812,7 @@ static int __init tegra_pmc_early_init(void) | |||
| 2719 | const struct of_device_id *match; | 2812 | const struct of_device_id *match; |
| 2720 | struct device_node *np; | 2813 | struct device_node *np; |
| 2721 | struct resource regs; | 2814 | struct resource regs; |
| 2815 | unsigned int i; | ||
| 2722 | bool invert; | 2816 | bool invert; |
| 2723 | 2817 | ||
| 2724 | mutex_init(&pmc->powergates_lock); | 2818 | mutex_init(&pmc->powergates_lock); |
| @@ -2775,7 +2869,10 @@ static int __init tegra_pmc_early_init(void) | |||
| 2775 | if (pmc->soc->maybe_tz_only) | 2869 | if (pmc->soc->maybe_tz_only) |
| 2776 | pmc->tz_only = tegra_pmc_detect_tz_only(pmc); | 2870 | pmc->tz_only = tegra_pmc_detect_tz_only(pmc); |
| 2777 | 2871 | ||
| 2778 | tegra_powergate_init(pmc, np); | 2872 | /* Create a bitmap of the available and valid partitions */ |
| 2873 | for (i = 0; i < pmc->soc->num_powergates; i++) | ||
| 2874 | if (pmc->soc->powergates[i]) | ||
| 2875 | set_bit(i, pmc->powergates_available); | ||
| 2779 | 2876 | ||
| 2780 | /* | 2877 | /* |
| 2781 | * Invert the interrupt polarity if a PMC device tree node | 2878 | * Invert the interrupt polarity if a PMC device tree node |
diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index be4570baad96..57960e92ebe0 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig | |||
| @@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA | |||
| 45 | config AMX3_PM | 45 | config AMX3_PM |
| 46 | tristate "AMx3 Power Management" | 46 | tristate "AMx3 Power Management" |
| 47 | depends on SOC_AM33XX || SOC_AM43XX | 47 | depends on SOC_AM33XX || SOC_AM43XX |
| 48 | depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM | 48 | depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP |
| 49 | help | 49 | help |
| 50 | Enable power management on AM335x and AM437x. Required for suspend to mem | 50 | Enable power management on AM335x and AM437x. Required for suspend to mem |
| 51 | and standby states on both AM335x and AM437x platforms and for deeper cpuidle | 51 | and standby states on both AM335x and AM437x platforms and for deeper cpuidle |
| 52 | c-states on AM335x. | 52 | c-states on AM335x. Also required for rtc and ddr in self-refresh low |
| 53 | power mode on AM437x platforms. | ||
| 53 | 54 | ||
| 54 | config WKUP_M3_IPC | 55 | config WKUP_M3_IPC |
| 55 | tristate "TI AMx3 Wkup-M3 IPC Driver" | 56 | tristate "TI AMx3 Wkup-M3 IPC Driver" |
diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index d0dab323651f..fc5802ccb1c0 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | * Vaibhav Bedia, Dave Gerlach | 6 | * Vaibhav Bedia, Dave Gerlach |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/clk.h> | ||
| 9 | #include <linux/cpu.h> | 10 | #include <linux/cpu.h> |
| 10 | #include <linux/err.h> | 11 | #include <linux/err.h> |
| 11 | #include <linux/genalloc.h> | 12 | #include <linux/genalloc.h> |
| @@ -13,9 +14,12 @@ | |||
| 13 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 14 | #include <linux/io.h> | 15 | #include <linux/io.h> |
| 15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/nvmem-consumer.h> | ||
| 16 | #include <linux/of.h> | 18 | #include <linux/of.h> |
| 17 | #include <linux/platform_data/pm33xx.h> | 19 | #include <linux/platform_data/pm33xx.h> |
| 18 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 21 | #include <linux/rtc.h> | ||
| 22 | #include <linux/rtc/rtc-omap.h> | ||
| 19 | #include <linux/sizes.h> | 23 | #include <linux/sizes.h> |
| 20 | #include <linux/sram.h> | 24 | #include <linux/sram.h> |
| 21 | #include <linux/suspend.h> | 25 | #include <linux/suspend.h> |
| @@ -29,33 +33,162 @@ | |||
| 29 | #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \ | 33 | #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \ |
| 30 | (unsigned long)pm_sram->do_wfi) | 34 | (unsigned long)pm_sram->do_wfi) |
| 31 | 35 | ||
| 36 | #define RTC_SCRATCH_RESUME_REG 0 | ||
| 37 | #define RTC_SCRATCH_MAGIC_REG 1 | ||
| 38 | #define RTC_REG_BOOT_MAGIC 0x8cd0 /* RTC */ | ||
| 39 | #define GIC_INT_SET_PENDING_BASE 0x200 | ||
| 40 | #define AM43XX_GIC_DIST_BASE 0x48241000 | ||
| 41 | |||
| 42 | static u32 rtc_magic_val; | ||
| 43 | |||
| 32 | static int (*am33xx_do_wfi_sram)(unsigned long unused); | 44 | static int (*am33xx_do_wfi_sram)(unsigned long unused); |
| 33 | static phys_addr_t am33xx_do_wfi_sram_phys; | 45 | static phys_addr_t am33xx_do_wfi_sram_phys; |
| 34 | 46 | ||
| 35 | static struct gen_pool *sram_pool, *sram_pool_data; | 47 | static struct gen_pool *sram_pool, *sram_pool_data; |
| 36 | static unsigned long ocmcram_location, ocmcram_location_data; | 48 | static unsigned long ocmcram_location, ocmcram_location_data; |
| 37 | 49 | ||
| 50 | static struct rtc_device *omap_rtc; | ||
| 51 | static void __iomem *gic_dist_base; | ||
| 52 | |||
| 38 | static struct am33xx_pm_platform_data *pm_ops; | 53 | static struct am33xx_pm_platform_data *pm_ops; |
| 39 | static struct am33xx_pm_sram_addr *pm_sram; | 54 | static struct am33xx_pm_sram_addr *pm_sram; |
| 40 | 55 | ||
| 41 | static struct device *pm33xx_dev; | 56 | static struct device *pm33xx_dev; |
| 42 | static struct wkup_m3_ipc *m3_ipc; | 57 | static struct wkup_m3_ipc *m3_ipc; |
| 43 | 58 | ||
| 59 | #ifdef CONFIG_SUSPEND | ||
| 60 | static int rtc_only_idle; | ||
| 61 | static int retrigger_irq; | ||
| 44 | static unsigned long suspend_wfi_flags; | 62 | static unsigned long suspend_wfi_flags; |
| 45 | 63 | ||
| 64 | static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0, | ||
| 65 | .src = "Unknown", | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct wkup_m3_wakeup_src rtc_alarm_wakeup = { | ||
| 69 | .irq_nr = 108, .src = "RTC Alarm", | ||
| 70 | }; | ||
| 71 | |||
| 72 | static struct wkup_m3_wakeup_src rtc_ext_wakeup = { | ||
| 73 | .irq_nr = 0, .src = "Ext wakeup", | ||
| 74 | }; | ||
| 75 | #endif | ||
| 76 | |||
| 46 | static u32 sram_suspend_address(unsigned long addr) | 77 | static u32 sram_suspend_address(unsigned long addr) |
| 47 | { | 78 | { |
| 48 | return ((unsigned long)am33xx_do_wfi_sram + | 79 | return ((unsigned long)am33xx_do_wfi_sram + |
| 49 | AMX3_PM_SRAM_SYMBOL_OFFSET(addr)); | 80 | AMX3_PM_SRAM_SYMBOL_OFFSET(addr)); |
| 50 | } | 81 | } |
| 51 | 82 | ||
| 83 | static int am33xx_push_sram_idle(void) | ||
| 84 | { | ||
| 85 | struct am33xx_pm_ro_sram_data ro_sram_data; | ||
| 86 | int ret; | ||
| 87 | u32 table_addr, ro_data_addr; | ||
| 88 | void *copy_addr; | ||
| 89 | |||
| 90 | ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; | ||
| 91 | ro_sram_data.amx3_pm_sram_data_phys = | ||
| 92 | gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); | ||
| 93 | ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr(); | ||
| 94 | |||
| 95 | /* Save physical address to calculate resume offset during pm init */ | ||
| 96 | am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, | ||
| 97 | ocmcram_location); | ||
| 98 | |||
| 99 | am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location, | ||
| 100 | pm_sram->do_wfi, | ||
| 101 | *pm_sram->do_wfi_sz); | ||
| 102 | if (!am33xx_do_wfi_sram) { | ||
| 103 | dev_err(pm33xx_dev, | ||
| 104 | "PM: %s: am33xx_do_wfi copy to sram failed\n", | ||
| 105 | __func__); | ||
| 106 | return -ENODEV; | ||
| 107 | } | ||
| 108 | |||
| 109 | table_addr = | ||
| 110 | sram_suspend_address((unsigned long)pm_sram->emif_sram_table); | ||
| 111 | ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr); | ||
| 112 | if (ret) { | ||
| 113 | dev_dbg(pm33xx_dev, | ||
| 114 | "PM: %s: EMIF function copy failed\n", __func__); | ||
| 115 | return -EPROBE_DEFER; | ||
| 116 | } | ||
| 117 | |||
| 118 | ro_data_addr = | ||
| 119 | sram_suspend_address((unsigned long)pm_sram->ro_sram_data); | ||
| 120 | copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr, | ||
| 121 | &ro_sram_data, | ||
| 122 | sizeof(ro_sram_data)); | ||
| 123 | if (!copy_addr) { | ||
| 124 | dev_err(pm33xx_dev, | ||
| 125 | "PM: %s: ro_sram_data copy to sram failed\n", | ||
| 126 | __func__); | ||
| 127 | return -ENODEV; | ||
| 128 | } | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int __init am43xx_map_gic(void) | ||
| 134 | { | ||
| 135 | gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K); | ||
| 136 | |||
| 137 | if (!gic_dist_base) | ||
| 138 | return -ENOMEM; | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 52 | #ifdef CONFIG_SUSPEND | 143 | #ifdef CONFIG_SUSPEND |
| 144 | struct wkup_m3_wakeup_src rtc_wake_src(void) | ||
| 145 | { | ||
| 146 | u32 i; | ||
| 147 | |||
| 148 | i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40; | ||
| 149 | |||
| 150 | if (i) { | ||
| 151 | retrigger_irq = rtc_alarm_wakeup.irq_nr; | ||
| 152 | return rtc_alarm_wakeup; | ||
| 153 | } | ||
| 154 | |||
| 155 | retrigger_irq = rtc_ext_wakeup.irq_nr; | ||
| 156 | |||
| 157 | return rtc_ext_wakeup; | ||
| 158 | } | ||
| 159 | |||
| 160 | int am33xx_rtc_only_idle(unsigned long wfi_flags) | ||
| 161 | { | ||
| 162 | omap_rtc_power_off_program(&omap_rtc->dev); | ||
| 163 | am33xx_do_wfi_sram(wfi_flags); | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 53 | static int am33xx_pm_suspend(suspend_state_t suspend_state) | 167 | static int am33xx_pm_suspend(suspend_state_t suspend_state) |
| 54 | { | 168 | { |
| 55 | int i, ret = 0; | 169 | int i, ret = 0; |
| 56 | 170 | ||
| 57 | ret = pm_ops->soc_suspend((unsigned long)suspend_state, | 171 | if (suspend_state == PM_SUSPEND_MEM && |
| 58 | am33xx_do_wfi_sram, suspend_wfi_flags); | 172 | pm_ops->check_off_mode_enable()) { |
| 173 | pm_ops->prepare_rtc_suspend(); | ||
| 174 | pm_ops->save_context(); | ||
| 175 | suspend_wfi_flags |= WFI_FLAG_RTC_ONLY; | ||
| 176 | clk_save_context(); | ||
| 177 | ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle, | ||
| 178 | suspend_wfi_flags); | ||
| 179 | |||
| 180 | suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY; | ||
| 181 | |||
| 182 | if (!ret) { | ||
| 183 | clk_restore_context(); | ||
| 184 | pm_ops->restore_context(); | ||
| 185 | m3_ipc->ops->set_rtc_only(m3_ipc); | ||
| 186 | am33xx_push_sram_idle(); | ||
| 187 | } | ||
| 188 | } else { | ||
| 189 | ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram, | ||
| 190 | suspend_wfi_flags); | ||
| 191 | } | ||
| 59 | 192 | ||
| 60 | if (ret) { | 193 | if (ret) { |
| 61 | dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); | 194 | dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); |
| @@ -77,8 +210,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) | |||
| 77 | "PM: CM3 returned unknown result = %d\n", i); | 210 | "PM: CM3 returned unknown result = %d\n", i); |
| 78 | ret = -1; | 211 | ret = -1; |
| 79 | } | 212 | } |
| 213 | |||
| 214 | /* print the wakeup reason */ | ||
| 215 | if (rtc_only_idle) { | ||
| 216 | wakeup_src = rtc_wake_src(); | ||
| 217 | pr_info("PM: Wakeup source %s\n", wakeup_src.src); | ||
| 218 | } else { | ||
| 219 | pr_info("PM: Wakeup source %s\n", | ||
| 220 | m3_ipc->ops->request_wake_src(m3_ipc)); | ||
| 221 | } | ||
| 80 | } | 222 | } |
| 81 | 223 | ||
| 224 | if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) | ||
| 225 | pm_ops->prepare_rtc_resume(); | ||
| 226 | |||
| 82 | return ret; | 227 | return ret; |
| 83 | } | 228 | } |
| 84 | 229 | ||
| @@ -101,6 +246,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state) | |||
| 101 | static int am33xx_pm_begin(suspend_state_t state) | 246 | static int am33xx_pm_begin(suspend_state_t state) |
| 102 | { | 247 | { |
| 103 | int ret = -EINVAL; | 248 | int ret = -EINVAL; |
| 249 | struct nvmem_device *nvmem; | ||
| 250 | |||
| 251 | if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) { | ||
| 252 | nvmem = devm_nvmem_device_get(&omap_rtc->dev, | ||
| 253 | "omap_rtc_scratch0"); | ||
| 254 | if (nvmem) | ||
| 255 | nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, | ||
| 256 | (void *)&rtc_magic_val); | ||
| 257 | rtc_only_idle = 1; | ||
| 258 | } else { | ||
| 259 | rtc_only_idle = 0; | ||
| 260 | } | ||
| 104 | 261 | ||
| 105 | switch (state) { | 262 | switch (state) { |
| 106 | case PM_SUSPEND_MEM: | 263 | case PM_SUSPEND_MEM: |
| @@ -116,7 +273,28 @@ static int am33xx_pm_begin(suspend_state_t state) | |||
| 116 | 273 | ||
| 117 | static void am33xx_pm_end(void) | 274 | static void am33xx_pm_end(void) |
| 118 | { | 275 | { |
| 276 | u32 val = 0; | ||
| 277 | struct nvmem_device *nvmem; | ||
| 278 | |||
| 279 | nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0"); | ||
| 119 | m3_ipc->ops->finish_low_power(m3_ipc); | 280 | m3_ipc->ops->finish_low_power(m3_ipc); |
| 281 | if (rtc_only_idle) { | ||
| 282 | if (retrigger_irq) | ||
| 283 | /* | ||
| 284 | * 32 bits of Interrupt Set-Pending correspond to 32 | ||
| 285 | * 32 interrupts. Compute the bit offset of the | ||
| 286 | * Interrupt and set that particular bit | ||
| 287 | * Compute the register offset by dividing interrupt | ||
| 288 | * number by 32 and mutiplying by 4 | ||
| 289 | */ | ||
| 290 | writel_relaxed(1 << (retrigger_irq & 31), | ||
| 291 | gic_dist_base + GIC_INT_SET_PENDING_BASE | ||
| 292 | + retrigger_irq / 32 * 4); | ||
| 293 | nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, | ||
| 294 | (void *)&val); | ||
| 295 | } | ||
| 296 | |||
| 297 | rtc_only_idle = 0; | ||
| 120 | } | 298 | } |
| 121 | 299 | ||
| 122 | static int am33xx_pm_valid(suspend_state_t state) | 300 | static int am33xx_pm_valid(suspend_state_t state) |
| @@ -219,51 +397,37 @@ mpu_put_node: | |||
| 219 | return ret; | 397 | return ret; |
| 220 | } | 398 | } |
| 221 | 399 | ||
| 222 | static int am33xx_push_sram_idle(void) | 400 | static int am33xx_pm_rtc_setup(void) |
| 223 | { | 401 | { |
| 224 | struct am33xx_pm_ro_sram_data ro_sram_data; | 402 | struct device_node *np; |
| 225 | int ret; | 403 | unsigned long val = 0; |
| 226 | u32 table_addr, ro_data_addr; | 404 | struct nvmem_device *nvmem; |
| 227 | void *copy_addr; | ||
| 228 | |||
| 229 | ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; | ||
| 230 | ro_sram_data.amx3_pm_sram_data_phys = | ||
| 231 | gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); | ||
| 232 | ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr(); | ||
| 233 | 405 | ||
| 234 | /* Save physical address to calculate resume offset during pm init */ | 406 | np = of_find_node_by_name(NULL, "rtc"); |
| 235 | am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, | ||
| 236 | ocmcram_location); | ||
| 237 | 407 | ||
| 238 | am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location, | 408 | if (of_device_is_available(np)) { |
| 239 | pm_sram->do_wfi, | 409 | omap_rtc = rtc_class_open("rtc0"); |
| 240 | *pm_sram->do_wfi_sz); | 410 | if (!omap_rtc) { |
| 241 | if (!am33xx_do_wfi_sram) { | 411 | pr_warn("PM: rtc0 not available"); |
| 242 | dev_err(pm33xx_dev, | 412 | return -EPROBE_DEFER; |
| 243 | "PM: %s: am33xx_do_wfi copy to sram failed\n", | 413 | } |
| 244 | __func__); | ||
| 245 | return -ENODEV; | ||
| 246 | } | ||
| 247 | |||
| 248 | table_addr = | ||
| 249 | sram_suspend_address((unsigned long)pm_sram->emif_sram_table); | ||
| 250 | ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr); | ||
| 251 | if (ret) { | ||
| 252 | dev_dbg(pm33xx_dev, | ||
| 253 | "PM: %s: EMIF function copy failed\n", __func__); | ||
| 254 | return -EPROBE_DEFER; | ||
| 255 | } | ||
| 256 | 414 | ||
| 257 | ro_data_addr = | 415 | nvmem = devm_nvmem_device_get(&omap_rtc->dev, |
| 258 | sram_suspend_address((unsigned long)pm_sram->ro_sram_data); | 416 | "omap_rtc_scratch0"); |
| 259 | copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr, | 417 | if (nvmem) { |
| 260 | &ro_sram_data, | 418 | nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4, |
| 261 | sizeof(ro_sram_data)); | 419 | 4, (void *)&rtc_magic_val); |
| 262 | if (!copy_addr) { | 420 | if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC) |
| 263 | dev_err(pm33xx_dev, | 421 | pr_warn("PM: bootloader does not support rtc-only!\n"); |
| 264 | "PM: %s: ro_sram_data copy to sram failed\n", | 422 | |
| 265 | __func__); | 423 | nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, |
| 266 | return -ENODEV; | 424 | 4, (void *)&val); |
| 425 | val = pm_sram->resume_address; | ||
| 426 | nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4, | ||
| 427 | 4, (void *)&val); | ||
| 428 | } | ||
| 429 | } else { | ||
| 430 | pr_warn("PM: no-rtc available, rtc-only mode disabled.\n"); | ||
| 267 | } | 431 | } |
| 268 | 432 | ||
| 269 | return 0; | 433 | return 0; |
| @@ -284,34 +448,42 @@ static int am33xx_pm_probe(struct platform_device *pdev) | |||
| 284 | return -ENODEV; | 448 | return -ENODEV; |
| 285 | } | 449 | } |
| 286 | 450 | ||
| 451 | ret = am43xx_map_gic(); | ||
| 452 | if (ret) { | ||
| 453 | pr_err("PM: Could not ioremap GIC base\n"); | ||
| 454 | return ret; | ||
| 455 | } | ||
| 456 | |||
| 287 | pm_sram = pm_ops->get_sram_addrs(); | 457 | pm_sram = pm_ops->get_sram_addrs(); |
| 288 | if (!pm_sram) { | 458 | if (!pm_sram) { |
| 289 | dev_err(dev, "PM: Cannot get PM asm function addresses!!\n"); | 459 | dev_err(dev, "PM: Cannot get PM asm function addresses!!\n"); |
| 290 | return -ENODEV; | 460 | return -ENODEV; |
| 291 | } | 461 | } |
| 292 | 462 | ||
| 463 | m3_ipc = wkup_m3_ipc_get(); | ||
| 464 | if (!m3_ipc) { | ||
| 465 | pr_err("PM: Cannot get wkup_m3_ipc handle\n"); | ||
| 466 | return -EPROBE_DEFER; | ||
| 467 | } | ||
| 468 | |||
| 293 | pm33xx_dev = dev; | 469 | pm33xx_dev = dev; |
| 294 | 470 | ||
| 295 | ret = am33xx_pm_alloc_sram(); | 471 | ret = am33xx_pm_alloc_sram(); |
| 296 | if (ret) | 472 | if (ret) |
| 297 | return ret; | 473 | return ret; |
| 298 | 474 | ||
| 299 | ret = am33xx_push_sram_idle(); | 475 | ret = am33xx_pm_rtc_setup(); |
| 300 | if (ret) | 476 | if (ret) |
| 301 | goto err_free_sram; | 477 | goto err_free_sram; |
| 302 | 478 | ||
| 303 | m3_ipc = wkup_m3_ipc_get(); | 479 | ret = am33xx_push_sram_idle(); |
| 304 | if (!m3_ipc) { | 480 | if (ret) |
| 305 | dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n"); | ||
| 306 | ret = -EPROBE_DEFER; | ||
| 307 | goto err_free_sram; | 481 | goto err_free_sram; |
| 308 | } | ||
| 309 | 482 | ||
| 310 | am33xx_pm_set_ipc_ops(); | 483 | am33xx_pm_set_ipc_ops(); |
| 311 | 484 | ||
| 312 | #ifdef CONFIG_SUSPEND | 485 | #ifdef CONFIG_SUSPEND |
| 313 | suspend_set_ops(&am33xx_pm_ops); | 486 | suspend_set_ops(&am33xx_pm_ops); |
| 314 | #endif /* CONFIG_SUSPEND */ | ||
| 315 | 487 | ||
| 316 | /* | 488 | /* |
| 317 | * For a system suspend we must flush the caches, we want | 489 | * For a system suspend we must flush the caches, we want |
| @@ -323,6 +495,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) | |||
| 323 | suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; | 495 | suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; |
| 324 | suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; | 496 | suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; |
| 325 | suspend_wfi_flags |= WFI_FLAG_WAKE_M3; | 497 | suspend_wfi_flags |= WFI_FLAG_WAKE_M3; |
| 498 | #endif /* CONFIG_SUSPEND */ | ||
| 326 | 499 | ||
| 327 | ret = pm_ops->init(); | 500 | ret = pm_ops->init(); |
| 328 | if (ret) { | 501 | if (ret) { |
diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c index 354d256e6e00..600f57cf0c2e 100644 --- a/drivers/soc/xilinx/zynqmp_pm_domains.c +++ b/drivers/soc/xilinx/zynqmp_pm_domains.c | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | /* Flag stating if PM nodes mapped to the PM domain has been requested */ | 23 | /* Flag stating if PM nodes mapped to the PM domain has been requested */ |
| 24 | #define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0) | 24 | #define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0) |
| 25 | 25 | ||
| 26 | static const struct zynqmp_eemi_ops *eemi_ops; | ||
| 27 | |||
| 26 | /** | 28 | /** |
| 27 | * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain | 29 | * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain |
| 28 | * @gpd: Generic power domain | 30 | * @gpd: Generic power domain |
| @@ -71,9 +73,8 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain) | |||
| 71 | { | 73 | { |
| 72 | int ret; | 74 | int ret; |
| 73 | struct zynqmp_pm_domain *pd; | 75 | struct zynqmp_pm_domain *pd; |
| 74 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 75 | 76 | ||
| 76 | if (!eemi_ops || !eemi_ops->set_requirement) | 77 | if (!eemi_ops->set_requirement) |
| 77 | return -ENXIO; | 78 | return -ENXIO; |
| 78 | 79 | ||
| 79 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); | 80 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); |
| @@ -107,9 +108,8 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) | |||
| 107 | struct zynqmp_pm_domain *pd; | 108 | struct zynqmp_pm_domain *pd; |
| 108 | u32 capabilities = 0; | 109 | u32 capabilities = 0; |
| 109 | bool may_wakeup; | 110 | bool may_wakeup; |
| 110 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 111 | 111 | ||
| 112 | if (!eemi_ops || !eemi_ops->set_requirement) | 112 | if (!eemi_ops->set_requirement) |
| 113 | return -ENXIO; | 113 | return -ENXIO; |
| 114 | 114 | ||
| 115 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); | 115 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); |
| @@ -160,9 +160,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain, | |||
| 160 | { | 160 | { |
| 161 | int ret; | 161 | int ret; |
| 162 | struct zynqmp_pm_domain *pd; | 162 | struct zynqmp_pm_domain *pd; |
| 163 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 164 | 163 | ||
| 165 | if (!eemi_ops || !eemi_ops->request_node) | 164 | if (!eemi_ops->request_node) |
| 166 | return -ENXIO; | 165 | return -ENXIO; |
| 167 | 166 | ||
| 168 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); | 167 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); |
| @@ -197,9 +196,8 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain, | |||
| 197 | { | 196 | { |
| 198 | int ret; | 197 | int ret; |
| 199 | struct zynqmp_pm_domain *pd; | 198 | struct zynqmp_pm_domain *pd; |
| 200 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 201 | 199 | ||
| 202 | if (!eemi_ops || !eemi_ops->release_node) | 200 | if (!eemi_ops->release_node) |
| 203 | return; | 201 | return; |
| 204 | 202 | ||
| 205 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); | 203 | pd = container_of(domain, struct zynqmp_pm_domain, gpd); |
| @@ -266,6 +264,10 @@ static int zynqmp_gpd_probe(struct platform_device *pdev) | |||
| 266 | struct zynqmp_pm_domain *pd; | 264 | struct zynqmp_pm_domain *pd; |
| 267 | struct device *dev = &pdev->dev; | 265 | struct device *dev = &pdev->dev; |
| 268 | 266 | ||
| 267 | eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 268 | if (IS_ERR(eemi_ops)) | ||
| 269 | return PTR_ERR(eemi_ops); | ||
| 270 | |||
| 269 | pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL); | 271 | pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL); |
| 270 | if (!pd) | 272 | if (!pd) |
| 271 | return -ENOMEM; | 273 | return -ENOMEM; |
diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 771cb59b9d22..1b9d14411a15 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c | |||
| @@ -31,6 +31,7 @@ static const char *const suspend_modes[] = { | |||
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD; | 33 | static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD; |
| 34 | static const struct zynqmp_eemi_ops *eemi_ops; | ||
| 34 | 35 | ||
| 35 | enum pm_api_cb_id { | 36 | enum pm_api_cb_id { |
| 36 | PM_INIT_SUSPEND_CB = 30, | 37 | PM_INIT_SUSPEND_CB = 30, |
| @@ -92,9 +93,8 @@ static ssize_t suspend_mode_store(struct device *dev, | |||
| 92 | const char *buf, size_t count) | 93 | const char *buf, size_t count) |
| 93 | { | 94 | { |
| 94 | int md, ret = -EINVAL; | 95 | int md, ret = -EINVAL; |
| 95 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 96 | 96 | ||
| 97 | if (!eemi_ops || !eemi_ops->set_suspend_mode) | 97 | if (!eemi_ops->set_suspend_mode) |
| 98 | return ret; | 98 | return ret; |
| 99 | 99 | ||
| 100 | for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++) | 100 | for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++) |
| @@ -120,9 +120,11 @@ static int zynqmp_pm_probe(struct platform_device *pdev) | |||
| 120 | int ret, irq; | 120 | int ret, irq; |
| 121 | u32 pm_api_version; | 121 | u32 pm_api_version; |
| 122 | 122 | ||
| 123 | const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); | 123 | eemi_ops = zynqmp_pm_get_eemi_ops(); |
| 124 | if (IS_ERR(eemi_ops)) | ||
| 125 | return PTR_ERR(eemi_ops); | ||
| 124 | 126 | ||
| 125 | if (!eemi_ops || !eemi_ops->get_api_version || !eemi_ops->init_finalize) | 127 | if (!eemi_ops->get_api_version || !eemi_ops->init_finalize) |
| 126 | return -ENXIO; | 128 | return -ENXIO; |
| 127 | 129 | ||
| 128 | eemi_ops->init_finalize(); | 130 | eemi_ops->init_finalize(); |
diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 9f83e1b17aa1..9850a0efe85a 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
| 15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
| 16 | #include <linux/dmaengine.h> | 16 | #include <linux/dmaengine.h> |
| 17 | #include <linux/firmware/xlnx-zynqmp.h> | ||
| 17 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
| 18 | #include <linux/io.h> | 19 | #include <linux/io.h> |
| 19 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| @@ -138,6 +139,7 @@ | |||
| 138 | 139 | ||
| 139 | #define SPI_AUTOSUSPEND_TIMEOUT 3000 | 140 | #define SPI_AUTOSUSPEND_TIMEOUT 3000 |
| 140 | enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; | 141 | enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; |
| 142 | static const struct zynqmp_eemi_ops *eemi_ops; | ||
| 141 | 143 | ||
| 142 | /** | 144 | /** |
| 143 | * struct zynqmp_qspi - Defines qspi driver instance | 145 | * struct zynqmp_qspi - Defines qspi driver instance |
| @@ -1021,6 +1023,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) | |||
| 1021 | struct resource *res; | 1023 | struct resource *res; |
| 1022 | struct device *dev = &pdev->dev; | 1024 | struct device *dev = &pdev->dev; |
| 1023 | 1025 | ||
| 1026 | eemi_ops = zynqmp_pm_get_eemi_ops(); | ||
| 1027 | if (IS_ERR(eemi_ops)) | ||
| 1028 | return PTR_ERR(eemi_ops); | ||
| 1029 | |||
| 1024 | master = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); | 1030 | master = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); |
| 1025 | if (!master) | 1031 | if (!master) |
| 1026 | return -ENOMEM; | 1032 | return -ENOMEM; |
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 0842b6e6af82..48963eab32f5 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c | |||
| @@ -419,9 +419,35 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn, | |||
| 419 | return true; | 419 | return true; |
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | static struct tee_shm_pool *optee_config_dyn_shm(void) | ||
| 423 | { | ||
| 424 | struct tee_shm_pool_mgr *priv_mgr; | ||
| 425 | struct tee_shm_pool_mgr *dmabuf_mgr; | ||
| 426 | void *rc; | ||
| 427 | |||
| 428 | rc = optee_shm_pool_alloc_pages(); | ||
| 429 | if (IS_ERR(rc)) | ||
| 430 | return rc; | ||
| 431 | priv_mgr = rc; | ||
| 432 | |||
| 433 | rc = optee_shm_pool_alloc_pages(); | ||
| 434 | if (IS_ERR(rc)) { | ||
| 435 | tee_shm_pool_mgr_destroy(priv_mgr); | ||
| 436 | return rc; | ||
| 437 | } | ||
| 438 | dmabuf_mgr = rc; | ||
| 439 | |||
| 440 | rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr); | ||
| 441 | if (IS_ERR(rc)) { | ||
| 442 | tee_shm_pool_mgr_destroy(priv_mgr); | ||
| 443 | tee_shm_pool_mgr_destroy(dmabuf_mgr); | ||
| 444 | } | ||
| 445 | |||
| 446 | return rc; | ||
| 447 | } | ||
| 448 | |||
| 422 | static struct tee_shm_pool * | 449 | static struct tee_shm_pool * |
| 423 | optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm, | 450 | optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm) |
| 424 | u32 sec_caps) | ||
| 425 | { | 451 | { |
| 426 | union { | 452 | union { |
| 427 | struct arm_smccc_res smccc; | 453 | struct arm_smccc_res smccc; |
| @@ -436,10 +462,11 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm, | |||
| 436 | struct tee_shm_pool_mgr *priv_mgr; | 462 | struct tee_shm_pool_mgr *priv_mgr; |
| 437 | struct tee_shm_pool_mgr *dmabuf_mgr; | 463 | struct tee_shm_pool_mgr *dmabuf_mgr; |
| 438 | void *rc; | 464 | void *rc; |
| 465 | const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; | ||
| 439 | 466 | ||
| 440 | invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc); | 467 | invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc); |
| 441 | if (res.result.status != OPTEE_SMC_RETURN_OK) { | 468 | if (res.result.status != OPTEE_SMC_RETURN_OK) { |
| 442 | pr_info("shm service not available\n"); | 469 | pr_err("static shm service not available\n"); |
| 443 | return ERR_PTR(-ENOENT); | 470 | return ERR_PTR(-ENOENT); |
| 444 | } | 471 | } |
| 445 | 472 | ||
| @@ -465,28 +492,15 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm, | |||
| 465 | } | 492 | } |
| 466 | vaddr = (unsigned long)va; | 493 | vaddr = (unsigned long)va; |
| 467 | 494 | ||
| 468 | /* | 495 | rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz, |
| 469 | * If OP-TEE can work with unregistered SHM, we will use own pool | 496 | 3 /* 8 bytes aligned */); |
| 470 | * for private shm | 497 | if (IS_ERR(rc)) |
| 471 | */ | 498 | goto err_memunmap; |
| 472 | if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) { | 499 | priv_mgr = rc; |
| 473 | rc = optee_shm_pool_alloc_pages(); | 500 | |
| 474 | if (IS_ERR(rc)) | 501 | vaddr += sz; |
| 475 | goto err_memunmap; | 502 | paddr += sz; |
| 476 | priv_mgr = rc; | 503 | size -= sz; |
| 477 | } else { | ||
| 478 | const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; | ||
| 479 | |||
| 480 | rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz, | ||
| 481 | 3 /* 8 bytes aligned */); | ||
| 482 | if (IS_ERR(rc)) | ||
| 483 | goto err_memunmap; | ||
| 484 | priv_mgr = rc; | ||
| 485 | |||
| 486 | vaddr += sz; | ||
| 487 | paddr += sz; | ||
| 488 | size -= sz; | ||
| 489 | } | ||
| 490 | 504 | ||
| 491 | rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT); | 505 | rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT); |
| 492 | if (IS_ERR(rc)) | 506 | if (IS_ERR(rc)) |
| @@ -552,7 +566,7 @@ static optee_invoke_fn *get_invoke_func(struct device_node *np) | |||
| 552 | static struct optee *optee_probe(struct device_node *np) | 566 | static struct optee *optee_probe(struct device_node *np) |
| 553 | { | 567 | { |
| 554 | optee_invoke_fn *invoke_fn; | 568 | optee_invoke_fn *invoke_fn; |
| 555 | struct tee_shm_pool *pool; | 569 | struct tee_shm_pool *pool = ERR_PTR(-EINVAL); |
| 556 | struct optee *optee = NULL; | 570 | struct optee *optee = NULL; |
| 557 | void *memremaped_shm = NULL; | 571 | void *memremaped_shm = NULL; |
| 558 | struct tee_device *teedev; | 572 | struct tee_device *teedev; |
| @@ -581,13 +595,17 @@ static struct optee *optee_probe(struct device_node *np) | |||
| 581 | } | 595 | } |
| 582 | 596 | ||
| 583 | /* | 597 | /* |
| 584 | * We have no other option for shared memory, if secure world | 598 | * Try to use dynamic shared memory if possible |
| 585 | * doesn't have any reserved memory we can use we can't continue. | ||
| 586 | */ | 599 | */ |
| 587 | if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) | 600 | if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) |
| 588 | return ERR_PTR(-EINVAL); | 601 | pool = optee_config_dyn_shm(); |
| 602 | |||
| 603 | /* | ||
| 604 | * If dynamic shared memory is not available or failed - try static one | ||
| 605 | */ | ||
| 606 | if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) | ||
| 607 | pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm); | ||
| 589 | 608 | ||
| 590 | pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps); | ||
| 591 | if (IS_ERR(pool)) | 609 | if (IS_ERR(pool)) |
| 592 | return (void *)pool; | 610 | return (void *)pool; |
| 593 | 611 | ||
diff --git a/include/linux/firmware/imx/sci.h b/include/linux/firmware/imx/sci.h index ebc55098faee..17ba4e405129 100644 --- a/include/linux/firmware/imx/sci.h +++ b/include/linux/firmware/imx/sci.h | |||
| @@ -15,4 +15,9 @@ | |||
| 15 | 15 | ||
| 16 | #include <linux/firmware/imx/svc/misc.h> | 16 | #include <linux/firmware/imx/svc/misc.h> |
| 17 | #include <linux/firmware/imx/svc/pm.h> | 17 | #include <linux/firmware/imx/svc/pm.h> |
| 18 | |||
| 19 | int imx_scu_enable_general_irq_channel(struct device *dev); | ||
| 20 | int imx_scu_irq_register_notifier(struct notifier_block *nb); | ||
| 21 | int imx_scu_irq_unregister_notifier(struct notifier_block *nb); | ||
| 22 | int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable); | ||
| 18 | #endif /* _SC_SCI_H */ | 23 | #endif /* _SC_SCI_H */ |
diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 642dab10f65d..1262ea6a1f4b 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h | |||
| @@ -48,6 +48,14 @@ | |||
| 48 | #define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U | 48 | #define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U |
| 49 | #define ZYNQMP_PM_CAPABILITY_POWER 0x8U | 49 | #define ZYNQMP_PM_CAPABILITY_POWER 0x8U |
| 50 | 50 | ||
| 51 | /* | ||
| 52 | * Firmware FPGA Manager flags | ||
| 53 | * XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration | ||
| 54 | * XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration | ||
| 55 | */ | ||
| 56 | #define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U | ||
| 57 | #define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0) | ||
| 58 | |||
| 51 | enum pm_api_id { | 59 | enum pm_api_id { |
| 52 | PM_GET_API_VERSION = 1, | 60 | PM_GET_API_VERSION = 1, |
| 53 | PM_REQUEST_NODE = 13, | 61 | PM_REQUEST_NODE = 13, |
| @@ -56,6 +64,8 @@ enum pm_api_id { | |||
| 56 | PM_RESET_ASSERT = 17, | 64 | PM_RESET_ASSERT = 17, |
| 57 | PM_RESET_GET_STATUS, | 65 | PM_RESET_GET_STATUS, |
| 58 | PM_PM_INIT_FINALIZE = 21, | 66 | PM_PM_INIT_FINALIZE = 21, |
| 67 | PM_FPGA_LOAD, | ||
| 68 | PM_FPGA_GET_STATUS, | ||
| 59 | PM_GET_CHIPID = 24, | 69 | PM_GET_CHIPID = 24, |
| 60 | PM_IOCTL = 34, | 70 | PM_IOCTL = 34, |
| 61 | PM_QUERY_DATA, | 71 | PM_QUERY_DATA, |
| @@ -258,6 +268,8 @@ struct zynqmp_pm_query_data { | |||
| 258 | struct zynqmp_eemi_ops { | 268 | struct zynqmp_eemi_ops { |
| 259 | int (*get_api_version)(u32 *version); | 269 | int (*get_api_version)(u32 *version); |
| 260 | int (*get_chipid)(u32 *idcode, u32 *version); | 270 | int (*get_chipid)(u32 *idcode, u32 *version); |
| 271 | int (*fpga_load)(const u64 address, const u32 size, const u32 flags); | ||
| 272 | int (*fpga_get_status)(u32 *value); | ||
| 261 | int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out); | 273 | int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out); |
| 262 | int (*clock_enable)(u32 clock_id); | 274 | int (*clock_enable)(u32 clock_id); |
| 263 | int (*clock_disable)(u32 clock_id); | 275 | int (*clock_disable)(u32 clock_id); |
| @@ -293,7 +305,7 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void); | |||
| 293 | #else | 305 | #else |
| 294 | static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) | 306 | static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) |
| 295 | { | 307 | { |
| 296 | return NULL; | 308 | return ERR_PTR(-ENODEV); |
| 297 | } | 309 | } |
| 298 | #endif | 310 | #endif |
| 299 | 311 | ||
diff --git a/include/linux/platform_data/pm33xx.h b/include/linux/platform_data/pm33xx.h index fbf5ed73c7cc..dd5971937a64 100644 --- a/include/linux/platform_data/pm33xx.h +++ b/include/linux/platform_data/pm33xx.h | |||
| @@ -51,6 +51,11 @@ struct am33xx_pm_platform_data { | |||
| 51 | unsigned long args); | 51 | unsigned long args); |
| 52 | struct am33xx_pm_sram_addr *(*get_sram_addrs)(void); | 52 | struct am33xx_pm_sram_addr *(*get_sram_addrs)(void); |
| 53 | void __iomem *(*get_rtc_base_addr)(void); | 53 | void __iomem *(*get_rtc_base_addr)(void); |
| 54 | void (*save_context)(void); | ||
| 55 | void (*restore_context)(void); | ||
| 56 | void (*prepare_rtc_suspend)(void); | ||
| 57 | void (*prepare_rtc_resume)(void); | ||
| 58 | int (*check_off_mode_enable)(void); | ||
| 54 | }; | 59 | }; |
| 55 | 60 | ||
| 56 | struct am33xx_pm_sram_data { | 61 | struct am33xx_pm_sram_data { |
diff --git a/include/linux/reset.h b/include/linux/reset.h index 95d555c2130a..e7793fc0fa93 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | #ifndef _LINUX_RESET_H_ | 2 | #ifndef _LINUX_RESET_H_ |
| 3 | #define _LINUX_RESET_H_ | 3 | #define _LINUX_RESET_H_ |
| 4 | 4 | ||
| 5 | #include <linux/err.h> | ||
| 6 | #include <linux/errno.h> | ||
| 5 | #include <linux/types.h> | 7 | #include <linux/types.h> |
| 6 | 8 | ||
| 7 | struct device; | 9 | struct device; |
diff --git a/include/linux/rtc/rtc-omap.h b/include/linux/rtc/rtc-omap.h new file mode 100644 index 000000000000..9f03a329e63f --- /dev/null +++ b/include/linux/rtc/rtc-omap.h | |||
| @@ -0,0 +1,7 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | |||
| 3 | #ifndef _LINUX_RTCOMAP_H_ | ||
| 4 | #define _LINUX_RTCOMAP_H_ | ||
| 5 | |||
| 6 | int omap_rtc_power_off_program(struct device *dev); | ||
| 7 | #endif /* _LINUX_RTCOMAP_H_ */ | ||
diff --git a/include/linux/ti-emif-sram.h b/include/linux/ti-emif-sram.h index 53604b087f2c..2fc854155c27 100644 --- a/include/linux/ti-emif-sram.h +++ b/include/linux/ti-emif-sram.h | |||
| @@ -55,6 +55,7 @@ struct ti_emif_pm_data { | |||
| 55 | struct ti_emif_pm_functions { | 55 | struct ti_emif_pm_functions { |
| 56 | u32 save_context; | 56 | u32 save_context; |
| 57 | u32 restore_context; | 57 | u32 restore_context; |
| 58 | u32 run_hw_leveling; | ||
| 58 | u32 enter_sr; | 59 | u32 enter_sr; |
| 59 | u32 exit_sr; | 60 | u32 exit_sr; |
| 60 | u32 abort_sr; | 61 | u32 abort_sr; |
| @@ -126,6 +127,8 @@ static inline void ti_emif_asm_offsets(void) | |||
| 126 | offsetof(struct ti_emif_pm_functions, save_context)); | 127 | offsetof(struct ti_emif_pm_functions, save_context)); |
| 127 | DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET, | 128 | DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET, |
| 128 | offsetof(struct ti_emif_pm_functions, restore_context)); | 129 | offsetof(struct ti_emif_pm_functions, restore_context)); |
| 130 | DEFINE(EMIF_PM_RUN_HW_LEVELING, | ||
| 131 | offsetof(struct ti_emif_pm_functions, run_hw_leveling)); | ||
| 129 | DEFINE(EMIF_PM_ENTER_SR_OFFSET, | 132 | DEFINE(EMIF_PM_ENTER_SR_OFFSET, |
| 130 | offsetof(struct ti_emif_pm_functions, enter_sr)); | 133 | offsetof(struct ti_emif_pm_functions, enter_sr)); |
| 131 | DEFINE(EMIF_PM_EXIT_SR_OFFSET, | 134 | DEFINE(EMIF_PM_EXIT_SR_OFFSET, |
