summaryrefslogtreecommitdiffstats
path: root/drivers/soc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-04 14:47:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-04 14:47:47 -0700
commite8547112910540afb71589ee807ae6a4259f9755 (patch)
tree7d3d7eb17be4e6d2b181bffc4d471e93063674b4 /drivers/soc
parent9ce32ac8f83729aca9f45ce9598dbc5451d1044b (diff)
parentffe3744a591fdce695da6b891378261e2caedc69 (diff)
downloadlinux-e8547112910540afb71589ee807ae6a4259f9755.tar.gz
linux-e8547112910540afb71589ee807ae6a4259f9755.tar.bz2
linux-e8547112910540afb71589ee807ae6a4259f9755.zip
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: "New SoC specific drivers: - NVIDIA Tegra PM Domain support for newer SoCs (Tegra186 and later) based on the "BPMP" firmware - Clocksource and system controller drivers for the newly added Action Semi platforms (both arm and arm64). Reset subsystem, merged through arm-soc by tradition: - New drivers for Altera Stratix10, TI Keystone and Cortina Gemini SoCs - Various subsystem-wide cleanups Updates for existing SoC-specific drivers - TI GPMC (General Purpose Memory Controller) - Mediatek "scpsys" system controller support for MT6797 - Broadcom "brcmstb_gisb" bus arbitrer - ARM SCPI firmware - Renesas "SYSC" system controller One more driver update was submitted for the Freescale/NXP DPAA data path acceleration that has previously been used on PowerPC chips. I ended up postponing the merge until some API questions for its unusual MMIO access are resolved" * tag 'armsoc-drivers' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (35 commits) clocksource: owl: Add S900 support clocksource: Add Owl timer soc: renesas: rcar-sysc: Use GENPD_FLAG_ALWAYS_ON firmware: tegra: Fix locking bugs in BPMP soc/tegra: flowctrl: Fix error handling soc/tegra: bpmp: Implement generic PM domains soc/tegra: bpmp: Update ABI header PM / Domains: Allow overriding the ->xlate() callback soc: brcmstb: enable drivers for ARM64 and BMIPS soc: renesas: Rework Kconfig and Makefile logic reset: Add the TI SCI reset driver dt-bindings: reset: Add TI SCI reset binding reset: use kref for reference counting soc: qcom: smsm: Improve error handling, quiesce probe deferral cpufreq: scpi: use new scpi_ops functions to remove duplicate code firmware: arm_scpi: add support to populate OPPs and get transition latency dt-bindings: reset: Add reset manager offsets for Stratix10 memory: omap-gpmc: add error message if bank-width property is absent memory: omap-gpmc: make dts snippet include semicolon reset: Add a Gemini reset controller ...
Diffstat (limited to 'drivers/soc')
-rw-r--r--drivers/soc/Kconfig1
-rw-r--r--drivers/soc/Makefile2
-rw-r--r--drivers/soc/bcm/Kconfig2
-rw-r--r--drivers/soc/imx/Makefile2
-rw-r--r--drivers/soc/mediatek/mtk-pmic-wrap.c14
-rw-r--r--drivers/soc/mediatek/mtk-scpsys.c149
-rw-r--r--drivers/soc/qcom/smsm.c9
-rw-r--r--drivers/soc/renesas/Kconfig63
-rw-r--r--drivers/soc/renesas/Makefile31
-rw-r--r--drivers/soc/renesas/rcar-sysc.c52
-rw-r--r--drivers/soc/renesas/rcar-sysc.h2
-rw-r--r--drivers/soc/tegra/Kconfig5
-rw-r--r--drivers/soc/tegra/Makefile1
-rw-r--r--drivers/soc/tegra/flowctrl.c2
-rw-r--r--drivers/soc/tegra/powergate-bpmp.c359
15 files changed, 622 insertions, 72 deletions
diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index a63eb0ffba98..07fc0ac51c52 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -7,6 +7,7 @@ source "drivers/soc/fsl/Kconfig"
source "drivers/soc/imx/Kconfig"
source "drivers/soc/mediatek/Kconfig"
source "drivers/soc/qcom/Kconfig"
+source "drivers/soc/renesas/Kconfig"
source "drivers/soc/rockchip/Kconfig"
source "drivers/soc/samsung/Kconfig"
source "drivers/soc/sunxi/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index a3b27a33c309..9241125416ba 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -11,7 +11,7 @@ obj-y += fsl/
obj-$(CONFIG_ARCH_MXC) += imx/
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
obj-$(CONFIG_ARCH_QCOM) += qcom/
-obj-$(CONFIG_ARCH_RENESAS) += renesas/
+obj-y += renesas/
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_SOC_SAMSUNG) += samsung/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig
index a39b0d58ddd0..49f1e2a75d61 100644
--- a/drivers/soc/bcm/Kconfig
+++ b/drivers/soc/bcm/Kconfig
@@ -11,7 +11,7 @@ config RASPBERRYPI_POWER
config SOC_BRCMSTB
bool "Broadcom STB SoC drivers"
- depends on ARM
+ depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST
select SOC_BUS
help
Enables drivers for the Broadcom Set-Top Box (STB) series of chips.
diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile
index 5b6e396c1121..aab41a5cc317 100644
--- a/drivers/soc/imx/Makefile
+++ b/drivers/soc/imx/Makefile
@@ -1,2 +1,2 @@
-obj-y += gpc.o
+obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_IMX7_PM_DOMAINS) += gpcv2.o
diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c
index a5f10936fb9c..c80a04e1b2b1 100644
--- a/drivers/soc/mediatek/mtk-pmic-wrap.c
+++ b/drivers/soc/mediatek/mtk-pmic-wrap.c
@@ -1117,6 +1117,11 @@ static int pwrap_probe(struct platform_device *pdev)
const struct of_device_id *of_slave_id = NULL;
struct resource *res;
+ if (!of_id) {
+ dev_err(&pdev->dev, "Error: No device match found\n");
+ return -ENODEV;
+ }
+
if (pdev->dev.of_node->child)
of_slave_id = of_match_node(of_slave_match_tbl,
pdev->dev.of_node->child);
@@ -1200,7 +1205,8 @@ static int pwrap_probe(struct platform_device *pdev)
if (!(pwrap_readl(wrp, PWRAP_WACS2_RDATA) & PWRAP_STATE_INIT_DONE0)) {
dev_dbg(wrp->dev, "initialization isn't finished\n");
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_out2;
}
/* Initialize watchdog, may not be done by the bootloader */
@@ -1220,8 +1226,10 @@ static int pwrap_probe(struct platform_device *pdev)
goto err_out2;
wrp->regmap = devm_regmap_init(wrp->dev, NULL, wrp, &pwrap_regmap_config);
- if (IS_ERR(wrp->regmap))
- return PTR_ERR(wrp->regmap);
+ if (IS_ERR(wrp->regmap)) {
+ ret = PTR_ERR(wrp->regmap);
+ goto err_out2;
+ }
ret = of_platform_populate(np, NULL, NULL, wrp->dev);
if (ret) {
diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c
index beb79162369a..ceb2cc495cd0 100644
--- a/drivers/soc/mediatek/mtk-scpsys.c
+++ b/drivers/soc/mediatek/mtk-scpsys.c
@@ -21,6 +21,7 @@
#include <linux/soc/mediatek/infracfg.h>
#include <dt-bindings/power/mt2701-power.h>
+#include <dt-bindings/power/mt6797-power.h>
#include <dt-bindings/power/mt8173-power.h>
#define SPM_VDE_PWR_CON 0x0210
@@ -71,6 +72,7 @@ enum clk_id {
CLK_VENC,
CLK_VENC_LT,
CLK_ETHIF,
+ CLK_VDEC,
CLK_MAX,
};
@@ -81,6 +83,7 @@ static const char * const clk_names[] = {
"venc",
"venc_lt",
"ethif",
+ "vdec",
NULL,
};
@@ -107,21 +110,28 @@ struct scp_domain {
struct regulator *supply;
};
+struct scp_ctrl_reg {
+ int pwr_sta_offs;
+ int pwr_sta2nd_offs;
+};
+
struct scp {
struct scp_domain *domains;
struct genpd_onecell_data pd_data;
struct device *dev;
void __iomem *base;
struct regmap *infracfg;
+ struct scp_ctrl_reg ctrl_reg;
};
static int scpsys_domain_is_on(struct scp_domain *scpd)
{
struct scp *scp = scpd->scp;
- u32 status = readl(scp->base + SPM_PWR_STATUS) & scpd->data->sta_mask;
- u32 status2 = readl(scp->base + SPM_PWR_STATUS_2ND) &
- scpd->data->sta_mask;
+ u32 status = readl(scp->base + scp->ctrl_reg.pwr_sta_offs) &
+ scpd->data->sta_mask;
+ u32 status2 = readl(scp->base + scp->ctrl_reg.pwr_sta2nd_offs) &
+ scpd->data->sta_mask;
/*
* A domain is on when both status bits are set. If only one is set
@@ -346,7 +356,8 @@ static void init_clks(struct platform_device *pdev, struct clk **clk)
}
static struct scp *init_scp(struct platform_device *pdev,
- const struct scp_domain_data *scp_domain_data, int num)
+ const struct scp_domain_data *scp_domain_data, int num,
+ struct scp_ctrl_reg *scp_ctrl_reg)
{
struct genpd_onecell_data *pd_data;
struct resource *res;
@@ -358,6 +369,9 @@ static struct scp *init_scp(struct platform_device *pdev,
if (!scp)
return ERR_PTR(-ENOMEM);
+ scp->ctrl_reg.pwr_sta_offs = scp_ctrl_reg->pwr_sta_offs;
+ scp->ctrl_reg.pwr_sta2nd_offs = scp_ctrl_reg->pwr_sta2nd_offs;
+
scp->dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -556,8 +570,13 @@ static const struct scp_domain_data scp_domain_data_mt2701[] = {
static int __init scpsys_probe_mt2701(struct platform_device *pdev)
{
struct scp *scp;
+ struct scp_ctrl_reg scp_reg;
- scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701);
+ scp_reg.pwr_sta_offs = SPM_PWR_STATUS;
+ scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND;
+
+ scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701,
+ &scp_reg);
if (IS_ERR(scp))
return PTR_ERR(scp);
@@ -567,6 +586,116 @@ static int __init scpsys_probe_mt2701(struct platform_device *pdev)
}
/*
+ * MT6797 power domain support
+ */
+
+static const struct scp_domain_data scp_domain_data_mt6797[] = {
+ [MT6797_POWER_DOMAIN_VDEC] = {
+ .name = "vdec",
+ .sta_mask = BIT(7),
+ .ctl_offs = 0x300,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_VDEC},
+ },
+ [MT6797_POWER_DOMAIN_VENC] = {
+ .name = "venc",
+ .sta_mask = BIT(21),
+ .ctl_offs = 0x304,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT6797_POWER_DOMAIN_ISP] = {
+ .name = "isp",
+ .sta_mask = BIT(5),
+ .ctl_offs = 0x308,
+ .sram_pdn_bits = GENMASK(9, 8),
+ .sram_pdn_ack_bits = GENMASK(13, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT6797_POWER_DOMAIN_MM] = {
+ .name = "mm",
+ .sta_mask = BIT(3),
+ .ctl_offs = 0x30C,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_MM},
+ .bus_prot_mask = (BIT(1) | BIT(2)),
+ },
+ [MT6797_POWER_DOMAIN_AUDIO] = {
+ .name = "audio",
+ .sta_mask = BIT(24),
+ .ctl_offs = 0x314,
+ .sram_pdn_bits = GENMASK(11, 8),
+ .sram_pdn_ack_bits = GENMASK(15, 12),
+ .clk_id = {CLK_NONE},
+ },
+ [MT6797_POWER_DOMAIN_MFG_ASYNC] = {
+ .name = "mfg_async",
+ .sta_mask = BIT(13),
+ .ctl_offs = 0x334,
+ .sram_pdn_bits = 0,
+ .sram_pdn_ack_bits = 0,
+ .clk_id = {CLK_MFG},
+ },
+ [MT6797_POWER_DOMAIN_MJC] = {
+ .name = "mjc",
+ .sta_mask = BIT(20),
+ .ctl_offs = 0x310,
+ .sram_pdn_bits = GENMASK(8, 8),
+ .sram_pdn_ack_bits = GENMASK(12, 12),
+ .clk_id = {CLK_NONE},
+ },
+};
+
+#define NUM_DOMAINS_MT6797 ARRAY_SIZE(scp_domain_data_mt6797)
+#define SPM_PWR_STATUS_MT6797 0x0180
+#define SPM_PWR_STATUS_2ND_MT6797 0x0184
+
+static int __init scpsys_probe_mt6797(struct platform_device *pdev)
+{
+ struct scp *scp;
+ struct genpd_onecell_data *pd_data;
+ int ret;
+ struct scp_ctrl_reg scp_reg;
+
+ scp_reg.pwr_sta_offs = SPM_PWR_STATUS_MT6797;
+ scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND_MT6797;
+
+ scp = init_scp(pdev, scp_domain_data_mt6797, NUM_DOMAINS_MT6797,
+ &scp_reg);
+ if (IS_ERR(scp))
+ return PTR_ERR(scp);
+
+ mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT6797);
+
+ pd_data = &scp->pd_data;
+
+ ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
+ pd_data->domains[MT6797_POWER_DOMAIN_VDEC]);
+ if (ret && IS_ENABLED(CONFIG_PM))
+ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+
+ ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
+ pd_data->domains[MT6797_POWER_DOMAIN_ISP]);
+ if (ret && IS_ENABLED(CONFIG_PM))
+ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+
+ ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
+ pd_data->domains[MT6797_POWER_DOMAIN_VENC]);
+ if (ret && IS_ENABLED(CONFIG_PM))
+ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+
+ ret = pm_genpd_add_subdomain(pd_data->domains[MT6797_POWER_DOMAIN_MM],
+ pd_data->domains[MT6797_POWER_DOMAIN_MJC]);
+ if (ret && IS_ENABLED(CONFIG_PM))
+ dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
+
+ return 0;
+}
+
+/*
* MT8173 power domain support
*/
@@ -667,8 +796,13 @@ static int __init scpsys_probe_mt8173(struct platform_device *pdev)
struct scp *scp;
struct genpd_onecell_data *pd_data;
int ret;
+ struct scp_ctrl_reg scp_reg;
- scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173);
+ scp_reg.pwr_sta_offs = SPM_PWR_STATUS;
+ scp_reg.pwr_sta2nd_offs = SPM_PWR_STATUS_2ND;
+
+ scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173,
+ &scp_reg);
if (IS_ERR(scp))
return PTR_ERR(scp);
@@ -698,6 +832,9 @@ static const struct of_device_id of_scpsys_match_tbl[] = {
.compatible = "mediatek,mt2701-scpsys",
.data = scpsys_probe_mt2701,
}, {
+ .compatible = "mediatek,mt6797-scpsys",
+ .data = scpsys_probe_mt6797,
+ }, {
.compatible = "mediatek,mt8173-scpsys",
.data = scpsys_probe_mt8173,
}, {
diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c
index d0337b2a71c8..dc540ea92e9d 100644
--- a/drivers/soc/qcom/smsm.c
+++ b/drivers/soc/qcom/smsm.c
@@ -439,14 +439,15 @@ static int smsm_get_size_info(struct qcom_smsm *smsm)
} *info;
info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_SMSM_SIZE_INFO, &size);
- if (PTR_ERR(info) == -ENOENT || size != sizeof(*info)) {
+ if (IS_ERR(info) && PTR_ERR(info) != -ENOENT) {
+ if (PTR_ERR(info) != -EPROBE_DEFER)
+ dev_err(smsm->dev, "unable to retrieve smsm size info\n");
+ return PTR_ERR(info);
+ } else if (IS_ERR(info) || size != sizeof(*info)) {
dev_warn(smsm->dev, "no smsm size info, using defaults\n");
smsm->num_entries = SMSM_DEFAULT_NUM_ENTRIES;
smsm->num_hosts = SMSM_DEFAULT_NUM_HOSTS;
return 0;
- } else if (IS_ERR(info)) {
- dev_err(smsm->dev, "unable to retrieve smsm size info\n");
- return PTR_ERR(info);
}
smsm->num_entries = info->num_entries;
diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig
new file mode 100644
index 000000000000..87a4be46bd98
--- /dev/null
+++ b/drivers/soc/renesas/Kconfig
@@ -0,0 +1,63 @@
+config SOC_RENESAS
+ bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS
+ default y if ARCH_RENESAS
+ select SOC_BUS
+ select RST_RCAR if ARCH_RCAR_GEN1 || ARCH_RCAR_GEN2 || \
+ ARCH_R8A7795 || ARCH_R8A7796
+ select SYSC_R8A7743 if ARCH_R8A7743
+ select SYSC_R8A7745 if ARCH_R8A7745
+ select SYSC_R8A7779 if ARCH_R8A7779
+ select SYSC_R8A7790 if ARCH_R8A7790
+ select SYSC_R8A7791 if ARCH_R8A7791 || ARCH_R8A7793
+ select SYSC_R8A7792 if ARCH_R8A7792
+ select SYSC_R8A7794 if ARCH_R8A7794
+ select SYSC_R8A7795 if ARCH_R8A7795
+ select SYSC_R8A7796 if ARCH_R8A7796
+
+if SOC_RENESAS
+
+# SoC
+config SYSC_R8A7743
+ bool "RZ/G1M System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7745
+ bool "RZ/G1E System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7779
+ bool "R-Car H1 System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7790
+ bool "R-Car H2 System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7791
+ bool "R-Car M2-W/N System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7792
+ bool "R-Car V2H System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7794
+ bool "R-Car E2 System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7795
+ bool "R-Car H3 System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+config SYSC_R8A7796
+ bool "R-Car M3-W System Controller support" if COMPILE_TEST
+ select SYSC_RCAR
+
+# Family
+config RST_RCAR
+ bool "R-Car Reset Controller support" if COMPILE_TEST
+
+config SYSC_RCAR
+ bool "R-Car System Controller support" if COMPILE_TEST
+
+endif # SOC_RENESAS
diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile
index d9115cb5ed9d..1a1a297b26a7 100644
--- a/drivers/soc/renesas/Makefile
+++ b/drivers/soc/renesas/Makefile
@@ -1,18 +1,17 @@
-obj-$(CONFIG_SOC_BUS) += renesas-soc.o
+# Generic, must be first because of soc_device_register()
+obj-$(CONFIG_SOC_RENESAS) += renesas-soc.o
-obj-$(CONFIG_ARCH_RCAR_GEN1) += rcar-rst.o
-obj-$(CONFIG_ARCH_RCAR_GEN2) += rcar-rst.o
-obj-$(CONFIG_ARCH_R8A7795) += rcar-rst.o
-obj-$(CONFIG_ARCH_R8A7796) += rcar-rst.o
+# SoC
+obj-$(CONFIG_SYSC_R8A7743) += r8a7743-sysc.o
+obj-$(CONFIG_SYSC_R8A7745) += r8a7745-sysc.o
+obj-$(CONFIG_SYSC_R8A7779) += r8a7779-sysc.o
+obj-$(CONFIG_SYSC_R8A7790) += r8a7790-sysc.o
+obj-$(CONFIG_SYSC_R8A7791) += r8a7791-sysc.o
+obj-$(CONFIG_SYSC_R8A7792) += r8a7792-sysc.o
+obj-$(CONFIG_SYSC_R8A7794) += r8a7794-sysc.o
+obj-$(CONFIG_SYSC_R8A7795) += r8a7795-sysc.o
+obj-$(CONFIG_SYSC_R8A7796) += r8a7796-sysc.o
-obj-$(CONFIG_ARCH_R8A7743) += rcar-sysc.o r8a7743-sysc.o
-obj-$(CONFIG_ARCH_R8A7745) += rcar-sysc.o r8a7745-sysc.o
-obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o
-obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o
-obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o
-obj-$(CONFIG_ARCH_R8A7792) += rcar-sysc.o r8a7792-sysc.o
-# R-Car M2-N is identical to R-Car M2-W w.r.t. power domains.
-obj-$(CONFIG_ARCH_R8A7793) += rcar-sysc.o r8a7791-sysc.o
-obj-$(CONFIG_ARCH_R8A7794) += rcar-sysc.o r8a7794-sysc.o
-obj-$(CONFIG_ARCH_R8A7795) += rcar-sysc.o r8a7795-sysc.o
-obj-$(CONFIG_ARCH_R8A7796) += rcar-sysc.o r8a7796-sysc.o
+# Family
+obj-$(CONFIG_RST_RCAR) += rcar-rst.o
+obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o
diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c
index 528a13742aeb..7c8da3c90011 100644
--- a/drivers/soc/renesas/rcar-sysc.c
+++ b/drivers/soc/renesas/rcar-sysc.c
@@ -181,17 +181,6 @@ static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd)
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
pr_debug("%s: %s\n", __func__, genpd->name);
-
- if (pd->flags & PD_NO_CR) {
- pr_debug("%s: Cannot control %s\n", __func__, genpd->name);
- return -EBUSY;
- }
-
- if (pd->flags & PD_BUSY) {
- pr_debug("%s: %s busy\n", __func__, genpd->name);
- return -EBUSY;
- }
-
return rcar_sysc_power_down(&pd->ch);
}
@@ -200,12 +189,6 @@ static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd)
struct rcar_sysc_pd *pd = to_rcar_pd(genpd);
pr_debug("%s: %s\n", __func__, genpd->name);
-
- if (pd->flags & PD_NO_CR) {
- pr_debug("%s: Cannot control %s\n", __func__, genpd->name);
- return 0;
- }
-
return rcar_sysc_power_up(&pd->ch);
}
@@ -223,8 +206,7 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
* only be turned off if the CPU is not in use.
*/
pr_debug("PM domain %s contains %s\n", name, "CPU");
- pd->flags |= PD_BUSY;
- gov = &pm_domain_always_on_gov;
+ genpd->flags |= GENPD_FLAG_ALWAYS_ON;
} else if (pd->flags & PD_SCU) {
/*
* This domain contains an SCU and cache-controller, and
@@ -232,19 +214,17 @@ static void __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd)
* not in use.
*/
pr_debug("PM domain %s contains %s\n", name, "SCU");
- pd->flags |= PD_BUSY;
- gov = &pm_domain_always_on_gov;
+ genpd->flags |= GENPD_FLAG_ALWAYS_ON;
} else if (pd->flags & PD_NO_CR) {
/*
* This domain cannot be turned off.
*/
- pd->flags |= PD_BUSY;
- gov = &pm_domain_always_on_gov;
+ genpd->flags |= GENPD_FLAG_ALWAYS_ON;
}
if (!(pd->flags & (PD_CPU | PD_SCU))) {
/* Enable Clock Domain for I/O devices */
- genpd->flags = GENPD_FLAG_PM_CLK;
+ genpd->flags |= GENPD_FLAG_PM_CLK;
if (has_cpg_mstp) {
genpd->attach_dev = cpg_mstp_attach_dev;
genpd->detach_dev = cpg_mstp_detach_dev;
@@ -275,35 +255,33 @@ finalize:
}
static const struct of_device_id rcar_sysc_matches[] = {
-#ifdef CONFIG_ARCH_R8A7743
+#ifdef CONFIG_SYSC_R8A7743
{ .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info },
#endif
-#ifdef CONFIG_ARCH_R8A7745
+#ifdef CONFIG_SYSC_R8A7745
{ .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info },
#endif
-#ifdef CONFIG_ARCH_R8A7779
+#ifdef CONFIG_SYSC_R8A7779
{ .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info },
#endif
-#ifdef CONFIG_ARCH_R8A7790
+#ifdef CONFIG_SYSC_R8A7790
{ .compatible = "renesas,r8a7790-sysc", .data = &r8a7790_sysc_info },
#endif
-#ifdef CONFIG_ARCH_R8A7791
+#ifdef CONFIG_SYSC_R8A7791
{ .compatible = "renesas,r8a7791-sysc", .data = &r8a7791_sysc_info },
-#endif
-#ifdef CONFIG_ARCH_R8A7792
- { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
-#endif
-#ifdef CONFIG_ARCH_R8A7793
/* R-Car M2-N is identical to R-Car M2-W w.r.t. power domains. */
{ .compatible = "renesas,r8a7793-sysc", .data = &r8a7791_sysc_info },
#endif
-#ifdef CONFIG_ARCH_R8A7794
+#ifdef CONFIG_SYSC_R8A7792
+ { .compatible = "renesas,r8a7792-sysc", .data = &r8a7792_sysc_info },
+#endif
+#ifdef CONFIG_SYSC_R8A7794
{ .compatible = "renesas,r8a7794-sysc", .data = &r8a7794_sysc_info },
#endif
-#ifdef CONFIG_ARCH_R8A7795
+#ifdef CONFIG_SYSC_R8A7795
{ .compatible = "renesas,r8a7795-sysc", .data = &r8a7795_sysc_info },
#endif
-#ifdef CONFIG_ARCH_R8A7796
+#ifdef CONFIG_SYSC_R8A7796
{ .compatible = "renesas,r8a7796-sysc", .data = &r8a7796_sysc_info },
#endif
{ /* sentinel */ }
diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h
index 07edb049a401..1a5bebaf54ba 100644
--- a/drivers/soc/renesas/rcar-sysc.h
+++ b/drivers/soc/renesas/rcar-sysc.h
@@ -20,8 +20,6 @@
#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */
#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */
-#define PD_BUSY BIT(3) /* Busy, for internal use only */
-
#define PD_CPU_CR PD_CPU /* CPU area has CR (R-Car H1) */
#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR (R-Car Gen2/3) */
#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */
diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig
index dcf088db40b6..1beb7c347344 100644
--- a/drivers/soc/tegra/Kconfig
+++ b/drivers/soc/tegra/Kconfig
@@ -115,3 +115,8 @@ config SOC_TEGRA_PMC
config SOC_TEGRA_PMC_TEGRA186
bool
+
+config SOC_TEGRA_POWERGATE_BPMP
+ def_bool y
+ depends on PM_GENERIC_DOMAINS
+ depends on TEGRA_BPMP
diff --git a/drivers/soc/tegra/Makefile b/drivers/soc/tegra/Makefile
index 4f81dd55e5d1..0e52b45721ac 100644
--- a/drivers/soc/tegra/Makefile
+++ b/drivers/soc/tegra/Makefile
@@ -4,3 +4,4 @@ obj-y += common.o
obj-$(CONFIG_SOC_TEGRA_FLOWCTRL) += flowctrl.o
obj-$(CONFIG_SOC_TEGRA_PMC) += pmc.o
obj-$(CONFIG_SOC_TEGRA_PMC_TEGRA186) += pmc-tegra186.o
+obj-$(CONFIG_SOC_TEGRA_POWERGATE_BPMP) += powergate-bpmp.o
diff --git a/drivers/soc/tegra/flowctrl.c b/drivers/soc/tegra/flowctrl.c
index 0e345c05fc65..5433cc7a043e 100644
--- a/drivers/soc/tegra/flowctrl.c
+++ b/drivers/soc/tegra/flowctrl.c
@@ -157,7 +157,7 @@ static int tegra_flowctrl_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tegra_flowctrl_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(tegra_flowctrl_base))
- return PTR_ERR(base);
+ return PTR_ERR(tegra_flowctrl_base);
iounmap(base);
diff --git a/drivers/soc/tegra/powergate-bpmp.c b/drivers/soc/tegra/powergate-bpmp.c
new file mode 100644
index 000000000000..8fc356039401
--- /dev/null
+++ b/drivers/soc/tegra/powergate-bpmp.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+
+#include <soc/tegra/bpmp.h>
+#include <soc/tegra/bpmp-abi.h>
+
+struct tegra_powergate_info {
+ unsigned int id;
+ char *name;
+};
+
+struct tegra_powergate {
+ struct generic_pm_domain genpd;
+ struct tegra_bpmp *bpmp;
+ unsigned int id;
+};
+
+static inline struct tegra_powergate *
+to_tegra_powergate(struct generic_pm_domain *genpd)
+{
+ return container_of(genpd, struct tegra_powergate, genpd);
+}
+
+static int tegra_bpmp_powergate_set_state(struct tegra_bpmp *bpmp,
+ unsigned int id, u32 state)
+{
+ struct mrq_pg_request request;
+ struct tegra_bpmp_message msg;
+
+ memset(&request, 0, sizeof(request));
+ request.cmd = CMD_PG_SET_STATE;
+ request.id = id;
+ request.set_state.state = state;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_PG;
+ msg.tx.data = &request;
+ msg.tx.size = sizeof(request);
+
+ return tegra_bpmp_transfer(bpmp, &msg);
+}
+
+static int tegra_bpmp_powergate_get_state(struct tegra_bpmp *bpmp,
+ unsigned int id)
+{
+ struct mrq_pg_response response;
+ struct mrq_pg_request request;
+ struct tegra_bpmp_message msg;
+ int err;
+
+ memset(&request, 0, sizeof(request));
+ request.cmd = CMD_PG_GET_STATE;
+ request.id = id;
+
+ memset(&response, 0, sizeof(response));
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_PG;
+ msg.tx.data = &request;
+ msg.tx.size = sizeof(request);
+ msg.rx.data = &response;
+ msg.rx.size = sizeof(response);
+
+ err = tegra_bpmp_transfer(bpmp, &msg);
+ if (err < 0)
+ return PG_STATE_OFF;
+
+ return response.get_state.state;
+}
+
+static int tegra_bpmp_powergate_get_max_id(struct tegra_bpmp *bpmp)
+{
+ struct mrq_pg_response response;
+ struct mrq_pg_request request;
+ struct tegra_bpmp_message msg;
+ int err;
+
+ memset(&request, 0, sizeof(request));
+ request.cmd = CMD_PG_GET_MAX_ID;
+
+ memset(&response, 0, sizeof(response));
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_PG;
+ msg.tx.data = &request;
+ msg.tx.size = sizeof(request);
+ msg.rx.data = &response;
+ msg.rx.size = sizeof(response);
+
+ err = tegra_bpmp_transfer(bpmp, &msg);
+ if (err < 0)
+ return err;
+
+ return response.get_max_id.max_id;
+}
+
+static char *tegra_bpmp_powergate_get_name(struct tegra_bpmp *bpmp,
+ unsigned int id)
+{
+ struct mrq_pg_response response;
+ struct mrq_pg_request request;
+ struct tegra_bpmp_message msg;
+ int err;
+
+ memset(&request, 0, sizeof(request));
+ request.cmd = CMD_PG_GET_NAME;
+ request.id = id;
+
+ memset(&response, 0, sizeof(response));
+
+ memset(&msg, 0, sizeof(msg));
+ msg.mrq = MRQ_PG;
+ msg.tx.data = &request;
+ msg.tx.size = sizeof(request);
+ msg.rx.data = &response;
+ msg.rx.size = sizeof(response);
+
+ err = tegra_bpmp_transfer(bpmp, &msg);
+ if (err < 0)
+ return NULL;
+
+ return kstrdup(response.get_name.name, GFP_KERNEL);
+}
+
+static inline bool tegra_bpmp_powergate_is_powered(struct tegra_bpmp *bpmp,
+ unsigned int id)
+{
+ return tegra_bpmp_powergate_get_state(bpmp, id) != PG_STATE_OFF;
+}
+
+static int tegra_powergate_power_on(struct generic_pm_domain *domain)
+{
+ struct tegra_powergate *powergate = to_tegra_powergate(domain);
+ struct tegra_bpmp *bpmp = powergate->bpmp;
+
+ return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
+ PG_STATE_ON);
+}
+
+static int tegra_powergate_power_off(struct generic_pm_domain *domain)
+{
+ struct tegra_powergate *powergate = to_tegra_powergate(domain);
+ struct tegra_bpmp *bpmp = powergate->bpmp;
+
+ return tegra_bpmp_powergate_set_state(bpmp, powergate->id,
+ PG_STATE_OFF);
+}
+
+static struct tegra_powergate *
+tegra_powergate_add(struct tegra_bpmp *bpmp,
+ const struct tegra_powergate_info *info)
+{
+ struct tegra_powergate *powergate;
+ bool off;
+ int err;
+
+ off = !tegra_bpmp_powergate_is_powered(bpmp, info->id);
+
+ powergate = devm_kzalloc(bpmp->dev, sizeof(*powergate), GFP_KERNEL);
+ if (!powergate)
+ return ERR_PTR(-ENOMEM);
+
+ powergate->id = info->id;
+ powergate->bpmp = bpmp;
+
+ powergate->genpd.name = kstrdup(info->name, GFP_KERNEL);
+ powergate->genpd.power_on = tegra_powergate_power_on;
+ powergate->genpd.power_off = tegra_powergate_power_off;
+
+ err = pm_genpd_init(&powergate->genpd, NULL, off);
+ if (err < 0) {
+ kfree(powergate->genpd.name);
+ return ERR_PTR(err);
+ }
+
+ return powergate;
+}
+
+static void tegra_powergate_remove(struct tegra_powergate *powergate)
+{
+ struct generic_pm_domain *genpd = &powergate->genpd;
+ struct tegra_bpmp *bpmp = powergate->bpmp;
+ int err;
+
+ err = pm_genpd_remove(genpd);
+ if (err < 0)
+ dev_err(bpmp->dev, "failed to remove power domain %s: %d\n",
+ genpd->name, err);
+
+ kfree(genpd->name);
+}
+
+static int
+tegra_bpmp_probe_powergates(struct tegra_bpmp *bpmp,
+ struct tegra_powergate_info **powergatesp)
+{
+ struct tegra_powergate_info *powergates;
+ unsigned int max_id, id, count = 0;
+ unsigned int num_holes = 0;
+ int err;
+
+ err = tegra_bpmp_powergate_get_max_id(bpmp);
+ if (err < 0)
+ return err;
+
+ max_id = err;
+
+ dev_dbg(bpmp->dev, "maximum powergate ID: %u\n", max_id);
+
+ powergates = kcalloc(max_id + 1, sizeof(*powergates), GFP_KERNEL);
+ if (!powergates)
+ return -ENOMEM;
+
+ for (id = 0; id <= max_id; id++) {
+ struct tegra_powergate_info *info = &powergates[count];
+
+ info->name = tegra_bpmp_powergate_get_name(bpmp, id);
+ if (!info->name || info->name[0] == '\0') {
+ num_holes++;
+ continue;
+ }
+
+ info->id = id;
+ count++;
+ }
+
+ dev_dbg(bpmp->dev, "holes: %u\n", num_holes);
+
+ *powergatesp = powergates;
+
+ return count;
+}
+
+static int tegra_bpmp_add_powergates(struct tegra_bpmp *bpmp,
+ struct tegra_powergate_info *powergates,
+ unsigned int count)
+{
+ struct genpd_onecell_data *genpd = &bpmp->genpd;
+ struct generic_pm_domain **domains;
+ struct tegra_powergate *powergate;
+ unsigned int i;
+ int err;
+
+ domains = kcalloc(count, sizeof(*domains), GFP_KERNEL);
+ if (!domains)
+ return -ENOMEM;
+
+ for (i = 0; i < count; i++) {
+ powergate = tegra_powergate_add(bpmp, &powergates[i]);
+ if (IS_ERR(powergate)) {
+ err = PTR_ERR(powergate);
+ goto remove;
+ }
+
+ dev_dbg(bpmp->dev, "added power domain %s\n",
+ powergate->genpd.name);
+ domains[i] = &powergate->genpd;
+ }
+
+ genpd->num_domains = count;
+ genpd->domains = domains;
+
+ return 0;
+
+remove:
+ while (i--) {
+ powergate = to_tegra_powergate(domains[i]);
+ tegra_powergate_remove(powergate);
+ }
+
+ kfree(genpd->domains);
+ return err;
+}
+
+static void tegra_bpmp_remove_powergates(struct tegra_bpmp *bpmp)
+{
+ struct genpd_onecell_data *genpd = &bpmp->genpd;
+ unsigned int i = genpd->num_domains;
+ struct tegra_powergate *powergate;
+
+ while (i--) {
+ dev_dbg(bpmp->dev, "removing power domain %s\n",
+ genpd->domains[i]->name);
+ powergate = to_tegra_powergate(genpd->domains[i]);
+ tegra_powergate_remove(powergate);
+ }
+}
+
+static struct generic_pm_domain *
+tegra_powergate_xlate(struct of_phandle_args *spec, void *data)
+{
+ struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
+ struct genpd_onecell_data *genpd = data;
+ unsigned int i;
+
+ for (i = 0; i < genpd->num_domains; i++) {
+ struct tegra_powergate *powergate;
+
+ powergate = to_tegra_powergate(genpd->domains[i]);
+ if (powergate->id == spec->args[0]) {
+ domain = &powergate->genpd;
+ break;
+ }
+ }
+
+ return domain;
+}
+
+int tegra_bpmp_init_powergates(struct tegra_bpmp *bpmp)
+{
+ struct device_node *np = bpmp->dev->of_node;
+ struct tegra_powergate_info *powergates;
+ struct device *dev = bpmp->dev;
+ unsigned int count, i;
+ int err;
+
+ err = tegra_bpmp_probe_powergates(bpmp, &powergates);
+ if (err < 0)
+ return err;
+
+ count = err;
+
+ dev_dbg(dev, "%u power domains probed\n", count);
+
+ err = tegra_bpmp_add_powergates(bpmp, powergates, count);
+ if (err < 0)
+ goto free;
+
+ bpmp->genpd.xlate = tegra_powergate_xlate;
+
+ err = of_genpd_add_provider_onecell(np, &bpmp->genpd);
+ if (err < 0) {
+ dev_err(dev, "failed to add power domain provider: %d\n", err);
+ tegra_bpmp_remove_powergates(bpmp);
+ }
+
+free:
+ for (i = 0; i < count; i++)
+ kfree(powergates[i].name);
+
+ kfree(powergates);
+ return err;
+}