Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/nvmem/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 7 kB image not shown  

Quelle  rockchip-efuse.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Rockchip eFuse Driver
 *
 * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
 * Author: Caesar Wang <wxt@rock-chips.com>
 */


#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>

#define RK3288_A_SHIFT  6
#define RK3288_A_MASK  0x3ff
#define RK3288_PGENB  BIT(3)
#define RK3288_LOAD  BIT(2)
#define RK3288_STROBE  BIT(1)
#define RK3288_CSB  BIT(0)

#define RK3328_SECURE_SIZES 96
#define RK3328_INT_STATUS 0x0018
#define RK3328_DOUT  0x0020
#define RK3328_AUTO_CTRL 0x0024
#define RK3328_INT_FINISH BIT(0)
#define RK3328_AUTO_ENB  BIT(0)
#define RK3328_AUTO_RD  BIT(1)

#define RK3399_A_SHIFT  16
#define RK3399_A_MASK  0x3ff
#define RK3399_NBYTES  4
#define RK3399_STROBSFTSEL BIT(9)
#define RK3399_RSB  BIT(7)
#define RK3399_PD  BIT(5)
#define RK3399_PGENB  BIT(3)
#define RK3399_LOAD  BIT(2)
#define RK3399_STROBE  BIT(1)
#define RK3399_CSB  BIT(0)

#define REG_EFUSE_CTRL  0x0000
#define REG_EFUSE_DOUT  0x0004

struct rockchip_efuse_chip {
 struct device *dev;
 void __iomem *base;
 struct clk *clk;
};

static int rockchip_rk3288_efuse_read(void *context, unsigned int offset,
          void *val, size_t bytes)
{
 struct rockchip_efuse_chip *efuse = context;
 u8 *buf = val;
 int ret;

 ret = clk_prepare_enable(efuse->clk);
 if (ret < 0) {
  dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
  return ret;
 }

 writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL);
 udelay(1);
 while (bytes--) {
  writel(readl(efuse->base + REG_EFUSE_CTRL) &
        (~(RK3288_A_MASK << RK3288_A_SHIFT)),
        efuse->base + REG_EFUSE_CTRL);
  writel(readl(efuse->base + REG_EFUSE_CTRL) |
        ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
        efuse->base + REG_EFUSE_CTRL);
  udelay(1);
  writel(readl(efuse->base + REG_EFUSE_CTRL) |
        RK3288_STROBE, efuse->base + REG_EFUSE_CTRL);
  udelay(1);
  *buf++ = readb(efuse->base + REG_EFUSE_DOUT);
  writel(readl(efuse->base + REG_EFUSE_CTRL) &
         (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL);
  udelay(1);
 }

 /* Switch to standby mode */
 writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL);

 clk_disable_unprepare(efuse->clk);

 return 0;
}

static int rockchip_rk3328_efuse_read(void *context, unsigned int offset,
          void *val, size_t bytes)
{
 struct rockchip_efuse_chip *efuse = context;
 unsigned int addr_start, addr_end, addr_offset, addr_len;
 u32 out_value, status;
 u8 *buf;
 int ret, i = 0;

 ret = clk_prepare_enable(efuse->clk);
 if (ret < 0) {
  dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
  return ret;
 }

 /* 128 Byte efuse, 96 Byte for secure, 32 Byte for non-secure */
 offset += RK3328_SECURE_SIZES;
 addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
 addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
 addr_offset = offset % RK3399_NBYTES;
 addr_len = addr_end - addr_start;

 buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
        GFP_KERNEL);
 if (!buf) {
  ret = -ENOMEM;
  goto nomem;
 }

 while (addr_len--) {
  writel(RK3328_AUTO_RD | RK3328_AUTO_ENB |
         ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
         efuse->base + RK3328_AUTO_CTRL);
  udelay(4);
  status = readl(efuse->base + RK3328_INT_STATUS);
  if (!(status & RK3328_INT_FINISH)) {
   ret = -EIO;
   goto err;
  }
  out_value = readl(efuse->base + RK3328_DOUT);
  writel(RK3328_INT_FINISH, efuse->base + RK3328_INT_STATUS);

  memcpy(&buf[i], &out_value, RK3399_NBYTES);
  i += RK3399_NBYTES;
 }

 memcpy(val, buf + addr_offset, bytes);
err:
 kfree(buf);
nomem:
 clk_disable_unprepare(efuse->clk);

 return ret;
}

static int rockchip_rk3399_efuse_read(void *context, unsigned int offset,
          void *val, size_t bytes)
{
 struct rockchip_efuse_chip *efuse = context;
 unsigned int addr_start, addr_end, addr_offset, addr_len;
 u32 out_value;
 u8 *buf;
 int ret, i = 0;

 ret = clk_prepare_enable(efuse->clk);
 if (ret < 0) {
  dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
  return ret;
 }

 addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
 addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
 addr_offset = offset % RK3399_NBYTES;
 addr_len = addr_end - addr_start;

 buf = kzalloc(array3_size(addr_len, RK3399_NBYTES, sizeof(*buf)),
        GFP_KERNEL);
 if (!buf) {
  clk_disable_unprepare(efuse->clk);
  return -ENOMEM;
 }

 writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
        efuse->base + REG_EFUSE_CTRL);
 udelay(1);
 while (addr_len--) {
  writel(readl(efuse->base + REG_EFUSE_CTRL) | RK3399_STROBE |
         ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
         efuse->base + REG_EFUSE_CTRL);
  udelay(1);
  out_value = readl(efuse->base + REG_EFUSE_DOUT);
  writel(readl(efuse->base + REG_EFUSE_CTRL) & (~RK3399_STROBE),
         efuse->base + REG_EFUSE_CTRL);
  udelay(1);

  memcpy(&buf[i], &out_value, RK3399_NBYTES);
  i += RK3399_NBYTES;
 }

 /* Switch to standby mode */
 writel(RK3399_PD | RK3399_CSB, efuse->base + REG_EFUSE_CTRL);

 memcpy(val, buf + addr_offset, bytes);

 kfree(buf);

 clk_disable_unprepare(efuse->clk);

 return 0;
}

static struct nvmem_config econfig = {
 .name = "rockchip-efuse",
 .add_legacy_fixed_of_cells = true,
 .type = NVMEM_TYPE_OTP,
 .stride = 1,
 .word_size = 1,
 .read_only = true,
};

static const struct of_device_id rockchip_efuse_match[] = {
 /* deprecated but kept around for dts binding compatibility */
 {
  .compatible = "rockchip,rockchip-efuse",
  .data = (void *)&rockchip_rk3288_efuse_read,
 },
 {
  .compatible = "rockchip,rk3066a-efuse",
  .data = (void *)&rockchip_rk3288_efuse_read,
 },
 {
  .compatible = "rockchip,rk3188-efuse",
  .data = (void *)&rockchip_rk3288_efuse_read,
 },
 {
  .compatible = "rockchip,rk3228-efuse",
  .data = (void *)&rockchip_rk3288_efuse_read,
 },
 {
  .compatible = "rockchip,rk3288-efuse",
  .data = (void *)&rockchip_rk3288_efuse_read,
 },
 {
  .compatible = "rockchip,rk3368-efuse",
  .data = (void *)&rockchip_rk3288_efuse_read,
 },
 {
  .compatible = "rockchip,rk3328-efuse",
  .data = (void *)&rockchip_rk3328_efuse_read,
 },
 {
  .compatible = "rockchip,rk3399-efuse",
  .data = (void *)&rockchip_rk3399_efuse_read,
 },
 { /* sentinel */},
};
MODULE_DEVICE_TABLE(of, rockchip_efuse_match);

static int rockchip_efuse_probe(struct platform_device *pdev)
{
 struct resource *res;
 struct nvmem_device *nvmem;
 struct rockchip_efuse_chip *efuse;
 const void *data;
 struct device *dev = &pdev->dev;

 data = of_device_get_match_data(dev);
 if (!data) {
  dev_err(dev, "failed to get match data\n");
  return -EINVAL;
 }

 efuse = devm_kzalloc(dev, sizeof(struct rockchip_efuse_chip),
        GFP_KERNEL);
 if (!efuse)
  return -ENOMEM;

 efuse->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 if (IS_ERR(efuse->base))
  return PTR_ERR(efuse->base);

 efuse->clk = devm_clk_get(dev, "pclk_efuse");
 if (IS_ERR(efuse->clk))
  return PTR_ERR(efuse->clk);

 efuse->dev = dev;
 if (of_property_read_u32(dev->of_node, "rockchip,efuse-size",
     &econfig.size))
  econfig.size = resource_size(res);
 econfig.reg_read = data;
 econfig.priv = efuse;
 econfig.dev = efuse->dev;
 nvmem = devm_nvmem_register(dev, &econfig);

 return PTR_ERR_OR_ZERO(nvmem);
}

static struct platform_driver rockchip_efuse_driver = {
 .probe = rockchip_efuse_probe,
 .driver = {
  .name = "rockchip-efuse",
  .of_match_table = rockchip_efuse_match,
 },
};

module_platform_driver(rockchip_efuse_driver);
MODULE_DESCRIPTION("rockchip_efuse driver");
MODULE_LICENSE("GPL v2");

Messung V0.5
C=96 H=92 G=93

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.