Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 May 2019 16:19:14 +0000 (09:19 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 May 2019 16:19:14 +0000 (09:19 -0700)
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:
Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt [new file with mode: 0644]
Documentation/devicetree/bindings/soc/mediatek/pwrap.txt
Documentation/xilinx/eemi.txt
MAINTAINERS
arch/arm/mach-omap2/pm33xx-core.c
arch/arm/mach-omap2/sleep43xx.S
arch/arm/mach-tegra/Kconfig
arch/arm/mach-tegra/cpuidle-tegra20.c
arch/arm/mach-tegra/cpuidle-tegra30.c
arch/arm/mach-tegra/iomap.h
arch/arm/mach-tegra/sleep-tegra30.S
drivers/bus/tegra-aconnect.c
drivers/clk/zynqmp/clkc.c
drivers/firmware/arm_scmi/driver.c
drivers/firmware/imx/Makefile
drivers/firmware/imx/imx-scu-irq.c [new file with mode: 0644]
drivers/firmware/imx/imx-scu.c
drivers/firmware/imx/scu-pd.c
drivers/firmware/xilinx/zynqmp-debug.c
drivers/firmware/xilinx/zynqmp.c
drivers/fpga/Kconfig
drivers/fpga/Makefile
drivers/fpga/zynqmp-fpga.c [new file with mode: 0644]
drivers/memory/emif.h
drivers/memory/tegra/mc.c
drivers/memory/tegra/mc.h
drivers/memory/tegra/tegra114.c
drivers/memory/tegra/tegra124.c
drivers/memory/tegra/tegra20.c
drivers/memory/tegra/tegra210.c
drivers/memory/tegra/tegra30.c
drivers/memory/ti-emif-pm.c
drivers/memory/ti-emif-sram-pm.S
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/nvmem/zynqmp_nvmem.c
drivers/reset/reset-zynqmp.c
drivers/rtc/rtc-omap.c
drivers/soc/Kconfig
drivers/soc/Makefile
drivers/soc/amlogic/meson-gx-pwrc-vpu.c
drivers/soc/amlogic/meson-gx-socinfo.c
drivers/soc/aspeed/Kconfig [new file with mode: 0644]
drivers/soc/aspeed/Makefile [new file with mode: 0644]
drivers/soc/aspeed/aspeed-lpc-ctrl.c [moved from drivers/misc/aspeed-lpc-ctrl.c with 100% similarity]
drivers/soc/aspeed/aspeed-lpc-snoop.c [moved from drivers/misc/aspeed-lpc-snoop.c with 100% similarity]
drivers/soc/aspeed/aspeed-p2a-ctrl.c [moved from drivers/misc/aspeed-p2a-ctrl.c with 100% similarity]
drivers/soc/imx/Makefile
drivers/soc/imx/gpc.c
drivers/soc/imx/gpcv2.c
drivers/soc/imx/soc-imx8.c [new file with mode: 0644]
drivers/soc/mediatek/mtk-pmic-wrap.c
drivers/soc/qcom/cmd-db.c
drivers/soc/qcom/qmi_interface.c
drivers/soc/qcom/rmtfs_mem.c
drivers/soc/qcom/rpmh-rsc.c
drivers/soc/renesas/renesas-soc.c
drivers/soc/rockchip/grf.c
drivers/soc/tegra/pmc.c
drivers/soc/ti/Kconfig
drivers/soc/ti/pm33xx.c
drivers/soc/xilinx/zynqmp_pm_domains.c
drivers/soc/xilinx/zynqmp_power.c
drivers/spi/spi-zynqmp-gqspi.c
drivers/tee/optee/core.c
include/linux/firmware/imx/sci.h
include/linux/firmware/xlnx-zynqmp.h
include/linux/platform_data/pm33xx.h
include/linux/reset.h
include/linux/rtc/rtc-omap.h [new file with mode: 0644]
include/linux/ti-emif-sram.h

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 (file)
index 0000000..3052bf6
--- /dev/null
@@ -0,0 +1,25 @@
+Devicetree bindings for Zynq Ultrascale MPSoC FPGA Manager.
+The ZynqMP SoC uses the PCAP (Processor configuration Port) to configure the
+Programmable Logic (PL). The configuration uses  the firmware interface.
+
+Required properties:
+- compatible: should contain "xlnx,zynqmp-pcap-fpga"
+
+Example for full FPGA configuration:
+
+       fpga-region0 {
+               compatible = "fpga-region";
+               fpga-mgr = <&zynqmp_pcap>;
+               #address-cells = <0x1>;
+               #size-cells = <0x1>;
+       };
+
+       firmware {
+               zynqmp_firmware: zynqmp-firmware {
+                       compatible = "xlnx,zynqmp-firmware";
+                       method = "smc";
+                       zynqmp_pcap: pcap {
+                               compatible = "xlnx,zynqmp-pcap-fpga";
+                       };
+               };
+       };
index 5a2ef17..7a32404 100644 (file)
@@ -25,6 +25,7 @@ Required properties in pwrap device node.
        "mediatek,mt8135-pwrap" for MT8135 SoCs
        "mediatek,mt8173-pwrap" for MT8173 SoCs
        "mediatek,mt8183-pwrap" for MT8183 SoCs
+       "mediatek,mt8516-pwrap" for MT8516 SoCs
 - interrupts: IRQ for pwrap in SOC
 - reg-names: Must include the following entries:
   "pwrap": Main registers base
index 0ab686c..5f39b4f 100644 (file)
@@ -41,8 +41,8 @@ Example of EEMI ops usage:
        int ret;
 
        eemi_ops = zynqmp_pm_get_eemi_ops();
-       if (!eemi_ops)
-               return -ENXIO;
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
 
        ret = eemi_ops->query_data(qdata, ret_payload);
 
index 5254b35..005902e 100644 (file)
@@ -2043,7 +2043,7 @@ W:        http://www.armlinux.org.uk/
 S:     Maintained
 
 ARM/QUALCOMM SUPPORT
-M:     Andy Gross <andy.gross@linaro.org>
+M:     Andy Gross <agross@kernel.org>
 M:     David Brown <david.brown@linaro.org>
 L:     linux-arm-msm@vger.kernel.org
 S:     Maintained
index c93b6ef..f11442e 100644 (file)
 #include <asm/suspend.h>
 #include <linux/errno.h>
 #include <linux/platform_data/pm33xx.h>
+#include <linux/clk.h>
+#include <linux/platform_data/gpio-omap.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/wkup_m3_ipc.h>
+#include <linux/of.h>
+#include <linux/rtc.h>
 
 #include "cm33xx.h"
 #include "common.h"
@@ -38,6 +44,29 @@ static int am43xx_map_scu(void)
        return 0;
 }
 
+static int am33xx_check_off_mode_enable(void)
+{
+       if (enable_off_mode)
+               pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
+
+       /* off mode not supported on am335x so return 0 always */
+       return 0;
+}
+
+static int am43xx_check_off_mode_enable(void)
+{
+       /*
+        * Check for am437x-gp-evm which has the right Hardware design to
+        * support this mode reliably.
+        */
+       if (of_machine_is_compatible("ti,am437x-gp-evm") && enable_off_mode)
+               return enable_off_mode;
+       else if (enable_off_mode)
+               pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n");
+
+       return 0;
+}
+
 static int amx3_common_init(void)
 {
        gfx_pwrdm = pwrdm_lookup("gfx_pwrdm");
@@ -141,7 +170,9 @@ static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long),
        scu_power_mode(scu_base, SCU_PM_POWEROFF);
        ret = cpu_suspend(args, fn);
        scu_power_mode(scu_base, SCU_PM_NORMAL);
-       amx3_post_suspend_common();
+
+       if (!am43xx_check_off_mode_enable())
+               amx3_post_suspend_common();
 
        return ret;
 }
@@ -163,10 +194,48 @@ void __iomem *am43xx_get_rtc_base_addr(void)
        return omap_hwmod_get_mpu_rt_va(rtc_oh);
 }
 
+static void am43xx_save_context(void)
+{
+}
+
+static void am33xx_save_context(void)
+{
+       omap_intc_save_context();
+}
+
+static void am33xx_restore_context(void)
+{
+       omap_intc_restore_context();
+}
+
+static void am43xx_restore_context(void)
+{
+       /*
+        * HACK: restore dpll_per_clkdcoldo register contents, to avoid
+        * breaking suspend-resume
+        */
+       writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14));
+}
+
+static void am43xx_prepare_rtc_suspend(void)
+{
+       omap_hwmod_enable(rtc_oh);
+}
+
+static void am43xx_prepare_rtc_resume(void)
+{
+       omap_hwmod_idle(rtc_oh);
+}
+
 static struct am33xx_pm_platform_data am33xx_ops = {
        .init = am33xx_suspend_init,
        .soc_suspend = am33xx_suspend,
        .get_sram_addrs = amx3_get_sram_addrs,
+       .save_context = am33xx_save_context,
+       .restore_context = am33xx_restore_context,
+       .prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
+       .prepare_rtc_resume = am43xx_prepare_rtc_resume,
+       .check_off_mode_enable = am33xx_check_off_mode_enable,
        .get_rtc_base_addr = am43xx_get_rtc_base_addr,
 };
 
@@ -174,6 +243,11 @@ static struct am33xx_pm_platform_data am43xx_ops = {
        .init = am43xx_suspend_init,
        .soc_suspend = am43xx_suspend,
        .get_sram_addrs = amx3_get_sram_addrs,
+       .save_context = am43xx_save_context,
+       .restore_context = am43xx_restore_context,
+       .prepare_rtc_suspend = am43xx_prepare_rtc_suspend,
+       .prepare_rtc_resume = am43xx_prepare_rtc_resume,
+       .check_off_mode_enable = am43xx_check_off_mode_enable,
        .get_rtc_base_addr = am43xx_get_rtc_base_addr,
 };
 
index 5b9343b..0c10314 100644 (file)
@@ -368,6 +368,9 @@ wait_emif_enable1:
        mov     r1, #AM43XX_EMIF_POWEROFF_DISABLE
        str     r1, [r2, #0x0]
 
+       ldr     r1, [r9, #EMIF_PM_RUN_HW_LEVELING]
+       blx     r1
+
 #ifdef CONFIG_CACHE_L2X0
        ldr     r2, l2_cache_base
        ldr     r0, [r2, #L2X0_CTRL]
index 63e89e7..3a06ba2 100644 (file)
@@ -10,6 +10,7 @@ menuconfig ARCH_TEGRA
        select HAVE_ARM_SCU if SMP
        select HAVE_ARM_TWD if SMP
        select PINCTRL
+       select PM
        select PM_OPP
        select RESET_CONTROLLER
        select SOC_BUS
index 3f24add..6620d61 100644 (file)
@@ -61,7 +61,8 @@ static struct cpuidle_driver tegra_idle_driver = {
                        .exit_latency     = 5000,
                        .target_residency = 10000,
                        .power_usage      = 0,
-                       .flags            = CPUIDLE_FLAG_COUPLED,
+                       .flags            = CPUIDLE_FLAG_COUPLED |
+                                           CPUIDLE_FLAG_TIMER_STOP,
                        .name             = "powered-down",
                        .desc             = "CPU power gated",
                },
@@ -136,12 +137,8 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev,
        if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready())
                return false;
 
-       tick_broadcast_enter();
-
        tegra_idle_lp2_last();
 
-       tick_broadcast_exit();
-
        if (cpu_online(1))
                tegra20_wake_cpu1_from_reset();
 
@@ -153,14 +150,10 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev,
                                         struct cpuidle_driver *drv,
                                         int index)
 {
-       tick_broadcast_enter();
-
        cpu_suspend(0, tegra20_sleep_cpu_secondary_finish);
 
        tegra20_cpu_clear_resettable();
 
-       tick_broadcast_exit();
-
        return true;
 }
 #else
index c141736..c8fe044 100644 (file)
@@ -56,6 +56,7 @@ static struct cpuidle_driver tegra_idle_driver = {
                        .exit_latency           = 2000,
                        .target_residency       = 2200,
                        .power_usage            = 0,
+                       .flags                  = CPUIDLE_FLAG_TIMER_STOP,
                        .name                   = "powered-down",
                        .desc                   = "CPU power gated",
                },
@@ -76,12 +77,8 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev,
                return false;
        }
 
-       tick_broadcast_enter();
-
        tegra_idle_lp2_last();
 
-       tick_broadcast_exit();
-
        return true;
 }
 
@@ -90,14 +87,10 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev,
                                        struct cpuidle_driver *drv,
                                        int index)
 {
-       tick_broadcast_enter();
-
        smp_wmb();
 
        cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
 
-       tick_broadcast_exit();
-
        return true;
 }
 #else
index 4af9e92..ba61db7 100644 (file)
 #define TEGRA_PMC_BASE                 0x7000E400
 #define TEGRA_PMC_SIZE                 SZ_256
 
-#define TEGRA_MC_BASE                  0x7000F000
-#define TEGRA_MC_SIZE                  SZ_1K
-
 #define TEGRA_EMC_BASE                 0x7000F400
 #define TEGRA_EMC_SIZE                 SZ_1K
 
-#define TEGRA114_MC_BASE               0x70019000
-#define TEGRA114_MC_SIZE               SZ_4K
-
 #define TEGRA_EMC0_BASE                        0x7001A000
 #define TEGRA_EMC0_SIZE                        SZ_2K
 
 #define TEGRA_EMC1_BASE                        0x7001A800
 #define TEGRA_EMC1_SIZE                        SZ_2K
 
-#define TEGRA124_MC_BASE               0x70019000
-#define TEGRA124_MC_SIZE               SZ_4K
-
 #define TEGRA124_EMC_BASE              0x7001B000
 #define TEGRA124_EMC_SIZE              SZ_2K
 
index d0b4c48..7727e00 100644 (file)
@@ -44,8 +44,6 @@
 #define EMC_XM2VTTGENPADCTRL           0x310
 #define EMC_XM2VTTGENPADCTRL2          0x314
 
-#define MC_EMEM_ARB_CFG                        0x90
-
 #define PMC_CTRL                       0x0
 #define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */
 
@@ -420,22 +418,6 @@ _pll_m_c_x_done:
        movweq  r0, #:lower16:TEGRA124_EMC_BASE
        movteq  r0, #:upper16:TEGRA124_EMC_BASE
 
-       cmp     r10, #TEGRA30
-       moveq   r2, #0x20
-       movweq  r4, #:lower16:TEGRA_MC_BASE
-       movteq  r4, #:upper16:TEGRA_MC_BASE
-       cmp     r10, #TEGRA114
-       moveq   r2, #0x34
-       movweq  r4, #:lower16:TEGRA114_MC_BASE
-       movteq  r4, #:upper16:TEGRA114_MC_BASE
-       cmp     r10, #TEGRA124
-       moveq   r2, #0x20
-       movweq  r4, #:lower16:TEGRA124_MC_BASE
-       movteq  r4, #:upper16:TEGRA124_MC_BASE
-
-       ldr     r1, [r5, r2]            @ restore MC_EMEM_ARB_CFG
-       str     r1, [r4, #MC_EMEM_ARB_CFG]
-
 exit_self_refresh:
        ldr     r1, [r5, #0xC]          @ restore EMC_XM2VTTGENPADCTRL
        str     r1, [r0, #EMC_XM2VTTGENPADCTRL]
@@ -564,7 +546,6 @@ tegra30_sdram_pad_address:
        .word   TEGRA_PMC_BASE + PMC_IO_DPD_STATUS                      @0x14
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT     @0x18
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST             @0x1c
-       .word   TEGRA_MC_BASE + MC_EMEM_ARB_CFG                         @0x20
 tegra30_sdram_pad_address_end:
 
 tegra114_sdram_pad_address:
@@ -581,7 +562,6 @@ tegra114_sdram_pad_address:
        .word   TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL                 @0x28
        .word   TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL                  @0x2c
        .word   TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2                 @0x30
-       .word   TEGRA114_MC_BASE + MC_EMEM_ARB_CFG                      @0x34
 tegra114_sdram_pad_adress_end:
 
 tegra124_sdram_pad_address:
@@ -593,7 +573,6 @@ tegra124_sdram_pad_address:
        .word   TEGRA_PMC_BASE + PMC_IO_DPD_STATUS                      @0x14
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT     @0x18
        .word   TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST             @0x1c
-       .word   TEGRA124_MC_BASE + MC_EMEM_ARB_CFG                      @0x20
 tegra124_sdram_pad_address_end:
 
 tegra30_sdram_pad_size:
index 084ae28..ac58142 100644 (file)
 #include <linux/module.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
-#include <linux/pm_clock.h>
 #include <linux/pm_runtime.h>
 
+struct tegra_aconnect {
+       struct clk      *ape_clk;
+       struct clk      *apb2ape_clk;
+};
+
 static int tegra_aconnect_probe(struct platform_device *pdev)
 {
-       int ret;
+       struct tegra_aconnect *aconnect;
 
        if (!pdev->dev.of_node)
                return -EINVAL;
 
-       ret = pm_clk_create(&pdev->dev);
-       if (ret)
-               return ret;
+       aconnect = devm_kzalloc(&pdev->dev, sizeof(struct tegra_aconnect),
+                               GFP_KERNEL);
+       if (!aconnect)
+               return -ENOMEM;
 
-       ret = of_pm_clk_add_clk(&pdev->dev, "ape");
-       if (ret)
-               goto clk_destroy;
+       aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape");
+       if (IS_ERR(aconnect->ape_clk)) {
+               dev_err(&pdev->dev, "Can't retrieve ape clock\n");
+               return PTR_ERR(aconnect->ape_clk);
+       }
 
-       ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape");
-       if (ret)
-               goto clk_destroy;
+       aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape");
+       if (IS_ERR(aconnect->apb2ape_clk)) {
+               dev_err(&pdev->dev, "Can't retrieve apb2ape clock\n");
+               return PTR_ERR(aconnect->apb2ape_clk);
+       }
 
+       dev_set_drvdata(&pdev->dev, aconnect);
        pm_runtime_enable(&pdev->dev);
 
        of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
@@ -41,35 +51,51 @@ static int tegra_aconnect_probe(struct platform_device *pdev)
        dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n");
 
        return 0;
-
-clk_destroy:
-       pm_clk_destroy(&pdev->dev);
-
-       return ret;
 }
 
 static int tegra_aconnect_remove(struct platform_device *pdev)
 {
        pm_runtime_disable(&pdev->dev);
 
-       pm_clk_destroy(&pdev->dev);
-
        return 0;
 }
 
 static int tegra_aconnect_runtime_resume(struct device *dev)
 {
-       return pm_clk_resume(dev);
+       struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
+       int ret;
+
+       ret = clk_prepare_enable(aconnect->ape_clk);
+       if (ret) {
+               dev_err(dev, "ape clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(aconnect->apb2ape_clk);
+       if (ret) {
+               clk_disable_unprepare(aconnect->ape_clk);
+               dev_err(dev, "apb2ape clk_enable failed: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
 }
 
 static int tegra_aconnect_runtime_suspend(struct device *dev)
 {
-       return pm_clk_suspend(dev);
+       struct tegra_aconnect *aconnect = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(aconnect->ape_clk);
+       clk_disable_unprepare(aconnect->apb2ape_clk);
+
+       return 0;
 }
 
 static const struct dev_pm_ops tegra_aconnect_pm_ops = {
        SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend,
                           tegra_aconnect_runtime_resume, NULL)
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                                     pm_runtime_force_resume)
 };
 
 static const struct of_device_id tegra_aconnect_of_match[] = {
index 8febd24..a11f93e 100644 (file)
@@ -739,8 +739,8 @@ static int zynqmp_clock_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
 
        eemi_ops = zynqmp_pm_get_eemi_ops();
-       if (!eemi_ops)
-               return -ENXIO;
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
 
        ret = zynqmp_clk_setup(dev->of_node);
 
index 8f952f2..b5bc4c7 100644 (file)
@@ -654,9 +654,7 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo)
 
 static int scmi_mailbox_check(struct device_node *np)
 {
-       struct of_phandle_args arg;
-
-       return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg);
+       return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, NULL);
 }
 
 static int scmi_mbox_free_channel(int id, void *p, void *data)
@@ -798,7 +796,9 @@ static int scmi_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       desc = of_match_device(scmi_of_match, dev)->data;
+       desc = of_device_get_match_data(dev);
+       if (!desc)
+               return -EINVAL;
 
        info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL);
        if (!info)
index 1b2e15b..802c4ad 100644 (file)
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_IMX_SCU)          += imx-scu.o misc.o
+obj-$(CONFIG_IMX_SCU)          += imx-scu.o misc.o imx-scu-irq.o
 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 (file)
index 0000000..043833a
--- /dev/null
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019 NXP
+ *
+ * Implementation of the SCU IRQ functions using MU.
+ *
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/firmware/imx/ipc.h>
+#include <linux/mailbox_client.h>
+
+#define IMX_SC_IRQ_FUNC_ENABLE 1
+#define IMX_SC_IRQ_FUNC_STATUS 2
+#define IMX_SC_IRQ_NUM_GROUP   4
+
+static u32 mu_resource_id;
+
+struct imx_sc_msg_irq_get_status {
+       struct imx_sc_rpc_msg hdr;
+       union {
+               struct {
+                       u16 resource;
+                       u8 group;
+                       u8 reserved;
+               } __packed req;
+               struct {
+                       u32 status;
+               } resp;
+       } data;
+};
+
+struct imx_sc_msg_irq_enable {
+       struct imx_sc_rpc_msg hdr;
+       u32 mask;
+       u16 resource;
+       u8 group;
+       u8 enable;
+} __packed;
+
+static struct imx_sc_ipc *imx_sc_irq_ipc_handle;
+static struct work_struct imx_sc_irq_work;
+static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain);
+
+int imx_scu_irq_register_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_register(
+               &imx_scu_irq_notifier_chain, nb);
+}
+EXPORT_SYMBOL(imx_scu_irq_register_notifier);
+
+int imx_scu_irq_unregister_notifier(struct notifier_block *nb)
+{
+       return atomic_notifier_chain_unregister(
+               &imx_scu_irq_notifier_chain, nb);
+}
+EXPORT_SYMBOL(imx_scu_irq_unregister_notifier);
+
+static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group)
+{
+       return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain,
+               status, (void *)group);
+}
+
+static void imx_scu_irq_work_handler(struct work_struct *work)
+{
+       struct imx_sc_msg_irq_get_status msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       u32 irq_status;
+       int ret;
+       u8 i;
+
+       for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) {
+               hdr->ver = IMX_SC_RPC_VERSION;
+               hdr->svc = IMX_SC_RPC_SVC_IRQ;
+               hdr->func = IMX_SC_IRQ_FUNC_STATUS;
+               hdr->size = 2;
+
+               msg.data.req.resource = mu_resource_id;
+               msg.data.req.group = i;
+
+               ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
+               if (ret) {
+                       pr_err("get irq group %d status failed, ret %d\n",
+                              i, ret);
+                       return;
+               }
+
+               irq_status = msg.data.resp.status;
+               if (!irq_status)
+                       continue;
+
+               imx_scu_irq_notifier_call_chain(irq_status, &i);
+       }
+}
+
+int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable)
+{
+       struct imx_sc_msg_irq_enable msg;
+       struct imx_sc_rpc_msg *hdr = &msg.hdr;
+       int ret;
+
+       hdr->ver = IMX_SC_RPC_VERSION;
+       hdr->svc = IMX_SC_RPC_SVC_IRQ;
+       hdr->func = IMX_SC_IRQ_FUNC_ENABLE;
+       hdr->size = 3;
+
+       msg.resource = mu_resource_id;
+       msg.group = group;
+       msg.mask = mask;
+       msg.enable = enable;
+
+       ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true);
+       if (ret)
+               pr_err("enable irq failed, group %d, mask %d, ret %d\n",
+                       group, mask, ret);
+
+       return ret;
+}
+EXPORT_SYMBOL(imx_scu_irq_group_enable);
+
+static void imx_scu_irq_callback(struct mbox_client *c, void *msg)
+{
+       schedule_work(&imx_sc_irq_work);
+}
+
+int imx_scu_enable_general_irq_channel(struct device *dev)
+{
+       struct of_phandle_args spec;
+       struct mbox_client *cl;
+       struct mbox_chan *ch;
+       int ret = 0, i = 0;
+
+       ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle);
+       if (ret)
+               return ret;
+
+       cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL);
+       if (!cl)
+               return -ENOMEM;
+
+       cl->dev = dev;
+       cl->rx_callback = imx_scu_irq_callback;
+
+       /* SCU general IRQ uses general interrupt channel 3 */
+       ch = mbox_request_channel_byname(cl, "gip3");
+       if (IS_ERR(ch)) {
+               ret = PTR_ERR(ch);
+               dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret);
+               devm_kfree(dev, cl);
+               return ret;
+       }
+
+       INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler);
+
+       if (!of_parse_phandle_with_args(dev->of_node, "mboxes",
+                                      "#mbox-cells", 0, &spec))
+               i = of_alias_get_id(spec.np, "mu");
+
+       /* use mu1 as general mu irq channel if failed */
+       if (i < 0)
+               i = 1;
+
+       mu_resource_id = IMX_SC_R_MU_0A + i;
+
+       return ret;
+}
+EXPORT_SYMBOL(imx_scu_enable_general_irq_channel);
index 2bb1a19..04a24a8 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/err.h>
 #include <linux/firmware/imx/types.h>
 #include <linux/firmware/imx/ipc.h>
+#include <linux/firmware/imx/sci.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
@@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev)
 
        imx_sc_ipc_handle = sc_ipc;
 
+       ret = imx_scu_enable_general_irq_channel(dev);
+       if (ret)
+               dev_warn(dev,
+                       "failed to enable general irq channel: %d\n", ret);
+
        dev_info(dev, "NXP i.MX SCU Initialized\n");
 
        return devm_of_platform_populate(dev);
index 39a94c7..480cec6 100644 (file)
@@ -74,7 +74,10 @@ struct imx_sc_pd_range {
        char *name;
        u32 rsrc;
        u8 num;
+
+       /* add domain index */
        bool postfix;
+       u8 start_from;
 };
 
 struct imx_sc_pd_soc {
@@ -84,71 +87,75 @@ struct imx_sc_pd_soc {
 
 static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
        /* LSIO SS */
-       { "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 },
-       { "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 },
-       { "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 },
-       { "lsio-kpp", IMX_SC_R_KPP, 1, 0 },
-       { "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 },
-       { "lsio-mu", IMX_SC_R_MU_0A, 14, 1 },
+       { "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
+       { "gpio", IMX_SC_R_GPIO_0, 8, true, 0 },
+       { "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
+       { "kpp", IMX_SC_R_KPP, 1, false, 0 },
+       { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
+       { "mu", IMX_SC_R_MU_0A, 14, true, 0 },
 
        /* CONN SS */
-       { "con-usb", IMX_SC_R_USB_0, 2, 1 },
-       { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 },
-       { "con-usb2", IMX_SC_R_USB_2, 1, 0 },
-       { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 },
-       { "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 },
-       { "con-enet", IMX_SC_R_ENET_0, 2, 1 },
-       { "con-nand", IMX_SC_R_NAND, 1, 0 },
-       { "con-mlb", IMX_SC_R_MLB_0, 1, 1 },
-
-       /* Audio DMA SS */
-       { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 },
-       { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 },
-       { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 },
-       { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 },
-       { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 },
-       { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 },
-       { "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 },
-       { "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 },
-       { "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 },
-       { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 },
-       { "adma-sai", IMX_SC_R_SAI_0, 3, 1 },
-       { "adma-amix", IMX_SC_R_AMIX, 1, 0 },
-       { "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 },
-       { "adma-dsp", IMX_SC_R_DSP, 1, 0 },
-       { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 },
-       { "adma-can", IMX_SC_R_CAN_0, 3, 1 },
-       { "adma-ftm", IMX_SC_R_FTM_0, 2, 1 },
-       { "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 },
-       { "adma-adc", IMX_SC_R_ADC_0, 1, 1 },
-       { "adma-lcd", IMX_SC_R_LCD_0, 1, 1 },
-       { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 },
-       { "adma-lpuart", IMX_SC_R_UART_0, 4, 1 },
-       { "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 },
-
-       /* VPU SS  */
-       { "vpu", IMX_SC_R_VPU, 1, 0 },
-       { "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 },
-       { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 },
-       { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 },
+       { "usb", IMX_SC_R_USB_0, 2, true, 0 },
+       { "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
+       { "usb2", IMX_SC_R_USB_2, 1, false, 0 },
+       { "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
+       { "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
+       { "enet", IMX_SC_R_ENET_0, 2, true, 0 },
+       { "nand", IMX_SC_R_NAND, 1, false, 0 },
+       { "mlb", IMX_SC_R_MLB_0, 1, true, 0 },
+
+       /* AUDIO SS */
+       { "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
+       { "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
+       { "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
+       { "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
+       { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
+       { "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
+       { "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
+       { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
+       { "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
+       { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
+       { "sai", IMX_SC_R_SAI_0, 3, true, 0 },
+       { "amix", IMX_SC_R_AMIX, 1, false, 0 },
+       { "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
+       { "dsp", IMX_SC_R_DSP, 1, false, 0 },
+       { "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 },
+
+       /* DMA SS */
+       { "can", IMX_SC_R_CAN_0, 3, true, 0 },
+       { "ftm", IMX_SC_R_FTM_0, 2, true, 0 },
+       { "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 },
+       { "adc", IMX_SC_R_ADC_0, 1, true, 0 },
+       { "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
+       { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
+       { "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
+       { "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
+
+       /* VPU SS */
+       { "vpu", IMX_SC_R_VPU, 1, false, 0 },
+       { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
+       { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
+       { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
 
        /* GPU SS */
-       { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 },
+       { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
 
        /* HSIO SS */
-       { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 },
-       { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 },
-       { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 },
+       { "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
+       { "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
+       { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },
+
+       /* MIPI SS */
+       { "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 },
+       { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
+       { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
 
-       /* MIPI/LVDS SS */
-       { "mipi0", IMX_SC_R_MIPI_0, 1, 0 },
-       { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 },
-       { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 },
-       { "lvds0", IMX_SC_R_LVDS_0, 1, 0 },
+       /* LVDS SS */
+       { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
 
        /* DC SS */
-       { "dc0", IMX_SC_R_DC_0, 1, 0 },
-       { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 },
+       { "dc0", IMX_SC_R_DC_0, 1, false, 0 },
+       { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
 };
 
 static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
@@ -236,7 +243,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx,
 
        if (pd_ranges->postfix)
                snprintf(sc_pd->name, sizeof(sc_pd->name),
-                        "%s%i", pd_ranges->name, idx);
+                        "%s%i", pd_ranges->name, pd_ranges->start_from + idx);
        else
                snprintf(sc_pd->name, sizeof(sc_pd->name),
                         "%s", pd_ranges->name);
index 2771df6..c6d0724 100644 (file)
@@ -90,9 +90,6 @@ static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret)
        int ret;
        struct zynqmp_pm_query_data qdata = {0};
 
-       if (!eemi_ops)
-               return -ENXIO;
-
        switch (pm_id) {
        case PM_GET_API_VERSION:
                ret = eemi_ops->get_api_version(&pm_api_version);
@@ -163,21 +160,14 @@ static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
 
        strcpy(debugfs_buf, "");
 
-       if (*off != 0 || len == 0)
+       if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1)
                return -EINVAL;
 
-       kern_buff = kzalloc(len, GFP_KERNEL);
-       if (!kern_buff)
-               return -ENOMEM;
-
+       kern_buff = memdup_user_nul(ptr, len);
+       if (IS_ERR(kern_buff))
+               return PTR_ERR(kern_buff);
        tmp_buff = kern_buff;
 
-       ret = strncpy_from_user(kern_buff, ptr, len);
-       if (ret < 0) {
-               ret = -EFAULT;
-               goto err;
-       }
-
        /* Read the API name from a user request */
        pm_api_req = strsep(&kern_buff, " ");
 
index 98f9361..fd3d837 100644 (file)
@@ -24,6 +24,8 @@
 #include <linux/firmware/xlnx-zynqmp.h>
 #include "zynqmp-debug.h"
 
+static const struct zynqmp_eemi_ops *eemi_ops_tbl;
+
 static const struct mfd_cell firmware_devs[] = {
        {
                .name = "zynqmp_power_controller",
@@ -538,6 +540,49 @@ static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset,
 }
 
 /**
+ * zynqmp_pm_fpga_load - Perform the fpga load
+ * @address:   Address to write to
+ * @size:      pl bitstream size
+ * @flags:     Bitstream type
+ *     -XILINX_ZYNQMP_PM_FPGA_FULL:  FPGA full reconfiguration
+ *     -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
+ *
+ * This function provides access to pmufw. To transfer
+ * the required bitstream into PL.
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_load(const u64 address, const u32 size,
+                              const u32 flags)
+{
+       return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address),
+                                  upper_32_bits(address), size, flags, NULL);
+}
+
+/**
+ * zynqmp_pm_fpga_get_status - Read value from PCAP status register
+ * @value: Value to read
+ *
+ * This function provides access to the pmufw to get the PCAP
+ * status
+ *
+ * Return: Returns status, either success or error+reason
+ */
+static int zynqmp_pm_fpga_get_status(u32 *value)
+{
+       u32 ret_payload[PAYLOAD_ARG_CNT];
+       int ret;
+
+       if (!value)
+               return -EINVAL;
+
+       ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload);
+       *value = ret_payload[1];
+
+       return ret;
+}
+
+/**
  * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller
  *                            master has initialized its own power management
  *
@@ -640,6 +685,8 @@ static const struct zynqmp_eemi_ops eemi_ops = {
        .request_node = zynqmp_pm_request_node,
        .release_node = zynqmp_pm_release_node,
        .set_requirement = zynqmp_pm_set_requirement,
+       .fpga_load = zynqmp_pm_fpga_load,
+       .fpga_get_status = zynqmp_pm_fpga_get_status,
 };
 
 /**
@@ -649,7 +696,11 @@ static const struct zynqmp_eemi_ops eemi_ops = {
  */
 const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
 {
-       return &eemi_ops;
+       if (eemi_ops_tbl)
+               return eemi_ops_tbl;
+       else
+               return ERR_PTR(-EPROBE_DEFER);
+
 }
 EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
 
@@ -694,6 +745,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev)
        pr_info("%s Trustzone version v%d.%d\n", __func__,
                pm_tz_version >> 16, pm_tz_version & 0xFFFF);
 
+       /* Assign eemi_ops_table */
+       eemi_ops_tbl = &eemi_ops;
+
        zynqmp_pm_api_debugfs_init();
 
        ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs,
index c20445b..d892f3e 100644 (file)
@@ -204,4 +204,13 @@ config FPGA_DFL_PCI
 
          To compile this as a module, choose M here.
 
+config FPGA_MGR_ZYNQMP_FPGA
+       tristate "Xilinx ZynqMP FPGA"
+       depends on ARCH_ZYNQMP || COMPILE_TEST
+       help
+         FPGA manager driver support for Xilinx ZynqMP FPGAs.
+         This driver uses the processor configuration port(PCAP)
+         to configure the programmable logic(PL) through PS
+         on ZynqMP SoC.
+
 endif # FPGA
index c0dd4c8..312b937 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC)  += stratix10-soc.o
 obj-$(CONFIG_FPGA_MGR_TS73XX)          += ts73xx-fpga.o
 obj-$(CONFIG_FPGA_MGR_XILINX_SPI)      += xilinx-spi.o
 obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA)       += zynq-fpga.o
+obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA)     += zynqmp-fpga.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE)         += altera-pr-ip-core.o
 obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT)    += altera-pr-ip-core-plat.o
 
diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c
new file mode 100644 (file)
index 0000000..f7cbaad
--- /dev/null
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Xilinx, Inc.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/string.h>
+#include <linux/firmware/xlnx-zynqmp.h>
+
+/* Constant Definitions */
+#define IXR_FPGA_DONE_MASK     BIT(3)
+
+/**
+ * struct zynqmp_fpga_priv - Private data structure
+ * @dev:       Device data structure
+ * @flags:     flags which is used to identify the bitfile type
+ */
+struct zynqmp_fpga_priv {
+       struct device *dev;
+       u32 flags;
+};
+
+static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr,
+                                     struct fpga_image_info *info,
+                                     const char *buf, size_t size)
+{
+       struct zynqmp_fpga_priv *priv;
+
+       priv = mgr->priv;
+       priv->flags = info->flags;
+
+       return 0;
+}
+
+static int zynqmp_fpga_ops_write(struct fpga_manager *mgr,
+                                const char *buf, size_t size)
+{
+       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+       struct zynqmp_fpga_priv *priv;
+       dma_addr_t dma_addr;
+       u32 eemi_flags = 0;
+       char *kbuf;
+       int ret;
+
+       if (!eemi_ops || !eemi_ops->fpga_load)
+               return -ENXIO;
+
+       priv = mgr->priv;
+
+       kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL);
+       if (!kbuf)
+               return -ENOMEM;
+
+       memcpy(kbuf, buf, size);
+
+       wmb(); /* ensure all writes are done before initiate FW call */
+
+       if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG)
+               eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL;
+
+       ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags);
+
+       dma_free_coherent(priv->dev, size, kbuf, dma_addr);
+
+       return ret;
+}
+
+static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr,
+                                         struct fpga_image_info *info)
+{
+       return 0;
+}
+
+static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr)
+{
+       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+       u32 status;
+
+       if (!eemi_ops || !eemi_ops->fpga_get_status)
+               return FPGA_MGR_STATE_UNKNOWN;
+
+       eemi_ops->fpga_get_status(&status);
+       if (status & IXR_FPGA_DONE_MASK)
+               return FPGA_MGR_STATE_OPERATING;
+
+       return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static const struct fpga_manager_ops zynqmp_fpga_ops = {
+       .state = zynqmp_fpga_ops_state,
+       .write_init = zynqmp_fpga_ops_write_init,
+       .write = zynqmp_fpga_ops_write,
+       .write_complete = zynqmp_fpga_ops_write_complete,
+};
+
+static int zynqmp_fpga_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct zynqmp_fpga_priv *priv;
+       struct fpga_manager *mgr;
+       int ret;
+
+       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->dev = dev;
+
+       mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager",
+                                  &zynqmp_fpga_ops, priv);
+       if (!mgr)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, mgr);
+
+       ret = fpga_mgr_register(mgr);
+       if (ret) {
+               dev_err(dev, "unable to register FPGA manager");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int zynqmp_fpga_remove(struct platform_device *pdev)
+{
+       struct fpga_manager *mgr = platform_get_drvdata(pdev);
+
+       fpga_mgr_unregister(mgr);
+
+       return 0;
+}
+
+static const struct of_device_id zynqmp_fpga_of_match[] = {
+       { .compatible = "xlnx,zynqmp-pcap-fpga", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match);
+
+static struct platform_driver zynqmp_fpga_driver = {
+       .probe = zynqmp_fpga_probe,
+       .remove = zynqmp_fpga_remove,
+       .driver = {
+               .name = "zynqmp_fpga_manager",
+               .of_match_table = of_match_ptr(zynqmp_fpga_of_match),
+       },
+};
+
+module_platform_driver(zynqmp_fpga_driver);
+
+MODULE_AUTHOR("Nava kishore Manne <navam@xilinx.com>");
+MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager");
+MODULE_LICENSE("GPL");
index 9e9f803..6b71fad 100644 (file)
 #define MCONNID_SHIFT                                  0
 #define MCONNID_MASK                                   (0xff << 0)
 
+/* READ_WRITE_LEVELING_CONTROL */
+#define RDWRLVLFULL_START                              0x80000000
+
 /* DDR_PHY_CTRL_1 - EMIF4D */
 #define DLL_SLAVE_DLY_CTRL_SHIFT_4D                    4
 #define DLL_SLAVE_DLY_CTRL_MASK_4D                     (0xFF << 4)
@@ -598,6 +601,7 @@ extern struct emif_regs_amx3 ti_emif_regs_amx3;
 
 void ti_emif_save_context(void);
 void ti_emif_restore_context(void);
+void ti_emif_run_hw_leveling(void);
 void ti_emif_enter_sr(void);
 void ti_emif_exit_sr(void);
 void ti_emif_abort_sr(void);
index 0a53598..163b6c6 100644 (file)
@@ -51,6 +51,9 @@
 #define MC_EMEM_ADR_CFG 0x54
 #define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0)
 
+#define MC_TIMING_CONTROL              0xfc
+#define MC_TIMING_UPDATE               BIT(0)
+
 static const struct of_device_id tegra_mc_of_match[] = {
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
        { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc },
@@ -74,7 +77,7 @@ static const struct of_device_id tegra_mc_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
 
-static int terga_mc_block_dma_common(struct tegra_mc *mc,
+static int tegra_mc_block_dma_common(struct tegra_mc *mc,
                                     const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -90,13 +93,13 @@ static int terga_mc_block_dma_common(struct tegra_mc *mc,
        return 0;
 }
 
-static bool terga_mc_dma_idling_common(struct tegra_mc *mc,
+static bool tegra_mc_dma_idling_common(struct tegra_mc *mc,
                                       const struct tegra_mc_reset *rst)
 {
        return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0;
 }
 
-static int terga_mc_unblock_dma_common(struct tegra_mc *mc,
+static int tegra_mc_unblock_dma_common(struct tegra_mc *mc,
                                       const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -112,17 +115,17 @@ static int terga_mc_unblock_dma_common(struct tegra_mc *mc,
        return 0;
 }
 
-static int terga_mc_reset_status_common(struct tegra_mc *mc,
+static int tegra_mc_reset_status_common(struct tegra_mc *mc,
                                        const struct tegra_mc_reset *rst)
 {
        return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0;
 }
 
-const struct tegra_mc_reset_ops terga_mc_reset_ops_common = {
-       .block_dma = terga_mc_block_dma_common,
-       .dma_idling = terga_mc_dma_idling_common,
-       .unblock_dma = terga_mc_unblock_dma_common,
-       .reset_status = terga_mc_reset_status_common,
+const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = {
+       .block_dma = tegra_mc_block_dma_common,
+       .dma_idling = tegra_mc_dma_idling_common,
+       .unblock_dma = tegra_mc_unblock_dma_common,
+       .reset_status = tegra_mc_reset_status_common,
 };
 
 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)
        u32 value;
 
        /* compute the number of MC clock cycles per tick */
-       tick = mc->tick * clk_get_rate(mc->clk);
+       tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk);
        do_div(tick, NSEC_PER_SEC);
 
-       value = readl(mc->regs + MC_EMEM_ARB_CFG);
+       value = mc_readl(mc, MC_EMEM_ARB_CFG);
        value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
        value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
-       writel(value, mc->regs + MC_EMEM_ARB_CFG);
+       mc_writel(mc, value, MC_EMEM_ARB_CFG);
 
        /* write latency allowance defaults */
        for (i = 0; i < mc->soc->num_clients; i++) {
                const struct tegra_mc_la *la = &mc->soc->clients[i].la;
                u32 value;
 
-               value = readl(mc->regs + la->reg);
+               value = mc_readl(mc, la->reg);
                value &= ~(la->mask << la->shift);
                value |= (la->def & la->mask) << la->shift;
-               writel(value, mc->regs + la->reg);
+               mc_writel(mc, value, la->reg);
        }
 
+       /* latch new values */
+       mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL);
+
        return 0;
 }
 
index 887a3b0..3929939 100644 (file)
@@ -35,7 +35,7 @@ static inline void mc_writel(struct tegra_mc *mc, u32 value,
        writel_relaxed(value, mc->regs + offset);
 }
 
-extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common;
+extern const struct tegra_mc_reset_ops tegra_mc_reset_ops_common;
 
 #ifdef CONFIG_ARCH_TEGRA_2x_SOC
 extern const struct tegra_mc_soc tegra20_mc_soc;
index 6560a51..62305fa 100644 (file)
@@ -572,7 +572,7 @@ static const struct tegra_mc_client tegra114_mc_clients[] = {
                },
        }, {
                .id = 0x34,
-               .name = "fdcwr2",
+               .name = "fdcdwr2",
                .swgroup = TEGRA_SWGROUP_NV,
                .smmu = {
                        .reg = 0x22c,
@@ -975,7 +975,7 @@ const struct tegra_mc_soc tegra114_mc_soc = {
        .smmu = &tegra114_smmu_soc,
        .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
                   MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra114_mc_resets,
        .num_resets = ARRAY_SIZE(tegra114_mc_resets),
 };
index b561a1f..8f8487b 100644 (file)
@@ -1074,7 +1074,7 @@ const struct tegra_mc_soc tegra124_mc_soc = {
        .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
                   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
                   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra124_mc_resets,
        .num_resets = ARRAY_SIZE(tegra124_mc_resets),
 };
@@ -1104,7 +1104,7 @@ const struct tegra_mc_soc tegra132_mc_soc = {
        .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
                   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
                   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra124_mc_resets,
        .num_resets = ARRAY_SIZE(tegra124_mc_resets),
 };
index 7119e53..121237b 100644 (file)
@@ -198,7 +198,7 @@ static const struct tegra_mc_reset tegra20_mc_resets[] = {
        TEGRA20_MC_RESET(VI,     0x100, 0x178, 0x104, 14),
 };
 
-static int terga20_mc_hotreset_assert(struct tegra_mc *mc,
+static int tegra20_mc_hotreset_assert(struct tegra_mc *mc,
                                      const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -214,7 +214,7 @@ static int terga20_mc_hotreset_assert(struct tegra_mc *mc,
        return 0;
 }
 
-static int terga20_mc_hotreset_deassert(struct tegra_mc *mc,
+static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc,
                                        const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -230,7 +230,7 @@ static int terga20_mc_hotreset_deassert(struct tegra_mc *mc,
        return 0;
 }
 
-static int terga20_mc_block_dma(struct tegra_mc *mc,
+static int tegra20_mc_block_dma(struct tegra_mc *mc,
                                const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -246,19 +246,19 @@ static int terga20_mc_block_dma(struct tegra_mc *mc,
        return 0;
 }
 
-static bool terga20_mc_dma_idling(struct tegra_mc *mc,
+static bool tegra20_mc_dma_idling(struct tegra_mc *mc,
                                  const struct tegra_mc_reset *rst)
 {
        return mc_readl(mc, rst->status) == 0;
 }
 
-static int terga20_mc_reset_status(struct tegra_mc *mc,
+static int tegra20_mc_reset_status(struct tegra_mc *mc,
                                   const struct tegra_mc_reset *rst)
 {
        return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0;
 }
 
-static int terga20_mc_unblock_dma(struct tegra_mc *mc,
+static int tegra20_mc_unblock_dma(struct tegra_mc *mc,
                                  const struct tegra_mc_reset *rst)
 {
        unsigned long flags;
@@ -274,13 +274,13 @@ static int terga20_mc_unblock_dma(struct tegra_mc *mc,
        return 0;
 }
 
-const struct tegra_mc_reset_ops terga20_mc_reset_ops = {
-       .hotreset_assert = terga20_mc_hotreset_assert,
-       .hotreset_deassert = terga20_mc_hotreset_deassert,
-       .block_dma = terga20_mc_block_dma,
-       .dma_idling = terga20_mc_dma_idling,
-       .unblock_dma = terga20_mc_unblock_dma,
-       .reset_status = terga20_mc_reset_status,
+static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = {
+       .hotreset_assert = tegra20_mc_hotreset_assert,
+       .hotreset_deassert = tegra20_mc_hotreset_deassert,
+       .block_dma = tegra20_mc_block_dma,
+       .dma_idling = tegra20_mc_dma_idling,
+       .unblock_dma = tegra20_mc_unblock_dma,
+       .reset_status = tegra20_mc_reset_status,
 };
 
 const struct tegra_mc_soc tegra20_mc_soc = {
@@ -290,7 +290,7 @@ const struct tegra_mc_soc tegra20_mc_soc = {
        .client_id_mask = 0x3f,
        .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE |
                   MC_INT_DECERR_EMEM,
-       .reset_ops = &terga20_mc_reset_ops,
+       .reset_ops = &tegra20_mc_reset_ops,
        .resets = tegra20_mc_resets,
        .num_resets = ARRAY_SIZE(tegra20_mc_resets),
 };
index d00a771..aa22cda 100644 (file)
@@ -1132,7 +1132,7 @@ const struct tegra_mc_soc tegra210_mc_soc = {
        .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
                   MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
                   MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra210_mc_resets,
        .num_resets = ARRAY_SIZE(tegra210_mc_resets),
 };
index bee5314..c9af0f6 100644 (file)
@@ -726,7 +726,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = {
                },
        }, {
                .id = 0x34,
-               .name = "fdcwr2",
+               .name = "fdcdwr2",
                .swgroup = TEGRA_SWGROUP_NV2,
                .smmu = {
                        .reg = 0x22c,
@@ -999,7 +999,7 @@ const struct tegra_mc_soc tegra30_mc_soc = {
        .smmu = &tegra30_smmu_soc,
        .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
                   MC_INT_DECERR_EMEM,
-       .reset_ops = &terga_mc_reset_ops_common,
+       .reset_ops = &tegra_mc_reset_ops_common,
        .resets = tegra30_mc_resets,
        .num_resets = ARRAY_SIZE(tegra30_mc_resets),
 };
index 2250d03..ab07aa1 100644 (file)
@@ -138,6 +138,9 @@ static int ti_emif_alloc_sram(struct device *dev,
        emif_data->pm_functions.exit_sr =
                sram_resume_address(emif_data,
                                    (unsigned long)ti_emif_exit_sr);
+       emif_data->pm_functions.run_hw_leveling =
+               sram_resume_address(emif_data,
+                                   (unsigned long)ti_emif_run_hw_leveling);
 
        emif_data->pm_data.regs_virt =
                (struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt;
index a536918..d75ae18 100644 (file)
@@ -27,6 +27,7 @@
 #define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK         0x0700
 
 #define EMIF_SDCFG_TYPE_DDR2                           0x2 << SDRAM_TYPE_SHIFT
+#define EMIF_SDCFG_TYPE_DDR3                           0x3 << SDRAM_TYPE_SHIFT
 #define EMIF_STATUS_READY                              0x4
 
 #define AM43XX_EMIF_PHY_CTRL_REG_COUNT                  0x120
@@ -245,6 +246,46 @@ emif_skip_restore_extra_regs:
 ENDPROC(ti_emif_restore_context)
 
 /*
+ * void ti_emif_run_hw_leveling(void)
+ *
+ * Used during resume to run hardware leveling again and restore the
+ * configuration of the EMIF PHY, only for DDR3.
+ */
+ENTRY(ti_emif_run_hw_leveling)
+       adr     r4, ti_emif_pm_sram_data
+       ldr     r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET]
+
+       ldr     r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
+       orr     r3, r3, #RDWRLVLFULL_START
+       ldr     r2, [r0, #EMIF_SDRAM_CONFIG]
+       and     r2, r2, #SDRAM_TYPE_MASK
+       cmp     r2, #EMIF_SDCFG_TYPE_DDR3
+       bne     skip_hwlvl
+
+       str     r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
+
+       /*
+        * If EMIF registers are touched during initial stage of HW
+        * leveling sequence there will be an L3 NOC timeout error issued
+        * as the EMIF will not respond, which is not fatal, but it is
+        * avoidable. This small wait loop is enough time for this condition
+        * to clear, even at worst case of CPU running at max speed of 1Ghz.
+        */
+       mov     r2, #0x2000
+1:
+       subs    r2, r2, #0x1
+       bne     1b
+
+       /* Bit clears when operation is complete */
+2:     ldr     r1, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL]
+       tst     r1, #RDWRLVLFULL_START
+       bne     2b
+
+skip_hwlvl:
+       mov     pc, lr
+ENDPROC(ti_emif_run_hw_leveling)
+
+/*
  * void ti_emif_enter_sr(void)
  *
  * Programs the EMIF to tell the SDRAM to enter into self-refresh
index 3209ee0..b80cb6a 100644 (file)
@@ -496,30 +496,6 @@ config VEXPRESS_SYSCFG
          bus. System Configuration interface is one of the possible means
          of generating transactions on this bus.
 
-config ASPEED_P2A_CTRL
-       depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
-       tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control"
-       help
-         Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through
-         ioctl()s, the driver also provides an interface for userspace mappings to
-         a pre-defined region.
-
-config ASPEED_LPC_CTRL
-       depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
-       tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
-       ---help---
-         Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
-         ioctl()s, the driver also provides a read/write interface to a BMC ram
-         region where the host LPC read/write region can be buffered.
-
-config ASPEED_LPC_SNOOP
-       tristate "Aspeed ast2500 HOST LPC snoop support"
-       depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON
-       help
-         Provides a driver to control the LPC snoop interface which
-         allows the BMC to listen on and save the data written by
-         the host to an arbitrary LPC I/O port.
-
 config PCI_ENDPOINT_TEST
        depends on PCI
        select CRC32
index c362395..b9affcd 100644 (file)
@@ -54,9 +54,6 @@ obj-$(CONFIG_GENWQE)          += genwqe/
 obj-$(CONFIG_ECHO)             += echo/
 obj-$(CONFIG_VEXPRESS_SYSCFG)  += vexpress-syscfg.o
 obj-$(CONFIG_CXL_BASE)         += cxl/
-obj-$(CONFIG_ASPEED_LPC_CTRL)  += aspeed-lpc-ctrl.o
-obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
-obj-$(CONFIG_ASPEED_P2A_CTRL)  += aspeed-p2a-ctrl.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)        += pci_endpoint_test.o
 obj-$(CONFIG_OCXL)             += ocxl/
 obj-y                          += cardreader/
index 490c8fc..5893543 100644 (file)
@@ -16,6 +16,8 @@ struct zynqmp_nvmem_data {
        struct nvmem_device *nvmem;
 };
 
+static const struct zynqmp_eemi_ops *eemi_ops;
+
 static int zynqmp_nvmem_read(void *context, unsigned int offset,
                             void *val, size_t bytes)
 {
@@ -23,9 +25,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset,
        int idcode, version;
        struct zynqmp_nvmem_data *priv = context;
 
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
-
-       if (!eemi_ops || !eemi_ops->get_chipid)
+       if (!eemi_ops->get_chipid)
                return -ENXIO;
 
        ret = eemi_ops->get_chipid(&idcode, &version);
@@ -61,6 +61,10 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
+
        priv->dev = dev;
        econfig.dev = dev;
        econfig.reg_read = zynqmp_nvmem_read;
index 2ef1f13..99e75d9 100644 (file)
@@ -79,11 +79,11 @@ static int zynqmp_reset_probe(struct platform_device *pdev)
        if (!priv)
                return -ENOMEM;
 
-       platform_set_drvdata(pdev, priv);
-
        priv->eemi_ops = zynqmp_pm_get_eemi_ops();
-       if (!priv->eemi_ops)
-               return -ENXIO;
+       if (IS_ERR(priv->eemi_ops))
+               return PTR_ERR(priv->eemi_ops);
+
+       platform_set_drvdata(pdev, priv);
 
        priv->rcdev.ops = &zynqmp_reset_ops;
        priv->rcdev.owner = THIS_MODULE;
index 32994b0..a2941c8 100644 (file)
@@ -403,15 +403,12 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
 
 static struct omap_rtc *omap_rtc_power_off_rtc;
 
-/*
- * omap_rtc_poweroff: RTC-controlled power off
- *
- * The RTC can be used to control an external PMIC via the pmic_power_en pin,
- * which can be configured to transition to OFF on ALARM2 events.
- *
- * Called with local interrupts disabled.
+/**
+ * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC
+ * generates pmic_pwr_enable control, which can be used to control an external
+ * PMIC.
  */
-static void omap_rtc_power_off(void)
+int omap_rtc_power_off_program(struct device *dev)
 {
        struct omap_rtc *rtc = omap_rtc_power_off_rtc;
        struct rtc_time tm;
@@ -425,6 +422,9 @@ static void omap_rtc_power_off(void)
        rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
 
 again:
+       /* Clear any existing ALARM2 event */
+       rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2);
+
        /* set alarm one second from now */
        omap_rtc_read_time_raw(rtc, &tm);
        seconds = tm.tm_sec;
@@ -461,6 +461,39 @@ again:
 
        rtc->type->lock(rtc);
 
+       return 0;
+}
+EXPORT_SYMBOL(omap_rtc_power_off_program);
+
+/*
+ * omap_rtc_poweroff: RTC-controlled power off
+ *
+ * The RTC can be used to control an external PMIC via the pmic_power_en pin,
+ * which can be configured to transition to OFF on ALARM2 events.
+ *
+ * Notes:
+ * The one-second alarm offset is the shortest offset possible as the alarm
+ * registers must be set before the next timer update and the offset
+ * calculation is too heavy for everything to be done within a single access
+ * period (~15 us).
+ *
+ * Called with local interrupts disabled.
+ */
+static void omap_rtc_power_off(void)
+{
+       struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc;
+       u32 val;
+
+       omap_rtc_power_off_program(rtc->dev.parent);
+
+       /* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */
+       omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc);
+       val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG);
+       val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) |
+                       OMAP_RTC_PMIC_EXT_WKUP_EN(0);
+       rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val);
+       omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc);
+
        /*
         * Wait for alarm to trigger (within one second) and external PMIC to
         * power off the system. Add a 500 ms margin for external latencies
index ae9bf20..75bdbb2 100644 (file)
@@ -2,6 +2,7 @@ menu "SOC (System On Chip) specific Drivers"
 
 source "drivers/soc/actions/Kconfig"
 source "drivers/soc/amlogic/Kconfig"
+source "drivers/soc/aspeed/Kconfig"
 source "drivers/soc/atmel/Kconfig"
 source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/fsl/Kconfig"
index c7c1a13..524ecdc 100644 (file)
@@ -4,6 +4,7 @@
 #
 
 obj-$(CONFIG_ARCH_ACTIONS)     += actions/
+obj-$(CONFIG_SOC_ASPEED)       += aspeed/
 obj-$(CONFIG_ARCH_AT91)                += atmel/
 obj-y                          += bcm/
 obj-$(CONFIG_ARCH_DOVE)                += dove/
index 6289965..511b685 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/bitfield.h>
 #include <linux/regmap.h>
 #include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
 #include <linux/reset.h>
 #include <linux/clk.h>
 
@@ -26,6 +27,7 @@
 #define HHI_MEM_PD_REG0                        (0x40 << 2)
 #define HHI_VPU_MEM_PD_REG0            (0x41 << 2)
 #define HHI_VPU_MEM_PD_REG1            (0x42 << 2)
+#define HHI_VPU_MEM_PD_REG2            (0x4d << 2)
 
 struct meson_gx_pwrc_vpu {
        struct generic_pm_domain genpd;
@@ -54,12 +56,55 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
        /* Power Down Memories */
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
-                                  0x2 << i, 0x3 << i);
+                                  0x3 << i, 0x3 << i);
                udelay(5);
        }
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
-                                  0x2 << i, 0x3 << i);
+                                  0x3 << i, 0x3 << i);
+               udelay(5);
+       }
+       for (i = 8; i < 16; i++) {
+               regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
+                                  BIT(i), BIT(i));
+               udelay(5);
+       }
+       udelay(20);
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI);
+
+       msleep(20);
+
+       clk_disable_unprepare(pd->vpu_clk);
+       clk_disable_unprepare(pd->vapb_clk);
+
+       return 0;
+}
+
+static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd)
+{
+       struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
+       int i;
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO);
+       udelay(20);
+
+       /* Power Down Memories */
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+                                  0x3 << i, 0x3 << i);
+               udelay(5);
+       }
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+                                  0x3 << i, 0x3 << i);
+               udelay(5);
+       }
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
+                                  0x3 << i, 0x3 << i);
                udelay(5);
        }
        for (i = 8; i < 16; i++) {
@@ -108,13 +153,67 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
        /* Power Up Memories */
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
-                                  0x2 << i, 0);
+                                  0x3 << i, 0);
+               udelay(5);
+       }
+
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
+                                  0x3 << i, 0);
+               udelay(5);
+       }
+
+       for (i = 8; i < 16; i++) {
+               regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0,
+                                  BIT(i), 0);
+               udelay(5);
+       }
+       udelay(20);
+
+       ret = reset_control_assert(pd->rstc);
+       if (ret)
+               return ret;
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI_ISO, 0);
+
+       ret = reset_control_deassert(pd->rstc);
+       if (ret)
+               return ret;
+
+       ret = meson_gx_pwrc_vpu_setup_clk(pd);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd)
+{
+       struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd);
+       int ret;
+       int i;
+
+       regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0,
+                          GEN_PWR_VPU_HDMI, 0);
+       udelay(20);
+
+       /* Power Up Memories */
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0,
+                                  0x3 << i, 0);
                udelay(5);
        }
 
        for (i = 0; i < 32; i += 2) {
                regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1,
-                                  0x2 << i, 0);
+                                  0x3 << i, 0);
+               udelay(5);
+       }
+
+       for (i = 0; i < 32; i += 2) {
+               regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2,
+                                  0x3 << i, 0);
                udelay(5);
        }
 
@@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = {
        },
 };
 
+static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = {
+       .genpd = {
+               .name = "vpu_hdmi",
+               .power_off = meson_g12a_pwrc_vpu_power_off,
+               .power_on = meson_g12a_pwrc_vpu_power_on,
+       },
+};
+
 static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
 {
+       const struct meson_gx_pwrc_vpu *vpu_pd_match;
        struct regmap *regmap_ao, *regmap_hhi;
+       struct meson_gx_pwrc_vpu *vpu_pd;
        struct reset_control *rstc;
        struct clk *vpu_clk;
        struct clk *vapb_clk;
        bool powered_off;
        int ret;
 
+       vpu_pd_match = of_device_get_match_data(&pdev->dev);
+       if (!vpu_pd_match) {
+               dev_err(&pdev->dev, "failed to get match data\n");
+               return -ENODEV;
+       }
+
+       vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL);
+       if (!vpu_pd)
+               return -ENOMEM;
+
+       memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd));
+
        regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node));
        if (IS_ERR(regmap_ao)) {
                dev_err(&pdev->dev, "failed to get regmap\n");
@@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev)
                return PTR_ERR(vapb_clk);
        }
 
-       vpu_hdmi_pd.regmap_ao = regmap_ao;
-       vpu_hdmi_pd.regmap_hhi = regmap_hhi;
-       vpu_hdmi_pd.rstc = rstc;
-       vpu_hdmi_pd.vpu_clk = vpu_clk;
-       vpu_hdmi_pd.vapb_clk = vapb_clk;
+       vpu_pd->regmap_ao = regmap_ao;
+       vpu_pd->regmap_hhi = regmap_hhi;
+       vpu_pd->rstc = rstc;
+       vpu_pd->vpu_clk = vpu_clk;
+       vpu_pd->vapb_clk = vapb_clk;
+
+       platform_set_drvdata(pdev, vpu_pd);
 
-       powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
+       powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
 
        /* If already powered, sync the clock states */
        if (!powered_off) {
-               ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd);
+               ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd);
                if (ret)
                        return ret;
        }
 
-       pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov,
+       pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov,
                      powered_off);
 
        return of_genpd_add_provider_simple(pdev->dev.of_node,
-                                           &vpu_hdmi_pd.genpd);
+                                           &vpu_pd->genpd);
 }
 
 static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev)
 {
+       struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev);
        bool powered_off;
 
-       powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd);
+       powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd);
        if (!powered_off)
-               meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd);
+               vpu_pd->genpd.power_off(&vpu_pd->genpd);
 }
 
 static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = {
-       { .compatible = "amlogic,meson-gx-pwrc-vpu" },
+       { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd },
+       {
+         .compatible = "amlogic,meson-g12a-pwrc-vpu",
+         .data = &vpu_hdmi_pd_g12a
+       },
        { /* sentinel */ }
 };
 
index 37ea0a1..bca3495 100644 (file)
@@ -37,26 +37,34 @@ static const struct meson_gx_soc_id {
        { "AXG", 0x25 },
        { "GXLX", 0x26 },
        { "TXHD", 0x27 },
+       { "G12A", 0x28 },
+       { "G12B", 0x29 },
 };
 
 static const struct meson_gx_package_id {
        const char *name;
        unsigned int major_id;
        unsigned int pack_id;
+       unsigned int pack_mask;
 } soc_packages[] = {
-       { "S905", 0x1f, 0 },
-       { "S905H", 0x1f, 0x13 },
-       { "S905M", 0x1f, 0x20 },
-       { "S905D", 0x21, 0 },
-       { "S905X", 0x21, 0x80 },
-       { "S905W", 0x21, 0xa0 },
-       { "S905L", 0x21, 0xc0 },
-       { "S905M2", 0x21, 0xe0 },
-       { "S912", 0x22, 0 },
-       { "962X", 0x24, 0x10 },
-       { "962E", 0x24, 0x20 },
-       { "A113X", 0x25, 0x37 },
-       { "A113D", 0x25, 0x22 },
+       { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */
+       { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */
+       { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */
+       { "S905D", 0x21, 0, 0xf0 },
+       { "S905X", 0x21, 0x80, 0xf0 },
+       { "S905W", 0x21, 0xa0, 0xf0 },
+       { "S905L", 0x21, 0xc0, 0xf0 },
+       { "S905M2", 0x21, 0xe0, 0xf0 },
+       { "S805X", 0x21, 0x30, 0xf0 },
+       { "S805Y", 0x21, 0xb0, 0xf0 },
+       { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */
+       { "962X", 0x24, 0x10, 0xf0 },
+       { "962E", 0x24, 0x20, 0xf0 },
+       { "A113X", 0x25, 0x37, 0xff },
+       { "A113D", 0x25, 0x22, 0xff },
+       { "S905D2", 0x28, 0x10, 0xf0 },
+       { "S905X2", 0x28, 0x40, 0xf0 },
+       { "S922X", 0x29, 0x40, 0xf0 },
 };
 
 static inline unsigned int socinfo_to_major(u32 socinfo)
@@ -81,13 +89,14 @@ static inline unsigned int socinfo_to_misc(u32 socinfo)
 
 static const char *socinfo_to_package_id(u32 socinfo)
 {
-       unsigned int pack = socinfo_to_pack(socinfo) & 0xf0;
+       unsigned int pack = socinfo_to_pack(socinfo);
        unsigned int major = socinfo_to_major(socinfo);
        int i;
 
        for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) {
                if (soc_packages[i].major_id == major &&
-                   soc_packages[i].pack_id == pack)
+                   soc_packages[i].pack_id ==
+                               (pack & soc_packages[i].pack_mask))
                        return soc_packages[i].name;
        }
 
@@ -123,8 +132,10 @@ static int __init meson_gx_socinfo_init(void)
                return -ENODEV;
 
        /* check if interface is enabled */
-       if (!of_device_is_available(np))
+       if (!of_device_is_available(np)) {
+               of_node_put(np);
                return -ENODEV;
+       }
 
        /* check if chip-id is available */
        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 (file)
index 0000000..765d101
--- /dev/null
@@ -0,0 +1,31 @@
+menu "Aspeed SoC drivers"
+
+config SOC_ASPEED
+       def_bool y
+       depends on ARCH_ASPEED || COMPILE_TEST
+
+config ASPEED_LPC_CTRL
+       depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+       tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control"
+       ---help---
+         Control Aspeed ast2400/2500 HOST LPC to BMC mappings through
+         ioctl()s, the driver also provides a read/write interface to a BMC ram
+         region where the host LPC read/write region can be buffered.
+
+config ASPEED_LPC_SNOOP
+       tristate "Aspeed ast2500 HOST LPC snoop support"
+       depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+       help
+         Provides a driver to control the LPC snoop interface which
+         allows the BMC to listen on and save the data written by
+         the host to an arbitrary LPC I/O port.
+
+config ASPEED_P2A_CTRL
+       depends on SOC_ASPEED && REGMAP && MFD_SYSCON
+       tristate "Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC bridge control"
+       help
+         Control Aspeed ast2400/2500 HOST P2A VGA MMIO to BMC mappings through
+         ioctl()s, the driver also provides an interface for userspace mappings to
+         a pre-defined region.
+
+endmenu
diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile
new file mode 100644 (file)
index 0000000..2f7b6da
--- /dev/null
@@ -0,0 +1,3 @@
+obj-$(CONFIG_ASPEED_LPC_CTRL)  += aspeed-lpc-ctrl.o
+obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o
+obj-$(CONFIG_ASPEED_P2A_CTRL)  += aspeed-p2a-ctrl.o
index 506a6f3..d6b529e 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
 obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o
+obj-$(CONFIG_ARCH_MXC) += soc-imx8.o
index 29b4365..d9231bd 100644 (file)
@@ -406,7 +406,6 @@ static int imx_gpc_probe(struct platform_device *pdev)
        const struct imx_gpc_dt_data *of_id_data = of_id->data;
        struct device_node *pgc_node;
        struct regmap *regmap;
-       struct resource *res;
        void __iomem *base;
        int ret;
 
@@ -417,8 +416,7 @@ static int imx_gpc_probe(struct platform_device *pdev)
            !pgc_node)
                return 0;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(&pdev->dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
index 176f473..31b8d00 100644 (file)
@@ -136,8 +136,8 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
                GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
        const bool enable_power_control = !on;
        const bool has_regulator = !IS_ERR(domain->regulator);
-       unsigned long deadline;
        int i, ret = 0;
+       u32 pxx_req;
 
        regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING,
                           domain->bits.map, domain->bits.map);
@@ -169,30 +169,19 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
         * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait
         * for PUP_REQ/PDN_REQ bit to be cleared
         */
-       deadline = jiffies + msecs_to_jiffies(1);
-       while (true) {
-               u32 pxx_req;
-
-               regmap_read(domain->regmap, offset, &pxx_req);
-
-               if (!(pxx_req & domain->bits.pxx))
-                       break;
-
-               if (time_after(jiffies, deadline)) {
-                       dev_err(domain->dev, "falied to command PGC\n");
-                       ret = -ETIMEDOUT;
-                       /*
-                        * If we were in a process of enabling a
-                        * domain and failed we might as well disable
-                        * the regulator we just enabled. And if it
-                        * was the opposite situation and we failed to
-                        * power down -- keep the regulator on
-                        */
-                       on = !on;
-                       break;
-               }
-
-               cpu_relax();
+       ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req,
+                                      !(pxx_req & domain->bits.pxx),
+                                      0, USEC_PER_MSEC);
+       if (ret) {
+               dev_err(domain->dev, "failed to command PGC\n");
+               /*
+                * If we were in a process of enabling a
+                * domain and failed we might as well disable
+                * the regulator we just enabled. And if it
+                * was the opposite situation and we failed to
+                * power down -- keep the regulator on
+                */
+               on = !on;
        }
 
        if (enable_power_control)
@@ -574,7 +563,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct device_node *pgc_np, *np;
        struct regmap *regmap;
-       struct resource *res;
        void __iomem *base;
        int ret;
 
@@ -584,8 +572,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res  = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       base = devm_ioremap_resource(dev, res);
+       base = devm_platform_ioremap_resource(pdev, 0);
        if (IS_ERR(base))
                return PTR_ERR(base);
 
diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c
new file mode 100644 (file)
index 0000000..fc6429f
--- /dev/null
@@ -0,0 +1,115 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2019 NXP.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#define REV_B1                         0x21
+
+#define IMX8MQ_SW_INFO_B1              0x40
+#define IMX8MQ_SW_MAGIC_B1             0xff0055aa
+
+struct imx8_soc_data {
+       char *name;
+       u32 (*soc_revision)(void);
+};
+
+static u32 __init imx8mq_soc_revision(void)
+{
+       struct device_node *np;
+       void __iomem *ocotp_base;
+       u32 magic;
+       u32 rev = 0;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp");
+       if (!np)
+               goto out;
+
+       ocotp_base = of_iomap(np, 0);
+       WARN_ON(!ocotp_base);
+
+       magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1);
+       if (magic == IMX8MQ_SW_MAGIC_B1)
+               rev = REV_B1;
+
+       iounmap(ocotp_base);
+
+out:
+       of_node_put(np);
+       return rev;
+}
+
+static const struct imx8_soc_data imx8mq_soc_data = {
+       .name = "i.MX8MQ",
+       .soc_revision = imx8mq_soc_revision,
+};
+
+static const struct of_device_id imx8_soc_match[] = {
+       { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, },
+       { }
+};
+
+#define imx8_revision(soc_rev) \
+       soc_rev ? \
+       kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf,  soc_rev & 0xf) : \
+       "unknown"
+
+static int __init imx8_soc_init(void)
+{
+       struct soc_device_attribute *soc_dev_attr;
+       struct soc_device *soc_dev;
+       struct device_node *root;
+       const struct of_device_id *id;
+       u32 soc_rev = 0;
+       const struct imx8_soc_data *data;
+       int ret;
+
+       soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+       if (!soc_dev_attr)
+               return -ENODEV;
+
+       soc_dev_attr->family = "Freescale i.MX";
+
+       root = of_find_node_by_path("/");
+       ret = of_property_read_string(root, "model", &soc_dev_attr->machine);
+       if (ret)
+               goto free_soc;
+
+       id = of_match_node(imx8_soc_match, root);
+       if (!id)
+               goto free_soc;
+
+       of_node_put(root);
+
+       data = id->data;
+       if (data) {
+               soc_dev_attr->soc_id = data->name;
+               if (data->soc_revision)
+                       soc_rev = data->soc_revision();
+       }
+
+       soc_dev_attr->revision = imx8_revision(soc_rev);
+       if (!soc_dev_attr->revision)
+               goto free_soc;
+
+       soc_dev = soc_device_register(soc_dev_attr);
+       if (IS_ERR(soc_dev))
+               goto free_rev;
+
+       return 0;
+
+free_rev:
+       kfree(soc_dev_attr->revision);
+free_soc:
+       kfree(soc_dev_attr);
+       of_node_put(root);
+       return -ENODEV;
+}
+device_initcall(imx8_soc_init);
index 8236a6c..c4449a1 100644 (file)
@@ -381,6 +381,10 @@ enum pwrap_regs {
        PWRAP_EXT_GPS_AUXADC_RDATA_ADDR,
        PWRAP_GPSINF_0_STA,
        PWRAP_GPSINF_1_STA,
+
+       /* MT8516 only regs */
+       PWRAP_OP_TYPE,
+       PWRAP_MSB_FIRST,
 };
 
 static int mt2701_regs[] = {
@@ -852,6 +856,91 @@ static int mt8183_regs[] = {
        [PWRAP_WACS2_VLDCLR] =                  0xC28,
 };
 
+static int mt8516_regs[] = {
+       [PWRAP_MUX_SEL] =               0x0,
+       [PWRAP_WRAP_EN] =               0x4,
+       [PWRAP_DIO_EN] =                0x8,
+       [PWRAP_SIDLY] =                 0xc,
+       [PWRAP_RDDMY] =                 0x10,
+       [PWRAP_SI_CK_CON] =             0x14,
+       [PWRAP_CSHEXT_WRITE] =          0x18,
+       [PWRAP_CSHEXT_READ] =           0x1c,
+       [PWRAP_CSLEXT_START] =          0x20,
+       [PWRAP_CSLEXT_END] =            0x24,
+       [PWRAP_STAUPD_PRD] =            0x28,
+       [PWRAP_STAUPD_GRPEN] =          0x2c,
+       [PWRAP_STAUPD_MAN_TRIG] =       0x40,
+       [PWRAP_STAUPD_STA] =            0x44,
+       [PWRAP_WRAP_STA] =              0x48,
+       [PWRAP_HARB_INIT] =             0x4c,
+       [PWRAP_HARB_HPRIO] =            0x50,
+       [PWRAP_HIPRIO_ARB_EN] =         0x54,
+       [PWRAP_HARB_STA0] =             0x58,
+       [PWRAP_HARB_STA1] =             0x5c,
+       [PWRAP_MAN_EN] =                0x60,
+       [PWRAP_MAN_CMD] =               0x64,
+       [PWRAP_MAN_RDATA] =             0x68,
+       [PWRAP_MAN_VLDCLR] =            0x6c,
+       [PWRAP_WACS0_EN] =              0x70,
+       [PWRAP_INIT_DONE0] =            0x74,
+       [PWRAP_WACS0_CMD] =             0x78,
+       [PWRAP_WACS0_RDATA] =           0x7c,
+       [PWRAP_WACS0_VLDCLR] =          0x80,
+       [PWRAP_WACS1_EN] =              0x84,
+       [PWRAP_INIT_DONE1] =            0x88,
+       [PWRAP_WACS1_CMD] =             0x8c,
+       [PWRAP_WACS1_RDATA] =           0x90,
+       [PWRAP_WACS1_VLDCLR] =          0x94,
+       [PWRAP_WACS2_EN] =              0x98,
+       [PWRAP_INIT_DONE2] =            0x9c,
+       [PWRAP_WACS2_CMD] =             0xa0,
+       [PWRAP_WACS2_RDATA] =           0xa4,
+       [PWRAP_WACS2_VLDCLR] =          0xa8,
+       [PWRAP_INT_EN] =                0xac,
+       [PWRAP_INT_FLG_RAW] =           0xb0,
+       [PWRAP_INT_FLG] =               0xb4,
+       [PWRAP_INT_CLR] =               0xb8,
+       [PWRAP_SIG_ADR] =               0xbc,
+       [PWRAP_SIG_MODE] =              0xc0,
+       [PWRAP_SIG_VALUE] =             0xc4,
+       [PWRAP_SIG_ERRVAL] =            0xc8,
+       [PWRAP_CRC_EN] =                0xcc,
+       [PWRAP_TIMER_EN] =              0xd0,
+       [PWRAP_TIMER_STA] =             0xd4,
+       [PWRAP_WDT_UNIT] =              0xd8,
+       [PWRAP_WDT_SRC_EN] =            0xdc,
+       [PWRAP_WDT_FLG] =               0xe0,
+       [PWRAP_DEBUG_INT_SEL] =         0xe4,
+       [PWRAP_DVFS_ADR0] =             0xe8,
+       [PWRAP_DVFS_WDATA0] =           0xec,
+       [PWRAP_DVFS_ADR1] =             0xf0,
+       [PWRAP_DVFS_WDATA1] =           0xf4,
+       [PWRAP_DVFS_ADR2] =             0xf8,
+       [PWRAP_DVFS_WDATA2] =           0xfc,
+       [PWRAP_DVFS_ADR3] =             0x100,
+       [PWRAP_DVFS_WDATA3] =           0x104,
+       [PWRAP_DVFS_ADR4] =             0x108,
+       [PWRAP_DVFS_WDATA4] =           0x10c,
+       [PWRAP_DVFS_ADR5] =             0x110,
+       [PWRAP_DVFS_WDATA5] =           0x114,
+       [PWRAP_DVFS_ADR6] =             0x118,
+       [PWRAP_DVFS_WDATA6] =           0x11c,
+       [PWRAP_DVFS_ADR7] =             0x120,
+       [PWRAP_DVFS_WDATA7] =           0x124,
+       [PWRAP_SPMINF_STA] =            0x128,
+       [PWRAP_CIPHER_KEY_SEL] =        0x12c,
+       [PWRAP_CIPHER_IV_SEL] =         0x130,
+       [PWRAP_CIPHER_EN] =             0x134,
+       [PWRAP_CIPHER_RDY] =            0x138,
+       [PWRAP_CIPHER_MODE] =           0x13c,
+       [PWRAP_CIPHER_SWRST] =          0x140,
+       [PWRAP_DCM_EN] =                0x144,
+       [PWRAP_DCM_DBC_PRD] =           0x148,
+       [PWRAP_SW_RST] =                0x168,
+       [PWRAP_OP_TYPE] =               0x16c,
+       [PWRAP_MSB_FIRST] =             0x170,
+};
+
 enum pmic_type {
        PMIC_MT6323,
        PMIC_MT6351,
@@ -869,6 +958,7 @@ enum pwrap_type {
        PWRAP_MT8135,
        PWRAP_MT8173,
        PWRAP_MT8183,
+       PWRAP_MT8516,
 };
 
 struct pmic_wrapper;
@@ -1281,7 +1371,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
 static int pwrap_init_cipher(struct pmic_wrapper *wrp)
 {
        int ret;
-       u32 rdata;
+       u32 rdata = 0;
 
        pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST);
        pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST);
@@ -1297,6 +1387,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
        case PWRAP_MT6765:
        case PWRAP_MT6797:
        case PWRAP_MT8173:
+       case PWRAP_MT8516:
                pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
                break;
        case PWRAP_MT7622:
@@ -1478,7 +1569,8 @@ static int pwrap_init(struct pmic_wrapper *wrp)
 {
        int ret;
 
-       reset_control_reset(wrp->rstc);
+       if (wrp->rstc)
+               reset_control_reset(wrp->rstc);
        if (wrp->rstc_bridge)
                reset_control_reset(wrp->rstc_bridge);
 
@@ -1764,6 +1856,18 @@ static const struct pmic_wrapper_type pwrap_mt8183 = {
        .init_soc_specific = pwrap_mt8183_init_soc_specific,
 };
 
+static struct pmic_wrapper_type pwrap_mt8516 = {
+       .regs = mt8516_regs,
+       .type = PWRAP_MT8516,
+       .arb_en_all = 0xff,
+       .int_en_all = ~(u32)(BIT(31) | BIT(2)),
+       .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
+       .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
+       .caps = PWRAP_CAP_DCM,
+       .init_reg_clock = pwrap_mt2701_init_reg_clock,
+       .init_soc_specific = NULL,
+};
+
 static const struct of_device_id of_pwrap_match_tbl[] = {
        {
                .compatible = "mediatek,mt2701-pwrap",
@@ -1787,6 +1891,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
                .compatible = "mediatek,mt8183-pwrap",
                .data = &pwrap_mt8183,
        }, {
+               .compatible = "mediatek,mt8516-pwrap",
+               .data = &pwrap_mt8516,
+       }, {
                /* sentinel */
        }
 };
index c701b3b..f6c3d17 100644 (file)
@@ -248,8 +248,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev)
        }
 
        cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB);
-       if (IS_ERR_OR_NULL(cmd_db_header)) {
-               ret = PTR_ERR(cmd_db_header);
+       if (!cmd_db_header) {
+               ret = -ENOMEM;
                cmd_db_header = NULL;
                return ret;
        }
index c239a28..f9e309f 100644 (file)
@@ -345,8 +345,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
        struct qmi_handle *qmi = txn->qmi;
        int ret;
 
-       ret = wait_for_completion_interruptible_timeout(&txn->completion,
-                                                       timeout);
+       ret = wait_for_completion_timeout(&txn->completion, timeout);
 
        mutex_lock(&qmi->txn_lock);
        mutex_lock(&txn->lock);
@@ -354,9 +353,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout)
        mutex_unlock(&txn->lock);
        mutex_unlock(&qmi->txn_lock);
 
-       if (ret < 0)
-               return ret;
-       else if (ret == 0)
+       if (ret == 0)
                return -ETIMEDOUT;
        else
                return txn->result;
index 7200d76..6f5e8be 100644 (file)
@@ -137,6 +137,26 @@ static struct class rmtfs_class = {
        .name           = "rmtfs",
 };
 
+static int qcom_rmtfs_mem_mmap(struct file *filep, struct vm_area_struct *vma)
+{
+       struct qcom_rmtfs_mem *rmtfs_mem = filep->private_data;
+
+       if (vma->vm_end - vma->vm_start > rmtfs_mem->size) {
+               dev_dbg(&rmtfs_mem->dev,
+                       "vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n",
+                       vma->vm_end, vma->vm_start,
+                       (vma->vm_end - vma->vm_start), &rmtfs_mem->size);
+               return -EINVAL;
+       }
+
+       vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
+       return remap_pfn_range(vma,
+                              vma->vm_start,
+                              rmtfs_mem->addr >> PAGE_SHIFT,
+                              vma->vm_end - vma->vm_start,
+                              vma->vm_page_prot);
+}
+
 static const struct file_operations qcom_rmtfs_mem_fops = {
        .owner = THIS_MODULE,
        .open = qcom_rmtfs_mem_open,
@@ -144,6 +164,7 @@ static const struct file_operations qcom_rmtfs_mem_fops = {
        .write = qcom_rmtfs_mem_write,
        .release = qcom_rmtfs_mem_release,
        .llseek = default_llseek,
+       .mmap = qcom_rmtfs_mem_mmap,
 };
 
 static void qcom_rmtfs_mem_release_device(struct device *dev)
index 75bd9a8..e278fc1 100644 (file)
@@ -459,7 +459,7 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg,
        do {
                slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS,
                                                  i, msg->num_cmds, 0);
-               if (slot == tcs->num_tcs * tcs->ncpt)
+               if (slot >= tcs->num_tcs * tcs->ncpt)
                        return -ENOMEM;
                i += tcs->ncpt;
        } while (slot + msg->num_cmds - 1 >= i);
index 4af96e6..3299cf5 100644 (file)
@@ -335,6 +335,9 @@ static int __init renesas_soc_init(void)
                /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
                if ((product & 0x7fff) == 0x5210)
                        product ^= 0x11;
+               /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */
+               if ((product & 0x7fff) == 0x5211)
+                       product ^= 0x12;
                if (soc->id && ((product >> 8) & 0xff) != soc->id) {
                        pr_warn("SoC mismatch (product = 0x%x)\n", product);
                        return -ENODEV;
index 96882ff..3b81e1d 100644 (file)
@@ -66,9 +66,11 @@ static const struct rockchip_grf_info rk3228_grf __initconst = {
 };
 
 #define RK3288_GRF_SOC_CON0            0x244
+#define RK3288_GRF_SOC_CON2            0x24c
 
 static const struct rockchip_grf_value rk3288_defaults[] __initconst = {
        { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) },
+       { "pwm select", RK3288_GRF_SOC_CON2, HIWORD_UPDATE(1, 1, 0) },
 };
 
 static const struct rockchip_grf_info rk3288_grf __initconst = {
index 0df2585..5648e5c 100644 (file)
@@ -272,6 +272,14 @@ static const char * const tegra30_reset_sources[] = {
        "WATCHDOG",
        "SENSOR",
        "SW_MAIN",
+       "LP0"
+};
+
+static const char * const tegra210_reset_sources[] = {
+       "POWER_ON_RESET",
+       "WATCHDOG",
+       "SENSOR",
+       "SW_MAIN",
        "LP0",
        "AOTAG"
 };
@@ -656,10 +664,15 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain)
        int err;
 
        err = tegra_powergate_power_up(pg, true);
-       if (err)
+       if (err) {
                dev_err(dev, "failed to turn on PM domain %s: %d\n",
                        pg->genpd.name, err);
+               goto out;
+       }
+
+       reset_control_release(pg->reset);
 
+out:
        return err;
 }
 
@@ -669,10 +682,18 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain)
        struct device *dev = pg->pmc->dev;
        int err;
 
+       err = reset_control_acquire(pg->reset);
+       if (err < 0) {
+               pr_err("failed to acquire resets: %d\n", err);
+               return err;
+       }
+
        err = tegra_powergate_power_down(pg);
-       if (err)
+       if (err) {
                dev_err(dev, "failed to turn off PM domain %s: %d\n",
                        pg->genpd.name, err);
+               reset_control_release(pg->reset);
+       }
 
        return err;
 }
@@ -937,38 +958,53 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg,
        struct device *dev = pg->pmc->dev;
        int err;
 
-       pg->reset = of_reset_control_array_get_exclusive(np);
+       pg->reset = of_reset_control_array_get_exclusive_released(np);
        if (IS_ERR(pg->reset)) {
                err = PTR_ERR(pg->reset);
                dev_err(dev, "failed to get device resets: %d\n", err);
                return err;
        }
 
-       if (off)
+       err = reset_control_acquire(pg->reset);
+       if (err < 0) {
+               pr_err("failed to acquire resets: %d\n", err);
+               goto out;
+       }
+
+       if (off) {
                err = reset_control_assert(pg->reset);
-       else
+       } else {
                err = reset_control_deassert(pg->reset);
+               if (err < 0)
+                       goto out;
 
-       if (err)
+               reset_control_release(pg->reset);
+       }
+
+out:
+       if (err) {
+               reset_control_release(pg->reset);
                reset_control_put(pg->reset);
+       }
 
        return err;
 }
 
-static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
+static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 {
        struct device *dev = pmc->dev;
        struct tegra_powergate *pg;
-       int id, err;
+       int id, err = 0;
        bool off;
 
        pg = kzalloc(sizeof(*pg), GFP_KERNEL);
        if (!pg)
-               return;
+               return -ENOMEM;
 
        id = tegra_powergate_lookup(pmc, np->name);
        if (id < 0) {
                dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id);
+               err = -ENODEV;
                goto free_mem;
        }
 
@@ -1021,7 +1057,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np)
 
        dev_dbg(dev, "added PM domain %s\n", pg->genpd.name);
 
-       return;
+       return 0;
 
 remove_genpd:
        pm_genpd_remove(&pg->genpd);
@@ -1040,25 +1076,67 @@ set_available:
 
 free_mem:
        kfree(pg);
+
+       return err;
 }
 
-static void tegra_powergate_init(struct tegra_pmc *pmc,
-                                struct device_node *parent)
+static int tegra_powergate_init(struct tegra_pmc *pmc,
+                               struct device_node *parent)
 {
        struct device_node *np, *child;
-       unsigned int i;
+       int err = 0;
+
+       np = of_get_child_by_name(parent, "powergates");
+       if (!np)
+               return 0;
+
+       for_each_child_of_node(np, child) {
+               err = tegra_powergate_add(pmc, child);
+               if (err < 0) {
+                       of_node_put(child);
+                       break;
+               }
+       }
+
+       of_node_put(np);
+
+       return err;
+}
+
+static void tegra_powergate_remove(struct generic_pm_domain *genpd)
+{
+       struct tegra_powergate *pg = to_powergate(genpd);
+
+       reset_control_put(pg->reset);
+
+       while (pg->num_clks--)
+               clk_put(pg->clks[pg->num_clks]);
+
+       kfree(pg->clks);
 
-       /* Create a bitmap of the available and valid partitions */
-       for (i = 0; i < pmc->soc->num_powergates; i++)
-               if (pmc->soc->powergates[i])
-                       set_bit(i, pmc->powergates_available);
+       set_bit(pg->id, pmc->powergates_available);
+
+       kfree(pg);
+}
+
+static void tegra_powergate_remove_all(struct device_node *parent)
+{
+       struct generic_pm_domain *genpd;
+       struct device_node *np, *child;
 
        np = of_get_child_by_name(parent, "powergates");
        if (!np)
                return;
 
-       for_each_child_of_node(np, child)
-               tegra_powergate_add(pmc, child);
+       for_each_child_of_node(np, child) {
+               of_genpd_del_provider(child);
+
+               genpd = of_genpd_remove_last(child);
+               if (IS_ERR(genpd))
+                       continue;
+
+               tegra_powergate_remove(genpd);
+       }
 
        of_node_put(np);
 }
@@ -1709,13 +1787,16 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
 static ssize_t reset_reason_show(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
-       u32 value, rst_src;
+       u32 value;
 
        value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
-       rst_src = (value & pmc->soc->regs->rst_source_mask) >>
-                       pmc->soc->regs->rst_source_shift;
+       value &= pmc->soc->regs->rst_source_mask;
+       value >>= pmc->soc->regs->rst_source_shift;
+
+       if (WARN_ON(value >= pmc->soc->num_reset_sources))
+               return sprintf(buf, "%s\n", "UNKNOWN");
 
-       return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]);
+       return sprintf(buf, "%s\n", pmc->soc->reset_sources[value]);
 }
 
 static DEVICE_ATTR_RO(reset_reason);
@@ -1723,13 +1804,16 @@ static DEVICE_ATTR_RO(reset_reason);
 static ssize_t reset_level_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
-       u32 value, rst_lvl;
+       u32 value;
 
        value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status);
-       rst_lvl = (value & pmc->soc->regs->rst_level_mask) >>
-                       pmc->soc->regs->rst_level_shift;
+       value &= pmc->soc->regs->rst_level_mask;
+       value >>= pmc->soc->regs->rst_level_shift;
 
-       return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]);
+       if (WARN_ON(value >= pmc->soc->num_reset_levels))
+               return sprintf(buf, "%s\n", "UNKNOWN");
+
+       return sprintf(buf, "%s\n", pmc->soc->reset_levels[value]);
 }
 
 static DEVICE_ATTR_RO(reset_level);
@@ -1999,7 +2083,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
        if (IS_ENABLED(CONFIG_DEBUG_FS)) {
                err = tegra_powergate_debugfs_init();
                if (err < 0)
-                       return err;
+                       goto cleanup_sysfs;
        }
 
        err = register_restart_handler(&tegra_pmc_restart_handler);
@@ -2013,9 +2097,13 @@ static int tegra_pmc_probe(struct platform_device *pdev)
        if (err)
                goto cleanup_restart_handler;
 
+       err = tegra_powergate_init(pmc, pdev->dev.of_node);
+       if (err < 0)
+               goto cleanup_powergates;
+
        err = tegra_pmc_irq_init(pmc);
        if (err < 0)
-               goto cleanup_restart_handler;
+               goto cleanup_powergates;
 
        mutex_lock(&pmc->powergates_lock);
        iounmap(pmc->base);
@@ -2026,10 +2114,15 @@ static int tegra_pmc_probe(struct platform_device *pdev)
 
        return 0;
 
+cleanup_powergates:
+       tegra_powergate_remove_all(pdev->dev.of_node);
 cleanup_restart_handler:
        unregister_restart_handler(&tegra_pmc_restart_handler);
 cleanup_debugfs:
        debugfs_remove(pmc->debugfs);
+cleanup_sysfs:
+       device_remove_file(&pdev->dev, &dev_attr_reset_reason);
+       device_remove_file(&pdev->dev, &dev_attr_reset_level);
        return err;
 }
 
@@ -2185,7 +2278,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
        .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2236,7 +2329,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
        .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2347,7 +2440,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
        .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2452,8 +2545,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
        .regs = &tegra20_pmc_regs,
        .init = tegra20_pmc_init,
        .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
-       .reset_sources = tegra30_reset_sources,
-       .num_reset_sources = 5,
+       .reset_sources = tegra210_reset_sources,
+       .num_reset_sources = ARRAY_SIZE(tegra210_reset_sources),
        .reset_levels = NULL,
        .num_reset_levels = 0,
 };
@@ -2578,9 +2671,9 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
        .init = NULL,
        .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
        .reset_sources = tegra186_reset_sources,
-       .num_reset_sources = 14,
+       .num_reset_sources = ARRAY_SIZE(tegra186_reset_sources),
        .reset_levels = tegra186_reset_levels,
-       .num_reset_levels = 3,
+       .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels),
        .num_wake_events = ARRAY_SIZE(tegra186_wake_events),
        .wake_events = tegra186_wake_events,
 };
@@ -2719,6 +2812,7 @@ static int __init tegra_pmc_early_init(void)
        const struct of_device_id *match;
        struct device_node *np;
        struct resource regs;
+       unsigned int i;
        bool invert;
 
        mutex_init(&pmc->powergates_lock);
@@ -2775,7 +2869,10 @@ static int __init tegra_pmc_early_init(void)
                if (pmc->soc->maybe_tz_only)
                        pmc->tz_only = tegra_pmc_detect_tz_only(pmc);
 
-               tegra_powergate_init(pmc, np);
+               /* Create a bitmap of the available and valid partitions */
+               for (i = 0; i < pmc->soc->num_powergates; i++)
+                       if (pmc->soc->powergates[i])
+                               set_bit(i, pmc->powergates_available);
 
                /*
                 * Invert the interrupt polarity if a PMC device tree node
index be4570b..57960e9 100644 (file)
@@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA
 config AMX3_PM
        tristate "AMx3 Power Management"
        depends on SOC_AM33XX || SOC_AM43XX
-       depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM
+       depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP
        help
          Enable power management on AM335x and AM437x. Required for suspend to mem
          and standby states on both AM335x and AM437x platforms and for deeper cpuidle
-         c-states on AM335x.
+         c-states on AM335x. Also required for rtc and ddr in self-refresh low
+         power mode on AM437x platforms.
 
 config WKUP_M3_IPC
        tristate "TI AMx3 Wkup-M3 IPC Driver"
index d0dab32..fc5802c 100644 (file)
@@ -6,6 +6,7 @@
  *     Vaibhav Bedia, Dave Gerlach
  */
 
+#include <linux/clk.h>
 #include <linux/cpu.h>
 #include <linux/err.h>
 #include <linux/genalloc.h>
 #include <linux/init.h>
 #include <linux/io.h>
 #include <linux/module.h>
+#include <linux/nvmem-consumer.h>
 #include <linux/of.h>
 #include <linux/platform_data/pm33xx.h>
 #include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/rtc/rtc-omap.h>
 #include <linux/sizes.h>
 #include <linux/sram.h>
 #include <linux/suspend.h>
 #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \
                                         (unsigned long)pm_sram->do_wfi)
 
+#define RTC_SCRATCH_RESUME_REG 0
+#define RTC_SCRATCH_MAGIC_REG  1
+#define RTC_REG_BOOT_MAGIC     0x8cd0 /* RTC */
+#define GIC_INT_SET_PENDING_BASE 0x200
+#define AM43XX_GIC_DIST_BASE   0x48241000
+
+static u32 rtc_magic_val;
+
 static int (*am33xx_do_wfi_sram)(unsigned long unused);
 static phys_addr_t am33xx_do_wfi_sram_phys;
 
 static struct gen_pool *sram_pool, *sram_pool_data;
 static unsigned long ocmcram_location, ocmcram_location_data;
 
+static struct rtc_device *omap_rtc;
+static void __iomem *gic_dist_base;
+
 static struct am33xx_pm_platform_data *pm_ops;
 static struct am33xx_pm_sram_addr *pm_sram;
 
 static struct device *pm33xx_dev;
 static struct wkup_m3_ipc *m3_ipc;
 
+#ifdef CONFIG_SUSPEND
+static int rtc_only_idle;
+static int retrigger_irq;
 static unsigned long suspend_wfi_flags;
 
+static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0,
+       .src = "Unknown",
+};
+
+static struct wkup_m3_wakeup_src rtc_alarm_wakeup = {
+       .irq_nr = 108, .src = "RTC Alarm",
+};
+
+static struct wkup_m3_wakeup_src rtc_ext_wakeup = {
+       .irq_nr = 0, .src = "Ext wakeup",
+};
+#endif
+
 static u32 sram_suspend_address(unsigned long addr)
 {
        return ((unsigned long)am33xx_do_wfi_sram +
                AMX3_PM_SRAM_SYMBOL_OFFSET(addr));
 }
 
+static int am33xx_push_sram_idle(void)
+{
+       struct am33xx_pm_ro_sram_data ro_sram_data;
+       int ret;
+       u32 table_addr, ro_data_addr;
+       void *copy_addr;
+
+       ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
+       ro_sram_data.amx3_pm_sram_data_phys =
+               gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
+       ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
+
+       /* Save physical address to calculate resume offset during pm init */
+       am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
+                                                       ocmcram_location);
+
+       am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location,
+                                           pm_sram->do_wfi,
+                                           *pm_sram->do_wfi_sz);
+       if (!am33xx_do_wfi_sram) {
+               dev_err(pm33xx_dev,
+                       "PM: %s: am33xx_do_wfi copy to sram failed\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       table_addr =
+               sram_suspend_address((unsigned long)pm_sram->emif_sram_table);
+       ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr);
+       if (ret) {
+               dev_dbg(pm33xx_dev,
+                       "PM: %s: EMIF function copy failed\n", __func__);
+               return -EPROBE_DEFER;
+       }
+
+       ro_data_addr =
+               sram_suspend_address((unsigned long)pm_sram->ro_sram_data);
+       copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr,
+                                  &ro_sram_data,
+                                  sizeof(ro_sram_data));
+       if (!copy_addr) {
+               dev_err(pm33xx_dev,
+                       "PM: %s: ro_sram_data copy to sram failed\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int __init am43xx_map_gic(void)
+{
+       gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K);
+
+       if (!gic_dist_base)
+               return -ENOMEM;
+
+       return 0;
+}
+
 #ifdef CONFIG_SUSPEND
+struct wkup_m3_wakeup_src rtc_wake_src(void)
+{
+       u32 i;
+
+       i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40;
+
+       if (i) {
+               retrigger_irq = rtc_alarm_wakeup.irq_nr;
+               return rtc_alarm_wakeup;
+       }
+
+       retrigger_irq = rtc_ext_wakeup.irq_nr;
+
+       return rtc_ext_wakeup;
+}
+
+int am33xx_rtc_only_idle(unsigned long wfi_flags)
+{
+       omap_rtc_power_off_program(&omap_rtc->dev);
+       am33xx_do_wfi_sram(wfi_flags);
+       return 0;
+}
+
 static int am33xx_pm_suspend(suspend_state_t suspend_state)
 {
        int i, ret = 0;
 
-       ret = pm_ops->soc_suspend((unsigned long)suspend_state,
-                                 am33xx_do_wfi_sram, suspend_wfi_flags);
+       if (suspend_state == PM_SUSPEND_MEM &&
+           pm_ops->check_off_mode_enable()) {
+               pm_ops->prepare_rtc_suspend();
+               pm_ops->save_context();
+               suspend_wfi_flags |= WFI_FLAG_RTC_ONLY;
+               clk_save_context();
+               ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle,
+                                         suspend_wfi_flags);
+
+               suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY;
+
+               if (!ret) {
+                       clk_restore_context();
+                       pm_ops->restore_context();
+                       m3_ipc->ops->set_rtc_only(m3_ipc);
+                       am33xx_push_sram_idle();
+               }
+       } else {
+               ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram,
+                                         suspend_wfi_flags);
+       }
 
        if (ret) {
                dev_err(pm33xx_dev, "PM: Kernel suspend failure\n");
@@ -77,8 +210,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state)
                                "PM: CM3 returned unknown result = %d\n", i);
                        ret = -1;
                }
+
+               /* print the wakeup reason */
+               if (rtc_only_idle) {
+                       wakeup_src = rtc_wake_src();
+                       pr_info("PM: Wakeup source %s\n", wakeup_src.src);
+               } else {
+                       pr_info("PM: Wakeup source %s\n",
+                               m3_ipc->ops->request_wake_src(m3_ipc));
+               }
        }
 
+       if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable())
+               pm_ops->prepare_rtc_resume();
+
        return ret;
 }
 
@@ -101,6 +246,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state)
 static int am33xx_pm_begin(suspend_state_t state)
 {
        int ret = -EINVAL;
+       struct nvmem_device *nvmem;
+
+       if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) {
+               nvmem = devm_nvmem_device_get(&omap_rtc->dev,
+                                             "omap_rtc_scratch0");
+               if (nvmem)
+                       nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
+                                          (void *)&rtc_magic_val);
+               rtc_only_idle = 1;
+       } else {
+               rtc_only_idle = 0;
+       }
 
        switch (state) {
        case PM_SUSPEND_MEM:
@@ -116,7 +273,28 @@ static int am33xx_pm_begin(suspend_state_t state)
 
 static void am33xx_pm_end(void)
 {
+       u32 val = 0;
+       struct nvmem_device *nvmem;
+
+       nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0");
        m3_ipc->ops->finish_low_power(m3_ipc);
+       if (rtc_only_idle) {
+               if (retrigger_irq)
+                       /*
+                        * 32 bits of Interrupt Set-Pending correspond to 32
+                        * 32 interrupts. Compute the bit offset of the
+                        * Interrupt and set that particular bit
+                        * Compute the register offset by dividing interrupt
+                        * number by 32 and mutiplying by 4
+                        */
+                       writel_relaxed(1 << (retrigger_irq & 31),
+                                      gic_dist_base + GIC_INT_SET_PENDING_BASE
+                                      + retrigger_irq / 32 * 4);
+                       nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4,
+                                          (void *)&val);
+       }
+
+       rtc_only_idle = 0;
 }
 
 static int am33xx_pm_valid(suspend_state_t state)
@@ -219,51 +397,37 @@ mpu_put_node:
        return ret;
 }
 
-static int am33xx_push_sram_idle(void)
+static int am33xx_pm_rtc_setup(void)
 {
-       struct am33xx_pm_ro_sram_data ro_sram_data;
-       int ret;
-       u32 table_addr, ro_data_addr;
-       void *copy_addr;
-
-       ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data;
-       ro_sram_data.amx3_pm_sram_data_phys =
-               gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data);
-       ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr();
+       struct device_node *np;
+       unsigned long val = 0;
+       struct nvmem_device *nvmem;
 
-       /* Save physical address to calculate resume offset during pm init */
-       am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool,
-                                                       ocmcram_location);
+       np = of_find_node_by_name(NULL, "rtc");
 
-       am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location,
-                                           pm_sram->do_wfi,
-                                           *pm_sram->do_wfi_sz);
-       if (!am33xx_do_wfi_sram) {
-               dev_err(pm33xx_dev,
-                       "PM: %s: am33xx_do_wfi copy to sram failed\n",
-                       __func__);
-               return -ENODEV;
-       }
-
-       table_addr =
-               sram_suspend_address((unsigned long)pm_sram->emif_sram_table);
-       ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr);
-       if (ret) {
-               dev_dbg(pm33xx_dev,
-                       "PM: %s: EMIF function copy failed\n", __func__);
-               return -EPROBE_DEFER;
-       }
+       if (of_device_is_available(np)) {
+               omap_rtc = rtc_class_open("rtc0");
+               if (!omap_rtc) {
+                       pr_warn("PM: rtc0 not available");
+                       return -EPROBE_DEFER;
+               }
 
-       ro_data_addr =
-               sram_suspend_address((unsigned long)pm_sram->ro_sram_data);
-       copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr,
-                                  &ro_sram_data,
-                                  sizeof(ro_sram_data));
-       if (!copy_addr) {
-               dev_err(pm33xx_dev,
-                       "PM: %s: ro_sram_data copy to sram failed\n",
-                       __func__);
-               return -ENODEV;
+               nvmem = devm_nvmem_device_get(&omap_rtc->dev,
+                                             "omap_rtc_scratch0");
+               if (nvmem) {
+                       nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
+                                         4, (void *)&rtc_magic_val);
+                       if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC)
+                               pr_warn("PM: bootloader does not support rtc-only!\n");
+
+                       nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4,
+                                          4, (void *)&val);
+                       val = pm_sram->resume_address;
+                       nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4,
+                                          4, (void *)&val);
+               }
+       } else {
+               pr_warn("PM: no-rtc available, rtc-only mode disabled.\n");
        }
 
        return 0;
@@ -284,34 +448,42 @@ static int am33xx_pm_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
+       ret = am43xx_map_gic();
+       if (ret) {
+               pr_err("PM: Could not ioremap GIC base\n");
+               return ret;
+       }
+
        pm_sram = pm_ops->get_sram_addrs();
        if (!pm_sram) {
                dev_err(dev, "PM: Cannot get PM asm function addresses!!\n");
                return -ENODEV;
        }
 
+       m3_ipc = wkup_m3_ipc_get();
+       if (!m3_ipc) {
+               pr_err("PM: Cannot get wkup_m3_ipc handle\n");
+               return -EPROBE_DEFER;
+       }
+
        pm33xx_dev = dev;
 
        ret = am33xx_pm_alloc_sram();
        if (ret)
                return ret;
 
-       ret = am33xx_push_sram_idle();
+       ret = am33xx_pm_rtc_setup();
        if (ret)
                goto err_free_sram;
 
-       m3_ipc = wkup_m3_ipc_get();
-       if (!m3_ipc) {
-               dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n");
-               ret = -EPROBE_DEFER;
+       ret = am33xx_push_sram_idle();
+       if (ret)
                goto err_free_sram;
-       }
 
        am33xx_pm_set_ipc_ops();
 
 #ifdef CONFIG_SUSPEND
        suspend_set_ops(&am33xx_pm_ops);
-#endif /* CONFIG_SUSPEND */
 
        /*
         * For a system suspend we must flush the caches, we want
@@ -323,6 +495,7 @@ static int am33xx_pm_probe(struct platform_device *pdev)
        suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH;
        suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF;
        suspend_wfi_flags |= WFI_FLAG_WAKE_M3;
+#endif /* CONFIG_SUSPEND */
 
        ret = pm_ops->init();
        if (ret) {
index 354d256..600f57c 100644 (file)
@@ -23,6 +23,8 @@
 /* Flag stating if PM nodes mapped to the PM domain has been requested */
 #define ZYNQMP_PM_DOMAIN_REQUESTED     BIT(0)
 
+static const struct zynqmp_eemi_ops *eemi_ops;
+
 /**
  * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain
  * @gpd:               Generic power domain
@@ -71,9 +73,8 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain)
 {
        int ret;
        struct zynqmp_pm_domain *pd;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->set_requirement)
+       if (!eemi_ops->set_requirement)
                return -ENXIO;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -107,9 +108,8 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain)
        struct zynqmp_pm_domain *pd;
        u32 capabilities = 0;
        bool may_wakeup;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->set_requirement)
+       if (!eemi_ops->set_requirement)
                return -ENXIO;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -160,9 +160,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain,
 {
        int ret;
        struct zynqmp_pm_domain *pd;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->request_node)
+       if (!eemi_ops->request_node)
                return -ENXIO;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -197,9 +196,8 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain,
 {
        int ret;
        struct zynqmp_pm_domain *pd;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->release_node)
+       if (!eemi_ops->release_node)
                return;
 
        pd = container_of(domain, struct zynqmp_pm_domain, gpd);
@@ -266,6 +264,10 @@ static int zynqmp_gpd_probe(struct platform_device *pdev)
        struct zynqmp_pm_domain *pd;
        struct device *dev = &pdev->dev;
 
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
+
        pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL);
        if (!pd)
                return -ENOMEM;
index 771cb59..1b9d144 100644 (file)
@@ -31,6 +31,7 @@ static const char *const suspend_modes[] = {
 };
 
 static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD;
+static const struct zynqmp_eemi_ops *eemi_ops;
 
 enum pm_api_cb_id {
        PM_INIT_SUSPEND_CB = 30,
@@ -92,9 +93,8 @@ static ssize_t suspend_mode_store(struct device *dev,
                                  const char *buf, size_t count)
 {
        int md, ret = -EINVAL;
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
 
-       if (!eemi_ops || !eemi_ops->set_suspend_mode)
+       if (!eemi_ops->set_suspend_mode)
                return ret;
 
        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)
        int ret, irq;
        u32 pm_api_version;
 
-       const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
 
-       if (!eemi_ops || !eemi_ops->get_api_version || !eemi_ops->init_finalize)
+       if (!eemi_ops->get_api_version || !eemi_ops->init_finalize)
                return -ENXIO;
 
        eemi_ops->init_finalize();
index 9f83e1b..9850a0e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
+#include <linux/firmware/xlnx-zynqmp.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/module.h>
 
 #define SPI_AUTOSUSPEND_TIMEOUT                3000
 enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA};
+static const struct zynqmp_eemi_ops *eemi_ops;
 
 /**
  * struct zynqmp_qspi - Defines qspi driver instance
@@ -1021,6 +1023,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev)
        struct resource *res;
        struct device *dev = &pdev->dev;
 
+       eemi_ops = zynqmp_pm_get_eemi_ops();
+       if (IS_ERR(eemi_ops))
+               return PTR_ERR(eemi_ops);
+
        master = spi_alloc_master(&pdev->dev, sizeof(*xqspi));
        if (!master)
                return -ENOMEM;
index 0842b6e..48963ea 100644 (file)
@@ -419,9 +419,35 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn,
        return true;
 }
 
+static struct tee_shm_pool *optee_config_dyn_shm(void)
+{
+       struct tee_shm_pool_mgr *priv_mgr;
+       struct tee_shm_pool_mgr *dmabuf_mgr;
+       void *rc;
+
+       rc = optee_shm_pool_alloc_pages();
+       if (IS_ERR(rc))
+               return rc;
+       priv_mgr = rc;
+
+       rc = optee_shm_pool_alloc_pages();
+       if (IS_ERR(rc)) {
+               tee_shm_pool_mgr_destroy(priv_mgr);
+               return rc;
+       }
+       dmabuf_mgr = rc;
+
+       rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr);
+       if (IS_ERR(rc)) {
+               tee_shm_pool_mgr_destroy(priv_mgr);
+               tee_shm_pool_mgr_destroy(dmabuf_mgr);
+       }
+
+       return rc;
+}
+
 static struct tee_shm_pool *
-optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
-                         u32 sec_caps)
+optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
 {
        union {
                struct arm_smccc_res smccc;
@@ -436,10 +462,11 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
        struct tee_shm_pool_mgr *priv_mgr;
        struct tee_shm_pool_mgr *dmabuf_mgr;
        void *rc;
+       const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
 
        invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
        if (res.result.status != OPTEE_SMC_RETURN_OK) {
-               pr_info("shm service not available\n");
+               pr_err("static shm service not available\n");
                return ERR_PTR(-ENOENT);
        }
 
@@ -465,28 +492,15 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm,
        }
        vaddr = (unsigned long)va;
 
-       /*
-        * If OP-TEE can work with unregistered SHM, we will use own pool
-        * for private shm
-        */
-       if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) {
-               rc = optee_shm_pool_alloc_pages();
-               if (IS_ERR(rc))
-                       goto err_memunmap;
-               priv_mgr = rc;
-       } else {
-               const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
-
-               rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
-                                                   3 /* 8 bytes aligned */);
-               if (IS_ERR(rc))
-                       goto err_memunmap;
-               priv_mgr = rc;
-
-               vaddr += sz;
-               paddr += sz;
-               size -= sz;
-       }
+       rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz,
+                                           3 /* 8 bytes aligned */);
+       if (IS_ERR(rc))
+               goto err_memunmap;
+       priv_mgr = rc;
+
+       vaddr += sz;
+       paddr += sz;
+       size -= sz;
 
        rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT);
        if (IS_ERR(rc))
@@ -552,7 +566,7 @@ static optee_invoke_fn *get_invoke_func(struct device_node *np)
 static struct optee *optee_probe(struct device_node *np)
 {
        optee_invoke_fn *invoke_fn;
-       struct tee_shm_pool *pool;
+       struct tee_shm_pool *pool = ERR_PTR(-EINVAL);
        struct optee *optee = NULL;
        void *memremaped_shm = NULL;
        struct tee_device *teedev;
@@ -581,13 +595,17 @@ static struct optee *optee_probe(struct device_node *np)
        }
 
        /*
-        * We have no other option for shared memory, if secure world
-        * doesn't have any reserved memory we can use we can't continue.
+        * Try to use dynamic shared memory if possible
         */
-       if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
-               return ERR_PTR(-EINVAL);
+       if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM)
+               pool = optee_config_dyn_shm();
+
+       /*
+        * If dynamic shared memory is not available or failed - try static one
+        */
+       if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM))
+               pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm);
 
-       pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps);
        if (IS_ERR(pool))
                return (void *)pool;
 
index ebc5509..17ba4e4 100644 (file)
@@ -15,4 +15,9 @@
 
 #include <linux/firmware/imx/svc/misc.h>
 #include <linux/firmware/imx/svc/pm.h>
+
+int imx_scu_enable_general_irq_channel(struct device *dev);
+int imx_scu_irq_register_notifier(struct notifier_block *nb);
+int imx_scu_irq_unregister_notifier(struct notifier_block *nb);
+int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable);
 #endif /* _SC_SCI_H */
index 642dab1..1262ea6 100644 (file)
 #define        ZYNQMP_PM_CAPABILITY_WAKEUP     0x4U
 #define        ZYNQMP_PM_CAPABILITY_POWER      0x8U
 
+/*
+ * Firmware FPGA Manager flags
+ * XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration
+ * XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration
+ */
+#define XILINX_ZYNQMP_PM_FPGA_FULL     0x0U
+#define XILINX_ZYNQMP_PM_FPGA_PARTIAL  BIT(0)
+
 enum pm_api_id {
        PM_GET_API_VERSION = 1,
        PM_REQUEST_NODE = 13,
@@ -56,6 +64,8 @@ enum pm_api_id {
        PM_RESET_ASSERT = 17,
        PM_RESET_GET_STATUS,
        PM_PM_INIT_FINALIZE = 21,
+       PM_FPGA_LOAD,
+       PM_FPGA_GET_STATUS,
        PM_GET_CHIPID = 24,
        PM_IOCTL = 34,
        PM_QUERY_DATA,
@@ -258,6 +268,8 @@ struct zynqmp_pm_query_data {
 struct zynqmp_eemi_ops {
        int (*get_api_version)(u32 *version);
        int (*get_chipid)(u32 *idcode, u32 *version);
+       int (*fpga_load)(const u64 address, const u32 size, const u32 flags);
+       int (*fpga_get_status)(u32 *value);
        int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out);
        int (*clock_enable)(u32 clock_id);
        int (*clock_disable)(u32 clock_id);
@@ -293,7 +305,7 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void);
 #else
 static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
 {
-       return NULL;
+       return ERR_PTR(-ENODEV);
 }
 #endif
 
index fbf5ed7..dd59719 100644 (file)
@@ -51,6 +51,11 @@ struct am33xx_pm_platform_data {
                               unsigned long args);
        struct  am33xx_pm_sram_addr *(*get_sram_addrs)(void);
        void __iomem *(*get_rtc_base_addr)(void);
+       void (*save_context)(void);
+       void (*restore_context)(void);
+       void (*prepare_rtc_suspend)(void);
+       void (*prepare_rtc_resume)(void);
+       int (*check_off_mode_enable)(void);
 };
 
 struct am33xx_pm_sram_data {
index 95d555c..e7793fc 100644 (file)
@@ -2,6 +2,8 @@
 #ifndef _LINUX_RESET_H_
 #define _LINUX_RESET_H_
 
+#include <linux/err.h>
+#include <linux/errno.h>
 #include <linux/types.h>
 
 struct device;
diff --git a/include/linux/rtc/rtc-omap.h b/include/linux/rtc/rtc-omap.h
new file mode 100644 (file)
index 0000000..9f03a32
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _LINUX_RTCOMAP_H_
+#define _LINUX_RTCOMAP_H_
+
+int omap_rtc_power_off_program(struct device *dev);
+#endif /* _LINUX_RTCOMAP_H_ */
index 53604b0..2fc8541 100644 (file)
@@ -55,6 +55,7 @@ struct ti_emif_pm_data {
 struct ti_emif_pm_functions {
        u32 save_context;
        u32 restore_context;
+       u32 run_hw_leveling;
        u32 enter_sr;
        u32 exit_sr;
        u32 abort_sr;
@@ -126,6 +127,8 @@ static inline void ti_emif_asm_offsets(void)
               offsetof(struct ti_emif_pm_functions, save_context));
        DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET,
               offsetof(struct ti_emif_pm_functions, restore_context));
+       DEFINE(EMIF_PM_RUN_HW_LEVELING,
+              offsetof(struct ti_emif_pm_functions, run_hw_leveling));
        DEFINE(EMIF_PM_ENTER_SR_OFFSET,
               offsetof(struct ti_emif_pm_functions, enter_sr));
        DEFINE(EMIF_PM_EXIT_SR_OFFSET,