fiq-debugger.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * Copyright (c) 2006-2022, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2022-11-21 GuEe-GUI first version
  9. */
  10. #include <rthw.h>
  11. #include <rtthread.h>
  12. #include <rtdevice.h>
  13. #include <drivers/serial_dm.h>
  14. #include <ioremap.h>
  15. #include <cpuport.h>
  16. #include "8250/regs.h"
  17. #define UART_USR 0x1f /* In: UART Status Register */
  18. #define UART_USR_RX_FIFO_FULL 0x10 /* Receive FIFO full */
  19. #define UART_USR_RX_FIFO_NOT_EMPTY 0x08 /* Receive FIFO not empty */
  20. #define UART_USR_TX_FIFO_EMPTY 0x04 /* Transmit FIFO empty */
  21. #define UART_USR_TX_FIFO_NOT_FULL 0x02 /* Transmit FIFO not full */
  22. #define UART_USR_BUSY 0x01 /* UART busy indicator */
  23. #define UART_SRR 0x22 /* software reset register */
  24. #define FIQ_DEBUGGER_NO_CHAR -1
  25. #define FIQ_DEBUGGER_BREAK -2
  26. struct rockchip_fiq_debugger
  27. {
  28. struct rt_serial_device parent;
  29. int irq;
  30. int baudrate;
  31. void *debug_port_base;
  32. rt_bool_t break_seen;
  33. };
  34. #define raw_to_fiq_debugger(raw) rt_container_of(raw, struct rockchip_fiq_debugger, parent)
  35. rt_inline void rockchip_fiq_write(struct rockchip_fiq_debugger *t, rt_uint32_t val, int off)
  36. {
  37. HWREG32(t->debug_port_base + off * 4) = val;
  38. }
  39. rt_inline rt_uint32_t rockchip_fiq_read(struct rockchip_fiq_debugger *t, int off)
  40. {
  41. return HWREG32(t->debug_port_base + off * 4);
  42. }
  43. rt_inline rt_uint32_t rockchip_fiq_read_lsr(struct rockchip_fiq_debugger *t)
  44. {
  45. rt_uint32_t ret = rockchip_fiq_read(t, UART_LSR);
  46. if (ret & UART_LSR_BI)
  47. {
  48. t->break_seen = true;
  49. }
  50. return ret;
  51. }
  52. static void fiq_debugger_isr(int irqno, void *param)
  53. {
  54. rt_uint32_t usr;
  55. struct rt_serial_device *serial = (struct rt_serial_device*)param;
  56. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  57. usr = rockchip_fiq_read(t, UART_USR);
  58. if ((usr & UART_USR_RX_FIFO_NOT_EMPTY) == UART_USR_RX_FIFO_NOT_EMPTY)
  59. {
  60. rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
  61. }
  62. if ((usr & UART_USR_BUSY) == UART_USR_BUSY)
  63. {
  64. /* Clear the USR */
  65. (void)rockchip_fiq_read(t, UART_USR);
  66. }
  67. }
  68. static rt_err_t fiq_debugger_uart_configure(struct rt_serial_device *serial, struct serial_configure *cfg)
  69. {
  70. int dll = 0, dlm = 0;
  71. rt_uint32_t baudrate, count = 10000;
  72. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  73. if (rockchip_fiq_read(t, UART_LSR) & UART_LSR_DR)
  74. {
  75. (void)rockchip_fiq_read(t, UART_RX);
  76. }
  77. while (!(rockchip_fiq_read(t, UART_LSR) & UART_LSR_TEMT) && count--)
  78. {
  79. rt_hw_us_delay(10);
  80. }
  81. if (cfg->baud_rate == 1500000 || cfg->baud_rate == 115200)
  82. {
  83. baudrate = cfg->baud_rate;
  84. }
  85. else
  86. {
  87. baudrate = t->baudrate;
  88. }
  89. switch (baudrate)
  90. {
  91. case 1500000:
  92. dll = 0x1;
  93. break;
  94. case 115200:
  95. default:
  96. dll = 0xd;
  97. break;
  98. }
  99. /* reset uart */
  100. rockchip_fiq_write(t, (1 << 1) | (1 << 2), UART_SRR);
  101. rt_hw_us_delay(10);
  102. /* set uart to loop back mode */
  103. rockchip_fiq_write(t, 0x10, UART_MCR);
  104. rockchip_fiq_write(t, 0x83, UART_LCR);
  105. /* set baud rate */
  106. rockchip_fiq_write(t, dll, UART_DLL);
  107. rockchip_fiq_write(t, dlm, UART_DLM);
  108. rockchip_fiq_write(t, 0x03, UART_LCR);
  109. /* enable rx interrupt */
  110. rockchip_fiq_write(t, UART_IER_RDI, UART_IER);
  111. /*
  112. * interrupt on every character when received, but we can enable fifo for TX
  113. * I found that if we enable the RX fifo, some problem may vanish such as
  114. * when you continuously input characters in the command line the uart irq
  115. * may be disable because of the uart irq is served when CPU is at IRQ
  116. * exception, but it is found unregistered, so it is disable.
  117. */
  118. rockchip_fiq_write(t, 0x01, UART_FCR);
  119. /* disbale loop back mode */
  120. rockchip_fiq_write(t, 0x0, UART_MCR);
  121. return RT_EOK;
  122. }
  123. static rt_err_t fiq_debugger_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
  124. {
  125. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  126. switch (cmd)
  127. {
  128. case RT_DEVICE_CTRL_CLR_INT:
  129. rt_hw_interrupt_mask(t->irq);
  130. break;
  131. case RT_DEVICE_CTRL_SET_INT:
  132. rt_hw_interrupt_umask(t->irq);
  133. break;
  134. }
  135. return RT_EOK;
  136. }
  137. static int fiq_debugger_uart_putc(struct rt_serial_device *serial, char c)
  138. {
  139. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  140. rt_uint32_t count = 10000;
  141. while (!(rockchip_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) && count--)
  142. {
  143. rt_hw_us_delay(10);
  144. }
  145. rockchip_fiq_write(t, c, UART_TX);
  146. return 1;
  147. }
  148. static int fiq_debugger_uart_getc(struct rt_serial_device *serial)
  149. {
  150. int ch = FIQ_DEBUGGER_NO_CHAR;
  151. rt_uint32_t lsr, temp;
  152. static rt_uint32_t n = 0;
  153. static char buf[32] = {};
  154. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  155. /* Clear uart interrupt status */
  156. rockchip_fiq_read(t, UART_USR);
  157. lsr = rockchip_fiq_read_lsr(t);
  158. if (lsr & UART_LSR_DR)
  159. {
  160. temp = rockchip_fiq_read(t, UART_RX);
  161. buf[n & 0x1f] = temp;
  162. n++;
  163. if (temp == 'q' && n > 2)
  164. {
  165. if ((buf[(n - 2) & 0x1f] == 'i') && (buf[(n - 3) & 0x1f] == 'f'))
  166. {
  167. ch = FIQ_DEBUGGER_BREAK;
  168. }
  169. else
  170. {
  171. ch = temp;
  172. }
  173. }
  174. else
  175. {
  176. ch = temp;
  177. }
  178. }
  179. return ch;
  180. }
  181. static const struct rt_uart_ops fiq_debugger_uart_ops =
  182. {
  183. .configure = fiq_debugger_uart_configure,
  184. .control = fiq_debugger_uart_control,
  185. .putc = fiq_debugger_uart_putc,
  186. .getc = fiq_debugger_uart_getc,
  187. };
  188. struct rockchip_fiq_debugger *rk_serial_debug_init(void *base, rt_ubase_t paddr,
  189. int irq, int signal_irq, int wakeup_irq, rt_uint32_t baudrate)
  190. {
  191. struct rockchip_fiq_debugger *t = rt_calloc(1, sizeof(*t));
  192. if (t)
  193. {
  194. const char *name;
  195. t->parent.ops = &fiq_debugger_uart_ops;
  196. t->parent.config = (struct serial_configure)RT_SERIAL_CONFIG_DEFAULT;
  197. t->parent.config.baud_rate = baudrate;
  198. t->irq = irq;
  199. t->baudrate = baudrate;
  200. t->debug_port_base = base;
  201. t->break_seen = RT_FALSE;
  202. serial_dev_set_name(&t->parent);
  203. name = rt_dm_dev_get_name(&t->parent.parent);
  204. rt_hw_serial_register(&t->parent, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, t);
  205. rt_hw_interrupt_install(t->irq, fiq_debugger_isr, &t->parent, name);
  206. }
  207. return t;
  208. }
  209. static rt_err_t rockchip_fiq_debugger_probe(struct rt_platform_device *pdev)
  210. {
  211. rt_err_t err = RT_EOK;
  212. void *base;
  213. rt_uint64_t regs[2];
  214. struct rt_clk *clk, *pclk;
  215. rt_bool_t found = RT_FALSE;
  216. char dev_name[RT_NAME_MAX];
  217. int irq, signal_irq = -1;
  218. rt_uint32_t serial_id, baudrate = 0, irq_mode = 0, wake_irq = -1;
  219. struct rt_ofw_node *np = pdev->parent.ofw_node;
  220. if (rt_ofw_prop_read_u32(np, "rockchip,serial-id", &serial_id) || serial_id == -1)
  221. {
  222. return -RT_EINVAL;
  223. }
  224. if (rt_ofw_prop_read_u32(np, "rockchip,irq-mode-enable", &irq_mode))
  225. {
  226. irq_mode = -1;
  227. }
  228. if (irq_mode == 1)
  229. {
  230. signal_irq = -1;
  231. }
  232. else if (!(signal_irq = rt_ofw_get_irq(np, 0)))
  233. {
  234. return -RT_EINVAL;
  235. }
  236. if (rt_ofw_prop_read_u32(np, "rockchip,wake-irq", &wake_irq))
  237. {
  238. wake_irq = -1;
  239. }
  240. if (rt_ofw_prop_read_u32(np, "rockchip,baudrate", &baudrate))
  241. {
  242. baudrate = 1500000;
  243. }
  244. rt_snprintf(dev_name, RT_NAME_MAX, "serial%d", serial_id);
  245. np = RT_NULL;
  246. do {
  247. np = rt_ofw_find_node_by_tag(np, "serial");
  248. if (np && rt_ofw_get_alias_id(np, "serial") == serial_id)
  249. {
  250. found = RT_TRUE;
  251. break;
  252. }
  253. } while(np);
  254. if (!found)
  255. {
  256. return -RT_EINVAL;
  257. }
  258. rt_memset(regs, 0, sizeof(regs));
  259. rt_ofw_get_address_array(np, 1, regs);
  260. pclk = rt_ofw_get_clk_by_name(np, "apb_pclk");
  261. clk = rt_ofw_get_clk_by_name(np, "baudclk");
  262. if (!pclk || !clk)
  263. {
  264. err = -RT_ERROR;
  265. goto _fail;
  266. }
  267. rt_clk_enable(clk);
  268. rt_clk_enable(pclk);
  269. if ((irq = rt_ofw_get_irq(np, 0)) < 0)
  270. {
  271. err = -RT_ERROR;
  272. goto _fail;
  273. }
  274. if ((base = rt_ioremap((void *)regs[0], regs[1])))
  275. {
  276. struct rockchip_fiq_debugger *t = rk_serial_debug_init(base,
  277. (rt_ubase_t)regs[0], irq, signal_irq, wake_irq, baudrate);
  278. if (t)
  279. {
  280. rt_dm_dev_bind_fwdata(&t->parent.parent, pdev->parent.ofw_node, &t->parent);
  281. }
  282. }
  283. return err;
  284. _fail:
  285. if (clk)
  286. {
  287. rt_clk_disable(clk);
  288. rt_clk_put(clk);
  289. }
  290. if (pclk)
  291. {
  292. rt_clk_disable(pclk);
  293. rt_clk_put(pclk);
  294. }
  295. return err;
  296. }
  297. static const struct rt_ofw_node_id rockchip_fiq_debugger_ofw_ids[] =
  298. {
  299. { .type = "ttyFIQ", .compatible = "rockchip,fiq-debugger" },
  300. { /* sentinel */ }
  301. };
  302. static struct rt_platform_driver rockchip_fiq_debugger_driver =
  303. {
  304. .name = "rockchip-fiq-debugger",
  305. .ids = rockchip_fiq_debugger_ofw_ids,
  306. .probe = rockchip_fiq_debugger_probe,
  307. };
  308. static int rockchip_fiq_debugger_drv_register(void)
  309. {
  310. rt_platform_driver_register(&rockchip_fiq_debugger_driver);
  311. return 0;
  312. }
  313. INIT_PLATFORM_EXPORT(rockchip_fiq_debugger_drv_register);