systracker_interface_v2.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  1. #include <linux/kernel.h>
  2. #include <linux/module.h>
  3. #include <linux/device.h>
  4. #include <linux/platform_device.h>
  5. #include <linux/kallsyms.h>
  6. #include <linux/interrupt.h>
  7. #include <linux/delay.h>
  8. #include <linux/sched.h>
  9. #include <linux/of_address.h>
  10. #include <linux/of_irq.h>
  11. #include <linux/signal.h>
  12. #include <asm/memory.h>
  13. #include <asm/system_misc.h>
  14. #include <linux/cpu.h>
  15. #include <mtk_ram_console.h>
  16. #include <mt-plat/sync_write.h>
  17. #include "systracker_v2.h"
  18. #define TRACKER_DEBUG 1
  19. #ifdef CONFIG_ARM64
  20. #define IOMEM(a) ((void __force __iomem *)((a)))
  21. #endif
  22. void __iomem *BUS_DBG_BASE;
  23. int systracker_irq;
  24. struct systracker_config_t track_config;
  25. struct systracker_entry_t track_entry;
  26. unsigned int is_systracker_irq_registered = 0;
  27. static const struct of_device_id systracker_of_ids[] = {
  28. { .compatible = "mediatek,bus_dbg-v2", },
  29. {}
  30. };
  31. static struct mt_systracker_driver mt_systracker_drv = {
  32. .driver = {
  33. .driver = {
  34. .name = "systracker",
  35. .bus = &platform_bus_type,
  36. .owner = THIS_MODULE,
  37. .of_match_table = systracker_of_ids,
  38. },
  39. .probe = systracker_probe,
  40. .remove = systracker_remove,
  41. .suspend = systracker_suspend,
  42. .resume = systracker_resume,
  43. },
  44. .device = {
  45. .name = "systracker",
  46. .id = 0,
  47. .dev = {
  48. },
  49. },
  50. .reset_systracker = NULL,
  51. .enable_watchpoint = NULL,
  52. .disable_watchpoint = NULL,
  53. .set_watchpoint_address = NULL,
  54. .enable_systracker = NULL,
  55. .disable_systracker = NULL,
  56. .test_systracker = NULL,
  57. .systracker_probe = NULL,
  58. .systracker_remove = NULL,
  59. .systracker_suspend = NULL,
  60. .systracker_resume = NULL,
  61. };
  62. static int systracker_platform_probe_default(struct platform_device *pdev)
  63. {
  64. pr_err("systracker probe\n");
  65. /* iomap register */
  66. BUS_DBG_BASE = of_iomap(pdev->dev.of_node, 0);
  67. if (!BUS_DBG_BASE) {
  68. pr_err("can't of_iomap for systracker!!\n");
  69. return -ENOMEM;
  70. }
  71. pr_err("of_iomap for systracker @ 0x%p\n", BUS_DBG_BASE);
  72. /* get irq # */
  73. systracker_irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
  74. pr_err("%s:%d: irq # %d\n", __func__, __LINE__, systracker_irq);
  75. #ifdef SYSTRACKER_TEST_SUIT
  76. if (!is_systracker_irq_registered) {
  77. if (request_irq(systracker_irq, (irq_handler_t)systracker_isr, IRQF_TRIGGER_LOW, "SYSTRACKER", NULL)) {
  78. pr_err("SYSTRACKER IRQ LINE NOT AVAILABLE!!\n");
  79. return -1;
  80. }
  81. is_systracker_irq_registered = 1;
  82. }
  83. #endif
  84. /* save entry info */
  85. save_entry();
  86. memset(&track_config, 0, sizeof(struct systracker_config_t));
  87. /* To latch last PC when tracker timeout, we need to enable interrupt mode */
  88. track_config.enable_timeout = 1;
  89. track_config.enable_slave_err = 1;
  90. track_config.enable_irq = 1;
  91. track_config.timeout_ms = 100;
  92. track_config.timeout2_ms = 2000;
  93. systracker_reset();
  94. systracker_enable();
  95. return 0;
  96. }
  97. int systracker_probe(struct platform_device *pdev)
  98. {
  99. if (mt_systracker_drv.systracker_probe)
  100. return mt_systracker_drv.systracker_probe(pdev);
  101. else
  102. return systracker_platform_probe_default(pdev);
  103. }
  104. int systracker_remove(struct platform_device *pdev)
  105. {
  106. if (mt_systracker_drv.systracker_remove)
  107. return mt_systracker_drv.systracker_remove(pdev);
  108. return 0;
  109. }
  110. int systracker_suspend(struct platform_device *pdev, pm_message_t state)
  111. {
  112. if (mt_systracker_drv.systracker_suspend)
  113. return mt_systracker_drv.systracker_suspend(pdev, state);
  114. return 0;
  115. }
  116. static int systracker_resume_default(struct platform_device *pdev)
  117. {
  118. if (track_config.state || track_config.enable_wp)
  119. systracker_enable();
  120. return 0;
  121. }
  122. int systracker_resume(struct platform_device *pdev)
  123. {
  124. if (mt_systracker_drv.systracker_resume)
  125. return mt_systracker_drv.systracker_resume(pdev);
  126. else
  127. return systracker_resume_default(pdev);
  128. }
  129. /* Some chip do not have reg dump, define a weak to avoid build error */
  130. extern int mt_reg_dump(char *buf) __attribute__((weak));
  131. /*
  132. * save entry info early
  133. */
  134. void save_entry(void)
  135. {
  136. int i = 0;
  137. track_entry.dbg_con = readl(IOMEM(BUS_DBG_CON));
  138. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  139. track_entry.ar_track_l[i] = readl(IOMEM(BUS_DBG_AR_TRACK_L(i)));
  140. track_entry.ar_track_h[i] = readl(IOMEM(BUS_DBG_AR_TRACK_H(i)));
  141. track_entry.ar_trans_tid[i] = readl(IOMEM(BUS_DBG_AR_TRANS_TID(i)));
  142. track_entry.aw_track_l[i] = readl(IOMEM(BUS_DBG_AW_TRACK_L(i)));
  143. track_entry.aw_track_h[i] = readl(IOMEM(BUS_DBG_AW_TRACK_H(i)));
  144. track_entry.aw_trans_tid[i] = readl(IOMEM(BUS_DBG_AW_TRANS_TID(i)));
  145. }
  146. }
  147. #ifdef SYSTRACKER_TEST_SUIT
  148. void systracker_test_cleanup(void)
  149. {
  150. if (mt_systracker_drv.systracker_test_cleanup)
  151. return mt_systracker_drv.systracker_test_cleanup();
  152. }
  153. #endif
  154. static void tracker_print(void)
  155. {
  156. unsigned int reg_value;
  157. int i;
  158. unsigned int entry_valid;
  159. unsigned int entry_tid;
  160. unsigned int entry_id;
  161. unsigned int entry_address;
  162. unsigned int entry_data_size;
  163. unsigned int entry_burst_length;
  164. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  165. entry_address = track_entry.ar_track_l[i];
  166. reg_value = track_entry.ar_track_h[i];
  167. entry_valid = extract_n2mbits(reg_value, 19, 19);
  168. entry_id = extract_n2mbits(reg_value, 7, 18);
  169. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  170. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  171. entry_tid = track_entry.ar_trans_tid[i];
  172. pr_err("read entry = %d, valid = 0x%x, tid = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  173. i, entry_valid, entry_tid, entry_id, entry_address, entry_data_size, entry_burst_length);
  174. }
  175. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  176. entry_address = track_entry.aw_track_l[i];
  177. reg_value = track_entry.aw_track_h[i];
  178. entry_valid = extract_n2mbits(reg_value, 19, 19);
  179. entry_id = extract_n2mbits(reg_value, 7, 18);
  180. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  181. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  182. entry_tid = track_entry.aw_trans_tid[i];
  183. pr_err("write entry = %d, valid = 0x%x, tid = 0x%x, write id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  184. i, entry_valid, entry_tid, entry_id, entry_address, entry_data_size, entry_burst_length);
  185. }
  186. }
  187. irqreturn_t systracker_isr(void)
  188. {
  189. unsigned int con;
  190. #ifdef SYSTRACKER_TEST_SUIT
  191. systracker_test_cleanup();
  192. #endif
  193. save_entry();
  194. pr_err("Sys Tracker ISR\n");
  195. con = readl(IOMEM(BUS_DBG_CON));
  196. writel(con | BUS_DBG_CON_IRQ_CLR, IOMEM(BUS_DBG_CON));
  197. mb();
  198. if (con & BUS_DBG_CON_IRQ_WP_STA)
  199. pr_err("[TRACKER] Watch address: 0x%x was touched\n", track_config.wp_phy_address);
  200. if (con & (BUS_DBG_CON_IRQ_AR_STA0|BUS_DBG_CON_IRQ_AR_STA1)) {
  201. pr_err("[TRAKER] Read time out trigger\n");
  202. tracker_print();
  203. }
  204. if (con & (BUS_DBG_CON_IRQ_AW_STA0|BUS_DBG_CON_IRQ_AW_STA1)) {
  205. pr_err("[TRAKER] Write time out trigger\n");
  206. tracker_print();
  207. }
  208. return IRQ_HANDLED;
  209. }
  210. static int systracker_watchpoint_enable_default(void)
  211. {
  212. if (!is_systracker_irq_registered) {
  213. if (request_irq(systracker_irq, (irq_handler_t)systracker_isr, IRQF_TRIGGER_LOW, "SYSTRACKER", NULL)) {
  214. pr_err("SYSTRACKER IRQ LINE NOT AVAILABLE!!\n");
  215. return -1;
  216. }
  217. is_systracker_irq_registered = 1;
  218. }
  219. track_config.enable_wp = 1;
  220. writel(track_config.wp_phy_address, IOMEM(BUS_DBG_WP));
  221. writel(0x0000000F, IOMEM(BUS_DBG_WP_MASK));
  222. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_WP_EN, IOMEM(BUS_DBG_CON));
  223. mb();
  224. return 0;
  225. }
  226. int systracker_watchpoint_enable(void)
  227. {
  228. if (mt_systracker_drv.enable_watchpoint)
  229. return mt_systracker_drv.enable_watchpoint();
  230. else
  231. return systracker_watchpoint_enable_default();
  232. }
  233. static int systracker_watchpoint_disable_default(void)
  234. {
  235. track_config.enable_wp = 0;
  236. writel(readl(IOMEM(BUS_DBG_CON)) & ~BUS_DBG_CON_WP_EN, IOMEM(BUS_DBG_CON));
  237. mb();
  238. return 0;
  239. }
  240. int systracker_watchpoint_disable(void)
  241. {
  242. if (mt_systracker_drv.disable_watchpoint)
  243. return mt_systracker_drv.disable_watchpoint();
  244. else
  245. return systracker_watchpoint_disable_default();
  246. }
  247. void systracker_reset_default(void)
  248. {
  249. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_SW_RST, IOMEM(BUS_DBG_CON));
  250. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_IRQ_CLR, IOMEM(BUS_DBG_CON));
  251. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_TIMEOUT_CLR, IOMEM(BUS_DBG_CON));
  252. mb();
  253. }
  254. void systracker_reset(void)
  255. {
  256. if (mt_systracker_drv.reset_systracker)
  257. mt_systracker_drv.reset_systracker();
  258. else
  259. systracker_reset_default();
  260. }
  261. unsigned int systracker_timeout_value_default(void)
  262. {
  263. /* prescale = (133 * (10 ^ 6)) / 16 = 8312500/s */
  264. return (BUS_DBG_BUS_MHZ * 1000 / 16) * track_config.timeout_ms;
  265. }
  266. unsigned int systracker_timeout2_value_default(void)
  267. {
  268. /* prescale = (133 * (10 ^ 6)) / 16 = 8312500/s */
  269. return (BUS_DBG_BUS_MHZ * 1000 / 16) * track_config.timeout2_ms;
  270. }
  271. unsigned int systracker_timeout_value(void)
  272. {
  273. if (mt_systracker_drv.systracker_timeout_value)
  274. return mt_systracker_drv.systracker_timeout_value();
  275. else
  276. return systracker_timeout_value_default();
  277. }
  278. unsigned int systracker_timeout2_value(void)
  279. {
  280. if (mt_systracker_drv.systracker_timeout2_value)
  281. return mt_systracker_drv.systracker_timeout2_value();
  282. else
  283. return systracker_timeout2_value_default();
  284. }
  285. void systracker_enable_default_ex(void)
  286. {
  287. unsigned int con;
  288. unsigned int timer_control_value;
  289. timer_control_value = systracker_timeout_value();
  290. writel(0, IOMEM(BUS_DBG_TIMER_CON0));
  291. timer_control_value = systracker_timeout2_value();
  292. writel(0, IOMEM(BUS_DBG_TIMER_CON1));
  293. track_config.state = 1;
  294. con = BUS_DBG_CON_BUS_DBG_EN | BUS_DBG_CON_BUS_OT_EN;
  295. if (track_config.enable_timeout)
  296. con |= BUS_DBG_CON_TIMEOUT_EN;
  297. if (track_config.enable_slave_err)
  298. con |= BUS_DBG_CON_SLV_ERR_EN;
  299. if (track_config.enable_irq) {
  300. con |= BUS_DBG_CON_IRQ_EN;
  301. con &= ~BUS_DBG_CON_IRQ_WP_EN;
  302. }
  303. con |= BUS_DBG_CON_HALT_ON_EN;
  304. writel(con, IOMEM(BUS_DBG_CON));
  305. mb();
  306. con |= BUS_DBG_CON_IRQ_WP_EN;
  307. writel(con, IOMEM(BUS_DBG_CON));
  308. mb();
  309. }
  310. void systracker_enable_default(void)
  311. {
  312. unsigned int con;
  313. unsigned int timer_control_value;
  314. timer_control_value = systracker_timeout_value();
  315. writel(timer_control_value, IOMEM(BUS_DBG_TIMER_CON0));
  316. timer_control_value = systracker_timeout2_value();
  317. writel(timer_control_value, IOMEM(BUS_DBG_TIMER_CON1));
  318. track_config.state = 1;
  319. con = BUS_DBG_CON_BUS_DBG_EN | BUS_DBG_CON_BUS_OT_EN;
  320. if (track_config.enable_timeout)
  321. con |= BUS_DBG_CON_TIMEOUT_EN;
  322. if (track_config.enable_slave_err)
  323. con |= BUS_DBG_CON_SLV_ERR_EN;
  324. if (track_config.enable_irq) {
  325. con |= BUS_DBG_CON_IRQ_EN;
  326. con &= ~BUS_DBG_CON_IRQ_WP_EN;
  327. }
  328. con |= BUS_DBG_CON_HALT_ON_EN;
  329. writel(con, IOMEM(BUS_DBG_CON));
  330. mb();
  331. con |= BUS_DBG_CON_IRQ_WP_EN;
  332. writel(con, IOMEM(BUS_DBG_CON));
  333. mb();
  334. }
  335. void systracker_enable(void)
  336. {
  337. if (mt_systracker_drv.enable_systracker)
  338. mt_systracker_drv.enable_systracker();
  339. else
  340. systracker_enable_default();
  341. }
  342. void enable_systracker(void)
  343. {
  344. systracker_enable();
  345. }
  346. static void systracker_disable_default(void)
  347. {
  348. track_config.state = 0;
  349. writel(readl(IOMEM(BUS_DBG_CON)) & ~BUS_DBG_CON_BUS_DBG_EN, IOMEM(BUS_DBG_CON));
  350. mb();
  351. }
  352. void systracker_disable(void)
  353. {
  354. if (mt_systracker_drv.disable_systracker)
  355. mt_systracker_drv.disable_systracker();
  356. else
  357. systracker_disable_default();
  358. }
  359. int systracker_hook_fault(void)
  360. {
  361. if (mt_systracker_drv.systracker_hook_fault)
  362. return mt_systracker_drv.systracker_hook_fault();
  363. pr_warn("mt_systracker_drv.systracker_hook_fault is NULL");
  364. return -1;
  365. }
  366. int systracker_test_init(void)
  367. {
  368. if (mt_systracker_drv.systracker_test_init)
  369. return mt_systracker_drv.systracker_test_init();
  370. pr_warn("mt_systracker_drv.systracker_test_init is NULL");
  371. return -1;
  372. }
  373. struct mt_systracker_driver *get_mt_systracker_drv(void)
  374. {
  375. return &mt_systracker_drv;
  376. }
  377. int tracker_dump(char *buf)
  378. {
  379. char *ptr = buf;
  380. unsigned int reg_value;
  381. int i;
  382. unsigned int entry_valid;
  383. unsigned int entry_tid;
  384. unsigned int entry_id;
  385. unsigned int entry_address;
  386. unsigned int entry_data_size;
  387. unsigned int entry_burst_length;
  388. {
  389. /* Get tracker info and save to buf */
  390. /* BUS_DBG_AR_TRACK_L(__n)
  391. * [31:0] ARADDR: DBG read tracker entry read address
  392. */
  393. /* BUS_DBG_AR_TRACK_H(__n)
  394. * [14] Valid:DBG read tracker entry valid
  395. * [13:7] ARID:DBG read tracker entry read ID
  396. * [6:4] ARSIZE:DBG read tracker entry read data size
  397. * [3:0] ARLEN: DBG read tracker entry read burst length
  398. */
  399. /* BUS_DBG_AR_TRACK_TID(__n)
  400. * [2:0] BUS_DBG_AR_TRANS0_ENTRY_ID: DBG read tracker entry ID of 1st transaction
  401. */
  402. #ifdef TRACKER_DEBUG
  403. pr_debug("Sys Tracker Dump\n");
  404. #endif
  405. ptr += sprintf(ptr, "[TRACKER] BUS_DBG_CON = (0x%x, 0x%x), T0= 0x%x, T1 = 0x%x\n",
  406. track_entry.dbg_con, readl(IOMEM(BUS_DBG_CON)),
  407. readl(IOMEM(BUS_DBG_TIMER_CON0)), readl(IOMEM(BUS_DBG_TIMER_CON1)));
  408. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  409. entry_address = track_entry.ar_track_l[i];
  410. reg_value = track_entry.ar_track_h[i];
  411. entry_valid = extract_n2mbits(reg_value, 19, 19);
  412. entry_id = extract_n2mbits(reg_value, 7, 18);
  413. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  414. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  415. entry_tid = track_entry.ar_trans_tid[i];
  416. ptr += sprintf(ptr,
  417. "read entry = %d, valid = 0x%x, tid = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  418. i, entry_valid, entry_tid, entry_id, entry_address, entry_data_size, entry_burst_length);
  419. #ifdef TRACKER_DEBUG
  420. pr_debug("read entry = %d, valid = 0x%x, tid = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  421. i, entry_valid, entry_tid, entry_id, entry_address, entry_data_size, entry_burst_length);
  422. #endif
  423. }
  424. /* BUS_DBG_AW_TRACK_L(__n)
  425. * [31:0] AWADDR: DBG write tracker entry write address
  426. */
  427. /* BUS_DBG_AW_TRACK_H(__n)
  428. * [14] Valid:DBG write tracker entry valid
  429. * [13:7] ARID:DBG write tracker entry write ID
  430. * [6:4] ARSIZE:DBG write tracker entry write data size
  431. * [3:0] ARLEN: DBG write tracker entry write burst length
  432. */
  433. /* BUS_DBG_AW_TRACK_TID(__n)
  434. * [2:0] BUS_DBG_AW_TRANS0_ENTRY_ID: DBG write tracker entry ID of 1st transaction
  435. */
  436. for (i = 0; i < BUS_DBG_NUM_TRACKER; i++) {
  437. entry_address = track_entry.aw_track_l[i];
  438. reg_value = track_entry.aw_track_h[i];
  439. entry_valid = extract_n2mbits(reg_value, 19, 19);
  440. entry_id = extract_n2mbits(reg_value, 7, 18);
  441. entry_data_size = extract_n2mbits(reg_value, 4, 6);
  442. entry_burst_length = extract_n2mbits(reg_value, 0, 3);
  443. entry_tid = track_entry.aw_trans_tid[i];
  444. ptr += sprintf(ptr,
  445. "write entry = %d, valid = 0x%x, tid = 0x%x, read id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  446. i, entry_valid, entry_tid, entry_id, entry_address, entry_data_size, entry_burst_length);
  447. #ifdef TRACKER_DEBUG
  448. pr_debug("write entry = %d, valid = 0x%x, tid = 0x%x, write id = 0x%x, address = 0x%x, data_size = 0x%x, burst_length = 0x%x\n",
  449. i, entry_valid, entry_tid, entry_id, entry_address, entry_data_size, entry_burst_length);
  450. #endif
  451. }
  452. return strlen(buf);
  453. }
  454. return -1;
  455. }
  456. static ssize_t tracker_run_show(struct device_driver *driver, char *buf)
  457. {
  458. return snprintf(buf, PAGE_SIZE, "%x\n", readl(IOMEM(BUS_DBG_CON)));
  459. }
  460. static ssize_t tracker_run_store(struct device_driver *driver, const char *buf, size_t count)
  461. {
  462. unsigned int value;
  463. if (unlikely(kstrtou32(buf, 10, &value) != 1))
  464. return -EINVAL;
  465. if (value == 1)
  466. systracker_enable();
  467. else if (value == 0)
  468. systracker_disable();
  469. else
  470. return -EINVAL;
  471. return count;
  472. }
  473. DRIVER_ATTR(tracker_run, 0644, tracker_run_show, tracker_run_store);
  474. static ssize_t enable_wp_show(struct device_driver *driver, char *buf)
  475. {
  476. return snprintf(buf, PAGE_SIZE, "%x\n", track_config.enable_wp);
  477. }
  478. static ssize_t enable_wp_store(struct device_driver *driver, const char *buf, size_t count)
  479. {
  480. unsigned int value;
  481. if (unlikely(kstrtou32(buf, 10, &value) != 1))
  482. return -EINVAL;
  483. if (value == 1)
  484. systracker_watchpoint_enable();
  485. else if (value == 0)
  486. systracker_watchpoint_disable();
  487. else
  488. return -EINVAL;
  489. return count;
  490. }
  491. DRIVER_ATTR(enable_wp, 0644, enable_wp_show, enable_wp_store);
  492. static ssize_t set_wp_address_show(struct device_driver *driver, char *buf)
  493. {
  494. return snprintf(buf, PAGE_SIZE, "%x\n", track_config.wp_phy_address);
  495. }
  496. int systracker_set_watchpoint_addr(unsigned int addr)
  497. {
  498. if (mt_systracker_drv.set_watchpoint_address)
  499. return mt_systracker_drv.set_watchpoint_address(addr);
  500. track_config.wp_phy_address = addr;
  501. return 0;
  502. }
  503. static ssize_t set_wp_address_store(struct device_driver *driver, const char *buf, size_t count)
  504. {
  505. unsigned int value;
  506. int ret;
  507. ret = kstrtou32(buf, 16, &value);
  508. pr_debug("watch address:0x%x, ret = %d\n", value, ret);
  509. systracker_set_watchpoint_addr(value);
  510. return count;
  511. }
  512. DRIVER_ATTR(set_wp_address, 0644, set_wp_address_show, set_wp_address_store);
  513. static ssize_t tracker_entry_dump_show(struct device_driver *driver, char *buf)
  514. {
  515. int ret = tracker_dump(buf);
  516. if (ret == -1)
  517. pr_err("Dump error in %s, %d\n", __func__, __LINE__);
  518. return strlen(buf);
  519. }
  520. static ssize_t tracker_swtrst_show(struct device_driver *driver, char *buf)
  521. {
  522. return 0;
  523. }
  524. static ssize_t tracker_swtrst_store(struct device_driver *driver, const char *buf, size_t count)
  525. {
  526. writel(readl(IOMEM(BUS_DBG_CON)) | BUS_DBG_CON_SW_RST, IOMEM(BUS_DBG_CON));
  527. return count;
  528. }
  529. DRIVER_ATTR(tracker_swtrst, 0664, tracker_swtrst_show, tracker_swtrst_store);
  530. #ifdef SYSTRACKER_TEST_SUIT
  531. void systracker_wp_test(void)
  532. {
  533. if (mt_systracker_drv.systracker_wp_test)
  534. mt_systracker_drv.systracker_wp_test();
  535. else
  536. pr_debug("mt_systracker_drv.systracker_wp_test is NULL");
  537. }
  538. /* this function expects */
  539. void systracker_read_timeout_test(void)
  540. {
  541. pr_err("we are going to have read timeout\n");
  542. if (mt_systracker_drv.systracker_read_timeout_test)
  543. mt_systracker_drv.systracker_read_timeout_test();
  544. else
  545. pr_debug("mt_systracker_drv.systracker_read_timeout_test is NULL");
  546. }
  547. void systracker_write_timeout_test(void)
  548. {
  549. pr_err("we are going to have write timeout\n");
  550. if (mt_systracker_drv.systracker_write_timeout_test)
  551. mt_systracker_drv.systracker_write_timeout_test();
  552. else
  553. pr_debug("mt_systracker_drv.systracker_write_timeout_test is NULL");
  554. }
  555. void systracker_timeout_withrecord_test(void)
  556. {
  557. pr_err("we are going to have read timeout, and then wdt happens\n");
  558. pr_err("Please check if there is related backtrace info in aee\n");
  559. if (mt_systracker_drv.systracker_withrecord_test)
  560. mt_systracker_drv.systracker_withrecord_test();
  561. else
  562. pr_debug("mt_systracker_drv.systracker_withrecord_test is NULL");
  563. }
  564. void systracker_notimeout_test(void)
  565. {
  566. pr_err("should hang forever from now on, never come back...\n");
  567. pr_err("ICE should not connect anymore\n");
  568. if (mt_systracker_drv.systracker_notimeout_test)
  569. mt_systracker_drv.systracker_notimeout_test();
  570. else
  571. pr_debug("mt_systracker_drv.systracker_notimeout_test is NULL");
  572. }
  573. static ssize_t test_suit_show(struct device_driver *driver, char *buf)
  574. {
  575. return snprintf(buf, PAGE_SIZE, "==Systracker test==\n"
  576. "1.Systracker show dump test\n"
  577. "2.Systracker watchpoint test\n"
  578. "3.Systracker read timeout test\n"
  579. "4.Systracker write timeout test\n"
  580. "5.Systracker timeout with record test\n"
  581. "6.Systracker no timeout test\n"
  582. );
  583. }
  584. static ssize_t test_suit_store(struct device_driver *driver, const char *buf, size_t count)
  585. {
  586. char *p = (char *)buf;
  587. unsigned long num;
  588. if (kstrtoul(p, 10, &num) != 0) {
  589. pr_err("[Tracker] kstrtoul fail for %s\n", p);
  590. return 0;
  591. }
  592. switch (num) {
  593. /* Test Systracker Function */
  594. case 1:
  595. return tracker_entry_dump_show(driver, p);
  596. case 2:
  597. systracker_wp_test();
  598. break;
  599. case 3:
  600. systracker_read_timeout_test();
  601. break;
  602. case 4:
  603. systracker_write_timeout_test();
  604. break;
  605. case 5:
  606. systracker_timeout_withrecord_test();
  607. break;
  608. case 6:
  609. systracker_notimeout_test();
  610. break;
  611. default:
  612. break;
  613. }
  614. return count;
  615. }
  616. DRIVER_ATTR(test_suit, 0664, test_suit_show, test_suit_store);
  617. #endif
  618. static ssize_t tracker_entry_dump_store(struct device_driver *driver, const char *buf, size_t count)
  619. {
  620. return count;
  621. }
  622. DRIVER_ATTR(tracker_entry_dump, 0664, tracker_entry_dump_show, tracker_entry_dump_store);
  623. static ssize_t tracker_last_status_show(struct device_driver *driver, char *buf)
  624. {
  625. if (track_entry.dbg_con & BUS_DBG_CON_TIMEOUT)
  626. return snprintf(buf, PAGE_SIZE, "1\n");
  627. else
  628. return snprintf(buf, PAGE_SIZE, "0\n");
  629. }
  630. static ssize_t tracker_last_status_store(struct device_driver *driver, const char *buf, size_t count)
  631. {
  632. return count;
  633. }
  634. DRIVER_ATTR(tracker_last_status, 0664, tracker_last_status_show, tracker_last_status_store);
  635. /*
  636. * driver initialization entry point
  637. */
  638. static int __init systracker_init(void)
  639. {
  640. int err = 0;
  641. int ret = 0;
  642. #ifdef SYSTRACKER_TEST_SUIT
  643. systracker_test_init();
  644. #endif
  645. err = platform_driver_register(&mt_systracker_drv.driver);
  646. if (err)
  647. return err;
  648. /* Create sysfs entry */
  649. ret = driver_create_file(&mt_systracker_drv.driver.driver , &driver_attr_tracker_entry_dump);
  650. ret |= driver_create_file(&mt_systracker_drv.driver.driver , &driver_attr_tracker_run);
  651. ret |= driver_create_file(&mt_systracker_drv.driver.driver , &driver_attr_enable_wp);
  652. ret |= driver_create_file(&mt_systracker_drv.driver.driver , &driver_attr_set_wp_address);
  653. ret |= driver_create_file(&mt_systracker_drv.driver.driver , &driver_attr_tracker_swtrst);
  654. ret |= driver_create_file(&mt_systracker_drv.driver.driver , &driver_attr_tracker_last_status);
  655. #ifdef SYSTRACKER_TEST_SUIT
  656. ret |= driver_create_file(&mt_systracker_drv.driver.driver , &driver_attr_test_suit);
  657. #endif
  658. if (ret)
  659. pr_err("Fail to create systracker_drv sysfs files");
  660. systracker_hook_fault();
  661. pr_debug("systracker init done\n");
  662. return 0;
  663. }
  664. /*
  665. * driver exit point
  666. */
  667. static void __exit systracker_exit(void)
  668. {
  669. }
  670. module_init(systracker_init);
  671. module_exit(systracker_exit);