1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* Copyright 2019 IBM Corp. */ 3 4 #include <linux/io.h> 5 #include <linux/of.h> 6 #include <linux/of_address.h> 7 #include <linux/of_platform.h> 8 #include <linux/platform_device.h> 9 #include <linux/slab.h> 10 #include <linux/sys_soc.h> 11 12 static struct { 13 const char *name; 14 const u32 id; 15 } const rev_table[] = { 16 /* AST2400 */ 17 { "AST2400", 0x02000303 }, 18 { "AST1400", 0x02010103 }, 19 { "AST1250", 0x02010303 }, 20 /* AST2500 */ 21 { "AST2500", 0x04000303 }, 22 { "AST2510", 0x04000103 }, 23 { "AST2520", 0x04000203 }, 24 { "AST2530", 0x04000403 }, 25 /* AST2600 */ 26 { "AST2600", 0x05000303 }, 27 { "AST2620", 0x05010203 }, 28 { "AST2605", 0x05030103 }, 29 { "AST2625", 0x05030403 }, 30 }; 31 32 static const char *siliconid_to_name(u32 siliconid) 33 { 34 unsigned int id = siliconid & 0xff00ffff; 35 unsigned int i; 36 37 for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) { 38 if (rev_table[i].id == id) 39 return rev_table[i].name; 40 } 41 42 return "Unknown"; 43 } 44 45 static const char *siliconid_to_rev(u32 siliconid) 46 { 47 unsigned int rev = (siliconid >> 16) & 0xff; 48 unsigned int gen = (siliconid >> 24) & 0xff; 49 50 if (gen < 0x5) { 51 /* AST2500 and below */ 52 switch (rev) { 53 case 0: 54 return "A0"; 55 case 1: 56 return "A1"; 57 case 3: 58 return "A2"; 59 } 60 } else { 61 /* AST2600 */ 62 switch (rev) { 63 case 0: 64 return "A0"; 65 case 1: 66 return "A1"; 67 case 2: 68 return "A2"; 69 case 3: 70 return "A3"; 71 } 72 } 73 74 return "??"; 75 } 76 77 static int __init aspeed_socinfo_init(void) 78 { 79 struct soc_device_attribute *attrs; 80 struct soc_device *soc_dev; 81 struct device_node *np; 82 void __iomem *reg; 83 bool has_chipid = false; 84 u32 siliconid; 85 u32 chipid[2]; 86 const char *machine = NULL; 87 88 np = of_find_compatible_node(NULL, NULL, "aspeed,silicon-id"); 89 if (!of_device_is_available(np)) { 90 of_node_put(np); 91 return -ENODEV; 92 } 93 94 reg = of_iomap(np, 0); 95 if (!reg) { 96 of_node_put(np); 97 return -ENODEV; 98 } 99 siliconid = readl(reg); 100 iounmap(reg); 101 102 /* This is optional, the ast2400 does not have it */ 103 reg = of_iomap(np, 1); 104 if (reg) { 105 has_chipid = true; 106 chipid[0] = readl(reg); 107 chipid[1] = readl(reg + 4); 108 iounmap(reg); 109 } 110 of_node_put(np); 111 112 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); 113 if (!attrs) 114 return -ENODEV; 115 116 /* 117 * Machine: Romulus BMC 118 * Family: AST2500 119 * Revision: A1 120 * SoC ID: raw silicon revision id 121 * Serial Number: 64-bit chipid 122 */ 123 124 np = of_find_node_by_path("/"); 125 of_property_read_string(np, "model", &machine); 126 if (machine) 127 attrs->machine = kstrdup(machine, GFP_KERNEL); 128 of_node_put(np); 129 130 attrs->family = siliconid_to_name(siliconid); 131 attrs->revision = siliconid_to_rev(siliconid); 132 attrs->soc_id = kasprintf(GFP_KERNEL, "%08x", siliconid); 133 134 if (has_chipid) 135 attrs->serial_number = kasprintf(GFP_KERNEL, "%08x%08x", 136 chipid[1], chipid[0]); 137 138 soc_dev = soc_device_register(attrs); 139 if (IS_ERR(soc_dev)) { 140 kfree(attrs->machine); 141 kfree(attrs->soc_id); 142 kfree(attrs->serial_number); 143 kfree(attrs); 144 return PTR_ERR(soc_dev); 145 } 146 147 pr_info("ASPEED %s rev %s (%s)\n", 148 attrs->family, 149 attrs->revision, 150 attrs->soc_id); 151 152 return 0; 153 } 154 early_initcall(aspeed_socinfo_init); 155