1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2021 Marvell. 3 */ 4 5 #include "roc_api.h" 6 #include "roc_priv.h" 7 8 struct roc_model *roc_model; 9 10 /* RoC and CPU IDs and revisions */ 11 #define VENDOR_ARM 0x41 /* 'A' */ 12 #define VENDOR_CAVIUM 0x43 /* 'C' */ 13 14 #define SOC_PART_CN10K 0xD49 15 16 #define PART_106xx 0xB9 17 #define PART_105xx 0xBA 18 #define PART_105xxN 0xBC 19 #define PART_98xx 0xB1 20 #define PART_96xx 0xB2 21 #define PART_95xx 0xB3 22 #define PART_95xxN 0xB4 23 #define PART_95xxMM 0xB5 24 #define PART_95O 0xB6 25 26 #define MODEL_IMPL_BITS 8 27 #define MODEL_IMPL_SHIFT 24 28 #define MODEL_IMPL_MASK ((1 << MODEL_IMPL_BITS) - 1) 29 #define MODEL_PART_BITS 12 30 #define MODEL_PART_SHIFT 4 31 #define MODEL_PART_MASK ((1 << MODEL_PART_BITS) - 1) 32 #define MODEL_MAJOR_BITS 4 33 #define MODEL_MAJOR_SHIFT 20 34 #define MODEL_MAJOR_MASK ((1 << MODEL_MAJOR_BITS) - 1) 35 #define MODEL_MINOR_BITS 4 36 #define MODEL_MINOR_SHIFT 0 37 #define MODEL_MINOR_MASK ((1 << MODEL_MINOR_BITS) - 1) 38 39 static const struct model_db { 40 uint32_t impl; 41 uint32_t part; 42 uint32_t major; 43 uint32_t minor; 44 uint64_t flag; 45 char name[ROC_MODEL_STR_LEN_MAX]; 46 } model_db[] = { 47 {VENDOR_ARM, PART_106xx, 0, 0, ROC_MODEL_CN106xx_A0, "cn10ka_a0"}, 48 {VENDOR_ARM, PART_105xx, 0, 0, ROC_MODEL_CNF105xx_A0, "cnf10ka_a0"}, 49 {VENDOR_ARM, PART_105xxN, 0, 0, ROC_MODEL_CNF105xxN_A0, "cnf10kb_a0"}, 50 {VENDOR_CAVIUM, PART_98xx, 0, 0, ROC_MODEL_CN98xx_A0, "cn98xx_a0"}, 51 {VENDOR_CAVIUM, PART_96xx, 0, 0, ROC_MODEL_CN96xx_A0, "cn96xx_a0"}, 52 {VENDOR_CAVIUM, PART_96xx, 0, 1, ROC_MODEL_CN96xx_B0, "cn96xx_b0"}, 53 {VENDOR_CAVIUM, PART_96xx, 2, 0, ROC_MODEL_CN96xx_C0, "cn96xx_c0"}, 54 {VENDOR_CAVIUM, PART_96xx, 2, 1, ROC_MODEL_CN96xx_C0, "cn96xx_c1"}, 55 {VENDOR_CAVIUM, PART_95xx, 0, 0, ROC_MODEL_CNF95xx_A0, "cnf95xx_a0"}, 56 {VENDOR_CAVIUM, PART_95xx, 1, 0, ROC_MODEL_CNF95xx_B0, "cnf95xx_b0"}, 57 {VENDOR_CAVIUM, PART_95xxN, 0, 0, ROC_MODEL_CNF95xxN_A0, "cnf95xxn_a0"}, 58 {VENDOR_CAVIUM, PART_95xxN, 0, 1, ROC_MODEL_CNF95xxN_A0, "cnf95xxn_a1"}, 59 {VENDOR_CAVIUM, PART_95xxN, 1, 0, ROC_MODEL_CNF95xxN_B0, "cnf95xxn_b0"}, 60 {VENDOR_CAVIUM, PART_95O, 0, 0, ROC_MODEL_CNF95xxO_A0, "cnf95O_a0"}, 61 {VENDOR_CAVIUM, PART_95xxMM, 0, 0, ROC_MODEL_CNF95xxMM_A0, 62 "cnf95xxmm_a0"}}; 63 64 static uint32_t 65 cn10k_part_get(void) 66 { 67 uint32_t soc = 0x0; 68 char buf[BUFSIZ]; 69 char *ptr; 70 FILE *fd; 71 72 /* Read the CPU compatible variant */ 73 fd = fopen("/proc/device-tree/compatible", "r"); 74 if (!fd) { 75 plt_err("Failed to open /proc/device-tree/compatible"); 76 goto err; 77 } 78 79 if (fgets(buf, sizeof(buf), fd) == NULL) { 80 plt_err("Failed to read from /proc/device-tree/compatible"); 81 goto fclose; 82 } 83 ptr = strchr(buf, ','); 84 if (!ptr) { 85 plt_err("Malformed 'CPU compatible': <%s>", buf); 86 goto fclose; 87 } 88 ptr++; 89 if (strcmp("cn10ka", ptr) == 0) { 90 soc = PART_106xx; 91 } else if (strcmp("cnf10ka", ptr) == 0) { 92 soc = PART_105xx; 93 } else if (strcmp("cnf10kb", ptr) == 0) { 94 soc = PART_105xxN; 95 } else { 96 plt_err("Unidentified 'CPU compatible': <%s>", ptr); 97 goto fclose; 98 } 99 100 fclose: 101 fclose(fd); 102 103 err: 104 return soc; 105 } 106 107 static bool 108 populate_model(struct roc_model *model, uint32_t midr) 109 { 110 uint32_t impl, major, part, minor; 111 bool found = false; 112 size_t i; 113 114 impl = (midr >> MODEL_IMPL_SHIFT) & MODEL_IMPL_MASK; 115 part = (midr >> MODEL_PART_SHIFT) & MODEL_PART_MASK; 116 major = (midr >> MODEL_MAJOR_SHIFT) & MODEL_MAJOR_MASK; 117 minor = (midr >> MODEL_MINOR_SHIFT) & MODEL_MINOR_MASK; 118 119 /* Update part number for cn10k from device-tree */ 120 if (part == SOC_PART_CN10K) 121 part = cn10k_part_get(); 122 123 for (i = 0; i < PLT_DIM(model_db); i++) 124 if (model_db[i].impl == impl && model_db[i].part == part && 125 model_db[i].major == major && model_db[i].minor == minor) { 126 model->flag = model_db[i].flag; 127 strncpy(model->name, model_db[i].name, 128 ROC_MODEL_STR_LEN_MAX - 1); 129 found = true; 130 break; 131 } 132 133 if (!found) { 134 model->flag = 0; 135 strncpy(model->name, "unknown", ROC_MODEL_STR_LEN_MAX - 1); 136 plt_err("Invalid RoC model (impl=0x%x, part=0x%x, major=0x%x, minor=0x%x)", 137 impl, part, major, minor); 138 } 139 140 return found; 141 } 142 143 static int 144 midr_get(unsigned long *val) 145 { 146 const char *file = 147 "/sys/devices/system/cpu/cpu0/regs/identification/midr_el1"; 148 int rc = UTIL_ERR_FS; 149 char buf[BUFSIZ]; 150 char *end = NULL; 151 FILE *f; 152 153 if (val == NULL) 154 goto err; 155 f = fopen(file, "r"); 156 if (f == NULL) 157 goto err; 158 159 if (fgets(buf, sizeof(buf), f) == NULL) 160 goto fclose; 161 162 *val = strtoul(buf, &end, 0); 163 if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) 164 goto fclose; 165 166 rc = 0; 167 fclose: 168 fclose(f); 169 err: 170 return rc; 171 } 172 173 static void 174 detect_invalid_config(void) 175 { 176 #ifdef ROC_PLATFORM_CN9K 177 #ifdef ROC_PLATFORM_CN10K 178 PLT_STATIC_ASSERT(0); 179 #endif 180 #endif 181 } 182 183 static uint64_t 184 env_lookup_flag(const char *name) 185 { 186 unsigned int i; 187 struct { 188 const char *name; 189 uint64_t flag; 190 } envs[] = { 191 {"HW_PLATFORM", ROC_ENV_HW}, 192 {"EMUL_PLATFORM", ROC_ENV_EMUL}, 193 {"ASIM_PLATFORM", ROC_ENV_ASIM}, 194 }; 195 196 for (i = 0; i < PLT_DIM(envs); i++) 197 if (!strncmp(envs[i].name, name, strlen(envs[i].name))) 198 return envs[i].flag; 199 200 return 0; 201 } 202 203 static void 204 of_env_get(struct roc_model *model) 205 { 206 const char *const path = "/proc/device-tree/soc@0/runplatform"; 207 uint64_t flag; 208 FILE *fp; 209 210 fp = fopen(path, "r"); 211 if (!fp) { 212 plt_err("Failed to open %s", path); 213 return; 214 } 215 216 if (!fgets(model->env, sizeof(model->env), fp)) { 217 plt_err("Failed to read %s", path); 218 goto err; 219 } 220 221 flag = env_lookup_flag(model->env); 222 if (flag == 0) { 223 plt_err("Unknown platform: %s", model->env); 224 goto err; 225 } 226 227 model->flag |= flag; 228 err: 229 fclose(fp); 230 } 231 232 int 233 roc_model_init(struct roc_model *model) 234 { 235 int rc = UTIL_ERR_PARAM; 236 unsigned long midr; 237 238 detect_invalid_config(); 239 240 if (!model) 241 goto err; 242 243 rc = midr_get(&midr); 244 if (rc) 245 goto err; 246 247 rc = UTIL_ERR_INVALID_MODEL; 248 if (!populate_model(model, midr)) 249 goto err; 250 251 of_env_get(model); 252 253 rc = 0; 254 plt_info("RoC Model: %s (%s)", model->name, model->env); 255 roc_model = model; 256 err: 257 return rc; 258 } 259