latch.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  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_v3(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; ++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. if (i < (self->nr_max_core - self->nr_max_big_core))
  148. {
  149. writel(0xd, anake_core_dbg_sel);
  150. pc_value_h = readl(anake_core_dbg_mon);
  151. writel(0xc, anake_core_dbg_sel);
  152. pc_value = (pc_value_h << 32) | readl(anake_core_dbg_mon);
  153. }
  154. else
  155. {
  156. writel(0x9, anake_core_dbg_sel);
  157. pc_value_h = readl(anake_core_dbg_mon);
  158. writel(0x8, anake_core_dbg_sel);
  159. pc_value = (pc_value_h << 32) | readl(anake_core_dbg_mon);
  160. }
  161. /* get the 64bit/32bit kernel information from bootopt */
  162. if (g_is_64bit_kernel) {
  163. if (i < (self->nr_max_core - self->nr_max_big_core))
  164. {
  165. fp_value_h = 0;
  166. fp_value = 0;
  167. sp_value_h = 0;
  168. sp_value = 0;
  169. }
  170. else
  171. {
  172. fp_value_h = 0;
  173. fp_value = 0;
  174. sp_value_h = 0;
  175. sp_value = 0;
  176. }
  177. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  178. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%016llx, SP = 0x%016llx\n",
  179. i, pc_value, fp_value, sp_value);
  180. } else {
  181. if (i < (self->nr_max_core - self->nr_max_big_core))
  182. {
  183. fp_value = 0;
  184. sp_value = 0;
  185. }
  186. else
  187. {
  188. fp_value = 0;
  189. sp_value = 0;
  190. }
  191. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  192. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%08llx, SP = 0x%08llx\n",
  193. i, pc_value, fp_value, sp_value);
  194. }
  195. }
  196. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  197. return 1;
  198. }
  199. int default_lastpc_dump_v2(const struct plt_cfg_pc_latch *self, char *buf, int *wp)
  200. {
  201. unsigned int i;
  202. unsigned long long pc_value_h, fp_value_h, sp_value_h;
  203. unsigned long long pc_value, fp_value, sp_value;
  204. unsigned long anake_core_dbg_sel, anake_core_dbg_mon;
  205. unsigned long cpu_power_status = 0;
  206. /* mcusys registers would be corrupted by DFD */
  207. if (dfd_internal_dump_before_reboot()) {
  208. *wp += dfd_internal_dump_get_decoded_lastpc(buf + *wp, LATCH_BUF_LENGTH - *wp);
  209. return 1;
  210. }
  211. /* get the power status information */
  212. cpu_power_status = plt_get_cpu_power_status_at_wdt();
  213. for (i = 0; i <= self->nr_max_core - self->nr_max_big_core - 1; ++i) {
  214. /* if CPUX is not powered on before reboot --> skip */
  215. if (extract_n2mbits(cpu_power_status, i, i) == 0) {
  216. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  217. "[LAST PC] CORE_%d PC = 0x0, FP = 0x0, SP = 0x0\n", i);
  218. continue;
  219. }
  220. anake_core_dbg_sel = MCUCFG_BASE + self->anake_core_dbg_sel + i * 0x800;
  221. anake_core_dbg_mon = MCUCFG_BASE + self->anake_core_dbg_mon + i * 0x800;
  222. writel(0xd, anake_core_dbg_sel);
  223. pc_value_h = readl(anake_core_dbg_mon);
  224. writel(0xc, anake_core_dbg_sel);
  225. pc_value = (pc_value_h << 32) | readl(anake_core_dbg_mon);
  226. /* get the 64bit/32bit kernel information from bootopt */
  227. if (g_is_64bit_kernel) {
  228. writel(0x9, anake_core_dbg_sel);
  229. fp_value_h = readl(anake_core_dbg_mon);
  230. writel(0x8, anake_core_dbg_sel);
  231. fp_value = (fp_value_h << 32) | readl(anake_core_dbg_mon);
  232. writel(0xb, anake_core_dbg_sel);
  233. sp_value_h = readl(anake_core_dbg_mon);
  234. writel(0xa, anake_core_dbg_sel);
  235. sp_value = (sp_value_h << 32) | readl(anake_core_dbg_mon);
  236. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  237. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%016llx, SP = 0x%016llx\n",
  238. i, pc_value, fp_value, sp_value);
  239. } else {
  240. writel(0x8, anake_core_dbg_sel);
  241. fp_value = readl(anake_core_dbg_mon);
  242. writel(0xa, anake_core_dbg_sel);
  243. sp_value = readl(anake_core_dbg_mon);
  244. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  245. "[LAST PC] CORE_%d PC = 0x%016llx, FP = 0x%08llx, SP = 0x%08llx\n",
  246. i, pc_value, fp_value, sp_value);
  247. }
  248. }
  249. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  250. return 1;
  251. }
  252. static int lastpc_dump(char *buf, int *wp)
  253. {
  254. if (buf == NULL || wp == NULL)
  255. return -1;
  256. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** lastpc ***************************\n");
  257. if (cfg_pc_latch.dump) {
  258. cfg_pc_latch.dump(&cfg_pc_latch, buf, wp);
  259. } else {
  260. if (cfg_pc_latch.version == LASTPC_V3)
  261. default_lastpc_dump_v3(&cfg_pc_latch, buf, wp);
  262. else if (cfg_pc_latch.version == LASTPC_V2)
  263. default_lastpc_dump_v2(&cfg_pc_latch, buf, wp);
  264. else
  265. default_lastpc_dump(&cfg_pc_latch, buf, wp);
  266. }
  267. return 1;
  268. }
  269. static int circular_buffer_dump(char *buf, int *wp)
  270. {
  271. unsigned int i, j, cpuid;
  272. unsigned int lastpc_valid_before_reboot = 1;
  273. unsigned long addr;
  274. unsigned long plat_sram_flag0;
  275. unsigned long cpu_power_status = 0;
  276. unsigned long long pc, pc_h;
  277. if (buf == NULL || wp == NULL)
  278. return -1;
  279. if (cfg_pc_latch.nr_max_big_core == 0 || cfg_pc_latch.version == LASTPC_V3)
  280. return 0;
  281. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  282. "\n*************************** circular buffer ***************************\n");
  283. if (cfg_pc_latch.plat_sram_flag0) {
  284. /* if lastpc_valid_before_reboot is 0 => circular buffer is invalid */
  285. plat_sram_flag0 = readl(cfg_pc_latch.plat_sram_flag0);
  286. lastpc_valid_before_reboot = extract_n2mbits(plat_sram_flag0, 1, 1);
  287. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  288. "plat_sram_flag0 = 0x%lx\n(lastpc_valid=%x, lastpc_valid_before_reboot=%x)\n\n",
  289. plat_sram_flag0, extract_n2mbits(plat_sram_flag0, 0, 0),
  290. lastpc_valid_before_reboot);
  291. }
  292. if (lastpc_valid_before_reboot == 0) {
  293. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "lastpc_valid_before_reboot is 0 => circular buffer is invalid\n\n");
  294. return 1;
  295. }
  296. /* get the power status information */
  297. cpu_power_status = plt_get_cpu_power_status_at_wdt();
  298. if (circular_buffer_op.unlock)
  299. circular_buffer_op.unlock();
  300. for (i = 0; i < cfg_pc_latch.nr_max_big_core; ++i) {
  301. cpuid = cfg_big_core[i].cpuid;
  302. if (extract_n2mbits(cpu_power_status, cpuid, cpuid) == 0)
  303. continue;
  304. addr = cfg_big_core[i].circular_buffer_addr;
  305. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[CIRCULAR BUFFER: CORE_%d]\n", cpuid);
  306. for (j = 0; j <= cfg_big_core[i].nr_circular_buffer_entry-1; ++j) {
  307. if (cfg_pc_latch.version == LASTPC_V2) {
  308. #ifdef MTK_SMC_ID_MGMT
  309. pc_h = mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8) + 4, 0);
  310. pc = (pc_h << 32) | mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8), 0);
  311. #else
  312. pc_h = mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8) + 4);
  313. pc = (pc_h << 32) | mt_secure_call(MTK_SIP_LK_PLAT_DEBUG, PLAT_LASTPC_SMC_READ_ENTRY, cpuid, (j*8));
  314. #endif
  315. } else {
  316. pc_h = readl(addr + (j*8) + 4);
  317. pc = (pc_h << 32) | readl(addr + (j*8));
  318. }
  319. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "0x%016llx\n", pc);
  320. }
  321. }
  322. if (circular_buffer_op.lock)
  323. circular_buffer_op.lock();
  324. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  325. return 1;
  326. }
  327. static int default_lastbus_mcusys_dump(const struct plt_cfg_bus_latch *self,
  328. char *buf, int *wp)
  329. {
  330. unsigned int i;
  331. unsigned long meter;
  332. unsigned long debug_raw;
  333. unsigned long w_counter, r_counter, c_counter;
  334. unsigned long mcu_base = MCUCFG_BASE;
  335. /* mcusys registers would be corrupted by DFD */
  336. if (!dfd_internal_dump_before_reboot()) {
  337. for (i = 0; i <= self->num_master_port-1; ++i) {
  338. debug_raw = readl(mcu_base + self->mcusys_offsets.bus_mcu_m0 + 4 * i);
  339. meter = readl(mcu_base + self->mcusys_offsets.bus_mcu_m0_m + 4 * i);
  340. w_counter = meter & 0x3f;
  341. r_counter = (meter >> 8) & 0x3f;
  342. if ((w_counter != 0) || (r_counter != 0)) {
  343. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[MCUSYS LAST BUS] Master %d: ", i);
  344. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  345. "aw_pending_counter = 0x%02lx, ar_pending_counter = 0x%02lx\n",
  346. w_counter, r_counter);
  347. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "STATUS = %03lx\n", debug_raw & 0x3ff);
  348. }
  349. }
  350. for (i = 1; i <= self->num_slave_port-1; ++i) {
  351. debug_raw = readl(mcu_base + self->mcusys_offsets.bus_mcu_s1 + 4 * (i-1));
  352. meter = readl(mcu_base + self->mcusys_offsets.bus_mcu_s1_m + 4 * (i-1));
  353. w_counter = meter & 0x3f;
  354. r_counter = (meter >> 8) & 0x3f;
  355. c_counter = (meter >> 16) & 0x3f;
  356. if ((w_counter != 0) || (r_counter != 0) || (c_counter != 0)) {
  357. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[MCUSYS LAST BUS] Slave %d: ", i);
  358. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  359. "aw_pending_counter = 0x%02lx, ar_pending_counter = 0x%02lx,",
  360. w_counter, r_counter);
  361. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, " ac_pending_counter = 0x%02lx\n", c_counter);
  362. if (i <= 2)
  363. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "STATUS = %04lx\n", debug_raw & 0x3fff);
  364. else
  365. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "STATUS = %04lx\n", debug_raw & 0xffff);
  366. }
  367. }
  368. }else {
  369. *wp += sprintf(buf + *wp, "DFD triggered\nPlease refer to dfd post-processing result for MCUSYS last bus\n");
  370. }
  371. return 0;
  372. }
  373. static int default_lastbus_perisys_dump(const struct plt_cfg_bus_latch *self,
  374. char *buf, int *wp)
  375. {
  376. unsigned int i;
  377. unsigned long peri_base = PERICFG_BASE;
  378. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[LAST BUS] PERISYS TIMEOUT:\n");
  379. /* always check: not be corrupted by DFD */
  380. if (self->secure_perisys == 1) {
  381. for (i = 0; i <= self->num_perisys_mon-1; ++i)
  382. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "PERI MON%d = %04lx\n",
  383. #ifdef MTK_SMC_ID_MGMT
  384. i, (unsigned long int)mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_MONITOR_GET, i, 0, 0));
  385. #else
  386. i, mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_MONITOR_GET, i, 0));
  387. #endif
  388. } else {
  389. for (i = 0; i <= self->num_perisys_mon-1; ++i)
  390. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "PERI MON%d = %04x\n",
  391. i, readl(peri_base + self->perisys_offsets.bus_peri_mon + 4*i));
  392. }
  393. return 0;
  394. }
  395. static int default_lastbus_infrasys_dump(const struct plt_cfg_bus_latch *self,
  396. char *buf, int *wp)
  397. {
  398. unsigned int i;
  399. unsigned long infra_base = INFRACFG_AO_BASE;
  400. if (self->num_infrasys_mon != 0) {
  401. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[LAST BUS] INFRASYS TIMEOUT:\n");
  402. for (i = 0; i <= self->num_infrasys_mon-1; ++i)
  403. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "INFRA SNAPSHOT%d = %04x\n",
  404. i, readl(infra_base + self->infrasys_offsets.bus_infra_snapshot + 4*i));
  405. }
  406. return 0;
  407. }
  408. static int is_perisys_timeout(const struct plt_cfg_bus_latch *self)
  409. {
  410. unsigned long peri_base = PERICFG_BASE;
  411. if (self->perisys_ops.is_timeout)
  412. return self->perisys_ops.is_timeout(self);
  413. if (self->secure_perisys == 1)
  414. #ifdef MTK_SMC_ID_MGMT
  415. return mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_CHECK_HANG, 0, 0, 0);
  416. #else
  417. return mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_CHECK_HANG, 0, 0);
  418. #endif
  419. else
  420. return (readl(peri_base + self->perisys_offsets.bus_peri_r1) & 0x1);
  421. return 0;
  422. }
  423. static int is_infrasys_timeout(const struct plt_cfg_bus_latch *self)
  424. {
  425. unsigned long infra_base = INFRACFG_AO_BASE;
  426. if (self->infrasys_ops.is_timeout)
  427. return self->infrasys_ops.is_timeout(self);
  428. return (readl(infra_base + self->infrasys_offsets.bus_infra_ctrl) & 0xFF000000);
  429. }
  430. static bool default_lastbus_is_timeout_v2(struct lastbus_monitor *m)
  431. {
  432. /* XXX
  433. * workaround for timeout loss.
  434. * debug_ctrl_ao*: infrabus_clk_detect [7:5] != 0
  435. */
  436. if (readl(m->base) & 0xe0)
  437. return 1;
  438. return (readl(m->base) & 0x1);
  439. }
  440. static void default_lastbus_dump_v2(struct lastbus_monitor *m, char *buf, int *wp)
  441. {
  442. unsigned int i;
  443. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "--- ");
  444. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "%s %p %d",
  445. m->name, m->base, m->num_ports);
  446. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, " ---\n");
  447. for (i = 0; i < m->num_ports; i++) {
  448. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "%08x\n",
  449. readl(m->base + 0x408 + (i * 4)));
  450. }
  451. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  452. }
  453. static int lastbus_dump_v2(char *buf, int *wp)
  454. {
  455. struct plt_cfg_bus_latch_v2 *setting;
  456. struct lastbus_monitor *m;
  457. unsigned int num_used_monitors;
  458. unsigned int i;
  459. bool is_timeout;
  460. setting = &cfg_bus_latch.v2;
  461. num_used_monitors = setting->used_num;
  462. for (i = 0; i < num_used_monitors; i++) {
  463. is_timeout = false;
  464. m = &setting->monitors[i];
  465. if (m->ops.is_timeout) {
  466. is_timeout = m->ops.is_timeout(m);
  467. } else {
  468. is_timeout = default_lastbus_is_timeout_v2(m);
  469. }
  470. if (is_timeout) {
  471. if (m->ops.dump) {
  472. m->ops.dump(m, buf, wp);
  473. } else {
  474. default_lastbus_dump_v2(m, buf, wp);
  475. }
  476. }
  477. }
  478. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  479. return 1;
  480. }
  481. static int lastbus_dump(char *buf, int *wp)
  482. {
  483. if (buf == NULL || wp == NULL)
  484. return -1;
  485. if (cfg_bus_latch.supported == 0)
  486. return 0;
  487. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  488. "\n*********************** %s lastbus ***********************\n", PLATFORM);
  489. if (cfg_bus_latch.mcusys_ops.dump) {
  490. cfg_bus_latch.mcusys_ops.dump(&cfg_bus_latch, buf, wp);
  491. } else {
  492. default_lastbus_mcusys_dump(&cfg_bus_latch, buf, wp);
  493. }
  494. if (cfg_bus_latch.sw_version == LASTBUS_SW_V2) {
  495. return lastbus_dump_v2(buf, wp);
  496. }
  497. if (is_infrasys_timeout(&cfg_bus_latch)) {
  498. if (cfg_bus_latch.infrasys_ops.dump) {
  499. cfg_bus_latch.infrasys_ops.dump(&cfg_bus_latch, buf, wp);
  500. } else {
  501. default_lastbus_infrasys_dump(&cfg_bus_latch, buf, wp);
  502. }
  503. }
  504. if (is_perisys_timeout(&cfg_bus_latch)) {
  505. if (cfg_bus_latch.perisys_ops.dump) {
  506. cfg_bus_latch.perisys_ops.dump(&cfg_bus_latch, buf, wp);
  507. } else {
  508. default_lastbus_perisys_dump(&cfg_bus_latch, buf, wp);
  509. }
  510. }
  511. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  512. return 1;
  513. }
  514. static int l2_parity_dump(char *buf, int *wp)
  515. {
  516. unsigned long ret;
  517. unsigned int err_found = 0;
  518. if (buf == NULL || wp == NULL)
  519. return -1;
  520. if (cfg_l2_parity_latch.supported != 1)
  521. return 0;
  522. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** l2c parity ***************************\n");
  523. /* mcusys registers would be corrupted by DFD */
  524. if (dfd_internal_dump_before_reboot()) {
  525. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "DFD triggered\nPlease refer to dfd post-processing result for L2C parity\n");
  526. return 1;
  527. }
  528. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp0_l2_cache_parity1_rdata);
  529. if (ret & 0x1) {
  530. /* get parity error in mp0 */
  531. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[L2C parity] get parity error in mp0\n");
  532. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "error count = 0x%x\n", extract_n2mbits(ret, 8, 15));
  533. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp0_l2_cache_parity2_rdata);
  534. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "index = 0x%x\n", extract_n2mbits(ret, 0, 14));
  535. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "bank = 0x%x\n", extract_n2mbits(ret, 16, 31));
  536. /* clear mcusys parity check registers */
  537. writel(0x0, MCUCFG_BASE + cfg_l2_parity_latch.mp0_l2_cache_parity1_rdata);
  538. err_found = 1;
  539. }
  540. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp1_l2_cache_parity1_rdata);
  541. if (ret & 0x1) {
  542. /* get parity error in mp1 */
  543. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[L2C parity] get parity error in mp1\n");
  544. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "error count = 0x%x\n", extract_n2mbits(ret, 8, 15));
  545. ret = readl(MCUCFG_BASE + cfg_l2_parity_latch.mp1_l2_cache_parity2_rdata);
  546. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "index = 0x%x\n", extract_n2mbits(ret, 0, 14));
  547. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "bank = 0x%x\n", extract_n2mbits(ret, 16, 31));
  548. /* clear mcusys parity check registers */
  549. writel(0x0, MCUCFG_BASE + cfg_l2_parity_latch.mp1_l2_cache_parity1_rdata);
  550. err_found = 1;
  551. }
  552. if (err_found == 0)
  553. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "[L2C parity] no parity error found\n");
  554. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  555. return 1;
  556. }
  557. void __attribute__((weak)) init_cfg_cache_latch(struct plt_cfg_cache_latch *p_cfg_cache_latch, unsigned int cache_level)
  558. {
  559. dprintf(CRITICAL, "%s: Please implement init_cfg_cache_latch() if using MTK new cache parity design\n", __func__);
  560. }
  561. static int cache_latch_dump(char *buf, int *wp)
  562. {
  563. unsigned int val;
  564. unsigned int base, leng;
  565. unsigned int offset;
  566. unsigned int cache_level, support_level;
  567. int err_found;
  568. if (buf == NULL || wp == NULL)
  569. return -1;
  570. init_cfg_cache_latch(&cfg_cache_latch, 0);
  571. if (cfg_cache_latch.support_level == 0)
  572. return 0;
  573. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** cache parity ***************************\n");
  574. /* mcusys registers would be corrupted by DFD */
  575. if (dfd_internal_dump_before_reboot()) {
  576. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "DFD triggered\nPlease refer to dfd post-processing result\n");
  577. return 1;
  578. }
  579. cache_level = 1;
  580. support_level = cfg_cache_latch.support_level >> 1;
  581. do {
  582. if ((support_level & 0x1) == 0)
  583. goto next_cache_level;
  584. init_cfg_cache_latch(&cfg_cache_latch, cache_level);
  585. if (cfg_cache_latch.ops.has_error)
  586. err_found = cfg_cache_latch.ops.has_error(&cfg_cache_latch);
  587. else {
  588. val = readl(MCUCFG_BASE + cfg_cache_latch.reg_info.ctrl_offset);
  589. err_found = (val & cfg_cache_latch.reg_info.ctrl_mask)? 1 : 0;
  590. }
  591. if (err_found) {
  592. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  593. "[L%dC parity] detect parity error!\n", cache_level);
  594. if (cfg_cache_latch.ops.dump)
  595. cfg_cache_latch.ops.dump(&cfg_cache_latch, buf, wp);
  596. else {
  597. base = MCUCFG_BASE + cfg_cache_latch.reg_info.dump_offset;
  598. leng = cfg_cache_latch.reg_info.dump_length;
  599. for (offset = 0; offset < leng; offset+=4)
  600. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  601. "[L%dC parity] offset 0x%08x, val 0x%08x\n",
  602. cache_level, (base + offset), readl(base + offset));
  603. }
  604. } else
  605. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
  606. "[L%dC parity] no parity error found\n", cache_level);
  607. if (cfg_cache_latch.ops.reset)
  608. cfg_cache_latch.ops.reset(&cfg_cache_latch);
  609. next_cache_level:
  610. cache_level++;
  611. support_level = support_level >> 1;
  612. } while (support_level);
  613. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n");
  614. return 1;
  615. }
  616. static int return_stack_dump(char *buf, int *wp)
  617. {
  618. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "\n*************************** return stack***************************\n");
  619. if (!dfd_internal_dump_before_reboot()) {
  620. *wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp, "NO DFD trigger \n");
  621. }
  622. else {
  623. *wp += dfd_get_decoded_return_stack(buf + *wp, LATCH_BUF_LENGTH - *wp);
  624. }
  625. return 1;
  626. }
  627. int latch_get(void **data, int *len)
  628. {
  629. int ret;
  630. *len = 0;
  631. *data = malloc(LATCH_BUF_LENGTH);
  632. if (*data == NULL)
  633. return 0;
  634. ret = lastpc_dump(*data, len);
  635. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  636. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  637. return ret;
  638. }
  639. ret = circular_buffer_dump(*data, len);
  640. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  641. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  642. return ret;
  643. }
  644. ret = lastbus_dump(*data, len);
  645. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  646. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  647. return ret;
  648. }
  649. ret = l2_parity_dump(*data, len);
  650. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  651. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  652. return ret;
  653. }
  654. ret = cache_latch_dump(*data, len);
  655. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  656. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  657. return ret;
  658. }
  659. ret = return_stack_dump(*data, len);
  660. if (ret < 0 || *len > LATCH_BUF_LENGTH) {
  661. *len = (*len > LATCH_BUF_LENGTH) ? LATCH_BUF_LENGTH : *len;
  662. return ret;
  663. }
  664. return 1;
  665. }
  666. void latch_put(void **data)
  667. {
  668. free(*data);
  669. }
  670. static int default_lastbus_perisys_init(const struct plt_cfg_bus_latch *self)
  671. {
  672. if (self->secure_perisys == 1)
  673. #ifdef MTK_SMC_ID_MGMT
  674. mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_INIT,
  675. self->perisys_timeout, self->perisys_enable, 0);
  676. #else
  677. mt_secure_call(MTK_SIP_LK_LASTBUS, LASTBSU_SMC_INIT,
  678. self->perisys_timeout, self->perisys_enable);
  679. #endif
  680. else {
  681. writel(self->perisys_timeout, PERICFG_BASE + self->perisys_offsets.bus_peri_r0);
  682. writel(self->perisys_enable, PERICFG_BASE + self->perisys_offsets.bus_peri_r1);
  683. }
  684. return 0;
  685. }
  686. static int default_lastbus_infrasys_init(const struct plt_cfg_bus_latch *self)
  687. {
  688. unsigned long addr = 0;
  689. if (self->num_infrasys_mon != 0) {
  690. addr = INFRACFG_AO_BASE + self->infrasys_offsets.bus_infra_ctrl;
  691. writel(self->infrasys_config, addr);
  692. writel(readl(addr)|self->infrasys_enable, addr);
  693. }
  694. return 0;
  695. }
  696. static void default_lastbus_init_single_v2(const struct lastbus_monitor *m)
  697. {
  698. writel(0xffff0008, m->base);
  699. writel(0xffff000c, m->base);
  700. }
  701. static void latch_lastbus_init_v2(void)
  702. {
  703. struct plt_cfg_bus_latch_v2 *setting;
  704. struct lastbus_monitor *m;
  705. unsigned int num_used_monitors;
  706. unsigned int i;
  707. setting = &cfg_bus_latch.v2;
  708. num_used_monitors = setting->used_num;
  709. for (i = 0; i < num_used_monitors; i++) {
  710. m = &setting->monitors[i];
  711. if (m->ops.init) {
  712. m->ops.init(m);
  713. } else {
  714. default_lastbus_init_single_v2(m);
  715. }
  716. }
  717. }
  718. void latch_lastbus_init(void)
  719. {
  720. if (cfg_bus_latch.supported == 0)
  721. return;
  722. if (cfg_bus_latch.sw_version == LASTBUS_SW_V2) {
  723. latch_lastbus_init_v2();
  724. return;
  725. }
  726. if (cfg_bus_latch.perisys_ops.init) {
  727. cfg_bus_latch.perisys_ops.init(&cfg_bus_latch);
  728. } else {
  729. default_lastbus_perisys_init(&cfg_bus_latch);
  730. }
  731. if (cfg_bus_latch.infrasys_ops.init) {
  732. cfg_bus_latch.infrasys_ops.init(&cfg_bus_latch);
  733. } else {
  734. default_lastbus_infrasys_init(&cfg_bus_latch);
  735. }
  736. }