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 /* AST2700 */ 31 { "AST2750", 0x06000003 }, 32 { "AST2700", 0x06000103 }, 33 { "AST2720", 0x06000203 }, 34 }; 35 36 static const char *siliconid_to_name(u32 siliconid) 37 { 38 unsigned int id = siliconid & 0xff00ffff; 39 unsigned int i; 40 41 for (i = 0 ; i < ARRAY_SIZE(rev_table) ; ++i) { 42 if (rev_table[i].id == id) 43 return rev_table[i].name; 44 } 45 46 return "Unknown"; 47 } 48 49 static const char *siliconid_to_rev(u32 siliconid) 50 { 51 unsigned int rev = (siliconid >> 16) & 0xff; 52 unsigned int gen = (siliconid >> 24) & 0xff; 53 54 if (gen < 0x5) { 55 /* AST2500 and below */ 56 switch (rev) { 57 case 0: 58 return "A0"; 59 case 1: 60 return "A1"; 61 case 3: 62 return "A2"; 63 } 64 } else { 65 /* AST2600 */ 66 switch (rev) { 67 case 0: 68 return "A0"; 69 case 1: 70 return "A1"; 71 case 2: 72 return "A2"; 73 case 3: 74 return "A3"; 75 } 76 } 77 78 return "??"; 79 } 80 81 static int __init aspeed_socinfo_init(void) 82 { 83 struct soc_device_attribute *attrs; 84 struct soc_device *soc_dev; 85 struct device_node *np; 86 void __iomem *reg; 87 bool has_chipid = false; 88 u32 siliconid; 89 u32 chipid[2]; 90 const char *machine = NULL; 91 92 np = of_find_compatible_node(NULL, NULL, "aspeed,silicon-id"); 93 if (!of_device_is_available(np)) { 94 of_node_put(np); 95 return -ENODEV; 96 } 97 98 reg = of_iomap(np, 0); 99 if (!reg) { 100 of_node_put(np); 101 return -ENODEV; 102 } 103 siliconid = readl(reg); 104 iounmap(reg); 105 106 /* This is optional, the ast2400 does not have it */ 107 reg = of_iomap(np, 1); 108 if (reg) { 109 has_chipid = true; 110 chipid[0] = readl(reg); 111 chipid[1] = readl(reg + 4); 112 iounmap(reg); 113 } 114 of_node_put(np); 115 116 attrs = kzalloc(sizeof(*attrs), GFP_KERNEL); 117 if (!attrs) 118 return -ENODEV; 119 120 /* 121 * Machine: Romulus BMC 122 * Family: AST2500 123 * Revision: A1 124 * SoC ID: raw silicon revision id 125 * Serial Number: 64-bit chipid 126 */ 127 128 np = of_find_node_by_path("/"); 129 of_property_read_string(np, "model", &machine); 130 if (machine) 131 attrs->machine = kstrdup(machine, GFP_KERNEL); 132 of_node_put(np); 133 134 attrs->family = siliconid_to_name(siliconid); 135 attrs->revision = siliconid_to_rev(siliconid); 136 attrs->soc_id = kasprintf(GFP_KERNEL, "%08x", siliconid); 137 138 if (has_chipid) 139 attrs->serial_number = kasprintf(GFP_KERNEL, "%08x%08x", 140 chipid[1], chipid[0]); 141 142 soc_dev = soc_device_register(attrs); 143 if (IS_ERR(soc_dev)) { 144 kfree(attrs->machine); 145 kfree(attrs->soc_id); 146 kfree(attrs->serial_number); 147 kfree(attrs); 148 return PTR_ERR(soc_dev); 149 } 150 151 pr_info("ASPEED %s rev %s (%s)\n", 152 attrs->family, 153 attrs->revision, 154 attrs->soc_id); 155 156 return 0; 157 } 158 early_initcall(aspeed_socinfo_init); 159