From 8bf9e48dfde18fd05cbd68de6356523e312a345b Mon Sep 17 00:00:00 2001 From: Algea Cao Date: Mon, 7 Mar 2022 18:35:16 +0800 Subject: [PATCH] nvmem: rk628-efuse: Support rk630 efuse Signed-off-by: Algea Cao Change-Id: I49e3b890d9fa98f569c36050c8ce830e85924923 --- drivers/nvmem/Kconfig | 1 + drivers/nvmem/rk628-efuse.c | 138 +++++++++++++++++++++++++++++------- include/linux/mfd/rk630.h | 8 +++ 3 files changed, 121 insertions(+), 26 deletions(-) diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index f3a9c13e98ab..9651f3feb7dc 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -105,6 +105,7 @@ config RK628_EFUSE depends on ARCH_ROCKCHIP || COMPILE_TEST depends on HAS_IOMEM depends on MFD_RK628 + default MFD_RK630 help This is a simple drive to dump specified values of Rk628 SoC from eFuse, such as cpu-leakage. diff --git a/drivers/nvmem/rk628-efuse.c b/drivers/nvmem/rk628-efuse.c index 04ee04d2a912..8c9a32dd6ced 100644 --- a/drivers/nvmem/rk628-efuse.c +++ b/drivers/nvmem/rk628-efuse.c @@ -21,6 +21,7 @@ #include #include #include +#include #define EFUSE_SIZE 64 @@ -58,6 +59,7 @@ #define EFUSE_REVISION 0x50 #define RK628_EFUSE_BASE 0xb0000 +#define RK630_EFUSE_BASE 0x50000 #define RK628_MOD 0x00 #define RK628_INT_STATUS 0x0018 #define RK628_DOUT 0x0020 @@ -75,11 +77,22 @@ #define REG_EFUSE_CTRL 0x0000 #define REG_EFUSE_DOUT 0x0004 +enum { + RK628_EFUSE, + RK630_EFUSE, +}; + +struct rk6xx_efuse_plat_data { + int device_type; + struct nvmem_config *econfig; +}; + struct rk628_efuse_chip { struct device *dev; u32 base; struct clk *clk; struct regmap *regmap; + struct regmap *cru; struct gpio_desc *avdd_gpio; }; @@ -158,12 +171,16 @@ static int rk628_efuse_read(void *context, unsigned int offset, unsigned int addr_start, addr_end, addr_offset, addr_len; u32 out_value, status; u8 *buf; - int ret, i = 0; + int ret = 0, i = 0; - ret = clk_prepare_enable(efuse->clk); - if (ret < 0) { - dev_err(efuse->dev, "failed to prepare/enable efuse pclk\n"); - return ret; + if (efuse->clk) { + ret = clk_prepare_enable(efuse->clk); + if (ret < 0) { + dev_err(efuse->dev, "failed to prepare/enable efuse pclk\n"); + return ret; + } + } else { + regmap_write(efuse->cru, CRU_GATE_CON0, PCLK_EFUSE_EN_MASK | PCLK_EFUSE_EN); } addr_start = rounddown(offset, RK628_NBYTES) / RK628_NBYTES; @@ -200,12 +217,15 @@ err: rk628_efuse_timing_deinit(efuse); kfree(buf); nomem: - clk_disable_unprepare(efuse->clk); + if (efuse->clk) + clk_disable_unprepare(efuse->clk); + else + regmap_write(efuse->cru, CRU_GATE_CON0, PCLK_EFUSE_EN_MASK); return ret; } -static struct nvmem_config econfig = { +static struct nvmem_config rk628_econfig = { .name = "rk628-efuse", .owner = THIS_MODULE, .stride = 1, @@ -213,6 +233,14 @@ static struct nvmem_config econfig = { .read_only = true, }; +static struct nvmem_config rk630_econfig = { + .name = "rk630-efuse", + .owner = THIS_MODULE, + .stride = 1, + .word_size = 1, + .read_only = true, +}; + static const struct regmap_range rk628_efuse_readable_ranges[] = { regmap_reg_range(RK628_EFUSE_BASE, RK628_EFUSE_BASE + EFUSE_REVISION), }; @@ -233,9 +261,45 @@ static const struct regmap_config rk628_efuse_regmap_config = { .rd_table = &rk628_efuse_readable_table, }; +static const struct regmap_range rk630_efuse_readable_ranges[] = { + regmap_reg_range(RK630_EFUSE_BASE, RK630_EFUSE_BASE + EFUSE_REVISION), +}; + +static const struct regmap_access_table rk630_efuse_readable_table = { + .yes_ranges = rk630_efuse_readable_ranges, + .n_yes_ranges = ARRAY_SIZE(rk630_efuse_readable_ranges), +}; + +const struct regmap_config rk630_efuse_regmap_config = { + .name = "rk630-efuse", + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .max_register = RK630_EFUSE_BASE + EFUSE_REVISION, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_LITTLE, + .rd_table = &rk630_efuse_readable_table, +}; +EXPORT_SYMBOL_GPL(rk630_efuse_regmap_config); + +static const struct rk6xx_efuse_plat_data rk628_efuse_drv_data = { + .device_type = RK628_EFUSE, + .econfig = &rk628_econfig, +}; + +static const struct rk6xx_efuse_plat_data rk630_efuse_drv_data = { + .device_type = RK630_EFUSE, + .econfig = &rk630_econfig, +}; + static const struct of_device_id rk628_efuse_match[] = { { .compatible = "rockchip,rk628-efuse", + .data = &rk628_efuse_drv_data + }, + { + .compatible = "rockchip,rk630-efuse", + .data = &rk630_efuse_drv_data }, { /* sentinel */ }, }; @@ -246,7 +310,8 @@ static int rk628_efuse_probe(struct platform_device *pdev) struct nvmem_device *nvmem; struct rk628_efuse_chip *efuse; struct device *dev = &pdev->dev; - struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent); + struct rk6xx_efuse_plat_data *plat_data; + const struct of_device_id *match; int ret; efuse = devm_kzalloc(&pdev->dev, sizeof(struct rk628_efuse_chip), @@ -254,29 +319,50 @@ static int rk628_efuse_probe(struct platform_device *pdev) if (!efuse) return -ENOMEM; - efuse->regmap = devm_regmap_init_i2c(rk628->client, - &rk628_efuse_regmap_config); - if (IS_ERR(efuse->regmap)) { - ret = PTR_ERR(efuse->regmap); - dev_err(dev, "failed to allocate register map: %d\n", - ret); - return ret; - } + match = of_match_node(rk628_efuse_match, pdev->dev.of_node); + plat_data = (struct rk6xx_efuse_plat_data *)match->data; + if (!plat_data) + return -ENOMEM; - efuse->clk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(efuse->clk)) { - dev_err(dev, "failed to get pclk: %ld\n", PTR_ERR(efuse->clk)); - return PTR_ERR(efuse->clk); + if (plat_data->device_type == RK628_EFUSE) { + struct rk628 *rk628 = dev_get_drvdata(pdev->dev.parent); + + efuse->regmap = devm_regmap_init_i2c(rk628->client, + &rk628_efuse_regmap_config); + if (IS_ERR(efuse->regmap)) { + ret = PTR_ERR(efuse->regmap); + dev_err(dev, "failed to allocate register map: %d\n", + ret); + return ret; + } + + efuse->clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(efuse->clk)) { + dev_err(dev, "failed to get pclk: %ld\n", PTR_ERR(efuse->clk)); + return PTR_ERR(efuse->clk); + } + + efuse->base = RK628_EFUSE_BASE; + } else { + struct rk630 *rk630 = dev_get_drvdata(pdev->dev.parent); + + efuse->regmap = rk630->efuse; + efuse->cru = rk630->cru; + efuse->base = RK630_EFUSE_BASE; + + if (!efuse->regmap | !efuse->cru) + return -ENODEV; + + efuse->clk = NULL; } efuse->avdd_gpio = devm_gpiod_get_optional(dev, "efuse", GPIOD_OUT_LOW); - efuse->base = RK628_EFUSE_BASE; efuse->dev = &pdev->dev; - econfig.size = EFUSE_SIZE; - econfig.reg_read = (void *)&rk628_efuse_read; - econfig.priv = efuse; - econfig.dev = efuse->dev; - nvmem = devm_nvmem_register(dev, &econfig); + plat_data->econfig->size = EFUSE_SIZE; + plat_data->econfig->reg_read = (void *)&rk628_efuse_read; + plat_data->econfig->priv = efuse; + plat_data->econfig->dev = efuse->dev; + nvmem = devm_nvmem_register(dev, plat_data->econfig); if (IS_ERR(nvmem)) return PTR_ERR(nvmem); diff --git a/include/linux/mfd/rk630.h b/include/linux/mfd/rk630.h index 4105a2bdad74..7f8feba721a8 100644 --- a/include/linux/mfd/rk630.h +++ b/include/linux/mfd/rk630.h @@ -13,9 +13,11 @@ #include #include +#ifndef HIWORD_UPDATE #define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) #define HIWORD_MASK(h, l) ((GENMASK((h), (l)) << 16) | GENMASK((h), (l))) #define HIWORD_UPDATE(v, h, l) ((((v) << (l)) & GENMASK((h), (l))) | (GENMASK((h), (l)) << 16)) +#endif #define RTC_REG(x) ((x) + 0x6000) #define RTC_SET_SECONDS RTC_REG(0x0) @@ -127,7 +129,9 @@ #define PLUMAGE_GRF_GPIO0_REN0 GRF_REG(0x0500) #define PLUMAGE_GRF_GPIO0_REN1 GRF_REG(0x0504) #define PLUMAGE_GRF_GPIO1_REN0 GRF_REG(0x0508) +#ifndef GRF_MAX_REGISTER #define GRF_MAX_REGISTER PLUMAGE_GRF_GPIO1_REN0 +#endif #define CRU_REG(x) ((x) + 0x140000) #define CRU_SPLL_CON0 CRU_REG(0x0000) @@ -154,6 +158,8 @@ #define CRU_CLKSEL_CON2 CRU_REG(0x0038) #define CRU_CLKSEL_CON3 CRU_REG(0x003c) #define CRU_GATE_CON0 CRU_REG(0x0040) +#define PCLK_EFUSE_EN_MASK BIT(14 + 16) +#define PCLK_EFUSE_EN BIT(14) #define DCLK_CVBS_1X_PLL_CLK_EN_MASK HIWORD_MASK(12, 12) #define DCLK_CVBS_1X_PLL_CLK_EN(x) HIWORD_UPDATE(x, 12, 12) #define DCLK_CVBS_4X_PLL_CLK_EN_MASK HIWORD_MASK(11, 11) @@ -221,12 +227,14 @@ struct rk630 { struct regmap *cru; struct regmap *tve; struct regmap *rtc; + struct regmap *efuse; struct gpio_desc *reset_gpio; int irq; struct regmap_irq_chip_data *irq_data; const struct regmap_irq_chip *regmap_irq_chip; }; +extern const struct regmap_config rk630_efuse_regmap_config; extern const struct regmap_config rk630_rtc_regmap_config; extern const struct regmap_config rk630_grf_regmap_config; extern const struct regmap_config rk630_cru_regmap_config;