socinfo.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2009-2017, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2017-2019, Linaro Ltd.
  5. */
  6. #include <linux/debugfs.h>
  7. #include <linux/err.h>
  8. #include <linux/module.h>
  9. #include <linux/platform_device.h>
  10. #include <linux/random.h>
  11. #include <linux/slab.h>
  12. #include <linux/soc/qcom/smem.h>
  13. #include <linux/string.h>
  14. #include <linux/sys_soc.h>
  15. #include <linux/types.h>
  16. /*
  17. * SoC version type with major number in the upper 16 bits and minor
  18. * number in the lower 16 bits.
  19. */
  20. #define SOCINFO_MAJOR(ver) (((ver) >> 16) & 0xffff)
  21. #define SOCINFO_MINOR(ver) ((ver) & 0xffff)
  22. #define SOCINFO_VERSION(maj, min) ((((maj) & 0xffff) << 16)|((min) & 0xffff))
  23. #define SMEM_SOCINFO_BUILD_ID_LENGTH 32
  24. #define SMEM_SOCINFO_CHIP_ID_LENGTH 32
  25. /*
  26. * SMEM item id, used to acquire handles to respective
  27. * SMEM region.
  28. */
  29. #define SMEM_HW_SW_BUILD_ID 137
  30. #ifdef CONFIG_DEBUG_FS
  31. #define SMEM_IMAGE_VERSION_BLOCKS_COUNT 32
  32. #define SMEM_IMAGE_VERSION_SIZE 4096
  33. #define SMEM_IMAGE_VERSION_NAME_SIZE 75
  34. #define SMEM_IMAGE_VERSION_VARIANT_SIZE 20
  35. #define SMEM_IMAGE_VERSION_OEM_SIZE 32
  36. /*
  37. * SMEM Image table indices
  38. */
  39. #define SMEM_IMAGE_TABLE_BOOT_INDEX 0
  40. #define SMEM_IMAGE_TABLE_TZ_INDEX 1
  41. #define SMEM_IMAGE_TABLE_RPM_INDEX 3
  42. #define SMEM_IMAGE_TABLE_APPS_INDEX 10
  43. #define SMEM_IMAGE_TABLE_MPSS_INDEX 11
  44. #define SMEM_IMAGE_TABLE_ADSP_INDEX 12
  45. #define SMEM_IMAGE_TABLE_CNSS_INDEX 13
  46. #define SMEM_IMAGE_TABLE_VIDEO_INDEX 14
  47. #define SMEM_IMAGE_VERSION_TABLE 469
  48. /*
  49. * SMEM Image table names
  50. */
  51. static const char *const socinfo_image_names[] = {
  52. [SMEM_IMAGE_TABLE_ADSP_INDEX] = "adsp",
  53. [SMEM_IMAGE_TABLE_APPS_INDEX] = "apps",
  54. [SMEM_IMAGE_TABLE_BOOT_INDEX] = "boot",
  55. [SMEM_IMAGE_TABLE_CNSS_INDEX] = "cnss",
  56. [SMEM_IMAGE_TABLE_MPSS_INDEX] = "mpss",
  57. [SMEM_IMAGE_TABLE_RPM_INDEX] = "rpm",
  58. [SMEM_IMAGE_TABLE_TZ_INDEX] = "tz",
  59. [SMEM_IMAGE_TABLE_VIDEO_INDEX] = "video",
  60. };
  61. static const char *const pmic_models[] = {
  62. [0] = "Unknown PMIC model",
  63. [9] = "PM8994",
  64. [11] = "PM8916",
  65. [13] = "PM8058",
  66. [14] = "PM8028",
  67. [15] = "PM8901",
  68. [16] = "PM8027",
  69. [17] = "ISL9519",
  70. [18] = "PM8921",
  71. [19] = "PM8018",
  72. [20] = "PM8015",
  73. [21] = "PM8014",
  74. [22] = "PM8821",
  75. [23] = "PM8038",
  76. [24] = "PM8922",
  77. [25] = "PM8917",
  78. };
  79. #endif /* CONFIG_DEBUG_FS */
  80. /* Socinfo SMEM item structure */
  81. struct socinfo {
  82. __le32 fmt;
  83. __le32 id;
  84. __le32 ver;
  85. char build_id[SMEM_SOCINFO_BUILD_ID_LENGTH];
  86. /* Version 2 */
  87. __le32 raw_id;
  88. __le32 raw_ver;
  89. /* Version 3 */
  90. __le32 hw_plat;
  91. /* Version 4 */
  92. __le32 plat_ver;
  93. /* Version 5 */
  94. __le32 accessory_chip;
  95. /* Version 6 */
  96. __le32 hw_plat_subtype;
  97. /* Version 7 */
  98. __le32 pmic_model;
  99. __le32 pmic_die_rev;
  100. /* Version 8 */
  101. __le32 pmic_model_1;
  102. __le32 pmic_die_rev_1;
  103. __le32 pmic_model_2;
  104. __le32 pmic_die_rev_2;
  105. /* Version 9 */
  106. __le32 foundry_id;
  107. /* Version 10 */
  108. __le32 serial_num;
  109. /* Version 11 */
  110. __le32 num_pmics;
  111. __le32 pmic_array_offset;
  112. /* Version 12 */
  113. __le32 chip_family;
  114. __le32 raw_device_family;
  115. __le32 raw_device_num;
  116. /* Version 13 */
  117. __le32 nproduct_id;
  118. char chip_id[SMEM_SOCINFO_CHIP_ID_LENGTH];
  119. /* Version 14 */
  120. __le32 num_clusters;
  121. __le32 ncluster_array_offset;
  122. __le32 num_defective_parts;
  123. __le32 ndefective_parts_array_offset;
  124. /* Version 15 */
  125. __le32 nmodem_supported;
  126. };
  127. #ifdef CONFIG_DEBUG_FS
  128. struct socinfo_params {
  129. u32 raw_device_family;
  130. u32 hw_plat_subtype;
  131. u32 accessory_chip;
  132. u32 raw_device_num;
  133. u32 chip_family;
  134. u32 foundry_id;
  135. u32 plat_ver;
  136. u32 raw_ver;
  137. u32 hw_plat;
  138. u32 fmt;
  139. u32 nproduct_id;
  140. u32 num_clusters;
  141. u32 ncluster_array_offset;
  142. u32 num_defective_parts;
  143. u32 ndefective_parts_array_offset;
  144. u32 nmodem_supported;
  145. };
  146. struct smem_image_version {
  147. char name[SMEM_IMAGE_VERSION_NAME_SIZE];
  148. char variant[SMEM_IMAGE_VERSION_VARIANT_SIZE];
  149. char pad;
  150. char oem[SMEM_IMAGE_VERSION_OEM_SIZE];
  151. };
  152. #endif /* CONFIG_DEBUG_FS */
  153. struct qcom_socinfo {
  154. struct soc_device *soc_dev;
  155. struct soc_device_attribute attr;
  156. #ifdef CONFIG_DEBUG_FS
  157. struct dentry *dbg_root;
  158. struct socinfo_params info;
  159. #endif /* CONFIG_DEBUG_FS */
  160. };
  161. struct soc_id {
  162. unsigned int id;
  163. const char *name;
  164. };
  165. static const struct soc_id soc_id[] = {
  166. { 87, "MSM8960" },
  167. { 109, "APQ8064" },
  168. { 122, "MSM8660A" },
  169. { 123, "MSM8260A" },
  170. { 124, "APQ8060A" },
  171. { 126, "MSM8974" },
  172. { 130, "MPQ8064" },
  173. { 138, "MSM8960AB" },
  174. { 139, "APQ8060AB" },
  175. { 140, "MSM8260AB" },
  176. { 141, "MSM8660AB" },
  177. { 178, "APQ8084" },
  178. { 184, "APQ8074" },
  179. { 185, "MSM8274" },
  180. { 186, "MSM8674" },
  181. { 194, "MSM8974PRO" },
  182. { 206, "MSM8916" },
  183. { 207, "MSM8994" },
  184. { 208, "APQ8074-AA" },
  185. { 209, "APQ8074-AB" },
  186. { 210, "APQ8074PRO" },
  187. { 211, "MSM8274-AA" },
  188. { 212, "MSM8274-AB" },
  189. { 213, "MSM8274PRO" },
  190. { 214, "MSM8674-AA" },
  191. { 215, "MSM8674-AB" },
  192. { 216, "MSM8674PRO" },
  193. { 217, "MSM8974-AA" },
  194. { 218, "MSM8974-AB" },
  195. { 233, "MSM8936" },
  196. { 239, "MSM8939" },
  197. { 240, "APQ8036" },
  198. { 241, "APQ8039" },
  199. { 246, "MSM8996" },
  200. { 247, "APQ8016" },
  201. { 248, "MSM8216" },
  202. { 249, "MSM8116" },
  203. { 250, "MSM8616" },
  204. { 251, "MSM8992" },
  205. { 253, "APQ8094" },
  206. { 291, "APQ8096" },
  207. { 305, "MSM8996SG" },
  208. { 310, "MSM8996AU" },
  209. { 311, "APQ8096AU" },
  210. { 312, "APQ8096SG" },
  211. { 318, "SDM630" },
  212. { 321, "SDM845" },
  213. { 341, "SDA845" },
  214. { 356, "SM8250" },
  215. { 402, "IPQ6018" },
  216. { 425, "SC7180" },
  217. };
  218. static const char *socinfo_machine(struct device *dev, unsigned int id)
  219. {
  220. int idx;
  221. for (idx = 0; idx < ARRAY_SIZE(soc_id); idx++) {
  222. if (soc_id[idx].id == id)
  223. return soc_id[idx].name;
  224. }
  225. return NULL;
  226. }
  227. #ifdef CONFIG_DEBUG_FS
  228. #define QCOM_OPEN(name, _func) \
  229. static int qcom_open_##name(struct inode *inode, struct file *file) \
  230. { \
  231. return single_open(file, _func, inode->i_private); \
  232. } \
  233. \
  234. static const struct file_operations qcom_ ##name## _ops = { \
  235. .open = qcom_open_##name, \
  236. .read = seq_read, \
  237. .llseek = seq_lseek, \
  238. .release = single_release, \
  239. }
  240. #define DEBUGFS_ADD(info, name) \
  241. debugfs_create_file(__stringify(name), 0400, \
  242. qcom_socinfo->dbg_root, \
  243. info, &qcom_ ##name## _ops)
  244. static int qcom_show_build_id(struct seq_file *seq, void *p)
  245. {
  246. struct socinfo *socinfo = seq->private;
  247. seq_printf(seq, "%s\n", socinfo->build_id);
  248. return 0;
  249. }
  250. static int qcom_show_pmic_model(struct seq_file *seq, void *p)
  251. {
  252. struct socinfo *socinfo = seq->private;
  253. int model = SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_model));
  254. if (model < 0)
  255. return -EINVAL;
  256. if (model < ARRAY_SIZE(pmic_models) && pmic_models[model])
  257. seq_printf(seq, "%s\n", pmic_models[model]);
  258. else
  259. seq_printf(seq, "unknown (%d)\n", model);
  260. return 0;
  261. }
  262. static int qcom_show_pmic_die_revision(struct seq_file *seq, void *p)
  263. {
  264. struct socinfo *socinfo = seq->private;
  265. seq_printf(seq, "%u.%u\n",
  266. SOCINFO_MAJOR(le32_to_cpu(socinfo->pmic_die_rev)),
  267. SOCINFO_MINOR(le32_to_cpu(socinfo->pmic_die_rev)));
  268. return 0;
  269. }
  270. static int qcom_show_chip_id(struct seq_file *seq, void *p)
  271. {
  272. struct socinfo *socinfo = seq->private;
  273. seq_printf(seq, "%s\n", socinfo->chip_id);
  274. return 0;
  275. }
  276. QCOM_OPEN(build_id, qcom_show_build_id);
  277. QCOM_OPEN(pmic_model, qcom_show_pmic_model);
  278. QCOM_OPEN(pmic_die_rev, qcom_show_pmic_die_revision);
  279. QCOM_OPEN(chip_id, qcom_show_chip_id);
  280. #define DEFINE_IMAGE_OPS(type) \
  281. static int show_image_##type(struct seq_file *seq, void *p) \
  282. { \
  283. struct smem_image_version *image_version = seq->private; \
  284. seq_puts(seq, image_version->type); \
  285. seq_putc(seq, '\n'); \
  286. return 0; \
  287. } \
  288. static int open_image_##type(struct inode *inode, struct file *file) \
  289. { \
  290. return single_open(file, show_image_##type, inode->i_private); \
  291. } \
  292. \
  293. static const struct file_operations qcom_image_##type##_ops = { \
  294. .open = open_image_##type, \
  295. .read = seq_read, \
  296. .llseek = seq_lseek, \
  297. .release = single_release, \
  298. }
  299. DEFINE_IMAGE_OPS(name);
  300. DEFINE_IMAGE_OPS(variant);
  301. DEFINE_IMAGE_OPS(oem);
  302. static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
  303. struct socinfo *info)
  304. {
  305. struct smem_image_version *versions;
  306. struct dentry *dentry;
  307. size_t size;
  308. int i;
  309. qcom_socinfo->dbg_root = debugfs_create_dir("qcom_socinfo", NULL);
  310. qcom_socinfo->info.fmt = __le32_to_cpu(info->fmt);
  311. debugfs_create_x32("info_fmt", 0400, qcom_socinfo->dbg_root,
  312. &qcom_socinfo->info.fmt);
  313. switch (qcom_socinfo->info.fmt) {
  314. case SOCINFO_VERSION(0, 15):
  315. qcom_socinfo->info.nmodem_supported = __le32_to_cpu(info->nmodem_supported);
  316. debugfs_create_u32("nmodem_supported", 0400, qcom_socinfo->dbg_root,
  317. &qcom_socinfo->info.nmodem_supported);
  318. fallthrough;
  319. case SOCINFO_VERSION(0, 14):
  320. qcom_socinfo->info.num_clusters = __le32_to_cpu(info->num_clusters);
  321. qcom_socinfo->info.ncluster_array_offset = __le32_to_cpu(info->ncluster_array_offset);
  322. qcom_socinfo->info.num_defective_parts = __le32_to_cpu(info->num_defective_parts);
  323. qcom_socinfo->info.ndefective_parts_array_offset = __le32_to_cpu(info->ndefective_parts_array_offset);
  324. debugfs_create_u32("num_clusters", 0400, qcom_socinfo->dbg_root,
  325. &qcom_socinfo->info.num_clusters);
  326. debugfs_create_u32("ncluster_array_offset", 0400, qcom_socinfo->dbg_root,
  327. &qcom_socinfo->info.ncluster_array_offset);
  328. debugfs_create_u32("num_defective_parts", 0400, qcom_socinfo->dbg_root,
  329. &qcom_socinfo->info.num_defective_parts);
  330. debugfs_create_u32("ndefective_parts_array_offset", 0400, qcom_socinfo->dbg_root,
  331. &qcom_socinfo->info.ndefective_parts_array_offset);
  332. fallthrough;
  333. case SOCINFO_VERSION(0, 13):
  334. qcom_socinfo->info.nproduct_id = __le32_to_cpu(info->nproduct_id);
  335. debugfs_create_u32("nproduct_id", 0400, qcom_socinfo->dbg_root,
  336. &qcom_socinfo->info.nproduct_id);
  337. DEBUGFS_ADD(info, chip_id);
  338. fallthrough;
  339. case SOCINFO_VERSION(0, 12):
  340. qcom_socinfo->info.chip_family =
  341. __le32_to_cpu(info->chip_family);
  342. qcom_socinfo->info.raw_device_family =
  343. __le32_to_cpu(info->raw_device_family);
  344. qcom_socinfo->info.raw_device_num =
  345. __le32_to_cpu(info->raw_device_num);
  346. debugfs_create_x32("chip_family", 0400, qcom_socinfo->dbg_root,
  347. &qcom_socinfo->info.chip_family);
  348. debugfs_create_x32("raw_device_family", 0400,
  349. qcom_socinfo->dbg_root,
  350. &qcom_socinfo->info.raw_device_family);
  351. debugfs_create_x32("raw_device_number", 0400,
  352. qcom_socinfo->dbg_root,
  353. &qcom_socinfo->info.raw_device_num);
  354. fallthrough;
  355. case SOCINFO_VERSION(0, 11):
  356. case SOCINFO_VERSION(0, 10):
  357. case SOCINFO_VERSION(0, 9):
  358. qcom_socinfo->info.foundry_id = __le32_to_cpu(info->foundry_id);
  359. debugfs_create_u32("foundry_id", 0400, qcom_socinfo->dbg_root,
  360. &qcom_socinfo->info.foundry_id);
  361. fallthrough;
  362. case SOCINFO_VERSION(0, 8):
  363. case SOCINFO_VERSION(0, 7):
  364. DEBUGFS_ADD(info, pmic_model);
  365. DEBUGFS_ADD(info, pmic_die_rev);
  366. fallthrough;
  367. case SOCINFO_VERSION(0, 6):
  368. qcom_socinfo->info.hw_plat_subtype =
  369. __le32_to_cpu(info->hw_plat_subtype);
  370. debugfs_create_u32("hardware_platform_subtype", 0400,
  371. qcom_socinfo->dbg_root,
  372. &qcom_socinfo->info.hw_plat_subtype);
  373. fallthrough;
  374. case SOCINFO_VERSION(0, 5):
  375. qcom_socinfo->info.accessory_chip =
  376. __le32_to_cpu(info->accessory_chip);
  377. debugfs_create_u32("accessory_chip", 0400,
  378. qcom_socinfo->dbg_root,
  379. &qcom_socinfo->info.accessory_chip);
  380. fallthrough;
  381. case SOCINFO_VERSION(0, 4):
  382. qcom_socinfo->info.plat_ver = __le32_to_cpu(info->plat_ver);
  383. debugfs_create_u32("platform_version", 0400,
  384. qcom_socinfo->dbg_root,
  385. &qcom_socinfo->info.plat_ver);
  386. fallthrough;
  387. case SOCINFO_VERSION(0, 3):
  388. qcom_socinfo->info.hw_plat = __le32_to_cpu(info->hw_plat);
  389. debugfs_create_u32("hardware_platform", 0400,
  390. qcom_socinfo->dbg_root,
  391. &qcom_socinfo->info.hw_plat);
  392. fallthrough;
  393. case SOCINFO_VERSION(0, 2):
  394. qcom_socinfo->info.raw_ver = __le32_to_cpu(info->raw_ver);
  395. debugfs_create_u32("raw_version", 0400, qcom_socinfo->dbg_root,
  396. &qcom_socinfo->info.raw_ver);
  397. fallthrough;
  398. case SOCINFO_VERSION(0, 1):
  399. DEBUGFS_ADD(info, build_id);
  400. break;
  401. }
  402. versions = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_IMAGE_VERSION_TABLE,
  403. &size);
  404. for (i = 0; i < ARRAY_SIZE(socinfo_image_names); i++) {
  405. if (!socinfo_image_names[i])
  406. continue;
  407. dentry = debugfs_create_dir(socinfo_image_names[i],
  408. qcom_socinfo->dbg_root);
  409. debugfs_create_file("name", 0400, dentry, &versions[i],
  410. &qcom_image_name_ops);
  411. debugfs_create_file("variant", 0400, dentry, &versions[i],
  412. &qcom_image_variant_ops);
  413. debugfs_create_file("oem", 0400, dentry, &versions[i],
  414. &qcom_image_oem_ops);
  415. }
  416. }
  417. static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo)
  418. {
  419. debugfs_remove_recursive(qcom_socinfo->dbg_root);
  420. }
  421. #else
  422. static void socinfo_debugfs_init(struct qcom_socinfo *qcom_socinfo,
  423. struct socinfo *info)
  424. {
  425. }
  426. static void socinfo_debugfs_exit(struct qcom_socinfo *qcom_socinfo) { }
  427. #endif /* CONFIG_DEBUG_FS */
  428. static int qcom_socinfo_probe(struct platform_device *pdev)
  429. {
  430. struct qcom_socinfo *qs;
  431. struct socinfo *info;
  432. size_t item_size;
  433. info = qcom_smem_get(QCOM_SMEM_HOST_ANY, SMEM_HW_SW_BUILD_ID,
  434. &item_size);
  435. if (IS_ERR(info)) {
  436. dev_err(&pdev->dev, "Couldn't find socinfo\n");
  437. return PTR_ERR(info);
  438. }
  439. qs = devm_kzalloc(&pdev->dev, sizeof(*qs), GFP_KERNEL);
  440. if (!qs)
  441. return -ENOMEM;
  442. qs->attr.family = "Snapdragon";
  443. qs->attr.machine = socinfo_machine(&pdev->dev,
  444. le32_to_cpu(info->id));
  445. qs->attr.soc_id = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u",
  446. le32_to_cpu(info->id));
  447. qs->attr.revision = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%u.%u",
  448. SOCINFO_MAJOR(le32_to_cpu(info->ver)),
  449. SOCINFO_MINOR(le32_to_cpu(info->ver)));
  450. if (offsetof(struct socinfo, serial_num) <= item_size)
  451. qs->attr.serial_number = devm_kasprintf(&pdev->dev, GFP_KERNEL,
  452. "%u",
  453. le32_to_cpu(info->serial_num));
  454. qs->soc_dev = soc_device_register(&qs->attr);
  455. if (IS_ERR(qs->soc_dev))
  456. return PTR_ERR(qs->soc_dev);
  457. socinfo_debugfs_init(qs, info);
  458. /* Feed the soc specific unique data into entropy pool */
  459. add_device_randomness(info, item_size);
  460. platform_set_drvdata(pdev, qs);
  461. return 0;
  462. }
  463. static int qcom_socinfo_remove(struct platform_device *pdev)
  464. {
  465. struct qcom_socinfo *qs = platform_get_drvdata(pdev);
  466. soc_device_unregister(qs->soc_dev);
  467. socinfo_debugfs_exit(qs);
  468. return 0;
  469. }
  470. static struct platform_driver qcom_socinfo_driver = {
  471. .probe = qcom_socinfo_probe,
  472. .remove = qcom_socinfo_remove,
  473. .driver = {
  474. .name = "qcom-socinfo",
  475. },
  476. };
  477. module_platform_driver(qcom_socinfo_driver);
  478. MODULE_DESCRIPTION("Qualcomm SoCinfo driver");
  479. MODULE_LICENSE("GPL v2");
  480. MODULE_ALIAS("platform:qcom-socinfo");