fiq-debugger.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /*
  2. * Copyright (c) 2006-2024 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 <ioremap.h>
  14. #include <cpuport.h>
  15. #include "regs.h"
  16. #include "serial_dm.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 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. switch (t->baudrate)
  82. {
  83. case 1500000:
  84. dll = 0x1;
  85. break;
  86. case 115200:
  87. default:
  88. dll = 0xd;
  89. break;
  90. }
  91. /* reset uart */
  92. rockchip_fiq_write(t, (1 << 1) | (1 << 2), UART_SRR);
  93. rt_hw_us_delay(10);
  94. /* set uart to loop back mode */
  95. rockchip_fiq_write(t, 0x10, UART_MCR);
  96. rockchip_fiq_write(t, 0x83, UART_LCR);
  97. /* set baud rate */
  98. rockchip_fiq_write(t, dll, UART_DLL);
  99. rockchip_fiq_write(t, dlm, UART_DLM);
  100. rockchip_fiq_write(t, 0x03, UART_LCR);
  101. /* enable rx interrupt */
  102. rockchip_fiq_write(t, UART_IER_RDI, UART_IER);
  103. /*
  104. * interrupt on every character when received, but we can enable fifo for TX
  105. * I found that if we enable the RX fifo, some problem may vanish such as
  106. * when you continuously input characters in the command line the uart irq
  107. * may be disable because of the uart irq is served when CPU is at IRQ
  108. * exception, but it is found unregistered, so it is disable.
  109. */
  110. rockchip_fiq_write(t, 0x01, UART_FCR);
  111. /* disbale loop back mode */
  112. rockchip_fiq_write(t, 0x0, UART_MCR);
  113. return RT_EOK;
  114. }
  115. static rt_err_t fiq_debugger_uart_control(struct rt_serial_device *serial, int cmd, void *arg)
  116. {
  117. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  118. switch (cmd)
  119. {
  120. case RT_DEVICE_CTRL_CLR_INT:
  121. rt_pic_irq_mask(t->irq);
  122. break;
  123. case RT_DEVICE_CTRL_SET_INT:
  124. rt_pic_irq_unmask(t->irq);
  125. break;
  126. }
  127. return RT_EOK;
  128. }
  129. static int fiq_debugger_uart_putc(struct rt_serial_device *serial, char c)
  130. {
  131. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  132. rt_uint32_t count = 10000;
  133. while (!(rockchip_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) && count--)
  134. {
  135. rt_hw_cpu_relax();
  136. }
  137. rockchip_fiq_write(t, c, UART_TX);
  138. return 1;
  139. }
  140. static int fiq_debugger_uart_getc(struct rt_serial_device *serial)
  141. {
  142. int ch = FIQ_DEBUGGER_NO_CHAR;
  143. rt_uint32_t lsr, temp;
  144. static rt_uint32_t n = 0;
  145. static char buf[32] = {};
  146. struct rockchip_fiq_debugger *t = raw_to_fiq_debugger(serial);
  147. /* Clear uart interrupt status */
  148. rockchip_fiq_read(t, UART_USR);
  149. lsr = rockchip_fiq_read_lsr(t);
  150. if (lsr & UART_LSR_DR)
  151. {
  152. temp = rockchip_fiq_read(t, UART_RX);
  153. buf[n & 0x1f] = temp;
  154. n++;
  155. if (temp == 'q' && n > 2)
  156. {
  157. if ((buf[(n - 2) & 0x1f] == 'i') && (buf[(n - 3) & 0x1f] == 'f'))
  158. {
  159. ch = FIQ_DEBUGGER_BREAK;
  160. }
  161. else
  162. {
  163. ch = temp;
  164. }
  165. }
  166. else
  167. {
  168. ch = temp;
  169. }
  170. }
  171. return ch;
  172. }
  173. static const struct rt_uart_ops fiq_debugger_uart_ops =
  174. {
  175. .configure = fiq_debugger_uart_configure,
  176. .control = fiq_debugger_uart_control,
  177. .putc = fiq_debugger_uart_putc,
  178. .getc = fiq_debugger_uart_getc,
  179. };
  180. struct rockchip_fiq_debugger *rk_serial_debug_init(void *base, rt_ubase_t paddr,
  181. int irq, int signal_irq, int wakeup_irq, rt_uint32_t baudrate)
  182. {
  183. struct rockchip_fiq_debugger *t = rt_calloc(1, sizeof(*t));
  184. if (t)
  185. {
  186. const char *name;
  187. t->parent.ops = &fiq_debugger_uart_ops;
  188. t->parent.config = (struct serial_configure)RT_SERIAL_CONFIG_DEFAULT;
  189. t->parent.config.baud_rate = baudrate;
  190. t->irq = irq;
  191. t->baudrate = baudrate;
  192. t->debug_port_base = base;
  193. t->break_seen = RT_FALSE;
  194. serial_dev_set_name(&t->parent);
  195. name = rt_dm_dev_get_name(&t->parent.parent);
  196. rt_hw_serial_register(&t->parent, name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, t);
  197. rt_pic_attach_irq(t->irq, fiq_debugger_isr, &t->parent, name, RT_IRQ_F_NONE);
  198. }
  199. return t;
  200. }
  201. static rt_err_t rockchip_fiq_debugger_probe(struct rt_platform_device *pdev)
  202. {
  203. rt_err_t err = RT_EOK;
  204. void *base;
  205. rt_uint64_t regs[2];
  206. struct rt_clk *clk, *pclk;
  207. rt_bool_t found = RT_FALSE;
  208. char dev_name[RT_NAME_MAX];
  209. int irq, signal_irq = -1;
  210. rt_uint32_t serial_id, baudrate = 0, irq_mode = 0, wake_irq = -1;
  211. struct rt_ofw_node *np = pdev->parent.ofw_node;
  212. if (rt_ofw_prop_read_u32(np, "rockchip,serial-id", &serial_id) || serial_id == -1)
  213. {
  214. return -RT_EINVAL;
  215. }
  216. if (rt_ofw_prop_read_u32(np, "rockchip,irq-mode-enable", &irq_mode))
  217. {
  218. irq_mode = -1;
  219. }
  220. if (irq_mode == 1)
  221. {
  222. signal_irq = -1;
  223. }
  224. else if (!(signal_irq = rt_ofw_get_irq(np, 0)))
  225. {
  226. return -RT_EINVAL;
  227. }
  228. if (rt_ofw_prop_read_u32(np, "rockchip,wake-irq", &wake_irq))
  229. {
  230. wake_irq = -1;
  231. }
  232. if (rt_ofw_prop_read_u32(np, "rockchip,baudrate", &baudrate))
  233. {
  234. baudrate = 1500000;
  235. }
  236. rt_snprintf(dev_name, RT_NAME_MAX, "serial%d", serial_id);
  237. np = RT_NULL;
  238. do {
  239. np = rt_ofw_find_node_by_tag(np, "serial");
  240. if (np && rt_ofw_get_alias_id(np, "serial") == serial_id)
  241. {
  242. found = RT_TRUE;
  243. break;
  244. }
  245. } while(np);
  246. if (!found)
  247. {
  248. return -RT_EINVAL;
  249. }
  250. rt_memset(regs, 0, sizeof(regs));
  251. rt_ofw_get_address_array(np, 1, regs);
  252. pclk = rt_ofw_get_clk_by_name(np, "apb_pclk");
  253. clk = rt_ofw_get_clk_by_name(np, "baudclk");
  254. if (!pclk || !clk)
  255. {
  256. err = -RT_ERROR;
  257. goto _fail;
  258. }
  259. rt_clk_enable(clk);
  260. rt_clk_enable(pclk);
  261. if ((irq = rt_ofw_get_irq(np, 0)) < 0)
  262. {
  263. err = -RT_ERROR;
  264. goto _fail;
  265. }
  266. if ((base = rt_ioremap((void *)regs[0], regs[1])))
  267. {
  268. struct rockchip_fiq_debugger *t = rk_serial_debug_init(base,
  269. (rt_ubase_t)regs[0], irq, signal_irq, wake_irq, baudrate);
  270. if (t)
  271. {
  272. rt_dm_dev_bind_fwdata(&t->parent.parent, pdev->parent.ofw_node, &t->parent);
  273. }
  274. }
  275. return err;
  276. _fail:
  277. if (clk)
  278. {
  279. rt_clk_disable(clk);
  280. rt_clk_put(clk);
  281. }
  282. if (pclk)
  283. {
  284. rt_clk_disable(pclk);
  285. rt_clk_put(pclk);
  286. }
  287. return err;
  288. }
  289. static const struct rt_ofw_node_id rockchip_fiq_debugger_ofw_ids[] =
  290. {
  291. { .type = "ttyFIQ", .compatible = "rockchip,fiq-debugger" },
  292. { /* sentinel */ }
  293. };
  294. static struct rt_platform_driver rockchip_fiq_debugger_driver =
  295. {
  296. .name = "rockchip-fiq-debugger",
  297. .ids = rockchip_fiq_debugger_ofw_ids,
  298. .probe = rockchip_fiq_debugger_probe,
  299. };
  300. static int rockchip_fiq_debugger_drv_register(void)
  301. {
  302. rt_platform_driver_register(&rockchip_fiq_debugger_driver);
  303. return 0;
  304. }
  305. INIT_PLATFORM_EXPORT(rockchip_fiq_debugger_drv_register);