diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index 5c8660374269..6ef9751e2509 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -15,7 +15,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -28,9 +29,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 { @@ -69,6 +72,8 @@ static const struct exynos_soc_id { { "EXYNOS990", 0xE9830000 }, { "EXYNOSAUTOV9", 0xAAA80000 }, { "EXYNOSAUTOV920", 0x0A920000 }, + /* Compatible with: google,gs101-otp */ + { "GS101", 0x9845000 }, }; static const char *exynos_product_id_to_name(unsigned int product_id) @@ -93,19 +98,53 @@ static int exynos_chipid_get_chipid_info(struct device *dev, return dev_err_probe(dev, ret, "failed to read Product ID\n"); 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 dev_err_probe(dev, ret, "failed to read revision\n"); + + 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_clk(&pdev->dev, "pclk", base, ®_config); +} + static void exynos_chipid_unregister_soc(void *data) { soc_device_unregister(data); @@ -127,7 +166,11 @@ static int exynos_chipid_probe(struct platform_device *pdev) return dev_err_probe(dev, -EINVAL, "failed to get match data\n"); - regmap = device_node_to_regmap(dev->of_node); + if (drv_data->efuse) + regmap = exynos_chipid_get_efuse_regmap(pdev); + else + regmap = device_node_to_regmap(dev->of_node); + if (IS_ERR(regmap)) return dev_err_probe(dev, PTR_ERR(regmap), "failed to get regmap\n"); @@ -177,19 +220,28 @@ static int exynos_chipid_probe(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, }, {