All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jagan Teki <jagan@amarulasolutions.com>
To: u-boot@lists.denx.de
Subject: [PATCH v6 01/17] misc: add driver for the SiFive otp controller
Date: Thu, 2 Apr 2020 14:45:30 +0530	[thread overview]
Message-ID: <CAMty3ZCgTkCTXtuBtWRwQVFTbDxqS4Nj8sTLgxJ=7FSwE8jCLg@mail.gmail.com> (raw)
In-Reply-To: <20200329170538.25449-2-pragnesh.patel@sifive.com>

On Sun, Mar 29, 2020 at 10:36 PM Pragnesh Patel
<pragnesh.patel@sifive.com> wrote:
>
> Added a misc driver to handle OTP memory in SiFive SoCs.
>
> Signed-off-by: Pragnesh Patel <pragnesh.patel@sifive.com>
> ---
>  drivers/misc/Kconfig      |   7 ++
>  drivers/misc/Makefile     |   1 +
>  drivers/misc/sifive-otp.c | 255 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 263 insertions(+)
>  create mode 100644 drivers/misc/sifive-otp.c
>
> diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
> index f18aa8f7ba..5caf61d077 100644
> --- a/drivers/misc/Kconfig
> +++ b/drivers/misc/Kconfig
> @@ -68,6 +68,13 @@ config ROCKCHIP_OTP
>           addressing and a length or through child-nodes that are generated
>           based on the e-fuse map retrieved from the DTS.
>
> +config SIFIVE_OTP
> +       bool "SiFive eMemory OTP driver"
> +       depends on RISCV && MISC
> +       help
> +         Enable support for reading and writing the eMemory OTP on the
> +         SiFive SoCs.
> +
>  config VEXPRESS_CONFIG
>         bool "Enable support for Arm Versatile Express config bus"
>         depends on MISC
> diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
> index 2b843de93c..ee888631b6 100644
> --- a/drivers/misc/Makefile
> +++ b/drivers/misc/Makefile
> @@ -58,6 +58,7 @@ obj-$(CONFIG_$(SPL_)PWRSEQ) += pwrseq-uclass.o
>  obj-$(CONFIG_QFW) += qfw.o
>  obj-$(CONFIG_ROCKCHIP_EFUSE) += rockchip-efuse.o
>  obj-$(CONFIG_ROCKCHIP_OTP) += rockchip-otp.o
> +obj-$(CONFIG_SIFIVE_OTP) += sifive-otp.o
>  obj-$(CONFIG_SANDBOX) += syscon_sandbox.o misc_sandbox.o
>  obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o
>  obj-$(CONFIG_SMSC_SIO1007) += smsc_sio1007.o
> diff --git a/drivers/misc/sifive-otp.c b/drivers/misc/sifive-otp.c
> new file mode 100644
> index 0000000000..c1c2386b97
> --- /dev/null
> +++ b/drivers/misc/sifive-otp.c
> @@ -0,0 +1,255 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * This is a driver for the eMemory EG004K32TQ028XW01 NeoFuse
> + * One-Time-Programmable (OTP) memory used within the SiFive FU540.
> + * It is documented in the FU540 manual here:
> + * https://www.sifive.com/documentation/chips/freedom-u540-c000-manual/
> + *
> + * Copyright (C) 2018 Philipp Hug <philipp@hug.cx>
> + * Copyright (C) 2018 Joey Hewitt <joey@joeyhewitt.com>
> + *
> + * Copyright (C) 2020 SiFive, Inc
> + */
> +
> +/*
> + * The FU540 stores 4096x32 bit (16KiB) values.
> + * Index 0x00-0xff are reserved for SiFive internal use. (first 1KiB)
> + * Right now first 1KiB is used to store only serial number.
> + */
> +
> +#include <common.h>
> +#include <dm/device.h>
> +#include <dm/read.h>
> +#include <linux/io.h>
> +#include <misc.h>
> +
> +#define BYTES_PER_FUSE         4
> +
> +#define PA_RESET_VAL           0x00
> +#define PAS_RESET_VAL          0x00
> +#define PAIO_RESET_VAL         0x00
> +#define PDIN_RESET_VAL         0x00
> +#define PTM_RESET_VAL          0x00
> +
> +#define PCLK_ENABLE_VAL                        BIT(0)
> +#define PCLK_DISABLE_VAL               0x00
> +
> +#define PWE_WRITE_ENABLE               BIT(0)
> +#define PWE_WRITE_DISABLE              0x00
> +
> +#define PTM_FUSE_PROGRAM_VAL           BIT(1)
> +
> +#define PCE_ENABLE_INPUT               BIT(0)
> +#define PCE_DISABLE_INPUT              0x00
> +
> +#define PPROG_ENABLE_INPUT             BIT(0)
> +#define PPROG_DISABLE_INPUT            0x00
> +
> +#define PTRIM_ENABLE_INPUT             BIT(0)
> +#define PTRIM_DISABLE_INPUT            0x00
> +
> +#define PDSTB_DEEP_STANDBY_ENABLE      BIT(0)
> +#define PDSTB_DEEP_STANDBY_DISABLE     0x00
> +
> +struct sifive_otp_regs {
> +       u32 pa;     /* Address input */
> +       u32 paio;   /* Program address input */
> +       u32 pas;    /* Program redundancy cell selection input */
> +       u32 pce;    /* OTP Macro enable input */
> +       u32 pclk;   /* Clock input */
> +       u32 pdin;   /* Write data input */
> +       u32 pdout;  /* Read data output */
> +       u32 pdstb;  /* Deep standby mode enable input (active low) */
> +       u32 pprog;  /* Program mode enable input */
> +       u32 ptc;    /* Test column enable input */
> +       u32 ptm;    /* Test mode enable input */
> +       u32 ptm_rep;/* Repair function test mode enable input */
> +       u32 ptr;    /* Test row enable input */
> +       u32 ptrim;  /* Repair function enable input */
> +       u32 pwe;    /* Write enable input (defines program cycle) */
> +};
> +
> +struct sifive_otp_platdata {
> +       struct sifive_otp_regs __iomem *regs;
> +       u32 total_fuses;
> +};
> +
> +/*
> + * offset and size are assumed aligned to the size of the fuses (32-bit).
> + */
> +static int sifive_otp_read(struct udevice *dev, int offset,
> +                          void *buf, int size)
> +{
> +       struct sifive_otp_platdata *plat = dev_get_platdata(dev);
> +       struct sifive_otp_regs *regs = (struct sifive_otp_regs *)plat->regs;
> +
> +       /* Check if offset and size are multiple of BYTES_PER_FUSE */
> +       if ((size % BYTES_PER_FUSE) || (offset % BYTES_PER_FUSE)) {
> +               printf("%s: size and offset must be multiple of 4.\n",
> +                      __func__);
> +               return -EINVAL;
> +       }
> +
> +       int fuseidx = offset / BYTES_PER_FUSE;
> +       int fusecount = size / BYTES_PER_FUSE;
> +
> +       /* check bounds */
> +       if (offset < 0 || size < 0)
> +               return -EINVAL;
> +       if (fuseidx >= plat->total_fuses)
> +               return -EINVAL;
> +       if ((fuseidx + fusecount) > plat->total_fuses)
> +               return -EINVAL;
> +
> +       u32 fusebuf[fusecount];
> +
> +       /* init OTP */
> +       writel(PDSTB_DEEP_STANDBY_ENABLE, &regs->pdstb);
> +       writel(PTRIM_ENABLE_INPUT, &regs->ptrim);
> +       writel(PCE_ENABLE_INPUT, &regs->pce);
> +
> +       /* read all requested fuses */
> +       for (unsigned int i = 0; i < fusecount; i++, fuseidx++) {
> +               writel(fuseidx, &regs->pa);
> +
> +               /* cycle clock to read */
> +               writel(PCLK_ENABLE_VAL, &regs->pclk);
> +               mdelay(1);
> +               writel(PCLK_DISABLE_VAL, &regs->pclk);
> +               mdelay(1);
> +
> +               /* read the value */
> +               fusebuf[i] = readl(&regs->pdout);
> +       }
> +
> +       /* shut down */
> +       writel(PCE_DISABLE_INPUT, &regs->pce);
> +       writel(PTRIM_DISABLE_INPUT, &regs->ptrim);
> +       writel(PDSTB_DEEP_STANDBY_DISABLE, &regs->pdstb);
> +
> +       /* copy out */
> +       memcpy(buf, fusebuf, size);
> +
> +       return size;
> +}
> +
> +/*
> + * Caution:
> + * OTP can be written only once, so use carefully.
> + *
> + * offset and size are assumed aligned to the size of the fuses (32-bit).
> + */
> +static int sifive_otp_write(struct udevice *dev, int offset,
> +                           const void *buf, int size)
> +{
> +       struct sifive_otp_platdata *plat = dev_get_platdata(dev);
> +       struct sifive_otp_regs *regs = (struct sifive_otp_regs *)plat->regs;
> +
> +       /* Check if offset and size are multiple of BYTES_PER_FUSE */
> +       if ((size % BYTES_PER_FUSE) || (offset % BYTES_PER_FUSE)) {
> +               printf("%s: size and offset must be multiple of 4.\n",
> +                      __func__);
> +               return -EINVAL;
> +       }
> +
> +       int fuseidx = offset / BYTES_PER_FUSE;
> +       int fusecount = size / BYTES_PER_FUSE;
> +       u32 *write_buf = (u32 *)buf;
> +       u32 write_data;
> +       int i, pas, bit;
> +
> +       /* check bounds */
> +       if (offset < 0 || size < 0)
> +               return -EINVAL;
> +       if (fuseidx >= plat->total_fuses)
> +               return -EINVAL;
> +       if ((fuseidx + fusecount) > plat->total_fuses)
> +               return -EINVAL;
> +
> +       /* init OTP */
> +       writel(PDSTB_DEEP_STANDBY_ENABLE, &regs->pdstb);
> +       writel(PTRIM_ENABLE_INPUT, &regs->ptrim);
> +
> +       /* reset registers */
> +       writel(PCLK_DISABLE_VAL, &regs->pclk);
> +       writel(PA_RESET_VAL, &regs->pa);
> +       writel(PAS_RESET_VAL, &regs->pas);
> +       writel(PAIO_RESET_VAL, &regs->paio);
> +       writel(PDIN_RESET_VAL, &regs->pdin);
> +       writel(PWE_WRITE_DISABLE, &regs->pwe);
> +       writel(PTM_FUSE_PROGRAM_VAL, &regs->ptm);
> +       mdelay(1);
> +
> +       writel(PCE_ENABLE_INPUT, &regs->pce);
> +       writel(PPROG_ENABLE_INPUT, &regs->pprog);
> +
> +       /* write all requested fuses */
> +       for (i = 0; i < fusecount; i++, fuseidx++) {
> +               writel(fuseidx, &regs->pa);
> +               write_data = *(write_buf++);
> +
> +               for (pas = 0; pas < 2; pas++) {
> +                       writel(pas, &regs->pas);
> +
> +                       for (bit = 0; bit < 32; bit++) {
> +                               writel(bit, &regs->paio);
> +                               writel(((write_data >> bit) & 1),
> +                                      &regs->pdin);
> +                               mdelay(1);
> +
> +                               writel(PWE_WRITE_ENABLE, &regs->pwe);
> +                               mdelay(1);
> +                               writel(PWE_WRITE_DISABLE, &regs->pwe);
> +                               mdelay(1);

are these delays with 1msec are based on the otp programming sequence,
if yes please add comments on that. rest looks good to me.

Jagan.

  reply	other threads:[~2020-04-02  9:15 UTC|newest]

Thread overview: 76+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-29 17:05 [PATCH v6 00/17] RISC-V SiFive FU540 support SPL Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 01/17] misc: add driver for the SiFive otp controller Pragnesh Patel
2020-04-02  9:15   ` Jagan Teki [this message]
2020-04-02 10:54     ` Pragnesh Patel
2020-04-20  8:05   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 02/17] riscv: sifive: fu540: Use OTP DM driver for serial environment variable Pragnesh Patel
2020-04-02  9:19   ` Jagan Teki
2020-04-02  9:24     ` Pragnesh Patel
2020-04-02  9:29       ` Jagan Teki
2020-04-02 10:17         ` Pragnesh Patel
2020-04-07  8:02           ` Jagan Teki
2020-04-07  8:10             ` Pragnesh Patel
2020-04-07  9:21               ` Jagan Teki
2020-04-08  4:44                 ` Pragnesh Patel
2020-04-20  6:30                   ` Bin Meng
2020-04-20  7:54                 ` Bin Meng
2020-04-20  8:15                   ` Jagan Teki
2020-04-20  8:18                     ` Bin Meng
2020-04-20  8:05   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 03/17] riscv: Add _image_binary_end for SPL Pragnesh Patel
2020-04-20  8:05   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 04/17] lib: Makefile: build crc7.c when CONFIG_MMC_SPI Pragnesh Patel
2020-04-02  9:20   ` Jagan Teki
2020-04-20  8:05   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 05/17] riscv: sifive: dts: fu540: Add board -u-boot.dtsi files Pragnesh Patel
2020-04-02  9:24   ` Jagan Teki
2020-03-29 17:05 ` [PATCH v6 06/17] sifive: fu540: add ddr driver Pragnesh Patel
2020-04-06 19:27   ` Jagan Teki
2020-04-08  7:41     ` Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 07/17] sifive: dts: fu540: Add DDR controller and phy register settings Pragnesh Patel
2020-04-06 19:30   ` Jagan Teki
2020-04-08  4:54     ` Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 08/17] clk: sifive: fu540-prci: Add clock enable and disable ops Pragnesh Patel
2020-04-20  9:02   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 09/17] clk: sifive: fu540-prci: Add clock initialization for SPL Pragnesh Patel
2020-04-06 19:35   ` Jagan Teki
2020-04-20  9:00     ` Bin Meng
2020-04-24 10:08       ` Pragnesh Patel
2020-04-24 13:00         ` Bin Meng
2020-04-24 13:34           ` Pragnesh Patel
2020-04-24 13:55             ` Bin Meng
2020-04-24 16:27               ` Pragnesh Patel
2020-04-25  1:32                 ` Bin Meng
2020-04-26 10:00     ` Pragnesh Patel
2020-04-27  1:24       ` Bin Meng
2020-04-28 13:56         ` Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 10/17] riscv: dts: sifive: Sync hifive-unleashed-a00 dts from linux Pragnesh Patel
2020-04-06 19:37   ` Jagan Teki
2020-04-08  6:52     ` Pragnesh Patel
2020-04-20  9:02   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 11/17] sifive: dts: fu540: Enable gpio in U-Boot SPL Pragnesh Patel
2020-04-20  9:34   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 12/17] riscv: sifive: fu540: add SPL configuration Pragnesh Patel
2020-04-20  9:35   ` Bin Meng
2020-04-24 13:57     ` Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 13/17] configs: fu540: Add config options for U-Boot SPL Pragnesh Patel
2020-04-20  9:35   ` Bin Meng
2020-04-24 14:06     ` Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 14/17] sifive: dts: fu540: Enable L2 Cache in U-Boot Pragnesh Patel
2020-04-20  9:35   ` Bin Meng
2020-03-29 17:05 ` [PATCH v6 15/17] riscv: sifive: fu540: enable all cache ways from u-boot proper Pragnesh Patel
2020-04-20  9:35   ` Bin Meng
2020-04-24 14:08     ` Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 16/17] sifive: fix palmer's email address Pragnesh Patel
2020-04-06 19:43   ` Jagan Teki
2020-04-08  4:45     ` Pragnesh Patel
2020-03-29 17:05 ` [PATCH v6 17/17] doc: update FU540 RISC-V documentation Pragnesh Patel
2020-04-20  9:46   ` Bin Meng
2020-04-24 14:10     ` Pragnesh Patel
2020-04-02  9:12 ` [PATCH v6 00/17] RISC-V SiFive FU540 support SPL Jagan Teki
2020-04-02  9:42   ` Pragnesh Patel
2020-04-02  9:49     ` Jagan Teki
2020-04-07  9:32 ` Jagan Teki
2020-04-08  4:42   ` Pragnesh Patel
2020-04-20 14:42     ` Bin Meng
2020-04-21  4:29       ` Pragnesh Patel

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAMty3ZCgTkCTXtuBtWRwQVFTbDxqS4Nj8sTLgxJ=7FSwE8jCLg@mail.gmail.com' \
    --to=jagan@amarulasolutions.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.