1 #include <linux/device.h>
2 #include <linux/platform_device.h>
5 #include <linux/tty_flip.h>
6 #include <asm/thread_info.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>
17 #include <linux/version.h>
19 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
20 #define TTY_FLIP_ARG(a) (a)
22 #define TTY_FLIP_ARG(a) ((a)->port)
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
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;
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
);
47 int fiq_uart_getc(struct platform_device
*pdev
)
51 if (ret_FIQ_DEBUGGER_BREAK
) {
52 ret_FIQ_DEBUGGER_BREAK
= 0;
53 return FIQ_DEBUGGER_BREAK
;
56 if (!(REG_UART_STATUS
& 0x01))
57 return FIQ_DEBUGGER_NO_CHAR
;
59 ch
= REG_UART_BASE
& 0xFF;
61 if (ch
== FIQ_DEBUGGER_BREAK_CH
)
62 return FIQ_DEBUGGER_BREAK
;
67 void fiq_uart_putc(struct platform_device
*pdev
, unsigned int c
)
69 while (! (REG_UART_STATUS
& 0x20));
71 REG_UART_BASE
= c
& 0xFF;
74 void fiq_uart_fixup(int uart_port
)
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
;
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
;
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
;
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
;
106 static void __push_event(u32 iir
, int data
)
108 if (((fiq_dbg_event_wr
+ 1) % MAX_FIQ_DBG_EVENT
) == fiq_dbg_event_rd
) {
112 fiq_dbg_events
[fiq_dbg_event_wr
].iir
= iir
;
113 fiq_dbg_events
[fiq_dbg_event_wr
].data
= data
;
115 fiq_dbg_event_wr
%= MAX_FIQ_DBG_EVENT
;
119 static int __pop_event(u32
*iir
, int *data
)
121 if (fiq_dbg_event_rd
== fiq_dbg_event_wr
) {
125 *iir
= fiq_dbg_events
[fiq_dbg_event_rd
].iir
;
126 *data
= fiq_dbg_events
[fiq_dbg_event_rd
].data
;
128 fiq_dbg_event_rd
%= MAX_FIQ_DBG_EVENT
;
133 #ifdef CONFIG_MT_PRINTK_UART_CONSOLE
134 extern bool printk_disable_uart
;
135 extern int mt_need_uart_console
;
137 static void mt_debug_fiq(void *arg
, void *regs
, void *svc_sp
)
141 int max_count
= UART_FIFO_SIZE
;
142 unsigned int this_cpu
;
145 #ifdef CONFIG_MT_PRINTK_UART_CONSOLE
146 if (REG_UART_STATUS
& 0x01)
147 printk_disable_uart
= 0;
150 iir
&= UART_IIR_INT_MASK
;
151 if (iir
== UART_IIR_NO_INT_PENDING
)
153 if (iir
== UART_IIR_THRE
) {
155 __push_event(iir
, data
);
157 while (max_count
-- > 0) {
158 if (!(REG_UART_STATUS
& 0x01)) {
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
);
171 __push_event(UART_IIR_NO_INT_PENDING
, data
);
175 this_cpu
= THREAD_INFO(svc_sp
)->cpu
;
176 need_irq
= debug_handle_uart_interrupt(arg
, this_cpu
, regs
, svc_sp
);
181 mt_disable_fiq(uart_irq_number
);
182 trigger_sw_irq(FIQ_DBG_SGI
);
186 irqreturn_t
mt_debug_signal_irq(int irq
, void *dev_id
)
188 struct tty_struct
*tty
= mt_console_uart
->port
.state
->port
.tty
;
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
);
199 if (!tty_insert_flip_char(TTY_FLIP_ARG(tty
), data
, TTY_NORMAL
)) {
203 tty_flip_buffer_push(TTY_FLIP_ARG(tty
));
205 /* handle commands which can only be handled in the IRQ context */
206 debug_handle_irq_context(dev_id
);
208 mt_enable_fiq(uart_irq_number
);
213 int mt_fiq_init(void *arg
)
215 return request_fiq(uart_irq_number
, (fiq_isr_handler
)mt_debug_fiq
, IRQF_TRIGGER_LOW
, arg
);