From 6aa841c8097fee1b17b343719c45694e3166ca34 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 10 Mar 2016 05:22:53 +0800 Subject: soc: rockchip: power-domain: make idle handling optional Not all new socs need to handle idle states on domain state changes, so add the possibility to make them optional. Signed-off-by: Elaine Zhang Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 43155e1f97b9..7ae7d84e6776 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -68,9 +68,9 @@ struct rockchip_pmu { { \ .pwr_mask = BIT(pwr), \ .status_mask = BIT(status), \ - .req_mask = BIT(req), \ - .idle_mask = BIT(idle), \ - .ack_mask = BIT(ack), \ + .req_mask = (req >= 0) ? BIT(req) : 0, \ + .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ + .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ } #define DOMAIN_RK3288(pwr, status, req) \ @@ -96,6 +96,9 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, struct rockchip_pmu *pmu = pd->pmu; unsigned int val; + if (pd_info->req_mask == 0) + return 0; + regmap_update_bits(pmu->regmap, pmu->info->req_offset, pd_info->req_mask, idle ? -1U : 0); -- cgit v1.2.3 From 1fe767a56c32730a947fc2bfcac5d14490bde6ff Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 10 Mar 2016 05:22:54 +0800 Subject: soc: rockchip: power-domain: allow domains only handling idle requests On some Rockchip SoC there exist child-domains only handling their idle state with the actual power-state handled by a (shared) parent- domain. So allow such types of domains. For them, we can determine their state (on/off) by checking the inverse idle-state instead. There exist one special case if both idle as well power handling were set as not present, but as the domain-data is defined in the code itself, we can expect the reasonable developer to define them in a correct way, without adding more checks. Signed-off-by: Elaine Zhang Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 7ae7d84e6776..fbad052c191a 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -66,8 +66,8 @@ struct rockchip_pmu { #define DOMAIN(pwr, status, req, idle, ack) \ { \ - .pwr_mask = BIT(pwr), \ - .status_mask = BIT(status), \ + .pwr_mask = (pwr >= 0) ? BIT(pwr) : 0, \ + .status_mask = (status >= 0) ? BIT(status) : 0, \ .req_mask = (req >= 0) ? BIT(req) : 0, \ .idle_mask = (idle >= 0) ? BIT(idle) : 0, \ .ack_mask = (ack >= 0) ? BIT(ack) : 0, \ @@ -119,6 +119,10 @@ static bool rockchip_pmu_domain_is_on(struct rockchip_pm_domain *pd) struct rockchip_pmu *pmu = pd->pmu; unsigned int val; + /* check idle status for idle-only domains */ + if (pd->info->status_mask == 0) + return !rockchip_pmu_domain_is_idle(pd); + regmap_read(pmu->regmap, pmu->info->status_offset, &val); /* 1'b0: power on, 1'b1: power off */ @@ -130,6 +134,9 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, { struct rockchip_pmu *pmu = pd->pmu; + if (pd->info->pwr_mask == 0) + return; + regmap_update_bits(pmu->regmap, pmu->info->pwr_offset, pd->info->pwr_mask, on ? 0 : -1U); -- cgit v1.2.3 From 6be05b5ec16132f3df3f1d857ab01e30f726b542 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 10 Mar 2016 05:22:55 +0800 Subject: soc: rockchip: power-domain: add support for sub-power domains This patch adds support for making one power domain a sub-domain of other domain. This is useful for modeling power dependences, which needs to have more than one power domain enabled to be operational. Signed-off-by: Elaine Zhang [restructured error handling in subdomain-addition] Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 63 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index fbad052c191a..c179de3cd514 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -370,6 +370,61 @@ static void rockchip_configure_pd_cnt(struct rockchip_pmu *pmu, regmap_write(pmu->regmap, domain_reg_offset + 4, count); } +static int rockchip_pm_add_subdomain(struct rockchip_pmu *pmu, + struct device_node *parent) +{ + struct device_node *np; + struct generic_pm_domain *child_domain, *parent_domain; + int error; + + for_each_child_of_node(parent, np) { + u32 idx; + + error = of_property_read_u32(parent, "reg", &idx); + if (error) { + dev_err(pmu->dev, + "%s: failed to retrieve domain id (reg): %d\n", + parent->name, error); + goto err_out; + } + parent_domain = pmu->genpd_data.domains[idx]; + + error = rockchip_pm_add_one_domain(pmu, np); + if (error) { + dev_err(pmu->dev, "failed to handle node %s: %d\n", + np->name, error); + goto err_out; + } + + error = of_property_read_u32(np, "reg", &idx); + if (error) { + dev_err(pmu->dev, + "%s: failed to retrieve domain id (reg): %d\n", + np->name, error); + goto err_out; + } + child_domain = pmu->genpd_data.domains[idx]; + + error = pm_genpd_add_subdomain(parent_domain, child_domain); + if (error) { + dev_err(pmu->dev, "%s failed to add subdomain %s: %d\n", + parent_domain->name, child_domain->name, error); + goto err_out; + } else { + dev_dbg(pmu->dev, "%s add subdomain: %s\n", + parent_domain->name, child_domain->name); + } + + rockchip_pm_add_subdomain(pmu, np); + } + + return 0; + +err_out: + of_node_put(np); + return error; +} + static int rockchip_pm_domain_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -436,6 +491,14 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) of_node_put(node); goto err_out; } + + error = rockchip_pm_add_subdomain(pmu, node); + if (error < 0) { + dev_err(dev, "failed to handle subdomain node %s: %d\n", + node->name, error); + of_node_put(node); + goto err_out; + } } if (error) { -- cgit v1.2.3 From fd8b62cc38b356bcdf20ac8f1a647db7b11240cf Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Thu, 10 Mar 2016 05:24:38 +0800 Subject: soc: rockchip: power-domain: Modify power domain driver for rk3399 This driver is modified to support RK3399 SoC. Signed-off-by: Elaine Zhang [small indentation fixups] Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index c179de3cd514..2116131528f7 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -19,6 +19,7 @@ #include #include #include +#include struct rockchip_domain_info { int pwr_mask; @@ -79,6 +80,9 @@ struct rockchip_pmu { #define DOMAIN_RK3368(pwr, status, req) \ DOMAIN(pwr, status, req, (req) + 16, req) +#define DOMAIN_RK3399(pwr, status, req) \ + DOMAIN(pwr, status, req, req, req) + static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) { struct rockchip_pmu *pmu = pd->pmu; @@ -530,6 +534,36 @@ static const struct rockchip_domain_info rk3368_pm_domains[] = { [RK3368_PD_GPU_1] = DOMAIN_RK3368(17, 16, 2), }; +static const struct rockchip_domain_info rk3399_pm_domains[] = { + [RK3399_PD_TCPD0] = DOMAIN_RK3399(8, 8, -1), + [RK3399_PD_TCPD1] = DOMAIN_RK3399(9, 9, -1), + [RK3399_PD_CCI] = DOMAIN_RK3399(10, 10, -1), + [RK3399_PD_CCI0] = DOMAIN_RK3399(-1, -1, 15), + [RK3399_PD_CCI1] = DOMAIN_RK3399(-1, -1, 16), + [RK3399_PD_PERILP] = DOMAIN_RK3399(11, 11, 1), + [RK3399_PD_PERIHP] = DOMAIN_RK3399(12, 12, 2), + [RK3399_PD_CENTER] = DOMAIN_RK3399(13, 13, 14), + [RK3399_PD_VIO] = DOMAIN_RK3399(14, 14, 17), + [RK3399_PD_GPU] = DOMAIN_RK3399(15, 15, 0), + [RK3399_PD_VCODEC] = DOMAIN_RK3399(16, 16, 3), + [RK3399_PD_VDU] = DOMAIN_RK3399(17, 17, 4), + [RK3399_PD_RGA] = DOMAIN_RK3399(18, 18, 5), + [RK3399_PD_IEP] = DOMAIN_RK3399(19, 19, 6), + [RK3399_PD_VO] = DOMAIN_RK3399(20, 20, -1), + [RK3399_PD_VOPB] = DOMAIN_RK3399(-1, -1, 7), + [RK3399_PD_VOPL] = DOMAIN_RK3399(-1, -1, 8), + [RK3399_PD_ISP0] = DOMAIN_RK3399(22, 22, 9), + [RK3399_PD_ISP1] = DOMAIN_RK3399(23, 23, 10), + [RK3399_PD_HDCP] = DOMAIN_RK3399(24, 24, 11), + [RK3399_PD_GMAC] = DOMAIN_RK3399(25, 25, 23), + [RK3399_PD_EMMC] = DOMAIN_RK3399(26, 26, 24), + [RK3399_PD_USB3] = DOMAIN_RK3399(27, 27, 12), + [RK3399_PD_EDP] = DOMAIN_RK3399(28, 28, 22), + [RK3399_PD_GIC] = DOMAIN_RK3399(29, 29, 27), + [RK3399_PD_SD] = DOMAIN_RK3399(30, 30, 28), + [RK3399_PD_SDIOAUDIO] = DOMAIN_RK3399(31, 31, 29), +}; + static const struct rockchip_pmu_info rk3288_pmu = { .pwr_offset = 0x08, .status_offset = 0x0c, @@ -564,6 +598,23 @@ static const struct rockchip_pmu_info rk3368_pmu = { .domain_info = rk3368_pm_domains, }; +static const struct rockchip_pmu_info rk3399_pmu = { + .pwr_offset = 0x14, + .status_offset = 0x18, + .req_offset = 0x60, + .idle_offset = 0x64, + .ack_offset = 0x68, + + .core_pwrcnt_offset = 0x9c, + .gpu_pwrcnt_offset = 0xa4, + + .core_power_transition_time = 24, + .gpu_power_transition_time = 24, + + .num_domains = ARRAY_SIZE(rk3399_pm_domains), + .domain_info = rk3399_pm_domains, +}; + static const struct of_device_id rockchip_pm_domain_dt_match[] = { { .compatible = "rockchip,rk3288-power-controller", @@ -573,6 +624,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { .compatible = "rockchip,rk3368-power-controller", .data = (void *)&rk3368_pmu, }, + { + .compatible = "rockchip,rk3399-power-controller", + .data = (void *)&rk3399_pmu, + }, { /* sentinel */ }, }; -- cgit v1.2.3 From 35b67291b4a85d37ec31f9d9ea3c5d3258ee0da6 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 4 Dec 2015 14:57:03 +0000 Subject: soc/tegra: pmc: Add missing structure members to kernel-doc Some members of the tegra_pmc structure are missing from the kernel-doc comment for this structure. Add the missing members. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index bc34cf7482fb..99ca91f09929 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -113,8 +113,10 @@ struct tegra_pmc_soc { /** * struct tegra_pmc - NVIDIA Tegra PMC + * @dev: pointer to PMC device structure * @base: pointer to I/O remapped register region * @clk: pointer to pclk clock + * @soc: pointer to SoC data structure * @rate: currently configured rate of pclk * @suspend_mode: lowest suspend mode available * @cpu_good_time: CPU power good time (in microseconds) -- cgit v1.2.3 From 1e52efdfc6a29f9bad767b92b89ae6ae772063cc Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 4 Dec 2015 14:57:04 +0000 Subject: soc/tegra: pmc: Fix sparse warning for tegra_pmc_init_tsense_reset() Sparse reports the following warning for tegra_pmc_init_tsense_reset(): drivers/soc/tegra/pmc.c:741:6: warning: symbol 'tegra_pmc_init_tsense_reset' was not declared. Should it be static? This function is only used internally by the PMC driver and so fix this by making it static. Signed-off-by: Jon Hunter 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 99ca91f09929..5b6125ecd69a 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -729,7 +729,7 @@ static void tegra_pmc_init(struct tegra_pmc *pmc) tegra_pmc_writel(value, PMC_CNTRL); } -void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) +static void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc) { static const char disabled[] = "emergency thermal reset disabled"; u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux; -- cgit v1.2.3 From 3195ac6d9cbeef23631913d67f8c1e76b891da4d Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 4 Dec 2015 14:57:05 +0000 Subject: soc/tegra: pmc: Remove debugfs entry on probe failure The debugfs entry for the PMC device will not be removed if the probe of the device fails to register the restart handler. This leaves behind the dangling debugfs entry with no driver backing it. Remove the entry to avoid this. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 5b6125ecd69a..e60fc2d33c94 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -117,6 +117,7 @@ struct tegra_pmc_soc { * @base: pointer to I/O remapped register region * @clk: pointer to pclk clock * @soc: pointer to SoC data structure + * @debugfs: pointer to debugfs entry * @rate: currently configured rate of pclk * @suspend_mode: lowest suspend mode available * @cpu_good_time: CPU power good time (in microseconds) @@ -136,6 +137,7 @@ struct tegra_pmc { struct device *dev; void __iomem *base; struct clk *clk; + struct dentry *debugfs; const struct tegra_pmc_soc *soc; @@ -447,11 +449,9 @@ static const struct file_operations powergate_fops = { static int tegra_powergate_debugfs_init(void) { - struct dentry *d; - - d = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, - &powergate_fops); - if (!d) + pmc->debugfs = debugfs_create_file("powergate", S_IRUGO, NULL, NULL, + &powergate_fops); + if (!pmc->debugfs) return -ENOMEM; return 0; @@ -844,6 +844,7 @@ static int tegra_pmc_probe(struct platform_device *pdev) err = register_restart_handler(&tegra_pmc_restart_handler); if (err) { + debugfs_remove(pmc->debugfs); dev_err(&pdev->dev, "unable to register restart handler, %d\n", err); return err; -- cgit v1.2.3 From e8de5b81ff930a95f1a45e6feb3df278ee9850ae Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 4 Dec 2015 14:57:08 +0000 Subject: soc/tegra: pmc: Remove non-existing power partitions for Tegra210 The power partitions L2, HEG, CELP and C1NC do not exist on Tegra210 but were incorrectly documented in the TRM. These will be removed from the TRM and so also remove their definitions. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index e60fc2d33c94..88c7e506177e 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1009,17 +1009,13 @@ static const char * const tegra210_powergates[] = { [TEGRA_POWERGATE_3D] = "3d", [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_PCIE] = "pcie", - [TEGRA_POWERGATE_L2] = "l2", [TEGRA_POWERGATE_MPE] = "mpe", - [TEGRA_POWERGATE_HEG] = "heg", [TEGRA_POWERGATE_SATA] = "sata", [TEGRA_POWERGATE_CPU1] = "cpu1", [TEGRA_POWERGATE_CPU2] = "cpu2", [TEGRA_POWERGATE_CPU3] = "cpu3", - [TEGRA_POWERGATE_CELP] = "celp", [TEGRA_POWERGATE_CPU0] = "cpu0", [TEGRA_POWERGATE_C0NC] = "c0nc", - [TEGRA_POWERGATE_C1NC] = "c1nc", [TEGRA_POWERGATE_SOR] = "sor", [TEGRA_POWERGATE_DIS] = "dis", [TEGRA_POWERGATE_DISB] = "disb", -- cgit v1.2.3 From 668419afe65c146e115897e8fef6ca23c48bf121 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 11 Feb 2016 18:03:19 +0000 Subject: soc/tegra: pmc: Remove non-existing L2 partition for Tegra124 Tegra124 does not have an L2 power partition and the L2 cache is part of the cluster 0 non-CPU (CONC) partition. Remove the L2 as a valid partition for Tegra124. The TRM also shows that there is no L2 partition for Tegra124. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 88c7e506177e..922430322877 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -967,7 +967,6 @@ static const char * const tegra124_powergates[] = { [TEGRA_POWERGATE_VENC] = "venc", [TEGRA_POWERGATE_PCIE] = "pcie", [TEGRA_POWERGATE_VDEC] = "vdec", - [TEGRA_POWERGATE_L2] = "l2", [TEGRA_POWERGATE_MPE] = "mpe", [TEGRA_POWERGATE_HEG] = "heg", [TEGRA_POWERGATE_SATA] = "sata", -- cgit v1.2.3 From 0259f522e04f19b433a4dc7586d80da106afbbcc Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 11 Feb 2016 18:03:20 +0000 Subject: soc/tegra: pmc: Restore base address on probe failure During early initialisation, the PMC registers are mapped and the PMC SoC data is populated in the PMC data structure. This allows other drivers access the PMC register space, via the public Tegra PMC APIs, prior to probing the PMC device. When the PMC device is probed, the PMC registers are mapped again and if successful the initial mapping is freed. If the probing of the PMC device fails after the registers are remapped, then the registers will be unmapped and hence the pointer to the PMC registers will be invalid. This could lead to a potential crash, because once the PMC SoC data pointer is populated, the driver assumes that the PMC register mapping is also valid and a user calling any of the public Tegra PMC APIs could trigger an exception because these APIs don't check that the mapping is still valid. Fix this by updating the mapping and freeing the original mapping only if probing the PMC device is successful. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 922430322877..900f72f0d757 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -807,7 +807,7 @@ out: static int tegra_pmc_probe(struct platform_device *pdev) { - void __iomem *base = pmc->base; + void __iomem *base, *tmp; struct resource *res; int err; @@ -817,11 +817,9 @@ static int tegra_pmc_probe(struct platform_device *pdev) /* take over the memory region from the early initialization */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - pmc->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(pmc->base)) - return PTR_ERR(pmc->base); - - iounmap(base); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); pmc->clk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(pmc->clk)) { @@ -850,6 +848,10 @@ static int tegra_pmc_probe(struct platform_device *pdev) return err; } + tmp = pmc->base; + pmc->base = base; + iounmap(tmp); + return 0; } -- cgit v1.2.3 From e8cf6616a346029fe3e3931dd34fc589fade4b6e Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 11 Feb 2016 18:03:21 +0000 Subject: soc/tegra: pmc: Protect public functions from potential race conditions The PMC base address pointer is initialised during early boot so that early platform code may used the PMC public functions. During the probe of the PMC driver the base address pointer is mapped again and the initial mapping is freed. This exposes a window where a device accessing the PMC registers via one of the public functions, could race with the updating of the pointer and lead to a invalid access. Furthermore, the only protection between multiple devices attempting to access the PMC registers is when setting the powergate state to on or off. None of the other public functions that access the PMC registers are protected. Use the existing mutex to protect paths that may race with regard to accessing the PMC registers. Note that functions tegra_io_rail_prepare()/poll() either return a negative value on failure or zero on success. Therefore, it is not necessary to check if the return value is less than zero and so only test that the return value is not zero to test for failure. This simplifies the error handling with the mutex locking in place. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 900f72f0d757..5449d1aa14e8 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -235,7 +235,10 @@ int tegra_powergate_is_powered(int id) if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) return -EINVAL; + mutex_lock(&pmc->powergates_lock); status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); + mutex_unlock(&pmc->powergates_lock); + return !!status; } @@ -250,6 +253,8 @@ int tegra_powergate_remove_clamping(int id) if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) return -EINVAL; + mutex_lock(&pmc->powergates_lock); + /* * On Tegra124 and later, the clamps for the GPU are controlled by a * separate register (with different semantics). @@ -257,7 +262,7 @@ int tegra_powergate_remove_clamping(int id) if (id == TEGRA_POWERGATE_3D) { if (pmc->soc->has_gpu_clamps) { tegra_pmc_writel(0, GPU_RG_CNTRL); - return 0; + goto out; } } @@ -274,6 +279,9 @@ int tegra_powergate_remove_clamping(int id) tegra_pmc_writel(mask, REMOVE_CLAMPING); +out: + mutex_unlock(&pmc->powergates_lock); + return 0; } EXPORT_SYMBOL(tegra_powergate_remove_clamping); @@ -520,9 +528,11 @@ int tegra_io_rail_power_on(int id) unsigned int bit, mask; int err; + mutex_lock(&pmc->powergates_lock); + err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err < 0) - return err; + if (err) + goto error; mask = 1 << bit; @@ -533,14 +543,17 @@ int tegra_io_rail_power_on(int id) tegra_pmc_writel(value, request); err = tegra_io_rail_poll(status, mask, 0, 250); - if (err < 0) { + if (err) { pr_info("tegra_io_rail_poll() failed: %d\n", err); - return err; + goto error; } tegra_io_rail_unprepare(); - return 0; +error: + mutex_unlock(&pmc->powergates_lock); + + return err; } EXPORT_SYMBOL(tegra_io_rail_power_on); @@ -550,10 +563,12 @@ int tegra_io_rail_power_off(int id) unsigned int bit, mask; int err; + mutex_lock(&pmc->powergates_lock); + err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err < 0) { + if (err) { pr_info("tegra_io_rail_prepare() failed: %d\n", err); - return err; + goto error; } mask = 1 << bit; @@ -565,12 +580,15 @@ int tegra_io_rail_power_off(int id) tegra_pmc_writel(value, request); err = tegra_io_rail_poll(status, mask, mask, 250); - if (err < 0) - return err; + if (err) + goto error; tegra_io_rail_unprepare(); - return 0; +error: + mutex_unlock(&pmc->powergates_lock); + + return err; } EXPORT_SYMBOL(tegra_io_rail_power_off); @@ -807,7 +825,7 @@ out: static int tegra_pmc_probe(struct platform_device *pdev) { - void __iomem *base, *tmp; + void __iomem *base; struct resource *res; int err; @@ -848,9 +866,10 @@ static int tegra_pmc_probe(struct platform_device *pdev) return err; } - tmp = pmc->base; + mutex_lock(&pmc->powergates_lock); + iounmap(pmc->base); pmc->base = base; - iounmap(tmp); + mutex_unlock(&pmc->powergates_lock); return 0; } -- cgit v1.2.3 From 70293ed09decd1ec4ae5632af27cab73c16a50ba Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 11 Feb 2016 18:03:22 +0000 Subject: soc/tegra: pmc: Change powergate and rail IDs to be an unsigned type The Tegra powergate and rail IDs are always positive values and so change the type to be unsigned and remove the tests to see if the ID is less than zero. Update the Tegra DC powergate type to be an unsigned as well. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 5449d1aa14e8..5f32a3e34476 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -179,7 +179,7 @@ static void tegra_pmc_writel(u32 value, unsigned long offset) * @id: partition ID * @new_state: new state of the partition */ -static int tegra_powergate_set(int id, bool new_state) +static int tegra_powergate_set(unsigned int id, bool new_state) { bool status; @@ -203,9 +203,9 @@ static int tegra_powergate_set(int id, bool new_state) * tegra_powergate_power_on() - power on partition * @id: partition ID */ -int tegra_powergate_power_on(int id) +int tegra_powergate_power_on(unsigned int id) { - if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) + if (!pmc->soc || id >= pmc->soc->num_powergates) return -EINVAL; return tegra_powergate_set(id, true); @@ -215,9 +215,9 @@ int tegra_powergate_power_on(int id) * tegra_powergate_power_off() - power off partition * @id: partition ID */ -int tegra_powergate_power_off(int id) +int tegra_powergate_power_off(unsigned int id) { - if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) + if (!pmc->soc || id >= pmc->soc->num_powergates) return -EINVAL; return tegra_powergate_set(id, false); @@ -228,11 +228,11 @@ EXPORT_SYMBOL(tegra_powergate_power_off); * tegra_powergate_is_powered() - check if partition is powered * @id: partition ID */ -int tegra_powergate_is_powered(int id) +int tegra_powergate_is_powered(unsigned int id) { u32 status; - if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) + if (!pmc->soc || id >= pmc->soc->num_powergates) return -EINVAL; mutex_lock(&pmc->powergates_lock); @@ -246,11 +246,11 @@ int tegra_powergate_is_powered(int id) * tegra_powergate_remove_clamping() - remove power clamps for partition * @id: partition ID */ -int tegra_powergate_remove_clamping(int id) +int tegra_powergate_remove_clamping(unsigned int id) { u32 mask; - if (!pmc->soc || id < 0 || id >= pmc->soc->num_powergates) + if (!pmc->soc || id >= pmc->soc->num_powergates) return -EINVAL; mutex_lock(&pmc->powergates_lock); @@ -294,7 +294,7 @@ EXPORT_SYMBOL(tegra_powergate_remove_clamping); * * Must be called with clk disabled, and returns with clk enabled. */ -int tegra_powergate_sequence_power_up(int id, struct clk *clk, +int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, struct reset_control *rst) { int ret; @@ -337,9 +337,9 @@ EXPORT_SYMBOL(tegra_powergate_sequence_power_up); * Returns the partition ID corresponding to the CPU partition ID or a * negative error code on failure. */ -static int tegra_get_cpu_powergate_id(int cpuid) +static int tegra_get_cpu_powergate_id(unsigned int cpuid) { - if (pmc->soc && cpuid > 0 && cpuid < pmc->soc->num_cpu_powergates) + if (pmc->soc && cpuid < pmc->soc->num_cpu_powergates) return pmc->soc->cpu_powergates[cpuid]; return -EINVAL; @@ -349,7 +349,7 @@ static int tegra_get_cpu_powergate_id(int cpuid) * tegra_pmc_cpu_is_powered() - check if CPU partition is powered * @cpuid: CPU partition ID */ -bool tegra_pmc_cpu_is_powered(int cpuid) +bool tegra_pmc_cpu_is_powered(unsigned int cpuid) { int id; @@ -364,7 +364,7 @@ bool tegra_pmc_cpu_is_powered(int cpuid) * tegra_pmc_cpu_power_on() - power on CPU partition * @cpuid: CPU partition ID */ -int tegra_pmc_cpu_power_on(int cpuid) +int tegra_pmc_cpu_power_on(unsigned int cpuid) { int id; @@ -379,7 +379,7 @@ int tegra_pmc_cpu_power_on(int cpuid) * tegra_pmc_cpu_remove_clamping() - remove power clamps for CPU partition * @cpuid: CPU partition ID */ -int tegra_pmc_cpu_remove_clamping(int cpuid) +int tegra_pmc_cpu_remove_clamping(unsigned int cpuid) { int id; @@ -465,7 +465,7 @@ static int tegra_powergate_debugfs_init(void) return 0; } -static int tegra_io_rail_prepare(int id, unsigned long *request, +static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, unsigned long *status, unsigned int *bit) { unsigned long rate, value; @@ -522,7 +522,7 @@ static void tegra_io_rail_unprepare(void) tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); } -int tegra_io_rail_power_on(int id) +int tegra_io_rail_power_on(unsigned int id) { unsigned long request, status, value; unsigned int bit, mask; @@ -557,7 +557,7 @@ error: } EXPORT_SYMBOL(tegra_io_rail_power_on); -int tegra_io_rail_power_off(int id) +int tegra_io_rail_power_off(unsigned int id) { unsigned long request, status, value; unsigned int bit, mask; -- cgit v1.2.3 From 0ecf2d33bb4686b5d8f06b3b18877de0d88d3af4 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 11 Feb 2016 18:03:23 +0000 Subject: soc/tegra: pmc: Fix testing of powergate state In tegra_powergate_set() the state of the powergates is read and OR'ed with the bit for the powergate of interest. This unsigned 32-bit value is then compared with a boolean value to test if the powergate is already in the desired state. When turning on a powergate, apart from the powergate that is represented by bit 0, this test will always return false and so we may attempt to turn on the powergate when it is already on. After OR'ing the bit for the powergate, check if the result is not equal to zero before comparing with the boolean value. Add a helper function to return the current state of a powergate and use this in both tegra_powergate_set() and tegra_powergate_is_powered() where we check the powergate status. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 5f32a3e34476..9e8d359baf0e 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -174,6 +174,11 @@ static void tegra_pmc_writel(u32 value, unsigned long offset) writel(value, pmc->base + offset); } +static inline bool tegra_powergate_state(int id) +{ + return (tegra_pmc_readl(PWRGATE_STATUS) & BIT(id)) != 0; +} + /** * tegra_powergate_set() - set the state of a partition * @id: partition ID @@ -181,13 +186,9 @@ static void tegra_pmc_writel(u32 value, unsigned long offset) */ static int tegra_powergate_set(unsigned int id, bool new_state) { - bool status; - mutex_lock(&pmc->powergates_lock); - status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); - - if (status == new_state) { + if (tegra_powergate_state(id) == new_state) { mutex_unlock(&pmc->powergates_lock); return 0; } @@ -230,16 +231,16 @@ EXPORT_SYMBOL(tegra_powergate_power_off); */ int tegra_powergate_is_powered(unsigned int id) { - u32 status; + int status; if (!pmc->soc || id >= pmc->soc->num_powergates) return -EINVAL; mutex_lock(&pmc->powergates_lock); - status = tegra_pmc_readl(PWRGATE_STATUS) & (1 << id); + status = tegra_powergate_state(id); mutex_unlock(&pmc->powergates_lock); - return !!status; + return status; } /** -- cgit v1.2.3 From 0a243bd438ce3d44e03140adf58df4df11dce978 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 11 Feb 2016 18:03:24 +0000 Subject: soc/tegra: pmc: Fix verification of valid partitions The Tegra power partitions are referenced by numerical IDs which are the same values programmed into the PMC registers for controlling the partition. For a given device, the valid partition IDs may not be contiguous and so simply checking that an ID is not greater than the maximum ID supported may not mean it is valid. Fix this by checking if the powergate is defined in the list of powergates for the Tegra SoC. Add a helper function for checking valid powergates and use where we need to verify if the powergate ID is valid or not. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 9e8d359baf0e..e75782b47267 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -179,6 +179,11 @@ static inline bool tegra_powergate_state(int id) return (tegra_pmc_readl(PWRGATE_STATUS) & BIT(id)) != 0; } +static inline bool tegra_powergate_is_valid(int id) +{ + return (pmc->soc && pmc->soc->powergates[id]); +} + /** * tegra_powergate_set() - set the state of a partition * @id: partition ID @@ -206,7 +211,7 @@ static int tegra_powergate_set(unsigned int id, bool new_state) */ int tegra_powergate_power_on(unsigned int id) { - if (!pmc->soc || id >= pmc->soc->num_powergates) + if (!tegra_powergate_is_valid(id)) return -EINVAL; return tegra_powergate_set(id, true); @@ -218,7 +223,7 @@ int tegra_powergate_power_on(unsigned int id) */ int tegra_powergate_power_off(unsigned int id) { - if (!pmc->soc || id >= pmc->soc->num_powergates) + if (!tegra_powergate_is_valid(id)) return -EINVAL; return tegra_powergate_set(id, false); @@ -233,7 +238,7 @@ int tegra_powergate_is_powered(unsigned int id) { int status; - if (!pmc->soc || id >= pmc->soc->num_powergates) + if (!tegra_powergate_is_valid(id)) return -EINVAL; mutex_lock(&pmc->powergates_lock); @@ -251,7 +256,7 @@ int tegra_powergate_remove_clamping(unsigned int id) { u32 mask; - if (!pmc->soc || id >= pmc->soc->num_powergates) + if (!tegra_powergate_is_valid(id)) return -EINVAL; mutex_lock(&pmc->powergates_lock); -- cgit v1.2.3 From c3ea297260b77a99a2383c1029a381d125f788fe Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 11 Feb 2016 18:03:25 +0000 Subject: soc/tegra: pmc: Remove additional check for a valid partition The function tegra_powergate_is_powered() verifies that the partition being queried is valid and so there is no need to check this before calling tegra_powergate_is_powered() in powergate_show(). So remove this extra check. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index e75782b47267..8e358dbffaed 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -434,16 +434,18 @@ static struct notifier_block tegra_pmc_restart_handler = { static int powergate_show(struct seq_file *s, void *data) { unsigned int i; + int status; seq_printf(s, " powergate powered\n"); seq_printf(s, "------------------\n"); for (i = 0; i < pmc->soc->num_powergates; i++) { - if (!pmc->soc->powergates[i]) + status = tegra_powergate_is_powered(i); + if (status < 0) continue; seq_printf(s, " %9s %7s\n", pmc->soc->powergates[i], - tegra_powergate_is_powered(i) ? "yes" : "no"); + status ? "yes" : "no"); } return 0; -- cgit v1.2.3 From bc9af23d314f5c846e66e9425b31df2815ef1763 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Mon, 15 Feb 2016 12:38:11 +0000 Subject: soc/tegra: pmc: Ensure GPU partition can be toggled on/off by PMC For Tegra124 and Tegra210, the GPU partition cannot be toggled on and off via the APBDEV_PMC_PWRGATE_TOGGLE_0 register. For these devices, the partition is simply powered up and down via an external regulator. For these devices, there is a separate register for controlling the signal clamping of the partition and this is described in the PMC SoC data by the "has_gpu_clamp" variable. Use this variable to determine if the GPU partition can be controlled via the APBDEV_PMC_PWRGATE_TOGGLE_0 register and ensure that no one can incorrectly try to toggle the GPU partition via the APBDEV_PMC_PWRGATE_TOGGLE_0 register. Furthermore, we cannot use the APBDEV_PMC_PWRGATE_STATUS_0 register to determine if the GPU partition is powered for Tegra124 and Tegra210. However, if the GPU partition is powered, then the signal clamp for the GPU partition should be removed and so use bit 0 of the APBDEV_PMC_GPU_RG_CNTRL_0 register to determine if the clamp has been removed (bit[0] = 0) and the GPU partition is powered. Signed-off-by: Jon Hunter Reviewed-by: Mathieu Poirier Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 8e358dbffaed..e4fd40fa27e8 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -176,7 +176,10 @@ static void tegra_pmc_writel(u32 value, unsigned long offset) static inline bool tegra_powergate_state(int id) { - return (tegra_pmc_readl(PWRGATE_STATUS) & BIT(id)) != 0; + if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) + return (tegra_pmc_readl(GPU_RG_CNTRL) & 0x1) == 0; + else + return (tegra_pmc_readl(PWRGATE_STATUS) & BIT(id)) != 0; } static inline bool tegra_powergate_is_valid(int id) @@ -191,6 +194,9 @@ static inline bool tegra_powergate_is_valid(int id) */ static int tegra_powergate_set(unsigned int id, bool new_state) { + if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) + return -EINVAL; + mutex_lock(&pmc->powergates_lock); if (tegra_powergate_state(id) == new_state) { -- cgit v1.2.3 From 0a2d87e0473fc5eea3f8168f5a24a35e4cf3f29c Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 26 Feb 2016 15:48:40 +0000 Subject: soc/tegra: pmc: Wait for powergate state to change Currently, the function tegra_powergate_set() simply sets the desired powergate state but does not wait for the state to change. In most cases we should wait for the state to change before proceeding. Currently, there is a case for Tegra114 and Tegra124 devices where we do not wait when starting the secondary CPU as this is not necessary. However, this is only done at boot time and so waiting here will only have a small impact on boot time. Therefore, update tegra_powergate_set() to wait when setting the powergate. By adding this feature, we can also eliminate the polling loop from tegra30_boot_secondary(). A function has been added for checking the status of the powergate and so update the tegra_powergate_is_powered() to use this macro as well. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index e4fd40fa27e8..08966c26d65c 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -194,6 +195,9 @@ static inline bool tegra_powergate_is_valid(int id) */ static int tegra_powergate_set(unsigned int id, bool new_state) { + bool status; + int err; + if (id == TEGRA_POWERGATE_3D && pmc->soc->has_gpu_clamps) return -EINVAL; @@ -206,9 +210,12 @@ static int tegra_powergate_set(unsigned int id, bool new_state) tegra_pmc_writel(PWRGATE_TOGGLE_START | id, PWRGATE_TOGGLE); + err = readx_poll_timeout(tegra_powergate_state, id, status, + status == new_state, 10, 100000); + mutex_unlock(&pmc->powergates_lock); - return 0; + return err; } /** -- cgit v1.2.3 From 4506697d9f8537a8d33e9e002f8efceb32d10757 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 15 Feb 2016 11:33:57 +0800 Subject: soc: rockchip: power-domain: check the existing of regmap Check return value of syscon_node_to_regmap for rockchip_pm_domain_probe. If err value is returned, probe procedure should abort. Signed-off-by: Shawn Lin Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 2116131528f7..ac729fe42cc9 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -475,6 +475,10 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) } pmu->regmap = syscon_node_to_regmap(parent->of_node); + if (IS_ERR(pmu->regmap)) { + dev_err(dev, "no regmap available\n"); + return PTR_ERR(pmu->regmap); + } /* * Configure power up and down transition delays for CORE -- cgit v1.2.3 From cef4bafcea2c33b0c296595cebd95f0cfd99f278 Mon Sep 17 00:00:00 2001 From: Justin Chen Date: Wed, 23 Mar 2016 11:56:50 -0700 Subject: soc: brcmstb: add SoC driver to brcmstb Value of soc_dev_attributes: * family = chip family id * soc_id = product id * revision = product revision Signed-off-by: Justin Chen Signed-off-by: Florian Fainelli --- drivers/soc/brcmstb/common.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'drivers/soc') diff --git a/drivers/soc/brcmstb/common.c b/drivers/soc/brcmstb/common.c index c262c029b1b8..daf86acf9d01 100644 --- a/drivers/soc/brcmstb/common.c +++ b/drivers/soc/brcmstb/common.c @@ -12,10 +12,18 @@ * GNU General Public License for more details. */ +#include #include +#include +#include +#include +#include #include +static u32 family_id; +static u32 product_id; + static const struct of_device_id brcmstb_machine_match[] = { { .compatible = "brcm,brcmstb", }, { } @@ -31,3 +39,53 @@ bool soc_is_brcmstb(void) return of_match_node(brcmstb_machine_match, root) != NULL; } + +static const struct of_device_id sun_top_ctrl_match[] = { + { .compatible = "brcm,brcmstb-sun-top-ctrl", }, + { } +}; + +static int __init brcmstb_soc_device_init(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + struct device_node *sun_top_ctrl; + void __iomem *sun_top_ctrl_base; + + sun_top_ctrl = of_find_matching_node(NULL, sun_top_ctrl_match); + if (!sun_top_ctrl) + return -ENODEV; + + sun_top_ctrl_base = of_iomap(sun_top_ctrl, 0); + if (!sun_top_ctrl_base) + return -ENODEV; + + family_id = readl(sun_top_ctrl_base); + product_id = readl(sun_top_ctrl_base + 0x4); + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + soc_dev_attr->family = kasprintf(GFP_KERNEL, "%x", + family_id >> 28 ? + family_id >> 16 : family_id >> 8); + soc_dev_attr->soc_id = kasprintf(GFP_KERNEL, "%x", + product_id >> 28 ? + product_id >> 16 : product_id >> 8); + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c%d", + ((product_id & 0xf0) >> 4) + 'A', + product_id & 0xf); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->family); + kfree(soc_dev_attr->soc_id); + kfree(soc_dev_attr->revision); + kfree(soc_dev_attr); + return -ENODEV; + } + + return 0; +} +arch_initcall(brcmstb_soc_device_init); -- cgit v1.2.3 From 9bebedb054f98b70c798423cba6d9ba903b27d63 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 19 Feb 2016 09:44:06 +0100 Subject: soc: mediatek: PMIC wrap: don't duplicate the wrapper data As we add support for more devices struct pmic_wrapper_type will grow and we do not really want to start duplicating all the elements in struct pmic_wrapper. Signed-off-by: John Crispin Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 0d9b19a78d27..340c4b520da1 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -376,9 +376,7 @@ struct pmic_wrapper { struct device *dev; void __iomem *base; struct regmap *regmap; - int *regs; - enum pwrap_type type; - u32 arb_en_all; + const struct pmic_wrapper_type *master; struct clk *clk_spi; struct clk *clk_wrap; struct reset_control *rstc; @@ -389,22 +387,22 @@ struct pmic_wrapper { static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp) { - return wrp->type == PWRAP_MT8135; + return wrp->master->type == PWRAP_MT8135; } static inline int pwrap_is_mt8173(struct pmic_wrapper *wrp) { - return wrp->type == PWRAP_MT8173; + return wrp->master->type == PWRAP_MT8173; } static u32 pwrap_readl(struct pmic_wrapper *wrp, enum pwrap_regs reg) { - return readl(wrp->base + wrp->regs[reg]); + return readl(wrp->base + wrp->master->regs[reg]); } static void pwrap_writel(struct pmic_wrapper *wrp, u32 val, enum pwrap_regs reg) { - writel(val, wrp->base + wrp->regs[reg]); + writel(val, wrp->base + wrp->master->regs[reg]); } static bool pwrap_is_fsm_idle(struct pmic_wrapper *wrp) @@ -697,7 +695,7 @@ static int pwrap_init(struct pmic_wrapper *wrp) pwrap_writel(wrp, 1, PWRAP_WRAP_EN); - pwrap_writel(wrp, wrp->arb_en_all, PWRAP_HIPRIO_ARB_EN); + pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN); pwrap_writel(wrp, 1, PWRAP_WACS2_EN); @@ -742,7 +740,7 @@ static int pwrap_init(struct pmic_wrapper *wrp) pwrap_writel(wrp, 0x1, PWRAP_CRC_EN); pwrap_writel(wrp, 0x0, PWRAP_SIG_MODE); pwrap_writel(wrp, PWRAP_DEW_CRC_VAL, PWRAP_SIG_ADR); - pwrap_writel(wrp, wrp->arb_en_all, PWRAP_HIPRIO_ARB_EN); + pwrap_writel(wrp, wrp->master->arb_en_all, PWRAP_HIPRIO_ARB_EN); if (pwrap_is_mt8135(wrp)) pwrap_writel(wrp, 0x7, PWRAP_RRARB_EN); @@ -836,7 +834,6 @@ static int pwrap_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = of_match_device(of_pwrap_match_tbl, &pdev->dev); - const struct pmic_wrapper_type *type; struct resource *res; wrp = devm_kzalloc(&pdev->dev, sizeof(*wrp), GFP_KERNEL); @@ -845,10 +842,7 @@ static int pwrap_probe(struct platform_device *pdev) platform_set_drvdata(pdev, wrp); - type = of_id->data; - wrp->regs = type->regs; - wrp->type = type->type; - wrp->arb_en_all = type->arb_en_all; + wrp->master = of_id->data; wrp->dev = &pdev->dev; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwrap"); -- cgit v1.2.3 From a397845338af260658f55b2ba73834940244cf6d Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 19 Feb 2016 09:44:07 +0100 Subject: soc: mediatek: PMIC wrap: add wrapper callbacks for init_reg_clock Split init_reg_clock up into SoC specific callbacks. The patch also reorders the code to avoid the need for callback function prototypes. Signed-off-by: John Crispin Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 70 +++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 32 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 340c4b520da1..b22b664b155b 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -354,24 +354,6 @@ enum pwrap_type { PWRAP_MT8173, }; -struct pmic_wrapper_type { - int *regs; - enum pwrap_type type; - u32 arb_en_all; -}; - -static struct pmic_wrapper_type pwrap_mt8135 = { - .regs = mt8135_regs, - .type = PWRAP_MT8135, - .arb_en_all = 0x1ff, -}; - -static struct pmic_wrapper_type pwrap_mt8173 = { - .regs = mt8173_regs, - .type = PWRAP_MT8173, - .arb_en_all = 0x3f, -}; - struct pmic_wrapper { struct device *dev; void __iomem *base; @@ -385,6 +367,13 @@ struct pmic_wrapper { void __iomem *bridge_base; }; +struct pmic_wrapper_type { + int *regs; + enum pwrap_type type; + u32 arb_en_all; + int (*init_reg_clock)(struct pmic_wrapper *wrp); +}; + static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp) { return wrp->master->type == PWRAP_MT8135; @@ -578,20 +567,23 @@ static int pwrap_init_sidly(struct pmic_wrapper *wrp) return 0; } -static int pwrap_init_reg_clock(struct pmic_wrapper *wrp) +static int pwrap_mt8135_init_reg_clock(struct pmic_wrapper *wrp) { - if (pwrap_is_mt8135(wrp)) { - pwrap_writel(wrp, 0x4, PWRAP_CSHEXT); - pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); - pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); - pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START); - pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END); - } else { - pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); - pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); - pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_START); - pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_END); - } + pwrap_writel(wrp, 0x4, PWRAP_CSHEXT); + pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); + pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); + pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_START); + pwrap_writel(wrp, 0x0, PWRAP_CSLEXT_END); + + return 0; +} + +static int pwrap_mt8173_init_reg_clock(struct pmic_wrapper *wrp) +{ + pwrap_writel(wrp, 0x0, PWRAP_CSHEXT_WRITE); + pwrap_writel(wrp, 0x4, PWRAP_CSHEXT_READ); + pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_START); + pwrap_writel(wrp, 0x2, PWRAP_CSLEXT_END); return 0; } @@ -699,7 +691,7 @@ static int pwrap_init(struct pmic_wrapper *wrp) pwrap_writel(wrp, 1, PWRAP_WACS2_EN); - ret = pwrap_init_reg_clock(wrp); + ret = wrp->master->init_reg_clock(wrp); if (ret) return ret; @@ -814,6 +806,20 @@ static const struct regmap_config pwrap_regmap_config = { .max_register = 0xffff, }; +static struct pmic_wrapper_type pwrap_mt8135 = { + .regs = mt8135_regs, + .type = PWRAP_MT8135, + .arb_en_all = 0x1ff, + .init_reg_clock = pwrap_mt8135_init_reg_clock, +}; + +static struct pmic_wrapper_type pwrap_mt8173 = { + .regs = mt8173_regs, + .type = PWRAP_MT8173, + .arb_en_all = 0x3f, + .init_reg_clock = pwrap_mt8173_init_reg_clock, +}; + static struct of_device_id of_pwrap_match_tbl[] = { { .compatible = "mediatek,mt8135-pwrap", -- cgit v1.2.3 From 41c11f32d86ac1b64c78b827f977432df4934147 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 19 Feb 2016 09:44:08 +0100 Subject: soc: mediatek: PMIC wrap: split SoC specific init into callback This patch moves the SoC specific wrapper init code into separate callback to avoid pwrap_init() getting too large. This is done by adding a new element called init_special to pmic_wrapper_type. Each currently supported SoC gets its own version of the callback and we copy the code that was previously inside pwrap_init() to these new callbacks. Finally we point the 2 instances of pmic_wrapper_type at the 2 new functions. Signed-off-by: John Crispin Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 67 ++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 25 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index b22b664b155b..22c89e96a731 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -372,6 +372,7 @@ struct pmic_wrapper_type { enum pwrap_type type; u32 arb_en_all; int (*init_reg_clock)(struct pmic_wrapper *wrp); + int (*init_soc_specific)(struct pmic_wrapper *wrp); }; static inline int pwrap_is_mt8135(struct pmic_wrapper *wrp) @@ -665,6 +666,41 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) return 0; } +static int pwrap_mt8135_init_soc_specific(struct pmic_wrapper *wrp) +{ + /* enable pwrap events and pwrap bridge in AP side */ + pwrap_writel(wrp, 0x1, PWRAP_EVENT_IN_EN); + pwrap_writel(wrp, 0xffff, PWRAP_EVENT_DST_EN); + writel(0x7f, wrp->bridge_base + PWRAP_MT8135_BRIDGE_IORD_ARB_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS3_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS4_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_UNIT); + writel(0xffff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_SRC_EN); + writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_TIMER_EN); + writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN); + + /* enable PMIC event out and sources */ + if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) || + pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) { + dev_err(wrp->dev, "enable dewrap fail\n"); + return -EFAULT; + } + + return 0; +} + +static int pwrap_mt8173_init_soc_specific(struct pmic_wrapper *wrp) +{ + /* PMIC_DEWRAP enables */ + if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) || + pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) { + dev_err(wrp->dev, "enable dewrap fail\n"); + return -EFAULT; + } + + return 0; +} + static int pwrap_init(struct pmic_wrapper *wrp) { int ret; @@ -743,31 +779,10 @@ static int pwrap_init(struct pmic_wrapper *wrp) pwrap_writel(wrp, 0x5, PWRAP_STAUPD_PRD); pwrap_writel(wrp, 0xff, PWRAP_STAUPD_GRPEN); - if (pwrap_is_mt8135(wrp)) { - /* enable pwrap events and pwrap bridge in AP side */ - pwrap_writel(wrp, 0x1, PWRAP_EVENT_IN_EN); - pwrap_writel(wrp, 0xffff, PWRAP_EVENT_DST_EN); - writel(0x7f, wrp->bridge_base + PWRAP_MT8135_BRIDGE_IORD_ARB_EN); - writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS3_EN); - writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WACS4_EN); - writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_UNIT); - writel(0xffff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_WDT_SRC_EN); - writel(0x1, wrp->bridge_base + PWRAP_MT8135_BRIDGE_TIMER_EN); - writel(0x7ff, wrp->bridge_base + PWRAP_MT8135_BRIDGE_INT_EN); - - /* enable PMIC event out and sources */ - if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) || - pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) { - dev_err(wrp->dev, "enable dewrap fail\n"); - return -EFAULT; - } - } else { - /* PMIC_DEWRAP enables */ - if (pwrap_write(wrp, PWRAP_DEW_EVENT_OUT_EN, 0x1) || - pwrap_write(wrp, PWRAP_DEW_EVENT_SRC_EN, 0xffff)) { - dev_err(wrp->dev, "enable dewrap fail\n"); - return -EFAULT; - } + if (wrp->master->init_soc_specific) { + ret = wrp->master->init_soc_specific(wrp); + if (ret) + return ret; } /* Setup the init done registers */ @@ -811,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = { .type = PWRAP_MT8135, .arb_en_all = 0x1ff, .init_reg_clock = pwrap_mt8135_init_reg_clock, + .init_soc_specific = pwrap_mt8135_init_soc_specific, }; static struct pmic_wrapper_type pwrap_mt8173 = { @@ -818,6 +834,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = { .type = PWRAP_MT8173, .arb_en_all = 0x3f, .init_reg_clock = pwrap_mt8173_init_reg_clock, + .init_soc_specific = pwrap_mt8173_init_soc_specific, }; static struct of_device_id of_pwrap_match_tbl[] = { -- cgit v1.2.3 From e5eef49bc34b2adda3d3d0549d92a7f252130e79 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 19 Feb 2016 09:44:09 +0100 Subject: soc: mediatek: PMIC wrap: WRAP_INT_EN needs a different bitmask for MT2701/7623 MT2701 and MT7623 use a different bitmask for PWRAP_INT_EN. Signed-off-by: John Crispin Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 22c89e96a731..9df113546160 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -371,6 +371,7 @@ struct pmic_wrapper_type { int *regs; enum pwrap_type type; u32 arb_en_all; + u32 int_en_all; int (*init_reg_clock)(struct pmic_wrapper *wrp); int (*init_soc_specific)(struct pmic_wrapper *wrp); }; @@ -825,6 +826,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = { .regs = mt8135_regs, .type = PWRAP_MT8135, .arb_en_all = 0x1ff, + .int_en_all = ~(BIT(31) | BIT(1)), .init_reg_clock = pwrap_mt8135_init_reg_clock, .init_soc_specific = pwrap_mt8135_init_soc_specific, }; @@ -833,6 +835,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = { .regs = mt8173_regs, .type = PWRAP_MT8173, .arb_en_all = 0x3f, + .int_en_all = ~(BIT(31) | BIT(1)), .init_reg_clock = pwrap_mt8173_init_reg_clock, .init_soc_specific = pwrap_mt8173_init_soc_specific, }; @@ -946,7 +949,7 @@ static int pwrap_probe(struct platform_device *pdev) PWRAP_WDT_SRC_MASK_NO_STAUPD : PWRAP_WDT_SRC_MASK_ALL; pwrap_writel(wrp, wdt_src, PWRAP_WDT_SRC_EN); pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); - pwrap_writel(wrp, ~((1 << 31) | (1 << 1)), PWRAP_INT_EN); + pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN); irq = platform_get_irq(pdev, 0); ret = devm_request_irq(wrp->dev, irq, pwrap_interrupt, IRQF_TRIGGER_HIGH, -- cgit v1.2.3 From 174f7b4ce15f9edd77caac67a82c686c54788485 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 19 Feb 2016 09:44:10 +0100 Subject: soc: mediatek: PMIC wrap: SPI_WRITE needs a different bitmask for MT2701/7623 Different SoCs will use different bitmask for the SPI_WRITE command. This patch defines the bitmask in the pmic_wrapper_type struct. This allows us to support new SoCs with a different bitmask to the one currently used. Signed-off-by: John Crispin Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 9df113546160..8ce1bad3b605 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -372,6 +372,7 @@ struct pmic_wrapper_type { enum pwrap_type type; u32 arb_en_all; u32 int_en_all; + u32 spi_w; int (*init_reg_clock)(struct pmic_wrapper *wrp); int (*init_soc_specific)(struct pmic_wrapper *wrp); }; @@ -511,15 +512,15 @@ static int pwrap_reset_spislave(struct pmic_wrapper *wrp) pwrap_writel(wrp, 1, PWRAP_MAN_EN); pwrap_writel(wrp, 0, PWRAP_DIO_EN); - pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_CSL, + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSL, PWRAP_MAN_CMD); - pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_OUTS, + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS, PWRAP_MAN_CMD); - pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_CSH, + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_CSH, PWRAP_MAN_CMD); for (i = 0; i < 4; i++) - pwrap_writel(wrp, PWRAP_MAN_CMD_SPI_WRITE | PWRAP_MAN_CMD_OP_OUTS, + pwrap_writel(wrp, wrp->master->spi_w | PWRAP_MAN_CMD_OP_OUTS, PWRAP_MAN_CMD); ret = pwrap_wait_for_state(wrp, pwrap_is_sync_idle); @@ -827,6 +828,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = { .type = PWRAP_MT8135, .arb_en_all = 0x1ff, .int_en_all = ~(BIT(31) | BIT(1)), + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, .init_reg_clock = pwrap_mt8135_init_reg_clock, .init_soc_specific = pwrap_mt8135_init_soc_specific, }; @@ -836,6 +838,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = { .type = PWRAP_MT8173, .arb_en_all = 0x3f, .int_en_all = ~(BIT(31) | BIT(1)), + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, .init_reg_clock = pwrap_mt8173_init_reg_clock, .init_soc_specific = pwrap_mt8173_init_soc_specific, }; -- cgit v1.2.3 From 95b25c589158d97fbc6d5504b434aef263798fa7 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 19 Feb 2016 09:44:11 +0100 Subject: soc: mediatek: PMIC wrap: move wdt_src into the pmic_wrapper_type struct Different SoCs will use different bitmask for the wdt_src. This patch defines the bitmask in the pmic_wrapper_type struct. This allows us to support new SoCs with a different bitmask to the one currently used. Signed-off-by: John Crispin Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 8ce1bad3b605..aa54df304449 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -373,6 +373,7 @@ struct pmic_wrapper_type { u32 arb_en_all; u32 int_en_all; u32 spi_w; + u32 wdt_src; int (*init_reg_clock)(struct pmic_wrapper *wrp); int (*init_soc_specific)(struct pmic_wrapper *wrp); }; @@ -829,6 +830,7 @@ static struct pmic_wrapper_type pwrap_mt8135 = { .arb_en_all = 0x1ff, .int_en_all = ~(BIT(31) | BIT(1)), .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, .init_reg_clock = pwrap_mt8135_init_reg_clock, .init_soc_specific = pwrap_mt8135_init_soc_specific, }; @@ -839,6 +841,7 @@ static struct pmic_wrapper_type pwrap_mt8173 = { .arb_en_all = 0x3f, .int_en_all = ~(BIT(31) | BIT(1)), .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_NO_STAUPD, .init_reg_clock = pwrap_mt8173_init_reg_clock, .init_soc_specific = pwrap_mt8173_init_soc_specific, }; @@ -858,7 +861,7 @@ MODULE_DEVICE_TABLE(of, of_pwrap_match_tbl); static int pwrap_probe(struct platform_device *pdev) { - int ret, irq, wdt_src; + int ret, irq; struct pmic_wrapper *wrp; struct device_node *np = pdev->dev.of_node; const struct of_device_id *of_id = @@ -948,9 +951,7 @@ static int pwrap_probe(struct platform_device *pdev) * Since STAUPD was not used on mt8173 platform, * so STAUPD of WDT_SRC which should be turned off */ - wdt_src = pwrap_is_mt8173(wrp) ? - PWRAP_WDT_SRC_MASK_NO_STAUPD : PWRAP_WDT_SRC_MASK_ALL; - pwrap_writel(wrp, wdt_src, PWRAP_WDT_SRC_EN); + pwrap_writel(wrp, wrp->master->wdt_src, PWRAP_WDT_SRC_EN); pwrap_writel(wrp, 0x1, PWRAP_TIMER_EN); pwrap_writel(wrp, wrp->master->int_en_all, PWRAP_INT_EN); -- cgit v1.2.3 From 25269cefb691d324a3fe2be4d2a7b81f6a733996 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Fri, 19 Feb 2016 09:44:12 +0100 Subject: soc: mediatek: PMIC wrap: remove pwrap_is_mt8135() and pwrap_is_mt8173() With more SoCs being added the list of helper functions like these would grow. To mitigate this problem we remove the existing helpers and change the code to test against the pmic type stored inside the pmic specific datastructure that our context structure points at. There is one usage of pwrap_is_mt8135() that is ambiguous as the test should not be dependent on mt8135, but rather on the existence of a bridge. Add a new element to pmic_wrapper_type to indicate if a bridge is present and use this where appropriate. Signed-off-by: John Crispin Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) (limited to 'drivers/soc') diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index aa54df304449..a2bacda5a65d 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -374,20 +37