summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/bus/ti-sysc.txt1
-rw-r--r--Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt7
-rw-r--r--Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt18
-rw-r--r--Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt1
-rw-r--r--Documentation/devicetree/bindings/soc/rockchip/power_domain.txt4
-rw-r--r--Documentation/devicetree/bindings/sram/sunxi-sram.txt9
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c23
-rw-r--r--drivers/bus/brcmstb_gisb.c12
-rw-r--r--drivers/bus/ti-sysc.c55
-rw-r--r--drivers/dma/pxa_dma.c5
-rw-r--r--drivers/firmware/imx/Kconfig6
-rw-r--r--drivers/firmware/imx/Makefile3
-rw-r--r--drivers/firmware/imx/scu-pd.c339
-rw-r--r--drivers/firmware/raspberrypi.c48
-rw-r--r--drivers/firmware/tegra/bpmp-debugfs.c29
-rw-r--r--drivers/firmware/tegra/bpmp.c77
-rw-r--r--drivers/gpu/drm/msm/adreno/a6xx_gmu.c59
-rw-r--r--drivers/memory/omap-gpmc.c8
-rw-r--r--drivers/memory/tegra/Kconfig10
-rw-r--r--drivers/memory/tegra/Makefile1
-rw-r--r--drivers/memory/tegra/tegra20-emc.c591
-rw-r--r--drivers/soc/Makefile2
-rw-r--r--drivers/soc/amlogic/Kconfig9
-rw-r--r--drivers/soc/amlogic/Makefile1
-rw-r--r--drivers/soc/amlogic/meson-clk-measure.c350
-rw-r--r--drivers/soc/atmel/soc.c10
-rw-r--r--drivers/soc/atmel/soc.h7
-rw-r--r--drivers/soc/bcm/brcmstb/common.c6
-rw-r--r--drivers/soc/bcm/brcmstb/pm/pm-arm.c2
-rw-r--r--drivers/soc/bcm/raspberrypi-power.c5
-rw-r--r--drivers/soc/imx/Kconfig6
-rw-r--r--drivers/soc/imx/Makefile2
-rw-r--r--drivers/soc/imx/gpc.c2
-rw-r--r--drivers/soc/imx/gpcv2.c296
-rw-r--r--drivers/soc/mediatek/Kconfig12
-rw-r--r--drivers/soc/mediatek/Makefile1
-rw-r--r--drivers/soc/mediatek/mtk-cmdq-helper.c300
-rw-r--r--drivers/soc/qcom/Kconfig5
-rw-r--r--drivers/soc/qcom/cmd-db.c93
-rw-r--r--drivers/soc/qcom/llcc-slice.c17
-rw-r--r--drivers/soc/qcom/qcom-geni-se.c25
-rw-r--r--drivers/soc/qcom/qmi_interface.c2
-rw-r--r--drivers/soc/qcom/smd-rpm.c1
-rw-r--r--drivers/soc/renesas/r8a77965-sysc.c1
-rw-r--r--drivers/soc/renesas/r8a77970-sysc.c5
-rw-r--r--drivers/soc/renesas/r8a77980-sysc.c10
-rw-r--r--drivers/soc/renesas/r8a77990-sysc.c23
-rw-r--r--drivers/soc/renesas/rcar-sysc.c65
-rw-r--r--drivers/soc/rockchip/pm_domains.c48
-rw-r--r--drivers/soc/sunxi/sunxi_sram.c22
-rw-r--r--drivers/soc/tegra/common.c6
-rw-r--r--drivers/soc/tegra/pmc.c472
-rw-r--r--drivers/soc/ti/wkup_m3_ipc.c1
-rw-r--r--include/dt-bindings/power/imx8mq-power.h21
-rw-r--r--include/dt-bindings/power/r8a77970-sysc.h7
-rw-r--r--include/dt-bindings/power/r8a77980-sysc.h6
-rw-r--r--include/dt-bindings/power/raspberrypi-power.h5
-rw-r--r--include/dt-bindings/power/rk3066-power.h22
-rw-r--r--include/dt-bindings/power/rk3188-power.h24
-rw-r--r--include/linux/dma/pxa-dma.h11
-rw-r--r--include/linux/soc/mediatek/mtk-cmdq.h133
-rw-r--r--include/linux/soc/qcom/qmi.h2
-rw-r--r--include/soc/bcm2835/raspberrypi-firmware.h5
-rw-r--r--include/soc/qcom/cmd-db.h12
-rw-r--r--include/soc/tegra/bpmp-abi.h1188
-rw-r--r--include/soc/tegra/bpmp.h7
-rw-r--r--include/soc/tegra/fuse.h1
-rw-r--r--include/soc/tegra/pmc.h21
68 files changed, 3910 insertions, 668 deletions
diff --git a/Documentation/devicetree/bindings/bus/ti-sysc.txt b/Documentation/devicetree/bindings/bus/ti-sysc.txt
index 91dc2333af01..85a23f551f02 100644
--- a/Documentation/devicetree/bindings/bus/ti-sysc.txt
+++ b/Documentation/devicetree/bindings/bus/ti-sysc.txt
@@ -35,6 +35,7 @@ Required standard properties:
"ti,sysc-omap3-sham"
"ti,sysc-omap-aes"
"ti,sysc-mcasp"
+ "ti,sysc-dra7-mcasp"
"ti,sysc-usb-host-fs"
"ti,sysc-dra7-mcan"
diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt
index 9acce75b29ab..7c947a996df1 100644
--- a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt
+++ b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt
@@ -6,7 +6,9 @@ Control (PGC) for various power domains.
Required properties:
-- compatible: Should be "fsl,imx7d-gpc"
+- compatible: Should be one of:
+ - "fsl,imx7d-gpc"
+ - "fsl,imx8mq-gpc"
- reg: should be register base and length as documented in the
datasheet
@@ -22,7 +24,8 @@ which, in turn, is expected to contain the following:
Required properties:
- reg: Power domain index. Valid values are defined in
- include/dt-bindings/power/imx7-power.h
+ include/dt-bindings/power/imx7-power.h for fsl,imx7d-gpc and
+ include/dt-bindings/power/imx8m-power.h for fsl,imx8mq-gpc
- #power-domain-cells: Should be 0
diff --git a/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt b/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt
new file mode 100644
index 000000000000..205a54bcd7c7
--- /dev/null
+++ b/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt
@@ -0,0 +1,18 @@
+Amlogic Internal Clock Measurer
+===============================
+
+The Amlogic SoCs contains an IP to measure the internal clocks.
+The precision is multiple of MHz, useful to debug the clock states.
+
+Required properties:
+- compatible: Shall contain one of the following :
+ "amlogic,meson-gx-clk-measure" for GX SoCs
+ "amlogic,meson8-clk-measure" for Meson8 SoCs
+ "amlogic,meson8b-clk-measure" for Meson8b SoCs
+- reg: base address and size of the Clock Measurer register space.
+
+Example:
+ clock-measure@8758 {
+ compatible = "amlogic,meson-gx-clk-measure";
+ reg = <0x0 0x8758 0x0 0x10>;
+ };
diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt
index 89e1cb9212f6..ec95705ba692 100644
--- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt
+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt
@@ -23,6 +23,7 @@ resources.
"qcom,rpm-msm8916"
"qcom,rpm-msm8974"
"qcom,rpm-msm8998"
+ "qcom,rpm-qcs404"
- qcom,smd-channels:
Usage: required
diff --git a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt
index 5d49d0a2ff29..8304eceb62e4 100644
--- a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt
+++ b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt
@@ -7,7 +7,9 @@ Required properties for power domain controller:
- compatible: Should be one of the following.
"rockchip,px30-power-controller" - for PX30 SoCs.
"rockchip,rk3036-power-controller" - for RK3036 SoCs.
+ "rockchip,rk3066-power-controller" - for RK3066 SoCs.
"rockchip,rk3128-power-controller" - for RK3128 SoCs.
+ "rockchip,rk3188-power-controller" - for RK3188 SoCs.
"rockchip,rk3228-power-controller" - for RK3228 SoCs.
"rockchip,rk3288-power-controller" - for RK3288 SoCs.
"rockchip,rk3328-power-controller" - for RK3328 SoCs.
@@ -23,7 +25,9 @@ Required properties for power domain sub nodes:
- reg: index of the power domain, should use macros in:
"include/dt-bindings/power/px30-power.h" - for PX30 type power domain.
"include/dt-bindings/power/rk3036-power.h" - for RK3036 type power domain.
+ "include/dt-bindings/power/rk3066-power.h" - for RK3066 type power domain.
"include/dt-bindings/power/rk3128-power.h" - for RK3128 type power domain.
+ "include/dt-bindings/power/rk3188-power.h" - for RK3188 type power domain.
"include/dt-bindings/power/rk3228-power.h" - for RK3228 type power domain.
"include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain.
"include/dt-bindings/power/rk3328-power.h" - for RK3328 type power domain.
diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
index 62dd0748f0ef..ab5a70bb9a64 100644
--- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt
+++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt
@@ -18,7 +18,9 @@ Required properties:
- "allwinner,sun8i-h3-system-control"
- "allwinner,sun50i-a64-sram-controller" (deprecated)
- "allwinner,sun50i-a64-system-control"
+ - "allwinner,sun50i-h5-system-control"
- "allwinner,sun50i-h6-system-control", "allwinner,sun50i-a64-system-control"
+ - "allwinner,suniv-f1c100s-system-control", "allwinner,sun4i-a10-system-control"
- reg : sram controller register offset + length
SRAM nodes
@@ -54,10 +56,17 @@ The valid sections compatible for H3 are:
The valid sections compatible for A64 are:
- allwinner,sun50i-a64-sram-c
+ - allwinner,sun50i-a64-sram-c1, allwinner,sun4i-a10-sram-c1
+
+The valid sections compatible for H5 are:
+ - allwinner,sun50i-h5-sram-c1, allwinner,sun4i-a10-sram-c1
The valid sections compatible for H6 are:
- allwinner,sun50i-h6-sram-c, allwinner,sun50i-a64-sram-c
+The valid sections compatible for F1C100s are:
+ - allwinner,suniv-f1c100s-sram-d, allwinner,sun4i-a10-sram-d
+
Devices using SRAM sections
---------------------------
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 921c9aaee63f..b5531dd3ae9c 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -2345,6 +2345,17 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data,
return 0;
}
+static void __init parse_module_flags(struct omap_hwmod *oh,
+ struct device_node *np)
+{
+ if (of_find_property(np, "ti,no-reset-on-init", NULL))
+ oh->flags |= HWMOD_INIT_NO_RESET;
+ if (of_find_property(np, "ti,no-idle-on-init", NULL))
+ oh->flags |= HWMOD_INIT_NO_IDLE;
+ if (of_find_property(np, "ti,no-idle", NULL))
+ oh->flags |= HWMOD_NO_IDLE;
+}
+
/**
* _init - initialize internal data for the hwmod @oh
* @oh: struct omap_hwmod *
@@ -2392,12 +2403,12 @@ static int __init _init(struct omap_hwmod *oh, void *data)
}
if (np) {
- if (of_find_property(np, "ti,no-reset-on-init", NULL))
- oh->flags |= HWMOD_INIT_NO_RESET;
- if (of_find_property(np, "ti,no-idle-on-init", NULL))
- oh->flags |= HWMOD_INIT_NO_IDLE;
- if (of_find_property(np, "ti,no-idle", NULL))
- oh->flags |= HWMOD_NO_IDLE;
+ struct device_node *child;
+
+ parse_module_flags(oh, np);
+ child = of_get_next_child(np, NULL);
+ if (child)
+ parse_module_flags(oh, child);
}
oh->_state = _HWMOD_STATE_INITIALIZED;
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index 68ac3e93b600..f58ff67e97ac 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -150,8 +150,7 @@ static ssize_t gisb_arb_get_timeout(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
+ struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
u32 timeout;
mutex_lock(&gdev->lock);
@@ -165,8 +164,7 @@ static ssize_t gisb_arb_set_timeout(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
+ struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
int val, ret;
ret = kstrtoint(buf, 10, &val);
@@ -418,8 +416,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
#ifdef CONFIG_PM_SLEEP
static int brcmstb_gisb_arb_suspend(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
+ struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
gdev->saved_timeout = gisb_read(gdev, ARB_TIMER);
@@ -431,8 +428,7 @@ static int brcmstb_gisb_arb_suspend(struct device *dev)
*/
static int brcmstb_gisb_arb_resume_noirq(struct device *dev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
+ struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev);
gisb_write(gdev, gdev->saved_timeout, ARB_TIMER);
diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c
index a3a2d39280d9..f94d33525771 100644
--- a/drivers/bus/ti-sysc.c
+++ b/drivers/bus/ti-sysc.c
@@ -91,6 +91,9 @@ struct sysc {
struct delayed_work idle_work;
};
+static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
+ bool is_child);
+
void sysc_write(struct sysc *ddata, int offset, u32 value)
{
writel_relaxed(value, ddata->module_va + offset);
@@ -214,8 +217,13 @@ static int sysc_get_clocks(struct sysc *ddata)
if (!ddata->clocks)
return -ENOMEM;
- for (i = 0; i < ddata->nr_clocks; i++) {
- error = sysc_get_one_clock(ddata, ddata->clock_roles[i]);
+ for (i = 0; i < SYSC_MAX_CLOCKS; i++) {
+ const char *name = ddata->clock_roles[i];
+
+ if (!name)
+ continue;
+
+ error = sysc_get_one_clock(ddata, name);
if (error && error != -ENOENT)
return error;
}
@@ -374,6 +382,7 @@ static int sysc_check_one_child(struct sysc *ddata,
dev_warn(ddata->dev, "really a child ti,hwmods property?");
sysc_check_quirk_stdout(ddata, np);
+ sysc_parse_dts_quirks(ddata, np, true);
return 0;
}
@@ -815,6 +824,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0),
SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0),
SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0),
+ SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0),
SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0),
SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0),
SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0),
@@ -833,7 +843,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = {
SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0),
SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0),
SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0),
+ SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0),
SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0),
+ SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0),
SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050,
0xffffffff, 0),
SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0),
@@ -1271,23 +1283,37 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = {
.mask = SYSC_QUIRK_NO_RESET_ON_INIT, },
};
-static int sysc_init_dts_quirks(struct sysc *ddata)
+static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np,
+ bool is_child)
{
- struct device_node *np = ddata->dev->of_node;
const struct property *prop;
- int i, len, error;
- u32 val;
-
- ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
+ int i, len;
for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) {
- prop = of_get_property(np, sysc_dts_quirks[i].name, &len);
+ const char *name = sysc_dts_quirks[i].name;
+
+ prop = of_get_property(np, name, &len);
if (!prop)
continue;
ddata->cfg.quirks |= sysc_dts_quirks[i].mask;
+ if (is_child) {
+ dev_warn(ddata->dev,
+ "dts flag should be at module level for %s\n",
+ name);
+ }
}
+}
+static int sysc_init_dts_quirks(struct sysc *ddata)
+{
+ struct device_node *np = ddata->dev->of_node;
+ int error;
+ u32 val;
+
+ ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL);
+
+ sysc_parse_dts_quirks(ddata, np, false);
error = of_property_read_u32(np, "ti,sysc-delay-us", &val);
if (!error) {
if (val > 255) {
@@ -1498,6 +1524,16 @@ static const struct sysc_regbits sysc_regbits_omap4_mcasp = {
static const struct sysc_capabilities sysc_omap4_mcasp = {
.type = TI_SYSC_OMAP4_MCASP,
.regbits = &sysc_regbits_omap4_mcasp,
+ .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED,
+};
+
+/*
+ * McASP found on dra7 and later
+ */
+static const struct sysc_capabilities sysc_dra7_mcasp = {
+ .type = TI_SYSC_OMAP4_SIMPLE,
+ .regbits = &sysc_regbits_omap4_simple,
+ .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED,
};
/*
@@ -1726,6 +1762,7 @@ static const struct of_device_id sysc_match[] = {
{ .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, },
{ .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, },
{ .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, },
+ { .compatible = "ti,sysc-dra7-mcasp", .data = &sysc_dra7_mcasp, },
{ .compatible = "ti,sysc-usb-host-fs",
.data = &sysc_omap4_usb_host_fs, },
{ .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, },
diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c
index 825725057e00..c7a328f81485 100644
--- a/drivers/dma/pxa_dma.c
+++ b/drivers/dma/pxa_dma.c
@@ -179,7 +179,7 @@ static unsigned int pxad_drcmr(unsigned int line)
return 0x1000 + line * 4;
}
-bool pxad_filter_fn(struct dma_chan *chan, void *param);
+static bool pxad_filter_fn(struct dma_chan *chan, void *param);
/*
* Debug fs
@@ -1500,7 +1500,7 @@ static struct platform_driver pxad_driver = {
.remove = pxad_remove,
};
-bool pxad_filter_fn(struct dma_chan *chan, void *param)
+static bool pxad_filter_fn(struct dma_chan *chan, void *param)
{
struct pxad_chan *c = to_pxad_chan(chan);
struct pxad_param *p = param;
@@ -1513,7 +1513,6 @@ bool pxad_filter_fn(struct dma_chan *chan, void *param)
return true;
}
-EXPORT_SYMBOL_GPL(pxad_filter_fn);
module_platform_driver(pxad_driver);
diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig
index b170c2851e48..6a7a7c2c5b5f 100644
--- a/drivers/firmware/imx/Kconfig
+++ b/drivers/firmware/imx/Kconfig
@@ -9,3 +9,9 @@ config IMX_SCU
This driver manages the IPC interface between host CPU and the
SCU firmware running on M4.
+
+config IMX_SCU_PD
+ bool "IMX SCU Power Domain driver"
+ depends on IMX_SCU
+ help
+ The System Controller Firmware (SCFW) based power domain driver.
diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile
index 0ac04dfda8d4..1b2e15b3c9ca 100644
--- a/drivers/firmware/imx/Makefile
+++ b/drivers/firmware/imx/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
-obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
+obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o
+obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o
diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c
new file mode 100644
index 000000000000..407245f2efd0
--- /dev/null
+++ b/drivers/firmware/imx/scu-pd.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ * Dong Aisheng <aisheng.dong@nxp.com>
+ *
+ * Implementation of the SCU based Power Domains
+ *
+ * NOTE: a better implementation suggested by Ulf Hansson is using a
+ * single global power domain and implement the ->attach|detach_dev()
+ * callback for the genpd and use the regular of_genpd_add_provider_simple().
+ * From within the ->attach_dev(), we could get the OF node for
+ * the device that is being attached and then parse the power-domain
+ * cell containing the "resource id" and store that in the per device
+ * struct generic_pm_domain_data (we have void pointer there for
+ * storing these kind of things).
+ *
+ * Additionally, we need to implement the ->stop() and ->start()
+ * callbacks of genpd, which is where you "power on/off" devices,
+ * rather than using the above ->power_on|off() callbacks.
+ *
+ * However, there're two known issues:
+ * 1. The ->attach_dev() of power domain infrastructure still does
+ * not support multi domains case as the struct device *dev passed
+ * in is a virtual PD device, it does not help for parsing the real
+ * device resource id from device tree, so it's unware of which
+ * real sub power domain of device should be attached.
+ *
+ * The framework needs some proper extension to support multi power
+ * domain cases.
+ *
+ * 2. It also breaks most of current drivers as the driver probe sequence
+ * behavior changed if removing ->power_on|off() callback and use
+ * ->start() and ->stop() instead. genpd_dev_pm_attach will only power
+ * up the domain and attach device, but will not call .start() which
+ * relies on device runtime pm. That means the device power is still
+ * not up before running driver probe function. For SCU enabled
+ * platforms, all device drivers accessing registers/clock without power
+ * domain enabled will trigger a HW access error. That means we need fix
+ * most drivers probe sequence with proper runtime pm.
+ *
+ * In summary, we need fix above two issue before being able to switch to
+ * the "single global power domain" way.
+ *
+ */
+
+#include <dt-bindings/firmware/imx/rsrc.h>
+#include <linux/firmware/imx/sci.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+
+/* SCU Power Mode Protocol definition */
+struct imx_sc_msg_req_set_resource_power_mode {
+ struct imx_sc_rpc_msg hdr;
+ u16 resource;
+ u8 mode;
+} __packed;
+
+#define IMX_SCU_PD_NAME_SIZE 20
+struct imx_sc_pm_domain {
+ struct generic_pm_domain pd;
+ char name[IMX_SCU_PD_NAME_SIZE];
+ u32 rsrc;
+};
+
+struct imx_sc_pd_range {
+ char *name;
+ u32 rsrc;
+ u8 num;
+ bool postfix;
+};
+