aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-10-29 18:16:01 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-10-29 18:16:01 -0400
commitb22b6beae6116e3a9c46ced312c626f6737a3fa6 (patch)
treec92228669e0444d91fd1445bc562351fd69b58cc /drivers
parent53b7a3b7ec00f207c18e71f58ef2bca48635c622 (diff)
parentc1a92909dbc2090753ff6224971d9b8ae5f93c97 (diff)
Merge tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
Pull ARM SoC driver updates from Arnd Bergmann: "The most noteworthy SoC driver changes this time include: - The TEE subsystem gains an in-kernel interface to access the TEE from device drivers. - The reset controller subsystem gains a driver for the Qualcomm Snapdragon 845 Power Domain Controller. - The Xilinx Zynq platform now has a firmware interface for its platform management unit. This contains a firmware "ioctl" interface that was a little controversial at first, but the version we merged solved that by not exposing arbitrary firmware calls to user space. - The Amlogic Meson platform gains a "canvas" driver that is used for video processing and shared between different high-level drivers. The rest is more of the usual, mostly related to SoC specific power management support and core drivers in drivers/soc: - Several Renesas SoCs (RZ/G1N, RZ/G2M, R-Car V3M, RZ/A2M) gain new features related to power and reset control. - The Mediatek mt8183 and mt6765 SoC platforms gain support for their respective power management chips. - A new driver for NXP i.MX8, which need a firmware interface for power management. - The SCPI firmware interface now contains support estimating power usage of performance states - The NVIDIA Tegra "pmc" driver gains a few new features, in particular a pinctrl interface for configuring the pads. - Lots of small changes for Qualcomm, in particular the "smem" device driver. - Some cleanups for the TI OMAP series related to their sysc controller. Additional cleanups and bugfixes in SoC specific drivers include the Meson, Keystone, NXP, AT91, Sunxi, Actions, and Tegra platforms" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (129 commits) firmware: tegra: bpmp: Implement suspend/resume support drivers: clk: Add ZynqMP clock driver dt-bindings: clock: Add bindings for ZynqMP clock driver firmware: xilinx: Add zynqmp IOCTL API for device control Documentation: xilinx: Add documentation for eemi APIs MAINTAINERS: imx: include drivers/firmware/imx path firmware: imx: add misc svc support firmware: imx: add SCU firmware driver support reset: Fix potential use-after-free in __of_reset_control_get() dt-bindings: arm: fsl: add scu binding doc soc: fsl: qbman: add interrupt coalesce changing APIs soc: fsl: bman_portals: defer probe after bman's probe soc: fsl: qbman: Use last response to determine valid bit soc: fsl: qbman: Add 64 bit DMA addressing requirement to QBMan soc: fsl: qbman: replace CPU 0 with any online CPU in hotplug handlers soc: fsl: qbman: Check if CPU is offline when initializing portals reset: qcom: PDC Global (Power Domain Controller) reset controller dt-bindings: reset: Add PDC Global binding for SDM845 SoCs reset: Grammar s/more then once/more than once/ bus: ti-sysc: Just use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/bus/imx-weim.c3
-rw-r--r--drivers/bus/ti-sysc.c171
-rw-r--r--drivers/clk/Kconfig1
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/zynqmp/Kconfig10
-rw-r--r--drivers/clk/zynqmp/Makefile4
-rw-r--r--drivers/clk/zynqmp/clk-gate-zynqmp.c144
-rw-r--r--drivers/clk/zynqmp/clk-mux-zynqmp.c141
-rw-r--r--drivers/clk/zynqmp/clk-zynqmp.h68
-rw-r--r--drivers/clk/zynqmp/clkc.c716
-rw-r--r--drivers/clk/zynqmp/divider.c217
-rw-r--r--drivers/clk/zynqmp/pll.c335
-rw-r--r--drivers/edac/Kconfig14
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/qcom_edac.c414
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/firmware/Makefile2
-rw-r--r--drivers/firmware/arm_scmi/base.c2
-rw-r--r--drivers/firmware/arm_scmi/clock.c2
-rw-r--r--drivers/firmware/arm_scmi/perf.c30
-rw-r--r--drivers/firmware/arm_scmi/power.c2
-rw-r--r--drivers/firmware/arm_scmi/sensors.c2
-rw-r--r--drivers/firmware/imx/Kconfig11
-rw-r--r--drivers/firmware/imx/Makefile2
-rw-r--r--drivers/firmware/imx/imx-scu.c270
-rw-r--r--drivers/firmware/imx/misc.c99
-rw-r--r--drivers/firmware/meson/meson_sm.c56
-rw-r--r--drivers/firmware/qcom_scm.c74
-rw-r--r--drivers/firmware/tegra/bpmp.c19
-rw-r--r--drivers/firmware/ti_sci.c24
-rw-r--r--drivers/firmware/xilinx/Kconfig23
-rw-r--r--drivers/firmware/xilinx/Makefile5
-rw-r--r--drivers/firmware/xilinx/zynqmp-debug.c250
-rw-r--r--drivers/firmware/xilinx/zynqmp-debug.h24
-rw-r--r--drivers/firmware/xilinx/zynqmp.c565
-rw-r--r--drivers/memory/atmel-ebi.c3
-rw-r--r--drivers/reset/Kconfig9
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c15
-rw-r--r--drivers/reset/reset-qcom-pdc.c124
-rw-r--r--drivers/soc/Makefile2
-rw-r--r--drivers/soc/actions/Kconfig2
-rw-r--r--drivers/soc/actions/Makefile2
-rw-r--r--drivers/soc/actions/owl-sps-helper.c6
-rw-r--r--drivers/soc/actions/owl-sps.c64
-rw-r--r--drivers/soc/amlogic/Kconfig7
-rw-r--r--drivers/soc/amlogic/Makefile1
-rw-r--r--drivers/soc/amlogic/meson-canvas.c185
-rw-r--r--drivers/soc/fsl/dpio/dpio-driver.c3
-rw-r--r--drivers/soc/fsl/qbman/Kconfig2
-rw-r--r--drivers/soc/fsl/qbman/bman.c6
-rw-r--r--drivers/soc/fsl/qbman/bman_portal.c14
-rw-r--r--drivers/soc/fsl/qbman/dpaa_sys.h20
-rw-r--r--drivers/soc/fsl/qbman/qman.c53
-rw-r--r--drivers/soc/fsl/qbman/qman_portal.c6
-rw-r--r--drivers/soc/fsl/qe/qe.c6
-rw-r--r--drivers/soc/imx/gpc.c26
-rw-r--r--drivers/soc/imx/gpcv2.c100
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c519
-rw-r--r--drivers/soc/qcom/Kconfig21
-rw-r--r--drivers/soc/qcom/apr.c4
-rw-r--r--drivers/soc/qcom/llcc-slice.c74
-rw-r--r--drivers/soc/qcom/rmtfs_mem.c5
-rw-r--r--drivers/soc/qcom/rpmh-rsc.c2
-rw-r--r--drivers/soc/qcom/smem.c174
-rw-r--r--drivers/soc/qcom/spm.c3
-rw-r--r--drivers/soc/qcom/wcnss_ctrl.c2
-rw-r--r--drivers/soc/renesas/Kconfig19
-rw-r--r--drivers/soc/renesas/Makefile2
-rw-r--r--drivers/soc/renesas/r8a7743-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7745-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a774a1-sysc.c45
-rw-r--r--drivers/soc/renesas/r8a774c0-sysc.c68
-rw-r--r--drivers/soc/renesas/r8a7779-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7790-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7791-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7792-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7794-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7795-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a7796-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a77970-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a77995-sysc.c5
-rw-r--r--drivers/soc/renesas/rcar-rst.c11
-rw-r--r--drivers/soc/renesas/rcar-sysc.c13
-rw-r--r--drivers/soc/renesas/rcar-sysc.h9
-rw-r--r--drivers/soc/renesas/renesas-soc.c100
-rw-r--r--drivers/soc/tegra/pmc.c513
-rw-r--r--drivers/soc/ti/knav_dma.c4
-rw-r--r--drivers/soc/ti/knav_qmss.h6
-rw-r--r--drivers/tee/optee/core.c2
-rw-r--r--drivers/tee/tee_core.c113
91 files changed, 5377 insertions, 748 deletions
diff --git a/drivers/bus/imx-weim.c b/drivers/bus/imx-weim.c
index 6a94aa6a22c2..d84996a4528e 100644
--- a/drivers/bus/imx-weim.c
+++ b/drivers/bus/imx-weim.c
@@ -156,9 +156,6 @@ static int __init weim_parse_dt(struct platform_device *pdev,
156 } 156 }
157 157
158 for_each_available_child_of_node(pdev->dev.of_node, child) { 158 for_each_available_child_of_node(pdev->dev.of_node, child) {
159 if (!child->name)
160 continue;
161
162 ret = weim_timing_setup(child, base, devtype); 159 ret = weim_timing_setup(child, base, devtype);
163 if (ret) 160 if (ret)
164 dev_warn(&pdev->dev, "%pOF set timing failed.\n", 161 dev_warn(&pdev->dev, "%pOF set timing failed.\n",
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index e4fe954e63a9..a3a2d39280d9 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -701,69 +701,7 @@ awake:
701 return error; 701 return error;
702} 702}
703 703
704#ifdef CONFIG_PM_SLEEP 704static int __maybe_unused sysc_noirq_suspend(struct device *dev)
705static int sysc_suspend(struct device *dev)
706{
707 struct sysc *ddata;
708 int error;
709
710 ddata = dev_get_drvdata(dev);
711
712 if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER |
713 SYSC_QUIRK_LEGACY_IDLE))
714 return 0;
715
716 if (!ddata->enabled)
717 return 0;
718
719 dev_dbg(ddata->dev, "%s %s\n", __func__,
720 ddata->name ? ddata->name : "");
721
722 error = pm_runtime_put_sync_suspend(dev);
723 if (error < 0) {
724 dev_warn(ddata->dev, "%s not idle %i %s\n",
725 __func__, error,
726 ddata->name ? ddata->name : "");
727
728 return 0;
729 }
730
731 ddata->needs_resume = true;
732
733 return 0;
734}
735
736static int sysc_resume(struct device *dev)
737{
738 struct sysc *ddata;
739 int error;
740
741 ddata = dev_get_drvdata(dev);
742
743 if (ddata->cfg.quirks & (SYSC_QUIRK_RESOURCE_PROVIDER |
744 SYSC_QUIRK_LEGACY_IDLE))
745 return 0;
746
747 if (ddata->needs_resume) {
748 dev_dbg(ddata->dev, "%s %s\n", __func__,
749 ddata->name ? ddata->name : "");
750
751 error = pm_runtime_get_sync(dev);
752 if (error < 0) {
753 dev_err(ddata->dev, "%s error %i %s\n",
754 __func__, error,
755 ddata->name ? ddata->name : "");
756
757 return error;
758 }
759
760 ddata->needs_resume = false;
761 }
762
763 return 0;
764}
765
766static int sysc_noirq_suspend(struct device *dev)
767{ 705{
768 struct sysc *ddata; 706 struct sysc *ddata;
769 707
@@ -772,21 +710,10 @@ static int sysc_noirq_suspend(struct device *dev)
772 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) 710 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
773 return 0; 711 return 0;
774 712
775 if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER)) 713 return pm_runtime_force_suspend(dev);
776 return 0;
777
778 if (!ddata->enabled)
779 return 0;
780
781 dev_dbg(ddata->dev, "%s %s\n", __func__,
782 ddata->name ? ddata->name : "");
783
784 ddata->needs_resume = true;
785
786 return sysc_runtime_suspend(dev);
787} 714}
788 715
789static int sysc_noirq_resume(struct device *dev) 716static int __maybe_unused sysc_noirq_resume(struct device *dev)
790{ 717{
791 struct sysc *ddata; 718 struct sysc *ddata;
792 719
@@ -795,24 +722,10 @@ static int sysc_noirq_resume(struct device *dev)
795 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE) 722 if (ddata->cfg.quirks & SYSC_QUIRK_LEGACY_IDLE)
796 return 0; 723 return 0;
797 724
798 if (!(ddata->cfg.quirks & SYSC_QUIRK_RESOURCE_PROVIDER)) 725 return pm_runtime_force_resume(dev);
799 return 0;
800
801 if (ddata->needs_resume) {
802 dev_dbg(ddata->dev, "%s %s\n", __func__,
803 ddata->name ? ddata->name : "");
804
805 ddata->needs_resume = false;
806
807 return sysc_runtime_resume(dev);
808 }
809
810 return 0;
811} 726}
812#endif
813 727
814static const struct dev_pm_ops sysc_pm_ops = { 728static const struct dev_pm_ops sysc_pm_ops = {
815 SET_SYSTEM_SLEEP_PM_OPS(sysc_suspend, sysc_resume)
816 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_noirq_suspend, sysc_noirq_resume) 729 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sysc_noirq_suspend, sysc_noirq_resume)
817 SET_RUNTIME_PM_OPS(sysc_runtime_suspend, 730 SET_RUNTIME_PM_OPS(sysc_runtime_suspend,
818 sysc_runtime_resume, 731 sysc_runtime_resume,
@@ -845,28 +758,8 @@ struct sysc_revision_quirk {
845 } 758 }
846 759
847static const struct sysc_revision_quirk sysc_revision_quirks[] = { 760static const struct sysc_revision_quirk sysc_revision_quirks[] = {
848 /* These need to use noirq_suspend */
849 SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff,
850 SYSC_QUIRK_RESOURCE_PROVIDER),
851 SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xffffffff,
852 SYSC_QUIRK_RESOURCE_PROVIDER),
853 SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffffffff,
854 SYSC_QUIRK_RESOURCE_PROVIDER),
855 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff,
856 SYSC_QUIRK_RESOURCE_PROVIDER),
857 SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xffffffff,
858 SYSC_QUIRK_RESOURCE_PROVIDER),
859 SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff,
860 SYSC_QUIRK_RESOURCE_PROVIDER),
861 SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff,
862 SYSC_QUIRK_RESOURCE_PROVIDER),
863 SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff,
864 SYSC_QUIRK_RESOURCE_PROVIDER),
865 SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff,
866 SYSC_QUIRK_RESOURCE_PROVIDER),
867
868 /* These drivers need to be fixed to not use pm_runtime_irq_safe() */ 761 /* These drivers need to be fixed to not use pm_runtime_irq_safe() */
869 SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffffffff, 762 SYSC_QUIRK("gpio", 0, 0, 0x10, 0x114, 0x50600801, 0xffff00ff,
870 SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET), 763 SYSC_QUIRK_LEGACY_IDLE | SYSC_QUIRK_OPT_CLKS_IN_RESET),
871 SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff, 764 SYSC_QUIRK("mmu", 0, 0, 0x10, 0x14, 0x00000020, 0xffffffff,
872 SYSC_QUIRK_LEGACY_IDLE), 765 SYSC_QUIRK_LEGACY_IDLE),
@@ -881,38 +774,70 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
881 SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff, 774 SYSC_QUIRK("timer", 0, 0, 0x10, 0x14, 0x00000015, 0xffffffff,
882 SYSC_QUIRK_LEGACY_IDLE), 775 SYSC_QUIRK_LEGACY_IDLE),
883 /* Some timers on omap4 and later */ 776 /* Some timers on omap4 and later */
884 SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffffffff, 777 SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x50002100, 0xffffffff,
778 SYSC_QUIRK_LEGACY_IDLE),
779 SYSC_QUIRK("timer", 0, 0, 0x10, -1, 0x4fff1301, 0xffff00ff,
885 SYSC_QUIRK_LEGACY_IDLE), 780 SYSC_QUIRK_LEGACY_IDLE),
886 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, 781 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff,
887 SYSC_QUIRK_LEGACY_IDLE), 782 SYSC_QUIRK_LEGACY_IDLE),
888 /* Uarts on omap4 and later */ 783 /* Uarts on omap4 and later */
889 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffffffff, 784 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff,
890 SYSC_QUIRK_LEGACY_IDLE), 785 SYSC_QUIRK_LEGACY_IDLE),
891 786 SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff,
892 /* These devices don't yet suspend properly without legacy setting */
893 SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffffffff,
894 SYSC_QUIRK_LEGACY_IDLE),
895 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xffffffff,
896 SYSC_QUIRK_LEGACY_IDLE),
897 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0d00, 0xffffffff,
898 SYSC_QUIRK_LEGACY_IDLE), 787 SYSC_QUIRK_LEGACY_IDLE),
899 788
900#ifdef DEBUG 789#ifdef DEBUG
790 SYSC_QUIRK("adc", 0, 0, 0x10, -1, 0x47300001, 0xffffffff, 0),
791 SYSC_QUIRK("atl", 0, 0, -1, -1, 0x0a070100, 0xffffffff, 0),
901 SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0), 792 SYSC_QUIRK("aess", 0, 0, 0x10, -1, 0x40000000, 0xffffffff, 0),
793 SYSC_QUIRK("cm", 0, 0, -1, -1, 0x40000301, 0xffffffff, 0),
794 SYSC_QUIRK("control", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
795 SYSC_QUIRK("cpgmac", 0, 0x1200, 0x1208, 0x1204, 0x4edb1902,
796 0xffff00f0, 0),
797 SYSC_QUIRK("dcan", 0, 0, -1, -1, 0xffffffff, 0xffffffff, 0),
798 SYSC_QUIRK("dcan", 0, 0, -1, -1, 0x00001401, 0xffffffff, 0),
799 SYSC_QUIRK("dwc3", 0, 0, 0x10, -1, 0x500a0200, 0xffffffff, 0),
800 SYSC_QUIRK("epwmss", 0, 0, 0x4, -1, 0x47400001, 0xffffffff, 0),
902 SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0), 801 SYSC_QUIRK("gpu", 0, 0x1fc00, 0x1fc10, -1, 0, 0, 0),
903 SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0), 802 SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x00000006, 0xffffffff, 0),
803 SYSC_QUIRK("hdq1w", 0, 0, 0x14, 0x18, 0x0000000a, 0xffffffff, 0),
904 SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0), 804 SYSC_QUIRK("hsi", 0, 0, 0x10, 0x14, 0x50043101, 0xffffffff, 0),
905 SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0), 805 SYSC_QUIRK("iss", 0, 0, 0x10, -1, 0x40000101, 0xffffffff, 0),
806 SYSC_QUIRK("i2c", 0, 0, 0x10, 0x90, 0x5040000a, 0xfffff0f0, 0),
807 SYSC_QUIRK("lcdc", 0, 0, 0x54, -1, 0x4f201000, 0xffffffff, 0),
906 SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0), 808 SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44306302, 0xffffffff, 0),
809 SYSC_QUIRK("mcasp", 0, 0, 0x4, -1, 0x44307b02, 0xffffffff, 0),
907 SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0), 810 SYSC_QUIRK("mcbsp", 0, -1, 0x8c, -1, 0, 0, 0),
811 SYSC_QUIRK("mcspi", 0, 0, 0x10, -1, 0x40300a0b, 0xffff00ff, 0),
812 SYSC_QUIRK("mcspi", 0, 0, 0x110, 0x114, 0x40300a0b, 0xffffffff, 0),
908 SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0), 813 SYSC_QUIRK("mailbox", 0, 0, 0x10, -1, 0x00000400, 0xffffffff, 0),
814 SYSC_QUIRK("m3", 0, 0, -1, -1, 0x5f580105, 0x0fff0f00, 0),
815 SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0),
816 SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0),
817 SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
818 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
819 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0),
820 SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0),
821 SYSC_QUIRK("scm", 0, 0, 0x10, -1, 0x40000900, 0xffffffff, 0),
822 SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4e8b0100, 0xffffffff, 0),
823 SYSC_QUIRK("scm", 0, 0, -1, -1, 0x4f000100, 0xffffffff, 0),
824 SYSC_QUIRK("scm", 0, 0, -1, -1, 0x40000900, 0xffffffff, 0),
825 SYSC_QUIRK("scrm", 0, 0, -1, -1, 0x00000010, 0xffffffff, 0),
826 SYSC_QUIRK("sdio", 0, 0, 0x10, -1, 0x40202301, 0xffff0ff0, 0),
827 SYSC_QUIRK("sdio", 0, 0x2fc, 0x110, 0x114, 0x31010000, 0xffffffff, 0),
828 SYSC_QUIRK("sdma", 0, 0, 0x2c, 0x28, 0x00010900, 0xffffffff, 0),
909 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0), 829 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40000902, 0xffffffff, 0),
910 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0), 830 SYSC_QUIRK("slimbus", 0, 0, 0x10, -1, 0x40002903, 0xffffffff, 0),
911 SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0), 831 SYSC_QUIRK("spinlock", 0, 0, 0x10, -1, 0x50020000, 0xffffffff, 0),
832 SYSC_QUIRK("rng", 0, 0x1fe0, 0x1fe4, -1, 0x00000020, 0xffffffff, 0),
833 SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0),
834 SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0),
912 SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), 835 SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
913 SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), 836 SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
914 SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, 837 SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
915 0xffffffff, 0), 838 0xffffffff, 0),
839 SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0),
840 SYSC_QUIRK("vfpe", 0, 0, 0x104, -1, 0x4d001200, 0xffffffff, 0),
916#endif 841#endif
917}; 842};
918 843
@@ -1221,8 +1146,8 @@ static int sysc_child_suspend_noirq(struct device *dev)
1221 if (!pm_runtime_status_suspended(dev)) { 1146 if (!pm_runtime_status_suspended(dev)) {
1222 error = pm_generic_runtime_suspend(dev); 1147 error = pm_generic_runtime_suspend(dev);
1223 if (error) { 1148 if (error) {
1224 dev_warn(dev, "%s busy at %i: %i\n", 1149 dev_dbg(dev, "%s busy at %i: %i\n",
1225 __func__, __LINE__, error); 1150 __func__, __LINE__, error);
1226 1151
1227 return 0; 1152 return 0;
1228 } 1153 }
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 292056bbb30e..1deafb4db60c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -299,5 +299,6 @@ source "drivers/clk/sunxi-ng/Kconfig"
299source "drivers/clk/tegra/Kconfig" 299source "drivers/clk/tegra/Kconfig"
300source "drivers/clk/ti/Kconfig" 300source "drivers/clk/ti/Kconfig"
301source "drivers/clk/uniphier/Kconfig" 301source "drivers/clk/uniphier/Kconfig"
302source "drivers/clk/zynqmp/Kconfig"
302 303
303endmenu 304endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index a84c5573cabe..ad11421bdacd 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -108,3 +108,4 @@ obj-$(CONFIG_X86) += x86/
108endif 108endif
109obj-$(CONFIG_ARCH_ZX) += zte/ 109obj-$(CONFIG_ARCH_ZX) += zte/
110obj-$(CONFIG_ARCH_ZYNQ) += zynq/ 110obj-$(CONFIG_ARCH_ZYNQ) += zynq/
111obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/
diff --git a/drivers/clk/zynqmp/Kconfig b/drivers/clk/zynqmp/Kconfig
new file mode 100644
index 000000000000..17086059be8b
--- /dev/null
+++ b/drivers/clk/zynqmp/Kconfig
@@ -0,0 +1,10 @@
1# SPDX-License-Identifier: GPL-2.0
2
3config COMMON_CLK_ZYNQMP
4 bool "Support for Xilinx ZynqMP Ultrascale+ clock controllers"
5 depends on ARCH_ZYNQMP || COMPILE_TEST
6 depends on ZYNQMP_FIRMWARE
7 help
8 Support for the Zynqmp Ultrascale clock controller.
9 It has a dependency on the PMU firmware.
10 Say Y if you want to include clock support.
diff --git a/drivers/clk/zynqmp/Makefile b/drivers/clk/zynqmp/Makefile
new file mode 100644
index 000000000000..0ec24bfe0f18
--- /dev/null
+++ b/drivers/clk/zynqmp/Makefile
@@ -0,0 +1,4 @@
1# SPDX-License-Identifier: GPL-2.0
2# Zynq Ultrascale+ MPSoC clock specific Makefile
3
4obj-$(CONFIG_ARCH_ZYNQMP) += pll.o clk-gate-zynqmp.o divider.o clk-mux-zynqmp.o clkc.o
diff --git a/drivers/clk/zynqmp/clk-gate-zynqmp.c b/drivers/clk/zynqmp/clk-gate-zynqmp.c
new file mode 100644
index 000000000000..83b236f20fff
--- /dev/null
+++ b/drivers/clk/zynqmp/clk-gate-zynqmp.c
@@ -0,0 +1,144 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Zynq UltraScale+ MPSoC clock controller
4 *
5 * Copyright (C) 2016-2018 Xilinx
6 *
7 * Gated clock implementation
8 */
9
10#include <linux/clk-provider.h>
11#include <linux/slab.h>
12#include "clk-zynqmp.h"
13
14/**
15 * struct clk_gate - gating clock
16 * @hw: handle between common and hardware-specific interfaces
17 * @flags: hardware-specific flags
18 * @clk_id: Id of clock
19 */
20struct zynqmp_clk_gate {
21 struct clk_hw hw;
22 u8 flags;
23 u32 clk_id;
24};
25
26#define to_zynqmp_clk_gate(_hw) container_of(_hw, struct zynqmp_clk_gate, hw)
27
28/**
29 * zynqmp_clk_gate_enable() - Enable clock
30 * @hw: handle between common and hardware-specific interfaces
31 *
32 * Return: 0 on success else error code
33 */
34static int zynqmp_clk_gate_enable(struct clk_hw *hw)
35{
36 struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
37 const char *clk_name = clk_hw_get_name(hw);
38 u32 clk_id = gate->clk_id;
39 int ret;
40 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
41
42 ret = eemi_ops->clock_enable(clk_id);
43
44 if (ret)
45 pr_warn_once("%s() clock enabled failed for %s, ret = %d\n",
46 __func__, clk_name, ret);
47
48 return ret;
49}
50
51/*
52 * zynqmp_clk_gate_disable() - Disable clock
53 * @hw: handle between common and hardware-specific interfaces
54 */
55static void zynqmp_clk_gate_disable(struct clk_hw *hw)
56{
57 struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
58 const char *clk_name = clk_hw_get_name(hw);
59 u32 clk_id = gate->clk_id;
60 int ret;
61 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
62
63 ret = eemi_ops->clock_disable(clk_id);
64
65 if (ret)
66 pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
67 __func__, clk_name, ret);
68}
69
70/**
71 * zynqmp_clk_gate_is_enable() - Check clock state
72 * @hw: handle between common and hardware-specific interfaces
73 *
74 * Return: 1 if enabled, 0 if disabled else error code
75 */
76static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw)
77{
78 struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw);
79 const char *clk_name = clk_hw_get_name(hw);
80 u32 clk_id = gate->clk_id;
81 int state, ret;
82 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
83
84 ret = eemi_ops->clock_getstate(clk_id, &state);
85 if (ret) {
86 pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
87 __func__, clk_name, ret);
88 return -EIO;
89 }
90
91 return state ? 1 : 0;
92}
93
94static const struct clk_ops zynqmp_clk_gate_ops = {
95 .enable = zynqmp_clk_gate_enable,
96 .disable = zynqmp_clk_gate_disable,
97 .is_enabled = zynqmp_clk_gate_is_enabled,
98};
99
100/**
101 * zynqmp_clk_register_gate() - Register a gate clock with the clock framework
102 * @name: Name of this clock
103 * @clk_id: Id of this clock
104 * @parents: Name of this clock's parents
105 * @num_parents: Number of parents
106 * @nodes: Clock topology node
107 *
108 * Return: clock hardware of the registered clock gate
109 */
110struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id,
111 const char * const *parents,
112 u8 num_parents,
113 const struct clock_topology *nodes)
114{
115 struct zynqmp_clk_gate *gate;
116 struct clk_hw *hw;
117 int ret;
118 struct clk_init_data init;
119
120 /* allocate the gate */
121 gate = kzalloc(sizeof(*gate), GFP_KERNEL);
122 if (!gate)
123 return ERR_PTR(-ENOMEM);
124
125 init.name = name;
126 init.ops = &zynqmp_clk_gate_ops;
127 init.flags = nodes->flag;
128 init.parent_names = parents;
129 init.num_parents = 1;
130
131 /* struct clk_gate assignments */
132 gate->flags = nodes->type_flag;
133 gate->hw.init = &init;
134 gate->clk_id = clk_id;
135
136 hw = &gate->hw;
137 ret = clk_hw_register(NULL, hw);
138 if (ret) {
139 kfree(gate);
140 hw = ERR_PTR(ret);
141 }
142
143 return hw;
144}
diff --git a/drivers/clk/zynqmp/clk-mux-zynqmp.c b/drivers/clk/zynqmp/clk-mux-zynqmp.c
new file mode 100644
index 000000000000..4143f560c28d
--- /dev/null
+++ b/drivers/clk/zynqmp/clk-mux-zynqmp.c
@@ -0,0 +1,141 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Zynq UltraScale+ MPSoC mux
4 *
5 * Copyright (C) 2016-2018 Xilinx
6 */
7
8#include <linux/clk-provider.h>
9#include <linux/slab.h>
10#include "clk-zynqmp.h"
11
12/*
13 * DOC: basic adjustable multiplexer clock that cannot gate
14 *
15 * Traits of this clock:
16 * prepare - clk_prepare only ensures that parents are prepared
17 * enable - clk_enable only ensures that parents are enabled
18 * rate - rate is only affected by parent switching. No clk_set_rate support
19 * parent - parent is adjustable through clk_set_parent
20 */
21
22/**
23 * struct zynqmp_clk_mux - multiplexer clock
24 *
25 * @hw: handle between common and hardware-specific interfaces
26 * @flags: hardware-specific flags
27 * @clk_id: Id of clock
28 */
29struct zynqmp_clk_mux {
30 struct clk_hw hw;
31 u8 flags;
32 u32 clk_id;
33};
34
35#define to_zynqmp_clk_mux(_hw) container_of(_hw, struct zynqmp_clk_mux, hw)
36
37/**
38 * zynqmp_clk_mux_get_parent() - Get parent of clock
39 * @hw: handle between common and hardware-specific interfaces
40 *
41 * Return: Parent index
42 */
43static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw)
44{
45 struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
46 const char *clk_name = clk_hw_get_name(hw);
47 u32 clk_id = mux->clk_id;
48 u32 val;
49 int ret;
50 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
51
52 ret = eemi_ops->clock_getparent(clk_id, &val);
53
54 if (ret)
55 pr_warn_once("%s() getparent failed for clock: %s, ret = %d\n",
56 __func__, clk_name, ret);
57
58 return val;
59}
60
61/**
62 * zynqmp_clk_mux_set_parent() - Set parent of clock
63 * @hw: handle between common and hardware-specific interfaces
64 * @index: Parent index
65 *
66 * Return: 0 on success else error+reason
67 */
68static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index)
69{
70 struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw);
71 const char *clk_name = clk_hw_get_name(hw);
72 u32 clk_id = mux->clk_id;
73 int ret;
74 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
75
76 ret = eemi_ops->clock_setparent(clk_id, index);
77
78 if (ret)
79 pr_warn_once("%s() set parent failed for clock: %s, ret = %d\n",
80 __func__, clk_name, ret);
81
82 return ret;
83}
84
85static const struct clk_ops zynqmp_clk_mux_ops = {
86 .get_parent = zynqmp_clk_mux_get_parent,
87 .set_parent = zynqmp_clk_mux_set_parent,
88 .determine_rate = __clk_mux_determine_rate,
89};
90
91static const struct clk_ops zynqmp_clk_mux_ro_ops = {
92 .get_parent = zynqmp_clk_mux_get_parent,
93};
94
95/**
96 * zynqmp_clk_register_mux() - Register a mux table with the clock
97 * framework
98 * @name: Name of this clock
99 * @clk_id: Id of this clock
100 * @parents: Name of this clock's parents
101 * @num_parents: Number of parents
102 * @nodes: Clock topology node
103 *
104 * Return: clock hardware of the registered clock mux
105 */
106struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
107 const char * const *parents,
108 u8 num_parents,
109 const struct clock_topology *nodes)
110{
111 struct zynqmp_clk_mux *mux;
112 struct clk_hw *hw;
113 struct clk_init_data init;
114 int ret;
115
116 mux = kzalloc(sizeof(*mux), GFP_KERNEL);
117 if (!mux)
118 return ERR_PTR(-ENOMEM);
119
120 init.name = name;
121 if (nodes->type_flag & CLK_MUX_READ_ONLY)
122 init.ops = &zynqmp_clk_mux_ro_ops;
123 else
124 init.ops = &zynqmp_clk_mux_ops;
125 init.flags = nodes->flag;
126 init.parent_names = parents;
127 init.num_parents = num_parents;
128 mux->flags = nodes->type_flag;
129 mux->hw.init = &init;
130 mux->clk_id = clk_id;
131
132 hw = &mux->hw;
133 ret = clk_hw_register(NULL, hw);
134 if (ret) {
135 kfree(hw);
136 hw = ERR_PTR(ret);
137 }
138
139 return hw;
140}
141EXPORT_SYMBOL_GPL(zynqmp_clk_register_mux);
diff --git a/drivers/clk/zynqmp/clk-zynqmp.h b/drivers/clk/zynqmp/clk-zynqmp.h
new file mode 100644
index 000000000000..7ab163b67249
--- /dev/null
+++ b/drivers/clk/zynqmp/clk-zynqmp.h
@@ -0,0 +1,68 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Copyright (C) 2016-2018 Xilinx
4 */
5
6#ifndef __LINUX_CLK_ZYNQMP_H_
7#define __LINUX_CLK_ZYNQMP_H_
8
9#include <linux/spinlock.h>
10
11#include <linux/firmware/xlnx-zynqmp.h>
12
13/* Clock APIs payload parameters */
14#define CLK_GET_NAME_RESP_LEN 16
15#define CLK_GET_TOPOLOGY_RESP_WORDS 3
16#define CLK_GET_PARENTS_RESP_WORDS 3
17#define CLK_GET_ATTR_RESP_WORDS 1
18
19enum topology_type {
20 TYPE_INVALID,
21 TYPE_MUX,
22 TYPE_PLL,
23 TYPE_FIXEDFACTOR,
24 TYPE_DIV1,
25 TYPE_DIV2,
26 TYPE_GATE,
27};
28
29/**
30 * struct clock_topology - Clock topology
31 * @type: Type of topology
32 * @flag: Topology flags
33 * @type_flag: Topology type specific flag
34 */
35struct clock_topology {
36 u32 type;
37 u32 flag;
38 u32 type_flag;
39};
40
41struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
42 const char * const *parents,
43 u8 num_parents,
44 const struct clock_topology *nodes);
45
46struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id,
47 const char * const *parents,
48 u8 num_parents,
49 const struct clock_topology *nodes);
50
51struct clk_hw *zynqmp_clk_register_divider(const char *name,
52 u32 clk_id,
53 const char * const *parents,
54 u8 num_parents,
55 const struct clock_topology *nodes);
56
57struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id,
58 const char * const *parents,
59 u8 num_parents,
60 const struct clock_topology *nodes);
61
62struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name,
63 u32 clk_id,
64 const char * const *parents,
65 u8 num_parents,
66 const struct clock_topology *nodes);
67
68#endif
diff --git a/drivers/clk/zynqmp/clkc.c b/drivers/clk/zynqmp/clkc.c
new file mode 100644
index 000000000000..9d7d297f0ea8
--- /dev/null
+++ b/drivers/clk/zynqmp/clkc.c
@@ -0,0 +1,716 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Zynq UltraScale+ MPSoC clock controller
4 *
5 * Copyright (C) 2016-2018 Xilinx
6 *
7 * Based on drivers/clk/zynq/clkc.c
8 */
9
10#include <linux/bitfield.h>
11#include <linux/clk.h>
12#include <linux/clk-provider.h>
13#include <linux/module.h>
14#include <linux/of_platform.h>
15#include <linux/slab.h>
16#include <linux/string.h>
17
18#include "clk-zynqmp.h"
19
20#define MAX_PARENT 100
21#define MAX_NODES 6
22#define MAX_NAME_LEN 50
23
24#define CLK_TYPE_SHIFT 2
25
26#define PM_API_PAYLOAD_LEN 3
27
28#define NA_PARENT 0xFFFFFFFF
29#define DUMMY_PARENT 0xFFFFFFFE
30
31#define CLK_TYPE_FIELD_LEN 4
32#define CLK_TOPOLOGY_NODE_OFFSET 16
33#define NODES_PER_RESP 3
34
35#define CLK_TYPE_FIELD_MASK 0xF
36#define CLK_FLAG_FIELD_MASK GENMASK(21, 8)
37#define CLK_TYPE_FLAG_FIELD_MASK GENMASK(31, 24)
38
39#define CLK_PARENTS_ID_LEN 16
40#define CLK_PARENTS_ID_MASK 0xFFFF
41
42/* Flags for parents */
43#define PARENT_CLK_SELF 0
44#define PARENT_CLK_NODE1 1
45#define PARENT_CLK_NODE2 2
46#define PARENT_CLK_NODE3 3
47#define PARENT_CLK_NODE4 4
48#define PARENT_CLK_EXTERNAL 5
49
50#define END_OF_CLK_NAME "END_OF_CLK"
51#define END_OF_TOPOLOGY_NODE 1
52#define END_OF_PARENTS 1
53#define RESERVED_CLK_NAME ""
54
55#define CLK_VALID_MASK 0x1
56
57enum clk_type {
58 CLK_TYPE_OUTPUT,
59 CLK_TYPE_EXTERNAL,
60};
61
62/**
63 * struct clock_parent - Clock parent
64 * @name: Parent name
65 * @id: Parent clock ID
66 * @flag: Parent flags
67 */
68struct clock_parent {
69 char name[MAX_NAME_LEN];
70 int id;
71 u32 flag;
72};
73
74/**
75 * struct zynqmp_clock - Clock
76 * @clk_name: Clock name
77 * @valid: Validity flag of clock
78 * @type: Clock type (Output/External)
79 * @node: Clock topology nodes
80 * @num_nodes: Number of nodes present in topology
81 * @parent: Parent of clock
82 * @num_parents: Number of parents of clock
83 */
84struct zynqmp_clock {
85 char clk_name[MAX_NAME_LEN];
86 u32 valid;
87 enum clk_type type;
88 struct clock_topology node[MAX_NODES];
89 u32 num_nodes;
90 struct clock_parent parent[MAX_PARENT];
91 u32 num_parents;
92};
93
94static const char clk_type_postfix[][10] = {
95 [TYPE_INVALID] = "",
96 [TYPE_MUX] = "_mux",
97 [TYPE_GATE] = "",
98 [TYPE_DIV1] = "_div1",
99 [TYPE_DIV2] = "_div2",
100 [TYPE_FIXEDFACTOR] = "_ff",
101 [TYPE_PLL] = ""
102};
103
104static struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id,
105 const char * const *parents,
106 u8 num_parents,
107 const struct clock_topology *nodes)
108 = {
109 [TYPE_INVALID] = NULL,
110 [TYPE_MUX] = zynqmp_clk_register_mux,
111 [TYPE_PLL] = zynqmp_clk_register_pll,
112 [TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor,
113 [TYPE_DIV1] = zynqmp_clk_register_divider,
114 [TYPE_DIV2] = zynqmp_clk_register_divider,
115 [TYPE_GATE] = zynqmp_clk_register_gate
116};
117
118static struct zynqmp_clock *clock;
119static struct clk_hw_onecell_data *zynqmp_data;
120static unsigned int clock_max_idx;
121static const struct zynqmp_eemi_ops *eemi_ops;
122
123/**
124 * zynqmp_is_valid_clock() - Check whether clock is valid or not
125 * @clk_id: Clock index
126 *
127 * Return: 1 if clock is valid, 0 if clock is invalid else error code
128 */
129static inline int zynqmp_is_valid_clock(u32 clk_id)
130{
131 if (clk_id > clock_max_idx)
132 return -ENODEV;
133
134 return clock[clk_id].valid;
135}
136
137/**
138 * zynqmp_get_clock_name() - Get name of clock from Clock index
139 * @clk_id: Clock index
140 * @clk_name: Name of clock
141 *
142 * Return: 0 on success else error code
143 */
144static int zynqmp_get_clock_name(u32 clk_id, char *clk_name)
145{
146 int ret;
147
148 ret = zynqmp_is_valid_clock(clk_id);
149 if (ret == 1) {
150 strncpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN);
151 return 0;
152 }
153
154 return ret == 0 ? -EINVAL : ret;
155}
156
157/**
158 * zynqmp_get_clock_type() - Get type of clock
159 * @clk_id: Clock index
160 * @type: Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL
161 *
162 * Return: 0 on success else error code
163 */
164static int zynqmp_get_clock_type(u32 clk_id, u32 *type)
165{
166 int ret;
167
168 ret = zynqmp_is_valid_clock(clk_id);
169 if (ret == 1) {
170 *type = clock[clk_id].type;
171 return 0;
172 }
173
174 return ret == 0 ? -EINVAL : ret;
175}
176
177/**
178 * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system
179 * @nclocks: Number of clocks in system/board.
180 *
181 * Call firmware API to get number of clocks.
182 *
183 * Return: 0 on success else error code.
184 */
185static int zynqmp_pm_clock_get_num_clocks(u32 *nclocks)
186{
187 struct zynqmp_pm_query_data qdata = {0};
188 u32 ret_payload[PAYLOAD_ARG_CNT];
189 int ret;
190
191 qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS;
192
193 ret = eemi_ops->query_data(qdata, ret_payload);
194 *nclocks = ret_payload[1];
195
196 return ret;
197}
198
199/**
200 * zynqmp_pm_clock_get_name() - Get the name of clock for given id
201 * @clock_id: ID of the clock to be queried
202 * @name: Name of given clock
203 *
204 * This function is used to get name of clock specified by given
205 * clock ID.
206 *
207 * Return: Returns 0, in case of error name would be 0
208 */
209static int zynqmp_pm_clock_get_name(u32 clock_id, char *name)
210{
211 struct zynqmp_pm_query_data qdata = {0};
212 u32 ret_payload[PAYLOAD_ARG_CNT];
213
214 qdata.qid = PM_QID_CLOCK_GET_NAME;
215 qdata.arg1 = clock_id;
216
217 eemi_ops->query_data(qdata, ret_payload);
218 memcpy(name, ret_payload, CLK_GET_NAME_RESP_LEN);
219
220 return 0;
221}
222
223/**
224 * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id
225 * @clock_id: ID of the clock to be queried
226 * @index: Node index of clock topology
227 * @topology: Buffer to store nodes in topology and flags
228 *
229 * This function is used to get topology information for the clock
230 * specified by given clock ID.
231 *
232 * This API will return 3 node of topology with a single response. To get
233 * other nodes, master should call same API in loop with new
234 * index till error is returned. E.g First call should have
235 * index 0 which will return nodes 0,1 and 2. Next call, index
236 * should be 3 which will return nodes 3,4 and 5 and so on.
237 *
238 * Return: 0 on success else error+reason
239 */
240static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, u32 *topology)
241{
242 struct zynqmp_pm_query_data qdata = {0};
243 u32 ret_payload[PAYLOAD_ARG_CNT];
244 int ret;
245
246 qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY;
247 qdata.arg1 = clock_id;
248 qdata.arg2 = index;
249
250 ret = eemi_ops->query_data(qdata, ret_payload);
251 memcpy(topology, &ret_payload[1], CLK_GET_TOPOLOGY_RESP_WORDS * 4);
252
253 return ret;
254}
255
256/**
257 * zynqmp_clk_register_fixed_factor() - Register fixed factor with the
258 * clock framework
259 * @name: Name of this clock
260 * @clk_id: Clock ID
261 * @parents: Name of this clock's parents
262 * @num_parents: Number of parents
263 * @nodes: Clock topology node
264 *
265 * Return: clock hardware to the registered clock
266 */
267struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id,
268 const char * const *parents,
269 u8 num_parents,
270 const struct clock_topology *nodes)
271{
272 u32 mult, div;
273 struct clk_hw *hw;
274 struct zynqmp_pm_query_data qdata = {0};
275 u32 ret_payload[PAYLOAD_ARG_CNT];
276 int ret;
277
278 qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS;
279 qdata.arg1 = clk_id;
280
281 ret = eemi_ops->query_data(qdata, ret_payload);
282 mult = ret_payload[1];
283 div = ret_payload[2];
284
285 hw = clk_hw_register_fixed_factor(NULL, name,
286 parents[0],
287 nodes->flag, mult,
288 div);
289
290 return hw;
291}
292
293/**
294 * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id
295 * @clock_id: Clock ID
296 * @index: Parent index
297 * @parents: 3 parents of the given clock
298 *
299 * This function is used to get 3 parents for the clock specified by
300 * given clock ID.
301 *
302 * This API will return 3 parents with a single response. To get
303 * other parents, master should call same API in loop with new
304 * parent index till error is returned. E.g First call should have
305 * index 0 which will return parents 0,1 and 2. Next call, index
306 * should be 3 which will return parent 3,4 and 5 and so on.
307 *
308 * Return: 0 on success else error+reason
309 */
310static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, u32 *parents)
311{
312 struct zynqmp_pm_query_data qdata = {0};
313 u32 ret_payload[PAYLOAD_ARG_CNT];
314 int ret;
315
316 qdata.qid = PM_QID_CLOCK_GET_PARENTS;
317 qdata.arg1 = clock_id;
318 qdata.arg2 = index;
319
320 ret = eemi_ops->query_data(qdata, ret_payload);
321 memcpy(parents, &ret_payload[1], CLK_GET_PARENTS_RESP_WORDS * 4);
322
323 return ret;
324}
325
326/**
327 * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id
328 * @clock_id: Clock ID
329 * @attr: Clock attributes
330 *
331 * This function is used to get clock's attributes(e.g. valid, clock type, etc).
332 *
333 * Return: 0 on success else error+reason
334 */
335static int zynqmp_pm_clock_get_attributes(u32 clock_id, u32 *attr)
336{
337 struct zynqmp_pm_query_data qdata = {0};
338 u32 ret_payload[PAYLOAD_ARG_CNT];
339 int ret;
340
341 qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES;
342 qdata.arg1 = clock_id;
343
344 ret = eemi_ops->query_data(qdata, ret_payload);
345 memcpy(attr, &ret_payload[1], CLK_GET_ATTR_RESP_WORDS * 4);
346
347 return ret;
348}
349
350/**
351 * __zynqmp_clock_get_topology() - Get topology data of clock from firmware
352 * response data
353 * @topology: Clock topology
354 * @data: Clock topology data received from firmware
355 * @nnodes: Number of nodes
356 *
357 * Return: 0 on success else error+reason
358 */
359static int __zynqmp_clock_get_topology(struct clock_topology *topology,
360 u32 *data, u32 *nnodes)
361{
362 int i;
363
364 for (i = 0; i < PM_API_PAYLOAD_LEN; i++) {
365 if (!(data[i] & CLK_TYPE_FIELD_MASK))
366 return END_OF_TOPOLOGY_NODE;
367 topology[*nnodes].type = data[i] & CLK_TYPE_FIELD_MASK;
368 topology[*nnodes].flag = FIELD_GET(CLK_FLAG_FIELD_MASK,
369 data[i]);
370 topology[*nnodes].type_flag =
371 FIELD_GET(CLK_TYPE_FLAG_FIELD_MASK, data[i]);
372 (*nnodes)++;
373 }
374
375 return 0;
376}
377
378/**
379 * zynqmp_clock_get_topology() - Get topology of clock from firmware using
380 * PM_API
381 * @clk_id: Clock index
382 * @topology: Clock topology
383 * @num_nodes: Number of nodes
384 *
385 * Return: 0 on success else error+reason
386 */
387static int zynqmp_clock_get_topology(u32 clk_id,
388 struct clock_topology *topology,
389 u32 *num_nodes)
390{
391 int j, ret;
392 u32 pm_resp[PM_API_PAYLOAD_LEN] = {0};
393
394 *num_nodes = 0;
395 for (j = 0; j <= MAX_NODES; j += 3) {
396 ret = zynqmp_pm_clock_get_topology(clk_id, j, pm_resp);
397 if (ret)
398 return ret;
399 ret = __zynqmp_clock_get_topology(topology, pm_resp, num_nodes);
400 if (ret == END_OF_TOPOLOGY_NODE)
401 return 0;
402 }
403
404 return 0;
405}
406
407/**
408 * __zynqmp_clock_get_topology() - Get parents info of clock from firmware
409 * response data
410 * @parents: Clock parents
411 * @data: Clock parents data received from firmware
412 * @nparent: Number of parent
413 *
414 * Return: 0 on success else error+reason
415 */
416static int __zynqmp_clock_get_parents(struct clock_parent *parents, u32 *data,
417 u32 *nparent)
418{
419 int i;
420 struct clock_parent *parent;
421
422 for (i = 0; i < PM_API_PAYLOAD_LEN; i++) {
423 if (data[i] == NA_PARENT)
424 return END_OF_PARENTS;
425
426 parent = &parents[i];
427 parent->id = data[i] & CLK_PARENTS_ID_MASK;
428 if (data[i] == DUMMY_PARENT) {
429 strcpy(parent->name, "dummy_name");
430 parent->flag = 0;
431 } else {
432 parent->flag = data[i] >> CLK_PARENTS_ID_LEN;
433 if (zynqmp_get_clock_name(parent->id, parent->name))
434 continue;
435 }
436 *nparent += 1;
437 }
438
439 return 0;
440}
441
442/**
443 * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API
444 * @clk_id: Clock index
445 * @parents: Clock parents
446 * @num_parents: Total number of parents
447 *
448 * Return: 0 on success else error+reason
449 */
450static int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents,
451 u32 *num_parents)
452{
453 int j = 0, ret;
454 u32 pm_resp[PM_API_PAYLOAD_LEN] = {0};
455
456 *num_parents = 0;
457 do {
458 /* Get parents from firmware */
459 ret = zynqmp_pm_clock_get_parents(clk_id, j, pm_resp);
460 if (ret)
461 return ret;
462
463 ret = __zynqmp_clock_get_parents(&parents[j], pm_resp,
464 num_parents);
465 if (ret == END_OF_PARENTS)
466 return 0;
467 j += PM_API_PAYLOAD_LEN;
468 } while (*num_parents <= MAX_PARENT);
469
470 return 0;
471}
472
473/**
474 * zynqmp_get_parent_list() - Create list of parents name
475 * @np: Device node
476 * @clk_id: Clock index
477 * @parent_list: List of parent's name
478 * @num_parents: Total number of parents
479 *
480 * Return: 0 on success else error+reason
481 */
482static int zynqmp_get_parent_list(struct device_node *np, u32 clk_id,
483 const char **parent_list, u32 *num_parents)
484{
485 int i = 0, ret;
486 u32 total_parents = clock[clk_id].num_parents;
487 struct clock_topology *clk_nodes;
488 struct clock_parent *parents;
489
490 clk_nodes = clock[clk_id].node;
491 parents = clock[clk_id].parent;
492
493 for (i = 0; i < total_parents; i++) {
494 if (!parents[i].flag) {
495 parent_list[i] = parents[i].name;
496 } else if (parents[i].flag == PARENT_CLK_EXTERNAL) {
497 ret = of_property_match_string(np, "clock-names",
498 parents[i].name);
499 if (ret < 0)
500 strcpy(parents[i].name, "dummy_name");
501 parent_list[i] = parents[i].name;
502 } else {
503 strcat(parents[i].name,
504 clk_type_postfix[clk_nodes[parents[i].flag - 1].
505 type]);
506 parent_list[i] = parents[i].name;
507 }
508 }
509
510 *num_parents = total_parents;
511 return 0;
512}
513
514/**
515 * zynqmp_register_clk_topology() - Register clock topology
516 * @clk_id: Clock index
517 * @clk_name: Clock Name
518 * @num_parents: Total number of parents
519 * @parent_names: List of parents name
520 *
521 * Return: Returns either clock hardware or error+reason
522 */
523static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name,
524 int num_parents,
525 const char **parent_names)
526{
527 int j;
528 u32 num_nodes;
529 char *clk_out = NULL;
530 struct clock_topology *nodes;
531 struct clk_hw *hw = NULL;
532
533 nodes = clock[clk_id].node;
534 num_nodes = clock[clk_id].num_nodes;
535
536 for (j = 0; j < num_nodes; j++) {
537 /*
538 * Clock name received from firmware is output clock name.
539 * Intermediate clock names are postfixed with type of clock.
540 */
541 if (j != (num_nodes - 1)) {
542 clk_out = kasprintf(GFP_KERNEL, "%s%s", clk_name,
543 clk_type_postfix[nodes[j].type]);
544 } else {
545 clk_out = kasprintf(GFP_KERNEL, "%s", clk_name);
546 }
547
548 if (!clk_topology[nodes[j].type])
549 continue;
550
551 hw = (*clk_topology[nodes[j].type])(clk_out, clk_id,
552 parent_names,
553 num_parents,
554 &nodes[j]);
555 if (IS_ERR(hw))
556 pr_warn_once("%s() %s register fail with %ld\n",
557 __func__, clk_name, PTR_ERR(hw));
558
559 parent_names[0] = clk_out;
560 }
561 kfree(clk_out);
562 return hw;
563}
564
565/**
566 * zynqmp_register_clocks() - Register clocks
567 * @np: Device node
568 *
569 * Return: 0 on success else error code
570 */
571static int zynqmp_register_clocks(struct device_node *np)
572{
573 int ret;
574 u32 i, total_parents = 0, type = 0;
575 const char *parent_names[MAX_PARENT];
576
577 for (i = 0; i < clock_max_idx; i++) {
578 char clk_name[MAX_NAME_LEN];
579
580 /* get clock name, continue to next clock if name not found */
581 if (zynqmp_get_clock_name(i, clk_name))
582 continue;
583
584 /* Check if clock is valid and output clock.
585 * Do not register invalid or external clock.
586 */
587 ret = zynqmp_get_clock_type(i, &type);
588 if (ret || type != CLK_TYPE_OUTPUT)
589 continue;
590
591 /* Get parents of clock*/
592 if (zynqmp_get_parent_list(np, i, parent_names,
593 &total_parents)) {
594 WARN_ONCE(1, "No parents found for %s\n",
595 clock[i].clk_name);
596 continue;
597 }
598
599 zynqmp_data->hws[i] =
600 zynqmp_register_clk_topology(i, clk_name,
601 total_parents,
602 parent_names);
603 }
604
605 for (i = 0; i < clock_max_idx; i++) {
606 if (IS_ERR(zynqmp_data->hws[i])) {
607 pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n",
608 clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i]));
609 WARN_ON(1);
610 }
611 }
612 return 0;
613}
614
615/**
616 * zynqmp_get_clock_info() - Get clock information from firmware using PM_API
617 */
618static void zynqmp_get_clock_info(void)
619{
620 int i, ret;
621 u32 attr, type = 0;
622
623 for (i = 0; i < clock_max_idx; i++) {
624 zynqmp_pm_clock_get_name(i, clock[i].clk_name);
625 if (!strcmp(clock[i].clk_name, RESERVED_CLK_NAME))
626 continue;
627
628 ret = zynqmp_pm_clock_get_attributes(i, &attr);
629 if (ret)
630 continue;
631
632 clock[i].valid = attr & CLK_VALID_MASK;
633 clock[i].type = attr >> CLK_TYPE_SHIFT ? CLK_TYPE_EXTERNAL :
634 CLK_TYPE_OUTPUT;
635 }
636
637 /* Get topology of all clock */
638 for (i = 0; i < clock_max_idx; i++) {
639 ret = zynqmp_get_clock_type(i, &type);
640 if (ret || type != CLK_TYPE_OUTPUT)
641 continue;
642
643 ret = zynqmp_clock_get_topology(i, clock[i].node,
644 &clock[i].num_nodes);
645 if (ret)
646 continue;
647
648 ret = zynqmp_clock_get_parents(i, clock[i].parent,
649 &clock[i].num_parents);
650 if (ret)
651 continue;
652 }
653}
654
655/**
656 * zynqmp_clk_setup() - Setup the clock framework and register clocks
657 * @np: Device node
658 *
659 * Return: 0 on success else error code
660 */
661static int zynqmp_clk_setup(struct device_node *np)
662{
663 int ret;
664
665 ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx);
666 if (ret)
667 return ret;
668
669 zynqmp_data = kzalloc(sizeof(*zynqmp_data) + sizeof(*zynqmp_data) *
670 clock_max_idx, GFP_KERNEL);
671 if (!zynqmp_data)
672 return -ENOMEM;
673
674 clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL);
675 if (!clock) {
676 kfree(zynqmp_data);
677 return -ENOMEM;
678 }
679
680 zynqmp_get_clock_info();
681 zynqmp_register_clocks(np);
682
683 zynqmp_data->num = clock_max_idx;
684 of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data);
685
686 return 0;
687}
688
689static int zynqmp_clock_probe(struct platform_device *pdev)
690{
691 int ret;
692 struct device *dev = &pdev->dev;
693
694 eemi_ops = zynqmp_pm_get_eemi_ops();
695 if (!eemi_ops)
696 return -ENXIO;
697
698 ret = zynqmp_clk_setup(dev->of_node);
699
700 return ret;
701}
702
703static const struct of_device_id zynqmp_clock_of_match[] = {
704 {.compatible = "xlnx,zynqmp-clk"},
705 {},
706};
707MODULE_DEVICE_TABLE(of, zynqmp_clock_of_match);
708
709static struct platform_driver zynqmp_clock_driver = {
710 .driver = {
711 .name = "zynqmp_clock",
712 .of_match_table = zynqmp_clock_of_match,
713 },
714 .probe = zynqmp_clock_probe,
715};
716module_platform_driver(zynqmp_clock_driver);
diff --git a/drivers/clk/zynqmp/divider.c b/drivers/clk/zynqmp/divider.c
new file mode 100644
index 000000000000..a371c66e72ef
--- /dev/null
+++ b/drivers/clk/zynqmp/divider.c
@@ -0,0 +1,217 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Zynq UltraScale+ MPSoC Divider support
4 *
5 * Copyright (C) 2016-2018 Xilinx
6 *
7 * Adjustable divider clock implementation
8 */
9
10#include <linux/clk.h>
11#include <linux/clk-provider.h>
12#include <linux/slab.h>
13#include "clk-zynqmp.h"
14
15/*
16 * DOC: basic adjustable divider clock that cannot gate
17 *
18 * Traits of this clock:
19 * prepare - clk_prepare only ensures that parents are prepared
20 * enable - clk_enable only ensures that parents are enabled
21 * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor)
22 * parent - fixed parent. No clk_set_parent support
23 */
24
25#define to_zynqmp_clk_divider(_hw) \
26 container_of(_hw, struct zynqmp_clk_divider, hw)
27
28#define CLK_FRAC BIT(13) /* has a fractional parent */
29
30/**
31 * struct zynqmp_clk_divider - adjustable divider clock
32 * @hw: handle between common and hardware-specific interfaces
33 * @flags: Hardware specific flags
34 * @clk_id: Id of clock
35 * @div_type: divisor type (TYPE_DIV1 or TYPE_DIV2)
36 */
37struct zynqmp_clk_divider {
38 struct clk_hw hw;
39 u8 flags;
40 u32 clk_id;
41 u32 div_type;
42};
43
44static inline int zynqmp_divider_get_val(unsigned long parent_rate,
45 unsigned long rate)
46{
47 return DIV_ROUND_CLOSEST(parent_rate, rate);
48}
49
50/**
51 * zynqmp_clk_divider_recalc_rate() - Recalc rate of divider clock
52 * @hw: handle between common and hardware-specific interfaces
53 * @parent_rate: rate of parent clock
54 *
55 * Return: 0 on success else error+reason
56 */
57static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw,
58 unsigned long parent_rate)
59{
60 struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
61 const char *clk_name = clk_hw_get_name(hw);
62 u32 clk_id = divider->clk_id;
63 u32 div_type = divider->div_type;
64 u32 div, value;
65 int ret;
66 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
67
68 ret = eemi_ops->clock_getdivider(clk_id, &div);
69
70 if (ret)
71 pr_warn_once("%s() get divider failed for %s, ret = %d\n",
72 __func__, clk_name, ret);
73
74 if (div_type == TYPE_DIV1)
75 value = div & 0xFFFF;
76 else
77 value = div >> 16;
78
79 return DIV_ROUND_UP_ULL(parent_rate, value);
80}
81
82/**
83 * zynqmp_clk_divider_round_rate() - Round rate of divider clock
84 * @hw: handle between common and hardware-specific interfaces
85 * @rate: rate of clock to be set
86 * @prate: rate of parent clock
87 *
88 * Return: 0 on success else error+reason
89 */
90static long zynqmp_clk_divider_round_rate(struct clk_hw *hw,
91 unsigned long rate,
92 unsigned long *prate)
93{
94 struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
95 const char *clk_name = clk_hw_get_name(hw);
96 u32 clk_id = divider->clk_id;
97 u32 div_type = divider->div_type;
98 u32 bestdiv;
99 int ret;
100 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
101
102 /* if read only, just return current value */
103 if (divider->flags & CLK_DIVIDER_READ_ONLY) {
104 ret = eemi_ops->clock_getdivider(clk_id, &bestdiv);
105
106 if (ret)
107 pr_warn_once("%s() get divider failed for %s, ret = %d\n",
108 __func__, clk_name, ret);
109 if (div_type == TYPE_DIV1)
110 bestdiv = bestdiv & 0xFFFF;
111 else
112 bestdiv = bestdiv >> 16;
113
114 return DIV_ROUND_UP_ULL((u64)*prate, bestdiv);
115 }
116
117 bestdiv = zynqmp_divider_get_val(*prate, rate);
118
119 if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) &&
120 (divider->flags & CLK_FRAC))
121 bestdiv = rate % *prate ? 1 : bestdiv;
122 *prate = rate * bestdiv;
123
124 return rate;
125}
126
127/**
128 * zynqmp_clk_divider_set_rate() - Set rate of divider clock
129 * @hw: handle between common and hardware-specific interfaces
130 * @rate: rate of clock to be set
131 * @parent_rate: rate of parent clock
132 *
133 * Return: 0 on success else error+reason
134 */
135static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
136 unsigned long parent_rate)
137{
138 struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw);
139 const char *clk_name = clk_hw_get_name(hw);
140 u32 clk_id = divider->clk_id;
141 u32 div_type = divider->div_type;
142 u32 value, div;
143 int ret;
144 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
145
146 value = zynqmp_divider_get_val(parent_rate, rate);
147 if (div_type == TYPE_DIV1) {
148 div = value & 0xFFFF;
149 div |= 0xffff << 16;
150 } else {
151 div = 0xffff;
152 div |= value << 16;
153 }
154
155 ret = eemi_ops->clock_setdivider(clk_id, div);
156
157 if (ret)
158 pr_warn_once("%s() set divider failed for %s, ret = %d\n",
159 __func__, clk_name, ret);
160
161 return ret;
162}
163
164static const struct clk_ops zynqmp_clk_divider_ops = {
165 .recalc_rate = zynqmp_clk_divider_recalc_rate,
166 .round_rate = zynqmp_clk_divider_round_rate,
167 .set_rate = zynqmp_clk_divider_set_rate,
168};
169
170/**
171 * zynqmp_clk_register_divider() - Register a divider clock
172 * @name: Name of this clock
173 * @clk_id: Id of clock
174 * @parents: Name of this clock's parents
175 * @num_parents: Number of parents
176 * @nodes: Clock topology node
177 *
178 * Return: clock hardware to registered clock divider
179 */
180struct clk_hw *zynqmp_clk_register_divider(const char *name,
181 u32 clk_id,
182 const char * const *parents,
183 u8 num_parents,
184 const struct clock_topology *nodes)
185{
186 struct zynqmp_clk_divider *div;
187 struct clk_hw *hw;
188 struct clk_init_data init;
189 int ret;
190
191 /* allocate the divider */
192 div = kzalloc(sizeof(*div), GFP_KERNEL);
193 if (!div)
194 return ERR_PTR(-ENOMEM);
195
196 init.name = name;
197 init.ops = &zynqmp_clk_divider_ops;
198 init.flags = nodes->flag;
199 init.parent_names = parents;
200 init.num_parents = 1;
201
202 /* struct clk_divider assignments */
203 div->flags = nodes->type_flag;
204 div->hw.init = &init;
205 div->clk_id = clk_id;
206 div->div_type = nodes->type;
207
208 hw = &div->hw;
209 ret = clk_hw_register(NULL, hw);
210 if (ret) {
211 kfree(div);
212 hw = ERR_PTR(ret);
213 }
214
215 return hw;
216}
217EXPORT_SYMBOL_GPL(zynqmp_clk_register_divider);
diff --git a/drivers/clk/zynqmp/pll.c b/drivers/clk/zynqmp/pll.c
new file mode 100644
index 000000000000..a541397a172c
--- /dev/null
+++ b/drivers/clk/zynqmp/pll.c
@@ -0,0 +1,335 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Zynq UltraScale+ MPSoC PLL driver
4 *
5 * Copyright (C) 2016-2018 Xilinx
6 */
7
8#include <linux/clk.h>
9#include <linux/clk-provider.h>
10#include <linux/slab.h>
11#include "clk-zynqmp.h"
12
13/**
14 * struct zynqmp_pll - PLL clock
15 * @hw: Handle between common and hardware-specific interfaces
16 * @clk_id: PLL clock ID
17 */
18struct zynqmp_pll {
19 struct clk_hw hw;
20 u32 clk_id;
21};
22
23#define to_zynqmp_pll(_hw) container_of(_hw, struct zynqmp_pll, hw)
24
25#define PLL_FBDIV_MIN 25
26#define PLL_FBDIV_MAX 125
27
28#define PS_PLL_VCO_MIN 1500000000
29#define PS_PLL_VCO_MAX 3000000000UL
30
31enum pll_mode {
32 PLL_MODE_INT,
33 PLL_MODE_FRAC,
34};
35
36#define FRAC_OFFSET 0x8
37#define PLLFCFG_FRAC_EN BIT(31)
38#define FRAC_DIV BIT(16) /* 2^16 */
39
40/**
41 * zynqmp_pll_get_mode() - Get mode of PLL
42 * @hw: Handle between common and hardware-specific interfaces
43 *
44 * Return: Mode of PLL
45 */
46static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw)
47{
48 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
49 u32 clk_id = clk->clk_id;
50 const char *clk_name = clk_hw_get_name(hw);
51 u32 ret_payload[PAYLOAD_ARG_CNT];
52 int ret;
53 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
54
55 ret = eemi_ops->ioctl(0, IOCTL_GET_PLL_FRAC_MODE, clk_id, 0,
56 ret_payload);
57 if (ret)
58 pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n",
59 __func__, clk_name, ret);
60
61 return ret_payload[1];
62}
63
64/**
65 * zynqmp_pll_set_mode() - Set the PLL mode
66 * @hw: Handle between common and hardware-specific interfaces
67 * @on: Flag to determine the mode
68 */
69static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on)
70{
71 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
72 u32 clk_id = clk->clk_id;
73 const char *clk_name = clk_hw_get_name(hw);
74 int ret;
75 u32 mode;
76 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
77
78 if (on)
79 mode = PLL_MODE_FRAC;
80 else
81 mode = PLL_MODE_INT;
82
83 ret = eemi_ops->ioctl(0, IOCTL_SET_PLL_FRAC_MODE, clk_id, mode, NULL);
84 if (ret)
85 pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n",
86 __func__, clk_name, ret);
87}
88
89/**
90 * zynqmp_pll_round_rate() - Round a clock frequency
91 * @hw: Handle between common and hardware-specific interfaces
92 * @rate: Desired clock frequency
93 * @prate: Clock frequency of parent clock
94 *
95 * Return: Frequency closest to @rate the hardware can generate
96 */
97static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate,
98 unsigned long *prate)
99{
100 u32 fbdiv;
101 long rate_div, f;
102
103 /* Enable the fractional mode if needed */
104 rate_div = (rate * FRAC_DIV) / *prate;
105 f = rate_div % FRAC_DIV;
106 zynqmp_pll_set_mode(hw, !!f);
107
108 if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
109 if (rate > PS_PLL_VCO_MAX) {
110 fbdiv = rate / PS_PLL_VCO_MAX;
111 rate = rate / (fbdiv + 1);
112 }
113 if (rate < PS_PLL_VCO_MIN) {
114 fbdiv = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate);
115 rate = rate * fbdiv;
116 }
117 return rate;
118 }
119
120 fbdiv = DIV_ROUND_CLOSEST(rate, *prate);
121 fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
122 return *prate * fbdiv;
123}
124
125/**
126 * zynqmp_pll_recalc_rate() - Recalculate clock frequency
127 * @hw: Handle between common and hardware-specific interfaces
128 * @parent_rate: Clock frequency of parent clock
129 *
130 * Return: Current clock frequency
131 */
132static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw,
133 unsigned long parent_rate)
134{
135 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
136 u32 clk_id = clk->clk_id;
137 const char *clk_name = clk_hw_get_name(hw);
138 u32 fbdiv, data;
139 unsigned long rate, frac;
140 u32 ret_payload[PAYLOAD_ARG_CNT];
141 int ret;
142 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
143
144 ret = eemi_ops->clock_getdivider(clk_id, &fbdiv);
145 if (ret)
146 pr_warn_once("%s() get divider failed for %s, ret = %d\n",
147 __func__, clk_name, ret);
148
149 rate = parent_rate * fbdiv;
150 if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
151 eemi_ops->ioctl(0, IOCTL_GET_PLL_FRAC_DATA, clk_id, 0,
152 ret_payload);
153 data = ret_payload[1];
154 frac = (parent_rate * data) / FRAC_DIV;
155 rate = rate + frac;
156 }
157
158 return rate;
159}
160
161/**
162 * zynqmp_pll_set_rate() - Set rate of PLL
163 * @hw: Handle between common and hardware-specific interfaces
164 * @rate: Frequency of clock to be set
165 * @parent_rate: Clock frequency of parent clock
166 *
167 * Set PLL divider to set desired rate.
168 *
169 * Returns: rate which is set on success else error code
170 */
171static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate,
172 unsigned long parent_rate)
173{
174 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
175 u32 clk_id = clk->clk_id;
176 const char *clk_name = clk_hw_get_name(hw);
177 u32 fbdiv;
178 long rate_div, frac, m, f;
179 int ret;
180 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
181
182 if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) {
183 rate_div = (rate * FRAC_DIV) / parent_rate;
184 m = rate_div / FRAC_DIV;
185 f = rate_div % FRAC_DIV;
186 m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX));
187 rate = parent_rate * m;
188 frac = (parent_rate * f) / FRAC_DIV;
189
190 ret = eemi_ops->clock_setdivider(clk_id, m);
191 if (ret)
192 pr_warn_once("%s() set divider failed for %s, ret = %d\n",
193 __func__, clk_name, ret);
194
195 eemi_ops->ioctl(0, IOCTL_SET_PLL_FRAC_DATA, clk_id, f, NULL);
196
197 return rate + frac;
198 }
199
200 fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate);
201 fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX);
202 ret = eemi_ops->clock_setdivider(clk_id, fbdiv);
203 if (ret)
204 pr_warn_once("%s() set divider failed for %s, ret = %d\n",
205 __func__, clk_name, ret);
206
207 return parent_rate * fbdiv;
208}
209
210/**
211 * zynqmp_pll_is_enabled() - Check if a clock is enabled
212 * @hw: Handle between common and hardware-specific interfaces
213 *
214 * Return: 1 if the clock is enabled, 0 otherwise
215 */
216static int zynqmp_pll_is_enabled(struct clk_hw *hw)
217{
218 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
219 const char *clk_name = clk_hw_get_name(hw);
220 u32 clk_id = clk->clk_id;
221 unsigned int state;
222 int ret;
223 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
224
225 ret = eemi_ops->clock_getstate(clk_id, &state);
226 if (ret) {
227 pr_warn_once("%s() clock get state failed for %s, ret = %d\n",
228 __func__, clk_name, ret);
229 return -EIO;
230 }
231
232 return state ? 1 : 0;
233}
234
235/**
236 * zynqmp_pll_enable() - Enable clock
237 * @hw: Handle between common and hardware-specific interfaces
238 *
239 * Return: 0 on success else error code
240 */
241static int zynqmp_pll_enable(struct clk_hw *hw)
242{
243 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
244 const char *clk_name = clk_hw_get_name(hw);
245 u32 clk_id = clk->clk_id;
246 int ret;
247 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
248
249 if (zynqmp_pll_is_enabled(hw))
250 return 0;
251
252 ret = eemi_ops->clock_enable(clk_id);
253 if (ret)
254 pr_warn_once("%s() clock enable failed for %s, ret = %d\n",
255 __func__, clk_name, ret);
256
257 return ret;
258}
259
260/**
261 * zynqmp_pll_disable() - Disable clock
262 * @hw: Handle between common and hardware-specific interfaces
263 */
264static void zynqmp_pll_disable(struct clk_hw *hw)
265{
266 struct zynqmp_pll *clk = to_zynqmp_pll(hw);
267 const char *clk_name = clk_hw_get_name(hw);
268 u32 clk_id = clk->clk_id;
269 int ret;
270 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
271
272 if (!zynqmp_pll_is_enabled(hw))
273 return;
274
275 ret = eemi_ops->clock_disable(clk_id);
276 if (ret)
277 pr_warn_once("%s() clock disable failed for %s, ret = %d\n",
278 __func__, clk_name, ret);
279}
280
281static const struct clk_ops zynqmp_pll_ops = {
282 .enable = zynqmp_pll_enable,
283 .disable = zynqmp_pll_disable,
284 .is_enabled = zynqmp_pll_is_enabled,
285 .round_rate = zynqmp_pll_round_rate,
286 .recalc_rate = zynqmp_pll_recalc_rate,
287 .set_rate = zynqmp_pll_set_rate,
288};
289
290/**
291 * zynqmp_clk_register_pll() - Register PLL with the clock framework
292 * @name: PLL name
293 * @clk_id: Clock ID
294 * @parents: Name of this clock's parents
295 * @num_parents: Number of parents
296 * @nodes: Clock topology node
297 *
298 * Return: clock hardware to the registered clock
299 */
300struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id,
301 const char * const *parents,
302 u8 num_parents,
303 const struct clock_topology *nodes)
304{
305 struct zynqmp_pll *pll;
306 struct clk_hw *hw;
307 struct clk_init_data init;
308 int ret;
309
310 init.name = name;
311 init.ops = &zynqmp_pll_ops;
312 init.flags = nodes->flag;
313 init.parent_names = parents;
314 init.num_parents = 1;
315
316 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
317 if (!pll)
318 return ERR_PTR(-ENOMEM);
319
320 pll->hw.init = &init;
321 pll->clk_id = clk_id;
322
323 hw = &pll->hw;
324 ret = clk_hw_register(NULL, hw);
325 if (ret) {
326 kfree(pll);
327 return ERR_PTR(ret);
328 }
329
330 clk_hw_set_rate_range(hw, PS_PLL_VCO_MIN, PS_PLL_VCO_MAX);
331 if (ret < 0)
332 pr_err("%s:ERROR clk_set_rate_range failed %d\n", name, ret);
333
334 return hw;
335}
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 57304b2e989f..df9467eef32a 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -460,4 +460,18 @@ config EDAC_TI
460 Support for error detection and correction on the 460 Support for error detection and correction on the
461 TI SoCs. 461 TI SoCs.
462 462
463config EDAC_QCOM
464 tristate "QCOM EDAC Controller"
465 depends on ARCH_QCOM && QCOM_LLCC
466 help
467 Support for error detection and correction on the
468 Qualcomm Technologies, Inc. SoCs.
469
470 This driver reports Single Bit Errors (SBEs) and Double Bit Errors (DBEs).
471 As of now, it supports error reporting for Last Level Cache Controller (LLCC)
472 of Tag RAM and Data RAM.
473
474 For debugging issues having to do with stability and overall system
475 health, you should probably say 'Y' here.
476
463endif # EDAC 477endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 02b43a7d8c3e..716096d08ea0 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -77,3 +77,4 @@ obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o
77obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o 77obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
78obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o 78obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
79obj-$(CONFIG_EDAC_TI) += ti_edac.o 79obj-$(CONFIG_EDAC_TI) += ti_edac.o
80obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o
diff --git a/drivers/edac/qcom_edac.c b/drivers/edac/qcom_edac.c
new file mode 100644
index 000000000000..82bd775124f2
--- /dev/null
+++ b/drivers/edac/qcom_edac.c
@@ -0,0 +1,414 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/edac.h>
7#include <linux/interrupt.h>
8#include <linux/kernel.h>
9#include <linux/of.h>
10#include <linux/platform_device.h>
11#include <linux/regmap.h>
12#include <linux/soc/qcom/llcc-qcom.h>
13
14#include "edac_mc.h"
15#include "edac_device.h"
16
17#define EDAC_LLCC "qcom_llcc"
18
19#define LLCC_ERP_PANIC_ON_UE 1
20
21#define TRP_SYN_REG_CNT 6
22#define DRP_SYN_REG_CNT 8
23
24#define LLCC_COMMON_STATUS0 0x0003000c
25#define LLCC_LB_CNT_MASK GENMASK(31, 28)
26#define LLCC_LB_CNT_SHIFT 28
27
28/* Single & double bit syndrome register offsets */
29#define TRP_ECC_SB_ERR_SYN0 0x0002304c
30#define TRP_ECC_DB_ERR_SYN0 0x00020370
31#define DRP_ECC_SB_ERR_SYN0 0x0004204c
32#define DRP_ECC_DB_ERR_SYN0 0x00042070
33
34/* Error register offsets */
35#define TRP_ECC_ERROR_STATUS1 0x00020348
36#define TRP_ECC_ERROR_STATUS0 0x00020344
37#define DRP_ECC_ERROR_STATUS1 0x00042048
38#define DRP_ECC_ERROR_STATUS0 0x00042044
39
40/* TRP, DRP interrupt register offsets */
41#define DRP_INTERRUPT_STATUS 0x00041000
42#define TRP_INTERRUPT_0_STATUS 0x00020480
43#define DRP_INTERRUPT_CLEAR 0x00041008
44#define DRP_ECC_ERROR_CNTR_CLEAR 0x00040004
45#define TRP_INTERRUPT_0_CLEAR 0x00020484
46#define TRP_ECC_ERROR_CNTR_CLEAR 0x00020440
47
48/* Mask and shift macros */
49#define ECC_DB_ERR_COUNT_MASK GENMASK(4, 0)
50#define ECC_DB_ERR_WAYS_MASK GENMASK(31, 16)
51#define ECC_DB_ERR_WAYS_SHIFT BIT(4)
52
53#define ECC_SB_ERR_COUNT_MASK GENMASK(23, 16)
54#define ECC_SB_ERR_COUNT_SHIFT BIT(4)
55#define ECC_SB_ERR_WAYS_MASK GENMASK(15, 0)
56
57#define SB_ECC_ERROR BIT(0)
58#define DB_ECC_ERROR BIT(1)
59
60#define DRP_TRP_INT_CLEAR GENMASK(1, 0)
61#define DRP_TRP_CNT_CLEAR GENMASK(1, 0)
62
63/* Config registers offsets*/
64#define DRP_ECC_ERROR_CFG 0x00040000
65
66/* Tag RAM, Data RAM interrupt register offsets */
67#define CMN_INTERRUPT_0_ENABLE 0x0003001c
68#define CMN_INTERRUPT_2_ENABLE 0x0003003c
69#define TRP_INTERRUPT_0_ENABLE 0x00020488
70#define DRP_INTERRUPT_ENABLE 0x0004100c
71
72#define SB_ERROR_THRESHOLD 0x1
73#define SB_ERROR_THRESHOLD_SHIFT 24
74#define SB_DB_TRP_INTERRUPT_ENABLE 0x3
75#define TRP0_INTERRUPT_ENABLE 0x1
76#define DRP0_INTERRUPT_ENABLE BIT(6)
77#define SB_DB_DRP_INTERRUPT_ENABLE 0x3
78
79enum {
80 LLCC_DRAM_CE = 0,
81 LLCC_DRAM_UE,
82 LLCC_TRAM_CE,
83 LLCC_TRAM_UE,
84};
85
86static const struct llcc_edac_reg_data edac_reg_data[] = {
87 [LLCC_DRAM_CE] = {
88 .name = "DRAM Single-bit",
89 .synd_reg = DRP_ECC_SB_ERR_SYN0,
90 .count_status_reg = DRP_ECC_ERROR_STATUS1,
91 .ways_status_reg = DRP_ECC_ERROR_STATUS0,
92 .reg_cnt = DRP_SYN_REG_CNT,
93 .count_mask = ECC_SB_ERR_COUNT_MASK,
94 .ways_mask = ECC_SB_ERR_WAYS_MASK,
95 .count_shift = ECC_SB_ERR_COUNT_SHIFT,
96 },
97 [LLCC_DRAM_UE] = {
98 .name = "DRAM Double-bit",
99 .synd_reg = DRP_ECC_DB_ERR_SYN0,
100 .count_status_reg = DRP_ECC_ERROR_STATUS1,
101 .ways_status_reg = DRP_ECC_ERROR_STATUS0,
102 .reg_cnt = DRP_SYN_REG_CNT,
103 .count_mask = ECC_DB_ERR_COUNT_MASK,
104 .ways_mask = ECC_DB_ERR_WAYS_MASK,
105 .ways_shift = ECC_DB_ERR_WAYS_SHIFT,
106 },
107 [LLCC_TRAM_CE] = {
108 .name = "TRAM Single-bit",
109 .synd_reg = TRP_ECC_SB_ERR_SYN0,
110 .count_status_reg = TRP_ECC_ERROR_STATUS1,
111 .ways_status_reg = TRP_ECC_ERROR_STATUS0,
112 .reg_cnt = TRP_SYN_REG_CNT,
113 .count_mask = ECC_SB_ERR_COUNT_MASK,
114 .ways_mask = ECC_SB_ERR_WAYS_MASK,
115 .count_shift = ECC_SB_ERR_COUNT_SHIFT,
116 },
117 [LLCC_TRAM_UE] = {
118 .name = "TRAM Double-bit",
119 .synd_reg = TRP_ECC_DB_ERR_SYN0,
120 .count_status_reg = TRP_ECC_ERROR_STATUS1,
121 .ways_status_reg = TRP_ECC_ERROR_STATUS0,
122 .reg_cnt = TRP_SYN_REG_CNT,
123 .count_mask = ECC_DB_ERR_COUNT_MASK,
124 .ways_mask = ECC_DB_ERR_WAYS_MASK,
125 .ways_shift = ECC_DB_ERR_WAYS_SHIFT,
126 },
127};
128
129static int qcom_llcc_core_setup(struct regmap *llcc_bcast_regmap)
130{
131 u32 sb_err_threshold;
132 int ret;
133
134 /*
135 * Configure interrupt enable registers such that Tag, Data RAM related
136 * interrupts are propagated to interrupt controller for servicing
137 */
138 ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE,
139 TRP0_INTERRUPT_ENABLE,
140 TRP0_INTERRUPT_ENABLE);
141 if (ret)
142 return ret;
143
144 ret = regmap_update_bits(llcc_bcast_regmap, TRP_INTERRUPT_0_ENABLE,
145 SB_DB_TRP_INTERRUPT_ENABLE,
146 SB_DB_TRP_INTERRUPT_ENABLE);
147 if (ret)
148 return ret;
149
150 sb_err_threshold = (SB_ERROR_THRESHOLD << SB_ERROR_THRESHOLD_SHIFT);
151 ret = regmap_write(llcc_bcast_regmap, DRP_ECC_ERROR_CFG,
152 sb_err_threshold);
153 if (ret)
154 return ret;
155
156 ret = regmap_update_bits(llcc_bcast_regmap, CMN_INTERRUPT_2_ENABLE,
157 DRP0_INTERRUPT_ENABLE,
158 DRP0_INTERRUPT_ENABLE);
159 if (ret)
160 return ret;
161
162 ret = regmap_write(llcc_bcast_regmap, DRP_INTERRUPT_ENABLE,
163 SB_DB_DRP_INTERRUPT_ENABLE);
164 return ret;
165}
166
167/* Clear the error interrupt and counter registers */
168static int
169qcom_llcc_clear_error_status(int err_type, struct llcc_drv_data *drv)
170{
171 int ret = 0;
172
173 switch (err_type) {
174 case LLCC_DRAM_CE:
175 case LLCC_DRAM_UE:
176 ret = regmap_write(drv->bcast_regmap, DRP_INTERRUPT_CLEAR,
177 DRP_TRP_INT_CLEAR);
178 if (ret)
179 return ret;
180
181 ret = regmap_write(drv->bcast_regmap, DRP_ECC_ERROR_CNTR_CLEAR,
182 DRP_TRP_CNT_CLEAR);
183 if (ret)
184 return ret;
185 break;
186 case LLCC_TRAM_CE:
187 case LLCC_TRAM_UE:
188 ret = regmap_write(drv->bcast_regmap, TRP_INTERRUPT_0_CLEAR,
189 DRP_TRP_INT_CLEAR);
190 if (ret)
191 return ret;
192
193 ret = regmap_write(drv->bcast_regmap, TRP_ECC_ERROR_CNTR_CLEAR,
194 DRP_TRP_CNT_CLEAR);
195 if (ret)
196 return ret;
197 break;
198 default:
199 ret = -EINVAL;
200 edac_printk(KERN_CRIT, EDAC_LLCC, "Unexpected error type: %d\n",
201 err_type);
202 }
203 return ret;
204}
205
206/* Dump Syndrome registers data for Tag RAM, Data RAM bit errors*/
207static int
208dump_syn_reg_values(struct llcc_drv_data *drv, u32 bank, int err_type)
209{
210 struct llcc_edac_reg_data reg_data = edac_reg_data[err_type];
211 int err_cnt, err_ways, ret, i;
212 u32 synd_reg, synd_val;
213
214 for (i = 0; i < reg_data.reg_cnt; i++) {
215 synd_reg = reg_data.synd_reg + (i * 4);
216 ret = regmap_read(drv->regmap, drv->offsets[bank] + synd_reg,
217 &synd_val);
218 if (ret)
219 goto clear;
220
221 edac_printk(KERN_CRIT, EDAC_LLCC, "%s: ECC_SYN%d: 0x%8x\n",
222 reg_data.name, i, synd_val);
223 }
224
225 ret = regmap_read(drv->regmap,
226 drv->offsets[bank] + reg_data.count_status_reg,
227 &err_cnt);
228 if (ret)
229 goto clear;
230
231 err_cnt &= reg_data.count_mask;
232 err_cnt >>= reg_data.count_shift;
233 edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error count: 0x%4x\n",
234 reg_data.name, err_cnt);
235
236 ret = regmap_read(drv->regmap,
237 drv->offsets[bank] + reg_data.ways_status_reg,
238 &err_ways);
239 if (ret)
240 goto clear;
241
242 err_ways &= reg_data.ways_mask;
243 err_ways >>= reg_data.ways_shift;
244
245 edac_printk(KERN_CRIT, EDAC_LLCC, "%s: Error ways: 0x%4x\n",
246 reg_data.name, err_ways);
247
248clear:
249 return qcom_llcc_clear_error_status(err_type, drv);
250}
251
252static int
253dump_syn_reg(struct edac_device_ctl_info *edev_ctl, int err_type, u32 bank)
254{
255 struct llcc_drv_data *drv = edev_ctl->pvt_info;
256 int ret;
257
258 ret = dump_syn_reg_values(drv, bank, err_type);
259 if (ret)
260 return ret;
261
262 switch (err_type) {
263 case LLCC_DRAM_CE:
264 edac_device_handle_ce(edev_ctl, 0, bank,
265 "LLCC Data RAM correctable Error");
266 break;
267 case LLCC_DRAM_UE:
268 edac_device_handle_ue(edev_ctl, 0, bank,
269 "LLCC Data RAM uncorrectable Error");
270 break;
271 case LLCC_TRAM_CE:
272 edac_device_handle_ce(edev_ctl, 0, bank,
273 "LLCC Tag RAM correctable Error");
274 break;
275 case LLCC_TRAM_UE:
276 edac_device_handle_ue(edev_ctl, 0, bank,
277 "LLCC Tag RAM uncorrectable Error");
278 break;
279 default:
280 ret = -EINVAL;
281 edac_printk(KERN_CRIT, EDAC_LLCC, "Unexpected error type: %d\n",
282 err_type);
283 }
284
285 return ret;
286}
287
288static irqreturn_t
289llcc_ecc_irq_handler(int irq, void *edev_ctl)
290{
291 struct edac_device_ctl_info *edac_dev_ctl = edev_ctl;
292 struct llcc_drv_data *drv = edac_dev_ctl->pvt_info;
293 irqreturn_t irq_rc = IRQ_NONE;
294 u32 drp_error, trp_error, i;
295 bool irq_handled;
296 int ret;
297
298 /* Iterate over the banks and look for Tag RAM or Data RAM errors */
299 for (i = 0; i < drv->num_banks; i++) {
300 ret = regmap_read(drv->regmap,
301 drv->offsets[i] + DRP_INTERRUPT_STATUS,
302 &drp_error);
303
304 if (!ret && (drp_error & SB_ECC_ERROR)) {
305 edac_printk(KERN_CRIT, EDAC_LLCC,
306 "Single Bit Error detected in Data RAM\n");
307 ret = dump_syn_reg(edev_ctl, LLCC_DRAM_CE, i);
308 } else if (!ret && (drp_error & DB_ECC_ERROR)) {
309 edac_printk(KERN_CRIT, EDAC_LLCC,
310 "Double Bit Error detected in Data RAM\n");
311 ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i);
312 }
313 if (!ret)
314 irq_handled = true;
315
316 ret = regmap_read(drv->regmap,
317 drv->offsets[i] + TRP_INTERRUPT_0_STATUS,
318 &trp_error);
319
320 if (!ret && (trp_error & SB_ECC_ERROR)) {
321 edac_printk(KERN_CRIT, EDAC_LLCC,
322 "Single Bit Error detected in Tag RAM\n");
323 ret = dump_syn_reg(edev_ctl, LLCC_TRAM_CE, i);
324 } else if (!ret && (trp_error & DB_ECC_ERROR)) {
325 edac_printk(KERN_CRIT, EDAC_LLCC,
326 "Double Bit Error detected in Tag RAM\n");
327 ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i);
328 }
329 if (!ret)
330 irq_handled = true;
331 }
332
333 if (irq_handled)
334 irq_rc = IRQ_HANDLED;
335
336 return irq_rc;
337}
338
339static int qcom_llcc_edac_probe(struct platform_device *pdev)
340{
341 struct llcc_drv_data *llcc_driv_data = pdev->dev.platform_data;
342 struct edac_device_ctl_info *edev_ctl;
343 struct device *dev = &pdev->dev;
344 int ecc_irq;
345 int rc;
346
347 rc = qcom_llcc_core_setup(llcc_driv_data->bcast_regmap);
348 if (rc)
349 return rc;
350
351 /* Allocate edac control info */
352 edev_ctl = edac_device_alloc_ctl_info(0, "qcom-llcc", 1, "bank",
353 llcc_driv_data->num_banks, 1,
354 NULL, 0,
355 edac_device_alloc_index());
356
357 if (!edev_ctl)
358 return -ENOMEM;
359
360 edev_ctl->dev = dev;
361 edev_ctl->mod_name = dev_name(dev);
362 edev_ctl->dev_name = dev_name(dev);
363 edev_ctl->ctl_name = "llcc";
364 edev_ctl->panic_on_ue = LLCC_ERP_PANIC_ON_UE;
365 edev_ctl->pvt_info = llcc_driv_data;
366
367 rc = edac_device_add_device(edev_ctl);
368 if (rc)
369 goto out_mem;
370
371 platform_set_drvdata(pdev, edev_ctl);
372
373 /* Request for ecc irq */
374 ecc_irq = llcc_driv_data->ecc_irq;
375 if (ecc_irq < 0) {
376 rc = -ENODEV;
377 goto out_dev;
378 }
379 rc = devm_request_irq(dev, ecc_irq, llcc_ecc_irq_handler,
380 IRQF_TRIGGER_HIGH, "llcc_ecc", edev_ctl);
381 if (rc)
382 goto out_dev;
383
384 return rc;
385
386out_dev:
387 edac_device_del_device(edev_ctl->dev);
388out_mem:
389 edac_device_free_ctl_info(edev_ctl);
390
391 return rc;
392}
393
394static int qcom_llcc_edac_remove(struct platform_device *pdev)
395{
396 struct edac_device_ctl_info *edev_ctl = dev_get_drvdata(&pdev->dev);
397
398 edac_device_del_device(edev_ctl->dev);
399 edac_device_free_ctl_info(edev_ctl);
400
401 return 0;
402}
403
404static struct platform_driver qcom_llcc_edac_driver = {
405 .probe = qcom_llcc_edac_probe,
406 .remove = qcom_llcc_edac_remove,
407 .driver = {
408 .name = "qcom_llcc_edac",
409 },
410};
411module_platform_driver(qcom_llcc_edac_driver);
412
413MODULE_DESCRIPTION("QCOM EDAC driver");
414MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 6e83880046d7..7670e8dda829 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -289,7 +289,9 @@ config HAVE_ARM_SMCCC
289source "drivers/firmware/broadcom/Kconfig" 289source "drivers/firmware/broadcom/Kconfig"
290source "drivers/firmware/google/Kconfig" 290source "drivers/firmware/google/Kconfig"
291source "drivers/firmware/efi/Kconfig" 291source "drivers/firmware/efi/Kconfig"
292source "drivers/firmware/imx/Kconfig"
292source "drivers/firmware/meson/Kconfig" 293source "drivers/firmware/meson/Kconfig"
293source "drivers/firmware/tegra/Kconfig" 294source "drivers/firmware/tegra/Kconfig"
295source "drivers/firmware/xilinx/Kconfig"
294 296
295endmenu 297endmenu
diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile
index e18a041cfc53..13660a951437 100644
--- a/drivers/firmware/Makefile
+++ b/drivers/firmware/Makefile
@@ -31,4 +31,6 @@ obj-y += meson/
31obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ 31obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
32obj-$(CONFIG_EFI) += efi/ 32obj-$(CONFIG_EFI) += efi/
33obj-$(CONFIG_UEFI_CPER) += efi/ 33obj-$(CONFIG_UEFI_CPER) += efi/
34obj-y += imx/
34obj-y += tegra/ 35obj-y += tegra/
36obj-y += xilinx/
diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c
index 9dff33ea6416..204390297f4b 100644
--- a/drivers/firmware/arm_scmi/base.c
+++ b/drivers/firmware/arm_scmi/base.c
@@ -208,7 +208,7 @@ static int scmi_base_discover_agent_get(const struct scmi_handle *handle,
208 208
209 ret = scmi_do_xfer(handle, t); 209 ret = scmi_do_xfer(handle, t);
210 if (!ret) 210 if (!ret)
211 memcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE); 211 strlcpy(name, t->rx.buf, SCMI_MAX_STR_SIZE);
212 212
213 scmi_xfer_put(handle, t); 213 scmi_xfer_put(handle, t);
214 214
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index e4119eb34986..30fc04e28431 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -111,7 +111,7 @@ static int scmi_clock_attributes_get(const struct scmi_handle *handle,
111 111
112 ret = scmi_do_xfer(handle, t); 112 ret = scmi_do_xfer(handle, t);
113 if (!ret) 113 if (!ret)
114 memcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE); 114 strlcpy(clk->name, attr->name, SCMI_MAX_STR_SIZE);
115 else 115 else
116 clk->name[0] = '\0'; 116 clk->name[0] = '\0';
117 117
diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c
index 64342944d917..3c8ae7cc35de 100644
--- a/drivers/firmware/arm_scmi/perf.c
+++ b/drivers/firmware/arm_scmi/perf.c
@@ -174,7 +174,7 @@ scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
174 dom_info->mult_factor = 174 dom_info->mult_factor =
175 (dom_info->sustained_freq_khz * 1000) / 175 (dom_info->sustained_freq_khz * 1000) /
176 dom_info->sustained_perf_level; 176 dom_info->sustained_perf_level;
177 memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); 177 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
178 } 178 }
179 179
180 scmi_xfer_put(handle, t); 180 scmi_xfer_put(handle, t);
@@ -427,6 +427,33 @@ static int scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain,
427 return ret; 427 return ret;
428} 428}
429 429
430static int scmi_dvfs_est_power_get(const struct scmi_handle *handle, u32 domain,
431 unsigned long *freq, unsigned long *power)
432{
433 struct scmi_perf_info *pi = handle->perf_priv;
434 struct perf_dom_info *dom;
435 unsigned long opp_freq;
436 int idx, ret = -EINVAL;
437 struct scmi_opp *opp;
438
439 dom = pi->dom_info + domain;
440 if (!dom)
441 return -EIO;
442
443 for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) {
444 opp_freq = opp->perf * dom->mult_factor;
445 if (opp_freq < *freq)
446 continue;
447
448 *freq = opp_freq;
449 *power = opp->power;
450 ret = 0;
451 break;
452 }
453
454 return ret;
455}
456
430static struct scmi_perf_ops perf_ops = { 457static struct scmi_perf_ops perf_ops = {
431 .limits_set = scmi_perf_limits_set, 458 .limits_set = scmi_perf_limits_set,
432 .limits_get = scmi_perf_limits_get, 459 .limits_get = scmi_perf_limits_get,
@@ -437,6 +464,7 @@ static struct scmi_perf_ops perf_ops = {
437 .device_opps_add = scmi_dvfs_device_opps_add, 464 .device_opps_add = scmi_dvfs_device_opps_add,
438 .freq_set = scmi_dvfs_freq_set, 465 .freq_set = scmi_dvfs_freq_set,
439 .freq_get = scmi_dvfs_freq_get, 466 .freq_get = scmi_dvfs_freq_get,
467 .est_power_get = scmi_dvfs_est_power_get,
440}; 468};
441 469
442static int scmi_perf_protocol_init(struct scmi_handle *handle) 470static int scmi_perf_protocol_init(struct scmi_handle *handle)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index cfa033b05aed..62f3401a1f01 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -106,7 +106,7 @@ scmi_power_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
106 dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags); 106 dom_info->state_set_notify = SUPPORTS_STATE_SET_NOTIFY(flags);
107 dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags); 107 dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
108 dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags); 108 dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
109 memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE); 109 strlcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
110 } 110 }
111 111
112 scmi_xfer_put(handle, t); 112 scmi_xfer_put(handle, t);
diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c
index 27f2092b9882..b53d5cc9c9f6 100644
--- a/drivers/firmware/arm_scmi/sensors.c
+++ b/drivers/firmware/arm_scmi/sensors.c
@@ -140,7 +140,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle,
140 s = &si->sensors[desc_index + cnt]; 140 s = &si->sensors[desc_index + cnt];
141 s->id = le32_to_cpu(buf->desc[cnt].id); 141 s->id = le32_to_cpu(buf->desc[cnt].id);
142 s->type = SENSOR_TYPE(attrh); 142 s->type = SENSOR_TYPE(attrh);
143 memcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE); 143 strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
144 } 144 }
145 145
146 desc_index += num_returned; 146 desc_index += num_returned;
diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
new file mode 100644
index 000000000000..b170c2851e48
--- /dev/null
+++ b/drivers/firmware/imx/Kconfig
@@ -0,0 +1,11 @@
1config IMX_SCU
2 bool "IMX SCU Protocol driver"
3 depends on IMX_MBOX
4 help
5 The System Controller Firmware (SCFW) is a low-level system function
6 which runs on a dedicated Cortex-M core to provide power, clock, and
7 resource management. It exists on some i.MX8 processors. e.g. i.MX8QM
8 (QM, QP), and i.MX8QX (QXP, DX).
9
10 This driver manages the IPC interface between host CPU and the
11 SCU firmware running on M4.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
new file mode 100644
index 000000000000..0ac04dfda8d4
--- /dev/null
+++ b/drivers/firmware/imx/Makefile
@@ -0,0 +1,2 @@
1# SPDX-License-Identifier: GPL-2.0
2obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c
new file mode 100644
index 000000000000..2bb1a19c413f
--- /dev/null
+++ b/drivers/firmware/imx/imx-scu.c
@@ -0,0 +1,270 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2018 NXP
4 * Author: Dong Aisheng <aisheng.dong@nxp.com>
5 *
6 * Implementation of the SCU IPC functions using MUs (client side).
7 *
8 */
9
10#include <linux/err.h>
11#include <linux/firmware/imx/types.h>
12#include <linux/firmware/imx/ipc.h>
13#include <linux/interrupt.h>
14#include <linux/irq.h>
15#include <linux/kernel.h>
16#include <linux/mailbox_client.h>
17#include <linux/module.h>
18#include <linux/mutex.h>
19#include <linux/of_platform.h>
20#include <linux/platform_device.h>
21
22#define SCU_MU_CHAN_NUM 8
23#define MAX_RX_TIMEOUT (msecs_to_jiffies(30))
24
25struct imx_sc_chan {
26 struct imx_sc_ipc *sc_ipc;
27
28 struct mbox_client cl;
29 struct mbox_chan *ch;
30 int idx;
31};
32
33struct imx_sc_ipc {
34 /* SCU uses 4 Tx and 4 Rx channels */
35 struct imx_sc_chan chans[SCU_MU_CHAN_NUM];
36 struct device *dev;
37 struct mutex lock;
38 struct completion done;
39
40 /* temporarily store the SCU msg */
41 u32 *msg;
42 u8 rx_size;
43 u8 count;
44};
45
46/*
47 * This type is used to indicate error response for most functions.
48 */
49enum imx_sc_error_codes {
50 IMX_SC_ERR_NONE = 0, /* Success */
51 IMX_SC_ERR_VERSION = 1, /* Incompatible API version */
52 IMX_SC_ERR_CONFIG = 2, /* Configuration error */
53 IMX_SC_ERR_PARM = 3, /* Bad parameter */
54 IMX_SC_ERR_NOACCESS = 4, /* Permission error (no access) */
55 IMX_SC_ERR_LOCKED = 5, /* Permission error (locked) */
56 IMX_SC_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */
57 IMX_SC_ERR_NOTFOUND = 7, /* Not found */
58 IMX_SC_ERR_NOPOWER = 8, /* No power */
59 IMX_SC_ERR_IPC = 9, /* Generic IPC error */
60 IMX_SC_ERR_BUSY = 10, /* Resource is currently busy/active */
61 IMX_SC_ERR_FAIL = 11, /* General I/O failure */
62 IMX_SC_ERR_LAST
63};
64
65static int imx_sc_linux_errmap[IMX_SC_ERR_LAST] = {
66 0, /* IMX_SC_ERR_NONE */
67 -EINVAL, /* IMX_SC_ERR_VERSION */
68 -EINVAL, /* IMX_SC_ERR_CONFIG */
69 -EINVAL, /* IMX_SC_ERR_PARM */
70 -EACCES, /* IMX_SC_ERR_NOACCESS */
71 -EACCES, /* IMX_SC_ERR_LOCKED */
72 -ERANGE, /* IMX_SC_ERR_UNAVAILABLE */
73 -EEXIST, /* IMX_SC_ERR_NOTFOUND */
74 -EPERM, /* IMX_SC_ERR_NOPOWER */
75 -EPIPE, /* IMX_SC_ERR_IPC */
76 -EBUSY, /* IMX_SC_ERR_BUSY */
77 -EIO, /* IMX_SC_ERR_FAIL */
78};
79
80static struct imx_sc_ipc *imx_sc_ipc_handle;
81
82static inline int imx_sc_to_linux_errno(int errno)
83{
84 if (errno >= IMX_SC_ERR_NONE && errno < IMX_SC_ERR_LAST)
85 return imx_sc_linux_errmap[errno];
86 return -EIO;
87}
88
89/*
90 * Get the default handle used by SCU
91 */
92int imx_scu_get_handle(struct imx_sc_ipc **ipc)
93{
94 if (!imx_sc_ipc_handle)
95 return -EPROBE_DEFER;
96
97 *ipc = imx_sc_ipc_handle;
98 return 0;
99}
100EXPORT_SYMBOL(imx_scu_get_handle);
101
102static void imx_scu_rx_callback(struct mbox_client *c, void *msg)
103{
104 struct imx_sc_chan *sc_chan = container_of(c, struct imx_sc_chan, cl);
105 struct imx_sc_ipc *sc_ipc = sc_chan->sc_ipc;
106 struct imx_sc_rpc_msg *hdr;
107 u32 *data = msg;
108
109 if (sc_chan->idx == 0) {
110 hdr = msg;
111 sc_ipc->rx_size = hdr->size;
112 dev_dbg(sc_ipc->dev, "msg rx size %u\n", sc_ipc->rx_size);
113 if (sc_ipc->rx_size > 4)
114 dev_warn(sc_ipc->dev, "RPC does not support receiving over 4 words: %u\n",
115 sc_ipc->rx_size);
116 }
117
118 sc_ipc->msg[sc_chan->idx] = *data;
119 sc_ipc->count++;
120
121 dev_dbg(sc_ipc->dev, "mu %u msg %u 0x%x\n", sc_chan->idx,
122 sc_ipc->count, *data);
123
124 if ((sc_ipc->rx_size != 0) && (sc_ipc->count == sc_ipc->rx_size))
125 complete(&sc_ipc->done);
126}
127
128static int imx_scu_ipc_write(struct imx_sc_ipc *sc_ipc, void *msg)
129{
130 struct imx_sc_rpc_msg *hdr = msg;
131 struct imx_sc_chan *sc_chan;
132 u32 *data = msg;
133 int ret;
134 int i;
135
136 /* Check size */
137 if (hdr->size > IMX_SC_RPC_MAX_MSG)
138 return -EINVAL;
139
140 dev_dbg(sc_ipc->dev, "RPC SVC %u FUNC %u SIZE %u\n", hdr->svc,
141 hdr->func, hdr->size);
142
143 for (i = 0; i < hdr->size; i++) {
144 sc_chan = &sc_ipc->chans[i % 4];
145 ret = mbox_send_message(sc_chan->ch, &data[i]);
146 if (ret < 0)
147 return ret;
148 }
149
150 return 0;
151}
152
153/*
154 * RPC command/response
155 */
156int imx_scu_call_rpc(struct imx_sc_ipc *sc_ipc, void *msg, bool have_resp)
157{
158 struct imx_sc_rpc_msg *hdr;
159 int ret;
160
161 if (WARN_ON(!sc_ipc || !msg))
162 return -EINVAL;
163
164 mutex_lock(&sc_ipc->lock);
165 reinit_completion(&sc_ipc->done);
166
167 sc_ipc->msg = msg;
168 sc_ipc->count = 0;
169 ret = imx_scu_ipc_write(sc_ipc, msg);
170 if (ret < 0) {
171 dev_err(sc_ipc->dev, "RPC send msg failed: %d\n", ret);
172 goto out;
173 }
174
175 if (have_resp) {
176 if (!wait_for_completion_timeout(&sc_ipc->done,
177 MAX_RX_TIMEOUT)) {
178 dev_err(sc_ipc->dev, "RPC send msg timeout\n");
179 mutex_unlock(&sc_ipc->lock);
180 return -ETIMEDOUT;
181 }
182
183 /* response status is stored in hdr->func field */
184 hdr = msg;
185 ret = hdr->func;
186 }
187
188out:
189 mutex_unlock(&sc_ipc->lock);
190
191 dev_dbg(sc_ipc->dev, "RPC SVC done\n");
192
193 return imx_sc_to_linux_errno(ret);
194}
195EXPORT_SYMBOL(imx_scu_call_rpc);
196
197static int imx_scu_probe(struct platform_device *pdev)
198{
199 struct device *dev = &pdev->dev;
200 struct imx_sc_ipc *sc_ipc;
201 struct imx_sc_chan *sc_chan;
202 struct mbox_client *cl;
203 char *chan_name;
204 int ret;
205 int i;
206
207 sc_ipc = devm_kzalloc(dev, sizeof(*sc_ipc), GFP_KERNEL);
208 if (!sc_ipc)
209 return -ENOMEM;
210
211 for (i = 0; i < SCU_MU_CHAN_NUM; i++) {
212 if (i < 4)
213 chan_name = kasprintf(GFP_KERNEL, "tx%d", i);
214 else
215 chan_name = kasprintf(GFP_KERNEL, "rx%d", i - 4);
216
217 if (!chan_name)
218 return -ENOMEM;
219
220 sc_chan = &sc_ipc->chans[i];
221 cl = &sc_chan->cl;
222 cl->dev = dev;
223 cl->tx_block = false;
224 cl->knows_txdone = true;
225 cl->rx_callback = imx_scu_rx_callback;
226
227 sc_chan->sc_ipc = sc_ipc;
228 sc_chan->idx = i % 4;
229 sc_chan->ch = mbox_request_channel_byname(cl, chan_name);
230 if (IS_ERR(sc_chan->ch)) {
231 ret = PTR_ERR(sc_chan->ch);
232 if (ret != -EPROBE_DEFER)
233 dev_err(dev, "Failed to request mbox chan %s ret %d\n",
234 chan_name, ret);
235 return ret;
236 }
237
238 dev_dbg(dev, "request mbox chan %s\n", chan_name);
239 /* chan_name is not used anymore by framework */
240 kfree(chan_name);
241 }
242
243 sc_ipc->dev = dev;
244 mutex_init(&sc_ipc->lock);
245 init_completion(&sc_ipc->done);
246
247 imx_sc_ipc_handle = sc_ipc;
248
249 dev_info(dev, "NXP i.MX SCU Initialized\n");
250
251 return devm_of_platform_populate(dev);
252}
253
254static const struct of_device_id imx_scu_match[] = {
255 { .compatible = "fsl,imx-scu", },
256 { /* Sentinel */ }
257};
258
259static struct platform_driver imx_scu_driver = {
260 .driver = {
261 .name = "imx-scu",
262 .of_match_table = imx_scu_match,
263 },
264 .probe = imx_scu_probe,
265};
266builtin_platform_driver(imx_scu_driver);
267
268MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
269MODULE_DESCRIPTION("IMX SCU firmware protocol driver");
270MODULE_LICENSE("GPL v2");
diff --git a/drivers/firmware/imx/misc.c b/drivers/firmware/imx/misc.c
new file mode 100644
index 000000000000..97f5424dbac9
--- /dev/null
+++ b/drivers/firmware/imx/misc.c
@@ -0,0 +1,99 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
4 * Copyright 2017~2018 NXP
5 * Author: Dong Aisheng <aisheng.dong@nxp.com>
6 *
7 * File containing client-side RPC functions for the MISC service. These
8 * function are ported to clients that communicate to the SC.
9 *
10 */
11
12#include <linux/firmware/imx/svc/misc.h>
13
14struct imx_sc_msg_req_misc_set_ctrl {
15 struct imx_sc_rpc_msg hdr;
16 u32 ctrl;
17 u32 val;
18 u16 resource;
19} __packed;
20
21struct imx_sc_msg_req_misc_get_ctrl {
22 struct imx_sc_rpc_msg hdr;
23 u32 ctrl;
24 u16 resource;
25} __packed;
26
27struct imx_sc_msg_resp_misc_get_ctrl {
28 struct imx_sc_rpc_msg hdr;
29 u32 val;
30} __packed;
31
32/*
33 * This function sets a miscellaneous control value.
34 *
35 * @param[in] ipc IPC handle
36 * @param[in] resource resource the control is associated with
37 * @param[in] ctrl control to change
38 * @param[in] val value to apply to the control
39 *
40 * @return Returns 0 for success and < 0 for errors.
41 */
42
43int imx_sc_misc_set_control(struct imx_sc_ipc *ipc, u32 resource,
44 u8 ctrl, u32 val)
45{
46 struct imx_sc_msg_req_misc_set_ctrl msg;
47 struct imx_sc_rpc_msg *hdr = &msg.hdr;
48
49 hdr->ver = IMX_SC_RPC_VERSION;
50 hdr->svc = (uint8_t)IMX_SC_RPC_SVC_MISC;
51 hdr->func = (uint8_t)IMX_SC_MISC_FUNC_SET_CONTROL;
52 hdr->size = 4;
53
54 msg.ctrl = ctrl;
55 msg.val = val;
56 msg.resource = resource;
57
58 return imx_scu_call_rpc(ipc, &msg, true);
59}
60EXPORT_SYMBOL(imx_sc_misc_set_control);
61
62/*
63 * This function gets a miscellaneous control value.
64 *
65 * @param[in] ipc IPC handle
66 * @param[in] resource resource the control is associated with
67 * @param[in] ctrl control to get
68 * @param[out] val pointer to return the control value
69 *
70 * @return Returns 0 for success and < 0 for errors.
71 */
72
73int imx_sc_misc_get_control(struct imx_sc_ipc *ipc, u32 resource,
74 u8 ctrl, u32 *val)
75{
76 struct imx_sc_msg_req_misc_get_ctrl msg;
77 struct imx_sc_msg_resp_misc_get_ctrl *resp;
78 struct imx_sc_rpc_msg *hdr = &msg.hdr;
79 int ret;
80
81 hdr->ver = IMX_SC_RPC_VERSION;
82 hdr->svc = (uint8_t)IMX_SC_RPC_SVC_MISC;
83 hdr->func = (uint8_t)IMX_SC_MISC_FUNC_GET_CONTROL;
84 hdr->size = 3;
85
86 msg.ctrl = ctrl;
87 msg.resource = resource;
88
89 ret = imx_scu_call_rpc(ipc, &msg, true);
90 if (ret)
91 return ret;
92
93 resp = (struct imx_sc_msg_resp_misc_get_ctrl *)&msg;
94 if (val != NULL)
95 *val = resp->val;
96
97 return 0;
98}
99EXPORT_SYMBOL(imx_sc_misc_get_control);
diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c
index 0ec2ca87318c..29fbc818a573 100644
--- a/drivers/firmware/meson/meson_sm.c
+++ b/drivers/firmware/meson/meson_sm.c
@@ -24,6 +24,7 @@
24#include <linux/printk.h> 24#include <linux/printk.h>
25#include <linux/types.h> 25#include <linux/types.h>
26#include <linux/sizes.h> 26#include <linux/sizes.h>
27 #include <linux/slab.h>
27 28
28#include <linux/firmware/meson/meson_sm.h> 29#include <linux/firmware/meson/meson_sm.h>
29 30
@@ -48,6 +49,7 @@ struct meson_sm_chip gxbb_chip = {
48 CMD(SM_EFUSE_READ, 0x82000030), 49 CMD(SM_EFUSE_READ, 0x82000030),
49 CMD(SM_EFUSE_WRITE, 0x82000031), 50 CMD(SM_EFUSE_WRITE, 0x82000031),
50 CMD(SM_EFUSE_USER_MAX, 0x82000033), 51 CMD(SM_EFUSE_USER_MAX, 0x82000033),
52 CMD(SM_GET_CHIP_ID, 0x82000044),
51 { /* sentinel */ }, 53 { /* sentinel */ },
52 }, 54 },
53}; 55};
@@ -214,6 +216,57 @@ int meson_sm_call_write(void *buffer, unsigned int size, unsigned int cmd_index,
214} 216}
215EXPORT_SYMBOL(meson_sm_call_write); 217EXPORT_SYMBOL(meson_sm_call_write);
216 218
219#define SM_CHIP_ID_LENGTH 119
220#define SM_CHIP_ID_OFFSET 4
221#define SM_CHIP_ID_SIZE 12
222
223static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
224 char *buf)
225{
226 uint8_t *id_buf;
227 int ret;
228
229 id_buf = kmalloc(SM_CHIP_ID_LENGTH, GFP_KERNEL);
230 if (!id_buf)
231 return -ENOMEM;
232
233 ret = meson_sm_call_read(id_buf, SM_CHIP_ID_LENGTH, SM_GET_CHIP_ID,
234 0, 0, 0, 0, 0);
235 if (ret < 0) {
236 kfree(id_buf);
237 return ret;
238 }
239
240 ret = sprintf(buf, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
241 id_buf[SM_CHIP_ID_OFFSET + 0],
242 id_buf[SM_CHIP_ID_OFFSET + 1],
243 id_buf[SM_CHIP_ID_OFFSET + 2],
244 id_buf[SM_CHIP_ID_OFFSET + 3],
245 id_buf[SM_CHIP_ID_OFFSET + 4],
246 id_buf[SM_CHIP_ID_OFFSET + 5],
247 id_buf[SM_CHIP_ID_OFFSET + 6],
248 id_buf[SM_CHIP_ID_OFFSET + 7],
249 id_buf[SM_CHIP_ID_OFFSET + 8],
250 id_buf[SM_CHIP_ID_OFFSET + 9],
251 id_buf[SM_CHIP_ID_OFFSET + 10],
252 id_buf[SM_CHIP_ID_OFFSET + 11]);
253
254 kfree(id_buf);
255
256 return ret;
257}
258
259static DEVICE_ATTR_RO(serial);
260
261static struct attribute *meson_sm_sysfs_attributes[] = {
262 &dev_attr_serial.attr,
263 NULL,
264};
265
266static const struct attribute_group meson_sm_sysfs_attr_group = {
267 .attrs = meson_sm_sysfs_attributes,
268};
269
217static const struct of_device_id meson_sm_ids[] = { 270static const struct of_device_id meson_sm_ids[] = {
218 { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip }, 271 { .compatible = "amlogic,meson-gxbb-sm", .data = &gxbb_chip },
219 { /* sentinel */ }, 272 { /* sentinel */ },
@@ -242,6 +295,9 @@ static int __init meson_sm_probe(struct platform_device *pdev)
242 fw.chip = chip; 295 fw.chip = chip;
243 pr_info("secure-monitor enabled\n"); 296 pr_info("secure-monitor enabled\n");
244 297
298 if (sysfs_create_group(&pdev->dev.kobj, &meson_sm_sysfs_attr_group))
299 goto out_in_base;
300
245 return 0; 301 return 0;
246 302
247out_in_base: 303out_in_base:
diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index e778af766fae..af4eee86919d 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -525,34 +525,44 @@ static int qcom_scm_probe(struct platform_device *pdev)
525 return ret; 525 return ret;
526 526
527 clks = (unsigned long)of_device_get_match_data(&pdev->dev); 527 clks = (unsigned long)of_device_get_match_data(&pdev->dev);
528 if (clks & SCM_HAS_CORE_CLK) { 528
529 scm->core_clk = devm_clk_get(&pdev->dev, "core"); 529 scm->core_clk = devm_clk_get(&pdev->dev, "core");
530 if (IS_ERR(scm->core_clk)) { 530 if (IS_ERR(scm->core_clk)) {
531 if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER) 531 if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
532 dev_err(&pdev->dev, 532 return PTR_ERR(scm->core_clk);
533 "failed to acquire core clk\n"); 533
534 if (clks & SCM_HAS_CORE_CLK) {
535 dev_err(&pdev->dev, "failed to acquire core clk\n");
534 return PTR_ERR(scm->core_clk); 536 return PTR_ERR(scm->core_clk);
535 } 537 }
538
539 scm->core_clk = NULL;
536 } 540 }
537 541
538 if (clks & SCM_HAS_IFACE_CLK) { 542 scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
539 scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); 543 if (IS_ERR(scm->iface_clk)) {
540 if (IS_ERR(scm->iface_clk)) { 544 if (PTR_ERR(scm->iface_clk) == -EPROBE_DEFER)
541 if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER) 545 return PTR_ERR(scm->iface_clk);
542 dev_err(&pdev->dev, 546
543 "failed to acquire iface clk\n"); 547 if (clks & SCM_HAS_IFACE_CLK) {
548 dev_err(&pdev->dev, "failed to acquire iface clk\n");
544 return PTR_ERR(scm->iface_clk); 549 return PTR_ERR(scm->iface_clk);
545 } 550 }
551
552 scm->iface_clk = NULL;
546 } 553 }
547 554
548 if (clks & SCM_HAS_BUS_CLK) { 555 scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
549 scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); 556 if (IS_ERR(scm->bus_clk)) {
550 if (IS_ERR(scm->bus_clk)) { 557 if (PTR_ERR(scm->bus_clk) == -EPROBE_DEFER)
551 if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER) 558 return PTR_ERR(scm->bus_clk);
552 dev_err(&pdev->dev, 559
553 "failed to acquire bus clk\n"); 560 if (clks & SCM_HAS_BUS_CLK) {
561 dev_err(&pdev->dev, "failed to acquire bus clk\n");
554 return PTR_ERR(scm->bus_clk); 562 return PTR_ERR(scm->bus_clk);
555 } 563 }
564
565 scm->bus_clk = NULL;
556 } 566 }
557 567
558 scm->reset.ops = &qcom_scm_pas_reset_ops; 568 scm->reset.ops = &qcom_scm_pas_reset_ops;
@@ -594,23 +604,23 @@ static const struct of_device_id qcom_scm_dt_match[] = {
594 { .compatible = "qcom,scm-apq8064", 604 { .compatible = "qcom,scm-apq8064",
595 /* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */ 605 /* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */
596 }, 606 },
597 { .compatible = "qcom,scm-msm8660", 607 { .compatible = "qcom,scm-apq8084", .data = (void *)(SCM_HAS_CORE_CLK |
598 .data = (void *) SCM_HAS_CORE_CLK, 608 SCM_HAS_IFACE_CLK |
599 }, 609 SCM_HAS_BUS_CLK)
600 { .compatible = "qcom,scm-msm8960",
601 .data = (void *) SCM_HAS_CORE_CLK,
602 },
603 { .compatible = "qcom,scm-msm8996",
604 .data = NULL, /* no clocks */
605 }, 610 },
606 { .compatible = "qcom,scm-ipq4019", 611 { .compatible = "qcom,scm-ipq4019" },
607 .data = NULL, /* no clocks */ 612 { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK },
613 { .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK },
614 { .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK |
615 SCM_HAS_IFACE_CLK |
616 SCM_HAS_BUS_CLK)
608 }, 617 },
609 { .compatible = "qcom,scm", 618 { .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK |
610 .data = (void *)(SCM_HAS_CORE_CLK 619 SCM_HAS_IFACE_CLK |
611 | SCM_HAS_IFACE_CLK 620 SCM_HAS_BUS_CLK)
612 | SCM_HAS_BUS_CLK),
613 }, 621 },
622 { .compatible = "qcom,scm-msm8996" },
623 { .compatible = "qcom,scm" },
614 {} 624 {}
615}; 625};
616 626
diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c
index 14a456afa379..a3d5b518c10e 100644
--- a/drivers/firmware/tegra/bpmp.c
+++ b/drivers/firmware/tegra/bpmp.c
@@ -18,6 +18,7 @@
18#include <linux/of_address.h> 18#include <linux/of_address.h>
19#include <linux/of_device.h> 19#include <linux/of_device.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/pm.h>
21#include <linux/semaphore.h> 22#include <linux/semaphore.h>
22#include <linux/sched/clock.h> 23#include <linux/sched/clock.h>
23 24
@@ -843,6 +844,23 @@ free_tx:
843 return err; 844 return err;
844} 845}
845 846
847static int __maybe_unused tegra_bpmp_resume(struct device *dev)
848{
849 struct tegra_bpmp *bpmp = dev_get_drvdata(dev);
850 unsigned int i;
851
852 /* reset message channels */
853 tegra_bpmp_channel_reset(bpmp->tx_channel);
854 tegra_bpmp_channel_reset(bpmp->rx_channel);
855
856 for (i = 0; i < bpmp->threaded.count; i++)
857 tegra_bpmp_channel_reset(&bpmp->threaded_channels[i]);
858
859 return 0;
860}
861
862static SIMPLE_DEV_PM_OPS(tegra_bpmp_pm_ops, NULL, tegra_bpmp_resume);
863
846static const struct tegra_bpmp_soc tegra186_soc = { 864static const struct tegra_bpmp_soc tegra186_soc = {
847 .channels = { 865 .channels = {
848 .cpu_tx = { 866 .cpu_tx = {
@@ -871,6 +889,7 @@ static struct platform_driver tegra_bpmp_driver = {
871 .driver = { 889 .driver = {
872 .name = "tegra-bpmp", 890 .name = "tegra-bpmp",
873 .of_match_table = tegra_bpmp_match, 891 .of_match_table = tegra_bpmp_match,
892 .pm = &tegra_bpmp_pm_ops,
874 }, 893 },
875 .probe = tegra_bpmp_probe, 894 .probe = tegra_bpmp_probe,
876}; 895};
diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 7fa744793bc5..69ed1464175c 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -66,14 +66,14 @@ struct ti_sci_xfers_info {
66 66
67/** 67/**
68 * struct ti_sci_desc - Description of SoC integration 68 * struct ti_sci_desc - Description of SoC integration
69 * @host_id: Host identifier representing the compute entity 69 * @default_host_id: Host identifier representing the compute entity
70 * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds) 70 * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds)
71 * @max_msgs: Maximum number of messages that can be pending 71 * @max_msgs: Maximum number of messages that can be pending
72 * simultaneously in the system 72 * simultaneously in the system
73 * @max_msg_size: Maximum size of data per message that can be handled. 73 * @max_msg_size: Maximum size of data per message that can be handled.
74 */ 74 */
75struct ti_sci_desc { 75struct ti_sci_desc {
76 u8 host_id; 76 u8 default_host_id;
77 int max_rx_timeout_ms; 77 int max_rx_timeout_ms;
78 int max_msgs; 78 int max_msgs;
79 int max_msg_size; 79 int max_msg_size;
@@ -94,6 +94,7 @@ struct ti_sci_desc {
94 * @chan_rx: Receive mailbox channel 94 * @chan_rx: Receive mailbox channel
95 * @minfo: Message info 95 * @minfo: Message info
96 * @node: list head 96 * @node: list head
97 * @host_id: Host ID
97 * @users: Number of users of this instance 98 * @users: Number of users of this instance
98 */ 99 */
99struct ti_sci_info { 100struct ti_sci_info {
@@ -110,6 +111,7 @@ struct ti_sci_info {
110 struct mbox_chan *chan_rx; 111 struct mbox_chan *chan_rx;
111 struct ti_sci_xfers_info minfo; 112 struct ti_sci_xfers_info minfo;
112 struct list_head node; 113 struct list_head node;
114 u8 host_id;
113 /* protected by ti_sci_list_mutex */ 115 /* protected by ti_sci_list_mutex */
114 int users; 116 int users;
115 117
@@ -370,7 +372,7 @@ static struct ti_sci_xfer *ti_sci_get_one_xfer(struct ti_sci_info *info,
370 372
371 hdr->seq = xfer_id; 373 hdr->seq = xfer_id;
372 hdr->type = msg_type; 374 hdr->type = msg_type;
373 hdr->host = info->desc->host_id; 375 hdr->host = info->host_id;
374 hdr->flags = msg_flags; 376 hdr->flags = msg_flags;
375 377
376 return xfer; 378 return xfer;
@@ -1793,7 +1795,7 @@ static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
1793 1795
1794/* Description for K2G */ 1796/* Description for K2G */
1795static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { 1797static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = {
1796 .host_id = 2, 1798 .default_host_id = 2,
1797 /* Conservative duration */ 1799 /* Conservative duration */
1798 .max_rx_timeout_ms = 1000, 1800 .max_rx_timeout_ms = 1000,
1799 /* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */ 1801 /* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */
@@ -1819,6 +1821,7 @@ static int ti_sci_probe(struct platform_device *pdev)
1819 int ret = -EINVAL; 1821 int ret = -EINVAL;
1820 int i; 1822 int i;
1821 int reboot = 0; 1823 int reboot = 0;
1824 u32 h_id;
1822 1825
1823 of_id = of_match_device(ti_sci_of_match, dev); 1826 of_id = of_match_device(ti_sci_of_match, dev);
1824 if (!of_id) { 1827 if (!of_id) {
@@ -1833,6 +1836,19 @@ static int ti_sci_probe(struct platform_device *pdev)
1833 1836
1834 info->dev = dev; 1837 info->dev = dev;
1835 info->desc = desc; 1838 info->desc = desc;
1839 ret = of_property_read_u32(dev->of_node, "ti,host-id", &h_id);
1840 /* if the property is not present in DT, use a default from desc */
1841 if (ret < 0) {
1842 info->host_id = info->desc->default_host_id;
1843 } else {
1844 if (!h_id) {
1845 dev_warn(dev, "Host ID 0 is reserved for firmware\n");
1846 info->host_id = info->desc->default_host_id;
1847 } else {
1848 info->host_id = h_id;
1849 }
1850 }
1851
1836 reboot = of_property_read_bool(dev->of_node, 1852 reboot = of_property_read_bool(dev->of_node,
1837 "ti,system-reboot-controller"); 1853 "ti,system-reboot-controller");
1838 INIT_LIST_HEAD(&info->node); 1854 INIT_LIST_HEAD(&info->node);
diff --git a/drivers/firmware/xilinx/Kconfig b/drivers/firmware/xilinx/Kconfig
new file mode 100644
index 000000000000..8f44b9cd295a
--- /dev/null
+++ b/drivers/firmware/xilinx/Kconfig
@@ -0,0 +1,23 @@
1# SPDX-License-Identifier: GPL-2.0
2# Kconfig for Xilinx firmwares
3
4menu "Zynq MPSoC Firmware Drivers"
5 depends on ARCH_ZYNQMP
6
7config ZYNQMP_FIRMWARE
8 bool "Enable Xilinx Zynq MPSoC firmware interface"
9 help
10 Firmware interface driver is used by different
11 drivers to communicate with the firmware for
12 various platform management services.
13 Say yes to enable ZynqMP firmware interface driver.
14 If in doubt, say N.
15
16config ZYNQMP_FIRMWARE_DEBUG
17 bool "Enable Xilinx Zynq MPSoC firmware debug APIs"
18 depends on ZYNQMP_FIRMWARE && DEBUG_FS
19 help
20 Say yes to enable ZynqMP firmware interface debug APIs.
21 If in doubt, say N.
22
23endmenu
diff --git a/drivers/firmware/xilinx/Makefile b/drivers/firmware/xilinx/Makefile
new file mode 100644
index 000000000000..875a53703c82
--- /dev/null
+++ b/drivers/firmware/xilinx/Makefile
@@ -0,0 +1,5 @@
1# SPDX-License-Identifier: GPL-2.0
2# Makefile for Xilinx firmwares
3
4obj-$(CONFIG_ZYNQMP_FIRMWARE) += zynqmp.o
5obj-$(CONFIG_ZYNQMP_FIRMWARE_DEBUG) += zynqmp-debug.o
diff --git a/drivers/firmware/xilinx/zynqmp-debug.c b/drivers/firmware/xilinx/zynqmp-debug.c
new file mode 100644
index 000000000000..2771df6df379
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp-debug.c
@@ -0,0 +1,250 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Xilinx Zynq MPSoC Firmware layer for debugfs APIs
4 *
5 * Copyright (C) 2014-2018 Xilinx, Inc.
6 *
7 * Michal Simek <michal.simek@xilinx.com>
8 * Davorin Mista <davorin.mista@aggios.com>
9 * Jolly Shah <jollys@xilinx.com>
10 * Rajan Vaja <rajanv@xilinx.com>
11 */
12
13#include <linux/compiler.h>
14#include <linux/module.h>
15#include <linux/slab.h>
16#include <linux/debugfs.h>
17#include <linux/uaccess.h>
18
19#include <linux/firmware/xlnx-zynqmp.h>
20#include "zynqmp-debug.h"
21
22#define PM_API_NAME_LEN 50
23
24struct pm_api_info {
25 u32 api_id;
26 char api_name[PM_API_NAME_LEN];
27 char api_name_len;
28};
29
30static char debugfs_buf[PAGE_SIZE];
31
32#define PM_API(id) {id, #id, strlen(#id)}
33static struct pm_api_info pm_api_list[] = {
34 PM_API(PM_GET_API_VERSION),
35 PM_API(PM_QUERY_DATA),
36};
37
38struct dentry *firmware_debugfs_root;
39
40/**
41 * zynqmp_pm_argument_value() - Extract argument value from a PM-API request
42 * @arg: Entered PM-API argument in string format
43 *
44 * Return: Argument value in unsigned integer format on success
45 * 0 otherwise
46 */
47static u64 zynqmp_pm_argument_value(char *arg)
48{
49 u64 value;
50
51 if (!arg)
52 return 0;
53
54 if (!kstrtou64(arg, 0, &value))
55 return value;
56
57 return 0;
58}
59
60/**
61 * get_pm_api_id() - Extract API-ID from a PM-API request
62 * @pm_api_req: Entered PM-API argument in string format
63 * @pm_id: API-ID
64 *
65 * Return: 0 on success else error code
66 */
67static int get_pm_api_id(char *pm_api_req, u32 *pm_id)
68{
69 int i;
70
71 for (i = 0; i < ARRAY_SIZE(pm_api_list) ; i++) {
72 if (!strncasecmp(pm_api_req, pm_api_list[i].api_name,
73 pm_api_list[i].api_name_len)) {
74 *pm_id = pm_api_list[i].api_id;
75 break;
76 }
77 }
78
79 /* If no name was entered look for PM-API ID instead */
80 if (i == ARRAY_SIZE(pm_api_list) && kstrtouint(pm_api_req, 10, pm_id))
81 return -EINVAL;
82
83 return 0;
84}
85
86static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret)
87{
88 const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops();
89 u32 pm_api_version;
90 int ret;
91 struct zynqmp_pm_query_data qdata = {0};
92
93 if (!eemi_ops)
94 return -ENXIO;
95
96 switch (pm_id) {
97 case PM_GET_API_VERSION:
98 ret = eemi_ops->get_api_version(&pm_api_version);
99 sprintf(debugfs_buf, "PM-API Version = %d.%d\n",
100 pm_api_version >> 16, pm_api_version & 0xffff);
101 break;
102 case PM_QUERY_DATA:
103 qdata.qid = pm_api_arg[0];
104 qdata.arg1 = pm_api_arg[1];
105 qdata.arg2 = pm_api_arg[2];
106 qdata.arg3 = pm_api_arg[3];
107
108 ret = eemi_ops->query_data(qdata, pm_api_ret);
109 if (ret)
110 break;
111
112 switch (qdata.qid) {
113 case PM_QID_CLOCK_GET_NAME:
114 sprintf(debugfs_buf, "Clock name = %s\n",
115 (char *)pm_api_ret);
116 break;
117 case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS:
118 sprintf(debugfs_buf, "Multiplier = %d, Divider = %d\n",
119 pm_api_ret[1], pm_api_ret[2]);
120 break;
121 default:
122 sprintf(debugfs_buf,
123 "data[0] = 0x%08x\ndata[1] = 0x%08x\n data[2] = 0x%08x\ndata[3] = 0x%08x\n",
124 pm_api_ret[0], pm_api_ret[1],
125 pm_api_ret[2], pm_api_ret[3]);
126 }
127 break;
128 default:
129 sprintf(debugfs_buf, "Unsupported PM-API request\n");
130 ret = -EINVAL;
131 }
132
133 return ret;
134}
135
136/**
137 * zynqmp_pm_debugfs_api_write() - debugfs write function
138 * @file: User file
139 * @ptr: User entered PM-API string
140 * @len: Length of the userspace buffer
141 * @off: Offset within the file
142 *
143 * Used for triggering pm api functions by writing
144 * echo <pm_api_id> > /sys/kernel/debug/zynqmp_pm/power or
145 * echo <pm_api_name> > /sys/kernel/debug/zynqmp_pm/power
146 *
147 * Return: Number of bytes copied if PM-API request succeeds,
148 * the corresponding error code otherwise
149 */
150static ssize_t zynqmp_pm_debugfs_api_write(struct file *file,
151 const char __user *ptr, size_t len,
152 loff_t *off)
153{
154 char *kern_buff, *tmp_buff;
155 char *pm_api_req;
156 u32 pm_id = 0;
157 u64 pm_api_arg[4] = {0, 0, 0, 0};
158 /* Return values from PM APIs calls */
159 u32 pm_api_ret[4] = {0, 0, 0, 0};
160
161 int ret;
162 int i = 0;
163
164 strcpy(debugfs_buf, "");
165
166 if (*off != 0 || len == 0)
167 return -EINVAL;
168
169 kern_buff = kzalloc(len, GFP_KERNEL);
170 if (!kern_buff)
171 return -ENOMEM;
172
173 tmp_buff = kern_buff;
174
175 ret = strncpy_from_user(kern_buff, ptr, len);
176 if (ret < 0) {
177 ret = -EFAULT;
178 goto err;
179 }
180
181 /* Read the API name from a user request */
182 pm_api_req = strsep(&kern_buff, " ");
183
184 ret = get_pm_api_id(pm_api_req, &pm_id);
185 if (ret < 0)
186 goto err;
187
188 /* Read node_id and arguments from the PM-API request */
189 pm_api_req = strsep(&kern_buff, " ");
190 while ((i < ARRAY_SIZE(pm_api_arg)) && pm_api_req) {
191 pm_api_arg[i++] = zynqmp_pm_argument_value(pm_api_req);
192 pm_api_req = strsep(&kern_buff, " ");
193 }
194
195 ret = process_api_request(pm_id, pm_api_arg, pm_api_ret);
196
197err:
198 kfree(tmp_buff);
199 if (ret)
200 return ret;
201
202 return len;
203}
204
205/**
206 * zynqmp_pm_debugfs_api_read() - debugfs read function
207 * @file: User file
208 * @ptr: Requested pm_api_version string
209 * @len: Length of the userspace buffer
210 * @off: Offset within the file
211 *
212 * Return: Length of the version string on success
213 * else error code
214 */
215static ssize_t zynqmp_pm_debugfs_api_read(struct file *file, char __user *ptr,
216 size_t len, loff_t *off)
217{
218 return simple_read_from_buffer(ptr, len, off, debugfs_buf,
219 strlen(debugfs_buf));
220}
221
222/* Setup debugfs fops */
223static const struct file_operations fops_zynqmp_pm_dbgfs = {
224 .owner = THIS_MODULE,
225 .write = zynqmp_pm_debugfs_api_write,
226 .read = zynqmp_pm_debugfs_api_read,
227};
228
229/**
230 * zynqmp_pm_api_debugfs_init - Initialize debugfs interface
231 *
232 * Return: None
233 */
234void zynqmp_pm_api_debugfs_init(void)
235{
236 /* Initialize debugfs interface */
237 firmware_debugfs_root = debugfs_create_dir("zynqmp-firmware", NULL);
238 debugfs_create_file("pm", 0660, firmware_debugfs_root, NULL,
239 &fops_zynqmp_pm_dbgfs);
240}
241
242/**
243 * zynqmp_pm_api_debugfs_exit - Remove debugfs interface
244 *
245 * Return: None
246 */
247void zynqmp_pm_api_debugfs_exit(void)
248{
249 debugfs_remove_recursive(firmware_debugfs_root);
250}
diff --git a/drivers/firmware/xilinx/zynqmp-debug.h b/drivers/firmware/xilinx/zynqmp-debug.h
new file mode 100644
index 000000000000..9929f8b433f5
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp-debug.h
@@ -0,0 +1,24 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * Xilinx Zynq MPSoC Firmware layer
4 *
5 * Copyright (C) 2014-2018 Xilinx
6 *
7 * Michal Simek <michal.simek@xilinx.com>
8 * Davorin Mista <davorin.mista@aggios.com>
9 * Jolly Shah <jollys@xilinx.com>
10 * Rajan Vaja <rajanv@xilinx.com>
11 */
12
13#ifndef __FIRMWARE_ZYNQMP_DEBUG_H__
14#define __FIRMWARE_ZYNQMP_DEBUG_H__
15
16#if IS_REACHABLE(CONFIG_ZYNQMP_FIRMWARE_DEBUG)
17void zynqmp_pm_api_debugfs_init(void);
18void zynqmp_pm_api_debugfs_exit(void);
19#else
20static inline void zynqmp_pm_api_debugfs_init(void) { }
21static inline void zynqmp_pm_api_debugfs_exit(void) { }
22#endif
23
24#endif /* __FIRMWARE_ZYNQMP_DEBUG_H__ */
diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c
new file mode 100644
index 000000000000..9a1c72a9280f
--- /dev/null
+++ b/drivers/firmware/xilinx/zynqmp.c
@@ -0,0 +1,565 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Xilinx Zynq MPSoC Firmware layer
4 *
5 * Copyright (C) 2014-2018 Xilinx, Inc.
6 *
7 * Michal Simek <michal.simek@xilinx.com>
8 * Davorin Mista <davorin.mista@aggios.com>
9 * Jolly Shah <jollys@xilinx.com>
10 * Rajan Vaja <rajanv@xilinx.com>
11 */
12
13#include <linux/arm-smccc.h>
14#include <linux/compiler.h>
15#include <linux/device.h>
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/of_platform.h>
20#include <linux/slab.h>
21#include <linux/uaccess.h>
22
23#include <linux/firmware/xlnx-zynqmp.h>
24#include "zynqmp-debug.h"
25
26/**
27 * zynqmp_pm_ret_code() - Convert PMU-FW error codes to Linux error codes
28 * @ret_status: PMUFW return code
29 *
30 * Return: corresponding Linux error code
31 */
32static int zynqmp_pm_ret_code(u32 ret_status)
33{
34 switch (ret_status) {
35 case XST_PM_SUCCESS:
36 case XST_PM_DOUBLE_REQ:
37 return 0;
38 case XST_PM_NO_ACCESS:
39 return -EACCES;
40 case XST_PM_ABORT_SUSPEND:
41 return -ECANCELED;
42 case XST_PM_INTERNAL:
43 case XST_PM_CONFLICT:
44 case XST_PM_INVALID_NODE:
45 default:
46 return -EINVAL;
47 }
48}
49
50static noinline int do_fw_call_fail(u64 arg0, u64 arg1, u64 arg2,
51 u32 *ret_payload)
52{
53 return -ENODEV;
54}
55
56/*
57 * PM function call wrapper
58 * Invoke do_fw_call_smc or do_fw_call_hvc, depending on the configuration
59 */
60static int (*do_fw_call)(u64, u64, u64, u32 *ret_payload) = do_fw_call_fail;
61
62/**
63 * do_fw_call_smc() - Call system-level platform management layer (SMC)
64 * @arg0: Argument 0 to SMC call
65 * @arg1: Argument 1 to SMC call
66 * @arg2: Argument 2 to SMC call
67 * @ret_payload: Returned value array
68 *
69 * Invoke platform management function via SMC call (no hypervisor present).
70 *
71 * Return: Returns status, either success or error+reason
72 */
73static noinline int do_fw_call_smc(u64 arg0, u64 arg1, u64 arg2,
74 u32 *ret_payload)
75{
76 struct arm_smccc_res res;
77
78 arm_smccc_smc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
79
80 if (ret_payload) {
81 ret_payload[0] = lower_32_bits(res.a0);
82 ret_payload[1] = upper_32_bits(res.a0);
83 ret_payload[2] = lower_32_bits(res.a1);
84 ret_payload[3] = upper_32_bits(res.a1);
85 }
86
87 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
88}
89
90/**
91 * do_fw_call_hvc() - Call system-level platform management layer (HVC)
92 * @arg0: Argument 0 to HVC call
93 * @arg1: Argument 1 to HVC call
94 * @arg2: Argument 2 to HVC call
95 * @ret_payload: Returned value array
96 *
97 * Invoke platform management function via HVC
98 * HVC-based for communication through hypervisor
99 * (no direct communication with ATF).
100 *
101 * Return: Returns status, either success or error+reason
102 */
103static noinline int do_fw_call_hvc(u64 arg0, u64 arg1, u64 arg2,
104 u32 *ret_payload)
105{
106 struct arm_smccc_res res;
107
108 arm_smccc_hvc(arg0, arg1, arg2, 0, 0, 0, 0, 0, &res);
109
110 if (ret_payload) {
111 ret_payload[0] = lower_32_bits(res.a0);
112 ret_payload[1] = upper_32_bits(res.a0);
113 ret_payload[2] = lower_32_bits(res.a1);
114 ret_payload[3] = upper_32_bits(res.a1);
115 }
116
117 return zynqmp_pm_ret_code((enum pm_ret_status)res.a0);
118}
119
120/**
121 * zynqmp_pm_invoke_fn() - Invoke the system-level platform management layer
122 * caller function depending on the configuration
123 * @pm_api_id: Requested PM-API call
124 * @arg0: Argument 0 to requested PM-API call
125 * @arg1: Argument 1 to requested PM-API call
126 * @arg2: Argument 2 to requested PM-API call
127 * @arg3: Argument 3 to requested PM-API call
128 * @ret_payload: Returned value array
129 *
130 * Invoke platform management function for SMC or HVC call, depending on
131 * configuration.
132 * Following SMC Calling Convention (SMCCC) for SMC64:
133 * Pm Function Identifier,
134 * PM_SIP_SVC + PM_API_ID =
135 * ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)
136 * ((SMC_64) << FUNCID_CC_SHIFT)
137 * ((SIP_START) << FUNCID_OEN_SHIFT)
138 * ((PM_API_ID) & FUNCID_NUM_MASK))
139 *
140 * PM_SIP_SVC - Registered ZynqMP SIP Service Call.
141 * PM_API_ID - Platform Management API ID.
142 *
143 * Return: Returns status, either success or error+reason
144 */
145int zynqmp_pm_invoke_fn(u32 pm_api_id, u32 arg0, u32 arg1,
146 u32 arg2, u32 arg3, u32 *ret_payload)
147{
148 /*
149 * Added SIP service call Function Identifier
150 * Make sure to stay in x0 register
151 */
152 u64 smc_arg[4];
153
154 smc_arg[0] = PM_SIP_SVC | pm_api_id;
155 smc_arg[1] = ((u64)arg1 << 32) | arg0;
156 smc_arg[2] = ((u64)arg3 << 32) | arg2;
157
158 return do_fw_call(smc_arg[0], smc_arg[1], smc_arg[2], ret_payload);
159}
160
161static u32 pm_api_version;
162static u32 pm_tz_version;
163
164/**
165 * zynqmp_pm_get_api_version() - Get version number of PMU PM firmware
166 * @version: Returned version value
167 *
168 * Return: Returns status, either success or error+reason
169 */
170static int zynqmp_pm_get_api_version(u32 *version)
171{
172 u32 ret_payload[PAYLOAD_ARG_CNT];
173 int ret;
174
175 if (!version)
176 return -EINVAL;
177
178 /* Check is PM API version already verified */
179 if (pm_api_version > 0) {
180 *version = pm_api_version;
181 return 0;
182 }
183 ret = zynqmp_pm_invoke_fn(PM_GET_API_VERSION, 0, 0, 0, 0, ret_payload);
184 *version = ret_payload[1];
185
186 return ret;
187}
188
189/**
190 * zynqmp_pm_get_trustzone_version() - Get secure trustzone firmware version
191 * @version: Returned version value
192 *
193 * Return: Returns status, either success or error+reason
194 */
195static int zynqmp_pm_get_trustzone_version(u32 *version)
196{
197 u32 ret_payload[PAYLOAD_ARG_CNT];
198 int ret;
199
200 if (!version)
201 return -EINVAL;
202
203 /* Check is PM trustzone version already verified */
204 if (pm_tz_version > 0) {
205 *version = pm_tz_version;
206 return 0;
207 }
208 ret = zynqmp_pm_invoke_fn(PM_GET_TRUSTZONE_VERSION, 0, 0,
209 0, 0, ret_payload);
210 *version = ret_payload[1];
211
212 return ret;
213}
214
215/**
216 * get_set_conduit_method() - Choose SMC or HVC based communication
217 * @np: Pointer to the device_node structure
218 *
219 * Use SMC or HVC-based functions to communicate with EL2/EL3.
220 *
221 * Return: Returns 0 on success or error code
222 */
223static int get_set_conduit_method(struct device_node *np)
224{
225 const char *method;
226
227 if (of_property_read_string(np, "method", &method)) {
228 pr_warn("%s missing \"method\" property\n", __func__);
229 return -ENXIO;
230 }
231
232 if (!strcmp("hvc", method)) {
233 do_fw_call = do_fw_call_hvc;
234 } else if (!strcmp("smc", method)) {
235 do_fw_call = do_fw_call_smc;
236 } else {
237 pr_warn("%s Invalid \"method\" property: %s\n",
238 __func__, method);
239 return -EINVAL;
240 }
241
242 return 0;
243}
244
245/**
246 * zynqmp_pm_query_data() - Get query data from firmware
247 * @qdata: Variable to the zynqmp_pm_query_data structure
248 * @out: Returned output value
249 *
250 * Return: Returns status, either success or error+reason
251 */
252static int zynqmp_pm_query_data(struct zynqmp_pm_query_data qdata, u32 *out)
253{
254 int ret;
255
256 ret = zynqmp_pm_invoke_fn(PM_QUERY_DATA, qdata.qid, qdata.arg1,
257 qdata.arg2, qdata.arg3, out);
258
259 /*
260 * For clock name query, all bytes in SMC response are clock name
261 * characters and return code is always success. For invalid clocks,
262 * clock name bytes would be zeros.
263 */
264 return qdata.qid == PM_QID_CLOCK_GET_NAME ? 0 : ret;
265}
266
267/**
268 * zynqmp_pm_clock_enable() - Enable the clock for given id
269 * @clock_id: ID of the clock to be enabled
270 *
271 * This function is used by master to enable the clock
272 * including peripherals and PLL clocks.
273 *
274 * Return: Returns status, either success or error+reason
275 */
276static int zynqmp_pm_clock_enable(u32 clock_id)
277{
278 return zynqmp_pm_invoke_fn(PM_CLOCK_ENABLE, clock_id, 0, 0, 0, NULL);
279}
280
281/**
282 * zynqmp_pm_clock_disable() - Disable the clock for given id
283 * @clock_id: ID of the clock to be disable
284 *
285 * This function is used by master to disable the clock
286 * including peripherals and PLL clocks.
287 *
288 * Return: Returns status, either success or error+reason
289 */
290static int zynqmp_pm_clock_disable(u32 clock_id)
291{
292 return zynqmp_pm_invoke_fn(PM_CLOCK_DISABLE, clock_id, 0, 0, 0, NULL);
293}
294
295/**
296 * zynqmp_pm_clock_getstate() - Get the clock state for given id
297 * @clock_id: ID of the clock to be queried
298 * @state: 1/0 (Enabled/Disabled)
299 *
300 * This function is used by master to get the state of clock
301 * including peripherals and PLL clocks.
302 *
303 * Return: Returns status, either success or error+reason
304 */
305static int zynqmp_pm_clock_getstate(u32 clock_id, u32 *state)
306{
307 u32 ret_payload[PAYLOAD_ARG_CNT];
308 int ret;
309
310 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETSTATE, clock_id, 0,
311 0, 0, ret_payload);
312 *state = ret_payload[1];
313
314 return ret;
315}
316
317/**
318 * zynqmp_pm_clock_setdivider() - Set the clock divider for given id
319 * @clock_id: ID of the clock
320 * @divider: divider value
321 *
322 * This function is used by master to set divider for any clock
323 * to achieve desired rate.
324 *
325 * Return: Returns status, either success or error+reason
326 */
327static int zynqmp_pm_clock_setdivider(u32 clock_id, u32 divider)
328{
329 return zynqmp_pm_invoke_fn(PM_CLOCK_SETDIVIDER, clock_id, divider,
330 0, 0, NULL);
331}
332
333/**
334 * zynqmp_pm_clock_getdivider() - Get the clock divider for given id
335 * @clock_id: ID of the clock
336 * @divider: divider value
337 *
338 * This function is used by master to get divider values
339 * for any clock.
340 *
341 * Return: Returns status, either success or error+reason
342 */
343static int zynqmp_pm_clock_getdivider(u32 clock_id, u32 *divider)
344{
345 u32 ret_payload[PAYLOAD_ARG_CNT];
346 int ret;
347
348 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETDIVIDER, clock_id, 0,
349 0, 0, ret_payload);
350 *divider = ret_payload[1];
351
352 return ret;
353}
354
355/**
356 * zynqmp_pm_clock_setrate() - Set the clock rate for given id
357 * @clock_id: ID of the clock
358 * @rate: rate value in hz
359 *
360 * This function is used by master to set rate for any clock.
361 *
362 * Return: Returns status, either success or error+reason
363 */
364static int zynqmp_pm_clock_setrate(u32 clock_id, u64 rate)
365{
366 return zynqmp_pm_invoke_fn(PM_CLOCK_SETRATE, clock_id,
367 lower_32_bits(rate),
368 upper_32_bits(rate),
369 0, NULL);
370}
371
372/**
373 * zynqmp_pm_clock_getrate() - Get the clock rate for given id
374 * @clock_id: ID of the clock
375 * @rate: rate value in hz
376 *
377 * This function is used by master to get rate
378 * for any clock.
379 *
380 * Return: Returns status, either success or error+reason
381 */
382static int zynqmp_pm_clock_getrate(u32 clock_id, u64 *rate)
383{
384 u32 ret_payload[PAYLOAD_ARG_CNT];
385 int ret;
386
387 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETRATE, clock_id, 0,
388 0, 0, ret_payload);
389 *rate = ((u64)ret_payload[2] << 32) | ret_payload[1];
390
391 return ret;
392}
393
394/**
395 * zynqmp_pm_clock_setparent() - Set the clock parent for given id
396 * @clock_id: ID of the clock
397 * @parent_id: parent id
398 *
399 * This function is used by master to set parent for any clock.
400 *
401 * Return: Returns status, either success or error+reason
402 */
403static int zynqmp_pm_clock_setparent(u32 clock_id, u32 parent_id)
404{
405 return zynqmp_pm_invoke_fn(PM_CLOCK_SETPARENT, clock_id,
406 parent_id, 0, 0, NULL);
407}
408
409/**
410 * zynqmp_pm_clock_getparent() - Get the clock parent for given id
411 * @clock_id: ID of the clock
412 * @parent_id: parent id
413 *
414 * This function is used by master to get parent index
415 * for any clock.
416 *
417 * Return: Returns status, either success or error+reason
418 */
419static int zynqmp_pm_clock_getparent(u32 clock_id, u32 *parent_id)
420{
421 u32 ret_payload[PAYLOAD_ARG_CNT];
422 int ret;
423
424 ret = zynqmp_pm_invoke_fn(PM_CLOCK_GETPARENT, clock_id, 0,
425 0, 0, ret_payload);
426 *parent_id = ret_payload[1];
427
428 return ret;
429}
430
431/**
432 * zynqmp_is_valid_ioctl() - Check whether IOCTL ID is valid or not
433 * @ioctl_id: IOCTL ID
434 *
435 * Return: 1 if IOCTL is valid else 0
436 */
437static inline int zynqmp_is_valid_ioctl(u32 ioctl_id)
438{
439 switch (ioctl_id) {
440 case IOCTL_SET_PLL_FRAC_MODE:
441 case IOCTL_GET_PLL_FRAC_MODE:
442 case IOCTL_SET_PLL_FRAC_DATA:
443 case IOCTL_GET_PLL_FRAC_DATA:
444 return 1;
445 default:
446 return 0;
447 }
448}
449
450/**
451 * zynqmp_pm_ioctl() - PM IOCTL API for device control and configs
452 * @node_id: Node ID of the device
453 * @ioctl_id: ID of the requested IOCTL
454 * @arg1: Argument 1 to requested IOCTL call
455 * @arg2: Argument 2 to requested IOCTL call
456 * @out: Returned output value
457 *
458 * This function calls IOCTL to firmware for device control and configuration.
459 *
460 * Return: Returns status, either success or error+reason
461 */
462static int zynqmp_pm_ioctl(u32 node_id, u32 ioctl_id, u32 arg1, u32 arg2,
463 u32 *out)
464{
465 if (!zynqmp_is_valid_ioctl(ioctl_id))
466 return -EINVAL;
467
468 return zynqmp_pm_invoke_fn(PM_IOCTL, node_id, ioctl_id,
469 arg1, arg2, out);
470}
471
472static const struct zynqmp_eemi_ops eemi_ops = {
473 .get_api_version = zynqmp_pm_get_api_version,
474 .query_data = zynqmp_pm_query_data,
475 .clock_enable = zynqmp_pm_clock_enable,
476 .clock_disable = zynqmp_pm_clock_disable,
477 .clock_getstate = zynqmp_pm_clock_getstate,
478 .clock_setdivider = zynqmp_pm_clock_setdivider,
479 .clock_getdivider = zynqmp_pm_clock_getdivider,
480 .clock_setrate = zynqmp_pm_clock_setrate,
481 .clock_getrate = zynqmp_pm_clock_getrate,
482 .clock_setparent = zynqmp_pm_clock_setparent,
483 .clock_getparent = zynqmp_pm_clock_getparent,
484 .ioctl = zynqmp_pm_ioctl,
485};
486
487/**
488 * zynqmp_pm_get_eemi_ops - Get eemi ops functions
489 *
490 * Return: Pointer of eemi_ops structure
491 */
492const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void)
493{
494 return &eemi_ops;
495}
496EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops);
497
498static int zynqmp_firmware_probe(struct platform_device *pdev)
499{
500 struct device *dev = &pdev->dev;
501 struct device_node *np;
502 int ret;
503
504 np = of_find_compatible_node(NULL, NULL, "xlnx,zynqmp");
505 if (!np)
506 return 0;
507 of_node_put(np);
508
509 ret = get_set_conduit_method(dev->of_node);
510 if (ret)
511 return ret;
512
513 /* Check PM API version number */
514 zynqmp_pm_get_api_version(&pm_api_version);
515 if (pm_api_version < ZYNQMP_PM_VERSION) {
516 panic("%s Platform Management API version error. Expected: v%d.%d - Found: v%d.%d\n",
517 __func__,
518 ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR,
519 pm_api_version >> 16, pm_api_version & 0xFFFF);
520 }
521
522 pr_info("%s Platform Management API v%d.%d\n", __func__,
523 pm_api_version >> 16, pm_api_version & 0xFFFF);
524
525 /* Check trustzone version number */
526 ret = zynqmp_pm_get_trustzone_version(&pm_tz_version);
527 if (ret)
528 panic("Legacy trustzone found without version support\n");
529
530 if (pm_tz_version < ZYNQMP_TZ_VERSION)
531 panic("%s Trustzone version error. Expected: v%d.%d - Found: v%d.%d\n",
532 __func__,
533 ZYNQMP_TZ_VERSION_MAJOR, ZYNQMP_TZ_VERSION_MINOR,
534 pm_tz_version >> 16, pm_tz_version & 0xFFFF);
535
536 pr_info("%s Trustzone version v%d.%d\n", __func__,
537 pm_tz_version >> 16, pm_tz_version & 0xFFFF);
538
539 zynqmp_pm_api_debugfs_init();
540
541 return of_platform_populate(dev->of_node, NULL, NULL, dev);
542}
543
544static int zynqmp_firmware_remove(struct platform_device *pdev)
545{
546 zynqmp_pm_api_debugfs_exit();
547
548 return 0;
549}
550
551static const struct of_device_id zynqmp_firmware_of_match[] = {
552 {.compatible = "xlnx,zynqmp-firmware"},
553 {},
554};
555MODULE_DEVICE_TABLE(of, zynqmp_firmware_of_match);
556
557static struct platform_driver zynqmp_firmware_driver = {
558 .driver = {
559 .name = "zynqmp_firmware",
560 .of_match_table = zynqmp_firmware_of_match,
561 },
562 .probe = zynqmp_firmware_probe,
563 .remove = zynqmp_firmware_remove,
564};
565module_platform_driver(zynqmp_firmware_driver);
diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c
index b907865d4664..c3748b414c27 100644
--- a/drivers/memory/atmel-ebi.c
+++ b/drivers/memory/atmel-ebi.c
@@ -327,8 +327,7 @@ static int atmel_ebi_dev_setup(struct atmel_ebi *ebi, struct device_node *np,
327 return -EINVAL; 327 return -EINVAL;
328 } 328 }
329 329
330 ebid = devm_kzalloc(ebi->dev, 330 ebid = devm_kzalloc(ebi->dev, struct_size(ebid, configs, numcs),
331 sizeof(*ebid) + (numcs * sizeof(*ebid->configs)),
332 GFP_KERNEL); 331 GFP_KERNEL);
333 if (!ebid) 332 if (!ebid)
334 return -ENOMEM; 333 return -ENOMEM;
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 13d28fdbdbb5..c21da9fe51ec 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -98,6 +98,15 @@ config RESET_QCOM_AOSS
98 reset signals provided by AOSS for Modem, Venus, ADSP, 98 reset signals provided by AOSS for Modem, Venus, ADSP,
99 GPU, Camera, Wireless, Display subsystem. Otherwise, say N. 99 GPU, Camera, Wireless, Display subsystem. Otherwise, say N.
100 100
101config RESET_QCOM_PDC
102 tristate "Qualcomm PDC Reset Driver"
103 depends on ARCH_QCOM || COMPILE_TEST
104 help
105 This enables the PDC (Power Domain Controller) reset driver
106 for Qualcomm Technologies Inc SDM845 SoCs. Say Y if you want
107 to control reset signals provided by PDC for Modem, Compute,
108 Display, GPU, Debug, AOP, Sensors, Audio, SP and APPS.
109
101config RESET_SIMPLE 110config RESET_SIMPLE
102 bool "Simple Reset Controller Driver" if COMPILE_TEST 111 bool "Simple Reset Controller Driver" if COMPILE_TEST
103 default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED 112 default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 4243c38228e2..d08e8b90046a 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
16obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o 16obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o
17obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o 17obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o
18obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o 18obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o
19obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o
19obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o 20obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o
20obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o 21obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o
21obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o 22obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index 225e34c56b94..d1887c0ed5d3 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -496,28 +496,29 @@ struct reset_control *__of_reset_control_get(struct device_node *node,
496 break; 496 break;
497 } 497 }
498 } 498 }
499 of_node_put(args.np);
500 499
501 if (!rcdev) { 500 if (!rcdev) {
502 mutex_unlock(&reset_list_mutex); 501 rstc = ERR_PTR(-EPROBE_DEFER);
503 return ERR_PTR(-EPROBE_DEFER); 502 goto out;
504 } 503 }
505 504
506 if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) { 505 if (WARN_ON(args.args_count != rcdev->of_reset_n_cells)) {
507 mutex_unlock(&reset_list_mutex); 506 rstc = ERR_PTR(-EINVAL);
508 return ERR_PTR(-EINVAL); 507 goto out;
509 } 508 }
510 509
511 rstc_id = rcdev->of_xlate(rcdev, &args); 510 rstc_id = rcdev->of_xlate(rcdev, &args);
512 if (rstc_id < 0) { 511 if (rstc_id < 0) {
513 mutex_unlock(&reset_list_mutex); 512 rstc = ERR_PTR(rstc_id);
514 return ERR_PTR(rstc_id); 513 goto out;
515 } 514 }
516 515
517 /* reset_list_mutex also protects the rcdev's reset_control list */ 516 /* reset_list_mutex also protects the rcdev's reset_control list */
518 rstc = __reset_control_get_internal(rcdev, rstc_id, shared); 517 rstc = __reset_control_get_internal(rcdev, rstc_id, shared);
519 518
519out:
520 mutex_unlock(&reset_list_mutex); 520 mutex_unlock(&reset_list_mutex);
521 of_node_put(args.np);
521 522
522 return rstc; 523 return rstc;
523} 524}
diff --git a/drivers/reset/reset-qcom-pdc.c b/drivers/reset/reset-qcom-pdc.c
new file mode 100644
index 000000000000..ab74bccd4a5b
--- /dev/null
+++ b/drivers/reset/reset-qcom-pdc.c
@@ -0,0 +1,124 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2018 The Linux Foundation. All rights reserved.
4 */
5
6#include <linux/module.h>
7#include <linux/of_device.h>
8#include <linux/platform_device.h>
9#include <linux/regmap.h>
10#include <linux/reset-controller.h>
11
12#include <dt-bindings/reset/qcom,sdm845-pdc.h>
13
14#define RPMH_PDC_SYNC_RESET 0x100
15
16struct qcom_pdc_reset_map {
17 u8 bit;
18};
19
20struct qcom_pdc_reset_data {
21 struct reset_controller_dev rcdev;
22 struct regmap *regmap;
23};
24
25static const struct regmap_config sdm845_pdc_regmap_config = {
26 .name = "pdc-reset",
27 .reg_bits = 32,
28 .reg_stride = 4,
29 .val_bits = 32,
30 .max_register = 0x20000,
31 .fast_io = true,
32};
33
34static const struct qcom_pdc_reset_map sdm845_pdc_resets[] = {
35 [PDC_APPS_SYNC_RESET] = {0},
36 [PDC_SP_SYNC_RESET] = {1},
37 [PDC_AUDIO_SYNC_RESET] = {2},
38 [PDC_SENSORS_SYNC_RESET] = {3},
39 [PDC_AOP_SYNC_RESET] = {4},
40 [PDC_DEBUG_SYNC_RESET] = {5},
41 [PDC_GPU_SYNC_RESET] = {6},
42 [PDC_DISPLAY_SYNC_RESET] = {7},
43 [PDC_COMPUTE_SYNC_RESET] = {8},
44 [PDC_MODEM_SYNC_RESET] = {9},
45};
46
47static inline struct qcom_pdc_reset_data *to_qcom_pdc_reset_data(
48 struct reset_controller_dev *rcdev)
49{
50 return container_of(rcdev, struct qcom_pdc_reset_data, rcdev);
51}
52
53static int qcom_pdc_control_assert(struct reset_controller_dev *rcdev,
54 unsigned long idx)
55{
56 struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
57
58 return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
59 BIT(sdm845_pdc_resets[idx].bit),
60 BIT(sdm845_pdc_resets[idx].bit));
61}
62
63static int qcom_pdc_control_deassert(struct reset_controller_dev *rcdev,
64 unsigned long idx)
65{
66 struct qcom_pdc_reset_data *data = to_qcom_pdc_reset_data(rcdev);
67
68 return regmap_update_bits(data->regmap, RPMH_PDC_SYNC_RESET,
69 BIT(sdm845_pdc_resets[idx].bit), 0);
70}
71
72static const struct reset_control_ops qcom_pdc_reset_ops = {
73 .assert = qcom_pdc_control_assert,
74 .deassert = qcom_pdc_control_deassert,
75};
76
77static int qcom_pdc_reset_probe(struct platform_device *pdev)
78{
79 struct qcom_pdc_reset_data *data;
80 struct device *dev = &pdev->dev;
81 void __iomem *base;
82 struct resource *res;
83
84 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
85 if (!data)
86 return -ENOMEM;
87
88 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
89 base = devm_ioremap_resource(dev, res);
90 if (IS_ERR(base))
91 return PTR_ERR(base);
92
93 data->regmap = devm_regmap_init_mmio(dev, base,
94 &sdm845_pdc_regmap_config);
95 if (IS_ERR(data->regmap)) {
96 dev_err(dev, "Unable to initialize regmap\n");
97 return PTR_ERR(data->regmap);
98 }
99
100 data->rcdev.owner = THIS_MODULE;
101 data->rcdev.ops = &qcom_pdc_reset_ops;
102 data->rcdev.nr_resets = ARRAY_SIZE(sdm845_pdc_resets);
103 data->rcdev.of_node = dev->of_node;
104
105 return devm_reset_controller_register(dev, &data->rcdev);
106}
107
108static const struct of_device_id qcom_pdc_reset_of_match[] = {
109 { .compatible = "qcom,sdm845-pdc-global" },
110 {}
111};
112MODULE_DEVICE_TABLE(of, qcom_pdc_reset_of_match);
113
114static struct platform_driver qcom_pdc_reset_driver = {
115 .probe = qcom_pdc_reset_probe,
116 .driver = {
117 .name = "qcom_pdc_reset",
118 .of_match_table = qcom_pdc_reset_of_match,
119 },
120};
121module_platform_driver(qcom_pdc_reset_driver);
122
123MODULE_DESCRIPTION("Qualcomm PDC Reset Driver");
124MODULE_LICENSE("GPL v2");
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 113e884697fd..446166ba0bec 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -18,7 +18,7 @@ obj-y += qcom/
18obj-y += renesas/ 18obj-y += renesas/
19obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ 19obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
20obj-$(CONFIG_SOC_SAMSUNG) += samsung/ 20obj-$(CONFIG_SOC_SAMSUNG) += samsung/
21obj-$(CONFIG_ARCH_SUNXI) += sunxi/ 21obj-y += sunxi/
22obj-$(CONFIG_ARCH_TEGRA) += tegra/ 22obj-$(CONFIG_ARCH_TEGRA) += tegra/
23obj-$(CONFIG_SOC_TI) += ti/ 23obj-$(CONFIG_SOC_TI) += ti/
24obj-$(CONFIG_ARCH_U8500) += ux500/ 24obj-$(CONFIG_ARCH_U8500) += ux500/
diff --git a/drivers/soc/actions/Kconfig b/drivers/soc/actions/Kconfig
index 9d68b5a771c3..1a0b9649efb4 100644
--- a/drivers/soc/actions/Kconfig
+++ b/drivers/soc/actions/Kconfig
@@ -10,7 +10,7 @@ config OWL_PM_DOMAINS
10 select PM_GENERIC_DOMAINS 10 select PM_GENERIC_DOMAINS
11 help 11 help
12 Say 'y' here to enable support for Smart Power System (SPS) 12 Say 'y' here to enable support for Smart Power System (SPS)
13 power-gating on Actions Semiconductor S500 SoC. 13 power-gating on Actions Semiconductor S500, S700 and S900 SoCs.
14 If unsure, say 'n'. 14 If unsure, say 'n'.
15 15
16endif 16endif
diff --git a/drivers/soc/actions/Makefile b/drivers/soc/actions/Makefile
index 1e101b06bab1..4db9e7b050e5 100644
--- a/drivers/soc/actions/Makefile
+++ b/drivers/soc/actions/Makefile
@@ -1,2 +1,4 @@
1# SPDX-License-Identifier: GPL-2.0+
2
1obj-$(CONFIG_OWL_PM_DOMAINS_HELPER) += owl-sps-helper.o 3obj-$(CONFIG_OWL_PM_DOMAINS_HELPER) += owl-sps-helper.o
2obj-$(CONFIG_OWL_PM_DOMAINS) += owl-sps.o 4obj-$(CONFIG_OWL_PM_DOMAINS) += owl-sps.o
diff --git a/drivers/soc/actions/owl-sps-helper.c b/drivers/soc/actions/owl-sps-helper.c
index 9d7a2c2b44ec..291a206d6f04 100644
--- a/drivers/soc/actions/owl-sps-helper.c
+++ b/drivers/soc/actions/owl-sps-helper.c
@@ -1,3 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+
1/* 2/*
2 * Actions Semi Owl Smart Power System (SPS) shared helpers 3 * Actions Semi Owl Smart Power System (SPS) shared helpers
3 * 4 *
@@ -5,11 +6,6 @@
5 * Author: Actions Semi, Inc. 6 * Author: Actions Semi, Inc.
6 * 7 *
7 * Copyright (c) 2017 Andreas Färber 8 * Copyright (c) 2017 Andreas Färber
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */ 9 */
14 10
15#include <linux/delay.h> 11#include <linux/delay.h>
diff --git a/drivers/soc/actions/owl-sps.c b/drivers/soc/actions/owl-sps.c
index 032921d8d41f..73a9e0bb7e8e 100644
--- a/drivers/soc/actions/owl-sps.c
+++ b/drivers/soc/actions/owl-sps.c
@@ -1,3 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+
1/* 2/*
2 * Actions Semi Owl Smart Power System (SPS) 3 * Actions Semi Owl Smart Power System (SPS)
3 * 4 *
@@ -5,11 +6,6 @@
5 * Author: Actions Semi, Inc. 6 * Author: Actions Semi, Inc.
6 * 7 *
7 * Copyright (c) 2017 Andreas Färber 8 * Copyright (c) 2017 Andreas Färber
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 */ 9 */
14 10
15#include <linux/of_address.h> 11#include <linux/of_address.h>
@@ -18,6 +14,7 @@
18#include <linux/soc/actions/owl-sps.h> 14#include <linux/soc/actions/owl-sps.h>
19#include <dt-bindings/power/owl-s500-powergate.h> 15#include <dt-bindings/power/owl-s500-powergate.h>
20#include <dt-bindings/power/owl-s700-powergate.h> 16#include <dt-bindings/power/owl-s700-powergate.h>
17#include <dt-bindings/power/owl-s900-powergate.h>
21 18
22struct owl_sps_domain_info { 19struct owl_sps_domain_info {
23 const char *name; 20 const char *name;
@@ -244,9 +241,66 @@ static const struct owl_sps_info s700_sps_info = {
244 .domains = s700_sps_domains, 241 .domains = s700_sps_domains,
245}; 242};
246 243
244static const struct owl_sps_domain_info s900_sps_domains[] = {
245 [S900_PD_GPU_B] = {
246 .name = "GPU_B",
247 .pwr_bit = 3,
248 },
249 [S900_PD_VCE] = {
250 .name = "VCE",
251 .pwr_bit = 4,
252 },
253 [S900_PD_SENSOR] = {
254 .name = "SENSOR",
255 .pwr_bit = 5,
256 },
257 [S900_PD_VDE] = {
258 .name = "VDE",
259 .pwr_bit = 6,
260 },
261 [S900_PD_HDE] = {
262 .name = "HDE",
263 .pwr_bit = 7,
264 },
265 [S900_PD_USB3] = {
266 .name = "USB3",
267 .pwr_bit = 8,
268 },
269 [S900_PD_DDR0] = {
270 .name = "DDR0",
271 .pwr_bit = 9,
272 },
273 [S900_PD_DDR1] = {
274 .name = "DDR1",
275 .pwr_bit = 10,
276 },
277 [S900_PD_DE] = {
278 .name = "DE",
279 .pwr_bit = 13,
280 },
281 [S900_PD_NAND] = {
282 .name = "NAND",
283 .pwr_bit = 14,
284 },
285 [S900_PD_USB2_H0] = {
286 .name = "USB2_H0",
287 .pwr_bit = 15,
288 },
289 [S900_PD_USB2_H1] = {
290 .name = "USB2_H1",
291 .pwr_bit = 16,
292 },
293};
294
295static const struct owl_sps_info s900_sps_info = {
296 .num_domains = ARRAY_SIZE(s900_sps_domains),
297 .domains = s900_sps_domains,
298};
299
247static const struct of_device_id owl_sps_of_matches[] = { 300static const struct of_device_id owl_sps_of_matches[] = {
248 { .compatible = "actions,s500-sps", .data = &s500_sps_info }, 301 { .compatible = "actions,s500-sps", .data = &s500_sps_info },
249 { .compatible = "actions,s700-sps", .data = &s700_sps_info }, 302 { .compatible = "actions,s700-sps", .data = &s700_sps_info },
303 { .compatible = "actions,s900-sps", .data = &s900_sps_info },
250 { } 304 { }
251}; 305};
252 306
diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig
index b04f6e4aedbc..2f282b472912 100644
--- a/drivers/soc/amlogic/Kconfig
+++ b/drivers/soc/amlogic/Kconfig
@@ -1,5 +1,12 @@
1menu "Amlogic SoC drivers" 1menu "Amlogic SoC drivers"
2 2
3config MESON_CANVAS
4 tristate "Amlogic Meson Canvas driver"
5 depends on ARCH_MESON || COMPILE_TEST
6 default n
7 help
8 Say yes to support the canvas IP for Amlogic SoCs.
9
3config MESON_GX_SOCINFO 10config MESON_GX_SOCINFO
4 bool "Amlogic Meson GX SoC Information driver" 11 bool "Amlogic Meson GX SoC Information driver"
5 depends on ARCH_MESON || COMPILE_TEST 12 depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile
index 8fa321893928..0ab16d35ac36 100644
--- a/drivers/soc/amlogic/Makefile
+++ b/drivers/soc/amlogic/Makefile
@@ -1,3 +1,4 @@
1obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o
1obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o 2obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o
2obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o 3obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o
3obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o 4obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o
diff --git a/drivers/soc/amlogic/meson-canvas.c b/drivers/soc/amlogic/meson-canvas.c
new file mode 100644
index 000000000000..fce33ca76bb6
--- /dev/null
+++ b/drivers/soc/amlogic/meson-canvas.c
@@ -0,0 +1,185 @@
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 BayLibre, SAS
4 * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
5 * Copyright (C) 2014 Endless Mobile
6 */
7
8#include <linux/kernel.h>
9#include <linux/mfd/syscon.h>
10#include <linux/module.h>
11#include <linux/regmap.h>
12#include <linux/soc/amlogic/meson-canvas.h>
13#include <linux/of_address.h>
14#include <linux/of_platform.h>
15#include <linux/io.h>
16
17#define NUM_CANVAS 256
18
19/* DMC Registers */
20#define DMC_CAV_LUT_DATAL 0x00
21 #define CANVAS_WIDTH_LBIT 29
22 #define CANVAS_WIDTH_LWID 3
23#define DMC_CAV_LUT_DATAH 0x04
24 #define CANVAS_WIDTH_HBIT 0
25 #define CANVAS_HEIGHT_BIT 9
26 #define CANVAS_WRAP_BIT 22
27 #define CANVAS_BLKMODE_BIT 24
28 #define CANVAS_ENDIAN_BIT 26
29#define DMC_CAV_LUT_ADDR 0x08
30 #define CANVAS_LUT_WR_EN BIT(9)
31 #define CANVAS_LUT_RD_EN BIT(8)
32
33struct meson_canvas {
34 struct device *dev;
35 void __iomem *reg_base;
36 spinlock_t lock; /* canvas device lock */
37 u8 used[NUM_CANVAS];
38};
39
40static void canvas_write(struct meson_canvas *canvas, u32 reg, u32 val)
41{
42 writel_relaxed(val, canvas->reg_base + reg);
43}
44
45static u32 canvas_read(struct meson_canvas *canvas, u32 reg)
46{
47 return readl_relaxed(canvas->reg_base + reg);
48}
49
50struct meson_canvas *meson_canvas_get(struct device *dev)
51{
52 struct device_node *canvas_node;
53 struct platform_device *canvas_pdev;
54
55 canvas_node = of_parse_phandle(dev->of_node, "amlogic,canvas", 0);
56 if (!canvas_node)
57 return ERR_PTR(-ENODEV);
58
59 canvas_pdev = of_find_device_by_node(canvas_node);
60 if (!canvas_pdev)
61 return ERR_PTR(-EPROBE_DEFER);
62
63 return dev_get_drvdata(&canvas_pdev->dev);
64}
65EXPORT_SYMBOL_GPL(meson_canvas_get);
66
67int meson_canvas_config(struct meson_canvas *canvas, u8 canvas_index,
68 u32 addr, u32 stride, u32 height,
69 unsigned int wrap,
70 unsigned int blkmode,
71 unsigned int endian)
72{
73 unsigned long flags;
74
75 spin_lock_irqsave(&canvas->lock, flags);
76 if (!canvas->used[canvas_index]) {
77 dev_err(canvas->dev,
78 "Trying to setup non allocated canvas %u\n",
79 canvas_index);
80 spin_unlock_irqrestore(&canvas->lock, flags);
81 return -EINVAL;
82 }
83
84 canvas_write(canvas, DMC_CAV_LUT_DATAL,
85 ((addr + 7) >> 3) |
86 (((stride + 7) >> 3) << CANVAS_WIDTH_LBIT));
87
88 canvas_write(canvas, DMC_CAV_LUT_DATAH,
89 ((((stride + 7) >> 3) >> CANVAS_WIDTH_LWID) <<
90 CANVAS_WIDTH_HBIT) |
91 (height << CANVAS_HEIGHT_BIT) |
92 (wrap << CANVAS_WRAP_BIT) |
93 (blkmode << CANVAS_BLKMODE_BIT) |
94 (endian << CANVAS_ENDIAN_BIT));
95
96 canvas_write(canvas, DMC_CAV_LUT_ADDR,
97 CANVAS_LUT_WR_EN | canvas_index);
98
99 /* Force a read-back to make sure everything is flushed. */
100 canvas_read(canvas, DMC_CAV_LUT_DATAH);
101 spin_unlock_irqrestore(&canvas->lock, flags);
102
103 return 0;
104}
105EXPORT_SYMBOL_GPL(meson_canvas_config);
106
107int meson_canvas_alloc(struct meson_canvas *canvas, u8 *canvas_index)
108{
109 int i;
110 unsigned long flags;
111
112 spin_lock_irqsave(&canvas->lock, flags);
113 for (i = 0; i < NUM_CANVAS; ++i) {
114 if (!canvas->used[i]) {
115 canvas->used[i] = 1;
116 spin_unlock_irqrestore(&canvas->lock, flags);
117 *canvas_index = i;
118 return 0;
119 }
120 }
121 spin_unlock_irqrestore(&canvas->lock, flags);
122
123 dev_err(canvas->dev, "No more canvas available\n");
124 return -ENODEV;
125}
126EXPORT_SYMBOL_GPL(meson_canvas_alloc);
127
128int meson_canvas_free(struct meson_canvas *canvas, u8 canvas_index)
129{
130 unsigned long flags;
131
132 spin_lock_irqsave(&canvas->lock, flags);
133 if (!canvas->used[canvas_index]) {
134 dev_err(canvas->dev,
135 "Trying to free unused canvas %u\n", canvas_index);
136 spin_unlock_irqrestore(&canvas->lock, flags);
137 return -EINVAL;
138 }
139 canvas->used[canvas_index] = 0;
140 spin_unlock_irqrestore(&canvas->lock, flags);
141
142 return 0;
143}
144EXPORT_SYMBOL_GPL(meson_canvas_free);
145
146static int meson_canvas_probe(struct platform_device *pdev)
147{
148 struct resource *res;
149 struct meson_canvas *canvas;
150 struct device *dev = &pdev->dev;
151
152 canvas = devm_kzalloc(dev, sizeof(*canvas), GFP_KERNEL);
153 if (!canvas)
154 return -ENOMEM;
155
156 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
157 canvas->reg_base = devm_ioremap_resource(dev, res);
158 if (IS_ERR(canvas->reg_base))
159 return PTR_ERR(canvas->reg_base);
160
161 canvas->dev = dev;
162 spin_lock_init(&canvas->lock);
163 dev_set_drvdata(dev, canvas);
164
165 return 0;
166}
167
168static const struct of_device_id canvas_dt_match[] = {
169 { .compatible = "amlogic,canvas" },
170 {}
171};
172MODULE_DEVICE_TABLE(of, canvas_dt_match);
173
174static struct platform_driver meson_canvas_driver = {
175 .probe = meson_canvas_probe,
176 .driver = {
177 .name = "amlogic-canvas",
178 .of_match_table = canvas_dt_match,
179 },
180};
181module_platform_driver(meson_canvas_driver);
182
183MODULE_DESCRIPTION("Amlogic Canvas driver");
184MODULE_AUTHOR("Maxime Jourdan <mjourdan@baylibre.com>");
185MODULE_LICENSE("GPL");
diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c
index b60b77bfaffa..e58fcc9096e8 100644
--- a/drivers/soc/fsl/dpio/dpio-driver.c
+++ b/drivers/soc/fsl/dpio/dpio-driver.c
@@ -50,13 +50,10 @@ static void unregister_dpio_irq_handlers(struct fsl_mc_device *dpio_dev)
50 50
51static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu) 51static int register_dpio_irq_handlers(struct fsl_mc_device *dpio_dev, int cpu)
52{ 52{
53 struct dpio_priv *priv;
54 int error; 53 int error;
55 struct fsl_mc_device_irq *irq; 54 struct fsl_mc_device_irq *irq;
56 cpumask_t mask; 55 cpumask_t mask;
57 56
58 priv = dev_get_drvdata(&dpio_dev->dev);
59
60 irq = dpio_dev->irqs[0]; 57 irq = dpio_dev->irqs[0];
61 error = devm_request_irq(&dpio_dev->dev, 58 error = devm_request_irq(&dpio_dev->dev,
62 irq->msi_desc->irq, 59 irq->msi_desc->irq,
diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig
index d570cb5fd381..b0943e541796 100644
--- a/drivers/soc/fsl/qbman/Kconfig
+++ b/drivers/soc/fsl/qbman/Kconfig
@@ -1,6 +1,6 @@
1menuconfig FSL_DPAA 1menuconfig FSL_DPAA
2 bool "QorIQ DPAA1 framework support" 2 bool "QorIQ DPAA1 framework support"
3 depends on (FSL_SOC_BOOKE || ARCH_LAYERSCAPE) 3 depends on ((FSL_SOC_BOOKE || ARCH_LAYERSCAPE) && ARCH_DMA_ADDR_T_64BIT)
4 select GENERIC_ALLOCATOR 4 select GENERIC_ALLOCATOR
5 help 5 help
6 The Freescale Data Path Acceleration Architecture (DPAA) is a set of 6 The Freescale Data Path Acceleration Architecture (DPAA) is a set of
diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c
index f9485cedc648..f84ab596bde8 100644
--- a/drivers/soc/fsl/qbman/bman.c
+++ b/drivers/soc/fsl/qbman/bman.c
@@ -562,11 +562,9 @@ static int bman_create_portal(struct bman_portal *portal,
562 dev_err(c->dev, "request_irq() failed\n"); 562 dev_err(c->dev, "request_irq() failed\n");
563 goto fail_irq; 563 goto fail_irq;
564 } 564 }
565 if (c->cpu != -1 && irq_can_set_affinity(c->irq) && 565
566 irq_set_affinity(c->irq, cpumask_of(c->cpu))) { 566 if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu))
567 dev_err(c->dev, "irq_set_affinity() failed\n");
568 goto fail_affinity; 567 goto fail_affinity;
569 }
570 568
571 /* Need RCR to be empty before continuing */ 569 /* Need RCR to be empty before continuing */
572 ret = bm_rcr_get_fill(p); 570 ret = bm_rcr_get_fill(p);
diff --git a/drivers/soc/fsl/qbman/bman_portal.c b/drivers/soc/fsl/qbman/bman_portal.c
index 2f71f7df3465..2c95cf59f3e7 100644
--- a/drivers/soc/fsl/qbman/bman_portal.c
+++ b/drivers/soc/fsl/qbman/bman_portal.c
@@ -65,7 +65,9 @@ static int bman_offline_cpu(unsigned int cpu)
65 if (!pcfg) 65 if (!pcfg)
66 return 0; 66 return 0;
67 67
68 irq_set_affinity(pcfg->irq, cpumask_of(0)); 68 /* use any other online CPU */
69 cpu = cpumask_any_but(cpu_online_mask, cpu);
70 irq_set_affinity(pcfg->irq, cpumask_of(cpu));
69 return 0; 71 return 0;
70} 72}
71 73
@@ -91,7 +93,15 @@ static int bman_portal_probe(struct platform_device *pdev)
91 struct device_node *node = dev->of_node; 93 struct device_node *node = dev->of_node;
92 struct bm_portal_config *pcfg; 94 struct bm_portal_config *pcfg;
93 struct resource *addr_phys[2]; 95 struct resource *addr_phys[2];
94 int irq, cpu; 96 int irq, cpu, err;
97
98 err = bman_is_probed();
99 if (!err)
100 return -EPROBE_DEFER;
101 if (err < 0) {
102 dev_err(&pdev->dev, "failing probe due to bman probe error\n");
103 return -ENODEV;
104 }
95 105
96 pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); 106 pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL);
97 if (!pcfg) 107 if (!pcfg)
diff --git a/drivers/soc/fsl/qbman/dpaa_sys.h b/drivers/soc/fsl/qbman/dpaa_sys.h
index 9f379000da85..ae8afa552b1e 100644
--- a/drivers/soc/fsl/qbman/dpaa_sys.h
+++ b/drivers/soc/fsl/qbman/dpaa_sys.h
@@ -111,4 +111,24 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
111#define QBMAN_MEMREMAP_ATTR MEMREMAP_WC 111#define QBMAN_MEMREMAP_ATTR MEMREMAP_WC
112#endif 112#endif
113 113
114static inline int dpaa_set_portal_irq_affinity(struct device *dev,
115 int irq, int cpu)
116{
117 int ret = 0;
118
119 if (!irq_can_set_affinity(irq)) {
120 dev_err(dev, "unable to set IRQ affinity\n");
121 return -EINVAL;
122 }
123
124 if (cpu == -1 || !cpu_online(cpu))
125 cpu = cpumask_any(cpu_online_mask);
126
127 ret = irq_set_affinity(irq, cpumask_of(cpu));
128 if (ret)
129 dev_err(dev, "irq_set_affinity() on CPU %d failed\n", cpu);
130
131 return ret;
132}
133
114#endif /* __DPAA_SYS_H */ 134#endif /* __DPAA_SYS_H */
diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 8cc015183043..5ce24718c2fd 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -850,12 +850,24 @@ static inline void qm_mr_set_ithresh(struct qm_portal *portal, u8 ithresh)
850 850
851static inline int qm_mc_init(struct qm_portal *portal) 851static inline int qm_mc_init(struct qm_portal *portal)
852{ 852{
853 u8 rr0, rr1;
853 struct qm_mc *mc = &portal->mc; 854 struct qm_mc *mc = &portal->mc;
854 855
855 mc->cr = portal->addr.ce + QM_CL_CR; 856 mc->cr = portal->addr.ce + QM_CL_CR;
856 mc->rr = portal->addr.ce + QM_CL_RR0; 857 mc->rr = portal->addr.ce + QM_CL_RR0;
857 mc->rridx = (mc->cr->_ncw_verb & QM_MCC_VERB_VBIT) 858 /*
858 ? 0 : 1; 859 * The expected valid bit polarity for the next CR command is 0
860 * if RR1 contains a valid response, and is 1 if RR0 contains a
861 * valid response. If both RR contain all 0, this indicates either
862 * that no command has been executed since reset (in which case the
863 * expected valid bit polarity is 1)
864 */
865 rr0 = mc->rr->verb;
866 rr1 = (mc->rr+1)->verb;
867 if ((rr0 == 0 && rr1 == 0) || rr0 != 0)
868 mc->rridx = 1;
869 else
870 mc->rridx = 0;
859 mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0; 871 mc->vbit = mc->rridx ? QM_MCC_VERB_VBIT : 0;
860#ifdef CONFIG_FSL_DPAA_CHECKING 872#ifdef CONFIG_FSL_DPAA_CHECKING
861 mc->state = qman_mc_idle; 873 mc->state = qman_mc_idle;
@@ -1000,6 +1012,37 @@ static inline void put_affine_portal(void)
1000 1012
1001static struct workqueue_struct *qm_portal_wq; 1013static struct workqueue_struct *qm_portal_wq;
1002 1014
1015void qman_dqrr_set_ithresh(struct qman_portal *portal, u8 ithresh)
1016{
1017 if (!portal)
1018 return;
1019
1020 qm_dqrr_set_ithresh(&portal->p, ithresh);
1021 portal->p.dqrr.ithresh = ithresh;
1022}
1023EXPORT_SYMBOL(qman_dqrr_set_ithresh);
1024
1025void qman_dqrr_get_ithresh(struct qman_portal *portal, u8 *ithresh)
1026{
1027 if (portal && ithresh)
1028 *ithresh = portal->p.dqrr.ithresh;
1029}
1030EXPORT_SYMBOL(qman_dqrr_get_ithresh);
1031
1032void qman_portal_get_iperiod(struct qman_portal *portal, u32 *iperiod)
1033{
1034 if (portal && iperiod)
1035 *iperiod = qm_in(&portal->p, QM_REG_ITPR);
1036}
1037EXPORT_SYMBOL(qman_portal_get_iperiod);
1038
1039void qman_portal_set_iperiod(struct qman_portal *portal, u32 iperiod)
1040{
1041 if (portal)
1042 qm_out(&portal->p, QM_REG_ITPR, iperiod);
1043}
1044EXPORT_SYMBOL(qman_portal_set_iperiod);
1045
1003int qman_wq_alloc(void) 1046int qman_wq_alloc(void)
1004{ 1047{
1005 qm_portal_wq = alloc_workqueue("qman_portal_wq", 0, 1); 1048 qm_portal_wq = alloc_workqueue("qman_portal_wq", 0, 1);
@@ -1210,11 +1253,9 @@ static int qman_create_portal(struct qman_portal *portal,
1210 dev_err(c->dev, "request_irq() failed\n"); 1253 dev_err(c->dev, "request_irq() failed\n");
1211 goto fail_irq; 1254 goto fail_irq;
1212 } 1255 }
1213 if (c->cpu != -1 && irq_can_set_affinity(c->irq) && 1256
1214 irq_set_affinity(c->irq, cpumask_of(c->cpu))) { 1257 if (dpaa_set_portal_irq_affinity(c->dev, c->irq, c->cpu))
1215 dev_err(c->dev, "irq_set_affinity() failed\n");
1216 goto fail_affinity; 1258 goto fail_affinity;
1217 }
1218 1259
1219 /* Need EQCR to be empty before continuing */ 1260 /* Need EQCR to be empty before continuing */
1220 isdr &= ~QM_PIRQ_EQCI; 1261 isdr &= ~QM_PIRQ_EQCI;
diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c
index 3e9391d117c5..661c9b234d32 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -195,8 +195,10 @@ static int qman_offline_cpu(unsigned int cpu)
195 if (p) { 195 if (p) {
196 pcfg = qman_get_qm_portal_config(p); 196 pcfg = qman_get_qm_portal_config(p);
197 if (pcfg) { 197 if (pcfg) {
198 irq_set_affinity(pcfg->irq, cpumask_of(0)); 198 /* select any other online CPU */
199 qman_portal_update_sdest(pcfg, 0); 199 cpu = cpumask_any_but(cpu_online_mask, cpu);
200 irq_set_affinity(pcfg->irq, cpumask_of(cpu));
201 qman_portal_update_sdest(pcfg, cpu);
200 } 202 }
201 } 203 }
202 return 0; 204 return 0;
diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c
index 2ef6fc6487c1..612d9c551be5 100644
--- a/drivers/soc/fsl/qe/qe.c
+++ b/drivers/soc/fsl/qe/qe.c
@@ -588,11 +588,7 @@ struct qe_firmware_info *qe_get_firmware_info(void)
588 } 588 }
589 589
590 /* Find the 'firmware' child node */ 590 /* Find the 'firmware' child node */
591 for_each_child_of_node(qe, fw) { 591 fw = of_get_child_by_name(qe, "firmware");
592 if (strcmp(fw->name, "firmware") == 0)
593 break;
594 }
595
596 of_node_put(qe); 592 of_node_put(qe);
597 593
598 /* Did we find the 'firmware' node? */ 594 /* Did we find the 'firmware' node? */
diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c
index b3da635970ea..aa3729ecaa9e 100644
--- a/drivers/soc/imx/gpc.c
+++ b/drivers/soc/imx/gpc.c
@@ -1,13 +1,7 @@
1// SPDX-License-Identifier: GPL-2.0+
1/* 2/*
2 * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de> 3 * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
3 * Copyright 2011-2013 Freescale Semiconductor, Inc. 4 * Copyright 2011-2013 Freescale Semiconductor, Inc.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */ 5 */
12 6
13#include <linux/clk.h> 7#include <linux/clk.h>
@@ -69,7 +63,7 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd)
69 u32 val; 63 u32 val;
70 64
71 /* Read ISO and ISO2SW power down delays */ 65 /* Read ISO and ISO2SW power down delays */
72 regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); 66 regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PDNSCR_OFFS, &val);
73 iso = val & 0x3f; 67 iso = val & 0x3f;
74 iso2sw = (val >> 8) & 0x3f; 68 iso2sw = (val >> 8) & 0x3f;
75 69
@@ -247,6 +241,7 @@ builtin_platform_driver(imx_pgc_power_domain_driver)
247#define GPC_PGC_DOMAIN_ARM 0 241#define GPC_PGC_DOMAIN_ARM 0
248#define GPC_PGC_DOMAIN_PU 1 242#define GPC_PGC_DOMAIN_PU 1
249#define GPC_PGC_DOMAIN_DISPLAY 2 243#define GPC_PGC_DOMAIN_DISPLAY 2
244#define GPC_PGC_DOMAIN_PCI 3
250 245
251static struct genpd_power_state imx6_pm_domain_pu_state = { 246static struct genpd_power_state imx6_pm_domain_pu_state = {
252 .power_off_latency_ns = 25000, 247 .power_off_latency_ns = 25000,
@@ -254,12 +249,13 @@ static struct genpd_power_state imx6_pm_domain_pu_state = {
254}; 249};
255 250
256static struct imx_pm_domain imx_gpc_domains[] = { 251static struct imx_pm_domain imx_gpc_domains[] = {
257 { 252 [GPC_PGC_DOMAIN_ARM] {
258 .base = { 253 .base = {
259 .name = "ARM", 254 .name = "ARM",
260 .flags = GENPD_FLAG_ALWAYS_ON, 255 .flags = GENPD_FLAG_ALWAYS_ON,
261 }, 256 },
262 }, { 257 },
258 [GPC_PGC_DOMAIN_PU] {
263 .base = { 259 .base = {
264 .name = "PU", 260 .name = "PU",
265 .power_off = imx6_pm_domain_power_off, 261 .power_off = imx6_pm_domain_power_off,
@@ -269,7 +265,8 @@ static struct imx_pm_domain imx_gpc_domains[] = {
269 }, 265 },
270 .reg_offs = 0x260, 266 .reg_offs = 0x260,
271 .cntr_pdn_bit = 0, 267 .cntr_pdn_bit = 0,
272 }, { 268 },
269 [GPC_PGC_DOMAIN_DISPLAY] {
273 .base = { 270 .base = {
274 .name = "DISPLAY", 271 .name = "DISPLAY",
275 .power_off = imx6_pm_domain_power_off, 272 .power_off = imx6_pm_domain_power_off,
@@ -277,7 +274,8 @@ static struct imx_pm_domain imx_gpc_domains[] = {
277 }, 274 },
278 .reg_offs = 0x240, 275 .reg_offs = 0x240,
279 .cntr_pdn_bit = 4, 276 .cntr_pdn_bit = 4,
280 }, { 277 },
278 [GPC_PGC_DOMAIN_PCI] {
281 .base = { 279 .base = {
282 .name = "PCI", 280 .name = "PCI",
283 .power_off = imx6_pm_domain_power_off, 281 .power_off = imx6_pm_domain_power_off,
@@ -348,8 +346,8 @@ static const struct regmap_config imx_gpc_regmap_config = {
348}; 346};
349 347
350static struct generic_pm_domain *imx_gpc_onecell_domains[] = { 348static struct generic_pm_domain *imx_gpc_onecell_domains[] = {
351 &imx_gpc_domains[0].base, 349 &imx_gpc_domains[GPC_PGC_DOMAIN_ARM].base,
352 &imx_gpc_domains[1].base, 350 &imx_gpc_domains[GPC_PGC_DOMAIN_PU].base,
353}; 351};
354 352
355static struct genpd_onecell_data imx_gpc_onecell_data = { 353static struct genpd_onecell_data imx_gpc_onecell_data = {
diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c
index 6ef18cf8f243..e7b5994fee9d 100644
--- a/drivers/soc/imx/gpcv2.c
+++ b/drivers/soc/imx/gpcv2.c
@@ -1,3 +1,4 @@
1// SPDX-License-Identifier: GPL-2.0+
1/* 2/*
2 * Copyright 2017 Impinj, Inc 3 * Copyright 2017 Impinj, Inc
3 * Author: Andrey Smirnov <andrew.smirnov@gmail.com> 4 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
@@ -5,29 +6,23 @@
5 * Based on the code of analogus driver: 6 * Based on the code of analogus driver:
6 * 7 *
7 * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de> 8 * Copyright 2015-2017 Pengutronix, Lucas Stach <kernel@pengutronix.de>
8 *
9 * The code contained herein is licensed under the GNU General Public
10 * License. You may obtain a copy of the GNU General Public License
11 * Version 2 or later at the following locations:
12 *
13 * http://www.opensource.org/licenses/gpl-license.html
14 * http://www.gnu.org/copyleft/gpl.html
15 */ 9 */
16 10
11#include <linux/of_device.h>
17#include <linux/platform_device.h> 12#include <linux/platform_device.h>
18#include <linux/pm_domain.h> 13#include <linux/pm_domain.h>
19#include <linux/regmap.h> 14#include <linux/regmap.h>
20#include <linux/regulator/consumer.h> 15#include <linux/regulator/consumer.h>
21#include <dt-bindings/power/imx7-power.h> 16#include <dt-bindings/power/imx7-power.h>
22 17
23#define GPC_LPCR_A7_BSC 0x000 18#define GPC_LPCR_A_CORE_BSC 0x000
24 19
25#define GPC_PGC_CPU_MAPPING 0x0ec 20#define GPC_PGC_CPU_MAPPING 0x0ec
26#define USB_HSIC_PHY_A7_DOMAIN BIT(6) 21#define USB_HSIC_PHY_A_CORE_DOMAIN BIT(6)
27#define USB_OTG2_PHY_A7_DOMAIN BIT(5) 22#define USB_OTG2_PHY_A_CORE_DOMAIN BIT(5)
28#define USB_OTG1_PHY_A7_DOMAIN BIT(4) 23#define USB_OTG1_PHY_A_CORE_DOMAIN BIT(4)
29#define PCIE_PHY_A7_DOMAIN BIT(3) 24#define PCIE_PHY_A_CORE_DOMAIN BIT(3)
30#define MIPI_PHY_A7_DOMAIN BIT(2) 25#define MIPI_PHY_A_CORE_DOMAIN BIT(2)
31 26
32#define GPC_PU_PGC_SW_PUP_REQ 0x0f8 27#define GPC_PU_PGC_SW_PUP_REQ 0x0f8
33#define GPC_PU_PGC_SW_PDN_REQ 0x104 28#define GPC_PU_PGC_SW_PDN_REQ 0x104
@@ -53,7 +48,7 @@
53 48
54#define GPC_PGC_CTRL_PCR BIT(0) 49#define GPC_PGC_CTRL_PCR BIT(0)
55 50
56struct imx7_pgc_domain { 51struct imx_pgc_domain {
57 struct generic_pm_domain genpd; 52 struct generic_pm_domain genpd;
58 struct regmap *regmap; 53 struct regmap *regmap;
59 struct regulator *regulator; 54 struct regulator *regulator;
@@ -69,11 +64,16 @@ struct imx7_pgc_domain {
69 struct device *dev; 64 struct device *dev;
70}; 65};
71 66
72static int imx7_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, 67struct imx_pgc_domain_data {
68 const struct imx_pgc_domain *domains;
69 size_t domains_num;
70};
71
72static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd,
73 bool on) 73 bool on)
74{ 74{
75 struct imx7_pgc_domain *domain = container_of(genpd, 75 struct imx_pgc_domain *domain = container_of(genpd,
76 struct imx7_pgc_domain, 76 struct imx_pgc_domain,
77 genpd); 77 genpd);
78 unsigned int offset = on ? 78 unsigned int offset = on ?
79 GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; 79 GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ;
@@ -150,24 +150,24 @@ unmap:
150 return ret; 150 return ret;
151} 151}
152 152
153static int imx7_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd) 153static int imx_gpc_pu_pgc_sw_pup_req(struct generic_pm_domain *genpd)
154{ 154{
155 return imx7_gpc_pu_pgc_sw_pxx_req(genpd, true); 155 return imx_gpc_pu_pgc_sw_pxx_req(genpd, true);
156} 156}
157 157
158static int imx7_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd) 158static int imx_gpc_pu_pgc_sw_pdn_req(struct generic_pm_domain *genpd)
159{ 159{
160 return imx7_gpc_pu_pgc_sw_pxx_req(genpd, false); 160 return imx_gpc_pu_pgc_sw_pxx_req(genpd, false);
161} 161}
162 162
163static const struct imx7_pgc_domain imx7_pgc_domains[] = { 163static const struct imx_pgc_domain imx7_pgc_domains[] = {
164 [IMX7_POWER_DOMAIN_MIPI_PHY] = { 164 [IMX7_POWER_DOMAIN_MIPI_PHY] = {
165 .genpd = { 165 .genpd = {
166 .name = "mipi-phy", 166 .name = "mipi-phy",
167 }, 167 },
168 .bits = { 168 .bits = {
169 .pxx = MIPI_PHY_SW_Pxx_REQ, 169 .pxx = MIPI_PHY_SW_Pxx_REQ,
170 .map = MIPI_PHY_A7_DOMAIN, 170 .map = MIPI_PHY_A_CORE_DOMAIN,
171 }, 171 },
172 .voltage = 1000000, 172 .voltage = 1000000,
173 .pgc = PGC_MIPI, 173 .pgc = PGC_MIPI,
@@ -179,7 +179,7 @@ static const struct imx7_pgc_domain imx7_pgc_domains[] = {
179 }, 179 },
180 .bits = { 180 .bits = {
181 .pxx = PCIE_PHY_SW_Pxx_REQ, 181 .pxx = PCIE_PHY_SW_Pxx_REQ,
182 .map = PCIE_PHY_A7_DOMAIN, 182 .map = PCIE_PHY_A_CORE_DOMAIN,
183 }, 183 },
184 .voltage = 1000000, 184 .voltage = 1000000,
185 .pgc = PGC_PCIE, 185 .pgc = PGC_PCIE,
@@ -191,16 +191,21 @@ static const struct imx7_pgc_domain imx7_pgc_domains[] = {
191 }, 191 },
192 .bits = { 192 .bits = {
193 .pxx = USB_HSIC_PHY_SW_Pxx_REQ, 193 .pxx = USB_HSIC_PHY_SW_Pxx_REQ,
194 .map = USB_HSIC_PHY_A7_DOMAIN, 194 .map = USB_HSIC_PHY_A_CORE_DOMAIN,
195 }, 195 },
196 .voltage = 1200000, 196 .voltage = 1200000,
197 .pgc = PGC_USB_HSIC, 197 .pgc = PGC_USB_HSIC,
198 }, 198 },
199}; 199};
200 200
201static int imx7_pgc_domain_probe(struct platform_device *pdev) 201static const struct imx_pgc_domain_data imx7_pgc_domain_data = {
202 .domains = imx7_pgc_domains,
203 .domains_num = ARRAY_SIZE(imx7_pgc_domains),
204};
205
206static int imx_pgc_domain_probe(struct platform_device *pdev)
202{ 207{
203 struct imx7_pgc_domain *domain = pdev->dev.platform_data; 208 struct imx_pgc_domain *domain = pdev->dev.platform_data;
204 int ret; 209 int ret;
205 210
206 domain->dev = &pdev->dev; 211 domain->dev = &pdev->dev;
@@ -233,9 +238,9 @@ static int imx7_pgc_domain_probe(struct platform_device *pdev)
233 return ret; 238 return ret;
234} 239}
235 240
236static int imx7_pgc_domain_remove(struct platform_device *pdev) 241static int imx_pgc_domain_remove(struct platform_device *pdev)
237{ 242{
238 struct imx7_pgc_domain *domain = pdev->dev.platform_data; 243 struct imx_pgc_domain *domain = pdev->dev.platform_data;
239 244
240 of_genpd_del_provider(domain->dev->of_node); 245 of_genpd_del_provider(domain->dev->of_node);
241 pm_genpd_remove(&domain->genpd); 246 pm_genpd_remove(&domain->genpd);
@@ -243,25 +248,26 @@ static int imx7_pgc_domain_remove(struct platform_device *pdev)
243 return 0; 248 return 0;
244} 249}
245 250
246static const struct platform_device_id imx7_pgc_domain_id[] = { 251static const struct platform_device_id imx_pgc_domain_id[] = {
247 { "imx7-pgc-domain", }, 252 { "imx-pgc-domain", },
248 { }, 253 { },
249}; 254};
250 255
251static struct platform_driver imx7_pgc_domain_driver = { 256static struct platform_driver imx_pgc_domain_driver = {
252 .driver = { 257 .driver = {
253 .name = "imx7-pgc", 258 .name = "imx-pgc",
254 }, 259 },
255 .probe = imx7_pgc_domain_probe, 260 .probe = imx_pgc_domain_probe,
256 .remove = imx7_pgc_domain_remove, 261 .remove = imx_pgc_domain_remove,
257 .id_table = imx7_pgc_domain_id, 262 .id_table = imx_pgc_domain_id,
258}; 263};
259builtin_platform_driver(imx7_pgc_domain_driver) 264builtin_platform_driver(imx_pgc_domain_driver)
260 265
261static int imx_gpcv2_probe(struct platform_device *pdev) 266static int imx_gpcv2_probe(struct platform_device *pdev)
262{ 267{
268 static const struct imx_pgc_domain_data *domain_data;
263 static const struct regmap_range yes_ranges[] = { 269 static const struct regmap_range yes_ranges[] = {
264 regmap_reg_range(GPC_LPCR_A7_BSC, 270 regmap_reg_range(GPC_LPCR_A_CORE_BSC,
265 GPC_M4_PU_PDN_FLG), 271 GPC_M4_PU_PDN_FLG),
266 regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI), 272 regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI),
267 GPC_PGC_SR(PGC_MIPI)), 273 GPC_PGC_SR(PGC_MIPI)),
@@ -307,9 +313,11 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
307 return ret; 313 return ret;
308 } 314 }
309 315
316 domain_data = of_device_get_match_data(&pdev->dev);
317
310 for_each_child_of_node(pgc_np, np) { 318 for_each_child_of_node(pgc_np, np) {
311 struct platform_device *pd_pdev; 319 struct platform_device *pd_pdev;
312 struct imx7_pgc_domain *domain; 320 struct imx_pgc_domain *domain;
313 u32 domain_index; 321 u32 domain_index;
314 322
315 ret = of_property_read_u32(np, "reg", &domain_index); 323 ret = of_property_read_u32(np, "reg", &domain_index);
@@ -319,14 +327,14 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
319 return ret; 327 return ret;
320 } 328 }
321 329
322 if (domain_index >= ARRAY_SIZE(imx7_pgc_domains)) { 330 if (domain_index >= domain_data->domains_num) {
323 dev_warn(dev, 331 dev_warn(dev,
324 "Domain index %d is out of bounds\n", 332 "Domain index %d is out of bounds\n",
325 domain_index); 333 domain_index);
326 continue; 334 continue;
327 } 335 }
328 336
329 pd_pdev = platform_device_alloc("imx7-pgc-domain", 337 pd_pdev = platform_device_alloc("imx-pgc-domain",
330 domain_index); 338 domain_index);
331 if (!pd_pdev) { 339 if (!pd_pdev) {
332 dev_err(dev, "Failed to allocate platform device\n"); 340 dev_err(dev, "Failed to allocate platform device\n");
@@ -335,8 +343,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
335 } 343 }
336 344
337 ret = platform_device_add_data(pd_pdev, 345 ret = platform_device_add_data(pd_pdev,
338 &imx7_pgc_domains[domain_index], 346 &domain_data->domains[domain_index],
339 sizeof(imx7_pgc_domains[domain_index])); 347 sizeof(domain_data->domains[domain_index]));
340 if (ret) { 348 if (ret) {
341 platform_device_put(pd_pdev); 349 platform_device_put(pd_pdev);
342 of_node_put(np); 350 of_node_put(np);
@@ -345,8 +353,8 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
345 353
346 domain = pd_pdev->dev.platform_data; 354 domain = pd_pdev->dev.platform_data;
347 domain->regmap = regmap; 355 domain->regmap = regmap;
348 domain->genpd.power_on = imx7_gpc_pu_pgc_sw_pup_req; 356 domain->genpd.power_on = imx_gpc_pu_pgc_sw_pup_req;
349 domain->genpd.power_off = imx7_gpc_pu_pgc_sw_pdn_req; 357 domain->genpd.power_off = imx_gpc_pu_pgc_sw_pdn_req;
350 358
351 pd_pdev->dev.parent = dev; 359 pd_pdev->dev.parent = dev;
352 pd_pdev->dev.of_node = np; 360 pd_pdev->dev.of_node = np;
@@ -363,7 +371,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev)
363} 371}
364 372
365static const struct of_device_id imx_gpcv2_dt_ids[] = { 373static const struct of_device_id imx_gpcv2_dt_ids[] = {
366 { .compatible = "fsl,imx7d-gpc" }, 374 { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, },
367 { } 375 { }
368}; 376};
369 377
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index 4e931fdf4d09..8236a6c87e19 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -76,6 +76,13 @@
76#define PWRAP_SLV_CAP_SECURITY BIT(2) 76#define PWRAP_SLV_CAP_SECURITY BIT(2)
77#define HAS_CAP(_c, _x) (((_c) & (_x)) == (_x)) 77#define HAS_CAP(_c, _x) (((_c) & (_x)) == (_x))
78 78
79/* Group of bits used for shown pwrap capability */
80#define PWRAP_CAP_BRIDGE BIT(0)
81#define PWRAP_CAP_RESET BIT(1)
82#define PWRAP_CAP_DCM BIT(2)
83#define PWRAP_CAP_INT1_EN BIT(3)
84#define PWRAP_CAP_WDT_SRC1 BIT(4)
85
79/* defines for slave device wrapper registers */ 86/* defines for slave device wrapper registers */
80enum dew_regs { 87enum dew_regs {
81 PWRAP_DEW_BASE, 88 PWRAP_DEW_BASE,
@@ -91,6 +98,27 @@ enum dew_regs {
91 PWRAP_DEW_CIPHER_MODE, 98 PWRAP_DEW_CIPHER_MODE,
92 PWRAP_DEW_CIPHER_SWRST, 99 PWRAP_DEW_CIPHER_SWRST,
93 100
101 /* MT6323 only regs */
102 PWRAP_DEW_CIPHER_EN,
103 PWRAP_DEW_RDDMY_NO,
104
105 /* MT6358 only regs */
106 PWRAP_SMT_CON1,
107 PWRAP_DRV_CON1,
108 PWRAP_FILTER_CON0,
109 PWRAP_GPIO_PULLEN0_CLR,
110 PWRAP_RG_SPI_CON0,
111 PWRAP_RG_SPI_RECORD0,
112 PWRAP_RG_SPI_CON2,
113 PWRAP_RG_SPI_CON3,
114 PWRAP_RG_SPI_CON4,
115 PWRAP_RG_SPI_CON5,
116 PWRAP_RG_SPI_CON6,
117 PWRAP_RG_SPI_CON7,
118 PWRAP_RG_SPI_CON8,
119 PWRAP_RG_SPI_CON13,
120 PWRAP_SPISLV_KEY,
121
94 /* MT6397 only regs */ 122 /* MT6397 only regs */
95 PWRAP_DEW_EVENT_OUT_EN, 123 PWRAP_DEW_EVENT_OUT_EN,
96 PWRAP_DEW_EVENT_SRC_EN, 124 PWRAP_DEW_EVENT_SRC_EN,
@@ -100,10 +128,6 @@ enum dew_regs {
100 PWRAP_DEW_EVENT_TEST, 128 PWRAP_DEW_EVENT_TEST,
101 PWRAP_DEW_CIPHER_LOAD, 129 PWRAP_DEW_CIPHER_LOAD,
102 PWRAP_DEW_CIPHER_START, 130 PWRAP_DEW_CIPHER_START,
103
104 /* MT6323 only regs */
105 PWRAP_DEW_CIPHER_EN,
106 PWRAP_DEW_RDDMY_NO,
107}; 131};
108 132
109static const u32 mt6323_regs[] = { 133static const u32 mt6323_regs[] = {
@@ -123,6 +147,64 @@ static const u32 mt6323_regs[] = {
123 [PWRAP_DEW_RDDMY_NO] = 0x01a4, 147 [PWRAP_DEW_RDDMY_NO] = 0x01a4,
124}; 148};
125 149
150static const u32 mt6351_regs[] = {
151 [PWRAP_DEW_DIO_EN] = 0x02F2,
152 [PWRAP_DEW_READ_TEST] = 0x02F4,
153 [PWRAP_DEW_WRITE_TEST] = 0x02F6,
154 [PWRAP_DEW_CRC_EN] = 0x02FA,
155 [PWRAP_DEW_CRC_VAL] = 0x02FC,
156 [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300,
157 [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302,
158 [PWRAP_DEW_CIPHER_EN] = 0x0304,
159 [PWRAP_DEW_CIPHER_RDY] = 0x0306,
160 [PWRAP_DEW_CIPHER_MODE] = 0x0308,
161 [PWRAP_DEW_CIPHER_SWRST] = 0x030A,
162 [PWRAP_DEW_RDDMY_NO] = 0x030C,
163};
164
165static const u32 mt6357_regs[] = {
166 [PWRAP_DEW_DIO_EN] = 0x040A,
167 [PWRAP_DEW_READ_TEST] = 0x040C,
168 [PWRAP_DEW_WRITE_TEST] = 0x040E,
169 [PWRAP_DEW_CRC_EN] = 0x0412,
170 [PWRAP_DEW_CRC_VAL] = 0x0414,
171 [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0418,
172 [PWRAP_DEW_CIPHER_IV_SEL] = 0x041A,
173 [PWRAP_DEW_CIPHER_EN] = 0x041C,
174 [PWRAP_DEW_CIPHER_RDY] = 0x041E,
175 [PWRAP_DEW_CIPHER_MODE] = 0x0420,
176 [PWRAP_DEW_CIPHER_SWRST] = 0x0422,
177 [PWRAP_DEW_RDDMY_NO] = 0x0424,
178};
179
180static const u32 mt6358_regs[] = {
181 [PWRAP_SMT_CON1] = 0x0030,
182 [PWRAP_DRV_CON1] = 0x0038,
183 [PWRAP_FILTER_CON0] = 0x0040,
184 [PWRAP_GPIO_PULLEN0_CLR] = 0x0098,
185 [PWRAP_RG_SPI_CON0] = 0x0408,
186 [PWRAP_RG_SPI_RECORD0] = 0x040a,
187 [PWRAP_DEW_DIO_EN] = 0x040c,
188 [PWRAP_DEW_READ_TEST] = 0x040e,
189 [PWRAP_DEW_WRITE_TEST] = 0x0410,
190 [PWRAP_DEW_CRC_EN] = 0x0414,
191 [PWRAP_DEW_CIPHER_KEY_SEL] = 0x041a,
192 [PWRAP_DEW_CIPHER_IV_SEL] = 0x041c,
193 [PWRAP_DEW_CIPHER_EN] = 0x041e,
194 [PWRAP_DEW_CIPHER_RDY] = 0x0420,
195 [PWRAP_DEW_CIPHER_MODE] = 0x0422,
196 [PWRAP_DEW_CIPHER_SWRST] = 0x0424,
197 [PWRAP_RG_SPI_CON2] = 0x0432,
198 [PWRAP_RG_SPI_CON3] = 0x0434,
199 [PWRAP_RG_SPI_CON4] = 0x0436,
200 [PWRAP_RG_SPI_CON5] = 0x0438,
201 [PWRAP_RG_SPI_CON6] = 0x043a,
202 [PWRAP_RG_SPI_CON7] = 0x043c,
203 [PWRAP_RG_SPI_CON8] = 0x043e,
204 [PWRAP_RG_SPI_CON13] = 0x0448,
205 [PWRAP_SPISLV_KEY] = 0x044a,
206};
207
126static const u32 mt6397_regs[] = { 208static const u32 mt6397_regs[] = {
127 [PWRAP_DEW_BASE] = 0xbc00, 209 [PWRAP_DEW_BASE] = 0xbc00,
128 [PWRAP_DEW_EVENT_OUT_EN] = 0xbc00, 210 [PWRAP_DEW_EVENT_OUT_EN] = 0xbc00,
@@ -146,21 +228,6 @@ static const u32 mt6397_regs[] = {
146 [PWRAP_DEW_CIPHER_SWRST] = 0xbc24, 228 [PWRAP_DEW_CIPHER_SWRST] = 0xbc24,
147}; 229};
148 230
149static const u32 mt6351_regs[] = {
150 [PWRAP_DEW_DIO_EN] = 0x02F2,
151 [PWRAP_DEW_READ_TEST] = 0x02F4,
152 [PWRAP_DEW_WRITE_TEST] = 0x02F6,
153 [PWRAP_DEW_CRC_EN] = 0x02FA,
154 [PWRAP_DEW_CRC_VAL] = 0x02FC,
155 [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300,
156 [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302,
157 [PWRAP_DEW_CIPHER_EN] = 0x0304,
158 [PWRAP_DEW_CIPHER_RDY] = 0x0306,
159 [PWRAP_DEW_CIPHER_MODE] = 0x0308,
160 [PWRAP_DEW_CIPHER_SWRST] = 0x030A,
161 [PWRAP_DEW_RDDMY_NO] = 0x030C,
162};
163
164enum pwrap_regs { 231enum pwrap_regs {
165 PWRAP_MUX_SEL, 232 PWRAP_MUX_SEL,
166 PWRAP_WRAP_EN, 233 PWRAP_WRAP_EN,
@@ -221,6 +288,8 @@ enum pwrap_regs {
221 PWRAP_CIPHER_SWRST, 288 PWRAP_CIPHER_SWRST,
222 PWRAP_DCM_EN, 289 PWRAP_DCM_EN,
223 PWRAP_DCM_DBC_PRD, 290 PWRAP_DCM_DBC_PRD,
291 PWRAP_EINT_STA0_ADR,
292 PWRAP_EINT_STA1_ADR,
224 293
225 /* MT2701 only regs */ 294 /* MT2701 only regs */
226 PWRAP_ADC_CMD_ADDR, 295 PWRAP_ADC_CMD_ADDR,
@@ -230,8 +299,6 @@ enum pwrap_regs {
230 PWRAP_ADC_RDATA_ADDR2, 299 PWRAP_ADC_RDATA_ADDR2,
231 300
232 /* MT7622 only regs */ 301 /* MT7622 only regs */
233 PWRAP_EINT_STA0_ADR,
234 PWRAP_EINT_STA1_ADR,
235 PWRAP_STA, 302 PWRAP_STA,
236 PWRAP_CLR, 303 PWRAP_CLR,
237 PWRAP_DVFS_ADR8, 304 PWRAP_DVFS_ADR8,
@@ -293,6 +360,27 @@ enum pwrap_regs {
293 PWRAP_DVFS_WDATA7, 360 PWRAP_DVFS_WDATA7,
294 PWRAP_SPMINF_STA, 361 PWRAP_SPMINF_STA,
295 PWRAP_CIPHER_EN, 362 PWRAP_CIPHER_EN,
363
364 /* MT8183 only regs */
365 PWRAP_SI_SAMPLE_CTRL,
366 PWRAP_CSLEXT_WRITE,
367 PWRAP_CSLEXT_READ,
368 PWRAP_EXT_CK_WRITE,
369 PWRAP_STAUPD_CTRL,
370 PWRAP_WACS_P2P_EN,
371 PWRAP_INIT_DONE_P2P,
372 PWRAP_WACS_MD32_EN,
373 PWRAP_INIT_DONE_MD32,
374 PWRAP_INT1_EN,
375 PWRAP_INT1_FLG,
376 PWRAP_INT1_CLR,
377 PWRAP_WDT_SRC_EN_1,
378 PWRAP_INT_GPS_AUXADC_CMD_ADDR,
379 PWRAP_INT_GPS_AUXADC_CMD,
380 PWRAP_INT_GPS_AUXADC_RDATA_ADDR,
381 PWRAP_EXT_GPS_AUXADC_RDATA_ADDR,
382 PWRAP_GPSINF_0_STA,
383 PWRAP_GPSINF_1_STA,
296}; 384};
297 385
298static int mt2701_regs[] = { 386static int mt2701_regs[] = {
@@ -381,6 +469,38 @@ static int mt2701_regs[] = {
381 [PWRAP_ADC_RDATA_ADDR2] = 0x154, 469 [PWRAP_ADC_RDATA_ADDR2] = 0x154,
382}; 470};
383 471
472static int mt6765_regs[] = {
473 [PWRAP_MUX_SEL] = 0x0,
474 [PWRAP_WRAP_EN] = 0x4,
475 [PWRAP_DIO_EN] = 0x8,
476 [PWRAP_RDDMY] = 0x20,
477 [PWRAP_CSHEXT_WRITE] = 0x24,
478 [PWRAP_CSHEXT_READ] = 0x28,
479 [PWRAP_CSLEXT_START] = 0x2C,
480 [PWRAP_CSLEXT_END] = 0x30,
481 [PWRAP_STAUPD_PRD] = 0x3C,
482 [PWRAP_HARB_HPRIO] = 0x68,
483 [PWRAP_HIPRIO_ARB_EN] = 0x6C,
484 [PWRAP_MAN_EN] = 0x7C,
485 [PWRAP_MAN_CMD] = 0x80,
486 [PWRAP_WACS0_EN] = 0x8C,
487 [PWRAP_WACS1_EN] = 0x94,
488 [PWRAP_WACS2_EN] = 0x9C,
489 [PWRAP_INIT_DONE2] = 0xA0,
490 [PWRAP_WACS2_CMD] = 0xC20,
491 [PWRAP_WACS2_RDATA] = 0xC24,
492 [PWRAP_WACS2_VLDCLR] = 0xC28,
493 [PWRAP_INT_EN] = 0xB4,
494 [PWRAP_INT_FLG_RAW] = 0xB8,
495 [PWRAP_INT_FLG] = 0xBC,
496 [PWRAP_INT_CLR] = 0xC0,
497 [PWRAP_TIMER_EN] = 0xE8,
498 [PWRAP_WDT_UNIT] = 0xF0,
499 [PWRAP_WDT_SRC_EN] = 0xF4,
500 [PWRAP_DCM_EN] = 0x1DC,
501 [PWRAP_DCM_DBC_PRD] = 0x1E0,
502};
503
384static int mt6797_regs[] = { 504static int mt6797_regs[] = {
385 [PWRAP_MUX_SEL] = 0x0, 505 [PWRAP_MUX_SEL] = 0x0,
386 [PWRAP_WRAP_EN] = 0x4, 506 [PWRAP_WRAP_EN] = 0x4,
@@ -526,6 +646,79 @@ static int mt7622_regs[] = {
526 [PWRAP_SPI2_CTRL] = 0x244, 646 [PWRAP_SPI2_CTRL] = 0x244,
527}; 647};
528 648
649static int mt8135_regs[] = {
650 [PWRAP_MUX_SEL] = 0x0,
651 [PWRAP_WRAP_EN] = 0x4,
652 [PWRAP_DIO_EN] = 0x8,
653 [PWRAP_SIDLY] = 0xc,
654 [PWRAP_CSHEXT] = 0x10,
655 [PWRAP_CSHEXT_WRITE] = 0x14,
656 [PWRAP_CSHEXT_READ] = 0x18,
657 [PWRAP_CSLEXT_START] = 0x1c,
658 [PWRAP_CSLEXT_END] = 0x20,
659 [PWRAP_STAUPD_PRD] = 0x24,
660 [PWRAP_STAUPD_GRPEN] = 0x28,
661 [PWRAP_STAUPD_MAN_TRIG] = 0x2c,
662 [PWRAP_STAUPD_STA] = 0x30,
663 [PWRAP_EVENT_IN_EN] = 0x34,
664 [PWRAP_EVENT_DST_EN] = 0x38,
665 [PWRAP_WRAP_STA] = 0x3c,
666 [PWRAP_RRARB_INIT] = 0x40,
667 [PWRAP_RRARB_EN] = 0x44,
668 [PWRAP_RRARB_STA0] = 0x48,
669 [PWRAP_RRARB_STA1] = 0x4c,
670 [PWRAP_HARB_INIT] = 0x50,
671 [PWRAP_HARB_HPRIO] = 0x54,
672 [PWRAP_HIPRIO_ARB_EN] = 0x58,
673 [PWRAP_HARB_STA0] = 0x5c,
674 [PWRAP_HARB_STA1] = 0x60,
675 [PWRAP_MAN_EN] = 0x64,
676 [PWRAP_MAN_CMD] = 0x68,
677 [PWRAP_MAN_RDATA] = 0x6c,
678 [PWRAP_MAN_VLDCLR] = 0x70,
679 [PWRAP_WACS0_EN] = 0x74,
680 [PWRAP_INIT_DONE0] = 0x78,
681 [PWRAP_WACS0_CMD] = 0x7c,
682 [PWRAP_WACS0_RDATA] = 0x80,
683 [PWRAP_WACS0_VLDCLR] = 0x84,
684 [PWRAP_WACS1_EN] = 0x88,
685 [PWRAP_INIT_DONE1] = 0x8c,
686 [PWRAP_WACS1_CMD] = 0x90,
687 [PWRAP_WACS1_RDATA] = 0x94,
688 [PWRAP_WACS1_VLDCLR] = 0x98,
689 [PWRAP_WACS2_EN] = 0x9c,
690 [PWRAP_INIT_DONE2] = 0xa0,
691 [PWRAP_WACS2_CMD] = 0xa4,
692 [PWRAP_WACS2_RDATA] = 0xa8,
693 [PWRAP_WACS2_VLDCLR] = 0xac,
694 [PWRAP_INT_EN] = 0xb0,
695 [PWRAP_INT_FLG_RAW] = 0xb4,
696 [PWRAP_INT_FLG] = 0xb8,
697 [PWRAP_INT_CLR] = 0xbc,
698 [PWRAP_SIG_ADR] = 0xc0,
699 [PWRAP_SIG_MODE] = 0xc4,
700 [PWRAP_SIG_VALUE] = 0xc8,
701 [PWRAP_SIG_ERRVAL] = 0xcc,
702 [PWRAP_CRC_EN] = 0xd0,
703 [PWRAP_EVENT_STA] = 0xd4,
704 [PWRAP_EVENT_STACLR] = 0xd8,
705 [PWRAP_TIMER_EN] = 0xdc,
706 [PWRAP_TIMER_STA] = 0xe0,
707 [PWRAP_WDT_UNIT] = 0xe4,
708 [PWRAP_WDT_SRC_EN] = 0xe8,
709 [PWRAP_WDT_FLG] = 0xec,
710 [PWRAP_DEBUG_INT_SEL] = 0xf0,
711 [PWRAP_CIPHER_KEY_SEL] = 0x134,
712 [PWRAP_CIPHER_IV_SEL] = 0x138,
713 [PWRAP_CIPHER_LOAD] = 0x13c,
714 [PWRAP_CIPHER_START] = 0x140,
715 [PWRAP_CIPHER_RDY] = 0x144,
716 [PWRAP_CIPHER_MODE] = 0x148,
717 [PWRAP_CIPHER_SWRST] = 0x14c,
718 [PWRAP_DCM_EN] = 0x15c,
719 [PWRAP_DCM_DBC_PRD] = 0x160,
720};
721
529static int mt8173_regs[] = { 722static int mt8173_regs[] = {
530 [PWRAP_MUX_SEL] = 0x0, 723 [PWRAP_MUX_SEL] = 0x0,
531 [PWRAP_WRAP_EN] = 0x4, 724 [PWRAP_WRAP_EN] = 0x4,
@@ -608,92 +801,74 @@ static int mt8173_regs[] = {
608 [PWRAP_DCM_DBC_PRD] = 0x148, 801 [PWRAP_DCM_DBC_PRD] = 0x148,
609}; 802};
610 803
611static int mt8135_regs[] = { 804static int mt8183_regs[] = {
612 [PWRAP_MUX_SEL] = 0x0, 805 [PWRAP_MUX_SEL] = 0x0,
613 [PWRAP_WRAP_EN] = 0x4, 806 [PWRAP_WRAP_EN] = 0x4,
614 [PWRAP_DIO_EN] = 0x8, 807 [PWRAP_DIO_EN] = 0x8,
615 [PWRAP_SIDLY] = 0xc, 808 [PWRAP_SI_SAMPLE_CTRL] = 0xC,
616 [PWRAP_CSHEXT] = 0x10, 809 [PWRAP_RDDMY] = 0x14,
617 [PWRAP_CSHEXT_WRITE] = 0x14, 810 [PWRAP_CSHEXT_WRITE] = 0x18,
618 [PWRAP_CSHEXT_READ] = 0x18, 811 [PWRAP_CSHEXT_READ] = 0x1C,
619 [PWRAP_CSLEXT_START] = 0x1c, 812 [PWRAP_CSLEXT_WRITE] = 0x20,
620 [PWRAP_CSLEXT_END] = 0x20, 813 [PWRAP_CSLEXT_READ] = 0x24,
621 [PWRAP_STAUPD_PRD] = 0x24, 814 [PWRAP_EXT_CK_WRITE] = 0x28,
622 [PWRAP_STAUPD_GRPEN] = 0x28, 815 [PWRAP_STAUPD_CTRL] = 0x30,
623 [PWRAP_STAUPD_MAN_TRIG] = 0x2c, 816 [PWRAP_STAUPD_GRPEN] = 0x34,
624 [PWRAP_STAUPD_STA] = 0x30, 817 [PWRAP_EINT_STA0_ADR] = 0x38,
625 [PWRAP_EVENT_IN_EN] = 0x34, 818 [PWRAP_HARB_HPRIO] = 0x5C,
626 [PWRAP_EVENT_DST_EN] = 0x38, 819 [PWRAP_HIPRIO_ARB_EN] = 0x60,
627 [PWRAP_WRAP_STA] = 0x3c, 820 [PWRAP_MAN_EN] = 0x70,
628 [PWRAP_RRARB_INIT] = 0x40, 821 [PWRAP_MAN_CMD] = 0x74,
629 [PWRAP_RRARB_EN] = 0x44, 822 [PWRAP_WACS0_EN] = 0x80,
630 [PWRAP_RRARB_STA0] = 0x48, 823 [PWRAP_INIT_DONE0] = 0x84,
631 [PWRAP_RRARB_STA1] = 0x4c, 824 [PWRAP_WACS1_EN] = 0x88,
632 [PWRAP_HARB_INIT] = 0x50, 825 [PWRAP_INIT_DONE1] = 0x8C,
633 [PWRAP_HARB_HPRIO] = 0x54, 826 [PWRAP_WACS2_EN] = 0x90,
634 [PWRAP_HIPRIO_ARB_EN] = 0x58, 827 [PWRAP_INIT_DONE2] = 0x94,
635 [PWRAP_HARB_STA0] = 0x5c, 828 [PWRAP_WACS_P2P_EN] = 0xA0,
636 [PWRAP_HARB_STA1] = 0x60, 829 [PWRAP_INIT_DONE_P2P] = 0xA4,
637 [PWRAP_MAN_EN] = 0x64, 830 [PWRAP_WACS_MD32_EN] = 0xA8,
638 [PWRAP_MAN_CMD] = 0x68, 831 [PWRAP_INIT_DONE_MD32] = 0xAC,
639 [PWRAP_MAN_RDATA] = 0x6c, 832 [PWRAP_INT_EN] = 0xB0,
640 [PWRAP_MAN_VLDCLR] = 0x70, 833 [PWRAP_INT_FLG] = 0xB8,
641 [PWRAP_WACS0_EN] = 0x74, 834 [PWRAP_INT_CLR] = 0xBC,
642 [PWRAP_INIT_DONE0] = 0x78, 835 [PWRAP_INT1_EN] = 0xC0,
643 [PWRAP_WACS0_CMD] = 0x7c, 836 [PWRAP_INT1_FLG] = 0xC8,
644 [PWRAP_WACS0_RDATA] = 0x80, 837 [PWRAP_INT1_CLR] = 0xCC,
645 [PWRAP_WACS0_VLDCLR] = 0x84, 838 [PWRAP_SIG_ADR] = 0xD0,
646 [PWRAP_WACS1_EN] = 0x88, 839 [PWRAP_CRC_EN] = 0xE0,
647 [PWRAP_INIT_DONE1] = 0x8c, 840 [PWRAP_TIMER_EN] = 0xE4,
648 [PWRAP_WACS1_CMD] = 0x90, 841 [PWRAP_WDT_UNIT] = 0xEC,
649 [PWRAP_WACS1_RDATA] = 0x94, 842 [PWRAP_WDT_SRC_EN] = 0xF0,
650 [PWRAP_WACS1_VLDCLR] = 0x98, 843 [PWRAP_WDT_SRC_EN_1] = 0xF4,
651 [PWRAP_WACS2_EN] = 0x9c, 844 [PWRAP_INT_GPS_AUXADC_CMD_ADDR] = 0x1DC,
652 [PWRAP_INIT_DONE2] = 0xa0, 845 [PWRAP_INT_GPS_AUXADC_CMD] = 0x1E0,
653 [PWRAP_WACS2_CMD] = 0xa4, 846 [PWRAP_INT_GPS_AUXADC_RDATA_ADDR] = 0x1E4,
654 [PWRAP_WACS2_RDATA] = 0xa8, 847 [PWRAP_EXT_GPS_AUXADC_RDATA_ADDR] = 0x1E8,
655 [PWRAP_WACS2_VLDCLR] = 0xac, 848 [PWRAP_GPSINF_0_STA] = 0x1EC,
656 [PWRAP_INT_EN] = 0xb0, 849 [PWRAP_GPSINF_1_STA] = 0x1F0,
657 [PWRAP_INT_FLG_RAW] = 0xb4, 850 [PWRAP_WACS2_CMD] = 0xC20,
658 [PWRAP_INT_FLG] = 0xb8, 851 [PWRAP_WACS2_RDATA] = 0xC24,
659 [PWRAP_INT_CLR] = 0xbc, 852 [PWRAP_WACS2_VLDCLR] = 0xC28,
660 [PWRAP_SIG_ADR] = 0xc0,
661 [PWRAP_SIG_MODE] = 0xc4,
662 [PWRAP_SIG_VALUE] = 0xc8,
663 [PWRAP_SIG_ERRVAL] = 0xcc,
664 [PWRAP_CRC_EN] = 0xd0,
665 [PWRAP_EVENT_STA] = 0xd4,
666 [PWRAP_EVENT_STACLR] = 0xd8,
667 [PWRAP_TIMER_EN] = 0xdc,
668 [PWRAP_TIMER_STA] = 0xe0,
669 [PWRAP_WDT_UNIT] = 0xe4,
670 [PWRAP_WDT_SRC_EN] = 0xe8,
671 [PWRAP_WDT_FLG] = 0xec,
672 [PWRAP_DEBUG_INT_SEL] = 0xf0,
673 [PWRAP_CIPHER_KEY_SEL] = 0x134,
674 [PWRAP_CIPHER_IV_SEL] = 0x138,
675 [PWRAP_CIPHER_LOAD] = 0x13c,
676 [PWRAP_CIPHER_START] = 0x140,
677 [PWRAP_CIPHER_RDY] = 0x144,
678 [PWRAP_CIPHER_MODE] = 0x148,
679 [PWRAP_CIPHER_SWRST] = 0x14c,
680 [PWRAP_DCM_EN] = 0x15c,
681 [PWRAP_DCM_DBC_PRD] = 0x160,
682}; 853};
683 854
684enum pmic_type { 855enum pmic_type {
685 PMIC_MT6323, 856 PMIC_MT6323,
686 PMIC_MT6351, 857 PMIC_MT6351,
858 PMIC_MT6357,
859 PMIC_MT6358,
687 PMIC_MT6380, 860 PMIC_MT6380,
688 PMIC_MT6397, 861 PMIC_MT6397,
689}; 862};
690 863
691enum pwrap_type { 864enum pwrap_type {
692 PWRAP_MT2701, 865 PWRAP_MT2701,
866 PWRAP_MT6765,
693 PWRAP_MT6797, 867 PWRAP_MT6797,
694 PWRAP_MT7622, 868 PWRAP_MT7622,
695 PWRAP_MT8135, 869 PWRAP_MT8135,
696 PWRAP_MT8173, 870 PWRAP_MT8173,
871 PWRAP_MT8183,
697}; 872};
698 873
699struct pmic_wrapper; 874struct pmic_wrapper;
@@ -731,9 +906,11 @@ struct pmic_wrapper_type {
731 enum pwrap_type type; 906 enum pwrap_type type;
732 u32 arb_en_all; 907 u32 arb_en_all;
733 u32 int_en_all; 908 u32 int_en_all;
909 u32 int1_en_all;
734 u32 spi_w; 910 u32 spi_w;
735 u32 wdt_src; 911 u32 wdt_src;
736 unsigned int has_bridge:1; 912 /* Flags indicating the capability for the target pwrap */
913 u32 caps;
737 int (*init_reg_clock)(struct pmic_wrapper *wrp); 914 int (*init_reg_clock)(struct pmic_wrapper *wrp);
738 int (*init_soc_specific)(struct pmic_wrapper *wrp); 915 int (*init_soc_specific)(struct pmic_wrapper *wrp);
739}; 916};
@@ -1096,7 +1273,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp)
1096 ret = pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_RDY], 1273 ret = pwrap_read(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_RDY],
1097 &rdata); 1274 &rdata);
1098 if (ret) 1275 if (ret)
1099 return 0; 1276 return false;
1100 1277
1101 return rdata == 1; 1278 return rdata == 1;
1102} 1279}
@@ -1117,6 +1294,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
1117 pwrap_writel(wrp, 1, PWRAP_CIPHER_START); 1294 pwrap_writel(wrp, 1, PWRAP_CIPHER_START);
1118 break; 1295 break;
1119 case PWRAP_MT2701: 1296 case PWRAP_MT2701:
1297 case PWRAP_MT6765:
1120 case PWRAP_MT6797: 1298 case PWRAP_MT6797:
1121 case PWRAP_MT8173: 1299 case PWRAP_MT8173:
1122 pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); 1300 pwrap_writel(wrp, 1, PWRAP_CIPHER_EN);
@@ -1124,6 +1302,8 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
1124 case PWRAP_MT7622: 1302 case PWRAP_MT7622:
1125 pwrap_writel(wrp, 0, PWRAP_CIPHER_EN); 1303 pwrap_writel(wrp, 0, PWRAP_CIPHER_EN);
1126 break; 1304 break;
1305 case PWRAP_MT8183:
1306 break;
1127 } 1307 }
1128 1308
1129 /* Config cipher mode @PMIC */ 1309 /* Config cipher mode @PMIC */
@@ -1141,6 +1321,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp)
1141 break; 1321 break;
1142 case PMIC_MT6323: 1322 case PMIC_MT6323:
1143 case PMIC_MT6351: 1323 case PMIC_MT6351:
1324 case PMIC_MT6357:
1144 pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN], 1325 pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN],
1145 0x1); 1326 0x1);
1146 break; 1327 break;
@@ -1276,6 +1457,23 @@ static int pwrap_mt7622_init_soc_specific(struct pmic_wrapper *wrp)
1276 return 0; 1457 return 0;
1277} 1458}
1278 1459
1460static int pwrap_mt8183_init_soc_specific(struct pmic_wrapper *wrp)
1461{
1462 pwrap_writel(wrp, 0xf5, PWRAP_STAUPD_GRPEN);
1463
1464 pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CRC_EN], 0x1);
1465 pwrap_writel(wrp, 1, PWRAP_CRC_EN);
1466 pwrap_writel(wrp, 0x416, PWRAP_SIG_ADR);
1467 pwrap_writel(wrp, 0x42e, PWRAP_EINT_STA0_ADR);
1468
1469 pwrap_writel(wrp, 1, PWRAP_WACS_P2P_EN);
1470 pwrap_writel(wrp, 1, PWRAP_WACS_MD32_EN);
1471 pwrap_writel(wrp, 1, PWRAP_INIT_DONE_P2P);
1472 pwrap_writel(wrp, 1, PWRAP_INIT_DONE_MD32);
1473
1474 return 0;
1475}
1476
1279static int pwrap_init(struct pmic_wrapper *wrp) 1477static int pwrap_init(struct pmic_wrapper *wrp)
1280{ 1478{
1281 int ret; 1479 int ret;
@@ -1348,7 +1546,7 @@ static int pwrap_init(struct pmic_wrapper *wrp)
1348 pwrap_writel(wrp, 1, PWRAP_INIT_DONE0); 1546 pwrap_writel(wrp, 1, PWRAP_INIT_DONE0);
1349 pwrap_writel(wrp, 1, PWRAP_INIT_DONE1); 1547 pwrap_writel(wrp, 1, PWRAP_INIT_DONE1);
1350 1548
1351 if (wrp->master->has_bridge) { 1549 if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
1352 writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3); 1550 writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE3);
1353 writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4); 1551 writel(1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INIT_DONE4);
1354 } 1552 }
@@ -1362,11 +1560,15 @@ static irqreturn_t pwrap_interrupt(int irqno, void *dev_id)
1362 struct pmic_wrapper *wrp = dev_id; 1560 struct pmic_wrapper *wrp = dev_id;
1363 1561
1364 rdata = pwrap_readl(wrp, PWRAP_INT_FLG); 1562 rdata = pwrap_readl(wrp, PWRAP_INT_FLG);
1365
1366 dev_err(wrp->dev, "unexpected interrupt int=0x%x\n", rdata); 1563 dev_err(wrp->dev, "unexpected interrupt int=0x%x\n", rdata);
1367
1368 pwrap_writel(wrp, 0xffffffff, PWRAP_INT_CLR); 1564 pwrap_writel(wrp, 0xffffffff, PWRAP_INT_CLR);
1369 1565
1566 if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN)) {
1567 rdata = pwrap_readl(wrp, PWRAP_INT1_FLG);
1568 dev_err(wrp->dev, "unexpected interrupt int1=0x%x\n", rdata);
1569 pwrap_writel(wrp, 0xffffffff, PWRAP_INT1_CLR);
1570 }
1571
1370 return IRQ_HANDLED; 1572 return IRQ_HANDLED;
1371} 1573}
1372 1574
@@ -1398,6 +1600,33 @@ static const struct pwrap_slv_type pmic_mt6323 = {
1398 .pwrap_write = pwrap_write16, 1600 .pwrap_write = pwrap_write16,
1399}; 1601};
1400 1602
1603static const struct pwrap_slv_type pmic_mt6351 = {
1604 .dew_regs = mt6351_regs,
1605 .type = PMIC_MT6351,
1606 .regmap = &pwrap_regmap_config16,
1607 .caps = 0,
1608 .pwrap_read = pwrap_read16,
1609 .pwrap_write = pwrap_write16,
1610};
1611
1612static const struct pwrap_slv_type pmic_mt6357 = {
1613 .dew_regs = mt6357_regs,
1614 .type = PMIC_MT6357,
1615 .regmap = &pwrap_regmap_config16,
1616 .caps = 0,
1617 .pwrap_read = pwrap_read16,
1618 .pwrap_write = pwrap_write16,
1619};
1620
1621static const struct pwrap_slv_type pmic_mt6358 = {
1622 .dew_regs = mt6358_regs,
1623 .type = PMIC_MT6358,
1624 .regmap = &pwrap_regmap_config16,
1625 .caps = PWRAP_SLV_CAP_SPI | PWRAP_SLV_CAP_DUALIO,
1626 .pwrap_read = pwrap_read16,
1627 .pwrap_write = pwrap_write16,
1628};
1629
1401static const struct pwrap_slv_type pmic_mt6380 = { 1630static const struct pwrap_slv_type pmic_mt6380 = {
1402 .dew_regs = NULL, 1631 .dew_regs = NULL,
1403 .type = PMIC_MT6380, 1632 .type = PMIC_MT6380,
@@ -1417,20 +1646,20 @@ static const struct pwrap_slv_type pmic_mt6397 = {
1417 .pwrap_write = pwrap_write16, 1646 .pwrap_write = pwrap_write16,
1418}; 1647};
1419 1648
1420static const struct pwrap_slv_type pmic_mt6351 = {
1421 .dew_regs = mt6351_regs,
1422 .type = PMIC_MT6351,
1423 .regmap = &pwrap_regmap_config16,
1424 .caps = 0,
1425 .pwrap_read = pwrap_read16,
1426 .pwrap_write = pwrap_write16,
1427};
1428
1429static const struct of_device_id of_slave_match_tbl[] = { 1649static const struct of_device_id of_slave_match_tbl[] = {
1430 { 1650 {
1431 .compatible = "mediatek,mt6323", 1651 .compatible = "mediatek,mt6323",
1432 .data = &pmic_mt6323, 1652 .data = &pmic_mt6323,
1433 }, { 1653 }, {
1654 .compatible = "mediatek,mt6351",
1655 .data = &pmic_mt6351,
1656 }, {
1657 .compatible = "mediatek,mt6357",
1658 .data = &pmic_mt6357,
1659 }, {
1660 .compatible = "mediatek,mt6358",
1661 .data = &pmic_mt6358,
1662 }, {
1434 /* The MT6380 PMIC only implements a regulator, so we bind it 1663 /* The MT6380 PMIC only implements a regulator, so we bind it
1435 * directly instead of using a MFD. 1664 * directly instead of using a MFD.
1436 */ 1665 */
@@ -1440,9 +1669,6 @@ static const struct of_device_id of_slave_match_tbl[] = {
1440 .compatible = "mediatek,mt6397", 1669 .compatible = "mediatek,mt6397",
1441 .data = &pmic_mt6397, 1670 .data = &pmic_mt6397,
1442 }, { 1671 }, {
1443 .compatible = "mediatek,mt6351",
1444 .data = &pmic_mt6351,
1445 }, {
1446 /* sentinel */ 1672 /* sentinel */
1447 } 1673 }
1448}; 1674};
@@ -1453,21 +1679,35 @@ static const struct pmic_wrapper_type pwrap_mt2701 = {
1453 .type = PWRAP_MT2701, 1679 .type = PWRAP_MT2701,
1454 .arb_en_all = 0x3f, 1680 .arb_en_all = 0x3f,
1455 .int_en_all = ~(u32)(BIT(31) | BIT(2)), 1681 .int_en_all = ~(u32)(BIT(31) | BIT(2)),
1682 .int1_en_all = 0,
1456 .spi_w = PWRAP_MAN_CMD_SPI_WRITE_NEW, 1683 .spi_w = PWRAP_MAN_CMD_SPI_WRITE_NEW,
1457 .wdt_src = PWRAP_WDT_SRC_MASK_ALL, 1684 .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
1458 .has_bridge = 0, 1685 .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
1459 .init_reg_clock = pwrap_mt2701_init_reg_clock, 1686 .init_reg_clock = pwrap_mt2701_init_reg_clock,
1460 .init_soc_specific = pwrap_mt2701_init_soc_specific, 1687 .init_soc_specific = pwrap_mt2701_init_soc_specific,
1461}; 1688};
1462 1689
1690static const struct pmic_wrapper_type pwrap_mt6765 = {
1691 .regs = mt6765_regs,
1692 .type = PWRAP_MT6765,
1693 .arb_en_all = 0x3fd35,
1694 .int_en_all = 0xffffffff,
1695 .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
1696 .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
1697 .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
1698 .init_reg_clock = pwrap_common_init_reg_clock,
1699 .init_soc_specific = NULL,
1700};
1701
1463static const struct pmic_wrapper_type pwrap_mt6797 = { 1702static const struct pmic_wrapper_type pwrap_mt6797 = {
1464 .regs = mt6797_regs, 1703 .regs = mt6797_regs,
1465 .type = PWRAP_MT6797, 1704 .type = PWRAP_MT6797,
1466 .arb_en_all = 0x01fff, 1705 .arb_en_all = 0x01fff,
1467 .int_en_all = 0xffffffc6, 1706 .int_en_all = 0xffffffc6,
1707 .int1_en_all = 0,
1468 .spi_w = PWRAP_MAN_CMD_SPI_WRITE, 1708 .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
1469 .wdt_src = PWRAP_WDT_SRC_MASK_ALL, 1709 .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
1470 .has_bridge = 0, 1710 .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
1471 .init_reg_clock = pwrap_common_init_reg_clock, 1711 .init_reg_clock = pwrap_common_init_reg_clock,
1472 .init_soc_specific = NULL, 1712 .init_soc_specific = NULL,
1473}; 1713};
@@ -1477,9 +1717,10 @@ static const struct pmic_wrapper_type pwrap_mt7622 = {
1477 .type = PWRAP_MT7622, 1717 .type = PWRAP_MT7622,
1478 .arb_en_all = 0xff, 1718 .arb_en_all = 0xff,
1479 .int_en_all = ~(u32)BIT(31), 1719 .int_en_all = ~(u32)BIT(31),
1720 .int1_en_all = 0,
1480 .spi_w = PWRAP_MAN_CMD_SPI_WRITE, 1721 .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
1481 .wdt_src = PWRAP_WDT_SRC_MASK_ALL, 1722 .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
1482 .has_bridge = 0, 1723 .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
1483 .init_reg_clock = pwrap_common_init_reg_clock, 1724 .init_reg_clock = pwrap_common_init_reg_clock,
1484 .init_soc_specific = pwrap_mt7622_init_soc_specific, 1725 .init_soc_specific = pwrap_mt7622_init_soc_specific,
1485}; 1726};
@@ -1489,9 +1730,10 @@ static const struct pmic_wrapper_type pwrap_mt8135 = {
1489 .type = PWRAP_MT8135, 1730 .type = PWRAP_MT8135,
1490 .arb_en_all = 0x1ff, 1731 .arb_en_all = 0x1ff,
1491 .int_en_all = ~(u32)(BIT(31) | BIT(1)), 1732 .int_en_all = ~(u32)(BIT(31) | BIT(1)),
1733 .int1_en_all = 0,
1492 .spi_w = PWRAP_MAN_CMD_SPI_WRITE, 1734 .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
1493 .wdt_src = PWRAP_WDT_SRC_MASK_ALL, 1735 .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
1494 .has_bridge = 1, 1736 .caps = PWRAP_CAP_BRIDGE | PWRAP_CAP_RESET | PWRAP_CAP_DCM,
1495 .init_reg_clock = pwrap_common_init_reg_clock, 1737 .init_reg_clock = pwrap_common_init_reg_clock,
1496 .init_soc_specific = pwrap_mt8135_init_soc_specific, 1738 .init_soc_specific = pwrap_mt8135_init_soc_specific,
1497}; 1739};
@@ -1501,18 +1743,35 @@ static const struct pmic_wrapper_type pwrap_mt8173 = {
1501 .type = PWRAP_MT8173, 1743 .type = PWRAP_MT8173,
1502 .arb_en_all = 0x3f, 1744 .arb_en_all = 0x3f,
1503 .int_en_all = ~(u32)(BIT(31) | BIT(1)), 1745 .int_en_all = ~(u32)(BIT(31) | BIT(1)),
1746 .int1_en_all = 0,
1504 .spi_w = PWRAP_MAN_CMD_SPI_WRITE, 1747 .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
1505 .wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD, 1748 .wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD,
1506 .has_bridge = 0, 1749 .caps = PWRAP_CAP_RESET | PWRAP_CAP_DCM,
1507 .init_reg_clock = pwrap_common_init_reg_clock, 1750 .init_reg_clock = pwrap_common_init_reg_clock,
1508 .init_soc_specific = pwrap_mt8173_init_soc_specific, 1751 .init_soc_specific = pwrap_mt8173_init_soc_specific,
1509}; 1752};
1510 1753
1754static const struct pmic_wrapper_type pwrap_mt8183 = {
1755 .regs = mt8183_regs,
1756 .type = PWRAP_MT8183,
1757 .arb_en_all = 0x3fa75,
1758 .int_en_all = 0xffffffff,
1759 .int1_en_all = 0xeef7ffff,
1760 .spi_w = PWRAP_MAN_CMD_SPI_WRITE,
1761 .wdt_src = PWRAP_WDT_SRC_MASK_ALL,
1762 .caps = PWRAP_CAP_INT1_EN | PWRAP_CAP_WDT_SRC1,
1763 .init_reg_clock = pwrap_common_init_reg_clock,
1764 .init_soc_specific = pwrap_mt8183_init_soc_specific,
1765};
1766
1511static const struct of_device_id of_pwrap_match_tbl[] = { 1767static const struct of_device_id of_pwrap_match_tbl[] = {
1512 { 1768 {
1513 .compatible = "mediatek,mt2701-pwrap", 1769 .compatible = "mediatek,mt2701-pwrap",
1514 .data = &pwrap_mt2701, 1770 .data = &pwrap_mt2701,
1515 }, { 1771 }, {
1772 .compatible = "mediatek,mt6765-pwrap",
1773 .data = &pwrap_mt6765,
1774 }, {
1516 .compatible = "mediatek,mt6797-pwrap", 1775 .compatible = "mediatek,mt6797-pwrap",
1517 .data = &pwrap_mt6797, 1776 .data = &pwrap_mt6797,
1518 }, { 1777 }, {
@@ -1525,6 +1784,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = {
1525 .compatible = "mediatek,mt8173-pwrap", 1784 .compatible = "mediatek,mt8173-pwrap",
1526 .data = &pwrap_mt8173, 1785 .data = &pwrap_mt8173,
1527 }, { 1786 }, {
1787 .compatible = "mediatek,mt8183-pwrap",
1788 .data = &pwrap_mt8183,
1789 }, {
1528 /* sentinel */ 1790 /* sentinel */
1529 } 1791 }
1530}; 1792};
@@ -1561,14 +1823,16 @@ static int pwrap_probe(struct platform_device *pdev)
1561 if (IS_ERR(wrp->base)) 1823 if (IS_ERR(wrp->base))
1562 return PTR_ERR(wrp->base); 1824 return PTR_ERR(wrp->base);
1563 1825
1564 wrp->rstc = devm_reset_control_get(wrp->dev, "pwrap"); 1826 if (HAS_CAP(wrp->master->caps, PWRAP_CAP_RESET)) {
1565 if (IS_ERR(wrp->rstc)) { 1827 wrp->rstc = devm_reset_control_get(wrp->dev, "pwrap");
1566 ret = PTR_ERR(wrp->rstc); 1828 if (IS_ERR(wrp->rstc)) {
1567 dev_dbg(wrp->dev, "cannot get pwrap reset: %d\n", ret); 1829 ret = PTR_ERR(wrp->rstc);
1568 return ret; 1830 dev_dbg(wrp->dev, "cannot get pwrap reset: %d\n", ret);
1831 return ret;
1832 }
1569 } 1833 }
1570 1834
1571 if (wrp->master->has_bridge) { 1835 if (HAS_CAP(wrp->master->caps, PWRAP_CAP_BRIDGE)) {
1572 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 1836 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
1573 "pwrap-bridge"); 1837 "pwrap-bridge");
1574 wrp->bridge_base = devm_ioremap_resource(wrp->dev, res); 1838 wrp->bridge_base = devm_ioremap_resource(wrp->dev, res);
@@ -1608,8 +1872,10 @@ static int pwrap_probe(struct platform_device *pdev)
1608 goto err_out1; 1872 goto err_out1;
1609 1873
1610 /* Enable internal dynamic clock */ 1874 /* Enable internal dynamic clock */
1611 pwrap_writel(wrp, 1, PWRAP_DCM_EN); 1875 if (HAS_CAP(wrp->master->caps, PWRAP_CAP_DCM)) {
1612 pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD); 1876 pwrap_writel(wrp, 1, PWRAP_DCM_EN);
1877 pwrap_writel(wrp, 0, PWRAP_DCM_DBC_PRD);
1878 }
1613 1879
1614 /* 1880 /*
1615 * The PMIC could already be initialized by the bootloader. 1881 * The PMIC could already be initialized by the bootloader.
@@ -1636,8 +1902,17 @@ static int pwrap_probe(struct platform_device *pdev)
1636 * so STAUPD of WDT_SRC which should be turned off 1902 * so STAUPD of WDT_SRC which should be turned off
1637 */ 1903 */
1638 pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN); 1904 pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN);
1905 if (HAS_CAP(wrp->master->caps, PWRAP_CAP_WDT_SRC1))
1906 pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN_1);
1907
1639 pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); 1908 pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN);
1640 pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN); 1909 pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN);
1910 /*
1911 * We add INT1 interrupt to handle starvation and request exception
1912 * If we support it, we should enable it here.
1913 */
1914 if (HAS_CAP(wrp->master->caps, PWRAP_CAP_INT1_EN))
1915 pwrap_writel(wrp, wrp->master->int1_en_all, PWRAP_INT1_EN);
1641 1916
1642 irq = platform_get_irq(pdev, 0); 1917 irq = platform_get_irq(pdev, 0);
1643 ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, 1918 ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt,
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig
index 41986d96f24b..684cb51694d1 100644
--- a/drivers/soc/qcom/Kconfig
+++ b/drivers/soc/qcom/Kconfig
@@ -33,7 +33,7 @@ config QCOM_GLINK_SSR
33 33
34config QCOM_GSBI 34config QCOM_GSBI
35 tristate "QCOM General Serial Bus Interface" 35 tristate "QCOM General Serial Bus Interface"
36 depends on ARCH_QCOM 36 depends on ARCH_QCOM || COMPILE_TEST
37 select MFD_SYSCON 37 select MFD_SYSCON
38 help 38 help
39 Say y here to enable GSBI support. The GSBI provides control 39 Say y here to enable GSBI support. The GSBI provides control
@@ -42,7 +42,7 @@ config QCOM_GSBI
42 42
43config QCOM_LLCC 43config QCOM_LLCC
44 tristate "Qualcomm Technologies, Inc. LLCC driver" 44 tristate "Qualcomm Technologies, Inc. LLCC driver"
45 depends on ARCH_QCOM 45 depends on ARCH_QCOM || COMPILE_TEST
46 help 46 help
47 Qualcomm Technologies, Inc. platform specific 47 Qualcomm Technologies, Inc. platform specific
48 Last Level Cache Controller(LLCC) driver. This provides interfaces 48 Last Level Cache Controller(LLCC) driver. This provides interfaces
@@ -73,7 +73,8 @@ config QCOM_PM
73 73
74config QCOM_QMI_HELPERS 74config QCOM_QMI_HELPERS
75 tristate 75 tristate
76 depends on (ARCH_QCOM || COMPILE_TEST) && NET 76 depends on ARCH_QCOM || COMPILE_TEST
77 depends on NET
77 help 78 help
78 Helper library for handling QMI encoded messages. QMI encoded 79 Helper library for handling QMI encoded messages. QMI encoded
79 messages are used in communication between the majority of QRTR 80 messages are used in communication between the majority of QRTR
@@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM
94 95
95config QCOM_RPMH 96config QCOM_RPMH
96 bool "Qualcomm RPM-Hardened (RPMH) Communication" 97 bool "Qualcomm RPM-Hardened (RPMH) Communication"
97 depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST 98 depends on ARCH_QCOM && ARM64 || COMPILE_TEST
98 help 99 help
99 Support for communication with the hardened-RPM blocks in 100 Support for communication with the hardened-RPM blocks in
100 Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an 101 Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
@@ -104,7 +105,7 @@ config QCOM_RPMH
104 105
105config QCOM_SMEM 106config QCOM_SMEM
106 tristate "Qualcomm Shared Memory Manager (SMEM)" 107 tristate "Qualcomm Shared Memory Manager (SMEM)"
107 depends on ARCH_QCOM 108 depends on ARCH_QCOM || COMPILE_TEST
108 depends on HWSPINLOCK 109 depends on HWSPINLOCK
109 help 110 help
110 Say y here to enable support for the Qualcomm Shared Memory Manager. 111 Say y here to enable support for the Qualcomm Shared Memory Manager.
@@ -113,8 +114,8 @@ config QCOM_SMEM
113 114
114config QCOM_SMD_RPM 115config QCOM_SMD_RPM
115 tristate "Qualcomm Resource Power Manager (RPM) over SMD" 116 tristate "Qualcomm Resource Power Manager (RPM) over SMD"
116 depends on ARCH_QCOM 117 depends on ARCH_QCOM || COMPILE_TEST
117 depends on RPMSG && OF 118 depends on RPMSG
118 help 119 help
119 If you say yes to this option, support will be included for the 120 If you say yes to this option, support will be included for the
120 Resource Power Manager system found in the Qualcomm 8974 based 121 Resource Power Manager system found in the Qualcomm 8974 based
@@ -134,6 +135,7 @@ config QCOM_SMP2P
134 depends on MAILBOX 135 depends on MAILBOX
135 depends on QCOM_SMEM 136 depends on QCOM_SMEM
136 select QCOM_SMEM_STATE 137 select QCOM_SMEM_STATE
138 select IRQ_DOMAIN
137 help 139 help
138 Say yes here to support the Qualcomm Shared Memory Point to Point 140 Say yes here to support the Qualcomm Shared Memory Point to Point
139 protocol. 141 protocol.
@@ -142,13 +144,14 @@ config QCOM_SMSM
142 tristate "Qualcomm Shared Memory State Machine" 144 tristate "Qualcomm Shared Memory State Machine"
143 depends on QCOM_SMEM 145 depends on QCOM_SMEM
144 select QCOM_SMEM_STATE 146 select QCOM_SMEM_STATE
147 select IRQ_DOMAIN
145 help 148 help
146 Say yes here to support the Qualcomm Shared Memory State Machine. 149 Say yes here to support the Qualcomm Shared Memory State Machine.
147 The state machine is represented by bits in shared memory. 150 The state machine is represented by bits in shared memory.
148 151
149config QCOM_WCNSS_CTRL 152config QCOM_WCNSS_CTRL
150 tristate "Qualcomm WCNSS control driver" 153 tristate "Qualcomm WCNSS control driver"
151 depends on ARCH_QCOM 154 depends on ARCH_QCOM || COMPILE_TEST
152 depends on RPMSG 155 depends on RPMSG
153 help 156 help
154 Client driver for the WCNSS_CTRL SMD channel, used to download nv 157 Client driver for the WCNSS_CTRL SMD channel, used to download nv
@@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL
156 159
157config QCOM_APR 160config QCOM_APR
158 tristate "Qualcomm APR Bus (Asynchronous Packet Router)" 161 tristate "Qualcomm APR Bus (Asynchronous Packet Router)"
159 depends on ARCH_QCOM 162 depends on ARCH_QCOM || COMPILE_TEST
160 depends on RPMSG 163 depends on RPMSG
161 help 164 help
162 Enable APR IPC protocol support between 165 Enable APR IPC protocol support between
diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c
index 4bda793ba6ae..74f8b9607daa 100644
--- a/drivers/soc/qcom/apr.c
+++ b/drivers/soc/qcom/apr.c
@@ -87,7 +87,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
87 } 87 }
88 88
89 if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) { 89 if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) {
90 dev_err(apr->dev, "APR: Wrong paket size\n"); 90 dev_err(apr->dev, "APR: Wrong packet size\n");
91 return -EINVAL; 91 return -EINVAL;
92 } 92 }
93 93
@@ -221,7 +221,7 @@ static int apr_add_device(struct device *dev, struct device_node *np,
221 if (np) 221 if (np)
222 snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np); 222 snprintf(adev->name, APR_NAME_SIZE, "%pOFn", np);
223 else 223 else
224 strncpy(adev->name, id->name, APR_NAME_SIZE); 224 strscpy(adev->name, id->name, APR_NAME_SIZE);
225 225
226 dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, 226 dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
227 id->domain_id, id->svc_id); 227 id->domain_id, id->svc_id);
diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c
index 54063a31132f..192ca761b2cb 100644
--- a/drivers/soc/qcom/llcc-slice.c
+++ b/drivers/soc/qcom/llcc-slice.c
@@ -13,6 +13,7 @@
13#include <linux/mutex.h> 13#include <linux/mutex.h>
14#include <linux/of_device.h> 14#include <linux/of_device.h>
15#include <linux/regmap.h> 15#include <linux/regmap.h>
16#include <linux/sizes.h>
16#include <linux/slab.h> 17#include <linux/slab.h>
17#include <linux/soc/qcom/llcc-qcom.h> 18#include <linux/soc/qcom/llcc-qcom.h>
18 19
@@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid,
106 u32 slice_status; 107 u32 slice_status;
107 int ret; 108 int ret;
108 109
109 act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid); 110 act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
110 status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid); 111 status_reg = LLCC_TRP_STATUSn(sid);
111 112
112 /* Set the ACTIVE trigger */ 113 /* Set the ACTIVE trigger */
113 act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; 114 act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
114 ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 115 ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
116 act_ctrl_reg_val);
115 if (ret) 117 if (ret)
116 return ret; 118 return ret;
117 119
118 /* Clear the ACTIVE trigger */ 120 /* Clear the ACTIVE trigger */
119 act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; 121 act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
120 ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); 122 ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
123 act_ctrl_reg_val);
121 if (ret) 124 if (ret)
122 return ret; 125 return ret;
123 126
124 ret = regmap_read_poll_timeout(drv_data->regmap, status_reg, 127 ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
125 slice_status, !(slice_status & status), 128 slice_status, !(slice_status & status),
126 0, LLCC_STATUS_READ_DELAY); 129 0, LLCC_STATUS_READ_DELAY);
127 return ret; 130 return ret;
@@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
223 u32 attr0_val; 226 u32 attr0_val;
224 u32 max_cap_cacheline; 227 u32 max_cap_cacheline;
225 u32 sz; 228 u32 sz;
226 int ret; 229 int ret = 0;
227 const struct llcc_slice_config *llcc_table; 230 const struct llcc_slice_config *llcc_table;
228 struct llcc_slice_desc desc; 231 struct llcc_slice_desc desc;
229 u32 bcast_off = drv_data->bcast_off;
230 232
231 sz = drv_data->cfg_size; 233 sz = drv_data->cfg_size;
232 llcc_table = drv_data->cfg; 234 llcc_table = drv_data->cfg;
233 235
234 for (i = 0; i < sz; i++) { 236 for (i = 0; i < sz; i++) {
235 attr1_cfg = bcast_off + 237 attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
236 LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); 238 attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
237 attr0_cfg = bcast_off +
238 LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
239 239
240 attr1_val = llcc_table[i].cache_mode; 240 attr1_val = llcc_table[i].cache_mode;
241 attr1_val |= llcc_table[i].probe_target_ways << 241 attr1_val |= llcc_table[i].probe_target_ways <<
@@ -260,10 +260,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
260 attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK; 260 attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
261 attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT; 261 attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
262 262
263 ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val); 263 ret = regmap_write(drv_data->bcast_regmap, attr1_cfg,
264 attr1_val);
264 if (ret) 265 if (ret)
265 return ret; 266 return ret;
266 ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val); 267 ret = regmap_write(drv_data->bcast_regmap, attr0_cfg,
268 attr0_val);
267 if (ret) 269 if (ret)
268 return ret; 270 return ret;
269 if (llcc_table[i].activate_on_init) { 271 if (llcc_table[i].activate_on_init) {
@@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev,
279{ 281{
280 u32 num_banks; 282 u32 num_banks;
281 struct device *dev = &pdev->dev; 283 struct device *dev = &pdev->dev;
282 struct resource *res; 284 struct resource *llcc_banks_res, *llcc_bcast_res;
283 void __iomem *base; 285 void __iomem *llcc_banks_base, *llcc_bcast_base;
284 int ret, i; 286 int ret, i;
287 struct platform_device *llcc_edac;
285 288
286 drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); 289 drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
287 if (!drv_data) 290 if (!drv_data)
288 return -ENOMEM; 291 return -ENOMEM;
289 292
290 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 293 llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
291 base = devm_ioremap_resource(&pdev->dev, res); 294 "llcc_base");
292 if (IS_ERR(base)) 295 llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res);
293 return PTR_ERR(base); 296 if (IS_ERR(llcc_banks_base))
297 return PTR_ERR(llcc_banks_base);
294 298
295 drv_data->regmap = devm_regmap_init_mmio(dev, base, 299 drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base,
296 &llcc_regmap_config); 300 &llcc_regmap_config);
297 if (IS_ERR(drv_data->regmap)) 301 if (IS_ERR(drv_data->regmap))
298 return PTR_ERR(drv_data->regmap); 302 return PTR_ERR(drv_data->regmap);
299 303
304 llcc_bcast_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
305 "llcc_broadcast_base");
306 llcc_bcast_base = devm_ioremap_resource(&pdev->dev, llcc_bcast_res);
307 if (IS_ERR(llcc_bcast_base))
308 return PTR_ERR(llcc_bcast_base);
309
310 drv_data->bcast_regmap = devm_regmap_init_mmio(dev, llcc_bcast_base,
311 &llcc_regmap_config);
312 if (IS_ERR(drv_data->bcast_regmap))
313 return PTR_ERR(drv_data->bcast_regmap);
314
300 ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, 315 ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
301 &num_banks); 316 &num_banks);
302 if (ret) 317 if (ret)
@@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev,
318 for (i = 0; i < num_banks; i++) 333 for (i = 0; i < num_banks; i++)
319 drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; 334 drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
320 335
321 drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE;
322
323 drv_data->bitmap = devm_kcalloc(dev, 336 drv_data->bitmap = devm_kcalloc(dev,
324 BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), 337 BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
325 GFP_KERNEL); 338 GFP_KERNEL);
@@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev,
331 mutex_init(&drv_data->lock); 344 mutex_init(&drv_data->lock);
332 platform_set_drvdata(pdev, drv_data); 345 platform_set_drvdata(pdev, drv_data);
333 346
334 return qcom_llcc_cfg_program(pdev); 347 ret = qcom_llcc_cfg_program(pdev);
348 if (ret)
349 return ret;
350
351 drv_data->ecc_irq = platform_get_irq(pdev, 0);
352 if (drv_data->ecc_irq >= 0) {
353 llcc_edac = platform_device_register_data(&pdev->dev,
354 "qcom_llcc_edac", -1, drv_data,
355 sizeof(*drv_data));
356 if (IS_ERR(llcc_edac))
357 dev_err(dev, "Failed to register llcc edac driver\n");
358 }
359
360 return ret;
335} 361}
336EXPORT_SYMBOL_GPL(qcom_llcc_probe); 362EXPORT_SYMBOL_GPL(qcom_llcc_probe);
337 363
diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c
index 8a3678c2e83c..97bb5989aa21 100644
--- a/drivers/soc/qcom/rmtfs_mem.c
+++ b/drivers/soc/qcom/rmtfs_mem.c
@@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
212 dev_err(&pdev->dev, "failed to parse qcom,vmid\n"); 212 dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
213 goto remove_cdev; 213 goto remove_cdev;
214 } else if (!ret) { 214 } else if (!ret) {
215 if (!qcom_scm_is_available()) {
216 ret = -EPROBE_DEFER;
217 goto remove_cdev;
218 }
219
215 perms[0].vmid = QCOM_SCM_VMID_HLOS; 220 perms[0].vmid = QCOM_SCM_VMID_HLOS;
216 perms[0].perm = QCOM_SCM_PERM_RW; 221 perms[0].perm = QCOM_SCM_PERM_RW;
217 perms[1].vmid = vmid; 222 perms[1].vmid = vmid;
diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c
index ee75da66d64b..75bd9a83aef0 100644
--- a/drivers/soc/qcom/rpmh-rsc.c
+++ b/drivers/soc/qcom/rpmh-rsc.c
@@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type)
121 return -EAGAIN; 121 return -EAGAIN;
122 } 122 }
123 write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0); 123 write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
124 write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
124 } 125 }
125 bitmap_zero(tcs->slots, MAX_TCS_SLOTS); 126 bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
126 spin_unlock(&tcs->lock); 127 spin_unlock(&tcs->lock);
@@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
239skip: 240skip:
240 /* Reclaim the TCS */ 241 /* Reclaim the TCS */
241 write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0); 242 write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
243 write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
242 write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i)); 244 write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
243 spin_lock(&drv->lock); 245 spin_lock(&drv->lock);
244 clear_bit(i, drv->tcs_in_use); 246 clear_bit(i, drv->tcs_in_use);
diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c
index bf4bd71ab53f..f80d040601fd 100644
--- a/drivers/soc/qcom/smem.c
+++ b/drivers/soc/qcom/smem.c
@@ -18,6 +18,7 @@
18#include <linux/of.h> 18#include <linux/of.h>
19#include <linux/of_address.h> 19#include <linux/of_address.h>
20#include <linux/platform_device.h> 20#include <linux/platform_device.h>
21#include <linux/sizes.h>
21#include <linux/slab.h> 22#include <linux/slab.h>
22#include <linux/soc/qcom/smem.h> 23#include <linux/soc/qcom/smem.h>
23 24
@@ -277,7 +278,7 @@ struct qcom_smem {
277 u32 item_count; 278 u32 item_count;
278 279
279 unsigned num_regions; 280 unsigned num_regions;
280 struct smem_region regions[0]; 281 struct smem_region regions[];
281}; 282};
282 283
283static void * 284static void *
@@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
489 size_t *size) 490 size_t *size)
490{ 491{
491 struct smem_header *header; 492 struct smem_header *header;
492 struct smem_region *area; 493 struct smem_region *region;
493 struct smem_global_entry *entry; 494 struct smem_global_entry *entry;
494 u32 aux_base; 495 u32 aux_base;
495 unsigned i; 496 unsigned i;
@@ -502,12 +503,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
502 aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK; 503 aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
503 504
504 for (i = 0; i < smem->num_regions; i++) { 505 for (i = 0; i < smem->num_regions; i++) {
505 area = &smem->regions[i]; 506 region = &smem->regions[i];
506 507
507 if (area->aux_base == aux_base || !aux_base) { 508 if (region->aux_base == aux_base || !aux_base) {
508 if (size != NULL) 509 if (size != NULL)
509 *size = le32_to_cpu(entry->size); 510 *size = le32_to_cpu(entry->size);
510 return area->virt_base + le32_to_cpu(entry->offset); 511 return region->virt_base + le32_to_cpu(entry->offset);
511 } 512 }
512 } 513 }
513 514
@@ -722,12 +723,59 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
722 return le16_to_cpu(info->num_items); 723 return le16_to_cpu(info->num_items);
723} 724}
724 725
726/*
727 * Validate the partition header for a partition whose partition
728 * table entry is supplied. Returns a pointer to its header if
729 * valid, or a null pointer otherwise.
730 */
731static struct smem_partition_header *
732qcom_smem_partition_header(struct qcom_smem *smem,
733 struct smem_ptable_entry *entry, u16 host0, u16 host1)
734{
735 struct smem_partition_header *header;
736 u32 size;
737
738 header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
739
740 if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
741 dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n",
742 header->magic[0], header->magic[1],
743 header->magic[2], header->magic[3]);
744 return NULL;
745 }
746
747 if (host0 != le16_to_cpu(header->host0)) {
748 dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
749 host0, le16_to_cpu(header->host0));
750 return NULL;
751 }
752 if (host1 != le16_to_cpu(header->host1)) {
753 dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
754 host1, le16_to_cpu(header->host1));
755 return NULL;
756 }
757
758 size = le32_to_cpu(header->size);
759 if (size != le32_to_cpu(entry->size)) {
760 dev_err(smem->dev, "bad partition size (%u != %u)\n",
761 size, le32_to_cpu(entry->size));
762 return NULL;
763 }
764
765 if (le32_to_cpu(header->offset_free_uncached) > size) {
766 dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
767 le32_to_cpu(header->offset_free_uncached), size);
768 return NULL;
769 }
770
771 return header;
772}
773
725static int qcom_smem_set_global_partition(struct qcom_smem *smem) 774static int qcom_smem_set_global_partition(struct qcom_smem *smem)
726{ 775{
727 struct smem_partition_header *header; 776 struct smem_partition_header *header;
728 struct smem_ptable_entry *entry; 777 struct smem_ptable_entry *entry;
729 struct smem_ptable *ptable; 778 struct smem_ptable *ptable;
730 u32 host0, host1, size;
731 bool found = false; 779 bool found = false;
732 int i; 780 int i;
733 781
@@ -742,10 +790,15 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
742 790
743 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { 791 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
744 entry = &ptable->entry[i]; 792 entry = &ptable->entry[i];
745 host0 = le16_to_cpu(entry->host0); 793 if (!le32_to_cpu(entry->offset))
746 host1 = le16_to_cpu(entry->host1); 794 continue;
795 if (!le32_to_cpu(entry->size))
796 continue;
797
798 if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
799 continue;
747 800
748 if (host0 == SMEM_GLOBAL_HOST && host0 == host1) { 801 if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
749 found = true; 802 found = true;
750 break; 803 break;
751 } 804 }
@@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
756 return -EINVAL; 809 return -EINVAL;
757 } 810 }
758 811
759 if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) { 812 header = qcom_smem_partition_header(smem, entry,
760 dev_err(smem->dev, "Invalid entry for global partition\n"); 813 SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
814 if (!header)
761 return -EINVAL; 815 return -EINVAL;
762 }
763
764 header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
765 host0 = le16_to_cpu(header->host0);
766 host1 = le16_to_cpu(header->host1);
767
768 if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
769 dev_err(smem->dev, "Global partition has invalid magic\n");
770 return -EINVAL;
771 }
772
773 if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) {
774 dev_err(smem->dev, "Global partition hosts are invalid\n");
775 return -EINVAL;
776 }
777
778 if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
779 dev_err(smem->dev, "Global partition has invalid size\n");
780 return -EINVAL;
781 }
782
783 size = le32_to_cpu(header->offset_free_uncached);
784 if (size > le32_to_cpu(header->size)) {
785 dev_err(smem->dev,
786 "Global partition has invalid free pointer\n");
787 return -EINVAL;
788 }
789 816
790 smem->global_partition = header; 817 smem->global_partition = header;
791 smem->global_cacheline = le32_to_cpu(entry->cacheline); 818 smem->global_cacheline = le32_to_cpu(entry->cacheline);
@@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
793 return 0; 820 return 0;
794} 821}
795 822
796static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, 823static int
797 unsigned int local_host) 824qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
798{ 825{
799 struct smem_partition_header *header; 826 struct smem_partition_header *header;
800 struct smem_ptable_entry *entry; 827 struct smem_ptable_entry *entry;
801 struct smem_ptable *ptable; 828 struct smem_ptable *ptable;
802 unsigned int remote_host; 829 unsigned int remote_host;
803 u32 host0, host1; 830 u16 host0, host1;
804 int i; 831 int i;
805 832
806 ptable = qcom_smem_get_ptable(smem); 833 ptable = qcom_smem_get_ptable(smem);
@@ -809,71 +836,33 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
809 836
810 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { 837 for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
811 entry = &ptable->entry[i]; 838 entry = &ptable->entry[i];
812 host0 = le16_to_cpu(entry->host0);
813 host1 = le16_to_cpu(entry->host1);
814
815 if (host0 != local_host && host1 != local_host)
816 continue;
817
818 if (!le32_to_cpu(entry->offset)) 839 if (!le32_to_cpu(entry->offset))
819 continue; 840 continue;
820
821 if (!le32_to_cpu(entry->size)) 841 if (!le32_to_cpu(entry->size))
822 continue; 842 continue;
823 843
844 host0 = le16_to_cpu(entry->host0);
845 host1 = le16_to_cpu(entry->host1);
824 if (host0 == local_host) 846 if (host0 == local_host)
825 remote_host = host1; 847 remote_host = host1;
826 else 848 else if (host1 == local_host)
827 remote_host = host0; 849 remote_host = host0;
850 else
851 continue;
828 852
829 if (remote_host >= SMEM_HOST_COUNT) { 853 if (remote_host >= SMEM_HOST_COUNT) {
830 dev_err(smem->dev, 854 dev_err(smem->dev, "bad host %hu\n", remote_host);
831 "Invalid remote host %d\n",
832 remote_host);
833 return -EINVAL; 855 return -EINVAL;
834 } 856 }
835 857
836 if (smem->partitions[remote_host]) { 858 if (smem->partitions[remote_host]) {
837 dev_err(smem->dev, 859 dev_err(smem->dev, "duplicate host %hu\n", remote_host);
838 "Already found a partition for host %d\n",
839 remote_host);
840 return -EINVAL;
841 }
842
843 header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
844 host0 = le16_to_cpu(header->host0);
845 host1 = le16_to_cpu(header->host1);
846
847 if (memcmp(header->magic, SMEM_PART_MAGIC,
848 sizeof(header->magic))) {
849 dev_err(smem->dev,
850 "Partition %d has invalid magic\n", i);
851 return -EINVAL; 860 return -EINVAL;
852 } 861 }
853 862
854 if (host0 != local_host && host1 != local_host) { 863 header = qcom_smem_partition_header(smem, entry, host0, host1);
855 dev_err(smem->dev, 864 if (!header)
856 "Partition %d hosts are invalid\n", i);
857 return -EINVAL; 865 return -EINVAL;
858 }
859
860 if (host0 != remote_host && host1 != remote_host) {
861 dev_err(smem->dev,
862 "Partition %d hosts are invalid\n", i);
863 return -EINVAL;
864 }
865
866 if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
867 dev_err(smem->dev,
868 "Partition %d has invalid size\n", i);
869 return -EINVAL;
870 }
871
872 if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) {
873 dev_err(smem->dev,
874 "Partition %d has invalid free pointer\n", i);
875 return -EINVAL;
876 }
877 866
878 smem->partitions[remote_host] = header; 867 smem->partitions[remote_host] = header;
879 smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); 868 smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline);
@@ -887,6 +876,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
887{ 876{
888 struct device_node *np; 877 struct device_node *np;
889 struct resource r; 878 struct resource r;
879 resource_size_t size;
890 int ret; 880 int ret;
891 881
892 np = of_parse_phandle(dev->of_node, name, 0); 882 np = of_parse_phandle(dev->of_node, name, 0);
@@ -899,12 +889,13 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
899 of_node_put(np); 889 of_node_put(np);
900 if (ret) 890 if (ret)
901 return ret; 891 return ret;
892 size = resource_size(&r);
902 893
903 smem->regions[i].aux_base = (u32)r.start; 894 smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
904 smem->regions[i].size = resource_size(&r);
905 smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
906 if (!smem->regions[i].virt_base) 895 if (!smem->regions[i].virt_base)
907 return -ENOMEM; 896 return -ENOMEM;
897 smem->regions[i].aux_base = (u32)r.start;
898 smem->regions[i].size = size;
908 899
909 return 0; 900 return 0;
910} 901}
@@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
962 return -EINVAL; 953 return -EINVAL;
963 } 954 }
964 955
956 BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
965 ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); 957 ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
966 if (ret < 0 && ret != -ENOENT) 958 if (ret < 0 && ret != -ENOENT)
967 return ret; 959 return ret;
diff --git a/drivers/soc/qcom/spm.c b/drivers/soc/qcom/spm.c
index f9d7a85b2822..53807e839664 100644
--- a/drivers/soc/qcom/spm.c
+++ b/drivers/soc/qcom/spm.c
@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
219 cpumask_t mask; 219 cpumask_t mask;
220 bool use_scm_power_down = false; 220 bool use_scm_power_down = false;
221 221
222 if (!qcom_scm_is_available())
223 return -EPROBE_DEFER;
224
222 for (i = 0; ; i++) { 225 for (i = 0; ; i++) {
223 state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); 226 state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
224 if (!state_node) 227 if (!state_node)
diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c
index df3ccb30bc2d..373400dd816d 100644
--- a/drivers/soc/qcom/wcnss_ctrl.c
+++ b/drivers/soc/qcom/wcnss_ctrl.c
@@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
281 struct rpmsg_channel_info chinfo; 281 struct rpmsg_channel_info chinfo;
282 struct wcnss_ctrl *_wcnss = wcnss; 282 struct wcnss_ctrl *_wcnss = wcnss;
283 283
284 strncpy(chinfo.name, name, sizeof(chinfo.name)); 284 strscpy(chinfo.name, name, sizeof(chinfo.name));
285 chinfo.src = RPMSG_ADDR_ANY; 285 chinfo.src = RPMSG_ADDR_ANY;
286 chinfo.dst = RPMSG_ADDR_ANY; 286 chinfo.dst = RPMSG_ADDR_ANY;
287 287
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
index 1d824cbd462d..407f02c80e8b 100644
--- a/drivers/soc/renesas/Kconfig
+++ b/drivers/soc/renesas/Kconfig
@@ -1,14 +1,17 @@
1# SPDX-License-Identifier: GPL-2.0
1config SOC_RENESAS 2config SOC_RENESAS
2 bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS 3 bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
3 default y if ARCH_RENESAS 4 default y if ARCH_RENESAS
4 select SOC_BUS 5 select SOC_BUS
5 select RST_RCAR if ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || \ 6 select RST_RCAR if ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || \
6 ARCH_R8A7795 || ARCH_R8A7796 || ARCH_R8A77965 || \ 7 ARCH_R8A774A1 || ARCH_R8A774C0 || ARCH_R8A7795 || \
7 ARCH_R8A77970 || ARCH_R8A77980 || ARCH_R8A77990 || \ 8 ARCH_R8A7796 || ARCH_R8A77965 || ARCH_R8A77970 || \
8 ARCH_R8A77995 9 ARCH_R8A77980 || ARCH_R8A77990 || ARCH_R8A77995
9 select SYSC_R8A7743 if ARCH_R8A7743 10 select SYSC_R8A7743 if ARCH_R8A7743 || ARCH_R8A7744
10 select SYSC_R8A7745 if ARCH_R8A7745 11 select SYSC_R8A7745 if ARCH_R8A7745
11 select SYSC_R8A77470 if ARCH_R8A77470 12 select SYSC_R8A77470 if ARCH_R8A77470
13 select SYSC_R8A774A1 if ARCH_R8A774A1
14 select SYSC_R8A774C0 if ARCH_R8A774C0
12 select SYSC_R8A7779 if ARCH_R8A7779 15 select SYSC_R8A7779 if ARCH_R8A7779
13 select SYSC_R8A7790 if ARCH_R8A7790 16 select SYSC_R8A7790 if ARCH_R8A7790
14 select SYSC_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793 17 select SYSC_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793
@@ -37,6 +40,14 @@ config SYSC_R8A77470
37 bool "RZ/G1C System Controller support" if COMPILE_TEST 40 bool "RZ/G1C System Controller support" if COMPILE_TEST
38 select SYSC_RCAR 41 select SYSC_RCAR
39 42
43config SYSC_R8A774A1
44 bool "RZ/G2M System Controller support" if COMPILE_TEST
45 select SYSC_RCAR
46
47config SYSC_R8A774C0
48 bool "RZ/G2E System Controller support" if COMPILE_TEST
49 select SYSC_RCAR
50
40config SYSC_R8A7779 51config SYSC_R8A7779
41 bool "R-Car H1 System Controller support" if COMPILE_TEST 52 bool "R-Car H1 System Controller support" if COMPILE_TEST
42 select SYSC_RCAR 53 select SYSC_RCAR
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index c37b0803c1b6..3bdd7dbc38a9 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -6,6 +6,8 @@ obj-$(CONFIG_SOC_RENESAS) += renesas-soc.o
6obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o 6obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o
7obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o 7obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o
8obj-$(CONFIG_SYSC_R8A77470) += r8a77470-sysc.o 8obj-$(CONFIG_SYSC_R8A77470) += r8a77470-sysc.o
9obj-$(CONFIG_SYSC_R8A774A1) += r8a774a1-sysc.o
10obj-$(CONFIG_SYSC_R8A774C0) += r8a774c0-sysc.o
9obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o 11obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o
10obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o 12obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o
11obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o 13obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o
diff --git a/drivers/soc/renesas/r8a7743-sysc.c b/drivers/soc/renesas/r8a7743-sysc.c
index 9583a327d90c..edf6436e879f 100644
--- a/drivers/soc/renesas/r8a7743-sysc.c
+++ b/drivers/soc/renesas/r8a7743-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas RZ/G1M System Controller 3 * Renesas RZ/G1M System Controller
3 * 4 *
4 * Copyright (C) 2016 Cogent Embedded Inc. 5 * Copyright (C) 2016 Cogent Embedded Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation; of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7745-sysc.c b/drivers/soc/renesas/r8a7745-sysc.c
index d17887c08aa1..65dc6b09cc85 100644
--- a/drivers/soc/renesas/r8a7745-sysc.c
+++ b/drivers/soc/renesas/r8a7745-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas RZ/G1E System Controller 3 * Renesas RZ/G1E System Controller
3 * 4 *
4 * Copyright (C) 2016 Cogent Embedded Inc. 5 * Copyright (C) 2016 Cogent Embedded Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation; of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a774a1-sysc.c b/drivers/soc/renesas/r8a774a1-sysc.c
new file mode 100644
index 000000000000..9db51ff6f5ed
--- /dev/null
+++ b/drivers/soc/renesas/r8a774a1-sysc.c
@@ -0,0 +1,45 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Renesas RZ/G2M System Controller
4 * Copyright (C) 2018 Renesas Electronics Corp.
5 *
6 * Based on Renesas R-Car M3-W System Controller
7 * Copyright (C) 2016 Glider bvba
8 */
9
10#include <linux/bug.h>
11#include <linux/kernel.h>
12
13#include <dt-bindings/power/r8a774a1-sysc.h>
14
15#include "rcar-sysc.h"
16
17static const struct rcar_sysc_area r8a774a1_areas[] __initconst = {
18 { "always-on", 0, 0, R8A774A1_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
19 { "ca57-scu", 0x1c0, 0, R8A774A1_PD_CA57_SCU, R8A774A1_PD_ALWAYS_ON,
20 PD_SCU },
21 { "ca57-cpu0", 0x80, 0, R8A774A1_PD_CA57_CPU0, R8A774A1_PD_CA57_SCU,
22 PD_CPU_NOCR },
23 { "ca57-cpu1", 0x80, 1, R8A774A1_PD_CA57_CPU1, R8A774A1_PD_CA57_SCU,
24 PD_CPU_NOCR },
25 { "ca53-scu", 0x140, 0, R8A774A1_PD_CA53_SCU, R8A774A1_PD_ALWAYS_ON,
26 PD_SCU },
27 { "ca53-cpu0", 0x200, 0, R8A774A1_PD_CA53_CPU0, R8A774A1_PD_CA53_SCU,
28 PD_CPU_NOCR },
29 { "ca53-cpu1", 0x200, 1, R8A774A1_PD_CA53_CPU1, R8A774A1_PD_CA53_SCU,
30 PD_CPU_NOCR },
31 { "ca53-cpu2", 0x200, 2, R8A774A1_PD_CA53_CPU2, R8A774A1_PD_CA53_SCU,
32 PD_CPU_NOCR },
33 { "ca53-cpu3", 0x200, 3, R8A774A1_PD_CA53_CPU3, R8A774A1_PD_CA53_SCU,
34 PD_CPU_NOCR },
35 { "a3vc", 0x380, 0, R8A774A1_PD_A3VC, R8A774A1_PD_ALWAYS_ON },
36 { "a2vc0", 0x3c0, 0, R8A774A1_PD_A2VC0, R8A774A1_PD_A3VC },
37 { "a2vc1", 0x3c0, 1, R8A774A1_PD_A2VC1, R8A774A1_PD_A3VC },
38 { "3dg-a", 0x100, 0, R8A774A1_PD_3DG_A, R8A774A1_PD_ALWAYS_ON },
39 { "3dg-b", 0x100, 1, R8A774A1_PD_3DG_B, R8A774A1_PD_3DG_A },
40};
41
42const struct rcar_sysc_info r8a774a1_sysc_info __initconst = {
43 .areas = r8a774a1_areas,
44 .num_areas = ARRAY_SIZE(r8a774a1_areas),
45};
diff --git a/drivers/soc/renesas/r8a774c0-sysc.c b/drivers/soc/renesas/r8a774c0-sysc.c
new file mode 100644
index 000000000000..e1ac4c0f6640
--- /dev/null
+++ b/drivers/soc/renesas/r8a774c0-sysc.c
@@ -0,0 +1,68 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Renesas RZ/G2E System Controller
4 * Copyright (C) 2018 Renesas Electronics Corp.
5 *
6 * Based on Renesas R-Car E3 System Controller
7 */
8
9#include <linux/bug.h>
10#include <linux/kernel.h>
11#include <linux/sys_soc.h>
12
13#include <dt-bindings/power/r8a774c0-sysc.h>
14
15#include "rcar-sysc.h"
16
17static struct rcar_sysc_area r8a774c0_areas[] __initdata = {
18 { "always-on", 0, 0, R8A774C0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON },
19 { "ca53-scu", 0x140, 0, R8A774C0_PD_CA53_SCU, R8A774C0_PD_ALWAYS_ON,
20 PD_SCU },
21 { "ca53-cpu0", 0x200, 0, R8A774C0_PD_CA53_CPU0, R8A774C0_PD_CA53_SCU,
22 PD_CPU_NOCR },
23 { "ca53-cpu1", 0x200, 1, R8A774C0_PD_CA53_CPU1, R8A774C0_PD_CA53_SCU,
24 PD_CPU_NOCR },
25 { "a3vc", 0x380, 0, R8A774C0_PD_A3VC, R8A774C0_PD_ALWAYS_ON },
26 { "a2vc1", 0x3c0, 1, R8A774C0_PD_A2VC1, R8A774C0_PD_A3VC },
27 { "3dg-a", 0x100, 0, R8A774C0_PD_3DG_A, R8A774C0_PD_ALWAYS_ON },
28 { "3dg-b", 0x100, 1, R8A774C0_PD_3DG_B, R8A774C0_PD_3DG_A },
29};
30
31static void __init rcar_sysc_fix_parent(struct rcar_sysc_area *areas,
32 unsigned int num_areas, u8 id,
33 int new_parent)
34{
35 unsigned int i;
36
37 for (i = 0; i < num_areas; i++)
38 if (areas[i].isr_bit == id) {
39 areas[i].parent = new_parent;
40 return;
41 }
42}
43
44/* Fixups for RZ/G2E ES1.0 revision */
45static const struct soc_device_attribute r8a774c0[] __initconst = {
46 { .soc_id = "r8a774c0", .revision = "ES1.0" },
47 { /* sentinel */ }
48};
49
50static int __init r8a774c0_sysc_init(void)
51{
52 if (soc_device_match(r8a774c0)) {
53 rcar_sysc_fix_parent(r8a774c0_areas,
54 ARRAY_SIZE(r8a774c0_areas),
55 R8A774C0_PD_3DG_A, R8A774C0_PD_3DG_B);
56 rcar_sysc_fix_parent(r8a774c0_areas,
57 ARRAY_SIZE(r8a774c0_areas),
58 R8A774C0_PD_3DG_B, R8A774C0_PD_ALWAYS_ON);
59 }
60
61 return 0;
62}
63
64const struct rcar_sysc_info r8a774c0_sysc_info __initconst = {
65 .init = r8a774c0_sysc_init,
66 .areas = r8a774c0_areas,
67 .num_areas = ARRAY_SIZE(r8a774c0_areas),
68};
diff --git a/drivers/soc/renesas/r8a7779-sysc.c b/drivers/soc/renesas/r8a7779-sysc.c
index 9e8e6b7faa04..517aa40fa6e6 100644
--- a/drivers/soc/renesas/r8a7779-sysc.c
+++ b/drivers/soc/renesas/r8a7779-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car H1 System Controller 3 * Renesas R-Car H1 System Controller
3 * 4 *
4 * Copyright (C) 2016 Glider bvba 5 * Copyright (C) 2016 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7790-sysc.c b/drivers/soc/renesas/r8a7790-sysc.c
index 7a567ad0ff73..9b5a6bb62152 100644
--- a/drivers/soc/renesas/r8a7790-sysc.c
+++ b/drivers/soc/renesas/r8a7790-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car H2 System Controller 3 * Renesas R-Car H2 System Controller
3 * 4 *
4 * Copyright (C) 2016 Glider bvba 5 * Copyright (C) 2016 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7791-sysc.c b/drivers/soc/renesas/r8a7791-sysc.c
index 03b9f41a34e6..acf545cdebfb 100644
--- a/drivers/soc/renesas/r8a7791-sysc.c
+++ b/drivers/soc/renesas/r8a7791-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car M2-W/N System Controller 3 * Renesas R-Car M2-W/N System Controller
3 * 4 *
4 * Copyright (C) 2016 Glider bvba 5 * Copyright (C) 2016 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7792-sysc.c b/drivers/soc/renesas/r8a7792-sysc.c
index ca7467d7b7ec..05b78525cc43 100644
--- a/drivers/soc/renesas/r8a7792-sysc.c
+++ b/drivers/soc/renesas/r8a7792-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car V2H (R8A7792) System Controller 3 * Renesas R-Car V2H (R8A7792) System Controller
3 * 4 *
4 * Copyright (C) 2016 Cogent Embedded Inc. 5 * Copyright (C) 2016 Cogent Embedded Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7794-sysc.c b/drivers/soc/renesas/r8a7794-sysc.c
index c4da2941e06c..0d42637fa662 100644
--- a/drivers/soc/renesas/r8a7794-sysc.c
+++ b/drivers/soc/renesas/r8a7794-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car E2 System Controller 3 * Renesas R-Car E2 System Controller
3 * 4 *
4 * Copyright (C) 2016 Glider bvba 5 * Copyright (C) 2016 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7795-sysc.c b/drivers/soc/renesas/r8a7795-sysc.c
index 7412666187b3..cda27a67de98 100644
--- a/drivers/soc/renesas/r8a7795-sysc.c
+++ b/drivers/soc/renesas/r8a7795-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car H3 System Controller 3 * Renesas R-Car H3 System Controller
3 * 4 *
4 * Copyright (C) 2016-2017 Glider bvba 5 * Copyright (C) 2016-2017 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a7796-sysc.c b/drivers/soc/renesas/r8a7796-sysc.c
index f700c842b9e1..1b06f868b6e8 100644
--- a/drivers/soc/renesas/r8a7796-sysc.c
+++ b/drivers/soc/renesas/r8a7796-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car M3-W System Controller 3 * Renesas R-Car M3-W System Controller
3 * 4 *
4 * Copyright (C) 2016 Glider bvba 5 * Copyright (C) 2016 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c
index caf894f193ed..35b30d6a8958 100644
--- a/drivers/soc/renesas/r8a77970-sysc.c
+++ b/drivers/soc/renesas/r8a77970-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car V3M System Controller 3 * Renesas R-Car V3M System Controller
3 * 4 *
4 * Copyright (C) 2017 Cogent Embedded Inc. 5 * Copyright (C) 2017 Cogent Embedded Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/r8a77995-sysc.c b/drivers/soc/renesas/r8a77995-sysc.c
index 1b2ef415bbe1..6243aaaf60fb 100644
--- a/drivers/soc/renesas/r8a77995-sysc.c
+++ b/drivers/soc/renesas/r8a77995-sysc.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas R-Car D3 System Controller 3 * Renesas R-Car D3 System Controller
3 * 4 *
4 * Copyright (C) 2017 Glider bvba 5 * Copyright (C) 2017 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10 7
11#include <linux/bug.h> 8#include <linux/bug.h>
diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c
index d9c1034e70e9..d183c381e8db 100644
--- a/drivers/soc/renesas/rcar-rst.c
+++ b/drivers/soc/renesas/rcar-rst.c
@@ -1,11 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * R-Car Gen1 RESET/WDT, R-Car Gen2, Gen3, and RZ/G RST Driver 3 * R-Car Gen1 RESET/WDT, R-Car Gen2, Gen3, and RZ/G RST Driver
3 * 4 *
4 * Copyright (C) 2016 Glider bvba 5 * Copyright (C) 2016 Glider bvba
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */ 6 */
10 7
11#include <linux/err.h> 8#include <linux/err.h>
@@ -41,10 +38,14 @@ static const struct rst_config rcar_rst_gen3 __initconst = {
41}; 38};
42 39
43static const struct of_device_id rcar_rst_matches[] __initconst = { 40static const struct of_device_id rcar_rst_matches[] __initconst = {
44 /* RZ/G is handled like R-Car Gen2 */ 41 /* RZ/G1 is handled like R-Car Gen2 */
45 { .compatible = "renesas,r8a7743-rst", .data = &rcar_rst_gen2 }, 42 { .compatible = "renesas,r8a7743-rst", .data = &rcar_rst_gen2 },
43 { .compatible = "renesas,r8a7744-rst", .data = &rcar_rst_gen2 },
46 { .compatible = "renesas,r8a7745-rst", .data = &rcar_rst_gen2 }, 44 { .compatible = "renesas,r8a7745-rst", .data = &rcar_rst_gen2 },
47 { .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 }, 45 { .compatible = "renesas,r8a77470-rst", .data = &rcar_rst_gen2 },
46 /* RZ/G2 is handled like R-Car Gen3 */
47 { .compatible = "renesas,r8a774a1-rst", .data = &rcar_rst_gen3 },
48 { .compatible = "renesas,r8a774c0-rst", .data = &rcar_rst_gen3 },
48 /* R-Car Gen1 */ 49 /* R-Car Gen1 */
49 { .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 }, 50 { .compatible = "renesas,r8a7778-reset-wdt", .data = &rcar_rst_gen1 },
50 { .compatible = "renesas,r8a7779-reset-wdt", .data = &rcar_rst_gen1 }, 51 { .compatible = "renesas,r8a7779-reset-wdt", .data = &rcar_rst_gen1 },
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index 029188e8be6e..af53363eda03 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -1,12 +1,9 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * R-Car SYSC Power management support 3 * R-Car SYSC Power management support
3 * 4 *
4 * Copyright (C) 2014 Magnus Damm 5 * Copyright (C) 2014 Magnus Damm
5 * Copyright (C) 2015-2017 Glider bvba 6 * Copyright (C) 2015-2017 Glider bvba
6 *
7 * This file is subject to the terms and conditions of the GNU General Public
8 * License. See the file "COPYING" in the main directory of this archive
9 * for more details.
10 */ 7 */
11 8
12#include <linux/clk/renesas.h> 9#include <linux/clk/renesas.h>
@@ -268,6 +265,8 @@ finalize:
268static const struct of_device_id rcar_sysc_matches[] __initconst = { 265static const struct of_device_id rcar_sysc_matches[] __initconst = {
269#ifdef CONFIG_SYSC_R8A7743 266#ifdef CONFIG_SYSC_R8A7743
270 { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info }, 267 { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
268 /* RZ/G1N is identical to RZ/G2M w.r.t. power domains. */
269 { .compatible = "renesas,r8a7744-sysc", .data = &r8a7743_sysc_info },
271#endif 270#endif
272#ifdef CONFIG_SYSC_R8A7745 271#ifdef CONFIG_SYSC_R8A7745
273 { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info }, 272 { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
@@ -275,6 +274,12 @@ static const struct of_device_id rcar_sysc_matches[] __initconst = {
275#ifdef CONFIG_SYSC_R8A77470 274#ifdef CONFIG_SYSC_R8A77470
276 { .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info }, 275 { .compatible = "renesas,r8a77470-sysc", .data = &r8a77470_sysc_info },
277#endif 276#endif
277#ifdef CONFIG_SYSC_R8A774A1
278 { .compatible = "renesas,r8a774a1-sysc", .data = &r8a774a1_sysc_info },
279#endif
280#ifdef CONFIG_SYSC_R8A774C0
281 { .compatible = "renesas,r8a774c0-sysc", .data = &r8a774c0_sysc_info },
282#endif
278#ifdef CONFIG_SYSC_R8A7779 283#ifdef CONFIG_SYSC_R8A7779
279 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, 284 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
280#endif 285#endif
diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h
index a22e7cf25e30..485520a5b295 100644
--- a/drivers/soc/renesas/rcar-sysc.h
+++ b/drivers/soc/renesas/rcar-sysc.h
@@ -1,11 +1,8 @@
1/* 1/* SPDX-License-Identifier: GPL-2.0
2 *
2 * Renesas R-Car System Controller 3 * Renesas R-Car System Controller
3 * 4 *
4 * Copyright (C) 2016 Glider bvba 5 * Copyright (C) 2016 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 */ 6 */
10#ifndef __SOC_RENESAS_RCAR_SYSC_H__ 7#ifndef __SOC_RENESAS_RCAR_SYSC_H__
11#define __SOC_RENESAS_RCAR_SYSC_H__ 8#define __SOC_RENESAS_RCAR_SYSC_H__
@@ -52,6 +49,8 @@ struct rcar_sysc_info {
52extern const struct rcar_sysc_info r8a7743_sysc_info; 49extern const struct rcar_sysc_info r8a7743_sysc_info;
53extern const struct rcar_sysc_info r8a7745_sysc_info; 50extern const struct rcar_sysc_info r8a7745_sysc_info;
54extern const struct rcar_sysc_info r8a77470_sysc_info; 51extern const struct rcar_sysc_info r8a77470_sysc_info;
52extern const struct rcar_sysc_info r8a774a1_sysc_info;
53extern const struct rcar_sysc_info r8a774c0_sysc_info;
55extern const struct rcar_sysc_info r8a7779_sysc_info; 54extern const struct rcar_sysc_info r8a7779_sysc_info;
56extern const struct rcar_sysc_info r8a7790_sysc_info; 55extern const struct rcar_sysc_info r8a7790_sysc_info;
57extern const struct rcar_sysc_info r8a7791_sysc_info; 56extern const struct rcar_sysc_info r8a7791_sysc_info;
diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c
index d44d0e687ab8..4af96e668a2f 100644
--- a/drivers/soc/renesas/renesas-soc.c
+++ b/drivers/soc/renesas/renesas-soc.c
@@ -1,16 +1,8 @@
1// SPDX-License-Identifier: GPL-2.0
1/* 2/*
2 * Renesas SoC Identification 3 * Renesas SoC Identification
3 * 4 *
4 * Copyright (C) 2014-2016 Glider bvba 5 * Copyright (C) 2014-2016 Glider bvba
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */ 6 */
15 7
16#include <linux/io.h> 8#include <linux/io.h>
@@ -46,15 +38,24 @@ static const struct renesas_family fam_rmobile __initconst __maybe_unused = {
46 .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ 38 .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
47}; 39};
48 40
49static const struct renesas_family fam_rza __initconst __maybe_unused = { 41static const struct renesas_family fam_rza1 __initconst __maybe_unused = {
50 .name = "RZ/A", 42 .name = "RZ/A1",
43};
44
45static const struct renesas_family fam_rza2 __initconst __maybe_unused = {
46 .name = "RZ/A2",
51}; 47};
52 48
53static const struct renesas_family fam_rzg __initconst __maybe_unused = { 49static const struct renesas_family fam_rzg1 __initconst __maybe_unused = {
54 .name = "RZ/G", 50 .name = "RZ/G1",
55 .reg = 0xff000044, /* PRR (Product Register) */ 51 .reg = 0xff000044, /* PRR (Product Register) */
56}; 52};
57 53
54static const struct renesas_family fam_rzg2 __initconst __maybe_unused = {
55 .name = "RZ/G2",
56 .reg = 0xfff00044, /* PRR (Product Register) */
57};
58
58static const struct renesas_family fam_shmobile __initconst __maybe_unused = { 59static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
59 .name = "SH-Mobile", 60 .name = "SH-Mobile",
60 .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ 61 .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */
@@ -67,7 +68,12 @@ struct renesas_soc {
67}; 68};
68 69
69static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = { 70static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = {
70 .family = &fam_rza, 71 .family = &fam_rza1,
72};
73
74static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused = {
75 .family = &fam_rza2,
76 .id = 0x3b,
71}; 77};
72 78
73static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = { 79static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = {
@@ -81,30 +87,40 @@ static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = {
81}; 87};
82 88
83static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = { 89static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = {
84 .family = &fam_rzg, 90 .family = &fam_rzg1,
85 .id = 0x45, 91 .id = 0x45,
86}; 92};
87 93
88static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = { 94static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = {
89 .family = &fam_rzg, 95 .family = &fam_rzg1,
90 .id = 0x47, 96 .id = 0x47,
91}; 97};
92 98
93static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = { 99static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = {
94 .family = &fam_rzg, 100 .family = &fam_rzg1,
95 .id = 0x4b, 101 .id = 0x4b,
96}; 102};
97 103
98static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = { 104static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = {
99 .family = &fam_rzg, 105 .family = &fam_rzg1,
100 .id = 0x4c, 106 .id = 0x4c,
101}; 107};
102 108
103static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = { 109static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = {
104 .family = &fam_rzg, 110 .family = &fam_rzg1,
105 .id = 0x53, 111 .id = 0x53,
106}; 112};
107 113
114static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = {
115 .family = &fam_rzg2,
116 .id = 0x52,
117};
118
119static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = {
120 .family = &fam_rzg2,
121 .id = 0x57,
122};
123
108static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { 124static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
109 .family = &fam_rcar_gen1, 125 .family = &fam_rcar_gen1,
110}; 126};
@@ -184,6 +200,9 @@ static const struct of_device_id renesas_socs[] __initconst = {
184#ifdef CONFIG_ARCH_R7S72100 200#ifdef CONFIG_ARCH_R7S72100
185 { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h }, 201 { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h },
186#endif 202#endif
203#ifdef CONFIG_ARCH_R7S9210
204 { .compatible = "renesas,r7s9210", .data = &soc_rz_a2m },
205#endif
187#ifdef CONFIG_ARCH_R8A73A4 206#ifdef CONFIG_ARCH_R8A73A4
188 { .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 }, 207 { .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 },
189#endif 208#endif
@@ -205,6 +224,12 @@ static const struct of_device_id renesas_socs[] __initconst = {
205#ifdef CONFIG_ARCH_R8A77470 224#ifdef CONFIG_ARCH_R8A77470
206 { .compatible = "renesas,r8a77470", .data = &soc_rz_g1c }, 225 { .compatible = "renesas,r8a77470", .data = &soc_rz_g1c },
207#endif 226#endif
227#ifdef CONFIG_ARCH_R8A774A1
228 { .compatible = "renesas,r8a774a1", .data = &soc_rz_g2m },
229#endif
230#ifdef CONFIG_ARCH_R8A774C0
231 { .compatible = "renesas,r8a774c0", .data = &soc_rz_g2e },
232#endif
208#ifdef CONFIG_ARCH_R8A7778 233#ifdef CONFIG_ARCH_R8A7778
209 { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a }, 234 { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a },
210#endif 235#endif
@@ -262,7 +287,7 @@ static int __init renesas_soc_init(void)
262 void __iomem *chipid = NULL; 287 void __iomem *chipid = NULL;
263 struct soc_device *soc_dev; 288 struct soc_device *soc_dev;
264 struct device_node *np; 289 struct device_node *np;
265 unsigned int product; 290 unsigned int product, eshi = 0, eslo;
266 291
267 match = of_match_node(renesas_socs, of_root); 292 match = of_match_node(renesas_socs, of_root);
268 if (!match) 293 if (!match)
@@ -271,6 +296,31 @@ static int __init renesas_soc_init(void)
271 soc = match->data; 296 soc = match->data;
272 family = soc->family; 297 family = soc->family;
273 298
299 np = of_find_compatible_node(NULL, NULL, "renesas,bsid");
300 if (np) {
301 chipid = of_iomap(np, 0);
302 of_node_put(np);
303
304 if (chipid) {
305 product = readl(chipid);
306 iounmap(chipid);
307
308 if (soc->id && ((product >> 16) & 0xff) != soc->id) {
309 pr_warn("SoC mismatch (product = 0x%x)\n",
310 product);
311 return -ENODEV;
312 }
313 }
314
315 /*
316 * TODO: Upper 4 bits of BSID are for chip version, but the
317 * format is not known at this time so we don't know how to
318 * specify eshi and eslo
319 */
320
321 goto done;
322 }
323
274 /* Try PRR first, then hardcoded fallback */ 324 /* Try PRR first, then hardcoded fallback */
275 np = of_find_compatible_node(NULL, NULL, "renesas,prr"); 325 np = of_find_compatible_node(NULL, NULL, "renesas,prr");
276 if (np) { 326 if (np) {
@@ -289,8 +339,11 @@ static int __init renesas_soc_init(void)
289 pr_warn("SoC mismatch (product = 0x%x)\n", product); 339 pr_warn("SoC mismatch (product = 0x%x)\n", product);
290 return -ENODEV; 340 return -ENODEV;
291 } 341 }
342 eshi = ((product >> 4) & 0x0f) + 1;
343 eslo = product & 0xf;
292 } 344 }
293 345
346done:
294 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 347 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
295 if (!soc_dev_attr) 348 if (!soc_dev_attr)
296 return -ENOMEM; 349 return -ENOMEM;
@@ -302,10 +355,9 @@ static int __init renesas_soc_init(void)
302 soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL); 355 soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
303 soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1, 356 soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1,
304 GFP_KERNEL); 357 GFP_KERNEL);
305 if (chipid) 358 if (eshi)
306 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", 359 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", eshi,
307 ((product >> 4) & 0x0f) + 1, 360 eslo);
308 product & 0xf);
309 361
310 pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family, 362 pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family,
311 soc_dev_attr->soc_id, soc_dev_attr->revision ?: ""); 363 soc_dev_attr->soc_id, soc_dev_attr->revision ?: "");
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index acbe63e925d5..1fa840e3d930 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -33,6 +33,9 @@
33#include <linux/of_address.h> 33#include <linux/of_address.h>
34#include <linux/of_clk.h> 34#include <linux/of_clk.h>
35#include <linux/of_platform.h> 35#include <linux/of_platform.h>
36#include <linux/pinctrl/pinctrl.h>
37#include <linux/pinctrl/pinconf.h>
38#include <linux/pinctrl/pinconf-generic.h>
36#include <linux/platform_device.h> 39#include <linux/platform_device.h>
37#include <linux/pm_domain.h> 40#include <linux/pm_domain.h>
38#include <linux/reboot.h> 41#include <linux/reboot.h>
@@ -45,6 +48,8 @@
45#include <soc/tegra/fuse.h> 48#include <soc/tegra/fuse.h>
46#include <soc/tegra/pmc.h> 49#include <soc/tegra/pmc.h>
47 50
51#include <dt-bindings/pinctrl/pinctrl-tegra-io-pad.h>
52
48#define PMC_CNTRL 0x0 53#define PMC_CNTRL 0x0
49#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ 54#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */
50#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ 55#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */
@@ -65,6 +70,8 @@
65 70
66#define PWRGATE_STATUS 0x38 71#define PWRGATE_STATUS 0x38
67 72
73#define PMC_IMPL_E_33V_PWR 0x40
74
68#define PMC_PWR_DET 0x48 75#define PMC_PWR_DET 0x48
69 76
70#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) 77#define PMC_SCRATCH0_MODE_RECOVERY BIT(31)
@@ -135,6 +142,7 @@ struct tegra_io_pad_soc {
135 enum tegra_io_pad id; 142 enum tegra_io_pad id;
136 unsigned int dpd; 143 unsigned int dpd;
137 unsigned int voltage; 144 unsigned int voltage;
145 const char *name;
138}; 146};
139 147
140struct tegra_pmc_regs { 148struct tegra_pmc_regs {
@@ -154,10 +162,14 @@ struct tegra_pmc_soc {
154 bool has_tsense_reset; 162 bool has_tsense_reset;
155 bool has_gpu_clamps; 163 bool has_gpu_clamps;
156 bool needs_mbist_war; 164 bool needs_mbist_war;
165 bool has_impl_33v_pwr;
157 166
158 const struct tegra_io_pad_soc *io_pads; 167 const struct tegra_io_pad_soc *io_pads;
159 unsigned int num_io_pads; 168 unsigned int num_io_pads;
160 169
170 const struct pinctrl_pin_desc *pin_descs;
171 unsigned int num_pin_descs;
172
161 const struct tegra_pmc_regs *regs; 173 const struct tegra_pmc_regs *regs;
162 void (*init)(struct tegra_pmc *pmc); 174 void (*init)(struct tegra_pmc *pmc);
163 void (*setup_irq_polarity)(struct tegra_pmc *pmc, 175 void (*setup_irq_polarity)(struct tegra_pmc *pmc,
@@ -216,6 +228,8 @@ struct tegra_pmc {
216 DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX); 228 DECLARE_BITMAP(powergates_available, TEGRA_POWERGATE_MAX);
217 229
218 struct mutex powergates_lock; 230 struct mutex powergates_lock;
231
232 struct pinctrl_dev *pctl_dev;
219}; 233};
220 234
221static struct tegra_pmc *pmc = &(struct tegra_pmc) { 235static struct tegra_pmc *pmc = &(struct tegra_pmc) {
@@ -919,11 +933,12 @@ tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id)
919 return NULL; 933 return NULL;
920} 934}
921 935
922static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, 936static int tegra_io_pad_get_dpd_register_bit(enum tegra_io_pad id,
923 unsigned long *status, u32 *mask) 937 unsigned long *request,
938 unsigned long *status,
939 u32 *mask)
924{ 940{
925 const struct tegra_io_pad_soc *pad; 941 const struct tegra_io_pad_soc *pad;
926 unsigned long rate, value;
927 942
928 pad = tegra_io_pad_find(pmc, id); 943 pad = tegra_io_pad_find(pmc, id);
929 if (!pad) { 944 if (!pad) {
@@ -944,6 +959,19 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request,
944 *request = pmc->soc->regs->dpd2_req; 959 *request = pmc->soc->regs->dpd2_req;
945 } 960 }
946 961
962 return 0;
963}
964
965static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request,
966 unsigned long *status, u32 *mask)
967{
968 unsigned long rate, value;
969 int err;
970
971 err = tegra_io_pad_get_dpd_register_bit(id, request, status, mask);
972 if (err)
973 return err;
974
947 if (pmc->clk) { 975 if (pmc->clk) {
948 rate = clk_get_rate(pmc->clk); 976 rate = clk_get_rate(pmc->clk);
949 if (!rate) { 977 if (!rate) {
@@ -1058,8 +1086,22 @@ unlock:
1058} 1086}
1059EXPORT_SYMBOL(tegra_io_pad_power_disable); 1087EXPORT_SYMBOL(tegra_io_pad_power_disable);
1060 1088
1061int tegra_io_pad_set_voltage(enum tegra_io_pad id, 1089static int tegra_io_pad_is_powered(enum tegra_io_pad id)
1062 enum tegra_io_pad_voltage voltage) 1090{
1091 unsigned long request, status;
1092 u32 mask, value;
1093 int err;
1094
1095 err = tegra_io_pad_get_dpd_register_bit(id, &request, &status, &mask);
1096 if (err)
1097 return err;
1098
1099 value = tegra_pmc_readl(status);
1100
1101 return !(value & mask);
1102}
1103
1104static int tegra_io_pad_set_voltage(enum tegra_io_pad id, int voltage)
1063{ 1105{
1064 const struct tegra_io_pad_soc *pad; 1106 const struct tegra_io_pad_soc *pad;
1065 u32 value; 1107 u32 value;
@@ -1073,20 +1115,31 @@ int tegra_io_pad_set_voltage(enum tegra_io_pad id,
1073 1115
1074 mutex_lock(&pmc->powergates_lock); 1116 mutex_lock(&pmc->powergates_lock);
1075 1117
1076 /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */ 1118 if (pmc->soc->has_impl_33v_pwr) {
1077 value = tegra_pmc_readl(PMC_PWR_DET); 1119 value = tegra_pmc_readl(PMC_IMPL_E_33V_PWR);
1078 value |= BIT(pad->voltage);
1079 tegra_pmc_writel(value, PMC_PWR_DET);
1080 1120
1081 /* update I/O voltage */ 1121 if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
1082 value = tegra_pmc_readl(PMC_PWR_DET_VALUE); 1122 value &= ~BIT(pad->voltage);
1123 else
1124 value |= BIT(pad->voltage);
1083 1125
1084 if (voltage == TEGRA_IO_PAD_1800000UV) 1126 tegra_pmc_writel(value, PMC_IMPL_E_33V_PWR);
1085 value &= ~BIT(pad->voltage); 1127 } else {
1086 else 1128 /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */
1129 value = tegra_pmc_readl(PMC_PWR_DET);
1087 value |= BIT(pad->voltage); 1130 value |= BIT(pad->voltage);
1131 tegra_pmc_writel(value, PMC_PWR_DET);
1088 1132
1089 tegra_pmc_writel(value, PMC_PWR_DET_VALUE); 1133 /* update I/O voltage */
1134 value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
1135
1136 if (voltage == TEGRA_IO_PAD_VOLTAGE_1V8)
1137 value &= ~BIT(pad->voltage);
1138 else
1139 value |= BIT(pad->voltage);
1140
1141 tegra_pmc_writel(value, PMC_PWR_DET_VALUE);
1142 }
1090 1143
1091 mutex_unlock(&pmc->powergates_lock); 1144 mutex_unlock(&pmc->powergates_lock);
1092 1145
@@ -1094,9 +1147,8 @@ int tegra_io_pad_set_voltage(enum tegra_io_pad id,
1094 1147
1095 return 0; 1148 return 0;
1096} 1149}
1097EXPORT_SYMBOL(tegra_io_pad_set_voltage);
1098 1150
1099int tegra_io_pad_get_voltage(enum tegra_io_pad id) 1151static int tegra_io_pad_get_voltage(enum tegra_io_pad id)
1100{ 1152{
1101 const struct tegra_io_pad_soc *pad; 1153 const struct tegra_io_pad_soc *pad;
1102 u32 value; 1154 u32 value;
@@ -1108,14 +1160,16 @@ int tegra_io_pad_get_voltage(enum tegra_io_pad id)
1108 if (pad->voltage == UINT_MAX) 1160 if (pad->voltage == UINT_MAX)
1109 return -ENOTSUPP; 1161 return -ENOTSUPP;
1110 1162
1111 value = tegra_pmc_readl(PMC_PWR_DET_VALUE); 1163 if (pmc->soc->has_impl_33v_pwr)
1164 value = tegra_pmc_readl(PMC_IMPL_E_33V_PWR);
1165 else
1166 value = tegra_pmc_readl(PMC_PWR_DET_VALUE);
1112 1167
1113 if ((value & BIT(pad->voltage)) == 0) 1168 if ((value & BIT(pad->voltage)) == 0)
1114 return TEGRA_IO_PAD_1800000UV; 1169 return TEGRA_IO_PAD_VOLTAGE_1V8;
1115 1170
1116 return TEGRA_IO_PAD_3300000UV; 1171 return TEGRA_IO_PAD_VOLTAGE_3V3;
1117} 1172}
1118EXPORT_SYMBOL(tegra_io_pad_get_voltage);
1119 1173
1120/** 1174/**
1121 * tegra_io_rail_power_on() - enable power to I/O rail 1175 * tegra_io_rail_power_on() - enable power to I/O rail
@@ -1288,7 +1342,7 @@ static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
1288 if (!pmc->soc->has_tsense_reset) 1342 if (!pmc->soc->has_tsense_reset)
1289 return; 1343 return;
1290 1344
1291 np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip"); 1345 np = of_get_child_by_name(pmc->dev->of_node, "i2c-thermtrip");
1292 if (!np) { 1346 if (!np) {
1293 dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled); 1347 dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
1294 return; 1348 return;
@@ -1353,6 +1407,142 @@ out:
1353 of_node_put(np); 1407 of_node_put(np);
1354} 1408}
1355 1409
1410static int tegra_io_pad_pinctrl_get_groups_count(struct pinctrl_dev *pctl_dev)
1411{
1412 return pmc->soc->num_io_pads;
1413}
1414
1415static const char *tegra_io_pad_pinctrl_get_group_name(
1416 struct pinctrl_dev *pctl, unsigned int group)
1417{
1418 return pmc->soc->io_pads[group].name;
1419}
1420
1421static int tegra_io_pad_pinctrl_get_group_pins(struct pinctrl_dev *pctl_dev,
1422 unsigned int group,
1423 const unsigned int **pins,
1424 unsigned int *num_pins)
1425{
1426 *pins = &pmc->soc->io_pads[group].id;
1427 *num_pins = 1;
1428 return 0;
1429}
1430
1431static const struct pinctrl_ops tegra_io_pad_pinctrl_ops = {
1432 .get_groups_count = tegra_io_pad_pinctrl_get_groups_count,
1433 .get_group_name = tegra_io_pad_pinctrl_get_group_name,
1434 .get_group_pins = tegra_io_pad_pinctrl_get_group_pins,
1435 .dt_node_to_map = pinconf_generic_dt_node_to_map_pin,
1436 .dt_free_map = pinconf_generic_dt_free_map,
1437};
1438
1439static int tegra_io_pad_pinconf_get(struct pinctrl_dev *pctl_dev,
1440 unsigned int pin, unsigned long *config)
1441{
1442 const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin);
1443 enum pin_config_param param = pinconf_to_config_param(*config);
1444 int ret;
1445 u32 arg;
1446
1447 if (!pad)
1448 return -EINVAL;
1449
1450 switch (param) {
1451 case PIN_CONFIG_POWER_SOURCE:
1452 ret = tegra_io_pad_get_voltage(pad->id);
1453 if (ret < 0)
1454 return ret;
1455 arg = ret;
1456 break;
1457 case PIN_CONFIG_LOW_POWER_MODE:
1458 ret = tegra_io_pad_is_powered(pad->id);
1459 if (ret < 0)
1460 return ret;
1461 arg = !ret;
1462 break;
1463 default:
1464 return -EINVAL;
1465 }
1466
1467 *config = pinconf_to_config_packed(param, arg);
1468
1469 return 0;
1470}
1471
1472static int tegra_io_pad_pinconf_set(struct pinctrl_dev *pctl_dev,
1473 unsigned int pin, unsigned long *configs,
1474 unsigned int num_configs)
1475{
1476 const struct tegra_io_pad_soc *pad = tegra_io_pad_find(pmc, pin);
1477 enum pin_config_param param;
1478 unsigned int i;
1479 int err;
1480 u32 arg;
1481
1482 if (!pad)
1483 return -EINVAL;
1484
1485 for (i = 0; i < num_configs; ++i) {
1486 param = pinconf_to_config_param(configs[i]);
1487 arg = pinconf_to_config_argument(configs[i]);
1488
1489 switch (param) {
1490 case PIN_CONFIG_LOW_POWER_MODE:
1491 if (arg)
1492 err = tegra_io_pad_power_disable(pad->id);
1493 else
1494 err = tegra_io_pad_power_enable(pad->id);
1495 if (err)
1496 return err;
1497 break;
1498 case PIN_CONFIG_POWER_SOURCE:
1499 if (arg != TEGRA_IO_PAD_VOLTAGE_1V8 &&
1500 arg != TEGRA_IO_PAD_VOLTAGE_3V3)
1501 return -EINVAL;
1502 err = tegra_io_pad_set_voltage(pad->id, arg);
1503 if (err)
1504 return err;
1505 break;
1506 default:
1507 return -EINVAL;
1508 }
1509 }
1510
1511 return 0;
1512}
1513
1514static const struct pinconf_ops tegra_io_pad_pinconf_ops = {
1515 .pin_config_get = tegra_io_pad_pinconf_get,
1516 .pin_config_set = tegra_io_pad_pinconf_set,
1517 .is_generic = true,
1518};
1519
1520static struct pinctrl_desc tegra_pmc_pctl_desc = {
1521 .pctlops = &tegra_io_pad_pinctrl_ops,
1522 .confops = &tegra_io_pad_pinconf_ops,
1523};
1524
1525static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc)
1526{
1527 int err = 0;
1528
1529 if (!pmc->soc->num_pin_descs)
1530 return 0;
1531
1532 tegra_pmc_pctl_desc.name = dev_name(pmc->dev);
1533 tegra_pmc_pctl_desc.pins = pmc->soc->pin_descs;
1534 tegra_pmc_pctl_desc.npins = pmc->soc->num_pin_descs;
1535
1536 pmc->pctl_dev = devm_pinctrl_register(pmc->dev, &tegra_pmc_pctl_desc,
1537 pmc);
1538 if (IS_ERR(pmc->pctl_dev)) {
1539 err = PTR_ERR(pmc->pctl_dev);
1540 dev_err(pmc->dev, "unable to register pinctrl, %d\n", err);
1541 }
1542
1543 return err;
1544}
1545
1356static int tegra_pmc_probe(struct platform_device *pdev) 1546static int tegra_pmc_probe(struct platform_device *pdev)
1357{ 1547{
1358 void __iomem *base; 1548 void __iomem *base;
@@ -1430,18 +1620,27 @@ static int tegra_pmc_probe(struct platform_device *pdev)
1430 1620
1431 err = register_restart_handler(&tegra_pmc_restart_handler); 1621 err = register_restart_handler(&tegra_pmc_restart_handler);
1432 if (err) { 1622 if (err) {
1433 debugfs_remove(pmc->debugfs);
1434 dev_err(&pdev->dev, "unable to register restart handler, %d\n", 1623 dev_err(&pdev->dev, "unable to register restart handler, %d\n",
1435 err); 1624 err);
1436 return err; 1625 goto cleanup_debugfs;
1437 } 1626 }
1438 1627
1628 err = tegra_pmc_pinctrl_init(pmc);
1629 if (err)
1630 goto cleanup_restart_handler;
1631
1439 mutex_lock(&pmc->powergates_lock); 1632 mutex_lock(&pmc->powergates_lock);
1440 iounmap(pmc->base); 1633 iounmap(pmc->base);
1441 pmc->base = base; 1634 pmc->base = base;
1442 mutex_unlock(&pmc->powergates_lock); 1635 mutex_unlock(&pmc->powergates_lock);
1443 1636
1444 return 0; 1637 return 0;
1638
1639cleanup_restart_handler:
1640 unregister_restart_handler(&tegra_pmc_restart_handler);
1641cleanup_debugfs:
1642 debugfs_remove(pmc->debugfs);
1643 return err;
1445} 1644}
1446 1645
1447#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM) 1646#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
@@ -1531,6 +1730,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
1531 .has_gpu_clamps = false, 1730 .has_gpu_clamps = false,
1532 .num_io_pads = 0, 1731 .num_io_pads = 0,
1533 .io_pads = NULL, 1732 .io_pads = NULL,
1733 .num_pin_descs = 0,
1734 .pin_descs = NULL,
1534 .regs = &tegra20_pmc_regs, 1735 .regs = &tegra20_pmc_regs,
1535 .init = tegra20_pmc_init, 1736 .init = tegra20_pmc_init,
1536 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 1737 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1567,8 +1768,11 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
1567 .cpu_powergates = tegra30_cpu_powergates, 1768 .cpu_powergates = tegra30_cpu_powergates,
1568 .has_tsense_reset = true, 1769 .has_tsense_reset = true,
1569 .has_gpu_clamps = false, 1770 .has_gpu_clamps = false,
1771 .has_impl_33v_pwr = false,
1570 .num_io_pads = 0, 1772 .num_io_pads = 0,
1571 .io_pads = NULL, 1773 .io_pads = NULL,
1774 .num_pin_descs = 0,
1775 .pin_descs = NULL,
1572 .regs = &tegra20_pmc_regs, 1776 .regs = &tegra20_pmc_regs,
1573 .init = tegra20_pmc_init, 1777 .init = tegra20_pmc_init,
1574 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 1778 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1609,8 +1813,11 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
1609 .cpu_powergates = tegra114_cpu_powergates, 1813 .cpu_powergates = tegra114_cpu_powergates,
1610 .has_tsense_reset = true, 1814 .has_tsense_reset = true,
1611 .has_gpu_clamps = false, 1815 .has_gpu_clamps = false,
1816 .has_impl_33v_pwr = false,
1612 .num_io_pads = 0, 1817 .num_io_pads = 0,
1613 .io_pads = NULL, 1818 .io_pads = NULL,
1819 .num_pin_descs = 0,
1820 .pin_descs = NULL,
1614 .regs = &tegra20_pmc_regs, 1821 .regs = &tegra20_pmc_regs,
1615 .init = tegra20_pmc_init, 1822 .init = tegra20_pmc_init,
1616 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 1823 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1649,37 +1856,59 @@ static const u8 tegra124_cpu_powergates[] = {
1649 TEGRA_POWERGATE_CPU3, 1856 TEGRA_POWERGATE_CPU3,
1650}; 1857};
1651 1858
1859#define TEGRA_IO_PAD(_id, _dpd, _voltage, _name) \
1860 ((struct tegra_io_pad_soc) { \
1861 .id = (_id), \
1862 .dpd = (_dpd), \
1863 .voltage = (_voltage), \
1864 .name = (_name), \
1865 })
1866
1867#define TEGRA_IO_PIN_DESC(_id, _dpd, _voltage, _name) \
1868 ((struct pinctrl_pin_desc) { \
1869 .number = (_id), \
1870 .name = (_name) \
1871 })
1872
1873#define TEGRA124_IO_PAD_TABLE(_pad) \
1874 /* .id .dpd .voltage .name */ \
1875 _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \
1876 _pad(TEGRA_IO_PAD_BB, 15, UINT_MAX, "bb"), \
1877 _pad(TEGRA_IO_PAD_CAM, 36, UINT_MAX, "cam"), \
1878 _pad(TEGRA_IO_PAD_COMP, 22, UINT_MAX, "comp"), \
1879 _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
1880 _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csb"), \
1881 _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "cse"), \
1882 _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
1883 _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \
1884 _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \
1885 _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \
1886 _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \
1887 _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
1888 _pad(TEGRA_IO_PAD_HV, 38, UINT_MAX, "hv"), \
1889 _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \
1890 _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
1891 _pad(TEGRA_IO_PAD_NAND, 13, UINT_MAX, "nand"), \
1892 _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \
1893 _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \
1894 _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
1895 _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \
1896 _pad(TEGRA_IO_PAD_SDMMC1, 33, UINT_MAX, "sdmmc1"), \
1897 _pad(TEGRA_IO_PAD_SDMMC3, 34, UINT_MAX, "sdmmc3"), \
1898 _pad(TEGRA_IO_PAD_SDMMC4, 35, UINT_MAX, "sdmmc4"), \
1899 _pad(TEGRA_IO_PAD_SYS_DDC, 58, UINT_MAX, "sys_ddc"), \
1900 _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \
1901 _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
1902 _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
1903 _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
1904 _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb_bias")
1905
1652static const struct tegra_io_pad_soc tegra124_io_pads[] = { 1906static const struct tegra_io_pad_soc tegra124_io_pads[] = {
1653 { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, 1907 TEGRA124_IO_PAD_TABLE(TEGRA_IO_PAD)
1654 { .id = TEGRA_IO_PAD_BB, .dpd = 15, .voltage = UINT_MAX }, 1908};
1655 { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = UINT_MAX }, 1909
1656 { .id = TEGRA_IO_PAD_COMP, .dpd = 22, .voltage = UINT_MAX }, 1910static const struct pinctrl_pin_desc tegra124_pin_descs[] = {
1657 { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, 1911 TEGRA124_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
1658 { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX },
1659 { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX },
1660 { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
1661 { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX },
1662 { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX },
1663 { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX },
1664 { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX },
1665 { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
1666 { .id = TEGRA_IO_PAD_HV, .dpd = 38, .voltage = UINT_MAX },
1667 { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX },
1668 { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
1669 { .id = TEGRA_IO_PAD_NAND, .dpd = 13, .voltage = UINT_MAX },
1670 { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX },
1671 { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX },
1672 { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
1673 { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX },
1674 { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = UINT_MAX },
1675 { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = UINT_MAX },
1676 { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 35, .voltage = UINT_MAX },
1677 { .id = TEGRA_IO_PAD_SYS_DDC, .dpd = 58, .voltage = UINT_MAX },
1678 { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX },
1679 { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
1680 { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
1681 { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
1682 { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
1683}; 1912};
1684 1913
1685static const struct tegra_pmc_soc tegra124_pmc_soc = { 1914static const struct tegra_pmc_soc tegra124_pmc_soc = {
@@ -1689,8 +1918,11 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
1689 .cpu_powergates = tegra124_cpu_powergates, 1918 .cpu_powergates = tegra124_cpu_powergates,
1690 .has_tsense_reset = true, 1919 .has_tsense_reset = true,
1691 .has_gpu_clamps = true, 1920 .has_gpu_clamps = true,
1921 .has_impl_33v_pwr = false,
1692 .num_io_pads = ARRAY_SIZE(tegra124_io_pads), 1922 .num_io_pads = ARRAY_SIZE(tegra124_io_pads),
1693 .io_pads = tegra124_io_pads, 1923 .io_pads = tegra124_io_pads,
1924 .num_pin_descs = ARRAY_SIZE(tegra124_pin_descs),
1925 .pin_descs = tegra124_pin_descs,
1694 .regs = &tegra20_pmc_regs, 1926 .regs = &tegra20_pmc_regs,
1695 .init = tegra20_pmc_init, 1927 .init = tegra20_pmc_init,
1696 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 1928 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
@@ -1730,45 +1962,53 @@ static const u8 tegra210_cpu_powergates[] = {
1730 TEGRA_POWERGATE_CPU3, 1962 TEGRA_POWERGATE_CPU3,
1731}; 1963};
1732 1964
1965#define TEGRA210_IO_PAD_TABLE(_pad) \
1966 /* .id .dpd .voltage .name */ \
1967 _pad(TEGRA_IO_PAD_AUDIO, 17, 5, "audio"), \
1968 _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 18, "audio-hv"), \
1969 _pad(TEGRA_IO_PAD_CAM, 36, 10, "cam"), \
1970 _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
1971 _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \
1972 _pad(TEGRA_IO_PAD_CSIC, 42, UINT_MAX, "csic"), \
1973 _pad(TEGRA_IO_PAD_CSID, 43, UINT_MAX, "csid"), \
1974 _pad(TEGRA_IO_PAD_CSIE, 44, UINT_MAX, "csie"), \
1975 _pad(TEGRA_IO_PAD_CSIF, 45, UINT_MAX, "csif"), \
1976 _pad(TEGRA_IO_PAD_DBG, 25, 19, "dbg"), \
1977 _pad(TEGRA_IO_PAD_DEBUG_NONAO, 26, UINT_MAX, "debug-nonao"), \
1978 _pad(TEGRA_IO_PAD_DMIC, 50, 20, "dmic"), \
1979 _pad(TEGRA_IO_PAD_DP, 51, UINT_MAX, "dp"), \
1980 _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
1981 _pad(TEGRA_IO_PAD_DSIB, 39, UINT_MAX, "dsib"), \
1982 _pad(TEGRA_IO_PAD_DSIC, 40, UINT_MAX, "dsic"), \
1983 _pad(TEGRA_IO_PAD_DSID, 41, UINT_MAX, "dsid"), \
1984 _pad(TEGRA_IO_PAD_EMMC, 35, UINT_MAX, "emmc"), \
1985 _pad(TEGRA_IO_PAD_EMMC2, 37, UINT_MAX, "emmc2"), \
1986 _pad(TEGRA_IO_PAD_GPIO, 27, 21, "gpio"), \
1987 _pad(TEGRA_IO_PAD_HDMI, 28, UINT_MAX, "hdmi"), \
1988 _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
1989 _pad(TEGRA_IO_PAD_LVDS, 57, UINT_MAX, "lvds"), \
1990 _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
1991 _pad(TEGRA_IO_PAD_PEX_BIAS, 4, UINT_MAX, "pex-bias"), \
1992 _pad(TEGRA_IO_PAD_PEX_CLK1, 5, UINT_MAX, "pex-clk1"), \
1993 _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
1994 _pad(TEGRA_IO_PAD_PEX_CNTRL, UINT_MAX, 11, "pex-cntrl"), \
1995 _pad(TEGRA_IO_PAD_SDMMC1, 33, 12, "sdmmc1"), \
1996 _pad(TEGRA_IO_PAD_SDMMC3, 34, 13, "sdmmc3"), \
1997 _pad(TEGRA_IO_PAD_SPI, 46, 22, "spi"), \
1998 _pad(TEGRA_IO_PAD_SPI_HV, 47, 23, "spi-hv"), \
1999 _pad(TEGRA_IO_PAD_UART, 14, 2, "uart"), \
2000 _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
2001 _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
2002 _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
2003 _pad(TEGRA_IO_PAD_USB3, 18, UINT_MAX, "usb3"), \
2004 _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias")
2005
1733static const struct tegra_io_pad_soc tegra210_io_pads[] = { 2006static const struct tegra_io_pad_soc tegra210_io_pads[] = {
1734 { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = 5 }, 2007 TEGRA210_IO_PAD_TABLE(TEGRA_IO_PAD)
1735 { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = 18 }, 2008};
1736 { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = 10 }, 2009
1737 { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, 2010static const struct pinctrl_pin_desc tegra210_pin_descs[] = {
1738 { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, 2011 TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
1739 { .id = TEGRA_IO_PAD_CSIC, .dpd = 42, .voltage = UINT_MAX },
1740 { .id = TEGRA_IO_PAD_CSID, .dpd = 43, .voltage = UINT_MAX },
1741 { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX },
1742 { .id = TEGRA_IO_PAD_CSIF, .dpd = 45, .voltage = UINT_MAX },
1743 { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = 19 },
1744 { .id = TEGRA_IO_PAD_DEBUG_NONAO, .dpd = 26, .voltage = UINT_MAX },
1745 { .id = TEGRA_IO_PAD_DMIC, .dpd = 50, .voltage = 20 },
1746 { .id = TEGRA_IO_PAD_DP, .dpd = 51, .voltage = UINT_MAX },
1747 { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX },
1748 { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX },
1749 { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX },
1750 { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX },
1751 { .id = TEGRA_IO_PAD_EMMC, .dpd = 35, .voltage = UINT_MAX },
1752 { .id = TEGRA_IO_PAD_EMMC2, .dpd = 37, .voltage = UINT_MAX },
1753 { .id = TEGRA_IO_PAD_GPIO, .dpd = 27, .voltage = 21 },
1754 { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX },
1755 { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
1756 { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX },
1757 { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX },
1758 { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX },
1759 { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX },
1760 { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
1761 { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = UINT_MAX, .voltage = 11 },
1762 { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = 12 },
1763 { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = 13 },
1764 { .id = TEGRA_IO_PAD_SPI, .dpd = 46, .voltage = 22 },
1765 { .id = TEGRA_IO_PAD_SPI_HV, .dpd = 47, .voltage = 23 },
1766 { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = 2 },
1767 { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
1768 { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
1769 { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
1770 { .id = TEGRA_IO_PAD_USB3, .dpd = 18, .voltage = UINT_MAX },
1771 { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
1772}; 2012};
1773 2013
1774static const struct tegra_pmc_soc tegra210_pmc_soc = { 2014static const struct tegra_pmc_soc tegra210_pmc_soc = {
@@ -1778,52 +2018,64 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = {
1778 .cpu_powergates = tegra210_cpu_powergates, 2018 .cpu_powergates = tegra210_cpu_powergates,
1779 .has_tsense_reset = true, 2019 .has_tsense_reset = true,
1780 .has_gpu_clamps = true, 2020 .has_gpu_clamps = true,
2021 .has_impl_33v_pwr = false,
1781 .needs_mbist_war = true, 2022 .needs_mbist_war = true,
1782 .num_io_pads = ARRAY_SIZE(tegra210_io_pads), 2023 .num_io_pads = ARRAY_SIZE(tegra210_io_pads),
1783 .io_pads = tegra210_io_pads, 2024 .io_pads = tegra210_io_pads,
2025 .num_pin_descs = ARRAY_SIZE(tegra210_pin_descs),
2026 .pin_descs = tegra210_pin_descs,
1784 .regs = &tegra20_pmc_regs, 2027 .regs = &tegra20_pmc_regs,
1785 .init = tegra20_pmc_init, 2028 .init = tegra20_pmc_init,
1786 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, 2029 .setup_irq_polarity = tegra20_pmc_setup_irq_polarity,
1787}; 2030};
1788 2031
2032#define TEGRA186_IO_PAD_TABLE(_pad) \
2033 /* .id .dpd .voltage .name */ \
2034 _pad(TEGRA_IO_PAD_CSIA, 0, UINT_MAX, "csia"), \
2035 _pad(TEGRA_IO_PAD_CSIB, 1, UINT_MAX, "csib"), \
2036 _pad(TEGRA_IO_PAD_DSI, 2, UINT_MAX, "dsi"), \
2037 _pad(TEGRA_IO_PAD_MIPI_BIAS, 3, UINT_MAX, "mipi-bias"), \
2038 _pad(TEGRA_IO_PAD_PEX_CLK_BIAS, 4, UINT_MAX, "pex-clk-bias"), \
2039 _pad(TEGRA_IO_PAD_PEX_CLK3, 5, UINT_MAX, "pex-clk3"), \
2040 _pad(TEGRA_IO_PAD_PEX_CLK2, 6, UINT_MAX, "pex-clk2"), \
2041 _pad(TEGRA_IO_PAD_PEX_CLK1, 7, UINT_MAX, "pex-clk1"), \
2042 _pad(TEGRA_IO_PAD_USB0, 9, UINT_MAX, "usb0"), \
2043 _pad(TEGRA_IO_PAD_USB1, 10, UINT_MAX, "usb1"), \
2044 _pad(TEGRA_IO_PAD_USB2, 11, UINT_MAX, "usb2"), \
2045 _pad(TEGRA_IO_PAD_USB_BIAS, 12, UINT_MAX, "usb-bias"), \
2046 _pad(TEGRA_IO_PAD_UART, 14, UINT_MAX, "uart"), \
2047 _pad(TEGRA_IO_PAD_AUDIO, 17, UINT_MAX, "audio"), \
2048 _pad(TEGRA_IO_PAD_HSIC, 19, UINT_MAX, "hsic"), \
2049 _pad(TEGRA_IO_PAD_DBG, 25, UINT_MAX, "dbg"), \
2050 _pad(TEGRA_IO_PAD_HDMI_DP0, 28, UINT_MAX, "hdmi-dp0"), \
2051 _pad(TEGRA_IO_PAD_HDMI_DP1, 29, UINT_MAX, "hdmi-dp1"), \
2052 _pad(TEGRA_IO_PAD_PEX_CNTRL, 32, UINT_MAX, "pex-cntrl"), \
2053 _pad(TEGRA_IO_PAD_SDMMC2_HV, 34, 5, "sdmmc2-hv"), \
2054 _pad(TEGRA_IO_PAD_SDMMC4, 36, UINT_MAX, "sdmmc4"), \
2055 _pad(TEGRA_IO_PAD_CAM, 38, UINT_MAX, "cam"), \
2056 _pad(TEGRA_IO_PAD_DSIB, 40, UINT_MAX, "dsib"), \
2057 _pad(TEGRA_IO_PAD_DSIC, 41, UINT_MAX, "dsic"), \
2058 _pad(TEGRA_IO_PAD_DSID, 42, UINT_MAX, "dsid"), \
2059 _pad(TEGRA_IO_PAD_CSIC, 43, UINT_MAX, "csic"), \
2060 _pad(TEGRA_IO_PAD_CSID, 44, UINT_MAX, "csid"), \
2061 _pad(TEGRA_IO_PAD_CSIE, 45, UINT_MAX, "csie"), \
2062 _pad(TEGRA_IO_PAD_CSIF, 46, UINT_MAX, "csif"), \
2063 _pad(TEGRA_IO_PAD_SPI, 47, UINT_MAX, "spi"), \
2064 _pad(TEGRA_IO_PAD_UFS, 49, UINT_MAX, "ufs"), \
2065 _pad(TEGRA_IO_PAD_DMIC_HV, 52, 2, "dmic-hv"), \
2066 _pad(TEGRA_IO_PAD_EDP, 53, UINT_MAX, "edp"), \
2067 _pad(TEGRA_IO_PAD_SDMMC1_HV, 55, 4, "sdmmc1-hv"), \
2068 _pad(TEGRA_IO_PAD_SDMMC3_HV, 56, 6, "sdmmc3-hv"), \
2069 _pad(TEGRA_IO_PAD_CONN, 60, UINT_MAX, "conn"), \
2070 _pad(TEGRA_IO_PAD_AUDIO_HV, 61, 1, "audio-hv"), \
2071 _pad(TEGRA_IO_PAD_AO_HV, UINT_MAX, 0, "ao-hv")
2072
1789static const struct tegra_io_pad_soc tegra186_io_pads[] = { 2073static const struct tegra_io_pad_soc tegra186_io_pads[] = {
1790 { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, 2074 TEGRA186_IO_PAD_TABLE(TEGRA_IO_PAD)
1791 { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, 2075};
1792 { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, 2076
1793 { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, 2077static const struct pinctrl_pin_desc tegra186_pin_descs[] = {
1794 { .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX }, 2078 TEGRA186_IO_PAD_TABLE(TEGRA_IO_PIN_DESC)
1795 { .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX },
1796 { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX },
1797 { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX },
1798 { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX },
1799 { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX },
1800 { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX },
1801 { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX },
1802 { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX },
1803 { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX },
1804 { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX },
1805 { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX },
1806 { .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX },
1807 { .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX },
1808 { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX },
1809 { .id = TEGRA_IO_PAD_SDMMC2_HV, .dpd = 34, .voltage = UINT_MAX },
1810 { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX },
1811 { .id = TEGRA_IO_PAD_CAM, .dpd = 38, .voltage = UINT_MAX },
1812 { .id = TEGRA_IO_PAD_DSIB, .dpd = 40, .voltage = UINT_MAX },
1813 { .id = TEGRA_IO_PAD_DSIC, .dpd = 41, .voltage = UINT_MAX },
1814 { .id = TEGRA_IO_PAD_DSID, .dpd = 42, .voltage = UINT_MAX },
1815 { .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX },
1816 { .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX },
1817 { .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX },
1818 { .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX },
1819 { .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX },
1820 { .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX },
1821 { .id = TEGRA_IO_PAD_DMIC_HV, .dpd = 52, .voltage = UINT_MAX },
1822 { .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX },
1823 { .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX },
1824 { .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX },
1825 { .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX },
1826 { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX },
1827}; 2079};
1828 2080
1829static const struct tegra_pmc_regs tegra186_pmc_regs = { 2081static const struct tegra_pmc_regs tegra186_pmc_regs = {
@@ -1876,8 +2128,11 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = {
1876 .cpu_powergates = NULL, 2128 .cpu_powergates = NULL,
1877 .has_tsense_reset = false, 2129 .has_tsense_reset = false,
1878 .has_gpu_clamps = false, 2130 .has_gpu_clamps = false,
2131 .has_impl_33v_pwr = true,
1879 .num_io_pads = ARRAY_SIZE(tegra186_io_pads), 2132 .num_io_pads = ARRAY_SIZE(tegra186_io_pads),
1880 .io_pads = tegra186_io_pads, 2133 .io_pads = tegra186_io_pads,
2134 .num_pin_descs = ARRAY_SIZE(tegra186_pin_descs),
2135 .pin_descs = tegra186_pin_descs,
1881 .regs = &tegra186_pmc_regs, 2136 .regs = &tegra186_pmc_regs,
1882 .init = NULL, 2137 .init = NULL,
1883 .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, 2138 .setup_irq_polarity = tegra186_pmc_setup_irq_polarity,
diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c
index bbd4e5bc8707..e05ab16d9a9e 100644
--- a/drivers/soc/ti/knav_dma.c
+++ b/drivers/soc/ti/knav_dma.c
@@ -438,7 +438,7 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
438 438
439 chan_num = of_channel_match_helper(dev->of_node, name, &instance); 439 chan_num = of_channel_match_helper(dev->of_node, name, &instance);
440 if (chan_num < 0) { 440 if (chan_num < 0) {
441 dev_err(kdev->dev, "No DMA instace with name %s\n", name); 441 dev_err(kdev->dev, "No DMA instance with name %s\n", name);
442 return (void *)-EINVAL; 442 return (void *)-EINVAL;
443 } 443 }
444 444
@@ -461,7 +461,7 @@ void *knav_dma_open_channel(struct device *dev, const char *name,
461 } 461 }
462 } 462 }
463 if (!found) { 463 if (!found) {
464 dev_err(kdev->dev, "No DMA instace with name %s\n", instance); 464 dev_err(kdev->dev, "No DMA instance with name %s\n", instance);
465 return (void *)-EINVAL; 465 return (void *)-EINVAL;
466 } 466 }
467 467
diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
index 3efc47e82973..7c128132799e 100644
--- a/drivers/soc/ti/knav_qmss.h
+++ b/drivers/soc/ti/knav_qmss.h
@@ -240,14 +240,14 @@ struct knav_pool {
240}; 240};
241 241
242/** 242/**
243 * struct knav_queue_inst: qmss queue instace properties 243 * struct knav_queue_inst: qmss queue instance properties
244 * @descs: descriptor pointer 244 * @descs: descriptor pointer
245 * @desc_head, desc_tail, desc_count: descriptor counters 245 * @desc_head, desc_tail, desc_count: descriptor counters
246 * @acc: accumulator channel pointer 246 * @acc: accumulator channel pointer
247 * @kdev: qmss device pointer 247 * @kdev: qmss device pointer
248 * @range: range info 248 * @range: range info
249 * @qmgr: queue manager info 249 * @qmgr: queue manager info
250 * @id: queue instace id 250 * @id: queue instance id
251 * @irq_num: irq line number 251 * @irq_num: irq line number
252 * @notify_needed: notifier needed based on queue type 252 * @notify_needed: notifier needed based on queue type
253 * @num_notifiers: total notifiers 253 * @num_notifiers: total notifiers
@@ -274,7 +274,7 @@ struct knav_queue_inst {
274/** 274/**
275 * struct knav_queue: qmss queue properties 275 * struct knav_queue: qmss queue properties
276 * @reg_push, reg_pop, reg_peek: push, pop queue registers 276 * @reg_push, reg_pop, reg_peek: push, pop queue registers
277 * @inst: qmss queue instace properties 277 * @inst: qmss queue instance properties
278 * @notifier_fn: notifier function 278 * @notifier_fn: notifier function
279 * @notifier_fn_arg: notifier function argument 279 * @notifier_fn_arg: notifier function argument
280 * @notifier_enabled: notier enabled for a give queue 280 * @notifier_enabled: notier enabled for a give queue
diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c
index e1aafe842d66..34dce850067b 100644
--- a/drivers/tee/optee/core.c
+++ b/drivers/tee/optee/core.c
@@ -696,7 +696,7 @@ static int __init optee_driver_init(void)
696 return -ENODEV; 696 return -ENODEV;
697 697
698 np = of_find_matching_node(fw_np, optee_match); 698 np = of_find_matching_node(fw_np, optee_match);
699 if (!np) 699 if (!np || !of_device_is_available(np))
700 return -ENODEV; 700 return -ENODEV;
701 701
702 optee = optee_probe(np); 702 optee = optee_probe(np);
diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c
index dd46b758852a..7b2bb4c50058 100644
--- a/drivers/tee/tee_core.c
+++ b/drivers/tee/tee_core.c
@@ -38,15 +38,13 @@ static DEFINE_SPINLOCK(driver_lock);
38static struct class *tee_class; 38static struct class *tee_class;
39static dev_t tee_devt; 39static dev_t tee_devt;
40 40
41static int tee_open(struct inode *inode, struct file *filp) 41static struct tee_context *teedev_open(struct tee_device *teedev)
42{ 42{
43 int rc; 43 int rc;
44 struct tee_device *teedev;
45 struct tee_context *ctx; 44 struct tee_context *ctx;
46 45
47 teedev = container_of(inode->i_cdev, struct tee_device, cdev);
48 if (!tee_device_get(teedev)) 46 if (!tee_device_get(teedev))
49 return -EINVAL; 47 return ERR_PTR(-EINVAL);
50 48
51 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 49 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
52 if (!ctx) { 50 if (!ctx) {
@@ -57,16 +55,16 @@ static int tee_open(struct inode *inode, struct file *filp)
57 kref_init(&ctx->refcount); 55 kref_init(&ctx->refcount);
58 ctx->teedev = teedev; 56 ctx->teedev = teedev;
59 INIT_LIST_HEAD(&ctx->list_shm); 57 INIT_LIST_HEAD(&ctx->list_shm);
60 filp->private_data = ctx;
61 rc = teedev->desc->ops->open(ctx); 58 rc = teedev->desc->ops->open(ctx);
62 if (rc) 59 if (rc)
63 goto err; 60 goto err;
64 61
65 return 0; 62 return ctx;
66err: 63err:
67 kfree(ctx); 64 kfree(ctx);
68 tee_device_put(teedev); 65 tee_device_put(teedev);
69 return rc; 66 return ERR_PTR(rc);
67
70} 68}
71 69
72void teedev_ctx_get(struct tee_context *ctx) 70void teedev_ctx_get(struct tee_context *ctx)
@@ -100,6 +98,18 @@ static void teedev_close_context(struct tee_context *ctx)
100 teedev_ctx_put(ctx); 98 teedev_ctx_put(ctx);
101} 99}
102 100
101static int tee_open(struct inode *inode, struct file *filp)
102{
103 struct tee_context *ctx;
104
105 ctx = teedev_open(container_of(inode->i_cdev, struct tee_device, cdev));
106 if (IS_ERR(ctx))
107 return PTR_ERR(ctx);
108
109 filp->private_data = ctx;
110 return 0;
111}
112
103static int tee_release(struct inode *inode, struct file *filp) 113static int tee_release(struct inode *inode, struct file *filp)
104{ 114{
105 teedev_close_context(filp->private_data); 115 teedev_close_context(filp->private_data);
@@ -928,6 +938,95 @@ void *tee_get_drvdata(struct tee_device *teedev)
928} 938}
929EXPORT_SYMBOL_GPL(tee_get_drvdata); 939EXPORT_SYMBOL_GPL(tee_get_drvdata);
930 940
941struct match_dev_data {
942 struct tee_ioctl_version_data *vers;
943 const void *data;
944 int (*match)(struct tee_ioctl_version_data *, const void *);
945};
946
947static int match_dev(struct device *dev, const void *data)
948{
949 const struct match_dev_data *match_data = data;
950 struct tee_device *teedev = container_of(dev, struct tee_device, dev);
951
952 teedev->desc->ops->get_version(teedev, match_data->vers);
953 return match_data->match(match_data->vers, match_data->data);
954}
955
956struct tee_context *
957tee_client_open_context(struct tee_context *start,
958 int (*match)(struct tee_ioctl_version_data *,
959 const void *),
960 const void *data, struct tee_ioctl_version_data *vers)
961{
962 struct device *dev = NULL;
963 struct device *put_dev = NULL;
964 struct tee_context *ctx = NULL;
965 struct tee_ioctl_version_data v;
966 struct match_dev_data match_data = { vers ? vers : &v, data, match };
967
968 if (start)
969 dev = &start->teedev->dev;
970
971 do {
972 dev = class_find_device(tee_class, dev, &match_data, match_dev);
973 if (!dev) {
974 ctx = ERR_PTR(-ENOENT);
975 break;
976 }
977
978 put_device(put_dev);
979 put_dev = dev;
980
981 ctx = teedev_open(container_of(dev, struct tee_device, dev));
982 } while (IS_ERR(ctx) && PTR_ERR(ctx) != -ENOMEM);
983
984 put_device(put_dev);
985 return ctx;
986}
987EXPORT_SYMBOL_GPL(tee_client_open_context);
988
989void tee_client_close_context(struct tee_context *ctx)
990{
991 teedev_close_context(ctx);
992}
993EXPORT_SYMBOL_GPL(tee_client_close_context);
994
995void tee_client_get_version(struct tee_context *ctx,
996 struct tee_ioctl_version_data *vers)
997{
998 ctx->teedev->desc->ops->get_version(ctx->teedev, vers);
999}
1000EXPORT_SYMBOL_GPL(tee_client_get_version);
1001
1002int tee_client_open_session(struct tee_context *ctx,
1003 struct tee_ioctl_open_session_arg *arg,
1004 struct tee_param *param)
1005{
1006 if (!ctx->teedev->desc->ops->open_session)
1007 return -EINVAL;
1008 return ctx->teedev->desc->ops->open_session(ctx, arg, param);
1009}
1010EXPORT_SYMBOL_GPL(tee_client_open_session);
1011
1012int tee_client_close_session(struct tee_context *ctx, u32 session)
1013{
1014 if (!ctx->teedev->desc->ops->close_session)
1015 return -EINVAL;
1016 return ctx->teedev->desc->ops->close_session(ctx, session);
1017}
1018EXPORT_SYMBOL_GPL(tee_client_close_session);
1019
1020int tee_client_invoke_func(struct tee_context *ctx,
1021 struct tee_ioctl_invoke_arg *arg,
1022 struct tee_param *param)
1023{
1024 if (!ctx->teedev->desc->ops->invoke_func)
1025 return -EINVAL;
1026 return ctx->teedev->desc->ops->invoke_func(ctx, arg, param);
1027}
1028EXPORT_SYMBOL_GPL(tee_client_invoke_func);
1029
931static int __init tee_init(void) 1030static int __init tee_init(void)
932{ 1031{
933 int rc; 1032 int rc;