pmic-pon-log.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */
  3. /* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. */
  4. #include <linux/err.h>
  5. #include <linux/ipc_logging.h>
  6. #include <linux/kernel.h>
  7. #include <linux/module.h>
  8. #include <linux/nvmem-consumer.h>
  9. #include <linux/of.h>
  10. #include <linux/of_device.h>
  11. #include <linux/platform_device.h>
  12. #include <linux/string.h>
  13. /* SDAM NVMEM register offsets: */
  14. #define REG_SDAM_COUNT 0x45
  15. #define REG_PUSH_PTR 0x46
  16. #define REG_PUSH_SDAM_NUM 0x47
  17. #define REG_FIFO_DATA_START 0x4B
  18. #define REG_FIFO_DATA_END 0xBF
  19. /* PMIC PON LOG binary format in the FIFO: */
  20. struct pmic_pon_log_entry {
  21. u8 state;
  22. u8 event;
  23. u8 data1;
  24. u8 data0;
  25. };
  26. #define FIFO_SIZE (REG_FIFO_DATA_END - REG_FIFO_DATA_START + 1)
  27. #define FIFO_ENTRY_SIZE (sizeof(struct pmic_pon_log_entry))
  28. #define IPC_LOG_PAGES 3
  29. struct pmic_pon_log_dev {
  30. struct device *dev;
  31. struct pmic_pon_log_entry *log;
  32. int log_len;
  33. int log_max_entries;
  34. void *ipc_log;
  35. struct nvmem_device **nvmem;
  36. int nvmem_count;
  37. int sdam_fifo_count;
  38. };
  39. enum pmic_pon_state {
  40. PMIC_PON_STATE_FAULT0 = 0x0,
  41. PMIC_PON_STATE_PON = 0x1,
  42. PMIC_PON_STATE_POFF = 0x2,
  43. PMIC_PON_STATE_ON = 0x3,
  44. PMIC_PON_STATE_RESET = 0x4,
  45. PMIC_PON_STATE_OFF = 0x5,
  46. PMIC_PON_STATE_FAULT6 = 0x6,
  47. PMIC_PON_STATE_WARM_RESET = 0x7,
  48. };
  49. static const char * const pmic_pon_state_label[] = {
  50. [PMIC_PON_STATE_FAULT0] = "FAULT",
  51. [PMIC_PON_STATE_PON] = "PON",
  52. [PMIC_PON_STATE_POFF] = "POFF",
  53. [PMIC_PON_STATE_ON] = "ON",
  54. [PMIC_PON_STATE_RESET] = "RESET",
  55. [PMIC_PON_STATE_OFF] = "OFF",
  56. [PMIC_PON_STATE_FAULT6] = "FAULT",
  57. [PMIC_PON_STATE_WARM_RESET] = "WARM_RESET",
  58. };
  59. enum pmic_pon_event {
  60. PMIC_PON_EVENT_PON_TRIGGER_RECEIVED = 0x01,
  61. PMIC_PON_EVENT_OTP_COPY_COMPLETE = 0x02,
  62. PMIC_PON_EVENT_TRIM_COMPLETE = 0x03,
  63. PMIC_PON_EVENT_XVLO_CHECK_COMPLETE = 0x04,
  64. PMIC_PON_EVENT_PMIC_CHECK_COMPLETE = 0x05,
  65. PMIC_PON_EVENT_RESET_TRIGGER_RECEIVED = 0x06,
  66. PMIC_PON_EVENT_RESET_TYPE = 0x07,
  67. PMIC_PON_EVENT_WARM_RESET_COUNT = 0x08,
  68. PMIC_PON_EVENT_FAULT_REASON_1_2 = 0x09,
  69. PMIC_PON_EVENT_FAULT_REASON_3 = 0x0A,
  70. PMIC_PON_EVENT_PBS_PC_DURING_FAULT = 0x0B,
  71. PMIC_PON_EVENT_FUNDAMENTAL_RESET = 0x0C,
  72. PMIC_PON_EVENT_PON_SEQ_START = 0x0D,
  73. PMIC_PON_EVENT_PON_SUCCESS = 0x0E,
  74. PMIC_PON_EVENT_WAITING_ON_PSHOLD = 0x0F,
  75. PMIC_PON_EVENT_PMIC_SID1_FAULT = 0x10,
  76. PMIC_PON_EVENT_PMIC_SID2_FAULT = 0x11,
  77. PMIC_PON_EVENT_PMIC_SID3_FAULT = 0x12,
  78. PMIC_PON_EVENT_PMIC_SID4_FAULT = 0x13,
  79. PMIC_PON_EVENT_PMIC_SID5_FAULT = 0x14,
  80. PMIC_PON_EVENT_PMIC_SID6_FAULT = 0x15,
  81. PMIC_PON_EVENT_PMIC_SID7_FAULT = 0x16,
  82. PMIC_PON_EVENT_PMIC_SID8_FAULT = 0x17,
  83. PMIC_PON_EVENT_PMIC_SID9_FAULT = 0x18,
  84. PMIC_PON_EVENT_PMIC_SID10_FAULT = 0x19,
  85. PMIC_PON_EVENT_PMIC_SID11_FAULT = 0x1A,
  86. PMIC_PON_EVENT_PMIC_SID12_FAULT = 0x1B,
  87. PMIC_PON_EVENT_PMIC_SID13_FAULT = 0x1C,
  88. PMIC_PON_EVENT_PMIC_VREG_READY_CHECK = 0x20,
  89. };
  90. enum pmic_pon_reset_type {
  91. PMIC_PON_RESET_TYPE_WARM_RESET = 0x1,
  92. PMIC_PON_RESET_TYPE_SHUTDOWN = 0x4,
  93. PMIC_PON_RESET_TYPE_HARD_RESET = 0x7,
  94. };
  95. static const char * const pmic_pon_reset_type_label[] = {
  96. [PMIC_PON_RESET_TYPE_WARM_RESET] = "WARM_RESET",
  97. [PMIC_PON_RESET_TYPE_SHUTDOWN] = "SHUTDOWN",
  98. [PMIC_PON_RESET_TYPE_HARD_RESET] = "HARD_RESET",
  99. };
  100. static const char * const pmic_pon_fault_reason1[8] = {
  101. [0] = "GP_FAULT0",
  102. [1] = "GP_FAULT1",
  103. [2] = "GP_FAULT2",
  104. [3] = "GP_FAULT3",
  105. [4] = "MBG_FAULT",
  106. [5] = "OVLO",
  107. [6] = "UVLO",
  108. [7] = "AVDD_RB",
  109. };
  110. static const char * const pmic_pon_fault_reason2[8] = {
  111. [0] = "UNKNOWN(0)",
  112. [1] = "UNKNOWN(1)",
  113. [2] = "PMIC_RB",
  114. [3] = "FAULT_N",
  115. [4] = "FAULT_WATCHDOG",
  116. [5] = "PBS_NACK",
  117. [6] = "RESTART_PON",
  118. [7] = "OVERTEMP_STAGE3",
  119. };
  120. static const char * const pmic_pon_fault_reason3[8] = {
  121. [0] = "GP_FAULT4",
  122. [1] = "GP_FAULT5",
  123. [2] = "GP_FAULT6",
  124. [3] = "GP_FAULT7",
  125. [4] = "GP_FAULT8",
  126. [5] = "GP_FAULT9",
  127. [6] = "GP_FAULT10",
  128. [7] = "GP_FAULT11",
  129. };
  130. static const char * const pmic_pon_s3_reset_reason[8] = {
  131. [0] = "UNKNOWN(0)",
  132. [1] = "UNKNOWN(1)",
  133. [2] = "UNKNOWN(2)",
  134. [3] = "UNKNOWN(3)",
  135. [4] = "FAULT_N",
  136. [5] = "FAULT_WATCHDOG",
  137. [6] = "PBS_NACK",
  138. [7] = "KPDPWR_AND/OR_RESIN",
  139. };
  140. static const char * const pmic_pon_pon_pbl_status[8] = {
  141. [0] = "UNKNOWN(0)",
  142. [1] = "UNKNOWN(1)",
  143. [2] = "UNKNOWN(2)",
  144. [3] = "UNKNOWN(3)",
  145. [4] = "UNKNOWN(4)",
  146. [5] = "UNKNOWN(5)",
  147. [6] = "XVDD",
  148. [7] = "DVDD",
  149. };
  150. struct pmic_pon_trigger_mapping {
  151. u16 code;
  152. const char *label;
  153. };
  154. static const struct pmic_pon_trigger_mapping pmic_pon_pon_trigger_map[] = {
  155. {0x0084, "PS_HOLD"},
  156. {0x0085, "HARD_RESET"},
  157. {0x0086, "RESIN_N"},
  158. {0x0087, "KPDPWR_N"},
  159. /* PM5100 USB PON trigger */
  160. {0x0202, "USB_CHARGER"},
  161. {0x0621, "RTC_ALARM"},
  162. {0x0640, "SMPL"},
  163. /* PMX75 USB PON trigger */
  164. {0x18A0, "USB_CHARGER"},
  165. {0x18C0, "PMIC_SID1_GPIO5"},
  166. /* PMI632 USB PON trigger */
  167. {0x2763, "USB_CHARGER"},
  168. /* PM8350B USB PON trigger */
  169. {0x31C2, "USB_CHARGER"},
  170. /* PM8550B USB PON trigger */
  171. /* PM7550BA USB PON trigger */
  172. {0x71C2, "USB_CHARGER"},
  173. /* PM7250B USB PON trigger */
  174. {0x8732, "USB_CHARGER"},
  175. };
  176. static const struct pmic_pon_trigger_mapping pmic_pon_reset_trigger_map[] = {
  177. {0x0080, "KPDPWR_N_S2"},
  178. {0x0081, "RESIN_N_S2"},
  179. {0x0082, "KPDPWR_N_AND_RESIN_N_S2"},
  180. {0x0083, "PMIC_WATCHDOG_S2"},
  181. {0x0084, "PS_HOLD"},
  182. {0x0085, "SW_RESET"},
  183. {0x0086, "RESIN_N_DEBOUNCE"},
  184. {0x0087, "KPDPWR_N_DEBOUNCE"},
  185. {0x21E3, "PMIC_SID2_BCL_ALARM"},
  186. {0x31F5, "PMIC_SID3_BCL_ALARM"},
  187. {0x11D0, "PMIC_SID1_OCP"},
  188. {0x21D0, "PMIC_SID2_OCP"},
  189. {0x41D0, "PMIC_SID4_OCP"},
  190. {0x51D0, "PMIC_SID5_OCP"},
  191. };
  192. static const enum pmic_pon_event pmic_pon_important_events[] = {
  193. PMIC_PON_EVENT_PON_TRIGGER_RECEIVED,
  194. PMIC_PON_EVENT_RESET_TRIGGER_RECEIVED,
  195. PMIC_PON_EVENT_RESET_TYPE,
  196. PMIC_PON_EVENT_FAULT_REASON_1_2,
  197. PMIC_PON_EVENT_FAULT_REASON_3,
  198. PMIC_PON_EVENT_FUNDAMENTAL_RESET,
  199. PMIC_PON_EVENT_PMIC_SID1_FAULT,
  200. PMIC_PON_EVENT_PMIC_SID2_FAULT,
  201. PMIC_PON_EVENT_PMIC_SID3_FAULT,
  202. PMIC_PON_EVENT_PMIC_SID4_FAULT,
  203. PMIC_PON_EVENT_PMIC_SID5_FAULT,
  204. PMIC_PON_EVENT_PMIC_SID6_FAULT,
  205. PMIC_PON_EVENT_PMIC_SID7_FAULT,
  206. PMIC_PON_EVENT_PMIC_SID8_FAULT,
  207. PMIC_PON_EVENT_PMIC_SID9_FAULT,
  208. PMIC_PON_EVENT_PMIC_SID10_FAULT,
  209. PMIC_PON_EVENT_PMIC_SID11_FAULT,
  210. PMIC_PON_EVENT_PMIC_SID12_FAULT,
  211. PMIC_PON_EVENT_PMIC_SID13_FAULT,
  212. PMIC_PON_EVENT_PMIC_VREG_READY_CHECK,
  213. };
  214. static bool pmic_pon_entry_is_important(const struct pmic_pon_log_entry *entry)
  215. {
  216. int i;
  217. for (i = 0; i < ARRAY_SIZE(pmic_pon_important_events); i++)
  218. if (entry->event == pmic_pon_important_events[i])
  219. return true;
  220. return false;
  221. }
  222. static int pmic_pon_log_read_entry(struct pmic_pon_log_dev *pon_dev,
  223. u32 entry_start_index, struct pmic_pon_log_entry *entry)
  224. {
  225. u8 *buf = (u8 *)entry;
  226. int ret, len, fifo_total_size, entry_start_sdam, entry_start_addr, i;
  227. fifo_total_size = FIFO_SIZE * pon_dev->sdam_fifo_count;
  228. entry_start_index = entry_start_index % fifo_total_size;
  229. entry_start_sdam = entry_start_index / FIFO_SIZE;
  230. entry_start_addr = (entry_start_index % FIFO_SIZE)
  231. + REG_FIFO_DATA_START;
  232. if (entry_start_addr + FIFO_ENTRY_SIZE - 1 > REG_FIFO_DATA_END) {
  233. /* The entry continues beyond the end of this SDAM */
  234. len = FIFO_SIZE - (entry_start_index % FIFO_SIZE);
  235. ret = nvmem_device_read(pon_dev->nvmem[entry_start_sdam],
  236. entry_start_addr, len, buf);
  237. if (ret < 0)
  238. return ret;
  239. i = (entry_start_sdam + 1) % pon_dev->sdam_fifo_count;
  240. ret = nvmem_device_read(pon_dev->nvmem[i], REG_FIFO_DATA_START,
  241. FIFO_ENTRY_SIZE - len, &buf[len]);
  242. } else {
  243. ret = nvmem_device_read(pon_dev->nvmem[entry_start_sdam],
  244. entry_start_addr, FIFO_ENTRY_SIZE, buf);
  245. }
  246. return ret;
  247. }
  248. static int pmic_pon_log_print_reason(char *buf, int buf_size, u8 data,
  249. const char * const *reason)
  250. {
  251. int pos = 0;
  252. int i;
  253. bool first;
  254. if (data == 0) {
  255. pos += scnprintf(buf + pos, buf_size - pos, "None");
  256. } else {
  257. first = true;
  258. for (i = 0; i < 8; i++) {
  259. if (data & BIT(i)) {
  260. pos += scnprintf(buf + pos, buf_size - pos,
  261. "%s%s",
  262. (first ? "" : ", "), reason[i]);
  263. first = false;
  264. }
  265. }
  266. }
  267. return pos;
  268. }
  269. #define BUF_SIZE 128
  270. static int pmic_pon_log_parse_entry(const struct pmic_pon_log_entry *entry,
  271. void *ipc_log)
  272. {
  273. char buf[BUF_SIZE];
  274. const char *label = NULL;
  275. bool is_important;
  276. int pos = 0;
  277. int i;
  278. u16 data;
  279. data = (entry->data1 << 8) | entry->data0;
  280. buf[0] = '\0';
  281. is_important = pmic_pon_entry_is_important(entry);
  282. switch (entry->event) {
  283. case PMIC_PON_EVENT_PON_TRIGGER_RECEIVED:
  284. for (i = 0; i < ARRAY_SIZE(pmic_pon_pon_trigger_map); i++) {
  285. if (pmic_pon_pon_trigger_map[i].code == data) {
  286. label = pmic_pon_pon_trigger_map[i].label;
  287. break;
  288. }
  289. }
  290. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  291. "PON Trigger: ");
  292. if (label) {
  293. pos += scnprintf(buf + pos, BUF_SIZE - pos, "%s",
  294. label);
  295. } else {
  296. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  297. "SID=0x%X, PID=0x%02X, IRQ=0x%X",
  298. entry->data1 >> 4, (data >> 4) & 0xFF,
  299. entry->data0 & 0x7);
  300. }
  301. break;
  302. case PMIC_PON_EVENT_OTP_COPY_COMPLETE:
  303. scnprintf(buf, BUF_SIZE,
  304. "OTP Copy Complete: last addr written=0x%04X",
  305. data);
  306. break;
  307. case PMIC_PON_EVENT_TRIM_COMPLETE:
  308. scnprintf(buf, BUF_SIZE, "Trim Complete: %u bytes written",
  309. data);
  310. break;
  311. case PMIC_PON_EVENT_XVLO_CHECK_COMPLETE:
  312. scnprintf(buf, BUF_SIZE, "XVLO Check Complete");
  313. break;
  314. case PMIC_PON_EVENT_PMIC_CHECK_COMPLETE:
  315. scnprintf(buf, BUF_SIZE, "PMICs Detected: SID Mask=0x%04X",
  316. data);
  317. break;
  318. case PMIC_PON_EVENT_RESET_TRIGGER_RECEIVED:
  319. for (i = 0; i < ARRAY_SIZE(pmic_pon_reset_trigger_map); i++) {
  320. if (pmic_pon_reset_trigger_map[i].code == data) {
  321. label = pmic_pon_reset_trigger_map[i].label;
  322. break;
  323. }
  324. }
  325. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  326. "Reset Trigger: ");
  327. if (label) {
  328. pos += scnprintf(buf + pos, BUF_SIZE - pos, "%s",
  329. label);
  330. } else {
  331. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  332. "SID=0x%X, PID=0x%02X, IRQ=0x%X",
  333. entry->data1 >> 4, (data >> 4) & 0xFF,
  334. entry->data0 & 0x7);
  335. }
  336. break;
  337. case PMIC_PON_EVENT_RESET_TYPE:
  338. if (entry->data0 < ARRAY_SIZE(pmic_pon_reset_type_label) &&
  339. pmic_pon_reset_type_label[entry->data0])
  340. scnprintf(buf, BUF_SIZE, "Reset Type: %s",
  341. pmic_pon_reset_type_label[entry->data0]);
  342. else
  343. scnprintf(buf, BUF_SIZE, "Reset Type: UNKNOWN (%u)",
  344. entry->data0);
  345. break;
  346. case PMIC_PON_EVENT_WARM_RESET_COUNT:
  347. scnprintf(buf, BUF_SIZE, "Warm Reset Count: %u", data);
  348. break;
  349. case PMIC_PON_EVENT_FAULT_REASON_1_2:
  350. if (!entry->data0 && !entry->data1)
  351. is_important = false;
  352. if (entry->data0 || !is_important) {
  353. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  354. "FAULT_REASON1=");
  355. pos += pmic_pon_log_print_reason(buf + pos,
  356. BUF_SIZE - pos, entry->data0,
  357. pmic_pon_fault_reason1);
  358. }
  359. if (entry->data1 || !is_important) {
  360. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  361. "%sFAULT_REASON2=",
  362. (entry->data0 || !is_important)
  363. ? "; " : "");
  364. pos += pmic_pon_log_print_reason(buf + pos,
  365. BUF_SIZE - pos, entry->data1,
  366. pmic_pon_fault_reason2);
  367. }
  368. break;
  369. case PMIC_PON_EVENT_FAULT_REASON_3:
  370. if (!entry->data0)
  371. is_important = false;
  372. pos += scnprintf(buf + pos, BUF_SIZE - pos, "FAULT_REASON3=");
  373. pos += pmic_pon_log_print_reason(buf + pos, BUF_SIZE - pos,
  374. entry->data0, pmic_pon_fault_reason3);
  375. break;
  376. case PMIC_PON_EVENT_PBS_PC_DURING_FAULT:
  377. scnprintf(buf, BUF_SIZE, "PBS PC at Fault: 0x%04X", data);
  378. break;
  379. case PMIC_PON_EVENT_FUNDAMENTAL_RESET:
  380. if (!entry->data0 && !entry->data1)
  381. is_important = false;
  382. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  383. "Fundamental Reset: ");
  384. if (entry->data1 || !is_important) {
  385. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  386. "PON_PBL_STATUS=");
  387. pos += pmic_pon_log_print_reason(buf + pos,
  388. BUF_SIZE - pos, entry->data1,
  389. pmic_pon_pon_pbl_status);
  390. }
  391. if (entry->data0 || !is_important) {
  392. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  393. "%sS3_RESET_REASON=",
  394. (entry->data1 || !is_important)
  395. ? "; " : "");
  396. pos += pmic_pon_log_print_reason(buf + pos,
  397. BUF_SIZE - pos, entry->data0,
  398. pmic_pon_s3_reset_reason);
  399. }
  400. break;
  401. case PMIC_PON_EVENT_PON_SEQ_START:
  402. scnprintf(buf, BUF_SIZE, "Begin PON Sequence");
  403. break;
  404. case PMIC_PON_EVENT_PON_SUCCESS:
  405. scnprintf(buf, BUF_SIZE, "PON Successful");
  406. break;
  407. case PMIC_PON_EVENT_WAITING_ON_PSHOLD:
  408. scnprintf(buf, BUF_SIZE, "Waiting on PS_HOLD");
  409. break;
  410. case PMIC_PON_EVENT_PMIC_SID1_FAULT ... PMIC_PON_EVENT_PMIC_SID13_FAULT:
  411. if (!entry->data0 && !entry->data1)
  412. is_important = false;
  413. pos += scnprintf(buf + pos, BUF_SIZE - pos, "PMIC SID%u ",
  414. entry->event - PMIC_PON_EVENT_PMIC_SID1_FAULT + 1);
  415. if (entry->data0 || !is_important) {
  416. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  417. "FAULT_REASON1=");
  418. pos += pmic_pon_log_print_reason(buf + pos,
  419. BUF_SIZE - pos, entry->data0,
  420. pmic_pon_fault_reason1);
  421. }
  422. if (entry->data1 || !is_important) {
  423. pos += scnprintf(buf + pos, BUF_SIZE - pos,
  424. "%sFAULT_REASON2=",
  425. (entry->data0 || !is_important)
  426. ? "; " : "");
  427. pos += pmic_pon_log_print_reason(buf + pos,
  428. BUF_SIZE - pos, entry->data1,
  429. pmic_pon_fault_reason2);
  430. }
  431. break;
  432. case PMIC_PON_EVENT_PMIC_VREG_READY_CHECK:
  433. if (!data)
  434. is_important = false;
  435. scnprintf(buf, BUF_SIZE, "VREG Check: %sVREG_FAULT detected",
  436. data ? "" : "No ");
  437. break;
  438. default:
  439. scnprintf(buf, BUF_SIZE, "Unknown Event (0x%02X): data=0x%04X",
  440. entry->event, data);
  441. break;
  442. }
  443. if (is_important)
  444. pr_info("PMIC PON log: %s\n", buf);
  445. else
  446. pr_debug("PMIC PON log: %s\n", buf);
  447. if (entry->state < ARRAY_SIZE(pmic_pon_state_label))
  448. ipc_log_string(ipc_log, "State=%s; %s\n",
  449. pmic_pon_state_label[entry->state], buf);
  450. else
  451. ipc_log_string(ipc_log, "State=Unknown (0x%02X); %s\n",
  452. entry->state, buf);
  453. return 0;
  454. }
  455. static int pmic_pon_log_parse(struct pmic_pon_log_dev *pon_dev)
  456. {
  457. int ret, i, addr_end, sdam_end, fifo_index_start, fifo_index_end, index;
  458. struct pmic_pon_log_entry entry;
  459. u8 buf;
  460. ret = nvmem_device_read(pon_dev->nvmem[0], REG_PUSH_PTR, 1, &buf);
  461. if (ret < 0)
  462. return ret;
  463. addr_end = buf;
  464. if (addr_end < REG_FIFO_DATA_START || addr_end > REG_FIFO_DATA_END) {
  465. dev_err(pon_dev->dev, "unexpected PON log end address: %02X\n",
  466. addr_end);
  467. return -EINVAL;
  468. }
  469. ret = nvmem_device_read(pon_dev->nvmem[0], REG_PUSH_SDAM_NUM, 1, &buf);
  470. if (ret < 0)
  471. return ret;
  472. sdam_end = buf;
  473. if (sdam_end >= pon_dev->sdam_fifo_count) {
  474. dev_err(pon_dev->dev, "unexpected PON log end SDAM index: %d\n",
  475. sdam_end);
  476. return -EINVAL;
  477. }
  478. fifo_index_end = sdam_end * FIFO_SIZE + addr_end - REG_FIFO_DATA_START;
  479. /*
  480. * Calculate the FIFO start index from the end index assuming that the
  481. * FIFO is full.
  482. */
  483. fifo_index_start = fifo_index_end
  484. - pon_dev->log_max_entries * FIFO_ENTRY_SIZE;
  485. if (fifo_index_start < 0)
  486. fifo_index_start += FIFO_SIZE * pon_dev->sdam_fifo_count;
  487. for (i = 0; i < pon_dev->log_max_entries; i++) {
  488. index = fifo_index_start + i * FIFO_ENTRY_SIZE;
  489. ret = pmic_pon_log_read_entry(pon_dev, index, &entry);
  490. if (ret < 0)
  491. return ret;
  492. if (entry.state == 0 && entry.event == 0 && entry.data1 == 0 &&
  493. entry.data0 == 0) {
  494. /*
  495. * Ignore all 0 entries which correspond to unused
  496. * FIFO space in the case that the FIFO has not wrapped
  497. * around.
  498. */
  499. continue;
  500. }
  501. ret = pmic_pon_log_parse_entry(&entry, pon_dev->ipc_log);
  502. if (ret < 0)
  503. return ret;
  504. pon_dev->log[pon_dev->log_len++] = entry;
  505. }
  506. return 0;
  507. }
  508. #define FAULT_REASON2_FAULT_N_MASK BIT(3)
  509. #define FAULT_REASON2_RESTART_PON_MASK BIT(6)
  510. /* Trigger a kernel panic if the last power off was caused by a PMIC fault. */
  511. static void pmic_pon_log_fault_panic(struct pmic_pon_log_dev *pon_dev)
  512. {
  513. int last_pon_success = pon_dev->log_len - 1;
  514. int prev_pon_success = 0;
  515. int warm_reset_skip_count = 0;
  516. bool pon_success_found = false;
  517. char buf[BUF_SIZE];
  518. u8 mask;
  519. int i;
  520. mask = (u8)~(FAULT_REASON2_RESTART_PON_MASK |
  521. FAULT_REASON2_FAULT_N_MASK);
  522. /*
  523. * Iterate over log events from newest to oldest. Find the most recent
  524. * and second most recent PON success events. Ignore PON success events
  525. * associated with a Warm Reset.
  526. */
  527. for (i = pon_dev->log_len - 1; i >= 0; i--) {
  528. if (pon_dev->log[i].event == PMIC_PON_EVENT_PON_SUCCESS) {
  529. if (!pon_success_found) {
  530. last_pon_success = i;
  531. pon_success_found = true;
  532. } else if (warm_reset_skip_count > 0) {
  533. warm_reset_skip_count--;
  534. } else {
  535. prev_pon_success = i;
  536. break;
  537. }
  538. } else if (pon_dev->log[i].event ==
  539. PMIC_PON_EVENT_WARM_RESET_COUNT) {
  540. warm_reset_skip_count = (pon_dev->log[i].data1 << 8) |
  541. pon_dev->log[i].data0;
  542. }
  543. }
  544. /*
  545. * Check if a fault event occurred between the previous and last PON
  546. * success events. Trigger a kernel panic if so.
  547. */
  548. for (i = prev_pon_success; i <= last_pon_success; i++) {
  549. switch (pon_dev->log[i].event) {
  550. case PMIC_PON_EVENT_FAULT_REASON_1_2:
  551. if (pon_dev->log[i].data0) {
  552. pmic_pon_log_print_reason(buf, BUF_SIZE,
  553. pon_dev->log[i].data0,
  554. pmic_pon_fault_reason1);
  555. panic("PMIC SID0 FAULT; FAULT_REASON1=%s", buf);
  556. } else if (pon_dev->log[i].data1 & mask) {
  557. pmic_pon_log_print_reason(buf, BUF_SIZE,
  558. pon_dev->log[i].data1,
  559. pmic_pon_fault_reason2);
  560. panic("PMIC SID0 FAULT; FAULT_REASON2=%s", buf);
  561. }
  562. break;
  563. case PMIC_PON_EVENT_FAULT_REASON_3:
  564. if (pon_dev->log[i].data0) {
  565. pmic_pon_log_print_reason(buf, BUF_SIZE,
  566. pon_dev->log[i].data0,
  567. pmic_pon_fault_reason3);
  568. panic("PMIC SID0 FAULT; FAULT_REASON3=%s", buf);
  569. }
  570. break;
  571. case PMIC_PON_EVENT_PMIC_SID1_FAULT ... PMIC_PON_EVENT_PMIC_SID13_FAULT:
  572. if (pon_dev->log[i].data0) {
  573. pmic_pon_log_print_reason(buf, BUF_SIZE,
  574. pon_dev->log[i].data0,
  575. pmic_pon_fault_reason1);
  576. panic("PMIC SID%u FAULT; FAULT_REASON1=%s",
  577. pon_dev->log[i].event -
  578. PMIC_PON_EVENT_PMIC_SID1_FAULT + 1,
  579. buf);
  580. } else if (pon_dev->log[i].data1 & mask) {
  581. pmic_pon_log_print_reason(buf, BUF_SIZE,
  582. pon_dev->log[i].data1,
  583. pmic_pon_fault_reason2);
  584. panic("PMIC SID%u FAULT; FAULT_REASON2=%s",
  585. pon_dev->log[i].event -
  586. PMIC_PON_EVENT_PMIC_SID1_FAULT + 1,
  587. buf);
  588. }
  589. break;
  590. default:
  591. break;
  592. }
  593. }
  594. }
  595. static int pmic_pon_log_probe(struct platform_device *pdev)
  596. {
  597. struct pmic_pon_log_dev *pon_dev;
  598. char buf[12] = "";
  599. int ret, i;
  600. u8 reg = 0;
  601. pon_dev = devm_kzalloc(&pdev->dev, sizeof(*pon_dev), GFP_KERNEL);
  602. if (!pon_dev)
  603. return -ENOMEM;
  604. pon_dev->dev = &pdev->dev;
  605. ret = of_count_phandle_with_args(pdev->dev.of_node, "nvmem", NULL);
  606. if (ret < 0) {
  607. if (ret != -EPROBE_DEFER)
  608. dev_err(&pdev->dev, "failed to get nvmem count, ret=%d\n",
  609. ret);
  610. return ret;
  611. } else if (ret == 0) {
  612. dev_err(&pdev->dev, "nvmem property empty\n");
  613. return -EINVAL;
  614. }
  615. pon_dev->nvmem_count = ret;
  616. pon_dev->nvmem = devm_kcalloc(&pdev->dev, pon_dev->nvmem_count,
  617. sizeof(*pon_dev->nvmem), GFP_KERNEL);
  618. if (!pon_dev->nvmem)
  619. return -ENOMEM;
  620. for (i = 0; i < pon_dev->nvmem_count; i++) {
  621. scnprintf(buf, ARRAY_SIZE(buf), "pon_log%d", i);
  622. pon_dev->nvmem[i] = devm_nvmem_device_get(&pdev->dev, buf);
  623. if (IS_ERR(pon_dev->nvmem[i]) && i == 0 &&
  624. PTR_ERR(pon_dev->nvmem[i]) != EPROBE_DEFER)
  625. pon_dev->nvmem[i] = devm_nvmem_device_get(&pdev->dev,
  626. "pon_log");
  627. if (IS_ERR(pon_dev->nvmem[i])) {
  628. ret = PTR_ERR(pon_dev->nvmem[i]);
  629. if (ret != -EPROBE_DEFER)
  630. dev_err(&pdev->dev, "failed to get nvmem device %d, ret=%d\n",
  631. i, ret);
  632. return ret;
  633. }
  634. }
  635. /* Read how many SDAMs are used for the PON log in PMIC hardware */
  636. ret = nvmem_device_read(pon_dev->nvmem[0], REG_SDAM_COUNT, 1, &reg);
  637. if (ret < 0)
  638. return ret;
  639. pon_dev->sdam_fifo_count = reg + 1;
  640. if (pon_dev->sdam_fifo_count > pon_dev->nvmem_count) {
  641. dev_err(&pdev->dev, "Missing nvmem handles; found %d, expected %d\n",
  642. pon_dev->nvmem_count, pon_dev->sdam_fifo_count);
  643. return -ENODEV;
  644. }
  645. pon_dev->log_max_entries = FIFO_SIZE * pon_dev->sdam_fifo_count
  646. / FIFO_ENTRY_SIZE;
  647. pon_dev->log = devm_kcalloc(&pdev->dev, pon_dev->log_max_entries,
  648. sizeof(*pon_dev->log), GFP_KERNEL);
  649. if (!pon_dev->log)
  650. return -ENOMEM;
  651. pon_dev->ipc_log = ipc_log_context_create(IPC_LOG_PAGES, "pmic_pon", 0);
  652. platform_set_drvdata(pdev, pon_dev);
  653. ret = pmic_pon_log_parse(pon_dev);
  654. if (ret < 0)
  655. dev_err(&pdev->dev, "PMIC PON log parsing failed, ret=%d\n",
  656. ret);
  657. if (of_property_read_bool(pdev->dev.of_node, "qcom,pmic-fault-panic"))
  658. pmic_pon_log_fault_panic(pon_dev);
  659. return ret;
  660. }
  661. static int pmic_pon_log_remove(struct platform_device *pdev)
  662. {
  663. struct pmic_pon_log_dev *pon_dev = platform_get_drvdata(pdev);
  664. ipc_log_context_destroy(pon_dev->ipc_log);
  665. return 0;
  666. }
  667. static const struct of_device_id pmic_pon_log_of_match[] = {
  668. { .compatible = "qcom,pmic-pon-log" },
  669. {}
  670. };
  671. MODULE_DEVICE_TABLE(of, pmic_pon_log_of_match);
  672. static struct platform_driver pmic_pon_log_driver = {
  673. .driver = {
  674. .name = "qti-pmic-pon-log",
  675. .of_match_table = of_match_ptr(pmic_pon_log_of_match),
  676. },
  677. .probe = pmic_pon_log_probe,
  678. .remove = pmic_pon_log_remove,
  679. };
  680. module_platform_driver(pmic_pon_log_driver);
  681. MODULE_DESCRIPTION("QTI PMIC PON log driver");
  682. MODULE_LICENSE("GPL v2");