From 4c7924fb905b02323ff6d9d20f370892615dccfa Mon Sep 17 00:00:00 2001 From: Julien Massot Date: Fri, 22 Oct 2021 14:21:01 +0200 Subject: soc: renesas: rcar-rst: Add support to set rproc boot address R-Car Gen3 SoC series has a realtime processor, the boot address of this processor can be set thanks to CR7BAR register of the reset module. Export this function so that it's possible to set the boot address from a remoteproc driver. Also drop the __initdata qualifier on rcar_rst_base, since we will use this address later than init time. Signed-off-by: Julien Massot Link: https://lore.kernel.org/r/20211022122101.66998-1-julien.massot@iot.bzh Signed-off-by: Geert Uytterhoeven --- drivers/soc/renesas/rcar-rst.c | 43 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c index 8a1e402ea799..1ad54e0c32e1 100644 --- a/drivers/soc/renesas/rcar-rst.c +++ b/drivers/soc/renesas/rcar-rst.c @@ -13,15 +13,43 @@ #define WDTRSTCR_RESET 0xA55A0002 #define WDTRSTCR 0x0054 +#define CR7BAR 0x0070 +#define CR7BAREN BIT(4) +#define CR7BAR_MASK 0xFFFC0000 + +static void __iomem *rcar_rst_base; +static u32 saved_mode __initdata; +static int (*rcar_rst_set_rproc_boot_addr_func)(u64 boot_addr); + static int rcar_rst_enable_wdt_reset(void __iomem *base) { iowrite32(WDTRSTCR_RESET, base + WDTRSTCR); return 0; } +/* + * Most of the R-Car Gen3 SoCs have an ARM Realtime Core. + * Firmware boot address has to be set in CR7BAR before + * starting the realtime core. + * Boot address must be aligned on a 256k boundary. + */ +static int rcar_rst_set_gen3_rproc_boot_addr(u64 boot_addr) +{ + if (boot_addr & ~(u64)CR7BAR_MASK) { + pr_err("Invalid boot address got %llx\n", boot_addr); + return -EINVAL; + } + + iowrite32(boot_addr, rcar_rst_base + CR7BAR); + iowrite32(boot_addr | CR7BAREN, rcar_rst_base + CR7BAR); + + return 0; +} + struct rst_config { unsigned int modemr; /* Mode Monitoring Register Offset */ int (*configure)(void __iomem *base); /* Platform specific config */ + int (*set_rproc_boot_addr)(u64 boot_addr); }; static const struct rst_config rcar_rst_gen1 __initconst = { @@ -35,6 +63,7 @@ static const struct rst_config rcar_rst_gen2 __initconst = { static const struct rst_config rcar_rst_gen3 __initconst = { .modemr = 0x60, + .set_rproc_boot_addr = rcar_rst_set_gen3_rproc_boot_addr, }; static const struct rst_config rcar_rst_r8a779a0 __initconst = { @@ -76,9 +105,6 @@ static const struct of_device_id rcar_rst_matches[] __initconst = { { /* sentinel */ } }; -static void __iomem *rcar_rst_base __initdata; -static u32 saved_mode __initdata; - static int __init rcar_rst_init(void) { const struct of_device_id *match; @@ -100,6 +126,8 @@ static int __init rcar_rst_init(void) rcar_rst_base = base; cfg = match->data; + rcar_rst_set_rproc_boot_addr_func = cfg->set_rproc_boot_addr; + saved_mode = ioread32(base + cfg->modemr); if (cfg->configure) { error = cfg->configure(base); @@ -130,3 +158,12 @@ int __init rcar_rst_read_mode_pins(u32 *mode) *mode = saved_mode; return 0; } + +int rcar_rst_set_rproc_boot_addr(u64 boot_addr) +{ + if (!rcar_rst_set_rproc_boot_addr_func) + return -EIO; + + return rcar_rst_set_rproc_boot_addr_func(boot_addr); +} +EXPORT_SYMBOL_GPL(rcar_rst_set_rproc_boot_addr); -- cgit v1.2.3 From 569e45a1135497d8dddc647bc615e26c49b070a8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 31 Oct 2021 21:52:12 +0100 Subject: soc: samsung: exynos-chipid: describe which SoCs go with compatibles The Exynos ChipID driver, like most of the Exynos drivers, uses one compatible for entire family of compatible devices using one devicetree "compatible". The compatibility is here described by programming interface (register layout), not by actual values, so the product ID register on one family of devices has different values for different SoCs. Describe which SoC goes with which compatible for documentation purposes, if the DTS is not available in mainline. Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20211031205212.59505-1-krzysztof.kozlowski@canonical.com --- drivers/soc/samsung/exynos-chipid.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index a28053ec7e6a..baf3afc69d79 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -42,6 +42,7 @@ static const struct exynos_soc_id { unsigned int id; } soc_ids[] = { /* List ordered by SoC name */ + /* Compatible with: samsung,exynos4210-chipid */ { "EXYNOS3250", 0xE3472000 }, { "EXYNOS4210", 0x43200000 }, /* EVT0 revision */ { "EXYNOS4210", 0x43210000 }, @@ -55,6 +56,7 @@ static const struct exynos_soc_id { { "EXYNOS5440", 0xE5440000 }, { "EXYNOS5800", 0xE5422000 }, { "EXYNOS7420", 0xE7420000 }, + /* Compatible with: samsung,exynos850-chipid */ { "EXYNOS850", 0xE3830000 }, { "EXYNOSAUTOV9", 0xAAA80000 }, }; -- cgit v1.2.3 From 214f78060713fe13e3ba3701dff51e46d9576a9c Mon Sep 17 00:00:00 2001 From: David Virag Date: Mon, 1 Nov 2021 01:48:53 +0100 Subject: soc: samsung: exynos-chipid: add Exynos7885 SoC support Exynos 7885 has product ID "0xE7885000". Add this ID to the IDs with the name. Signed-off-by: David Virag Link: https://lore.kernel.org/r/20211101004853.55810-1-virag.david003@gmail.com Signed-off-by: Krzysztof Kozlowski --- drivers/soc/samsung/exynos-chipid.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index baf3afc69d79..2746d05936d3 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -57,6 +57,7 @@ static const struct exynos_soc_id { { "EXYNOS5800", 0xE5422000 }, { "EXYNOS7420", 0xE7420000 }, /* Compatible with: samsung,exynos850-chipid */ + { "EXYNOS7885", 0xE7885000 }, { "EXYNOS850", 0xE3830000 }, { "EXYNOSAUTOV9", 0xAAA80000 }, }; -- cgit v1.2.3 From f5dc0140d483fcc6417d1d655481f0ff1de390b0 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Thu, 28 Oct 2021 17:43:13 +0300 Subject: soc: samsung: exynos-pmu: Add Exynos850 support Exynos850 SoC can reuse PMU driver functionality. Add corresponding compatible string. Signed-off-by: Sam Protsenko Link: https://lore.kernel.org/r/20211028144313.9444-2-semen.protsenko@linaro.org Signed-off-by: Krzysztof Kozlowski --- drivers/soc/samsung/exynos-pmu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c index a18c93a4646c..732c86ce2be8 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -94,6 +94,8 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = { .compatible = "samsung,exynos5433-pmu", }, { .compatible = "samsung,exynos7-pmu", + }, { + .compatible = "samsung,exynos850-pmu", }, { /*sentinel*/ }, }; -- cgit v1.2.3 From bd9ccaec6ac998196baa11380ad4651a7df62ef0 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 13 Nov 2021 13:53:58 +0800 Subject: soc: qcom: qmi: Fix a typo in a comment The double word `client' in a comment is repeated, thus one of them should be removed. Signed-off-by: Jason Wang Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211113055358.206533-1-wangborong@cdjrlc.com --- drivers/soc/qcom/qmi_interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 1a03eaa38c46..c8c4c730b135 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -96,7 +96,7 @@ static void qmi_recv_del_server(struct qmi_handle *qmi, * @node: id of the dying node * * Signals the client that all previously registered services on this node are - * now gone and then calls the bye callback to allow the client client further + * now gone and then calls the bye callback to allow the client further * cleaning up resources associated with this remote. */ static void qmi_recv_bye(struct qmi_handle *qmi, -- cgit v1.2.3 From 7ba9dd0d04a8af868bc0785d79bde4ac0240328f Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 8 Nov 2021 21:44:40 +0800 Subject: soc: qcom: rpmpd: Drop unused res_name from struct rpmpd The res_name field in struct rpmpd is unused. Drop it. Signed-off-by: Shawn Guo Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211108134442.30051-2-shawn.guo@linaro.org --- drivers/soc/qcom/rpmpd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 4f69fb9b2e0e..3e7905854eb9 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -102,7 +102,6 @@ struct rpmpd { const bool active_only; unsigned int corner; bool enabled; - const char *res_name; const int res_type; const int res_id; struct qcom_smd_rpm *rpm; -- cgit v1.2.3 From 1cd3921aa95ebf4a6d1f93fb736449441c530aa1 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Mon, 8 Nov 2021 21:44:42 +0800 Subject: soc: qcom: rpmpd: Add QCM2290 support QCM2290 has the same RPM power domains as SM6115. Add QCM2290 support by reusing SM6115 power domains. Signed-off-by: Shawn Guo Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211108134442.30051-4-shawn.guo@linaro.org --- drivers/soc/qcom/rpmpd.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 3e7905854eb9..36b2381039e6 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -395,6 +395,23 @@ static const struct rpmpd_desc sm6115_desc = { .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, }; +static struct rpmpd *qcm2290_rpmpds[] = { + [QCM2290_VDDCX] = &sm6115_vddcx, + [QCM2290_VDDCX_AO] = &sm6115_vddcx_ao, + [QCM2290_VDDCX_VFL] = &sm6115_vddcx_vfl, + [QCM2290_VDDMX] = &sm6115_vddmx, + [QCM2290_VDDMX_AO] = &sm6115_vddmx_ao, + [QCM2290_VDDMX_VFL] = &sm6115_vddmx_vfl, + [QCM2290_VDD_LPI_CX] = &sm6115_vdd_lpi_cx, + [QCM2290_VDD_LPI_MX] = &sm6115_vdd_lpi_mx, +}; + +static const struct rpmpd_desc qcm2290_desc = { + .rpmpds = qcm2290_rpmpds, + .num_pds = ARRAY_SIZE(qcm2290_rpmpds), + .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, +}; + static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc }, { .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc }, @@ -404,6 +421,7 @@ static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc }, { .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc }, { .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc }, + { .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc }, { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, { .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc }, { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc }, -- cgit v1.2.3 From f756f435f7dd823f2d4bd593ce1bf3168def1308 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Sat, 16 Oct 2021 23:05:47 +0200 Subject: soc: imx: gpcv2: Synchronously suspend MIX domains In case the following power domain sequence happens, iMX8M Mini always hangs: gpumix:on -> gpu:on -> gpu:off -> gpu:on This is likely due to another quirk of the GPC block. This situation can be prevented by always synchronously powering off both the domain and MIX domain. Make it so. This turns the aforementioned sequence into: gpumix:on -> gpu:on -> gpu:off -> gpumix:off -> gpumix:on -> gpu:on Signed-off-by: Marek Vasut Cc: Frieder Schrempf Cc: Lucas Stach Cc: NXP Linux Team Cc: Peng Fan Cc: Shawn Guo Acked-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index b8d52d8d29db..e757044ab751 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -377,7 +377,7 @@ static int imx_pgc_power_down(struct generic_pm_domain *genpd) } } - pm_runtime_put(domain->dev); + pm_runtime_put_sync_suspend(domain->dev); return 0; -- cgit v1.2.3 From 8aa35e0bb5eaa42bac415ad0847985daa7b4890c Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Mon, 21 Jun 2021 20:08:28 +0200 Subject: soc: ti: pruss: fix referenced node in error message So far, "(null)" is reported for the node that is missing clocks. Signed-off-by: Jan Kiszka Acked-by: Suman Anna Signed-off-by: Nishanth Menon Link: https://lore.kernel.org/r/d6e24953-ea89-fd1c-6e16-7a0142118054@siemens.com --- drivers/soc/ti/pruss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index 49da387d7749..b36779309e49 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -129,7 +129,7 @@ static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node) clks_np = of_get_child_by_name(cfg_node, "clocks"); if (!clks_np) { - dev_err(dev, "%pOF is missing its 'clocks' node\n", clks_np); + dev_err(dev, "%pOF is missing its 'clocks' node\n", cfg_node); return -ENODEV; } -- cgit v1.2.3 From 8361b8b29f9389084b679db854cf733375c64763 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Sat, 20 Nov 2021 13:39:16 -0600 Subject: soc: imx: gpcv2: keep i.MX8MM VPU-H1 bus clock active Enable the vpu-h1 clock when the domain is active because reading or writing to the VPU-H1 IP block cause the system to hang. Fixes: 656ade7aa42a ("soc: imx: gpcv2: keep i.MX8M* bus clocks enabled") Signed-off-by: Adam Ford Reviewed-by: Fabio Estevam Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index e757044ab751..8176380b02e6 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -734,6 +734,7 @@ static const struct imx_pgc_domain imx8mm_pgc_domains[] = { .map = IMX8MM_VPUH1_A53_DOMAIN, }, .pgc = BIT(IMX8MM_PGC_VPUH1), + .keep_clocks = true, }, [IMX8MM_POWER_DOMAIN_DISPMIX] = { -- cgit v1.2.3 From 05b22caa7490e4f4c94bbde33c61cf72d187b8f7 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 10 Nov 2021 20:00:52 +0100 Subject: soc: renesas: Consolidate product register handling Currently renesas_soc_init() scans the whole device tree up to three times, to find a device node describing a product register. Furthermore, the product register handling for the different variants is very similar, with the major difference being the location of the product bitfield inside the product register. Reduce scanning to a single pass using of_find_matching_node_and_match() instead. Switch to a common handling of product registers, by storing the intrinsics of each product register type in the data field of the corresponding match entry. Signed-off-by: Geert Uytterhoeven Tested-by: Lad Prabhakar Link: https://lore.kernel.org/r/057721f46c7499de4133135488f0f3da7fb39265.1636570669.git.geert+renesas@glider.be --- drivers/soc/renesas/renesas-soc.c | 115 +++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 59 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 7961b0be1850..dff90f504963 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -328,94 +328,92 @@ static const struct of_device_id renesas_socs[] __initconst = { { /* sentinel */ } }; +struct renesas_id { + unsigned int offset; + u32 mask; +}; + +static const struct renesas_id id_bsid __initconst = { + .offset = 0, + .mask = 0xff0000, + /* + * TODO: Upper 4 bits of BSID are for chip version, but the format is + * not known at this time so we don't know how to specify eshi and eslo + */ +}; + +static const struct renesas_id id_rzg2l __initconst = { + .offset = 0xa04, + .mask = 0xfffffff, +}; + +static const struct renesas_id id_prr __initconst = { + .offset = 0, + .mask = 0xff00, +}; + +static const struct of_device_id renesas_ids[] __initconst = { + { .compatible = "renesas,bsid", .data = &id_bsid }, + { .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l }, + { .compatible = "renesas,prr", .data = &id_prr }, + { /* sentinel */ } +}; + static int __init renesas_soc_init(void) { struct soc_device_attribute *soc_dev_attr; + unsigned int product, eshi = 0, eslo; const struct renesas_family *family; const struct of_device_id *match; const struct renesas_soc *soc; + const struct renesas_id *id; void __iomem *chipid = NULL; struct soc_device *soc_dev; struct device_node *np; - unsigned int product, eshi = 0, eslo; + const char *soc_id; match = of_match_node(renesas_socs, of_root); if (!match) return -ENODEV; + soc_id = strchr(match->compatible, ',') + 1; soc = match->data; family = soc->family; - np = of_find_compatible_node(NULL, NULL, "renesas,bsid"); + np = of_find_matching_node_and_match(NULL, renesas_ids, &match); if (np) { + id = match->data; chipid = of_iomap(np, 0); of_node_put(np); - - if (chipid) { - product = readl(chipid); - iounmap(chipid); - - if (soc->id && ((product >> 16) & 0xff) != soc->id) { - pr_warn("SoC mismatch (product = 0x%x)\n", - product); - return -ENODEV; - } - } - - /* - * TODO: Upper 4 bits of BSID are for chip version, but the - * format is not known at this time so we don't know how to - * specify eshi and eslo - */ - - goto done; + } else if (soc->id && family->reg) { + /* Try hardcoded CCCR/PRR fallback */ + id = &id_prr; + chipid = ioremap(family->reg, 4); } - np = of_find_compatible_node(NULL, NULL, "renesas,r9a07g044-sysc"); - if (np) { - chipid = of_iomap(np, 0); - of_node_put(np); + if (chipid) { + product = readl(chipid + id->offset); + iounmap(chipid); - if (chipid) { - product = readl(chipid + 0x0a04); - iounmap(chipid); + if (id == &id_prr) { + /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ + if ((product & 0x7fff) == 0x5210) + product ^= 0x11; + /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */ + if ((product & 0x7fff) == 0x5211) + product ^= 0x12; - if (soc->id && (product & 0xfffffff) != soc->id) { - pr_warn("SoC mismatch (product = 0x%x)\n", - product); - return -ENODEV; - } + eshi = ((product >> 4) & 0x0f) + 1; + eslo = product & 0xf; } - goto done; - } - - /* Try PRR first, then hardcoded fallback */ - np = of_find_compatible_node(NULL, NULL, "renesas,prr"); - if (np) { - chipid = of_iomap(np, 0); - of_node_put(np); - } else if (soc->id && family->reg) { - chipid = ioremap(family->reg, 4); - } - if (chipid) { - product = readl(chipid); - iounmap(chipid); - /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ - if ((product & 0x7fff) == 0x5210) - product ^= 0x11; - /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */ - if ((product & 0x7fff) == 0x5211) - product ^= 0x12; - if (soc->id && ((product >> 8) & 0xff) != soc->id) { + if (soc->id && + ((product & id->mask) >> __ffs(id->mask)) != soc->id) { pr_warn("SoC mismatch (product = 0x%x)\n", product); return -ENODEV; } - eshi = ((product >> 4) & 0x0f) + 1; - eslo = product & 0xf; } -done: soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); if (!soc_dev_attr) return -ENOMEM; @@ -425,8 +423,7 @@ done: of_node_put(np); soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL); - soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1, - GFP_KERNEL); + soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL); if (eshi) soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", eshi, eslo); -- cgit v1.2.3 From 6df9d38f9146e83b473f0c9e57fb5fdf3fcc93e2 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 24 Nov 2021 16:34:18 +0900 Subject: soc: apple: Add driver for Apple PMGR power state controls Implements genpd and reset providers for downstream devices. Each instance of the driver binds to a single register and represents a single SoC power domain. The driver does not currently implement all features (clockgate-only state, misc flags), but we declare the respective registers for documentation purposes. These features will be added as they become useful for downstream devices. This also creates the apple/soc tree and Kconfig submenu. Acked-by: Linus Walleij Signed-off-by: Hector Martin --- drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/apple/Kconfig | 22 +++ drivers/soc/apple/Makefile | 2 + drivers/soc/apple/apple-pmgr-pwrstate.c | 317 ++++++++++++++++++++++++++++++++ 5 files changed, 343 insertions(+) create mode 100644 drivers/soc/apple/Kconfig create mode 100644 drivers/soc/apple/Makefile create mode 100644 drivers/soc/apple/apple-pmgr-pwrstate.c (limited to 'drivers/soc') diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index e8a30c4c5aec..a8562678c437 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -3,6 +3,7 @@ menu "SOC (System On Chip) specific Drivers" source "drivers/soc/actions/Kconfig" source "drivers/soc/amlogic/Kconfig" +source "drivers/soc/apple/Kconfig" source "drivers/soc/aspeed/Kconfig" source "drivers/soc/atmel/Kconfig" source "drivers/soc/bcm/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index a05e9fbcd3e0..adb30c2d4fea 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_ARCH_ACTIONS) += actions/ +obj-$(CONFIG_ARCH_APPLE) += apple/ obj-y += aspeed/ obj-$(CONFIG_ARCH_AT91) += atmel/ obj-y += bcm/ diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig new file mode 100644 index 000000000000..3eb14abf8d33 --- /dev/null +++ b/drivers/soc/apple/Kconfig @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if ARCH_APPLE || COMPILE_TEST + +menu "Apple SoC drivers" + +config APPLE_PMGR_PWRSTATE + tristate "Apple SoC PMGR power state control" + depends on PM + select REGMAP + select MFD_SYSCON + select PM_GENERIC_DOMAINS + select RESET_CONTROLLER + default ARCH_APPLE + help + The PMGR block in Apple SoCs provides high-level power state + controls for SoC devices. This driver manages them through the + generic power domain framework, and also provides reset support. + +endmenu + +endif diff --git a/drivers/soc/apple/Makefile b/drivers/soc/apple/Makefile new file mode 100644 index 000000000000..c114e84667e4 --- /dev/null +++ b/drivers/soc/apple/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_APPLE_PMGR_PWRSTATE) += apple-pmgr-pwrstate.o diff --git a/drivers/soc/apple/apple-pmgr-pwrstate.c b/drivers/soc/apple/apple-pmgr-pwrstate.c new file mode 100644 index 000000000000..8ad9d5fdefbf --- /dev/null +++ b/drivers/soc/apple/apple-pmgr-pwrstate.c @@ -0,0 +1,317 @@ +// SPDX-License-Identifier: GPL-2.0-only OR MIT +/* + * Apple SoC PMGR device power state driver + * + * Copyright The Asahi Linux Contributors + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define APPLE_PMGR_RESET BIT(31) +#define APPLE_PMGR_AUTO_ENABLE BIT(28) +#define APPLE_PMGR_PS_AUTO GENMASK(27, 24) +#define APPLE_PMGR_PARENT_OFF BIT(11) +#define APPLE_PMGR_DEV_DISABLE BIT(10) +#define APPLE_PMGR_WAS_CLKGATED BIT(9) +#define APPLE_PMGR_WAS_PWRGATED BIT(8) +#define APPLE_PMGR_PS_ACTUAL GENMASK(7, 4) +#define APPLE_PMGR_PS_TARGET GENMASK(3, 0) + +#define APPLE_PMGR_FLAGS (APPLE_PMGR_WAS_CLKGATED | APPLE_PMGR_WAS_PWRGATED) + +#define APPLE_PMGR_PS_ACTIVE 0xf +#define APPLE_PMGR_PS_CLKGATE 0x4 +#define APPLE_PMGR_PS_PWRGATE 0x0 + +#define APPLE_PMGR_PS_SET_TIMEOUT 100 +#define APPLE_PMGR_RESET_TIME 1 + +struct apple_pmgr_ps { + struct device *dev; + struct generic_pm_domain genpd; + struct reset_controller_dev rcdev; + struct regmap *regmap; + u32 offset; +}; + +#define genpd_to_apple_pmgr_ps(_genpd) container_of(_genpd, struct apple_pmgr_ps, genpd) +#define rcdev_to_apple_pmgr_ps(_rcdev) container_of(_rcdev, struct apple_pmgr_ps, rcdev) + +static int apple_pmgr_ps_set(struct generic_pm_domain *genpd, u32 pstate, bool auto_enable) +{ + int ret; + struct apple_pmgr_ps *ps = genpd_to_apple_pmgr_ps(genpd); + u32 reg; + + ret = regmap_read(ps->regmap, ps->offset, ®); + if (ret < 0) + return ret; + + /* Resets are synchronous, and only work if the device is powered and clocked. */ + if (reg & APPLE_PMGR_RESET && pstate != APPLE_PMGR_PS_ACTIVE) + dev_err(ps->dev, "PS %s: powering off with RESET active\n", + genpd->name); + + reg &= ~(APPLE_PMGR_AUTO_ENABLE | APPLE_PMGR_FLAGS | APPLE_PMGR_PS_TARGET); + reg |= FIELD_PREP(APPLE_PMGR_PS_TARGET, pstate); + + dev_dbg(ps->dev, "PS %s: pwrstate = 0x%x: 0x%x\n", genpd->name, pstate, reg); + + regmap_write(ps->regmap, ps->offset, reg); + + ret = regmap_read_poll_timeout_atomic( + ps->regmap, ps->offset, reg, + (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == pstate), 1, + APPLE_PMGR_PS_SET_TIMEOUT); + if (ret < 0) + dev_err(ps->dev, "PS %s: Failed to reach power state 0x%x (now: 0x%x)\n", + genpd->name, pstate, reg); + + if (auto_enable) { + /* Not all devices implement this; this is a no-op where not implemented. */ + reg &= ~APPLE_PMGR_FLAGS; + reg |= APPLE_PMGR_AUTO_ENABLE; + regmap_write(ps->regmap, ps->offset, reg); + } + + return ret; +} + +static bool apple_pmgr_ps_is_active(struct apple_pmgr_ps *ps) +{ + u32 reg = 0; + + regmap_read(ps->regmap, ps->offset, ®); + /* + * We consider domains as active if they are actually on, or if they have auto-PM + * enabled and the intended target is on. + */ + return (FIELD_GET(APPLE_PMGR_PS_ACTUAL, reg) == APPLE_PMGR_PS_ACTIVE || + (FIELD_GET(APPLE_PMGR_PS_TARGET, reg) == APPLE_PMGR_PS_ACTIVE && + reg & APPLE_PMGR_AUTO_ENABLE)); +} + +static int apple_pmgr_ps_power_on(struct generic_pm_domain *genpd) +{ + return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_ACTIVE, true); +} + +static int apple_pmgr_ps_power_off(struct generic_pm_domain *genpd) +{ + return apple_pmgr_ps_set(genpd, APPLE_PMGR_PS_PWRGATE, false); +} + +static int apple_pmgr_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + + mutex_lock(&ps->genpd.mlock); + + if (ps->genpd.status == GENPD_STATE_OFF) + dev_err(ps->dev, "PS 0x%x: asserting RESET while powered down\n", ps->offset); + + dev_dbg(ps->dev, "PS 0x%x: assert reset\n", ps->offset); + /* Quiesce device before asserting reset */ + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, + APPLE_PMGR_DEV_DISABLE); + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, + APPLE_PMGR_RESET); + + mutex_unlock(&ps->genpd.mlock); + + return 0; +} + +static int apple_pmgr_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + + mutex_lock(&ps->genpd.mlock); + + dev_dbg(ps->dev, "PS 0x%x: deassert reset\n", ps->offset); + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_RESET, 0); + regmap_update_bits(ps->regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_DEV_DISABLE, 0); + + if (ps->genpd.status == GENPD_STATE_OFF) + dev_err(ps->dev, "PS 0x%x: RESET was deasserted while powered down\n", ps->offset); + + mutex_unlock(&ps->genpd.mlock); + + return 0; +} + +static int apple_pmgr_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) +{ + int ret; + + ret = apple_pmgr_reset_assert(rcdev, id); + if (ret) + return ret; + + usleep_range(APPLE_PMGR_RESET_TIME, 2 * APPLE_PMGR_RESET_TIME); + + return apple_pmgr_reset_deassert(rcdev, id); +} + +static int apple_pmgr_reset_status(struct reset_controller_dev *rcdev, unsigned long id) +{ + struct apple_pmgr_ps *ps = rcdev_to_apple_pmgr_ps(rcdev); + u32 reg = 0; + + regmap_read(ps->regmap, ps->offset, ®); + + return !!(reg & APPLE_PMGR_RESET); +} + +const struct reset_control_ops apple_pmgr_reset_ops = { + .assert = apple_pmgr_reset_assert, + .deassert = apple_pmgr_reset_deassert, + .reset = apple_pmgr_reset_reset, + .status = apple_pmgr_reset_status, +}; + +static int apple_pmgr_reset_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + return 0; +} + +static int apple_pmgr_ps_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *node = dev->of_node; + struct apple_pmgr_ps *ps; + struct regmap *regmap; + struct of_phandle_iterator it; + int ret; + const char *name; + bool active; + + regmap = syscon_node_to_regmap(node->parent); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ps = devm_kzalloc(dev, sizeof(*ps), GFP_KERNEL); + if (!ps) + return -ENOMEM; + + ps->dev = dev; + ps->regmap = regmap; + + ret = of_property_read_string(node, "label", &name); + if (ret < 0) { + dev_err(dev, "missing label property\n"); + return ret; + } + + ret = of_property_read_u32(node, "reg", &ps->offset); + if (ret < 0) { + dev_err(dev, "missing reg property\n"); + return ret; + } + + ps->genpd.name = name; + ps->genpd.power_on = apple_pmgr_ps_power_on; + ps->genpd.power_off = apple_pmgr_ps_power_off; + + active = apple_pmgr_ps_is_active(ps); + if (of_property_read_bool(node, "apple,always-on")) { + ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON; + if (!active) { + dev_warn(dev, "always-on domain %s is not on at boot\n", name); + /* Turn it on so pm_genpd_init does not fail */ + active = apple_pmgr_ps_power_on(&ps->genpd) == 0; + } + } + + /* Turn on auto-PM if the domain is already on */ + if (active) + regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_AUTO_ENABLE, + APPLE_PMGR_AUTO_ENABLE); + + ret = pm_genpd_init(&ps->genpd, NULL, !active); + if (ret < 0) { + dev_err(dev, "pm_genpd_init failed\n"); + return ret; + } + + ret = of_genpd_add_provider_simple(node, &ps->genpd); + if (ret < 0) { + dev_err(dev, "of_genpd_add_provider_simple failed\n"); + return ret; + } + + of_for_each_phandle(&it, ret, node, "power-domains", "#power-domain-cells", -1) { + struct of_phandle_args parent, child; + + parent.np = it.node; + parent.args_count = of_phandle_iterator_args(&it, parent.args, MAX_PHANDLE_ARGS); + child.np = node; + child.args_count = 0; + ret = of_genpd_add_subdomain(&parent, &child); + + if (ret == -EPROBE_DEFER) { + of_node_put(parent.np); + goto err_remove; + } else if (ret < 0) { + dev_err(dev, "failed to add to parent domain: %d (%s -> %s)\n", + ret, it.node->name, node->name); + of_node_put(parent.np); + goto err_remove; + } + } + + /* + * Do not participate in regular PM; parent power domains are handled via the + * genpd hierarchy. + */ + pm_genpd_remove_device(dev); + + ps->rcdev.owner = THIS_MODULE; + ps->rcdev.nr_resets = 1; + ps->rcdev.ops = &apple_pmgr_reset_ops; + ps->rcdev.of_node = dev->of_node; + ps->rcdev.of_reset_n_cells = 0; + ps->rcdev.of_xlate = apple_pmgr_reset_xlate; + + ret = devm_reset_controller_register(dev, &ps->rcdev); + if (ret < 0) + goto err_remove; + + return 0; +err_remove: + of_genpd_del_provider(node); + pm_genpd_remove(&ps->genpd); + return ret; +} + +static const struct of_device_id apple_pmgr_ps_of_match[] = { + { .compatible = "apple,pmgr-pwrstate" }, + {} +}; + +MODULE_DEVICE_TABLE(of, apple_pmgr_ps_of_match); + +static struct platform_driver apple_pmgr_ps_driver = { + .probe = apple_pmgr_ps_probe, + .driver = { + .name = "apple-pmgr-pwrstate", + .of_match_table = apple_pmgr_ps_of_match, + }, +}; + +MODULE_AUTHOR("Hector Martin "); +MODULE_DESCRIPTION("PMGR power state driver for Apple SoCs"); +MODULE_LICENSE("GPL v2"); + +module_platform_driver(apple_pmgr_ps_driver); -- cgit v1.2.3 From e62906d6315f652b80640df0f980086462a4953b Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 1 Dec 2021 16:32:59 +0900 Subject: soc: renesas: rcar-gen4-sysc: Introduce R-Car Gen4 SYSC driver According to the official website [1], the R-Car V3U SoC is based on the R-Car Gen4 architecture. So, introduce R-Car Gen4 SYSC driver. [1] https://www.renesas.com/us/en/products/automotive-products/automotive-system-chips-socs/r-car-v3u-best-class-r-car-v3u-asil-d-system-chip-automated-driving Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20211201073308.1003945-6-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/soc/renesas/Kconfig | 4 + drivers/soc/renesas/Makefile | 1 + drivers/soc/renesas/r8a779a0-sysc.c | 380 +---------------------------------- drivers/soc/renesas/rcar-gen4-sysc.c | 373 ++++++++++++++++++++++++++++++++++ drivers/soc/renesas/rcar-gen4-sysc.h | 42 ++++ 5 files changed, 423 insertions(+), 377 deletions(-) create mode 100644 drivers/soc/renesas/rcar-gen4-sysc.c create mode 100644 drivers/soc/renesas/rcar-gen4-sysc.h (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index ce16ef5c939c..2b09d6cf0d66 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -297,6 +297,9 @@ config RST_RCAR config SYSC_RCAR bool "System Controller support for R-Car" if COMPILE_TEST +config SYSC_RCAR_GEN4 + bool "System Controller support for R-Car Gen4" if COMPILE_TEST + config SYSC_R8A77995 bool "System Controller support for R-Car D3" if COMPILE_TEST select SYSC_RCAR @@ -351,6 +354,7 @@ config SYSC_R8A77970 config SYSC_R8A779A0 bool "System Controller support for R-Car V3U" if COMPILE_TEST + select SYSC_RCAR_GEN4 config SYSC_RMOBILE bool "System Controller support for R-Mobile" if COMPILE_TEST diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 9b29bed2a597..db90f3b06007 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -32,4 +32,5 @@ endif # Family obj-$(CONFIG_RST_RCAR) += rcar-rst.o obj-$(CONFIG_SYSC_RCAR) += rcar-sysc.o +obj-$(CONFIG_SYSC_RCAR_GEN4) += rcar-gen4-sysc.o obj-$(CONFIG_SYSC_RMOBILE) += rmobile-sysc.o diff --git a/drivers/soc/renesas/r8a779a0-sysc.c b/drivers/soc/renesas/r8a779a0-sysc.c index 7410b9fa9846..fdfc857df334 100644 --- a/drivers/soc/renesas/r8a779a0-sysc.c +++ b/drivers/soc/renesas/r8a779a0-sysc.c @@ -21,35 +21,9 @@ #include -/* - * Power Domain flags - */ -#define PD_CPU BIT(0) /* Area contains main CPU core */ -#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_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR */ -#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ - -/* - * Description of a Power Area - */ -struct r8a779a0_sysc_area { - const char *name; - u8 pdr; /* PDRn */ - int parent; /* -1 if none */ - unsigned int flags; /* See PD_* */ -}; - -/* - * SoC-specific Power Area Description - */ -struct r8a779a0_sysc_info { - const struct r8a779a0_sysc_area *areas; - unsigned int num_areas; -}; +#include "rcar-gen4-sysc.h" -static struct r8a779a0_sysc_area r8a779a0_areas[] __initdata = { +static struct rcar_gen4_sysc_area r8a779a0_areas[] __initdata = { { "always-on", R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, { "a3e0", R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU }, { "a3e1", R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU }, @@ -96,355 +70,7 @@ static struct r8a779a0_sysc_area r8a779a0_areas[] __initdata = { { "a1dsp1", R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 }, }; -static const struct r8a779a0_sysc_info r8a779a0_sysc_info __initconst = { +const struct rcar_gen4_sysc_info r8a779a0_sysc_info __initconst = { .areas = r8a779a0_areas, .num_areas = ARRAY_SIZE(r8a779a0_areas), }; - -/* SYSC Common */ -#define SYSCSR 0x000 /* SYSC Status Register */ -#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */ -#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */ -#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */ -#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */ -#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */ - -/* Power Domain Registers */ -#define PDRSR(n) (0x1000 + ((n) * 0x40)) -#define PDRONCR(n) (0x1004 + ((n) * 0x40)) -#define PDROFFCR(n) (0x1008 + ((n) * 0x40)) -#define PDRESR(n) (0x100C + ((n) * 0x40)) - -/* PWRON/PWROFF */ -#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */ - -/* PDRESR */ -#define PDRESR_ERR BIT(0) - -/* PDRSR */ -#define PDRSR_OFF BIT(0) /* Power-OFF state */ -#define PDRSR_ON BIT(4) /* Power-ON state */ -#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */ -#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */ - -#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ - -#define SYSCSR_TIMEOUT 10000 -#define SYSCSR_DELAY_US 10 - -#define PDRESR_RETRIES 1000 -#define PDRESR_DELAY_US 10 - -#define SYSCISR_TIMEOUT 10000 -#define SYSCISR_DELAY_US 10 - -#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) - -static void __iomem *r8a779a0_sysc_base; -static DEFINE_SPINLOCK(r8a779a0_sysc_lock); /* SMP CPUs + I/O devices */ - -static int r8a779a0_sysc_pwr_on_off(u8 pdr, bool on) -{ - unsigned int reg_offs; - u32 val; - int ret; - - if (on) - reg_offs = PDRONCR(pdr); - else - reg_offs = PDROFFCR(pdr); - - /* Wait until SYSC is ready to accept a power request */ - ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCSR, val, - (val & SYSCSR_BUSY) == SYSCSR_BUSY, - SYSCSR_DELAY_US, SYSCSR_TIMEOUT); - if (ret < 0) - return -EAGAIN; - - /* Submit power shutoff or power resume request */ - iowrite32(PWRON_PWROFF, r8a779a0_sysc_base + reg_offs); - - return 0; -} - -static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) -{ - u32 val; - int ret; - - iowrite32(isr_mask, r8a779a0_sysc_base + SYSCISCR(reg_idx)); - - ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx), - val, !(val & isr_mask), - SYSCISR_DELAY_US, SYSCISR_TIMEOUT); - if (ret < 0) { - pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); - return -EIO; - } - - return 0; -} - -static int r8a779a0_sysc_power(u8 pdr, bool on) -{ - unsigned int isr_mask; - unsigned int reg_idx, bit_idx; - unsigned int status; - unsigned long flags; - int ret = 0; - u32 val; - int k; - - spin_lock_irqsave(&r8a779a0_sysc_lock, flags); - - reg_idx = pdr / NUM_DOMAINS_EACH_REG; - bit_idx = pdr % NUM_DOMAINS_EACH_REG; - - isr_mask = BIT(bit_idx); - - /* - * The interrupt source needs to be enabled, but masked, to prevent the - * CPU from receiving it. - */ - iowrite32(ioread32(r8a779a0_sysc_base + SYSCIER(reg_idx)) | isr_mask, - r8a779a0_sysc_base + SYSCIER(reg_idx)); - iowrite32(ioread32(r8a779a0_sysc_base + SYSCIMR(reg_idx)) | isr_mask, - r8a779a0_sysc_base + SYSCIMR(reg_idx)); - - ret = clear_irq_flags(reg_idx, isr_mask); - if (ret) - goto out; - - /* Submit power shutoff or resume request until it was accepted */ - for (k = 0; k < PDRESR_RETRIES; k++) { - ret = r8a779a0_sysc_pwr_on_off(pdr, on); - if (ret) - goto out; - - status = ioread32(r8a779a0_sysc_base + PDRESR(pdr)); - if (!(status & PDRESR_ERR)) - break; - - udelay(PDRESR_DELAY_US); - } - - if (k == PDRESR_RETRIES) { - ret = -EIO; - goto out; - } - - /* Wait until the power shutoff or resume request has completed * */ - ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx), - val, (val & isr_mask), - SYSCISR_DELAY_US, SYSCISR_TIMEOUT); - if (ret < 0) { - ret = -EIO; - goto out; - } - - /* Clear interrupt flags */ - ret = clear_irq_flags(reg_idx, isr_mask); - if (ret) - goto out; - - out: - spin_unlock_irqrestore(&r8a779a0_sysc_lock, flags); - - pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", - pdr, ioread32(r8a779a0_sysc_base + SYSCISCR(reg_idx)), ret); - return ret; -} - -static bool r8a779a0_sysc_power_is_off(u8 pdr) -{ - unsigned int st; - - st = ioread32(r8a779a0_sysc_base + PDRSR(pdr)); - - if (st & PDRSR_OFF) - return true; - - return false; -} - -struct r8a779a0_sysc_pd { - struct generic_pm_domain genpd; - u8 pdr; - unsigned int flags; - char name[]; -}; - -static inline struct r8a779a0_sysc_pd *to_r8a779a0_pd(struct generic_pm_domain *d) -{ - return container_of(d, struct r8a779a0_sysc_pd, genpd); -} - -static int r8a779a0_sysc_pd_power_off(struct generic_pm_domain *genpd) -{ - struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd); - - pr_debug("%s: %s\n", __func__, genpd->name); - return r8a779a0_sysc_power(pd->pdr, false); -} - -static int r8a779a0_sysc_pd_power_on(struct generic_pm_domain *genpd) -{ - struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd); - - pr_debug("%s: %s\n", __func__, genpd->name); - return r8a779a0_sysc_power(pd->pdr, true); -} - -static int __init r8a779a0_sysc_pd_setup(struct r8a779a0_sysc_pd *pd) -{ - struct generic_pm_domain *genpd = &pd->genpd; - const char *name = pd->genpd.name; - int error; - - if (pd->flags & PD_CPU) { - /* - * This domain contains a CPU core and therefore it should - * only be turned off if the CPU is not in use. - */ - pr_debug("PM domain %s contains %s\n", name, "CPU"); - genpd->flags |= GENPD_FLAG_ALWAYS_ON; - } else if (pd->flags & PD_SCU) { - /* - * This domain contains an SCU and cache-controller, and - * therefore it should only be turned off if the CPU cores are - * not in use. - */ - pr_debug("PM domain %s contains %s\n", name, "SCU"); - genpd->flags |= GENPD_FLAG_ALWAYS_ON; - } else if (pd->flags & PD_NO_CR) { - /* - * This domain cannot be turned off. - */ - 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_FLAG_ACTIVE_WAKEUP; - genpd->attach_dev = cpg_mssr_attach_dev; - genpd->detach_dev = cpg_mssr_detach_dev; - } - - genpd->power_off = r8a779a0_sysc_pd_power_off; - genpd->power_on = r8a779a0_sysc_pd_power_on; - - if (pd->flags & (PD_CPU | PD_NO_CR)) { - /* Skip CPUs (handled by SMP code) and areas without control */ - pr_debug("%s: Not touching %s\n", __func__, genpd->name); - goto finalize; - } - - if (!r8a779a0_sysc_power_is_off(pd->pdr)) { - pr_debug("%s: %s is already powered\n", __func__, genpd->name); - goto finalize; - } - - r8a779a0_sysc_power(pd->pdr, true); - -finalize: - error = pm_genpd_init(genpd, &simple_qos_governor, false); - if (error) - pr_err("Failed to init PM domain %s: %d\n", name, error); - - return error; -} - -static const struct of_device_id r8a779a0_sysc_matches[] __initconst = { - { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info }, - { /* sentinel */ } -}; - -struct r8a779a0_pm_domains { - struct genpd_onecell_data onecell_data; - struct generic_pm_domain *domains[R8A779A0_PD_ALWAYS_ON + 1]; -}; - -static struct genpd_onecell_data *r8a779a0_sysc_onecell_data; - -static int __init r8a779a0_sysc_pd_init(void) -{ - const struct r8a779a0_sysc_info *info; - const struct of_device_id *match; - struct r8a779a0_pm_domains *domains; - struct device_node *np; - void __iomem *base; - unsigned int i; - int error; - - np = of_find_matching_node_and_match(NULL, r8a779a0_sysc_matches, &match); - if (!np) - return -ENODEV; - - info = match->data; - - base = of_iomap(np, 0); - if (!base) { - pr_warn("%pOF: Cannot map regs\n", np); - error = -ENOMEM; - goto out_put; - } - - r8a779a0_sysc_base = base; - - domains = kzalloc(sizeof(*domains), GFP_KERNEL); - if (!domains) { - error = -ENOMEM; - goto out_put; - } - - domains->onecell_data.domains = domains->domains; - domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); - r8a779a0_sysc_onecell_data = &domains->onecell_data; - - for (i = 0; i < info->num_areas; i++) { - const struct r8a779a0_sysc_area *area = &info->areas[i]; - struct r8a779a0_sysc_pd *pd; - size_t n; - - if (!area->name) { - /* Skip NULLified area */ - continue; - } - - n = strlen(area->name) + 1; - pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL); - if (!pd) { - error = -ENOMEM; - goto out_put; - } - - memcpy(pd->name, area->name, n); - pd->genpd.name = pd->name; - pd->pdr = area->pdr; - pd->flags = area->flags; - - error = r8a779a0_sysc_pd_setup(pd); - if (error) - goto out_put; - - domains->domains[area->pdr] = &pd->genpd; - - if (area->parent < 0) - continue; - - error = pm_genpd_add_subdomain(domains->domains[area->parent], - &pd->genpd); - if (error) { - pr_warn("Failed to add PM subdomain %s to parent %u\n", - area->name, area->parent); - goto out_put; - } - } - - error = of_genpd_add_provider_onecell(np, &domains->onecell_data); - -out_put: - of_node_put(np); - return error; -} -early_initcall(r8a779a0_sysc_pd_init); diff --git a/drivers/soc/renesas/rcar-gen4-sysc.c b/drivers/soc/renesas/rcar-gen4-sysc.c new file mode 100644 index 000000000000..d9a0929f5f1d --- /dev/null +++ b/drivers/soc/renesas/rcar-gen4-sysc.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R-Car Gen4 SYSC Power management support + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rcar-gen4-sysc.h" + +/* SYSC Common */ +#define SYSCSR 0x000 /* SYSC Status Register */ +#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */ +#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */ +#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */ +#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */ +#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */ + +/* Power Domain Registers */ +#define PDRSR(n) (0x1000 + ((n) * 0x40)) +#define PDRONCR(n) (0x1004 + ((n) * 0x40)) +#define PDROFFCR(n) (0x1008 + ((n) * 0x40)) +#define PDRESR(n) (0x100C + ((n) * 0x40)) + +/* PWRON/PWROFF */ +#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */ + +/* PDRESR */ +#define PDRESR_ERR BIT(0) + +/* PDRSR */ +#define PDRSR_OFF BIT(0) /* Power-OFF state */ +#define PDRSR_ON BIT(4) /* Power-ON state */ +#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */ +#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */ + +#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ + +#define SYSCSR_TIMEOUT 10000 +#define SYSCSR_DELAY_US 10 + +#define PDRESR_RETRIES 1000 +#define PDRESR_DELAY_US 10 + +#define SYSCISR_TIMEOUT 10000 +#define SYSCISR_DELAY_US 10 + +#define RCAR_GEN4_PD_ALWAYS_ON 64 +#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) + +static void __iomem *rcar_gen4_sysc_base; +static DEFINE_SPINLOCK(rcar_gen4_sysc_lock); /* SMP CPUs + I/O devices */ + +static int rcar_gen4_sysc_pwr_on_off(u8 pdr, bool on) +{ + unsigned int reg_offs; + u32 val; + int ret; + + if (on) + reg_offs = PDRONCR(pdr); + else + reg_offs = PDROFFCR(pdr); + + /* Wait until SYSC is ready to accept a power request */ + ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCSR, val, + (val & SYSCSR_BUSY) == SYSCSR_BUSY, + SYSCSR_DELAY_US, SYSCSR_TIMEOUT); + if (ret < 0) + return -EAGAIN; + + /* Submit power shutoff or power resume request */ + iowrite32(PWRON_PWROFF, rcar_gen4_sysc_base + reg_offs); + + return 0; +} + +static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) +{ + u32 val; + int ret; + + iowrite32(isr_mask, rcar_gen4_sysc_base + SYSCISCR(reg_idx)); + + ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), + val, !(val & isr_mask), + SYSCISR_DELAY_US, SYSCISR_TIMEOUT); + if (ret < 0) { + pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); + return -EIO; + } + + return 0; +} + +static int rcar_gen4_sysc_power(u8 pdr, bool on) +{ + unsigned int isr_mask; + unsigned int reg_idx, bit_idx; + unsigned int status; + unsigned long flags; + int ret = 0; + u32 val; + int k; + + spin_lock_irqsave(&rcar_gen4_sysc_lock, flags); + + reg_idx = pdr / NUM_DOMAINS_EACH_REG; + bit_idx = pdr % NUM_DOMAINS_EACH_REG; + + isr_mask = BIT(bit_idx); + + /* + * The interrupt source needs to be enabled, but masked, to prevent the + * CPU from receiving it. + */ + iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIER(reg_idx)) | isr_mask, + rcar_gen4_sysc_base + SYSCIER(reg_idx)); + iowrite32(ioread32(rcar_gen4_sysc_base + SYSCIMR(reg_idx)) | isr_mask, + rcar_gen4_sysc_base + SYSCIMR(reg_idx)); + + ret = clear_irq_flags(reg_idx, isr_mask); + if (ret) + goto out; + + /* Submit power shutoff or resume request until it was accepted */ + for (k = 0; k < PDRESR_RETRIES; k++) { + ret = rcar_gen4_sysc_pwr_on_off(pdr, on); + if (ret) + goto out; + + status = ioread32(rcar_gen4_sysc_base + PDRESR(pdr)); + if (!(status & PDRESR_ERR)) + break; + + udelay(PDRESR_DELAY_US); + } + + if (k == PDRESR_RETRIES) { + ret = -EIO; + goto out; + } + + /* Wait until the power shutoff or resume request has completed * */ + ret = readl_poll_timeout_atomic(rcar_gen4_sysc_base + SYSCISCR(reg_idx), + val, (val & isr_mask), + SYSCISR_DELAY_US, SYSCISR_TIMEOUT); + if (ret < 0) { + ret = -EIO; + goto out; + } + + /* Clear interrupt flags */ + ret = clear_irq_flags(reg_idx, isr_mask); + if (ret) + goto out; + + out: + spin_unlock_irqrestore(&rcar_gen4_sysc_lock, flags); + + pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", + pdr, ioread32(rcar_gen4_sysc_base + SYSCISCR(reg_idx)), ret); + return ret; +} + +static bool rcar_gen4_sysc_power_is_off(u8 pdr) +{ + unsigned int st; + + st = ioread32(rcar_gen4_sysc_base + PDRSR(pdr)); + + if (st & PDRSR_OFF) + return true; + + return false; +} + +struct rcar_gen4_sysc_pd { + struct generic_pm_domain genpd; + u8 pdr; + unsigned int flags; + char name[]; +}; + +static inline struct rcar_gen4_sysc_pd *to_rcar_gen4_pd(struct generic_pm_domain *d) +{ + return container_of(d, struct rcar_gen4_sysc_pd, genpd); +} + +static int rcar_gen4_sysc_pd_power_off(struct generic_pm_domain *genpd) +{ + struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return rcar_gen4_sysc_power(pd->pdr, false); +} + +static int rcar_gen4_sysc_pd_power_on(struct generic_pm_domain *genpd) +{ + struct rcar_gen4_sysc_pd *pd = to_rcar_gen4_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return rcar_gen4_sysc_power(pd->pdr, true); +} + +static int __init rcar_gen4_sysc_pd_setup(struct rcar_gen4_sysc_pd *pd) +{ + struct generic_pm_domain *genpd = &pd->genpd; + const char *name = pd->genpd.name; + int error; + + if (pd->flags & PD_CPU) { + /* + * This domain contains a CPU core and therefore it should + * only be turned off if the CPU is not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "CPU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_SCU) { + /* + * This domain contains an SCU and cache-controller, and + * therefore it should only be turned off if the CPU cores are + * not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "SCU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_NO_CR) { + /* + * This domain cannot be turned off. + */ + 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_FLAG_ACTIVE_WAKEUP; + genpd->attach_dev = cpg_mssr_attach_dev; + genpd->detach_dev = cpg_mssr_detach_dev; + } + + genpd->power_off = rcar_gen4_sysc_pd_power_off; + genpd->power_on = rcar_gen4_sysc_pd_power_on; + + if (pd->flags & (PD_CPU | PD_NO_CR)) { + /* Skip CPUs (handled by SMP code) and areas without control */ + pr_debug("%s: Not touching %s\n", __func__, genpd->name); + goto finalize; + } + + if (!rcar_gen4_sysc_power_is_off(pd->pdr)) { + pr_debug("%s: %s is already powered\n", __func__, genpd->name); + goto finalize; + } + + rcar_gen4_sysc_power(pd->pdr, true); + +finalize: + error = pm_genpd_init(genpd, &simple_qos_governor, false); + if (error) + pr_err("Failed to init PM domain %s: %d\n", name, error); + + return error; +} + +static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = { +#ifdef CONFIG_SYSC_R8A779A0 + { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info }, +#endif + { /* sentinel */ } +}; + +struct rcar_gen4_pm_domains { + struct genpd_onecell_data onecell_data; + struct generic_pm_domain *domains[RCAR_GEN4_PD_ALWAYS_ON + 1]; +}; + +static struct genpd_onecell_data *rcar_gen4_sysc_onecell_data; + +static int __init rcar_gen4_sysc_pd_init(void) +{ + const struct rcar_gen4_sysc_info *info; + const struct of_device_id *match; + struct rcar_gen4_pm_domains *domains; + struct device_node *np; + void __iomem *base; + unsigned int i; + int error; + + np = of_find_matching_node_and_match(NULL, rcar_gen4_sysc_matches, &match); + if (!np) + return -ENODEV; + + info = match->data; + + base = of_iomap(np, 0); + if (!base) { + pr_warn("%pOF: Cannot map regs\n", np); + error = -ENOMEM; + goto out_put; + } + + rcar_gen4_sysc_base = base; + + domains = kzalloc(sizeof(*domains), GFP_KERNEL); + if (!domains) { + error = -ENOMEM; + goto out_put; + } + + domains->onecell_data.domains = domains->domains; + domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); + rcar_gen4_sysc_onecell_data = &domains->onecell_data; + + for (i = 0; i < info->num_areas; i++) { + const struct rcar_gen4_sysc_area *area = &info->areas[i]; + struct rcar_gen4_sysc_pd *pd; + size_t n; + + if (!area->name) { + /* Skip NULLified area */ + continue; + } + + n = strlen(area->name) + 1; + pd = kzalloc(sizeof(*pd) + n, GFP_KERNEL); + if (!pd) { + error = -ENOMEM; + goto out_put; + } + + memcpy(pd->name, area->name, n); + pd->genpd.name = pd->name; + pd->pdr = area->pdr; + pd->flags = area->flags; + + error = rcar_gen4_sysc_pd_setup(pd); + if (error) + goto out_put; + + domains->domains[area->pdr] = &pd->genpd; + + if (area->parent < 0) + continue; + + error = pm_genpd_add_subdomain(domains->domains[area->parent], + &pd->genpd); + if (error) { + pr_warn("Failed to add PM subdomain %s to parent %u\n", + area->name, area->parent); + goto out_put; + } + } + + error = of_genpd_add_provider_onecell(np, &domains->onecell_data); + +out_put: + of_node_put(np); + return error; +} +early_initcall(rcar_gen4_sysc_pd_init); diff --git a/drivers/soc/renesas/rcar-gen4-sysc.h b/drivers/soc/renesas/rcar-gen4-sysc.h new file mode 100644 index 000000000000..3470a9e2f5c7 --- /dev/null +++ b/drivers/soc/renesas/rcar-gen4-sysc.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * R-Car Gen4 System Controller + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ +#ifndef __SOC_RENESAS_RCAR_GEN4_SYSC_H__ +#define __SOC_RENESAS_RCAR_GEN4_SYSC_H__ + +#include + +/* + * Power Domain flags + */ +#define PD_CPU BIT(0) /* Area contains main CPU core */ +#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_CPU_NOCR (PD_CPU | PD_NO_CR) /* CPU area lacks CR */ +#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ + +/* + * Description of a Power Area + */ +struct rcar_gen4_sysc_area { + const char *name; + u8 pdr; /* PDRn */ + int parent; /* -1 if none */ + unsigned int flags; /* See PD_* */ +}; + +/* + * SoC-specific Power Area Description + */ +struct rcar_gen4_sysc_info { + const struct rcar_gen4_sysc_area *areas; + unsigned int num_areas; +}; + +extern const struct rcar_gen4_sysc_info r8a779a0_sysc_info; + +#endif /* __SOC_RENESAS_RCAR_GEN4_SYSC_H__ */ -- cgit v1.2.3 From 654d5fdb8923994f5e79a7f0faf722958d1d759f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 1 Dec 2021 16:33:00 +0900 Subject: soc: renesas: r8a779f0-sysc: Add r8a779f0 support Add support for R-Car S4-8 (R8A779F0) SoC power areas and register access. Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20211201073308.1003945-7-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/soc/renesas/Kconfig | 4 +++ drivers/soc/renesas/Makefile | 1 + drivers/soc/renesas/r8a779f0-sysc.c | 47 ++++++++++++++++++++++++++++++++++++ drivers/soc/renesas/rcar-gen4-sysc.c | 3 +++ drivers/soc/renesas/rcar-gen4-sysc.h | 1 + 5 files changed, 56 insertions(+) create mode 100644 drivers/soc/renesas/r8a779f0-sysc.c (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 2b09d6cf0d66..59a4106a66e9 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -340,6 +340,10 @@ config SYSC_R8A77961 bool "System Controller support for R-Car M3-W+" if COMPILE_TEST select SYSC_RCAR +config SYSC_R8A779F0 + bool "System Controller support for R-Car S4-8" if COMPILE_TEST + select SYSC_RCAR_GEN4 + config SYSC_R8A7792 bool "System Controller support for R-Car V2H" if COMPILE_TEST select SYSC_RCAR diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index db90f3b06007..deeb41f84f01 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o +obj-$(CONFIG_SYSC_R8A779F0) += r8a779f0-sysc.o ifdef CONFIG_SMP obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o endif diff --git a/drivers/soc/renesas/r8a779f0-sysc.c b/drivers/soc/renesas/r8a779f0-sysc.c new file mode 100644 index 000000000000..5602aa6bd7ed --- /dev/null +++ b/drivers/soc/renesas/r8a779f0-sysc.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car S4-8 System Controller + * + * Copyright (C) 2021 Renesas Electronics Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rcar-gen4-sysc.h" + +static struct rcar_gen4_sysc_area r8a779f0_areas[] __initdata = { + { "always-on", R8A779F0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "a3e0", R8A779F0_PD_A3E0, R8A779F0_PD_ALWAYS_ON, PD_SCU }, + { "a3e1", R8A779F0_PD_A3E1, R8A779F0_PD_ALWAYS_ON, PD_SCU }, + { "a2e0d0", R8A779F0_PD_A2E0D0, R8A779F0_PD_A3E0, PD_SCU }, + { "a2e0d1", R8A779F0_PD_A2E0D1, R8A779F0_PD_A3E0, PD_SCU }, + { "a2e1d0", R8A779F0_PD_A2E1D0, R8A779F0_PD_A3E1, PD_SCU }, + { "a2e1d1", R8A779F0_PD_A2E1D1, R8A779F0_PD_A3E1, PD_SCU }, + { "a1e0d0c0", R8A779F0_PD_A1E0D0C0, R8A779F0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c1", R8A779F0_PD_A1E0D0C1, R8A779F0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d1c0", R8A779F0_PD_A1E0D1C0, R8A779F0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e0d1c1", R8A779F0_PD_A1E0D1C1, R8A779F0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e1d0c0", R8A779F0_PD_A1E1D0C0, R8A779F0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d0c1", R8A779F0_PD_A1E1D0C1, R8A779F0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d1c0", R8A779F0_PD_A1E1D1C0, R8A779F0_PD_A2E1D1, PD_CPU_NOCR }, + { "a1e1d1c1", R8A779F0_PD_A1E1D1C1, R8A779F0_PD_A2E1D1, PD_CPU_NOCR }, +}; + +const struct rcar_gen4_sysc_info r8a779f0_sysc_info __initconst = { + .areas = r8a779f0_areas, + .num_areas = ARRAY_SIZE(r8a779f0_areas), +}; diff --git a/drivers/soc/renesas/rcar-gen4-sysc.c b/drivers/soc/renesas/rcar-gen4-sysc.c index d9a0929f5f1d..831162a57f9a 100644 --- a/drivers/soc/renesas/rcar-gen4-sysc.c +++ b/drivers/soc/renesas/rcar-gen4-sysc.c @@ -278,6 +278,9 @@ finalize: static const struct of_device_id rcar_gen4_sysc_matches[] __initconst = { #ifdef CONFIG_SYSC_R8A779A0 { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info }, +#endif +#ifdef CONFIG_SYSC_R8A779F0 + { .compatible = "renesas,r8a779f0-sysc", .data = &r8a779f0_sysc_info }, #endif { /* sentinel */ } }; diff --git a/drivers/soc/renesas/rcar-gen4-sysc.h b/drivers/soc/renesas/rcar-gen4-sysc.h index 3470a9e2f5c7..0e0bd102b1f9 100644 --- a/drivers/soc/renesas/rcar-gen4-sysc.h +++ b/drivers/soc/renesas/rcar-gen4-sysc.h @@ -38,5 +38,6 @@ struct rcar_gen4_sysc_info { }; extern const struct rcar_gen4_sysc_info r8a779a0_sysc_info; +extern const struct rcar_gen4_sysc_info r8a779f0_sysc_info; #endif /* __SOC_RENESAS_RCAR_GEN4_SYSC_H__ */ -- cgit v1.2.3 From 9711633587f4fb4376265781c75e39c2a7b21d6f Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 1 Dec 2021 16:33:01 +0900 Subject: soc: renesas: Identify R-Car S4-8 Add support for identifying the R-Car S4-8 (R8A779F0) SoC. Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20211201073308.1003945-8-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/soc/renesas/Kconfig | 7 +++++++ drivers/soc/renesas/renesas-soc.c | 12 ++++++++++++ 2 files changed, 19 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 59a4106a66e9..2cbd03db2cc7 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -235,6 +235,13 @@ config ARCH_R8A77961 This enables support for the Renesas R-Car M3-W+ SoC. This includes different gradings like R-Car M3e and M3e-2G. +config ARCH_R8A779F0 + bool "ARM64 Platform support for R-Car S4-8" + select ARCH_RCAR_GEN3 + select SYSC_R8A779F0 + help + This enables support for the Renesas R-Car S4-8 SoC. + config ARCH_R8A77980 bool "ARM64 Platform support for R-Car V3H" select ARCH_RCAR_GEN3 diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index dff90f504963..62540ffc581a 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -33,6 +33,10 @@ static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = { .reg = 0xfff00044, /* PRR (Product Register) */ }; +static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused = { + .name = "R-Car Gen4", +}; + static const struct renesas_family fam_rmobile __initconst __maybe_unused = { .name = "R-Mobile", .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ @@ -214,6 +218,11 @@ static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = { .id = 0x59, }; +static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused = { + .family = &fam_rcar_gen4, + .id = 0x5a, +}; + static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { .family = &fam_shmobile, .id = 0x37, @@ -319,6 +328,9 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A779A0 { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u }, #endif +#ifdef CONFIG_ARCH_R8A779F0 + { .compatible = "renesas,r8a779f0", .data = &soc_rcar_s4 }, +#endif #if defined(CONFIG_ARCH_R9A07G044) { .compatible = "renesas,r9a07g044", .data = &soc_rz_g2l }, #endif -- cgit v1.2.3 From 363b41dd25397f553bebf87594eca9b2d6445b55 Mon Sep 17 00:00:00 2001 From: Yoshihiro Shimoda Date: Wed, 1 Dec 2021 16:33:04 +0900 Subject: soc: renesas: rcar-rst: Add support for R-Car S4-8 Add support for R-Car S4-8 (R8A779F0) to the R-Car RST driver. The register map of R-Car S4-8 is the same as R-Car V3U so that renames "V3U" and "r8a779a0" to "Gen4". Signed-off-by: Yoshihiro Shimoda Link: https://lore.kernel.org/r/20211201073308.1003945-11-yoshihiro.shimoda.uh@renesas.com Signed-off-by: Geert Uytterhoeven --- drivers/soc/renesas/rcar-rst.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c index 1ad54e0c32e1..4d293eb2d8f3 100644 --- a/drivers/soc/renesas/rcar-rst.c +++ b/drivers/soc/renesas/rcar-rst.c @@ -66,7 +66,7 @@ static const struct rst_config rcar_rst_gen3 __initconst = { .set_rproc_boot_addr = rcar_rst_set_gen3_rproc_boot_addr, }; -static const struct rst_config rcar_rst_r8a779a0 __initconst = { +static const struct rst_config rcar_rst_gen4 __initconst = { .modemr = 0x00, /* MODEMR0 and it has CPG related bits */ }; @@ -100,8 +100,9 @@ static const struct of_device_id rcar_rst_matches[] __initconst = { { .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 }, - /* R-Car V3U */ - { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_r8a779a0 }, + /* R-Car Gen4 */ + { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_gen4 }, + { .compatible = "renesas,r8a779f0-rst", .data = &rcar_rst_gen4 }, { /* sentinel */ } }; -- cgit v1.2.3 From 7fd890b89dea55eb5866640eb8befad26d558161 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 25 Aug 2021 17:03:10 +0200 Subject: soc: xilinx: move PM_INIT_FINALIZE to zynqmp_pm_domains driver PM_INIT_FINALIZE tells the PMU FW that Linux is able to handle the power management nodes that are provided by the PMU FW. Nodes that are not requested are shut down after this call. Calling PM_INIT_FINALIZE from the zynqmp_power driver is wrong. The PM node request mechanism is implemented in the zynqmp_pm_domains driver, which must also call PM_INIT_FINALIZE. Due to the behavior of the PMU FW, all devices must be powered up before PM_INIT_FINALIZE is called, because otherwise the devices might misbehave. Calling PM_INIT_FINALIZE from the sync_state device callback ensures that all users probed successfully before the PMU FW is allowed to power off unused domains. Signed-off-by: Michael Tretter Acked-by: Michal Simek Acked-by: Rajan Vaja Link: https://lore.kernel.org/r/20210825150313.4033156-2-m.tretter@pengutronix.de Signed-off-by: Michal Simek --- drivers/soc/xilinx/zynqmp_pm_domains.c | 16 ++++++++++++++++ drivers/soc/xilinx/zynqmp_power.c | 1 - 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c index 226d343f0a6a..81e8e10f1092 100644 --- a/drivers/soc/xilinx/zynqmp_pm_domains.c +++ b/drivers/soc/xilinx/zynqmp_pm_domains.c @@ -152,11 +152,17 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain, struct device *dev) { + struct device_link *link; int ret; struct zynqmp_pm_domain *pd; pd = container_of(domain, struct zynqmp_pm_domain, gpd); + link = device_link_add(dev, &domain->dev, DL_FLAG_SYNC_STATE_ONLY); + if (!link) + dev_dbg(&domain->dev, "failed to create device link for %s\n", + dev_name(dev)); + /* If this is not the first device to attach there is nothing to do */ if (domain->device_count) return 0; @@ -299,9 +305,19 @@ static int zynqmp_gpd_remove(struct platform_device *pdev) return 0; } +static void zynqmp_gpd_sync_state(struct device *dev) +{ + int ret; + + ret = zynqmp_pm_init_finalize(); + if (ret) + dev_warn(dev, "failed to release power management to firmware\n"); +} + static struct platform_driver zynqmp_power_domain_driver = { .driver = { .name = "zynqmp_power_controller", + .sync_state = zynqmp_gpd_sync_state, }, .probe = zynqmp_gpd_probe, .remove = zynqmp_gpd_remove, diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index c556623dae02..f8c301984d4f 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -178,7 +178,6 @@ static int zynqmp_pm_probe(struct platform_device *pdev) u32 pm_api_version; struct mbox_client *client; - zynqmp_pm_init_finalize(); zynqmp_pm_get_api_version(&pm_api_version); /* Check PM API version number */ -- cgit v1.2.3 From c4245100f7461e0dd1f16ef0e0fcc19bcd826de3 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 25 Aug 2021 17:03:11 +0200 Subject: soc: xilinx: cleanup debug and error messages Use dev_err/dev_dbg instead of pr_err/pr_debug. Add the PM node ids to supplement the (arbitrary) power domain names to include information which PM nodes are requested by the driver. Drop function names from the messages, because they can easily be added with dynamic debug. Remove comments explaining that error messages are printed on errors. Signed-off-by: Michael Tretter Acked-by: Michal Simek Acked-by: Rajan Vaja Link: https://lore.kernel.org/r/20210825150313.4033156-3-m.tretter@pengutronix.de Signed-off-by: Michal Simek --- drivers/soc/xilinx/zynqmp_pm_domains.c | 45 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c index 81e8e10f1092..27c46c68e5cc 100644 --- a/drivers/soc/xilinx/zynqmp_pm_domains.c +++ b/drivers/soc/xilinx/zynqmp_pm_domains.c @@ -80,12 +80,15 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain) ZYNQMP_PM_MAX_QOS, ZYNQMP_PM_REQUEST_ACK_BLOCKING); if (ret) { - pr_err("%s() %s set requirement for node %d failed: %d\n", - __func__, domain->name, pd->node_id, ret); + dev_err(&domain->dev, + "failed to set requirement to 0x%x for PM node id %d: %d\n", + ZYNQMP_PM_CAPABILITY_ACCESS, pd->node_id, ret); return ret; } - pr_debug("%s() Powered on %s domain\n", __func__, domain->name); + dev_dbg(&domain->dev, "set requirement to 0x%x for PM node id %d\n", + ZYNQMP_PM_CAPABILITY_ACCESS, pd->node_id); + return 0; } @@ -110,8 +113,8 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) /* If domain is already released there is nothing to be done */ if (!(pd->flags & ZYNQMP_PM_DOMAIN_REQUESTED)) { - pr_debug("%s() %s domain is already released\n", - __func__, domain->name); + dev_dbg(&domain->dev, "PM node id %d is already released\n", + pd->node_id); return 0; } @@ -128,17 +131,16 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) ret = zynqmp_pm_set_requirement(pd->node_id, capabilities, 0, ZYNQMP_PM_REQUEST_ACK_NO); - /** - * If powering down of any node inside this domain fails, - * report and return the error - */ if (ret) { - pr_err("%s() %s set requirement for node %d failed: %d\n", - __func__, domain->name, pd->node_id, ret); + dev_err(&domain->dev, + "failed to set requirement to 0x%x for PM node id %d: %d\n", + capabilities, pd->node_id, ret); return ret; } - pr_debug("%s() Powered off %s domain\n", __func__, domain->name); + dev_dbg(&domain->dev, "set requirement to 0x%x for PM node id %d\n", + capabilities, pd->node_id); + return 0; } @@ -169,17 +171,17 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain, ret = zynqmp_pm_request_node(pd->node_id, 0, 0, ZYNQMP_PM_REQUEST_ACK_BLOCKING); - /* If requesting a node fails print and return the error */ if (ret) { - pr_err("%s() %s request failed for node %d: %d\n", - __func__, domain->name, pd->node_id, ret); + dev_err(&domain->dev, "%s request failed for node %d: %d\n", + domain->name, pd->node_id, ret); return ret; } pd->flags |= ZYNQMP_PM_DOMAIN_REQUESTED; - pr_debug("%s() %s attached to %s domain\n", __func__, - dev_name(dev), domain->name); + dev_dbg(&domain->dev, "%s requested PM node id %d\n", + dev_name(dev), pd->node_id); + return 0; } @@ -201,17 +203,16 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain, return; ret = zynqmp_pm_release_node(pd->node_id); - /* If releasing a node fails print the error and return */ if (ret) { - pr_err("%s() %s release failed for node %d: %d\n", - __func__, domain->name, pd->node_id, ret); + dev_err(&domain->dev, "failed to release PM node id %d: %d\n", + pd->node_id, ret); return; } pd->flags &= ~ZYNQMP_PM_DOMAIN_REQUESTED; - pr_debug("%s() %s detached from %s domain\n", __func__, - dev_name(dev), domain->name); + dev_dbg(&domain->dev, "%s released PM node id %d\n", + dev_name(dev), pd->node_id); } static struct generic_pm_domain *zynqmp_gpd_xlate -- cgit v1.2.3 From e7a9106c32c0527735a01ae00d5d9edbdb573b40 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 25 Aug 2021 17:03:12 +0200 Subject: soc: xilinx: use a properly named field instead of flags Instead of defining a flags field and a single bit in this field to signal that a PM node has been requested, use a boolean field with a descriptive name. No functional change, but using a proper name instead of flags makes the code easier to read. Signed-off-by: Michael Tretter Acked-by: Michal Simek Acked-by: Rajan Vaja Link: https://lore.kernel.org/r/20210825150313.4033156-4-m.tretter@pengutronix.de Signed-off-by: Michal Simek --- drivers/soc/xilinx/zynqmp_pm_domains.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c index 27c46c68e5cc..53b0041f9fe0 100644 --- a/drivers/soc/xilinx/zynqmp_pm_domains.c +++ b/drivers/soc/xilinx/zynqmp_pm_domains.c @@ -20,8 +20,6 @@ #include #define ZYNQMP_NUM_DOMAINS (100) -/* Flag stating if PM nodes mapped to the PM domain has been requested */ -#define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0) static int min_capability; @@ -29,12 +27,12 @@ static int min_capability; * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain * @gpd: Generic power domain * @node_id: PM node ID corresponding to device inside PM domain - * @flags: ZynqMP PM domain flags + * @requested: The PM node mapped to the PM domain has been requested */ struct zynqmp_pm_domain { struct generic_pm_domain gpd; u32 node_id; - u8 flags; + bool requested; }; /** @@ -112,7 +110,7 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) pd = container_of(domain, struct zynqmp_pm_domain, gpd); /* If domain is already released there is nothing to be done */ - if (!(pd->flags & ZYNQMP_PM_DOMAIN_REQUESTED)) { + if (!pd->requested) { dev_dbg(&domain->dev, "PM node id %d is already released\n", pd->node_id); return 0; @@ -177,7 +175,7 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain, return ret; } - pd->flags |= ZYNQMP_PM_DOMAIN_REQUESTED; + pd->requested = true; dev_dbg(&domain->dev, "%s requested PM node id %d\n", dev_name(dev), pd->node_id); @@ -209,7 +207,7 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain, return; } - pd->flags &= ~ZYNQMP_PM_DOMAIN_REQUESTED; + pd->requested = false; dev_dbg(&domain->dev, "%s released PM node id %d\n", dev_name(dev), pd->node_id); -- cgit v1.2.3 From 628e8ba1d331397d580e65a61c0fb4b5ae8e5ccb Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Wed, 25 Aug 2021 17:03:13 +0200 Subject: soc: xilinx: add a to_zynqmp_pm_domain macro Replace container_of for converting a generic_pm_domain to a zynqmp_pm_domain with a macro definition to simplify the code. Signed-off-by: Michael Tretter Acked-by: Michal Simek Acked-by: Rajan Vaja Link: https://lore.kernel.org/r/20210825150313.4033156-5-m.tretter@pengutronix.de Signed-off-by: Michal Simek --- drivers/soc/xilinx/zynqmp_pm_domains.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c index 53b0041f9fe0..fcce2433bd6d 100644 --- a/drivers/soc/xilinx/zynqmp_pm_domains.c +++ b/drivers/soc/xilinx/zynqmp_pm_domains.c @@ -35,6 +35,9 @@ struct zynqmp_pm_domain { bool requested; }; +#define to_zynqmp_pm_domain(pm_domain) \ + container_of(pm_domain, struct zynqmp_pm_domain, gpd) + /** * zynqmp_gpd_is_active_wakeup_path() - Check if device is in wakeup source * path @@ -69,10 +72,9 @@ static int zynqmp_gpd_is_active_wakeup_path(struct device *dev, void *not_used) */ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain) { + struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain); int ret; - struct zynqmp_pm_domain *pd; - pd = container_of(domain, struct zynqmp_pm_domain, gpd); ret = zynqmp_pm_set_requirement(pd->node_id, ZYNQMP_PM_CAPABILITY_ACCESS, ZYNQMP_PM_MAX_QOS, @@ -101,14 +103,12 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain) */ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) { + struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain); int ret; struct pm_domain_data *pdd, *tmp; - struct zynqmp_pm_domain *pd; u32 capabilities = min_capability; bool may_wakeup; - pd = container_of(domain, struct zynqmp_pm_domain, gpd); - /* If domain is already released there is nothing to be done */ if (!pd->requested) { dev_dbg(&domain->dev, "PM node id %d is already released\n", @@ -152,11 +152,9 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain, struct device *dev) { + struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain); struct device_link *link; int ret; - struct zynqmp_pm_domain *pd; - - pd = container_of(domain, struct zynqmp_pm_domain, gpd); link = device_link_add(dev, &domain->dev, DL_FLAG_SYNC_STATE_ONLY); if (!link) @@ -191,10 +189,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain, static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain, struct device *dev) { + struct zynqmp_pm_domain *pd = to_zynqmp_pm_domain(domain); int ret; - struct zynqmp_pm_domain *pd; - - pd = container_of(domain, struct zynqmp_pm_domain, gpd); /* If this is not the last device to detach there is nothing to do */ if (domain->device_count) @@ -220,7 +216,7 @@ static struct generic_pm_domain *zynqmp_gpd_xlate unsigned int i, idx = genpdspec->args[0]; struct zynqmp_pm_domain *pd; - pd = container_of(genpd_data->domains[0], struct zynqmp_pm_domain, gpd); + pd = to_zynqmp_pm_domain(genpd_data->domains[0]); if (genpdspec->args_count != 1) return ERR_PTR(-EINVAL); -- cgit v1.2.3 From cc1fe1e54ba565aaec0006796db65b7c3b1ccd69 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Thu, 9 Dec 2021 13:45:00 +0900 Subject: soc: apple: apple-pmgr-pwrstate: Add auto-PM min level support This is seemingly required for DCP/DCPEXT, without which they refuse to boot properly. They need to be set to minimum state 4 (clock gated). Reviewed-by: Sven Peter Signed-off-by: Hector Martin --- drivers/soc/apple/apple-pmgr-pwrstate.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/apple/apple-pmgr-pwrstate.c b/drivers/soc/apple/apple-pmgr-pwrstate.c index 8ad9d5fdefbf..e1122288409a 100644 --- a/drivers/soc/apple/apple-pmgr-pwrstate.c +++ b/drivers/soc/apple/apple-pmgr-pwrstate.c @@ -20,6 +20,7 @@ #define APPLE_PMGR_RESET BIT(31) #define APPLE_PMGR_AUTO_ENABLE BIT(28) #define APPLE_PMGR_PS_AUTO GENMASK(27, 24) +#define APPLE_PMGR_PS_MIN GENMASK(19, 16) #define APPLE_PMGR_PARENT_OFF BIT(11) #define APPLE_PMGR_DEV_DISABLE BIT(10) #define APPLE_PMGR_WAS_CLKGATED BIT(9) @@ -42,6 +43,7 @@ struct apple_pmgr_ps { struct reset_controller_dev rcdev; struct regmap *regmap; u32 offset; + u32 min_state; }; #define genpd_to_apple_pmgr_ps(_genpd) container_of(_genpd, struct apple_pmgr_ps, genpd) @@ -224,6 +226,11 @@ static int apple_pmgr_ps_probe(struct platform_device *pdev) ps->genpd.power_on = apple_pmgr_ps_power_on; ps->genpd.power_off = apple_pmgr_ps_power_off; + ret = of_property_read_u32(node, "apple,min-state", &ps->min_state); + if (ret == 0 && ps->min_state <= APPLE_PMGR_PS_ACTIVE) + regmap_update_bits(regmap, ps->offset, APPLE_PMGR_FLAGS | APPLE_PMGR_PS_MIN, + FIELD_PREP(APPLE_PMGR_PS_MIN, ps->min_state)); + active = apple_pmgr_ps_is_active(ps); if (of_property_read_bool(node, "apple,always-on")) { ps->genpd.flags |= GENPD_FLAG_ALWAYS_ON; -- cgit v1.2.3 From a34ff76a161583d24d29816a6cce85232ea7d9d0 Mon Sep 17 00:00:00 2001 From: Aswath Govindraju Date: Fri, 3 Dec 2021 17:39:13 +0530 Subject: soc: ti: k3-socinfo: Add entry for J721S2 SoC family J721S2 SoC's JTAG PARTNO is 0xBB75. Signed-off-by: Aswath Govindraju Signed-off-by: Nishanth Menon Reviewed-by: Kishon Vijay Abraham I Link: https://lore.kernel.org/r/20211203120913.14737-1-a-govindraju@ti.com --- drivers/soc/ti/k3-socinfo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c index fd91129de6e5..b6b2150aca4e 100644 --- a/drivers/soc/ti/k3-socinfo.c +++ b/drivers/soc/ti/k3-socinfo.c @@ -40,7 +40,8 @@ static const struct k3_soc_id { { 0xBB5A, "AM65X" }, { 0xBB64, "J721E" }, { 0xBB6D, "J7200" }, - { 0xBB38, "AM64X" } + { 0xBB38, "AM64X" }, + { 0xBB75, "J721S2"}, }; static int -- cgit v1.2.3 From 8e136c5ea43ae08c5d672deb1c3f494782a4392a Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Wed, 15 Dec 2021 20:27:54 +0900 Subject: soc: apple: apple-pmgr-pwrstate: Do not build as a module This doesn't make any sense as a module since it is a critical device, and it turns out of_phandle_iterator_args was not exported so the module version doesn't build anyway. Fixes: 6df9d38f9146 ("soc: apple: Add driver for Apple PMGR power state controls") Reported-by: kernel test robot Reviewed-by: Sven Peter Signed-off-by: Hector Martin --- drivers/soc/apple/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/apple/Kconfig b/drivers/soc/apple/Kconfig index 3eb14abf8d33..9b8de31d6a8f 100644 --- a/drivers/soc/apple/Kconfig +++ b/drivers/soc/apple/Kconfig @@ -5,7 +5,7 @@ if ARCH_APPLE || COMPILE_TEST menu "Apple SoC drivers" config APPLE_PMGR_PWRSTATE - tristate "Apple SoC PMGR power state control" + bool "Apple SoC PMGR power state control" depends on PM select REGMAP select MFD_SYSCON -- cgit v1.2.3 From 1bb0b8b195d821d009bae61248da14f2b17bd44a Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Tue, 14 Dec 2021 01:55:44 +0000 Subject: soc: ti: knav_dma: Fix NULL vs IS_ERR() checking in dma_init Since devm_ioremap_resource() function return error pointers. The pktdma_get_regs() function does not return NULL, It return error pointers too. Using IS_ERR() to check the return value to fix this. Signed-off-by: Miaoqian Lin Signed-off-by: Nishanth Menon Link: https://lore.kernel.org/r/20211214015544.7270-1-linmq006@gmail.com --- drivers/soc/ti/knav_dma.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index 591d14ebcb11..700d8eecd8c4 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -646,31 +646,31 @@ static int dma_init(struct device_node *cloud, struct device_node *dma_node) } dma->reg_global = pktdma_get_regs(dma, node, 0, &size); - if (!dma->reg_global) - return -ENODEV; + if (IS_ERR(dma->reg_global)) + return PTR_ERR(dma->reg_global); if (size < sizeof(struct reg_global)) { dev_err(kdev->dev, "bad size %pa for global regs\n", &size); return -ENODEV; } dma->reg_tx_chan = pktdma_get_regs(dma, node, 1, &size); - if (!dma->reg_tx_chan) - return -ENODEV; + if (IS_ERR(dma->reg_tx_chan)) + return PTR_ERR(dma->reg_tx_chan); max_tx_chan = size / sizeof(struct reg_chan); dma->reg_rx_chan = pktdma_get_regs(dma, node, 2, &size); - if (!dma->reg_rx_chan) - return -ENODEV; + if (IS_ERR(dma->reg_rx_chan)) + return PTR_ERR(dma->reg_rx_chan); max_rx_chan = size / sizeof(struct reg_chan); dma->reg_tx_sched = pktdma_get_regs(dma, node, 3, &size); - if (!dma->reg_tx_sched) - return -ENODEV; + if (IS_ERR(dma->reg_tx_sched)) + return PTR_ERR(dma->reg_tx_sched); max_tx_sched = size / sizeof(struct reg_tx_sched); dma->reg_rx_flow = pktdma_get_regs(dma, node, 4, &size); - if (!dma->reg_rx_flow) - return -ENODEV; + if (IS_ERR(dma->reg_rx_flow)) + return PTR_ERR(dma->reg_rx_flow); max_rx_flow = size / sizeof(struct reg_rx_flow); dma->rx_priority = DMA_PRIO_DEFAULT; -- cgit v1.2.3 From 66209e6fbd564f1bb3c69248423e4b761904a943 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 1 Dec 2021 02:23:10 +0300 Subject: soc/tegra: Don't print error message when OPPs not available Previously we assumed that devm_tegra_core_dev_init_opp_table() will be used only by drivers that will always have device with OPP table, but this is not true anymore. For example now Tegra30 will have OPP table for PWM, but Tegra20 not and both use the same driver. Hence let's not print the error message about missing OPP table in the common helper, we can print it elsewhere. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index 35c882da55fc..32c346b72635 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -136,9 +136,7 @@ int devm_tegra_core_dev_init_opp_table(struct device *dev, */ err = devm_pm_opp_of_add_table(dev); if (err) { - if (err == -ENODEV) - dev_err_once(dev, "OPP table not found, please update device-tree\n"); - else + if (err != -ENODEV) dev_err(dev, "failed to add OPP table: %d\n", err); return err; -- cgit v1.2.3 From 765d95f8ac54af611c804bb956b79391cfc1d27b Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 30 Nov 2021 11:44:06 +0000 Subject: soc/tegra: pmc: Add reboot notifier The Tegra PMC driver implements a restart handler that supports Tegra specific reboot commands such as placing the device into 'recovery' mode in order to reprogram the platform. This is accomplished by setting the appropriate bit in the PMC scratch0 register prior to rebooting the platform. For Tegra platforms that support PSCI or EFI, the default Tegra restart handler is not called and the PSCI or EFI restart handler is called instead. Hence, for Tegra platforms that support PSCI or EFI, the Tegra specific reboot commands do not currently work. Fix this by moving the code that programs the PMC scratch0 register into a separate reboot notifier that will always be called on reboot. Signed-off-by: Jon Hunter Reviewed-by: Dmitry Osipenko Tested-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 575d6d5b4294..6db0e31ac6fa 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1064,10 +1064,8 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid) return tegra_powergate_remove_clamping(id); } -static int tegra_pmc_restart_notify(struct notifier_block *this, - unsigned long action, void *data) +static void tegra_pmc_program_reboot_reason(const char *cmd) { - const char *cmd = data; u32 value; value = tegra_pmc_scratch_readl(pmc, pmc->soc->regs->scratch0); @@ -1085,6 +1083,25 @@ static int tegra_pmc_restart_notify(struct notifier_block *this, } tegra_pmc_scratch_writel(pmc, value, pmc->soc->regs->scratch0); +} + +static int tegra_pmc_reboot_notify(struct notifier_block *this, + unsigned long action, void *data) +{ + if (action == SYS_RESTART) + tegra_pmc_program_reboot_reason(data); + + return NOTIFY_DONE; +} + +static struct notifier_block tegra_pmc_reboot_notifier = { + .notifier_call = tegra_pmc_reboot_notify, +}; + +static int tegra_pmc_restart_notify(struct notifier_block *this, + unsigned long action, void *data) +{ + u32 value; /* reset everything but PMC_SCRATCH0 and PMC_RST_STATUS */ value = tegra_pmc_readl(pmc, PMC_CNTRL); @@ -2890,6 +2907,14 @@ static int tegra_pmc_probe(struct platform_device *pdev) goto cleanup_sysfs; } + err = devm_register_reboot_notifier(&pdev->dev, + &tegra_pmc_reboot_notifier); + if (err) { + dev_err(&pdev->dev, "unable to register reboot notifier, %d\n", + err); + goto cleanup_debugfs; + } + err = register_restart_handler(&tegra_pmc_restart_handler); if (err) { dev_err(&pdev->dev, "unable to register restart handler, %d\n", -- cgit v1.2.3 From aeecc50ace0480e6df565093e578b129902918db Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 1 Dec 2021 02:23:35 +0300 Subject: soc/tegra: fuse: Reset hardware The FUSE controller is enabled at a boot time. Reset it in order to put hardware and clock into clean and disabled state. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/fuse-tegra.c | 25 +++++++++++++++++++++++++ drivers/soc/tegra/fuse/fuse.h | 1 + 2 files changed, 26 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index f2151815db58..cc032729a143 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -243,6 +244,30 @@ static int tegra_fuse_probe(struct platform_device *pdev) goto restore; } + fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse"); + if (IS_ERR(fuse->rst)) { + err = PTR_ERR(fuse->rst); + dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n", + fuse->rst); + goto restore; + } + + /* + * FUSE clock is enabled at a boot time, hence this resume/suspend + * disables the clock besides the h/w resetting. + */ + err = pm_runtime_resume_and_get(&pdev->dev); + if (err) + goto restore; + + err = reset_control_reset(fuse->rst); + pm_runtime_put(&pdev->dev); + + if (err < 0) { + dev_err(&pdev->dev, "failed to reset FUSE: %d\n", err); + goto restore; + } + /* release the early I/O memory mapping */ iounmap(base); diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index de58feba0435..1b719d85bd04 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -43,6 +43,7 @@ struct tegra_fuse { void __iomem *base; phys_addr_t phys; struct clk *clk; + struct reset_control *rst; u32 (*read_early)(struct tegra_fuse *fuse, unsigned int offset); u32 (*read)(struct tegra_fuse *fuse, unsigned int offset); -- cgit v1.2.3 From 88724b78a84c85350c21ac8d4432f2cf5a77a10a Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 1 Dec 2021 02:23:36 +0300 Subject: soc/tegra: fuse: Use resource-managed helpers Use resource-managed helpers to make code cleaner and more correct, properly releasing all resources in case of driver probe error. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/fuse/fuse-tegra.c | 32 ++++++++++++++++++-------------- drivers/soc/tegra/fuse/fuse-tegra20.c | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 17 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index cc032729a143..fe4f935ce73a 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -182,6 +182,12 @@ static const struct nvmem_cell_info tegra_fuse_cells[] = { }, }; +static void tegra_fuse_restore(void *base) +{ + fuse->clk = NULL; + fuse->base = base; +} + static int tegra_fuse_probe(struct platform_device *pdev) { void __iomem *base = fuse->base; @@ -189,13 +195,16 @@ static int tegra_fuse_probe(struct platform_device *pdev) struct resource *res; int err; + err = devm_add_action(&pdev->dev, tegra_fuse_restore, base); + if (err) + return err; + /* take over the memory region from the early initialization */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); fuse->phys = res->start; fuse->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(fuse->base)) { err = PTR_ERR(fuse->base); - fuse->base = base; return err; } @@ -205,19 +214,20 @@ static int tegra_fuse_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get FUSE clock: %ld", PTR_ERR(fuse->clk)); - fuse->base = base; return PTR_ERR(fuse->clk); } platform_set_drvdata(pdev, fuse); fuse->dev = &pdev->dev; - pm_runtime_enable(&pdev->dev); + err = devm_pm_runtime_enable(&pdev->dev); + if (err) + return err; if (fuse->soc->probe) { err = fuse->soc->probe(fuse); if (err < 0) - goto restore; + return err; } memset(&nvmem, 0, sizeof(nvmem)); @@ -241,7 +251,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) err = PTR_ERR(fuse->nvmem); dev_err(&pdev->dev, "failed to register NVMEM device: %d\n", err); - goto restore; + return err; } fuse->rst = devm_reset_control_get_optional(&pdev->dev, "fuse"); @@ -249,7 +259,7 @@ static int tegra_fuse_probe(struct platform_device *pdev) err = PTR_ERR(fuse->rst); dev_err(&pdev->dev, "failed to get FUSE reset: %pe\n", fuse->rst); - goto restore; + return err; } /* @@ -258,26 +268,20 @@ static int tegra_fuse_probe(struct platform_device *pdev) */ err = pm_runtime_resume_and_get(&pdev->dev); if (err) - goto restore; + return err; err = reset_control_reset(fuse->rst); pm_runtime_put(&pdev->dev); if (err < 0) { dev_err(&pdev->dev, "failed to reset FUSE: %d\n", err); - goto restore; + return err; } /* release the early I/O memory mapping */ iounmap(base); return 0; - -restore: - fuse->clk = NULL; - fuse->base = base; - pm_runtime_disable(&pdev->dev); - return err; } static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev) diff --git a/drivers/soc/tegra/fuse/fuse-tegra20.c b/drivers/soc/tegra/fuse/fuse-tegra20.c index 8ec9fc5e5e4b..12503f563e36 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra20.c +++ b/drivers/soc/tegra/fuse/fuse-tegra20.c @@ -94,9 +94,28 @@ static bool dma_filter(struct dma_chan *chan, void *filter_param) return of_device_is_compatible(np, "nvidia,tegra20-apbdma"); } +static void tegra20_fuse_release_channel(void *data) +{ + struct tegra_fuse *fuse = data; + + dma_release_channel(fuse->apbdma.chan); + fuse->apbdma.chan = NULL; +} + +static void tegra20_fuse_free_coherent(void *data) +{ + struct tegra_fuse *fuse = data; + + dma_free_coherent(fuse->dev, sizeof(u32), fuse->apbdma.virt, + fuse->apbdma.phys); + fuse->apbdma.virt = NULL; + fuse->apbdma.phys = 0x0; +} + static int tegra20_fuse_probe(struct tegra_fuse *fuse) { dma_cap_mask_t mask; + int err; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); @@ -105,13 +124,21 @@ static int tegra20_fuse_probe(struct tegra_fuse *fuse) if (!fuse->apbdma.chan) return -EPROBE_DEFER; + err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_release_channel, + fuse); + if (err) + return err; + fuse->apbdma.virt = dma_alloc_coherent(fuse->dev, sizeof(u32), &fuse->apbdma.phys, GFP_KERNEL); - if (!fuse->apbdma.virt) { - dma_release_channel(fuse->apbdma.chan); + if (!fuse->apbdma.virt) return -ENOMEM; - } + + err = devm_add_action_or_reset(fuse->dev, tegra20_fuse_free_coherent, + fuse); + if (err) + return err; fuse->apbdma.config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; fuse->apbdma.config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; -- cgit v1.2.3 From 80ef351c98714bb95bafd30b3faa6f11d8d58eb7 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 1 Dec 2021 02:23:37 +0300 Subject: soc/tegra: regulators: Prepare for suspend Depending on hardware version, Tegra SoC may require a higher voltages during resume from system suspend, otherwise hardware will crash. Set SoC voltages to a nominal levels during suspend. Link: https://lore.kernel.org/all/a8280b5b-7347-8995-c97b-10b798cdf057@gmail.com/ Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/regulators-tegra20.c | 99 ++++++++++++++++++++++++++ drivers/soc/tegra/regulators-tegra30.c | 122 +++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/regulators-tegra20.c b/drivers/soc/tegra/regulators-tegra20.c index b8ce9fd0650d..6a2f90ab9d3e 100644 --- a/drivers/soc/tegra/regulators-tegra20.c +++ b/drivers/soc/tegra/regulators-tegra20.c @@ -16,7 +16,9 @@ #include #include #include +#include +#include #include struct tegra_regulator_coupler { @@ -25,9 +27,12 @@ struct tegra_regulator_coupler { struct regulator_dev *cpu_rdev; struct regulator_dev *rtc_rdev; struct notifier_block reboot_notifier; + struct notifier_block suspend_notifier; int core_min_uV, cpu_min_uV; bool sys_reboot_mode_req; bool sys_reboot_mode; + bool sys_suspend_mode_req; + bool sys_suspend_mode; }; static inline struct tegra_regulator_coupler * @@ -105,6 +110,28 @@ static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev, return 150000; } +static int tegra20_cpu_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + case 0: + return 1100000; + case 1: + return 1025000; + default: + return 1125000; + } +} + +static int tegra20_core_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + default: + return 1225000; + case 2: + return 1300000; + } +} + static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, struct regulator_dev *core_rdev, struct regulator_dev *rtc_rdev, @@ -144,6 +171,11 @@ static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + core_min_uV = clamp(tegra20_core_nominal_uV(), + core_min_uV, core_max_uV); + core_uV = regulator_get_voltage_rdev(core_rdev); if (core_uV < 0) return core_uV; @@ -279,6 +311,11 @@ static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, if (tegra->sys_reboot_mode) cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + cpu_min_uV = clamp(tegra20_cpu_nominal_uV(), + cpu_min_uV, cpu_max_uV); + if (cpu_min_uV > cpu_uV) { err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, cpu_uV, cpu_min_uV); @@ -320,6 +357,7 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, } tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req); if (rdev == cpu_rdev) return tegra20_cpu_voltage_update(tegra, cpu_rdev, @@ -334,6 +372,63 @@ static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, return -EPERM; } +static int tegra20_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra, + bool sys_suspend_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev) + return 0; + + /* + * All power domains are enabled early during resume from suspend + * by GENPD core. Domains like VENC may require a higher voltage + * when enabled during resume from suspend. This also prepares + * hardware for resuming from LP0. + */ + + WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode); + + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + return 0; +} + +static int tegra20_regulator_suspend(struct notifier_block *notifier, + unsigned long mode, void *arg) +{ + struct tegra_regulator_coupler *tegra; + int ret = 0; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + suspend_notifier); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + ret = tegra20_regulator_prepare_suspend(tegra, true); + break; + + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + ret = tegra20_regulator_prepare_suspend(tegra, false); + break; + } + + if (ret) + pr_err("failed to prepare regulators: %d\n", ret); + + return notifier_from_errno(ret); +} + static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, bool sys_reboot_mode) { @@ -444,6 +539,7 @@ static struct tegra_regulator_coupler tegra20_coupler = { .balance_voltage = tegra20_regulator_balance_voltage, }, .reboot_notifier.notifier_call = tegra20_regulator_reboot, + .suspend_notifier.notifier_call = tegra20_regulator_suspend, }; static int __init tegra_regulator_coupler_init(void) @@ -456,6 +552,9 @@ static int __init tegra_regulator_coupler_init(void) err = register_reboot_notifier(&tegra20_coupler.reboot_notifier); WARN_ON(err); + err = register_pm_notifier(&tegra20_coupler.suspend_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra20_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); diff --git a/drivers/soc/tegra/regulators-tegra30.c b/drivers/soc/tegra/regulators-tegra30.c index e74bbc9c7859..8fd43c689134 100644 --- a/drivers/soc/tegra/regulators-tegra30.c +++ b/drivers/soc/tegra/regulators-tegra30.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,9 +26,12 @@ struct tegra_regulator_coupler { struct regulator_dev *core_rdev; struct regulator_dev *cpu_rdev; struct notifier_block reboot_notifier; + struct notifier_block suspend_notifier; int core_min_uV, cpu_min_uV; bool sys_reboot_mode_req; bool sys_reboot_mode; + bool sys_suspend_mode_req; + bool sys_suspend_mode; }; static inline struct tegra_regulator_coupler * @@ -113,6 +117,52 @@ static int tegra30_core_cpu_limit(int cpu_uV) return -EINVAL; } +static int tegra30_cpu_nominal_uV(void) +{ + switch (tegra_sku_info.cpu_speedo_id) { + case 10 ... 11: + return 850000; + + case 9: + return 912000; + + case 1 ... 3: + case 7 ... 8: + return 1050000; + + default: + return 1125000; + + case 4 ... 6: + case 12 ... 13: + return 1237000; + } +} + +static int tegra30_core_nominal_uV(void) +{ + switch (tegra_sku_info.soc_speedo_id) { + case 0: + return 1200000; + + case 1: + if (tegra_sku_info.cpu_speedo_id != 7 && + tegra_sku_info.cpu_speedo_id != 8) + return 1200000; + + fallthrough; + + case 2: + if (tegra_sku_info.cpu_speedo_id != 13) + return 1300000; + + return 1350000; + + default: + return 1250000; + } +} + static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, struct regulator_dev *cpu_rdev, struct regulator_dev *core_rdev) @@ -168,6 +218,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (err) return err; + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + core_min_uV = clamp(tegra30_core_nominal_uV(), + core_min_uV, core_max_uV); + core_uV = regulator_get_voltage_rdev(core_rdev); if (core_uV < 0) return core_uV; @@ -223,6 +278,11 @@ static int tegra30_voltage_update(struct tegra_regulator_coupler *tegra, if (tegra->sys_reboot_mode) cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); + /* prepare voltage level for suspend */ + if (tegra->sys_suspend_mode) + cpu_min_uV = clamp(tegra30_cpu_nominal_uV(), + cpu_min_uV, cpu_max_uV); + if (core_min_limited_uV > core_uV) { pr_err("core voltage constraint violated: %d %d %d\n", core_uV, core_min_limited_uV, cpu_uV); @@ -292,10 +352,68 @@ static int tegra30_regulator_balance_voltage(struct regulator_coupler *coupler, } tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); + tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req); return tegra30_voltage_update(tegra, cpu_rdev, core_rdev); } +static int tegra30_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra, + bool sys_suspend_mode) +{ + int err; + + if (!tegra->core_rdev || !tegra->cpu_rdev) + return 0; + + /* + * All power domains are enabled early during resume from suspend + * by GENPD core. Domains like VENC may require a higher voltage + * when enabled during resume from suspend. This also prepares + * hardware for resuming from LP0. + */ + + WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode); + + err = regulator_sync_voltage_rdev(tegra->cpu_rdev); + if (err) + return err; + + err = regulator_sync_voltage_rdev(tegra->core_rdev); + if (err) + return err; + + return 0; +} + +static int tegra30_regulator_suspend(struct notifier_block *notifier, + unsigned long mode, void *arg) +{ + struct tegra_regulator_coupler *tegra; + int ret = 0; + + tegra = container_of(notifier, struct tegra_regulator_coupler, + suspend_notifier); + + switch (mode) { + case PM_HIBERNATION_PREPARE: + case PM_RESTORE_PREPARE: + case PM_SUSPEND_PREPARE: + ret = tegra30_regulator_prepare_suspend(tegra, true); + break; + + case PM_POST_HIBERNATION: + case PM_POST_RESTORE: + case PM_POST_SUSPEND: + ret = tegra30_regulator_prepare_suspend(tegra, false); + break; + } + + if (ret) + pr_err("failed to prepare regulators: %d\n", ret); + + return notifier_from_errno(ret); +} + static int tegra30_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, bool sys_reboot_mode) { @@ -395,6 +513,7 @@ static struct tegra_regulator_coupler tegra30_coupler = { .balance_voltage = tegra30_regulator_balance_voltage, }, .reboot_notifier.notifier_call = tegra30_regulator_reboot, + .suspend_notifier.notifier_call = tegra30_regulator_suspend, }; static int __init tegra_regulator_coupler_init(void) @@ -407,6 +526,9 @@ static int __init tegra_regulator_coupler_init(void) err = register_reboot_notifier(&tegra30_coupler.reboot_notifier); WARN_ON(err); + err = register_pm_notifier(&tegra30_coupler.suspend_notifier); + WARN_ON(err); + return regulator_coupler_register(&tegra30_coupler.coupler); } arch_initcall(tegra_regulator_coupler_init); -- cgit v1.2.3 From 006da96c840ff60a1764fc38ee7adc3dc4191d79 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 1 Dec 2021 02:23:08 +0300 Subject: soc/tegra: Enable runtime PM during OPP state-syncing GENPD core now can set up domain's performance state properly while device is RPM-suspended. Runtime PM of a device must be enabled during setup because GENPD checks whether device is suspended and check doesn't work while RPM is disabled. Instead of replicating the boilerplate RPM-enable code around OPP helper for each driver, let's make OPP helper to take care of enabling it. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/common.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index cd33e99249c3..35c882da55fc 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ static int tegra_core_dev_init_opp_state(struct device *dev) { unsigned long rate; struct clk *clk; + bool rpm_enabled; int err; clk = devm_clk_get(dev, NULL); @@ -57,8 +59,31 @@ static int tegra_core_dev_init_opp_state(struct device *dev) return -EINVAL; } + /* + * Runtime PM of the device must be enabled in order to set up + * GENPD's performance properly because GENPD core checks whether + * device is suspended and this check doesn't work while RPM is + * disabled. This makes sure the OPP vote below gets cached in + * GENPD for the device. Instead, the vote is done the next time + * the device gets runtime resumed. + */ + rpm_enabled = pm_runtime_enabled(dev); + if (!rpm_enabled) + pm_runtime_enable(dev); + + /* should never happen in practice */ + if (!pm_runtime_enabled(dev)) { + dev_WARN(dev, "failed to enable runtime PM\n"); + pm_runtime_disable(dev); + return -EINVAL; + } + /* first dummy rate-setting initializes voltage vote */ err = dev_pm_opp_set_rate(dev, rate); + + if (!rpm_enabled) + pm_runtime_disable(dev); + if (err) { dev_err(dev, "failed to initialize OPP clock: %d\n", err); return err; -- cgit v1.2.3 From 8d1a3411da0c90f506c5e2f69529f4ba2954d3a3 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 1 Dec 2021 02:23:38 +0300 Subject: soc/tegra: pmc: Rename 3d power domains Device-tree schema doesn't allow domain name to start with a number. We don't use 3d domain yet in device-trees, so rename it to the name used by Tegra TRMs: TD, TD2. Reported-by: David Heidelberg Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 6db0e31ac6fa..cc8c22327311 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -2988,7 +2988,7 @@ static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume); static const char * const tegra20_powergates[] = { [TEGRA_POWERGATE_CPU] = "cpu", - [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_PCIE] = "pcie", @@ -3096,7 +3096,7 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { static const char * const tegra30_powergates[] = { [TEGRA_POWERGATE_CPU] = "cpu0", - [TEGRA_POWERGATE_3D] = "3d0", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_PCIE] = "pcie", @@ -3108,7 +3108,7 @@ static const char * const tegra30_powergates[] = { [TEGRA_POWERGATE_CPU2] = "cpu2", [TEGRA_POWERGATE_CPU3] = "cpu3", [TEGRA_POWERGATE_CELP] = "celp", - [TEGRA_POWERGATE_3D1] = "3d1", + [TEGRA_POWERGATE_3D1] = "td2", }; static const u8 tegra30_cpu_powergates[] = { @@ -3157,7 +3157,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { static const char * const tegra114_powergates[] = { [TEGRA_POWERGATE_CPU] = "crail", - [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_3D] = "td", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_VDEC] = "vdec", [TEGRA_POWERGATE_MPE] = "mpe", -- cgit v1.2.3 From 81c4c86c66650f61c6d7a712737d43a3e4d072bf Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Wed, 1 Dec 2021 02:23:39 +0300 Subject: soc/tegra: pmc: Rename core power domain CORE power domain uses name of device-tree node, which is inconsistent with the names of PMC domains. Set the name to "core" to make it consistent. Reviewed-by: Ulf Hansson Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index cc8c22327311..5aceacbd8ce0 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1370,7 +1370,7 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) if (!genpd) return -ENOMEM; - genpd->name = np->name; + genpd->name = "core"; genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; -- cgit v1.2.3 From e2a6d22f3b48dffcab1dbcb162572ef5a923f24d Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 14 Dec 2021 18:46:18 -0600 Subject: soc: imx: gpcv2: keep i.MX8MN gpumix bus clock enabled Like the i.MX8MM, keep the gpumix clocks running when the domain is active. Signed-off-by: Adam Ford Reviewed-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 8176380b02e6..a0eab9f41a71 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -841,6 +841,7 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = { .hskack = IMX8MN_GPUMIX_HSK_PWRDNACKN, }, .pgc = BIT(IMX8MN_PGC_GPUMIX), + .keep_clocks = true, }, }; -- cgit v1.2.3 From a0ec8a3a4c8122c1abae04e90c66e79e77eed357 Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 14 Dec 2021 18:46:19 -0600 Subject: soc: imx: gpcv2: Add dispmix and mipi domains to imx8mn The dispmix will be needed for the blkctl driver, so add it to the gpcv2. Signed-off-by: Adam Ford Reviewed-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index a0eab9f41a71..3e59d479d001 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -843,6 +843,31 @@ static const struct imx_pgc_domain imx8mn_pgc_domains[] = { .pgc = BIT(IMX8MN_PGC_GPUMIX), .keep_clocks = true, }, + + [IMX8MN_POWER_DOMAIN_DISPMIX] = { + .genpd = { + .name = "dispmix", + }, + .bits = { + .pxx = IMX8MN_DISPMIX_SW_Pxx_REQ, + .map = IMX8MN_DISPMIX_A53_DOMAIN, + .hskreq = IMX8MN_DISPMIX_HSK_PWRDNREQN, + .hskack = IMX8MN_DISPMIX_HSK_PWRDNACKN, + }, + .pgc = BIT(IMX8MN_PGC_DISPMIX), + .keep_clocks = true, + }, + + [IMX8MN_POWER_DOMAIN_MIPI] = { + .genpd = { + .name = "mipi", + }, + .bits = { + .pxx = IMX8MN_MIPI_SW_Pxx_REQ, + .map = IMX8MN_MIPI_A53_DOMAIN, + }, + .pgc = BIT(IMX8MN_PGC_MIPI), + }, }; static const struct regmap_range imx8mn_yes_ranges[] = { -- cgit v1.2.3 From 7f511d514e8c34b6dd0c17b5496e48b2a6a2626c Mon Sep 17 00:00:00 2001 From: Adam Ford Date: Tue, 14 Dec 2021 18:46:22 -0600 Subject: soc: imx: imx8m-blk-ctrl: add i.MX8MN DISP blk-ctrl This adds the description for the i.MX8MN disp blk-ctrl. Signed-off-by: Adam Ford Reviewed-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/imx8m-blk-ctrl.c | 77 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/imx/imx8m-blk-ctrl.c b/drivers/soc/imx/imx8m-blk-ctrl.c index 519b3651d1d9..58a7f11e7e08 100644 --- a/drivers/soc/imx/imx8m-blk-ctrl.c +++ b/drivers/soc/imx/imx8m-blk-ctrl.c @@ -14,6 +14,7 @@ #include #include +#include #define BLK_SFT_RSTN 0x0 #define BLK_CLK_EN 0x4 @@ -498,6 +499,77 @@ static const struct imx8m_blk_ctrl_data imx8mm_disp_blk_ctl_dev_data = { .num_domains = ARRAY_SIZE(imx8mm_disp_blk_ctl_domain_data), }; + +static int imx8mn_disp_power_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct imx8m_blk_ctrl *bc = container_of(nb, struct imx8m_blk_ctrl, + power_nb); + + if (action != GENPD_NOTIFY_ON && action != GENPD_NOTIFY_PRE_OFF) + return NOTIFY_OK; + + /* Enable bus clock and deassert bus reset */ + regmap_set_bits(bc->regmap, BLK_CLK_EN, BIT(8)); + regmap_set_bits(bc->regmap, BLK_SFT_RSTN, BIT(8)); + + /* + * On power up we have no software backchannel to the GPC to + * wait for the ADB handshake to happen, so we just delay for a + * bit. On power down the GPC driver waits for the handshake. + */ + if (action == GENPD_NOTIFY_ON) + udelay(5); + + + return NOTIFY_OK; +} + +static const struct imx8m_blk_ctrl_domain_data imx8mn_disp_blk_ctl_domain_data[] = { + [IMX8MN_DISPBLK_PD_MIPI_DSI] = { + .name = "dispblk-mipi-dsi", + .clk_names = (const char *[]){ "dsi-pclk", "dsi-ref", }, + .num_clks = 2, + .gpc_name = "mipi-dsi", + .rst_mask = BIT(0) | BIT(1), + .clk_mask = BIT(0) | BIT(1), + .mipi_phy_rst_mask = BIT(17), + }, + [IMX8MN_DISPBLK_PD_MIPI_CSI] = { + .name = "dispblk-mipi-csi", + .clk_names = (const char *[]){ "csi-aclk", "csi-pclk" }, + .num_clks = 2, + .gpc_name = "mipi-csi", + .rst_mask = BIT(2) | BIT(3), + .clk_mask = BIT(2) | BIT(3), + .mipi_phy_rst_mask = BIT(16), + }, + [IMX8MN_DISPBLK_PD_LCDIF] = { + .name = "dispblk-lcdif", + .clk_names = (const char *[]){ "lcdif-axi", "lcdif-apb", "lcdif-pix", }, + .num_clks = 3, + .gpc_name = "lcdif", + .rst_mask = BIT(4) | BIT(5), + .clk_mask = BIT(4) | BIT(5), + }, + [IMX8MN_DISPBLK_PD_ISI] = { + .name = "dispblk-isi", + .clk_names = (const char *[]){ "disp_axi", "disp_apb", "disp_axi_root", + "disp_apb_root"}, + .num_clks = 4, + .gpc_name = "isi", + .rst_mask = BIT(6) | BIT(7), + .clk_mask = BIT(6) | BIT(7), + }, +}; + +static const struct imx8m_blk_ctrl_data imx8mn_disp_blk_ctl_dev_data = { + .max_reg = 0x84, + .power_notifier_fn = imx8mn_disp_power_notifier, + .domains = imx8mn_disp_blk_ctl_domain_data, + .num_domains = ARRAY_SIZE(imx8mn_disp_blk_ctl_domain_data), +}; + static const struct of_device_id imx8m_blk_ctrl_of_match[] = { { .compatible = "fsl,imx8mm-vpu-blk-ctrl", @@ -505,7 +577,10 @@ static const struct of_device_id imx8m_blk_ctrl_of_match[] = { }, { .compatible = "fsl,imx8mm-disp-blk-ctrl", .data = &imx8mm_disp_blk_ctl_dev_data - } ,{ + }, { + .compatible = "fsl,imx8mn-disp-blk-ctrl", + .data = &imx8mn_disp_blk_ctl_dev_data + }, { /* Sentinel */ } }; -- cgit v1.2.3 From b603377e408fb41dbb0971635c57e123edbb5bf8 Mon Sep 17 00:00:00 2001 From: Sam Protsenko Date: Sat, 4 Dec 2021 21:57:54 +0200 Subject: soc: samsung: Add USI driver USIv2 IP-core is found on modern ARM64 Exynos SoCs (like Exynos850) and provides selectable serial protocol (one of: UART, SPI, I2C). USIv2 registers usually reside in the same register map as a particular underlying protocol it implements, but have some particular offset. E.g. on Exynos850 the USI_UART has 0x13820000 base address, where UART registers have 0x00..0x40 offsets, and USI registers have 0xc0..0xdc offsets. Desired protocol can be chosen via SW_CONF register from System Register block of the same domain as USI. Before starting to use a particular protocol, USIv2 must be configured properly: 1. Select protocol to be used via System Register 2. Clear "reset" flag in USI_CON 3. Configure HWACG behavior (e.g. for UART Rx the HWACG must be disabled, so that the IP clock is not gated automatically); this is done using USI_OPTION register 4. Keep both USI clocks (PCLK and IPCLK) running during USI registers modification This driver implements the above behavior. Of course, USIv2 driver should be probed before UART/I2C/SPI drivers. It can be achieved by embedding UART/I2C/SPI nodes inside of the USI node (in Device Tree); driver then walks underlying nodes and instantiates those. Driver also handles USI configuration on PM resume, as register contents can be lost during CPU suspend. This driver is designed with different USI versions in mind. So it should be relatively easy to add new USI revisions to it later. Signed-off-by: Sam Protsenko Link: https://lore.kernel.org/r/20211204195757.8600-3-semen.protsenko@linaro.org Tested-by: Chanho Park Signed-off-by: Krzysztof Kozlowski --- drivers/soc/samsung/Kconfig | 14 ++ drivers/soc/samsung/Makefile | 2 + drivers/soc/samsung/exynos-usi.c | 285 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 301 insertions(+) create mode 100644 drivers/soc/samsung/exynos-usi.c (limited to 'drivers/soc') diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index e2cedef1e8d1..a9f8b224322e 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -23,6 +23,20 @@ config EXYNOS_CHIPID Support for Samsung Exynos SoC ChipID and Adaptive Supply Voltage. This driver can also be built as module (exynos_chipid). +config EXYNOS_USI + tristate "Exynos USI (Universal Serial Interface) driver" + default ARCH_EXYNOS && ARM64 + depends on ARCH_EXYNOS || COMPILE_TEST + select MFD_SYSCON + help + Enable support for USI block. USI (Universal Serial Interface) is an + IP-core found in modern Samsung Exynos SoCs, like Exynos850 and + ExynosAutoV0. USI block can be configured to provide one of the + following serial protocols: UART, SPI or High Speed I2C. + + This driver allows one to configure USI for desired protocol, which + is usually done in USI node in Device Tree. + config EXYNOS_PMU bool "Exynos PMU controller driver" if COMPILE_TEST depends on ARCH_EXYNOS || ((ARM || ARM64) && COMPILE_TEST) diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index 2ae4bea804cf..9f59d1905ab0 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -4,6 +4,8 @@ obj-$(CONFIG_EXYNOS_ASV_ARM) += exynos5422-asv.o obj-$(CONFIG_EXYNOS_CHIPID) += exynos_chipid.o exynos_chipid-y += exynos-chipid.o exynos-asv.o +obj-$(CONFIG_EXYNOS_USI) += exynos-usi.o + obj-$(CONFIG_EXYNOS_PMU) += exynos-pmu.o obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \ diff --git a/drivers/soc/samsung/exynos-usi.c b/drivers/soc/samsung/exynos-usi.c new file mode 100644 index 000000000000..114352695ac2 --- /dev/null +++ b/drivers/soc/samsung/exynos-usi.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 Linaro Ltd. + * Author: Sam Protsenko + * + * Samsung Exynos USI driver (Universal Serial Interface). + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* USIv2: System Register: SW_CONF register bits */ +#define USI_V2_SW_CONF_NONE 0x0 +#define USI_V2_SW_CONF_UART BIT(0) +#define USI_V2_SW_CONF_SPI BIT(1) +#define USI_V2_SW_CONF_I2C BIT(2) +#define USI_V2_SW_CONF_MASK (USI_V2_SW_CONF_UART | USI_V2_SW_CONF_SPI | \ + USI_V2_SW_CONF_I2C) + +/* USIv2: USI register offsets */ +#define USI_CON 0x04 +#define USI_OPTION 0x08 + +/* USIv2: USI register bits */ +#define USI_CON_RESET BIT(0) +#define USI_OPTION_CLKREQ_ON BIT(1) +#define USI_OPTION_CLKSTOP_ON BIT(2) + +enum exynos_usi_ver { + USI_VER2 = 2, +}; + +struct exynos_usi_variant { + enum exynos_usi_ver ver; /* USI IP-core version */ + unsigned int sw_conf_mask; /* SW_CONF mask for all protocols */ + size_t min_mode; /* first index in exynos_usi_modes[] */ + size_t max_mode; /* last index in exynos_usi_modes[] */ + size_t num_clks; /* number of clocks to assert */ + const char * const *clk_names; /* clock names to assert */ +}; + +struct exynos_usi { + struct device *dev; + void __iomem *regs; /* USI register map */ + struct clk_bulk_data *clks; /* USI clocks */ + + size_t mode; /* current USI SW_CONF mode index */ + bool clkreq_on; /* always provide clock to IP */ + + /* System Register */ + struct regmap *sysreg; /* System Register map */ + unsigned int sw_conf; /* SW_CONF register offset in sysreg */ + + const struct exynos_usi_variant *data; +}; + +struct exynos_usi_mode { + const char *name; /* mode name */ + unsigned int val; /* mode register value */ +}; + +static const struct exynos_usi_mode exynos_usi_modes[] = { + [USI_V2_NONE] = { .name = "none", .val = USI_V2_SW_CONF_NONE }, + [USI_V2_UART] = { .name = "uart", .val = USI_V2_SW_CONF_UART }, + [USI_V2_SPI] = { .name = "spi", .val = USI_V2_SW_CONF_SPI }, + [USI_V2_I2C] = { .name = "i2c", .val = USI_V2_SW_CONF_I2C }, +}; + +static const char * const exynos850_usi_clk_names[] = { "pclk", "ipclk" }; +static const struct exynos_usi_variant exynos850_usi_data = { + .ver = USI_VER2, + .sw_conf_mask = USI_V2_SW_CONF_MASK, + .min_mode = USI_V2_NONE, + .max_mode = USI_V2_I2C, + .num_clks = ARRAY_SIZE(exynos850_usi_clk_names), + .clk_names = exynos850_usi_clk_names, +}; + +static const struct of_device_id exynos_usi_dt_match[] = { + { + .compatible = "samsung,exynos850-usi", + .data = &exynos850_usi_data, + }, + { } /* sentinel */ +}; +MODULE_DEVICE_TABLE(of, exynos_usi_dt_match); + +/** + * exynos_usi_set_sw_conf - Set USI block configuration mode + * @usi: USI driver object + * @mode: Mode index + * + * Select underlying serial protocol (UART/SPI/I2C) in USI IP-core. + * + * Return: 0 on success, or negative error code on failure. + */ +static int exynos_usi_set_sw_conf(struct exynos_usi *usi, size_t mode) +{ + unsigned int val; + int ret; + + if (mode < usi->data->min_mode || mode > usi->data->max_mode) + return -EINVAL; + + val = exynos_usi_modes[mode].val; + ret = regmap_update_bits(usi->sysreg, usi->sw_conf, + usi->data->sw_conf_mask, val); + if (ret) + return ret; + + usi->mode = mode; + dev_dbg(usi->dev, "protocol: %s\n", exynos_usi_modes[usi->mode].name); + + return 0; +} + +/** + * exynos_usi_enable - Initialize USI block + * @usi: USI driver object + * + * USI IP-core start state is "reset" (on startup and after CPU resume). This + * routine enables the USI block by clearing the reset flag. It also configures + * HWACG behavior (needed e.g. for UART Rx). It should be performed before + * underlying protocol becomes functional. + * + * Return: 0 on success, or negative error code on failure. + */ +static int exynos_usi_enable(const struct exynos_usi *usi) +{ + u32 val; + int ret; + + ret = clk_bulk_prepare_enable(usi->data->num_clks, usi->clks); + if (ret) + return ret; + + /* Enable USI block */ + val = readl(usi->regs + USI_CON); + val &= ~USI_CON_RESET; + writel(val, usi->regs + USI_CON); + udelay(1); + + /* Continuously provide the clock to USI IP w/o gating */ + if (usi->clkreq_on) { + val = readl(usi->regs + USI_OPTION); + val &= ~USI_OPTION_CLKSTOP_ON; + val |= USI_OPTION_CLKREQ_ON; + writel(val, usi->regs + USI_OPTION); + } + + clk_bulk_disable_unprepare(usi->data->num_clks, usi->clks); + + return ret; +} + +static int exynos_usi_configure(struct exynos_usi *usi) +{ + int ret; + + ret = exynos_usi_set_sw_conf(usi, usi->mode); + if (ret) + return ret; + + if (usi->data->ver == USI_VER2) + return exynos_usi_enable(usi); + + return 0; +} + +static int exynos_usi_parse_dt(struct device_node *np, struct exynos_usi *usi) +{ + int ret; + u32 mode; + + ret = of_property_read_u32(np, "samsung,mode", &mode); + if (ret) + return ret; + if (mode < usi->data->min_mode || mode > usi->data->max_mode) + return -EINVAL; + usi->mode = mode; + + usi->sysreg = syscon_regmap_lookup_by_phandle(np, "samsung,sysreg"); + if (IS_ERR(usi->sysreg)) + return PTR_ERR(usi->sysreg); + + ret = of_property_read_u32_index(np, "samsung,sysreg", 1, + &usi->sw_conf); + if (ret) + return ret; + + usi->clkreq_on = of_property_read_bool(np, "samsung,clkreq-on"); + + return 0; +} + +static int exynos_usi_get_clocks(struct exynos_usi *usi) +{ + const size_t num = usi->data->num_clks; + struct device *dev = usi->dev; + size_t i; + + if (num == 0) + return 0; + + usi->clks = devm_kcalloc(dev, num, sizeof(*usi->clks), GFP_KERNEL); + if (!usi->clks) + return -ENOMEM; + + for (i = 0; i < num; ++i) + usi->clks[i].id = usi->data->clk_names[i]; + + return devm_clk_bulk_get(dev, num, usi->clks); +} + +static int exynos_usi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct exynos_usi *usi; + int ret; + + usi = devm_kzalloc(dev, sizeof(*usi), GFP_KERNEL); + if (!usi) + return -ENOMEM; + + usi->dev = dev; + platform_set_drvdata(pdev, usi); + + usi->data = of_device_get_match_data(dev); + if (!usi->data) + return -EINVAL; + + ret = exynos_usi_parse_dt(np, usi); + if (ret) + return ret; + + ret = exynos_usi_get_clocks(usi); + if (ret) + return ret; + + if (usi->data->ver == USI_VER2) { + usi->regs = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(usi->regs)) + return PTR_ERR(usi->regs); + } + + ret = exynos_usi_configure(usi); + if (ret) + return ret; + + /* Make it possible to embed protocol nodes into USI np */ + return of_platform_populate(np, NULL, NULL, dev); +} + +static int __maybe_unused exynos_usi_resume_noirq(struct device *dev) +{ + struct exynos_usi *usi = dev_get_drvdata(dev); + + return exynos_usi_configure(usi); +} + +static const struct dev_pm_ops exynos_usi_pm = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, exynos_usi_resume_noirq) +}; + +static struct platform_driver exynos_usi_driver = { + .driver = { + .name = "exynos-usi", + .pm = &exynos_usi_pm, + .of_match_table = exynos_usi_dt_match, + }, + .probe = exynos_usi_probe, +}; +module_platform_driver(exynos_usi_driver); + +MODULE_DESCRIPTION("Samsung USI driver"); +MODULE_AUTHOR("Sam Protsenko "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 708dbf4490c8ddf55d79b9f3855219b92d108760 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Fri, 19 Nov 2021 22:39:52 +0100 Subject: soc: qcom: stats: Add fixed sleep stats offset for older RPM firmwares Not all RPM firmware versions have the dynamic sleep stats offset available. Most older versions use a fixed offset of 0xdba0. Add support for this using new SoC-specific compatibles for APQ8084, MSM8226, MSM8916 and MSM8974. Even older SoCs seem to use a different offset and stats format. If needed those could be supported in the future by adding separate compatibles for those with a different stats_config. Cc: Maulik Shah Signed-off-by: Stephan Gerhold Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211119213953.31970-3-stephan@gerhold.net --- drivers/soc/qcom/qcom_stats.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index 131d24caabf8..d6bfd1bbdc2a 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -237,6 +237,15 @@ static const struct stats_config rpm_data = { .subsystem_stats_in_smem = false, }; +/* Older RPM firmwares have the stats at a fixed offset instead */ +static const struct stats_config rpm_data_dba0 = { + .stats_offset = 0xdba0, + .num_records = 2, + .appended_stats_avail = true, + .dynamic_offset = false, + .subsystem_stats_in_smem = false, +}; + static const struct stats_config rpmh_data = { .stats_offset = 0x48, .num_records = 3, @@ -246,6 +255,10 @@ static const struct stats_config rpmh_data = { }; static const struct of_device_id qcom_stats_table[] = { + { .compatible = "qcom,apq8084-rpm-stats", .data = &rpm_data_dba0 }, + { .compatible = "qcom,msm8226-rpm-stats", .data = &rpm_data_dba0 }, + { .compatible = "qcom,msm8916-rpm-stats", .data = &rpm_data_dba0 }, + { .compatible = "qcom,msm8974-rpm-stats", .data = &rpm_data_dba0 }, { .compatible = "qcom,rpm-stats", .data = &rpm_data }, { .compatible = "qcom,rpmh-stats", .data = &rpmh_data }, { } -- cgit v1.2.3 From 6fc61c39ee1adb5f4115d288c876772fcd8b6979 Mon Sep 17 00:00:00 2001 From: Konrad Dybcio Date: Sun, 21 Nov 2021 01:20:46 +0100 Subject: soc: qcom: llcc: Add configuration data for SM8350 Add LLCC configuration data for SM8350 SoC. Signed-off-by: Konrad Dybcio Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211121002050.36977-2-konrad.dybcio@somainline.org --- drivers/soc/qcom/llcc-qcom.c | 28 ++++++++++++++++++++++++++++ include/linux/soc/qcom/llcc-qcom.h | 3 +++ 2 files changed, 31 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 6bf2f1d1f2c5..ec52f29c8867 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -195,6 +195,28 @@ static const struct llcc_slice_config sm8250_data[] = { { LLCC_WRCACHE, 31, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, }; +static const struct llcc_slice_config sm8350_data[] = { + { LLCC_CPUSS, 1, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 1 }, + { LLCC_VIDSC0, 2, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_AUDIO, 6, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 0 }, + { LLCC_MDMHPGRW, 7, 1024, 3, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_CMPT, 10, 3072, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_GPUHTW, 11, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_GPU, 12, 1024, 1, 0, 0xfff, 0x0, 0, 0, 0, 1, 1, 0 }, + { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 }, + { LLCC_DISP, 16, 3072, 2, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_MDMPNG, 21, 1024, 0, 1, 0xf, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_AUDHW, 22, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_CVP, 28, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_MODPE, 29, 256, 1, 1, 0xf, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0x1, 1, 0, 0, 0, 1, 0 }, + { LLCC_WRCACHE, 31, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 }, + { LLCC_CVPFW, 17, 512, 1, 0, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_CPUSS1, 3, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, + { LLCC_CPUHWT, 5, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 0, 1 }, +}; + static const struct qcom_llcc_config sc7180_cfg = { .sct_data = sc7180_data, .size = ARRAY_SIZE(sc7180_data), @@ -228,6 +250,11 @@ static const struct qcom_llcc_config sm8250_cfg = { .size = ARRAY_SIZE(sm8250_data), }; +static const struct qcom_llcc_config sm8350_cfg = { + .sct_data = sm8350_data, + .size = ARRAY_SIZE(sm8350_data), +}; + static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER; /** @@ -644,6 +671,7 @@ static const struct of_device_id qcom_llcc_of_match[] = { { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg }, { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg }, { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg }, + { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg }, { } }; diff --git a/include/linux/soc/qcom/llcc-qcom.h b/include/linux/soc/qcom/llcc-qcom.h index 437c9df13229..9e8fd92c96b7 100644 --- a/include/linux/soc/qcom/llcc-qcom.h +++ b/include/linux/soc/qcom/llcc-qcom.h @@ -33,6 +33,9 @@ #define LLCC_MODPE 29 #define LLCC_APTCM 30 #define LLCC_WRCACHE 31 +#define LLCC_CVPFW 32 +#define LLCC_CPUSS1 33 +#define LLCC_CPUHWT 36 /** * struct llcc_slice_desc - Cache slice descriptor -- cgit v1.2.3 From 92c550f9ffd2884bb5def52b5c0485a35e452784 Mon Sep 17 00:00:00 2001 From: Changcheng Deng Date: Thu, 25 Nov 2021 01:43:11 +0000 Subject: PM: AVS: qcom-cpr: Use div64_ul instead of do_div do_div() does a 64-by-32 division. Here the divisor is an unsigned long which on some platforms is 64 bit wide. So use div64_ul instead of do_div to avoid a possible truncation. Reported-by: Zeal Robot Signed-off-by: Changcheng Deng Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211125014311.45942-1-deng.changcheng@zte.com.cn --- drivers/soc/qcom/cpr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/cpr.c b/drivers/soc/qcom/cpr.c index 1d818a8ba208..e9b854ed1bdf 100644 --- a/drivers/soc/qcom/cpr.c +++ b/drivers/soc/qcom/cpr.c @@ -1010,7 +1010,7 @@ static int cpr_interpolate(const struct corner *corner, int step_volt, return corner->uV; temp = f_diff * (uV_high - uV_low); - do_div(temp, f_high - f_low); + temp = div64_ul(temp, f_high - f_low); /* * max_volt_scale has units of uV/MHz while freq values -- cgit v1.2.3 From 3925b909f75800e69bd1a65130a0440191a9e60a Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Sun, 28 Nov 2021 22:03:17 +0100 Subject: soc: qcom: aoss: constify static struct thermal_cooling_device_ops The only usage of qmp_cooling_device_ops is to pass its address to devm_thermal_of_cooling_device_register() which takes a pointer to const struct thermal_cooling_device_ops as argument. Make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211128210317.25504-1-rikard.falkeborn@gmail.com --- drivers/soc/qcom/qcom_aoss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 34acf58bbb0d..cbe5e39fdaeb 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -352,7 +352,7 @@ static int qmp_cdev_set_cur_state(struct thermal_cooling_device *cdev, return ret; } -static struct thermal_cooling_device_ops qmp_cooling_device_ops = { +static const struct thermal_cooling_device_ops qmp_cooling_device_ops = { .get_max_state = qmp_cdev_get_max_state, .get_cur_state = qmp_cdev_get_cur_state, .set_cur_state = qmp_cdev_set_cur_state, -- cgit v1.2.3 From 82c6bf7585cdb5e1bc8f8b1a2925ad692585e1f4 Mon Sep 17 00:00:00 2001 From: Martin Botka Date: Tue, 30 Nov 2021 22:23:30 +0100 Subject: soc: qcom: rpmpd: Add support for sm6125 Add RPM power domains located in Qualcomm SM6125 SoC. Signed-off-by: Martin Botka Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211130212332.25401-2-martin.botka@somainline.org --- drivers/soc/qcom/rpmpd.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmpd.c b/drivers/soc/qcom/rpmpd.c index 36b2381039e6..0a8d8d24bfb7 100644 --- a/drivers/soc/qcom/rpmpd.c +++ b/drivers/soc/qcom/rpmpd.c @@ -395,6 +395,28 @@ static const struct rpmpd_desc sm6115_desc = { .max_state = RPM_SMD_LEVEL_TURBO_NO_CPR, }; +/* sm6125 RPM Power domains */ +DEFINE_RPMPD_PAIR(sm6125, vddcx, vddcx_ao, RWCX, LEVEL, 0); +DEFINE_RPMPD_VFL(sm6125, vddcx_vfl, RWCX, 0); + +DEFINE_RPMPD_PAIR(sm6125, vddmx, vddmx_ao, RWMX, LEVEL, 0); +DEFINE_RPMPD_VFL(sm6125, vddmx_vfl, RWMX, 0); + +static struct rpmpd *sm6125_rpmpds[] = { + [SM6125_VDDCX] = &sm6125_vddcx, + [SM6125_VDDCX_AO] = &sm6125_vddcx_ao, + [SM6125_VDDCX_VFL] = &sm6125_vddcx_vfl, + [SM6125_VDDMX] = &sm6125_vddmx, + [SM6125_VDDMX_AO] = &sm6125_vddmx_ao, + [SM6125_VDDMX_VFL] = &sm6125_vddmx_vfl, +}; + +static const struct rpmpd_desc sm6125_desc = { + .rpmpds = sm6125_rpmpds, + .num_pds = ARRAY_SIZE(sm6125_rpmpds), + .max_state = RPM_SMD_LEVEL_BINNING, +}; + static struct rpmpd *qcm2290_rpmpds[] = { [QCM2290_VDDCX] = &sm6115_vddcx, [QCM2290_VDDCX_AO] = &sm6115_vddcx_ao, @@ -425,6 +447,7 @@ static const struct of_device_id rpmpd_match_table[] = { { .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc }, { .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc }, { .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc }, + { .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc }, { } }; MODULE_DEVICE_TABLE(of, rpmpd_match_table); -- cgit v1.2.3 From aa9fc2c7e5777ae44a2f03e041d3f4b3e4a02860 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 1 Dec 2021 12:57:42 +0530 Subject: soc: qcom: smem: Update max processor count Update max processor count to reflect the number of co-processors on SM8450 SoCs. Signed-off-by: Dmitry Baryshkov Signed-off-by: Vinod Koul Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211201072745.3969077-5-vkoul@kernel.org --- drivers/soc/qcom/smem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index c7e519bfdc8a..e2057d8f1eff 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -85,7 +85,7 @@ #define SMEM_GLOBAL_HOST 0xfffe /* Max number of processors/hosts in a system */ -#define SMEM_HOST_COUNT 14 +#define SMEM_HOST_COUNT 15 /** * struct smem_proc_comm - proc_comm communication struct (legacy) -- cgit v1.2.3 From 5d12289516d943dd6f348826a9f56f84199af0b1 Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 1 Dec 2021 12:57:44 +0530 Subject: soc: qcom: rpmhpd: Add SM8450 power domains Add the power domains exposed by RPMH in the Qualcomm SM8450 platform. Unlike previous generations CX domain is not a child of MX domain. Signed-off-by: Dmitry Baryshkov Signed-off-by: Vinod Koul Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211201072745.3969077-7-vkoul@kernel.org --- drivers/soc/qcom/rpmhpd.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index 1118345d8824..e7e150ce1b1a 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -253,6 +253,57 @@ static const struct rpmhpd_desc sm8350_desc = { .num_pds = ARRAY_SIZE(sm8350_rpmhpds), }; +/* SM8450 RPMH powerdomains */ +static struct rpmhpd sm8450_cx_ao; +static struct rpmhpd sm8450_cx = { + .pd = { .name = "cx", }, + .peer = &sm8450_cx_ao, + .res_name = "cx.lvl", +}; + +static struct rpmhpd sm8450_cx_ao = { + .pd = { .name = "cx_ao", }, + .active_only = true, + .res_name = "cx.lvl", +}; + +static struct rpmhpd sm8450_mmcx_ao; +static struct rpmhpd sm8450_mmcx = { + .pd = { .name = "mmcx", }, + .peer = &sm8450_mmcx_ao, + .parent = &sm8450_cx.pd, + .res_name = "mmcx.lvl", +}; + +static struct rpmhpd sm8450_mmcx_ao = { + .pd = { .name = "mmcx_ao", }, + .active_only = true, + .peer = &sm8450_mmcx, + .parent = &sm8450_cx_ao.pd, + .res_name = "mmcx.lvl", +}; + +static struct rpmhpd *sm8450_rpmhpds[] = { + [SM8450_CX] = &sm8450_cx, + [SM8450_CX_AO] = &sm8450_cx_ao, + [SM8450_EBI] = &sdm845_ebi, + [SM8450_GFX] = &sdm845_gfx, + [SM8450_LCX] = &sdm845_lcx, + [SM8450_LMX] = &sdm845_lmx, + [SM8450_MMCX] = &sm8450_mmcx, + [SM8450_MMCX_AO] = &sm8450_mmcx_ao, + [SM8450_MX] = &sdm845_mx, + [SM8450_MX_AO] = &sdm845_mx_ao, + [SM8450_MXC] = &sm8350_mxc, + [SM8450_MXC_AO] = &sm8350_mxc_ao, + [SM8450_MSS] = &sdm845_mss, +}; + +static const struct rpmhpd_desc sm8450_desc = { + .rpmhpds = sm8450_rpmhpds, + .num_pds = ARRAY_SIZE(sm8450_rpmhpds), +}; + /* SC7180 RPMH powerdomains */ static struct rpmhpd *sc7180_rpmhpds[] = { [SC7180_CX] = &sdm845_cx, @@ -318,6 +369,7 @@ static const struct of_device_id rpmhpd_match_table[] = { { .compatible = "qcom,sm8150-rpmhpd", .data = &sm8150_desc }, { .compatible = "qcom,sm8250-rpmhpd", .data = &sm8250_desc }, { .compatible = "qcom,sm8350-rpmhpd", .data = &sm8350_desc }, + { .compatible = "qcom,sm8450-rpmhpd", .data = &sm8450_desc }, { } }; MODULE_DEVICE_TABLE(of, rpmhpd_match_table); -- cgit v1.2.3 From 9e4cdb4ca7e1fc4cca021cd8fefc4488c6c63bfa Mon Sep 17 00:00:00 2001 From: Dmitry Baryshkov Date: Wed, 1 Dec 2021 12:57:45 +0530 Subject: soc: qcom: socinfo: add SM8450 ID Add the ID for the Qualcomm SM8450 SoC. Signed-off-by: Dmitry Baryshkov Signed-off-by: Vinod Koul Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211201072745.3969077-8-vkoul@kernel.org --- drivers/soc/qcom/socinfo.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 9a0eb59405e8..113dc57b74c3 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -315,6 +315,7 @@ static const struct soc_id soc_id[] = { { 425, "SC7180" }, { 453, "IPQ6005" }, { 455, "QRB5165" }, + { 457, "SM8450" }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) -- cgit v1.2.3 From 84e3b09292a481df5afe8a6b6fff8ded746506e3 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 9 Dec 2021 21:01:54 +0530 Subject: soc: qcom: rpmhpd: sm8450: Add the missing .peer for sm8450_cx_ao sm8450_cx and sm8450_cx_ao should be peers of each other, add the missing .peer entry for sm8450_cx_ao Cc: Dmitry Baryshkov Cc: Vinod Koul Signed-off-by: Rajendra Nayak Reviewed-by: Dmitry Baryshkov Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1639063917-9011-2-git-send-email-quic_rjendra@quicinc.com --- drivers/soc/qcom/rpmhpd.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index e7e150ce1b1a..2032cf355e52 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -264,6 +264,7 @@ static struct rpmhpd sm8450_cx = { static struct rpmhpd sm8450_cx_ao = { .pd = { .name = "cx_ao", }, .active_only = true, + .peer = &sm8450_cx, .res_name = "cx.lvl", }; -- cgit v1.2.3 From 09bb67c104b5d27718a7191eff057ee7a45fc035 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 9 Dec 2021 21:01:55 +0530 Subject: soc: qcom: rpmhpd: Rename rpmhpd struct names The rpmhpd structs were named with a SoC-name prefix, but then they got reused across multiple SoC families making things confusing. Rename all the struct names to remove SoC-name prefixes. While we do this we end up with some power-domains without parents, and some with and at times different parents across SoCs. use a _w__parent suffix for such cases. No functional change as part of this patch. Signed-off-by: Rajendra Nayak Reviewed-by: Matthias Kaehlcke Reviewed-by: Bjorn Andersson Reviewed-by: Stephen Boyd Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1639063917-9011-3-git-send-email-quic_rjendra@quicinc.com --- drivers/soc/qcom/rpmhpd.c | 341 +++++++++++++++++++++++----------------------- 1 file changed, 171 insertions(+), 170 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index 2032cf355e52..a12db32433c5 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -63,73 +63,132 @@ struct rpmhpd_desc { static DEFINE_MUTEX(rpmhpd_lock); -/* SDM845 RPMH powerdomains */ +/* RPMH powerdomains */ -static struct rpmhpd sdm845_ebi = { +static struct rpmhpd ebi = { .pd = { .name = "ebi", }, .res_name = "ebi.lvl", }; -static struct rpmhpd sdm845_lmx = { +static struct rpmhpd lmx = { .pd = { .name = "lmx", }, .res_name = "lmx.lvl", }; -static struct rpmhpd sdm845_lcx = { +static struct rpmhpd lcx = { .pd = { .name = "lcx", }, .res_name = "lcx.lvl", }; -static struct rpmhpd sdm845_gfx = { +static struct rpmhpd gfx = { .pd = { .name = "gfx", }, .res_name = "gfx.lvl", }; -static struct rpmhpd sdm845_mss = { +static struct rpmhpd mss = { .pd = { .name = "mss", }, .res_name = "mss.lvl", }; -static struct rpmhpd sdm845_mx_ao; -static struct rpmhpd sdm845_mx = { +static struct rpmhpd mx_ao; +static struct rpmhpd mx = { .pd = { .name = "mx", }, - .peer = &sdm845_mx_ao, + .peer = &mx_ao, .res_name = "mx.lvl", }; -static struct rpmhpd sdm845_mx_ao = { +static struct rpmhpd mx_ao = { .pd = { .name = "mx_ao", }, .active_only = true, - .peer = &sdm845_mx, + .peer = &mx, .res_name = "mx.lvl", }; -static struct rpmhpd sdm845_cx_ao; -static struct rpmhpd sdm845_cx = { +static struct rpmhpd cx_ao; +static struct rpmhpd cx = { + .pd = { .name = "cx", }, + .peer = &cx_ao, + .res_name = "cx.lvl", +}; + +static struct rpmhpd cx_ao = { + .pd = { .name = "cx_ao", }, + .active_only = true, + .peer = &cx, + .res_name = "cx.lvl", +}; + +static struct rpmhpd cx_ao_w_mx_parent; +static struct rpmhpd cx_w_mx_parent = { .pd = { .name = "cx", }, - .peer = &sdm845_cx_ao, - .parent = &sdm845_mx.pd, + .peer = &cx_ao_w_mx_parent, + .parent = &mx.pd, .res_name = "cx.lvl", }; -static struct rpmhpd sdm845_cx_ao = { +static struct rpmhpd cx_ao_w_mx_parent = { .pd = { .name = "cx_ao", }, .active_only = true, - .peer = &sdm845_cx, - .parent = &sdm845_mx_ao.pd, + .peer = &cx_w_mx_parent, + .parent = &mx_ao.pd, .res_name = "cx.lvl", }; +static struct rpmhpd mmcx_ao; +static struct rpmhpd mmcx = { + .pd = { .name = "mmcx", }, + .peer = &mmcx_ao, + .res_name = "mmcx.lvl", +}; + +static struct rpmhpd mmcx_ao = { + .pd = { .name = "mmcx_ao", }, + .active_only = true, + .peer = &mmcx, + .res_name = "mmcx.lvl", +}; + +static struct rpmhpd mmcx_ao_w_cx_parent; +static struct rpmhpd mmcx_w_cx_parent = { + .pd = { .name = "mmcx", }, + .peer = &mmcx_ao_w_cx_parent, + .parent = &cx.pd, + .res_name = "mmcx.lvl", +}; + +static struct rpmhpd mmcx_ao_w_cx_parent = { + .pd = { .name = "mmcx_ao", }, + .active_only = true, + .peer = &mmcx_w_cx_parent, + .parent = &cx_ao.pd, + .res_name = "mmcx.lvl", +}; + +static struct rpmhpd mxc_ao; +static struct rpmhpd mxc = { + .pd = { .name = "mxc", }, + .peer = &mxc_ao, + .res_name = "mxc.lvl", +}; + +static struct rpmhpd mxc_ao = { + .pd = { .name = "mxc_ao", }, + .active_only = true, + .peer = &mxc, + .res_name = "mxc.lvl", +}; + +/* SDM845 RPMH powerdomains */ static struct rpmhpd *sdm845_rpmhpds[] = { - [SDM845_EBI] = &sdm845_ebi, - [SDM845_MX] = &sdm845_mx, - [SDM845_MX_AO] = &sdm845_mx_ao, - [SDM845_CX] = &sdm845_cx, - [SDM845_CX_AO] = &sdm845_cx_ao, - [SDM845_LMX] = &sdm845_lmx, - [SDM845_LCX] = &sdm845_lcx, - [SDM845_GFX] = &sdm845_gfx, - [SDM845_MSS] = &sdm845_mss, + [SDM845_EBI] = &ebi, + [SDM845_MX] = &mx, + [SDM845_MX_AO] = &mx_ao, + [SDM845_CX] = &cx_w_mx_parent, + [SDM845_CX_AO] = &cx_ao_w_mx_parent, + [SDM845_LMX] = &lmx, + [SDM845_LCX] = &lcx, + [SDM845_GFX] = &gfx, + [SDM845_MSS] = &mss, }; static const struct rpmhpd_desc sdm845_desc = { @@ -139,9 +198,9 @@ static const struct rpmhpd_desc sdm845_desc = { /* SDX55 RPMH powerdomains */ static struct rpmhpd *sdx55_rpmhpds[] = { - [SDX55_MSS] = &sdm845_mss, - [SDX55_MX] = &sdm845_mx, - [SDX55_CX] = &sdm845_cx, + [SDX55_MSS] = &mss, + [SDX55_MX] = &mx, + [SDX55_CX] = &cx_w_mx_parent, }; static const struct rpmhpd_desc sdx55_desc = { @@ -151,12 +210,12 @@ static const struct rpmhpd_desc sdx55_desc = { /* SM6350 RPMH powerdomains */ static struct rpmhpd *sm6350_rpmhpds[] = { - [SM6350_CX] = &sdm845_cx, - [SM6350_GFX] = &sdm845_gfx, - [SM6350_LCX] = &sdm845_lcx, - [SM6350_LMX] = &sdm845_lmx, - [SM6350_MSS] = &sdm845_mss, - [SM6350_MX] = &sdm845_mx, + [SM6350_CX] = &cx_w_mx_parent, + [SM6350_GFX] = &gfx, + [SM6350_LCX] = &lcx, + [SM6350_LMX] = &lmx, + [SM6350_MSS] = &mss, + [SM6350_MX] = &mx, }; static const struct rpmhpd_desc sm6350_desc = { @@ -165,33 +224,18 @@ static const struct rpmhpd_desc sm6350_desc = { }; /* SM8150 RPMH powerdomains */ - -static struct rpmhpd sm8150_mmcx_ao; -static struct rpmhpd sm8150_mmcx = { - .pd = { .name = "mmcx", }, - .peer = &sm8150_mmcx_ao, - .res_name = "mmcx.lvl", -}; - -static struct rpmhpd sm8150_mmcx_ao = { - .pd = { .name = "mmcx_ao", }, - .active_only = true, - .peer = &sm8150_mmcx, - .res_name = "mmcx.lvl", -}; - static struct rpmhpd *sm8150_rpmhpds[] = { - [SM8150_MSS] = &sdm845_mss, - [SM8150_EBI] = &sdm845_ebi, - [SM8150_LMX] = &sdm845_lmx, - [SM8150_LCX] = &sdm845_lcx, - [SM8150_GFX] = &sdm845_gfx, - [SM8150_MX] = &sdm845_mx, - [SM8150_MX_AO] = &sdm845_mx_ao, - [SM8150_CX] = &sdm845_cx, - [SM8150_CX_AO] = &sdm845_cx_ao, - [SM8150_MMCX] = &sm8150_mmcx, - [SM8150_MMCX_AO] = &sm8150_mmcx_ao, + [SM8150_MSS] = &mss, + [SM8150_EBI] = &ebi, + [SM8150_LMX] = &lmx, + [SM8150_LCX] = &lcx, + [SM8150_GFX] = &gfx, + [SM8150_MX] = &mx, + [SM8150_MX_AO] = &mx_ao, + [SM8150_CX] = &cx_w_mx_parent, + [SM8150_CX_AO] = &cx_ao_w_mx_parent, + [SM8150_MMCX] = &mmcx, + [SM8150_MMCX_AO] = &mmcx_ao, }; static const struct rpmhpd_desc sm8150_desc = { @@ -199,17 +243,18 @@ static const struct rpmhpd_desc sm8150_desc = { .num_pds = ARRAY_SIZE(sm8150_rpmhpds), }; +/* SM8250 RPMH powerdomains */ static struct rpmhpd *sm8250_rpmhpds[] = { - [SM8250_CX] = &sdm845_cx, - [SM8250_CX_AO] = &sdm845_cx_ao, - [SM8250_EBI] = &sdm845_ebi, - [SM8250_GFX] = &sdm845_gfx, - [SM8250_LCX] = &sdm845_lcx, - [SM8250_LMX] = &sdm845_lmx, - [SM8250_MMCX] = &sm8150_mmcx, - [SM8250_MMCX_AO] = &sm8150_mmcx_ao, - [SM8250_MX] = &sdm845_mx, - [SM8250_MX_AO] = &sdm845_mx_ao, + [SM8250_CX] = &cx_w_mx_parent, + [SM8250_CX_AO] = &cx_ao_w_mx_parent, + [SM8250_EBI] = &ebi, + [SM8250_GFX] = &gfx, + [SM8250_LCX] = &lcx, + [SM8250_LMX] = &lmx, + [SM8250_MMCX] = &mmcx, + [SM8250_MMCX_AO] = &mmcx_ao, + [SM8250_MX] = &mx, + [SM8250_MX_AO] = &mx_ao, }; static const struct rpmhpd_desc sm8250_desc = { @@ -218,34 +263,20 @@ static const struct rpmhpd_desc sm8250_desc = { }; /* SM8350 Power domains */ -static struct rpmhpd sm8350_mxc_ao; -static struct rpmhpd sm8350_mxc = { - .pd = { .name = "mxc", }, - .peer = &sm8350_mxc_ao, - .res_name = "mxc.lvl", -}; - -static struct rpmhpd sm8350_mxc_ao = { - .pd = { .name = "mxc_ao", }, - .active_only = true, - .peer = &sm8350_mxc, - .res_name = "mxc.lvl", -}; - static struct rpmhpd *sm8350_rpmhpds[] = { - [SM8350_CX] = &sdm845_cx, - [SM8350_CX_AO] = &sdm845_cx_ao, - [SM8350_EBI] = &sdm845_ebi, - [SM8350_GFX] = &sdm845_gfx, - [SM8350_LCX] = &sdm845_lcx, - [SM8350_LMX] = &sdm845_lmx, - [SM8350_MMCX] = &sm8150_mmcx, - [SM8350_MMCX_AO] = &sm8150_mmcx_ao, - [SM8350_MX] = &sdm845_mx, - [SM8350_MX_AO] = &sdm845_mx_ao, - [SM8350_MXC] = &sm8350_mxc, - [SM8350_MXC_AO] = &sm8350_mxc_ao, - [SM8350_MSS] = &sdm845_mss, + [SM8350_CX] = &cx_w_mx_parent, + [SM8350_CX_AO] = &cx_ao_w_mx_parent, + [SM8350_EBI] = &ebi, + [SM8350_GFX] = &gfx, + [SM8350_LCX] = &lcx, + [SM8350_LMX] = &lmx, + [SM8350_MMCX] = &mmcx, + [SM8350_MMCX_AO] = &mmcx_ao, + [SM8350_MX] = &mx, + [SM8350_MX_AO] = &mx_ao, + [SM8350_MXC] = &mxc, + [SM8350_MXC_AO] = &mxc_ao, + [SM8350_MSS] = &mss, }; static const struct rpmhpd_desc sm8350_desc = { @@ -254,50 +285,20 @@ static const struct rpmhpd_desc sm8350_desc = { }; /* SM8450 RPMH powerdomains */ -static struct rpmhpd sm8450_cx_ao; -static struct rpmhpd sm8450_cx = { - .pd = { .name = "cx", }, - .peer = &sm8450_cx_ao, - .res_name = "cx.lvl", -}; - -static struct rpmhpd sm8450_cx_ao = { - .pd = { .name = "cx_ao", }, - .active_only = true, - .peer = &sm8450_cx, - .res_name = "cx.lvl", -}; - -static struct rpmhpd sm8450_mmcx_ao; -static struct rpmhpd sm8450_mmcx = { - .pd = { .name = "mmcx", }, - .peer = &sm8450_mmcx_ao, - .parent = &sm8450_cx.pd, - .res_name = "mmcx.lvl", -}; - -static struct rpmhpd sm8450_mmcx_ao = { - .pd = { .name = "mmcx_ao", }, - .active_only = true, - .peer = &sm8450_mmcx, - .parent = &sm8450_cx_ao.pd, - .res_name = "mmcx.lvl", -}; - static struct rpmhpd *sm8450_rpmhpds[] = { - [SM8450_CX] = &sm8450_cx, - [SM8450_CX_AO] = &sm8450_cx_ao, - [SM8450_EBI] = &sdm845_ebi, - [SM8450_GFX] = &sdm845_gfx, - [SM8450_LCX] = &sdm845_lcx, - [SM8450_LMX] = &sdm845_lmx, - [SM8450_MMCX] = &sm8450_mmcx, - [SM8450_MMCX_AO] = &sm8450_mmcx_ao, - [SM8450_MX] = &sdm845_mx, - [SM8450_MX_AO] = &sdm845_mx_ao, - [SM8450_MXC] = &sm8350_mxc, - [SM8450_MXC_AO] = &sm8350_mxc_ao, - [SM8450_MSS] = &sdm845_mss, + [SM8450_CX] = &cx, + [SM8450_CX_AO] = &cx_ao, + [SM8450_EBI] = &ebi, + [SM8450_GFX] = &gfx, + [SM8450_LCX] = &lcx, + [SM8450_LMX] = &lmx, + [SM8450_MMCX] = &mmcx_w_cx_parent, + [SM8450_MMCX_AO] = &mmcx_ao_w_cx_parent, + [SM8450_MX] = &mx, + [SM8450_MX_AO] = &mx_ao, + [SM8450_MXC] = &mxc, + [SM8450_MXC_AO] = &mxc_ao, + [SM8450_MSS] = &mss, }; static const struct rpmhpd_desc sm8450_desc = { @@ -307,14 +308,14 @@ static const struct rpmhpd_desc sm8450_desc = { /* SC7180 RPMH powerdomains */ static struct rpmhpd *sc7180_rpmhpds[] = { - [SC7180_CX] = &sdm845_cx, - [SC7180_CX_AO] = &sdm845_cx_ao, - [SC7180_GFX] = &sdm845_gfx, - [SC7180_MX] = &sdm845_mx, - [SC7180_MX_AO] = &sdm845_mx_ao, - [SC7180_LMX] = &sdm845_lmx, - [SC7180_LCX] = &sdm845_lcx, - [SC7180_MSS] = &sdm845_mss, + [SC7180_CX] = &cx_w_mx_parent, + [SC7180_CX_AO] = &cx_ao_w_mx_parent, + [SC7180_GFX] = &gfx, + [SC7180_MX] = &mx, + [SC7180_MX_AO] = &mx_ao, + [SC7180_LMX] = &lmx, + [SC7180_LCX] = &lcx, + [SC7180_MSS] = &mss, }; static const struct rpmhpd_desc sc7180_desc = { @@ -324,15 +325,15 @@ static const struct rpmhpd_desc sc7180_desc = { /* SC7280 RPMH powerdomains */ static struct rpmhpd *sc7280_rpmhpds[] = { - [SC7280_CX] = &sdm845_cx, - [SC7280_CX_AO] = &sdm845_cx_ao, - [SC7280_EBI] = &sdm845_ebi, - [SC7280_GFX] = &sdm845_gfx, - [SC7280_MX] = &sdm845_mx, - [SC7280_MX_AO] = &sdm845_mx_ao, - [SC7280_LMX] = &sdm845_lmx, - [SC7280_LCX] = &sdm845_lcx, - [SC7280_MSS] = &sdm845_mss, + [SC7280_CX] = &cx_w_mx_parent, + [SC7280_CX_AO] = &cx_ao_w_mx_parent, + [SC7280_EBI] = &ebi, + [SC7280_GFX] = &gfx, + [SC7280_MX] = &mx, + [SC7280_MX_AO] = &mx_ao, + [SC7280_LMX] = &lmx, + [SC7280_LCX] = &lcx, + [SC7280_MSS] = &mss, }; static const struct rpmhpd_desc sc7280_desc = { @@ -342,17 +343,17 @@ static const struct rpmhpd_desc sc7280_desc = { /* SC8180x RPMH powerdomains */ static struct rpmhpd *sc8180x_rpmhpds[] = { - [SC8180X_CX] = &sdm845_cx, - [SC8180X_CX_AO] = &sdm845_cx_ao, - [SC8180X_EBI] = &sdm845_ebi, - [SC8180X_GFX] = &sdm845_gfx, - [SC8180X_LCX] = &sdm845_lcx, - [SC8180X_LMX] = &sdm845_lmx, - [SC8180X_MMCX] = &sm8150_mmcx, - [SC8180X_MMCX_AO] = &sm8150_mmcx_ao, - [SC8180X_MSS] = &sdm845_mss, - [SC8180X_MX] = &sdm845_mx, - [SC8180X_MX_AO] = &sdm845_mx_ao, + [SC8180X_CX] = &cx_w_mx_parent, + [SC8180X_CX_AO] = &cx_ao_w_mx_parent, + [SC8180X_EBI] = &ebi, + [SC8180X_GFX] = &gfx, + [SC8180X_LCX] = &lcx, + [SC8180X_LMX] = &lmx, + [SC8180X_MMCX] = &mmcx, + [SC8180X_MMCX_AO] = &mmcx_ao, + [SC8180X_MSS] = &mss, + [SC8180X_MX] = &mx, + [SC8180X_MX_AO] = &mx_ao, }; static const struct rpmhpd_desc sc8180x_desc = { -- cgit v1.2.3 From 7d6a0a4dcf148681bb7760f9aad100ee3d3ce836 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 9 Dec 2021 21:01:56 +0530 Subject: soc: qcom: rpmhpd: Remove mx/cx relationship on sc7280 The requirement to specify the active + sleep and active-only MX power-domains as the parents of the corresponding CX power domains is not applicable on sc7280. Fix it by using the cx/cx_ao structs for sc7280 instead of the _w_mx_parent ones. Signed-off-by: Rajendra Nayak Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1639063917-9011-4-git-send-email-quic_rjendra@quicinc.com --- drivers/soc/qcom/rpmhpd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index a12db32433c5..63602049eaa0 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -325,8 +325,8 @@ static const struct rpmhpd_desc sc7180_desc = { /* SC7280 RPMH powerdomains */ static struct rpmhpd *sc7280_rpmhpds[] = { - [SC7280_CX] = &cx_w_mx_parent, - [SC7280_CX_AO] = &cx_ao_w_mx_parent, + [SC7280_CX] = &cx, + [SC7280_CX_AO] = &cx_ao, [SC7280_EBI] = &ebi, [SC7280_GFX] = &gfx, [SC7280_MX] = &mx, -- cgit v1.2.3 From 90c74c1c2574e9454fb3a7ae2cddc9433aa89d49 Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 9 Dec 2021 21:01:57 +0530 Subject: soc: qcom: rpmhpd: Sort power-domain definitions and lists Sort all power-domain defines and the SoC specific lists in alphabetical order for better readability. No functional changes. Signed-off-by: Rajendra Nayak Reviewed-by: Bjorn Andersson Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/1639063917-9011-5-git-send-email-quic_rjendra@quicinc.com --- drivers/soc/qcom/rpmhpd.c | 122 +++++++++++++++++++++++----------------------- 1 file changed, 62 insertions(+), 60 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmhpd.c b/drivers/soc/qcom/rpmhpd.c index 63602049eaa0..58f1dc9b9cb7 100644 --- a/drivers/soc/qcom/rpmhpd.c +++ b/drivers/soc/qcom/rpmhpd.c @@ -65,46 +65,9 @@ static DEFINE_MUTEX(rpmhpd_lock); /* RPMH powerdomains */ -static struct rpmhpd ebi = { - .pd = { .name = "ebi", }, - .res_name = "ebi.lvl", -}; - -static struct rpmhpd lmx = { - .pd = { .name = "lmx", }, - .res_name = "lmx.lvl", -}; - -static struct rpmhpd lcx = { - .pd = { .name = "lcx", }, - .res_name = "lcx.lvl", -}; - -static struct rpmhpd gfx = { - .pd = { .name = "gfx", }, - .res_name = "gfx.lvl", -}; - -static struct rpmhpd mss = { - .pd = { .name = "mss", }, - .res_name = "mss.lvl", -}; - -static struct rpmhpd mx_ao; -static struct rpmhpd mx = { - .pd = { .name = "mx", }, - .peer = &mx_ao, - .res_name = "mx.lvl", -}; - -static struct rpmhpd mx_ao = { - .pd = { .name = "mx_ao", }, - .active_only = true, - .peer = &mx, - .res_name = "mx.lvl", -}; - static struct rpmhpd cx_ao; +static struct rpmhpd mx; +static struct rpmhpd mx_ao; static struct rpmhpd cx = { .pd = { .name = "cx", }, .peer = &cx_ao, @@ -134,6 +97,26 @@ static struct rpmhpd cx_ao_w_mx_parent = { .res_name = "cx.lvl", }; +static struct rpmhpd ebi = { + .pd = { .name = "ebi", }, + .res_name = "ebi.lvl", +}; + +static struct rpmhpd gfx = { + .pd = { .name = "gfx", }, + .res_name = "gfx.lvl", +}; + +static struct rpmhpd lcx = { + .pd = { .name = "lcx", }, + .res_name = "lcx.lvl", +}; + +static struct rpmhpd lmx = { + .pd = { .name = "lmx", }, + .res_name = "lmx.lvl", +}; + static struct rpmhpd mmcx_ao; static struct rpmhpd mmcx = { .pd = { .name = "mmcx", }, @@ -164,6 +147,25 @@ static struct rpmhpd mmcx_ao_w_cx_parent = { .res_name = "mmcx.lvl", }; +static struct rpmhpd mss = { + .pd = { .name = "mss", }, + .res_name = "mss.lvl", +}; + +static struct rpmhpd mx_ao; +static struct rpmhpd mx = { + .pd = { .name = "mx", }, + .peer = &mx_ao, + .res_name = "mx.lvl", +}; + +static struct rpmhpd mx_ao = { + .pd = { .name = "mx_ao", }, + .active_only = true, + .peer = &mx, + .res_name = "mx.lvl", +}; + static struct rpmhpd mxc_ao; static struct rpmhpd mxc = { .pd = { .name = "mxc", }, @@ -180,15 +182,15 @@ static struct rpmhpd mxc_ao = { /* SDM845 RPMH powerdomains */ static struct rpmhpd *sdm845_rpmhpds[] = { - [SDM845_EBI] = &ebi, - [SDM845_MX] = &mx, - [SDM845_MX_AO] = &mx_ao, [SDM845_CX] = &cx_w_mx_parent, [SDM845_CX_AO] = &cx_ao_w_mx_parent, - [SDM845_LMX] = &lmx, - [SDM845_LCX] = &lcx, + [SDM845_EBI] = &ebi, [SDM845_GFX] = &gfx, + [SDM845_LCX] = &lcx, + [SDM845_LMX] = &lmx, [SDM845_MSS] = &mss, + [SDM845_MX] = &mx, + [SDM845_MX_AO] = &mx_ao, }; static const struct rpmhpd_desc sdm845_desc = { @@ -198,9 +200,9 @@ static const struct rpmhpd_desc sdm845_desc = { /* SDX55 RPMH powerdomains */ static struct rpmhpd *sdx55_rpmhpds[] = { + [SDX55_CX] = &cx_w_mx_parent, [SDX55_MSS] = &mss, [SDX55_MX] = &mx, - [SDX55_CX] = &cx_w_mx_parent, }; static const struct rpmhpd_desc sdx55_desc = { @@ -225,17 +227,17 @@ static const struct rpmhpd_desc sm6350_desc = { /* SM8150 RPMH powerdomains */ static struct rpmhpd *sm8150_rpmhpds[] = { - [SM8150_MSS] = &mss, - [SM8150_EBI] = &ebi, - [SM8150_LMX] = &lmx, - [SM8150_LCX] = &lcx, - [SM8150_GFX] = &gfx, - [SM8150_MX] = &mx, - [SM8150_MX_AO] = &mx_ao, [SM8150_CX] = &cx_w_mx_parent, [SM8150_CX_AO] = &cx_ao_w_mx_parent, + [SM8150_EBI] = &ebi, + [SM8150_GFX] = &gfx, + [SM8150_LCX] = &lcx, + [SM8150_LMX] = &lmx, [SM8150_MMCX] = &mmcx, [SM8150_MMCX_AO] = &mmcx_ao, + [SM8150_MSS] = &mss, + [SM8150_MX] = &mx, + [SM8150_MX_AO] = &mx_ao, }; static const struct rpmhpd_desc sm8150_desc = { @@ -272,11 +274,11 @@ static struct rpmhpd *sm8350_rpmhpds[] = { [SM8350_LMX] = &lmx, [SM8350_MMCX] = &mmcx, [SM8350_MMCX_AO] = &mmcx_ao, + [SM8350_MSS] = &mss, [SM8350_MX] = &mx, [SM8350_MX_AO] = &mx_ao, [SM8350_MXC] = &mxc, [SM8350_MXC_AO] = &mxc_ao, - [SM8350_MSS] = &mss, }; static const struct rpmhpd_desc sm8350_desc = { @@ -294,11 +296,11 @@ static struct rpmhpd *sm8450_rpmhpds[] = { [SM8450_LMX] = &lmx, [SM8450_MMCX] = &mmcx_w_cx_parent, [SM8450_MMCX_AO] = &mmcx_ao_w_cx_parent, + [SM8450_MSS] = &mss, [SM8450_MX] = &mx, [SM8450_MX_AO] = &mx_ao, [SM8450_MXC] = &mxc, [SM8450_MXC_AO] = &mxc_ao, - [SM8450_MSS] = &mss, }; static const struct rpmhpd_desc sm8450_desc = { @@ -311,11 +313,11 @@ static struct rpmhpd *sc7180_rpmhpds[] = { [SC7180_CX] = &cx_w_mx_parent, [SC7180_CX_AO] = &cx_ao_w_mx_parent, [SC7180_GFX] = &gfx, - [SC7180_MX] = &mx, - [SC7180_MX_AO] = &mx_ao, - [SC7180_LMX] = &lmx, [SC7180_LCX] = &lcx, + [SC7180_LMX] = &lmx, [SC7180_MSS] = &mss, + [SC7180_MX] = &mx, + [SC7180_MX_AO] = &mx_ao, }; static const struct rpmhpd_desc sc7180_desc = { @@ -329,11 +331,11 @@ static struct rpmhpd *sc7280_rpmhpds[] = { [SC7280_CX_AO] = &cx_ao, [SC7280_EBI] = &ebi, [SC7280_GFX] = &gfx, - [SC7280_MX] = &mx, - [SC7280_MX_AO] = &mx_ao, - [SC7280_LMX] = &lmx, [SC7280_LCX] = &lcx, + [SC7280_LMX] = &lmx, [SC7280_MSS] = &mss, + [SC7280_MX] = &mx, + [SC7280_MX_AO] = &mx_ao, }; static const struct rpmhpd_desc sc7280_desc = { -- cgit v1.2.3 From d39cec003ab0d6b91f9709c59daa6f0480d232e2 Mon Sep 17 00:00:00 2001 From: Luca Weiss Date: Mon, 13 Dec 2021 09:11:11 +0100 Subject: soc: qcom: socinfo: Add SM6350 and SM7225 Both SoCs are known as 'lagoon' downstream. Add their ids to the socinfo driver. Signed-off-by: Luca Weiss Reviewed-by: Konrad Dybcio Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211213081111.20217-1-luca.weiss@fairphone.com --- drivers/soc/qcom/socinfo.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 113dc57b74c3..6dc0f39c0ec3 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -313,9 +313,11 @@ static const struct soc_id soc_id[] = { { 421, "IPQ6000" }, { 422, "IPQ6010" }, { 425, "SC7180" }, + { 434, "SM6350" }, { 453, "IPQ6005" }, { 455, "QRB5165" }, { 457, "SM8450" }, + { 459, "SM7225" }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) -- cgit v1.2.3 From e395f021ccebc239e4fec02fec47f5f0eef44ebd Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Sat, 11 Dec 2021 17:06:26 +0800 Subject: soc: qcom: rpmh-rsc: Fix typo in a comment The double `for' in the comment in line 694 is repeated. Remove one of them from the comment. Signed-off-by: Jason Wang Signed-off-by: Bjorn Andersson Link: https://lore.kernel.org/r/20211211090626.248801-1-wangborong@cdjrlc.com --- drivers/soc/qcom/rpmh-rsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 3a12a482f6b2..01c2f50cb97e 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -691,7 +691,7 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg, * @drv: The controller. * @msg: The data to be written to the controller. * - * This should only be called for for sleep/wake state, never active-only + * This should only be called for sleep/wake state, never active-only * state. * * The caller must ensure that no other RPMH actions are happening and the -- cgit v1.2.3