import PULS_20160108
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / misc / mediatek / uart / mt8127 / platform_fiq_debugger.c
1 #include <linux/device.h>
2 #include <linux/platform_device.h>
3 #include <linux/irq.h>
4 #include <linux/tty.h>
5 #include <linux/tty_flip.h>
6 #include <asm/thread_info.h>
7 #include <asm/fiq.h>
8 #include <asm/fiq_glue.h>
9 #include <asm/fiq_debugger.h>
10 #include <mach/irqs.h>
11 #include <mach/mt_reg_base.h>
12 #include <linux/uart/mtk_uart.h>
13 #include <linux/uart/mtk_uart_intf.h>
14 #include <linux/of_irq.h>
15 #include <linux/of_address.h>
16
17 #include <linux/version.h>
18
19 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
20 #define TTY_FLIP_ARG(a) (a)
21 #else
22 #define TTY_FLIP_ARG(a) ((a)->port)
23 #endif
24
25 #define THREAD_INFO(sp) ((struct thread_info *) \
26 ((unsigned long)(sp) & ~(THREAD_SIZE - 1)))
27 #define REG_UART_BASE *((volatile unsigned int*)(console_base_addr + 0x00))
28 #define REG_UART_STATUS *((volatile unsigned int*)(console_base_addr + 0x14))
29 #define REG_UART_IIR *((volatile unsigned int*)(console_base_addr + 0x08))
30 #define FIQ_DEBUGGER_BREAK_CH 6 /* CTRL + F */
31 #define MAX_FIQ_DBG_EVENT 1024
32
33 static struct fiq_dbg_event fiq_dbg_events[MAX_FIQ_DBG_EVENT];
34 static int fiq_dbg_event_rd, fiq_dbg_event_wr;
35 static unsigned int fiq_dbg_event_ov;
36 static int console_base_addr = UART2_BASE;
37 static int ret_FIQ_DEBUGGER_BREAK;
38 static int uart_irq_number = -1;
39
40 extern struct mtk_uart *mt_console_uart;
41 extern int is_fiq_debug_console_enable(void *argv);
42 extern bool debug_handle_uart_interrupt(void *state, int this_cpu, void *regs, void *svc_sp);
43 extern void mtk_uart_tx_handler(struct mtk_uart *uart);
44 extern void mtk_uart_get_modem_status(struct mtk_uart *uart);
45 extern void debug_handle_irq_context(void *arg);
46
47 int fiq_uart_getc(struct platform_device *pdev)
48 {
49 int ch;
50
51 if (ret_FIQ_DEBUGGER_BREAK) {
52 ret_FIQ_DEBUGGER_BREAK = 0;
53 return FIQ_DEBUGGER_BREAK;
54 }
55
56 if (!(REG_UART_STATUS & 0x01))
57 return FIQ_DEBUGGER_NO_CHAR;
58
59 ch = REG_UART_BASE & 0xFF;
60
61 if (ch == FIQ_DEBUGGER_BREAK_CH)
62 return FIQ_DEBUGGER_BREAK;
63
64 return ch;
65 }
66
67 void fiq_uart_putc(struct platform_device *pdev, unsigned int c)
68 {
69 while (! (REG_UART_STATUS & 0x20));
70
71 REG_UART_BASE = c & 0xFF;
72 }
73
74 void fiq_uart_fixup(int uart_port)
75 {
76 switch (uart_port) {
77 case 0:
78 console_base_addr = UART1_BASE;
79 fiq_resource[1].start = MT_UART1_IRQ_ID;
80 fiq_resource[1].end = MT_UART1_IRQ_ID;
81 uart_irq_number = MT_UART1_IRQ_ID;
82 break;
83 case 1:
84 console_base_addr = UART2_BASE;
85 fiq_resource[1].start = MT_UART2_IRQ_ID;
86 fiq_resource[1].end = MT_UART2_IRQ_ID;
87 uart_irq_number = MT_UART2_IRQ_ID;
88 break;
89 case 2:
90 console_base_addr = UART3_BASE;
91 fiq_resource[1].start = MT_UART3_IRQ_ID;
92 fiq_resource[1].end = MT_UART3_IRQ_ID;
93 uart_irq_number = MT_UART3_IRQ_ID;
94 break;
95 case 3:
96 console_base_addr = UART4_BASE;
97 fiq_resource[1].start = MT_UART4_IRQ_ID;
98 fiq_resource[1].end = MT_UART4_IRQ_ID;
99 uart_irq_number = MT_UART4_IRQ_ID;
100 break;
101 default:
102 break;
103 }
104 }
105
106 static void __push_event(u32 iir, int data)
107 {
108 if (((fiq_dbg_event_wr + 1) % MAX_FIQ_DBG_EVENT) == fiq_dbg_event_rd) {
109 /* full */
110 fiq_dbg_event_ov++;
111 } else {
112 fiq_dbg_events[fiq_dbg_event_wr].iir = iir;
113 fiq_dbg_events[fiq_dbg_event_wr].data = data;
114 fiq_dbg_event_wr++;
115 fiq_dbg_event_wr %= MAX_FIQ_DBG_EVENT;
116 }
117 }
118
119 static int __pop_event(u32 *iir, int *data)
120 {
121 if (fiq_dbg_event_rd == fiq_dbg_event_wr) {
122 /* empty */
123 return -1;
124 } else {
125 *iir = fiq_dbg_events[fiq_dbg_event_rd].iir;
126 *data = fiq_dbg_events[fiq_dbg_event_rd].data;
127 fiq_dbg_event_rd++;
128 fiq_dbg_event_rd %= MAX_FIQ_DBG_EVENT;
129 return 0;
130 }
131 }
132
133 #ifdef CONFIG_MT_PRINTK_UART_CONSOLE
134 extern bool printk_disable_uart;
135 extern int mt_need_uart_console;
136 #endif
137 static void mt_debug_fiq(void *arg, void *regs, void *svc_sp)
138 {
139 u32 iir;
140 int data = -1;
141 int max_count = UART_FIFO_SIZE;
142 unsigned int this_cpu;
143 int need_irq = 1;
144
145 #ifdef CONFIG_MT_PRINTK_UART_CONSOLE
146 if (REG_UART_STATUS & 0x01)
147 printk_disable_uart = 0;
148 #endif
149 iir = REG_UART_IIR;
150 iir &= UART_IIR_INT_MASK;
151 if (iir == UART_IIR_NO_INT_PENDING)
152 return ;
153 if (iir == UART_IIR_THRE) {
154 }
155 __push_event(iir, data);
156
157 while (max_count-- > 0) {
158 if (!(REG_UART_STATUS & 0x01)) {
159 break;
160 }
161
162 if (is_fiq_debug_console_enable(arg)) {
163 data = mt_console_uart->read_byte(mt_console_uart);
164 if (data == FIQ_DEBUGGER_BREAK_CH) {
165 /* enter FIQ debugger mode */
166 ret_FIQ_DEBUGGER_BREAK = 1;
167 this_cpu = THREAD_INFO(svc_sp)->cpu;
168 debug_handle_uart_interrupt(arg, this_cpu, regs, svc_sp);
169 return ;
170 }
171 __push_event(UART_IIR_NO_INT_PENDING, data);
172 /*why need_irq?*/
173 need_irq = 1;
174 } else {
175 this_cpu = THREAD_INFO(svc_sp)->cpu;
176 need_irq = debug_handle_uart_interrupt(arg, this_cpu, regs, svc_sp);
177 }
178 }
179
180 if (need_irq) {
181 mt_disable_fiq(uart_irq_number);
182 trigger_sw_irq(FIQ_DBG_SGI);
183 }
184 }
185
186 irqreturn_t mt_debug_signal_irq(int irq, void *dev_id)
187 {
188 struct tty_struct *tty = mt_console_uart->port.state->port.tty;
189 u32 iir;
190 int data;
191
192 while (__pop_event(&iir, &data) >= 0) {
193 if (iir == UART_IIR_MS) {
194 mtk_uart_get_modem_status(mt_console_uart);
195 } else if (iir == UART_IIR_THRE) {
196 mtk_uart_tx_handler(mt_console_uart);
197 }
198 if (data != -1) {
199 if (!tty_insert_flip_char(TTY_FLIP_ARG(tty), data, TTY_NORMAL)) {
200 }
201 }
202 }
203 tty_flip_buffer_push(TTY_FLIP_ARG(tty));
204
205 /* handle commands which can only be handled in the IRQ context */
206 debug_handle_irq_context(dev_id);
207
208 mt_enable_fiq(uart_irq_number);
209
210 return IRQ_HANDLED;
211 }
212
213 int mt_fiq_init(void *arg)
214 {
215 return request_fiq(uart_irq_number, (fiq_isr_handler)mt_debug_fiq, IRQF_TRIGGER_LOW, arg);
216 }