Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.13 332 lines 8.4 kB view raw
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 52static const char *mem_names[ST_SLIM_MEM_MAX] = { 53 [ST_SLIM_DMEM] = "dmem", 54 [ST_SLIM_IMEM] = "imem", 55}; 56 57static 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 74err_put_clks: 75 while (--clk >= 0) 76 clk_put(slim_rproc->clks[clk]); 77 78 return err; 79} 80 81static 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 89static 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 101err_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 */ 111static 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 153static 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 176static 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 199static 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 221struct 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 slim_rproc->slimcore = devm_platform_ioremap_resource_byname(pdev, "slimcore"); 263 if (IS_ERR(slim_rproc->slimcore)) { 264 dev_err(&pdev->dev, "failed to ioremap slimcore IO\n"); 265 err = PTR_ERR(slim_rproc->slimcore); 266 goto err; 267 } 268 269 slim_rproc->peri = devm_platform_ioremap_resource_byname(pdev, "peripherals"); 270 if (IS_ERR(slim_rproc->peri)) { 271 dev_err(&pdev->dev, "failed to ioremap peripherals IO\n"); 272 err = PTR_ERR(slim_rproc->peri); 273 goto err; 274 } 275 276 err = slim_clk_get(slim_rproc, dev); 277 if (err) 278 goto err; 279 280 err = slim_clk_enable(slim_rproc); 281 if (err) { 282 dev_err(dev, "Failed to enable clocks\n"); 283 goto err_clk_put; 284 } 285 286 /* Register as a remoteproc device */ 287 err = rproc_add(rproc); 288 if (err) { 289 dev_err(dev, "registration of slim remoteproc failed\n"); 290 goto err_clk_dis; 291 } 292 293 return slim_rproc; 294 295err_clk_dis: 296 slim_clk_disable(slim_rproc); 297err_clk_put: 298 for (i = 0; i < ST_SLIM_MAX_CLK && slim_rproc->clks[i]; i++) 299 clk_put(slim_rproc->clks[i]); 300err: 301 rproc_free(rproc); 302 return ERR_PTR(err); 303} 304EXPORT_SYMBOL(st_slim_rproc_alloc); 305 306/** 307 * st_slim_rproc_put() - put slim rproc resources 308 * @slim_rproc: Pointer to the st_slim_rproc struct 309 * 310 * Function for calling respective _put() functions on slim_rproc resources. 311 * 312 */ 313void st_slim_rproc_put(struct st_slim_rproc *slim_rproc) 314{ 315 int clk; 316 317 if (!slim_rproc) 318 return; 319 320 slim_clk_disable(slim_rproc); 321 322 for (clk = 0; clk < ST_SLIM_MAX_CLK && slim_rproc->clks[clk]; clk++) 323 clk_put(slim_rproc->clks[clk]); 324 325 rproc_del(slim_rproc->rproc); 326 rproc_free(slim_rproc->rproc); 327} 328EXPORT_SYMBOL(st_slim_rproc_put); 329 330MODULE_AUTHOR("Peter Griffin <peter.griffin@linaro.org>"); 331MODULE_DESCRIPTION("STMicroelectronics SLIM core rproc driver"); 332MODULE_LICENSE("GPL v2");