linux/drivers/reset/reset-uniphier.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Socionext Inc.
   3 *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 */
  15
  16#include <linux/mfd/syscon.h>
  17#include <linux/module.h>
  18#include <linux/of.h>
  19#include <linux/of_device.h>
  20#include <linux/platform_device.h>
  21#include <linux/regmap.h>
  22#include <linux/reset-controller.h>
  23
  24struct uniphier_reset_data {
  25        unsigned int id;
  26        unsigned int reg;
  27        unsigned int bit;
  28        unsigned int flags;
  29#define UNIPHIER_RESET_ACTIVE_LOW               BIT(0)
  30};
  31
  32#define UNIPHIER_RESET_ID_END           (unsigned int)(-1)
  33
  34#define UNIPHIER_RESET_END                              \
  35        { .id = UNIPHIER_RESET_ID_END }
  36
  37#define UNIPHIER_RESET(_id, _reg, _bit)                 \
  38        {                                               \
  39                .id = (_id),                            \
  40                .reg = (_reg),                          \
  41                .bit = (_bit),                          \
  42        }
  43
  44#define UNIPHIER_RESETX(_id, _reg, _bit)                \
  45        {                                               \
  46                .id = (_id),                            \
  47                .reg = (_reg),                          \
  48                .bit = (_bit),                          \
  49                .flags = UNIPHIER_RESET_ACTIVE_LOW,     \
  50        }
  51
  52/* System reset data */
  53#define UNIPHIER_SLD3_SYS_RESET_STDMAC(id)              \
  54        UNIPHIER_RESETX((id), 0x2000, 10)
  55
  56#define UNIPHIER_LD11_SYS_RESET_STDMAC(id)              \
  57        UNIPHIER_RESETX((id), 0x200c, 8)
  58
  59#define UNIPHIER_PRO4_SYS_RESET_GIO(id)                 \
  60        UNIPHIER_RESETX((id), 0x2000, 6)
  61
  62#define UNIPHIER_LD20_SYS_RESET_GIO(id)                 \
  63        UNIPHIER_RESETX((id), 0x200c, 5)
  64
  65#define UNIPHIER_PRO4_SYS_RESET_USB3(id, ch)            \
  66        UNIPHIER_RESETX((id), 0x2000 + 0x4 * (ch), 17)
  67
  68const struct uniphier_reset_data uniphier_sld3_sys_reset_data[] = {
  69        UNIPHIER_SLD3_SYS_RESET_STDMAC(8),      /* Ether, HSC, MIO */
  70        UNIPHIER_RESET_END,
  71};
  72
  73const struct uniphier_reset_data uniphier_pro4_sys_reset_data[] = {
  74        UNIPHIER_SLD3_SYS_RESET_STDMAC(8),      /* HSC, MIO, RLE */
  75        UNIPHIER_PRO4_SYS_RESET_GIO(12),        /* Ether, SATA, USB3 */
  76        UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
  77        UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
  78        UNIPHIER_RESET_END,
  79};
  80
  81const struct uniphier_reset_data uniphier_pro5_sys_reset_data[] = {
  82        UNIPHIER_SLD3_SYS_RESET_STDMAC(8),      /* HSC */
  83        UNIPHIER_PRO4_SYS_RESET_GIO(12),        /* PCIe, USB3 */
  84        UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
  85        UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
  86        UNIPHIER_RESET_END,
  87};
  88
  89const struct uniphier_reset_data uniphier_pxs2_sys_reset_data[] = {
  90        UNIPHIER_SLD3_SYS_RESET_STDMAC(8),      /* HSC, RLE */
  91        UNIPHIER_PRO4_SYS_RESET_USB3(14, 0),
  92        UNIPHIER_PRO4_SYS_RESET_USB3(15, 1),
  93        UNIPHIER_RESETX(16, 0x2014, 4),         /* USB30-PHY0 */
  94        UNIPHIER_RESETX(17, 0x2014, 0),         /* USB30-PHY1 */
  95        UNIPHIER_RESETX(18, 0x2014, 2),         /* USB30-PHY2 */
  96        UNIPHIER_RESETX(20, 0x2014, 5),         /* USB31-PHY0 */
  97        UNIPHIER_RESETX(21, 0x2014, 1),         /* USB31-PHY1 */
  98        UNIPHIER_RESETX(28, 0x2014, 12),        /* SATA */
  99        UNIPHIER_RESET(29, 0x2014, 8),          /* SATA-PHY (active high) */
 100        UNIPHIER_RESET_END,
 101};
 102
 103const struct uniphier_reset_data uniphier_ld11_sys_reset_data[] = {
 104        UNIPHIER_LD11_SYS_RESET_STDMAC(8),      /* HSC, MIO */
 105        UNIPHIER_RESET_END,
 106};
 107
 108const struct uniphier_reset_data uniphier_ld20_sys_reset_data[] = {
 109        UNIPHIER_LD11_SYS_RESET_STDMAC(8),      /* HSC */
 110        UNIPHIER_LD20_SYS_RESET_GIO(12),        /* PCIe, USB3 */
 111        UNIPHIER_RESETX(16, 0x200c, 12),        /* USB30-PHY0 */
 112        UNIPHIER_RESETX(17, 0x200c, 13),        /* USB30-PHY1 */
 113        UNIPHIER_RESETX(18, 0x200c, 14),        /* USB30-PHY2 */
 114        UNIPHIER_RESETX(19, 0x200c, 15),        /* USB30-PHY3 */
 115        UNIPHIER_RESET_END,
 116};
 117
 118/* Media I/O reset data */
 119#define UNIPHIER_MIO_RESET_SD(id, ch)                   \
 120        UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 0)
 121
 122#define UNIPHIER_MIO_RESET_SD_BRIDGE(id, ch)            \
 123        UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 26)
 124
 125#define UNIPHIER_MIO_RESET_EMMC_HW_RESET(id, ch)        \
 126        UNIPHIER_RESETX((id), 0x80 + 0x200 * (ch), 0)
 127
 128#define UNIPHIER_MIO_RESET_USB2(id, ch)                 \
 129        UNIPHIER_RESETX((id), 0x114 + 0x200 * (ch), 0)
 130
 131#define UNIPHIER_MIO_RESET_USB2_BRIDGE(id, ch)          \
 132        UNIPHIER_RESETX((id), 0x110 + 0x200 * (ch), 24)
 133
 134#define UNIPHIER_MIO_RESET_DMAC(id)                     \
 135        UNIPHIER_RESETX((id), 0x110, 17)
 136
 137const struct uniphier_reset_data uniphier_sld3_mio_reset_data[] = {
 138        UNIPHIER_MIO_RESET_SD(0, 0),
 139        UNIPHIER_MIO_RESET_SD(1, 1),
 140        UNIPHIER_MIO_RESET_SD(2, 2),
 141        UNIPHIER_MIO_RESET_SD_BRIDGE(3, 0),
 142        UNIPHIER_MIO_RESET_SD_BRIDGE(4, 1),
 143        UNIPHIER_MIO_RESET_SD_BRIDGE(5, 2),
 144        UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
 145        UNIPHIER_MIO_RESET_DMAC(7),
 146        UNIPHIER_MIO_RESET_USB2(8, 0),
 147        UNIPHIER_MIO_RESET_USB2(9, 1),
 148        UNIPHIER_MIO_RESET_USB2(10, 2),
 149        UNIPHIER_MIO_RESET_USB2(11, 3),
 150        UNIPHIER_MIO_RESET_USB2_BRIDGE(12, 0),
 151        UNIPHIER_MIO_RESET_USB2_BRIDGE(13, 1),
 152        UNIPHIER_MIO_RESET_USB2_BRIDGE(14, 2),
 153        UNIPHIER_MIO_RESET_USB2_BRIDGE(15, 3),
 154        UNIPHIER_RESET_END,
 155};
 156
 157const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = {
 158        UNIPHIER_MIO_RESET_SD(0, 0),
 159        UNIPHIER_MIO_RESET_SD(1, 1),
 160        UNIPHIER_MIO_RESET_EMMC_HW_RESET(6, 1),
 161        UNIPHIER_RESET_END,
 162};
 163
 164/* Peripheral reset data */
 165#define UNIPHIER_PERI_RESET_UART(id, ch)                \
 166        UNIPHIER_RESETX((id), 0x114, 19 + (ch))
 167
 168#define UNIPHIER_PERI_RESET_I2C(id, ch)                 \
 169        UNIPHIER_RESETX((id), 0x114, 5 + (ch))
 170
 171#define UNIPHIER_PERI_RESET_FI2C(id, ch)                \
 172        UNIPHIER_RESETX((id), 0x114, 24 + (ch))
 173
 174const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = {
 175        UNIPHIER_PERI_RESET_UART(0, 0),
 176        UNIPHIER_PERI_RESET_UART(1, 1),
 177        UNIPHIER_PERI_RESET_UART(2, 2),
 178        UNIPHIER_PERI_RESET_UART(3, 3),
 179        UNIPHIER_PERI_RESET_I2C(4, 0),
 180        UNIPHIER_PERI_RESET_I2C(5, 1),
 181        UNIPHIER_PERI_RESET_I2C(6, 2),
 182        UNIPHIER_PERI_RESET_I2C(7, 3),
 183        UNIPHIER_PERI_RESET_I2C(8, 4),
 184        UNIPHIER_RESET_END,
 185};
 186
 187const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = {
 188        UNIPHIER_PERI_RESET_UART(0, 0),
 189        UNIPHIER_PERI_RESET_UART(1, 1),
 190        UNIPHIER_PERI_RESET_UART(2, 2),
 191        UNIPHIER_PERI_RESET_UART(3, 3),
 192        UNIPHIER_PERI_RESET_FI2C(4, 0),
 193        UNIPHIER_PERI_RESET_FI2C(5, 1),
 194        UNIPHIER_PERI_RESET_FI2C(6, 2),
 195        UNIPHIER_PERI_RESET_FI2C(7, 3),
 196        UNIPHIER_PERI_RESET_FI2C(8, 4),
 197        UNIPHIER_PERI_RESET_FI2C(9, 5),
 198        UNIPHIER_PERI_RESET_FI2C(10, 6),
 199        UNIPHIER_RESET_END,
 200};
 201
 202/* core implementaton */
 203struct uniphier_reset_priv {
 204        struct reset_controller_dev rcdev;
 205        struct device *dev;
 206        struct regmap *regmap;
 207        const struct uniphier_reset_data *data;
 208};
 209
 210#define to_uniphier_reset_priv(_rcdev) \
 211                        container_of(_rcdev, struct uniphier_reset_priv, rcdev)
 212
 213static int uniphier_reset_update(struct reset_controller_dev *rcdev,
 214                                 unsigned long id, int assert)
 215{
 216        struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
 217        const struct uniphier_reset_data *p;
 218
 219        for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
 220                unsigned int mask, val;
 221
 222                if (p->id != id)
 223                        continue;
 224
 225                mask = BIT(p->bit);
 226
 227                if (assert)
 228                        val = mask;
 229                else
 230                        val = ~mask;
 231
 232                if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
 233                        val = ~val;
 234
 235                return regmap_write_bits(priv->regmap, p->reg, mask, val);
 236        }
 237
 238        dev_err(priv->dev, "reset_id=%lu was not handled\n", id);
 239        return -EINVAL;
 240}
 241
 242static int uniphier_reset_assert(struct reset_controller_dev *rcdev,
 243                                 unsigned long id)
 244{
 245        return uniphier_reset_update(rcdev, id, 1);
 246}
 247
 248static int uniphier_reset_deassert(struct reset_controller_dev *rcdev,
 249                                   unsigned long id)
 250{
 251        return uniphier_reset_update(rcdev, id, 0);
 252}
 253
 254static int uniphier_reset_status(struct reset_controller_dev *rcdev,
 255                                 unsigned long id)
 256{
 257        struct uniphier_reset_priv *priv = to_uniphier_reset_priv(rcdev);
 258        const struct uniphier_reset_data *p;
 259
 260        for (p = priv->data; p->id != UNIPHIER_RESET_ID_END; p++) {
 261                unsigned int val;
 262                int ret, asserted;
 263
 264                if (p->id != id)
 265                        continue;
 266
 267                ret = regmap_read(priv->regmap, p->reg, &val);
 268                if (ret)
 269                        return ret;
 270
 271                asserted = !!(val & BIT(p->bit));
 272
 273                if (p->flags & UNIPHIER_RESET_ACTIVE_LOW)
 274                        asserted = !asserted;
 275
 276                return asserted;
 277        }
 278
 279        dev_err(priv->dev, "reset_id=%lu was not found\n", id);
 280        return -EINVAL;
 281}
 282
 283static const struct reset_control_ops uniphier_reset_ops = {
 284        .assert = uniphier_reset_assert,
 285        .deassert = uniphier_reset_deassert,
 286        .status = uniphier_reset_status,
 287};
 288
 289static int uniphier_reset_probe(struct platform_device *pdev)
 290{
 291        struct device *dev = &pdev->dev;
 292        struct uniphier_reset_priv *priv;
 293        const struct uniphier_reset_data *p, *data;
 294        struct regmap *regmap;
 295        struct device_node *parent;
 296        unsigned int nr_resets = 0;
 297
 298        data = of_device_get_match_data(dev);
 299        if (WARN_ON(!data))
 300                return -EINVAL;
 301
 302        parent = of_get_parent(dev->of_node); /* parent should be syscon node */
 303        regmap = syscon_node_to_regmap(parent);
 304        of_node_put(parent);
 305        if (IS_ERR(regmap)) {
 306                dev_err(dev, "failed to get regmap (error %ld)\n",
 307                        PTR_ERR(regmap));
 308                return PTR_ERR(regmap);
 309        }
 310
 311        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 312        if (!priv)
 313                return -ENOMEM;
 314
 315        for (p = data; p->id != UNIPHIER_RESET_ID_END; p++)
 316                nr_resets = max(nr_resets, p->id + 1);
 317
 318        priv->rcdev.ops = &uniphier_reset_ops;
 319        priv->rcdev.owner = dev->driver->owner;
 320        priv->rcdev.of_node = dev->of_node;
 321        priv->rcdev.nr_resets = nr_resets;
 322        priv->dev = dev;
 323        priv->regmap = regmap;
 324        priv->data = data;
 325
 326        return devm_reset_controller_register(&pdev->dev, &priv->rcdev);
 327}
 328
 329static const struct of_device_id uniphier_reset_match[] = {
 330        /* System reset */
 331        {
 332                .compatible = "socionext,uniphier-sld3-reset",
 333                .data = uniphier_sld3_sys_reset_data,
 334        },
 335        {
 336                .compatible = "socionext,uniphier-ld4-reset",
 337                .data = uniphier_sld3_sys_reset_data,
 338        },
 339        {
 340                .compatible = "socionext,uniphier-pro4-reset",
 341                .data = uniphier_pro4_sys_reset_data,
 342        },
 343        {
 344                .compatible = "socionext,uniphier-sld8-reset",
 345                .data = uniphier_sld3_sys_reset_data,
 346        },
 347        {
 348                .compatible = "socionext,uniphier-pro5-reset",
 349                .data = uniphier_pro5_sys_reset_data,
 350        },
 351        {
 352                .compatible = "socionext,uniphier-pxs2-reset",
 353                .data = uniphier_pxs2_sys_reset_data,
 354        },
 355        {
 356                .compatible = "socionext,uniphier-ld11-reset",
 357                .data = uniphier_ld11_sys_reset_data,
 358        },
 359        {
 360                .compatible = "socionext,uniphier-ld20-reset",
 361                .data = uniphier_ld20_sys_reset_data,
 362        },
 363        /* Media I/O reset, SD reset */
 364        {
 365                .compatible = "socionext,uniphier-sld3-mio-reset",
 366                .data = uniphier_sld3_mio_reset_data,
 367        },
 368        {
 369                .compatible = "socionext,uniphier-ld4-mio-reset",
 370                .data = uniphier_sld3_mio_reset_data,
 371        },
 372        {
 373                .compatible = "socionext,uniphier-pro4-mio-reset",
 374                .data = uniphier_sld3_mio_reset_data,
 375        },
 376        {
 377                .compatible = "socionext,uniphier-sld8-mio-reset",
 378                .data = uniphier_sld3_mio_reset_data,
 379        },
 380        {
 381                .compatible = "socionext,uniphier-pro5-sd-reset",
 382                .data = uniphier_pro5_sd_reset_data,
 383        },
 384        {
 385                .compatible = "socionext,uniphier-pxs2-sd-reset",
 386                .data = uniphier_pro5_sd_reset_data,
 387        },
 388        {
 389                .compatible = "socionext,uniphier-ld11-mio-reset",
 390                .data = uniphier_sld3_mio_reset_data,
 391        },
 392        {
 393                .compatible = "socionext,uniphier-ld20-sd-reset",
 394                .data = uniphier_pro5_sd_reset_data,
 395        },
 396        /* Peripheral reset */
 397        {
 398                .compatible = "socionext,uniphier-ld4-peri-reset",
 399                .data = uniphier_ld4_peri_reset_data,
 400        },
 401        {
 402                .compatible = "socionext,uniphier-pro4-peri-reset",
 403                .data = uniphier_pro4_peri_reset_data,
 404        },
 405        {
 406                .compatible = "socionext,uniphier-sld8-peri-reset",
 407                .data = uniphier_ld4_peri_reset_data,
 408        },
 409        {
 410                .compatible = "socionext,uniphier-pro5-peri-reset",
 411                .data = uniphier_pro4_peri_reset_data,
 412        },
 413        {
 414                .compatible = "socionext,uniphier-pxs2-peri-reset",
 415                .data = uniphier_pro4_peri_reset_data,
 416        },
 417        {
 418                .compatible = "socionext,uniphier-ld11-peri-reset",
 419                .data = uniphier_pro4_peri_reset_data,
 420        },
 421        {
 422                .compatible = "socionext,uniphier-ld20-peri-reset",
 423                .data = uniphier_pro4_peri_reset_data,
 424        },
 425        { /* sentinel */ }
 426};
 427MODULE_DEVICE_TABLE(of, uniphier_reset_match);
 428
 429static struct platform_driver uniphier_reset_driver = {
 430        .probe = uniphier_reset_probe,
 431        .driver = {
 432                .name = "uniphier-reset",
 433                .of_match_table = uniphier_reset_match,
 434        },
 435};
 436module_platform_driver(uniphier_reset_driver);
 437
 438MODULE_AUTHOR("Masahiro Yamada <yamada.masahiro@socionext.com>");
 439MODULE_DESCRIPTION("UniPhier Reset Controller Driver");
 440MODULE_LICENSE("GPL");
 441