1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Renesas SoC Identification
4  *
5  * Copyright (C) 2014-2016 Glider bvba
6  */
7 
8 #include <linux/io.h>
9 #include <linux/of.h>
10 #include <linux/of_address.h>
11 #include <linux/slab.h>
12 #include <linux/string.h>
13 #include <linux/sys_soc.h>
14 
15 
16 struct renesas_family {
17 	const char name[16];
18 	u32 reg;			/* CCCR or PRR, if not in DT */
19 };
20 
21 static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused = {
22 	.name	= "R-Car Gen1",
23 	.reg	= 0xff000044,		/* PRR (Product Register) */
24 };
25 
26 static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused = {
27 	.name	= "R-Car Gen2",
28 	.reg	= 0xff000044,		/* PRR (Product Register) */
29 };
30 
31 static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = {
32 	.name	= "R-Car Gen3",
33 	.reg	= 0xfff00044,		/* PRR (Product Register) */
34 };
35 
36 static const struct renesas_family fam_rcar_gen4 __initconst __maybe_unused = {
37 	.name	= "R-Car Gen4",
38 };
39 
40 static const struct renesas_family fam_rmobile __initconst __maybe_unused = {
41 	.name	= "R-Mobile",
42 	.reg	= 0xe600101c,		/* CCCR (Common Chip Code Register) */
43 };
44 
45 static const struct renesas_family fam_rza1 __initconst __maybe_unused = {
46 	.name	= "RZ/A1",
47 };
48 
49 static const struct renesas_family fam_rza2 __initconst __maybe_unused = {
50 	.name	= "RZ/A2",
51 };
52 
53 static const struct renesas_family fam_rzg1 __initconst __maybe_unused = {
54 	.name	= "RZ/G1",
55 	.reg	= 0xff000044,		/* PRR (Product Register) */
56 };
57 
58 static const struct renesas_family fam_rzg2 __initconst __maybe_unused = {
59 	.name	= "RZ/G2",
60 	.reg	= 0xfff00044,		/* PRR (Product Register) */
61 };
62 
63 static const struct renesas_family fam_rzg2l __initconst __maybe_unused = {
64 	.name	= "RZ/G2L",
65 };
66 
67 static const struct renesas_family fam_rzv2l __initconst __maybe_unused = {
68 	.name	= "RZ/V2L",
69 };
70 
71 static const struct renesas_family fam_shmobile __initconst __maybe_unused = {
72 	.name	= "SH-Mobile",
73 	.reg	= 0xe600101c,		/* CCCR (Common Chip Code Register) */
74 };
75 
76 
77 struct renesas_soc {
78 	const struct renesas_family *family;
79 	u32 id;
80 };
81 
82 static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = {
83 	.family	= &fam_rza1,
84 };
85 
86 static const struct renesas_soc soc_rz_a2m __initconst __maybe_unused = {
87 	.family	= &fam_rza2,
88 	.id	= 0x3b,
89 };
90 
91 static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = {
92 	.family	= &fam_rmobile,
93 	.id	= 0x3f,
94 };
95 
96 static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = {
97 	.family	= &fam_rmobile,
98 	.id	= 0x40,
99 };
100 
101 static const struct renesas_soc soc_rz_g1h __initconst __maybe_unused = {
102 	.family	= &fam_rzg1,
103 	.id	= 0x45,
104 };
105 
106 static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = {
107 	.family	= &fam_rzg1,
108 	.id	= 0x47,
109 };
110 
111 static const struct renesas_soc soc_rz_g1n __initconst __maybe_unused = {
112 	.family	= &fam_rzg1,
113 	.id	= 0x4b,
114 };
115 
116 static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = {
117 	.family	= &fam_rzg1,
118 	.id	= 0x4c,
119 };
120 
121 static const struct renesas_soc soc_rz_g1c __initconst __maybe_unused = {
122 	.family	= &fam_rzg1,
123 	.id	= 0x53,
124 };
125 
126 static const struct renesas_soc soc_rz_g2m __initconst __maybe_unused = {
127 	.family	= &fam_rzg2,
128 	.id	= 0x52,
129 };
130 
131 static const struct renesas_soc soc_rz_g2n __initconst __maybe_unused = {
132 	.family = &fam_rzg2,
133 	.id     = 0x55,
134 };
135 
136 static const struct renesas_soc soc_rz_g2e __initconst __maybe_unused = {
137 	.family	= &fam_rzg2,
138 	.id	= 0x57,
139 };
140 
141 static const struct renesas_soc soc_rz_g2h __initconst __maybe_unused = {
142 	.family	= &fam_rzg2,
143 	.id	= 0x4f,
144 };
145 
146 static const struct renesas_soc soc_rz_g2l __initconst __maybe_unused = {
147 	.family = &fam_rzg2l,
148 	.id     = 0x841c447,
149 };
150 
151 static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = {
152 	.family = &fam_rzv2l,
153 	.id     = 0x8447447,
154 };
155 
156 static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = {
157 	.family	= &fam_rcar_gen1,
158 };
159 
160 static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = {
161 	.family	= &fam_rcar_gen1,
162 	.id	= 0x3b,
163 };
164 
165 static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = {
166 	.family	= &fam_rcar_gen2,
167 	.id	= 0x45,
168 };
169 
170 static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = {
171 	.family	= &fam_rcar_gen2,
172 	.id	= 0x47,
173 };
174 
175 static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = {
176 	.family	= &fam_rcar_gen2,
177 	.id	= 0x4a,
178 };
179 
180 static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = {
181 	.family	= &fam_rcar_gen2,
182 	.id	= 0x4b,
183 };
184 
185 static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = {
186 	.family	= &fam_rcar_gen2,
187 	.id	= 0x4c,
188 };
189 
190 static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = {
191 	.family	= &fam_rcar_gen3,
192 	.id	= 0x4f,
193 };
194 
195 static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = {
196 	.family	= &fam_rcar_gen3,
197 	.id	= 0x52,
198 };
199 
200 static const struct renesas_soc soc_rcar_m3_n __initconst __maybe_unused = {
201 	.family = &fam_rcar_gen3,
202 	.id     = 0x55,
203 };
204 
205 static const struct renesas_soc soc_rcar_v3m __initconst __maybe_unused = {
206 	.family	= &fam_rcar_gen3,
207 	.id	= 0x54,
208 };
209 
210 static const struct renesas_soc soc_rcar_v3h __initconst __maybe_unused = {
211 	.family	= &fam_rcar_gen3,
212 	.id	= 0x56,
213 };
214 
215 static const struct renesas_soc soc_rcar_e3 __initconst __maybe_unused = {
216 	.family	= &fam_rcar_gen3,
217 	.id	= 0x57,
218 };
219 
220 static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = {
221 	.family	= &fam_rcar_gen3,
222 	.id	= 0x58,
223 };
224 
225 static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = {
226 	.family	= &fam_rcar_gen3,
227 	.id	= 0x59,
228 };
229 
230 static const struct renesas_soc soc_rcar_s4 __initconst __maybe_unused = {
231 	.family	= &fam_rcar_gen4,
232 	.id	= 0x5a,
233 };
234 
235 static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = {
236 	.family	= &fam_shmobile,
237 	.id	= 0x37,
238 };
239 
240 
241 static const struct of_device_id renesas_socs[] __initconst = {
242 #ifdef CONFIG_ARCH_R7S72100
243 	{ .compatible = "renesas,r7s72100",	.data = &soc_rz_a1h },
244 #endif
245 #ifdef CONFIG_ARCH_R7S9210
246 	{ .compatible = "renesas,r7s9210",	.data = &soc_rz_a2m },
247 #endif
248 #ifdef CONFIG_ARCH_R8A73A4
249 	{ .compatible = "renesas,r8a73a4",	.data = &soc_rmobile_ape6 },
250 #endif
251 #ifdef CONFIG_ARCH_R8A7740
252 	{ .compatible = "renesas,r8a7740",	.data = &soc_rmobile_a1 },
253 #endif
254 #ifdef CONFIG_ARCH_R8A7742
255 	{ .compatible = "renesas,r8a7742",	.data = &soc_rz_g1h },
256 #endif
257 #ifdef CONFIG_ARCH_R8A7743
258 	{ .compatible = "renesas,r8a7743",	.data = &soc_rz_g1m },
259 #endif
260 #ifdef CONFIG_ARCH_R8A7744
261 	{ .compatible = "renesas,r8a7744",	.data = &soc_rz_g1n },
262 #endif
263 #ifdef CONFIG_ARCH_R8A7745
264 	{ .compatible = "renesas,r8a7745",	.data = &soc_rz_g1e },
265 #endif
266 #ifdef CONFIG_ARCH_R8A77470
267 	{ .compatible = "renesas,r8a77470",	.data = &soc_rz_g1c },
268 #endif
269 #ifdef CONFIG_ARCH_R8A774A1
270 	{ .compatible = "renesas,r8a774a1",	.data = &soc_rz_g2m },
271 #endif
272 #ifdef CONFIG_ARCH_R8A774B1
273 	{ .compatible = "renesas,r8a774b1",	.data = &soc_rz_g2n },
274 #endif
275 #ifdef CONFIG_ARCH_R8A774C0
276 	{ .compatible = "renesas,r8a774c0",	.data = &soc_rz_g2e },
277 #endif
278 #ifdef CONFIG_ARCH_R8A774E1
279 	{ .compatible = "renesas,r8a774e1",	.data = &soc_rz_g2h },
280 #endif
281 #ifdef CONFIG_ARCH_R8A7778
282 	{ .compatible = "renesas,r8a7778",	.data = &soc_rcar_m1a },
283 #endif
284 #ifdef CONFIG_ARCH_R8A7779
285 	{ .compatible = "renesas,r8a7779",	.data = &soc_rcar_h1 },
286 #endif
287 #ifdef CONFIG_ARCH_R8A7790
288 	{ .compatible = "renesas,r8a7790",	.data = &soc_rcar_h2 },
289 #endif
290 #ifdef CONFIG_ARCH_R8A7791
291 	{ .compatible = "renesas,r8a7791",	.data = &soc_rcar_m2_w },
292 #endif
293 #ifdef CONFIG_ARCH_R8A7792
294 	{ .compatible = "renesas,r8a7792",	.data = &soc_rcar_v2h },
295 #endif
296 #ifdef CONFIG_ARCH_R8A7793
297 	{ .compatible = "renesas,r8a7793",	.data = &soc_rcar_m2_n },
298 #endif
299 #ifdef CONFIG_ARCH_R8A7794
300 	{ .compatible = "renesas,r8a7794",	.data = &soc_rcar_e2 },
301 #endif
302 #if defined(CONFIG_ARCH_R8A77950) || defined(CONFIG_ARCH_R8A77951)
303 	{ .compatible = "renesas,r8a7795",	.data = &soc_rcar_h3 },
304 #endif
305 #ifdef CONFIG_ARCH_R8A77951
306 	{ .compatible = "renesas,r8a779m0",	.data = &soc_rcar_h3 },
307 	{ .compatible = "renesas,r8a779m1",	.data = &soc_rcar_h3 },
308 	{ .compatible = "renesas,r8a779m8",	.data = &soc_rcar_h3 },
309 #endif
310 #ifdef CONFIG_ARCH_R8A77960
311 	{ .compatible = "renesas,r8a7796",	.data = &soc_rcar_m3_w },
312 #endif
313 #ifdef CONFIG_ARCH_R8A77961
314 	{ .compatible = "renesas,r8a77961",	.data = &soc_rcar_m3_w },
315 	{ .compatible = "renesas,r8a779m2",	.data = &soc_rcar_m3_w },
316 	{ .compatible = "renesas,r8a779m3",	.data = &soc_rcar_m3_w },
317 #endif
318 #ifdef CONFIG_ARCH_R8A77965
319 	{ .compatible = "renesas,r8a77965",	.data = &soc_rcar_m3_n },
320 	{ .compatible = "renesas,r8a779m4",	.data = &soc_rcar_m3_n },
321 	{ .compatible = "renesas,r8a779m5",	.data = &soc_rcar_m3_n },
322 #endif
323 #ifdef CONFIG_ARCH_R8A77970
324 	{ .compatible = "renesas,r8a77970",	.data = &soc_rcar_v3m },
325 #endif
326 #ifdef CONFIG_ARCH_R8A77980
327 	{ .compatible = "renesas,r8a77980",	.data = &soc_rcar_v3h },
328 #endif
329 #ifdef CONFIG_ARCH_R8A77990
330 	{ .compatible = "renesas,r8a77990",	.data = &soc_rcar_e3 },
331 	{ .compatible = "renesas,r8a779m6",	.data = &soc_rcar_e3 },
332 #endif
333 #ifdef CONFIG_ARCH_R8A77995
334 	{ .compatible = "renesas,r8a77995",	.data = &soc_rcar_d3 },
335 	{ .compatible = "renesas,r8a779m7",	.data = &soc_rcar_d3 },
336 #endif
337 #ifdef CONFIG_ARCH_R8A779A0
338 	{ .compatible = "renesas,r8a779a0",	.data = &soc_rcar_v3u },
339 #endif
340 #ifdef CONFIG_ARCH_R8A779F0
341 	{ .compatible = "renesas,r8a779f0",	.data = &soc_rcar_s4 },
342 #endif
343 #if defined(CONFIG_ARCH_R9A07G044)
344 	{ .compatible = "renesas,r9a07g044",	.data = &soc_rz_g2l },
345 #endif
346 #if defined(CONFIG_ARCH_R9A07G054)
347 	{ .compatible = "renesas,r9a07g054",	.data = &soc_rz_v2l },
348 #endif
349 #ifdef CONFIG_ARCH_SH73A0
350 	{ .compatible = "renesas,sh73a0",	.data = &soc_shmobile_ag5 },
351 #endif
352 	{ /* sentinel */ }
353 };
354 
355 struct renesas_id {
356 	unsigned int offset;
357 	u32 mask;
358 };
359 
360 static const struct renesas_id id_bsid __initconst = {
361 	.offset = 0,
362 	.mask = 0xff0000,
363 	/*
364 	 * TODO: Upper 4 bits of BSID are for chip version, but the format is
365 	 * not known at this time so we don't know how to specify eshi and eslo
366 	 */
367 };
368 
369 static const struct renesas_id id_rzg2l __initconst = {
370 	.offset = 0xa04,
371 	.mask = 0xfffffff,
372 };
373 
374 static const struct renesas_id id_prr __initconst = {
375 	.offset = 0,
376 	.mask = 0xff00,
377 };
378 
379 static const struct of_device_id renesas_ids[] __initconst = {
380 	{ .compatible = "renesas,bsid",			.data = &id_bsid },
381 	{ .compatible = "renesas,r9a07g044-sysc",	.data = &id_rzg2l },
382 	{ .compatible = "renesas,r9a07g054-sysc",	.data = &id_rzg2l },
383 	{ .compatible = "renesas,prr",			.data = &id_prr },
384 	{ /* sentinel */ }
385 };
386 
387 static int __init renesas_soc_init(void)
388 {
389 	struct soc_device_attribute *soc_dev_attr;
390 	unsigned int product, eshi = 0, eslo;
391 	const struct renesas_family *family;
392 	const struct of_device_id *match;
393 	const struct renesas_soc *soc;
394 	const struct renesas_id *id;
395 	void __iomem *chipid = NULL;
396 	const char *rev_prefix = "";
397 	struct soc_device *soc_dev;
398 	struct device_node *np;
399 	const char *soc_id;
400 	int ret;
401 
402 	match = of_match_node(renesas_socs, of_root);
403 	if (!match)
404 		return -ENODEV;
405 
406 	soc_id = strchr(match->compatible, ',') + 1;
407 	soc = match->data;
408 	family = soc->family;
409 
410 	np = of_find_matching_node_and_match(NULL, renesas_ids, &match);
411 	if (np) {
412 		id = match->data;
413 		chipid = of_iomap(np, 0);
414 		of_node_put(np);
415 	} else if (soc->id && family->reg) {
416 		/* Try hardcoded CCCR/PRR fallback */
417 		id = &id_prr;
418 		chipid = ioremap(family->reg, 4);
419 	}
420 
421 	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
422 	if (!soc_dev_attr)
423 		return -ENOMEM;
424 
425 	np = of_find_node_by_path("/");
426 	of_property_read_string(np, "model", &soc_dev_attr->machine);
427 	of_node_put(np);
428 
429 	soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL);
430 	soc_dev_attr->soc_id = kstrdup_const(soc_id, GFP_KERNEL);
431 
432 	if (chipid) {
433 		product = readl(chipid + id->offset);
434 		iounmap(chipid);
435 
436 		if (id == &id_prr) {
437 			/* R-Car M3-W ES1.1 incorrectly identifies as ES2.0 */
438 			if ((product & 0x7fff) == 0x5210)
439 				product ^= 0x11;
440 			/* R-Car M3-W ES1.3 incorrectly identifies as ES2.1 */
441 			if ((product & 0x7fff) == 0x5211)
442 				product ^= 0x12;
443 
444 			eshi = ((product >> 4) & 0x0f) + 1;
445 			eslo = product & 0xf;
446 			soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u",
447 							   eshi, eslo);
448 		}  else if (id == &id_rzg2l) {
449 			eshi =  ((product >> 28) & 0x0f);
450 			soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%u",
451 							   eshi);
452 			rev_prefix = "Rev ";
453 		}
454 
455 		if (soc->id &&
456 		    ((product & id->mask) >> __ffs(id->mask)) != soc->id) {
457 			pr_warn("SoC mismatch (product = 0x%x)\n", product);
458 			ret = -ENODEV;
459 			goto free_soc_dev_attr;
460 		}
461 	}
462 
463 	pr_info("Detected Renesas %s %s %s%s\n", soc_dev_attr->family,
464 		soc_dev_attr->soc_id, rev_prefix, soc_dev_attr->revision ?: "");
465 
466 	soc_dev = soc_device_register(soc_dev_attr);
467 	if (IS_ERR(soc_dev)) {
468 		ret = PTR_ERR(soc_dev);
469 		goto free_soc_dev_attr;
470 	}
471 
472 	return 0;
473 
474 free_soc_dev_attr:
475 	kfree(soc_dev_attr->revision);
476 	kfree_const(soc_dev_attr->soc_id);
477 	kfree_const(soc_dev_attr->family);
478 	kfree(soc_dev_attr);
479 	return ret;
480 }
481 early_initcall(renesas_soc_init);
482