1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * SLIM core rproc driver 4 * 5 * Copyright (C) 2016 STMicroelectronics 6 * 7 * Author: Peter Griffin <peter.griffin@linaro.org> 8 */ 9 10 #include <linux/clk.h> 11 #include <linux/err.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/of.h> 15 #include <linux/platform_device.h> 16 #include <linux/remoteproc.h> 17 #include <linux/remoteproc/st_slim_rproc.h> 18 #include "remoteproc_internal.h" 19 20 /* SLIM core registers */ 21 #define SLIM_ID_OFST 0x0 22 #define SLIM_VER_OFST 0x4 23 24 #define SLIM_EN_OFST 0x8 25 #define SLIM_EN_RUN BIT(0) 26 27 #define SLIM_CLK_GATE_OFST 0xC 28 #define SLIM_CLK_GATE_DIS BIT(0) 29 #define SLIM_CLK_GATE_RESET BIT(2) 30 31 #define SLIM_SLIM_PC_OFST 0x20 32 33 /* DMEM registers */ 34 #define SLIM_REV_ID_OFST 0x0 35 #define SLIM_REV_ID_MIN_MASK GENMASK(15, 8) 36 #define SLIM_REV_ID_MIN(id) ((id & SLIM_REV_ID_MIN_MASK) >> 8) 37 #define SLIM_REV_ID_MAJ_MASK GENMASK(23, 16) 38 #define SLIM_REV_ID_MAJ(id) ((id & SLIM_REV_ID_MAJ_MASK) >> 16) 39 40 41 /* peripherals registers */ 42 #define SLIM_STBUS_SYNC_OFST 0xF88 43 #define SLIM_STBUS_SYNC_DIS BIT(0) 44 45 #define SLIM_INT_SET_OFST 0xFD4 46 #define SLIM_INT_CLR_OFST 0xFD8 47 #define SLIM_INT_MASK_OFST 0xFDC 48 49 #define SLIM_CMD_CLR_OFST 0xFC8 50 #define SLIM_CMD_MASK_OFST 0xFCC 51 52 static const char *mem_names[ST_SLIM_MEM_MAX] = { 53 [ST_SLIM_DMEM] = "dmem", 54 [ST_SLIM_IMEM] = "imem", 55 }; 56 57 static int slim_clk_get(struct st_slim_rproc *slim_rproc, struct device *dev) 58 { 59 int clk, err; 60 61 for (clk = 0; clk < ST_SLIM_MAX_CLK; clk++) { 62 slim_rproc->clks[clk] = of_clk_get(dev->of_node, clk); 63 if (IS_ERR(slim_rproc->clks[clk])) { 64 err = PTR_ERR(slim_rproc->clks[clk]); 65 if (err == -EPROBE_DEFER) 66 goto err_put_clks; 67 slim_rproc->clks[clk] = NULL; 68 break; 69 } 70 } 71 72 return 0; 73 74 err_put_clks: 75 while (--clk >= 0) 76 clk_put(slim_rproc->clks[clk]); 77 78 return err; 79 } 80 81 static void slim_clk_disable(struct st_slim_rproc *slim_rproc) 82 { 83 int clk; 84 85 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) 86 clk_disable_unprepare(slim_rproc->clks[clk]); 87 } 88 89 static int slim_clk_enable(struct st_slim_rproc *slim_rproc) 90 { 91 int clk, ret; 92 93 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) { 94 ret = clk_prepare_enable(slim_rproc->clks[clk]); 95 if (ret) 96 goto err_disable_clks; 97 } 98 99 return 0; 100 101 err_disable_clks: 102 while (--clk >= 0) 103 clk_disable_unprepare(slim_rproc->clks[clk]); 104 105 return ret; 106 } 107 108 /* 109 * Remoteproc slim specific device handlers 110 */ 111 static int slim_rproc_start(struct rproc *rproc) 112 { 113 struct device *dev = &rproc->dev; 114 struct st_slim_rproc *slim_rproc = rproc->priv; 115 unsigned long hw_id, hw_ver, fw_rev; 116 u32 val; 117 118 /* disable CPU pipeline clock & reset CPU pipeline */ 119 val = SLIM_CLK_GATE_DIS | SLIM_CLK_GATE_RESET; 120 writel(val, slim_rproc->slimcore + SLIM_CLK_GATE_OFST); 121 122 /* disable SLIM core STBus sync */ 123 writel(SLIM_STBUS_SYNC_DIS, slim_rproc->peri + SLIM_STBUS_SYNC_OFST); 124 125 /* enable cpu pipeline clock */ 126 writel(!SLIM_CLK_GATE_DIS, 127 slim_rproc->slimcore + SLIM_CLK_GATE_OFST); 128 129 /* clear int & cmd mailbox */ 130 writel(~0U, slim_rproc->peri + SLIM_INT_CLR_OFST); 131 writel(~0U, slim_rproc->peri + SLIM_CMD_CLR_OFST); 132 133 /* enable all channels cmd & int */ 134 writel(~0U, slim_rproc->peri + SLIM_INT_MASK_OFST); 135 writel(~0U, slim_rproc->peri + SLIM_CMD_MASK_OFST); 136 137 /* enable cpu */ 138 writel(SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST); 139 140 hw_id = readl_relaxed(slim_rproc->slimcore + SLIM_ID_OFST); 141 hw_ver = readl_relaxed(slim_rproc->slimcore + SLIM_VER_OFST); 142 143 fw_rev = readl(slim_rproc->mem[ST_SLIM_DMEM].cpu_addr + 144 SLIM_REV_ID_OFST); 145 146 dev_info(dev, "fw rev:%ld.%ld on SLIM %ld.%ld\n", 147 SLIM_REV_ID_MAJ(fw_rev), SLIM_REV_ID_MIN(fw_rev), 148 hw_id, hw_ver); 149 150 return 0; 151 } 152 153 static int slim_rproc_stop(struct rproc *rproc) 154 { 155 struct st_slim_rproc *slim_rproc = rproc->priv; 156 u32 val; 157 158 /* mask all (cmd & int) channels */ 159 writel(0UL, slim_rproc->peri + SLIM_INT_MASK_OFST); 160 writel(0UL, slim_rproc->peri + SLIM_CMD_MASK_OFST); 161 162 /* disable cpu pipeline clock */ 163 writel(SLIM_CLK_GATE_DIS, slim_rproc->slimcore + SLIM_CLK_GATE_OFST); 164 165 writel(!SLIM_EN_RUN, slim_rproc->slimcore + SLIM_EN_OFST); 166 167 val = readl(slim_rproc->slimcore + SLIM_EN_OFST); 168 if (val & SLIM_EN_RUN) 169 dev_warn(&rproc->dev, "Failed to disable SLIM"); 170 171 dev_dbg(&rproc->dev, "slim stopped\n"); 172 173 return 0; 174 } 175 176 static void *slim_rproc_da_to_va(struct rproc *rproc, u64 da, size_t len, bool *is_iomem) 177 { 178 struct st_slim_rproc *slim_rproc = rproc->priv; 179 void *va = NULL; 180 int i; 181 182 for (i = 0; i < ST_SLIM_MEM_MAX; i++) { 183 if (da != slim_rproc->mem[i].bus_addr) 184 continue; 185 186 if (len <= slim_rproc->mem[i].size) { 187 /* __force to make sparse happy with type conversion */ 188 va = (__force void *)slim_rproc->mem[i].cpu_addr; 189 break; 190 } 191 } 192 193 dev_dbg(&rproc->dev, "da = 0x%llx len = 0x%zx va = 0x%pK\n", 194 da, len, va); 195 196 return va; 197 } 198 199 static const struct rproc_ops slim_rproc_ops = { 200 .start = slim_rproc_start, 201 .stop = slim_rproc_stop, 202 .da_to_va = slim_rproc_da_to_va, 203 .get_boot_addr = rproc_elf_get_boot_addr, 204 .load = rproc_elf_load_segments, 205 .sanity_check = rproc_elf_sanity_check, 206 }; 207 208 /** 209 * st_slim_rproc_alloc() - allocate and initialise slim rproc 210 * @pdev: Pointer to the platform_device struct 211 * @fw_name: Name of firmware for rproc to use 212 * 213 * Function for allocating and initialising a slim rproc for use by 214 * device drivers whose IP is based around the SLIM core. It 215 * obtains and enables any clocks required by the SLIM core and also 216 * ioremaps the various IO. 217 * 218 * Return: st_slim_rproc pointer or PTR_ERR() on error. 219 */ 220 221 struct st_slim_rproc *st_slim_rproc_alloc(struct platform_device *pdev, 222 char *fw_name) 223 { 224 struct device *dev = &pdev->dev; 225 struct st_slim_rproc *slim_rproc; 226 struct device_node *np = dev->of_node; 227 struct rproc *rproc; 228 struct resource *res; 229 int err, i; 230 231 if (!fw_name) 232 return ERR_PTR(-EINVAL); 233 234 if (!of_device_is_compatible(np, "st,slim-rproc")) 235 return ERR_PTR(-EINVAL); 236 237 rproc = rproc_alloc(dev, np->name, &slim_rproc_ops, 238 fw_name, sizeof(*slim_rproc)); 239 if (!rproc) 240 return ERR_PTR(-ENOMEM); 241 242 rproc->has_iommu = false; 243 244 slim_rproc = rproc->priv; 245 slim_rproc->rproc = rproc; 246 247 /* get imem and dmem */ 248 for (i = 0; i < ARRAY_SIZE(mem_names); i++) { 249 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 250 mem_names[i]); 251 252 slim_rproc->mem[i].cpu_addr = devm_ioremap_resource(dev, res); 253 if (IS_ERR(slim_rproc->mem[i].cpu_addr)) { 254 dev_err(&pdev->dev, "devm_ioremap_resource failed\n"); 255 err = PTR_ERR(slim_rproc->mem[i].cpu_addr); 256 goto err; 257 } 258 slim_rproc->mem[i].bus_addr = res->start; 259 slim_rproc->mem[i].size = resource_size(res); 260 } 261 262 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "slimcore"); 263 slim_rproc->slimcore = devm_ioremap_resource(dev, res); 264 if (IS_ERR(slim_rproc->slimcore)) { 265 dev_err(&pdev->dev, "failed to ioremap slimcore IO\n"); 266 err = PTR_ERR(slim_rproc->slimcore); 267 goto err; 268 } 269 270 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "peripherals"); 271 slim_rproc->peri = devm_ioremap_resource(dev, res); 272 if (IS_ERR(slim_rproc->peri)) { 273 dev_err(&pdev->dev, "failed to ioremap peripherals IO\n"); 274 err = PTR_ERR(slim_rproc->peri); 275 goto err; 276 } 277 278 err = slim_clk_get(slim_rproc, dev); 279 if (err) 280 goto err; 281 282 err = slim_clk_enable(slim_rproc); 283 if (err) { 284 dev_err(dev, "Failed to enable clocks\n"); 285 goto err_clk_put; 286 } 287 288 /* Register as a remoteproc device */ 289 err = rproc_add(rproc); 290 if (err) { 291 dev_err(dev, "registration of slim remoteproc failed\n"); 292 goto err_clk_dis; 293 } 294 295 return slim_rproc; 296 297 err_clk_dis: 298 slim_clk_disable(slim_rproc); 299 err_clk_put: 300 for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++) 301 clk_put(slim_rproc->clks[i]); 302 err: 303 rproc_free(rproc); 304 return ERR_PTR(err); 305 } 306 EXPORT_SYMBOL(st_slim_rproc_alloc); 307 308 /** 309 * st_slim_rproc_put() - put slim rproc resources 310 * @slim_rproc: Pointer to the st_slim_rproc struct 311 * 312 * Function for calling respective _put() functions on slim_rproc resources. 313 * 314 */ 315 void st_slim_rproc_put(struct st_slim_rproc *slim_rproc) 316 { 317 int clk; 318 319 if (!slim_rproc) 320 return; 321 322 slim_clk_disable(slim_rproc); 323 324 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) 325 clk_put(slim_rproc->clks[clk]); 326 327 rproc_del(slim_rproc->rproc); 328 rproc_free(slim_rproc->rproc); 329 } 330 EXPORT_SYMBOL(st_slim_rproc_put); 331 332 MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); 333 MODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver"); 334 MODULE_LICENSE("GPL v2"); 335