1 /*
2  * Copyright (c) 2015 Brian Swetland
3  *
4  * Use of this source code is governed by a MIT-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/MIT
7  */
8 
9 #include <lk/debug.h>
10 #include <lk/reg.h>
11 #include <kernel/thread.h>
12 #include <lib/cbuf.h>
13 
14 #include <arch/arm/cm.h>
15 #include <platform/lpc43xx-uart.h>
16 #include <platform/lpc43xx-clocks.h>
17 
18 static cbuf_t console_rx_buf;
19 
20 #ifndef TARGET_DEBUG_BAUDRATE
21 #define TARGET_DEBUG_BAUDRATE 115200
22 #endif
23 
24 #if TARGET_DEBUG_UART == 1
25 #define UART_BASE UART0_BASE
26 #define UART_IRQ lpc43xx_USART0_IRQ
27 #define UART_IRQn USART0_IRQn
28 #elif TARGET_DEBUG_UART == 2
29 #define UART_BASE UART1_BASE
30 #define UART_IRQ lpc43xx_UART1_IRQ
31 #define UART_IRQn UART1_IRQn
32 #elif TARGET_DEBUG_UART == 3
33 #define UART_BASE UART2_BASE
34 #define UART_IRQ lpc43xx_USART2_IRQ
35 #define UART_IRQn USART2_IRQn
36 #elif TARGET_DEBUG_UART == 4
37 #define UART_BASE UART3_BASE
38 #define UART_IRQ lpc43xx_USART3_IRQ
39 #define UART_IRQn USART3_IRQn
40 #else
41 #warning TARGET_DEBUG_UART unspecified
42 #endif
43 
44 static u32 base_uart_clk[4] = {
45     BASE_UART0_CLK,
46     BASE_UART1_CLK,
47     BASE_UART2_CLK,
48     BASE_UART3_CLK
49 };
50 
51 extern uint8_t __lpc43xx_main_clock_sel;
52 extern uint32_t __lpc43xx_main_clock_mhz;
53 
54 #define ITM_STIM0   0xE0000000
55 #define ITM_TER     0xE0000E00
56 #define ITM_TCR     0xE0000E80
57 #define ITM_LAR     0xE0000FB0
58 
59 #define TPI_ACPR    0xE0040010
60 #define TPI_SPPR    0xE00400F0
61 #define TPI_FFCR    0xE0040304
62 
63 #define DEMCR       0xE000EDFC
64 #define DEMCR_TRCENA    (1 << 24)
65 
lpc43xx_debug_early_init(void)66 void lpc43xx_debug_early_init(void) {
67     // ensure ITM and DWT are enabled
68     writel(readl(DEMCR) | DEMCR_TRCENA, DEMCR);
69 
70     writel((1 << 9) | (1 << 16) | (2 << 10), DWT_CTRL);
71 
72     // configure TPIU for one-wire, nrz, 6mbps
73     writel((__lpc43xx_main_clock_mhz / 6000000) - 1, TPI_ACPR);
74     writel(2, TPI_SPPR);
75     writel(0x100, TPI_FFCR);
76 
77     // configure ITM
78     writel(0xC5ACCE55, ITM_LAR); // unlock regs
79     writel(0x0001000D, ITM_TCR); // ID=1, enable ITM, SYNC, DWT events
80     writel(0xFFFFFFFF, ITM_TER); // enable all trace ports
81 
82 #ifdef UART_BASE
83 #if TARGET_DEBUG_BAUDRATE == 115200
84     // config for 115200-n-8-1 from 12MHz clock
85     writel(BASE_CLK_SEL(CLK_IRC), base_uart_clk[TARGET_DEBUG_UART - 1]);
86     writel(LCR_DLAB, UART_BASE + REG_LCR);
87     writel(4, UART_BASE + REG_DLL);
88     writel(0, UART_BASE + REG_DLM);
89     writel(FDR_DIVADDVAL(5) | FDR_MULVAL(8), UART_BASE + REG_FDR);
90 #else
91     uint32_t div = __lpc43xx_main_clock_mhz / 16 / TARGET_DEBUG_BAUDRATE;
92     writel(BASE_CLK_SEL(__lpc43xx_main_clock_sel),
93            base_uart_clk[TARGET_DEBUG_UART - 1]);
94     writel(LCR_DLAB, UART_BASE + REG_LCR);
95     writel(div & 0xFF, UART_BASE + REG_DLL);
96     writel((div >> 8) & 0xFF, UART_BASE + REG_DLM);
97 #endif
98     writel(LCR_WLS_8 | LCR_SBS_1, UART_BASE + REG_LCR);
99     writel(FCR_FIFOEN | FCR_RX_TRIG_1, UART_BASE + REG_FCR);
100     writel(IER_RBRIE, UART_BASE + REG_IER);
101     NVIC_EnableIRQ(UART_IRQn);
102 #endif
103 }
104 
lpc43xx_debug_init(void)105 void lpc43xx_debug_init(void) {
106     cbuf_initialize(&console_rx_buf, 64);
107 }
108 
109 #ifdef UART_BASE
UART_IRQ(void)110 void UART_IRQ (void) {
111     arm_cm_irq_entry();
112     while (readl(UART_BASE + REG_LSR) & LSR_RDR) {
113         unsigned c = readl(UART_BASE + REG_RBR);
114         if (cbuf_space_avail(&console_rx_buf)) {
115             cbuf_write_char(&console_rx_buf, c, false);
116         }
117     }
118     arm_cm_irq_exit(1);
119 }
120 #endif
121 
platform_dputc(char c)122 void platform_dputc(char c) {
123     // if ITM is enabled, send character to STIM0
124     if (readl(ITM_TCR) & 1) {
125         while (!readl(ITM_STIM0)) ;
126         writeb(c, ITM_STIM0);
127     }
128 #ifdef UART_BASE
129     while (!(readl(UART_BASE + REG_LSR) & LSR_THRE)) ;
130     writel(c, UART_BASE + REG_THR);
131 #endif
132 }
133 
platform_dgetc(char * c,bool wait)134 int platform_dgetc(char *c, bool wait) {
135     if (cbuf_read_char(&console_rx_buf, c, wait) == 0)
136         return -1;
137     return 0;
138 }
139 
140 #define DCRDR 0xE000EDF8
141 
_debugmonitor(void)142 void _debugmonitor(void) {
143     u32 n;
144     arm_cm_irq_entry();
145     n = readl(DCRDR);
146     if (n & 0x80000000) {
147         switch (n >> 24) {
148             case 0x80: // write to console
149                 if (cbuf_space_avail(&console_rx_buf)) {
150                     cbuf_write_char(&console_rx_buf, n & 0xFF, false);
151                 }
152                 n = 0;
153                 break;
154             default:
155                 n = 0x01000000;
156         }
157         writel(n, DCRDR);
158     }
159     arm_cm_irq_exit(1);
160 }
161