From 15160f6de0bba712fcea078c5ac7571fe33fcd5d Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Thu, 28 Feb 2019 12:00:48 +0100 Subject: [PATCH 01/57] soc: renesas: Identify R-Car M3-W ES1.3 The Product Register of R-Car M3-W ES1.3 incorrectly identifies the SoC revision as ES2.1. Add a workaround to fix this. Signed-off-by: Takeshi Kihara Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- drivers/soc/renesas/renesas-soc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 4af96e668a2f..3299cf5365f3 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -335,6 +335,9 @@ static int __init renesas_soc_init(void) /* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */ if ((product & 0x7fff) == 0x5210) product ^= 0x11; + /* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */ + if ((product & 0x7fff) == 0x5211) + product ^= 0x12; if (soc->id && ((product >> 8) & 0xff) != soc->id) { pr_warn("SoC mismatch (product = 0x%x)\n", product); return -ENODEV; From b9472f7d8224460499dd7128ec944735ed5345a0 Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Mon, 18 Feb 2019 22:43:09 +0100 Subject: [PATCH 02/57] firmware: xilinx: fix debugfs write handler - Userspace wants to write a string with `len` bytes, not counting the terminating NULL, so we should allocate `len+1` bytes. It looks like the current code relied on having a nullbyte directly behind `kern_buff`, which happens to work reliably as long as `len` isn't one of the kmalloc size classes. - strncpy_from_user() is completely wrong here; userspace is giving us a (not necessarily null-terminated) buffer and its length. strncpy_from_user() is for cases in which we don't know the length. - Don't let broken userspace allocate arbitrarily big kmalloc allocations. Just use memdup_user_nul(), which is designed precisely for things like this. Signed-off-by: Jann Horn Acked-by: Jolly Shah Signed-off-by: Michal Simek --- drivers/firmware/xilinx/zynqmp-debug.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/firmware/xilinx/zynqmp-debug.c b/drivers/firmware/xilinx/zynqmp-debug.c index 2771df6df379..90b66cdbfd58 100644 --- a/drivers/firmware/xilinx/zynqmp-debug.c +++ b/drivers/firmware/xilinx/zynqmp-debug.c @@ -163,21 +163,14 @@ static ssize_t zynqmp_pm_debugfs_api_write(struct file *file, strcpy(debugfs_buf, ""); - if (*off != 0 || len == 0) + if (*off != 0 || len <= 1 || len > PAGE_SIZE - 1) return -EINVAL; - kern_buff = kzalloc(len, GFP_KERNEL); - if (!kern_buff) - return -ENOMEM; - + kern_buff = memdup_user_nul(ptr, len); + if (IS_ERR(kern_buff)) + return PTR_ERR(kern_buff); tmp_buff = kern_buff; - ret = strncpy_from_user(kern_buff, ptr, len); - if (ret < 0) { - ret = -EFAULT; - goto err; - } - /* Read the API name from a user request */ pm_api_req = strsep(&kern_buff, " "); From 3d0313786470acb414b7d5fdd2202f061acffb02 Mon Sep 17 00:00:00 2001 From: Rajan Vaja Date: Mon, 4 Mar 2019 15:18:08 -0800 Subject: [PATCH 03/57] drivers: Defer probe if firmware is not ready Driver needs ZynqMP firmware interface to call EEMI APIs. In case firmware is not ready, dependent drivers should wait until the firmware is ready. Signed-off-by: Rajan Vaja Signed-off-by: Jolly Shah Signed-off-by: Michal Simek --- Documentation/xilinx/eemi.txt | 4 ++-- drivers/clk/zynqmp/clkc.c | 4 ++-- drivers/firmware/xilinx/zynqmp-debug.c | 3 --- drivers/firmware/xilinx/zynqmp.c | 11 ++++++++++- drivers/nvmem/zynqmp_nvmem.c | 10 +++++++--- drivers/reset/reset-zynqmp.c | 8 ++++---- drivers/soc/xilinx/zynqmp_pm_domains.c | 18 ++++++++++-------- drivers/soc/xilinx/zynqmp_power.c | 10 ++++++---- drivers/spi/spi-zynqmp-gqspi.c | 5 +++++ include/linux/firmware/xlnx-zynqmp.h | 2 +- 10 files changed, 47 insertions(+), 28 deletions(-) diff --git a/Documentation/xilinx/eemi.txt b/Documentation/xilinx/eemi.txt index 0ab686c173be..5f39b4ffdcd4 100644 --- a/Documentation/xilinx/eemi.txt +++ b/Documentation/xilinx/eemi.txt @@ -41,8 +41,8 @@ Example of EEMI ops usage: int ret; eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!eemi_ops) - return -ENXIO; + if (IS_ERR(eemi_ops)) + return PTR_ERR(eemi_ops); ret = eemi_ops->query_data(qdata, ret_payload); diff --git a/drivers/clk/zynqmp/clkc.c b/drivers/clk/zynqmp/clkc.c index b0908ec62f73..2b1d43457f09 100644 --- a/drivers/clk/zynqmp/clkc.c +++ b/drivers/clk/zynqmp/clkc.c @@ -695,8 +695,8 @@ static int zynqmp_clock_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!eemi_ops) - return -ENXIO; + if (IS_ERR(eemi_ops)) + return PTR_ERR(eemi_ops); ret = zynqmp_clk_setup(dev->of_node); diff --git a/drivers/firmware/xilinx/zynqmp-debug.c b/drivers/firmware/xilinx/zynqmp-debug.c index 90b66cdbfd58..c6d0724da4db 100644 --- a/drivers/firmware/xilinx/zynqmp-debug.c +++ b/drivers/firmware/xilinx/zynqmp-debug.c @@ -90,9 +90,6 @@ static int process_api_request(u32 pm_id, u64 *pm_api_arg, u32 *pm_api_ret) int ret; struct zynqmp_pm_query_data qdata = {0}; - if (!eemi_ops) - return -ENXIO; - switch (pm_id) { case PM_GET_API_VERSION: ret = eemi_ops->get_api_version(&pm_api_version); diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 98f936125643..87a1d636c0dc 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -24,6 +24,8 @@ #include #include "zynqmp-debug.h" +static const struct zynqmp_eemi_ops *eemi_ops_tbl; + static const struct mfd_cell firmware_devs[] = { { .name = "zynqmp_power_controller", @@ -649,7 +651,11 @@ static const struct zynqmp_eemi_ops eemi_ops = { */ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) { - return &eemi_ops; + if (eemi_ops_tbl) + return eemi_ops_tbl; + else + return ERR_PTR(-EPROBE_DEFER); + } EXPORT_SYMBOL_GPL(zynqmp_pm_get_eemi_ops); @@ -694,6 +700,9 @@ static int zynqmp_firmware_probe(struct platform_device *pdev) pr_info("%s Trustzone version v%d.%d\n", __func__, pm_tz_version >> 16, pm_tz_version & 0xFFFF); + /* Assign eemi_ops_table */ + eemi_ops_tbl = &eemi_ops; + zynqmp_pm_api_debugfs_init(); ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, firmware_devs, diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index 490c8fcaec80..5893543918c8 100644 --- a/drivers/nvmem/zynqmp_nvmem.c +++ b/drivers/nvmem/zynqmp_nvmem.c @@ -16,6 +16,8 @@ struct zynqmp_nvmem_data { struct nvmem_device *nvmem; }; +static const struct zynqmp_eemi_ops *eemi_ops; + static int zynqmp_nvmem_read(void *context, unsigned int offset, void *val, size_t bytes) { @@ -23,9 +25,7 @@ static int zynqmp_nvmem_read(void *context, unsigned int offset, int idcode, version; struct zynqmp_nvmem_data *priv = context; - const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); - - if (!eemi_ops || !eemi_ops->get_chipid) + if (!eemi_ops->get_chipid) return -ENXIO; ret = eemi_ops->get_chipid(&idcode, &version); @@ -61,6 +61,10 @@ static int zynqmp_nvmem_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + eemi_ops = zynqmp_pm_get_eemi_ops(); + if (IS_ERR(eemi_ops)) + return PTR_ERR(eemi_ops); + priv->dev = dev; econfig.dev = dev; econfig.reg_read = zynqmp_nvmem_read; diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index 2ef1f13aa47b..99e75d92dada 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -79,11 +79,11 @@ static int zynqmp_reset_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - platform_set_drvdata(pdev, priv); - priv->eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!priv->eemi_ops) - return -ENXIO; + if (IS_ERR(priv->eemi_ops)) + return PTR_ERR(priv->eemi_ops); + + platform_set_drvdata(pdev, priv); priv->rcdev.ops = &zynqmp_reset_ops; priv->rcdev.owner = THIS_MODULE; diff --git a/drivers/soc/xilinx/zynqmp_pm_domains.c b/drivers/soc/xilinx/zynqmp_pm_domains.c index 354d256e6e00..600f57cf0c2e 100644 --- a/drivers/soc/xilinx/zynqmp_pm_domains.c +++ b/drivers/soc/xilinx/zynqmp_pm_domains.c @@ -23,6 +23,8 @@ /* Flag stating if PM nodes mapped to the PM domain has been requested */ #define ZYNQMP_PM_DOMAIN_REQUESTED BIT(0) +static const struct zynqmp_eemi_ops *eemi_ops; + /** * struct zynqmp_pm_domain - Wrapper around struct generic_pm_domain * @gpd: Generic power domain @@ -71,9 +73,8 @@ static int zynqmp_gpd_power_on(struct generic_pm_domain *domain) { int ret; struct zynqmp_pm_domain *pd; - const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!eemi_ops || !eemi_ops->set_requirement) + if (!eemi_ops->set_requirement) return -ENXIO; pd = container_of(domain, struct zynqmp_pm_domain, gpd); @@ -107,9 +108,8 @@ static int zynqmp_gpd_power_off(struct generic_pm_domain *domain) struct zynqmp_pm_domain *pd; u32 capabilities = 0; bool may_wakeup; - const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!eemi_ops || !eemi_ops->set_requirement) + if (!eemi_ops->set_requirement) return -ENXIO; pd = container_of(domain, struct zynqmp_pm_domain, gpd); @@ -160,9 +160,8 @@ static int zynqmp_gpd_attach_dev(struct generic_pm_domain *domain, { int ret; struct zynqmp_pm_domain *pd; - const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!eemi_ops || !eemi_ops->request_node) + if (!eemi_ops->request_node) return -ENXIO; pd = container_of(domain, struct zynqmp_pm_domain, gpd); @@ -197,9 +196,8 @@ static void zynqmp_gpd_detach_dev(struct generic_pm_domain *domain, { int ret; struct zynqmp_pm_domain *pd; - const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!eemi_ops || !eemi_ops->release_node) + if (!eemi_ops->release_node) return; pd = container_of(domain, struct zynqmp_pm_domain, gpd); @@ -266,6 +264,10 @@ static int zynqmp_gpd_probe(struct platform_device *pdev) struct zynqmp_pm_domain *pd; struct device *dev = &pdev->dev; + eemi_ops = zynqmp_pm_get_eemi_ops(); + if (IS_ERR(eemi_ops)) + return PTR_ERR(eemi_ops); + pd = devm_kcalloc(dev, ZYNQMP_NUM_DOMAINS, sizeof(*pd), GFP_KERNEL); if (!pd) return -ENOMEM; diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 771cb59b9d22..1b9d14411a15 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -31,6 +31,7 @@ static const char *const suspend_modes[] = { }; static enum pm_suspend_mode suspend_mode = PM_SUSPEND_MODE_STD; +static const struct zynqmp_eemi_ops *eemi_ops; enum pm_api_cb_id { PM_INIT_SUSPEND_CB = 30, @@ -92,9 +93,8 @@ static ssize_t suspend_mode_store(struct device *dev, const char *buf, size_t count) { int md, ret = -EINVAL; - const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); - if (!eemi_ops || !eemi_ops->set_suspend_mode) + if (!eemi_ops->set_suspend_mode) return ret; for (md = PM_SUSPEND_MODE_FIRST; md < ARRAY_SIZE(suspend_modes); md++) @@ -120,9 +120,11 @@ static int zynqmp_pm_probe(struct platform_device *pdev) int ret, irq; u32 pm_api_version; - const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); + eemi_ops = zynqmp_pm_get_eemi_ops(); + if (IS_ERR(eemi_ops)) + return PTR_ERR(eemi_ops); - if (!eemi_ops || !eemi_ops->get_api_version || !eemi_ops->init_finalize) + if (!eemi_ops->get_api_version || !eemi_ops->init_finalize) return -ENXIO; eemi_ops->init_finalize(); diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 9f83e1b17aa1..d07b6f940f9f 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -138,6 +138,7 @@ #define SPI_AUTOSUSPEND_TIMEOUT 3000 enum mode_type {GQSPI_MODE_IO, GQSPI_MODE_DMA}; +static const struct zynqmp_eemi_ops *eemi_ops; /** * struct zynqmp_qspi - Defines qspi driver instance @@ -1021,6 +1022,10 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) struct resource *res; struct device *dev = &pdev->dev; + eemi_ops = zynqmp_pm_get_eemi_ops(); + if (IS_ERR(eemi_ops)) + return PTR_ERR(eemi_ops); + master = spi_alloc_master(&pdev->dev, sizeof(*xqspi)); if (!master) return -ENOMEM; diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 642dab10f65d..3533ee557043 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -293,7 +293,7 @@ const struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void); #else static inline struct zynqmp_eemi_ops *zynqmp_pm_get_eemi_ops(void) { - return NULL; + return ERR_PTR(-ENODEV); } #endif From dce47aed20c7de3ee2011b7a63e67f08e9dcfb5e Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Mar 2019 15:01:45 +0100 Subject: [PATCH 04/57] soc: amlogic: gx-socinfo: Add mask for each SoC packages When updated IDs on f842c41adc04 ("amlogic: meson-gx-socinfo: Update soc ids") we introduced packages ids using the full 8bit value, but in the function socinfo_to_package_id() the id was filtered with the 0xf0 mask. While the 0xf0 mask is valid for most board, it filters out the lower 4 bits which encodes some characteristics of the chip. This patch moves the mask into the meson_gx_package_id table to be applied on each package name independently and add the correct mask for some specific entries. An example is the S905, in the vendor code the S905 is package_id different from 0x20, and S905M is exactly 0x20. Another example are the The Wetek Hub & Play2 boards using a S905-H variant, which is the S905 SoC with some licence bits enabled. These licence bits are encoded in the lower 4bits, so to detect the -H variant, we must detect the id == 0x3 with the 0xf mask. Fixes: f842c41adc04 ("amlogic: meson-gx-socinfo: Update soc ids") Signed-off-by: Neil Armstrong Signed-off-by: Kevin Hilman --- drivers/soc/amlogic/meson-gx-socinfo.c | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index 37ea0a1c24c8..1ae339f5eadb 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c @@ -43,20 +43,21 @@ static const struct meson_gx_package_id { const char *name; unsigned int major_id; unsigned int pack_id; + unsigned int pack_mask; } soc_packages[] = { - { "S905", 0x1f, 0 }, - { "S905H", 0x1f, 0x13 }, - { "S905M", 0x1f, 0x20 }, - { "S905D", 0x21, 0 }, - { "S905X", 0x21, 0x80 }, - { "S905W", 0x21, 0xa0 }, - { "S905L", 0x21, 0xc0 }, - { "S905M2", 0x21, 0xe0 }, - { "S912", 0x22, 0 }, - { "962X", 0x24, 0x10 }, - { "962E", 0x24, 0x20 }, - { "A113X", 0x25, 0x37 }, - { "A113D", 0x25, 0x22 }, + { "S905", 0x1f, 0, 0x20 }, /* pack_id != 0x20 */ + { "S905H", 0x1f, 0x3, 0xf }, /* pack_id & 0xf == 0x3 */ + { "S905M", 0x1f, 0x20, 0xf0 }, /* pack_id == 0x20 */ + { "S905D", 0x21, 0, 0xf0 }, + { "S905X", 0x21, 0x80, 0xf0 }, + { "S905W", 0x21, 0xa0, 0xf0 }, + { "S905L", 0x21, 0xc0, 0xf0 }, + { "S905M2", 0x21, 0xe0, 0xf0 }, + { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ + { "962X", 0x24, 0x10, 0xf0 }, + { "962E", 0x24, 0x20, 0xf0 }, + { "A113X", 0x25, 0x37, 0xff }, + { "A113D", 0x25, 0x22, 0xff }, }; static inline unsigned int socinfo_to_major(u32 socinfo) @@ -81,13 +82,14 @@ static inline unsigned int socinfo_to_misc(u32 socinfo) static const char *socinfo_to_package_id(u32 socinfo) { - unsigned int pack = socinfo_to_pack(socinfo) & 0xf0; + unsigned int pack = socinfo_to_pack(socinfo); unsigned int major = socinfo_to_major(socinfo); int i; for (i = 0 ; i < ARRAY_SIZE(soc_packages) ; ++i) { if (soc_packages[i].major_id == major && - soc_packages[i].pack_id == pack) + soc_packages[i].pack_id == + (pack & soc_packages[i].pack_mask)) return soc_packages[i].name; } From 65f80df58eb770b2b687c35142c113d1ad6fa415 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 7 Mar 2019 15:01:46 +0100 Subject: [PATCH 05/57] soc: amlogic: gx-socinfo: Add new SoC IDs and Packages IDs This adds the: - G12A SoC ID and S905X2, S905D2 package IDs, found booting the X96 Max and U200 Reference Board - G12B SoC ID and S922X package ID, found booting the Odroid-N2 - S805X, S805Y package IDs found in the vendor U-Boot source Signed-off-by: Neil Armstrong Signed-off-by: Kevin Hilman --- drivers/soc/amlogic/meson-gx-socinfo.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index 1ae339f5eadb..c8d138d85f34 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c @@ -37,6 +37,8 @@ static const struct meson_gx_soc_id { { "AXG", 0x25 }, { "GXLX", 0x26 }, { "TXHD", 0x27 }, + { "G12A", 0x28 }, + { "G12B", 0x29 }, }; static const struct meson_gx_package_id { @@ -53,11 +55,16 @@ static const struct meson_gx_package_id { { "S905W", 0x21, 0xa0, 0xf0 }, { "S905L", 0x21, 0xc0, 0xf0 }, { "S905M2", 0x21, 0xe0, 0xf0 }, + { "S805X", 0x21, 0x30, 0xf0 }, + { "S805Y", 0x21, 0xb0, 0xf0 }, { "S912", 0x22, 0, 0x0 }, /* Only S912 is known for GXM */ { "962X", 0x24, 0x10, 0xf0 }, { "962E", 0x24, 0x20, 0xf0 }, { "A113X", 0x25, 0x37, 0xff }, { "A113D", 0x25, 0x22, 0xff }, + { "S905D2", 0x28, 0x10, 0xf0 }, + { "S905X2", 0x28, 0x40, 0xf0 }, + { "S922X", 0x29, 0x40, 0xf0 }, }; static inline unsigned int socinfo_to_major(u32 socinfo) From fdda0a6adc33536ad468f07db27325423703c5bc Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 23 Feb 2019 14:20:40 +0100 Subject: [PATCH 06/57] meson-gx-socinfo: add missing of_node_put after of_device_is_available Add an of_node_put when a tested device node is not available. The semantic patch that fixes this problem is as follows (http://coccinelle.lip6.fr): // @@ identifier f; local idexpression e; expression x; @@ e = f(...); ... when != of_node_put(e) when != x = e when != e = x when any if (<+...of_device_is_available(e)...+>) { ... when != of_node_put(e) ( return e; | + of_node_put(e); return ...; ) } // Fixes: a9daaba2965e8 ("soc: Add Amlogic SoC Information driver") Signed-off-by: Julia Lawall Signed-off-by: Kevin Hilman --- drivers/soc/amlogic/meson-gx-socinfo.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/soc/amlogic/meson-gx-socinfo.c b/drivers/soc/amlogic/meson-gx-socinfo.c index c8d138d85f34..bca34954518e 100644 --- a/drivers/soc/amlogic/meson-gx-socinfo.c +++ b/drivers/soc/amlogic/meson-gx-socinfo.c @@ -132,8 +132,10 @@ static int __init meson_gx_socinfo_init(void) return -ENODEV; /* check if interface is enabled */ - if (!of_device_is_available(np)) + if (!of_device_is_available(np)) { + of_node_put(np); return -ENODEV; + } /* check if chip-id is available */ if (!of_property_read_bool(np, "amlogic,has-chip-id")) From 8217a7a2c76259ff1f2623b60c3bcede052cdb49 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Tue, 19 Feb 2019 18:14:29 -0800 Subject: [PATCH 07/57] soc: imx: gpcv2: Make use of regmap_read_poll_timeout() Replace explicit polling loop with a call to regmap_read_poll_timeout() to avoid code repetition. Also fix misspelled "failed" while at it. Signed-off-by: Andrey Smirnov Cc: Lucas Stach Cc: Chris Healy Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Reviewed-by: Lucas Stach Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 176f473127b6..e06bf12a1e4b 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -136,8 +136,8 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, GPC_PU_PGC_SW_PUP_REQ : GPC_PU_PGC_SW_PDN_REQ; const bool enable_power_control = !on; const bool has_regulator = !IS_ERR(domain->regulator); - unsigned long deadline; int i, ret = 0; + u32 pxx_req; regmap_update_bits(domain->regmap, GPC_PGC_CPU_MAPPING, domain->bits.map, domain->bits.map); @@ -169,30 +169,19 @@ static int imx_gpc_pu_pgc_sw_pxx_req(struct generic_pm_domain *genpd, * As per "5.5.9.4 Example Code 4" in IMX7DRM.pdf wait * for PUP_REQ/PDN_REQ bit to be cleared */ - deadline = jiffies + msecs_to_jiffies(1); - while (true) { - u32 pxx_req; - - regmap_read(domain->regmap, offset, &pxx_req); - - if (!(pxx_req & domain->bits.pxx)) - break; - - if (time_after(jiffies, deadline)) { - dev_err(domain->dev, "falied to command PGC\n"); - ret = -ETIMEDOUT; - /* - * If we were in a process of enabling a - * domain and failed we might as well disable - * the regulator we just enabled. And if it - * was the opposite situation and we failed to - * power down -- keep the regulator on - */ - on = !on; - break; - } - - cpu_relax(); + ret = regmap_read_poll_timeout(domain->regmap, offset, pxx_req, + !(pxx_req & domain->bits.pxx), + 0, USEC_PER_MSEC); + if (ret) { + dev_err(domain->dev, "failed to command PGC\n"); + /* + * If we were in a process of enabling a + * domain and failed we might as well disable + * the regulator we just enabled. And if it + * was the opposite situation and we failed to + * power down -- keep the regulator on + */ + on = !on; } if (enable_power_control) From 9d616d62faefd573f6eaf687f6c83a872708afcf Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 20 Feb 2019 14:38:27 +0000 Subject: [PATCH 08/57] firmware: imx: scu-pd: use bool to set postfix Using bool instead 0/1 to indicate whether adding a postfix for domain names which can improve the code readability and less confusing. Cc: Ulf Hansson Cc: Shawn Guo Cc: Sascha Hauer Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/firmware/imx/scu-pd.c | 102 +++++++++++++++++----------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 39a94c7177fc..e7802ec591c2 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -84,71 +84,71 @@ struct imx_sc_pd_soc { 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 }, + { "lsio-pwm", IMX_SC_R_PWM_0, 8, true }, + { "lsio-gpio", IMX_SC_R_GPIO_0, 8, true }, + { "lsio-gpt", IMX_SC_R_GPT_0, 5, true }, + { "lsio-kpp", IMX_SC_R_KPP, 1, false }, + { "lsio-fspi", IMX_SC_R_FSPI_0, 2, true }, + { "lsio-mu", IMX_SC_R_MU_0A, 14, true }, /* 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 }, + { "con-usb", IMX_SC_R_USB_0, 2, true }, + { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, false }, + { "con-usb2", IMX_SC_R_USB_2, 1, false }, + { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, false }, + { "con-sdhc", IMX_SC_R_SDHC_0, 3, true }, + { "con-enet", IMX_SC_R_ENET_0, 2, true }, + { "con-nand", IMX_SC_R_NAND, 1, false }, + { "con-mlb", IMX_SC_R_MLB_0, 1, true }, /* 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 }, + { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false }, + { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false }, + { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false }, + { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true }, + { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true }, + { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true }, + { "adma-asrc0", IMX_SC_R_ASRC_0, 1, false }, + { "adma-asrc1", IMX_SC_R_ASRC_1, 1, false }, + { "adma-esai0", IMX_SC_R_ESAI_0, 1, false }, + { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, false }, + { "adma-sai", IMX_SC_R_SAI_0, 3, true }, + { "adma-amix", IMX_SC_R_AMIX, 1, false }, + { "adma-mqs0", IMX_SC_R_MQS_0, 1, false }, + { "adma-dsp", IMX_SC_R_DSP, 1, false }, + { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, false }, + { "adma-can", IMX_SC_R_CAN_0, 3, true }, + { "adma-ftm", IMX_SC_R_FTM_0, 2, true }, + { "adma-lpi2c", IMX_SC_R_I2C_0, 4, true }, + { "adma-adc", IMX_SC_R_ADC_0, 1, true }, + { "adma-lcd", IMX_SC_R_LCD_0, 1, true }, + { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true }, + { "adma-lpuart", IMX_SC_R_UART_0, 4, true }, + { "adma-lpspi", IMX_SC_R_SPI_0, 4, true }, /* 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 }, + { "vpu", IMX_SC_R_VPU, 1, false }, + { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true }, + { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false }, + { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false }, /* GPU SS */ - { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, 1 }, + { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true }, /* 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 }, + { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, false }, + { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, false }, + { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false }, /* 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 }, + { "mipi0", IMX_SC_R_MIPI_0, 1, false }, + { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false }, + { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true }, + { "lvds0", IMX_SC_R_LVDS_0, 1, false }, /* DC SS */ - { "dc0", IMX_SC_R_DC_0, 1, 0 }, - { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, 1 }, + { "dc0", IMX_SC_R_DC_0, 1, false }, + { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true }, }; static const struct imx_sc_pd_soc imx8qxp_scu_pd = { From ad8cc071c557b075b923bf27aee8a7dae7338f5e Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 20 Feb 2019 14:38:32 +0000 Subject: [PATCH 09/57] firmware: imx: scu-pd: add specifying the base of domain name index support As the domain resource id in the same type may not be continuous, so it's hard to describe all such power domains with current struct imx_sc_pd_range. Adding the optional base for domain name index to address this issue. Then we can add the discrete domains easily later. Cc: Ulf Hansson Cc: Shawn Guo Cc: Sascha Hauer Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/firmware/imx/scu-pd.c | 107 +++++++++++++++++----------------- 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index e7802ec591c2..8a2b6ada58ad 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -74,7 +74,10 @@ struct imx_sc_pd_range { char *name; u32 rsrc; u8 num; + + /* add domain index */ bool postfix; + u8 start_from; }; struct imx_sc_pd_soc { @@ -84,71 +87,71 @@ struct imx_sc_pd_soc { static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { /* LSIO SS */ - { "lsio-pwm", IMX_SC_R_PWM_0, 8, true }, - { "lsio-gpio", IMX_SC_R_GPIO_0, 8, true }, - { "lsio-gpt", IMX_SC_R_GPT_0, 5, true }, - { "lsio-kpp", IMX_SC_R_KPP, 1, false }, - { "lsio-fspi", IMX_SC_R_FSPI_0, 2, true }, - { "lsio-mu", IMX_SC_R_MU_0A, 14, true }, + { "lsio-pwm", IMX_SC_R_PWM_0, 8, true, 0 }, + { "lsio-gpio", IMX_SC_R_GPIO_0, 8, true, 0 }, + { "lsio-gpt", IMX_SC_R_GPT_0, 5, true, 0 }, + { "lsio-kpp", IMX_SC_R_KPP, 1, false, 0 }, + { "lsio-fspi", IMX_SC_R_FSPI_0, 2, true, 0 }, + { "lsio-mu", IMX_SC_R_MU_0A, 14, true, 0 }, /* CONN SS */ - { "con-usb", IMX_SC_R_USB_0, 2, true }, - { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, false }, - { "con-usb2", IMX_SC_R_USB_2, 1, false }, - { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, false }, - { "con-sdhc", IMX_SC_R_SDHC_0, 3, true }, - { "con-enet", IMX_SC_R_ENET_0, 2, true }, - { "con-nand", IMX_SC_R_NAND, 1, false }, - { "con-mlb", IMX_SC_R_MLB_0, 1, true }, + { "con-usb", IMX_SC_R_USB_0, 2, true, 0 }, + { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 }, + { "con-usb2", IMX_SC_R_USB_2, 1, false, 0 }, + { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 }, + { "con-sdhc", IMX_SC_R_SDHC_0, 3, true, 0 }, + { "con-enet", IMX_SC_R_ENET_0, 2, true, 0 }, + { "con-nand", IMX_SC_R_NAND, 1, false, 0 }, + { "con-mlb", IMX_SC_R_MLB_0, 1, true, 0 }, /* Audio DMA SS */ - { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false }, - { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false }, - { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false }, - { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true }, - { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true }, - { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true }, - { "adma-asrc0", IMX_SC_R_ASRC_0, 1, false }, - { "adma-asrc1", IMX_SC_R_ASRC_1, 1, false }, - { "adma-esai0", IMX_SC_R_ESAI_0, 1, false }, - { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, false }, - { "adma-sai", IMX_SC_R_SAI_0, 3, true }, - { "adma-amix", IMX_SC_R_AMIX, 1, false }, - { "adma-mqs0", IMX_SC_R_MQS_0, 1, false }, - { "adma-dsp", IMX_SC_R_DSP, 1, false }, - { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, false }, - { "adma-can", IMX_SC_R_CAN_0, 3, true }, - { "adma-ftm", IMX_SC_R_FTM_0, 2, true }, - { "adma-lpi2c", IMX_SC_R_I2C_0, 4, true }, - { "adma-adc", IMX_SC_R_ADC_0, 1, true }, - { "adma-lcd", IMX_SC_R_LCD_0, 1, true }, - { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true }, - { "adma-lpuart", IMX_SC_R_UART_0, 4, true }, - { "adma-lpspi", IMX_SC_R_SPI_0, 4, true }, + { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 }, + { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 }, + { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 }, + { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 }, + { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 }, + { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 }, + { "adma-asrc0", IMX_SC_R_ASRC_0, 1, false, 0 }, + { "adma-asrc1", IMX_SC_R_ASRC_1, 1, false, 0 }, + { "adma-esai0", IMX_SC_R_ESAI_0, 1, false, 0 }, + { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 }, + { "adma-sai", IMX_SC_R_SAI_0, 3, true, 0 }, + { "adma-amix", IMX_SC_R_AMIX, 1, false, 0 }, + { "adma-mqs0", IMX_SC_R_MQS_0, 1, false, 0 }, + { "adma-dsp", IMX_SC_R_DSP, 1, false, 0 }, + { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 }, + { "adma-can", IMX_SC_R_CAN_0, 3, true, 0 }, + { "adma-ftm", IMX_SC_R_FTM_0, 2, true, 0 }, + { "adma-lpi2c", IMX_SC_R_I2C_0, 4, true, 0 }, + { "adma-adc", IMX_SC_R_ADC_0, 1, true, 0 }, + { "adma-lcd", IMX_SC_R_LCD_0, 1, true, 0 }, + { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 }, + { "adma-lpuart", IMX_SC_R_UART_0, 4, true, 0 }, + { "adma-lpspi", IMX_SC_R_SPI_0, 4, true, 0 }, /* VPU SS */ - { "vpu", IMX_SC_R_VPU, 1, false }, - { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true }, - { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false }, - { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false }, + { "vpu", IMX_SC_R_VPU, 1, false, 0 }, + { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 }, + { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 }, + { "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 }, /* GPU SS */ - { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true }, + { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 }, /* HSIO SS */ - { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, false }, - { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, false }, - { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false }, + { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 }, + { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 }, + { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 }, /* MIPI/LVDS SS */ - { "mipi0", IMX_SC_R_MIPI_0, 1, false }, - { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false }, - { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true }, - { "lvds0", IMX_SC_R_LVDS_0, 1, false }, + { "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 }, + { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 }, + { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 }, + { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 }, /* DC SS */ - { "dc0", IMX_SC_R_DC_0, 1, false }, - { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true }, + { "dc0", IMX_SC_R_DC_0, 1, false, 0 }, + { "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 }, }; static const struct imx_sc_pd_soc imx8qxp_scu_pd = { @@ -236,7 +239,7 @@ imx_scu_add_pm_domain(struct device *dev, int idx, if (pd_ranges->postfix) snprintf(sc_pd->name, sizeof(sc_pd->name), - "%s%i", pd_ranges->name, idx); + "%s%i", pd_ranges->name, pd_ranges->start_from + idx); else snprintf(sc_pd->name, sizeof(sc_pd->name), "%s", pd_ranges->name); From 32654dad06e24e2909c64b4fc3d61689f5522975 Mon Sep 17 00:00:00 2001 From: Aisheng Dong Date: Wed, 20 Feb 2019 14:38:36 +0000 Subject: [PATCH 10/57] firmware: imx: scu-pd: decouple the SS information from domain names As resource power domain service is provided by SCU firmware, no SS information required. So we can remove the SS indicator from the domain names, then the domains defined can be better shared among different SCU based platforms. Cc: Ulf Hansson Cc: Shawn Guo Cc: Sascha Hauer Cc: "Rafael J. Wysocki" Cc: Kevin Hilman Cc: linux-pm@vger.kernel.org Signed-off-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/firmware/imx/scu-pd.c | 88 ++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index 8a2b6ada58ad..480cec69e2c9 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -87,49 +87,51 @@ struct imx_sc_pd_soc { static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { /* LSIO SS */ - { "lsio-pwm", IMX_SC_R_PWM_0, 8, true, 0 }, - { "lsio-gpio", IMX_SC_R_GPIO_0, 8, true, 0 }, - { "lsio-gpt", IMX_SC_R_GPT_0, 5, true, 0 }, - { "lsio-kpp", IMX_SC_R_KPP, 1, false, 0 }, - { "lsio-fspi", IMX_SC_R_FSPI_0, 2, true, 0 }, - { "lsio-mu", IMX_SC_R_MU_0A, 14, true, 0 }, + { "pwm", IMX_SC_R_PWM_0, 8, true, 0 }, + { "gpio", IMX_SC_R_GPIO_0, 8, true, 0 }, + { "gpt", IMX_SC_R_GPT_0, 5, true, 0 }, + { "kpp", IMX_SC_R_KPP, 1, false, 0 }, + { "fspi", IMX_SC_R_FSPI_0, 2, true, 0 }, + { "mu", IMX_SC_R_MU_0A, 14, true, 0 }, /* CONN SS */ - { "con-usb", IMX_SC_R_USB_0, 2, true, 0 }, - { "con-usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 }, - { "con-usb2", IMX_SC_R_USB_2, 1, false, 0 }, - { "con-usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 }, - { "con-sdhc", IMX_SC_R_SDHC_0, 3, true, 0 }, - { "con-enet", IMX_SC_R_ENET_0, 2, true, 0 }, - { "con-nand", IMX_SC_R_NAND, 1, false, 0 }, - { "con-mlb", IMX_SC_R_MLB_0, 1, true, 0 }, + { "usb", IMX_SC_R_USB_0, 2, true, 0 }, + { "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 }, + { "usb2", IMX_SC_R_USB_2, 1, false, 0 }, + { "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 }, + { "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 }, + { "enet", IMX_SC_R_ENET_0, 2, true, 0 }, + { "nand", IMX_SC_R_NAND, 1, false, 0 }, + { "mlb", IMX_SC_R_MLB_0, 1, true, 0 }, - /* Audio DMA SS */ - { "adma-audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 }, - { "adma-audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 }, - { "adma-audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 }, - { "adma-dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 }, - { "adma-dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 }, - { "adma-dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 }, - { "adma-asrc0", IMX_SC_R_ASRC_0, 1, false, 0 }, - { "adma-asrc1", IMX_SC_R_ASRC_1, 1, false, 0 }, - { "adma-esai0", IMX_SC_R_ESAI_0, 1, false, 0 }, - { "adma-spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 }, - { "adma-sai", IMX_SC_R_SAI_0, 3, true, 0 }, - { "adma-amix", IMX_SC_R_AMIX, 1, false, 0 }, - { "adma-mqs0", IMX_SC_R_MQS_0, 1, false, 0 }, - { "adma-dsp", IMX_SC_R_DSP, 1, false, 0 }, - { "adma-dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 }, - { "adma-can", IMX_SC_R_CAN_0, 3, true, 0 }, - { "adma-ftm", IMX_SC_R_FTM_0, 2, true, 0 }, - { "adma-lpi2c", IMX_SC_R_I2C_0, 4, true, 0 }, - { "adma-adc", IMX_SC_R_ADC_0, 1, true, 0 }, - { "adma-lcd", IMX_SC_R_LCD_0, 1, true, 0 }, - { "adma-lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 }, - { "adma-lpuart", IMX_SC_R_UART_0, 4, true, 0 }, - { "adma-lpspi", IMX_SC_R_SPI_0, 4, true, 0 }, + /* AUDIO SS */ + { "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 }, + { "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 }, + { "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 }, + { "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 }, + { "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 }, + { "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 }, + { "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 }, + { "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 }, + { "esai0", IMX_SC_R_ESAI_0, 1, false, 0 }, + { "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 }, + { "sai", IMX_SC_R_SAI_0, 3, true, 0 }, + { "amix", IMX_SC_R_AMIX, 1, false, 0 }, + { "mqs0", IMX_SC_R_MQS_0, 1, false, 0 }, + { "dsp", IMX_SC_R_DSP, 1, false, 0 }, + { "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 }, - /* VPU SS */ + /* DMA SS */ + { "can", IMX_SC_R_CAN_0, 3, true, 0 }, + { "ftm", IMX_SC_R_FTM_0, 2, true, 0 }, + { "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 }, + { "adc", IMX_SC_R_ADC_0, 1, true, 0 }, + { "lcd", IMX_SC_R_LCD_0, 1, true, 0 }, + { "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 }, + { "lpuart", IMX_SC_R_UART_0, 4, true, 0 }, + { "lpspi", IMX_SC_R_SPI_0, 4, true, 0 }, + + /* VPU SS */ { "vpu", IMX_SC_R_VPU, 1, false, 0 }, { "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 }, { "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 }, @@ -139,14 +141,16 @@ static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = { { "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 }, /* HSIO SS */ - { "hsio-pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 }, - { "hsio-serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 }, + { "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 }, + { "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 }, { "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 }, - /* MIPI/LVDS SS */ + /* MIPI SS */ { "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 }, { "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 }, { "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 }, + + /* LVDS SS */ { "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 }, /* DC SS */ From 7fe5719b4364fe9b673c3763007915877f3922c0 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 18 Feb 2019 17:36:43 +0100 Subject: [PATCH 11/57] soc/tegra: pmc: Implement acquire/release for resets By implementing the acquire/release protocol, the resets can be shared with other drivers that also adhere to this protocol. This will be used for example by the SOR driver to put hardware into a known good state, irrespective of whether or not the power domain can be reset. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 43 +++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 0df258518693..0c5f79528e5f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -656,10 +656,15 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain) int err; err = tegra_powergate_power_up(pg, true); - if (err) + if (err) { dev_err(dev, "failed to turn on PM domain %s: %d\n", pg->genpd.name, err); + goto out; + } + reset_control_release(pg->reset); + +out: return err; } @@ -669,10 +674,18 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain) struct device *dev = pg->pmc->dev; int err; + err = reset_control_acquire(pg->reset); + if (err < 0) { + pr_err("failed to acquire resets: %d\n", err); + return err; + } + err = tegra_powergate_power_down(pg); - if (err) + if (err) { dev_err(dev, "failed to turn off PM domain %s: %d\n", pg->genpd.name, err); + reset_control_release(pg->reset); + } return err; } @@ -937,20 +950,34 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, struct device *dev = pg->pmc->dev; int err; - pg->reset = of_reset_control_array_get_exclusive(np); + pg->reset = of_reset_control_array_get_exclusive_released(np); if (IS_ERR(pg->reset)) { err = PTR_ERR(pg->reset); dev_err(dev, "failed to get device resets: %d\n", err); return err; } - if (off) - err = reset_control_assert(pg->reset); - else - err = reset_control_deassert(pg->reset); + err = reset_control_acquire(pg->reset); + if (err < 0) { + pr_err("failed to acquire resets: %d\n", err); + goto out; + } - if (err) + if (off) { + err = reset_control_assert(pg->reset); + } else { + err = reset_control_deassert(pg->reset); + if (err < 0) + goto out; + + reset_control_release(pg->reset); + } + +out: + if (err) { + reset_control_release(pg->reset); reset_control_put(pg->reset); + } return err; } From 8da3daaa097171edd9658a82bbd3f335bc2e03ad Mon Sep 17 00:00:00 2001 From: Ankit Jain Date: Mon, 4 Feb 2019 10:15:43 +0530 Subject: [PATCH 12/57] soc: qcom: rmtfs: Add support for mmap functionality This change adds mmap functionality to rmtfs_mem driver. Userspace application can map the address and use this mapped address directly as buffer for read/write call to disk. and avoid the read/write call to the shared path to copy the buffer to userspace application. Reviewed-by: Bjorn Andersson Signed-off-by: Ankit Jain Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/rmtfs_mem.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index 7200d762a951..6f5e8be9689c 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c @@ -137,6 +137,26 @@ static struct class rmtfs_class = { .name = "rmtfs", }; +static int qcom_rmtfs_mem_mmap(struct file *filep, struct vm_area_struct *vma) +{ + struct qcom_rmtfs_mem *rmtfs_mem = filep->private_data; + + if (vma->vm_end - vma->vm_start > rmtfs_mem->size) { + dev_dbg(&rmtfs_mem->dev, + "vm_end[%lu] - vm_start[%lu] [%lu] > mem->size[%pa]\n", + vma->vm_end, vma->vm_start, + (vma->vm_end - vma->vm_start), &rmtfs_mem->size); + return -EINVAL; + } + + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + return remap_pfn_range(vma, + vma->vm_start, + rmtfs_mem->addr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + vma->vm_page_prot); +} + static const struct file_operations qcom_rmtfs_mem_fops = { .owner = THIS_MODULE, .open = qcom_rmtfs_mem_open, @@ -144,6 +164,7 @@ static const struct file_operations qcom_rmtfs_mem_fops = { .write = qcom_rmtfs_mem_write, .release = qcom_rmtfs_mem_release, .llseek = default_llseek, + .mmap = qcom_rmtfs_mem_mmap, }; static void qcom_rmtfs_mem_release_device(struct device *dev) From 9324df5817c01f55fcde24da0da9df2c2f9392ac Mon Sep 17 00:00:00 2001 From: Chris Lew Date: Thu, 21 Feb 2019 18:33:39 -0800 Subject: [PATCH 13/57] soc: qcom: qmi: Change txn wait to non-interruptible Current QMI clients are not userspace facing, if their threads are signaled, they do not do any signal checking or propagate the ERESTARTSYS return code up. Remove the interruptible option so clients can finish their QMI transactions even if the thread is signaled. Reviewed-by: Bjorn Andersson Signed-off-by: Chris Lew Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/qmi_interface.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index c239a28e503f..f9e309f0acd3 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -345,8 +345,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) struct qmi_handle *qmi = txn->qmi; int ret; - ret = wait_for_completion_interruptible_timeout(&txn->completion, - timeout); + ret = wait_for_completion_timeout(&txn->completion, timeout); mutex_lock(&qmi->txn_lock); mutex_lock(&txn->lock); @@ -354,9 +353,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) mutex_unlock(&txn->lock); mutex_unlock(&qmi->txn_lock); - if (ret < 0) - return ret; - else if (ret == 0) + if (ret == 0) return -ETIMEDOUT; else return txn->result; From 93b260528020792032e50725383f27a27897bb0f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 28 Feb 2019 08:48:49 +0300 Subject: [PATCH 14/57] soc: qcom: cmd-db: Fix an error code in cmd_db_dev_probe() The memremap() function doesn't return error pointers, it returns NULL. This code is returning "ret = PTR_ERR(NULL);" which is success, but it should return -ENOMEM. Fixes: 312416d9171a ("drivers: qcom: add command DB driver") Signed-off-by: Dan Carpenter Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/cmd-db.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index c701b3b010f1..f6c3d17b05c7 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -248,8 +248,8 @@ static int cmd_db_dev_probe(struct platform_device *pdev) } cmd_db_header = memremap(rmem->base, rmem->size, MEMREMAP_WB); - if (IS_ERR_OR_NULL(cmd_db_header)) { - ret = PTR_ERR(cmd_db_header); + if (!cmd_db_header) { + ret = -ENOMEM; cmd_db_header = NULL; return ret; } From 40b2bb1b132a0f07e8ebbdc364e28270c9dbbc08 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Wed, 27 Feb 2019 13:50:28 +0530 Subject: [PATCH 15/57] ARM: tegra: enforce PM requirement Currently runtime PM is enabled for Tegra HDA driver. One of the concern raised was about handling !PM case in HDA driver. In this case, there is a need to manage clocks and power explicitly in the driver and reviewers were not really convinced about this. The consensus at the end was to enforce PM requirement to keep things simple, rather driver mentioning a dependency on PM. This is how it is done for ARM 64-bit Tegra platforms and the same can be done for 32-bit Tegra platforms too. Finally the objective is to remove dependency on PM availability for all Tegra drivers. The detailed discussion can be found in following patch, https://patchwork.ozlabs.org/patch/1031007/ Signed-off-by: Sameer Pujar Reviewed-by: Thierry Reding Reviewed-by: Jonathan Hunter Reviewed-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 7f3b83e0d324..51a8fa3566ef 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -10,6 +10,7 @@ menuconfig ARCH_TEGRA select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select PINCTRL + select PM select PM_OPP select ARCH_HAS_RESET_CONTROLLER select RESET_CONTROLLER From 0d7dab926130e194decf1b4dabbf66de6e68bf0c Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Wed, 13 Mar 2019 10:11:58 +0530 Subject: [PATCH 16/57] bus: tegra-aconnect: use devm_clk_*() helpers aconnect bus driver is using pm_clk_*() interface for managing clocks. With this, clocks seem to be always ON. This happens on Tegra devices which use BPMP co-processor to manage clock resources, where clocks are enabled during prepare phase. This is necessary because calls to BPMP are always blocking. When pm_clk_*() interface is used on such Tegra devices, clock prepare count is not balanced till driver remove() gets executed and hence clocks are seen ON always. Thus this patch replaces pm_clk_*() with devm_clk_*() framework. Suggested-by: Mohan Kumar D Reviewed-by: Jonathan Hunter Signed-off-by: Sameer Pujar Signed-off-by: Thierry Reding --- drivers/bus/tegra-aconnect.c | 64 +++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c index 084ae286fa23..9349157b3a5b 100644 --- a/drivers/bus/tegra-aconnect.c +++ b/drivers/bus/tegra-aconnect.c @@ -12,28 +12,38 @@ #include #include #include -#include #include +struct tegra_aconnect { + struct clk *ape_clk; + struct clk *apb2ape_clk; +}; + static int tegra_aconnect_probe(struct platform_device *pdev) { - int ret; + struct tegra_aconnect *aconnect; if (!pdev->dev.of_node) return -EINVAL; - ret = pm_clk_create(&pdev->dev); - if (ret) - return ret; + aconnect = devm_kzalloc(&pdev->dev, sizeof(struct tegra_aconnect), + GFP_KERNEL); + if (!aconnect) + return -ENOMEM; - ret = of_pm_clk_add_clk(&pdev->dev, "ape"); - if (ret) - goto clk_destroy; + aconnect->ape_clk = devm_clk_get(&pdev->dev, "ape"); + if (IS_ERR(aconnect->ape_clk)) { + dev_err(&pdev->dev, "Can't retrieve ape clock\n"); + return PTR_ERR(aconnect->ape_clk); + } - ret = of_pm_clk_add_clk(&pdev->dev, "apb2ape"); - if (ret) - goto clk_destroy; + aconnect->apb2ape_clk = devm_clk_get(&pdev->dev, "apb2ape"); + if (IS_ERR(aconnect->apb2ape_clk)) { + dev_err(&pdev->dev, "Can't retrieve apb2ape clock\n"); + return PTR_ERR(aconnect->apb2ape_clk); + } + dev_set_drvdata(&pdev->dev, aconnect); pm_runtime_enable(&pdev->dev); of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); @@ -41,30 +51,44 @@ static int tegra_aconnect_probe(struct platform_device *pdev) dev_info(&pdev->dev, "Tegra ACONNECT bus registered\n"); return 0; - -clk_destroy: - pm_clk_destroy(&pdev->dev); - - return ret; } static int tegra_aconnect_remove(struct platform_device *pdev) { pm_runtime_disable(&pdev->dev); - pm_clk_destroy(&pdev->dev); - return 0; } static int tegra_aconnect_runtime_resume(struct device *dev) { - return pm_clk_resume(dev); + struct tegra_aconnect *aconnect = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(aconnect->ape_clk); + if (ret) { + dev_err(dev, "ape clk_enable failed: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(aconnect->apb2ape_clk); + if (ret) { + clk_disable_unprepare(aconnect->ape_clk); + dev_err(dev, "apb2ape clk_enable failed: %d\n", ret); + return ret; + } + + return 0; } static int tegra_aconnect_runtime_suspend(struct device *dev) { - return pm_clk_suspend(dev); + struct tegra_aconnect *aconnect = dev_get_drvdata(dev); + + clk_disable_unprepare(aconnect->ape_clk); + clk_disable_unprepare(aconnect->apb2ape_clk); + + return 0; } static const struct dev_pm_ops tegra_aconnect_pm_ops = { From 1427736e64c3a8b513cd984332f596055a7ca196 Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Wed, 13 Mar 2019 10:11:59 +0530 Subject: [PATCH 17/57] bus: tegra-aconnect: add system sleep callbacks pm_runtime_force_suspend() and pm_runtime_force_resume() are used as system sleep noirq suspend and resume callbacks. If the driver is active till late suspend, where runtime PM cannot run, force suspend is essential for the device. This makes sure that the device is put into low power state during system wide PM transitions to sleep states. Signed-off-by: Sameer Pujar Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/bus/tegra-aconnect.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bus/tegra-aconnect.c b/drivers/bus/tegra-aconnect.c index 9349157b3a5b..ac58142301f4 100644 --- a/drivers/bus/tegra-aconnect.c +++ b/drivers/bus/tegra-aconnect.c @@ -94,6 +94,8 @@ static int tegra_aconnect_runtime_suspend(struct device *dev) static const struct dev_pm_ops tegra_aconnect_pm_ops = { SET_RUNTIME_PM_OPS(tegra_aconnect_runtime_suspend, tegra_aconnect_runtime_resume, NULL) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static const struct of_device_id tegra_aconnect_of_match[] = { From d005aa750c9b7ca7f77dafd6dda33a0fcb6e7ae3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 2 Apr 2019 08:20:08 -0700 Subject: [PATCH 18/57] reset: fix linux/reset.h errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header file uses errno constant(s) and the ERR_PTR() macro but does not #include the appropriate header files that provide those facilities, so add 2 header files to fix build errors. CC [M] drivers/gpu/drm/lima/lima_device.o In file included from ../drivers/gpu/drm/lima/lima_device.c:5:0: ../include/linux/reset.h: In function ‘__device_reset’: ../include/linux/reset.h:77:25: error: ‘ENOTSUPP’ undeclared (first use in this function) return optional ? 0 : -ENOTSUPP; ../include/linux/reset.h:77:25: note: each undeclared identifier is reported only once for each function it appears in ../include/linux/reset.h: In function ‘__of_reset_control_get’: ../include/linux/reset.h:85:36: error: ‘ENOTSUPP’ undeclared (first use in this function) return optional ? NULL : ERR_PTR(-ENOTSUPP); ../include/linux/reset.h: In function ‘__reset_control_get’: ../include/linux/reset.h:93:36: error: ‘ENOTSUPP’ undeclared (first use in this function) return optional ? NULL : ERR_PTR(-ENOTSUPP); ../include/linux/reset.h: In function ‘__devm_reset_control_get’: ../include/linux/reset.h:101:36: error: ‘ENOTSUPP’ undeclared (first use in this function) return optional ? NULL : ERR_PTR(-ENOTSUPP); ../include/linux/reset.h: In function ‘devm_reset_control_array_get’: ../include/linux/reset.h:107:36: error: ‘ENOTSUPP’ undeclared (first use in this function) return optional ? NULL : ERR_PTR(-ENOTSUPP); ../include/linux/reset.h: In function ‘of_reset_control_array_get’: ../include/linux/reset.h:114:36: error: ‘ENOTSUPP’ undeclared (first use in this function) return optional ? NULL : ERR_PTR(-ENOTSUPP); In file included from ../drivers/gpu/drm/lima/lima_device.c:5:0: ../include/linux/reset.h: In function ‘__devm_reset_control_get’: ../include/linux/reset.h:102:1: warning: control reaches end of non-void function [-Wreturn-type] } Signed-off-by: Randy Dunlap Signed-off-by: Philipp Zabel --- include/linux/reset.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/reset.h b/include/linux/reset.h index 95d555c2130a..e7793fc0fa93 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -2,6 +2,8 @@ #ifndef _LINUX_RESET_H_ #define _LINUX_RESET_H_ +#include +#include #include struct device; From 6256f7f7f217b2216fcb73929508325f4ee98237 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 3 Apr 2019 10:27:39 +0530 Subject: [PATCH 19/57] rtc: OMAP: Add support for rtc-only mode Prepare rtc driver for rtc-only with DDR in self-refresh mode. omap_rtc_power_off now should cater to two features: 1) RTC plus DDR in self-refresh is power a saving mode where in the entire system including the different voltage rails from PMIC are shutdown except the ones feeding on to RTC and DDR. DDR is kept in self-refresh hence the contents are preserved. RTC ALARM2 is connected to PMIC_EN line once we the ALARM2 is triggered we enter the mode with DDR in self-refresh and RTC Ticking. After a predetermined time an RTC ALARM1 triggers waking up the system[1]. The control goes to bootloader. The bootloader then checks RTC scratchpad registers to confirm it was an rtc_only wakeup and follows a different path, configure bare minimal clocks for ddr and then jumps to the resume address in another RTC scratchpad registers and transfers the control to Kernel. Kernel then restores the saved context. omap_rtc_power_off_program does the ALARM2 programming part. [1] http://www.ti.com/lit/ug/spruhl7h/spruhl7h.pdf Page 2884 2) Power-off: This is usual poweroff mode. omap_rtc_power_off calls the above omap_rtc_power_off_program function and in addition to that programs the OMAP_RTC_PMIC_REG for any external wake ups for PMIC like the pushbutton and shuts off the PMIC. Hence the split in omap_rtc_power_off. Signed-off-by: Keerthy Acked-by: Alexandre Belloni [tony@atomide.com: folded in a fix for compile warning] Signed-off-by: Tony Lindgren --- drivers/rtc/rtc-omap.c | 51 +++++++++++++++++++++++++++++------- include/linux/rtc/rtc-omap.h | 7 +++++ 2 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 include/linux/rtc/rtc-omap.h diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index bbff0e2deb84..19b11b824d9c 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -415,15 +415,12 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) static struct omap_rtc *omap_rtc_power_off_rtc; -/* - * omap_rtc_poweroff: RTC-controlled power off - * - * The RTC can be used to control an external PMIC via the pmic_power_en pin, - * which can be configured to transition to OFF on ALARM2 events. - * - * Called with local interrupts disabled. +/** + * omap_rtc_power_off_program: Set the pmic power off sequence. The RTC + * generates pmic_pwr_enable control, which can be used to control an external + * PMIC. */ -static void omap_rtc_power_off(void) +int omap_rtc_power_off_program(struct device *dev) { struct omap_rtc *rtc = omap_rtc_power_off_rtc; struct rtc_time tm; @@ -437,6 +434,9 @@ static void omap_rtc_power_off(void) rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); again: + /* Clear any existing ALARM2 event */ + rtc_writel(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM2); + /* set alarm one second from now */ omap_rtc_read_time_raw(rtc, &tm); seconds = tm.tm_sec; @@ -447,7 +447,7 @@ again: if (tm2bcd(&tm) < 0) { dev_err(&rtc->rtc->dev, "power off failed\n"); rtc->type->lock(rtc); - return; + return -EINVAL; } rtc_wait_not_busy(rtc); @@ -477,6 +477,39 @@ again: rtc->type->lock(rtc); + return 0; +} +EXPORT_SYMBOL(omap_rtc_power_off_program); + +/* + * omap_rtc_poweroff: RTC-controlled power off + * + * The RTC can be used to control an external PMIC via the pmic_power_en pin, + * which can be configured to transition to OFF on ALARM2 events. + * + * Notes: + * The one-second alarm offset is the shortest offset possible as the alarm + * registers must be set before the next timer update and the offset + * calculation is too heavy for everything to be done within a single access + * period (~15 us). + * + * Called with local interrupts disabled. + */ +static void omap_rtc_power_off(void) +{ + struct rtc_device *rtc = omap_rtc_power_off_rtc->rtc; + u32 val; + + omap_rtc_power_off_program(rtc->dev.parent); + + /* Set PMIC power enable and EXT_WAKEUP in case PB power on is used */ + omap_rtc_power_off_rtc->type->unlock(omap_rtc_power_off_rtc); + val = rtc_readl(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG); + val |= OMAP_RTC_PMIC_POWER_EN_EN | OMAP_RTC_PMIC_EXT_WKUP_POL(0) | + OMAP_RTC_PMIC_EXT_WKUP_EN(0); + rtc_writel(omap_rtc_power_off_rtc, OMAP_RTC_PMIC_REG, val); + omap_rtc_power_off_rtc->type->lock(omap_rtc_power_off_rtc); + /* * Wait for alarm to trigger (within one second) and external PMIC to * power off the system. Add a 500 ms margin for external latencies diff --git a/include/linux/rtc/rtc-omap.h b/include/linux/rtc/rtc-omap.h new file mode 100644 index 000000000000..9f03a329e63f --- /dev/null +++ b/include/linux/rtc/rtc-omap.h @@ -0,0 +1,7 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef _LINUX_RTCOMAP_H_ +#define _LINUX_RTCOMAP_H_ + +int omap_rtc_power_off_program(struct device *dev); +#endif /* _LINUX_RTCOMAP_H_ */ From 44c22a2d12a5c04da56e746819a5d2cc4cf4a5d7 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 3 Apr 2019 10:27:40 +0530 Subject: [PATCH 20/57] ARM: OMAP2+: pm33xx: Add support for rtc+ddr in self refresh mode Add support for rtc+ddr in self refresh mode. Add addtional pm hooks for save/restore and rtc suspend/resume. Signed-off-by: Keerthy Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/pm33xx-core.c | 76 +++++++++++++++++++++++++++- include/linux/platform_data/pm33xx.h | 5 ++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-omap2/pm33xx-core.c b/arch/arm/mach-omap2/pm33xx-core.c index 724cf5774a6c..f81cc45a25b1 100644 --- a/arch/arm/mach-omap2/pm33xx-core.c +++ b/arch/arm/mach-omap2/pm33xx-core.c @@ -10,6 +10,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "cm33xx.h" #include "common.h" @@ -38,6 +44,29 @@ static int am43xx_map_scu(void) return 0; } +static int am33xx_check_off_mode_enable(void) +{ + if (enable_off_mode) + pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); + + /* off mode not supported on am335x so return 0 always */ + return 0; +} + +static int am43xx_check_off_mode_enable(void) +{ + /* + * Check for am437x-gp-evm which has the right Hardware design to + * support this mode reliably. + */ + if (of_machine_is_compatible("ti,am437x-gp-evm") && enable_off_mode) + return enable_off_mode; + else if (enable_off_mode) + pr_warn("WARNING: This platform does not support off-mode, entering DeepSleep suspend.\n"); + + return 0; +} + static int amx3_common_init(void) { gfx_pwrdm = pwrdm_lookup("gfx_pwrdm"); @@ -139,7 +168,9 @@ static int am43xx_suspend(unsigned int state, int (*fn)(unsigned long), scu_power_mode(scu_base, SCU_PM_POWEROFF); ret = cpu_suspend(args, fn); scu_power_mode(scu_base, SCU_PM_NORMAL); - amx3_post_suspend_common(); + + if (!am43xx_check_off_mode_enable()) + amx3_post_suspend_common(); return ret; } @@ -161,10 +192,48 @@ void __iomem *am43xx_get_rtc_base_addr(void) return omap_hwmod_get_mpu_rt_va(rtc_oh); } +static void am43xx_save_context(void) +{ +} + +static void am33xx_save_context(void) +{ + omap_intc_save_context(); +} + +static void am33xx_restore_context(void) +{ + omap_intc_restore_context(); +} + +static void am43xx_restore_context(void) +{ + /* + * HACK: restore dpll_per_clkdcoldo register contents, to avoid + * breaking suspend-resume + */ + writel_relaxed(0x0, AM33XX_L4_WK_IO_ADDRESS(0x44df2e14)); +} + +static void am43xx_prepare_rtc_suspend(void) +{ + omap_hwmod_enable(rtc_oh); +} + +static void am43xx_prepare_rtc_resume(void) +{ + omap_hwmod_idle(rtc_oh); +} + static struct am33xx_pm_platform_data am33xx_ops = { .init = am33xx_suspend_init, .soc_suspend = am33xx_suspend, .get_sram_addrs = amx3_get_sram_addrs, + .save_context = am33xx_save_context, + .restore_context = am33xx_restore_context, + .prepare_rtc_suspend = am43xx_prepare_rtc_suspend, + .prepare_rtc_resume = am43xx_prepare_rtc_resume, + .check_off_mode_enable = am33xx_check_off_mode_enable, .get_rtc_base_addr = am43xx_get_rtc_base_addr, }; @@ -172,6 +241,11 @@ static struct am33xx_pm_platform_data am43xx_ops = { .init = am43xx_suspend_init, .soc_suspend = am43xx_suspend, .get_sram_addrs = amx3_get_sram_addrs, + .save_context = am43xx_save_context, + .restore_context = am43xx_restore_context, + .prepare_rtc_suspend = am43xx_prepare_rtc_suspend, + .prepare_rtc_resume = am43xx_prepare_rtc_resume, + .check_off_mode_enable = am43xx_check_off_mode_enable, .get_rtc_base_addr = am43xx_get_rtc_base_addr, }; diff --git a/include/linux/platform_data/pm33xx.h b/include/linux/platform_data/pm33xx.h index fbf5ed73c7cc..dd5971937a64 100644 --- a/include/linux/platform_data/pm33xx.h +++ b/include/linux/platform_data/pm33xx.h @@ -51,6 +51,11 @@ struct am33xx_pm_platform_data { unsigned long args); struct am33xx_pm_sram_addr *(*get_sram_addrs)(void); void __iomem *(*get_rtc_base_addr)(void); + void (*save_context)(void); + void (*restore_context)(void); + void (*prepare_rtc_suspend)(void); + void (*prepare_rtc_resume)(void); + int (*check_off_mode_enable)(void); }; struct am33xx_pm_sram_data { From 1c6c03545089ef13a5dd6ef85900765be64aea49 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 3 Apr 2019 10:27:41 +0530 Subject: [PATCH 21/57] soc: ti: pm33xx: Move the am33xx_push_sram_idle to the top Move the am33xx_push_sram_idle function to the top as a preparation for rtc+ddr mode as the function will be called by multiple functions currently present before it. No functional changes. Signed-off-by: Keerthy Signed-off-by: Tony Lindgren --- drivers/soc/ti/pm33xx.c | 100 ++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index d0dab323651f..69128993776d 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -49,6 +49,56 @@ static u32 sram_suspend_address(unsigned long addr) AMX3_PM_SRAM_SYMBOL_OFFSET(addr)); } +static int am33xx_push_sram_idle(void) +{ + struct am33xx_pm_ro_sram_data ro_sram_data; + int ret; + u32 table_addr, ro_data_addr; + void *copy_addr; + + ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; + ro_sram_data.amx3_pm_sram_data_phys = + gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); + ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr(); + + /* Save physical address to calculate resume offset during pm init */ + am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, + ocmcram_location); + + am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location, + pm_sram->do_wfi, + *pm_sram->do_wfi_sz); + if (!am33xx_do_wfi_sram) { + dev_err(pm33xx_dev, + "PM: %s: am33xx_do_wfi copy to sram failed\n", + __func__); + return -ENODEV; + } + + table_addr = + sram_suspend_address((unsigned long)pm_sram->emif_sram_table); + ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr); + if (ret) { + dev_dbg(pm33xx_dev, + "PM: %s: EMIF function copy failed\n", __func__); + return -EPROBE_DEFER; + } + + ro_data_addr = + sram_suspend_address((unsigned long)pm_sram->ro_sram_data); + copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr, + &ro_sram_data, + sizeof(ro_sram_data)); + if (!copy_addr) { + dev_err(pm33xx_dev, + "PM: %s: ro_sram_data copy to sram failed\n", + __func__); + return -ENODEV; + } + + return 0; +} + #ifdef CONFIG_SUSPEND static int am33xx_pm_suspend(suspend_state_t suspend_state) { @@ -219,56 +269,6 @@ mpu_put_node: return ret; } -static int am33xx_push_sram_idle(void) -{ - struct am33xx_pm_ro_sram_data ro_sram_data; - int ret; - u32 table_addr, ro_data_addr; - void *copy_addr; - - ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; - ro_sram_data.amx3_pm_sram_data_phys = - gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); - ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr(); - - /* Save physical address to calculate resume offset during pm init */ - am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, - ocmcram_location); - - am33xx_do_wfi_sram = sram_exec_copy(sram_pool, (void *)ocmcram_location, - pm_sram->do_wfi, - *pm_sram->do_wfi_sz); - if (!am33xx_do_wfi_sram) { - dev_err(pm33xx_dev, - "PM: %s: am33xx_do_wfi copy to sram failed\n", - __func__); - return -ENODEV; - } - - table_addr = - sram_suspend_address((unsigned long)pm_sram->emif_sram_table); - ret = ti_emif_copy_pm_function_table(sram_pool, (void *)table_addr); - if (ret) { - dev_dbg(pm33xx_dev, - "PM: %s: EMIF function copy failed\n", __func__); - return -EPROBE_DEFER; - } - - ro_data_addr = - sram_suspend_address((unsigned long)pm_sram->ro_sram_data); - copy_addr = sram_exec_copy(sram_pool, (void *)ro_data_addr, - &ro_sram_data, - sizeof(ro_sram_data)); - if (!copy_addr) { - dev_err(pm33xx_dev, - "PM: %s: ro_sram_data copy to sram failed\n", - __func__); - return -ENODEV; - } - - return 0; -} - static int am33xx_pm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; From 5a99ae0092fe24fd581fdb6b9c2b48f94f92cf32 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Wed, 3 Apr 2019 10:27:42 +0530 Subject: [PATCH 22/57] soc: ti: pm33xx: AM437X: Add rtc_only with ddr in self-refresh support During RTC-only suspend, power is lost to the wkup domain, so we need to save and restore the state of that domain. We also need to store some information within the RTC registers so that u-boot can do the right thing at powerup. The state is entered by getting the RTC to bring the pmic_power_en line low which will instruct the PMIC to disable the appropriate power rails after putting DDR into self-refresh mode. To bring pmic_power_en low, we need to get an ALARM2 event. Since we are running from SRAM at that point, it means calculating what the next second is (via ASM) and programming that into the RTC. This patch also adds support for wake up source detection. Signed-off-by: Keerthy Signed-off-by: Dave Gerlach Signed-off-by: Tony Lindgren --- drivers/soc/ti/Kconfig | 5 +- drivers/soc/ti/pm33xx.c | 191 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 185 insertions(+), 11 deletions(-) diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index be4570baad96..57960e92ebe0 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -45,11 +45,12 @@ config KEYSTONE_NAVIGATOR_DMA config AMX3_PM tristate "AMx3 Power Management" depends on SOC_AM33XX || SOC_AM43XX - depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM + depends on WKUP_M3_IPC && TI_EMIF_SRAM && SRAM && RTC_DRV_OMAP help Enable power management on AM335x and AM437x. Required for suspend to mem and standby states on both AM335x and AM437x platforms and for deeper cpuidle - c-states on AM335x. + c-states on AM335x. Also required for rtc and ddr in self-refresh low + power mode on AM437x platforms. config WKUP_M3_IPC tristate "TI AMx3 Wkup-M3 IPC Driver" diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 69128993776d..fc5802ccb1c0 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -6,6 +6,7 @@ * Vaibhav Bedia, Dave Gerlach */ +#include #include #include #include @@ -13,9 +14,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -29,20 +33,47 @@ #define AMX3_PM_SRAM_SYMBOL_OFFSET(sym) ((unsigned long)(sym) - \ (unsigned long)pm_sram->do_wfi) +#define RTC_SCRATCH_RESUME_REG 0 +#define RTC_SCRATCH_MAGIC_REG 1 +#define RTC_REG_BOOT_MAGIC 0x8cd0 /* RTC */ +#define GIC_INT_SET_PENDING_BASE 0x200 +#define AM43XX_GIC_DIST_BASE 0x48241000 + +static u32 rtc_magic_val; + static int (*am33xx_do_wfi_sram)(unsigned long unused); static phys_addr_t am33xx_do_wfi_sram_phys; static struct gen_pool *sram_pool, *sram_pool_data; static unsigned long ocmcram_location, ocmcram_location_data; +static struct rtc_device *omap_rtc; +static void __iomem *gic_dist_base; + static struct am33xx_pm_platform_data *pm_ops; static struct am33xx_pm_sram_addr *pm_sram; static struct device *pm33xx_dev; static struct wkup_m3_ipc *m3_ipc; +#ifdef CONFIG_SUSPEND +static int rtc_only_idle; +static int retrigger_irq; static unsigned long suspend_wfi_flags; +static struct wkup_m3_wakeup_src wakeup_src = {.irq_nr = 0, + .src = "Unknown", +}; + +static struct wkup_m3_wakeup_src rtc_alarm_wakeup = { + .irq_nr = 108, .src = "RTC Alarm", +}; + +static struct wkup_m3_wakeup_src rtc_ext_wakeup = { + .irq_nr = 0, .src = "Ext wakeup", +}; +#endif + static u32 sram_suspend_address(unsigned long addr) { return ((unsigned long)am33xx_do_wfi_sram + @@ -99,13 +130,65 @@ static int am33xx_push_sram_idle(void) return 0; } +static int __init am43xx_map_gic(void) +{ + gic_dist_base = ioremap(AM43XX_GIC_DIST_BASE, SZ_4K); + + if (!gic_dist_base) + return -ENOMEM; + + return 0; +} + #ifdef CONFIG_SUSPEND +struct wkup_m3_wakeup_src rtc_wake_src(void) +{ + u32 i; + + i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40; + + if (i) { + retrigger_irq = rtc_alarm_wakeup.irq_nr; + return rtc_alarm_wakeup; + } + + retrigger_irq = rtc_ext_wakeup.irq_nr; + + return rtc_ext_wakeup; +} + +int am33xx_rtc_only_idle(unsigned long wfi_flags) +{ + omap_rtc_power_off_program(&omap_rtc->dev); + am33xx_do_wfi_sram(wfi_flags); + return 0; +} + static int am33xx_pm_suspend(suspend_state_t suspend_state) { int i, ret = 0; - ret = pm_ops->soc_suspend((unsigned long)suspend_state, - am33xx_do_wfi_sram, suspend_wfi_flags); + if (suspend_state == PM_SUSPEND_MEM && + pm_ops->check_off_mode_enable()) { + pm_ops->prepare_rtc_suspend(); + pm_ops->save_context(); + suspend_wfi_flags |= WFI_FLAG_RTC_ONLY; + clk_save_context(); + ret = pm_ops->soc_suspend(suspend_state, am33xx_rtc_only_idle, + suspend_wfi_flags); + + suspend_wfi_flags &= ~WFI_FLAG_RTC_ONLY; + + if (!ret) { + clk_restore_context(); + pm_ops->restore_context(); + m3_ipc->ops->set_rtc_only(m3_ipc); + am33xx_push_sram_idle(); + } + } else { + ret = pm_ops->soc_suspend(suspend_state, am33xx_do_wfi_sram, + suspend_wfi_flags); + } if (ret) { dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); @@ -127,8 +210,20 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) "PM: CM3 returned unknown result = %d\n", i); ret = -1; } + + /* print the wakeup reason */ + if (rtc_only_idle) { + wakeup_src = rtc_wake_src(); + pr_info("PM: Wakeup source %s\n", wakeup_src.src); + } else { + pr_info("PM: Wakeup source %s\n", + m3_ipc->ops->request_wake_src(m3_ipc)); + } } + if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) + pm_ops->prepare_rtc_resume(); + return ret; } @@ -151,6 +246,18 @@ static int am33xx_pm_enter(suspend_state_t suspend_state) static int am33xx_pm_begin(suspend_state_t state) { int ret = -EINVAL; + struct nvmem_device *nvmem; + + if (state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) { + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&rtc_magic_val); + rtc_only_idle = 1; + } else { + rtc_only_idle = 0; + } switch (state) { case PM_SUSPEND_MEM: @@ -166,7 +273,28 @@ static int am33xx_pm_begin(suspend_state_t state) static void am33xx_pm_end(void) { + u32 val = 0; + struct nvmem_device *nvmem; + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, "omap_rtc_scratch0"); m3_ipc->ops->finish_low_power(m3_ipc); + if (rtc_only_idle) { + if (retrigger_irq) + /* + * 32 bits of Interrupt Set-Pending correspond to 32 + * 32 interrupts. Compute the bit offset of the + * Interrupt and set that particular bit + * Compute the register offset by dividing interrupt + * number by 32 and mutiplying by 4 + */ + writel_relaxed(1 << (retrigger_irq & 31), + gic_dist_base + GIC_INT_SET_PENDING_BASE + + retrigger_irq / 32 * 4); + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, 4, + (void *)&val); + } + + rtc_only_idle = 0; } static int am33xx_pm_valid(suspend_state_t state) @@ -269,6 +397,42 @@ mpu_put_node: return ret; } +static int am33xx_pm_rtc_setup(void) +{ + struct device_node *np; + unsigned long val = 0; + struct nvmem_device *nvmem; + + np = of_find_node_by_name(NULL, "rtc"); + + if (of_device_is_available(np)) { + omap_rtc = rtc_class_open("rtc0"); + if (!omap_rtc) { + pr_warn("PM: rtc0 not available"); + return -EPROBE_DEFER; + } + + nvmem = devm_nvmem_device_get(&omap_rtc->dev, + "omap_rtc_scratch0"); + if (nvmem) { + nvmem_device_read(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&rtc_magic_val); + if ((rtc_magic_val & 0xffff) != RTC_REG_BOOT_MAGIC) + pr_warn("PM: bootloader does not support rtc-only!\n"); + + nvmem_device_write(nvmem, RTC_SCRATCH_MAGIC_REG * 4, + 4, (void *)&val); + val = pm_sram->resume_address; + nvmem_device_write(nvmem, RTC_SCRATCH_RESUME_REG * 4, + 4, (void *)&val); + } + } else { + pr_warn("PM: no-rtc available, rtc-only mode disabled.\n"); + } + + return 0; +} + static int am33xx_pm_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -284,34 +448,42 @@ static int am33xx_pm_probe(struct platform_device *pdev) return -ENODEV; } + ret = am43xx_map_gic(); + if (ret) { + pr_err("PM: Could not ioremap GIC base\n"); + return ret; + } + pm_sram = pm_ops->get_sram_addrs(); if (!pm_sram) { dev_err(dev, "PM: Cannot get PM asm function addresses!!\n"); return -ENODEV; } + m3_ipc = wkup_m3_ipc_get(); + if (!m3_ipc) { + pr_err("PM: Cannot get wkup_m3_ipc handle\n"); + return -EPROBE_DEFER; + } + pm33xx_dev = dev; ret = am33xx_pm_alloc_sram(); if (ret) return ret; - ret = am33xx_push_sram_idle(); + ret = am33xx_pm_rtc_setup(); if (ret) goto err_free_sram; - m3_ipc = wkup_m3_ipc_get(); - if (!m3_ipc) { - dev_dbg(dev, "PM: Cannot get wkup_m3_ipc handle\n"); - ret = -EPROBE_DEFER; + ret = am33xx_push_sram_idle(); + if (ret) goto err_free_sram; - } am33xx_pm_set_ipc_ops(); #ifdef CONFIG_SUSPEND suspend_set_ops(&am33xx_pm_ops); -#endif /* CONFIG_SUSPEND */ /* * For a system suspend we must flush the caches, we want @@ -323,6 +495,7 @@ static int am33xx_pm_probe(struct platform_device *pdev) suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; suspend_wfi_flags |= WFI_FLAG_WAKE_M3; +#endif /* CONFIG_SUSPEND */ ret = pm_ops->init(); if (ret) { From 6c110561eb2d4d1496961c13a92f96f29eea7c72 Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Tue, 2 Apr 2019 11:57:42 -0500 Subject: [PATCH 23/57] memory: ti-emif-sram: Add ti_emif_run_hw_leveling for DDR3 hardware leveling In certain situations, such as when returning from low power modes, the EMIF must re-run hardware leveling to properly restore DDR3 access. This is accomplished by introducing a new ti-emif-sram-pm call, ti_emif_run_hw_leveling, to check if DDR3 is in use and if so, trigger the full write and read leveling processes. Suggested-by: Brad Griffis Signed-off-by: Dave Gerlach Acked-by: Santosh Shilimkar Signed-off-by: Tony Lindgren --- drivers/memory/emif.h | 4 ++++ drivers/memory/ti-emif-pm.c | 3 +++ drivers/memory/ti-emif-sram-pm.S | 41 ++++++++++++++++++++++++++++++++ include/linux/ti-emif-sram.h | 3 +++ 4 files changed, 51 insertions(+) diff --git a/drivers/memory/emif.h b/drivers/memory/emif.h index 9e9f8037955d..6b71fadb3cfa 100644 --- a/drivers/memory/emif.h +++ b/drivers/memory/emif.h @@ -537,6 +537,9 @@ #define MCONNID_SHIFT 0 #define MCONNID_MASK (0xff << 0) +/* READ_WRITE_LEVELING_CONTROL */ +#define RDWRLVLFULL_START 0x80000000 + /* DDR_PHY_CTRL_1 - EMIF4D */ #define DLL_SLAVE_DLY_CTRL_SHIFT_4D 4 #define DLL_SLAVE_DLY_CTRL_MASK_4D (0xFF << 4) @@ -598,6 +601,7 @@ extern struct emif_regs_amx3 ti_emif_regs_amx3; void ti_emif_save_context(void); void ti_emif_restore_context(void); +void ti_emif_run_hw_leveling(void); void ti_emif_enter_sr(void); void ti_emif_exit_sr(void); void ti_emif_abort_sr(void); diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c index 2250d03ea17f..ab07aa163138 100644 --- a/drivers/memory/ti-emif-pm.c +++ b/drivers/memory/ti-emif-pm.c @@ -138,6 +138,9 @@ static int ti_emif_alloc_sram(struct device *dev, emif_data->pm_functions.exit_sr = sram_resume_address(emif_data, (unsigned long)ti_emif_exit_sr); + emif_data->pm_functions.run_hw_leveling = + sram_resume_address(emif_data, + (unsigned long)ti_emif_run_hw_leveling); emif_data->pm_data.regs_virt = (struct emif_regs_amx3 *)emif_data->ti_emif_sram_data_virt; diff --git a/drivers/memory/ti-emif-sram-pm.S b/drivers/memory/ti-emif-sram-pm.S index a5369181e5c2..d75ae18efa7d 100644 --- a/drivers/memory/ti-emif-sram-pm.S +++ b/drivers/memory/ti-emif-sram-pm.S @@ -27,6 +27,7 @@ #define EMIF_POWER_MGMT_SELF_REFRESH_MODE_MASK 0x0700 #define EMIF_SDCFG_TYPE_DDR2 0x2 << SDRAM_TYPE_SHIFT +#define EMIF_SDCFG_TYPE_DDR3 0x3 << SDRAM_TYPE_SHIFT #define EMIF_STATUS_READY 0x4 #define AM43XX_EMIF_PHY_CTRL_REG_COUNT 0x120 @@ -244,6 +245,46 @@ emif_skip_restore_extra_regs: mov pc, lr ENDPROC(ti_emif_restore_context) +/* + * void ti_emif_run_hw_leveling(void) + * + * Used during resume to run hardware leveling again and restore the + * configuration of the EMIF PHY, only for DDR3. + */ +ENTRY(ti_emif_run_hw_leveling) + adr r4, ti_emif_pm_sram_data + ldr r0, [r4, #EMIF_PM_BASE_ADDR_PHYS_OFFSET] + + ldr r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] + orr r3, r3, #RDWRLVLFULL_START + ldr r2, [r0, #EMIF_SDRAM_CONFIG] + and r2, r2, #SDRAM_TYPE_MASK + cmp r2, #EMIF_SDCFG_TYPE_DDR3 + bne skip_hwlvl + + str r3, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] + + /* + * If EMIF registers are touched during initial stage of HW + * leveling sequence there will be an L3 NOC timeout error issued + * as the EMIF will not respond, which is not fatal, but it is + * avoidable. This small wait loop is enough time for this condition + * to clear, even at worst case of CPU running at max speed of 1Ghz. + */ + mov r2, #0x2000 +1: + subs r2, r2, #0x1 + bne 1b + + /* Bit clears when operation is complete */ +2: ldr r1, [r0, #EMIF_READ_WRITE_LEVELING_CONTROL] + tst r1, #RDWRLVLFULL_START + bne 2b + +skip_hwlvl: + mov pc, lr +ENDPROC(ti_emif_run_hw_leveling) + /* * void ti_emif_enter_sr(void) * diff --git a/include/linux/ti-emif-sram.h b/include/linux/ti-emif-sram.h index 53604b087f2c..2fc854155c27 100644 --- a/include/linux/ti-emif-sram.h +++ b/include/linux/ti-emif-sram.h @@ -55,6 +55,7 @@ struct ti_emif_pm_data { struct ti_emif_pm_functions { u32 save_context; u32 restore_context; + u32 run_hw_leveling; u32 enter_sr; u32 exit_sr; u32 abort_sr; @@ -126,6 +127,8 @@ static inline void ti_emif_asm_offsets(void) offsetof(struct ti_emif_pm_functions, save_context)); DEFINE(EMIF_PM_RESTORE_CONTEXT_OFFSET, offsetof(struct ti_emif_pm_functions, restore_context)); + DEFINE(EMIF_PM_RUN_HW_LEVELING, + offsetof(struct ti_emif_pm_functions, run_hw_leveling)); DEFINE(EMIF_PM_ENTER_SR_OFFSET, offsetof(struct ti_emif_pm_functions, enter_sr)); DEFINE(EMIF_PM_EXIT_SR_OFFSET, From 11140cc40ddc3e7a2f2e3352e8a0587a93ba75df Mon Sep 17 00:00:00 2001 From: Dave Gerlach Date: Tue, 2 Apr 2019 11:57:43 -0500 Subject: [PATCH 24/57] ARM: OMAP2+: sleep43xx: Run EMIF HW leveling on resume path When returning from DeepSleep mode on AM437x platforms the EMIF must run DDR hardware leveling, same as done during u-boot, to properly restore the EMIF PHY to it's operational state on platforms using DDR3. Call the ti-emif-sram-pm run_hw_leveling routine to perform this. This happens after all other EMIF values are restored so the exact same configuration used at boot is used at the end of EMIF resume as well. Signed-off-by: Dave Gerlach Signed-off-by: Tony Lindgren --- arch/arm/mach-omap2/sleep43xx.S | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/mach-omap2/sleep43xx.S b/arch/arm/mach-omap2/sleep43xx.S index 5b9343b58fc7..0c1031442571 100644 --- a/arch/arm/mach-omap2/sleep43xx.S +++ b/arch/arm/mach-omap2/sleep43xx.S @@ -368,6 +368,9 @@ wait_emif_enable1: mov r1, #AM43XX_EMIF_POWEROFF_DISABLE str r1, [r2, #0x0] + ldr r1, [r9, #EMIF_PM_RUN_HW_LEVELING] + blx r1 + #ifdef CONFIG_CACHE_L2X0 ldr r2, l2_cache_base ldr r0, [r2, #L2X0_CTRL] From bbeac60f064158aa92b4c72fb50b12231e62cbcd Mon Sep 17 00:00:00 2001 From: Maulik Shah Date: Thu, 21 Feb 2019 18:10:36 +0530 Subject: [PATCH 25/57] drivers: soc: qcom: rpmh-rsc: Correct check for slot number The return index value from bitmap_find_next_zero_area can be higher than available slot. So correct the check to return error in such case. Signed-off-by: Maulik Shah Signed-off-by: Raju P.L.S.S.S.N Reviewed-by: Lina Iyer Signed-off-by: Andy Gross --- drivers/soc/qcom/rpmh-rsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index 75bd9a83aef0..e278fc11fe5c 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -459,7 +459,7 @@ static int find_slots(struct tcs_group *tcs, const struct tcs_request *msg, do { slot = bitmap_find_next_zero_area(tcs->slots, MAX_TCS_SLOTS, i, msg->num_cmds, 0); - if (slot == tcs->num_tcs * tcs->ncpt) + if (slot >= tcs->num_tcs * tcs->ncpt) return -ENOMEM; i += tcs->ncpt; } while (slot + msg->num_cmds - 1 >= i); From ccc1de31ab54bbf3e9fe2df1f562ea92d8fe8e44 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 1 Apr 2019 06:07:08 +0000 Subject: [PATCH 26/57] soc: imx: gpc: use devm_platform_ioremap_resource() to simplify code Use the new helper devm_platform_ioremap_resource() which wraps the platform_get_resource() and devm_ioremap_resource() together, to simplify the code. Signed-off-by: Anson Huang Reviewed-by: Mukesh Ojha Signed-off-by: Shawn Guo --- drivers/soc/imx/gpc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 7d14a4b4e82a..a8f1e47ce698 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -406,7 +406,6 @@ static int imx_gpc_probe(struct platform_device *pdev) const struct imx_gpc_dt_data *of_id_data = of_id->data; struct device_node *pgc_node; struct regmap *regmap; - struct resource *res; void __iomem *base; int ret; @@ -417,8 +416,7 @@ static int imx_gpc_probe(struct platform_device *pdev) !pgc_node) return 0; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); From 9f735c4e94fcbec66aa282eebb92c4aa3de88c6d Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Mon, 1 Apr 2019 06:07:13 +0000 Subject: [PATCH 27/57] soc: imx: gpcv2: use devm_platform_ioremap_resource() to simplify code Use the new helper devm_platform_ioremap_resource() which wraps the platform_get_resource() and devm_ioremap_resource() together, to simplify the code. Signed-off-by: Anson Huang Reviewed-by: Mukesh Ojha Signed-off-by: Shawn Guo --- drivers/soc/imx/gpcv2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index e06bf12a1e4b..31b8d002d855 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -563,7 +563,6 @@ static int imx_gpcv2_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device_node *pgc_np, *np; struct regmap *regmap; - struct resource *res; void __iomem *base; int ret; @@ -573,8 +572,7 @@ static int imx_gpcv2_probe(struct platform_device *pdev) return -EINVAL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, res); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); From 851826c7566e9bb4d03eb050634031ecc802affb Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Tue, 9 Apr 2019 04:59:55 +0000 Subject: [PATCH 28/57] firmware: imx: enable imx scu general irq function The System Controller Firmware (SCFW) controls RTC, thermal and WDOG etc., these resources' interrupt function are managed by SCU. When any IRQ pending, SCU will notify Linux via MU general interrupt channel #3, and Linux kernel needs to call SCU APIs to get IRQ status and notify each module to handle the interrupt. Since there is no data transmission for SCU IRQ notification, so doorbell mode is used for this MU channel, and SCU driver will use notifier mechanism to broadcast to every module which registers the SCU block notifier. Signed-off-by: Anson Huang Reviewed-by: Dong Aisheng Signed-off-by: Shawn Guo --- drivers/firmware/imx/Makefile | 2 +- drivers/firmware/imx/imx-scu-irq.c | 168 +++++++++++++++++++++++++++++ drivers/firmware/imx/imx-scu.c | 6 ++ include/linux/firmware/imx/sci.h | 5 + 4 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 drivers/firmware/imx/imx-scu-irq.c diff --git a/drivers/firmware/imx/Makefile b/drivers/firmware/imx/Makefile index 1b2e15b3c9ca..802c4ad8e8f9 100644 --- a/drivers/firmware/imx/Makefile +++ b/drivers/firmware/imx/Makefile @@ -1,3 +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 imx-scu-irq.o obj-$(CONFIG_IMX_SCU_PD) += scu-pd.o diff --git a/drivers/firmware/imx/imx-scu-irq.c b/drivers/firmware/imx/imx-scu-irq.c new file mode 100644 index 000000000000..043833ad3c1a --- /dev/null +++ b/drivers/firmware/imx/imx-scu-irq.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2019 NXP + * + * Implementation of the SCU IRQ functions using MU. + * + */ + +#include +#include +#include + +#define IMX_SC_IRQ_FUNC_ENABLE 1 +#define IMX_SC_IRQ_FUNC_STATUS 2 +#define IMX_SC_IRQ_NUM_GROUP 4 + +static u32 mu_resource_id; + +struct imx_sc_msg_irq_get_status { + struct imx_sc_rpc_msg hdr; + union { + struct { + u16 resource; + u8 group; + u8 reserved; + } __packed req; + struct { + u32 status; + } resp; + } data; +}; + +struct imx_sc_msg_irq_enable { + struct imx_sc_rpc_msg hdr; + u32 mask; + u16 resource; + u8 group; + u8 enable; +} __packed; + +static struct imx_sc_ipc *imx_sc_irq_ipc_handle; +static struct work_struct imx_sc_irq_work; +static ATOMIC_NOTIFIER_HEAD(imx_scu_irq_notifier_chain); + +int imx_scu_irq_register_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register( + &imx_scu_irq_notifier_chain, nb); +} +EXPORT_SYMBOL(imx_scu_irq_register_notifier); + +int imx_scu_irq_unregister_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister( + &imx_scu_irq_notifier_chain, nb); +} +EXPORT_SYMBOL(imx_scu_irq_unregister_notifier); + +static int imx_scu_irq_notifier_call_chain(unsigned long status, u8 *group) +{ + return atomic_notifier_call_chain(&imx_scu_irq_notifier_chain, + status, (void *)group); +} + +static void imx_scu_irq_work_handler(struct work_struct *work) +{ + struct imx_sc_msg_irq_get_status msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + u32 irq_status; + int ret; + u8 i; + + for (i = 0; i < IMX_SC_IRQ_NUM_GROUP; i++) { + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_IRQ; + hdr->func = IMX_SC_IRQ_FUNC_STATUS; + hdr->size = 2; + + msg.data.req.resource = mu_resource_id; + msg.data.req.group = i; + + ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); + if (ret) { + pr_err("get irq group %d status failed, ret %d\n", + i, ret); + return; + } + + irq_status = msg.data.resp.status; + if (!irq_status) + continue; + + imx_scu_irq_notifier_call_chain(irq_status, &i); + } +} + +int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable) +{ + struct imx_sc_msg_irq_enable msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_IRQ; + hdr->func = IMX_SC_IRQ_FUNC_ENABLE; + hdr->size = 3; + + msg.resource = mu_resource_id; + msg.group = group; + msg.mask = mask; + msg.enable = enable; + + ret = imx_scu_call_rpc(imx_sc_irq_ipc_handle, &msg, true); + if (ret) + pr_err("enable irq failed, group %d, mask %d, ret %d\n", + group, mask, ret); + + return ret; +} +EXPORT_SYMBOL(imx_scu_irq_group_enable); + +static void imx_scu_irq_callback(struct mbox_client *c, void *msg) +{ + schedule_work(&imx_sc_irq_work); +} + +int imx_scu_enable_general_irq_channel(struct device *dev) +{ + struct of_phandle_args spec; + struct mbox_client *cl; + struct mbox_chan *ch; + int ret = 0, i = 0; + + ret = imx_scu_get_handle(&imx_sc_irq_ipc_handle); + if (ret) + return ret; + + cl = devm_kzalloc(dev, sizeof(*cl), GFP_KERNEL); + if (!cl) + return -ENOMEM; + + cl->dev = dev; + cl->rx_callback = imx_scu_irq_callback; + + /* SCU general IRQ uses general interrupt channel 3 */ + ch = mbox_request_channel_byname(cl, "gip3"); + if (IS_ERR(ch)) { + ret = PTR_ERR(ch); + dev_err(dev, "failed to request mbox chan gip3, ret %d\n", ret); + devm_kfree(dev, cl); + return ret; + } + + INIT_WORK(&imx_sc_irq_work, imx_scu_irq_work_handler); + + if (!of_parse_phandle_with_args(dev->of_node, "mboxes", + "#mbox-cells", 0, &spec)) + i = of_alias_get_id(spec.np, "mu"); + + /* use mu1 as general mu irq channel if failed */ + if (i < 0) + i = 1; + + mu_resource_id = IMX_SC_R_MU_0A + i; + + return ret; +} +EXPORT_SYMBOL(imx_scu_enable_general_irq_channel); diff --git a/drivers/firmware/imx/imx-scu.c b/drivers/firmware/imx/imx-scu.c index 2bb1a19c413f..04a24a863d6e 100644 --- a/drivers/firmware/imx/imx-scu.c +++ b/drivers/firmware/imx/imx-scu.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -246,6 +247,11 @@ static int imx_scu_probe(struct platform_device *pdev) imx_sc_ipc_handle = sc_ipc; + ret = imx_scu_enable_general_irq_channel(dev); + if (ret) + dev_warn(dev, + "failed to enable general irq channel: %d\n", ret); + dev_info(dev, "NXP i.MX SCU Initialized\n"); return devm_of_platform_populate(dev); diff --git a/include/linux/firmware/imx/sci.h b/include/linux/firmware/imx/sci.h index ebc55098faee..17ba4e405129 100644 --- a/include/linux/firmware/imx/sci.h +++ b/include/linux/firmware/imx/sci.h @@ -15,4 +15,9 @@ #include #include + +int imx_scu_enable_general_irq_channel(struct device *dev); +int imx_scu_irq_register_notifier(struct notifier_block *nb); +int imx_scu_irq_unregister_notifier(struct notifier_block *nb); +int imx_scu_irq_group_enable(u8 group, u32 mask, u8 enable); #endif /* _SC_SCI_H */ From f2222a9e8033ceca2ed8b1addea1d541b536ab7b Mon Sep 17 00:00:00 2001 From: Yue Haibing Date: Wed, 10 Apr 2019 22:04:50 +0800 Subject: [PATCH 29/57] memory: tegra: Make terga20_mc_reset_ops static Fix sparse warning: drivers/memory/tegra/tegra20.c:277:33: warning: symbol 'terga20_mc_reset_ops' was not declared. Should it be static? Reported-by: Hulk Robot Signed-off-by: Yue Haibing Signed-off-by: Thierry Reding --- drivers/memory/tegra/tegra20.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index 7119e532471c..b786aec089e7 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -274,7 +274,7 @@ static int terga20_mc_unblock_dma(struct tegra_mc *mc, return 0; } -const struct tegra_mc_reset_ops terga20_mc_reset_ops = { +static const struct tegra_mc_reset_ops terga20_mc_reset_ops = { .hotreset_assert = terga20_mc_hotreset_assert, .hotreset_deassert = terga20_mc_hotreset_deassert, .block_dma = terga20_mc_block_dma, From bbdc00a7de24cc90315b1775fb74841373fe12f7 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 9 Apr 2019 13:49:05 -0700 Subject: [PATCH 30/57] soc: rockchip: Set the proper PWM for rk3288 The rk3288 SoC has two PWM implementations available, the "old" implementation and the "new" one. You can switch between the two of them by flipping a bit in the grf. The "old" implementation is the default at chip power up but isn't the one that's officially supposed to be used. ...and, in fact, the driver that gets selected in Linux using the rk3288 device tree only supports the "new" implementation. Long ago I tried to get a switch to the right IP block landed in the PWM driver (search for "rk3288: Switch to use the proper PWM IP") but that got rejected. In the mean time the grf has grown a full-fledged driver that already sets other random bits like this. That means we can now get the fix landed. For those wondering how things could have possibly worked for the last 4.5 years, folks have mostly been relying on the bootloader to set this bit. ...but occasionally folks have pointed back to my old patch series [1] in downstream kernels. [1] https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1391597.html Signed-off-by: Douglas Anderson Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/grf.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c index 96882ffde67e..3b81e1d75a97 100644 --- a/drivers/soc/rockchip/grf.c +++ b/drivers/soc/rockchip/grf.c @@ -66,9 +66,11 @@ static const struct rockchip_grf_info rk3228_grf __initconst = { }; #define RK3288_GRF_SOC_CON0 0x244 +#define RK3288_GRF_SOC_CON2 0x24c static const struct rockchip_grf_value rk3288_defaults[] __initconst = { { "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) }, + { "pwm select", RK3288_GRF_SOC_CON2, HIWORD_UPDATE(1, 1, 0) }, }; static const struct rockchip_grf_info rk3288_grf __initconst = { From cb2b58391e40d0877b1f60023c8be72696ff8511 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 11 Apr 2019 10:48:25 +0200 Subject: [PATCH 31/57] memory: tegra: Properly spell "tegra" Rename all occurrences of "terga" to "tegra". It's an easy typo to make and a difficult one to spot. Reviewed-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/memory/tegra/mc.c | 18 +++++++++--------- drivers/memory/tegra/mc.h | 2 +- drivers/memory/tegra/tegra114.c | 2 +- drivers/memory/tegra/tegra124.c | 4 ++-- drivers/memory/tegra/tegra20.c | 28 ++++++++++++++-------------- drivers/memory/tegra/tegra210.c | 2 +- drivers/memory/tegra/tegra30.c | 2 +- 7 files changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 0a53598d982f..a08b61a86760 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -74,7 +74,7 @@ static const struct of_device_id tegra_mc_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_mc_of_match); -static int terga_mc_block_dma_common(struct tegra_mc *mc, +static int tegra_mc_block_dma_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -90,13 +90,13 @@ static int terga_mc_block_dma_common(struct tegra_mc *mc, return 0; } -static bool terga_mc_dma_idling_common(struct tegra_mc *mc, +static bool tegra_mc_dma_idling_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { return (mc_readl(mc, rst->status) & BIT(rst->bit)) != 0; } -static int terga_mc_unblock_dma_common(struct tegra_mc *mc, +static int tegra_mc_unblock_dma_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -112,17 +112,17 @@ static int terga_mc_unblock_dma_common(struct tegra_mc *mc, return 0; } -static int terga_mc_reset_status_common(struct tegra_mc *mc, +static int tegra_mc_reset_status_common(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { return (mc_readl(mc, rst->control) & BIT(rst->bit)) != 0; } -const struct tegra_mc_reset_ops terga_mc_reset_ops_common = { - .block_dma = terga_mc_block_dma_common, - .dma_idling = terga_mc_dma_idling_common, - .unblock_dma = terga_mc_unblock_dma_common, - .reset_status = terga_mc_reset_status_common, +const struct tegra_mc_reset_ops tegra_mc_reset_ops_common = { + .block_dma = tegra_mc_block_dma_common, + .dma_idling = tegra_mc_dma_idling_common, + .unblock_dma = tegra_mc_unblock_dma_common, + .reset_status = tegra_mc_reset_status_common, }; static inline struct tegra_mc *reset_to_mc(struct reset_controller_dev *rcdev) diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h index 887a3b07334f..392993955c93 100644 --- a/drivers/memory/tegra/mc.h +++ b/drivers/memory/tegra/mc.h @@ -35,7 +35,7 @@ static inline void mc_writel(struct tegra_mc *mc, u32 value, writel_relaxed(value, mc->regs + offset); } -extern const struct tegra_mc_reset_ops terga_mc_reset_ops_common; +extern const struct tegra_mc_reset_ops tegra_mc_reset_ops_common; #ifdef CONFIG_ARCH_TEGRA_2x_SOC extern const struct tegra_mc_soc tegra20_mc_soc; diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index 6560a5101322..7247a46b71a8 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -975,7 +975,7 @@ const struct tegra_mc_soc tegra114_mc_soc = { .smmu = &tegra114_smmu_soc, .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, - .reset_ops = &terga_mc_reset_ops_common, + .reset_ops = &tegra_mc_reset_ops_common, .resets = tegra114_mc_resets, .num_resets = ARRAY_SIZE(tegra114_mc_resets), }; diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index b561a1fe7f46..8f8487bda642 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -1074,7 +1074,7 @@ const struct tegra_mc_soc tegra124_mc_soc = { .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, - .reset_ops = &terga_mc_reset_ops_common, + .reset_ops = &tegra_mc_reset_ops_common, .resets = tegra124_mc_resets, .num_resets = ARRAY_SIZE(tegra124_mc_resets), }; @@ -1104,7 +1104,7 @@ const struct tegra_mc_soc tegra132_mc_soc = { .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, - .reset_ops = &terga_mc_reset_ops_common, + .reset_ops = &tegra_mc_reset_ops_common, .resets = tegra124_mc_resets, .num_resets = ARRAY_SIZE(tegra124_mc_resets), }; diff --git a/drivers/memory/tegra/tegra20.c b/drivers/memory/tegra/tegra20.c index b786aec089e7..121237b16add 100644 --- a/drivers/memory/tegra/tegra20.c +++ b/drivers/memory/tegra/tegra20.c @@ -198,7 +198,7 @@ static const struct tegra_mc_reset tegra20_mc_resets[] = { TEGRA20_MC_RESET(VI, 0x100, 0x178, 0x104, 14), }; -static int terga20_mc_hotreset_assert(struct tegra_mc *mc, +static int tegra20_mc_hotreset_assert(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -214,7 +214,7 @@ static int terga20_mc_hotreset_assert(struct tegra_mc *mc, return 0; } -static int terga20_mc_hotreset_deassert(struct tegra_mc *mc, +static int tegra20_mc_hotreset_deassert(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -230,7 +230,7 @@ static int terga20_mc_hotreset_deassert(struct tegra_mc *mc, return 0; } -static int terga20_mc_block_dma(struct tegra_mc *mc, +static int tegra20_mc_block_dma(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -246,19 +246,19 @@ static int terga20_mc_block_dma(struct tegra_mc *mc, return 0; } -static bool terga20_mc_dma_idling(struct tegra_mc *mc, +static bool tegra20_mc_dma_idling(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { return mc_readl(mc, rst->status) == 0; } -static int terga20_mc_reset_status(struct tegra_mc *mc, +static int tegra20_mc_reset_status(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { return (mc_readl(mc, rst->reset) & BIT(rst->bit)) == 0; } -static int terga20_mc_unblock_dma(struct tegra_mc *mc, +static int tegra20_mc_unblock_dma(struct tegra_mc *mc, const struct tegra_mc_reset *rst) { unsigned long flags; @@ -274,13 +274,13 @@ static int terga20_mc_unblock_dma(struct tegra_mc *mc, return 0; } -static const struct tegra_mc_reset_ops terga20_mc_reset_ops = { - .hotreset_assert = terga20_mc_hotreset_assert, - .hotreset_deassert = terga20_mc_hotreset_deassert, - .block_dma = terga20_mc_block_dma, - .dma_idling = terga20_mc_dma_idling, - .unblock_dma = terga20_mc_unblock_dma, - .reset_status = terga20_mc_reset_status, +static const struct tegra_mc_reset_ops tegra20_mc_reset_ops = { + .hotreset_assert = tegra20_mc_hotreset_assert, + .hotreset_deassert = tegra20_mc_hotreset_deassert, + .block_dma = tegra20_mc_block_dma, + .dma_idling = tegra20_mc_dma_idling, + .unblock_dma = tegra20_mc_unblock_dma, + .reset_status = tegra20_mc_reset_status, }; const struct tegra_mc_soc tegra20_mc_soc = { @@ -290,7 +290,7 @@ const struct tegra_mc_soc tegra20_mc_soc = { .client_id_mask = 0x3f, .intmask = MC_INT_SECURITY_VIOLATION | MC_INT_INVALID_GART_PAGE | MC_INT_DECERR_EMEM, - .reset_ops = &terga20_mc_reset_ops, + .reset_ops = &tegra20_mc_reset_ops, .resets = tegra20_mc_resets, .num_resets = ARRAY_SIZE(tegra20_mc_resets), }; diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index d00a77160407..aa22cda637eb 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -1132,7 +1132,7 @@ const struct tegra_mc_soc tegra210_mc_soc = { .intmask = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR | MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, - .reset_ops = &terga_mc_reset_ops_common, + .reset_ops = &tegra_mc_reset_ops_common, .resets = tegra210_mc_resets, .num_resets = ARRAY_SIZE(tegra210_mc_resets), }; diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index bee5314ed404..68499ffdf0f4 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -999,7 +999,7 @@ const struct tegra_mc_soc tegra30_mc_soc = { .smmu = &tegra30_smmu_soc, .intmask = MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION | MC_INT_DECERR_EMEM, - .reset_ops = &terga_mc_reset_ops_common, + .reset_ops = &tegra_mc_reset_ops_common, .resets = tegra30_mc_resets, .num_resets = ARRAY_SIZE(tegra30_mc_resets), }; From fa7fe29a645b4da08efe8ff2392898b88f9ded9f Mon Sep 17 00:00:00 2001 From: Steven Price Date: Mon, 25 Mar 2019 17:37:22 +0000 Subject: [PATCH 32/57] firmware: arm_scmi: fix of_node leak in scmi_mailbox_check of_parse_phandle_with_args() requires the caller to call of_node_put() on the returned args->np pointer. Otherwise the reference count will remain incremented. However, in this case, since we don't actually use the returned pointer, we can simply pass in NULL. Fixes: aa4f886f3893f ("firmware: arm_scmi: add basic driver infrastructure for SCMI") Signed-off-by: Steven Price Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 8f952f2f1a29..dd967d675c08 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -654,9 +654,7 @@ static int scmi_xfer_info_init(struct scmi_info *sinfo) static int scmi_mailbox_check(struct device_node *np) { - struct of_phandle_args arg; - - return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, &arg); + return of_parse_phandle_with_args(np, "mboxes", "#mbox-cells", 0, NULL); } static int scmi_mbox_free_channel(int id, void *p, void *data) From d9350f21e5fe2614e1f78ef20c3a3e83c4a36391 Mon Sep 17 00:00:00 2001 From: Aditya Pakki Date: Fri, 22 Mar 2019 16:55:03 -0500 Subject: [PATCH 33/57] firmware: arm_scmi: replace of_match_device->data with of_device_get_match_data() of_match_device can return NULL if no matching device is found though it's highly unlikely to happen in scmi_probe as it's called only if a valid match is found. However we can use of_device_get_match_data() instead of of_match_device()->data to handle NULL pointer checks and return -EINVAL in such a scenario. Reviewed-by: Steven Price Signed-off-by: Aditya Pakki Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scmi/driver.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index dd967d675c08..b5bc4c7a8fab 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -796,7 +796,9 @@ static int scmi_probe(struct platform_device *pdev) return -EINVAL; } - desc = of_match_device(scmi_of_match, dev)->data; + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) From 4bad8b0709f59cc210207201b2cba86e4fc28bf5 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Sat, 23 Mar 2019 22:15:51 +0100 Subject: [PATCH 34/57] dt-bindings: pwrap: mediatek: add pwrap support for MT8516 Add binding documentation of pwrap for MT8516 SoCs. Signed-off-by: Fabien Parent Acked-by: Rob Herring Signed-off-by: Matthias Brugger --- Documentation/devicetree/bindings/soc/mediatek/pwrap.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt index 5a2ef1726e2a..7a32404c6114 100644 --- a/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt +++ b/Documentation/devicetree/bindings/soc/mediatek/pwrap.txt @@ -25,6 +25,7 @@ Required properties in pwrap device node. "mediatek,mt8135-pwrap" for MT8135 SoCs "mediatek,mt8173-pwrap" for MT8173 SoCs "mediatek,mt8183-pwrap" for MT8183 SoCs + "mediatek,mt8516-pwrap" for MT8516 SoCs - interrupts: IRQ for pwrap in SOC - reg-names: Must include the following entries: "pwrap": Main registers base From a51f4c031de35bc30d56bede232ffd2ae9c5fd6d Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Sat, 23 Mar 2019 22:15:52 +0100 Subject: [PATCH 35/57] soc: mediatek: pwrap: add missing check on rstc The variable rstc is set only when the SoC PWRAP have the PWRAP_CAP_RESET capability. Check whether rstc is set before using it to avoid errors. Signed-off-by: Fabien Parent Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 8236a6c87e19..b3ba2301f569 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -1478,7 +1478,8 @@ static int pwrap_init(struct pmic_wrapper *wrp) { int ret; - reset_control_reset(wrp->rstc); + if (wrp->rstc) + reset_control_reset(wrp->rstc); if (wrp->rstc_bridge) reset_control_reset(wrp->rstc_bridge); From 45a0686b91205ad4a83cfe8548e95a04f69565e0 Mon Sep 17 00:00:00 2001 From: Fabien Parent Date: Sat, 23 Mar 2019 22:15:53 +0100 Subject: [PATCH 36/57] soc: mediatek: pwrap: add support for MT8516 pwrap Add the code to support the pwrap IP on the MediaTek MT8516 SoC. Signed-off-by: Fabien Parent Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 106 +++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index b3ba2301f569..73f0be0567bd 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -381,6 +381,10 @@ enum pwrap_regs { PWRAP_EXT_GPS_AUXADC_RDATA_ADDR, PWRAP_GPSINF_0_STA, PWRAP_GPSINF_1_STA, + + /* MT8516 only regs */ + PWRAP_OP_TYPE, + PWRAP_MSB_FIRST, }; static int mt2701_regs[] = { @@ -852,6 +856,91 @@ static int mt8183_regs[] = { [PWRAP_WACS2_VLDCLR] = 0xC28, }; +static int mt8516_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xc, + [PWRAP_RDDMY] = 0x10, + [PWRAP_SI_CK_CON] = 0x14, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1c, + [PWRAP_CSLEXT_START] = 0x20, + [PWRAP_CSLEXT_END] = 0x24, + [PWRAP_STAUPD_PRD] = 0x28, + [PWRAP_STAUPD_GRPEN] = 0x2c, + [PWRAP_STAUPD_MAN_TRIG] = 0x40, + [PWRAP_STAUPD_STA] = 0x44, + [PWRAP_WRAP_STA] = 0x48, + [PWRAP_HARB_INIT] = 0x4c, + [PWRAP_HARB_HPRIO] = 0x50, + [PWRAP_HIPRIO_ARB_EN] = 0x54, + [PWRAP_HARB_STA0] = 0x58, + [PWRAP_HARB_STA1] = 0x5c, + [PWRAP_MAN_EN] = 0x60, + [PWRAP_MAN_CMD] = 0x64, + [PWRAP_MAN_RDATA] = 0x68, + [PWRAP_MAN_VLDCLR] = 0x6c, + [PWRAP_WACS0_EN] = 0x70, + [PWRAP_INIT_DONE0] = 0x74, + [PWRAP_WACS0_CMD] = 0x78, + [PWRAP_WACS0_RDATA] = 0x7c, + [PWRAP_WACS0_VLDCLR] = 0x80, + [PWRAP_WACS1_EN] = 0x84, + [PWRAP_INIT_DONE1] = 0x88, + [PWRAP_WACS1_CMD] = 0x8c, + [PWRAP_WACS1_RDATA] = 0x90, + [PWRAP_WACS1_VLDCLR] = 0x94, + [PWRAP_WACS2_EN] = 0x98, + [PWRAP_INIT_DONE2] = 0x9c, + [PWRAP_WACS2_CMD] = 0xa0, + [PWRAP_WACS2_RDATA] = 0xa4, + [PWRAP_WACS2_VLDCLR] = 0xa8, + [PWRAP_INT_EN] = 0xac, + [PWRAP_INT_FLG_RAW] = 0xb0, + [PWRAP_INT_FLG] = 0xb4, + [PWRAP_INT_CLR] = 0xb8, + [PWRAP_SIG_ADR] = 0xbc, + [PWRAP_SIG_MODE] = 0xc0, + [PWRAP_SIG_VALUE] = 0xc4, + [PWRAP_SIG_ERRVAL] = 0xc8, + [PWRAP_CRC_EN] = 0xcc, + [PWRAP_TIMER_EN] = 0xd0, + [PWRAP_TIMER_STA] = 0xd4, + [PWRAP_WDT_UNIT] = 0xd8, + [PWRAP_WDT_SRC_EN] = 0xdc, + [PWRAP_WDT_FLG] = 0xe0, + [PWRAP_DEBUG_INT_SEL] = 0xe4, + [PWRAP_DVFS_ADR0] = 0xe8, + [PWRAP_DVFS_WDATA0] = 0xec, + [PWRAP_DVFS_ADR1] = 0xf0, + [PWRAP_DVFS_WDATA1] = 0xf4, + [PWRAP_DVFS_ADR2] = 0xf8, + [PWRAP_DVFS_WDATA2] = 0xfc, + [PWRAP_DVFS_ADR3] = 0x100, + [PWRAP_DVFS_WDATA3] = 0x104, + [PWRAP_DVFS_ADR4] = 0x108, + [PWRAP_DVFS_WDATA4] = 0x10c, + [PWRAP_DVFS_ADR5] = 0x110, + [PWRAP_DVFS_WDATA5] = 0x114, + [PWRAP_DVFS_ADR6] = 0x118, + [PWRAP_DVFS_WDATA6] = 0x11c, + [PWRAP_DVFS_ADR7] = 0x120, + [PWRAP_DVFS_WDATA7] = 0x124, + [PWRAP_SPMINF_STA] = 0x128, + [PWRAP_CIPHER_KEY_SEL] = 0x12c, + [PWRAP_CIPHER_IV_SEL] = 0x130, + [PWRAP_CIPHER_EN] = 0x134, + [PWRAP_CIPHER_RDY] = 0x138, + [PWRAP_CIPHER_MODE] = 0x13c, + [PWRAP_CIPHER_SWRST] = 0x140, + [PWRAP_DCM_EN] = 0x144, + [PWRAP_DCM_DBC_PRD] = 0x148, + [PWRAP_SW_RST] = 0x168, + [PWRAP_OP_TYPE] = 0x16c, + [PWRAP_MSB_FIRST] = 0x170, +}; + enum pmic_type { PMIC_MT6323, PMIC_MT6351, @@ -869,6 +958,7 @@ enum pwrap_type { PWRAP_MT8135, PWRAP_MT8173, PWRAP_MT8183, + PWRAP_MT8516, }; struct pmic_wrapper; @@ -1297,6 +1387,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) case PWRAP_MT6765: case PWRAP_MT6797: case PWRAP_MT8173: + case PWRAP_MT8516: pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); break; case PWRAP_MT7622: @@ -1765,6 +1856,18 @@ static const struct pmic_wrapper_type pwrap_mt8183 = { .init_soc_specific = pwrap_mt8183_init_soc_specific, }; +static struct pmic_wrapper_type pwrap_mt8516 = { + .regs = mt8516_regs, + .type = PWRAP_MT8516, + .arb_en_all = 0xff, + .int_en_all = ~(u32)(BIT(31) | BIT(2)), + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .caps = PWRAP_CAP_DCM, + .init_reg_clock = pwrap_mt2701_init_reg_clock, + .init_soc_specific = NULL, +}; + static const struct of_device_id of_pwrap_match_tbl[] = { { .compatible = "mediatek,mt2701-pwrap", @@ -1787,6 +1890,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = { }, { .compatible = "mediatek,mt8183-pwrap", .data = &pwrap_mt8183, + }, { + .compatible = "mediatek,mt8516-pwrap", + .data = &pwrap_mt8516, }, { /* sentinel */ } From 89e28da82836530f1ac7a3a32fecc31f22d79b3e Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Thu, 7 Mar 2019 15:56:51 -0700 Subject: [PATCH 37/57] soc: mediatek: pwrap: Zero initialize rdata in pwrap_init_cipher When building with -Wsometimes-uninitialized, Clang warns: drivers/soc/mediatek/mtk-pmic-wrap.c:1358:6: error: variable 'rdata' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized] If pwrap_write returns non-zero, pwrap_read will not be called to initialize rdata, meaning that we will use some random uninitialized stack value in our print statement. Zero initialize rdata in case this happens. Link: https://github.com/ClangBuiltLinux/linux/issues/401 Signed-off-by: Nathan Chancellor Reviewed-by: Nick Desaulniers Reviewed-by: Arnd Bergmann Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-pmic-wrap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 73f0be0567bd..c4449a163991 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -1371,7 +1371,7 @@ static bool pwrap_is_pmic_cipher_ready(struct pmic_wrapper *wrp) static int pwrap_init_cipher(struct pmic_wrapper *wrp) { int ret; - u32 rdata; + u32 rdata = 0; pwrap_writel(wrp, 0x1, PWRAP_CIPHER_SWRST); pwrap_writel(wrp, 0x0, PWRAP_CIPHER_SWRST); From e840decc1954521ff73bbc87b5b3ea36af1704d2 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Mon, 15 Apr 2019 12:47:46 +0530 Subject: [PATCH 38/57] firmware: xilinx: Add fpga API's This Patch Adds fpga API's to support the Bitstream loading by using firmware interface. Signed-off-by: Nava kishore Manne Reviewed-by: Moritz Fischer Signed-off-by: Michal Simek --- drivers/firmware/xilinx/zynqmp.c | 45 ++++++++++++++++++++++++++++ include/linux/firmware/xlnx-zynqmp.h | 12 ++++++++ 2 files changed, 57 insertions(+) diff --git a/drivers/firmware/xilinx/zynqmp.c b/drivers/firmware/xilinx/zynqmp.c index 87a1d636c0dc..fd3d83745208 100644 --- a/drivers/firmware/xilinx/zynqmp.c +++ b/drivers/firmware/xilinx/zynqmp.c @@ -539,6 +539,49 @@ static int zynqmp_pm_reset_get_status(const enum zynqmp_pm_reset reset, return ret; } +/** + * zynqmp_pm_fpga_load - Perform the fpga load + * @address: Address to write to + * @size: pl bitstream size + * @flags: Bitstream type + * -XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration + * -XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration + * + * This function provides access to pmufw. To transfer + * the required bitstream into PL. + * + * Return: Returns status, either success or error+reason + */ +static int zynqmp_pm_fpga_load(const u64 address, const u32 size, + const u32 flags) +{ + return zynqmp_pm_invoke_fn(PM_FPGA_LOAD, lower_32_bits(address), + upper_32_bits(address), size, flags, NULL); +} + +/** + * zynqmp_pm_fpga_get_status - Read value from PCAP status register + * @value: Value to read + * + * This function provides access to the pmufw to get the PCAP + * status + * + * Return: Returns status, either success or error+reason + */ +static int zynqmp_pm_fpga_get_status(u32 *value) +{ + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!value) + return -EINVAL; + + ret = zynqmp_pm_invoke_fn(PM_FPGA_GET_STATUS, 0, 0, 0, 0, ret_payload); + *value = ret_payload[1]; + + return ret; +} + /** * zynqmp_pm_init_finalize() - PM call to inform firmware that the caller * master has initialized its own power management @@ -642,6 +685,8 @@ static const struct zynqmp_eemi_ops eemi_ops = { .request_node = zynqmp_pm_request_node, .release_node = zynqmp_pm_release_node, .set_requirement = zynqmp_pm_set_requirement, + .fpga_load = zynqmp_pm_fpga_load, + .fpga_get_status = zynqmp_pm_fpga_get_status, }; /** diff --git a/include/linux/firmware/xlnx-zynqmp.h b/include/linux/firmware/xlnx-zynqmp.h index 3533ee557043..1262ea6a1f4b 100644 --- a/include/linux/firmware/xlnx-zynqmp.h +++ b/include/linux/firmware/xlnx-zynqmp.h @@ -48,6 +48,14 @@ #define ZYNQMP_PM_CAPABILITY_WAKEUP 0x4U #define ZYNQMP_PM_CAPABILITY_POWER 0x8U +/* + * Firmware FPGA Manager flags + * XILINX_ZYNQMP_PM_FPGA_FULL: FPGA full reconfiguration + * XILINX_ZYNQMP_PM_FPGA_PARTIAL: FPGA partial reconfiguration + */ +#define XILINX_ZYNQMP_PM_FPGA_FULL 0x0U +#define XILINX_ZYNQMP_PM_FPGA_PARTIAL BIT(0) + enum pm_api_id { PM_GET_API_VERSION = 1, PM_REQUEST_NODE = 13, @@ -56,6 +64,8 @@ enum pm_api_id { PM_RESET_ASSERT = 17, PM_RESET_GET_STATUS, PM_PM_INIT_FINALIZE = 21, + PM_FPGA_LOAD, + PM_FPGA_GET_STATUS, PM_GET_CHIPID = 24, PM_IOCTL = 34, PM_QUERY_DATA, @@ -258,6 +268,8 @@ struct zynqmp_pm_query_data { struct zynqmp_eemi_ops { int (*get_api_version)(u32 *version); int (*get_chipid)(u32 *idcode, u32 *version); + int (*fpga_load)(const u64 address, const u32 size, const u32 flags); + int (*fpga_get_status)(u32 *value); int (*query_data)(struct zynqmp_pm_query_data qdata, u32 *out); int (*clock_enable)(u32 clock_id); int (*clock_disable)(u32 clock_id); From 9b0879620ea8b612f1baab188cb867fd055899d6 Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Mon, 15 Apr 2019 12:47:47 +0530 Subject: [PATCH 39/57] dt-bindings: fpga: Add bindings for ZynqMP fpga driver Add documentation to describe Xilinx ZynqMP fpga driver bindings. Signed-off-by: Nava kishore Manne Reviewed-by: Rob Herring Acked-by: Alan Tull Acked-by: Moritz Fischer Signed-off-by: Michal Simek --- .../bindings/fpga/xlnx,zynqmp-pcap-fpga.txt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt diff --git a/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt b/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt new file mode 100644 index 000000000000..3052bf619dd5 --- /dev/null +++ b/Documentation/devicetree/bindings/fpga/xlnx,zynqmp-pcap-fpga.txt @@ -0,0 +1,25 @@ +Devicetree bindings for Zynq Ultrascale MPSoC FPGA Manager. +The ZynqMP SoC uses the PCAP (Processor configuration Port) to configure the +Programmable Logic (PL). The configuration uses the firmware interface. + +Required properties: +- compatible: should contain "xlnx,zynqmp-pcap-fpga" + +Example for full FPGA configuration: + + fpga-region0 { + compatible = "fpga-region"; + fpga-mgr = <&zynqmp_pcap>; + #address-cells = <0x1>; + #size-cells = <0x1>; + }; + + firmware { + zynqmp_firmware: zynqmp-firmware { + compatible = "xlnx,zynqmp-firmware"; + method = "smc"; + zynqmp_pcap: pcap { + compatible = "xlnx,zynqmp-pcap-fpga"; + }; + }; + }; From c09f7471127e9debf3e814ffef4f4012c31a5a3d Mon Sep 17 00:00:00 2001 From: Nava kishore Manne Date: Mon, 15 Apr 2019 12:47:48 +0530 Subject: [PATCH 40/57] fpga manager: Adding FPGA Manager support for Xilinx zynqmp This patch adds FPGA Manager support for the Xilinx ZynqMP chip. Signed-off-by: Nava kishore Manne Reviewed-by: Moritz Fischer Acked-by: Alan Tull Signed-off-by: Michal Simek --- drivers/fpga/Kconfig | 9 +++ drivers/fpga/Makefile | 1 + drivers/fpga/zynqmp-fpga.c | 159 +++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 drivers/fpga/zynqmp-fpga.c diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig index c20445b867ae..d892f3efcd76 100644 --- a/drivers/fpga/Kconfig +++ b/drivers/fpga/Kconfig @@ -204,4 +204,13 @@ config FPGA_DFL_PCI To compile this as a module, choose M here. +config FPGA_MGR_ZYNQMP_FPGA + tristate "Xilinx ZynqMP FPGA" + depends on ARCH_ZYNQMP || COMPILE_TEST + help + FPGA manager driver support for Xilinx ZynqMP FPGAs. + This driver uses the processor configuration port(PCAP) + to configure the programmable logic(PL) through PS + on ZynqMP SoC. + endif # FPGA diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile index c0dd4c82fbdb..312b9371742f 100644 --- a/drivers/fpga/Makefile +++ b/drivers/fpga/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o +obj-$(CONFIG_FPGA_MGR_ZYNQMP_FPGA) += zynqmp-fpga.o obj-$(CONFIG_ALTERA_PR_IP_CORE) += altera-pr-ip-core.o obj-$(CONFIG_ALTERA_PR_IP_CORE_PLAT) += altera-pr-ip-core-plat.o diff --git a/drivers/fpga/zynqmp-fpga.c b/drivers/fpga/zynqmp-fpga.c new file mode 100644 index 000000000000..f7cbaadf49ab --- /dev/null +++ b/drivers/fpga/zynqmp-fpga.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2019 Xilinx, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Constant Definitions */ +#define IXR_FPGA_DONE_MASK BIT(3) + +/** + * struct zynqmp_fpga_priv - Private data structure + * @dev: Device data structure + * @flags: flags which is used to identify the bitfile type + */ +struct zynqmp_fpga_priv { + struct device *dev; + u32 flags; +}; + +static int zynqmp_fpga_ops_write_init(struct fpga_manager *mgr, + struct fpga_image_info *info, + const char *buf, size_t size) +{ + struct zynqmp_fpga_priv *priv; + + priv = mgr->priv; + priv->flags = info->flags; + + return 0; +} + +static int zynqmp_fpga_ops_write(struct fpga_manager *mgr, + const char *buf, size_t size) +{ + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); + struct zynqmp_fpga_priv *priv; + dma_addr_t dma_addr; + u32 eemi_flags = 0; + char *kbuf; + int ret; + + if (!eemi_ops || !eemi_ops->fpga_load) + return -ENXIO; + + priv = mgr->priv; + + kbuf = dma_alloc_coherent(priv->dev, size, &dma_addr, GFP_KERNEL); + if (!kbuf) + return -ENOMEM; + + memcpy(kbuf, buf, size); + + wmb(); /* ensure all writes are done before initiate FW call */ + + if (priv->flags & FPGA_MGR_PARTIAL_RECONFIG) + eemi_flags |= XILINX_ZYNQMP_PM_FPGA_PARTIAL; + + ret = eemi_ops->fpga_load(dma_addr, size, eemi_flags); + + dma_free_coherent(priv->dev, size, kbuf, dma_addr); + + return ret; +} + +static int zynqmp_fpga_ops_write_complete(struct fpga_manager *mgr, + struct fpga_image_info *info) +{ + return 0; +} + +static enum fpga_mgr_states zynqmp_fpga_ops_state(struct fpga_manager *mgr) +{ + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); + u32 status; + + if (!eemi_ops || !eemi_ops->fpga_get_status) + return FPGA_MGR_STATE_UNKNOWN; + + eemi_ops->fpga_get_status(&status); + if (status & IXR_FPGA_DONE_MASK) + return FPGA_MGR_STATE_OPERATING; + + return FPGA_MGR_STATE_UNKNOWN; +} + +static const struct fpga_manager_ops zynqmp_fpga_ops = { + .state = zynqmp_fpga_ops_state, + .write_init = zynqmp_fpga_ops_write_init, + .write = zynqmp_fpga_ops_write, + .write_complete = zynqmp_fpga_ops_write_complete, +}; + +static int zynqmp_fpga_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zynqmp_fpga_priv *priv; + struct fpga_manager *mgr; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + + mgr = devm_fpga_mgr_create(dev, "Xilinx ZynqMP FPGA Manager", + &zynqmp_fpga_ops, priv); + if (!mgr) + return -ENOMEM; + + platform_set_drvdata(pdev, mgr); + + ret = fpga_mgr_register(mgr); + if (ret) { + dev_err(dev, "unable to register FPGA manager"); + return ret; + } + + return 0; +} + +static int zynqmp_fpga_remove(struct platform_device *pdev) +{ + struct fpga_manager *mgr = platform_get_drvdata(pdev); + + fpga_mgr_unregister(mgr); + + return 0; +} + +static const struct of_device_id zynqmp_fpga_of_match[] = { + { .compatible = "xlnx,zynqmp-pcap-fpga", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, zynqmp_fpga_of_match); + +static struct platform_driver zynqmp_fpga_driver = { + .probe = zynqmp_fpga_probe, + .remove = zynqmp_fpga_remove, + .driver = { + .name = "zynqmp_fpga_manager", + .of_match_table = of_match_ptr(zynqmp_fpga_of_match), + }, +}; + +module_platform_driver(zynqmp_fpga_driver); + +MODULE_AUTHOR("Nava kishore Manne "); +MODULE_DESCRIPTION("Xilinx ZynqMp FPGA Manager"); +MODULE_LICENSE("GPL"); From 2fe3b4bbc93ec30a173ebae7d2b8c530416df3af Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 1 Apr 2019 09:48:01 +0200 Subject: [PATCH 41/57] soc: amlogic: meson-gx-pwrc-vpu: Fix power on/off register bitmask The register bitmask to power on/off the VPU memories was incorectly set to 0x2 instead of 0x3. While still working, let's use the recommended vendor value instead. Fixes: 75fcb5ca4b46 ("soc: amlogic: add Meson GX VPU Domains driver") Signed-off-by: Neil Armstrong Signed-off-by: Kevin Hilman --- drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c index 6289965c42e9..05421d029dff 100644 --- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c @@ -54,12 +54,12 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) /* Power Down Memories */ for (i = 0; i < 32; i += 2) { regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x2 << i, 0x3 << i); + 0x3 << i, 0x3 << i); udelay(5); } for (i = 0; i < 32; i += 2) { regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x2 << i, 0x3 << i); + 0x3 << i, 0x3 << i); udelay(5); } for (i = 8; i < 16; i++) { @@ -108,13 +108,13 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) /* Power Up Memories */ for (i = 0; i < 32; i += 2) { regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, - 0x2 << i, 0); + 0x3 << i, 0); udelay(5); } for (i = 0; i < 32; i += 2) { regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, - 0x2 << i, 0); + 0x3 << i, 0); udelay(5); } From bb1dca3a3900a00b881286c96340d6ab85eafe0c Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 1 Apr 2019 09:52:58 +0200 Subject: [PATCH 42/57] soc: amlogic: meson-gx-pwrc-vpu: Add support for G12A The Amlogic G12A SoC has a very similar VPU Power Controller setup than the older GXBB, GXL & GXm SoCs. This patch adds the variant support for G12A. Signed-off-by: Neil Armstrong Signed-off-by: Kevin Hilman --- drivers/soc/amlogic/meson-gx-pwrc-vpu.c | 152 ++++++++++++++++++++++-- 1 file changed, 140 insertions(+), 12 deletions(-) diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c index 05421d029dff..511b6856225d 100644 --- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,7 @@ #define HHI_MEM_PD_REG0 (0x40 << 2) #define HHI_VPU_MEM_PD_REG0 (0x41 << 2) #define HHI_VPU_MEM_PD_REG1 (0x42 << 2) +#define HHI_VPU_MEM_PD_REG2 (0x4d << 2) struct meson_gx_pwrc_vpu { struct generic_pm_domain genpd; @@ -80,6 +82,49 @@ static int meson_gx_pwrc_vpu_power_off(struct generic_pm_domain *genpd) return 0; } +static int meson_g12a_pwrc_vpu_power_off(struct generic_pm_domain *genpd) +{ + struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); + int i; + + regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI_ISO, GEN_PWR_VPU_HDMI_ISO); + udelay(20); + + /* Power Down Memories */ + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, + 0x3 << i, 0x3 << i); + udelay(5); + } + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, + 0x3 << i, 0x3 << i); + udelay(5); + } + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, + 0x3 << i, 0x3 << i); + udelay(5); + } + for (i = 8; i < 16; i++) { + regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, + BIT(i), BIT(i)); + udelay(5); + } + udelay(20); + + regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI, GEN_PWR_VPU_HDMI); + + msleep(20); + + clk_disable_unprepare(pd->vpu_clk); + clk_disable_unprepare(pd->vapb_clk); + + return 0; +} + static int meson_gx_pwrc_vpu_setup_clk(struct meson_gx_pwrc_vpu *pd) { int ret; @@ -143,6 +188,60 @@ static int meson_gx_pwrc_vpu_power_on(struct generic_pm_domain *genpd) return 0; } +static int meson_g12a_pwrc_vpu_power_on(struct generic_pm_domain *genpd) +{ + struct meson_gx_pwrc_vpu *pd = genpd_to_pd(genpd); + int ret; + int i; + + regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI, 0); + udelay(20); + + /* Power Up Memories */ + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG0, + 0x3 << i, 0); + udelay(5); + } + + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG1, + 0x3 << i, 0); + udelay(5); + } + + for (i = 0; i < 32; i += 2) { + regmap_update_bits(pd->regmap_hhi, HHI_VPU_MEM_PD_REG2, + 0x3 << i, 0); + udelay(5); + } + + for (i = 8; i < 16; i++) { + regmap_update_bits(pd->regmap_hhi, HHI_MEM_PD_REG0, + BIT(i), 0); + udelay(5); + } + udelay(20); + + ret = reset_control_assert(pd->rstc); + if (ret) + return ret; + + regmap_update_bits(pd->regmap_ao, AO_RTI_GEN_PWR_SLEEP0, + GEN_PWR_VPU_HDMI_ISO, 0); + + ret = reset_control_deassert(pd->rstc); + if (ret) + return ret; + + ret = meson_gx_pwrc_vpu_setup_clk(pd); + if (ret) + return ret; + + return 0; +} + static bool meson_gx_pwrc_vpu_get_power(struct meson_gx_pwrc_vpu *pd) { u32 reg; @@ -160,15 +259,37 @@ static struct meson_gx_pwrc_vpu vpu_hdmi_pd = { }, }; +static struct meson_gx_pwrc_vpu vpu_hdmi_pd_g12a = { + .genpd = { + .name = "vpu_hdmi", + .power_off = meson_g12a_pwrc_vpu_power_off, + .power_on = meson_g12a_pwrc_vpu_power_on, + }, +}; + static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) { + const struct meson_gx_pwrc_vpu *vpu_pd_match; struct regmap *regmap_ao, *regmap_hhi; + struct meson_gx_pwrc_vpu *vpu_pd; struct reset_control *rstc; struct clk *vpu_clk; struct clk *vapb_clk; bool powered_off; int ret; + vpu_pd_match = of_device_get_match_data(&pdev->dev); + if (!vpu_pd_match) { + dev_err(&pdev->dev, "failed to get match data\n"); + return -ENODEV; + } + + vpu_pd = devm_kzalloc(&pdev->dev, sizeof(*vpu_pd), GFP_KERNEL); + if (!vpu_pd) + return -ENOMEM; + + memcpy(vpu_pd, vpu_pd_match, sizeof(*vpu_pd)); + regmap_ao = syscon_node_to_regmap(of_get_parent(pdev->dev.of_node)); if (IS_ERR(regmap_ao)) { dev_err(&pdev->dev, "failed to get regmap\n"); @@ -201,39 +322,46 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) return PTR_ERR(vapb_clk); } - vpu_hdmi_pd.regmap_ao = regmap_ao; - vpu_hdmi_pd.regmap_hhi = regmap_hhi; - vpu_hdmi_pd.rstc = rstc; - vpu_hdmi_pd.vpu_clk = vpu_clk; - vpu_hdmi_pd.vapb_clk = vapb_clk; + vpu_pd->regmap_ao = regmap_ao; + vpu_pd->regmap_hhi = regmap_hhi; + vpu_pd->rstc = rstc; + vpu_pd->vpu_clk = vpu_clk; + vpu_pd->vapb_clk = vapb_clk; - powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); + platform_set_drvdata(pdev, vpu_pd); + + powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); /* If already powered, sync the clock states */ if (!powered_off) { - ret = meson_gx_pwrc_vpu_setup_clk(&vpu_hdmi_pd); + ret = meson_gx_pwrc_vpu_setup_clk(vpu_pd); if (ret) return ret; } - pm_genpd_init(&vpu_hdmi_pd.genpd, &pm_domain_always_on_gov, + pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov, powered_off); return of_genpd_add_provider_simple(pdev->dev.of_node, - &vpu_hdmi_pd.genpd); + &vpu_pd->genpd); } static void meson_gx_pwrc_vpu_shutdown(struct platform_device *pdev) { + struct meson_gx_pwrc_vpu *vpu_pd = platform_get_drvdata(pdev); bool powered_off; - powered_off = meson_gx_pwrc_vpu_get_power(&vpu_hdmi_pd); + powered_off = meson_gx_pwrc_vpu_get_power(vpu_pd); if (!powered_off) - meson_gx_pwrc_vpu_power_off(&vpu_hdmi_pd.genpd); + vpu_pd->genpd.power_off(&vpu_pd->genpd); } static const struct of_device_id meson_gx_pwrc_vpu_match_table[] = { - { .compatible = "amlogic,meson-gx-pwrc-vpu" }, + { .compatible = "amlogic,meson-gx-pwrc-vpu", .data = &vpu_hdmi_pd }, + { + .compatible = "amlogic,meson-g12a-pwrc-vpu", + .data = &vpu_hdmi_pd_g12a + }, { /* sentinel */ } }; From 00cdaa1b811f36afa52a5956350c263ded4944a6 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 16 Apr 2019 17:48:06 +0100 Subject: [PATCH 43/57] soc/tegra: pmc: Fix reset sources and levels Commit 5f84bb1a4099 ("soc/tegra: pmc: Add sysfs entries for reset info") added support for reading the Tegra reset source and level from sysfs. However, there are a few issues with this commit which are ... 1. The number of reset sources for Tegra210 is defined as 5 but it should be 6. 2. The number of reset sources for Tegra186 is defined as 13 but it should be 15. 3. The SoC data variables num_reset_sources and num_reset_levels are defined but never used. Fix the above by ... 1. Removing the reset source 'AOTAG' from the tegra30_reset_sources because this is only applicable for Tegra210. 2. Adding a new tegra210_reset_sources structure for Tegra210 reset sources. 3. Correct the number of reset sources for Tegra210 and Tegra186 by using the ARRAY_SIZE macro. 4. Updating the functions reset_reason_show() and reset_level_show() to check whether the value read is valid. While we are at it clean-up these functions to remove an unnecessary u32 variable. Fixes: 5f84bb1a4099 ("soc/tegra: pmc: Add sysfs entries for reset info") Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 44 +++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 0c5f79528e5f..7953aa7b11df 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -268,6 +268,14 @@ static const char * const tegra186_reset_levels[] = { }; static const char * const tegra30_reset_sources[] = { + "POWER_ON_RESET", + "WATCHDOG", + "SENSOR", + "SW_MAIN", + "LP0" +}; + +static const char * const tegra210_reset_sources[] = { "POWER_ON_RESET", "WATCHDOG", "SENSOR", @@ -1736,13 +1744,16 @@ static int tegra_pmc_pinctrl_init(struct tegra_pmc *pmc) static ssize_t reset_reason_show(struct device *dev, struct device_attribute *attr, char *buf) { - u32 value, rst_src; + u32 value; value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); - rst_src = (value & pmc->soc->regs->rst_source_mask) >> - pmc->soc->regs->rst_source_shift; + value &= pmc->soc->regs->rst_source_mask; + value >>= pmc->soc->regs->rst_source_shift; - return sprintf(buf, "%s\n", pmc->soc->reset_sources[rst_src]); + if (WARN_ON(value >= pmc->soc->num_reset_sources)) + return sprintf(buf, "%s\n", "UNKNOWN"); + + return sprintf(buf, "%s\n", pmc->soc->reset_sources[value]); } static DEVICE_ATTR_RO(reset_reason); @@ -1750,13 +1761,16 @@ 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; + u32 value; value = tegra_pmc_readl(pmc, pmc->soc->regs->rst_status); - rst_lvl = (value & pmc->soc->regs->rst_level_mask) >> - pmc->soc->regs->rst_level_shift; + value &= pmc->soc->regs->rst_level_mask; + value >>= pmc->soc->regs->rst_level_shift; - return sprintf(buf, "%s\n", pmc->soc->reset_levels[rst_lvl]); + if (WARN_ON(value >= pmc->soc->num_reset_levels)) + return sprintf(buf, "%s\n", "UNKNOWN"); + + return sprintf(buf, "%s\n", pmc->soc->reset_levels[value]); } static DEVICE_ATTR_RO(reset_level); @@ -2212,7 +2226,7 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = { .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .reset_sources = tegra30_reset_sources, - .num_reset_sources = 5, + .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, .num_reset_levels = 0, }; @@ -2263,7 +2277,7 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = { .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .reset_sources = tegra30_reset_sources, - .num_reset_sources = 5, + .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, .num_reset_levels = 0, }; @@ -2374,7 +2388,7 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .init = tegra20_pmc_init, .setup_irq_polarity = tegra20_pmc_setup_irq_polarity, .reset_sources = tegra30_reset_sources, - .num_reset_sources = 5, + .num_reset_sources = ARRAY_SIZE(tegra30_reset_sources), .reset_levels = NULL, .num_reset_levels = 0, }; @@ -2479,8 +2493,8 @@ 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_sources = tegra210_reset_sources, + .num_reset_sources = ARRAY_SIZE(tegra210_reset_sources), .reset_levels = NULL, .num_reset_levels = 0, }; @@ -2605,9 +2619,9 @@ static const struct tegra_pmc_soc tegra186_pmc_soc = { .init = NULL, .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, .reset_sources = tegra186_reset_sources, - .num_reset_sources = 14, + .num_reset_sources = ARRAY_SIZE(tegra186_reset_sources), .reset_levels = tegra186_reset_levels, - .num_reset_levels = 3, + .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), .num_wake_events = ARRAY_SIZE(tegra186_wake_events), .wake_events = tegra186_wake_events, }; From a46b51cd2a57d52d5047e1d48240536243eeab34 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 16 Apr 2019 17:48:07 +0100 Subject: [PATCH 44/57] soc/tegra: pmc: Remove reset sysfs entries on error Commit 5f84bb1a4099 ("soc/tegra: pmc: Add sysfs entries for reset info") added sysfs entries for Tegra reset source and level. However, these sysfs are not removed on error and so if the registering of PMC device is probe deferred, then the next time we attempt to probe the PMC device warnings such as the following will be displayed on boot ... sysfs: cannot create duplicate filename '/devices/platform/7000e400.pmc/reset_reason' Fix this by calling device_remove_file() for each sysfs entry added on failure. Note that we call device_remove_file() unconditionally without checking if the sysfs entry was created in the first place, but this should be OK because kernfs_remove_by_name_ns() will fail silently. Fixes: 5f84bb1a4099 ("soc/tegra: pmc: Add sysfs entries for reset info") Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 7953aa7b11df..741afb141887 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -2040,7 +2040,7 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_powergate_debugfs_init(); if (err < 0) - return err; + goto cleanup_sysfs; } err = register_restart_handler(&tegra_pmc_restart_handler); @@ -2071,6 +2071,9 @@ cleanup_restart_handler: unregister_restart_handler(&tegra_pmc_restart_handler); cleanup_debugfs: debugfs_remove(pmc->debugfs); +cleanup_sysfs: + device_remove_file(&pdev->dev, &dev_attr_reset_reason); + device_remove_file(&pdev->dev, &dev_attr_reset_level); return err; } From 6ac2a01de1700c1b6d889f02f61c4c9602573a8d Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 16 Apr 2019 17:48:08 +0100 Subject: [PATCH 45/57] soc/tegra: pmc: Move powergate initialisation to probe Commit 8df127456f29 ("soc/tegra: pmc: Enable XUSB partitions on boot") was added as a workaround to ensure that the XUSB powergates or domains were turned on early during boot because as this time the Tegra XHCI driver did not handle the power domains at all. Now that the Tegra XHCI driver has been updated to properly managed the power domains, the workaround to enable the XUSB power domain early has been removed. This also means that we can now move the initialisation of the powergates into the PMC driver probe. Therefore, move the powergate initialisation into the PMC driver probe and return any errors detected. To handle any errors, functions to cleanup and remove any power-domains registered with the generic power-domain framework have been added. Finally the initialisation of the 'powergates_available' bitmask is kept in the PMC early init function to allow the legacy PMC powergate APIs to be called during early boot for enabling secondary CPUs on 32-bit Tegra devices. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 83 +++++++++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 15 deletions(-) diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 741afb141887..5648e5c09ef5 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -990,20 +990,21 @@ out: return err; } -static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) +static int tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) { struct device *dev = pmc->dev; struct tegra_powergate *pg; - int id, err; + int id, err = 0; bool off; pg = kzalloc(sizeof(*pg), GFP_KERNEL); if (!pg) - return; + return -ENOMEM; id = tegra_powergate_lookup(pmc, np->name); if (id < 0) { dev_err(dev, "powergate lookup failed for %pOFn: %d\n", np, id); + err = -ENODEV; goto free_mem; } @@ -1056,7 +1057,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) dev_dbg(dev, "added PM domain %s\n", pg->genpd.name); - return; + return 0; remove_genpd: pm_genpd_remove(&pg->genpd); @@ -1075,25 +1076,67 @@ set_available: free_mem: kfree(pg); + + return err; } -static void tegra_powergate_init(struct tegra_pmc *pmc, - struct device_node *parent) +static int tegra_powergate_init(struct tegra_pmc *pmc, + struct device_node *parent) { struct device_node *np, *child; - unsigned int i; + int err = 0; - /* Create a bitmap of the available and valid partitions */ - for (i = 0; i < pmc->soc->num_powergates; i++) - if (pmc->soc->powergates[i]) - set_bit(i, pmc->powergates_available); + np = of_get_child_by_name(parent, "powergates"); + if (!np) + return 0; + + for_each_child_of_node(np, child) { + err = tegra_powergate_add(pmc, child); + if (err < 0) { + of_node_put(child); + break; + } + } + + of_node_put(np); + + return err; +} + +static void tegra_powergate_remove(struct generic_pm_domain *genpd) +{ + struct tegra_powergate *pg = to_powergate(genpd); + + reset_control_put(pg->reset); + + while (pg->num_clks--) + clk_put(pg->clks[pg->num_clks]); + + kfree(pg->clks); + + set_bit(pg->id, pmc->powergates_available); + + kfree(pg); +} + +static void tegra_powergate_remove_all(struct device_node *parent) +{ + struct generic_pm_domain *genpd; + struct device_node *np, *child; np = of_get_child_by_name(parent, "powergates"); if (!np) return; - for_each_child_of_node(np, child) - tegra_powergate_add(pmc, child); + for_each_child_of_node(np, child) { + of_genpd_del_provider(child); + + genpd = of_genpd_remove_last(child); + if (IS_ERR(genpd)) + continue; + + tegra_powergate_remove(genpd); + } of_node_put(np); } @@ -2054,9 +2097,13 @@ static int tegra_pmc_probe(struct platform_device *pdev) if (err) goto cleanup_restart_handler; + err = tegra_powergate_init(pmc, pdev->dev.of_node); + if (err < 0) + goto cleanup_powergates; + err = tegra_pmc_irq_init(pmc); if (err < 0) - goto cleanup_restart_handler; + goto cleanup_powergates; mutex_lock(&pmc->powergates_lock); iounmap(pmc->base); @@ -2067,6 +2114,8 @@ static int tegra_pmc_probe(struct platform_device *pdev) return 0; +cleanup_powergates: + tegra_powergate_remove_all(pdev->dev.of_node); cleanup_restart_handler: unregister_restart_handler(&tegra_pmc_restart_handler); cleanup_debugfs: @@ -2763,6 +2812,7 @@ static int __init tegra_pmc_early_init(void) const struct of_device_id *match; struct device_node *np; struct resource regs; + unsigned int i; bool invert; mutex_init(&pmc->powergates_lock); @@ -2819,7 +2869,10 @@ static int __init tegra_pmc_early_init(void) if (pmc->soc->maybe_tz_only) pmc->tz_only = tegra_pmc_detect_tz_only(pmc); - tegra_powergate_init(pmc, np); + /* Create a bitmap of the available and valid partitions */ + for (i = 0; i < pmc->soc->num_powergates; i++) + if (pmc->soc->powergates[i]) + set_bit(i, pmc->powergates_available); /* * Invert the interrupt polarity if a PMC device tree node From 9733b072a12a422e2bf17bc7ba8b39769853d4a2 Mon Sep 17 00:00:00 2001 From: Volodymyr Babchuk Date: Fri, 7 Sep 2018 21:37:07 +0300 Subject: [PATCH 46/57] optee: allow to work without static shared memory On virtualized systems it is possible that OP-TEE will provide only dynamic shared memory support. So it is fine to boot without static SHM enabled if dymanic one is supported. Signed-off-by: Volodymyr Babchuk Signed-off-by: Jens Wiklander --- drivers/tee/optee/core.c | 78 ++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index 947f9b28de9e..fdce6293e03d 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -419,9 +419,35 @@ static bool optee_msg_exchange_capabilities(optee_invoke_fn *invoke_fn, return true; } +static struct tee_shm_pool *optee_config_dyn_shm(void) +{ + struct tee_shm_pool_mgr *priv_mgr; + struct tee_shm_pool_mgr *dmabuf_mgr; + void *rc; + + rc = optee_shm_pool_alloc_pages(); + if (IS_ERR(rc)) + return rc; + priv_mgr = rc; + + rc = optee_shm_pool_alloc_pages(); + if (IS_ERR(rc)) { + tee_shm_pool_mgr_destroy(priv_mgr); + return rc; + } + dmabuf_mgr = rc; + + rc = tee_shm_pool_alloc(priv_mgr, dmabuf_mgr); + if (IS_ERR(rc)) { + tee_shm_pool_mgr_destroy(priv_mgr); + tee_shm_pool_mgr_destroy(dmabuf_mgr); + } + + return rc; +} + static struct tee_shm_pool * -optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm, - u32 sec_caps) +optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm) { union { struct arm_smccc_res smccc; @@ -436,10 +462,11 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm, struct tee_shm_pool_mgr *priv_mgr; struct tee_shm_pool_mgr *dmabuf_mgr; void *rc; + const int sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc); if (res.result.status != OPTEE_SMC_RETURN_OK) { - pr_info("shm service not available\n"); + pr_err("static shm service not available\n"); return ERR_PTR(-ENOENT); } @@ -465,28 +492,15 @@ optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm, } vaddr = (unsigned long)va; - /* - * If OP-TEE can work with unregistered SHM, we will use own pool - * for private shm - */ - if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) { - rc = optee_shm_pool_alloc_pages(); - if (IS_ERR(rc)) - goto err_memunmap; - priv_mgr = rc; - } else { - const size_t sz = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE; + rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz, + 3 /* 8 bytes aligned */); + if (IS_ERR(rc)) + goto err_memunmap; + priv_mgr = rc; - rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, sz, - 3 /* 8 bytes aligned */); - if (IS_ERR(rc)) - goto err_memunmap; - priv_mgr = rc; - - vaddr += sz; - paddr += sz; - size -= sz; - } + vaddr += sz; + paddr += sz; + size -= sz; rc = tee_shm_pool_mgr_alloc_res_mem(vaddr, paddr, size, PAGE_SHIFT); if (IS_ERR(rc)) @@ -552,7 +566,7 @@ static optee_invoke_fn *get_invoke_func(struct device_node *np) static struct optee *optee_probe(struct device_node *np) { optee_invoke_fn *invoke_fn; - struct tee_shm_pool *pool; + struct tee_shm_pool *pool = ERR_PTR(-EINVAL); struct optee *optee = NULL; void *memremaped_shm = NULL; struct tee_device *teedev; @@ -581,13 +595,17 @@ static struct optee *optee_probe(struct device_node *np) } /* - * We have no other option for shared memory, if secure world - * doesn't have any reserved memory we can use we can't continue. + * Try to use dynamic shared memory if possible */ - if (!(sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) - return ERR_PTR(-EINVAL); + if (sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) + pool = optee_config_dyn_shm(); + + /* + * If dynamic shared memory is not available or failed - try static one + */ + if (IS_ERR(pool) && (sec_caps & OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM)) + pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm); - pool = optee_config_shm_memremap(invoke_fn, &memremaped_shm, sec_caps); if (IS_ERR(pool)) return (void *)pool; From 36841ba2796324507452f9854bf08b2c65836cce Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Sun, 24 Feb 2019 18:21:14 +0300 Subject: [PATCH 47/57] ARM: tegra: cpuidle: Handle tick broadcasting within cpuidle core on Tegra20/30 Tegra20/30 drivers do not handle the tick_broadcast_enter() error which potentially could happen when CPU timer isn't permitted to be stopped. Let's just move out the broadcasting to the CPUIDLE core by setting the respective flag in the Tegra20/30 drivers. This patch doesn't fix any problem because currently tick_broadcast_enter() could fail only on ARM64, so consider this change as a minor cleanup. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/cpuidle-tegra20.c | 11 ++--------- arch/arm/mach-tegra/cpuidle-tegra30.c | 9 +-------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c index 3f24addd7972..6620d61b5ec5 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra20.c +++ b/arch/arm/mach-tegra/cpuidle-tegra20.c @@ -61,7 +61,8 @@ static struct cpuidle_driver tegra_idle_driver = { .exit_latency = 5000, .target_residency = 10000, .power_usage = 0, - .flags = CPUIDLE_FLAG_COUPLED, + .flags = CPUIDLE_FLAG_COUPLED | + CPUIDLE_FLAG_TIMER_STOP, .name = "powered-down", .desc = "CPU power gated", }, @@ -136,12 +137,8 @@ static bool tegra20_cpu_cluster_power_down(struct cpuidle_device *dev, if (tegra20_reset_cpu_1() || !tegra_cpu_rail_off_ready()) return false; - tick_broadcast_enter(); - tegra_idle_lp2_last(); - tick_broadcast_exit(); - if (cpu_online(1)) tegra20_wake_cpu1_from_reset(); @@ -153,14 +150,10 @@ static bool tegra20_idle_enter_lp2_cpu_1(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - tick_broadcast_enter(); - cpu_suspend(0, tegra20_sleep_cpu_secondary_finish); tegra20_cpu_clear_resettable(); - tick_broadcast_exit(); - return true; } #else diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c index c1417361e10e..c8fe0447e3a9 100644 --- a/arch/arm/mach-tegra/cpuidle-tegra30.c +++ b/arch/arm/mach-tegra/cpuidle-tegra30.c @@ -56,6 +56,7 @@ static struct cpuidle_driver tegra_idle_driver = { .exit_latency = 2000, .target_residency = 2200, .power_usage = 0, + .flags = CPUIDLE_FLAG_TIMER_STOP, .name = "powered-down", .desc = "CPU power gated", }, @@ -76,12 +77,8 @@ static bool tegra30_cpu_cluster_power_down(struct cpuidle_device *dev, return false; } - tick_broadcast_enter(); - tegra_idle_lp2_last(); - tick_broadcast_exit(); - return true; } @@ -90,14 +87,10 @@ static bool tegra30_cpu_core_power_down(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) { - tick_broadcast_enter(); - smp_wmb(); cpu_suspend(0, tegra30_sleep_cpu_secondary_finish); - tick_broadcast_exit(); - return true; } #else From 76b959a44c0b9c60cd41627cecb022c78042ad74 Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 12 Apr 2019 01:12:47 +0300 Subject: [PATCH 48/57] memory: tegra: Fix missed registers values latching Some of Memory Controller registers are shadowed and require latching in order to copy assembly state into the active, MC_EMEM_ARB_CFG is one of these registers. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/memory/tegra/mc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index a08b61a86760..1735e23dbc28 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -51,6 +51,9 @@ #define MC_EMEM_ADR_CFG 0x54 #define MC_EMEM_ADR_CFG_EMEM_NUMDEV BIT(0) +#define MC_TIMING_CONTROL 0xfc +#define MC_TIMING_UPDATE BIT(0) + static const struct of_device_id tegra_mc_of_match[] = { #ifdef CONFIG_ARCH_TEGRA_2x_SOC { .compatible = "nvidia,tegra20-mc-gart", .data = &tegra20_mc_soc }, @@ -301,6 +304,9 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) writel(value, mc->regs + la->reg); } + /* latch new values */ + writel(MC_TIMING_UPDATE, mc->regs + MC_TIMING_CONTROL); + return 0; } From b906c056b6023c390f18347169071193fda57dde Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 12 Apr 2019 01:12:48 +0300 Subject: [PATCH 49/57] memory: tegra: Fix integer overflow on tick value calculation Multiplying the Memory Controller clock rate by the tick count results in an integer overflow and in result the truncated tick value is being programmed into hardware, such that the GR3D memory client performance is reduced by two times. Cc: stable Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/memory/tegra/mc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 1735e23dbc28..483ac3c1a762 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -285,7 +285,7 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) u32 value; /* compute the number of MC clock cycles per tick */ - tick = mc->tick * clk_get_rate(mc->clk); + tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); do_div(tick, NSEC_PER_SEC); value = readl(mc->regs + MC_EMEM_ARB_CFG); From 48791f972234301a72e4c40745d0abafa0985d2d Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 12 Apr 2019 01:12:49 +0300 Subject: [PATCH 50/57] memory: tegra: Replace readl-writel with mc_readl-mc_writel There is no need for a memory barriers on reading/writing of register values as we only care about the read/write order, hence let's use the common helpers. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/memory/tegra/mc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index 483ac3c1a762..163b6c69e651 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -288,24 +288,24 @@ static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc) tick = (unsigned long long)mc->tick * clk_get_rate(mc->clk); do_div(tick, NSEC_PER_SEC); - value = readl(mc->regs + MC_EMEM_ARB_CFG); + value = mc_readl(mc, MC_EMEM_ARB_CFG); value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK; value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick); - writel(value, mc->regs + MC_EMEM_ARB_CFG); + mc_writel(mc, value, MC_EMEM_ARB_CFG); /* write latency allowance defaults */ for (i = 0; i < mc->soc->num_clients; i++) { const struct tegra_mc_la *la = &mc->soc->clients[i].la; u32 value; - value = readl(mc->regs + la->reg); + value = mc_readl(mc, la->reg); value &= ~(la->mask << la->shift); value |= (la->def & la->mask) << la->shift; - writel(value, mc->regs + la->reg); + mc_writel(mc, value, la->reg); } /* latch new values */ - writel(MC_TIMING_UPDATE, mc->regs + MC_TIMING_CONTROL); + mc_writel(mc, MC_TIMING_UPDATE, MC_TIMING_CONTROL); return 0; } From a359de1b4055b2e9c0e8d650b099fcb5ceca25fe Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Fri, 12 Apr 2019 01:12:50 +0300 Subject: [PATCH 51/57] Revert "ARM: tegra: Restore memory arbitration on resume from LP1 on Tegra30+" Turned out that the actual bug was in the Memory Controller driver that programmed shadowed registers without latching the new values and then there was a bug on EMEM arbitration configuration calculation that results in a wrong value being latched on resume from suspend. The Memory Controller has been fixed properly now, hence the workaround patch could be reverted safely. Signed-off-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- arch/arm/mach-tegra/iomap.h | 9 --------- arch/arm/mach-tegra/sleep-tegra30.S | 21 --------------------- 2 files changed, 30 deletions(-) diff --git a/arch/arm/mach-tegra/iomap.h b/arch/arm/mach-tegra/iomap.h index 9bc291e76887..9e5b2f869fc8 100644 --- a/arch/arm/mach-tegra/iomap.h +++ b/arch/arm/mach-tegra/iomap.h @@ -79,24 +79,15 @@ #define TEGRA_PMC_BASE 0x7000E400 #define TEGRA_PMC_SIZE SZ_256 -#define TEGRA_MC_BASE 0x7000F000 -#define TEGRA_MC_SIZE SZ_1K - #define TEGRA_EMC_BASE 0x7000F400 #define TEGRA_EMC_SIZE SZ_1K -#define TEGRA114_MC_BASE 0x70019000 -#define TEGRA114_MC_SIZE SZ_4K - #define TEGRA_EMC0_BASE 0x7001A000 #define TEGRA_EMC0_SIZE SZ_2K #define TEGRA_EMC1_BASE 0x7001A800 #define TEGRA_EMC1_SIZE SZ_2K -#define TEGRA124_MC_BASE 0x70019000 -#define TEGRA124_MC_SIZE SZ_4K - #define TEGRA124_EMC_BASE 0x7001B000 #define TEGRA124_EMC_SIZE SZ_2K diff --git a/arch/arm/mach-tegra/sleep-tegra30.S b/arch/arm/mach-tegra/sleep-tegra30.S index d0b4c486ddbf..7727e005c30e 100644 --- a/arch/arm/mach-tegra/sleep-tegra30.S +++ b/arch/arm/mach-tegra/sleep-tegra30.S @@ -44,8 +44,6 @@ #define EMC_XM2VTTGENPADCTRL 0x310 #define EMC_XM2VTTGENPADCTRL2 0x314 -#define MC_EMEM_ARB_CFG 0x90 - #define PMC_CTRL 0x0 #define PMC_CTRL_SIDE_EFFECT_LP0 (1 << 14) /* enter LP0 when CPU pwr gated */ @@ -420,22 +418,6 @@ _pll_m_c_x_done: movweq r0, #:lower16:TEGRA124_EMC_BASE movteq r0, #:upper16:TEGRA124_EMC_BASE - cmp r10, #TEGRA30 - moveq r2, #0x20 - movweq r4, #:lower16:TEGRA_MC_BASE - movteq r4, #:upper16:TEGRA_MC_BASE - cmp r10, #TEGRA114 - moveq r2, #0x34 - movweq r4, #:lower16:TEGRA114_MC_BASE - movteq r4, #:upper16:TEGRA114_MC_BASE - cmp r10, #TEGRA124 - moveq r2, #0x20 - movweq r4, #:lower16:TEGRA124_MC_BASE - movteq r4, #:upper16:TEGRA124_MC_BASE - - ldr r1, [r5, r2] @ restore MC_EMEM_ARB_CFG - str r1, [r4, #MC_EMEM_ARB_CFG] - exit_self_refresh: ldr r1, [r5, #0xC] @ restore EMC_XM2VTTGENPADCTRL str r1, [r0, #EMC_XM2VTTGENPADCTRL] @@ -564,7 +546,6 @@ tegra30_sdram_pad_address: .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c - .word TEGRA_MC_BASE + MC_EMEM_ARB_CFG @0x20 tegra30_sdram_pad_address_end: tegra114_sdram_pad_address: @@ -581,7 +562,6 @@ tegra114_sdram_pad_address: .word TEGRA_EMC1_BASE + EMC_AUTO_CAL_INTERVAL @0x28 .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL @0x2c .word TEGRA_EMC1_BASE + EMC_XM2VTTGENPADCTRL2 @0x30 - .word TEGRA114_MC_BASE + MC_EMEM_ARB_CFG @0x34 tegra114_sdram_pad_adress_end: tegra124_sdram_pad_address: @@ -593,7 +573,6 @@ tegra124_sdram_pad_address: .word TEGRA_PMC_BASE + PMC_IO_DPD_STATUS @0x14 .word TEGRA_CLK_RESET_BASE + CLK_RESET_CLK_SOURCE_MSELECT @0x18 .word TEGRA_CLK_RESET_BASE + CLK_RESET_SCLK_BURST @0x1c - .word TEGRA124_MC_BASE + MC_EMEM_ARB_CFG @0x20 tegra124_sdram_pad_address_end: tegra30_sdram_pad_size: From 67a8d5b0fadfd931f7e6a78e9ee7b2792a7114aa Mon Sep 17 00:00:00 2001 From: Edward Cragg Date: Fri, 8 Mar 2019 11:21:55 +0000 Subject: [PATCH 52/57] memory: tegra: Fix a typos for "fdcdwr2" mc client Fix typo for fdcwr2 to fdcdwr2 to match the TRM. Signed-off-by: Edward Cragg Signed-off-by: Kejia Hu Acked-by: Jon Hunter Reviewed-by: Dmitry Osipenko Signed-off-by: Thierry Reding --- drivers/memory/tegra/tegra114.c | 2 +- drivers/memory/tegra/tegra30.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c index 7247a46b71a8..62305fafd641 100644 --- a/drivers/memory/tegra/tegra114.c +++ b/drivers/memory/tegra/tegra114.c @@ -572,7 +572,7 @@ static const struct tegra_mc_client tegra114_mc_clients[] = { }, }, { .id = 0x34, - .name = "fdcwr2", + .name = "fdcdwr2", .swgroup = TEGRA_SWGROUP_NV, .smmu = { .reg = 0x22c, diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c index 68499ffdf0f4..c9af0f682ead 100644 --- a/drivers/memory/tegra/tegra30.c +++ b/drivers/memory/tegra/tegra30.c @@ -726,7 +726,7 @@ static const struct tegra_mc_client tegra30_mc_clients[] = { }, }, { .id = 0x34, - .name = "fdcwr2", + .name = "fdcdwr2", .swgroup = TEGRA_SWGROUP_NV2, .smmu = { .reg = 0x22c, From 2616b3deaf9c5db18f78689968d4c998bda8a983 Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Tue, 9 Apr 2019 23:56:44 -0500 Subject: [PATCH 53/57] MAINTAINERS: Update email for Qualcomm SoC maintainer This patch changes the email for Andy Gross to agross@kernel.org. Reviewed-by: Bjorn Andersson Signed-off-by: Andy Gross --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index e17ebf70b548..cf39fb06e1d7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1984,7 +1984,7 @@ W: http://www.armlinux.org.uk/ S: Maintained ARM/QUALCOMM SUPPORT -M: Andy Gross +M: Andy Gross M: David Brown L: linux-arm-msm@vger.kernel.org S: Maintained From a7e26f356ca12906a164d83c9e9f8527ee7da022 Mon Sep 17 00:00:00 2001 From: Abel Vesa Date: Fri, 22 Mar 2019 16:49:20 +0000 Subject: [PATCH 54/57] soc: imx: Add generic i.MX8 SoC driver Add generic i.MX8 SoC driver along with the i.MX8MQ SoC specific code. For now, only i.MX8MQ revision B1 is supported. For any other, i.MX8MQ revision it will print 'unknown'. Signed-off-by: Abel Vesa Reviewed-by: Leonard Crestez Signed-off-by: Shawn Guo --- drivers/soc/imx/Makefile | 1 + drivers/soc/imx/soc-imx8.c | 115 +++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 drivers/soc/imx/soc-imx8.c diff --git a/drivers/soc/imx/Makefile b/drivers/soc/imx/Makefile index 506a6f3c2b9b..d6b529e06d9a 100644 --- a/drivers/soc/imx/Makefile +++ b/drivers/soc/imx/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o obj-$(CONFIG_IMX_GPCV2_PM_DOMAINS) += gpcv2.o +obj-$(CONFIG_ARCH_MXC) += soc-imx8.o diff --git a/drivers/soc/imx/soc-imx8.c b/drivers/soc/imx/soc-imx8.c new file mode 100644 index 000000000000..fc6429f9170a --- /dev/null +++ b/drivers/soc/imx/soc-imx8.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 NXP. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define REV_B1 0x21 + +#define IMX8MQ_SW_INFO_B1 0x40 +#define IMX8MQ_SW_MAGIC_B1 0xff0055aa + +struct imx8_soc_data { + char *name; + u32 (*soc_revision)(void); +}; + +static u32 __init imx8mq_soc_revision(void) +{ + struct device_node *np; + void __iomem *ocotp_base; + u32 magic; + u32 rev = 0; + + np = of_find_compatible_node(NULL, NULL, "fsl,imx8mq-ocotp"); + if (!np) + goto out; + + ocotp_base = of_iomap(np, 0); + WARN_ON(!ocotp_base); + + magic = readl_relaxed(ocotp_base + IMX8MQ_SW_INFO_B1); + if (magic == IMX8MQ_SW_MAGIC_B1) + rev = REV_B1; + + iounmap(ocotp_base); + +out: + of_node_put(np); + return rev; +} + +static const struct imx8_soc_data imx8mq_soc_data = { + .name = "i.MX8MQ", + .soc_revision = imx8mq_soc_revision, +}; + +static const struct of_device_id imx8_soc_match[] = { + { .compatible = "fsl,imx8mq", .data = &imx8mq_soc_data, }, + { } +}; + +#define imx8_revision(soc_rev) \ + soc_rev ? \ + kasprintf(GFP_KERNEL, "%d.%d", (soc_rev >> 4) & 0xf, soc_rev & 0xf) : \ + "unknown" + +static int __init imx8_soc_init(void) +{ + struct soc_device_attribute *soc_dev_attr; + struct soc_device *soc_dev; + struct device_node *root; + const struct of_device_id *id; + u32 soc_rev = 0; + const struct imx8_soc_data *data; + int ret; + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENODEV; + + soc_dev_attr->family = "Freescale i.MX"; + + root = of_find_node_by_path("/"); + ret = of_property_read_string(root, "model", &soc_dev_attr->machine); + if (ret) + goto free_soc; + + id = of_match_node(imx8_soc_match, root); + if (!id) + goto free_soc; + + of_node_put(root); + + data = id->data; + if (data) { + soc_dev_attr->soc_id = data->name; + if (data->soc_revision) + soc_rev = data->soc_revision(); + } + + soc_dev_attr->revision = imx8_revision(soc_rev); + if (!soc_dev_attr->revision) + goto free_soc; + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) + goto free_rev; + + return 0; + +free_rev: + kfree(soc_dev_attr->revision); +free_soc: + kfree(soc_dev_attr); + of_node_put(root); + return -ENODEV; +} +device_initcall(imx8_soc_init); From ab7b7c715e9a3b74d4e2ee33e6cd5d1bde5332cc Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Mon, 29 Apr 2019 09:15:14 -0700 Subject: [PATCH 55/57] spi: zynqmp: Fix build break Missing include: drivers/spi/spi-zynqmp-gqspi.c:1025:13: error: implicit declaration of function 'zynqmp_pm_get_eemi_ops'; did you mean 'zynqmp_process_dma_irq'? [-Werror=implicit-function-declaration] Fixes: 3d0313786470a ('drivers: Defer probe if firmware is not ready') Cc: Rajan Vaja Cc: Jolly Shah Cc: Michal Simek Signed-off-by: Olof Johansson --- drivers/spi/spi-zynqmp-gqspi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index d07b6f940f9f..9850a0efe85a 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include From 524feb799408e5d45c6aa82763a9f52489d1e19f Mon Sep 17 00:00:00 2001 From: Patrick Venture Date: Mon, 22 Apr 2019 10:54:19 -0700 Subject: [PATCH 56/57] soc: add aspeed folder and misc drivers Create a SoC folder for the ASPEED parts and place the misc drivers currently present into this folder. These drivers are not generic part drivers, but rather only apply to the ASPEED SoCs. Signed-off-by: Patrick Venture Acked-by: Arnd Bergmann Signed-off-by: Olof Johansson --- drivers/misc/Kconfig | 16 ---------------- drivers/misc/Makefile | 2 -- drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + drivers/soc/aspeed/Kconfig | 19 +++++++++++++++++++ drivers/soc/aspeed/Makefile | 2 ++ .../{misc => soc/aspeed}/aspeed-lpc-ctrl.c | 0 .../{misc => soc/aspeed}/aspeed-lpc-snoop.c | 0 8 files changed, 23 insertions(+), 18 deletions(-) create mode 100644 drivers/soc/aspeed/Kconfig create mode 100644 drivers/soc/aspeed/Makefile rename drivers/{misc => soc/aspeed}/aspeed-lpc-ctrl.c (100%) rename drivers/{misc => soc/aspeed}/aspeed-lpc-snoop.c (100%) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 42ab8ec92a04..b80cb6af0cb4 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -496,22 +496,6 @@ config VEXPRESS_SYSCFG bus. System Configuration interface is one of the possible means of generating transactions on this bus. -config ASPEED_LPC_CTRL - depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON - tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control" - ---help--- - Control Aspeed ast2400/2500 HOST LPC to BMC mappings through - ioctl()s, the driver also provides a read/write interface to a BMC ram - region where the host LPC read/write region can be buffered. - -config ASPEED_LPC_SNOOP - tristate "Aspeed ast2500 HOST LPC snoop support" - depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON - help - Provides a driver to control the LPC snoop interface which - allows the BMC to listen on and save the data written by - the host to an arbitrary LPC I/O port. - config PCI_ENDPOINT_TEST depends on PCI select CRC32 diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index d5b7d3404dc7..b9affcdaa3d6 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -54,8 +54,6 @@ obj-$(CONFIG_GENWQE) += genwqe/ obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o obj-$(CONFIG_CXL_BASE) += cxl/ -obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o -obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o obj-$(CONFIG_PCI_ENDPOINT_TEST) += pci_endpoint_test.o obj-$(CONFIG_OCXL) += ocxl/ obj-y += cardreader/ diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig index c07b4a85253f..b750a88547c7 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -2,6 +2,7 @@ menu "SOC (System On Chip) specific Drivers" source "drivers/soc/actions/Kconfig" source "drivers/soc/amlogic/Kconfig" +source "drivers/soc/aspeed/Kconfig" source "drivers/soc/atmel/Kconfig" source "drivers/soc/bcm/Kconfig" source "drivers/soc/fsl/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile index 90b686e586c6..814128fe479f 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_ARCH_ACTIONS) += actions/ +obj-$(CONFIG_ARCH_ASPEED) += aspeed/ obj-$(CONFIG_ARCH_AT91) += atmel/ obj-y += bcm/ obj-$(CONFIG_ARCH_DOVE) += dove/ diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig new file mode 100644 index 000000000000..457282cd1da5 --- /dev/null +++ b/drivers/soc/aspeed/Kconfig @@ -0,0 +1,19 @@ +menu "Aspeed SoC drivers" + +config ASPEED_LPC_CTRL + depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON + tristate "Aspeed ast2400/2500 HOST LPC to BMC bridge control" + ---help--- + Control Aspeed ast2400/2500 HOST LPC to BMC mappings through + ioctl()s, the driver also provides a read/write interface to a BMC ram + region where the host LPC read/write region can be buffered. + +config ASPEED_LPC_SNOOP + tristate "Aspeed ast2500 HOST LPC snoop support" + depends on (ARCH_ASPEED || COMPILE_TEST) && REGMAP && MFD_SYSCON + help + Provides a driver to control the LPC snoop interface which + allows the BMC to listen on and save the data written by + the host to an arbitrary LPC I/O port. + + diff --git a/drivers/soc/aspeed/Makefile b/drivers/soc/aspeed/Makefile new file mode 100644 index 000000000000..cfaa9adc67b5 --- /dev/null +++ b/drivers/soc/aspeed/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_ASPEED_LPC_CTRL) += aspeed-lpc-ctrl.o +obj-$(CONFIG_ASPEED_LPC_SNOOP) += aspeed-lpc-snoop.o diff --git a/drivers/misc/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c similarity index 100% rename from drivers/misc/aspeed-lpc-ctrl.c rename to drivers/soc/aspeed/aspeed-lpc-ctrl.c diff --git a/drivers/misc/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c similarity index 100% rename from drivers/misc/aspeed-lpc-snoop.c rename to drivers/soc/aspeed/aspeed-lpc-snoop.c From 80d0c649244253d8cb3ba32d708c1431e7ac8fbf Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Mon, 29 Apr 2019 12:25:41 -0700 Subject: [PATCH 57/57] soc: aspeed: fix Kconfig Fixes build break: scripts/kconfig/conf --allnoconfig Kconfig drivers/soc/Kconfig:24: 'menu' in different file than 'menu' drivers/soc/aspeed/Kconfig:1: location of the 'menu' drivers/Kconfig:233: 'menu' in different file than 'menu' drivers/soc/aspeed/Kconfig:1: location of the 'menu' :34: syntax error Signed-off-by: Patrick Venture Signed-off-by: Olof Johansson --- drivers/soc/aspeed/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/aspeed/Kconfig b/drivers/soc/aspeed/Kconfig index 457282cd1da5..858b5e3f79c9 100644 --- a/drivers/soc/aspeed/Kconfig +++ b/drivers/soc/aspeed/Kconfig @@ -17,3 +17,4 @@ config ASPEED_LPC_SNOOP the host to an arbitrary LPC I/O port. +endmenu