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 v5.5-rc6 391 lines 11 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * OMAP2+ PRM driver 4 * 5 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ 6 * Tero Kristo <t-kristo@ti.com> 7 */ 8 9#include <linux/kernel.h> 10#include <linux/device.h> 11#include <linux/io.h> 12#include <linux/iopoll.h> 13#include <linux/of.h> 14#include <linux/of_device.h> 15#include <linux/platform_device.h> 16#include <linux/reset-controller.h> 17#include <linux/delay.h> 18 19#include <linux/platform_data/ti-prm.h> 20 21struct omap_rst_map { 22 s8 rst; 23 s8 st; 24}; 25 26struct omap_prm_data { 27 u32 base; 28 const char *name; 29 const char *clkdm_name; 30 u16 rstctrl; 31 u16 rstst; 32 const struct omap_rst_map *rstmap; 33 u8 flags; 34}; 35 36struct omap_prm { 37 const struct omap_prm_data *data; 38 void __iomem *base; 39}; 40 41struct omap_reset_data { 42 struct reset_controller_dev rcdev; 43 struct omap_prm *prm; 44 u32 mask; 45 spinlock_t lock; 46 struct clockdomain *clkdm; 47 struct device *dev; 48}; 49 50#define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev) 51 52#define OMAP_MAX_RESETS 8 53#define OMAP_RESET_MAX_WAIT 10000 54 55#define OMAP_PRM_HAS_RSTCTRL BIT(0) 56#define OMAP_PRM_HAS_RSTST BIT(1) 57#define OMAP_PRM_HAS_NO_CLKDM BIT(2) 58 59#define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST) 60 61static const struct omap_rst_map rst_map_0[] = { 62 { .rst = 0, .st = 0 }, 63 { .rst = -1 }, 64}; 65 66static const struct omap_rst_map rst_map_01[] = { 67 { .rst = 0, .st = 0 }, 68 { .rst = 1, .st = 1 }, 69 { .rst = -1 }, 70}; 71 72static const struct omap_rst_map rst_map_012[] = { 73 { .rst = 0, .st = 0 }, 74 { .rst = 1, .st = 1 }, 75 { .rst = 2, .st = 2 }, 76 { .rst = -1 }, 77}; 78 79static const struct omap_prm_data omap4_prm_data[] = { 80 { .name = "tesla", .base = 0x4a306400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 81 { .name = "core", .base = 0x4a306700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati", .rstmap = rst_map_012 }, 82 { .name = "ivahd", .base = 0x4a306f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, 83 { .name = "device", .base = 0x4a307b00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 84 { }, 85}; 86 87static const struct omap_prm_data omap5_prm_data[] = { 88 { .name = "dsp", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 89 { .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu", .rstmap = rst_map_012 }, 90 { .name = "iva", .base = 0x4ae07200, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, 91 { .name = "device", .base = 0x4ae07c00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 92 { }, 93}; 94 95static const struct omap_prm_data dra7_prm_data[] = { 96 { .name = "dsp1", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 97 { .name = "ipu", .base = 0x4ae06500, .rstctrl = 0x10, .rstst = 0x14, .clkdm_name = "ipu1", .rstmap = rst_map_012 }, 98 { .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu2", .rstmap = rst_map_012 }, 99 { .name = "iva", .base = 0x4ae06f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, 100 { .name = "dsp2", .base = 0x4ae07b00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 101 { .name = "eve1", .base = 0x4ae07b40, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 102 { .name = "eve2", .base = 0x4ae07b80, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 103 { .name = "eve3", .base = 0x4ae07bc0, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 104 { .name = "eve4", .base = 0x4ae07c00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, 105 { }, 106}; 107 108static const struct omap_rst_map am3_per_rst_map[] = { 109 { .rst = 1 }, 110 { .rst = -1 }, 111}; 112 113static const struct omap_rst_map am3_wkup_rst_map[] = { 114 { .rst = 3, .st = 5 }, 115 { .rst = -1 }, 116}; 117 118static const struct omap_prm_data am3_prm_data[] = { 119 { .name = "per", .base = 0x44e00c00, .rstctrl = 0x0, .rstmap = am3_per_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp" }, 120 { .name = "wkup", .base = 0x44e00d00, .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 121 { .name = "device", .base = 0x44e00f00, .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 122 { .name = "gfx", .base = 0x44e01100, .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" }, 123 { }, 124}; 125 126static const struct omap_rst_map am4_per_rst_map[] = { 127 { .rst = 1, .st = 0 }, 128 { .rst = -1 }, 129}; 130 131static const struct omap_rst_map am4_device_rst_map[] = { 132 { .rst = 0, .st = 1 }, 133 { .rst = 1, .st = 0 }, 134 { .rst = -1 }, 135}; 136 137static const struct omap_prm_data am4_prm_data[] = { 138 { .name = "gfx", .base = 0x44df0400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" }, 139 { .name = "per", .base = 0x44df0800, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map, .clkdm_name = "pruss_ocp" }, 140 { .name = "wkup", .base = 0x44df2000, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_NO_CLKDM }, 141 { .name = "device", .base = 0x44df4000, .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, 142 { }, 143}; 144 145static const struct of_device_id omap_prm_id_table[] = { 146 { .compatible = "ti,omap4-prm-inst", .data = omap4_prm_data }, 147 { .compatible = "ti,omap5-prm-inst", .data = omap5_prm_data }, 148 { .compatible = "ti,dra7-prm-inst", .data = dra7_prm_data }, 149 { .compatible = "ti,am3-prm-inst", .data = am3_prm_data }, 150 { .compatible = "ti,am4-prm-inst", .data = am4_prm_data }, 151 { }, 152}; 153 154static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id) 155{ 156 if (reset->mask & BIT(id)) 157 return true; 158 159 return false; 160} 161 162static int omap_reset_get_st_bit(struct omap_reset_data *reset, 163 unsigned long id) 164{ 165 const struct omap_rst_map *map = reset->prm->data->rstmap; 166 167 while (map->rst >= 0) { 168 if (map->rst == id) 169 return map->st; 170 171 map++; 172 } 173 174 return id; 175} 176 177static int omap_reset_status(struct reset_controller_dev *rcdev, 178 unsigned long id) 179{ 180 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 181 u32 v; 182 int st_bit = omap_reset_get_st_bit(reset, id); 183 bool has_rstst = reset->prm->data->rstst || 184 (reset->prm->data->flags & OMAP_PRM_HAS_RSTST); 185 186 /* Check if we have rstst */ 187 if (!has_rstst) 188 return -ENOTSUPP; 189 190 /* Check if hw reset line is asserted */ 191 v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 192 if (v & BIT(id)) 193 return 1; 194 195 /* 196 * Check reset status, high value means reset sequence has been 197 * completed successfully so we can return 0 here (reset deasserted) 198 */ 199 v = readl_relaxed(reset->prm->base + reset->prm->data->rstst); 200 v >>= st_bit; 201 v &= 1; 202 203 return !v; 204} 205 206static int omap_reset_assert(struct reset_controller_dev *rcdev, 207 unsigned long id) 208{ 209 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 210 u32 v; 211 unsigned long flags; 212 213 /* assert the reset control line */ 214 spin_lock_irqsave(&reset->lock, flags); 215 v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 216 v |= 1 << id; 217 writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 218 spin_unlock_irqrestore(&reset->lock, flags); 219 220 return 0; 221} 222 223static int omap_reset_deassert(struct reset_controller_dev *rcdev, 224 unsigned long id) 225{ 226 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 227 u32 v; 228 int st_bit; 229 bool has_rstst; 230 unsigned long flags; 231 struct ti_prm_platform_data *pdata = dev_get_platdata(reset->dev); 232 int ret = 0; 233 234 has_rstst = reset->prm->data->rstst || 235 (reset->prm->data->flags & OMAP_PRM_HAS_RSTST); 236 237 if (has_rstst) { 238 st_bit = omap_reset_get_st_bit(reset, id); 239 240 /* Clear the reset status by writing 1 to the status bit */ 241 v = 1 << st_bit; 242 writel_relaxed(v, reset->prm->base + reset->prm->data->rstst); 243 } 244 245 if (reset->clkdm) 246 pdata->clkdm_deny_idle(reset->clkdm); 247 248 /* de-assert the reset control line */ 249 spin_lock_irqsave(&reset->lock, flags); 250 v = readl_relaxed(reset->prm->base + reset->prm->data->rstctrl); 251 v &= ~(1 << id); 252 writel_relaxed(v, reset->prm->base + reset->prm->data->rstctrl); 253 spin_unlock_irqrestore(&reset->lock, flags); 254 255 if (!has_rstst) 256 goto exit; 257 258 /* wait for the status to be set */ 259 ret = readl_relaxed_poll_timeout(reset->prm->base + 260 reset->prm->data->rstst, 261 v, v & BIT(st_bit), 1, 262 OMAP_RESET_MAX_WAIT); 263 if (ret) 264 pr_err("%s: timedout waiting for %s:%lu\n", __func__, 265 reset->prm->data->name, id); 266 267exit: 268 if (reset->clkdm) 269 pdata->clkdm_allow_idle(reset->clkdm); 270 271 return ret; 272} 273 274static const struct reset_control_ops omap_reset_ops = { 275 .assert = omap_reset_assert, 276 .deassert = omap_reset_deassert, 277 .status = omap_reset_status, 278}; 279 280static int omap_prm_reset_xlate(struct reset_controller_dev *rcdev, 281 const struct of_phandle_args *reset_spec) 282{ 283 struct omap_reset_data *reset = to_omap_reset_data(rcdev); 284 285 if (!_is_valid_reset(reset, reset_spec->args[0])) 286 return -EINVAL; 287 288 return reset_spec->args[0]; 289} 290 291static int omap_prm_reset_init(struct platform_device *pdev, 292 struct omap_prm *prm) 293{ 294 struct omap_reset_data *reset; 295 const struct omap_rst_map *map; 296 struct ti_prm_platform_data *pdata = dev_get_platdata(&pdev->dev); 297 char buf[32]; 298 299 /* 300 * Check if we have controllable resets. If either rstctrl is non-zero 301 * or OMAP_PRM_HAS_RSTCTRL flag is set, we have reset control register 302 * for the domain. 303 */ 304 if (!prm->data->rstctrl && !(prm->data->flags & OMAP_PRM_HAS_RSTCTRL)) 305 return 0; 306 307 /* Check if we have the pdata callbacks in place */ 308 if (!pdata || !pdata->clkdm_lookup || !pdata->clkdm_deny_idle || 309 !pdata->clkdm_allow_idle) 310 return -EINVAL; 311 312 map = prm->data->rstmap; 313 if (!map) 314 return -EINVAL; 315 316 reset = devm_kzalloc(&pdev->dev, sizeof(*reset), GFP_KERNEL); 317 if (!reset) 318 return -ENOMEM; 319 320 reset->rcdev.owner = THIS_MODULE; 321 reset->rcdev.ops = &omap_reset_ops; 322 reset->rcdev.of_node = pdev->dev.of_node; 323 reset->rcdev.nr_resets = OMAP_MAX_RESETS; 324 reset->rcdev.of_xlate = omap_prm_reset_xlate; 325 reset->rcdev.of_reset_n_cells = 1; 326 reset->dev = &pdev->dev; 327 spin_lock_init(&reset->lock); 328 329 reset->prm = prm; 330 331 sprintf(buf, "%s_clkdm", prm->data->clkdm_name ? prm->data->clkdm_name : 332 prm->data->name); 333 334 if (!(prm->data->flags & OMAP_PRM_HAS_NO_CLKDM)) { 335 reset->clkdm = pdata->clkdm_lookup(buf); 336 if (!reset->clkdm) 337 return -EINVAL; 338 } 339 340 while (map->rst >= 0) { 341 reset->mask |= BIT(map->rst); 342 map++; 343 } 344 345 return devm_reset_controller_register(&pdev->dev, &reset->rcdev); 346} 347 348static int omap_prm_probe(struct platform_device *pdev) 349{ 350 struct resource *res; 351 const struct omap_prm_data *data; 352 struct omap_prm *prm; 353 const struct of_device_id *match; 354 355 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 356 if (!res) 357 return -ENODEV; 358 359 match = of_match_device(omap_prm_id_table, &pdev->dev); 360 if (!match) 361 return -ENOTSUPP; 362 363 prm = devm_kzalloc(&pdev->dev, sizeof(*prm), GFP_KERNEL); 364 if (!prm) 365 return -ENOMEM; 366 367 data = match->data; 368 369 while (data->base != res->start) { 370 if (!data->base) 371 return -EINVAL; 372 data++; 373 } 374 375 prm->data = data; 376 377 prm->base = devm_ioremap_resource(&pdev->dev, res); 378 if (IS_ERR(prm->base)) 379 return PTR_ERR(prm->base); 380 381 return omap_prm_reset_init(pdev, prm); 382} 383 384static struct platform_driver omap_prm_driver = { 385 .probe = omap_prm_probe, 386 .driver = { 387 .name = KBUILD_MODNAME, 388 .of_match_table = omap_prm_id_table, 389 }, 390}; 391builtin_platform_driver(omap_prm_driver);