lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAMz4kuLWAT0aXy=xNPaeBDdixZCxUoE+joWsLMXb6MrmRiBr1Q@mail.gmail.com>
Date:   Mon, 9 Jul 2018 17:26:21 +0800
From:   Baolin Wang <baolin.wang@...aro.org>
To:     Srinivas Kandagatla <srinivas.kandagatla@...aro.org>,
        Rob Herring <robh+dt@...nel.org>,
        Mark Rutland <mark.rutland@....com>
Cc:     Mark Brown <broonie@...nel.org>, freeman.liu@...eadtrum.com,
        Baolin Wang <baolin.wang@...aro.org>,
        DTML <devicetree@...r.kernel.org>,
        LKML <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v2 2/2] nvmem: Add Spreadtrum SC27XX efuse support

Hi Srinivas,

On 25 June 2018 at 14:31, Baolin Wang <baolin.wang@...aro.org> wrote:
> From: Freeman Liu <freeman.liu@...eadtrum.com>
>
> This patch add the efuse driver which is embeded in Spreadtrum SC27XX
> series PMICs. The sc27xx efuse contains 32 blocks and each block's
> data width is 16 bits.
>
> Signed-off-by: Freeman Liu <freeman.liu@...eadtrum.com>
> Signed-off-by: Baolin Wang <baolin.wang@...aro.org>
> ---
> Changes since v1:
>  - Fix one typo.
> ---

Do you have any comments for this patch set? Thanks.

>  drivers/nvmem/Kconfig        |   11 ++
>  drivers/nvmem/Makefile       |    3 +-
>  drivers/nvmem/sc27xx-efuse.c |  263 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 276 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/nvmem/sc27xx-efuse.c
>
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index 54a3c29..0a7a470e 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -181,4 +181,15 @@ config RAVE_SP_EEPROM
>         help
>           Say y here to enable Rave SP EEPROM support.
>
> +config SC27XX_EFUSE
> +       tristate "Spreadtrum SC27XX eFuse Support"
> +       depends on MFD_SC27XX_PMIC || COMPILE_TEST
> +       depends on HAS_IOMEM
> +       help
> +         This is a simple driver to dump specified values of Spreadtrum
> +         SC27XX PMICs from eFuse.
> +
> +         This driver can also be built as a module. If so, the module
> +         will be called nvmem-sc27xx-efuse.
> +
>  endif
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index 27e96a8..4e8c616 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -39,4 +39,5 @@ obj-$(CONFIG_NVMEM_SNVS_LPGPR)        += nvmem_snvs_lpgpr.o
>  nvmem_snvs_lpgpr-y             := snvs_lpgpr.o
>  obj-$(CONFIG_RAVE_SP_EEPROM)   += nvmem-rave-sp-eeprom.o
>  nvmem-rave-sp-eeprom-y         := rave-sp-eeprom.o
> -
> +obj-$(CONFIG_SC27XX_EFUSE)     += nvmem-sc27xx-efuse.o
> +nvmem-sc27xx-efuse-y           := sc27xx-efuse.o
> diff --git a/drivers/nvmem/sc27xx-efuse.c b/drivers/nvmem/sc27xx-efuse.c
> new file mode 100644
> index 0000000..07c210c
> --- /dev/null
> +++ b/drivers/nvmem/sc27xx-efuse.c
> @@ -0,0 +1,263 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2018 Spreadtrum Communications Inc.
> +
> +#include <linux/hwspinlock.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/nvmem-provider.h>
> +
> +/* PMIC global registers definition */
> +#define SC27XX_MODULE_EN               0xc08
> +#define SC27XX_EFUSE_EN                        BIT(6)
> +
> +/* Efuse controller registers definition */
> +#define SC27XX_EFUSE_GLB_CTRL          0x0
> +#define SC27XX_EFUSE_DATA_RD           0x4
> +#define SC27XX_EFUSE_DATA_WR           0x8
> +#define SC27XX_EFUSE_BLOCK_INDEX       0xc
> +#define SC27XX_EFUSE_MODE_CTRL         0x10
> +#define SC27XX_EFUSE_STATUS            0x14
> +#define SC27XX_EFUSE_WR_TIMING_CTRL    0x20
> +#define SC27XX_EFUSE_RD_TIMING_CTRL    0x24
> +#define SC27XX_EFUSE_EFUSE_DEB_CTRL    0x28
> +
> +/* Mask definition for SC27XX_EFUSE_BLOCK_INDEX register */
> +#define SC27XX_EFUSE_BLOCK_MASK                GENMASK(4, 0)
> +
> +/* Bits definitions for SC27XX_EFUSE_MODE_CTRL register */
> +#define SC27XX_EFUSE_PG_START          BIT(0)
> +#define SC27XX_EFUSE_RD_START          BIT(1)
> +#define SC27XX_EFUSE_CLR_RDDONE                BIT(2)
> +
> +/* Bits definitions for SC27XX_EFUSE_STATUS register */
> +#define SC27XX_EFUSE_PGM_BUSY          BIT(0)
> +#define SC27XX_EFUSE_READ_BUSY         BIT(1)
> +#define SC27XX_EFUSE_STANDBY           BIT(2)
> +#define SC27XX_EFUSE_GLOBAL_PROT       BIT(3)
> +#define SC27XX_EFUSE_RD_DONE           BIT(4)
> +
> +/* Block number and block width (bytes) definitions */
> +#define SC27XX_EFUSE_BLOCK_MAX         32
> +#define SC27XX_EFUSE_BLOCK_WIDTH       2
> +
> +/* Timeout (ms) for the trylock of hardware spinlocks */
> +#define SC27XX_EFUSE_HWLOCK_TIMEOUT    5000
> +
> +/* Timeout (us) of polling the status */
> +#define SC27XX_EFUSE_POLL_TIMEOUT      3000000
> +#define SC27XX_EFUSE_POLL_DELAY_US     10000
> +
> +struct sc27xx_efuse {
> +       struct device *dev;
> +       struct regmap *regmap;
> +       struct hwspinlock *hwlock;
> +       struct mutex mutex;
> +       u32 base;
> +};
> +
> +/*
> + * On Spreadtrum platform, we have multi-subsystems will access the unique
> + * efuse controller, so we need one hardware spinlock to synchronize between
> + * the multiple subsystems.
> + */
> +static int sc27xx_efuse_lock(struct sc27xx_efuse *efuse)
> +{
> +       int ret;
> +
> +       mutex_lock(&efuse->mutex);
> +
> +       ret = hwspin_lock_timeout_raw(efuse->hwlock,
> +                                     SC27XX_EFUSE_HWLOCK_TIMEOUT);
> +       if (ret) {
> +               dev_err(efuse->dev, "timeout to get the hwspinlock\n");
> +               mutex_unlock(&efuse->mutex);
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static void sc27xx_efuse_unlock(struct sc27xx_efuse *efuse)
> +{
> +       hwspin_unlock_raw(efuse->hwlock);
> +       mutex_unlock(&efuse->mutex);
> +}
> +
> +static int sc27xx_efuse_poll_status(struct sc27xx_efuse *efuse, u32 bits)
> +{
> +       int ret;
> +       u32 val;
> +
> +       ret = regmap_read_poll_timeout(efuse->regmap,
> +                                      efuse->base + SC27XX_EFUSE_STATUS,
> +                                      val, (val & bits),
> +                                      SC27XX_EFUSE_POLL_DELAY_US,
> +                                      SC27XX_EFUSE_POLL_TIMEOUT);
> +       if (ret) {
> +               dev_err(efuse->dev, "timeout to update the efuse status\n");
> +               return ret;
> +       }
> +
> +       return 0;
> +}
> +
> +static int sc27xx_efuse_read(void *context, u32 offset, void *val, size_t bytes)
> +{
> +       struct sc27xx_efuse *efuse = context;
> +       u32 buf;
> +       int ret;
> +
> +       if (offset > SC27XX_EFUSE_BLOCK_MAX || bytes > SC27XX_EFUSE_BLOCK_WIDTH)
> +               return -EINVAL;
> +
> +       ret = sc27xx_efuse_lock(efuse);
> +       if (ret)
> +               return ret;
> +
> +       /* Enable the efuse controller. */
> +       ret = regmap_update_bits(efuse->regmap, SC27XX_MODULE_EN,
> +                                SC27XX_EFUSE_EN, SC27XX_EFUSE_EN);
> +       if (ret)
> +               goto unlock_efuse;
> +
> +       /*
> +        * Before reading, we should ensure the efuse controller is in
> +        * standby state.
> +        */
> +       ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_STANDBY);
> +       if (ret)
> +               goto disable_efuse;
> +
> +       /* Set the block address to be read. */
> +       ret = regmap_write(efuse->regmap, efuse->base + SC27XX_EFUSE_BLOCK_INDEX,
> +                          offset & SC27XX_EFUSE_BLOCK_MASK);
> +       if (ret)
> +               goto disable_efuse;
> +
> +       /* Start reading process from efuse memory. */
> +       ret = regmap_update_bits(efuse->regmap,
> +                                efuse->base + SC27XX_EFUSE_MODE_CTRL,
> +                                SC27XX_EFUSE_RD_START,
> +                                SC27XX_EFUSE_RD_START);
> +       if (ret)
> +               goto disable_efuse;
> +
> +       /*
> +        * Polling the read done status to make sure the reading process
> +        * is completed, that means the data can be read out now.
> +        */
> +       ret = sc27xx_efuse_poll_status(efuse, SC27XX_EFUSE_RD_DONE);
> +       if (ret)
> +               goto disable_efuse;
> +
> +       /* Read data from efuse memory. */
> +       ret = regmap_read(efuse->regmap, efuse->base + SC27XX_EFUSE_DATA_RD,
> +                         &buf);
> +       if (ret)
> +               goto disable_efuse;
> +
> +       /* Clear the read done flag. */
> +       ret = regmap_update_bits(efuse->regmap,
> +                                efuse->base + SC27XX_EFUSE_MODE_CTRL,
> +                                SC27XX_EFUSE_CLR_RDDONE,
> +                                SC27XX_EFUSE_CLR_RDDONE);
> +
> +disable_efuse:
> +       /* Disable the efuse controller after reading. */
> +       regmap_update_bits(efuse->regmap, SC27XX_MODULE_EN, SC27XX_EFUSE_EN, 0);
> +unlock_efuse:
> +       sc27xx_efuse_unlock(efuse);
> +
> +       if (!ret)
> +               memcpy(val, &buf, bytes);
> +
> +       return ret;
> +}
> +
> +static int sc27xx_efuse_probe(struct platform_device *pdev)
> +{
> +       struct device_node *np = pdev->dev.of_node;
> +       struct nvmem_config econfig = { };
> +       struct nvmem_device *nvmem;
> +       struct sc27xx_efuse *efuse;
> +       int ret;
> +
> +       efuse = devm_kzalloc(&pdev->dev, sizeof(*efuse), GFP_KERNEL);
> +       if (!efuse)
> +               return -ENOMEM;
> +
> +       efuse->regmap = dev_get_regmap(pdev->dev.parent, NULL);
> +       if (!efuse->regmap) {
> +               dev_err(&pdev->dev, "failed to get efuse regmap\n");
> +               return -ENODEV;
> +       }
> +
> +       ret = of_property_read_u32(np, "reg", &efuse->base);
> +       if (ret) {
> +               dev_err(&pdev->dev, "failed to get efuse base address\n");
> +               return ret;
> +       }
> +
> +       ret = of_hwspin_lock_get_id(np, 0);
> +       if (ret < 0) {
> +               dev_err(&pdev->dev, "failed to get hwspinlock id\n");
> +               return ret;
> +       }
> +
> +       efuse->hwlock = hwspin_lock_request_specific(ret);
> +       if (!efuse->hwlock) {
> +               dev_err(&pdev->dev, "failed to request hwspinlock\n");
> +               return -ENXIO;
> +       }
> +
> +       mutex_init(&efuse->mutex);
> +       efuse->dev = &pdev->dev;
> +       platform_set_drvdata(pdev, efuse);
> +
> +       econfig.stride = 1;
> +       econfig.word_size = 1;
> +       econfig.read_only = true;
> +       econfig.name = "sc27xx-efuse";
> +       econfig.size = SC27XX_EFUSE_BLOCK_MAX * SC27XX_EFUSE_BLOCK_WIDTH;
> +       econfig.reg_read = sc27xx_efuse_read;
> +       econfig.priv = efuse;
> +       econfig.dev = &pdev->dev;
> +       nvmem = devm_nvmem_register(&pdev->dev, &econfig);
> +       if (IS_ERR(nvmem)) {
> +               dev_err(&pdev->dev, "failed to register nvmem config\n");
> +               hwspin_lock_free(efuse->hwlock);
> +               return PTR_ERR(nvmem);
> +       }
> +
> +       return 0;
> +}
> +
> +static int sc27xx_efuse_remove(struct platform_device *pdev)
> +{
> +       struct sc27xx_efuse *efuse = platform_get_drvdata(pdev);
> +
> +       hwspin_lock_free(efuse->hwlock);
> +       return 0;
> +}
> +
> +static const struct of_device_id sc27xx_efuse_of_match[] = {
> +       { .compatible = "sprd,sc2731-efuse" },
> +       { }
> +};
> +
> +static struct platform_driver sc27xx_efuse_driver = {
> +       .probe = sc27xx_efuse_probe,
> +       .remove = sc27xx_efuse_remove,
> +       .driver = {
> +               .name = "sc27xx-efuse",
> +               .of_match_table = sc27xx_efuse_of_match,
> +       },
> +};
> +
> +module_platform_driver(sc27xx_efuse_driver);
> +
> +MODULE_AUTHOR("Freeman Liu <freeman.liu@...eadtrum.com>");
> +MODULE_DESCRIPTION("Spreadtrum SC27xx efuse driver");
> +MODULE_LICENSE("GPL v2");
> --
> 1.7.9.5
>



-- 
Baolin Wang
Best Regards

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ