latch.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. /* Copyright Statement:
  2. *
  3. * This software/firmware and related documentation ("MediaTek Software") are
  4. * protected under relevant copyright laws. The information contained herein
  5. * is confidential and proprietary to MediaTek Inc. and/or its licensors.
  6. * Without the prior written permission of MediaTek inc. and/or its licensors,
  7. * any reproduction, modification, use or disclosure of MediaTek Software,
  8. * and information contained herein, in whole or in part, shall be strictly prohibited.
  9. */
  10. /* MediaTek Inc. (C) 2016. All rights reserved.
  11. *
  12. * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
  13. * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
  14. * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
  15. * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
  18. * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
  19. * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
  20. * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
  21. * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
  22. * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
  23. * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
  24. * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
  25. * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
  26. * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
  27. * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
  28. * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
  29. * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
  30. */
  31. #include <reg.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34. #include <malloc.h>
  35. #include <mt_typedefs.h>
  36. #include <platform/mt_reg_base.h>
  37. #include <platform/sync_write.h>
  38. #include <plat_debug_interface.h>
  39. #include <latch.h>
  40. #include "utils.h"
  41. #include "dfd.h"
  42. #include <debug.h>
  43. static struct plt_cfg_cache_latch cfg_cache_latch;
  44. static int default_lastpc_dump(const struct plt_cfg_pc_latch *self, char *buf, int *wp)
  45. {
  46. unsigned int i, cpu_in_cluster = 0, cluster_id;
  47. unsigned int lastpc_valid_before_reboot = 1;
  48. unsigned long long pc_value_h, fp_value_h, sp_value_h;
  49. unsigned long long pc_value, fp_value, sp_value;
  50. unsigned long dbg_ctrl_base, dbg_flag_base;
  51. unsigned long cpu_power_status = 0;
  52. unsigned long plat_sram_flag0;
  53. /* mcusys registers would be corrupted by DFD */
  54. if (dfd_internal_dump_before_reboot()) {
  55. *wp += dfd_internal_dump_get_decoded_lastpc(buf + *wp, LATCH_BUF_LENGTH - *wp);
  56. return 1;
  57. }
  58. if (self->plat_sram_flag0) {
  59. /* must check lastpc_valid_before_reboot */
  60. plat_sram_flag0 = readl(self->plat_sram_flag0);
  61. lastpc_valid_before_reboot = extract_n2mbits(plat_sram_flag0, 1, 1);
  62. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  63. "plat_sram_flag0 = 0x%lx\n(lastpc_valid=%x, lastpc_valid_before_reboot=%x)\n\n",
  64. plat_sram_flag0, extract_n2mbits(plat_sram_flag0, 0, 0),
  65. lastpc_valid_before_reboot);
  66. }
  67. /* get the power status information */
  68. cpu_power_status = plt_get_cpu_power_status_at_wdt();
  69. for (i = 0; i <= self->nr_max_core-1; ++i) {
  70. /* if lastpc_valid_before_reboot is not 1 --> only dump CPU0, skip others */
  71. if (lastpc_valid_before_reboot != 1 && i >= 1) {
  72. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  73. "[LAST PC] CORE_%d PC = 0x0, FP = 0x0, SP = 0x0\n", i);
  74. continue;
  75. }
  76. /* if CPUX is not powered on before reboot --> skip */
  77. if (extract_n2mbits(cpu_power_status, i, i) == 0) {
  78. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  79. "[LAST PC] CORE_%d PC = 0x0, FP = 0x0, SP = 0x0\n", i);
  80. continue;
  81. }
  82. cluster_id = plt_get_cluster_id(i, &cpu_in_cluster);
  83. if (cluster_id == 0) {
  84. /* MP0 */
  85. dbg_ctrl_base = MCUCFG_BASE + self->mp0_dbg_ctrl;
  86. dbg_flag_base = MCUCFG_BASE + self->mp0_dbg_flag;
  87. } else if (cluster_id == 1) {
  88. /* MP1 */
  89. dbg_ctrl_base = MCUCFG_BASE + self->mp1_dbg_ctrl;
  90. dbg_flag_base = MCUCFG_BASE + self->mp1_dbg_flag;
  91. } else
  92. continue;
  93. writel((cpu_in_cluster << 4) | 1, dbg_ctrl_base);
  94. pc_value_h = readl(dbg_flag_base);
  95. writel((cpu_in_cluster << 4) | 0, dbg_ctrl_base);
  96. pc_value = (pc_value_h << 32) | readl(dbg_flag_base);
  97. /* TODO: query kernel symbol */
  98. /* get the 64bit/32bit kernel information from bootopt */
  99. if (g_is_64bit_kernel) {
  100. writel((cpu_in_cluster << 4) | 5, dbg_ctrl_base);
  101. fp_value_h = readl(dbg_flag_base);
  102. writel((cpu_in_cluster << 4) | 4, dbg_ctrl_base);
  103. fp_value = (fp_value_h << 32) | readl(dbg_flag_base);
  104. writel((cpu_in_cluster << 4) | 7, dbg_ctrl_base);
  105. sp_value_h = readl(dbg_flag_base);
  106. writel((cpu_in_cluster << 4) | 6, dbg_ctrl_base);
  107. sp_value = (sp_value_h << 32) | readl(dbg_flag_base);
  108. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  109. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%016llx, SP = 0x%016llx\n",
  110. i, pc_value, fp_value, sp_value);
  111. } else {
  112. writel((cpu_in_cluster << 4) | 2, dbg_ctrl_base);
  113. fp_value = readl(dbg_flag_base);
  114. writel((cpu_in_cluster << 4) | 3, dbg_ctrl_base);
  115. sp_value = readl(dbg_flag_base);
  116. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  117. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%08llx, SP = 0x%08llx\n",
  118. i, pc_value, fp_value, sp_value);
  119. }
  120. }
  121. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  122. return 1;
  123. }
  124. int default_lastpc_dump_v2(const struct plt_cfg_pc_latch *self, char *buf, int *wp)
  125. {
  126. unsigned int i;
  127. unsigned long long pc_value_h, fp_value_h, sp_value_h;
  128. unsigned long long pc_value, fp_value, sp_value;
  129. unsigned long anake_core_dbg_sel, anake_core_dbg_mon;
  130. unsigned long cpu_power_status = 0;
  131. /* mcusys registers would be corrupted by DFD */
  132. if (dfd_internal_dump_before_reboot()) {
  133. *wp += dfd_internal_dump_get_decoded_lastpc(buf + *wp, LATCH_BUF_LENGTH - *wp);
  134. return 1;
  135. }
  136. /* get the power status information */
  137. cpu_power_status = plt_get_cpu_power_status_at_wdt();
  138. for (i = 0; i <= self->nr_max_core - self->nr_max_big_core - 1; ++i) {
  139. /* if CPUX is not powered on before reboot --> skip */
  140. if (extract_n2mbits(cpu_power_status, i, i) == 0) {
  141. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  142. "[LAST PC] CORE_%d PC = 0x0, FP = 0x0, SP = 0x0\n", i);
  143. continue;
  144. }
  145. anake_core_dbg_sel = MCUCFG_BASE + self->anake_core_dbg_sel + i * 0x800;
  146. anake_core_dbg_mon = MCUCFG_BASE + self->anake_core_dbg_mon + i * 0x800;
  147. writel(0xd, anake_core_dbg_sel);
  148. pc_value_h = readl(anake_core_dbg_mon);
  149. writel(0xc, anake_core_dbg_sel);
  150. pc_value = (pc_value_h << 32) | readl(anake_core_dbg_mon);
  151. /* get the 64bit/32bit kernel information from bootopt */
  152. if (g_is_64bit_kernel) {
  153. writel(0x9, anake_core_dbg_sel);
  154. fp_value_h = readl(anake_core_dbg_mon);
  155. writel(0x8, anake_core_dbg_sel);
  156. fp_value = (fp_value_h << 32) | readl(anake_core_dbg_mon);
  157. writel(0xb, anake_core_dbg_sel);
  158. sp_value_h = readl(anake_core_dbg_mon);
  159. writel(0xa, anake_core_dbg_sel);
  160. sp_value = (sp_value_h << 32) | readl(anake_core_dbg_mon);
  161. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  162. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%016llx, SP = 0x%016llx\n",
  163. i, pc_value, fp_value, sp_value);
  164. } else {
  165. writel(0x8, anake_core_dbg_sel);
  166. fp_value = readl(anake_core_dbg_mon);
  167. writel(0xa, anake_core_dbg_sel);
  168. sp_value = readl(anake_core_dbg_mon);
  169. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  170. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%08llx, SP = 0x%08llx\n",
  171. i, pc_value, fp_value, sp_value);
  172. }
  173. }
  174. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  175. return 1;
  176. }
  177. static int lastpc_dump(char *buf, int *wp)
  178. {
  179. if (buf == NULL || wp == NULL)
  180. return -1;
  181. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** lastpc ***************************\n");
  182. if (cfg_pc_latch.dump) {
  183. cfg_pc_latch.dump(&cfg_pc_latch, buf, wp);
  184. } else {
  185. if (cfg_pc_latch.version == LASTPC_V2)
  186. default_lastpc_dump_v2(&cfg_pc_latch, buf, wp);
  187. else
  188. default_lastpc_dump(&cfg_pc_latch, buf, wp);
  189. }
  190. return 1;
  191. }
  192. static int circular_buffer_dump(char *buf, int *wp)
  193. {
  194. unsigned int i, j, cpuid;
  195. unsigned int lastpc_valid_before_reboot = 1;
  196. unsigned long addr;
  197. unsigned long plat_sram_flag0;
  198. unsigned long cpu_power_status = 0;
  199. unsigned long long pc, pc_h;
  200. if (buf == NULL || wp == NULL)
  201. return -1;
  202. if (cfg_pc_latch.nr_max_big_core == 0)
  203. return 0;
  204. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  205. "\n*************************** circular buffer ***************************\n");
  206. if (cfg_pc_latch.plat_sram_flag0) {
  207. /* if lastpc_valid_before_reboot is 0 => circular buffer is invalid */
  208. plat_sram_flag0 = readl(cfg_pc_latch.plat_sram_flag0);
  209. lastpc_valid_before_reboot = extract_n2mbits(plat_sram_flag0, 1, 1);
  210. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  211. "plat_sram_flag0 = 0x%lx\n(lastpc_valid=%x, lastpc_valid_before_reboot=%x)\n\n",
  212. plat_sram_flag0, extract_n2mbits(plat_sram_flag0, 0, 0),
  213. lastpc_valid_before_reboot);
  214. }
  215. if (lastpc_valid_before_reboot == 0) {
  216. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "lastpc_valid_before_reboot is 0 => circular buffer is invalid\n\n");
  217. return 1;
  218. }
  219. /* get the power status information */
  220. cpu_power_status = plt_get_cpu_power_status_at_wdt();
  221. if (circular_buffer_op.unlock)
  222. circular_buffer_op.unlock();
  223. for (i = 0; i < cfg_pc_latch.nr_max_big_core; ++i) {
  224. cpuid = cfg_big_core[i].cpuid;
  225. if (extract_n2mbits(cpu_power_status, cpuid, cpuid) == 0)
  226. continue;
  227. addr = cfg_big_core[i].circular_buffer_addr;
  228. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[CIRCULAR BUFFER: CORE_%d]\n", cpuid);
  229. for (j = 0; j <= cfg_big_core[i].nr_circular_buffer_entry-1; ++j) {
  230. if (cfg_pc_latch.version == LASTPC_V2) {
  231. #ifdef MTK_SMC_ID_MGMT
  232. pc_h = mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8) + 4, 0);
  233. pc = (pc_h << 32) | mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8), 0);
  234. #else
  235. pc_h = mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8) + 4);
  236. pc = (pc_h << 32) | mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8));
  237. #endif
  238. } else {
  239. pc_h = readl(addr + (j*8) + 4);
  240. pc = (pc_h << 32) | readl(addr + (j*8));
  241. }
  242. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "0x%016llx\n", pc);
  243. }
  244. }
  245. if (circular_buffer_op.lock)
  246. circular_buffer_op.lock();
  247. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  248. return 1;
  249. }
  250. static int default_lastbus_mcusys_dump(const struct plt_cfg_bus_latch *self,
  251. char *buf, int *wp)
  252. {
  253. unsigned int i;
  254. unsigned long meter;
  255. unsigned long debug_raw;
  256. unsigned long w_counter, r_counter, c_counter;
  257. unsigned long mcu_base = MCUCFG_BASE;
  258. /* mcusys registers would be corrupted by DFD */
  259. if (!dfd_internal_dump_before_reboot()) {
  260. for (i = 0; i <= self->num_master_port-1; ++i) {
  261. debug_raw = readl(mcu_base + self->mcusys_offsets.bus_mcu_m0 + 4 * i);
  262. meter = readl(mcu_base + self->mcusys_offsets.bus_mcu_m0_m + 4 * i);
  263. w_counter = meter & 0x3f;
  264. r_counter = (meter >> 8) & 0x3f;
  265. if ((w_counter != 0) || (r_counter != 0)) {
  266. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[MCUSYS LAST BUS] Master %d: ", i);
  267. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  268. "aw_pending_counter = 0x%02lx, ar_pending_counter = 0x%02lx\n",
  269. w_counter, r_counter);
  270. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "STATUS = %03lx\n", debug_raw & 0x3ff);
  271. }
  272. }
  273. for (i = 1; i <= self->num_slave_port-1; ++i) {
  274. debug_raw = readl(mcu_base + self->mcusys_offsets.bus_mcu_s1 + 4 * (i-1));
  275. meter = readl(mcu_base + self->mcusys_offsets.bus_mcu_s1_m + 4 * (i-1));
  276. w_counter = meter & 0x3f;
  277. r_counter = (meter >> 8) & 0x3f;
  278. c_counter = (meter >> 16) & 0x3f;
  279. if ((w_counter != 0) || (r_counter != 0) || (c_counter != 0)) {
  280. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[MCUSYS LAST BUS] Slave %d: ", i);
  281. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  282. "aw_pending_counter = 0x%02lx, ar_pending_counter = 0x%02lx,",
  283. w_counter, r_counter);
  284. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, " ac_pending_counter = 0x%02lx\n", c_counter);
  285. if (i <= 2)
  286. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "STATUS = %04lx\n", debug_raw & 0x3fff);
  287. else
  288. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "STATUS = %04lx\n", debug_raw & 0xffff);
  289. }
  290. }
  291. }else {
  292. *wp += sprintf(buf + *wp, "DFD triggered\nPlease refer to dfd post-processing result for MCUSYS last bus\n");
  293. }
  294. return 0;
  295. }
  296. static int default_lastbus_perisys_dump(const struct plt_cfg_bus_latch *self,
  297. char *buf, int *wp)
  298. {
  299. unsigned int i;
  300. unsigned long peri_base = PERICFG_BASE;
  301. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[LAST BUS] PERISYS TIMEOUT:\n");
  302. /* always check: not be corrupted by DFD */
  303. if (self->secure_perisys == 1) {
  304. for (i = 0; i <= self->num_perisys_mon-1; ++i)
  305. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "PERI MON%d = %04lx\n",
  306. #ifdef MTK_SMC_ID_MGMT
  307. i, (unsigned long int)mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_MONITOR_GET, i, 0, 0));
  308. #else
  309. i, mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_MONITOR_GET, i, 0));
  310. #endif
  311. } else {
  312. for (i = 0; i <= self->num_perisys_mon-1; ++i)
  313. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "PERI MON%d = %04x\n",
  314. i, readl(peri_base + self->perisys_offsets.bus_peri_mon + 4*i));
  315. }
  316. return 0;
  317. }
  318. static int default_lastbus_infrasys_dump(const struct plt_cfg_bus_latch *self,
  319. char *buf, int *wp)
  320. {
  321. unsigned int i;
  322. unsigned long infra_base = INFRACFG_AO_BASE;
  323. if (self->num_infrasys_mon != 0) {
  324. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[LAST BUS] INFRASYS TIMEOUT:\n");
  325. for (i = 0; i <= self->num_infrasys_mon-1; ++i)
  326. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "INFRA SNAPSHOT%d = %04x\n",
  327. i, readl(infra_base + self->infrasys_offsets.bus_infra_snapshot + 4*i));
  328. }
  329. return 0;
  330. }
  331. static int is_perisys_timeout(const struct plt_cfg_bus_latch *self)
  332. {
  333. unsigned long peri_base = PERICFG_BASE;
  334. if (self->perisys_ops.is_timeout)
  335. return self->perisys_ops.is_timeout(self);
  336. if (self->secure_perisys == 1)
  337. #ifdef MTK_SMC_ID_MGMT
  338. return mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_CHECK_HANG, 0, 0, 0);
  339. #else
  340. return mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_CHECK_HANG, 0, 0);
  341. #endif
  342. else
  343. return (readl(peri_base + self->perisys_offsets.bus_peri_r1) & 0x1);
  344. return 0;
  345. }
  346. static int is_infrasys_timeout(const struct plt_cfg_bus_latch *self)
  347. {
  348. unsigned long infra_base = INFRACFG_AO_BASE;
  349. if (self->infrasys_ops.is_timeout)
  350. return self->infrasys_ops.is_timeout(self);
  351. return (readl(infra_base + self->infrasys_offsets.bus_infra_ctrl) & 0xFF000000);
  352. }
  353. static int lastbus_dump(char *buf, int *wp)
  354. {
  355. if (buf == NULL || wp == NULL)
  356. return -1;
  357. if (cfg_bus_latch.supported == 0)
  358. return 0;
  359. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** lastbus ***************************\n");
  360. if (cfg_bus_latch.mcusys_ops.dump) {
  361. cfg_bus_latch.mcusys_ops.dump(&cfg_bus_latch, buf, wp);
  362. } else {
  363. default_lastbus_mcusys_dump(&cfg_bus_latch, buf, wp);
  364. }
  365. if (is_infrasys_timeout(&cfg_bus_latch)) {
  366. if (cfg_bus_latch.infrasys_ops.dump) {
  367. cfg_bus_latch.infrasys_ops.dump(&cfg_bus_latch, buf, wp);
  368. } else {
  369. default_lastbus_infrasys_dump(&cfg_bus_latch, buf, wp);
  370. }
  371. }
  372. if (is_perisys_timeout(&cfg_bus_latch)) {
  373. if (cfg_bus_latch.perisys_ops.dump) {
  374. cfg_bus_latch.perisys_ops.dump(&cfg_bus_latch, buf, wp);
  375. } else {
  376. default_lastbus_perisys_dump(&cfg_bus_latch, buf, wp);
  377. }
  378. }
  379. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  380. return 1;
  381. }
  382. static int l2_parity_dump(char *buf, int *wp)
  383. {
  384. unsigned long ret;
  385. unsigned int err_found = 0;
  386. if (buf == NULL || wp == NULL)
  387. return -1;
  388. if (cfg_l2_parity_latch.supported != 1)
  389. return 0;
  390. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** l2c parity ***************************\n");
  391. /* mcusys registers would be corrupted by DFD */
  392. if (dfd_internal_dump_before_reboot()) {
  393. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "DFD triggered\nPlease refer to dfd post-processing result for L2C parity\n");
  394. return 1;
  395. }
  396. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp0_l2_cache_parity1_rdata);
  397. if (ret & 0x1) {
  398. /* get parity error in mp0 */
  399. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[L2C parity] get parity error in mp0\n");
  400. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "error count = 0x%x\n", extract_n2mbits(ret, 8, 15));
  401. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp0_l2_cache_parity2_rdata);
  402. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "index = 0x%x\n", extract_n2mbits(ret, 0, 14));
  403. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "bank = 0x%x\n", extract_n2mbits(ret, 16, 31));
  404. /* clear mcusys parity check registers */
  405. writel(0x0, MCUCFG_BASE + cfg_l2_parity_latch.mp0_l2_cache_parity1_rdata);
  406. err_found = 1;
  407. }
  408. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp1_l2_cache_parity1_rdata);
  409. if (ret & 0x1) {
  410. /* get parity error in mp1 */
  411. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[L2C parity] get parity error in mp1\n");
  412. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "error count = 0x%x\n", extract_n2mbits(ret, 8, 15));
  413. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp1_l2_cache_parity2_rdata);
  414. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "index = 0x%x\n", extract_n2mbits(ret, 0, 14));
  415. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "bank = 0x%x\n", extract_n2mbits(ret, 16, 31));
  416. /* clear mcusys parity check registers */
  417. writel(0x0, MCUCFG_BASE + cfg_l2_parity_latch.mp1_l2_cache_parity1_rdata);
  418. err_found = 1;
  419. }
  420. if (err_found == 0)
  421. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[L2C parity] no parity error found\n");
  422. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  423. return 1;
  424. }
  425. void __attribute__((weak)) init_cfg_cache_latch(struct plt_cfg_cache_latch *p_cfg_cache_latch, unsigned int cache_level)
  426. {
  427. dprintf(CRITICAL, "%s: Please implement init_cfg_cache_latch() if using MTK new cache parity design\n", __func__);
  428. }
  429. static int cache_latch_dump(char *buf, int *wp)
  430. {
  431. unsigned int val;
  432. unsigned int base, leng;
  433. unsigned int offset;
  434. unsigned int cache_level, support_level;
  435. int err_found;
  436. if (buf == NULL || wp == NULL)
  437. return -1;
  438. init_cfg_cache_latch(&cfg_cache_latch, 0);
  439. if (cfg_cache_latch.support_level == 0)
  440. return 0;
  441. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** cache parity ***************************\n");
  442. /* mcusys registers would be corrupted by DFD */
  443. if (dfd_internal_dump_before_reboot()) {
  444. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "DFD triggered\nPlease refer to dfd post-processing result\n");
  445. return 1;
  446. }
  447. cache_level = 1;
  448. support_level = cfg_cache_latch.support_level >> 1;
  449. do {
  450. if ((support_level & 0x1) == 0)
  451. goto next_cache_level;
  452. init_cfg_cache_latch(&cfg_cache_latch, cache_level);
  453. if (cfg_cache_latch.ops.has_error)
  454. err_found = cfg_cache_latch.ops.has_error(&cfg_cache_latch);
  455. else {
  456. val = readl(MCUCFG_BASE + cfg_cache_latch.reg_info.ctrl_offset);
  457. err_found = (val & cfg_cache_latch.reg_info.ctrl_mask)? 1 : 0;
  458. }
  459. if (err_found) {
  460. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  461. "[L%dC parity] detect parity error!\n", cache_level);
  462. if (cfg_cache_latch.ops.dump)
  463. cfg_cache_latch.ops.dump(&cfg_cache_latch, buf, wp);
  464. else {
  465. base = MCUCFG_BASE + cfg_cache_latch.reg_info.dump_offset;
  466. leng = cfg_cache_latch.reg_info.dump_length;
  467. for (offset = 0; offset < leng; offset+=4)
  468. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  469. "[L%dC parity] offset 0x%08x, val 0x%08x\n",
  470. cache_level, (base + offset), readl(base + offset));
  471. }
  472. } else
  473. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  474. "[L%dC parity] no parity error found\n", cache_level);
  475. if (cfg_cache_latch.ops.reset)
  476. cfg_cache_latch.ops.reset(&cfg_cache_latch);
  477. next_cache_level:
  478. cache_level++;
  479. support_level = support_level >> 1;
  480. } while (support_level);
  481. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  482. return 1;
  483. }
  484. static int return_stack_dump(char *buf, int *wp)
  485. {
  486. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** return stack***************************\n");
  487. if (!dfd_internal_dump_before_reboot()) {
  488. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "NO DFD trigger \n");
  489. }
  490. else {
  491. *wp += dfd_get_decoded_return_stack(buf + *wp, LATCH_BUF_LENGTH - *wp);
  492. }
  493. return 1;
  494. }
  495. int latch_get(void **data, int *len)
  496. {
  497. int ret;
  498. *len = 0;
  499. *data = malloc(LATCH_BUF_LENGTH);
  500. if (*data == NULL)
  501. return 0;
  502. ret = lastpc_dump(*data, len);
  503. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  504. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  505. return ret;
  506. }
  507. ret = circular_buffer_dump(*data, len);
  508. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  509. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  510. return ret;
  511. }
  512. ret = lastbus_dump(*data, len);
  513. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  514. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  515. return ret;
  516. }
  517. ret = l2_parity_dump(*data, len);
  518. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  519. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  520. return ret;
  521. }
  522. ret = cache_latch_dump(*data, len);
  523. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  524. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  525. return ret;
  526. }
  527. ret = return_stack_dump(*data, len);
  528. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  529. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  530. return ret;
  531. }
  532. return 1;
  533. }
  534. void latch_put(void **data)
  535. {
  536. free(*data);
  537. }
  538. static int default_lastbus_perisys_init(const struct plt_cfg_bus_latch *self)
  539. {
  540. if (self->secure_perisys == 1)
  541. #ifdef MTK_SMC_ID_MGMT
  542. mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_INIT,
  543. self->perisys_timeout, self->perisys_enable, 0);
  544. #else
  545. mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_INIT,
  546. self->perisys_timeout, self->perisys_enable);
  547. #endif
  548. else {
  549. writel(self->perisys_timeout, PERICFG_BASE + self->perisys_offsets.bus_peri_r0);
  550. writel(self->perisys_enable, PERICFG_BASE + self->perisys_offsets.bus_peri_r1);
  551. }
  552. return 0;
  553. }
  554. static int default_lastbus_infrasys_init(const struct plt_cfg_bus_latch *self)
  555. {
  556. unsigned long addr = 0;
  557. if (self->num_infrasys_mon != 0) {
  558. addr = INFRACFG_AO_BASE + self->infrasys_offsets.bus_infra_ctrl;
  559. writel(self->infrasys_config, addr);
  560. writel(readl(addr)|self->infrasys_enable, addr);
  561. }
  562. return 0;
  563. }
  564. void latch_lastbus_init(void)
  565. {
  566. if (cfg_bus_latch.supported == 0)
  567. return;
  568. if (cfg_bus_latch.perisys_ops.init) {
  569. cfg_bus_latch.perisys_ops.init(&cfg_bus_latch);
  570. } else {
  571. default_lastbus_perisys_init(&cfg_bus_latch);
  572. }
  573. if (cfg_bus_latch.infrasys_ops.init) {
  574. cfg_bus_latch.infrasys_ops.init(&cfg_bus_latch);
  575. } else {
  576. default_lastbus_infrasys_init(&cfg_bus_latch);
  577. }
  578. }