linux/drivers/soc/ti/omap_prm.c
<<
>>
Prefs
   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_atomic(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);
 392