18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2017 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk.h> 78c2ecf20Sopenharmony_ci#include <linux/err.h> 88c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/of_address.h> 138c2ecf20Sopenharmony_ci#include <linux/of_device.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/remoteproc.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define IMX7D_SRC_SCR 0x0C 198c2ecf20Sopenharmony_ci#define IMX7D_ENABLE_M4 BIT(3) 208c2ecf20Sopenharmony_ci#define IMX7D_SW_M4P_RST BIT(2) 218c2ecf20Sopenharmony_ci#define IMX7D_SW_M4C_RST BIT(1) 228c2ecf20Sopenharmony_ci#define IMX7D_SW_M4C_NON_SCLR_RST BIT(0) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define IMX7D_M4_RST_MASK (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ 258c2ecf20Sopenharmony_ci | IMX7D_SW_M4C_RST \ 268c2ecf20Sopenharmony_ci | IMX7D_SW_M4C_NON_SCLR_RST) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define IMX7D_M4_START (IMX7D_ENABLE_M4 | IMX7D_SW_M4P_RST \ 298c2ecf20Sopenharmony_ci | IMX7D_SW_M4C_RST) 308c2ecf20Sopenharmony_ci#define IMX7D_M4_STOP IMX7D_SW_M4C_NON_SCLR_RST 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* Address: 0x020D8000 */ 338c2ecf20Sopenharmony_ci#define IMX6SX_SRC_SCR 0x00 348c2ecf20Sopenharmony_ci#define IMX6SX_ENABLE_M4 BIT(22) 358c2ecf20Sopenharmony_ci#define IMX6SX_SW_M4P_RST BIT(12) 368c2ecf20Sopenharmony_ci#define IMX6SX_SW_M4C_NON_SCLR_RST BIT(4) 378c2ecf20Sopenharmony_ci#define IMX6SX_SW_M4C_RST BIT(3) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define IMX6SX_M4_START (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ 408c2ecf20Sopenharmony_ci | IMX6SX_SW_M4C_RST) 418c2ecf20Sopenharmony_ci#define IMX6SX_M4_STOP IMX6SX_SW_M4C_NON_SCLR_RST 428c2ecf20Sopenharmony_ci#define IMX6SX_M4_RST_MASK (IMX6SX_ENABLE_M4 | IMX6SX_SW_M4P_RST \ 438c2ecf20Sopenharmony_ci | IMX6SX_SW_M4C_NON_SCLR_RST \ 448c2ecf20Sopenharmony_ci | IMX6SX_SW_M4C_RST) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define IMX7D_RPROC_MEM_MAX 8 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/** 498c2ecf20Sopenharmony_ci * struct imx_rproc_mem - slim internal memory structure 508c2ecf20Sopenharmony_ci * @cpu_addr: MPU virtual address of the memory region 518c2ecf20Sopenharmony_ci * @sys_addr: Bus address used to access the memory region 528c2ecf20Sopenharmony_ci * @size: Size of the memory region 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_cistruct imx_rproc_mem { 558c2ecf20Sopenharmony_ci void __iomem *cpu_addr; 568c2ecf20Sopenharmony_ci phys_addr_t sys_addr; 578c2ecf20Sopenharmony_ci size_t size; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* att flags */ 618c2ecf20Sopenharmony_ci/* M4 own area. Can be mapped at probe */ 628c2ecf20Sopenharmony_ci#define ATT_OWN BIT(1) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* address translation table */ 658c2ecf20Sopenharmony_cistruct imx_rproc_att { 668c2ecf20Sopenharmony_ci u32 da; /* device address (From Cortex M4 view)*/ 678c2ecf20Sopenharmony_ci u32 sa; /* system bus address */ 688c2ecf20Sopenharmony_ci u32 size; /* size of reg range */ 698c2ecf20Sopenharmony_ci int flags; 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct imx_rproc_dcfg { 738c2ecf20Sopenharmony_ci u32 src_reg; 748c2ecf20Sopenharmony_ci u32 src_mask; 758c2ecf20Sopenharmony_ci u32 src_start; 768c2ecf20Sopenharmony_ci u32 src_stop; 778c2ecf20Sopenharmony_ci const struct imx_rproc_att *att; 788c2ecf20Sopenharmony_ci size_t att_size; 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistruct imx_rproc { 828c2ecf20Sopenharmony_ci struct device *dev; 838c2ecf20Sopenharmony_ci struct regmap *regmap; 848c2ecf20Sopenharmony_ci struct rproc *rproc; 858c2ecf20Sopenharmony_ci const struct imx_rproc_dcfg *dcfg; 868c2ecf20Sopenharmony_ci struct imx_rproc_mem mem[IMX7D_RPROC_MEM_MAX]; 878c2ecf20Sopenharmony_ci struct clk *clk; 888c2ecf20Sopenharmony_ci}; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic const struct imx_rproc_att imx_rproc_att_imx7d[] = { 918c2ecf20Sopenharmony_ci /* dev addr , sys addr , size , flags */ 928c2ecf20Sopenharmony_ci /* OCRAM_S (M4 Boot code) - alias */ 938c2ecf20Sopenharmony_ci { 0x00000000, 0x00180000, 0x00008000, 0 }, 948c2ecf20Sopenharmony_ci /* OCRAM_S (Code) */ 958c2ecf20Sopenharmony_ci { 0x00180000, 0x00180000, 0x00008000, ATT_OWN }, 968c2ecf20Sopenharmony_ci /* OCRAM (Code) - alias */ 978c2ecf20Sopenharmony_ci { 0x00900000, 0x00900000, 0x00020000, 0 }, 988c2ecf20Sopenharmony_ci /* OCRAM_EPDC (Code) - alias */ 998c2ecf20Sopenharmony_ci { 0x00920000, 0x00920000, 0x00020000, 0 }, 1008c2ecf20Sopenharmony_ci /* OCRAM_PXP (Code) - alias */ 1018c2ecf20Sopenharmony_ci { 0x00940000, 0x00940000, 0x00008000, 0 }, 1028c2ecf20Sopenharmony_ci /* TCML (Code) */ 1038c2ecf20Sopenharmony_ci { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, 1048c2ecf20Sopenharmony_ci /* DDR (Code) - alias, first part of DDR (Data) */ 1058c2ecf20Sopenharmony_ci { 0x10000000, 0x80000000, 0x0FFF0000, 0 }, 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* TCMU (Data) */ 1088c2ecf20Sopenharmony_ci { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, 1098c2ecf20Sopenharmony_ci /* OCRAM (Data) */ 1108c2ecf20Sopenharmony_ci { 0x20200000, 0x00900000, 0x00020000, 0 }, 1118c2ecf20Sopenharmony_ci /* OCRAM_EPDC (Data) */ 1128c2ecf20Sopenharmony_ci { 0x20220000, 0x00920000, 0x00020000, 0 }, 1138c2ecf20Sopenharmony_ci /* OCRAM_PXP (Data) */ 1148c2ecf20Sopenharmony_ci { 0x20240000, 0x00940000, 0x00008000, 0 }, 1158c2ecf20Sopenharmony_ci /* DDR (Data) */ 1168c2ecf20Sopenharmony_ci { 0x80000000, 0x80000000, 0x60000000, 0 }, 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct imx_rproc_att imx_rproc_att_imx6sx[] = { 1208c2ecf20Sopenharmony_ci /* dev addr , sys addr , size , flags */ 1218c2ecf20Sopenharmony_ci /* TCML (M4 Boot Code) - alias */ 1228c2ecf20Sopenharmony_ci { 0x00000000, 0x007F8000, 0x00008000, 0 }, 1238c2ecf20Sopenharmony_ci /* OCRAM_S (Code) */ 1248c2ecf20Sopenharmony_ci { 0x00180000, 0x008F8000, 0x00004000, 0 }, 1258c2ecf20Sopenharmony_ci /* OCRAM_S (Code) - alias */ 1268c2ecf20Sopenharmony_ci { 0x00180000, 0x008FC000, 0x00004000, 0 }, 1278c2ecf20Sopenharmony_ci /* TCML (Code) */ 1288c2ecf20Sopenharmony_ci { 0x1FFF8000, 0x007F8000, 0x00008000, ATT_OWN }, 1298c2ecf20Sopenharmony_ci /* DDR (Code) - alias, first part of DDR (Data) */ 1308c2ecf20Sopenharmony_ci { 0x10000000, 0x80000000, 0x0FFF8000, 0 }, 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* TCMU (Data) */ 1338c2ecf20Sopenharmony_ci { 0x20000000, 0x00800000, 0x00008000, ATT_OWN }, 1348c2ecf20Sopenharmony_ci /* OCRAM_S (Data) - alias? */ 1358c2ecf20Sopenharmony_ci { 0x208F8000, 0x008F8000, 0x00004000, 0 }, 1368c2ecf20Sopenharmony_ci /* DDR (Data) */ 1378c2ecf20Sopenharmony_ci { 0x80000000, 0x80000000, 0x60000000, 0 }, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct imx_rproc_dcfg imx_rproc_cfg_imx7d = { 1418c2ecf20Sopenharmony_ci .src_reg = IMX7D_SRC_SCR, 1428c2ecf20Sopenharmony_ci .src_mask = IMX7D_M4_RST_MASK, 1438c2ecf20Sopenharmony_ci .src_start = IMX7D_M4_START, 1448c2ecf20Sopenharmony_ci .src_stop = IMX7D_M4_STOP, 1458c2ecf20Sopenharmony_ci .att = imx_rproc_att_imx7d, 1468c2ecf20Sopenharmony_ci .att_size = ARRAY_SIZE(imx_rproc_att_imx7d), 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic const struct imx_rproc_dcfg imx_rproc_cfg_imx6sx = { 1508c2ecf20Sopenharmony_ci .src_reg = IMX6SX_SRC_SCR, 1518c2ecf20Sopenharmony_ci .src_mask = IMX6SX_M4_RST_MASK, 1528c2ecf20Sopenharmony_ci .src_start = IMX6SX_M4_START, 1538c2ecf20Sopenharmony_ci .src_stop = IMX6SX_M4_STOP, 1548c2ecf20Sopenharmony_ci .att = imx_rproc_att_imx6sx, 1558c2ecf20Sopenharmony_ci .att_size = ARRAY_SIZE(imx_rproc_att_imx6sx), 1568c2ecf20Sopenharmony_ci}; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic int imx_rproc_start(struct rproc *rproc) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct imx_rproc *priv = rproc->priv; 1618c2ecf20Sopenharmony_ci const struct imx_rproc_dcfg *dcfg = priv->dcfg; 1628c2ecf20Sopenharmony_ci struct device *dev = priv->dev; 1638c2ecf20Sopenharmony_ci int ret; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, dcfg->src_reg, 1668c2ecf20Sopenharmony_ci dcfg->src_mask, dcfg->src_start); 1678c2ecf20Sopenharmony_ci if (ret) 1688c2ecf20Sopenharmony_ci dev_err(dev, "Failed to enable M4!\n"); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci return ret; 1718c2ecf20Sopenharmony_ci} 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int imx_rproc_stop(struct rproc *rproc) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci struct imx_rproc *priv = rproc->priv; 1768c2ecf20Sopenharmony_ci const struct imx_rproc_dcfg *dcfg = priv->dcfg; 1778c2ecf20Sopenharmony_ci struct device *dev = priv->dev; 1788c2ecf20Sopenharmony_ci int ret; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci ret = regmap_update_bits(priv->regmap, dcfg->src_reg, 1818c2ecf20Sopenharmony_ci dcfg->src_mask, dcfg->src_stop); 1828c2ecf20Sopenharmony_ci if (ret) 1838c2ecf20Sopenharmony_ci dev_err(dev, "Failed to stop M4!\n"); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int imx_rproc_da_to_sys(struct imx_rproc *priv, u64 da, 1898c2ecf20Sopenharmony_ci size_t len, u64 *sys) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci const struct imx_rproc_dcfg *dcfg = priv->dcfg; 1928c2ecf20Sopenharmony_ci int i; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* parse address translation table */ 1958c2ecf20Sopenharmony_ci for (i = 0; i < dcfg->att_size; i++) { 1968c2ecf20Sopenharmony_ci const struct imx_rproc_att *att = &dcfg->att[i]; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (da >= att->da && da + len < att->da + att->size) { 1998c2ecf20Sopenharmony_ci unsigned int offset = da - att->da; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci *sys = att->sa + offset; 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci dev_warn(priv->dev, "Translation failed: da = 0x%llx len = 0x%zx\n", 2078c2ecf20Sopenharmony_ci da, len); 2088c2ecf20Sopenharmony_ci return -ENOENT; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void *imx_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct imx_rproc *priv = rproc->priv; 2148c2ecf20Sopenharmony_ci void *va = NULL; 2158c2ecf20Sopenharmony_ci u64 sys; 2168c2ecf20Sopenharmony_ci int i; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (len == 0) 2198c2ecf20Sopenharmony_ci return NULL; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* 2228c2ecf20Sopenharmony_ci * On device side we have many aliases, so we need to convert device 2238c2ecf20Sopenharmony_ci * address (M4) to system bus address first. 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci if (imx_rproc_da_to_sys(priv, da, len, &sys)) 2268c2ecf20Sopenharmony_ci return NULL; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci for (i = 0; i < IMX7D_RPROC_MEM_MAX; i++) { 2298c2ecf20Sopenharmony_ci if (sys >= priv->mem[i].sys_addr && sys + len < 2308c2ecf20Sopenharmony_ci priv->mem[i].sys_addr + priv->mem[i].size) { 2318c2ecf20Sopenharmony_ci unsigned int offset = sys - priv->mem[i].sys_addr; 2328c2ecf20Sopenharmony_ci /* __force to make sparse happy with type conversion */ 2338c2ecf20Sopenharmony_ci va = (__force void *)(priv->mem[i].cpu_addr + offset); 2348c2ecf20Sopenharmony_ci break; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%p\n", 2398c2ecf20Sopenharmony_ci da, len, va); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci return va; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic const struct rproc_ops imx_rproc_ops = { 2458c2ecf20Sopenharmony_ci .start = imx_rproc_start, 2468c2ecf20Sopenharmony_ci .stop = imx_rproc_stop, 2478c2ecf20Sopenharmony_ci .da_to_va = imx_rproc_da_to_va, 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int imx_rproc_addr_init(struct imx_rproc *priv, 2518c2ecf20Sopenharmony_ci struct platform_device *pdev) 2528c2ecf20Sopenharmony_ci{ 2538c2ecf20Sopenharmony_ci const struct imx_rproc_dcfg *dcfg = priv->dcfg; 2548c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2558c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 2568c2ecf20Sopenharmony_ci int a, b = 0, err, nph; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci /* remap required addresses */ 2598c2ecf20Sopenharmony_ci for (a = 0; a < dcfg->att_size; a++) { 2608c2ecf20Sopenharmony_ci const struct imx_rproc_att *att = &dcfg->att[a]; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!(att->flags & ATT_OWN)) 2638c2ecf20Sopenharmony_ci continue; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (b >= IMX7D_RPROC_MEM_MAX) 2668c2ecf20Sopenharmony_ci break; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci priv->mem[b].cpu_addr = devm_ioremap(&pdev->dev, 2698c2ecf20Sopenharmony_ci att->sa, att->size); 2708c2ecf20Sopenharmony_ci if (!priv->mem[b].cpu_addr) { 2718c2ecf20Sopenharmony_ci dev_err(dev, "devm_ioremap_resource failed\n"); 2728c2ecf20Sopenharmony_ci return -ENOMEM; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci priv->mem[b].sys_addr = att->sa; 2758c2ecf20Sopenharmony_ci priv->mem[b].size = att->size; 2768c2ecf20Sopenharmony_ci b++; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* memory-region is optional property */ 2808c2ecf20Sopenharmony_ci nph = of_count_phandle_with_args(np, "memory-region", NULL); 2818c2ecf20Sopenharmony_ci if (nph <= 0) 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* remap optional addresses */ 2858c2ecf20Sopenharmony_ci for (a = 0; a < nph; a++) { 2868c2ecf20Sopenharmony_ci struct device_node *node; 2878c2ecf20Sopenharmony_ci struct resource res; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci node = of_parse_phandle(np, "memory-region", a); 2908c2ecf20Sopenharmony_ci err = of_address_to_resource(node, 0, &res); 2918c2ecf20Sopenharmony_ci if (err) { 2928c2ecf20Sopenharmony_ci dev_err(dev, "unable to resolve memory region\n"); 2938c2ecf20Sopenharmony_ci return err; 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (b >= IMX7D_RPROC_MEM_MAX) 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci priv->mem[b].cpu_addr = devm_ioremap_resource(&pdev->dev, &res); 3008c2ecf20Sopenharmony_ci if (IS_ERR(priv->mem[b].cpu_addr)) { 3018c2ecf20Sopenharmony_ci dev_err(dev, "devm_ioremap_resource failed\n"); 3028c2ecf20Sopenharmony_ci err = PTR_ERR(priv->mem[b].cpu_addr); 3038c2ecf20Sopenharmony_ci return err; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci priv->mem[b].sys_addr = res.start; 3068c2ecf20Sopenharmony_ci priv->mem[b].size = resource_size(&res); 3078c2ecf20Sopenharmony_ci b++; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic int imx_rproc_probe(struct platform_device *pdev) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3168c2ecf20Sopenharmony_ci struct device_node *np = dev->of_node; 3178c2ecf20Sopenharmony_ci struct imx_rproc *priv; 3188c2ecf20Sopenharmony_ci struct rproc *rproc; 3198c2ecf20Sopenharmony_ci struct regmap_config config = { .name = "imx-rproc" }; 3208c2ecf20Sopenharmony_ci const struct imx_rproc_dcfg *dcfg; 3218c2ecf20Sopenharmony_ci struct regmap *regmap; 3228c2ecf20Sopenharmony_ci int ret; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci regmap = syscon_regmap_lookup_by_phandle(np, "syscon"); 3258c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) { 3268c2ecf20Sopenharmony_ci dev_err(dev, "failed to find syscon\n"); 3278c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci regmap_attach_dev(dev, regmap, &config); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* set some other name then imx */ 3328c2ecf20Sopenharmony_ci rproc = rproc_alloc(dev, "imx-rproc", &imx_rproc_ops, 3338c2ecf20Sopenharmony_ci NULL, sizeof(*priv)); 3348c2ecf20Sopenharmony_ci if (!rproc) 3358c2ecf20Sopenharmony_ci return -ENOMEM; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci dcfg = of_device_get_match_data(dev); 3388c2ecf20Sopenharmony_ci if (!dcfg) { 3398c2ecf20Sopenharmony_ci ret = -EINVAL; 3408c2ecf20Sopenharmony_ci goto err_put_rproc; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci priv = rproc->priv; 3448c2ecf20Sopenharmony_ci priv->rproc = rproc; 3458c2ecf20Sopenharmony_ci priv->regmap = regmap; 3468c2ecf20Sopenharmony_ci priv->dcfg = dcfg; 3478c2ecf20Sopenharmony_ci priv->dev = dev; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci dev_set_drvdata(dev, rproc); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci ret = imx_rproc_addr_init(priv, pdev); 3528c2ecf20Sopenharmony_ci if (ret) { 3538c2ecf20Sopenharmony_ci dev_err(dev, "failed on imx_rproc_addr_init\n"); 3548c2ecf20Sopenharmony_ci goto err_put_rproc; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci priv->clk = devm_clk_get(dev, NULL); 3588c2ecf20Sopenharmony_ci if (IS_ERR(priv->clk)) { 3598c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get clock\n"); 3608c2ecf20Sopenharmony_ci ret = PTR_ERR(priv->clk); 3618c2ecf20Sopenharmony_ci goto err_put_rproc; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * clk for M4 block including memory. Should be 3668c2ecf20Sopenharmony_ci * enabled before .start for FW transfer. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->clk); 3698c2ecf20Sopenharmony_ci if (ret) { 3708c2ecf20Sopenharmony_ci dev_err(&rproc->dev, "Failed to enable clock\n"); 3718c2ecf20Sopenharmony_ci goto err_put_rproc; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci ret = rproc_add(rproc); 3758c2ecf20Sopenharmony_ci if (ret) { 3768c2ecf20Sopenharmony_ci dev_err(dev, "rproc_add failed\n"); 3778c2ecf20Sopenharmony_ci goto err_put_clk; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cierr_put_clk: 3838c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 3848c2ecf20Sopenharmony_cierr_put_rproc: 3858c2ecf20Sopenharmony_ci rproc_free(rproc); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return ret; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int imx_rproc_remove(struct platform_device *pdev) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct rproc *rproc = platform_get_drvdata(pdev); 3938c2ecf20Sopenharmony_ci struct imx_rproc *priv = rproc->priv; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->clk); 3968c2ecf20Sopenharmony_ci rproc_del(rproc); 3978c2ecf20Sopenharmony_ci rproc_free(rproc); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic const struct of_device_id imx_rproc_of_match[] = { 4038c2ecf20Sopenharmony_ci { .compatible = "fsl,imx7d-cm4", .data = &imx_rproc_cfg_imx7d }, 4048c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6sx-cm4", .data = &imx_rproc_cfg_imx6sx }, 4058c2ecf20Sopenharmony_ci {}, 4068c2ecf20Sopenharmony_ci}; 4078c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, imx_rproc_of_match); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic struct platform_driver imx_rproc_driver = { 4108c2ecf20Sopenharmony_ci .probe = imx_rproc_probe, 4118c2ecf20Sopenharmony_ci .remove = imx_rproc_remove, 4128c2ecf20Sopenharmony_ci .driver = { 4138c2ecf20Sopenharmony_ci .name = "imx-rproc", 4148c2ecf20Sopenharmony_ci .of_match_table = imx_rproc_of_match, 4158c2ecf20Sopenharmony_ci }, 4168c2ecf20Sopenharmony_ci}; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cimodule_platform_driver(imx_rproc_driver); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IMX6SX/7D remote processor control driver"); 4228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Oleksij Rempel <o.rempel@pengutronix.de>"); 423