[PATCH v2 2/7] soc: samsung: exynos-chipid: add google,gs101-otp support
From: Tudor Ambarus <tudor.ambarus@linaro.org>
Date: 2025-11-18 13:56:21
Also in:
linux-devicetree, linux-samsung-soc, lkml
Subsystem:
arm/samsung s3c, s5p and exynos arm architectures, the rest · Maintainers:
Krzysztof Kozlowski, Peter Griffin, Linus Torvalds
GS101 is different (but also e850 and autov9 I assume) from the SoCs that are currently handled by the exynos-chipid driver because the chip ID info is part of the OTP registers. GS101 OTP has a clock, an interrupt line, a register space (that contains product and chip ID, TMU data, ASV, etc) and a 32Kbit memory space that can be read/program/locked with specific commands. On GS101 the "ChipID block" is just an abstraction, it's not a physical device. When the power-on sequence progresses, the OTP chipid values are loaded to the OTP registers. Add the GS101 chip ID support. The support is intentionally added in the exynos-chipid driver, and not in a dedicated Exynos OTP driver, because we estimate that there will not be any OTP consumers in the kernel other than the chip ID/SoC interface. The downstream GS101 drivers confirm this supposition. Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org> --- drivers/soc/samsung/exynos-chipid.c | 86 ++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 11 deletions(-)
diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c
index d3b4b5508e0c808ee9f7b0039073ef57915d60fc..8904ffdaf9a6f6d069cc6af18a24dd00a2780892 100644
--- a/drivers/soc/samsung/exynos-chipid.c
+++ b/drivers/soc/samsung/exynos-chipid.c@@ -13,8 +13,11 @@ */ #include <linux/array_size.h> +#include <linux/clk.h> #include <linux/device.h> -#include <linux/errno.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/ioport.h> #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h>
@@ -27,9 +30,11 @@ #include "exynos-asv.h" struct exynos_chipid_variant { - unsigned int rev_reg; /* revision register offset */ + unsigned int main_rev_reg; /* main revision register offset */ + unsigned int sub_rev_reg; /* sub revision register offset */ unsigned int main_rev_shift; /* main revision offset in rev_reg */ unsigned int sub_rev_shift; /* sub revision offset in rev_reg */ + bool efuse; }; struct exynos_chipid_info {
@@ -68,6 +73,8 @@ static const struct exynos_soc_id { { "EXYNOS990", 0xE9830000 }, { "EXYNOSAUTOV9", 0xAAA80000 }, { "EXYNOSAUTOV920", 0x0A920000 }, + /* Compatible with: google,gs101-otp */ + { "GS101", 0x9845000 }, }; static const char *product_id_to_soc_id(unsigned int product_id)
@@ -92,18 +99,52 @@ static int exynos_chipid_get_chipid_info(struct regmap *regmap, return ret; soc_info->product_id = val & EXYNOS_MASK; - if (data->rev_reg != EXYNOS_CHIPID_REG_PRO_ID) { - ret = regmap_read(regmap, data->rev_reg, &val); + if (data->sub_rev_reg == EXYNOS_CHIPID_REG_PRO_ID) { + /* exynos4210 case */ + main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK; + sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK; + } else { + unsigned int val2; + + ret = regmap_read(regmap, data->sub_rev_reg, &val2); if (ret < 0) return ret; + + if (data->main_rev_reg == EXYNOS_CHIPID_REG_PRO_ID) + /* gs101 case */ + main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK; + else + /* exynos850 case */ + main_rev = (val2 >> data->main_rev_shift) & EXYNOS_REV_PART_MASK; + + sub_rev = (val2 >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK; } - main_rev = (val >> data->main_rev_shift) & EXYNOS_REV_PART_MASK; - sub_rev = (val >> data->sub_rev_shift) & EXYNOS_REV_PART_MASK; + soc_info->revision = (main_rev << EXYNOS_REV_PART_SHIFT) | sub_rev; return 0; } +static struct regmap *exynos_chipid_get_efuse_regmap(struct platform_device *pdev) +{ + struct resource *res; + void __iomem *base; + + base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(base)) + return ERR_CAST(base); + + const struct regmap_config reg_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .use_relaxed_mmio = true, + .max_register = (resource_size(res) - reg_config.reg_stride), + }; + + return devm_regmap_init_mmio(&pdev->dev, base, ®_config); +} + static int exynos_chipid_probe(struct platform_device *pdev) { const struct exynos_chipid_variant *drv_data;
@@ -119,9 +160,23 @@ static int exynos_chipid_probe(struct platform_device *pdev) if (!drv_data) return -EINVAL; - regmap = device_node_to_regmap(dev->of_node); - if (IS_ERR(regmap)) - return PTR_ERR(regmap); + if (drv_data->efuse) { + struct clk *clk; + + regmap = exynos_chipid_get_efuse_regmap(pdev); + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "failed to get efuse regmap\n"); + + clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), + "failed to get clock\n"); + } else { + regmap = device_node_to_regmap(dev->of_node); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + } ret = exynos_chipid_get_chipid_info(regmap, drv_data, &soc_info); if (ret < 0)
@@ -177,19 +232,28 @@ static void exynos_chipid_remove(struct platform_device *pdev) } static const struct exynos_chipid_variant exynos4210_chipid_drv_data = { - .rev_reg = 0x0, .main_rev_shift = 4, .sub_rev_shift = 0, }; static const struct exynos_chipid_variant exynos850_chipid_drv_data = { - .rev_reg = 0x10, + .main_rev_reg = 0x10, + .sub_rev_reg = 0x10, .main_rev_shift = 20, .sub_rev_shift = 16, }; +static const struct exynos_chipid_variant gs101_chipid_drv_data = { + .sub_rev_reg = 0x10, + .sub_rev_shift = 16, + .efuse = true, +}; + static const struct of_device_id exynos_chipid_of_device_ids[] = { { + .compatible = "google,gs101-otp", + .data = &gs101_chipid_drv_data, + }, { .compatible = "samsung,exynos4210-chipid", .data = &exynos4210_chipid_drv_data, }, {
--
2.52.0.rc1.455.g30608eb744-goog