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 { "EXYNOS3250", 0xE3472000 }, 24 { "EXYNOS4210", 0x43200000 }, /* EVT0 revision */ 25 { "EXYNOS4210", 0x43210000 }, 26 { "EXYNOS4212", 0x43220000 }, 27 { "EXYNOS4412", 0xE4412000 }, 28 { "EXYNOS5250", 0x43520000 }, 29 { "EXYNOS5260", 0xE5260000 }, 30 { "EXYNOS5410", 0xE5410000 }, 31 { "EXYNOS5420", 0xE5420000 }, 32 { "EXYNOS5440", 0xE5440000 }, 33 { "EXYNOS5800", 0xE5422000 }, 34 { "EXYNOS7420", 0xE7420000 }, 35 { "EXYNOS5433", 0xE5433000 }, 36 }; 37 38 static const char * __init product_id_to_soc_id(unsigned int product_id) 39 { 40 int i; 41 42 for (i = 0; i < ARRAY_SIZE(soc_ids); i++) 43 if ((product_id & EXYNOS_MASK) == soc_ids[i].id) 44 return soc_ids[i].name; 45 return NULL; 46 } 47 48 static int __init exynos_chipid_early_init(void) 49 { 50 struct soc_device_attribute *soc_dev_attr; 51 struct soc_device *soc_dev; 52 struct device_node *root; 53 struct device_node *syscon; 54 struct regmap *regmap; 55 u32 product_id; 56 u32 revision; 57 int ret; 58 59 syscon = of_find_compatible_node(NULL, NULL, 60 "samsung,exynos4210-chipid"); 61 if (!syscon) 62 return ENODEV; 63 64 regmap = device_node_to_regmap(syscon); 65 of_node_put(syscon); 66 67 if (IS_ERR(regmap)) 68 return PTR_ERR(regmap); 69 70 ret = regmap_read(regmap, EXYNOS_CHIPID_REG_PRO_ID, &product_id); 71 if (ret < 0) 72 return ret; 73 74 revision = product_id & EXYNOS_REV_MASK; 75 76 soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); 77 if (!soc_dev_attr) 78 return -ENOMEM; 79 80 soc_dev_attr->family = "Samsung Exynos"; 81 82 root = of_find_node_by_path("/"); 83 of_property_read_string(root, "model", &soc_dev_attr->machine); 84 of_node_put(root); 85 86 soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%x", revision); 87 soc_dev_attr->soc_id = product_id_to_soc_id(product_id); 88 if (!soc_dev_attr->soc_id) { 89 pr_err("Unknown SoC\n"); 90 ret = -ENODEV; 91 goto err; 92 } 93 94 /* please note that the actual registration will be deferred */ 95 soc_dev = soc_device_register(soc_dev_attr); 96 if (IS_ERR(soc_dev)) { 97 ret = PTR_ERR(soc_dev); 98 goto err; 99 } 100 101 /* it is too early to use dev_info() here (soc_dev is NULL) */ 102 pr_info("soc soc0: Exynos: CPU[%s] PRO_ID[0x%x] REV[0x%x] Detected\n", 103 soc_dev_attr->soc_id, product_id, revision); 104 105 return 0; 106 107 err: 108 kfree(soc_dev_attr->revision); 109 kfree(soc_dev_attr); 110 return ret; 111 } 112 113 early_initcall(exynos_chipid_early_init); 114