ARM: rockchip: support console write by thread
[firefly-linux-kernel-4.4.55.git] / arch / arm / mach-rockchip / rk_fiq_debugger.c
1 /*
2  * arch/arm/plat-rk/rk_fiq_debugger.c
3  *
4  * Serial Debugger Interface for Rockchip
5  *
6  * Copyright (C) 2012 ROCKCHIP, Inc.
7  * Copyright (C) 2008 Google, Inc.
8  *
9  * This software is licensed under the terms of the GNU General Public
10  * License version 2, as published by the Free Software Foundation, and
11  * may be copied, distributed, and modified under those terms.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 #include <stdarg.h>
20 #include <linux/module.h>
21 #include <linux/io.h>
22 #include <linux/of.h>
23 #include <linux/of_address.h>
24 #include <linux/of_irq.h>
25 #include <linux/interrupt.h>
26 #include <linux/clk.h>
27 #include <linux/platform_device.h>
28 #include <linux/irq.h>
29 #include <linux/serial_reg.h>
30 #include <linux/slab.h>
31 #include <linux/stacktrace.h>
32 #include <linux/uaccess.h>
33 #include <linux/kfifo.h>
34 #include <linux/kthread.h>
35 #include <linux/sched/rt.h>
36 #include <asm/fiq_debugger.h>
37 #include <linux/irqchip/arm-gic.h>
38 #include "rk_fiq_debugger.h"
39
40 struct rk_fiq_debugger {
41         struct fiq_debugger_pdata pdata;
42         void __iomem *debug_port_base;
43         bool break_seen;
44 #ifdef CONFIG_RK_CONSOLE_THREAD
45         struct task_struct *console_task;
46 #endif
47 };
48
49 static inline void rk_fiq_write(struct rk_fiq_debugger *t,
50         unsigned int val, unsigned int off)
51 {
52         __raw_writel(val, t->debug_port_base + off * 4);
53 }
54
55 static inline unsigned int rk_fiq_read(struct rk_fiq_debugger *t,
56         unsigned int off)
57 {
58         return __raw_readl(t->debug_port_base + off * 4);
59 }
60
61 static inline unsigned int rk_fiq_read_lsr(struct rk_fiq_debugger *t)
62 {
63         unsigned int lsr;
64
65         lsr = rk_fiq_read(t, UART_LSR);
66         if (lsr & UART_LSR_BI)
67                 t->break_seen = true;
68
69         return lsr;
70 }
71
72 static int debug_port_init(struct platform_device *pdev)
73 {
74         struct rk_fiq_debugger *t;
75         t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
76
77         if (rk_fiq_read(t, UART_LSR) & UART_LSR_DR)
78                 (void)rk_fiq_read(t, UART_RX);
79         /* enable rx and lsr interrupt */
80         rk_fiq_write(t, UART_IER_RLSI | UART_IER_RDI, UART_IER);
81         /* interrupt on every character when receive,but we can enable fifo for TX
82         I found that if we enable the RX fifo, some problem may vanish such as when
83         you continuously input characters in the command line the uart irq may be disable
84         because of the uart irq is served when CPU is at IRQ exception,but it is
85         found unregistered, so it is disable.
86         hhb@rock-chips.com */
87         rk_fiq_write(t, 0xc1, UART_FCR);
88
89         return 0;
90 }
91
92 static int debug_getc(struct platform_device *pdev)
93 {
94         unsigned int lsr;
95         struct rk_fiq_debugger *t;
96         t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
97
98         lsr = rk_fiq_read_lsr(t);
99
100         if (lsr & UART_LSR_BI || t->break_seen) {
101                 t->break_seen = false;
102                 return FIQ_DEBUGGER_BREAK;
103         }
104
105         if (lsr & UART_LSR_DR)
106                 return rk_fiq_read(t, UART_RX);
107
108         return FIQ_DEBUGGER_NO_CHAR;
109 }
110
111 static void debug_putc(struct platform_device *pdev, unsigned int c)
112 {
113         struct rk_fiq_debugger *t;
114         t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
115
116 //      while (!(rk_fiq_read_lsr(t) & UART_LSR_THRE))
117 //              cpu_relax();
118         //enable TX FIFO
119         while (!(rk_fiq_read(t, 0x1F) & 0x02))
120                 cpu_relax();
121         rk_fiq_write(t, c, UART_TX);
122 }
123
124 static void debug_flush(struct platform_device *pdev)
125 {
126         struct rk_fiq_debugger *t;
127         t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
128
129         while (!(rk_fiq_read_lsr(t) & UART_LSR_TEMT))
130                 cpu_relax();
131 }
132
133 #ifdef CONFIG_RK_CONSOLE_THREAD
134 static DEFINE_KFIFO(fifo, unsigned char, SZ_64K);
135
136 static int console_thread(void *data)
137 {
138         struct platform_device *pdev = data;
139         struct rk_fiq_debugger *t;
140         unsigned char c;
141         t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
142
143         while (1) {
144                 set_current_state(TASK_INTERRUPTIBLE);
145                 schedule();
146                 if (kthread_should_stop())
147                         break;
148                 set_current_state(TASK_RUNNING);
149                 while (kfifo_get(&fifo, &c))
150                         debug_putc(pdev, c);
151                 debug_flush(pdev);
152         }
153
154         return 0;
155 }
156
157 static void console_write(struct platform_device *pdev, const char *s, unsigned int count)
158 {
159         unsigned char c, r = '\r';
160         static bool oops = false;
161         struct rk_fiq_debugger *t;
162         t = container_of(dev_get_platdata(&pdev->dev), typeof(*t), pdata);
163
164         if (oops_in_progress || oops) {
165                 debug_flush(pdev);
166                 while (kfifo_get(&fifo, &c))
167                         debug_putc(pdev, c);
168                 while (count--) {
169                         if (*s == '\n') {
170                                 debug_putc(pdev, r);
171                         }
172                         debug_putc(pdev, *s++);
173                 }
174                 debug_flush(pdev);
175                 oops = true;
176                 return;
177         }
178
179         while (count--) {
180                 if (*s == '\n') {
181                         kfifo_put(&fifo, &r);
182                 }
183                 kfifo_put(&fifo, s++);
184         }
185         wake_up_process(t->console_task);
186 }
187 #endif
188
189
190 static void fiq_enable(struct platform_device *pdev, unsigned int irq, bool on)
191 {
192         if (on)
193                 enable_irq(irq);
194         else
195                 disable_irq(irq);
196 }
197
198 static int rk_fiq_debugger_id;
199
200 void rk_serial_debug_init(void __iomem *base, int irq, int signal_irq, int wakeup_irq)
201 {
202         struct rk_fiq_debugger *t = NULL;
203         struct platform_device *pdev = NULL;
204         struct resource *res = NULL;
205         int res_count = 0;
206
207         if (!base) {
208                 pr_err("Invalid fiq debugger uart base\n");
209                 return;
210         }
211
212         t = kzalloc(sizeof(struct rk_fiq_debugger), GFP_KERNEL);
213         if (!t) {
214                 pr_err("Failed to allocate for fiq debugger\n");
215                 return;
216         }
217
218         t->pdata.uart_init = debug_port_init;
219         t->pdata.uart_getc = debug_getc;
220         t->pdata.uart_putc = debug_putc;
221 #ifndef CONFIG_RK_CONSOLE_THREAD
222         t->pdata.uart_flush = debug_flush;
223 #endif
224         t->pdata.fiq_enable = fiq_enable;
225         t->pdata.force_irq = NULL;  //force_irq;
226         t->debug_port_base = base;
227
228         res = kzalloc(sizeof(struct resource) * 3, GFP_KERNEL);
229         if (!res) {
230                 pr_err("Failed to alloc fiq debugger resources\n");
231                 goto out2;
232         }
233
234         pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL);
235         if (!pdev) {
236                 pr_err("Failed to alloc fiq debugger platform device\n");
237                 goto out3;
238         };
239
240         if (irq > 0) {
241                 res[0].flags = IORESOURCE_IRQ;
242                 res[0].start = irq;
243                 res[0].end = irq;
244                 res[0].name = "fiq";
245                 res_count++;
246         }
247
248         if (signal_irq > 0) {
249                 res[1].flags = IORESOURCE_IRQ;
250                 res[1].start = signal_irq;
251                 res[1].end = signal_irq;
252                 res[1].name = "signal";
253                 res_count++;
254         }
255
256         if (wakeup_irq > 0) {
257                 res[2].flags = IORESOURCE_IRQ;
258                 res[2].start = wakeup_irq;
259                 res[2].end = wakeup_irq;
260                 res[2].name = "wakeup";
261                 res_count++;
262         }
263
264 #ifdef CONFIG_RK_CONSOLE_THREAD
265         t->console_task = kthread_create(console_thread, pdev, "kconsole");
266         if (!IS_ERR(t->console_task)) {
267                 struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
268                 t->pdata.console_write = console_write;
269                 sched_setscheduler_nocheck(t->console_task, SCHED_FIFO, &param);
270         }
271 #endif
272
273         pdev->name = "fiq_debugger";
274         pdev->id = rk_fiq_debugger_id++;
275         pdev->dev.platform_data = &t->pdata;
276         pdev->resource = res;
277         pdev->num_resources = res_count;
278         if (platform_device_register(pdev)) {
279                 pr_err("Failed to register fiq debugger\n");
280                 goto out4;
281         }
282         return;
283
284 out4:
285         kfree(pdev);
286 out3:
287         kfree(res);
288 out2:
289         kfree(t);
290 }
291
292 static const struct of_device_id ids[] __initconst = {
293         { .compatible = "rockchip,fiq-debugger" },
294         {}
295 };
296
297 static int __init rk_fiq_debugger_init(void) {
298
299         void __iomem *base;
300         struct device_node *np;
301         unsigned int i, id, serial_id, ok = 0;
302         u32 irq, signal_irq = 0, wake_irq = 0;
303
304         np = of_find_matching_node(NULL, ids);
305
306         if (!np) {
307                 printk("fiq-debugger is missing in device tree!\n");
308                 return -ENODEV;
309         }
310
311         if (!of_device_is_available(np)) {
312                 printk("fiq-debugger is disabled in device tree\n");
313                 return -ENODEV;
314         }
315
316         if (of_property_read_u32(np, "rockchip,serial-id", &serial_id)) {
317                 return -EINVAL; 
318         }
319
320         if (of_property_read_u32(np, "rockchip,signal-irq", &signal_irq)) {
321                 signal_irq = -1;
322         }
323
324         if (of_property_read_u32(np, "rockchip,wake-irq", &wake_irq)) {
325                 wake_irq = -1;
326         }
327         
328         np = NULL;
329         for (i = 0; i < 5; i++) {
330                 np = of_find_node_by_name(np, "serial");
331                 if (np) {
332                         id = of_alias_get_id(np, "serial");
333                         if (id == serial_id) {
334                                 ok = 1;
335                                 break;
336                         }
337                 }
338         }
339         if (!ok)
340                 return -EINVAL;
341
342         irq = irq_of_parse_and_map(np, 0);
343         if (!irq)
344                 return -EINVAL;
345
346         base = of_iomap(np, 0);
347         if (base)
348                 rk_serial_debug_init(base, irq, signal_irq, wake_irq);
349
350         return 0;
351 }
352
353 postcore_initcall_sync(rk_fiq_debugger_init);