From a9beb0a21c8b740ab611c4385e2c59f5911a4da6 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 28 Aug 2017 00:33:23 +0200 Subject: [PATCH 01/73] dt-bindings: add power-domain header for RK3188 SoCs Add rk3188 power-domains as described by the TRM. Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring --- include/dt-bindings/power/rk3188-power.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 include/dt-bindings/power/rk3188-power.h diff --git a/include/dt-bindings/power/rk3188-power.h b/include/dt-bindings/power/rk3188-power.h new file mode 100644 index 000000000000..93d23dfba33f --- /dev/null +++ b/include/dt-bindings/power/rk3188-power.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_POWER_RK3188_POWER_H__ +#define __DT_BINDINGS_POWER_RK3188_POWER_H__ + +/* VD_CORE */ +#define RK3188_PD_A9_0 0 +#define RK3188_PD_A9_1 1 +#define RK3188_PD_A9_2 2 +#define RK3188_PD_A9_3 3 +#define RK3188_PD_DBG 4 +#define RK3188_PD_SCU 5 + +/* VD_LOGIC */ +#define RK3188_PD_VIDEO 6 +#define RK3188_PD_VIO 7 +#define RK3188_PD_GPU 8 +#define RK3188_PD_PERI 9 +#define RK3188_PD_CPU 10 +#define RK3188_PD_ALIVE 11 + +/* VD_PMU */ +#define RK3188_PD_RTC 12 + +#endif From 2e99be2874484609ade7d80f688fa8c6dc42759b Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 28 Aug 2017 00:36:25 +0200 Subject: [PATCH 02/73] dt-bindings: add power-domain header for RK3066 SoCs Add rk3066 power-domains as described by the TRM. Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring --- include/dt-bindings/power/rk3066-power.h | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 include/dt-bindings/power/rk3066-power.h diff --git a/include/dt-bindings/power/rk3066-power.h b/include/dt-bindings/power/rk3066-power.h new file mode 100644 index 000000000000..acf9f310ac53 --- /dev/null +++ b/include/dt-bindings/power/rk3066-power.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_POWER_RK3066_POWER_H__ +#define __DT_BINDINGS_POWER_RK3066_POWER_H__ + +/* VD_CORE */ +#define RK3066_PD_A9_0 0 +#define RK3066_PD_A9_1 1 +#define RK3066_PD_DBG 4 +#define RK3066_PD_SCU 5 + +/* VD_LOGIC */ +#define RK3066_PD_VIDEO 6 +#define RK3066_PD_VIO 7 +#define RK3066_PD_GPU 8 +#define RK3066_PD_PERI 9 +#define RK3066_PD_CPU 10 +#define RK3066_PD_ALIVE 11 + +/* VD_PMU */ +#define RK3066_PD_RTC 12 + +#endif From a53e71cedf184054cec1097665faf0e9f8e5b090 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 15 Sep 2017 09:34:23 +0200 Subject: [PATCH 03/73] dt-bindings: add compatibles for rk3066/rk3188 power controllers Add the compatible values for the power-domain controllers found on rk3066 and rk3188. Signed-off-by: Heiko Stuebner Reviewed-by: Rob Herring --- .../devicetree/bindings/soc/rockchip/power_domain.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt index 5d49d0a2ff29..8304eceb62e4 100644 --- a/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt +++ b/Documentation/devicetree/bindings/soc/rockchip/power_domain.txt @@ -7,7 +7,9 @@ Required properties for power domain controller: - compatible: Should be one of the following. "rockchip,px30-power-controller" - for PX30 SoCs. "rockchip,rk3036-power-controller" - for RK3036 SoCs. + "rockchip,rk3066-power-controller" - for RK3066 SoCs. "rockchip,rk3128-power-controller" - for RK3128 SoCs. + "rockchip,rk3188-power-controller" - for RK3188 SoCs. "rockchip,rk3228-power-controller" - for RK3228 SoCs. "rockchip,rk3288-power-controller" - for RK3288 SoCs. "rockchip,rk3328-power-controller" - for RK3328 SoCs. @@ -23,7 +25,9 @@ Required properties for power domain sub nodes: - reg: index of the power domain, should use macros in: "include/dt-bindings/power/px30-power.h" - for PX30 type power domain. "include/dt-bindings/power/rk3036-power.h" - for RK3036 type power domain. + "include/dt-bindings/power/rk3066-power.h" - for RK3066 type power domain. "include/dt-bindings/power/rk3128-power.h" - for RK3128 type power domain. + "include/dt-bindings/power/rk3188-power.h" - for RK3188 type power domain. "include/dt-bindings/power/rk3228-power.h" - for RK3228 type power domain. "include/dt-bindings/power/rk3288-power.h" - for RK3288 type power domain. "include/dt-bindings/power/rk3328-power.h" - for RK3328 type power domain. From a0d5e7d4995f132d002ec4bf202555c109a0cd9a Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Mon, 28 Aug 2017 00:34:30 +0200 Subject: [PATCH 04/73] soc: rockchip: power-domain: add rk3188 powerdomains Add power-domains found on rk3188 socs. Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 6f86a726bb45..d227c2cde2b7 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -745,6 +746,14 @@ static const struct rockchip_domain_info rk3128_pm_domains[] = { [RK3128_PD_GPU] = DOMAIN_RK3288(1, 1, 3, false), }; +static const struct rockchip_domain_info rk3188_pm_domains[] = { + [RK3188_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false), + [RK3188_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false), + [RK3188_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false), + [RK3188_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false), + [RK3188_PD_CPU] = DOMAIN(5, 5, 1, 26, 31, false), +}; + static const struct rockchip_domain_info rk3228_pm_domains[] = { [RK3228_PD_CORE] = DOMAIN_RK3036(0, 0, 16, true), [RK3228_PD_MSCH] = DOMAIN_RK3036(1, 1, 17, true), @@ -857,6 +866,17 @@ static const struct rockchip_pmu_info rk3128_pmu = { .domain_info = rk3128_pm_domains, }; +static const struct rockchip_pmu_info rk3188_pmu = { + .pwr_offset = 0x08, + .status_offset = 0x0c, + .req_offset = 0x38, /* PMU_MISC_CON1 */ + .idle_offset = 0x0c, + .ack_offset = 0x0c, + + .num_domains = ARRAY_SIZE(rk3188_pm_domains), + .domain_info = rk3188_pm_domains, +}; + static const struct rockchip_pmu_info rk3228_pmu = { .req_offset = 0x40c, .idle_offset = 0x488, @@ -952,6 +972,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { .compatible = "rockchip,rk3128-power-controller", .data = (void *)&rk3128_pmu, }, + { + .compatible = "rockchip,rk3188-power-controller", + .data = (void *)&rk3188_pmu, + }, { .compatible = "rockchip,rk3228-power-controller", .data = (void *)&rk3228_pmu, From fb14ada11d62fb849fc357a25ef8016ba438ba10 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 27 Sep 2018 12:27:11 -0700 Subject: [PATCH 05/73] soc: bcm: brcmstb: Fix re-entry point with a THUMB2_KERNEL When the kernel is built with CONFIG_THUMB2_KERNEL we would set the kernel's resume entry point to be a function that is already built as Thumb-2 code while the boot agent doing the resume is in ARM mode, so this does not work. There is a header label defined: cpu_resume_arm which we can use to do the switching for us. Fixes: 0b741b8234c8 ("soc: bcm: brcmstb: Add support for S2/S3/S5 suspend states (ARM)") Signed-off-by: Florian Fainelli --- drivers/soc/bcm/brcmstb/pm/pm-arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c index a5577dd5eb08..8ee06347447c 100644 --- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c +++ b/drivers/soc/bcm/brcmstb/pm/pm-arm.c @@ -404,7 +404,7 @@ noinline int brcmstb_pm_s3_finish(void) { struct brcmstb_s3_params *params = ctrl.s3_params; dma_addr_t params_pa = ctrl.s3_params_pa; - phys_addr_t reentry = virt_to_phys(&cpu_resume); + phys_addr_t reentry = virt_to_phys(&cpu_resume_arm); enum bsp_initiate_command cmd; u32 flags; From 0810d5cc29a1e4bb9e738a478b746aebf8dc1931 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sun, 21 Oct 2018 21:59:58 +0200 Subject: [PATCH 06/73] bus: brcmstb_gisb: simplify getting .driver_data We should get 'driver_data' from 'struct device' directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Signed-off-by: Florian Fainelli --- drivers/bus/brcmstb_gisb.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index 68ac3e93b600..f58ff67e97ac 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -150,8 +150,7 @@ static ssize_t gisb_arb_get_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); u32 timeout; mutex_lock(&gdev->lock); @@ -165,8 +164,7 @@ static ssize_t gisb_arb_set_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct platform_device *pdev = to_platform_device(dev); - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); int val, ret; ret = kstrtoint(buf, 10, &val); @@ -418,8 +416,7 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int brcmstb_gisb_arb_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); gdev->saved_timeout = gisb_read(gdev, ARB_TIMER); @@ -431,8 +428,7 @@ static int brcmstb_gisb_arb_suspend(struct device *dev) */ static int brcmstb_gisb_arb_resume_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev); + struct brcmstb_gisb_arb_device *gdev = dev_get_drvdata(dev); gisb_write(gdev, gdev->saved_timeout, ARB_TIMER); From 24869610e867e9791f0fdab70ff60f246299b859 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Tue, 23 Oct 2018 12:38:18 +0200 Subject: [PATCH 07/73] soc: rockchip: power-domain: add rk3066 powerdomains Add power-domains found on rk3066 socs. Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index d227c2cde2b7..847c7c482b26 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -738,6 +739,14 @@ static const struct rockchip_domain_info rk3036_pm_domains[] = { [RK3036_PD_SYS] = DOMAIN_RK3036(8, 22, 29, false), }; +static const struct rockchip_domain_info rk3066_pm_domains[] = { + [RK3066_PD_GPU] = DOMAIN(9, 9, 3, 24, 29, false), + [RK3066_PD_VIDEO] = DOMAIN(8, 8, 4, 23, 28, false), + [RK3066_PD_VIO] = DOMAIN(7, 7, 5, 22, 27, false), + [RK3066_PD_PERI] = DOMAIN(6, 6, 2, 25, 30, false), + [RK3066_PD_CPU] = DOMAIN(-1, 5, 1, 26, 31, false), +}; + static const struct rockchip_domain_info rk3128_pm_domains[] = { [RK3128_PD_CORE] = DOMAIN_RK3288(0, 0, 4, false), [RK3128_PD_MSCH] = DOMAIN_RK3288(-1, -1, 6, true), @@ -855,6 +864,17 @@ static const struct rockchip_pmu_info rk3036_pmu = { .domain_info = rk3036_pm_domains, }; +static const struct rockchip_pmu_info rk3066_pmu = { + .pwr_offset = 0x08, + .status_offset = 0x0c, + .req_offset = 0x38, /* PMU_MISC_CON1 */ + .idle_offset = 0x0c, + .ack_offset = 0x0c, + + .num_domains = ARRAY_SIZE(rk3066_pm_domains), + .domain_info = rk3066_pm_domains, +}; + static const struct rockchip_pmu_info rk3128_pmu = { .pwr_offset = 0x04, .status_offset = 0x08, @@ -968,6 +988,10 @@ static const struct of_device_id rockchip_pm_domain_dt_match[] = { .compatible = "rockchip,rk3036-power-controller", .data = (void *)&rk3036_pmu, }, + { + .compatible = "rockchip,rk3066-power-controller", + .data = (void *)&rk3066_pmu, + }, { .compatible = "rockchip,rk3128-power-controller", .data = (void *)&rk3128_pmu, From d78b5bde0ffc33d20f014b3ad4d7aaac8b79d34e Mon Sep 17 00:00:00 2001 From: Timo Alho Date: Mon, 22 Oct 2018 16:19:36 +0300 Subject: [PATCH 08/73] firmware: tegra: Add helper to check for supported MRQs Add a helper function to check that firmware is supporting a given MRQ command. Signed-off-by: Timo Alho Acked-by: Sivaram Nair Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/firmware/tegra/bpmp.c | 25 +++++++++++++++++++++++++ include/soc/tegra/bpmp.h | 7 +++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index a3d5b518c10e..90c6089fed84 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -470,6 +470,31 @@ unlock: } EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); +bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) +{ + struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; + struct mrq_query_abi_response resp; + struct tegra_bpmp_message msg = { + .mrq = MRQ_QUERY_ABI, + .tx = { + .data = &req, + .size = sizeof(req), + }, + .rx = { + .data = &resp, + .size = sizeof(resp), + }, + }; + int ret; + + ret = tegra_bpmp_transfer(bpmp, &msg); + if (ret || msg.rx.ret) + return false; + + return resp.status == 0; +} +EXPORT_SYMBOL_GPL(tegra_bpmp_mrq_is_supported); + static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, struct tegra_bpmp_channel *channel, void *data) diff --git a/include/soc/tegra/bpmp.h b/include/soc/tegra/bpmp.h index e69e4c4d80ae..b02f926a0216 100644 --- a/include/soc/tegra/bpmp.h +++ b/include/soc/tegra/bpmp.h @@ -129,6 +129,7 @@ int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, tegra_bpmp_mrq_handler_t handler, void *data); void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, void *data); +bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq); #else static inline struct tegra_bpmp *tegra_bpmp_get(struct device *dev) { @@ -164,6 +165,12 @@ static inline void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, void *data) { } + +static inline bool tegra_bpmp_mrq_is_supported(struct tegra_bpmp *bpmp, + unsigned int mrq) +{ + return false; +} #endif #if IS_ENABLED(CONFIG_CLK_TEGRA_BPMP) From 43dc7485807a8ffde12e242e557a1992478de4de Mon Sep 17 00:00:00 2001 From: Timo Alho Date: Mon, 22 Oct 2018 16:19:37 +0300 Subject: [PATCH 09/73] firmware: tegra: Switch to global mrq_is_supported() Patch "firmware: tegra: add helper to check for supported MRQs" added an API to check if MRQ is supported. Remove the implementation from bpmp debugfs code in favor of that. Signed-off-by: Timo Alho Acked-by: Sivaram Nair Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/firmware/tegra/bpmp-debugfs.c | 29 +-------------------------- 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/drivers/firmware/tegra/bpmp-debugfs.c b/drivers/firmware/tegra/bpmp-debugfs.c index f7f6a0a5cb07..a84df1a8ca2b 100644 --- a/drivers/firmware/tegra/bpmp-debugfs.c +++ b/drivers/firmware/tegra/bpmp-debugfs.c @@ -379,33 +379,6 @@ static int create_debugfs_mirror(struct tegra_bpmp *bpmp, void *buf, return err; } -static int mrq_is_supported(struct tegra_bpmp *bpmp, unsigned int mrq) -{ - struct mrq_query_abi_request req = { .mrq = cpu_to_le32(mrq) }; - struct mrq_query_abi_response resp; - struct tegra_bpmp_message msg = { - .mrq = MRQ_QUERY_ABI, - .tx = { - .data = &req, - .size = sizeof(req), - }, - .rx = { - .data = &resp, - .size = sizeof(resp), - }, - }; - int ret; - - ret = tegra_bpmp_transfer(bpmp, &msg); - if (ret < 0) { - /* something went wrong; assume not supported */ - dev_warn(bpmp->dev, "tegra_bpmp_transfer failed (%d)\n", ret); - return 0; - } - - return resp.status ? 0 : 1; -} - int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) { dma_addr_t phys; @@ -415,7 +388,7 @@ int tegra_bpmp_init_debugfs(struct tegra_bpmp *bpmp) int ret; struct dentry *root; - if (!mrq_is_supported(bpmp, MRQ_DEBUGFS)) + if (!tegra_bpmp_mrq_is_supported(bpmp, MRQ_DEBUGFS)) return 0; root = debugfs_create_dir("bpmp", NULL); From 2b86c11b99d3fc4e82af65c5b00b4334a6dfe6c9 Mon Sep 17 00:00:00 2001 From: Timo Alho Date: Mon, 22 Oct 2018 16:19:38 +0300 Subject: [PATCH 10/73] firmware: tegra: Print version tag at full Last two characters of the version tag that is 32 bytes long were stripped out. Signed-off-by: Timo Alho Acked-by: Sivaram Nair Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/firmware/tegra/bpmp.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 90c6089fed84..191f8a91c466 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -28,6 +28,7 @@ #define MSG_ACK BIT(0) #define MSG_RING BIT(1) +#define TAG_SZ 32 static inline struct tegra_bpmp * mbox_client_to_bpmp(struct mbox_client *client) @@ -556,7 +557,10 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, void *virt; int err; - virt = dma_alloc_coherent(bpmp->dev, MSG_DATA_MIN_SZ, &phys, + if (size != TAG_SZ) + return -EINVAL; + + virt = dma_alloc_coherent(bpmp->dev, TAG_SZ, &phys, GFP_KERNEL | GFP_DMA32); if (!virt) return -ENOMEM; @@ -574,9 +578,9 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, local_irq_restore(flags); if (err == 0) - strlcpy(tag, virt, size); + memcpy(tag, virt, TAG_SZ); - dma_free_coherent(bpmp->dev, MSG_DATA_MIN_SZ, virt, phys); + dma_free_coherent(bpmp->dev, TAG_SZ, virt, phys); return err; } @@ -689,7 +693,7 @@ static int tegra_bpmp_probe(struct platform_device *pdev) { struct tegra_bpmp *bpmp; unsigned int i; - char tag[32]; + char tag[TAG_SZ]; size_t size; int err; @@ -817,13 +821,13 @@ static int tegra_bpmp_probe(struct platform_device *pdev) goto free_mrq; } - err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag) - 1); + err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag)); if (err < 0) { dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err); goto free_mrq; } - dev_info(&pdev->dev, "firmware: %s\n", tag); + dev_info(&pdev->dev, "firmware: %.*s\n", (int)sizeof(tag), tag); platform_set_drvdata(pdev, bpmp); From 4bef358c9071748aa3e55f70f3ba5abc6363fcfe Mon Sep 17 00:00:00 2001 From: Timo Alho Date: Mon, 22 Oct 2018 16:19:39 +0300 Subject: [PATCH 11/73] soc/tegra: bpmp: Update ABI header Update the firmware header file to a more recent version. The major changes in the new version are: * add a new MRQ for firmware version query ABI and deprecates the old * add ABI to query Tegra194 CPU frequency limits * add ABI to control subset of PCIE UPHY state The new header contains also some editorial changes to the documentation. Signed-off-by: Timo Alho Acked-by: Sivaram Nair Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- include/soc/tegra/bpmp-abi.h | 1192 +++++++++++++++++++++++++++------- 1 file changed, 949 insertions(+), 243 deletions(-) diff --git a/include/soc/tegra/bpmp-abi.h b/include/soc/tegra/bpmp-abi.h index 98d8d38b99a1..ab7f8796a260 100644 --- a/include/soc/tegra/bpmp-abi.h +++ b/include/soc/tegra/bpmp-abi.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -40,7 +40,6 @@ * @file */ - /** * @defgroup MRQ MRQ Messages * @brief Messages sent to/from BPMP via IPC @@ -53,7 +52,7 @@ */ /** - * @addtogroup MRQ_Format Message Format + * @addtogroup MRQ_Format * @{ * The CPU requests the BPMP to perform a particular service by * sending it an IVC frame containing a single MRQ message. An MRQ @@ -76,7 +75,7 @@ /** * @ingroup MRQ_Format - * @brief header for an MRQ message + * @brief Header for an MRQ message * * Provides the MRQ number for the MRQ message: #mrq. The remainder of * the MRQ message is a payload (immediately following the @@ -86,7 +85,7 @@ struct mrq_request { /** @brief MRQ number of the request */ uint32_t mrq; /** - * @brief flags providing follow up directions to the receiver + * @brief Flags providing follow up directions to the receiver * * | Bit | Description | * |-----|--------------------------------------------| @@ -98,7 +97,7 @@ struct mrq_request { /** * @ingroup MRQ_Format - * @brief header for an MRQ response + * @brief Header for an MRQ response * * Provides an error code for the associated MRQ message. The * remainder of the MRQ response is a payload (immediately following @@ -106,9 +105,9 @@ struct mrq_request { * mrq_request::mrq */ struct mrq_response { - /** @brief error code for the MRQ request itself */ + /** @brief Error code for the MRQ request itself */ int32_t err; - /** @brief reserved for future use */ + /** @brief Reserved for future use */ uint32_t flags; } __ABI_PACKED; @@ -152,6 +151,14 @@ struct mrq_response { #define MRQ_TRACE_ITER 64 #define MRQ_RINGBUF_CONSOLE 65 #define MRQ_PG 66 +#define MRQ_CPU_NDIV_LIMITS 67 +#define MRQ_STRAP 68 +#define MRQ_UPHY 69 +#define MRQ_CPU_AUTO_CC3 70 +#define MRQ_QUERY_FW_TAG 71 +#define MRQ_FMON 72 +#define MRQ_EC 73 +#define MRQ_FBVOLT_STATUS 74 /** @} */ @@ -160,31 +167,35 @@ struct mrq_response { * @brief Maximum MRQ code to be sent by CPU software to * BPMP. Subject to change in future */ -#define MAX_CPU_MRQ_ID 66 +#define MAX_CPU_MRQ_ID 74 /** - * @addtogroup MRQ_Payloads Message Payloads + * @addtogroup MRQ_Payloads * @{ - * @defgroup Ping + * @defgroup Ping Ping * @defgroup Query_Tag Query Tag * @defgroup Module Loadable Modules - * @defgroup Trace - * @defgroup Debugfs - * @defgroup Reset - * @defgroup I2C - * @defgroup Clocks + * @defgroup Trace Trace + * @defgroup Debugfs Debug File System + * @defgroup Reset Reset + * @defgroup I2C I2C + * @defgroup Clocks Clocks * @defgroup ABI_info ABI Info - * @defgroup MC_Flush MC Flush - * @defgroup Powergating - * @defgroup Thermal + * @defgroup Powergating Power Gating + * @defgroup Thermal Thermal * @defgroup Vhint CPU Voltage hint - * @defgroup MRQ_Deprecated Deprecated MRQ messages - * @defgroup EMC - * @defgroup RingbufConsole + * @defgroup EMC EMC + * @defgroup CPU NDIV Limits + * @defgroup RingbufConsole Ring Buffer Console + * @defgroup Strap Straps + * @defgroup UPHY UPHY + * @defgroup CC3 Auto-CC3 + * @defgroup FMON FMON + * @defgroup EC EC + * @defgroup Fbvolt_status Fuse Burn Voltage Status * @} */ - /** * @ingroup MRQ_Codes * @def MRQ_PING @@ -214,20 +225,20 @@ struct mrq_response { /** * @ingroup Ping - * @brief request with #MRQ_PING + * @brief Request with #MRQ_PING * * Used by the sender of an #MRQ_PING message to request a pong from * recipient. The response from the recipient is computed based on * #challenge. */ struct mrq_ping_request { -/** @brief arbitrarily chosen value */ +/** @brief Arbitrarily chosen value */ uint32_t challenge; } __ABI_PACKED; /** * @ingroup Ping - * @brief response to #MRQ_PING + * @brief Response to #MRQ_PING * * Sent in response to an #MRQ_PING message. #reply should be the * mrq_ping_request challenge left shifted by 1 with the carry-bit @@ -235,14 +246,16 @@ struct mrq_ping_request { * */ struct mrq_ping_response { - /** @brief response to the MRQ_PING challege */ + /** @brief Response to the MRQ_PING challege */ uint32_t reply; } __ABI_PACKED; /** * @ingroup MRQ_Codes * @def MRQ_QUERY_TAG - * @brief Query BPMP firmware's tag (i.e. version information) + * @brief Query BPMP firmware's tag (i.e. unique identifer) + * + * @deprecated Use #MRQ_QUERY_FW_TAG instead. * * * Platforms: All * * Initiators: CCPLEX @@ -254,25 +267,50 @@ struct mrq_ping_response { /** * @ingroup Query_Tag - * @brief request with #MRQ_QUERY_TAG + * @brief Request with #MRQ_QUERY_TAG * - * Used by #MRQ_QUERY_TAG call to ask BPMP to fill in the memory - * pointed by #addr with BPMP firmware header. - * - * The sender is reponsible for ensuring that #addr is mapped in to - * the recipient's address map. + * @deprecated This structure will be removed in future version. + * Use MRQ_QUERY_FW_TAG instead. */ struct mrq_query_tag_request { - /** @brief base address to store the firmware header */ + /** @brief Base address to store the firmware tag */ uint32_t addr; } __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_QUERY_FW_TAG + * @brief Query BPMP firmware's tag (i.e. unique identifier) + * + * * Platforms: All + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: N/A + * * Response Payload: @ref mrq_query_fw_tag_response + * + */ + +/** + * @ingroup Query_Tag + * @brief Response to #MRQ_QUERY_FW_TAG + * + * Sent in response to #MRQ_QUERY_FW_TAG message. #tag contains the unique + * identifier for the version of firmware issuing the reply. + * + */ +struct mrq_query_fw_tag_response { + /** @brief Array to store tag information */ + uint8_t tag[32]; +} __ABI_PACKED; + /** * @ingroup MRQ_Codes * @def MRQ_MODULE_LOAD - * @brief dynamically load a BPMP code module + * @brief Dynamically load a BPMP code module * - * * Platforms: All + * * Platforms: T210, T214, T186 + * @cond (bpmp_t210 || bpmp_t214 || bpmp_t186) * * Initiators: CCPLEX * * Targets: BPMP * * Request Payload: @ref mrq_module_load_request @@ -284,7 +322,7 @@ struct mrq_query_tag_request { /** * @ingroup Module - * @brief request with #MRQ_MODULE_LOAD + * @brief Request with #MRQ_MODULE_LOAD * * Used by #MRQ_MODULE_LOAD calls to ask the recipient to dynamically * load the code located at #phys_addr and having size #size @@ -300,29 +338,31 @@ struct mrq_query_tag_request { * */ struct mrq_module_load_request { - /** @brief base address of the code to load. Treated as (void *) */ + /** @brief Base address of the code to load. Treated as (void *) */ uint32_t phys_addr; /* (void *) */ - /** @brief size in bytes of code to load */ + /** @brief Size in bytes of code to load */ uint32_t size; } __ABI_PACKED; /** * @ingroup Module - * @brief response to #MRQ_MODULE_LOAD + * @brief Response to #MRQ_MODULE_LOAD * * @todo document mrq_response::err */ struct mrq_module_load_response { - /** @brief handle to the loaded module */ + /** @brief Handle to the loaded module */ uint32_t base; } __ABI_PACKED; +/** @endcond*/ /** * @ingroup MRQ_Codes * @def MRQ_MODULE_UNLOAD - * @brief unload a previously loaded code module + * @brief Unload a previously loaded code module * - * * Platforms: All + * * Platforms: T210, T214, T186 + * @cond (bpmp_t210 || bpmp_t214 || bpmp_t186) * * Initiators: CCPLEX * * Targets: BPMP * * Request Payload: @ref mrq_module_unload_request @@ -333,20 +373,21 @@ struct mrq_module_load_response { /** * @ingroup Module - * @brief request with #MRQ_MODULE_UNLOAD + * @brief Request with #MRQ_MODULE_UNLOAD * * Used by #MRQ_MODULE_UNLOAD calls to request that a previously loaded * module be unloaded. */ struct mrq_module_unload_request { - /** @brief handle of the module to unload */ + /** @brief Handle of the module to unload */ uint32_t base; } __ABI_PACKED; +/** @endcond*/ /** * @ingroup MRQ_Codes * @def MRQ_TRACE_MODIFY - * @brief modify the set of enabled trace events + * @brief Modify the set of enabled trace events * * * Platforms: All * * Initiators: CCPLEX @@ -359,22 +400,22 @@ struct mrq_module_unload_request { /** * @ingroup Trace - * @brief request with #MRQ_TRACE_MODIFY + * @brief Request with #MRQ_TRACE_MODIFY * * Used by %MRQ_TRACE_MODIFY calls to enable or disable specify trace * events. #set takes precedence for any bit set in both #set and * #clr. */ struct mrq_trace_modify_request { - /** @brief bit mask of trace events to disable */ + /** @brief Bit mask of trace events to disable */ uint32_t clr; - /** @brief bit mask of trace events to enable */ + /** @brief Bit mask of trace events to enable */ uint32_t set; } __ABI_PACKED; /** * @ingroup Trace - * @brief response to #MRQ_TRACE_MODIFY + * @brief Response to #MRQ_TRACE_MODIFY * * Sent in repsonse to an #MRQ_TRACE_MODIFY message. #mask reflects the * state of which events are enabled after the recipient acted on the @@ -382,7 +423,7 @@ struct mrq_trace_modify_request { * */ struct mrq_trace_modify_response { - /** @brief bit mask of trace event enable states */ + /** @brief Bit mask of trace event enable states */ uint32_t mask; } __ABI_PACKED; @@ -407,7 +448,7 @@ struct mrq_trace_modify_response { /** * @ingroup Trace - * @brief request with #MRQ_WRITE_TRACE + * @brief Request with #MRQ_WRITE_TRACE * * Used by MRQ_WRITE_TRACE calls to ask the recipient to copy trace * data from the recipient's local buffer to the output buffer. #area @@ -420,22 +461,22 @@ struct mrq_trace_modify_response { * overwrites. */ struct mrq_write_trace_request { - /** @brief base address of output buffer */ + /** @brief Base address of output buffer */ uint32_t area; - /** @brief size in bytes of the output buffer */ + /** @brief Size in bytes of the output buffer */ uint32_t size; } __ABI_PACKED; /** * @ingroup Trace - * @brief response to #MRQ_WRITE_TRACE + * @brief Response to #MRQ_WRITE_TRACE * * Once this response is sent, the respondent will not access the * output buffer further. */ struct mrq_write_trace_response { /** - * @brief flag whether more data remains in local buffer + * @brief Flag whether more data remains in local buffer * * Value is 1 if the entire local trace buffer has been * drained to the outputbuffer. Value is 0 otherwise. @@ -456,9 +497,10 @@ struct mrq_threaded_ping_response { /** * @ingroup MRQ_Codes * @def MRQ_MODULE_MAIL - * @brief send a message to a loadable module + * @brief Send a message to a loadable module * - * * Platforms: All + * * Platforms: T210, T214, T186 + * @cond (bpmp_t210 || bpmp_t214 || bpmp_t186) * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_module_mail_request @@ -469,12 +511,12 @@ struct mrq_threaded_ping_response { /** * @ingroup Module - * @brief request with #MRQ_MODULE_MAIL + * @brief Request with #MRQ_MODULE_MAIL */ struct mrq_module_mail_request { - /** @brief handle to the previously loaded module */ + /** @brief Handle to the previously loaded module */ uint32_t base; - /** @brief module-specific mail payload + /** @brief Module-specific mail payload * * The length of data[ ] is unknown to the BPMP core firmware * but it is limited to the size of an IPC message. @@ -484,23 +526,24 @@ struct mrq_module_mail_request { /** * @ingroup Module - * @brief response to #MRQ_MODULE_MAIL + * @brief Response to #MRQ_MODULE_MAIL */ struct mrq_module_mail_response { - /** @brief module-specific mail payload + /** @brief Module-specific mail payload * * The length of data[ ] is unknown to the BPMP core firmware * but it is limited to the size of an IPC message. */ uint8_t data[EMPTY_ARRAY]; } __ABI_PACKED; +/** @endcond */ /** * @ingroup MRQ_Codes * @def MRQ_DEBUGFS * @brief Interact with BPMP's debugfs file nodes * - * * Platforms: T186 + * * Platforms: T186, T194 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_debugfs_request @@ -529,65 +572,70 @@ struct mrq_module_mail_response { * * @} */ + /** @ingroup Debugfs */ enum mrq_debugfs_commands { + /** @brief Perform read */ CMD_DEBUGFS_READ = 1, + /** @brief Perform write */ CMD_DEBUGFS_WRITE = 2, + /** @brief Perform dumping directory */ CMD_DEBUGFS_DUMPDIR = 3, + /** @brief Not a command */ CMD_DEBUGFS_MAX }; /** * @ingroup Debugfs - * @brief parameters for CMD_DEBUGFS_READ/WRITE command + * @brief Parameters for CMD_DEBUGFS_READ/WRITE command */ struct cmd_debugfs_fileop_request { - /** @brief physical address pointing at filename */ + /** @brief Physical address pointing at filename */ uint32_t fnameaddr; - /** @brief length in bytes of filename buffer */ + /** @brief Length in bytes of filename buffer */ uint32_t fnamelen; - /** @brief physical address pointing to data buffer */ + /** @brief Physical address pointing to data buffer */ uint32_t dataaddr; - /** @brief length in bytes of data buffer */ + /** @brief Length in bytes of data buffer */ uint32_t datalen; } __ABI_PACKED; /** * @ingroup Debugfs - * @brief parameters for CMD_DEBUGFS_READ/WRITE command + * @brief Parameters for CMD_DEBUGFS_READ/WRITE command */ struct cmd_debugfs_dumpdir_request { - /** @brief physical address pointing to data buffer */ + /** @brief Physical address pointing to data buffer */ uint32_t dataaddr; - /** @brief length in bytes of data buffer */ + /** @brief Length in bytes of data buffer */ uint32_t datalen; } __ABI_PACKED; /** * @ingroup Debugfs - * @brief response data for CMD_DEBUGFS_READ/WRITE command + * @brief Response data for CMD_DEBUGFS_READ/WRITE command */ struct cmd_debugfs_fileop_response { - /** @brief always 0 */ + /** @brief Always 0 */ uint32_t reserved; - /** @brief number of bytes read from or written to data buffer */ + /** @brief Number of bytes read from or written to data buffer */ uint32_t nbytes; } __ABI_PACKED; /** * @ingroup Debugfs - * @brief response data for CMD_DEBUGFS_DUMPDIR command + * @brief Response data for CMD_DEBUGFS_DUMPDIR command */ struct cmd_debugfs_dumpdir_response { - /** @brief always 0 */ + /** @brief Always 0 */ uint32_t reserved; - /** @brief number of bytes read from or written to data buffer */ + /** @brief Number of bytes read from or written to data buffer */ uint32_t nbytes; } __ABI_PACKED; /** * @ingroup Debugfs - * @brief request with #MRQ_DEBUGFS. + * @brief Request with #MRQ_DEBUGFS. * * The sender of an MRQ_DEBUGFS message uses #cmd to specify a debugfs * command to execute. Legal commands are the values of @ref @@ -601,6 +649,7 @@ struct cmd_debugfs_dumpdir_response { * |CMD_DEBUGFS_DUMPDIR|dumpdir| */ struct mrq_debugfs_request { + /** @brief Sub-command (@ref mrq_debugfs_commands) */ uint32_t cmd; union { struct cmd_debugfs_fileop_request fop; @@ -612,14 +661,14 @@ struct mrq_debugfs_request { * @ingroup Debugfs */ struct mrq_debugfs_response { - /** @brief always 0 */ + /** @brief Always 0 */ int32_t reserved; union { - /** @brief response data for CMD_DEBUGFS_READ OR + /** @brief Response data for CMD_DEBUGFS_READ OR * CMD_DEBUGFS_WRITE command */ struct cmd_debugfs_fileop_response fop; - /** @brief response data for CMD_DEBUGFS_DUMPDIR command */ + /** @brief Response data for CMD_DEBUGFS_DUMPDIR command */ struct cmd_debugfs_dumpdir_response dumpdir; } __UNION_ANON; } __ABI_PACKED; @@ -633,57 +682,58 @@ struct mrq_debugfs_response { #define DEBUGFS_S_IWUSR (1 << 7) /** @} */ - /** * @ingroup MRQ_Codes * @def MRQ_RESET - * @brief reset an IP block + * @brief Reset an IP block * - * * Platforms: T186 + * * Platforms: T186, T194 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_reset_request * * Response Payload: @ref mrq_reset_response + * + * @addtogroup Reset + * @{ */ -/** - * @ingroup Reset - */ enum mrq_reset_commands { + /** @brief Assert module reset */ CMD_RESET_ASSERT = 1, + /** @brief Deassert module reset */ CMD_RESET_DEASSERT = 2, + /** @brief Assert and deassert the module reset */ CMD_RESET_MODULE = 3, + /** @brief Get the highest reset ID */ CMD_RESET_GET_MAX_ID = 4, - CMD_RESET_MAX, /* not part of ABI and subject to change */ + /** @brief Not part of ABI and subject to change */ + CMD_RESET_MAX, }; /** - * @ingroup Reset - * @brief request with MRQ_RESET + * @brief Request with MRQ_RESET * * Used by the sender of an #MRQ_RESET message to request BPMP to * assert or or deassert a given reset line. */ struct mrq_reset_request { - /** @brief reset action to perform (@enum mrq_reset_commands) */ + /** @brief Reset action to perform (@ref mrq_reset_commands) */ uint32_t cmd; - /** @brief id of the reset to affected */ + /** @brief Id of the reset to affected */ uint32_t reset_id; } __ABI_PACKED; /** - * @ingroup Reset * @brief Response for MRQ_RESET sub-command CMD_RESET_GET_MAX_ID. When * this sub-command is not supported, firmware will return -BPMP_EBADCMD * in mrq_response::err. */ struct cmd_reset_get_max_id_response { - /** @brief max reset id */ + /** @brief Max reset id */ uint32_t max_id; } __ABI_PACKED; /** - * @ingroup Reset * @brief Response with MRQ_RESET * * Each sub-command supported by @ref mrq_reset_request may return @@ -703,32 +753,25 @@ struct mrq_reset_response { } __UNION_ANON; } __ABI_PACKED; +/** @} */ + /** * @ingroup MRQ_Codes * @def MRQ_I2C - * @brief issue an i2c transaction + * @brief Issue an i2c transaction * - * * Platforms: T186 + * * Platforms: T186, T194 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_i2c_request * * Response Payload: @ref mrq_i2c_response - */ - -/** + * * @addtogroup I2C * @{ */ #define TEGRA_I2C_IPC_MAX_IN_BUF_SIZE (MSG_DATA_MIN_SZ - 12) #define TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE (MSG_DATA_MIN_SZ - 4) -/** @} */ -/** - * @ingroup I2C - * @name Serial I2C flags - * Use these flags with serial_i2c_request::flags - * @{ - */ #define SERIALI2C_TEN 0x0010 #define SERIALI2C_RD 0x0001 #define SERIALI2C_STOP 0x8000 @@ -737,15 +780,13 @@ struct mrq_reset_response { #define SERIALI2C_IGNORE_NAK 0x1000 #define SERIALI2C_NO_RD_ACK 0x0800 #define SERIALI2C_RECV_LEN 0x0400 -/** @} */ -/** @ingroup I2C */ + enum { CMD_I2C_XFER = 1 }; /** - * @ingroup I2C - * @brief serializable i2c request + * @brief Serializable i2c request * * Instances of this structure are packed (little-endian) into * cmd_i2c_xfer_request::data_buf. Each instance represents a single @@ -762,80 +803,75 @@ enum { struct serial_i2c_request { /** @brief I2C slave address */ uint16_t addr; - /** @brief bitmask of SERIALI2C_ flags */ + /** @brief Bitmask of SERIALI2C_ flags */ uint16_t flags; - /** @brief length of I2C transaction in bytes */ + /** @brief Length of I2C transaction in bytes */ uint16_t len; - /** @brief for write transactions only, #len bytes of data */ + /** @brief For write transactions only, #len bytes of data */ uint8_t data[]; } __ABI_PACKED; /** - * @ingroup I2C - * @brief trigger one or more i2c transactions + * @brief Trigger one or more i2c transactions */ struct cmd_i2c_xfer_request { - /** @brief valid bus number from mach-t186/i2c-t186.h*/ + /** @brief Valid bus number from @ref bpmp_i2c_ids*/ uint32_t bus_id; - /** @brief count of valid bytes in #data_buf*/ + /** @brief Count of valid bytes in #data_buf*/ uint32_t data_size; - /** @brief serialized packed instances of @ref serial_i2c_request*/ + /** @brief Serialized packed instances of @ref serial_i2c_request*/ uint8_t data_buf[TEGRA_I2C_IPC_MAX_IN_BUF_SIZE]; } __ABI_PACKED; /** - * @ingroup I2C - * @brief container for data read from the i2c bus + * @brief Container for data read from the i2c bus * * Processing an cmd_i2c_xfer_request::data_buf causes BPMP to execute * zero or more I2C reads. The data read from the bus is serialized * into #data_buf. */ struct cmd_i2c_xfer_response { - /** @brief count of valid bytes in #data_buf*/ + /** @brief Count of valid bytes in #data_buf*/ uint32_t data_size; - /** @brief i2c read data */ + /** @brief I2c read data */ uint8_t data_buf[TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE]; } __ABI_PACKED; /** - * @ingroup I2C - * @brief request with #MRQ_I2C + * @brief Request with #MRQ_I2C */ struct mrq_i2c_request { - /** @brief always CMD_I2C_XFER (i.e. 1) */ + /** @brief Always CMD_I2C_XFER (i.e. 1) */ uint32_t cmd; - /** @brief parameters of the transfer request */ + /** @brief Parameters of the transfer request */ struct cmd_i2c_xfer_request xfer; } __ABI_PACKED; /** - * @ingroup I2C - * @brief response to #MRQ_I2C + * @brief Response to #MRQ_I2C */ struct mrq_i2c_response { struct cmd_i2c_xfer_response xfer; } __ABI_PACKED; +/** @} */ + /** * @ingroup MRQ_Codes * @def MRQ_CLK + * @brief Perform a clock operation * - * * Platforms: T186 + * * Platforms: T186, T194 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_clk_request * * Response Payload: @ref mrq_clk_response + * * @addtogroup Clocks * @{ */ - -/** - * @name MRQ_CLK sub-commands - * @{ - */ enum { CMD_CLK_GET_RATE = 1, CMD_CLK_SET_RATE = 2, @@ -847,20 +883,13 @@ enum { CMD_CLK_DISABLE = 8, CMD_CLK_GET_ALL_INFO = 14, CMD_CLK_GET_MAX_CLK_ID = 15, + CMD_CLK_GET_FMAX_AT_VMIN = 16, CMD_CLK_MAX, }; -/** @} */ -/** - * @name MRQ_CLK properties - * Flag bits for cmd_clk_properties_response::flags and - * cmd_clk_get_all_info_response::flags - * @{ - */ #define BPMP_CLK_HAS_MUX (1 << 0) #define BPMP_CLK_HAS_SET_RATE (1 << 1) #define BPMP_CLK_IS_ROOT (1 << 2) -/** @} */ #define MRQ_CLK_NAME_MAXLEN 40 #define MRQ_CLK_MAX_PARENTS 16 @@ -959,11 +988,19 @@ struct cmd_clk_get_max_clk_id_request { struct cmd_clk_get_max_clk_id_response { uint32_t max_id; } __ABI_PACKED; -/** @} */ + +/** @private */ +struct cmd_clk_get_fmax_at_vmin_request { + EMPTY +} __ABI_PACKED; + +struct cmd_clk_get_fmax_at_vmin_response { + int64_t rate; +} __ABI_PACKED; /** * @ingroup Clocks - * @brief request with #MRQ_CLK + * @brief Request with #MRQ_CLK * * Used by the sender of an #MRQ_CLK message to control clocks. The * clk_request is split into several sub-commands. Some sub-commands @@ -982,11 +1019,13 @@ struct cmd_clk_get_max_clk_id_response { * |CMD_CLK_DISABLE |- | * |CMD_CLK_GET_ALL_INFO |- | * |CMD_CLK_GET_MAX_CLK_ID |- | + * |CMD_CLK_GET_FMAX_AT_VMIN |- + * | * */ struct mrq_clk_request { - /** @brief sub-command and clock id concatenated to 32-bit word. + /** @brief Sub-command and clock id concatenated to 32-bit word. * - bits[31..24] is the sub-cmd. * - bits[23..0] is the clock id */ @@ -1010,12 +1049,14 @@ struct mrq_clk_request { struct cmd_clk_get_all_info_request clk_get_all_info; /** @private */ struct cmd_clk_get_max_clk_id_request clk_get_max_clk_id; + /** @private */ + struct cmd_clk_get_fmax_at_vmin_request clk_get_fmax_at_vmin; } __UNION_ANON; } __ABI_PACKED; /** * @ingroup Clocks - * @brief response to MRQ_CLK + * @brief Response to MRQ_CLK * * Each sub-command supported by @ref mrq_clk_request may return * sub-command-specific data. Some do and some do not as indicated in @@ -1033,6 +1074,7 @@ struct mrq_clk_request { * |CMD_CLK_DISABLE |- | * |CMD_CLK_GET_ALL_INFO |clk_get_all_info | * |CMD_CLK_GET_MAX_CLK_ID |clk_get_max_id | + * |CMD_CLK_GET_FMAX_AT_VMIN |clk_get_fmax_at_vmin | * */ @@ -1050,13 +1092,16 @@ struct mrq_clk_response { struct cmd_clk_is_enabled_response clk_is_enabled; struct cmd_clk_get_all_info_response clk_get_all_info; struct cmd_clk_get_max_clk_id_response clk_get_max_clk_id; + struct cmd_clk_get_fmax_at_vmin_response clk_get_fmax_at_vmin; } __UNION_ANON; } __ABI_PACKED; +/** @} */ + /** * @ingroup MRQ_Codes * @def MRQ_QUERY_ABI - * @brief check if an MRQ is implemented + * @brief Check if an MRQ is implemented * * * Platforms: All * * Initiators: Any @@ -1067,7 +1112,7 @@ struct mrq_clk_response { /** * @ingroup ABI_info - * @brief request with MRQ_QUERY_ABI + * @brief Request with MRQ_QUERY_ABI * * Used by #MRQ_QUERY_ABI call to check if MRQ code #mrq is supported * by the recipient. @@ -1079,7 +1124,7 @@ struct mrq_query_abi_request { /** * @ingroup ABI_info - * @brief response to MRQ_QUERY_ABI + * @brief Response to MRQ_QUERY_ABI * * @note mrq_response::err of 0 indicates that the query was * successful, not that the MRQ itself is supported! @@ -1092,19 +1137,19 @@ struct mrq_query_abi_response { /** * @ingroup MRQ_Codes * @def MRQ_PG_READ_STATE - * @brief read the power-gating state of a partition + * @brief Read the power-gating state of a partition * * * Platforms: T186 + * @cond bpmp_t186 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_pg_read_state_request * * Response Payload: @ref mrq_pg_read_state_response - * @addtogroup Powergating - * @{ */ /** - * @brief request with #MRQ_PG_READ_STATE + * @ingroup Powergating + * @brief Request with #MRQ_PG_READ_STATE * * Used by MRQ_PG_READ_STATE call to read the current state of a * partition. @@ -1115,39 +1160,40 @@ struct mrq_pg_read_state_request { } __ABI_PACKED; /** - * @brief response to MRQ_PG_READ_STATE + * @ingroup Powergating + * @brief Response to MRQ_PG_READ_STATE * @todo define possible errors. */ struct mrq_pg_read_state_response { - /** @brief read as don't care */ + /** @brief Read as don't care */ uint32_t sram_state; - /** @brief state of power partition + /** @brief State of power partition * * 0 : off * * 1 : on */ uint32_t logic_state; } __ABI_PACKED; - +/** @endcond*/ /** @} */ /** * @ingroup MRQ_Codes * @def MRQ_PG_UPDATE_STATE - * @brief modify the power-gating state of a partition. In contrast to + * @brief Modify the power-gating state of a partition. In contrast to * MRQ_PG calls, the operations that change state (on/off) of power * partition are reference counted. * * * Platforms: T186 + * @cond bpmp_t186 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_pg_update_state_request * * Response Payload: N/A - * @addtogroup Powergating - * @{ */ /** - * @brief request with mrq_pg_update_state_request + * @ingroup Powergating + * @brief Request with mrq_pg_update_state_request * * Used by #MRQ_PG_UPDATE_STATE call to request BPMP to change the * state of a power partition #partition_id. @@ -1155,20 +1201,20 @@ struct mrq_pg_read_state_response { struct mrq_pg_update_state_request { /** @brief ID of partition */ uint32_t partition_id; - /** @brief secondary control of power partition + /** @brief Secondary control of power partition * @details Ignored by many versions of the BPMP * firmware. For maximum compatibility, set the value - * according to @logic_state + * according to @ref logic_state * * 0x1: power ON partition (@ref logic_state == 0x3) * * 0x3: power OFF partition (@ref logic_state == 0x1) */ uint32_t sram_state; - /** @brief controls state of power partition, legal values are + /** @brief Controls state of power partition, legal values are * * 0x1 : power OFF partition * * 0x3 : power ON partition */ uint32_t logic_state; - /** @brief change state of clocks of the power partition, legal values + /** @brief Change state of clocks of the power partition, legal values * * 0x0 : do not change clock state * * 0x1 : disable partition clocks (only applicable when * @ref logic_state == 0x1) @@ -1177,7 +1223,7 @@ struct mrq_pg_update_state_request { */ uint32_t clock_state; } __ABI_PACKED; -/** @} */ +/** @endcond*/ /** * @ingroup MRQ_Codes @@ -1186,19 +1232,20 @@ struct mrq_pg_update_state_request { * MRQ_PG_UPDATE_STATE, operations that change the power partition * state are NOT reference counted * - * * Platforms: T186 + * @note BPMP-FW forcefully turns off some partitions as part of SC7 entry + * because their state cannot be adequately restored on exit. Therefore, + * it is recommended to power off all domains via MRQ_PG prior to SC7 entry. + * See @ref bpmp_pdomain_ids for further detail. + * + * * Platforms: T186, T194 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_pg_request * * Response Payload: @ref mrq_pg_response + * * @addtogroup Powergating * @{ */ - -/** - * @name MRQ_PG sub-commands - * @{ - */ enum mrq_pg_cmd { /** * @brief Check whether the BPMP driver supports the specified @@ -1232,7 +1279,7 @@ enum mrq_pg_cmd { CMD_PG_GET_STATE = 2, /** - * @brief get the name string of specified power domain id. + * @brief Get the name string of specified power domain id. * * mrq_response:err is * 0: Success @@ -1242,7 +1289,7 @@ enum mrq_pg_cmd { /** - * @brief get the highest power domain id in the system. Not + * @brief Get the highest power domain id in the system. Not * all IDs between 0 and max_id are valid IDs. * * mrq_response:err is @@ -1251,35 +1298,36 @@ enum mrq_pg_cmd { */ CMD_PG_GET_MAX_ID = 4, }; -/** @} */ #define MRQ_PG_NAME_MAXLEN 40 -/** - * @brief possible power domain states in - * cmd_pg_set_state_request:state and cmd_pg_get_state_response:state. - * PG_STATE_OFF: power domain is OFF - * PG_STATE_ON: power domain is ON - * PG_STATE_RUNNING: power domain is ON and made into directly usable - * state by turning on the clocks associated with - * the domain - */ enum pg_states { + /** @brief Power domain is OFF */ PG_STATE_OFF = 0, + /** @brief Power domain is ON */ PG_STATE_ON = 1, + /** + * @brief a legacy state where power domain and the clock + * associated to the domain are ON. + * This state is only supported in T186, and the use of it is + * deprecated. + */ PG_STATE_RUNNING = 2, }; struct cmd_pg_query_abi_request { - uint32_t type; /* enum mrq_pg_cmd */ + /** @ref mrq_pg_cmd */ + uint32_t type; } __ABI_PACKED; struct cmd_pg_set_state_request { - uint32_t state; /* enum pg_states */ + /** @ref pg_states */ + uint32_t state; } __ABI_PACKED; struct cmd_pg_get_state_response { - uint32_t state; /* enum pg_states */ + /** @ref pg_states */ + uint32_t state; } __ABI_PACKED; struct cmd_pg_get_name_response { @@ -1291,8 +1339,7 @@ struct cmd_pg_get_max_id_response { } __ABI_PACKED; /** - * @ingroup Powergating - * @brief request with #MRQ_PG + * @brief Request with #MRQ_PG * * Used by the sender of an #MRQ_PG message to control power * partitions. The pg_request is split into several sub-commands. Some @@ -1308,7 +1355,6 @@ struct cmd_pg_get_max_id_response { * |CMD_PG_GET_MAX_ID | - | * */ - struct mrq_pg_request { uint32_t cmd; uint32_t id; @@ -1319,8 +1365,7 @@ struct mrq_pg_request { } __ABI_PACKED; /** - * @ingroup Powergating - * @brief response to MRQ_PG + * @brief Response to MRQ_PG * * Each sub-command supported by @ref mrq_pg_request may return * sub-command-specific data. Some do and some do not as indicated in @@ -1333,9 +1378,7 @@ struct mrq_pg_request { * |CMD_PG_GET_STATE | get_state | * |CMD_PG_GET_NAME | get_name | * |CMD_PG_GET_MAX_ID | get_max_id | - * */ - struct mrq_pg_response { union { struct cmd_pg_get_state_response get_state; @@ -1344,12 +1387,14 @@ struct mrq_pg_response { } __UNION_ANON; } __ABI_PACKED; +/** @} */ + /** * @ingroup MRQ_Codes * @def MRQ_THERMAL - * @brief interact with BPMP thermal framework + * @brief Interact with BPMP thermal framework * - * * Platforms: T186 + * * Platforms: T186, T194 * * Initiators: Any * * Targets: Any * * Request Payload: TODO @@ -1562,17 +1607,18 @@ union mrq_thermal_bpmp_to_host_response { * @brief Query CPU voltage hint data * * * Platforms: T186 + * @cond bpmp_t186 * * Initiators: CCPLEX * * Targets: BPMP * * Request Payload: @ref mrq_cpu_vhint_request * * Response Payload: N/A * - * @addtogroup Vhint CPU Voltage hint + * @addtogroup Vhint * @{ */ /** - * @brief request with #MRQ_CPU_VHINT + * @brief Request with #MRQ_CPU_VHINT * * Used by #MRQ_CPU_VHINT call by CCPLEX to retrieve voltage hint data * from BPMP to memory space pointed by #addr. CCPLEX is responsible @@ -1581,16 +1627,16 @@ union mrq_thermal_bpmp_to_host_response { */ struct mrq_cpu_vhint_request { /** @brief IOVA address for the #cpu_vhint_data */ - uint32_t addr; /* struct cpu_vhint_data * */ + uint32_t addr; /** @brief ID of the cluster whose data is requested */ - uint32_t cluster_id; /* enum cluster_id */ + uint32_t cluster_id; } __ABI_PACKED; /** - * @brief description of the CPU v/f relation + * @brief Description of the CPU v/f relation * - * Used by #MRQ_CPU_VHINT call to carry data pointed by #addr of - * struct mrq_cpu_vhint_request + * Used by #MRQ_CPU_VHINT call to carry data pointed by + * #mrq_cpu_vhint_request::addr */ struct cpu_vhint_data { uint32_t ref_clk_hz; /**< reference frequency in Hz */ @@ -1612,7 +1658,7 @@ struct cpu_vhint_data { /** reserved for future use */ uint16_t reserved[328]; } __ABI_PACKED; - +/** @endcond */ /** @} */ /** @@ -1620,7 +1666,7 @@ struct cpu_vhint_data { * @def MRQ_ABI_RATCHET * @brief ABI ratchet value query * - * * Platforms: T186 + * * Platforms: T186, T194 * * Initiators: Any * * Targets: BPMP * * Request Payload: @ref mrq_abi_ratchet_request @@ -1630,7 +1676,7 @@ struct cpu_vhint_data { */ /** - * @brief an ABI compatibility mechanism + * @brief An ABI compatibility mechanism * * BPMP_ABI_RATCHET_VALUE may increase for various reasons in a future * revision of this header file. @@ -1644,7 +1690,7 @@ struct cpu_vhint_data { #define BPMP_ABI_RATCHET_VALUE 3 /** - * @brief request with #MRQ_ABI_RATCHET. + * @brief Request with #MRQ_ABI_RATCHET. * * #ratchet should be #BPMP_ABI_RATCHET_VALUE from the ABI header * against which the requester was compiled. @@ -1657,12 +1703,12 @@ struct cpu_vhint_data { * Otherwise, err shall be 0. */ struct mrq_abi_ratchet_request { - /** @brief requester's ratchet value */ + /** @brief Requester's ratchet value */ uint16_t ratchet; }; /** - * @brief response to #MRQ_ABI_RATCHET + * @brief Response to #MRQ_ABI_RATCHET * * #ratchet shall be #BPMP_ABI_RATCHET_VALUE from the ABI header * against which BPMP firwmare was compiled. @@ -1685,9 +1731,9 @@ struct mrq_abi_ratchet_response { /** * @ingroup MRQ_Codes * @def MRQ_EMC_DVFS_LATENCY - * @brief query frequency dependent EMC DVFS latency + * @brief Query frequency dependent EMC DVFS latency * - * * Platforms: T186 + * * Platforms: T186, T194 * * Initiators: CCPLEX * * Targets: BPMP * * Request Payload: N/A @@ -1697,7 +1743,7 @@ struct mrq_abi_ratchet_response { */ /** - * @brief used by @ref mrq_emc_dvfs_latency_response + * @brief Used by @ref mrq_emc_dvfs_latency_response */ struct emc_dvfs_latency { /** @brief EMC frequency in kHz */ @@ -1708,10 +1754,10 @@ struct emc_dvfs_latency { #define EMC_DVFS_LATENCY_MAX_SIZE 14 /** - * @brief response to #MRQ_EMC_DVFS_LATENCY + * @brief Response to #MRQ_EMC_DVFS_LATENCY */ struct mrq_emc_dvfs_latency_response { - /** @brief the number valid entries in #pairs */ + /** @brief The number valid entries in #pairs */ uint32_t num_pairs; /** @brief EMC information */ struct emc_dvfs_latency pairs[EMC_DVFS_LATENCY_MAX_SIZE]; @@ -1719,10 +1765,98 @@ struct mrq_emc_dvfs_latency_response { /** @} */ +/** + * @ingroup MRQ_Codes + * @def MRQ_CPU_NDIV_LIMITS + * @brief CPU freq. limits in ndiv + * + * * Platforms: T194 onwards + * @cond bpmp_t194 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_cpu_ndiv_limits_request + * * Response Payload: @ref mrq_cpu_ndiv_limits_response + * @addtogroup CPU + * @{ + */ + +/** + * @brief Request for ndiv limits of a cluster + */ +struct mrq_cpu_ndiv_limits_request { + /** @brief Enum cluster_id */ + uint32_t cluster_id; +} __ABI_PACKED; + +/** + * @brief Response to #MRQ_CPU_NDIV_LIMITS + */ +struct mrq_cpu_ndiv_limits_response { + /** @brief Reference frequency in Hz */ + uint32_t ref_clk_hz; + /** @brief Post divider value */ + uint16_t pdiv; + /** @brief Input divider value */ + uint16_t mdiv; + /** @brief FMAX expressed with max NDIV value */ + uint16_t ndiv_max; + /** @brief Minimum allowed NDIV value */ + uint16_t ndiv_min; +} __ABI_PACKED; + +/** @} */ +/** @endcond */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_CPU_AUTO_CC3 + * @brief Query CPU cluster auto-CC3 configuration + * + * * Platforms: T194 onwards + * @cond bpmp_t194 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_cpu_auto_cc3_request + * * Response Payload: @ref mrq_cpu_auto_cc3_response + * @addtogroup CC3 + * + * Queries from BPMP auto-CC3 configuration (allowed/not allowed) for a + * specified cluster. CCPLEX s/w uses this information to override its own + * device tree auto-CC3 settings, so that BPMP device tree is a single source of + * auto-CC3 platform configuration. + * + * @{ + */ + +/** + * @brief Request for auto-CC3 configuration of a cluster + */ +struct mrq_cpu_auto_cc3_request { + /** @brief Enum cluster_id (logical cluster id, known to CCPLEX s/w) */ + uint32_t cluster_id; +} __ABI_PACKED; + +/** + * @brief Response to #MRQ_CPU_AUTO_CC3 + */ +struct mrq_cpu_auto_cc3_response { + /** + * @brief auto-CC3 configuration + * + * - bits[31..10] reserved. + * - bits[9..1] cc3 ndiv + * - bit [0] if "1" auto-CC3 is allowed, if "0" auto-CC3 is not allowed + */ + uint32_t auto_cc3_config; +} __ABI_PACKED; + +/** @} */ +/** @endcond */ + /** * @ingroup MRQ_Codes * @def MRQ_TRACE_ITER - * @brief manage the trace iterator + * @brief Manage the trace iterator * * * Platforms: All * * Initiators: CCPLEX @@ -1735,12 +1869,12 @@ struct mrq_emc_dvfs_latency_response { enum { /** @brief (re)start the tracing now. Ignore older events */ TRACE_ITER_INIT = 0, - /** @brief clobber all events in the trace buffer */ + /** @brief Clobber all events in the trace buffer */ TRACE_ITER_CLEAN = 1 }; /** - * @brief request with #MRQ_TRACE_ITER + * @brief Request with #MRQ_TRACE_ITER */ struct mrq_trace_iter_request { /** @brief TRACE_ITER_INIT or TRACE_ITER_CLEAN */ @@ -1900,7 +2034,7 @@ struct cmd_ringbuf_console_get_fifo_resp { */ struct mrq_ringbuf_console_host_to_bpmp_request { /** - * @brief type of request. Values listed in enum + * @brief Type of request. Values listed in enum * #mrq_ringbuf_console_host_to_bpmp_cmd. */ uint32_t type; @@ -1927,49 +2061,616 @@ union mrq_ringbuf_console_bpmp_to_host_response { } __ABI_PACKED; /** @} */ -/* - * 4. Enumerations +/** + * @ingroup MRQ_Codes + * @def MRQ_STRAP + * @brief Set a strap value controlled by BPMP + * + * * Platforms: T194 onwards + * @cond bpmp_t194 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_strap_request + * * Response Payload: N/A + * @addtogroup Strap + * + * A strap is an input that is sampled by a hardware unit during the + * unit's startup process. The sampled value of a strap affects the + * behavior of the unit until the unit is restarted. Many hardware + * units sample their straps at the instant that their resets are + * deasserted. + * + * BPMP owns registers which act as straps to various units. It + * exposes limited control of those straps via #MRQ_STRAP. + * + * @{ + */ +enum mrq_strap_cmd { + /** @private */ + STRAP_RESERVED = 0, + /** @brief Set a strap value */ + STRAP_SET = 1 +}; + +/** + * @brief Request with #MRQ_STRAP + */ +struct mrq_strap_request { + /** @brief @ref mrq_strap_cmd */ + uint32_t cmd; + /** @brief Strap ID from @ref Strap_Ids */ + uint32_t id; + /** @brief Desired value for strap (if cmd is #STRAP_SET) */ + uint32_t value; +} __ABI_PACKED; + +/** + * @defgroup Strap_Ids Strap Identifiers + * @} + */ +/** @endcond */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_UPHY + * @brief Perform a UPHY operation + * + * * Platforms: T194 onwards + * @cond bpmp_t194 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_uphy_request + * * Response Payload: @ref mrq_uphy_response + * + * @addtogroup UPHY + * @{ + */ +enum { + CMD_UPHY_PCIE_LANE_MARGIN_CONTROL = 1, + CMD_UPHY_PCIE_LANE_MARGIN_STATUS = 2, + CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT = 3, + CMD_UPHY_PCIE_CONTROLLER_STATE = 4, + CMD_UPHY_MAX, +}; + +struct cmd_uphy_margin_control_request { + /** @brief Enable margin */ + int32_t en; + /** @brief Clear the number of error and sections */ + int32_t clr; + /** @brief Set x offset (1's complement) for left/right margin type (y should be 0) */ + uint32_t x; + /** @brief Set y offset (1's complement) for left/right margin type (x should be 0) */ + uint32_t y; + /** @brief Set number of bit blocks for each margin section */ + uint32_t nblks; +} __ABI_PACKED; + +struct cmd_uphy_margin_status_response { + /** @brief Number of errors observed */ + uint32_t status; +} __ABI_PACKED; + +struct cmd_uphy_ep_controller_pll_init_request { + /** @brief EP controller number, valid: 0, 4, 5 */ + uint8_t ep_controller; +} __ABI_PACKED; + +struct cmd_uphy_pcie_controller_state_request { + /** @brief PCIE controller number, valid: 0, 1, 2, 3, 4 */ + uint8_t pcie_controller; + uint8_t enable; +} __ABI_PACKED; + +/** + * @ingroup UPHY + * @brief Request with #MRQ_UPHY + * + * Used by the sender of an #MRQ_UPHY message to control UPHY Lane RX margining. + * The uphy_request is split into several sub-commands. Some sub-commands + * require no additional data. Others have a sub-command specific payload + * + * |sub-command |payload | + * |------------------------------------ |----------------------------------------| + * |CMD_UPHY_PCIE_LANE_MARGIN_CONTROL |uphy_set_margin_control | + * |CMD_UPHY_PCIE_LANE_MARGIN_STATUS | | + * |CMD_UPHY_PCIE_EP_CONTROLLER_PLL_INIT |cmd_uphy_ep_controller_pll_init_request | + * |CMD_UPHY_PCIE_CONTROLLER_STATE |cmd_uphy_pcie_controller_state_request | + * */ -/* - * 4.1 CPU enumerations +struct mrq_uphy_request { + /** @brief Lane number. */ + uint16_t lane; + /** @brief Sub-command id. */ + uint16_t cmd; + + union { + struct cmd_uphy_margin_control_request uphy_set_margin_control; + struct cmd_uphy_ep_controller_pll_init_request ep_ctrlr_pll_init; + struct cmd_uphy_pcie_controller_state_request controller_state; + } __UNION_ANON; +} __ABI_PACKED; + +/** + * @ingroup UPHY + * @brief Response to MRQ_UPHY * - * See + * Each sub-command supported by @ref mrq_uphy_request may return + * sub-command-specific data. Some do and some do not as indicated in + * the following table * - * 4.2 CPU Cluster enumerations + * |sub-command |payload | + * |---------------------------- |------------------------| + * |CMD_UPHY_PCIE_LANE_MARGIN_CONTROL | | + * |CMD_UPHY_PCIE_LANE_MARGIN_STATUS |uphy_get_margin_status | * - * See - * - * 4.3 System low power state enumerations - * - * See */ -/* - * 4.4 Clock enumerations +struct mrq_uphy_response { + union { + struct cmd_uphy_margin_status_response uphy_get_margin_status; + } __UNION_ANON; +} __ABI_PACKED; + +/** @} */ +/** @endcond */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_FMON + * @brief Perform a frequency monitor configuration operations + * + * * Platforms: T194 onwards + * @cond bpmp_t194 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_fmon_request + * * Response Payload: @ref mrq_fmon_response + * + * @addtogroup FMON + * @{ + */ +enum { + /** + * @brief Clamp FMON configuration to specified rate. + * + * The monitored clock must be running for clamp to succeed. If + * clamped, FMON configuration is preserved when clock rate + * and/or state is changed. + */ + CMD_FMON_GEAR_CLAMP = 1, + /** + * @brief Release clamped FMON configuration. + * + * Allow FMON configuration to follow monitored clock rate + * and/or state changes. + */ + CMD_FMON_GEAR_FREE = 2, + /** + * @brief Return rate FMON is clamped at, or 0 if FMON is not + * clamped. + * + * Inherently racy, since clamp state can be changed + * concurrently. Useful for testing. + */ + CMD_FMON_GEAR_GET = 3, + CMD_FMON_NUM, +}; + +struct cmd_fmon_gear_clamp_request { + int32_t unused; + int64_t rate; +} __ABI_PACKED; + +/** @private */ +struct cmd_fmon_gear_clamp_response { + EMPTY +} __ABI_PACKED; + +/** @private */ +struct cmd_fmon_gear_free_request { + EMPTY +} __ABI_PACKED; + +/** @private */ +struct cmd_fmon_gear_free_response { + EMPTY +} __ABI_PACKED; + +/** @private */ +struct cmd_fmon_gear_get_request { + EMPTY +} __ABI_PACKED; + +struct cmd_fmon_gear_get_response { + int64_t rate; +} __ABI_PACKED; + +/** + * @ingroup FMON + * @brief Request with #MRQ_FMON + * + * Used by the sender of an #MRQ_FMON message to configure clock + * frequency monitors. The FMON request is split into several + * sub-commands. Some sub-commands require no additional data. + * Others have a sub-command specific payload + * + * |sub-command |payload | + * |----------------------------|-----------------------| + * |CMD_FMON_GEAR_CLAMP |fmon_gear_clamp | + * |CMD_FMON_GEAR_FREE |- | + * |CMD_FMON_GEAR_GET |- | * - * For clock enumerations, see */ -/* - * 4.5 Reset enumerations +struct mrq_fmon_request { + /** @brief Sub-command and clock id concatenated to 32-bit word. + * - bits[31..24] is the sub-cmd. + * - bits[23..0] is monitored clock id used to select target + * FMON + */ + uint32_t cmd_and_id; + + union { + struct cmd_fmon_gear_clamp_request fmon_gear_clamp; + /** @private */ + struct cmd_fmon_gear_free_request fmon_gear_free; + /** @private */ + struct cmd_fmon_gear_get_request fmon_gear_get; + } __UNION_ANON; +} __ABI_PACKED; + +/** + * @ingroup FMON + * @brief Response to MRQ_FMON + * + * Each sub-command supported by @ref mrq_fmon_request may + * return sub-command-specific data as indicated below. + * + * |sub-command |payload | + * |----------------------------|------------------------| + * |CMD_FMON_GEAR_CLAMP |- | + * |CMD_FMON_GEAR_FREE |- | + * |CMD_FMON_GEAR_GET |fmon_gear_get | * - * For reset enumerations, see */ -/* - * 4.6 Thermal sensor enumerations +struct mrq_fmon_response { + union { + /** @private */ + struct cmd_fmon_gear_clamp_response fmon_gear_clamp; + /** @private */ + struct cmd_fmon_gear_free_response fmon_gear_free; + struct cmd_fmon_gear_get_response fmon_gear_get; + } __UNION_ANON; +} __ABI_PACKED; + +/** @} */ +/** @endcond */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_EC + * @brief Provide status information on faults reported by Error + * Collator (EC) to HSM. * - * For thermal sensor enumerations, see + * * Platforms: T194 onwards + * @cond bpmp_t194 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_ec_request + * * Response Payload: @ref mrq_ec_response + * + * @note This MRQ ABI is under construction, and subject to change + * + * @addtogroup EC + * @{ + */ +enum { + /** + * @brief Retrieve specified EC status. + * + * mrq_response::err is 0 if the operation was successful, or @n + * -#BPMP_ENODEV if target EC is not owned by BPMP @n + * -#BPMP_EACCES if target EC power domain is turned off + */ + CMD_EC_STATUS_GET = 1, + CMD_EC_NUM, +}; + +/** @brief BPMP ECs error types */ +enum bpmp_ec_err_type { + /** @brief Parity error on internal data path + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_PARITY_INTERNAL = 1, + + /** @brief ECC SEC error on internal data path + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_ECC_SEC_INTERNAL = 2, + + /** @brief ECC DED error on internal data path + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_ECC_DED_INTERNAL = 3, + + /** @brief Comparator error + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_COMPARATOR = 4, + + /** @brief Register parity error + * + * Error descriptor @ref ec_err_reg_parity_desc. + */ + EC_ERR_TYPE_REGISTER_PARITY = 5, + + /** @brief Parity error from on-chip SRAM/FIFO + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_PARITY_SRAM = 6, + + /** @brief Clock Monitor error + * + * Error descriptor @ref ec_err_fmon_desc. + */ + EC_ERR_TYPE_CLOCK_MONITOR = 9, + + /** @brief Voltage Monitor error + * + * Error descriptor @ref ec_err_vmon_desc. + */ + EC_ERR_TYPE_VOLTAGE_MONITOR = 10, + + /** @brief SW Correctable error + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_SW_CORRECTABLE = 16, + + /** @brief SW Uncorrectable error + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_SW_UNCORRECTABLE = 17, + + /** @brief Other HW Correctable error + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_OTHER_HW_CORRECTABLE = 32, + + /** @brief Other HW Uncorrectable error + * + * Error descriptor @ref ec_err_simple_desc. + */ + EC_ERR_TYPE_OTHER_HW_UNCORRECTABLE = 33, +}; + +/** @brief Group of registers with parity error. */ +enum ec_registers_group { + /** @brief Functional registers group */ + EC_ERR_GROUP_FUNC_REG = 0, + /** @brief SCR registers group */ + EC_ERR_GROUP_SCR_REG = 1, +}; + +/** + * @defgroup bpmp_ec_status_flags EC Status Flags + * @addtogroup bpmp_ec_status_flags + * @{ + */ +/** @brief No EC error found flag */ +#define EC_STATUS_FLAG_NO_ERROR 0x0001 +/** @brief Last EC error found flag */ +#define EC_STATUS_FLAG_LAST_ERROR 0x0002 +/** @brief EC latent error flag */ +#define EC_STATUS_FLAG_LATENT_ERROR 0x0004 +/** @} */ + +/** + * @defgroup bpmp_ec_desc_flags EC Descriptor Flags + * @addtogroup bpmp_ec_desc_flags + * @{ + */ +/** @brief EC descriptor error resolved flag */ +#define EC_DESC_FLAG_RESOLVED 0x0001 +/** @brief EC descriptor failed to retrieve id flag */ +#define EC_DESC_FLAG_NO_ID 0x0002 +/** @} */ + +/** + * |error type | fmon_clk_id values | + * |---------------------------------|---------------------------| + * |@ref EC_ERR_TYPE_CLOCK_MONITOR |@ref bpmp_clock_ids | + */ +struct ec_err_fmon_desc { + /** @brief Bitmask of @ref bpmp_ec_desc_flags */ + uint16_t desc_flags; + /** @brief FMON monitored clock id */ + uint16_t fmon_clk_id; + /** @brief Bitmask of @ref bpmp_fmon_faults_flags */ + uint32_t fmon_faults; + /** @brief FMON faults access error */ + int32_t fmon_access_error; +} __ABI_PACKED; + +/** + * |error type | vmon_adc_id values | + * |---------------------------------|---------------------------| + * |@ref EC_ERR_TYPE_VOLTAGE_MONITOR |@ref bpmp_adc_ids | + */ +struct ec_err_vmon_desc { + /** @brief Bitmask of @ref bpmp_ec_desc_flags */ + uint16_t desc_flags; + /** @brief VMON rail adc id */ + uint16_t vmon_adc_id; + /** @brief Bitmask of @ref bpmp_vmon_faults_flags */ + uint32_t vmon_faults; + /** @brief VMON faults access error */ + int32_t vmon_access_error; +} __ABI_PACKED; + +/** + * |error type | reg_id values | + * |---------------------------------|---------------------------| + * |@ref EC_ERR_TYPE_REGISTER_PARITY |@ref bpmp_ec_registers_ids | + */ +struct ec_err_reg_parity_desc { + /** @brief Bitmask of @ref bpmp_ec_desc_flags */ + uint16_t desc_flags; + /** @brief Register id */ + uint16_t reg_id; + /** @brief Register group @ref ec_registers_group */ + uint16_t reg_group; +} __ABI_PACKED; + +/** + * |error type | err_source_id values | + * |----------------------------------------|---------------------------| + * |@ref EC_ERR_TYPE_PARITY_INTERNAL |@ref bpmp_ec_ipath_ids | + * |@ref EC_ERR_TYPE_ECC_SEC_INTERNAL |@ref bpmp_ec_ipath_ids | + * |@ref EC_ERR_TYPE_ECC_DED_INTERNAL |@ref bpmp_ec_ipath_ids | + * |@ref EC_ERR_TYPE_COMPARATOR |@ref bpmp_ec_comparator_ids| + * |@ref EC_ERR_TYPE_PARITY_SRAM |@ref bpmp_clock_ids | + * |@ref EC_ERR_TYPE_SW_CORRECTABLE |@ref bpmp_ec_misc_ids | + * |@ref EC_ERR_TYPE_SW_UNCORRECTABLE |@ref bpmp_ec_misc_ids | + * |@ref EC_ERR_TYPE_OTHER_HW_CORRECTABLE |@ref bpmp_ec_misc_ids | + * |@ref EC_ERR_TYPE_OTHER_HW_UNCORRECTABLE |@ref bpmp_ec_misc_ids | + */ +struct ec_err_simple_desc { + /** @brief Bitmask of @ref bpmp_ec_desc_flags */ + uint16_t desc_flags; + /** @brief Error source id. Id space depends on error type. */ + uint16_t err_source_id; +} __ABI_PACKED; + +/** @brief Union of EC error descriptors */ +union ec_err_desc { + struct ec_err_fmon_desc fmon_desc; + struct ec_err_vmon_desc vmon_desc; + struct ec_err_reg_parity_desc reg_parity_desc; + struct ec_err_simple_desc simple_desc; +} __ABI_PACKED; + +struct cmd_ec_status_get_request { + /** @brief HSM error line number that identifies target EC. */ + uint32_t ec_hsm_id; +} __ABI_PACKED; + +/** EC status maximum number of descriptors */ +#define EC_ERR_STATUS_DESC_MAX_NUM 4 + +struct cmd_ec_status_get_response { + /** @brief Target EC id (the same id received with request). */ + uint32_t ec_hsm_id; + /** + * @brief Bitmask of @ref bpmp_ec_status_flags + * + * If NO_ERROR flag is set, error_ fields should be ignored + */ + uint32_t ec_status_flags; + /** @brief Found EC error index. */ + uint32_t error_idx; + /** @brief Found EC error type @ref bpmp_ec_err_type. */ + uint32_t error_type; + /** @brief Number of returned EC error descriptors */ + uint32_t error_desc_num; + /** @brief EC error descriptors */ + union ec_err_desc error_descs[EC_ERR_STATUS_DESC_MAX_NUM]; +} __ABI_PACKED; + +/** + * @ingroup EC + * @brief Request with #MRQ_EC + * + * Used by the sender of an #MRQ_EC message to access ECs owned + * by BPMP. + * + * |sub-command |payload | + * |----------------------------|-----------------------| + * |@ref CMD_EC_STATUS_GET |ec_status_get | + * + */ + +struct mrq_ec_request { + /** @brief Sub-command id. */ + uint32_t cmd_id; + + union { + struct cmd_ec_status_get_request ec_status_get; + } __UNION_ANON; +} __ABI_PACKED; + +/** + * @ingroup EC + * @brief Response to MRQ_EC + * + * Each sub-command supported by @ref mrq_ec_request may return + * sub-command-specific data as indicated below. + * + * |sub-command |payload | + * |----------------------------|------------------------| + * |@ref CMD_EC_STATUS_GET |ec_status_get | + * + */ + +struct mrq_ec_response { + union { + struct cmd_ec_status_get_response ec_status_get; + } __UNION_ANON; +} __ABI_PACKED; + +/** @} */ +/** @endcond */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_FBVOLT_STATUS + * @brief Provides status information about voltage state for fuse burning + * + * * Platforms: T194 onwards + * @cond bpmp_t194 + * * Initiators: CCPLEX + * * Target: BPMP + * * Request Payload: None + * * Response Payload: @ref mrq_fbvolt_status_response + * @{ */ /** - * @defgroup Error_Codes + * @ingroup Fbvolt_status + * @brief Response to #MRQ_FBVOLT_STATUS + * + * Value of #ready reflects if core voltages are in a suitable state for buring + * fuses. A value of 0x1 indicates that core voltages are ready for burning + * fuses. A value of 0x0 indicates that core voltages are not ready. + */ +struct mrq_fbvolt_status_response { + /** @brief Bit [0:0] - ready status, bits [31:1] - reserved */ + uint32_t ready; + /** @brief Reserved */ + uint32_t unused; +} __ABI_PACKED; + +/** @} */ +/** @endcond */ + +/** + * @addtogroup Error_Codes * Negative values for mrq_response::err generally indicate some * error. The ABI defines the following error codes. Negating these * defines is an exercise left to the user. * @{ */ + /** @brief No such file or directory */ #define BPMP_ENOENT 2 /** @brief No MRQ handler */ @@ -1994,6 +2695,11 @@ union mrq_ringbuf_console_bpmp_to_host_response { #define BPMP_ETIMEDOUT 23 /** @brief Out of range */ #define BPMP_ERANGE 34 +/** @brief Function not implemented */ +#define BPMP_ENOSYS 38 +/** @brief Invalid slot */ +#define BPMP_EBADSLT 57 + /** @} */ -/** @} */ + #endif From af51c25fb59d4365c259ab93f388462e0998a2ed Mon Sep 17 00:00:00 2001 From: Timo Alho Date: Mon, 22 Oct 2018 16:19:40 +0300 Subject: [PATCH 12/73] firmware: tegra: Use in-band messages for firmware version query Add support for a new MRQ, that uses in-band messaging instead of IOVA buffer, to retrieve the firmware version 'tag' during boot. If an older firmware is used, that does not support the new MRQ, fall back to the earlier implementation. Signed-off-by: Timo Alho Acked-by: Sivaram Nair Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/firmware/tegra/bpmp.c | 36 +++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 191f8a91c466..689478b92bce 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -547,8 +547,9 @@ static int tegra_bpmp_ping(struct tegra_bpmp *bpmp) return err; } -static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, - size_t size) +/* deprecated version of tag query */ +static int tegra_bpmp_get_firmware_tag_old(struct tegra_bpmp *bpmp, char *tag, + size_t size) { struct mrq_query_tag_request request; struct tegra_bpmp_message msg; @@ -585,6 +586,37 @@ static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, return err; } +static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, + size_t size) +{ + if (tegra_bpmp_mrq_is_supported(bpmp, MRQ_QUERY_FW_TAG)) { + struct mrq_query_fw_tag_response resp; + struct tegra_bpmp_message msg = { + .mrq = MRQ_QUERY_FW_TAG, + .rx = { + .data = &resp, + .size = sizeof(resp), + }, + }; + int err; + + if (size != sizeof(resp.tag)) + return -EINVAL; + + err = tegra_bpmp_transfer(bpmp, &msg); + + if (err) + return err; + if (msg.rx.ret < 0) + return -EINVAL; + + memcpy(tag, resp.tag, sizeof(resp.tag)); + return 0; + } + + return tegra_bpmp_get_firmware_tag_old(bpmp, tag, size); +} + static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) { unsigned long flags = channel->ob->flags; From 96e5da7c842424bcf64afe1082b960b42b96190b Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 21 Oct 2018 21:30:52 +0300 Subject: [PATCH 13/73] memory: tegra: Introduce Tegra20 EMC driver Introduce driver for the External Memory Controller (EMC) found on Tegra20 chips, which controls the external DRAM on the board. The purpose of this driver is to program memory timing for external memory on the EMC clock rate change. Signed-off-by: Dmitry Osipenko Acked-by: Peter De Schrijver Signed-off-by: Thierry Reding --- drivers/memory/tegra/Kconfig | 10 + drivers/memory/tegra/Makefile | 1 + drivers/memory/tegra/tegra20-emc.c | 591 +++++++++++++++++++++++++++++ 3 files changed, 602 insertions(+) create mode 100644 drivers/memory/tegra/tegra20-emc.c diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig index 6d74e499e18d..34e0b70f5c5f 100644 --- a/drivers/memory/tegra/Kconfig +++ b/drivers/memory/tegra/Kconfig @@ -6,6 +6,16 @@ config TEGRA_MC This driver supports the Memory Controller (MC) hardware found on NVIDIA Tegra SoCs. +config TEGRA20_EMC + bool "NVIDIA Tegra20 External Memory Controller driver" + default y + depends on ARCH_TEGRA_2x_SOC + help + This driver is for the External Memory Controller (EMC) found on + Tegra20 chips. The EMC controls the external DRAM on the board. + This driver is required to change memory timings / clock rate for + external memory. + config TEGRA124_EMC bool "NVIDIA Tegra124 External Memory Controller driver" default y diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile index 94ab16ba075b..3971a6b7c487 100644 --- a/drivers/memory/tegra/Makefile +++ b/drivers/memory/tegra/Makefile @@ -10,5 +10,6 @@ tegra-mc-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o obj-$(CONFIG_TEGRA_MC) += tegra-mc.o +obj-$(CONFIG_TEGRA20_EMC) += tegra20-emc.o obj-$(CONFIG_TEGRA124_EMC) += tegra124-emc.o obj-$(CONFIG_ARCH_TEGRA_186_SOC) += tegra186.o diff --git a/drivers/memory/tegra/tegra20-emc.c b/drivers/memory/tegra/tegra20-emc.c new file mode 100644 index 000000000000..9ee5bef49e47 --- /dev/null +++ b/drivers/memory/tegra/tegra20-emc.c @@ -0,0 +1,591 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Tegra20 External Memory Controller driver + * + * Author: Dmitry Osipenko + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define EMC_INTSTATUS 0x000 +#define EMC_INTMASK 0x004 +#define EMC_TIMING_CONTROL 0x028 +#define EMC_RC 0x02c +#define EMC_RFC 0x030 +#define EMC_RAS 0x034 +#define EMC_RP 0x038 +#define EMC_R2W 0x03c +#define EMC_W2R 0x040 +#define EMC_R2P 0x044 +#define EMC_W2P 0x048 +#define EMC_RD_RCD 0x04c +#define EMC_WR_RCD 0x050 +#define EMC_RRD 0x054 +#define EMC_REXT 0x058 +#define EMC_WDV 0x05c +#define EMC_QUSE 0x060 +#define EMC_QRST 0x064 +#define EMC_QSAFE 0x068 +#define EMC_RDV 0x06c +#define EMC_REFRESH 0x070 +#define EMC_BURST_REFRESH_NUM 0x074 +#define EMC_PDEX2WR 0x078 +#define EMC_PDEX2RD 0x07c +#define EMC_PCHG2PDEN 0x080 +#define EMC_ACT2PDEN 0x084 +#define EMC_AR2PDEN 0x088 +#define EMC_RW2PDEN 0x08c +#define EMC_TXSR 0x090 +#define EMC_TCKE 0x094 +#define EMC_TFAW 0x098 +#define EMC_TRPAB 0x09c +#define EMC_TCLKSTABLE 0x0a0 +#define EMC_TCLKSTOP 0x0a4 +#define EMC_TREFBW 0x0a8 +#define EMC_QUSE_EXTRA 0x0ac +#define EMC_ODT_WRITE 0x0b0 +#define EMC_ODT_READ 0x0b4 +#define EMC_FBIO_CFG5 0x104 +#define EMC_FBIO_CFG6 0x114 +#define EMC_AUTO_CAL_INTERVAL 0x2a8 +#define EMC_CFG_2 0x2b8 +#define EMC_CFG_DIG_DLL 0x2bc +#define EMC_DLL_XFORM_DQS 0x2c0 +#define EMC_DLL_XFORM_QUSE 0x2c4 +#define EMC_ZCAL_REF_CNT 0x2e0 +#define EMC_ZCAL_WAIT_CNT 0x2e4 +#define EMC_CFG_CLKTRIM_0 0x2d0 +#define EMC_CFG_CLKTRIM_1 0x2d4 +#define EMC_CFG_CLKTRIM_2 0x2d8 + +#define EMC_CLKCHANGE_REQ_ENABLE BIT(0) +#define EMC_CLKCHANGE_PD_ENABLE BIT(1) +#define EMC_CLKCHANGE_SR_ENABLE BIT(2) + +#define EMC_TIMING_UPDATE BIT(0) + +#define EMC_REFRESH_OVERFLOW_INT BIT(3) +#define EMC_CLKCHANGE_COMPLETE_INT BIT(4) + +static const u16 emc_timing_registers[] = { + EMC_RC, + EMC_RFC, + EMC_RAS, + EMC_RP, + EMC_R2W, + EMC_W2R, + EMC_R2P, + EMC_W2P, + EMC_RD_RCD, + EMC_WR_RCD, + EMC_RRD, + EMC_REXT, + EMC_WDV, + EMC_QUSE, + EMC_QRST, + EMC_QSAFE, + EMC_RDV, + EMC_REFRESH, + EMC_BURST_REFRESH_NUM, + EMC_PDEX2WR, + EMC_PDEX2RD, + EMC_PCHG2PDEN, + EMC_ACT2PDEN, + EMC_AR2PDEN, + EMC_RW2PDEN, + EMC_TXSR, + EMC_TCKE, + EMC_TFAW, + EMC_TRPAB, + EMC_TCLKSTABLE, + EMC_TCLKSTOP, + EMC_TREFBW, + EMC_QUSE_EXTRA, + EMC_FBIO_CFG6, + EMC_ODT_WRITE, + EMC_ODT_READ, + EMC_FBIO_CFG5, + EMC_CFG_DIG_DLL, + EMC_DLL_XFORM_DQS, + EMC_DLL_XFORM_QUSE, + EMC_ZCAL_REF_CNT, + EMC_ZCAL_WAIT_CNT, + EMC_AUTO_CAL_INTERVAL, + EMC_CFG_CLKTRIM_0, + EMC_CFG_CLKTRIM_1, + EMC_CFG_CLKTRIM_2, +}; + +struct emc_timing { + unsigned long rate; + u32 data[ARRAY_SIZE(emc_timing_registers)]; +}; + +struct tegra_emc { + struct device *dev; + struct completion clk_handshake_complete; + struct notifier_block clk_nb; + struct clk *backup_clk; + struct clk *emc_mux; + struct clk *pll_m; + struct clk *clk; + void __iomem *regs; + + struct emc_timing *timings; + unsigned int num_timings; +}; + +static irqreturn_t tegra_emc_isr(int irq, void *data) +{ + struct tegra_emc *emc = data; + u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT; + u32 status; + + status = readl_relaxed(emc->regs + EMC_INTSTATUS) & intmask; + if (!status) + return IRQ_NONE; + + /* notify about EMC-CAR handshake completion */ + if (status & EMC_CLKCHANGE_COMPLETE_INT) + complete(&emc->clk_handshake_complete); + + /* notify about HW problem */ + if (status & EMC_REFRESH_OVERFLOW_INT) + dev_err_ratelimited(emc->dev, + "refresh request overflow timeout\n"); + + /* clear interrupts */ + writel_relaxed(status, emc->regs + EMC_INTSTATUS); + + return IRQ_HANDLED; +} + +static struct emc_timing *tegra_emc_find_timing(struct tegra_emc *emc, + unsigned long rate) +{ + struct emc_timing *timing = NULL; + unsigned int i; + + for (i = 0; i < emc->num_timings; i++) { + if (emc->timings[i].rate >= rate) { + timing = &emc->timings[i]; + break; + } + } + + if (!timing) { + dev_err(emc->dev, "no timing for rate %lu\n", rate); + return NULL; + } + + return timing; +} + +static int emc_prepare_timing_change(struct tegra_emc *emc, unsigned long rate) +{ + struct emc_timing *timing = tegra_emc_find_timing(emc, rate); + unsigned int i; + + if (!timing) + return -EINVAL; + + dev_dbg(emc->dev, "%s: using timing rate %lu for requested rate %lu\n", + __func__, timing->rate, rate); + + /* program shadow registers */ + for (i = 0; i < ARRAY_SIZE(timing->data); i++) + writel_relaxed(timing->data[i], + emc->regs + emc_timing_registers[i]); + + /* wait until programming has settled */ + readl_relaxed(emc->regs + emc_timing_registers[i - 1]); + + reinit_completion(&emc->clk_handshake_complete); + + return 0; +} + +static int emc_complete_timing_change(struct tegra_emc *emc, bool flush) +{ + long timeout; + + dev_dbg(emc->dev, "%s: flush %d\n", __func__, flush); + + if (flush) { + /* manually initiate memory timing update */ + writel_relaxed(EMC_TIMING_UPDATE, + emc->regs + EMC_TIMING_CONTROL); + return 0; + } + + timeout = wait_for_completion_timeout(&emc->clk_handshake_complete, + usecs_to_jiffies(100)); + if (timeout == 0) { + dev_err(emc->dev, "EMC-CAR handshake failed\n"); + return -EIO; + } else if (timeout < 0) { + dev_err(emc->dev, "failed to wait for EMC-CAR handshake: %ld\n", + timeout); + return timeout; + } + + return 0; +} + +static int tegra_emc_clk_change_notify(struct notifier_block *nb, + unsigned long msg, void *data) +{ + struct tegra_emc *emc = container_of(nb, struct tegra_emc, clk_nb); + struct clk_notifier_data *cnd = data; + int err; + + switch (msg) { + case PRE_RATE_CHANGE: + err = emc_prepare_timing_change(emc, cnd->new_rate); + break; + + case ABORT_RATE_CHANGE: + err = emc_prepare_timing_change(emc, cnd->old_rate); + if (err) + break; + + err = emc_complete_timing_change(emc, true); + break; + + case POST_RATE_CHANGE: + err = emc_complete_timing_change(emc, false); + break; + + default: + return NOTIFY_DONE; + } + + return notifier_from_errno(err); +} + +static int load_one_timing_from_dt(struct tegra_emc *emc, + struct emc_timing *timing, + struct device_node *node) +{ + u32 rate; + int err; + + if (!of_device_is_compatible(node, "nvidia,tegra20-emc-table")) { + dev_err(emc->dev, "incompatible DT node: %pOF\n", node); + return -EINVAL; + } + + err = of_property_read_u32(node, "clock-frequency", &rate); + if (err) { + dev_err(emc->dev, "timing %pOF: failed to read rate: %d\n", + node, err); + return err; + } + + err = of_property_read_u32_array(node, "nvidia,emc-registers", + timing->data, + ARRAY_SIZE(emc_timing_registers)); + if (err) { + dev_err(emc->dev, + "timing %pOF: failed to read emc timing data: %d\n", + node, err); + return err; + } + + /* + * The EMC clock rate is twice the bus rate, and the bus rate is + * measured in kHz. + */ + timing->rate = rate * 2 * 1000; + + dev_dbg(emc->dev, "%s: %pOF: EMC rate %lu\n", + __func__, node, timing->rate); + + return 0; +} + +static int cmp_timings(const void *_a, const void *_b) +{ + const struct emc_timing *a = _a; + const struct emc_timing *b = _b; + + if (a->rate < b->rate) + return -1; + + if (a->rate > b->rate) + return 1; + + return 0; +} + +static int tegra_emc_load_timings_from_dt(struct tegra_emc *emc, + struct device_node *node) +{ + struct device_node *child; + struct emc_timing *timing; + int child_count; + int err; + + child_count = of_get_child_count(node); + if (!child_count) { + dev_err(emc->dev, "no memory timings in DT node: %pOF\n", node); + return -EINVAL; + } + + emc->timings = devm_kcalloc(emc->dev, child_count, sizeof(*timing), + GFP_KERNEL); + if (!emc->timings) + return -ENOMEM; + + emc->num_timings = child_count; + timing = emc->timings; + + for_each_child_of_node(node, child) { + err = load_one_timing_from_dt(emc, timing++, child); + if (err) { + of_node_put(child); + return err; + } + } + + sort(emc->timings, emc->num_timings, sizeof(*timing), cmp_timings, + NULL); + + return 0; +} + +static struct device_node * +tegra_emc_find_node_by_ram_code(struct device *dev) +{ + struct device_node *np; + u32 value, ram_code; + int err; + + if (!of_property_read_bool(dev->of_node, "nvidia,use-ram-code")) + return of_node_get(dev->of_node); + + ram_code = tegra_read_ram_code(); + + for (np = of_find_node_by_name(dev->of_node, "emc-tables"); np; + np = of_find_node_by_name(np, "emc-tables")) { + err = of_property_read_u32(np, "nvidia,ram-code", &value); + if (err || value != ram_code) { + of_node_put(np); + continue; + } + + return np; + } + + dev_err(dev, "no memory timings for RAM code %u found in device tree\n", + ram_code); + + return NULL; +} + +static int emc_setup_hw(struct tegra_emc *emc) +{ + u32 intmask = EMC_REFRESH_OVERFLOW_INT | EMC_CLKCHANGE_COMPLETE_INT; + u32 emc_cfg; + + emc_cfg = readl_relaxed(emc->regs + EMC_CFG_2); + + /* + * Depending on a memory type, DRAM should enter either self-refresh + * or power-down state on EMC clock change. + */ + if (!(emc_cfg & EMC_CLKCHANGE_PD_ENABLE) && + !(emc_cfg & EMC_CLKCHANGE_SR_ENABLE)) { + dev_err(emc->dev, + "bootloader didn't specify DRAM auto-suspend mode\n"); + return -EINVAL; + } + + /* enable EMC and CAR to handshake on PLL divider/source changes */ + emc_cfg |= EMC_CLKCHANGE_REQ_ENABLE; + writel_relaxed(emc_cfg, emc->regs + EMC_CFG_2); + + /* initialize interrupt */ + writel_relaxed(intmask, emc->regs + EMC_INTMASK); + writel_relaxed(intmask, emc->regs + EMC_INTSTATUS); + + return 0; +} + +static int emc_init(struct tegra_emc *emc, unsigned long rate) +{ + int err; + + err = clk_set_parent(emc->emc_mux, emc->backup_clk); + if (err) { + dev_err(emc->dev, + "failed to reparent to backup source: %d\n", err); + return err; + } + + err = clk_set_rate(emc->pll_m, rate); + if (err) { + dev_err(emc->dev, + "failed to change pll_m rate: %d\n", err); + return err; + } + + err = clk_set_parent(emc->emc_mux, emc->pll_m); + if (err) { + dev_err(emc->dev, + "failed to reparent to pll_m: %d\n", err); + return err; + } + + err = clk_set_rate(emc->clk, rate); + if (err) { + dev_err(emc->dev, + "failed to change emc rate: %d\n", err); + return err; + } + + return 0; +} + +static int tegra_emc_probe(struct platform_device *pdev) +{ + struct device_node *np; + struct tegra_emc *emc; + struct resource *res; + int irq, err; + + /* driver has nothing to do in a case of memory timing absence */ + if (of_get_child_count(pdev->dev.of_node) == 0) { + dev_info(&pdev->dev, + "EMC device tree node doesn't have memory timings\n"); + return 0; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "interrupt not specified\n"); + dev_err(&pdev->dev, "please update your device tree\n"); + return irq; + } + + np = tegra_emc_find_node_by_ram_code(&pdev->dev); + if (!np) + return -EINVAL; + + emc = devm_kzalloc(&pdev->dev, sizeof(*emc), GFP_KERNEL); + if (!emc) { + of_node_put(np); + return -ENOMEM; + } + + init_completion(&emc->clk_handshake_complete); + emc->clk_nb.notifier_call = tegra_emc_clk_change_notify; + emc->dev = &pdev->dev; + + err = tegra_emc_load_timings_from_dt(emc, np); + of_node_put(np); + if (err) + return err; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + emc->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(emc->regs)) + return PTR_ERR(emc->regs); + + err = emc_setup_hw(emc); + if (err) + return err; + + err = devm_request_irq(&pdev->dev, irq, tegra_emc_isr, 0, + dev_name(&pdev->dev), emc); + if (err) { + dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", irq, err); + return err; + } + + emc->clk = devm_clk_get(&pdev->dev, "emc"); + if (IS_ERR(emc->clk)) { + err = PTR_ERR(emc->clk); + dev_err(&pdev->dev, "failed to get emc clock: %d\n", err); + return err; + } + + emc->pll_m = clk_get_sys(NULL, "pll_m"); + if (IS_ERR(emc->pll_m)) { + err = PTR_ERR(emc->pll_m); + dev_err(&pdev->dev, "failed to get pll_m clock: %d\n", err); + return err; + } + + emc->backup_clk = clk_get_sys(NULL, "pll_p"); + if (IS_ERR(emc->backup_clk)) { + err = PTR_ERR(emc->backup_clk); + dev_err(&pdev->dev, "failed to get pll_p clock: %d\n", err); + goto put_pll_m; + } + + emc->emc_mux = clk_get_parent(emc->clk); + if (IS_ERR(emc->emc_mux)) { + err = PTR_ERR(emc->emc_mux); + dev_err(&pdev->dev, "failed to get emc_mux clock: %d\n", err); + goto put_backup; + } + + err = clk_notifier_register(emc->clk, &emc->clk_nb); + if (err) { + dev_err(&pdev->dev, "failed to register clk notifier: %d\n", + err); + goto put_backup; + } + + /* set DRAM clock rate to maximum */ + err = emc_init(emc, emc->timings[emc->num_timings - 1].rate); + if (err) { + dev_err(&pdev->dev, "failed to initialize EMC clock rate: %d\n", + err); + goto unreg_notifier; + } + + return 0; + +unreg_notifier: + clk_notifier_unregister(emc->clk, &emc->clk_nb); +put_backup: + clk_put(emc->backup_clk); +put_pll_m: + clk_put(emc->pll_m); + + return err; +} + +static const struct of_device_id tegra_emc_of_match[] = { + { .compatible = "nvidia,tegra20-emc", }, + {}, +}; + +static struct platform_driver tegra_emc_driver = { + .probe = tegra_emc_probe, + .driver = { + .name = "tegra20-emc", + .of_match_table = tegra_emc_of_match, + .suppress_bind_attrs = true, + }, +}; + +static int __init tegra_emc_init(void) +{ + return platform_driver_register(&tegra_emc_driver); +} +subsys_initcall(tegra_emc_init); From 3bb2f843c0e7f69385e65448fae38d78c208e699 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 28 Sep 2018 15:11:49 +0100 Subject: [PATCH 14/73] soc/tegra: pmc: Don't power-up XUSB power-domains Now that the Tegra xHCI driver manages the XUSB power-domains itself, remove the code to power-up the power-domains used by the xHCI device from the PMC driver on boot. Signed-off-by: Jon Hunter Acked-by: Thierry Reding Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 1fa840e3d930..1a82aa423e4a 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -847,22 +847,6 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) goto remove_resets; } - /* - * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB - * host and super-speed partitions. Once the XHCI driver - * manages the partitions itself this code can be removed. Note - * that we don't register these partitions with the genpd core - * to avoid it from powering down the partitions as they appear - * to be unused. - */ - if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) && - (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) { - if (off) - WARN_ON(tegra_powergate_power_up(pg, true)); - - goto remove_resets; - } - err = pm_genpd_init(&pg->genpd, NULL, off); if (err < 0) { pr_err("failed to initialise PM domain %pOFn: %d\n", np, From 5f84bb1a4099e26d04d7fe379aa1b825de39d757 Mon Sep 17 00:00:00 2001 From: Sandipan Patra Date: Wed, 24 Oct 2018 12:38:00 +0530 Subject: [PATCH 15/73] soc/tegra: pmc: Add sysfs entries for reset info Implement read-only reset_reason and reset_level sysfs attributes that can be used to query the reset reason and level at runtime. Signed-off-by: Sandipan Patra Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 129 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 128 insertions(+), 1 deletion(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 1a82aa423e4a..22c28a4ace4d 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -2,6 +2,7 @@ * drivers/soc/tegra/pmc.c * * Copyright (c) 2010 Google, Inc + * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross @@ -92,7 +93,6 @@ #define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) #define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) -#define PMC_RST_STATUS 0x1b4 #define PMC_RST_STATUS_POR 0 #define PMC_RST_STATUS_WATCHDOG 1 #define PMC_RST_STATUS_SENSOR 2 @@ -151,6 +151,11 @@ struct tegra_pmc_regs { unsigned int dpd_status; unsigned int dpd2_req; unsigned int dpd2_status; + unsigned int rst_status; + unsigned int rst_source_shift; + unsigned int rst_source_mask; + unsigned int rst_level_shift; + unsigned int rst_level_mask; }; struct tegra_pmc_soc { @@ -175,6 +180,42 @@ struct tegra_pmc_soc { void (*setup_irq_polarity)(struct tegra_pmc *pmc, struct device_node *np, bool invert); + + const char * const *reset_sources; + unsigned int num_reset_sources; + const char * const *reset_levels; + unsigned int num_reset_levels; +}; + +static const char * const tegra186_reset_sources[] = { + "SYS_RESET", + "AOWDT", + "MCCPLEXWDT", + "BPMPWDT", + "SCEWDT", + "SPEWDT", + "APEWDT", + "BCCPLEXWDT", + "SENSOR", + "AOTAG", + "VFSENSOR", + "SWREST", + "SC7", + "HSM", + "CORESIGHT" +}; + +static const char * const tegra186_reset_levels[] = { + "L0", "L1", "L2", "WARM" +}; + +static const char * const tegra30_reset_sources[] = { + "POWER_ON_RESET", + "WATCHDOG", + "SENSOR", + "SW_MAIN", + "LP0", + "AOTAG" }; /** @@ -1527,6 +1568,56 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) return err; } +static ssize_t reset_reason_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value, rst_src; + + value = tegra_pmc_readl(pmc->soc->regs->rst_status); + rst_src = (value & pmc->soc->regs->rst_source_mask) >> + pmc->soc->regs->rst_source_shift; + + return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]); +} + +static DEVICE_ATTR_RO(reset_reason); + +static ssize_t reset_level_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u32 value, rst_lvl; + + value = tegra_pmc_readl(pmc->soc->regs->rst_status); + rst_lvl = (value & pmc->soc->regs->rst_level_mask) >> + pmc->soc->regs->rst_level_shift; + + return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]); +} + +static DEVICE_ATTR_RO(reset_level); + +static void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc) +{ + struct device *dev = pmc->dev; + int err = 0; + + if (pmc->soc->reset_sources) { + err = device_create_file(dev, &dev_attr_reset_reason); + if (err < 0) + dev_warn(dev, + "failed to create attr \"reset_reason\": %d\n", + err); + } + + if (pmc->soc->reset_levels) { + err = device_create_file(dev, &dev_attr_reset_level); + if (err < 0) + dev_warn(dev, + "failed to create attr \"reset_level\": %d\n", + err); + } +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base; @@ -1596,6 +1687,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) tegra_pmc_init_tsense_reset(pmc); + tegra_pmc_reset_sysfs_init(pmc); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_powergate_debugfs_init(); if (err < 0) @@ -1662,6 +1755,11 @@ static const struct tegra_pmc_regs tegra20_pmc_regs = { .dpd_status = 0x1bc, .dpd2_req = 0x1c0, .dpd2_status = 0x1c4, + .rst_status = 0x1b4, + .rst_source_shift = 0x0, + .rst_source_mask = 0x7, + .rst_level_shift = 0x0, + .rst_level_mask = 0x0, }; static void tegra20_pmc_init(struct tegra_pmc *pmc) @@ -1719,6 +1817,10 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .reset_sources = NULL, + .num_reset_sources = 0, + .reset_levels = NULL, + .num_reset_levels = 0, }; static const char * const tegra30_powergates[] = { @@ -1760,6 +1862,10 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .reset_sources = tegra30_reset_sources, + .num_reset_sources = 5, + .reset_levels = NULL, + .num_reset_levels = 0, }; static const char * const tegra114_powergates[] = { @@ -1805,6 +1911,10 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .reset_sources = tegra30_reset_sources, + .num_reset_sources = 5, + .reset_levels = NULL, + .num_reset_levels = 0, }; static const char * const tegra124_powergates[] = { @@ -1910,6 +2020,10 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .reset_sources = tegra30_reset_sources, + .num_reset_sources = 5, + .reset_levels = NULL, + .num_reset_levels = 0, }; static const char * const tegra210_powergates[] = { @@ -2011,6 +2125,10 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .regs = &tegra20_pmc_regs, .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, + .reset_sources = tegra30_reset_sources, + .num_reset_sources = 5, + .reset_levels = NULL, + .num_reset_levels = 0, }; #define TEGRA186_IO_PAD_TABLE(_pad) \ @@ -2068,6 +2186,11 @@ static const struct tegra_pmc_regs tegra186_pmc_regs = { .dpd_status = 0x78, .dpd2_req = 0x7c, .dpd2_status = 0x80, + .rst_status = 0x70, + .rst_source_shift = 0x2, + .rst_source_mask = 0x3C, + .rst_level_shift = 0x0, + .rst_level_mask = 0x3, }; static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, @@ -2120,6 +2243,10 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .regs = &tegra186_pmc_regs, .init = NULL, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .reset_sources = tegra186_reset_sources, + .num_reset_sources = 14, + .reset_levels = tegra186_reset_levels, + .num_reset_levels = 3, }; static const struct of_device_id tegra_pmc_match[] = { From b6e1fd17a38bd1d97c11d69fd3207b3ef9bfa4b3 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 21 Oct 2018 21:36:14 +0300 Subject: [PATCH 16/73] soc/tegra: pmc: Drop locking from tegra_powergate_is_powered() This fixes splats like the one below if CONFIG_DEBUG_ATOMIC_SLEEP=y and machine (Tegra30) booted with SMP=n or all secondary CPU's are put offline. Locking isn't needed because it protects atomic operation. BUG: sleeping function called from invalid context at kernel/locking/mutex.c:254 in_atomic(): 1, irqs_disabled(): 128, pid: 0, name: swapper/0 CPU: 0 PID: 0 Comm: swapper/0 Tainted: G C 4.18.0-next-20180821-00180-gc3ebb6544e44-dirty #823 Hardware name: NVIDIA Tegra SoC (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x20/0x24) [] (show_stack) from [] (dump_stack+0x94/0xa8) [] (dump_stack) from [] (___might_sleep+0x13c/0x174) [] (___might_sleep) from [] (__might_sleep+0x70/0xa8) [] (__might_sleep) from [] (mutex_lock+0x2c/0x70) [] (mutex_lock) from [] (tegra_powergate_is_powered+0x44/0xa8) [] (tegra_powergate_is_powered) from [] (tegra30_cpu_rail_off_ready+0x30/0x74) [] (tegra30_cpu_rail_off_ready) from [] (tegra30_idle_lp2+0xa0/0x108) [] (tegra30_idle_lp2) from [] (cpuidle_enter_state+0x140/0x540) [] (cpuidle_enter_state) from [] (cpuidle_enter+0x40/0x4c) [] (cpuidle_enter) from [] (call_cpuidle+0x30/0x48) [] (call_cpuidle) from [] (do_idle+0x238/0x28c) [] (do_idle) from [] (cpu_startup_entry+0x28/0x2c) [] (cpu_startup_entry) from [] (rest_init+0xd8/0xdc) [] (rest_init) from [] (start_kernel+0x41c/0x430) Signed-off-by: Dmitry Osipenko Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 22c28a4ace4d..bb76aec4bafe 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -579,16 +579,10 @@ EXPORT_SYMBOL(tegra_powergate_power_off); */ int tegra_powergate_is_powered(unsigned int id) { - int status; - if (!tegra_powergate_is_valid(id)) return -EINVAL; - mutex_lock(&pmc->powergates_lock); - status = tegra_powergate_state(id); - mutex_unlock(&pmc->powergates_lock); - - return status; + return tegra_powergate_state(id); } /** From 1866d58be7ec02b656ef913a46eb1f0c5ff2b25f Mon Sep 17 00:00:00 2001 From: Bo Yan Date: Tue, 13 Nov 2018 09:51:05 -0800 Subject: [PATCH 17/73] soc/tegra: fuse: Remove duplicated function declaration The function tegra_read_chipid() is declared twice in fuse.h. Remove the redundant declaration. Signed-off-by: Bo Yan Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- include/soc/tegra/fuse.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/soc/tegra/fuse.h b/include/soc/tegra/fuse.h index 9b6ea0c72117..8fb2f8a87339 100644 --- a/include/soc/tegra/fuse.h +++ b/include/soc/tegra/fuse.h @@ -60,7 +60,6 @@ struct tegra_sku_info { u32 tegra_read_straps(void); u32 tegra_read_ram_code(void); -u32 tegra_read_chipid(void); int tegra_fuse_readl(unsigned long offset, u32 *value); extern struct tegra_sku_info tegra_sku_info; From c800cd7824bd8ceb1291f90e3f124c9172f59177 Mon Sep 17 00:00:00 2001 From: "A.s. Dong" Date: Thu, 1 Nov 2018 15:20:13 +0000 Subject: [PATCH 18/73] firmware: imx: add SCU power domain driver Some i.MX SoCs contain a system controller that is responsible for controlling the state of the IPs that are present. Communication between the host processor running an OS and the system controller happens through a SCU protocol. This patch adds SCU protocol based power domains drivers. Cc: Ulf Hansson Cc: Rob Herring Cc: Shawn Guo Cc: Sascha Hauer Cc: Fabio Estevam Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Signed-off-by: Dong Aisheng Reviewed-by: Ulf Hansson Signed-off-by: Shawn Guo --- drivers/firmware/imx/Kconfig | 6 + drivers/firmware/imx/Makefile | 3 +- drivers/firmware/imx/scu-pd.c | 339 ++++++++++++++++++++++++++++++++++ 3 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/imx/scu-pd.c diff --git a/drivers/firmware/imx/Kconfig b/drivers/firmware/imx/Kconfig index b170c2851e48..6a7a7c2c5b5f 100644 --- a/drivers/firmware/imx/Kconfig +++ b/drivers/firmware/imx/Kconfig @@ -9,3 +9,9 @@ config IMX_SCU This driver manages the IPC interface between host CPU and the SCU firmware running on M4. + +config IMX_SCU_PD + bool "IMX SCU Power Domain driver" + depends on IMX_SCU + help + The System Controller Firmware (SCFW) based power domain driver. diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 0ac04dfda8d4..1b2e15b3c9ca 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o +obj-$(CONFIG_IMX_SCU) += imx-scu.o misc.o +obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c new file mode 100644 index 000000000000..407245f2efd0 --- /dev/null +++ b/drivers/firmware/imx/scu-pd.c @@ -0,0 +1,339 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * Copyright 2017-2018 NXP + * Dong Aisheng + * + * Implementation of the SCU based Power Domains + * + * NOTE: a better implementation suggested by Ulf Hansson is using a + * single global power domain and implement the ->attach|detach_dev() + * callback for the genpd and use the regular of_genpd_add_provider_simple(). + * From within the ->attach_dev(), we could get the OF node for + * the device that is being attached and then parse the power-domain + * cell containing the "resource id" and store that in the per device + * struct generic_pm_domain_data (we have void pointer there for + * storing these kind of things). + * + * Additionally, we need to implement the ->stop() and ->start() + * callbacks of genpd, which is where you "power on/off" devices, + * rather than using the above ->power_on|off() callbacks. + * + * However, there're two known issues: + * 1. The ->attach_dev() of power domain infrastructure still does + * not support multi domains case as the struct device *dev passed + * in is a virtual PD device, it does not help for parsing the real + * device resource id from device tree, so it's unware of which + * real sub power domain of device should be attached. + * + * The framework needs some proper extension to support multi power + * domain cases. + * + * 2. It also breaks most of current drivers as the driver probe sequence + * behavior changed if removing ->power_on|off() callback and use + * ->start() and ->stop() instead. genpd_dev_pm_attach will only power + * up the domain and attach device, but will not call .start() which + * relies on device runtime pm. That means the device power is still + * not up before running driver probe function. For SCU enabled + * platforms, all device drivers accessing registers/clock without power + * domain enabled will trigger a HW access error. That means we need fix + * most drivers probe sequence with proper runtime pm. + * + * In summary, we need fix above two issue before being able to switch to + * the "single global power domain" way. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* SCU Power Mode Protocol definition */ +struct imx_sc_msg_req_set_resource_power_mode { + struct imx_sc_rpc_msg hdr; + u16 resource; + u8 mode; +} __packed; + +#define IMX_SCU_PD_NAME_SIZE 20 +struct imx_sc_pm_domain { + struct generic_pm_domain pd; + char name[IMX_SCU_PD_NAME_SIZE]; + u32 rsrc; +}; + +struct imx_sc_pd_range { + char *name; + u32 rsrc; + u8 num; + bool postfix; +}; + +struct imx_sc_pd_soc { + const struct imx_sc_pd_range *pd_ranges; + u8 num_ranges; +}; + +static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { + /* LSIO SS */ + { "lsio-pwm", IMX_SC_R_PWM_0, 8, 1 }, + { "lsio-gpio", IMX_SC_R_GPIO_0, 8, 1 }, + { "lsio-gpt", IMX_SC_R_GPT_0, 5, 1 }, + { "lsio-kpp", IMX_SC_R_KPP, 1, 0 }, + { "lsio-fspi", IMX_SC_R_FSPI_0, 2, 1 }, + { "lsio-mu", IMX_SC_R_MU_0A, 14, 1 }, + + /* CONN SS */ + { "con-usb", IMX_SC_R_USB_0, 2, 1 }, + { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, 0 }, + { "con-usb2", IMX_SC_R_USB_2, 1, 0 }, + { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, 0 }, + { "con-sdhc", IMX_SC_R_SDHC_0, 3, 1 }, + { "con-enet", IMX_SC_R_ENET_0, 2, 1 }, + { "con-nand", IMX_SC_R_NAND, 1, 0 }, + { "con-mlb", IMX_SC_R_MLB_0, 1, 1 }, + + /* Audio DMA SS */ + { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, 0 }, + { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, 0 }, + { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, 0 }, + { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, 1 }, + { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, 1 }, + { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, 1 }, + { "adma-asrc0", IMX_SC_R_ASRC_0, 1, 0 }, + { "adma-asrc1", IMX_SC_R_ASRC_1, 1, 0 }, + { "adma-esai0", IMX_SC_R_ESAI_0, 1, 0 }, + { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, 0 }, + { "adma-sai", IMX_SC_R_SAI_0, 3, 1 }, + { "adma-amix", IMX_SC_R_AMIX, 1, 0 }, + { "adma-mqs0", IMX_SC_R_MQS_0, 1, 0 }, + { "adma-dsp", IMX_SC_R_DSP, 1, 0 }, + { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, 0 }, + { "adma-can", IMX_SC_R_CAN_0, 3, 1 }, + { "adma-ftm", IMX_SC_R_FTM_0, 2, 1 }, + { "adma-lpi2c", IMX_SC_R_I2C_0, 4, 1 }, + { "adma-adc", IMX_SC_R_ADC_0, 1, 1 }, + { "adma-lcd", IMX_SC_R_LCD_0, 1, 1 }, + { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, 1 }, + { "adma-lpuart", IMX_SC_R_UART_0, 4, 1 }, + { "adma-lpspi", IMX_SC_R_SPI_0, 4, 1 }, + + /* VPU SS */ + { "vpu", IMX_SC_R_VPU, 1, 0 }, + { "vpu-pid", IMX_SC_R_VPU_PID0, 8, 1 }, + { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, 0 }, + { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, 0 }, + + /* GPU SS */ + { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 }, + + /* HSIO SS */ + { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, 0 }, + { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, 0 }, + { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, 0 }, + + /* MIPI/LVDS SS */ + { "mipi0", IMX_SC_R_MIPI_0, 1, 0 }, + { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, 0 }, + { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, 1 }, + { "lvds0", IMX_SC_R_LVDS_0, 1, 0 }, + + /* DC SS */ + { "dc0", IMX_SC_R_DC_0, 1, 0 }, + { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 }, +}; + +static const struct imx_sc_pd_soc imx8qxp_scu_pd = { + .pd_ranges = imx8qxp_scu_pd_ranges, + .num_ranges = ARRAY_SIZE(imx8qxp_scu_pd_ranges), +}; + +static struct imx_sc_ipc *pm_ipc_handle; + +static inline struct imx_sc_pm_domain * +to_imx_sc_pd(struct generic_pm_domain *genpd) +{ + return container_of(genpd, struct imx_sc_pm_domain, pd); +} + +static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on) +{ + struct imx_sc_msg_req_set_resource_power_mode msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + struct imx_sc_pm_domain *pd; + int ret; + + pd = to_imx_sc_pd(domain); + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_PM; + hdr->func = IMX_SC_PM_FUNC_SET_RESOURCE_POWER_MODE; + hdr->size = 2; + + msg.resource = pd->rsrc; + msg.mode = power_on ? IMX_SC_PM_PW_MODE_ON : IMX_SC_PM_PW_MODE_LP; + + ret = imx_scu_call_rpc(pm_ipc_handle, &msg, true); + if (ret) + dev_err(&domain->dev, "failed to power %s resource %d ret %d\n", + power_on ? "up" : "off", pd->rsrc, ret); + + return ret; +} + +static int imx_sc_pd_power_on(struct generic_pm_domain *domain) +{ + return imx_sc_pd_power(domain, true); +} + +static int imx_sc_pd_power_off(struct generic_pm_domain *domain) +{ + return imx_sc_pd_power(domain, false); +} + +static struct generic_pm_domain *imx_scu_pd_xlate(struct of_phandle_args *spec, + void *data) +{ + struct generic_pm_domain *domain = ERR_PTR(-ENOENT); + struct genpd_onecell_data *pd_data = data; + unsigned int i; + + for (i = 0; i < pd_data->num_domains; i++) { + struct imx_sc_pm_domain *sc_pd; + + sc_pd = to_imx_sc_pd(pd_data->domains[i]); + if (sc_pd->rsrc == spec->args[0]) { + domain = &sc_pd->pd; + break; + } + } + + return domain; +} + +static struct imx_sc_pm_domain * +imx_scu_add_pm_domain(struct device *dev, int idx, + const struct imx_sc_pd_range *pd_ranges) +{ + struct imx_sc_pm_domain *sc_pd; + int ret; + + sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL); + if (!sc_pd) + return ERR_PTR(-ENOMEM); + + sc_pd->rsrc = pd_ranges->rsrc + idx; + sc_pd->pd.power_off = imx_sc_pd_power_off; + sc_pd->pd.power_on = imx_sc_pd_power_on; + + if (pd_ranges->postfix) + snprintf(sc_pd->name, sizeof(sc_pd->name), + "%s%i", pd_ranges->name, idx); + else + snprintf(sc_pd->name, sizeof(sc_pd->name), + "%s", pd_ranges->name); + + sc_pd->pd.name = sc_pd->name; + + if (sc_pd->rsrc >= IMX_SC_R_LAST) { + dev_warn(dev, "invalid pd %s rsrc id %d found", + sc_pd->name, sc_pd->rsrc); + + devm_kfree(dev, sc_pd); + return NULL; + } + + ret = pm_genpd_init(&sc_pd->pd, NULL, true); + if (ret) { + dev_warn(dev, "failed to init pd %s rsrc id %d", + sc_pd->name, sc_pd->rsrc); + devm_kfree(dev, sc_pd); + return NULL; + } + + return sc_pd; +} + +static int imx_scu_init_pm_domains(struct device *dev, + const struct imx_sc_pd_soc *pd_soc) +{ + const struct imx_sc_pd_range *pd_ranges = pd_soc->pd_ranges; + struct generic_pm_domain **domains; + struct genpd_onecell_data *pd_data; + struct imx_sc_pm_domain *sc_pd; + u32 count = 0; + int i, j; + + for (i = 0; i < pd_soc->num_ranges; i++) + count += pd_ranges[i].num; + + domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL); + if (!domains) + return -ENOMEM; + + pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL); + if (!pd_data) + return -ENOMEM; + + count = 0; + for (i = 0; i < pd_soc->num_ranges; i++) { + for (j = 0; j < pd_ranges[i].num; j++) { + sc_pd = imx_scu_add_pm_domain(dev, j, &pd_ranges[i]); + if (IS_ERR_OR_NULL(sc_pd)) + continue; + + domains[count++] = &sc_pd->pd; + dev_dbg(dev, "added power domain %s\n", sc_pd->pd.name); + } + } + + pd_data->domains = domains; + pd_data->num_domains = count; + pd_data->xlate = imx_scu_pd_xlate; + + of_genpd_add_provider_onecell(dev->of_node, pd_data); + + return 0; +} + +static int imx_sc_pd_probe(struct platform_device *pdev) +{ + const struct imx_sc_pd_soc *pd_soc; + int ret; + + ret = imx_scu_get_handle(&pm_ipc_handle); + if (ret) + return ret; + + pd_soc = of_device_get_match_data(&pdev->dev); + if (!pd_soc) + return -ENODEV; + + return imx_scu_init_pm_domains(&pdev->dev, pd_soc); +} + +static const struct of_device_id imx_sc_pd_match[] = { + { .compatible = "fsl,imx8qxp-scu-pd", &imx8qxp_scu_pd}, + { /* sentinel */ } +}; + +static struct platform_driver imx_sc_pd_driver = { + .driver = { + .name = "imx-scu-pd", + .of_match_table = imx_sc_pd_match, + }, + .probe = imx_sc_pd_probe, +}; +builtin_platform_driver(imx_sc_pd_driver); + +MODULE_AUTHOR("Dong Aisheng "); +MODULE_DESCRIPTION("IMX SCU Power Domain driver"); +MODULE_LICENSE("GPL v2"); From 279536a564f6479725ad23cb139783f16a974d4f Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 3 Oct 2018 17:53:50 +0530 Subject: [PATCH 19/73] soc: qcom: Add irq clear handling during SE init when the kernel inits a SE, its quite possible we have pending interrupts from bootloaders which did not handle/clear them. So do this in kernel at the SE init, to avoid some of it causing bad behavior, while at it also club all the register writes needed to clear the se irqs into a function to avoid repeating it over. Signed-off-by: Alok Chauhan Reviewed-by: Douglas Anderson Signed-off-by: Andy Gross --- drivers/soc/qcom/qcom-geni-se.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index ee89ffb6dde8..6b8ef01472e9 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -215,6 +215,16 @@ static void geni_se_io_init(void __iomem *base) writel_relaxed(FORCE_DEFAULT, base + GENI_FORCE_DEFAULT_REG); } +static void geni_se_irq_clear(struct geni_se *se) +{ + writel_relaxed(0, se->base + SE_GSI_EVENT_EN); + writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); + writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); + writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); + writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); + writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); +} + /** * geni_se_init() - Initialize the GENI serial engine * @se: Pointer to the concerned serial engine. @@ -228,6 +238,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) { u32 val; + geni_se_irq_clear(se); geni_se_io_init(se->base); geni_se_io_set_mode(se->base); @@ -249,12 +260,7 @@ static void geni_se_select_fifo_mode(struct geni_se *se) u32 proto = geni_se_read_proto(se); u32 val; - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); - writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); - writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); - writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); + geni_se_irq_clear(se); val = readl_relaxed(se->base + SE_GENI_M_IRQ_EN); if (proto != GENI_SE_UART) { @@ -277,12 +283,7 @@ static void geni_se_select_dma_mode(struct geni_se *se) { u32 val; - writel_relaxed(0, se->base + SE_GSI_EVENT_EN); - writel_relaxed(0xffffffff, se->base + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(0xffffffff, se->base + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(0xffffffff, se->base + SE_DMA_TX_IRQ_CLR); - writel_relaxed(0xffffffff, se->base + SE_DMA_RX_IRQ_CLR); - writel_relaxed(0xffffffff, se->base + SE_IRQ_EN); + geni_se_irq_clear(se); val = readl_relaxed(se->base + SE_GENI_DMA_MODE_EN); val |= GENI_DMA_MODE_EN; From 8c1919a2b48f172bfb4db5aa93d5809dd26738b3 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 6 Jul 2018 14:57:19 +0200 Subject: [PATCH 20/73] soc: qcom/llcc: add MODULE_LICENSE tag The lack of a MODULE_LICENSE tag prevents building the llcc driver as a loadable module: FATAL: modpost: GPL-incompatible module llcc-slice.ko uses GPL-only symbol 'ktime_get' This adds the appropriate license and description tags. Signed-off-by: Arnd Bergmann Signed-off-by: Andy Gross --- drivers/soc/qcom/llcc-slice.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 192ca761b2cb..7f55203d28d7 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c @@ -16,6 +16,7 @@ #include #include #include +#include #define ACTIVATE BIT(0) #define DEACTIVATE BIT(1) @@ -360,5 +361,5 @@ int qcom_llcc_probe(struct platform_device *pdev, return ret; } EXPORT_SYMBOL_GPL(qcom_llcc_probe); - MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm Last Level Cache Controller"); From e0f2cfeb59c81cbcfc7fbcb7ec0636020499813b Mon Sep 17 00:00:00 2001 From: Jordan Crouse Date: Fri, 5 Oct 2018 18:38:29 +0530 Subject: [PATCH 21/73] soc: qcom: llcc-slice: Add error checks for API functions llcc_slice_getd can return a ERR_PTR code on failure. Add a IS_ERR_OR_NULL check to subsequent API calls that use struct llcc_slice_desc to guard against faults and to let the leaf drivers get away with safely using a ERR_PTR() encoded "pointer" in the aftermath of a llcc_slice_getd error. Signed-off-by: Jordan Crouse Reviewed-by: Vivek Gautam Signed-off-by: Andy Gross --- drivers/soc/qcom/llcc-slice.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 7f55203d28d7..6a7d0162fe0e 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c @@ -96,7 +96,8 @@ EXPORT_SYMBOL_GPL(llcc_slice_getd); */ void llcc_slice_putd(struct llcc_slice_desc *desc) { - kfree(desc); + if (!IS_ERR_OR_NULL(desc)) + kfree(desc); } EXPORT_SYMBOL_GPL(llcc_slice_putd); @@ -143,6 +144,9 @@ int llcc_slice_activate(struct llcc_slice_desc *desc) int ret; u32 act_ctrl_val; + if (IS_ERR_OR_NULL(desc)) + return -EINVAL; + mutex_lock(&drv_data->lock); if (test_bit(desc->slice_id, drv_data->bitmap)) { mutex_unlock(&drv_data->lock); @@ -177,6 +181,9 @@ int llcc_slice_deactivate(struct llcc_slice_desc *desc) u32 act_ctrl_val; int ret; + if (IS_ERR_OR_NULL(desc)) + return -EINVAL; + mutex_lock(&drv_data->lock); if (!test_bit(desc->slice_id, drv_data->bitmap)) { mutex_unlock(&drv_data->lock); @@ -204,6 +211,9 @@ EXPORT_SYMBOL_GPL(llcc_slice_deactivate); */ int llcc_get_slice_id(struct llcc_slice_desc *desc) { + if (IS_ERR_OR_NULL(desc)) + return -EINVAL; + return desc->slice_id; } EXPORT_SYMBOL_GPL(llcc_get_slice_id); @@ -214,6 +224,9 @@ EXPORT_SYMBOL_GPL(llcc_get_slice_id); */ size_t llcc_get_slice_size(struct llcc_slice_desc *desc) { + if (IS_ERR_OR_NULL(desc)) + return 0; + return desc->slice_size; } EXPORT_SYMBOL_GPL(llcc_get_slice_size); From c4fe17e0e3a346cc855b7b41c00ff7b04c56d32b Mon Sep 17 00:00:00 2001 From: Arun Kumar Neelakantam Date: Wed, 3 Oct 2018 11:10:02 +0530 Subject: [PATCH 22/73] soc: qcom: qmi_interface: Limit txn ids to U16_MAX Txn IDs created up to INT_MAX cause overflow while storing the IDs in u16 type supported by QMI header. Limit the txn IDs max value to U16_MAX to avoid overflow. Signed-off-by: Arun Kumar Neelakantam Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/qmi_interface.c | 2 +- include/linux/soc/qcom/qmi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 938ca41c56cd..c239a28e503f 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -318,7 +318,7 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, txn->dest = c_struct; mutex_lock(&qmi->txn_lock); - ret = idr_alloc_cyclic(&qmi->txns, txn, 0, INT_MAX, GFP_KERNEL); + ret = idr_alloc_cyclic(&qmi->txns, txn, 0, U16_MAX, GFP_KERNEL); if (ret < 0) pr_err("failed to allocate transaction id\n"); diff --git a/include/linux/soc/qcom/qmi.h b/include/linux/soc/qcom/qmi.h index f4de33654a60..5efa2b67fa55 100644 --- a/include/linux/soc/qcom/qmi.h +++ b/include/linux/soc/qcom/qmi.h @@ -166,7 +166,7 @@ struct qmi_ops { struct qmi_txn { struct qmi_handle *qmi; - int id; + u16 id; struct mutex lock; struct completion completion; From 808e10330b0a0bebed8fa3c6bb4e8fe728ca2c2a Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 1 Oct 2018 11:55:54 +0200 Subject: [PATCH 23/73] soc: qcom: Drop help text for QCOM_QMI_HELPERS The help text is visible in menuconfig, however QCOM_QMI_HELPERS is a hidden kconfig, so it is not selectable in menuconfig. Remove the help text so that it is more clear that this is intentionally a hidden kconfig. Signed-off-by: Niklas Cassel Reviewed-by: Alex Elder Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/Kconfig | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 684cb51694d1..fcbf8a2e4080 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -75,11 +75,6 @@ config QCOM_QMI_HELPERS tristate depends on ARCH_QCOM || COMPILE_TEST depends on NET - help - Helper library for handling QMI encoded messages. QMI encoded - messages are used in communication between the majority of QRTR - clients and this helpers provide the common functionality needed for - doing this from a kernel driver. config QCOM_RMTFS_MEM tristate "Qualcomm Remote Filesystem memory driver" From 84fa36eb30f2e02ebf07a22fea2550a7a3938bec Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 26 Sep 2018 11:02:33 -0700 Subject: [PATCH 24/73] soc: qcom: cmd-db: Remove memcpy()ing from cmd_db_get_header() The cmd_db_get_header() function is a static local function that doesn't need to copy anything from one place to another. Instead, it can just point into the region by returning pointers to what we're looking for. If we do that, we should mark what we're returning as const so that code can't modify cmd-db without an obvious cast. Cc: Mahesh Sivasubramanian Cc: Lina Iyer Cc: Bjorn Andersson Cc: Evan Green Signed-off-by: Stephen Boyd Signed-off-by: Andy Gross --- drivers/soc/qcom/cmd-db.c | 60 +++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index a6f646295f06..5c9cc6824891 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -101,8 +101,7 @@ static bool cmd_db_magic_matches(const struct cmd_db_header *header) static struct cmd_db_header *cmd_db_header; - -static inline void *rsc_to_entry_header(struct rsc_hdr *hdr) +static inline const void *rsc_to_entry_header(const struct rsc_hdr *hdr) { u16 offset = le16_to_cpu(hdr->header_offset); @@ -110,7 +109,7 @@ static inline void *rsc_to_entry_header(struct rsc_hdr *hdr) } static inline void * -rsc_offset(struct rsc_hdr *hdr, struct entry_header *ent) +rsc_offset(const struct rsc_hdr *hdr, const struct entry_header *ent) { u16 offset = le16_to_cpu(hdr->data_offset); u16 loffset = le16_to_cpu(ent->offset); @@ -134,11 +133,11 @@ int cmd_db_ready(void) } EXPORT_SYMBOL(cmd_db_ready); -static int cmd_db_get_header(const char *id, struct entry_header *eh, - struct rsc_hdr *rh) +static int cmd_db_get_header(const char *id, const struct entry_header **eh, + const struct rsc_hdr **rh) { - struct rsc_hdr *rsc_hdr; - struct entry_header *ent; + const struct rsc_hdr *rsc_hdr; + const struct entry_header *ent; int ret, i, j; u8 query[8]; @@ -146,9 +145,6 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh, if (ret) return ret; - if (!eh || !rh) - return -EINVAL; - /* Pad out query string to same length as in DB */ strncpy(query, id, sizeof(query)); @@ -159,14 +155,13 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh, ent = rsc_to_entry_header(rsc_hdr); for (j = 0; j < le16_to_cpu(rsc_hdr->cnt); j++, ent++) { - if (memcmp(ent->id, query, sizeof(ent->id)) == 0) - break; - } - - if (j < le16_to_cpu(rsc_hdr->cnt)) { - memcpy(eh, ent, sizeof(*ent)); - memcpy(rh, rsc_hdr, sizeof(*rh)); - return 0; + if (memcmp(ent->id, query, sizeof(ent->id)) == 0) { + if (eh) + *eh = ent; + if (rh) + *rh = rsc_hdr; + return 0; + } } } @@ -186,12 +181,11 @@ static int cmd_db_get_header(const char *id, struct entry_header *eh, u32 cmd_db_read_addr(const char *id) { int ret; - struct entry_header ent; - struct rsc_hdr rsc_hdr; + const struct entry_header *ent; - ret = cmd_db_get_header(id, &ent, &rsc_hdr); + ret = cmd_db_get_header(id, &ent, NULL); - return ret < 0 ? 0 : le32_to_cpu(ent.addr); + return ret < 0 ? 0 : le32_to_cpu(ent->addr); } EXPORT_SYMBOL(cmd_db_read_addr); @@ -207,8 +201,8 @@ EXPORT_SYMBOL(cmd_db_read_addr); int cmd_db_read_aux_data(const char *id, u8 *data, size_t len) { int ret; - struct entry_header ent; - struct rsc_hdr rsc_hdr; + const struct entry_header *ent; + const struct rsc_hdr *rsc_hdr; u16 ent_len; if (!data) @@ -218,12 +212,12 @@ int cmd_db_read_aux_data(const char *id, u8 *data, size_t len) if (ret) return ret; - ent_len = le16_to_cpu(ent.len); + ent_len = le16_to_cpu(ent->len); if (len < ent_len) return -EINVAL; len = min_t(u16, ent_len, len); - memcpy(data, rsc_offset(&rsc_hdr, &ent), len); + memcpy(data, rsc_offset(rsc_hdr, ent), len); return len; } @@ -239,12 +233,11 @@ EXPORT_SYMBOL(cmd_db_read_aux_data); size_t cmd_db_read_aux_data_len(const char *id) { int ret; - struct entry_header ent; - struct rsc_hdr rsc_hdr; + const struct entry_header *ent; - ret = cmd_db_get_header(id, &ent, &rsc_hdr); + ret = cmd_db_get_header(id, &ent, NULL); - return ret < 0 ? 0 : le16_to_cpu(ent.len); + return ret < 0 ? 0 : le16_to_cpu(ent->len); } EXPORT_SYMBOL(cmd_db_read_aux_data_len); @@ -258,15 +251,14 @@ EXPORT_SYMBOL(cmd_db_read_aux_data_len); enum cmd_db_hw_type cmd_db_read_slave_id(const char *id) { int ret; - struct entry_header ent; - struct rsc_hdr rsc_hdr; + const struct entry_header *ent; u32 addr; - ret = cmd_db_get_header(id, &ent, &rsc_hdr); + ret = cmd_db_get_header(id, &ent, NULL); if (ret < 0) return CMD_DB_HW_INVALID; - addr = le32_to_cpu(ent.addr); + addr = le32_to_cpu(ent->addr); return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK; } EXPORT_SYMBOL(cmd_db_read_slave_id); From ed3cafa79ea756be653d22087c017af95ea78a49 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Wed, 26 Sep 2018 11:02:34 -0700 Subject: [PATCH 25/73] soc: qcom: cmd-db: Stop memcpy()ing in cmd_db_read_aux_data() Let's change the function signature to return the pointer to memory or an error pointer on failure, and take an argument that lets us return the size of the aux data read. This way we can remove the cmd_db_read_aux_data_len() API entirely and also get rid of the memcpy operation from cmd_db to the caller. Updating the only user of this code shows that making this change allows us to remove a function and put the lookup where the user is. Cc: Mahesh Sivasubramanian Cc: Lina Iyer Cc: Bjorn Andersson Cc: Evan Green Cc: Jordan Crouse Cc: Rob Clark Signed-off-by: Stephen Boyd Signed-off-by: Andy Gross --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 54 ++++++++++----------------- drivers/soc/qcom/cmd-db.c | 43 ++++----------------- include/soc/qcom/cmd-db.h | 12 ++---- 3 files changed, 30 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index d4e98e5876bc..546599a7ab05 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -902,26 +902,6 @@ static int a6xx_gmu_memory_probe(struct a6xx_gmu *gmu) return ret; } -/* Get the list of RPMh voltage levels from cmd-db */ -static int a6xx_gmu_rpmh_arc_cmds(const char *id, void *vals, int size) -{ - u32 len = cmd_db_read_aux_data_len(id); - - if (!len) - return 0; - - if (WARN_ON(len > size)) - return -EINVAL; - - cmd_db_read_aux_data(id, vals, len); - - /* - * The data comes back as an array of unsigned shorts so adjust the - * count accordingly - */ - return len >> 1; -} - /* Return the 'arc-level' for the given frequency */ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) { @@ -949,11 +929,25 @@ static u32 a6xx_gmu_get_arc_level(struct device *dev, unsigned long freq) } static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, - unsigned long *freqs, int freqs_count, - u16 *pri, int pri_count, - u16 *sec, int sec_count) + unsigned long *freqs, int freqs_count, const char *id) { int i, j; + const u16 *pri, *sec; + size_t pri_count, sec_count; + + pri = cmd_db_read_aux_data(id, &pri_count); + /* + * The data comes back as an array of unsigned shorts so adjust the + * count accordingly + */ + pri_count >>= 1; + if (!pri_count) + return -EINVAL; + + sec = cmd_db_read_aux_data("mx.lvl", &sec_count); + sec_count >>= 1; + if (!sec_count) + return -EINVAL; /* Construct a vote for each frequency */ for (i = 0; i < freqs_count; i++) { @@ -1012,25 +1006,15 @@ static int a6xx_gmu_rpmh_votes_init(struct a6xx_gmu *gmu) struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; struct msm_gpu *gpu = &adreno_gpu->base; - - u16 gx[16], cx[16], mx[16]; - u32 gxcount, cxcount, mxcount; int ret; - /* Get the list of available voltage levels for each component */ - gxcount = a6xx_gmu_rpmh_arc_cmds("gfx.lvl", gx, sizeof(gx)); - cxcount = a6xx_gmu_rpmh_arc_cmds("cx.lvl", cx, sizeof(cx)); - mxcount = a6xx_gmu_rpmh_arc_cmds("mx.lvl", mx, sizeof(mx)); - /* Build the GX votes */ ret = a6xx_gmu_rpmh_arc_votes_init(&gpu->pdev->dev, gmu->gx_arc_votes, - gmu->gpu_freqs, gmu->nr_gpu_freqs, - gx, gxcount, mx, mxcount); + gmu->gpu_freqs, gmu->nr_gpu_freqs, "gfx.lvl"); /* Build the CX votes */ ret |= a6xx_gmu_rpmh_arc_votes_init(gmu->dev, gmu->cx_arc_votes, - gmu->gmu_freqs, gmu->nr_gmu_freqs, - cx, cxcount, mx, mxcount); + gmu->gmu_freqs, gmu->nr_gmu_freqs, "cx.lvl"); return ret; } diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index 5c9cc6824891..c701b3b010f1 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -192,55 +192,28 @@ EXPORT_SYMBOL(cmd_db_read_addr); /** * cmd_db_read_aux_data() - Query command db for aux data. * - * @id: Resource to retrieve AUX Data on. - * @data: Data buffer to copy returned aux data to. Returns size on NULL - * @len: Caller provides size of data buffer passed in. + * @id: Resource to retrieve AUX Data on + * @len: size of data buffer returned * - * Return: size of data on success, errno otherwise + * Return: pointer to data on success, error pointer otherwise */ -int cmd_db_read_aux_data(const char *id, u8 *data, size_t len) +const void *cmd_db_read_aux_data(const char *id, size_t *len) { int ret; const struct entry_header *ent; const struct rsc_hdr *rsc_hdr; - u16 ent_len; - - if (!data) - return -EINVAL; ret = cmd_db_get_header(id, &ent, &rsc_hdr); if (ret) - return ret; + return ERR_PTR(ret); - ent_len = le16_to_cpu(ent->len); - if (len < ent_len) - return -EINVAL; + if (len) + *len = le16_to_cpu(ent->len); - len = min_t(u16, ent_len, len); - memcpy(data, rsc_offset(rsc_hdr, ent), len); - - return len; + return rsc_offset(rsc_hdr, ent); } EXPORT_SYMBOL(cmd_db_read_aux_data); -/** - * cmd_db_read_aux_data_len - Get the length of the auxiliary data stored in DB. - * - * @id: Resource to retrieve AUX Data. - * - * Return: size on success, 0 on error - */ -size_t cmd_db_read_aux_data_len(const char *id) -{ - int ret; - const struct entry_header *ent; - - ret = cmd_db_get_header(id, &ent, NULL); - - return ret < 0 ? 0 : le16_to_cpu(ent->len); -} -EXPORT_SYMBOL(cmd_db_read_aux_data_len); - /** * cmd_db_read_slave_id - Get the slave ID for a given resource address * diff --git a/include/soc/qcom/cmd-db.h b/include/soc/qcom/cmd-db.h index 578180cbc134..af9722223925 100644 --- a/include/soc/qcom/cmd-db.h +++ b/include/soc/qcom/cmd-db.h @@ -18,9 +18,7 @@ enum cmd_db_hw_type { #if IS_ENABLED(CONFIG_QCOM_COMMAND_DB) u32 cmd_db_read_addr(const char *resource_id); -int cmd_db_read_aux_data(const char *resource_id, u8 *data, size_t len); - -size_t cmd_db_read_aux_data_len(const char *resource_id); +const void *cmd_db_read_aux_data(const char *resource_id, size_t *len); enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id); @@ -29,12 +27,8 @@ int cmd_db_ready(void); static inline u32 cmd_db_read_addr(const char *resource_id) { return 0; } -static inline int cmd_db_read_aux_data(const char *resource_id, u8 *data, - size_t len) -{ return -ENODEV; } - -static inline size_t cmd_db_read_aux_data_len(const char *resource_id) -{ return -ENODEV; } +static inline const void *cmd_db_read_aux_data(const char *resource_id, size_t *len) +{ return ERR_PTR(-ENODEV); } static inline enum cmd_db_hw_type cmd_db_read_slave_id(const char *resource_id) { return -ENODEV; } From 0829187b17d8019f9bb40c56d47f37b1991a2189 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Sat, 6 Oct 2018 13:31:56 +0200 Subject: [PATCH 26/73] firmware: raspberrypi: Define timeout for transactions We should never assume to get a reply from the firmware otherwise the call could block forever and the user don't get informed. So define a timeout of 1 sec and print a stacktrace once in the unlikely case the timeout expired. Signed-off-by: Stefan Wahren Reviewed-by: Eric Anholt --- drivers/firmware/raspberrypi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index a200a2174611..bf45ac450954 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -56,8 +56,12 @@ rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data) reinit_completion(&fw->c); ret = mbox_send_message(fw->chan, &message); if (ret >= 0) { - wait_for_completion(&fw->c); - ret = 0; + if (wait_for_completion_timeout(&fw->c, HZ)) { + ret = 0; + } else { + ret = -ETIMEDOUT; + WARN_ONCE(1, "Firmware transaction timeout"); + } } else { dev_err(fw->cl.dev, "mbox_send_message returned %d\n", ret); } From bb661b70883717154e194cad544e2b9c25895268 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 22 Oct 2018 22:35:02 +0200 Subject: [PATCH 27/73] soc: bcm: Switch raspberrypi-power to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Cc: Alexander Aring Cc: Eric Anholt Signed-off-by: Stefan Wahren Reviewed-by: Eric Anholt --- drivers/soc/bcm/raspberrypi-power.c | 5 +---- include/dt-bindings/power/raspberrypi-power.h | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/soc/bcm/raspberrypi-power.c b/drivers/soc/bcm/raspberrypi-power.c index a78dfe0a2b50..5d1aacdd84ef 100644 --- a/drivers/soc/bcm/raspberrypi-power.c +++ b/drivers/soc/bcm/raspberrypi-power.c @@ -1,8 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 /* (C) 2015 Pengutronix, Alexander Aring - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. * * Authors: * Alexander Aring diff --git a/include/dt-bindings/power/raspberrypi-power.h b/include/dt-bindings/power/raspberrypi-power.h index b3ff8e09a78f..3575f9f4b0bd 100644 --- a/include/dt-bindings/power/raspberrypi-power.h +++ b/include/dt-bindings/power/raspberrypi-power.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright © 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef _DT_BINDINGS_ARM_BCM2835_RPI_POWER_H From 41bb5769b7f4b7a85e4b92c37429228279b4f569 Mon Sep 17 00:00:00 2001 From: Maxime Jourdan Date: Mon, 12 Nov 2018 17:46:54 +0100 Subject: [PATCH 28/73] drivers: soc: Allow building the amlogic drivers without ARCH_MESON The current condition makes it difficult to compile the amlogic/ drivers with COMPILE_TEST, or without ARCH_MESON in general. Fixes kbuild errors with patch series that depend on drivers in that directory, for instance the meson video decoder. Signed-off-by: Maxime Jourdan Signed-off-by: Kevin Hilman --- drivers/soc/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 446166ba0bec..90b686e586c6 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -13,7 +13,7 @@ obj-$(CONFIG_ARCH_GEMINI) += gemini/ obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_SOC_XWAY) += lantiq/ obj-y += mediatek/ -obj-$(CONFIG_ARCH_MESON) += amlogic/ +obj-y += amlogic/ obj-y += qcom/ obj-y += renesas/ obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ From 7b4f8ac2f1acdff3c0cce23d8c3b86434a6e768a Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Nov 2018 14:46:52 -0800 Subject: [PATCH 29/73] bus: ti-sysc: Fix getting optional clocks in clock_roles We can have holes in clock_roles with interface clock missing for example. Currently getting an optional clock will fail if there are only a functional clock and an optional clock. Fixes: 09dfe5810762 ("bus: ti-sysc: Add handling for clkctrl opt clocks") Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index a3a2d39280d9..c878dc51d7f9 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -214,8 +214,13 @@ static int sysc_get_clocks(struct sysc *ddata) if (!ddata->clocks) return -ENOMEM; - for (i = 0; i < ddata->nr_clocks; i++) { - error = sysc_get_one_clock(ddata, ddata->clock_roles[i]); + for (i = 0; i < SYSC_MAX_CLOCKS; i++) { + const char *name = ddata->clock_roles[i]; + + if (!name) + continue; + + error = sysc_get_one_clock(ddata, name); if (error && error != -ENOENT) return error; } From 2c63a833e4500b341a62bf97e67488909ae12086 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Nov 2018 14:46:53 -0800 Subject: [PATCH 30/73] bus: ti-sysc: Add mcasp optional clocks flag We have OPT_CLKS_NEEDED in legacy platform data, but it's missing from the ti-sysc driver for device tree based configuration. In order to pass OPT_CLKS_NEEDED quirk flag we need to update omap4 module data and add a new compatible for dra7 as the module layout is different from sysc_regbits_omap4_mcasp. Fixes: 70a65240efb1 ("bus: ti-sysc: Add register bits for interconnect target modules") Cc: Mark Rutland Cc: Rob Herring Signed-off-by: Tony Lindgren --- Documentation/devicetree/bindings/bus/ti-sysc.txt | 1 + drivers/bus/ti-sysc.c | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/bus/ti-sysc.txt b/Documentation/devicetree/bindings/bus/ti-sysc.txt index 91dc2333af01..85a23f551f02 100644 --- a/Documentation/devicetree/bindings/bus/ti-sysc.txt +++ b/Documentation/devicetree/bindings/bus/ti-sysc.txt @@ -35,6 +35,7 @@ Required standard properties: "ti,sysc-omap3-sham" "ti,sysc-omap-aes" "ti,sysc-mcasp" + "ti,sysc-dra7-mcasp" "ti,sysc-usb-host-fs" "ti,sysc-dra7-mcan" diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index c878dc51d7f9..64c71f0f3f59 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -1503,6 +1503,16 @@ static const struct sysc_regbits sysc_regbits_omap4_mcasp = { static const struct sysc_capabilities sysc_omap4_mcasp = { .type = TI_SYSC_OMAP4_MCASP, .regbits = &sysc_regbits_omap4_mcasp, + .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED, +}; + +/* + * McASP found on dra7 and later + */ +static const struct sysc_capabilities sysc_dra7_mcasp = { + .type = TI_SYSC_OMAP4_SIMPLE, + .regbits = &sysc_regbits_omap4_simple, + .mod_quirks = SYSC_QUIRK_OPT_CLKS_NEEDED, }; /* @@ -1731,6 +1741,7 @@ static const struct of_device_id sysc_match[] = { { .compatible = "ti,sysc-omap3-sham", .data = &sysc_omap3_sham, }, { .compatible = "ti,sysc-omap-aes", .data = &sysc_omap3_aes, }, { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, + { .compatible = "ti,sysc-dra7-mcasp", .data = &sysc_dra7_mcasp, }, { .compatible = "ti,sysc-usb-host-fs", .data = &sysc_omap4_usb_host_fs, }, { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, From f01067005ec3dc03d49e430ec91243111ce518c2 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Thu, 15 Nov 2018 14:46:53 -0800 Subject: [PATCH 31/73] bus: ti-sysc: Detect devices for debug on omap5 We want to see the names of detected devices when DEBUG is enabled. Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 64c71f0f3f59..46a6c528b543 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -820,6 +820,7 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("ocp2scp", 0, 0, 0x10, 0x14, 0x50060005, 0xfffffff0, 0), SYSC_QUIRK("ocp2scp", 0, 0, -1, -1, 0x50060007, 0xffffffff, 0), SYSC_QUIRK("padconf", 0, 0, 0x10, -1, 0x4fff0800, 0xffffffff, 0), + SYSC_QUIRK("padconf", 0, 0, -1, -1, 0x40001100, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000100, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x00004102, 0xffffffff, 0), SYSC_QUIRK("prcm", 0, 0, -1, -1, 0x40000400, 0xffffffff, 0), @@ -838,7 +839,9 @@ static const struct sysc_revision_quirk sysc_revision_quirks[] = { SYSC_QUIRK("rtc", 0, 0x74, 0x78, -1, 0x4eb01908, 0xffff00f0, 0), SYSC_QUIRK("timer32k", 0, 0, 0x4, -1, 0x00000060, 0xffffffff, 0), SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000004, 0xffffffff, 0), + SYSC_QUIRK("usbhstll", 0, 0, 0x10, 0x14, 0x00000008, 0xffffffff, 0), SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, 0x14, 0x50700100, 0xffffffff, 0), + SYSC_QUIRK("usb_host_hs", 0, 0, 0x10, -1, 0x50700101, 0xffffffff, 0), SYSC_QUIRK("usb_otg_hs", 0, 0x400, 0x404, 0x408, 0x00000050, 0xffffffff, 0), SYSC_QUIRK("wdt", 0, 0, 0x10, 0x14, 0x502a0500, 0xfffff0f0, 0), From 91c6ada69f396e663acb2b713e8acb8a9463557d Mon Sep 17 00:00:00 2001 From: James Hughes Date: Fri, 16 Nov 2018 14:39:07 +0000 Subject: [PATCH 32/73] firmware: raspberrypi: Fix firmware calls with large buffers Commit a1547e0bca51 ("firmware: raspberrypi: Remove VLA usage") moved away from VLA's to a fixed maximum size for mailbox data. However, some mailbox calls use larger data buffers than the maximum allowed in that change. This fix therefor moves from using fixed buffers to kmalloc to ensure all sizes are catered for. There is some documentation, which is somewhat out of date, on the mailbox calls here : https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface Fixes: a1547e0bca51 ("firmware: raspberrypi: Remove VLA usage") Signed-off-by: James Hughes Reviewed-by: Eric Anholt Signed-off-by: Stefan Wahren --- drivers/firmware/raspberrypi.c | 35 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index bf45ac450954..d3f7d1434657 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #define MBOX_MSG(chan, data28) (((data28) & ~0xf) | ((chan) & 0xf)) @@ -21,8 +22,6 @@ #define MBOX_DATA28(msg) ((msg) & ~0xf) #define MBOX_CHAN_PROPERTY 8 -#define MAX_RPI_FW_PROP_BUF_SIZE 32 - static struct platform_device *rpi_hwmon; struct rpi_firmware { @@ -148,28 +147,30 @@ EXPORT_SYMBOL_GPL(rpi_firmware_property_list); int rpi_firmware_property(struct rpi_firmware *fw, u32 tag, void *tag_data, size_t buf_size) { - /* Single tags are very small (generally 8 bytes), so the - * stack should be safe. - */ - u8 data[sizeof(struct rpi_firmware_property_tag_header) + - MAX_RPI_FW_PROP_BUF_SIZE]; - struct rpi_firmware_property_tag_header *header = - (struct rpi_firmware_property_tag_header *)data; + struct rpi_firmware_property_tag_header *header; int ret; - if (WARN_ON(buf_size > sizeof(data) - sizeof(*header))) - return -EINVAL; + /* Some mailboxes can use over 1k bytes. Rather than checking + * size and using stack or kmalloc depending on requirements, + * just use kmalloc. Mailboxes don't get called enough to worry + * too much about the time taken in the allocation. + */ + void *data = kmalloc(sizeof(*header) + buf_size, GFP_KERNEL); + if (!data) + return -ENOMEM; + + header = data; header->tag = tag; header->buf_size = buf_size; header->req_resp_size = 0; - memcpy(data + sizeof(struct rpi_firmware_property_tag_header), - tag_data, buf_size); + memcpy(data + sizeof(*header), tag_data, buf_size); - ret = rpi_firmware_property_list(fw, &data, buf_size + sizeof(*header)); - memcpy(tag_data, - data + sizeof(struct rpi_firmware_property_tag_header), - buf_size); + ret = rpi_firmware_property_list(fw, data, buf_size + sizeof(*header)); + + memcpy(tag_data, data + sizeof(*header), buf_size); + + kfree(data); return ret; } From 03b10fecb92143aa2599180ee2efd3388fe6ecc0 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Mon, 12 Nov 2018 10:47:40 +0530 Subject: [PATCH 33/73] soc: ti: wkup_m3: Add PRCM int16 as the wake up source Add PRCM int16 as the wake up source. Signed-off-by: Keerthy Signed-off-by: Tony Lindgren --- drivers/soc/ti/wkup_m3_ipc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index f5cb8c0af09f..d65e361c5de1 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -57,6 +57,7 @@ static struct wkup_m3_ipc *m3_ipc_state; static const struct wkup_m3_wakeup_src wakeups[] = { + {.irq_nr = 16, .src = "PRCM"}, {.irq_nr = 35, .src = "USB0_PHY"}, {.irq_nr = 36, .src = "USB1_PHY"}, {.irq_nr = 40, .src = "I2C0"}, From 502b431cda801645fd73857f7b47a4666de3cb62 Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Mon, 22 Oct 2018 22:26:24 +0200 Subject: [PATCH 34/73] firmware: raspberrypi: Switch to SPDX identifier Adopt the SPDX license identifier headers to ease license compliance management. Cc: Eric Anholt Signed-off-by: Stefan Wahren Reviewed-by: Eric Anholt --- drivers/firmware/raspberrypi.c | 5 +---- include/soc/bcm2835/raspberrypi-firmware.h | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index d3f7d1434657..a13558154ac3 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Defines interfaces for interacting wtih the Raspberry Pi firmware's * property channel. * * Copyright © 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #include diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h index c4a5c9e9fb47..4be1aa4435ae 100644 --- a/include/soc/bcm2835/raspberrypi-firmware.h +++ b/include/soc/bcm2835/raspberrypi-firmware.h @@ -1,9 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright © 2015 Broadcom - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. */ #ifndef __SOC_RASPBERRY_FIRMWARE_H__ From 9eb40fa2cd2d1f6829e7b49bb22692f754b9cfe0 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 21 Nov 2018 07:49:12 -0500 Subject: [PATCH 35/73] soc/tegra: Don't leak device tree node reference of_find_node_by_path() acquires a reference to the node returned by it and that reference needs to be dropped by its caller. soc_is_tegra() doesn't do that, so fix it. Signed-off-by: Yangtao Li Acked-by: Jon Hunter [treding: slightly rewrite to avoid inline comparison] Signed-off-by: Thierry Reding --- drivers/soc/tegra/common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/soc/tegra/common.c b/drivers/soc/tegra/common.c index cd8f41351add..7bfb154d6fa5 100644 --- a/drivers/soc/tegra/common.c +++ b/drivers/soc/tegra/common.c @@ -22,11 +22,15 @@ static const struct of_device_id tegra_machine_match[] = { bool soc_is_tegra(void) { + const struct of_device_id *match; struct device_node *root; root = of_find_node_by_path("/"); if (!root) return false; - return of_match_node(tegra_machine_match, root) != NULL; + match = of_match_node(tegra_machine_match, root); + of_node_put(root); + + return match != NULL; } From 57ba33d56884bed7f7043b37b668bb2067abf13b Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 22 Nov 2018 08:12:07 -0500 Subject: [PATCH 36/73] soc/tegra: pmc: Change to use DEFINE_SHOW_ATTRIBUTE macro Use DEFINE_SHOW_ATTRIBUTE macro to simplify the code. Signed-off-by: Yangtao Li Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index bb76aec4bafe..a4276f6bc8a3 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -752,17 +752,7 @@ static int powergate_show(struct seq_file *s, void *data) return 0; } -static int powergate_open(struct inode *inode, struct file *file) -{ - return single_open(file, powergate_show, inode->i_private); -} - -static const struct file_operations powergate_fops = { - .open = powergate_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(powergate); static int tegra_powergate_debugfs_init(void) { From 2a8c9f1203c6cda24dd032a1007bf3abd4e541f0 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 22 Nov 2018 07:59:41 -0500 Subject: [PATCH 37/73] soc: sunxi: Change to use DEFINE_SHOW_ATTRIBUTE macro Use DEFINE_SHOW_ATTRIBUTE macro to simplify the code. Signed-off-by: Yangtao Li Signed-off-by: Maxime Ripard --- drivers/soc/sunxi/sunxi_sram.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index b4b0f3480bd3..71e3ee4a3f19 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -155,17 +155,7 @@ static int sunxi_sram_show(struct seq_file *s, void *data) return 0; } -static int sunxi_sram_open(struct inode *inode, struct file *file) -{ - return single_open(file, sunxi_sram_show, inode->i_private); -} - -static const struct file_operations sunxi_sram_fops = { - .open = sunxi_sram_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(sunxi_sram); static inline struct sunxi_sram_desc *to_sram_desc(const struct sunxi_sram_data *data) { From eac9c48aac0822c2621aa6f3a03b501cd6524bf6 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 25 Jan 2018 14:43:45 +0200 Subject: [PATCH 38/73] soc/tegra: pmc: Add Tegra194 support The PMC controller on Tegra194 has a couple of new I/O pads and drops others compared to Tegra186. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 66 ++++++++++++++++++++++++++++++++++++++++- include/soc/tegra/pmc.h | 21 +++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index a4276f6bc8a3..6bf1abe73df7 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -2233,8 +2233,72 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .num_reset_levels = 3, }; +static const struct tegra_io_pad_soc tegra194_io_pads[] = { + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK3, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 7, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EQOS, .dpd = 8, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2_BIAS, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DAP3, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DAP5, .dpd = 12, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PWR_CTL, .dpd = 15, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SOC_GPIO53, .dpd = 16, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_GP_PWM2, .dpd = 18, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_GP_PWM3, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SOC_GPIO12, .dpd = 20, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SOC_GPIO13, .dpd = 21, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SOC_GPIO10, .dpd = 22, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UART4, .dpd = 23, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UART5, .dpd = 24, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI_DP3, .dpd = 26, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI_DP2, .dpd = 27, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI_DP0, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI_DP1, .dpd = 29, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CTL2, .dpd = 33, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_L0_RST_N, .dpd = 34, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_L1_RST_N, .dpd = 35, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 36, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_L5_RST_N, .dpd = 37, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIC, .dpd = 43, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSID, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 45, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIF, .dpd = 46, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SPI, .dpd = 47, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UFS, .dpd = 49, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIG, .dpd = 50, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIH, .dpd = 51, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EDP, .dpd = 53, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC1_HV, .dpd = 55, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC3_HV, .dpd = 56, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CONN, .dpd = 60, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX }, +}; + +static const struct tegra_pmc_soc tegra194_pmc_soc = { + .num_powergates = 0, + .powergates = NULL, + .num_cpu_powergates = 0, + .cpu_powergates = NULL, + .has_tsense_reset = false, + .has_gpu_clamps = false, + .num_io_pads = ARRAY_SIZE(tegra194_io_pads), + .io_pads = tegra194_io_pads, + .regs = &tegra186_pmc_regs, + .init = NULL, + .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, +}; + static const struct of_device_id tegra_pmc_match[] = { - { .compatible = "nvidia,tegra194-pmc", .data = &tegra186_pmc_soc }, + { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc }, { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, { .compatible = "nvidia,tegra132-pmc", .data = &tegra124_pmc_soc }, diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index 562426812ab2..fd816f6aa9cc 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -90,6 +90,10 @@ enum tegra_io_pad { TEGRA_IO_PAD_CSID, TEGRA_IO_PAD_CSIE, TEGRA_IO_PAD_CSIF, + TEGRA_IO_PAD_CSIG, + TEGRA_IO_PAD_CSIH, + TEGRA_IO_PAD_DAP3, + TEGRA_IO_PAD_DAP5, TEGRA_IO_PAD_DBG, TEGRA_IO_PAD_DEBUG_NONAO, TEGRA_IO_PAD_DMIC, @@ -102,10 +106,15 @@ enum tegra_io_pad { TEGRA_IO_PAD_EDP, TEGRA_IO_PAD_EMMC, TEGRA_IO_PAD_EMMC2, + TEGRA_IO_PAD_EQOS, TEGRA_IO_PAD_GPIO, + TEGRA_IO_PAD_GP_PWM2, + TEGRA_IO_PAD_GP_PWM3, TEGRA_IO_PAD_HDMI, TEGRA_IO_PAD_HDMI_DP0, TEGRA_IO_PAD_HDMI_DP1, + TEGRA_IO_PAD_HDMI_DP2, + TEGRA_IO_PAD_HDMI_DP3, TEGRA_IO_PAD_HSIC, TEGRA_IO_PAD_HV, TEGRA_IO_PAD_LVDS, @@ -115,8 +124,14 @@ enum tegra_io_pad { TEGRA_IO_PAD_PEX_CLK_BIAS, TEGRA_IO_PAD_PEX_CLK1, TEGRA_IO_PAD_PEX_CLK2, + TEGRA_IO_PAD_PEX_CLK2_BIAS, TEGRA_IO_PAD_PEX_CLK3, TEGRA_IO_PAD_PEX_CNTRL, + TEGRA_IO_PAD_PEX_CTL2, + TEGRA_IO_PAD_PEX_L0_RST_N, + TEGRA_IO_PAD_PEX_L1_RST_N, + TEGRA_IO_PAD_PEX_L5_RST_N, + TEGRA_IO_PAD_PWR_CTL, TEGRA_IO_PAD_SDMMC1, TEGRA_IO_PAD_SDMMC1_HV, TEGRA_IO_PAD_SDMMC2, @@ -124,10 +139,16 @@ enum tegra_io_pad { TEGRA_IO_PAD_SDMMC3, TEGRA_IO_PAD_SDMMC3_HV, TEGRA_IO_PAD_SDMMC4, + TEGRA_IO_PAD_SOC_GPIO10, + TEGRA_IO_PAD_SOC_GPIO12, + TEGRA_IO_PAD_SOC_GPIO13, + TEGRA_IO_PAD_SOC_GPIO53, TEGRA_IO_PAD_SPI, TEGRA_IO_PAD_SPI_HV, TEGRA_IO_PAD_SYS_DDC, TEGRA_IO_PAD_UART, + TEGRA_IO_PAD_UART4, + TEGRA_IO_PAD_UART5, TEGRA_IO_PAD_UFS, TEGRA_IO_PAD_USB0, TEGRA_IO_PAD_USB1, From 19906e6b16672178959c4f3e1345c46ed33f83ac Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 17 Sep 2018 15:08:17 +0200 Subject: [PATCH 39/73] soc/tegra: pmc: Add wake event support The power management controller has top-level controls that allow certain interrupts (such as from the RTC or a subset of GPIOs) to wake the system from sleep. Implement infrastructure to support these wake events. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 225 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 225 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 6bf1abe73df7..dffc49c3572f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -30,9 +30,12 @@ #include #include #include +#include +#include #include #include #include +#include #include #include #include @@ -49,6 +52,7 @@ #include #include +#include #include #define PMC_CNTRL 0x0 @@ -126,6 +130,16 @@ #define GPU_RG_CNTRL 0x2d4 /* Tegra186 and later */ +#define WAKE_AOWAKE_CNTRL(x) (0x000 + ((x) << 2)) +#define WAKE_AOWAKE_CNTRL_LEVEL (1 << 3) +#define WAKE_AOWAKE_MASK_W(x) (0x180 + ((x) << 2)) +#define WAKE_AOWAKE_MASK_R(x) (0x300 + ((x) << 2)) +#define WAKE_AOWAKE_STATUS_W(x) (0x30c + ((x) << 2)) +#define WAKE_AOWAKE_STATUS_R(x) (0x48c + ((x) << 2)) +#define WAKE_AOWAKE_TIER0_ROUTING(x) (0x4b4 + ((x) << 2)) +#define WAKE_AOWAKE_TIER1_ROUTING(x) (0x4c0 + ((x) << 2)) +#define WAKE_AOWAKE_TIER2_ROUTING(x) (0x4cc + ((x) << 2)) + #define WAKE_AOWAKE_CTRL 0x4f4 #define WAKE_AOWAKE_CTRL_INTR_POLARITY BIT(0) @@ -158,6 +172,38 @@ struct tegra_pmc_regs { unsigned int rst_level_mask; }; +struct tegra_wake_event { + const char *name; + unsigned int id; + unsigned int irq; + struct { + unsigned int instance; + unsigned int pin; + } gpio; +}; + +#define TEGRA_WAKE_IRQ(_name, _id, _irq) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = _irq, \ + .gpio = { \ + .instance = UINT_MAX, \ + .pin = UINT_MAX, \ + }, \ + } + +#define TEGRA_WAKE_GPIO(_name, _id, _instance, _pin) \ + { \ + .name = _name, \ + .id = _id, \ + .irq = 0, \ + .gpio = { \ + .instance = _instance, \ + .pin = _pin, \ + }, \ + } + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; @@ -185,6 +231,9 @@ struct tegra_pmc_soc { unsigned int num_reset_sources; const char * const *reset_levels; unsigned int num_reset_levels; + + const struct tegra_wake_event *wake_events; + unsigned int num_wake_events; }; static const char * const tegra186_reset_sources[] = { @@ -271,6 +320,9 @@ struct tegra_pmc { struct mutex powergates_lock; struct pinctrl_dev *pctl_dev; + + struct irq_domain *domain; + struct irq_chip irq; }; static struct tegra_pmc *pmc = &(struct tegra_pmc) { @@ -1602,6 +1654,175 @@ static void tegra_pmc_reset_sysfs_init(struct tegra_pmc *pmc) } } +static int tegra_pmc_irq_translate(struct irq_domain *domain, + struct irq_fwspec *fwspec, + unsigned long *hwirq, + unsigned int *type) +{ + if (WARN_ON(fwspec->param_count < 2)) + return -EINVAL; + + *hwirq = fwspec->param[0]; + *type = fwspec->param[1]; + + return 0; +} + +static int tegra_pmc_irq_alloc(struct irq_domain *domain, unsigned int virq, + unsigned int num_irqs, void *data) +{ + struct tegra_pmc *pmc = domain->host_data; + const struct tegra_pmc_soc *soc = pmc->soc; + struct irq_fwspec *fwspec = data; + unsigned int i; + int err = 0; + + for (i = 0; i < soc->num_wake_events; i++) { + const struct tegra_wake_event *event = &soc->wake_events[i]; + + if (fwspec->param_count == 2) { + struct irq_fwspec spec; + + if (event->id != fwspec->param[0]) + continue; + + err = irq_domain_set_hwirq_and_chip(domain, virq, + event->id, + &pmc->irq, pmc); + if (err < 0) + break; + + spec.fwnode = &pmc->dev->of_node->fwnode; + spec.param_count = 3; + spec.param[0] = GIC_SPI; + spec.param[1] = event->irq; + spec.param[2] = fwspec->param[1]; + + err = irq_domain_alloc_irqs_parent(domain, virq, + num_irqs, &spec); + + break; + } + + if (fwspec->param_count == 3) { + if (event->gpio.instance != fwspec->param[0] || + event->gpio.pin != fwspec->param[1]) + continue; + + err = irq_domain_set_hwirq_and_chip(domain, virq, + event->id, + &pmc->irq, pmc); + + break; + } + } + + if (i == soc->num_wake_events) + err = irq_domain_set_hwirq_and_chip(domain, virq, ULONG_MAX, + &pmc->irq, pmc); + + return err; +} + +static const struct irq_domain_ops tegra_pmc_irq_domain_ops = { + .translate = tegra_pmc_irq_translate, + .alloc = tegra_pmc_irq_alloc, +}; + +static int tegra_pmc_irq_set_wake(struct irq_data *data, unsigned int on) +{ + struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); + unsigned int offset, bit; + u32 value; + + offset = data->hwirq / 32; + bit = data->hwirq % 32; + + /* clear wake status */ + writel(0x1, pmc->wake + WAKE_AOWAKE_STATUS_W(data->hwirq)); + + /* route wake to tier 2 */ + value = readl(pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); + + if (!on) + value &= ~(1 << bit); + else + value |= 1 << bit; + + writel(value, pmc->wake + WAKE_AOWAKE_TIER2_ROUTING(offset)); + + /* enable wakeup event */ + writel(!!on, pmc->wake + WAKE_AOWAKE_MASK_W(data->hwirq)); + + return 0; +} + +static int tegra_pmc_irq_set_type(struct irq_data *data, unsigned int type) +{ + struct tegra_pmc *pmc = irq_data_get_irq_chip_data(data); + u32 value; + + if (data->hwirq == ULONG_MAX) + return 0; + + value = readl(pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + case IRQ_TYPE_LEVEL_HIGH: + value |= WAKE_AOWAKE_CNTRL_LEVEL; + break; + + case IRQ_TYPE_EDGE_FALLING: + case IRQ_TYPE_LEVEL_LOW: + value &= ~WAKE_AOWAKE_CNTRL_LEVEL; + break; + + case IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING: + value ^= WAKE_AOWAKE_CNTRL_LEVEL; + break; + + default: + return -EINVAL; + } + + writel(value, pmc->wake + WAKE_AOWAKE_CNTRL(data->hwirq)); + + return 0; +} + +static int tegra_pmc_irq_init(struct tegra_pmc *pmc) +{ + struct irq_domain *parent = NULL; + struct device_node *np; + + np = of_irq_find_parent(pmc->dev->of_node); + if (np) { + parent = irq_find_host(np); + of_node_put(np); + } + + if (!parent) + return 0; + + pmc->irq.name = dev_name(pmc->dev); + pmc->irq.irq_mask = irq_chip_mask_parent; + pmc->irq.irq_unmask = irq_chip_unmask_parent; + pmc->irq.irq_eoi = irq_chip_eoi_parent; + pmc->irq.irq_set_affinity = irq_chip_set_affinity_parent; + pmc->irq.irq_set_type = tegra_pmc_irq_set_type; + pmc->irq.irq_set_wake = tegra_pmc_irq_set_wake; + + pmc->domain = irq_domain_add_hierarchy(parent, 0, 96, pmc->dev->of_node, + &tegra_pmc_irq_domain_ops, pmc); + if (!pmc->domain) { + dev_err(pmc->dev, "failed to allocate domain\n"); + return -ENOMEM; + } + + return 0; +} + static int tegra_pmc_probe(struct platform_device *pdev) { void __iomem *base; @@ -1690,6 +1911,10 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (err) goto cleanup_restart_handler; + err = tegra_pmc_irq_init(pmc); + if (err < 0) + goto cleanup_restart_handler; + mutex_lock(&pmc->powergates_lock); iounmap(pmc->base); pmc->base = base; From e59333c83fe9e7cb35f60522848408c20958044a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 19 Sep 2018 18:41:59 +0200 Subject: [PATCH 40/73] soc/tegra: pmc: Add initial Tegra186 wake events Tegra186 support 96 wake events in total. Many of them are never used, so only the most common ones (RTC alarm and power key) are currently defined. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index dffc49c3572f..d6ec2e5b906e 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -54,6 +54,7 @@ #include #include +#include #define PMC_CNTRL 0x0 #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ @@ -2437,6 +2438,11 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, iounmap(wake); } +static const struct tegra_wake_event tegra186_wake_events[] = { + TEGRA_WAKE_GPIO("power", 29, 1, TEGRA_AON_GPIO(FF, 0)), + TEGRA_WAKE_IRQ("rtc", 73, 10), +}; + static const struct tegra_pmc_soc tegra186_pmc_soc = { .num_powergates = 0, .powergates = NULL, @@ -2456,6 +2462,8 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .num_reset_sources = 14, .reset_levels = tegra186_reset_levels, .num_reset_levels = 3, + .num_wake_events = ARRAY_SIZE(tegra186_wake_events), + .wake_events = tegra186_wake_events, }; static const struct tegra_io_pad_soc tegra194_io_pads[] = { From e3e403c218cd07b497127a29e604fc26a71e8558 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 19 Sep 2018 18:42:37 +0200 Subject: [PATCH 41/73] soc/tegra: pmc: Add initial Tegra194 wake events Tegra194 supports 96 wake events in total. Many of them are never used, so only the most common ones (RTC alarm and power key) are currently defined. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d6ec2e5b906e..8c46b0aace0b 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -55,6 +55,7 @@ #include #include #include +#include #define PMC_CNTRL 0x0 #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ @@ -2516,6 +2517,11 @@ static const struct tegra_io_pad_soc tegra194_io_pads[] = { { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = UINT_MAX }, }; +static const struct tegra_wake_event tegra194_wake_events[] = { + TEGRA_WAKE_GPIO("power", 29, 1, TEGRA194_AON_GPIO(EE, 4)), + TEGRA_WAKE_IRQ("rtc", 73, 10), +}; + static const struct tegra_pmc_soc tegra194_pmc_soc = { .num_powergates = 0, .powergates = NULL, @@ -2528,6 +2534,8 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .regs = &tegra186_pmc_regs, .init = NULL, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .num_wake_events = ARRAY_SIZE(tegra194_wake_events), + .wake_events = tegra194_wake_events, }; static const struct of_device_id tegra_pmc_match[] = { From 1861a7f07e02292830a1ca256328d370deefea30 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 24 Nov 2018 09:52:23 -0500 Subject: [PATCH 42/73] soc: bcm: brcmstb: Don't leak device tree node reference of_find_node_by_path() acquires a reference to the node returned by it and that reference needs to be dropped by its caller. soc_is_brcmstb() doesn't do that, so fix it. [treding: slightly rewrite to avoid inline comparison] Fixes: d52fad262041 ("soc: add stubs for brcmstb SoC's") Signed-off-by: Yangtao Li Signed-off-by: Florian Fainelli --- drivers/soc/bcm/brcmstb/common.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/soc/bcm/brcmstb/common.c b/drivers/soc/bcm/brcmstb/common.c index 14185451901d..bf9123f727e8 100644 --- a/drivers/soc/bcm/brcmstb/common.c +++ b/drivers/soc/bcm/brcmstb/common.c @@ -31,13 +31,17 @@ static const struct of_device_id brcmstb_machine_match[] = { bool soc_is_brcmstb(void) { + const struct of_device_id *match; struct device_node *root; root = of_find_node_by_path("/"); if (!root) return false; - return of_match_node(brcmstb_machine_match, root) != NULL; + match = of_match_node(brcmstb_machine_match, root); + of_node_put(root); + + return match != NULL; } u32 brcmstb_get_family_id(void) From 9095d0f8eae4bf6b4d63a36623ee1ad5a164df43 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 19 Nov 2018 01:57:15 +0000 Subject: [PATCH 43/73] soc: qcom: llcc-slice: Remove duplicated include from llcc-slice.c Remove duplicated include. Signed-off-by: YueHaibing Signed-off-by: Andy Gross --- drivers/soc/qcom/llcc-slice.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/soc/qcom/llcc-slice.c b/drivers/soc/qcom/llcc-slice.c index 6a7d0162fe0e..80667f7be52c 100644 --- a/drivers/soc/qcom/llcc-slice.c +++ b/drivers/soc/qcom/llcc-slice.c @@ -16,7 +16,6 @@ #include #include #include -#include #define ACTIVATE BIT(0) #define DEACTIVATE BIT(1) From b4c29e89026892494952b648f03958906d357129 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Sun, 18 Nov 2018 14:53:10 +0100 Subject: [PATCH 44/73] dt-bindings: amlogic: Add Internal Clock Measurer bindings The Amlogic Meson SoCs embeds a clock measurer IP to measure the internal clock paths frequencies. Acked-by: Martin Blumenstingl Signed-off-by: Neil Armstrong Reviewed-by: Rob Herring Signed-off-by: Kevin Hilman --- .../bindings/soc/amlogic/clk-measure.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt diff --git a/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt b/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt new file mode 100644 index 000000000000..205a54bcd7c7 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/amlogic/clk-measure.txt @@ -0,0 +1,18 @@ +Amlogic Internal Clock Measurer +=============================== + +The Amlogic SoCs contains an IP to measure the internal clocks. +The precision is multiple of MHz, useful to debug the clock states. + +Required properties: +- compatible: Shall contain one of the following : + "amlogic,meson-gx-clk-measure" for GX SoCs + "amlogic,meson8-clk-measure" for Meson8 SoCs + "amlogic,meson8b-clk-measure" for Meson8b SoCs +- reg: base address and size of the Clock Measurer register space. + +Example: + clock-measure@8758 { + compatible = "amlogic,meson-gx-clk-measure"; + reg = <0x0 0x8758 0x0 0x10>; + }; From 2b45ebef39a2caad409f70b22b4a2a41df9815b6 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Sun, 18 Nov 2018 14:50:23 +0100 Subject: [PATCH 45/73] soc: amlogic: Add Meson Clock Measure driver The Amlogic Meson SoCs embeds a clock measurer IP to measure the internal clock paths frequencies. The precision is determined by stepping into the duration until the counter overflows. The debugfs slows a pretty summary and each clock can be measured individually aswell. Cc: Martin Blumenstingl Signed-off-by: Neil Armstrong Reviewed-by: Martin Blumenstingl Tested-by: Martin Blumenstingl Signed-off-by: Kevin Hilman --- drivers/soc/amlogic/Kconfig | 8 + drivers/soc/amlogic/Makefile | 1 + drivers/soc/amlogic/meson-clk-measure.c | 350 ++++++++++++++++++++++++ 3 files changed, 359 insertions(+) create mode 100644 drivers/soc/amlogic/meson-clk-measure.c diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig index 2f282b472912..36633bb6c8bb 100644 --- a/drivers/soc/amlogic/Kconfig +++ b/drivers/soc/amlogic/Kconfig @@ -7,6 +7,14 @@ config MESON_CANVAS help Say yes to support the canvas IP for Amlogic SoCs. +config MESON_CLK_MEASURE + bool "Amlogic Meson SoC Clock Measure driver" + depends on ARCH_MESON || COMPILE_TEST + default ARCH_MESON + help + Say yes to support of Measuring a set of internal SoC clocks + from the debugfs interface. + config MESON_GX_SOCINFO bool "Amlogic Meson GX SoC Information driver" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/soc/amlogic/Makefile b/drivers/soc/amlogic/Makefile index 0ab16d35ac36..bf2d109f61e9 100644 --- a/drivers/soc/amlogic/Makefile +++ b/drivers/soc/amlogic/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_MESON_CANVAS) += meson-canvas.o +obj-$(CONFIG_MESON_CLK_MEASURE) += meson-clk-measure.o obj-$(CONFIG_MESON_GX_SOCINFO) += meson-gx-socinfo.o obj-$(CONFIG_MESON_GX_PM_DOMAINS) += meson-gx-pwrc-vpu.o obj-$(CONFIG_MESON_MX_SOCINFO) += meson-mx-socinfo.o diff --git a/drivers/soc/amlogic/meson-clk-measure.c b/drivers/soc/amlogic/meson-clk-measure.c new file mode 100644 index 000000000000..daea191a66fa --- /dev/null +++ b/drivers/soc/amlogic/meson-clk-measure.c @@ -0,0 +1,350 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2018 BayLibre, SAS + * Author: Neil Armstrong + */ + +#include +#include +#include +#include +#include +#include + +#define MSR_CLK_DUTY 0x0 +#define MSR_CLK_REG0 0x4 +#define MSR_CLK_REG1 0x8 +#define MSR_CLK_REG2 0xc + +#define MSR_DURATION GENMASK(15, 0) +#define MSR_ENABLE BIT(16) +#define MSR_CONT BIT(17) /* continuous measurement */ +#define MSR_INTR BIT(18) /* interrupts */ +#define MSR_RUN BIT(19) +#define MSR_CLK_SRC GENMASK(26, 20) +#define MSR_BUSY BIT(31) + +#define MSR_VAL_MASK GENMASK(15, 0) + +#define DIV_MIN 32 +#define DIV_STEP 32 +#define DIV_MAX 640 + +#define CLK_MSR_MAX 128 + +struct meson_msr_id { + struct meson_msr *priv; + unsigned int id; + const char *name; +}; + +struct meson_msr { + struct regmap *regmap; + struct meson_msr_id msr_table[CLK_MSR_MAX]; +}; + +#define CLK_MSR_ID(__id, __name) \ + [__id] = {.id = __id, .name = __name,} + +static struct meson_msr_id clk_msr_m8[CLK_MSR_MAX] = { + CLK_MSR_ID(0, "ring_osc_out_ee0"), + CLK_MSR_ID(1, "ring_osc_out_ee1"), + CLK_MSR_ID(2, "ring_osc_out_ee2"), + CLK_MSR_ID(3, "a9_ring_osck"), + CLK_MSR_ID(6, "vid_pll"), + CLK_MSR_ID(7, "clk81"), + CLK_MSR_ID(8, "encp"), + CLK_MSR_ID(9, "encl"), + CLK_MSR_ID(11, "eth_rmii"), + CLK_MSR_ID(13, "amclk"), + CLK_MSR_ID(14, "fec_clk_0"), + CLK_MSR_ID(15, "fec_clk_1"), + CLK_MSR_ID(16, "fec_clk_2"), + CLK_MSR_ID(18, "a9_clk_div16"), + CLK_MSR_ID(19, "hdmi_sys"), + CLK_MSR_ID(20, "rtc_osc_clk_out"), + CLK_MSR_ID(21, "i2s_clk_in_src0"), + CLK_MSR_ID(22, "clk_rmii_from_pad"), + CLK_MSR_ID(23, "hdmi_ch0_tmds"), + CLK_MSR_ID(24, "lvds_fifo"), + CLK_MSR_ID(26, "sc_clk_int"), + CLK_MSR_ID(28, "sar_adc"), + CLK_MSR_ID(30, "mpll_clk_test_out"), + CLK_MSR_ID(31, "audac_clkpi"), + CLK_MSR_ID(32, "vdac"), + CLK_MSR_ID(33, "sdhc_rx"), + CLK_MSR_ID(34, "sdhc_sd"), + CLK_MSR_ID(35, "mali"), + CLK_MSR_ID(36, "hdmi_tx_pixel"), + CLK_MSR_ID(38, "vdin_meas"), + CLK_MSR_ID(39, "pcm_sclk"), + CLK_MSR_ID(40, "pcm_mclk"), + CLK_MSR_ID(41, "eth_rx_tx"), + CLK_MSR_ID(42, "pwm_d"), + CLK_MSR_ID(43, "pwm_c"), + CLK_MSR_ID(44, "pwm_b"), + CLK_MSR_ID(45, "pwm_a"), + CLK_MSR_ID(46, "pcm2_sclk"), + CLK_MSR_ID(47, "ddr_dpll_pt"), + CLK_MSR_ID(48, "pwm_f"), + CLK_MSR_ID(49, "pwm_e"), + CLK_MSR_ID(59, "hcodec"), + CLK_MSR_ID(60, "usb_32k_alt"), + CLK_MSR_ID(61, "gpio"), + CLK_MSR_ID(62, "vid2_pll"), + CLK_MSR_ID(63, "mipi_csi_cfg"), +}; + +static struct meson_msr_id clk_msr_gx[CLK_MSR_MAX] = { + CLK_MSR_ID(0, "ring_osc_out_ee_0"), + CLK_MSR_ID(1, "ring_osc_out_ee_1"), + CLK_MSR_ID(2, "ring_osc_out_ee_2"), + CLK_MSR_ID(3, "a53_ring_osc"), + CLK_MSR_ID(4, "gp0_pll"), + CLK_MSR_ID(6, "enci"), + CLK_MSR_ID(7, "clk81"), + CLK_MSR_ID(8, "encp"), + CLK_MSR_ID(9, "encl"), + CLK_MSR_ID(10, "vdac"), + CLK_MSR_ID(11, "rgmii_tx"), + CLK_MSR_ID(12, "pdm"), + CLK_MSR_ID(13, "amclk"), + CLK_MSR_ID(14, "fec_0"), + CLK_MSR_ID(15, "fec_1"), + CLK_MSR_ID(16, "fec_2"), + CLK_MSR_ID(17, "sys_pll_div16"), + CLK_MSR_ID(18, "sys_cpu_div16"), + CLK_MSR_ID(19, "hdmitx_sys"), + CLK_MSR_ID(20, "rtc_osc_out"), + CLK_MSR_ID(21, "i2s_in_src0"), + CLK_MSR_ID(22, "eth_phy_ref"), + CLK_MSR_ID(23, "hdmi_todig"), + CLK_MSR_ID(26, "sc_int"), + CLK_MSR_ID(28, "sar_adc"), + CLK_MSR_ID(31, "mpll_test_out"), + CLK_MSR_ID(32, "vdec"), + CLK_MSR_ID(35, "mali"), + CLK_MSR_ID(36, "hdmi_tx_pixel"), + CLK_MSR_ID(37, "i958"), + CLK_MSR_ID(38, "vdin_meas"), + CLK_MSR_ID(39, "pcm_sclk"), + CLK_MSR_ID(40, "pcm_mclk"), + CLK_MSR_ID(41, "eth_rx_or_rmii"), + CLK_MSR_ID(42, "mp0_out"), + CLK_MSR_ID(43, "fclk_div5"), + CLK_MSR_ID(44, "pwm_b"), + CLK_MSR_ID(45, "pwm_a"), + CLK_MSR_ID(46, "vpu"), + CLK_MSR_ID(47, "ddr_dpll_pt"), + CLK_MSR_ID(48, "mp1_out"), + CLK_MSR_ID(49, "mp2_out"), + CLK_MSR_ID(50, "mp3_out"), + CLK_MSR_ID(51, "nand_core"), + CLK_MSR_ID(52, "sd_emmc_b"), + CLK_MSR_ID(53, "sd_emmc_a"), + CLK_MSR_ID(55, "vid_pll_div_out"), + CLK_MSR_ID(56, "cci"), + CLK_MSR_ID(57, "wave420l_c"), + CLK_MSR_ID(58, "wave420l_b"), + CLK_MSR_ID(59, "hcodec"), + CLK_MSR_ID(60, "alt_32k"), + CLK_MSR_ID(61, "gpio_msr"), + CLK_MSR_ID(62, "hevc"), + CLK_MSR_ID(66, "vid_lock"), + CLK_MSR_ID(70, "pwm_f"), + CLK_MSR_ID(71, "pwm_e"), + CLK_MSR_ID(72, "pwm_d"), + CLK_MSR_ID(73, "pwm_c"), + CLK_MSR_ID(75, "aoclkx2_int"), + CLK_MSR_ID(76, "aoclk_int"), + CLK_MSR_ID(77, "rng_ring_osc_0"), + CLK_MSR_ID(78, "rng_ring_osc_1"), + CLK_MSR_ID(79, "rng_ring_osc_2"), + CLK_MSR_ID(80, "rng_ring_osc_3"), + CLK_MSR_ID(81, "vapb"), + CLK_MSR_ID(82, "ge2d"), +}; + +static int meson_measure_id(struct meson_msr_id *clk_msr_id, + unsigned int duration) +{ + struct meson_msr *priv = clk_msr_id->priv; + unsigned int val; + int ret; + + regmap_write(priv->regmap, MSR_CLK_REG0, 0); + + /* Set measurement duration */ + regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_DURATION, + FIELD_PREP(MSR_DURATION, duration - 1)); + + /* Set ID */ + regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_CLK_SRC, + FIELD_PREP(MSR_CLK_SRC, clk_msr_id->id)); + + /* Enable & Start */ + regmap_update_bits(priv->regmap, MSR_CLK_REG0, + MSR_RUN | MSR_ENABLE, + MSR_RUN | MSR_ENABLE); + + ret = regmap_read_poll_timeout(priv->regmap, MSR_CLK_REG0, + val, !(val & MSR_BUSY), 10, 10000); + if (ret) + return ret; + + /* Disable */ + regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_ENABLE, 0); + + /* Get the value in multiple of gate time counts */ + regmap_read(priv->regmap, MSR_CLK_REG2, &val); + + if (val >= MSR_VAL_MASK) + return -EINVAL; + + return DIV_ROUND_CLOSEST_ULL((val & MSR_VAL_MASK) * 1000000ULL, + duration); +} + +static int meson_measure_best_id(struct meson_msr_id *clk_msr_id, + unsigned int *precision) +{ + unsigned int duration = DIV_MAX; + int ret; + + /* Start from max duration and down to min duration */ + do { + ret = meson_measure_id(clk_msr_id, duration); + if (ret >= 0) + *precision = (2 * 1000000) / duration; + else + duration -= DIV_STEP; + } while (duration >= DIV_MIN && ret == -EINVAL); + + return ret; +} + +static int clk_msr_show(struct seq_file *s, void *data) +{ + struct meson_msr_id *clk_msr_id = s->private; + unsigned int precision = 0; + int val; + + val = meson_measure_best_id(clk_msr_id, &precision); + if (val < 0) + return val; + + seq_printf(s, "%d\t+/-%dHz\n", val, precision); + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(clk_msr); + +static int clk_msr_summary_show(struct seq_file *s, void *data) +{ + struct meson_msr_id *msr_table = s->private; + unsigned int precision = 0; + int val, i; + + seq_puts(s, " clock rate precision\n"); + seq_puts(s, "---------------------------------------------\n"); + + for (i = 0 ; i < CLK_MSR_MAX ; ++i) { + if (!msr_table[i].name) + continue; + + val = meson_measure_best_id(&msr_table[i], &precision); + if (val < 0) + return val; + + seq_printf(s, " %-20s %10d +/-%dHz\n", + msr_table[i].name, val, precision); + } + + return 0; +} +DEFINE_SHOW_ATTRIBUTE(clk_msr_summary); + +static const struct regmap_config meson_clk_msr_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = MSR_CLK_REG2, +}; + +static int meson_msr_probe(struct platform_device *pdev) +{ + const struct meson_msr_id *match_data; + struct meson_msr *priv; + struct resource *res; + struct dentry *root, *clks; + void __iomem *base; + int i; + + priv = devm_kzalloc(&pdev->dev, sizeof(struct meson_msr), + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + match_data = device_get_match_data(&pdev->dev); + if (!match_data) { + dev_err(&pdev->dev, "failed to get match data\n"); + return -ENODEV; + } + + memcpy(priv->msr_table, match_data, sizeof(priv->msr_table)); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "io resource mapping failed\n"); + return PTR_ERR(base); + } + + priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &meson_clk_msr_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + root = debugfs_create_dir("meson-clk-msr", NULL); + clks = debugfs_create_dir("clks", root); + + debugfs_create_file("measure_summary", 0444, root, + priv->msr_table, &clk_msr_summary_fops); + + for (i = 0 ; i < CLK_MSR_MAX ; ++i) { + if (!priv->msr_table[i].name) + continue; + + priv->msr_table[i].priv = priv; + + debugfs_create_file(priv->msr_table[i].name, 0444, clks, + &priv->msr_table[i], &clk_msr_fops); + } + + return 0; +} + +static const struct of_device_id meson_msr_match_table[] = { + { + .compatible = "amlogic,meson-gx-clk-measure", + .data = (void *)clk_msr_gx, + }, + { + .compatible = "amlogic,meson8-clk-measure", + .data = (void *)clk_msr_m8, + }, + { + .compatible = "amlogic,meson8b-clk-measure", + .data = (void *)clk_msr_m8, + }, + { /* sentinel */ } +}; + +static struct platform_driver meson_msr_driver = { + .probe = meson_msr_probe, + .driver = { + .name = "meson_msr", + .of_match_table = meson_msr_match_table, + }, +}; +builtin_platform_driver(meson_msr_driver); From b7e386177fa53c3d704754095bd81189ef43bce4 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 19 Sep 2018 18:45:40 -0700 Subject: [PATCH 46/73] soc: qcom: smd-rpm: Add QCS404 compatible This patch adds a compatible for the rpm on the Qualcomm QCS404 platform. Signed-off-by: Bjorn Andersson Reviewed-by: Vinod Koul Signed-off-by: Andy Gross --- Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt | 1 + drivers/soc/qcom/smd-rpm.c | 1 + 2 files changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt index 89e1cb9212f6..ec95705ba692 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd-rpm.txt @@ -23,6 +23,7 @@ resources. "qcom,rpm-msm8916" "qcom,rpm-msm8974" "qcom,rpm-msm8998" + "qcom,rpm-qcs404" - qcom,smd-channels: Usage: required diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index 93517ed83355..b8e63724a49d 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -227,6 +227,7 @@ static const struct of_device_id qcom_smd_rpm_of_match[] = { { .compatible = "qcom,rpm-msm8974" }, { .compatible = "qcom,rpm-msm8996" }, { .compatible = "qcom,rpm-msm8998" }, + { .compatible = "qcom,rpm-qcs404" }, {} }; MODULE_DEVICE_TABLE(of, qcom_smd_rpm_of_match); From b601f73130a375c912d9f2ec93c5f3cea5d6a3da Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 29 Nov 2018 08:38:26 -0800 Subject: [PATCH 47/73] drm: msm: Check cmd_db_read_aux_data() for failure We need to check the call to cmd_db_read_aux_data() for the error case, so that we don't continue and use potentially uninitialized values for 'pri_count' and 'sec_count'. Otherwise, we get the following compiler warnings: drivers/gpu/drm/msm/adreno/a6xx_gmu.c: In function 'a6xx_gmu_rpmh_arc_votes_init.isra.12': drivers/gpu/drm/msm/adreno/a6xx_gmu.c:943:12: warning: 'pri_count' is used uninitialized in this function [-Wuninitialized] pri_count >>= 1; ^~~ drivers/gpu/drm/msm/adreno/a6xx_gmu.c:948:12: warning: 'sec_count' may be used uninitialized in this function [-Wmaybe-uninitialized] sec_count >>= 1; ^~~ Reported-by: Stephen Rothwell Reported-by: kbuild test robot Cc: Jordan Crouse Cc: Bjorn Andersson Cc: Evan Green Cc: Jordan Crouse Cc: Rob Clark Fixes: ed3cafa79ea7 ("soc: qcom: cmd-db: Stop memcpy()ing in cmd_db_read_aux_data()") Signed-off-by: Stephen Boyd Reviewed-by: Andy Gross Acked-by: Rob Clark Signed-off-by: Andy Gross --- drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 546599a7ab05..0fb4718ef0df 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -936,6 +936,8 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, size_t pri_count, sec_count; pri = cmd_db_read_aux_data(id, &pri_count); + if (IS_ERR(pri)) + return PTR_ERR(pri); /* * The data comes back as an array of unsigned shorts so adjust the * count accordingly @@ -945,6 +947,9 @@ static int a6xx_gmu_rpmh_arc_votes_init(struct device *dev, u32 *votes, return -EINVAL; sec = cmd_db_read_aux_data("mx.lvl", &sec_count); + if (IS_ERR(sec)) + return PTR_ERR(sec); + sec_count >>= 1; if (!sec_count) return -EINVAL; From a93913cecb3c98c2310da42a9650cfd817fb00b8 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 29 Nov 2018 11:56:14 +0100 Subject: [PATCH 48/73] soc: renesas: r8a77965-sysc: Remove non-existent A3IR power domain The R-Car Gen3 HardWare Manual Errata for Rev. 0.80 (Feb 28, 2018) removed the A3IR power domain on R-Car M3-N, as this SoC does not have an Image Processing Unit (IMP-X5). The definition in the DT bindings header cannot be removed yet, until its (incorrect) user has been removed. Fixes: a527709b78b3c997 ("soc: renesas: rcar-sysc: Add R-Car M3-N support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/r8a77965-sysc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/soc/renesas/r8a77965-sysc.c b/drivers/soc/renesas/r8a77965-sysc.c index d7f7928e3c07..e0533beb50fd 100644 --- a/drivers/soc/renesas/r8a77965-sysc.c +++ b/drivers/soc/renesas/r8a77965-sysc.c @@ -28,7 +28,6 @@ static const struct rcar_sysc_area r8a77965_areas[] __initconst = { { "a2vc1", 0x3c0, 1, R8A77965_PD_A2VC1, R8A77965_PD_A3VC }, { "3dg-a", 0x100, 0, R8A77965_PD_3DG_A, R8A77965_PD_ALWAYS_ON }, { "3dg-b", 0x100, 1, R8A77965_PD_3DG_B, R8A77965_PD_3DG_A }, - { "a3ir", 0x180, 0, R8A77965_PD_A3IR, R8A77965_PD_ALWAYS_ON }, }; const struct rcar_sysc_info r8a77965_sysc_info __initconst = { From da3e1c57caf93ed379f14686e877f806111abe7c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 29 Nov 2018 11:56:15 +0100 Subject: [PATCH 49/73] soc: renesas: r8a77970-sysc: Remove non-existent CR7 power domain The R-Car Gen3 HardWare Manual Errata for Rev. 0.80 (Feb 28, 2018) removed the CR7 power domain on R-Car V3M, as this SoC does not have an ARM Cortex-R7 Realtime Core. As this definition was never used from DT, it can just be removed. Fixes: 833bdb47c826a1a6 ("dt-bindings: power: add R8A77970 SYSC power domain definitions") Fixes: bab9b2a74fe9da96 ("soc: renesas: rcar-sysc: add R8A77970 support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/r8a77970-sysc.c | 1 - include/dt-bindings/power/r8a77970-sysc.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c index 35b30d6a8958..2c6d76490ca0 100644 --- a/drivers/soc/renesas/r8a77970-sysc.c +++ b/drivers/soc/renesas/r8a77970-sysc.c @@ -20,7 +20,6 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = { PD_CPU_NOCR }, { "ca53-cpu1", 0x200, 1, R8A77970_PD_CA53_CPU1, R8A77970_PD_CA53_SCU, PD_CPU_NOCR }, - { "cr7", 0x240, 0, R8A77970_PD_CR7, R8A77970_PD_ALWAYS_ON }, { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON }, { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR }, { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR }, diff --git a/include/dt-bindings/power/r8a77970-sysc.h b/include/dt-bindings/power/r8a77970-sysc.h index bf54779d1625..5c1ef1398b70 100644 --- a/include/dt-bindings/power/r8a77970-sysc.h +++ b/include/dt-bindings/power/r8a77970-sysc.h @@ -16,7 +16,6 @@ #define R8A77970_PD_CA53_CPU0 5 #define R8A77970_PD_CA53_CPU1 6 -#define R8A77970_PD_CR7 13 #define R8A77970_PD_CA53_SCU 21 #define R8A77970_PD_A2IR0 23 #define R8A77970_PD_A3IR 24 From b5eb730e031acaba2d25e8f522ac5966a70885ae Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 29 Nov 2018 11:56:16 +0100 Subject: [PATCH 50/73] soc: renesas: r8a77970-sysc: Correct names of A2DP/A2CN power domains The R-Car Gen3 HardWare Manual Errata for Rev. 0.80 (Feb 28, 2018) renamed the A2IR2 and A2IR3 power domains on R-Car V3M to A2DP resp. A2CN. As these definitions are not yet used from DT, they can just be renamed. While at it, fix the indentation of the A3IR definition. Fixes: 833bdb47c826a1a6 ("dt-bindings: power: add R8A77970 SYSC power domain definitions") Fixes: bab9b2a74fe9da96 ("soc: renesas: rcar-sysc: add R8A77970 support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/r8a77970-sysc.c | 4 ++-- include/dt-bindings/power/r8a77970-sysc.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/soc/renesas/r8a77970-sysc.c b/drivers/soc/renesas/r8a77970-sysc.c index 2c6d76490ca0..280c48b80f24 100644 --- a/drivers/soc/renesas/r8a77970-sysc.c +++ b/drivers/soc/renesas/r8a77970-sysc.c @@ -23,8 +23,8 @@ static const struct rcar_sysc_area r8a77970_areas[] __initconst = { { "a3ir", 0x180, 0, R8A77970_PD_A3IR, R8A77970_PD_ALWAYS_ON }, { "a2ir0", 0x400, 0, R8A77970_PD_A2IR0, R8A77970_PD_A3IR }, { "a2ir1", 0x400, 1, R8A77970_PD_A2IR1, R8A77970_PD_A3IR }, - { "a2ir2", 0x400, 2, R8A77970_PD_A2IR2, R8A77970_PD_A3IR }, - { "a2ir3", 0x400, 3, R8A77970_PD_A2IR3, R8A77970_PD_A3IR }, + { "a2dp", 0x400, 2, R8A77970_PD_A2DP, R8A77970_PD_A3IR }, + { "a2cn", 0x400, 3, R8A77970_PD_A2CN, R8A77970_PD_A3IR }, { "a2sc0", 0x400, 4, R8A77970_PD_A2SC0, R8A77970_PD_A3IR }, { "a2sc1", 0x400, 5, R8A77970_PD_A2SC1, R8A77970_PD_A3IR }, }; diff --git a/include/dt-bindings/power/r8a77970-sysc.h b/include/dt-bindings/power/r8a77970-sysc.h index 5c1ef1398b70..85cc5f23cf9f 100644 --- a/include/dt-bindings/power/r8a77970-sysc.h +++ b/include/dt-bindings/power/r8a77970-sysc.h @@ -18,10 +18,10 @@ #define R8A77970_PD_CA53_CPU1 6 #define R8A77970_PD_CA53_SCU 21 #define R8A77970_PD_A2IR0 23 -#define R8A77970_PD_A3IR 24 +#define R8A77970_PD_A3IR 24 #define R8A77970_PD_A2IR1 27 -#define R8A77970_PD_A2IR2 28 -#define R8A77970_PD_A2IR3 29 +#define R8A77970_PD_A2DP 28 +#define R8A77970_PD_A2CN 29 #define R8A77970_PD_A2SC0 30 #define R8A77970_PD_A2SC1 31 From 97473bc85b22ac610b1810b6a9a4669a6cb0b7b0 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 29 Nov 2018 11:56:17 +0100 Subject: [PATCH 51/73] soc: renesas: r8a77980-sysc: Correct names of A2DP[01] power domains The R-Car Gen3 HardWare Manual Errata for Rev. 0.80 (Feb 28, 2018) renamed the A2PD0 and A2DP0 power domains on R-Car V3H to A2DP0 resp. A2DP1. As these definitions are not yet used from DT, they can just be renamed. Fixes: 7755b40d07a8dba7 ("dt-bindings: power: add R8A77980 SYSC power domain definitions") Fixes: 41d6d8bd8ae94ca9 ("soc: renesas: rcar-sysc: add R8A77980 support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/r8a77980-sysc.c | 4 ++-- include/dt-bindings/power/r8a77980-sysc.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/renesas/r8a77980-sysc.c b/drivers/soc/renesas/r8a77980-sysc.c index 9265fb525ef3..dbb2621ce4e3 100644 --- a/drivers/soc/renesas/r8a77980-sysc.c +++ b/drivers/soc/renesas/r8a77980-sysc.c @@ -38,8 +38,8 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = { { "a2sc2", 0x400, 8, R8A77980_PD_A2SC2, R8A77980_PD_A3IR }, { "a2sc3", 0x400, 9, R8A77980_PD_A2SC3, R8A77980_PD_A3IR }, { "a2sc4", 0x400, 10, R8A77980_PD_A2SC4, R8A77980_PD_A3IR }, - { "a2pd0", 0x400, 11, R8A77980_PD_A2PD0, R8A77980_PD_A3IR }, - { "a2pd1", 0x400, 12, R8A77980_PD_A2PD1, R8A77980_PD_A3IR }, + { "a2dp0", 0x400, 11, R8A77980_PD_A2DP0, R8A77980_PD_A3IR }, + { "a2dp1", 0x400, 12, R8A77980_PD_A2DP1, R8A77980_PD_A3IR }, { "a2cn", 0x400, 13, R8A77980_PD_A2CN, R8A77980_PD_A3IR }, { "a3vip", 0x2c0, 0, R8A77980_PD_A3VIP, R8A77980_PD_ALWAYS_ON }, { "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_A3VIP }, diff --git a/include/dt-bindings/power/r8a77980-sysc.h b/include/dt-bindings/power/r8a77980-sysc.h index 2c90c1237725..7bebe7e8dbdb 100644 --- a/include/dt-bindings/power/r8a77980-sysc.h +++ b/include/dt-bindings/power/r8a77980-sysc.h @@ -15,8 +15,8 @@ #define R8A77980_PD_A2SC2 0 #define R8A77980_PD_A2SC3 1 #define R8A77980_PD_A2SC4 2 -#define R8A77980_PD_A2PD0 3 -#define R8A77980_PD_A2PD1 4 +#define R8A77980_PD_A2DP0 3 +#define R8A77980_PD_A2DP1 4 #define R8A77980_PD_CA53_CPU0 5 #define R8A77980_PD_CA53_CPU1 6 #define R8A77980_PD_CA53_CPU2 7 From 160bfa7c724b348a90a12dd9694f351927a15b8e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 29 Nov 2018 11:56:18 +0100 Subject: [PATCH 52/73] soc: renesas: r8a77980-sysc: Correct A3VIP[012] power domain hierarchy The R-Car Gen3 HardWare Manual Errata for Rev. 0.80 (Feb 28, 2018) renamed the A3VIP power domain on R-Car V3H to A3VIP0, and clarified the power domain hierarchy for the A3VIP[012] power domains. As the definition for the A3VIP0 domain is not yet used from DT, it can just be renamed. Fixes: 7755b40d07a8dba7 ("dt-bindings: power: add R8A77980 SYSC power domain definitions") Fixes: 41d6d8bd8ae94ca9 ("soc: renesas: rcar-sysc: add R8A77980 support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/r8a77980-sysc.c | 6 +++--- include/dt-bindings/power/r8a77980-sysc.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/renesas/r8a77980-sysc.c b/drivers/soc/renesas/r8a77980-sysc.c index dbb2621ce4e3..a8dbe55e8ba8 100644 --- a/drivers/soc/renesas/r8a77980-sysc.c +++ b/drivers/soc/renesas/r8a77980-sysc.c @@ -41,9 +41,9 @@ static const struct rcar_sysc_area r8a77980_areas[] __initconst = { { "a2dp0", 0x400, 11, R8A77980_PD_A2DP0, R8A77980_PD_A3IR }, { "a2dp1", 0x400, 12, R8A77980_PD_A2DP1, R8A77980_PD_A3IR }, { "a2cn", 0x400, 13, R8A77980_PD_A2CN, R8A77980_PD_A3IR }, - { "a3vip", 0x2c0, 0, R8A77980_PD_A3VIP, R8A77980_PD_ALWAYS_ON }, - { "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_A3VIP }, - { "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_A3VIP }, + { "a3vip0", 0x2c0, 0, R8A77980_PD_A3VIP0, R8A77980_PD_ALWAYS_ON }, + { "a3vip1", 0x300, 0, R8A77980_PD_A3VIP1, R8A77980_PD_ALWAYS_ON }, + { "a3vip2", 0x280, 0, R8A77980_PD_A3VIP2, R8A77980_PD_ALWAYS_ON }, }; const struct rcar_sysc_info r8a77980_sysc_info __initconst = { diff --git a/include/dt-bindings/power/r8a77980-sysc.h b/include/dt-bindings/power/r8a77980-sysc.h index 7bebe7e8dbdb..e12c8587b87e 100644 --- a/include/dt-bindings/power/r8a77980-sysc.h +++ b/include/dt-bindings/power/r8a77980-sysc.h @@ -22,7 +22,7 @@ #define R8A77980_PD_CA53_CPU2 7 #define R8A77980_PD_CA53_CPU3 8 #define R8A77980_PD_A2CN 10 -#define R8A77980_PD_A3VIP 11 +#define R8A77980_PD_A3VIP0 11 #define R8A77980_PD_A2IR5 12 #define R8A77980_PD_CR7 13 #define R8A77980_PD_A2IR4 15 From 576f1b4bc80220e1f88f1de5ecb25d99a6e9fa04 Mon Sep 17 00:00:00 2001 From: Houlong Wei Date: Thu, 29 Nov 2018 11:37:09 +0800 Subject: [PATCH 53/73] soc: mediatek: Add Mediatek CMDQ helper Add Mediatek CMDQ helper to create CMDQ packet and assemble GCE op code. Signed-off-by: Houlong Wei Signed-off-by: HS Liao Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/Kconfig | 12 + drivers/soc/mediatek/Makefile | 1 + drivers/soc/mediatek/mtk-cmdq-helper.c | 300 +++++++++++++++++++++++++ include/linux/soc/mediatek/mtk-cmdq.h | 133 +++++++++++ 4 files changed, 446 insertions(+) create mode 100644 drivers/soc/mediatek/mtk-cmdq-helper.c create mode 100644 include/linux/soc/mediatek/mtk-cmdq.h diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index a7d0667338f2..17bd7590464f 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -4,6 +4,18 @@ menu "MediaTek SoC drivers" depends on ARCH_MEDIATEK || COMPILE_TEST +config MTK_CMDQ + tristate "MediaTek CMDQ Support" + depends on ARCH_MEDIATEK || COMPILE_TEST + select MAILBOX + select MTK_CMDQ_MBOX + select MTK_INFRACFG + help + Say yes here to add support for the MediaTek Command Queue (CMDQ) + driver. The CMDQ is used to help read/write registers with critical + time limitation, such as updating display configuration during the + vblank. + config MTK_INFRACFG bool "MediaTek INFRACFG Support" select REGMAP diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile index 12998b08819e..64ce5eeaba32 100644 --- a/drivers/soc/mediatek/Makefile +++ b/drivers/soc/mediatek/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c new file mode 100644 index 000000000000..ff9fef5a032b --- /dev/null +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2018 MediaTek Inc. + +#include +#include +#include +#include +#include +#include + +#define CMDQ_ARG_A_WRITE_MASK 0xffff +#define CMDQ_WRITE_ENABLE_MASK BIT(0) +#define CMDQ_EOC_IRQ_EN BIT(0) +#define CMDQ_EOC_CMD ((u64)((CMDQ_CODE_EOC << CMDQ_OP_CODE_SHIFT)) \ + << 32 | CMDQ_EOC_IRQ_EN) + +static void cmdq_client_timeout(struct timer_list *t) +{ + struct cmdq_client *client = from_timer(client, t, timer); + + dev_err(client->client.dev, "cmdq timeout!\n"); +} + +struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, u32 timeout) +{ + struct cmdq_client *client; + + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return (struct cmdq_client *)-ENOMEM; + + client->timeout_ms = timeout; + if (timeout != CMDQ_NO_TIMEOUT) { + spin_lock_init(&client->lock); + timer_setup(&client->timer, cmdq_client_timeout, 0); + } + client->pkt_cnt = 0; + client->client.dev = dev; + client->client.tx_block = false; + client->chan = mbox_request_channel(&client->client, index); + + if (IS_ERR(client->chan)) { + long err; + + dev_err(dev, "failed to request channel\n"); + err = PTR_ERR(client->chan); + kfree(client); + + return ERR_PTR(err); + } + + return client; +} +EXPORT_SYMBOL(cmdq_mbox_create); + +void cmdq_mbox_destroy(struct cmdq_client *client) +{ + if (client->timeout_ms != CMDQ_NO_TIMEOUT) { + spin_lock(&client->lock); + del_timer_sync(&client->timer); + spin_unlock(&client->lock); + } + mbox_free_channel(client->chan); + kfree(client); +} +EXPORT_SYMBOL(cmdq_mbox_destroy); + +struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size) +{ + struct cmdq_pkt *pkt; + struct device *dev; + dma_addr_t dma_addr; + + pkt = kzalloc(sizeof(*pkt), GFP_KERNEL); + if (!pkt) + return ERR_PTR(-ENOMEM); + pkt->va_base = kzalloc(size, GFP_KERNEL); + if (!pkt->va_base) { + kfree(pkt); + return ERR_PTR(-ENOMEM); + } + pkt->buf_size = size; + pkt->cl = (void *)client; + + dev = client->chan->mbox->dev; + dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_addr)) { + dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size); + kfree(pkt->va_base); + kfree(pkt); + return ERR_PTR(-ENOMEM); + } + + pkt->pa_base = dma_addr; + + return pkt; +} +EXPORT_SYMBOL(cmdq_pkt_create); + +void cmdq_pkt_destroy(struct cmdq_pkt *pkt) +{ + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size, + DMA_TO_DEVICE); + kfree(pkt->va_base); + kfree(pkt); +} +EXPORT_SYMBOL(cmdq_pkt_destroy); + +static int cmdq_pkt_append_command(struct cmdq_pkt *pkt, enum cmdq_code code, + u32 arg_a, u32 arg_b) +{ + u64 *cmd_ptr; + + if (unlikely(pkt->cmd_buf_size + CMDQ_INST_SIZE > pkt->buf_size)) { + /* + * In the case of allocated buffer size (pkt->buf_size) is used + * up, the real required size (pkt->cmdq_buf_size) is still + * increased, so that the user knows how much memory should be + * ultimately allocated after appending all commands and + * flushing the command packet. Therefor, the user can call + * cmdq_pkt_create() again with the real required buffer size. + */ + pkt->cmd_buf_size += CMDQ_INST_SIZE; + WARN_ONCE(1, "%s: buffer size %u is too small !\n", + __func__, (u32)pkt->buf_size); + return -ENOMEM; + } + cmd_ptr = pkt->va_base + pkt->cmd_buf_size; + (*cmd_ptr) = (u64)((code << CMDQ_OP_CODE_SHIFT) | arg_a) << 32 | arg_b; + pkt->cmd_buf_size += CMDQ_INST_SIZE; + + return 0; +} + +int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset) +{ + u32 arg_a = (offset & CMDQ_ARG_A_WRITE_MASK) | + (subsys << CMDQ_SUBSYS_SHIFT); + + return cmdq_pkt_append_command(pkt, CMDQ_CODE_WRITE, arg_a, value); +} +EXPORT_SYMBOL(cmdq_pkt_write); + +int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value, + u32 subsys, u32 offset, u32 mask) +{ + u32 offset_mask = offset; + int err = 0; + + if (mask != 0xffffffff) { + err = cmdq_pkt_append_command(pkt, CMDQ_CODE_MASK, 0, ~mask); + offset_mask |= CMDQ_WRITE_ENABLE_MASK; + } + err |= cmdq_pkt_write(pkt, value, subsys, offset_mask); + + return err; +} +EXPORT_SYMBOL(cmdq_pkt_write_mask); + +int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event) +{ + u32 arg_b; + + if (event >= CMDQ_MAX_EVENT) + return -EINVAL; + + /* + * WFE arg_b + * bit 0-11: wait value + * bit 15: 1 - wait, 0 - no wait + * bit 16-27: update value + * bit 31: 1 - update, 0 - no update + */ + arg_b = CMDQ_WFE_UPDATE | CMDQ_WFE_WAIT | CMDQ_WFE_WAIT_VALUE; + + return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, arg_b); +} +EXPORT_SYMBOL(cmdq_pkt_wfe); + +int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event) +{ + if (event >= CMDQ_MAX_EVENT) + return -EINVAL; + + return cmdq_pkt_append_command(pkt, CMDQ_CODE_WFE, event, + CMDQ_WFE_UPDATE); +} +EXPORT_SYMBOL(cmdq_pkt_clear_event); + +static int cmdq_pkt_finalize(struct cmdq_pkt *pkt) +{ + int err; + + /* insert EOC and generate IRQ for each command iteration */ + err = cmdq_pkt_append_command(pkt, CMDQ_CODE_EOC, 0, CMDQ_EOC_IRQ_EN); + + /* JUMP to end */ + err |= cmdq_pkt_append_command(pkt, CMDQ_CODE_JUMP, 0, CMDQ_JUMP_PASS); + + return err; +} + +static void cmdq_pkt_flush_async_cb(struct cmdq_cb_data data) +{ + struct cmdq_pkt *pkt = (struct cmdq_pkt *)data.data; + struct cmdq_task_cb *cb = &pkt->cb; + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + if (client->timeout_ms != CMDQ_NO_TIMEOUT) { + unsigned long flags = 0; + + spin_lock_irqsave(&client->lock, flags); + if (--client->pkt_cnt == 0) + del_timer(&client->timer); + else + mod_timer(&client->timer, jiffies + + msecs_to_jiffies(client->timeout_ms)); + spin_unlock_irqrestore(&client->lock, flags); + } + + dma_sync_single_for_cpu(client->chan->mbox->dev, pkt->pa_base, + pkt->cmd_buf_size, DMA_TO_DEVICE); + if (cb->cb) { + data.data = cb->data; + cb->cb(data); + } +} + +int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, + void *data) +{ + int err; + unsigned long flags = 0; + struct cmdq_client *client = (struct cmdq_client *)pkt->cl; + + err = cmdq_pkt_finalize(pkt); + if (err < 0) + return err; + + pkt->cb.cb = cb; + pkt->cb.data = data; + pkt->async_cb.cb = cmdq_pkt_flush_async_cb; + pkt->async_cb.data = pkt; + + dma_sync_single_for_device(client->chan->mbox->dev, pkt->pa_base, + pkt->cmd_buf_size, DMA_TO_DEVICE); + + if (client->timeout_ms != CMDQ_NO_TIMEOUT) { + spin_lock_irqsave(&client->lock, flags); + if (client->pkt_cnt++ == 0) + mod_timer(&client->timer, jiffies + + msecs_to_jiffies(client->timeout_ms)); + spin_unlock_irqrestore(&client->lock, flags); + } + + mbox_send_message(client->chan, pkt); + /* We can send next packet immediately, so just call txdone. */ + mbox_client_txdone(client->chan, 0); + + return 0; +} +EXPORT_SYMBOL(cmdq_pkt_flush_async); + +struct cmdq_flush_completion { + struct completion cmplt; + bool err; +}; + +static void cmdq_pkt_flush_cb(struct cmdq_cb_data data) +{ + struct cmdq_flush_completion *cmplt; + + cmplt = (struct cmdq_flush_completion *)data.data; + if (data.sta != CMDQ_CB_NORMAL) + cmplt->err = true; + else + cmplt->err = false; + complete(&cmplt->cmplt); +} + +int cmdq_pkt_flush(struct cmdq_pkt *pkt) +{ + struct cmdq_flush_completion cmplt; + int err; + + init_completion(&cmplt.cmplt); + err = cmdq_pkt_flush_async(pkt, cmdq_pkt_flush_cb, &cmplt); + if (err < 0) + return err; + wait_for_completion(&cmplt.cmplt); + + return cmplt.err ? -EFAULT : 0; +} +EXPORT_SYMBOL(cmdq_pkt_flush); + +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/soc/mediatek/mtk-cmdq.h b/include/linux/soc/mediatek/mtk-cmdq.h new file mode 100644 index 000000000000..54ade13a9b15 --- /dev/null +++ b/include/linux/soc/mediatek/mtk-cmdq.h @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 MediaTek Inc. + * + */ + +#ifndef __MTK_CMDQ_H__ +#define __MTK_CMDQ_H__ + +#include +#include +#include + +#define CMDQ_NO_TIMEOUT 0xffffffffu + +/** cmdq event maximum */ +#define CMDQ_MAX_EVENT 0x3ff + +struct cmdq_pkt; + +struct cmdq_client { + spinlock_t lock; + u32 pkt_cnt; + struct mbox_client client; + struct mbox_chan *chan; + struct timer_list timer; + u32 timeout_ms; /* in unit of microsecond */ +}; + +/** + * cmdq_mbox_create() - create CMDQ mailbox client and channel + * @dev: device of CMDQ mailbox client + * @index: index of CMDQ mailbox channel + * @timeout: timeout of a pkt execution by GCE, in unit of microsecond, set + * CMDQ_NO_TIMEOUT if a timer is not used. + * + * Return: CMDQ mailbox client pointer + */ +struct cmdq_client *cmdq_mbox_create(struct device *dev, int index, + u32 timeout); + +/** + * cmdq_mbox_destroy() - destroy CMDQ mailbox client and channel + * @client: the CMDQ mailbox client + */ +void cmdq_mbox_destroy(struct cmdq_client *client); + +/** + * cmdq_pkt_create() - create a CMDQ packet + * @client: the CMDQ mailbox client + * @size: required CMDQ buffer size + * + * Return: CMDQ packet pointer + */ +struct cmdq_pkt *cmdq_pkt_create(struct cmdq_client *client, size_t size); + +/** + * cmdq_pkt_destroy() - destroy the CMDQ packet + * @pkt: the CMDQ packet + */ +void cmdq_pkt_destroy(struct cmdq_pkt *pkt); + +/** + * cmdq_pkt_write() - append write command to the CMDQ packet + * @pkt: the CMDQ packet + * @value: the specified target register value + * @subsys: the CMDQ sub system code + * @offset: register offset from CMDQ sub system + * + * Return: 0 for success; else the error code is returned + */ +int cmdq_pkt_write(struct cmdq_pkt *pkt, u32 value, u32 subsys, u32 offset); + +/** + * cmdq_pkt_write_mask() - append write command with mask to the CMDQ packet + * @pkt: the CMDQ packet + * @value: the specified target register value + * @subsys: the CMDQ sub system code + * @offset: register offset from CMDQ sub system + * @mask: the specified target register mask + * + * Return: 0 for success; else the error code is returned + */ +int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u32 value, + u32 subsys, u32 offset, u32 mask); + +/** + * cmdq_pkt_wfe() - append wait for event command to the CMDQ packet + * @pkt: the CMDQ packet + * @event: the desired event type to "wait and CLEAR" + * + * Return: 0 for success; else the error code is returned + */ +int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u32 event); + +/** + * cmdq_pkt_clear_event() - append clear event command to the CMDQ packet + * @pkt: the CMDQ packet + * @event: the desired event to be cleared + * + * Return: 0 for success; else the error code is returned + */ +int cmdq_pkt_clear_event(struct cmdq_pkt *pkt, u32 event); + +/** + * cmdq_pkt_flush_async() - trigger CMDQ to asynchronously execute the CMDQ + * packet and call back at the end of done packet + * @pkt: the CMDQ packet + * @cb: called at the end of done packet + * @data: this data will pass back to cb + * + * Return: 0 for success; else the error code is returned + * + * Trigger CMDQ to asynchronously execute the CMDQ packet and call back + * at the end of done packet. Note that this is an ASYNC function. When the + * function returned, it may or may not be finished. + */ +int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb, + void *data); + +/** + * cmdq_pkt_flush() - trigger CMDQ to execute the CMDQ packet + * @pkt: the CMDQ packet + * + * Return: 0 for success; else the error code is returned + * + * Trigger CMDQ to execute the CMDQ packet. Note that this is a + * synchronous flush function. When the function returned, the recorded + * commands have been done. + */ +int cmdq_pkt_flush(struct cmdq_pkt *pkt); + +#endif /* __MTK_CMDQ_H__ */ From c2a70a319afb9e3dee16567cec4d9bf8dd358b59 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 17 Jun 2018 19:02:15 +0200 Subject: [PATCH 54/73] dmaengine: pxa: make the filter function internal As the pxa architecture and all its related drivers do not rely anymore on the filter function, thanks to the slave map conversion, make pxad_filter_fn() static, and remove it from the global namespace. Signed-off-by: Robert Jarzmik Acked-by: Vinod Koul --- drivers/dma/pxa_dma.c | 5 ++--- include/linux/dma/pxa-dma.h | 11 ----------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index 825725057e00..c7a328f81485 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -179,7 +179,7 @@ static unsigned int pxad_drcmr(unsigned int line) return 0x1000 + line * 4; } -bool pxad_filter_fn(struct dma_chan *chan, void *param); +static bool pxad_filter_fn(struct dma_chan *chan, void *param); /* * Debug fs @@ -1500,7 +1500,7 @@ static struct platform_driver pxad_driver = { .remove = pxad_remove, }; -bool pxad_filter_fn(struct dma_chan *chan, void *param) +static bool pxad_filter_fn(struct dma_chan *chan, void *param) { struct pxad_chan *c = to_pxad_chan(chan); struct pxad_param *p = param; @@ -1513,7 +1513,6 @@ bool pxad_filter_fn(struct dma_chan *chan, void *param) return true; } -EXPORT_SYMBOL_GPL(pxad_filter_fn); module_platform_driver(pxad_driver); diff --git a/include/linux/dma/pxa-dma.h b/include/linux/dma/pxa-dma.h index 9fc594f69eff..fceb5df07097 100644 --- a/include/linux/dma/pxa-dma.h +++ b/include/linux/dma/pxa-dma.h @@ -23,15 +23,4 @@ struct pxad_param { enum pxad_chan_prio prio; }; -struct dma_chan; - -#ifdef CONFIG_PXA_DMA -bool pxad_filter_fn(struct dma_chan *chan, void *param); -#else -static inline bool pxad_filter_fn(struct dma_chan *chan, void *param) -{ - return false; -} -#endif - #endif /* _PXA_DMA_H_ */ From a800f418420d37f60fa471665a156c45d2702437 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 16 Nov 2018 16:49:25 +0100 Subject: [PATCH 55/73] soc: imx: gpcv2: prefix i.MX7 specific defines So we can add i.MX8M support without introducing name clashes. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index e7b5994fee9d..4183f7f830c8 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -18,19 +18,19 @@ #define GPC_LPCR_A_CORE_BSC 0x000 #define GPC_PGC_CPU_MAPPING 0x0ec -#define USB_HSIC_PHY_A_CORE_DOMAIN BIT(6) -#define USB_OTG2_PHY_A_CORE_DOMAIN BIT(5) -#define USB_OTG1_PHY_A_CORE_DOMAIN BIT(4) -#define PCIE_PHY_A_CORE_DOMAIN BIT(3) -#define MIPI_PHY_A_CORE_DOMAIN BIT(2) +#define IMX7_USB_HSIC_PHY_A_CORE_DOMAIN BIT(6) +#define IMX7_USB_OTG2_PHY_A_CORE_DOMAIN BIT(5) +#define IMX7_USB_OTG1_PHY_A_CORE_DOMAIN BIT(4) +#define IMX7_PCIE_PHY_A_CORE_DOMAIN BIT(3) +#define IMX7_MIPI_PHY_A_CORE_DOMAIN BIT(2) #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 #define GPC_PU_PGC_SW_PDN_REQ 0x104 -#define USB_HSIC_PHY_SW_Pxx_REQ BIT(4) -#define USB_OTG2_PHY_SW_Pxx_REQ BIT(3) -#define USB_OTG1_PHY_SW_Pxx_REQ BIT(2) -#define PCIE_PHY_SW_Pxx_REQ BIT(1) -#define MIPI_PHY_SW_Pxx_REQ BIT(0) +#define IMX7_USB_HSIC_PHY_SW_Pxx_REQ BIT(4) +#define IMX7_USB_OTG2_PHY_SW_Pxx_REQ BIT(3) +#define IMX7_USB_OTG1_PHY_SW_Pxx_REQ BIT(2) +#define IMX7_PCIE_PHY_SW_Pxx_REQ BIT(1) +#define IMX7_MIPI_PHY_SW_Pxx_REQ BIT(0) #define GPC_M4_PU_PDN_FLG 0x1bc @@ -40,9 +40,9 @@ * GPC_PGC memory map are incorrect, below offset * values are from design RTL. */ -#define PGC_MIPI 16 -#define PGC_PCIE 17 -#define PGC_USB_HSIC 20 +#define IMX7_PGC_MIPI 16 +#define IMX7_PGC_PCIE 17 +#define IMX7_PGC_USB_HSIC 20 #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) @@ -166,11 +166,11 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = { .name = "mipi-phy", }, .bits = { - .pxx = MIPI_PHY_SW_Pxx_REQ, - .map = MIPI_PHY_A_CORE_DOMAIN, + .pxx = IMX7_MIPI_PHY_SW_Pxx_REQ, + .map = IMX7_MIPI_PHY_A_CORE_DOMAIN, }, .voltage = 1000000, - .pgc = PGC_MIPI, + .pgc = IMX7_PGC_MIPI, }, [IMX7_POWER_DOMAIN_PCIE_PHY] = { @@ -178,11 +178,11 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = { .name = "pcie-phy", }, .bits = { - .pxx = PCIE_PHY_SW_Pxx_REQ, - .map = PCIE_PHY_A_CORE_DOMAIN, + .pxx = IMX7_PCIE_PHY_SW_Pxx_REQ, + .map = IMX7_PCIE_PHY_A_CORE_DOMAIN, }, .voltage = 1000000, - .pgc = PGC_PCIE, + .pgc = IMX7_PGC_PCIE, }, [IMX7_POWER_DOMAIN_USB_HSIC_PHY] = { @@ -190,11 +190,11 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = { .name = "usb-hsic-phy", }, .bits = { - .pxx = USB_HSIC_PHY_SW_Pxx_REQ, - .map = USB_HSIC_PHY_A_CORE_DOMAIN, + .pxx = IMX7_USB_HSIC_PHY_SW_Pxx_REQ, + .map = IMX7_USB_HSIC_PHY_A_CORE_DOMAIN, }, .voltage = 1200000, - .pgc = PGC_USB_HSIC, + .pgc = IMX7_PGC_USB_HSIC, }, }; @@ -269,12 +269,12 @@ static int imx_gpcv2_probe(struct platform_device *pdev) static const struct regmap_range yes_ranges[] = { regmap_reg_range(GPC_LPCR_A_CORE_BSC, GPC_M4_PU_PDN_FLG), - regmap_reg_range(GPC_PGC_CTRL(PGC_MIPI), - GPC_PGC_SR(PGC_MIPI)), - regmap_reg_range(GPC_PGC_CTRL(PGC_PCIE), - GPC_PGC_SR(PGC_PCIE)), - regmap_reg_range(GPC_PGC_CTRL(PGC_USB_HSIC), - GPC_PGC_SR(PGC_USB_HSIC)), + regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_MIPI), + GPC_PGC_SR(IMX7_PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_PCIE), + GPC_PGC_SR(IMX7_PGC_PCIE)), + regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_USB_HSIC), + GPC_PGC_SR(IMX7_PGC_USB_HSIC)), }; static const struct regmap_access_table access_table = { .yes_ranges = yes_ranges, From e125dcba83f59b87b1db30f5b7075705d95cfcf7 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 16 Nov 2018 16:49:26 +0100 Subject: [PATCH 56/73] soc: imx: gpcv2: move register access table to domain data The valid register ranges are defined by the implemented power domains, which are different between the individual SoCs where the GPCv2 is used. Signed-off-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 44 ++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 4183f7f830c8..fe2cf6b61b05 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -67,6 +67,7 @@ struct imx_pgc_domain { struct imx_pgc_domain_data { const struct imx_pgc_domain *domains; size_t domains_num; + const struct regmap_access_table *reg_access_table; }; static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, @@ -198,9 +199,26 @@ static const struct imx_pgc_domain imx7_pgc_domains[] = { }, }; +static const struct regmap_range imx7_yes_ranges[] = { + regmap_reg_range(GPC_LPCR_A_CORE_BSC, + GPC_M4_PU_PDN_FLG), + regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_MIPI), + GPC_PGC_SR(IMX7_PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_PCIE), + GPC_PGC_SR(IMX7_PGC_PCIE)), + regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_USB_HSIC), + GPC_PGC_SR(IMX7_PGC_USB_HSIC)), +}; + +static const struct regmap_access_table imx7_access_table = { + .yes_ranges = imx7_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(imx7_yes_ranges), +}; + static const struct imx_pgc_domain_data imx7_pgc_domain_data = { .domains = imx7_pgc_domains, .domains_num = ARRAY_SIZE(imx7_pgc_domains), + .reg_access_table = &imx7_access_table, }; static int imx_pgc_domain_probe(struct platform_device *pdev) @@ -265,27 +283,15 @@ builtin_platform_driver(imx_pgc_domain_driver) static int imx_gpcv2_probe(struct platform_device *pdev) { - static const struct imx_pgc_domain_data *domain_data; - static const struct regmap_range yes_ranges[] = { - regmap_reg_range(GPC_LPCR_A_CORE_BSC, - GPC_M4_PU_PDN_FLG), - regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_MIPI), - GPC_PGC_SR(IMX7_PGC_MIPI)), - regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_PCIE), - GPC_PGC_SR(IMX7_PGC_PCIE)), - regmap_reg_range(GPC_PGC_CTRL(IMX7_PGC_USB_HSIC), - GPC_PGC_SR(IMX7_PGC_USB_HSIC)), - }; - static const struct regmap_access_table access_table = { - .yes_ranges = yes_ranges, - .n_yes_ranges = ARRAY_SIZE(yes_ranges), - }; - static const struct regmap_config regmap_config = { + const struct imx_pgc_domain_data *domain_data = + of_device_get_match_data(&pdev->dev); + + struct regmap_config regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, - .rd_table = &access_table, - .wr_table = &access_table, + .rd_table = domain_data->reg_access_table, + .wr_table = domain_data->reg_access_table, .max_register = SZ_4K, }; struct device *dev = &pdev->dev; @@ -313,8 +319,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) return ret; } - domain_data = of_device_get_match_data(&pdev->dev); - for_each_child_of_node(pgc_np, np) { struct platform_device *pd_pdev; struct imx_pgc_domain *domain; From 685efffe37c921cf1d56dd3c8617dc67bc343a99 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 16 Nov 2018 16:49:27 +0100 Subject: [PATCH 57/73] soc: imx: gpcv2: add support for i.MX8MQ SoC The GPCv2 on the Freescale i.MX8MQ SoC works in the same way as the GPCv2 on the i.MX7, but only controls more power domains with a different mapping. Signed-off-by: Lucas Stach Acked-by: Rob Herring Signed-off-by: Shawn Guo --- .../bindings/power/fsl,imx-gpcv2.txt | 7 +- drivers/soc/imx/Kconfig | 6 +- drivers/soc/imx/Makefile | 2 +- drivers/soc/imx/gpcv2.c | 208 +++++++++++++++++- include/dt-bindings/power/imx8mq-power.h | 21 ++ 5 files changed, 237 insertions(+), 7 deletions(-) create mode 100644 include/dt-bindings/power/imx8mq-power.h diff --git a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt index 9acce75b29ab..7c947a996df1 100644 --- a/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt +++ b/Documentation/devicetree/bindings/power/fsl,imx-gpcv2.txt @@ -6,7 +6,9 @@ Control (PGC) for various power domains. Required properties: -- compatible: Should be "fsl,imx7d-gpc" +- compatible: Should be one of: + - "fsl,imx7d-gpc" + - "fsl,imx8mq-gpc" - reg: should be register base and length as documented in the datasheet @@ -22,7 +24,8 @@ which, in turn, is expected to contain the following: Required properties: - reg: Power domain index. Valid values are defined in - include/dt-bindings/power/imx7-power.h + include/dt-bindings/power/imx7-power.h for fsl,imx7d-gpc and + include/dt-bindings/power/imx8m-power.h for fsl,imx8mq-gpc - #power-domain-cells: Should be 0 diff --git a/drivers/soc/imx/Kconfig b/drivers/soc/imx/Kconfig index a5b86a28f343..2112d18dbb7b 100644 --- a/drivers/soc/imx/Kconfig +++ b/drivers/soc/imx/Kconfig @@ -1,8 +1,8 @@ menu "i.MX SoC drivers" -config IMX7_PM_DOMAINS - bool "i.MX7 PM domains" - depends on SOC_IMX7D || (COMPILE_TEST && OF) +config IMX_GPCV2_PM_DOMAINS + bool "i.MX GPCv2 PM domains" + depends on SOC_IMX7D || SOC_IMX8MQ || (COMPILE_TEST && OF) depends on PM select PM_GENERIC_DOMAINS default y if SOC_IMX7D diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index aab41a5cc317..506a6f3c2b9b 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o -obj-$(CONFIG_IMX7_PM_DOMAINS) += gpcv2.o +obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index fe2cf6b61b05..8b4f48a2ca57 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -14,24 +14,55 @@ #include #include #include +#include #define GPC_LPCR_A_CORE_BSC 0x000 #define GPC_PGC_CPU_MAPPING 0x0ec + #define IMX7_USB_HSIC_PHY_A_CORE_DOMAIN BIT(6) #define IMX7_USB_OTG2_PHY_A_CORE_DOMAIN BIT(5) #define IMX7_USB_OTG1_PHY_A_CORE_DOMAIN BIT(4) #define IMX7_PCIE_PHY_A_CORE_DOMAIN BIT(3) #define IMX7_MIPI_PHY_A_CORE_DOMAIN BIT(2) +#define IMX8M_PCIE2_A53_DOMAIN BIT(15) +#define IMX8M_MIPI_CSI2_A53_DOMAIN BIT(14) +#define IMX8M_MIPI_CSI1_A53_DOMAIN BIT(13) +#define IMX8M_DISP_A53_DOMAIN BIT(12) +#define IMX8M_HDMI_A53_DOMAIN BIT(11) +#define IMX8M_VPU_A53_DOMAIN BIT(10) +#define IMX8M_GPU_A53_DOMAIN BIT(9) +#define IMX8M_DDR2_A53_DOMAIN BIT(8) +#define IMX8M_DDR1_A53_DOMAIN BIT(7) +#define IMX8M_OTG2_A53_DOMAIN BIT(5) +#define IMX8M_OTG1_A53_DOMAIN BIT(4) +#define IMX8M_PCIE1_A53_DOMAIN BIT(3) +#define IMX8M_MIPI_A53_DOMAIN BIT(2) + #define GPC_PU_PGC_SW_PUP_REQ 0x0f8 #define GPC_PU_PGC_SW_PDN_REQ 0x104 + #define IMX7_USB_HSIC_PHY_SW_Pxx_REQ BIT(4) #define IMX7_USB_OTG2_PHY_SW_Pxx_REQ BIT(3) #define IMX7_USB_OTG1_PHY_SW_Pxx_REQ BIT(2) #define IMX7_PCIE_PHY_SW_Pxx_REQ BIT(1) #define IMX7_MIPI_PHY_SW_Pxx_REQ BIT(0) +#define IMX8M_PCIE2_SW_Pxx_REQ BIT(13) +#define IMX8M_MIPI_CSI2_SW_Pxx_REQ BIT(12) +#define IMX8M_MIPI_CSI1_SW_Pxx_REQ BIT(11) +#define IMX8M_DISP_SW_Pxx_REQ BIT(10) +#define IMX8M_HDMI_SW_Pxx_REQ BIT(9) +#define IMX8M_VPU_SW_Pxx_REQ BIT(8) +#define IMX8M_GPU_SW_Pxx_REQ BIT(7) +#define IMX8M_DDR2_SW_Pxx_REQ BIT(6) +#define IMX8M_DDR1_SW_Pxx_REQ BIT(5) +#define IMX8M_OTG2_SW_Pxx_REQ BIT(3) +#define IMX8M_OTG1_SW_Pxx_REQ BIT(2) +#define IMX8M_PCIE1_SW_Pxx_REQ BIT(1) +#define IMX8M_MIPI_SW_Pxx_REQ BIT(0) + #define GPC_M4_PU_PDN_FLG 0x1bc /* @@ -43,6 +74,19 @@ #define IMX7_PGC_MIPI 16 #define IMX7_PGC_PCIE 17 #define IMX7_PGC_USB_HSIC 20 + +#define IMX8M_PGC_MIPI 16 +#define IMX8M_PGC_PCIE1 17 +#define IMX8M_PGC_OTG1 18 +#define IMX8M_PGC_OTG2 19 +#define IMX8M_PGC_DDR1 21 +#define IMX8M_PGC_GPU 23 +#define IMX8M_PGC_VPU 24 +#define IMX8M_PGC_DISP 26 +#define IMX8M_PGC_MIPI_CSI1 27 +#define IMX8M_PGC_MIPI_CSI2 28 +#define IMX8M_PGC_PCIE2 29 + #define GPC_PGC_CTRL(n) (0x800 + (n) * 0x40) #define GPC_PGC_SR(n) (GPC_PGC_CTRL(n) + 0xc) @@ -221,6 +265,167 @@ static const struct imx_pgc_domain_data imx7_pgc_domain_data = { .reg_access_table = &imx7_access_table, }; +static const struct imx_pgc_domain imx8m_pgc_domains[] = { + [IMX8M_POWER_DOMAIN_MIPI] = { + .genpd = { + .name = "mipi", + }, + .bits = { + .pxx = IMX8M_MIPI_SW_Pxx_REQ, + .map = IMX8M_MIPI_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_MIPI, + }, + + [IMX8M_POWER_DOMAIN_PCIE1] = { + .genpd = { + .name = "pcie1", + }, + .bits = { + .pxx = IMX8M_PCIE1_SW_Pxx_REQ, + .map = IMX8M_PCIE1_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_PCIE1, + }, + + [IMX8M_POWER_DOMAIN_USB_OTG1] = { + .genpd = { + .name = "usb-otg1", + }, + .bits = { + .pxx = IMX8M_OTG1_SW_Pxx_REQ, + .map = IMX8M_OTG1_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_OTG1, + }, + + [IMX8M_POWER_DOMAIN_USB_OTG2] = { + .genpd = { + .name = "usb-otg2", + }, + .bits = { + .pxx = IMX8M_OTG2_SW_Pxx_REQ, + .map = IMX8M_OTG2_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_OTG2, + }, + + [IMX8M_POWER_DOMAIN_DDR1] = { + .genpd = { + .name = "ddr1", + }, + .bits = { + .pxx = IMX8M_DDR1_SW_Pxx_REQ, + .map = IMX8M_DDR2_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_DDR1, + }, + + [IMX8M_POWER_DOMAIN_GPU] = { + .genpd = { + .name = "gpu", + }, + .bits = { + .pxx = IMX8M_GPU_SW_Pxx_REQ, + .map = IMX8M_GPU_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_GPU, + }, + + [IMX8M_POWER_DOMAIN_VPU] = { + .genpd = { + .name = "vpu", + }, + .bits = { + .pxx = IMX8M_VPU_SW_Pxx_REQ, + .map = IMX8M_VPU_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_VPU, + }, + + [IMX8M_POWER_DOMAIN_DISP] = { + .genpd = { + .name = "disp", + }, + .bits = { + .pxx = IMX8M_DISP_SW_Pxx_REQ, + .map = IMX8M_DISP_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_DISP, + }, + + [IMX8M_POWER_DOMAIN_MIPI_CSI1] = { + .genpd = { + .name = "mipi-csi1", + }, + .bits = { + .pxx = IMX8M_MIPI_CSI1_SW_Pxx_REQ, + .map = IMX8M_MIPI_CSI1_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_MIPI_CSI1, + }, + + [IMX8M_POWER_DOMAIN_MIPI_CSI2] = { + .genpd = { + .name = "mipi-csi2", + }, + .bits = { + .pxx = IMX8M_MIPI_CSI2_SW_Pxx_REQ, + .map = IMX8M_MIPI_CSI2_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_MIPI_CSI2, + }, + + [IMX8M_POWER_DOMAIN_PCIE2] = { + .genpd = { + .name = "pcie2", + }, + .bits = { + .pxx = IMX8M_PCIE2_SW_Pxx_REQ, + .map = IMX8M_PCIE2_A53_DOMAIN, + }, + .pgc = IMX8M_PGC_PCIE2, + }, +}; + +static const struct regmap_range imx8m_yes_ranges[] = { + regmap_reg_range(GPC_LPCR_A_CORE_BSC, + GPC_M4_PU_PDN_FLG), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI), + GPC_PGC_SR(IMX8M_PGC_MIPI)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE1), + GPC_PGC_SR(IMX8M_PGC_PCIE1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG1), + GPC_PGC_SR(IMX8M_PGC_OTG1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_OTG2), + GPC_PGC_SR(IMX8M_PGC_OTG2)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DDR1), + GPC_PGC_SR(IMX8M_PGC_DDR1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_GPU), + GPC_PGC_SR(IMX8M_PGC_GPU)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_VPU), + GPC_PGC_SR(IMX8M_PGC_VPU)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_DISP), + GPC_PGC_SR(IMX8M_PGC_DISP)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI1), + GPC_PGC_SR(IMX8M_PGC_MIPI_CSI1)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_MIPI_CSI2), + GPC_PGC_SR(IMX8M_PGC_MIPI_CSI2)), + regmap_reg_range(GPC_PGC_CTRL(IMX8M_PGC_PCIE2), + GPC_PGC_SR(IMX8M_PGC_PCIE2)), +}; + +static const struct regmap_access_table imx8m_access_table = { + .yes_ranges = imx8m_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(imx8m_yes_ranges), +}; + +static const struct imx_pgc_domain_data imx8m_pgc_domain_data = { + .domains = imx8m_pgc_domains, + .domains_num = ARRAY_SIZE(imx8m_pgc_domains), + .reg_access_table = &imx8m_access_table, +}; + static int imx_pgc_domain_probe(struct platform_device *pdev) { struct imx_pgc_domain *domain = pdev->dev.platform_data; @@ -235,7 +440,7 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) dev_err(domain->dev, "Failed to get domain's regulator\n"); return PTR_ERR(domain->regulator); } - } else { + } else if (domain->voltage) { regulator_set_voltage(domain->regulator, domain->voltage, domain->voltage); } @@ -376,6 +581,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev) static const struct of_device_id imx_gpcv2_dt_ids[] = { { .compatible = "fsl,imx7d-gpc", .data = &imx7_pgc_domain_data, }, + { .compatible = "fsl,imx8mq-gpc", .data = &imx8m_pgc_domain_data, }, { } }; diff --git a/include/dt-bindings/power/imx8mq-power.h b/include/dt-bindings/power/imx8mq-power.h new file mode 100644 index 000000000000..8a513bd9166e --- /dev/null +++ b/include/dt-bindings/power/imx8mq-power.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */ +/* + * Copyright (C) 2018 Pengutronix, Lucas Stach + */ + +#ifndef __DT_BINDINGS_IMX8MQ_POWER_H__ +#define __DT_BINDINGS_IMX8MQ_POWER_H__ + +#define IMX8M_POWER_DOMAIN_MIPI 0 +#define IMX8M_POWER_DOMAIN_PCIE1 1 +#define IMX8M_POWER_DOMAIN_USB_OTG1 2 +#define IMX8M_POWER_DOMAIN_USB_OTG2 3 +#define IMX8M_POWER_DOMAIN_DDR1 4 +#define IMX8M_POWER_DOMAIN_GPU 5 +#define IMX8M_POWER_DOMAIN_VPU 6 +#define IMX8M_POWER_DOMAIN_DISP 7 +#define IMX8M_POWER_DOMAIN_MIPI_CSI1 8 +#define IMX8M_POWER_DOMAIN_MIPI_CSI2 9 +#define IMX8M_POWER_DOMAIN_PCIE2 10 + +#endif From 15e53723ce2bcbe225be9c4bd9566ebb13f2298d Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 5 Dec 2018 10:24:33 +0100 Subject: [PATCH 58/73] soc: sunxi: sram: Enable EMAC clock access for H3 variant Just like the A64 and H5, the H3 SoC uses the system control block to enable the EMAC clock. Add a variant structure definition for the H3 and use it over the A10 one. This will allow using the H3-specific binding for the syscon node attached to the EMAC instead of the generic syscon binding. Signed-off-by: Paul Kocialkowski Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/soc/sunxi/sunxi_sram.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 71e3ee4a3f19..fd81a3c0db45 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -290,6 +290,10 @@ static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = { /* Nothing special */ }; +static const struct sunxi_sramc_variant sun8i_h3_sramc_variant = { + .has_emac_clock = true, +}; + static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = { .has_emac_clock = true, }; @@ -369,7 +373,7 @@ static const struct of_device_id sunxi_sram_dt_match[] = { }, { .compatible = "allwinner,sun8i-h3-system-control", - .data = &sun4i_a10_sramc_variant, + .data = &sun8i_h3_sramc_variant, }, { .compatible = "allwinner,sun50i-a64-sram-controller", From c7739268222ed819f85ec9b8c909aa5fc402cc23 Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 5 Dec 2018 10:24:35 +0100 Subject: [PATCH 59/73] soc: sunxi: sram: Add support for the H5 SoC system control This adds the H5 SoC compatible to the list of device-tree matches for the SRAM driver. Since the variant is the same as the A64 (that precedes the H5), the same variant description is used. Signed-off-by: Paul Kocialkowski Signed-off-by: Maxime Ripard --- drivers/soc/sunxi/sunxi_sram.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index fd81a3c0db45..1b0d50f36349 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -383,6 +383,10 @@ static const struct of_device_id sunxi_sram_dt_match[] = { .compatible = "allwinner,sun50i-a64-system-control", .data = &sun50i_a64_sramc_variant, }, + { + .compatible = "allwinner,sun50i-h5-system-control", + .data = &sun50i_a64_sramc_variant, + }, { }, }; MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match); From 46d1ec73c19067dad22523632306e3fffedb5f11 Mon Sep 17 00:00:00 2001 From: Mesih Kilinc Date: Sun, 2 Dec 2018 23:23:48 +0300 Subject: [PATCH 60/73] dt-bindings: sram: Add Allwinner suniv F1C100s The suniv ARMv5 F1C100s chip has similar sram controller to sun4i A10. Add compatible string for it. Signed-off-by: Mesih Kilinc Reviewed-by: Rob Herring Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/sram/sunxi-sram.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt index 62dd0748f0ef..5c84850dd0df 100644 --- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt +++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt @@ -19,6 +19,7 @@ Required properties: - "allwinner,sun50i-a64-sram-controller" (deprecated) - "allwinner,sun50i-a64-system-control" - "allwinner,sun50i-h6-system-control", "allwinner,sun50i-a64-system-control" + - "allwinner,suniv-f1c100s-system-control", "allwinner,sun4i-a10-system-control" - reg : sram controller register offset + length SRAM nodes @@ -58,6 +59,9 @@ The valid sections compatible for A64 are: The valid sections compatible for H6 are: - allwinner,sun50i-h6-sram-c, allwinner,sun50i-a64-sram-c +The valid sections compatible for F1C100s are: + - allwinner,suniv-f1c100s-sram-d, allwinner,sun4i-a10-sram-d + Devices using SRAM sections --------------------------- From ebc0a24d11b3618e7680e117ee3be421c09ad43a Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 5 Dec 2018 10:24:34 +0100 Subject: [PATCH 61/73] dt-bindings: sram: sunxi: Add bindings for the H5 with SRAM C1 This introduces new bindings for the H5 SoC in the SRAM controller. Because the SRAM layout is different from other SoCs, no backward compatibility is assumed with any of them. However, the C1 SRAM section alone looks similar to previous SoCs, so it is compatible with the initial A10 binding. Signed-off-by: Paul Kocialkowski Acked-by: Chen-Yu Tsai Reviewed-by: Rob Herring Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/sram/sunxi-sram.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt index 5c84850dd0df..5c9a54ad3b53 100644 --- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt +++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt @@ -18,6 +18,7 @@ Required properties: - "allwinner,sun8i-h3-system-control" - "allwinner,sun50i-a64-sram-controller" (deprecated) - "allwinner,sun50i-a64-system-control" + - "allwinner,sun50i-h5-system-control" - "allwinner,sun50i-h6-system-control", "allwinner,sun50i-a64-system-control" - "allwinner,suniv-f1c100s-system-control", "allwinner,sun4i-a10-system-control" - reg : sram controller register offset + length @@ -56,6 +57,9 @@ The valid sections compatible for H3 are: The valid sections compatible for A64 are: - allwinner,sun50i-a64-sram-c +The valid sections compatible for H5 are: + - allwinner,sun50i-h5-sram-c1, allwinner,sun4i-a10-sram-c1 + The valid sections compatible for H6 are: - allwinner,sun50i-h6-sram-c, allwinner,sun50i-a64-sram-c From d44d37cb27df5501de0693fb03803e244653713c Mon Sep 17 00:00:00 2001 From: Paul Kocialkowski Date: Wed, 5 Dec 2018 10:24:38 +0100 Subject: [PATCH 62/73] dt-bindings: sram: sunxi: Add compatible for the A64 SRAM C1 This introduces a new compatible for the A64 SRAM C1 section, that is compatible with the SRAM C1 section as found on the A10. Signed-off-by: Paul Kocialkowski Acked-by: Chen-Yu Tsai Reviewed-by: Rob Herring Signed-off-by: Maxime Ripard --- Documentation/devicetree/bindings/sram/sunxi-sram.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/sram/sunxi-sram.txt b/Documentation/devicetree/bindings/sram/sunxi-sram.txt index 5c9a54ad3b53..ab5a70bb9a64 100644 --- a/Documentation/devicetree/bindings/sram/sunxi-sram.txt +++ b/Documentation/devicetree/bindings/sram/sunxi-sram.txt @@ -56,6 +56,7 @@ The valid sections compatible for H3 are: The valid sections compatible for A64 are: - allwinner,sun50i-a64-sram-c + - allwinner,sun50i-a64-sram-c1, allwinner,sun4i-a10-sram-c1 The valid sections compatible for H5 are: - allwinner,sun50i-h5-sram-c1, allwinner,sun4i-a10-sram-c1 From b0d7fbf8b174168c580bb310964c3c809e5569a9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 5 Dec 2018 16:39:42 +0100 Subject: [PATCH 63/73] soc: renesas: r8a77990-sysc: Fix initialization order of 3DG-{A,B} The workaround for the wrong hierarchy of the 3DG-{A,B} power domains on R-Car E3 ES1.0 corrected the parent domains. However, the 3DG-{A,B} power domains were still initialized and powered in the wrong order, causing 3DG operation to fail. Fix this by changing the order in the table at runtime, when running on an affected SoC. Fixes: 086b399965a7ee7e ("soc: renesas: r8a77990-sysc: Add workaround for 3DG-{A,B}") Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/r8a77990-sysc.c | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/drivers/soc/renesas/r8a77990-sysc.c b/drivers/soc/renesas/r8a77990-sysc.c index 15579ebc5ed2..664b244eb1dd 100644 --- a/drivers/soc/renesas/r8a77990-sysc.c +++ b/drivers/soc/renesas/r8a77990-sysc.c @@ -28,19 +28,6 @@ static struct rcar_sysc_area r8a77990_areas[] __initdata = { { "3dg-b", 0x100, 1, R8A77990_PD_3DG_B, R8A77990_PD_3DG_A }, }; -static void __init rcar_sysc_fix_parent(struct rcar_sysc_area *areas, - unsigned int num_areas, u8 id, - int new_parent) -{ - unsigned int i; - - for (i = 0; i < num_areas; i++) - if (areas[i].isr_bit == id) { - areas[i].parent = new_parent; - return; - } -} - /* Fixups for R-Car E3 ES1.0 revision */ static const struct soc_device_attribute r8a77990[] __initconst = { { .soc_id = "r8a77990", .revision = "ES1.0" }, @@ -50,12 +37,10 @@ static const struct soc_device_attribute r8a77990[] __initconst = { static int __init r8a77990_sysc_init(void) { if (soc_device_match(r8a77990)) { - rcar_sysc_fix_parent(r8a77990_areas, - ARRAY_SIZE(r8a77990_areas), - R8A77990_PD_3DG_A, R8A77990_PD_3DG_B); - rcar_sysc_fix_parent(r8a77990_areas, - ARRAY_SIZE(r8a77990_areas), - R8A77990_PD_3DG_B, R8A77990_PD_ALWAYS_ON); + /* Fix incorrect 3DG hierarchy */ + swap(r8a77990_areas[7], r8a77990_areas[8]); + r8a77990_areas[7].parent = R8A77990_PD_ALWAYS_ON; + r8a77990_areas[8].parent = R8A77990_PD_3DG_B; } return 0; From 319c84090696517f377a80225534677adf192e92 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 5 Dec 2018 16:39:43 +0100 Subject: [PATCH 64/73] soc: renesas: rcar-sysc: Remove rcar_sysc_power_{down,up}() helpers Until commit 7e8a50df26f4e700 ("soc: renesas: rcar-sysc: Drop legacy handling"), the rcar_sysc_power_{down,up}() helpers were public, as they were called by the legacy (pre-DT) CPU power management code on R-Car H1 and R-Car Gen2 before. As they are just one-line wrappers around rcar_sysc_power(), it makes sense to just remove them. This also avoids a bool/helper/bool conversion in rcar_sysc_power_cpu(), where a bool is checked to call one of two helper functions, which just call rcar_sysc_power() with hardcoded boolean values again. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/rcar-sysc.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index af53363eda03..73fae6a9728d 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -146,16 +146,6 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) return ret; } -static int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) -{ - return rcar_sysc_power(sysc_ch, false); -} - -static int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) -{ - return rcar_sysc_power(sysc_ch, true); -} - static bool rcar_sysc_power_is_off(const struct rcar_sysc_ch *sysc_ch) { unsigned int st; @@ -184,7 +174,7 @@ static int rcar_sysc_pd_power_off(struct generic_pm_domain *genpd) struct rcar_sysc_pd *pd = to_rcar_pd(genpd); pr_debug("%s: %s\n", __func__, genpd->name); - return rcar_sysc_power_down(&pd->ch); + return rcar_sysc_power(&pd->ch, false); } static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) @@ -192,7 +182,7 @@ static int rcar_sysc_pd_power_on(struct generic_pm_domain *genpd) struct rcar_sysc_pd *pd = to_rcar_pd(genpd); pr_debug("%s: %s\n", __func__, genpd->name); - return rcar_sysc_power_up(&pd->ch); + return rcar_sysc_power(&pd->ch, true); } static bool has_cpg_mstp; @@ -252,7 +242,7 @@ static int __init rcar_sysc_pd_setup(struct rcar_sysc_pd *pd) goto finalize; } - rcar_sysc_power_up(&pd->ch); + rcar_sysc_power(&pd->ch, true); finalize: error = pm_genpd_init(genpd, gov, false); @@ -478,8 +468,7 @@ static int rcar_sysc_power_cpu(unsigned int idx, bool on) if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx) continue; - return on ? rcar_sysc_power_up(&pd->ch) - : rcar_sysc_power_down(&pd->ch); + return rcar_sysc_power(&pd->ch, on); } return -ENOENT; From 1585124d9563da64f481dc0e7c568c344002bc13 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 5 Dec 2018 16:39:44 +0100 Subject: [PATCH 65/73] soc: renesas: rcar-sysc: Merge PM Domain registration and linking Commit 977d5ba4507dfe5b ("soc: renesas: rcar-sysc: Make PM domain initialization more robust") split PM Domain registration and the linking of children to their parents, to accommodate PM Domain tables that list child domains before their parents. However, this failed to realize that parent power domains must be powered up before their children anyway, and that this thus must be reflected by the order in the PM Domain tables. Revert the split, as it did not help anyway. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/rcar-sysc.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 73fae6a9728d..123e553510e8 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -381,9 +381,6 @@ static int __init rcar_sysc_pd_init(void) pr_debug("%pOF: syscier = 0x%08x\n", np, syscier); iowrite32(syscier, base + SYSCIER); - /* - * First, create all PM domains - */ for (i = 0; i < info->num_areas; i++) { const struct rcar_sysc_area *area = &info->areas[i]; struct rcar_sysc_pd *pd; @@ -411,22 +408,17 @@ static int __init rcar_sysc_pd_init(void) goto out_put; domains->domains[area->isr_bit] = &pd->genpd; - } - /* - * Second, link all PM domains to their parents - */ - for (i = 0; i < info->num_areas; i++) { - const struct rcar_sysc_area *area = &info->areas[i]; - - if (!area->name || area->parent < 0) + if (area->parent < 0) continue; error = pm_genpd_add_subdomain(domains->domains[area->parent], - domains->domains[area->isr_bit]); - if (error) + &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); From 7fc4650cc2417d7a2907a000f6f88240baa42018 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 5 Dec 2018 16:39:45 +0100 Subject: [PATCH 66/73] soc: renesas: rcar-sysc: Fix power domain control after system resume To control power to a power domain, the System Controller (SYSC) needs the corresponding interrupt source to be enabled, but masked, to prevent the CPU from receiving it. Currently this is handled in the driver's probe() routine, and set up for every domain present, even if it will not be controlled directly by SYSC (CPU domains are powered through the APMU on R-Car Gen2 and later). On R-Car Gen3, PSCI powers down the SoC during system suspend, thus losing any configured interrupt state. Hence after system resume, power domains not controlled through the APMU (e.g. A3IR, A3VC, A3VP) fail to power up. Fix this by replacing the global interrupt setup in the probe() routine by a domain-specific interrupt setup in rcar_sysc_power(), where the domain's power is actually controlled. This brings the code more in line with the flowchart in the Hardware User's Manual. Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/rcar-sysc.c | 28 +++++++++------------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 123e553510e8..0c80fab4f8de 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -105,6 +105,15 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) spin_lock_irqsave(&rcar_sysc_lock, flags); + /* + * The interrupt source needs to be enabled, but masked, to prevent the + * CPU from receiving it. + */ + iowrite32(ioread32(rcar_sysc_base + SYSCIMR) | isr_mask, + rcar_sysc_base + SYSCIMR); + iowrite32(ioread32(rcar_sysc_base + SYSCIER) | isr_mask, + rcar_sysc_base + SYSCIER); + iowrite32(isr_mask, rcar_sysc_base + SYSCISCR); /* Submit power shutoff or resume request until it was accepted */ @@ -324,7 +333,6 @@ static int __init rcar_sysc_pd_init(void) const struct of_device_id *match; struct rcar_pm_domains *domains; struct device_node *np; - u32 syscier, syscimr; void __iomem *base; unsigned int i; int error; @@ -363,24 +371,6 @@ static int __init rcar_sysc_pd_init(void) domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); rcar_sysc_onecell_data = &domains->onecell_data; - for (i = 0, syscier = 0; i < info->num_areas; i++) - syscier |= BIT(info->areas[i].isr_bit); - - /* - * Mask all interrupt sources to prevent the CPU from receiving them. - * Make sure not to clear reserved bits that were set before. - */ - syscimr = ioread32(base + SYSCIMR); - syscimr |= syscier; - pr_debug("%pOF: syscimr = 0x%08x\n", np, syscimr); - iowrite32(syscimr, base + SYSCIMR); - - /* - * SYSC needs all interrupt sources enabled to control power. - */ - pr_debug("%pOF: syscier = 0x%08x\n", np, syscier); - iowrite32(syscier, base + SYSCIER); - for (i = 0; i < info->num_areas; i++) { const struct rcar_sysc_area *area = &info->areas[i]; struct rcar_sysc_pd *pd; From b6444cf5fa607469d9a14edef2edad32773f4514 Mon Sep 17 00:00:00 2001 From: Leonard Crestez Date: Mon, 8 Oct 2018 18:06:19 +0000 Subject: [PATCH 67/73] soc: imx: gpc: Increase GPC_CLK_MAX to 7 The DISPLAY power domain on imx6sx has 7 clocks. Signed-off-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/soc/imx/gpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index aa3729ecaa9e..7d14a4b4e82a 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -35,7 +35,7 @@ #define GPU_VPU_PUP_REQ BIT(1) #define GPU_VPU_PDN_REQ BIT(0) -#define GPC_CLK_MAX 6 +#define GPC_CLK_MAX 7 #define PGC_DOMAIN_FLAG_NO_PD BIT(0) From f56c06271c1c3caef9c7ef200e3d89967fd98a8e Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Mon, 10 Dec 2018 19:45:55 +0000 Subject: [PATCH 68/73] soc: amlogic: meson-clk-measure: Add missing REGMAP_MMIO dependency This patchs adds a missing dependency on REGMAP_MMIO. This cause the following build failure on SPARC: drivers/soc/amlogic/meson-clk-measure.o: In function `meson_msr_probe': meson-clk-measure.c:(.text+0xc4): undefined reference to `__devm_regmap_init_mmio_clk' Signed-off-by: Corentin Labbe Signed-off-by: Kevin Hilman --- drivers/soc/amlogic/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/amlogic/Kconfig b/drivers/soc/amlogic/Kconfig index 36633bb6c8bb..5501ad5650b2 100644 --- a/drivers/soc/amlogic/Kconfig +++ b/drivers/soc/amlogic/Kconfig @@ -11,6 +11,7 @@ config MESON_CLK_MEASURE bool "Amlogic Meson SoC Clock Measure driver" depends on ARCH_MESON || COMPILE_TEST default ARCH_MESON + select REGMAP_MMIO help Say yes to support of Measuring a set of internal SoC clocks from the debugfs interface. From 4f2122473363b569db652dc09029715ad808e1a6 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 10 Dec 2018 14:11:10 -0800 Subject: [PATCH 69/73] ARM: OMAP2+: Check also the first dts child for hwmod flags Until the board specific dts files are updated to have hwmod flags at the interconnect target module level, we want to keep things working both for old and new dts files. So let's also check the first child for hwmod flags. The module flags are for the whole module, so only the first child should ever have them. Cc: Peter Ujfalusi Reported-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/omap_hwmod.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c index 083dcd9942ce..b506d5d9da82 100644 --- a/arch/arm/mach-omap2/omap_hwmod.c +++ b/arch/arm/mach-omap2/omap_hwmod.c @@ -2345,6 +2345,17 @@ static int __init _init_mpu_rt_base(struct omap_hwmod *oh, void *data, return 0; } +static void __init parse_module_flags(struct omap_hwmod *oh, + struct device_node *np) +{ + if (of_find_property(np, "ti,no-reset-on-init", NULL)) + oh->flags |= HWMOD_INIT_NO_RESET; + if (of_find_property(np, "ti,no-idle-on-init", NULL)) + oh->flags |= HWMOD_INIT_NO_IDLE; + if (of_find_property(np, "ti,no-idle", NULL)) + oh->flags |= HWMOD_NO_IDLE; +} + /** * _init - initialize internal data for the hwmod @oh * @oh: struct omap_hwmod * @@ -2392,12 +2403,12 @@ static int __init _init(struct omap_hwmod *oh, void *data) } if (np) { - if (of_find_property(np, "ti,no-reset-on-init", NULL)) - oh->flags |= HWMOD_INIT_NO_RESET; - if (of_find_property(np, "ti,no-idle-on-init", NULL)) - oh->flags |= HWMOD_INIT_NO_IDLE; - if (of_find_property(np, "ti,no-idle", NULL)) - oh->flags |= HWMOD_NO_IDLE; + struct device_node *child; + + parse_module_flags(oh, np); + child = of_get_next_child(np, NULL); + if (child) + parse_module_flags(oh, child); } oh->_state = _HWMOD_STATE_INITIALIZED; From 4014c08ba39476a18af546186da625a6833a1529 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 10 Dec 2018 14:11:26 -0800 Subject: [PATCH 70/73] bus: ti-sysc: Check for no-reset and no-idle flags at the child level With ti-sysc, we need to now have the device tree properties for ti,no-reset-on-init and ti,no-idle-on-init at the module level instead of the child device level. Let's check for these properties at the child device level to enable quirks, and warn about moving the properties to the module level. Otherwise am335x-evm based boards tagging gpio1 with ti,no-reset-on-init will have their DDR power disabled if wired up in such a tricky way. Note that this should not be an issue for earlier kernels as we don't rely on this until the dts files have been updated to probe with ti-sysc interconnect target driver. Cc: Peter Ujfalusi Reported-by: Peter Ujfalusi Signed-off-by: Tony Lindgren --- drivers/bus/ti-sysc.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 46a6c528b543..f94d33525771 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -91,6 +91,9 @@ struct sysc { struct delayed_work idle_work; }; +static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, + bool is_child); + void sysc_write(struct sysc *ddata, int offset, u32 value) { writel_relaxed(value, ddata->module_va + offset); @@ -379,6 +382,7 @@ static int sysc_check_one_child(struct sysc *ddata, dev_warn(ddata->dev, "really a child ti,hwmods property?"); sysc_check_quirk_stdout(ddata, np); + sysc_parse_dts_quirks(ddata, np, true); return 0; } @@ -1279,23 +1283,37 @@ static const struct sysc_dts_quirk sysc_dts_quirks[] = { .mask = SYSC_QUIRK_NO_RESET_ON_INIT, }, }; -static int sysc_init_dts_quirks(struct sysc *ddata) +static void sysc_parse_dts_quirks(struct sysc *ddata, struct device_node *np, + bool is_child) { - struct device_node *np = ddata->dev->of_node; const struct property *prop; - int i, len, error; - u32 val; - - ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); + int i, len; for (i = 0; i < ARRAY_SIZE(sysc_dts_quirks); i++) { - prop = of_get_property(np, sysc_dts_quirks[i].name, &len); + const char *name = sysc_dts_quirks[i].name; + + prop = of_get_property(np, name, &len); if (!prop) continue; ddata->cfg.quirks |= sysc_dts_quirks[i].mask; + if (is_child) { + dev_warn(ddata->dev, + "dts flag should be at module level for %s\n", + name); + } } +} +static int sysc_init_dts_quirks(struct sysc *ddata) +{ + struct device_node *np = ddata->dev->of_node; + int error; + u32 val; + + ddata->legacy_mode = of_get_property(np, "ti,hwmods", NULL); + + sysc_parse_dts_quirks(ddata, np, false); error = of_property_read_u32(np, "ti,sysc-delay-us", &val); if (!error) { if (val > 255) { From c2ade654dbf7d02f09ad491f5621fc321d4af96b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 5 Dec 2018 13:50:30 -0600 Subject: [PATCH 71/73] memory: omap-gpmc: Use of_node_name_eq for node name comparisons Convert string compares of DT node names to use of_node_name_eq helper instead. This removes direct access to the node name pointer. For instances using of_node_cmp, this has the side effect of now using case sensitive comparisons. This should not matter for any FDT based system which this is. Cc: Roger Quadros Cc: Tony Lindgren Cc: linux-omap@vger.kernel.org Signed-off-by: Rob Herring Signed-off-by: Tony Lindgren --- drivers/memory/omap-gpmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index c215287e80cf..a66dea4f1ed2 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -2060,7 +2060,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, * timings. */ name = gpmc_cs_get_name(cs); - if (name && of_node_cmp(child->name, name) == 0) + if (name && of_node_name_eq(child, name)) goto no_timings; ret = gpmc_cs_request(cs, resource_size(&res), &base); @@ -2068,7 +2068,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs); return ret; } - gpmc_cs_set_name(cs, child->name); + gpmc_cs_set_name(cs, child->full_name); gpmc_read_settings_dt(child, &gpmc_s); gpmc_read_timings_dt(child, &gpmc_t); @@ -2113,7 +2113,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, goto err; } - if (of_node_cmp(child->name, "nand") == 0) { + if (of_node_name_eq(child, "nand")) { /* Warn about older DT blobs with no compatible property */ if (!of_property_read_bool(child, "compatible")) { dev_warn(&pdev->dev, @@ -2123,7 +2123,7 @@ static int gpmc_probe_generic_child(struct platform_device *pdev, } } - if (of_node_cmp(child->name, "onenand") == 0) { + if (of_node_name_eq(child, "onenand")) { /* Warn about older DT blobs with no compatible property */ if (!of_property_read_bool(child, "compatible")) { dev_warn(&pdev->dev, From 15653dc850e4bc64dffd9105faab063f81c4b3b2 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 28 Nov 2018 12:00:35 +0100 Subject: [PATCH 72/73] ARM: at91: add support in soc driver for LPDDR2 SiP Add some more SiP components to be detected by this soc.c driver. Signed-off-by: Nicolas Ferre Signed-off-by: Alexandre Belloni --- drivers/soc/atmel/soc.c | 8 ++++++++ drivers/soc/atmel/soc.h | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c index 4dd03b099c89..2cc272ddf906 100644 --- a/drivers/soc/atmel/soc.c +++ b/drivers/soc/atmel/soc.c @@ -90,12 +90,20 @@ static const struct at91_soc __initconst socs[] = { "sama5d27c 128MiB SiP", "sama5d2"), AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_D5M_EXID_MATCH, "sama5d27c 64MiB SiP", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD1G_EXID_MATCH, + "sama5d27c 128MiB LPDDR2 SiP", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27C_LD2G_EXID_MATCH, + "sama5d27c 256MiB LPDDR2 SiP", "sama5d2"), AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, "sama5d28", "sama5d2"), AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, "sama5d28", "sama5d2"), AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_D1G_EXID_MATCH, "sama5d28c 128MiB SiP", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD1G_EXID_MATCH, + "sama5d28c 128MiB LPDDR2 SiP", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28C_LD2G_EXID_MATCH, + "sama5d28c 256MiB LPDDR2 SiP", "sama5d2"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, "sama5d31", "sama5d3"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, diff --git a/drivers/soc/atmel/soc.h b/drivers/soc/atmel/soc.h index 94cd5d1ab502..ed89b24ecee1 100644 --- a/drivers/soc/atmel/soc.h +++ b/drivers/soc/atmel/soc.h @@ -73,9 +73,13 @@ at91_soc_init(const struct at91_soc *socs); #define SAMA5D26CU_EXID_MATCH 0x00000012 #define SAMA5D27C_D1G_EXID_MATCH 0x00000033 #define SAMA5D27C_D5M_EXID_MATCH 0x00000032 +#define SAMA5D27C_LD1G_EXID_MATCH 0x00000061 +#define SAMA5D27C_LD2G_EXID_MATCH 0x00000062 #define SAMA5D27CU_EXID_MATCH 0x00000011 #define SAMA5D27CN_EXID_MATCH 0x00000021 #define SAMA5D28C_D1G_EXID_MATCH 0x00000013 +#define SAMA5D28C_LD1G_EXID_MATCH 0x00000071 +#define SAMA5D28C_LD2G_EXID_MATCH 0x00000072 #define SAMA5D28CU_EXID_MATCH 0x00000010 #define SAMA5D28CN_EXID_MATCH 0x00000020 From 446e8986a2417148aed14f362831bf2425d434cb Mon Sep 17 00:00:00 2001 From: Sandeep Sheriker Mallikarjun Date: Wed, 12 Dec 2018 11:41:10 +0100 Subject: [PATCH 73/73] ARM: at91: add support in soc driver for new SAM9X60 Add detection of new SAM9X60 by this soc.c driver. Signed-off-by: Nicolas Ferre [nicolas.ferre@microchip.com: split patch] Signed-off-by: Sandeep Sheriker Mallikarjun Signed-off-by: Alexandre Belloni --- drivers/soc/atmel/soc.c | 2 ++ drivers/soc/atmel/soc.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/soc/atmel/soc.c b/drivers/soc/atmel/soc.c index 2cc272ddf906..096a83cf0caf 100644 --- a/drivers/soc/atmel/soc.c +++ b/drivers/soc/atmel/soc.c @@ -66,6 +66,8 @@ static const struct at91_soc __initconst socs[] = { AT91_SOC(AT91SAM9XE128_CIDR_MATCH, 0, "at91sam9xe128", "at91sam9xe128"), AT91_SOC(AT91SAM9XE256_CIDR_MATCH, 0, "at91sam9xe256", "at91sam9xe256"), AT91_SOC(AT91SAM9XE512_CIDR_MATCH, 0, "at91sam9xe512", "at91sam9xe512"), + AT91_SOC(SAM9X60_CIDR_MATCH, SAM9X60_EXID_MATCH, + "sam9x60", "sam9x60"), #endif #ifdef CONFIG_SOC_SAMA5 AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, diff --git a/drivers/soc/atmel/soc.h b/drivers/soc/atmel/soc.h index ed89b24ecee1..ee652e4841a5 100644 --- a/drivers/soc/atmel/soc.h +++ b/drivers/soc/atmel/soc.h @@ -42,6 +42,7 @@ at91_soc_init(const struct at91_soc *socs); #define AT91SAM9G45_CIDR_MATCH 0x019b05a0 #define AT91SAM9X5_CIDR_MATCH 0x019a05a0 #define AT91SAM9N12_CIDR_MATCH 0x019a07a0 +#define SAM9X60_CIDR_MATCH 0x019b35a0 #define AT91SAM9M11_EXID_MATCH 0x00000001 #define AT91SAM9M10_EXID_MATCH 0x00000002 @@ -58,6 +59,8 @@ at91_soc_init(const struct at91_soc *socs); #define AT91SAM9N12_EXID_MATCH 0x00000006 #define AT91SAM9CN11_EXID_MATCH 0x00000009 +#define SAM9X60_EXID_MATCH 0x00000000 + #define AT91SAM9XE128_CIDR_MATCH 0x329973a0 #define AT91SAM9XE256_CIDR_MATCH 0x329a93a0 #define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0