1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2019 Samsung Electronics Co., Ltd. 4 * http://www.samsung.com/ 5 * 6 * Exynos - CHIP ID support 7 * Author: Pankaj Dubey <pankaj.dubey@samsung.com> 8 * Author: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com> 9 */ 10 11 #include <linux/io.h> 12 #include <linux/mfd/syscon.h> 13 #include <linux/of.h> 14 #include <linux/regmap.h> 15 #include <linux/slab.h> 16 #include <linux/soc/samsung/exynos-chipid.h> 17 #include <linux/sys_soc.h> 18 19 static const struct exynos_soc_id { 20 const char *name; 21 unsigned int id; 22 } soc_ids[] = { 23 /* List ordered by SoC name */ 24 { "EXYNOS3250", 0xE3472000 }, 25 { "EXYNOS4210", 0x43200000 }, /* EVT0 revision */ 26 { "EXYNOS4210", 0x43210000 }, 27 { "EXYNOS4212", 0x43220000 }, 28 { "EXYNOS4412", 0xE4412000 }, 29 { "EXYNOS5250", 0x43520000 }, 30 { "EXYNOS5260", 0xE5260000 }, 31 { "EXYNOS5410", 0xE5410000 }, 32 { "EXYNOS5420", 0xE5420000 }, 33 { "EXYNOS5433", 0xE5433000 }, 34 { "EXYNOS5440", 0xE5440000 }, 35 { "EXYNOS5800", 0xE5422000 }, 36 { "EXYNOS7420", 0xE7420000 }, 37 }; 38 39 static const char * __init product_id_to_soc_id(unsigned int product_id) 40 { 41 int i; 42 43 for (i = 0; i < ARRAY_SIZE(soc_ids); i++) 44 if ((product_id & EXYNOS_MASK) == soc_ids[i].id) 45 return soc_ids[i].name; 46 return NULL; 47 } 48 49 static int __init exynos_chipid_early_init(void) 50 { 51 struct soc_device_attribute *soc_dev_attr; 52 struct soc_device *soc_dev; 53 struct device_node *root; 54 struct device_node *syscon; 55 struct regmap *regmap; 56 u32 product_id; 57 u32 revision; 58 int ret; 59 60 syscon = of_find_compatible_node(NULL, NULL, 61 "samsung,exynos4210-chipid"); 62 if (!syscon) 63 return -ENODEV; 64 65 regmap = device_node_to_regmap(syscon); 66 of_node_put(syscon); 67 68 if (IS_ERR(regmap)) 69 return PTR_ERR(regmap); 70 71 ret = regmap_read(regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id); 72 if (ret < 0) 73 return ret; 74 75 revision = product_id & EXYNOS_REV_MASK; 76 77 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 78 if (!soc_dev_attr) 79 return -ENOMEM; 80 81 soc_dev_attr->family = "Samsung Exynos"; 82 83 root = of_find_node_by_path("/"); 84 of_property_read_string(root, "model", &soc_dev_attr->machine); 85 of_node_put(root); 86 87 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision); 88 soc_dev_attr->soc_id = product_id_to_soc_id(product_id); 89 if (!soc_dev_attr->soc_id) { 90 pr_err("Unknown SoC\n"); 91 ret = -ENODEV; 92 goto err; 93 } 94 95 /* please note that the actual registration will be deferred */ 96 soc_dev = soc_device_register(soc_dev_attr); 97 if (IS_ERR(soc_dev)) { 98 ret = PTR_ERR(soc_dev); 99 goto err; 100 } 101 102 dev_info(soc_device_to_device(soc_dev), 103 "Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n", 104 soc_dev_attr->soc_id, product_id, revision); 105 106 return 0; 107 108 err: 109 kfree(soc_dev_attr->revision); 110 kfree(soc_dev_attr); 111 return ret; 112 } 113 114 arch_initcall(exynos_chipid_early_init); 115