linux/drivers/nvmem/rockchip-efuse.c
<<
>>
Prefs
   1/*
   2 * Rockchip eFuse Driver
   3 *
   4 * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
   5 * Author: Caesar Wang <wxt@rock-chips.com>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of version 2 of the GNU General Public License as
   9 * published by the Free Software Foundation.
  10 *
  11 * This program is distributed in the hope that it will be useful, but WITHOUT
  12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14 * more details.
  15 */
  16
  17#include <linux/clk.h>
  18#include <linux/delay.h>
  19#include <linux/device.h>
  20#include <linux/io.h>
  21#include <linux/module.h>
  22#include <linux/nvmem-provider.h>
  23#include <linux/slab.h>
  24#include <linux/of.h>
  25#include <linux/of_platform.h>
  26#include <linux/platform_device.h>
  27
  28#define RK3288_A_SHIFT          6
  29#define RK3288_A_MASK           0x3ff
  30#define RK3288_PGENB            BIT(3)
  31#define RK3288_LOAD             BIT(2)
  32#define RK3288_STROBE           BIT(1)
  33#define RK3288_CSB              BIT(0)
  34
  35#define RK3328_SECURE_SIZES     96
  36#define RK3328_INT_STATUS       0x0018
  37#define RK3328_DOUT             0x0020
  38#define RK3328_AUTO_CTRL        0x0024
  39#define RK3328_INT_FINISH       BIT(0)
  40#define RK3328_AUTO_ENB         BIT(0)
  41#define RK3328_AUTO_RD          BIT(1)
  42
  43#define RK3399_A_SHIFT          16
  44#define RK3399_A_MASK           0x3ff
  45#define RK3399_NBYTES           4
  46#define RK3399_STROBSFTSEL      BIT(9)
  47#define RK3399_RSB              BIT(7)
  48#define RK3399_PD               BIT(5)
  49#define RK3399_PGENB            BIT(3)
  50#define RK3399_LOAD             BIT(2)
  51#define RK3399_STROBE           BIT(1)
  52#define RK3399_CSB              BIT(0)
  53
  54#define REG_EFUSE_CTRL          0x0000
  55#define REG_EFUSE_DOUT          0x0004
  56
  57struct rockchip_efuse_chip {
  58        struct device *dev;
  59        void __iomem *base;
  60        struct clk *clk;
  61};
  62
  63static int rockchip_rk3288_efuse_read(void *context, unsigned int offset,
  64                                      void *val, size_t bytes)
  65{
  66        struct rockchip_efuse_chip *efuse = context;
  67        u8 *buf = val;
  68        int ret;
  69
  70        ret = clk_prepare_enable(efuse->clk);
  71        if (ret < 0) {
  72                dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
  73                return ret;
  74        }
  75
  76        writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL);
  77        udelay(1);
  78        while (bytes--) {
  79                writel(readl(efuse->base + REG_EFUSE_CTRL) &
  80                             (~(RK3288_A_MASK << RK3288_A_SHIFT)),
  81                             efuse->base + REG_EFUSE_CTRL);
  82                writel(readl(efuse->base + REG_EFUSE_CTRL) |
  83                             ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
  84                             efuse->base + REG_EFUSE_CTRL);
  85                udelay(1);
  86                writel(readl(efuse->base + REG_EFUSE_CTRL) |
  87                             RK3288_STROBE, efuse->base + REG_EFUSE_CTRL);
  88                udelay(1);
  89                *buf++ = readb(efuse->base + REG_EFUSE_DOUT);
  90                writel(readl(efuse->base + REG_EFUSE_CTRL) &
  91                       (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL);
  92                udelay(1);
  93        }
  94
  95        /* Switch to standby mode */
  96        writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL);
  97
  98        clk_disable_unprepare(efuse->clk);
  99
 100        return 0;
 101}
 102
 103static int rockchip_rk3328_efuse_read(void *context, unsigned int offset,
 104                                      void *val, size_t bytes)
 105{
 106        struct rockchip_efuse_chip *efuse = context;
 107        unsigned int addr_start, addr_end, addr_offset, addr_len;
 108        u32 out_value, status;
 109        u8 *buf;
 110        int ret, i = 0;
 111
 112        ret = clk_prepare_enable(efuse->clk);
 113        if (ret < 0) {
 114                dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
 115                return ret;
 116        }
 117
 118        /* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */
 119        offset += RK3328_SECURE_SIZES;
 120        addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
 121        addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
 122        addr_offset = offset % RK3399_NBYTES;
 123        addr_len = addr_end - addr_start;
 124
 125        buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
 126                      GFP_KERNEL);
 127        if (!buf) {
 128                ret = -ENOMEM;
 129                goto nomem;
 130        }
 131
 132        while (addr_len--) {
 133                writel(RK3328_AUTO_RD | RK3328_AUTO_ENB |
 134                       ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
 135                       efuse->base + RK3328_AUTO_CTRL);
 136                udelay(4);
 137                status = readl(efuse->base + RK3328_INT_STATUS);
 138                if (!(status & RK3328_INT_FINISH)) {
 139                        ret = -EIO;
 140                        goto err;
 141                }
 142                out_value = readl(efuse->base + RK3328_DOUT);
 143                writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);
 144
 145                memcpy(&buf[i], &out_value, RK3399_NBYTES);
 146                i += RK3399_NBYTES;
 147        }
 148
 149        memcpy(val, buf + addr_offset, bytes);
 150err:
 151        kfree(buf);
 152nomem:
 153        clk_disable_unprepare(efuse->clk);
 154
 155        return ret;
 156}
 157
 158static int rockchip_rk3399_efuse_read(void *context, unsigned int offset,
 159                                      void *val, size_t bytes)
 160{
 161        struct rockchip_efuse_chip *efuse = context;
 162        unsigned int addr_start, addr_end, addr_offset, addr_len;
 163        u32 out_value;
 164        u8 *buf;
 165        int ret, i = 0;
 166
 167        ret = clk_prepare_enable(efuse->clk);
 168        if (ret < 0) {
 169                dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
 170                return ret;
 171        }
 172
 173        addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
 174        addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
 175        addr_offset = offset % RK3399_NBYTES;
 176        addr_len = addr_end - addr_start;
 177
 178        buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
 179                      GFP_KERNEL);
 180        if (!buf) {
 181                clk_disable_unprepare(efuse->clk);
 182                return -ENOMEM;
 183        }
 184
 185        writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
 186               efuse->base + REG_EFUSE_CTRL);
 187        udelay(1);
 188        while (addr_len--) {
 189                writel(readl(efuse->base + REG_EFUSE_CTRL) | RK3399_STROBE |
 190                       ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
 191                       efuse->base + REG_EFUSE_CTRL);
 192                udelay(1);
 193                out_value = readl(efuse->base + REG_EFUSE_DOUT);
 194                writel(readl(efuse->base + REG_EFUSE_CTRL) & (~RK3399_STROBE),
 195                       efuse->base + REG_EFUSE_CTRL);
 196                udelay(1);
 197
 198                memcpy(&buf[i], &out_value, RK3399_NBYTES);
 199                i += RK3399_NBYTES;
 200        }
 201
 202        /* Switch to standby mode */
 203        writel(RK3399_PD | RK3399_CSB, efuse->base + REG_EFUSE_CTRL);
 204
 205        memcpy(val, buf + addr_offset, bytes);
 206
 207        kfree(buf);
 208
 209        clk_disable_unprepare(efuse->clk);
 210
 211        return 0;
 212}
 213
 214static struct nvmem_config econfig = {
 215        .name = "rockchip-efuse",
 216        .stride = 1,
 217        .word_size = 1,
 218        .read_only = true,
 219};
 220
 221static const struct of_device_id rockchip_efuse_match[] = {
 222        /* deprecated but kept around for dts binding compatibility */
 223        {
 224                .compatible = "rockchip,rockchip-efuse",
 225                .data = (void *)&rockchip_rk3288_efuse_read,
 226        },
 227        {
 228                .compatible = "rockchip,rk3066a-efuse",
 229                .data = (void *)&rockchip_rk3288_efuse_read,
 230        },
 231        {
 232                .compatible = "rockchip,rk3188-efuse",
 233                .data = (void *)&rockchip_rk3288_efuse_read,
 234        },
 235        {
 236                .compatible = "rockchip,rk3228-efuse",
 237                .data = (void *)&rockchip_rk3288_efuse_read,
 238        },
 239        {
 240                .compatible = "rockchip,rk3288-efuse",
 241                .data = (void *)&rockchip_rk3288_efuse_read,
 242        },
 243        {
 244                .compatible = "rockchip,rk3368-efuse",
 245                .data = (void *)&rockchip_rk3288_efuse_read,
 246        },
 247        {
 248                .compatible = "rockchip,rk3328-efuse",
 249                .data = (void *)&rockchip_rk3328_efuse_read,
 250        },
 251        {
 252                .compatible = "rockchip,rk3399-efuse",
 253                .data = (void *)&rockchip_rk3399_efuse_read,
 254        },
 255        { /* sentinel */},
 256};
 257MODULE_DEVICE_TABLE(of, rockchip_efuse_match);
 258
 259static int rockchip_efuse_probe(struct platform_device *pdev)
 260{
 261        struct resource *res;
 262        struct nvmem_device *nvmem;
 263        struct rockchip_efuse_chip *efuse;
 264        const void *data;
 265        struct device *dev = &pdev->dev;
 266
 267        data = of_device_get_match_data(dev);
 268        if (!data) {
 269                dev_err(dev, "failed to get match data\n");
 270                return -EINVAL;
 271        }
 272
 273        efuse = devm_kzalloc(dev, sizeof(struct rockchip_efuse_chip),
 274                             GFP_KERNEL);
 275        if (!efuse)
 276                return -ENOMEM;
 277
 278        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 279        efuse->base = devm_ioremap_resource(dev, res);
 280        if (IS_ERR(efuse->base))
 281                return PTR_ERR(efuse->base);
 282
 283        efuse->clk = devm_clk_get(dev, "pclk_efuse");
 284        if (IS_ERR(efuse->clk))
 285                return PTR_ERR(efuse->clk);
 286
 287        efuse->dev = dev;
 288        if (of_property_read_u32(dev->of_node, "rockchip,efuse-size",
 289                                 &econfig.size))
 290                econfig.size = resource_size(res);
 291        econfig.reg_read = data;
 292        econfig.priv = efuse;
 293        econfig.dev = efuse->dev;
 294        nvmem = devm_nvmem_register(dev, &econfig);
 295
 296        return PTR_ERR_OR_ZERO(nvmem);
 297}
 298
 299static struct platform_driver rockchip_efuse_driver = {
 300        .probe = rockchip_efuse_probe,
 301        .driver = {
 302                .name = "rockchip-efuse",
 303                .of_match_table = rockchip_efuse_match,
 304        },
 305};
 306
 307module_platform_driver(rockchip_efuse_driver);
 308MODULE_DESCRIPTION("rockchip_efuse driver");
 309MODULE_LICENSE("GPL v2");
 310