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