linux/drivers/nvmem/rockchip-otp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Rockchip OTP Driver
   4 *
   5 * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
   6 * Author: Finley Xiao <finley.xiao@rock-chips.com>
   7 */
   8
   9#include <linux/clk.h>
  10#include <linux/delay.h>
  11#include <linux/device.h>
  12#include <linux/io.h>
  13#include <linux/iopoll.h>
  14#include <linux/module.h>
  15#include <linux/nvmem-provider.h>
  16#include <linux/reset.h>
  17#include <linux/slab.h>
  18#include <linux/of.h>
  19#include <linux/of_platform.h>
  20#include <linux/platform_device.h>
  21
  22/* OTP Register Offsets */
  23#define OTPC_SBPI_CTRL                  0x0020
  24#define OTPC_SBPI_CMD_VALID_PRE         0x0024
  25#define OTPC_SBPI_CS_VALID_PRE          0x0028
  26#define OTPC_SBPI_STATUS                0x002C
  27#define OTPC_USER_CTRL                  0x0100
  28#define OTPC_USER_ADDR                  0x0104
  29#define OTPC_USER_ENABLE                0x0108
  30#define OTPC_USER_Q                     0x0124
  31#define OTPC_INT_STATUS                 0x0304
  32#define OTPC_SBPI_CMD0_OFFSET           0x1000
  33#define OTPC_SBPI_CMD1_OFFSET           0x1004
  34
  35/* OTP Register bits and masks */
  36#define OTPC_USER_ADDR_MASK             GENMASK(31, 16)
  37#define OTPC_USE_USER                   BIT(0)
  38#define OTPC_USE_USER_MASK              GENMASK(16, 16)
  39#define OTPC_USER_FSM_ENABLE            BIT(0)
  40#define OTPC_USER_FSM_ENABLE_MASK       GENMASK(16, 16)
  41#define OTPC_SBPI_DONE                  BIT(1)
  42#define OTPC_USER_DONE                  BIT(2)
  43
  44#define SBPI_DAP_ADDR                   0x02
  45#define SBPI_DAP_ADDR_SHIFT             8
  46#define SBPI_DAP_ADDR_MASK              GENMASK(31, 24)
  47#define SBPI_CMD_VALID_MASK             GENMASK(31, 16)
  48#define SBPI_DAP_CMD_WRF                0xC0
  49#define SBPI_DAP_REG_ECC                0x3A
  50#define SBPI_ECC_ENABLE                 0x00
  51#define SBPI_ECC_DISABLE                0x09
  52#define SBPI_ENABLE                     BIT(0)
  53#define SBPI_ENABLE_MASK                GENMASK(16, 16)
  54
  55#define OTPC_TIMEOUT                    10000
  56
  57struct rockchip_otp {
  58        struct device *dev;
  59        void __iomem *base;
  60        struct clk_bulk_data    *clks;
  61        int num_clks;
  62        struct reset_control *rst;
  63};
  64
  65/* list of required clocks */
  66static const char * const rockchip_otp_clocks[] = {
  67        "otp", "apb_pclk", "phy",
  68};
  69
  70struct rockchip_data {
  71        int size;
  72};
  73
  74static int rockchip_otp_reset(struct rockchip_otp *otp)
  75{
  76        int ret;
  77
  78        ret = reset_control_assert(otp->rst);
  79        if (ret) {
  80                dev_err(otp->dev, "failed to assert otp phy %d\n", ret);
  81                return ret;
  82        }
  83
  84        udelay(2);
  85
  86        ret = reset_control_deassert(otp->rst);
  87        if (ret) {
  88                dev_err(otp->dev, "failed to deassert otp phy %d\n", ret);
  89                return ret;
  90        }
  91
  92        return 0;
  93}
  94
  95static int rockchip_otp_wait_status(struct rockchip_otp *otp, u32 flag)
  96{
  97        u32 status = 0;
  98        int ret;
  99
 100        ret = readl_poll_timeout_atomic(otp->base + OTPC_INT_STATUS, status,
 101                                        (status & flag), 1, OTPC_TIMEOUT);
 102        if (ret)
 103                return ret;
 104
 105        /* clean int status */
 106        writel(flag, otp->base + OTPC_INT_STATUS);
 107
 108        return 0;
 109}
 110
 111static int rockchip_otp_ecc_enable(struct rockchip_otp *otp, bool enable)
 112{
 113        int ret = 0;
 114
 115        writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
 116               otp->base + OTPC_SBPI_CTRL);
 117
 118        writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
 119        writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
 120               otp->base + OTPC_SBPI_CMD0_OFFSET);
 121        if (enable)
 122                writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
 123        else
 124                writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
 125
 126        writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
 127
 128        ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
 129        if (ret < 0)
 130                dev_err(otp->dev, "timeout during ecc_enable\n");
 131
 132        return ret;
 133}
 134
 135static int rockchip_otp_read(void *context, unsigned int offset,
 136                             void *val, size_t bytes)
 137{
 138        struct rockchip_otp *otp = context;
 139        u8 *buf = val;
 140        int ret = 0;
 141
 142        ret = clk_bulk_prepare_enable(otp->num_clks, otp->clks);
 143        if (ret < 0) {
 144                dev_err(otp->dev, "failed to prepare/enable clks\n");
 145                return ret;
 146        }
 147
 148        ret = rockchip_otp_reset(otp);
 149        if (ret) {
 150                dev_err(otp->dev, "failed to reset otp phy\n");
 151                goto disable_clks;
 152        }
 153
 154        ret = rockchip_otp_ecc_enable(otp, false);
 155        if (ret < 0) {
 156                dev_err(otp->dev, "rockchip_otp_ecc_enable err\n");
 157                goto disable_clks;
 158        }
 159
 160        writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
 161        udelay(5);
 162        while (bytes--) {
 163                writel(offset++ | OTPC_USER_ADDR_MASK,
 164                       otp->base + OTPC_USER_ADDR);
 165                writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
 166                       otp->base + OTPC_USER_ENABLE);
 167                ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
 168                if (ret < 0) {
 169                        dev_err(otp->dev, "timeout during read setup\n");
 170                        goto read_end;
 171                }
 172                *buf++ = readb(otp->base + OTPC_USER_Q);
 173        }
 174
 175read_end:
 176        writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
 177disable_clks:
 178        clk_bulk_disable_unprepare(otp->num_clks, otp->clks);
 179
 180        return ret;
 181}
 182
 183static struct nvmem_config otp_config = {
 184        .name = "rockchip-otp",
 185        .owner = THIS_MODULE,
 186        .read_only = true,
 187        .stride = 1,
 188        .word_size = 1,
 189        .reg_read = rockchip_otp_read,
 190};
 191
 192static const struct rockchip_data px30_data = {
 193        .size = 0x40,
 194};
 195
 196static const struct of_device_id rockchip_otp_match[] = {
 197        {
 198                .compatible = "rockchip,px30-otp",
 199                .data = (void *)&px30_data,
 200        },
 201        {
 202                .compatible = "rockchip,rk3308-otp",
 203                .data = (void *)&px30_data,
 204        },
 205        { /* sentinel */ },
 206};
 207MODULE_DEVICE_TABLE(of, rockchip_otp_match);
 208
 209static int rockchip_otp_probe(struct platform_device *pdev)
 210{
 211        struct device *dev = &pdev->dev;
 212        struct rockchip_otp *otp;
 213        const struct rockchip_data *data;
 214        struct nvmem_device *nvmem;
 215        int ret, i;
 216
 217        data = of_device_get_match_data(dev);
 218        if (!data) {
 219                dev_err(dev, "failed to get match data\n");
 220                return -EINVAL;
 221        }
 222
 223        otp = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_otp),
 224                           GFP_KERNEL);
 225        if (!otp)
 226                return -ENOMEM;
 227
 228        otp->dev = dev;
 229        otp->base = devm_platform_ioremap_resource(pdev, 0);
 230        if (IS_ERR(otp->base))
 231                return PTR_ERR(otp->base);
 232
 233        otp->num_clks = ARRAY_SIZE(rockchip_otp_clocks);
 234        otp->clks = devm_kcalloc(dev, otp->num_clks,
 235                                     sizeof(*otp->clks), GFP_KERNEL);
 236        if (!otp->clks)
 237                return -ENOMEM;
 238
 239        for (i = 0; i < otp->num_clks; ++i)
 240                otp->clks[i].id = rockchip_otp_clocks[i];
 241
 242        ret = devm_clk_bulk_get(dev, otp->num_clks, otp->clks);
 243        if (ret)
 244                return ret;
 245
 246        otp->rst = devm_reset_control_get(dev, "phy");
 247        if (IS_ERR(otp->rst))
 248                return PTR_ERR(otp->rst);
 249
 250        otp_config.size = data->size;
 251        otp_config.priv = otp;
 252        otp_config.dev = dev;
 253        nvmem = devm_nvmem_register(dev, &otp_config);
 254
 255        return PTR_ERR_OR_ZERO(nvmem);
 256}
 257
 258static struct platform_driver rockchip_otp_driver = {
 259        .probe = rockchip_otp_probe,
 260        .driver = {
 261                .name = "rockchip-otp",
 262                .of_match_table = rockchip_otp_match,
 263        },
 264};
 265
 266module_platform_driver(rockchip_otp_driver);
 267MODULE_DESCRIPTION("Rockchip OTP driver");
 268MODULE_LICENSE("GPL v2");
 269