blob: f3e4b450cf4920935c9be95d79529bc7f88c7c13 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2009-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13/*
14 * SOC Info Routines
15 *
16 */
17
18#include <linux/types.h>
19#include <linux/sysdev.h>
20#include <asm/mach-types.h>
21#include <mach/socinfo.h>
22
23#include "smd_private.h"
24
25#define BUILD_ID_LENGTH 32
26
27enum {
28 HW_PLATFORM_UNKNOWN = 0,
29 HW_PLATFORM_SURF = 1,
30 HW_PLATFORM_FFA = 2,
31 HW_PLATFORM_FLUID = 3,
32 HW_PLATFORM_SVLTE_FFA = 4,
33 HW_PLATFORM_SVLTE_SURF = 5,
Zhang Chang Kenef05b172011-07-27 15:28:13 -040034 HW_PLATFORM_DRAGON = 6,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035 HW_PLATFORM_INVALID
36};
37
38const char *hw_platform[] = {
39 [HW_PLATFORM_UNKNOWN] = "Unknown",
40 [HW_PLATFORM_SURF] = "Surf",
41 [HW_PLATFORM_FFA] = "FFA",
42 [HW_PLATFORM_FLUID] = "Fluid",
43 [HW_PLATFORM_SVLTE_FFA] = "SVLTE_FFA",
Zhang Chang Kenef05b172011-07-27 15:28:13 -040044 [HW_PLATFORM_SVLTE_SURF] = "SLVTE_SURF",
45 [HW_PLATFORM_DRAGON] = "Dragon"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046};
47
48enum {
49 ACCESSORY_CHIP_UNKNOWN = 0,
50 ACCESSORY_CHIP_CHARM = 58,
51};
52
53enum {
54 PLATFORM_SUBTYPE_UNKNOWN = 0x0,
55 PLATFORM_SUBTYPE_CHARM = 0x1,
56 PLATFORM_SUBTYPE_STRANGE = 0x2,
57 PLATFORM_SUBTYPE_STRANGE_2A = 0x3,
58 PLATFORM_SUBTYPE_INVALID,
59};
60
61const char *hw_platform_subtype[] = {
62 [PLATFORM_SUBTYPE_UNKNOWN] = "Unknown",
63 [PLATFORM_SUBTYPE_CHARM] = "charm",
64 [PLATFORM_SUBTYPE_STRANGE] = "strange",
65 [PLATFORM_SUBTYPE_STRANGE_2A] = "strange_2a,"
66};
67
68/* Used to parse shared memory. Must match the modem. */
69struct socinfo_v1 {
70 uint32_t format;
71 uint32_t id;
72 uint32_t version;
73 char build_id[BUILD_ID_LENGTH];
74};
75
76struct socinfo_v2 {
77 struct socinfo_v1 v1;
78
79 /* only valid when format==2 */
80 uint32_t raw_id;
81 uint32_t raw_version;
82};
83
84struct socinfo_v3 {
85 struct socinfo_v2 v2;
86
87 /* only valid when format==3 */
88 uint32_t hw_platform;
89};
90
91struct socinfo_v4 {
92 struct socinfo_v3 v3;
93
94 /* only valid when format==4 */
95 uint32_t platform_version;
96};
97
98struct socinfo_v5 {
99 struct socinfo_v4 v4;
100
101 /* only valid when format==5 */
102 uint32_t accessory_chip;
103};
104
105struct socinfo_v6 {
106 struct socinfo_v5 v5;
107
108 /* only valid when format==6 */
109 uint32_t hw_platform_subtype;
110};
111
112static union {
113 struct socinfo_v1 v1;
114 struct socinfo_v2 v2;
115 struct socinfo_v3 v3;
116 struct socinfo_v4 v4;
117 struct socinfo_v5 v5;
118 struct socinfo_v6 v6;
119} *socinfo;
120
121static enum msm_cpu cpu_of_id[] = {
122
123 /* 7x01 IDs */
124 [1] = MSM_CPU_7X01,
125 [16] = MSM_CPU_7X01,
126 [17] = MSM_CPU_7X01,
127 [18] = MSM_CPU_7X01,
128 [19] = MSM_CPU_7X01,
129 [23] = MSM_CPU_7X01,
130 [25] = MSM_CPU_7X01,
131 [26] = MSM_CPU_7X01,
132 [32] = MSM_CPU_7X01,
133 [33] = MSM_CPU_7X01,
134 [34] = MSM_CPU_7X01,
135 [35] = MSM_CPU_7X01,
136
137 /* 7x25 IDs */
138 [20] = MSM_CPU_7X25,
139 [21] = MSM_CPU_7X25, /* 7225 */
140 [24] = MSM_CPU_7X25, /* 7525 */
141 [27] = MSM_CPU_7X25, /* 7625 */
142 [39] = MSM_CPU_7X25,
143 [40] = MSM_CPU_7X25,
144 [41] = MSM_CPU_7X25,
145 [42] = MSM_CPU_7X25,
146 [62] = MSM_CPU_7X25, /* 7625-1 */
147 [63] = MSM_CPU_7X25, /* 7225-1 */
148 [66] = MSM_CPU_7X25, /* 7225-2 */
149
150
151 /* 7x27 IDs */
152 [43] = MSM_CPU_7X27,
153 [44] = MSM_CPU_7X27,
154 [61] = MSM_CPU_7X27,
155 [67] = MSM_CPU_7X27, /* 7227-1 */
156 [68] = MSM_CPU_7X27, /* 7627-1 */
157 [69] = MSM_CPU_7X27, /* 7627-2 */
158
159
160 /* 8x50 IDs */
161 [30] = MSM_CPU_8X50,
162 [36] = MSM_CPU_8X50,
163 [37] = MSM_CPU_8X50,
164 [38] = MSM_CPU_8X50,
165
166 /* 7x30 IDs */
167 [59] = MSM_CPU_7X30,
168 [60] = MSM_CPU_7X30,
169
170 /* 8x55 IDs */
171 [74] = MSM_CPU_8X55,
172 [75] = MSM_CPU_8X55,
173 [85] = MSM_CPU_8X55,
174
175 /* 8x60 IDs */
176 [70] = MSM_CPU_8X60,
177 [71] = MSM_CPU_8X60,
178 [86] = MSM_CPU_8X60,
179
180 /* 8960 IDs */
181 [87] = MSM_CPU_8960,
182
183 /* 7x25A IDs */
184 [88] = MSM_CPU_7X25A,
185 [89] = MSM_CPU_7X25A,
186 [96] = MSM_CPU_7X25A,
187
188 /* 7x27A IDs */
189 [90] = MSM_CPU_7X27A,
190 [91] = MSM_CPU_7X27A,
191 [92] = MSM_CPU_7X27A,
192 [97] = MSM_CPU_7X27A,
193
194 /* FSM9xxx ID */
195 [94] = FSM_CPU_9XXX,
196 [95] = FSM_CPU_9XXX,
197
198 /* 7x25AA ID */
199 [98] = MSM_CPU_7X25AA,
200 [99] = MSM_CPU_7X25AA,
201 [100] = MSM_CPU_7X25AA,
202
Joel Kingbf2ff512011-07-22 13:43:11 -0700203 /* 7x27AA ID */
204 [101] = MSM_CPU_7X27AA,
205 [102] = MSM_CPU_7X27AA,
206 [103] = MSM_CPU_7X27AA,
207
208 /* 8064 IDs*/
209 [109] = MSM_CPU_8064,
210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700211 /* Uninitialized IDs are not known to run Linux.
212 MSM_CPU_UNKNOWN is set to 0 to ensure these IDs are
213 considered as unknown CPU. */
214};
215
216static enum msm_cpu cur_cpu;
217
218static struct socinfo_v1 dummy_socinfo = {
219 .format = 1,
220 .version = 1,
221 .build_id = "Dummy socinfo placeholder"
222};
223
224uint32_t socinfo_get_id(void)
225{
226 return (socinfo) ? socinfo->v1.id : 0;
227}
228EXPORT_SYMBOL_GPL(socinfo_get_id);
229
230uint32_t socinfo_get_version(void)
231{
232 return (socinfo) ? socinfo->v1.version : 0;
233}
234
235char *socinfo_get_build_id(void)
236{
237 return (socinfo) ? socinfo->v1.build_id : NULL;
238}
239
240uint32_t socinfo_get_raw_id(void)
241{
242 return socinfo ?
243 (socinfo->v1.format >= 2 ? socinfo->v2.raw_id : 0)
244 : 0;
245}
246
247uint32_t socinfo_get_raw_version(void)
248{
249 return socinfo ?
250 (socinfo->v1.format >= 2 ? socinfo->v2.raw_version : 0)
251 : 0;
252}
253
254uint32_t socinfo_get_platform_type(void)
255{
256 return socinfo ?
257 (socinfo->v1.format >= 3 ? socinfo->v3.hw_platform : 0)
258 : 0;
259}
260
261
262uint32_t socinfo_get_platform_version(void)
263{
264 return socinfo ?
265 (socinfo->v1.format >= 4 ? socinfo->v4.platform_version : 0)
266 : 0;
267}
268
269/* This information is directly encoded by the machine id */
270/* Thus no external callers rely on this information at the moment */
271static uint32_t socinfo_get_accessory_chip(void)
272{
273 return socinfo ?
274 (socinfo->v1.format >= 5 ? socinfo->v5.accessory_chip : 0)
275 : 0;
276}
277
278uint32_t socinfo_get_platform_subtype(void)
279{
280 return socinfo ?
281 (socinfo->v1.format >= 6 ? socinfo->v6.hw_platform_subtype : 0)
282 : 0;
283}
284
285enum msm_cpu socinfo_get_msm_cpu(void)
286{
287 return cur_cpu;
288}
289EXPORT_SYMBOL_GPL(socinfo_get_msm_cpu);
290
291static ssize_t
292socinfo_show_id(struct sys_device *dev,
293 struct sysdev_attribute *attr,
294 char *buf)
295{
296 if (!socinfo) {
297 pr_err("%s: No socinfo found!\n", __func__);
298 return 0;
299 }
300
301 return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_id());
302}
303
304static ssize_t
305socinfo_show_version(struct sys_device *dev,
306 struct sysdev_attribute *attr,
307 char *buf)
308{
309 uint32_t version;
310
311 if (!socinfo) {
312 pr_err("%s: No socinfo found!\n", __func__);
313 return 0;
314 }
315
316 version = socinfo_get_version();
317 return snprintf(buf, PAGE_SIZE, "%u.%u\n",
318 SOCINFO_VERSION_MAJOR(version),
319 SOCINFO_VERSION_MINOR(version));
320}
321
322static ssize_t
323socinfo_show_build_id(struct sys_device *dev,
324 struct sysdev_attribute *attr,
325 char *buf)
326{
327 if (!socinfo) {
328 pr_err("%s: No socinfo found!\n", __func__);
329 return 0;
330 }
331
332 return snprintf(buf, PAGE_SIZE, "%-.32s\n", socinfo_get_build_id());
333}
334
335static ssize_t
336socinfo_show_raw_id(struct sys_device *dev,
337 struct sysdev_attribute *attr,
338 char *buf)
339{
340 if (!socinfo) {
341 pr_err("%s: No socinfo found!\n", __func__);
342 return 0;
343 }
344 if (socinfo->v1.format < 2) {
345 pr_err("%s: Raw ID not available!\n", __func__);
346 return 0;
347 }
348
349 return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_id());
350}
351
352static ssize_t
353socinfo_show_raw_version(struct sys_device *dev,
354 struct sysdev_attribute *attr,
355 char *buf)
356{
357 if (!socinfo) {
358 pr_err("%s: No socinfo found!\n", __func__);
359 return 0;
360 }
361 if (socinfo->v1.format < 2) {
362 pr_err("%s: Raw version not available!\n", __func__);
363 return 0;
364 }
365
366 return snprintf(buf, PAGE_SIZE, "%u\n", socinfo_get_raw_version());
367}
368
369static ssize_t
370socinfo_show_platform_type(struct sys_device *dev,
371 struct sysdev_attribute *attr,
372 char *buf)
373{
374 uint32_t hw_type;
375
376 if (!socinfo) {
377 pr_err("%s: No socinfo found!\n", __func__);
378 return 0;
379 }
380 if (socinfo->v1.format < 3) {
381 pr_err("%s: platform type not available!\n", __func__);
382 return 0;
383 }
384
385 hw_type = socinfo_get_platform_type();
386 if (hw_type >= HW_PLATFORM_INVALID) {
387 pr_err("%s: Invalid hardware platform type found\n",
388 __func__);
389 hw_type = HW_PLATFORM_UNKNOWN;
390 }
391
392 return snprintf(buf, PAGE_SIZE, "%-.32s\n", hw_platform[hw_type]);
393}
394
395static ssize_t
396socinfo_show_platform_version(struct sys_device *dev,
397 struct sysdev_attribute *attr,
398 char *buf)
399{
400
401 if (!socinfo) {
402 pr_err("%s: No socinfo found!\n", __func__);
403 return 0;
404 }
405 if (socinfo->v1.format < 4) {
406 pr_err("%s: platform version not available!\n", __func__);
407 return 0;
408 }
409
410 return snprintf(buf, PAGE_SIZE, "%u\n",
411 socinfo_get_platform_version());
412}
413
414static ssize_t
415socinfo_show_accessory_chip(struct sys_device *dev,
416 struct sysdev_attribute *attr,
417 char *buf)
418{
419 if (!socinfo) {
420 pr_err("%s: No socinfo found!\n", __func__);
421 return 0;
422 }
423 if (socinfo->v1.format < 5) {
424 pr_err("%s: accessory chip not available!\n", __func__);
425 return 0;
426 }
427
428 return snprintf(buf, PAGE_SIZE, "%u\n",
429 socinfo_get_accessory_chip());
430}
431
432static ssize_t
433socinfo_show_platform_subtype(struct sys_device *dev,
434 struct sysdev_attribute *attr,
435 char *buf)
436{
437 uint32_t hw_subtype;
438 if (!socinfo) {
439 pr_err("%s: No socinfo found!\n", __func__);
440 return 0;
441 }
442 if (socinfo->v1.format < 6) {
443 pr_err("%s: platform subtype not available!\n", __func__);
444 return 0;
445 }
446
447 hw_subtype = socinfo_get_platform_subtype();
448 if (hw_subtype >= PLATFORM_SUBTYPE_INVALID) {
449 pr_err("%s: Invalid hardware platform sub type found\n",
450 __func__);
451 hw_subtype = PLATFORM_SUBTYPE_UNKNOWN;
452 }
453 return snprintf(buf, PAGE_SIZE, "%-.32s\n",
454 hw_platform_subtype[hw_subtype]);
455}
456
457static struct sysdev_attribute socinfo_v1_files[] = {
458 _SYSDEV_ATTR(id, 0444, socinfo_show_id, NULL),
459 _SYSDEV_ATTR(version, 0444, socinfo_show_version, NULL),
460 _SYSDEV_ATTR(build_id, 0444, socinfo_show_build_id, NULL),
461};
462
463static struct sysdev_attribute socinfo_v2_files[] = {
464 _SYSDEV_ATTR(raw_id, 0444, socinfo_show_raw_id, NULL),
465 _SYSDEV_ATTR(raw_version, 0444, socinfo_show_raw_version, NULL),
466};
467
468static struct sysdev_attribute socinfo_v3_files[] = {
469 _SYSDEV_ATTR(hw_platform, 0444, socinfo_show_platform_type, NULL),
470};
471
472static struct sysdev_attribute socinfo_v4_files[] = {
473 _SYSDEV_ATTR(platform_version, 0444,
474 socinfo_show_platform_version, NULL),
475};
476
477static struct sysdev_attribute socinfo_v5_files[] = {
478 _SYSDEV_ATTR(accessory_chip, 0444,
479 socinfo_show_accessory_chip, NULL),
480};
481
482static struct sysdev_attribute socinfo_v6_files[] = {
483 _SYSDEV_ATTR(platform_subtype, 0444,
484 socinfo_show_platform_subtype, NULL),
485};
486
487static struct sysdev_class soc_sysdev_class = {
488 .name = "soc",
489};
490
491static struct sys_device soc_sys_device = {
492 .id = 0,
493 .cls = &soc_sysdev_class,
494};
495
496static int __init socinfo_create_files(struct sys_device *dev,
497 struct sysdev_attribute files[],
498 int size)
499{
500 int i;
501 for (i = 0; i < size; i++) {
502 int err = sysdev_create_file(dev, &files[i]);
503 if (err) {
504 pr_err("%s: sysdev_create_file(%s)=%d\n",
505 __func__, files[i].attr.name, err);
506 return err;
507 }
508 }
509 return 0;
510}
511
512static int __init socinfo_init_sysdev(void)
513{
514 int err;
515
516 if (!socinfo) {
517 pr_err("%s: No socinfo found!\n", __func__);
518 return -ENODEV;
519 }
520
521 err = sysdev_class_register(&soc_sysdev_class);
522 if (err) {
523 pr_err("%s: sysdev_class_register fail (%d)\n",
524 __func__, err);
525 return err;
526 }
527 err = sysdev_register(&soc_sys_device);
528 if (err) {
529 pr_err("%s: sysdev_register fail (%d)\n",
530 __func__, err);
531 return err;
532 }
533 socinfo_create_files(&soc_sys_device, socinfo_v1_files,
534 ARRAY_SIZE(socinfo_v1_files));
535 if (socinfo->v1.format < 2)
536 return err;
537 socinfo_create_files(&soc_sys_device, socinfo_v2_files,
538 ARRAY_SIZE(socinfo_v2_files));
539
540 if (socinfo->v1.format < 3)
541 return err;
542
543 socinfo_create_files(&soc_sys_device, socinfo_v3_files,
544 ARRAY_SIZE(socinfo_v3_files));
545
546 if (socinfo->v1.format < 4)
547 return err;
548
549 socinfo_create_files(&soc_sys_device, socinfo_v4_files,
550 ARRAY_SIZE(socinfo_v4_files));
551
552 if (socinfo->v1.format < 5)
553 return err;
554
555 socinfo_create_files(&soc_sys_device, socinfo_v5_files,
556 ARRAY_SIZE(socinfo_v5_files));
557
558 if (socinfo->v1.format < 6)
559 return err;
560
561 return socinfo_create_files(&soc_sys_device, socinfo_v6_files,
562 ARRAY_SIZE(socinfo_v6_files));
563
564}
565
566arch_initcall(socinfo_init_sysdev);
567
568void *setup_dummy_socinfo(void)
569{
570 if (machine_is_msm8960_rumi3() || machine_is_msm8960_sim() ||
571 machine_is_msm8960_cdp())
572 dummy_socinfo.id = 87;
Joel Kingbf2ff512011-07-22 13:43:11 -0700573 else if (machine_is_apq8064_sim())
574 dummy_socinfo.id = 109;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 return (void *) &dummy_socinfo;
576}
577
578int __init socinfo_init(void)
579{
580 socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID, sizeof(struct socinfo_v6));
581
582 if (!socinfo)
583 socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
584 sizeof(struct socinfo_v5));
585
586 if (!socinfo)
587 socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
588 sizeof(struct socinfo_v4));
589
590 if (!socinfo)
591 socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
592 sizeof(struct socinfo_v3));
593
594 if (!socinfo)
595 socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
596 sizeof(struct socinfo_v2));
597
598 if (!socinfo)
599 socinfo = smem_alloc(SMEM_HW_SW_BUILD_ID,
600 sizeof(struct socinfo_v1));
601
602 if (!socinfo) {
603 pr_warn("%s: Can't find SMEM_HW_SW_BUILD_ID; falling back on "
604 "dummy values.\n", __func__);
605 socinfo = setup_dummy_socinfo();
606 }
607
608 WARN(!socinfo_get_id(), "Unknown SOC ID!\n");
609 WARN(socinfo_get_id() >= ARRAY_SIZE(cpu_of_id),
610 "New IDs added! ID => CPU mapping might need an update.\n");
611
612 if (socinfo->v1.id < ARRAY_SIZE(cpu_of_id))
613 cur_cpu = cpu_of_id[socinfo->v1.id];
614
615 switch (socinfo->v1.format) {
616 case 1:
617 pr_info("%s: v%u, id=%u, ver=%u.%u\n",
618 __func__, socinfo->v1.format, socinfo->v1.id,
619 SOCINFO_VERSION_MAJOR(socinfo->v1.version),
620 SOCINFO_VERSION_MINOR(socinfo->v1.version));
621 break;
622 case 2:
623 pr_info("%s: v%u, id=%u, ver=%u.%u, "
624 "raw_id=%u, raw_ver=%u\n",
625 __func__, socinfo->v1.format, socinfo->v1.id,
626 SOCINFO_VERSION_MAJOR(socinfo->v1.version),
627 SOCINFO_VERSION_MINOR(socinfo->v1.version),
628 socinfo->v2.raw_id, socinfo->v2.raw_version);
629 break;
630 case 3:
631 pr_info("%s: v%u, id=%u, ver=%u.%u, "
632 "raw_id=%u, raw_ver=%u, hw_plat=%u\n",
633 __func__, socinfo->v1.format, socinfo->v1.id,
634 SOCINFO_VERSION_MAJOR(socinfo->v1.version),
635 SOCINFO_VERSION_MINOR(socinfo->v1.version),
636 socinfo->v2.raw_id, socinfo->v2.raw_version,
637 socinfo->v3.hw_platform);
638 break;
639 case 4:
640 pr_info("%s: v%u, id=%u, ver=%u.%u, "
641 "raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n",
642 __func__, socinfo->v1.format, socinfo->v1.id,
643 SOCINFO_VERSION_MAJOR(socinfo->v1.version),
644 SOCINFO_VERSION_MINOR(socinfo->v1.version),
645 socinfo->v2.raw_id, socinfo->v2.raw_version,
646 socinfo->v3.hw_platform, socinfo->v4.platform_version);
647 break;
648 case 5:
649 pr_info("%s: v%u, id=%u, ver=%u.%u, "
650 "raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n"
651 " accessory_chip=%u\n", __func__, socinfo->v1.format,
652 socinfo->v1.id,
653 SOCINFO_VERSION_MAJOR(socinfo->v1.version),
654 SOCINFO_VERSION_MINOR(socinfo->v1.version),
655 socinfo->v2.raw_id, socinfo->v2.raw_version,
656 socinfo->v3.hw_platform, socinfo->v4.platform_version,
657 socinfo->v5.accessory_chip);
658 break;
659 case 6:
660 pr_info("%s: v%u, id=%u, ver=%u.%u, "
661 "raw_id=%u, raw_ver=%u, hw_plat=%u, hw_plat_ver=%u\n"
662 " accessory_chip=%u hw_plat_subtype=%u\n", __func__,
663 socinfo->v1.format,
664 socinfo->v1.id,
665 SOCINFO_VERSION_MAJOR(socinfo->v1.version),
666 SOCINFO_VERSION_MINOR(socinfo->v1.version),
667 socinfo->v2.raw_id, socinfo->v2.raw_version,
668 socinfo->v3.hw_platform, socinfo->v4.platform_version,
669 socinfo->v5.accessory_chip,
670 socinfo->v6.hw_platform_subtype);
671 break;
672 default:
673 pr_err("%s: Unknown format found\n", __func__);
674 break;
675 }
676
677 return 0;
678}