Commit 4729d77332a4383770c780b7709d5e14f12a4d1e
1 parent
421d085252
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
CRISv32: Implement early console
Signed-off-by: Jesper Nilsson <jesper.nilsson@axis.com>
Showing 1 changed file with 56 additions and 26 deletions Inline Diff
arch/cris/arch-v32/kernel/debugport.c
1 | /* | 1 | /* |
2 | * Copyright (C) 2003, Axis Communications AB. | 2 | * Copyright (C) 2003, Axis Communications AB. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #include <linux/console.h> | 5 | #include <linux/console.h> |
6 | #include <linux/kernel.h> | ||
6 | #include <linux/init.h> | 7 | #include <linux/init.h> |
8 | #include <linux/string.h> | ||
7 | #include <hwregs/reg_rdwr.h> | 9 | #include <hwregs/reg_rdwr.h> |
8 | #include <hwregs/reg_map.h> | 10 | #include <hwregs/reg_map.h> |
9 | #include <hwregs/ser_defs.h> | 11 | #include <hwregs/ser_defs.h> |
10 | #include <hwregs/dma_defs.h> | 12 | #include <hwregs/dma_defs.h> |
11 | #include <mach/pinmux.h> | 13 | #include <mach/pinmux.h> |
12 | 14 | ||
13 | struct dbg_port | 15 | struct dbg_port |
14 | { | 16 | { |
15 | unsigned char nbr; | 17 | unsigned char nbr; |
16 | unsigned long instance; | 18 | unsigned long instance; |
17 | unsigned int started; | 19 | unsigned int started; |
18 | unsigned long baudrate; | 20 | unsigned long baudrate; |
19 | unsigned char parity; | 21 | unsigned char parity; |
20 | unsigned int bits; | 22 | unsigned int bits; |
21 | }; | 23 | }; |
22 | 24 | ||
23 | struct dbg_port ports[] = | 25 | struct dbg_port ports[] = |
24 | { | 26 | { |
25 | { | 27 | { |
26 | 0, | 28 | 0, |
27 | regi_ser0, | 29 | regi_ser0, |
28 | 0, | 30 | 0, |
29 | 115200, | 31 | 115200, |
30 | 'N', | 32 | 'N', |
31 | 8 | 33 | 8 |
32 | }, | 34 | }, |
33 | { | 35 | { |
34 | 1, | 36 | 1, |
35 | regi_ser1, | 37 | regi_ser1, |
36 | 0, | 38 | 0, |
37 | 115200, | 39 | 115200, |
38 | 'N', | 40 | 'N', |
39 | 8 | 41 | 8 |
40 | }, | 42 | }, |
41 | { | 43 | { |
42 | 2, | 44 | 2, |
43 | regi_ser2, | 45 | regi_ser2, |
44 | 0, | 46 | 0, |
45 | 115200, | 47 | 115200, |
46 | 'N', | 48 | 'N', |
47 | 8 | 49 | 8 |
48 | }, | 50 | }, |
49 | { | 51 | { |
50 | 3, | 52 | 3, |
51 | regi_ser3, | 53 | regi_ser3, |
52 | 0, | 54 | 0, |
53 | 115200, | 55 | 115200, |
54 | 'N', | 56 | 'N', |
55 | 8 | 57 | 8 |
56 | }, | 58 | }, |
57 | #if CONFIG_ETRAX_SERIAL_PORTS == 5 | 59 | #if CONFIG_ETRAX_SERIAL_PORTS == 5 |
58 | { | 60 | { |
59 | 4, | 61 | 4, |
60 | regi_ser4, | 62 | regi_ser4, |
61 | 0, | 63 | 0, |
62 | 115200, | 64 | 115200, |
63 | 'N', | 65 | 'N', |
64 | 8 | 66 | 8 |
65 | }, | 67 | }, |
66 | #endif | 68 | #endif |
67 | }; | 69 | }; |
70 | |||
68 | static struct dbg_port *port = | 71 | static struct dbg_port *port = |
69 | #if defined(CONFIG_ETRAX_DEBUG_PORT0) | 72 | #if defined(CONFIG_ETRAX_DEBUG_PORT0) |
70 | &ports[0]; | 73 | &ports[0]; |
71 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) | 74 | #elif defined(CONFIG_ETRAX_DEBUG_PORT1) |
72 | &ports[1]; | 75 | &ports[1]; |
73 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) | 76 | #elif defined(CONFIG_ETRAX_DEBUG_PORT2) |
74 | &ports[2]; | 77 | &ports[2]; |
75 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) | 78 | #elif defined(CONFIG_ETRAX_DEBUG_PORT3) |
76 | &ports[3]; | 79 | &ports[3]; |
77 | #elif defined(CONFIG_ETRAX_DEBUG_PORT4) | 80 | #elif defined(CONFIG_ETRAX_DEBUG_PORT4) |
78 | &ports[4]; | 81 | &ports[4]; |
79 | #else | 82 | #else |
80 | NULL; | 83 | NULL; |
81 | #endif | 84 | #endif |
82 | 85 | ||
83 | #ifdef CONFIG_ETRAX_KGDB | 86 | #ifdef CONFIG_ETRAX_KGDB |
84 | static struct dbg_port *kgdb_port = | 87 | static struct dbg_port *kgdb_port = |
85 | #if defined(CONFIG_ETRAX_KGDB_PORT0) | 88 | #if defined(CONFIG_ETRAX_KGDB_PORT0) |
86 | &ports[0]; | 89 | &ports[0]; |
87 | #elif defined(CONFIG_ETRAX_KGDB_PORT1) | 90 | #elif defined(CONFIG_ETRAX_KGDB_PORT1) |
88 | &ports[1]; | 91 | &ports[1]; |
89 | #elif defined(CONFIG_ETRAX_KGDB_PORT2) | 92 | #elif defined(CONFIG_ETRAX_KGDB_PORT2) |
90 | &ports[2]; | 93 | &ports[2]; |
91 | #elif defined(CONFIG_ETRAX_KGDB_PORT3) | 94 | #elif defined(CONFIG_ETRAX_KGDB_PORT3) |
92 | &ports[3]; | 95 | &ports[3]; |
93 | #elif defined(CONFIG_ETRAX_KGDB_PORT4) | 96 | #elif defined(CONFIG_ETRAX_KGDB_PORT4) |
94 | &ports[4]; | 97 | &ports[4]; |
95 | #else | 98 | #else |
96 | NULL; | 99 | NULL; |
97 | #endif | 100 | #endif |
98 | #endif | 101 | #endif |
99 | 102 | ||
100 | static void | 103 | static void start_port(struct dbg_port *p) |
101 | start_port(struct dbg_port* p) | ||
102 | { | 104 | { |
103 | if (!p) | 105 | /* Set up serial port registers */ |
104 | return; | 106 | reg_ser_rw_tr_ctrl tr_ctrl = {0}; |
107 | reg_ser_rw_tr_dma_en tr_dma_en = {0}; | ||
105 | 108 | ||
106 | if (p->started) | 109 | reg_ser_rw_rec_ctrl rec_ctrl = {0}; |
110 | reg_ser_rw_tr_baud_div tr_baud_div = {0}; | ||
111 | reg_ser_rw_rec_baud_div rec_baud_div = {0}; | ||
112 | |||
113 | if (!p || p->started) | ||
107 | return; | 114 | return; |
115 | |||
108 | p->started = 1; | 116 | p->started = 1; |
109 | 117 | ||
110 | if (p->nbr == 1) | 118 | if (p->nbr == 1) |
111 | crisv32_pinmux_alloc_fixed(pinmux_ser1); | 119 | crisv32_pinmux_alloc_fixed(pinmux_ser1); |
112 | else if (p->nbr == 2) | 120 | else if (p->nbr == 2) |
113 | crisv32_pinmux_alloc_fixed(pinmux_ser2); | 121 | crisv32_pinmux_alloc_fixed(pinmux_ser2); |
114 | else if (p->nbr == 3) | 122 | else if (p->nbr == 3) |
115 | crisv32_pinmux_alloc_fixed(pinmux_ser3); | 123 | crisv32_pinmux_alloc_fixed(pinmux_ser3); |
116 | #if CONFIG_ETRAX_SERIAL_PORTS == 5 | 124 | #if CONFIG_ETRAX_SERIAL_PORTS == 5 |
117 | else if (p->nbr == 4) | 125 | else if (p->nbr == 4) |
118 | crisv32_pinmux_alloc_fixed(pinmux_ser4); | 126 | crisv32_pinmux_alloc_fixed(pinmux_ser4); |
119 | #endif | 127 | #endif |
120 | 128 | ||
121 | /* Set up serial port registers */ | ||
122 | reg_ser_rw_tr_ctrl tr_ctrl = {0}; | ||
123 | reg_ser_rw_tr_dma_en tr_dma_en = {0}; | ||
124 | |||
125 | reg_ser_rw_rec_ctrl rec_ctrl = {0}; | ||
126 | reg_ser_rw_tr_baud_div tr_baud_div = {0}; | ||
127 | reg_ser_rw_rec_baud_div rec_baud_div = {0}; | ||
128 | |||
129 | tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493; | 129 | tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493; |
130 | tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no; | 130 | tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no; |
131 | tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8; | 131 | tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8; |
132 | tr_ctrl.en = rec_ctrl.en = 1; | 132 | tr_ctrl.en = rec_ctrl.en = 1; |
133 | 133 | ||
134 | if (p->parity == 'O') | 134 | if (p->parity == 'O') { |
135 | { | ||
136 | tr_ctrl.par_en = regk_ser_yes; | 135 | tr_ctrl.par_en = regk_ser_yes; |
137 | tr_ctrl.par = regk_ser_odd; | 136 | tr_ctrl.par = regk_ser_odd; |
138 | rec_ctrl.par_en = regk_ser_yes; | 137 | rec_ctrl.par_en = regk_ser_yes; |
139 | rec_ctrl.par = regk_ser_odd; | 138 | rec_ctrl.par = regk_ser_odd; |
140 | } | 139 | } else if (p->parity == 'E') { |
141 | else if (p->parity == 'E') | ||
142 | { | ||
143 | tr_ctrl.par_en = regk_ser_yes; | 140 | tr_ctrl.par_en = regk_ser_yes; |
144 | tr_ctrl.par = regk_ser_even; | 141 | tr_ctrl.par = regk_ser_even; |
145 | rec_ctrl.par_en = regk_ser_yes; | 142 | rec_ctrl.par_en = regk_ser_yes; |
146 | rec_ctrl.par = regk_ser_odd; | 143 | rec_ctrl.par = regk_ser_odd; |
147 | } | 144 | } |
148 | 145 | ||
149 | if (p->bits == 7) | 146 | if (p->bits == 7) { |
150 | { | ||
151 | tr_ctrl.data_bits = regk_ser_bits7; | 147 | tr_ctrl.data_bits = regk_ser_bits7; |
152 | rec_ctrl.data_bits = regk_ser_bits7; | 148 | rec_ctrl.data_bits = regk_ser_bits7; |
153 | } | 149 | } |
154 | 150 | ||
155 | REG_WR (ser, p->instance, rw_tr_baud_div, tr_baud_div); | 151 | REG_WR (ser, p->instance, rw_tr_baud_div, tr_baud_div); |
156 | REG_WR (ser, p->instance, rw_rec_baud_div, rec_baud_div); | 152 | REG_WR (ser, p->instance, rw_rec_baud_div, rec_baud_div); |
157 | REG_WR (ser, p->instance, rw_tr_dma_en, tr_dma_en); | 153 | REG_WR (ser, p->instance, rw_tr_dma_en, tr_dma_en); |
158 | REG_WR (ser, p->instance, rw_tr_ctrl, tr_ctrl); | 154 | REG_WR (ser, p->instance, rw_tr_ctrl, tr_ctrl); |
159 | REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl); | 155 | REG_WR (ser, p->instance, rw_rec_ctrl, rec_ctrl); |
160 | } | 156 | } |
161 | 157 | ||
162 | #ifdef CONFIG_ETRAX_KGDB | 158 | #ifdef CONFIG_ETRAX_KGDB |
163 | /* Use polling to get a single character from the kernel debug port */ | 159 | /* Use polling to get a single character from the kernel debug port */ |
164 | int | 160 | int getDebugChar(void) |
165 | getDebugChar(void) | ||
166 | { | 161 | { |
167 | reg_ser_rs_stat_din stat; | 162 | reg_ser_rs_stat_din stat; |
168 | reg_ser_rw_ack_intr ack_intr = { 0 }; | 163 | reg_ser_rw_ack_intr ack_intr = { 0 }; |
169 | 164 | ||
170 | do { | 165 | do { |
171 | stat = REG_RD(ser, kgdb_port->instance, rs_stat_din); | 166 | stat = REG_RD(ser, kgdb_port->instance, rs_stat_din); |
172 | } while (!stat.dav); | 167 | } while (!stat.dav); |
173 | 168 | ||
174 | /* Ack the data_avail interrupt. */ | 169 | /* Ack the data_avail interrupt. */ |
175 | ack_intr.dav = 1; | 170 | ack_intr.dav = 1; |
176 | REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr); | 171 | REG_WR(ser, kgdb_port->instance, rw_ack_intr, ack_intr); |
177 | 172 | ||
178 | return stat.data; | 173 | return stat.data; |
179 | } | 174 | } |
180 | 175 | ||
181 | /* Use polling to put a single character to the kernel debug port */ | 176 | /* Use polling to put a single character to the kernel debug port */ |
182 | void | 177 | void putDebugChar(int val) |
183 | putDebugChar(int val) | ||
184 | { | 178 | { |
185 | reg_ser_r_stat_din stat; | 179 | reg_ser_r_stat_din stat; |
186 | do { | 180 | do { |
187 | stat = REG_RD(ser, kgdb_port->instance, r_stat_din); | 181 | stat = REG_RD(ser, kgdb_port->instance, r_stat_din); |
188 | } while (!stat.tr_rdy); | 182 | } while (!stat.tr_rdy); |
189 | REG_WR_INT(ser, kgdb_port->instance, rw_dout, val); | 183 | REG_WR_INT(ser, kgdb_port->instance, rw_dout, val); |
190 | } | 184 | } |
191 | #endif /* CONFIG_ETRAX_KGDB */ | 185 | #endif /* CONFIG_ETRAX_KGDB */ |
192 | 186 | ||
187 | static void __init early_putch(int c) | ||
188 | { | ||
189 | reg_ser_r_stat_din stat; | ||
190 | /* Wait until transmitter is ready and send. */ | ||
191 | do | ||
192 | stat = REG_RD(ser, port->instance, r_stat_din); | ||
193 | while (!stat.tr_rdy); | ||
194 | REG_WR_INT(ser, port->instance, rw_dout, c); | ||
195 | } | ||
196 | |||
197 | static void __init | ||
198 | early_console_write(struct console *con, const char *s, unsigned n) | ||
199 | { | ||
200 | extern void reset_watchdog(void); | ||
201 | int i; | ||
202 | |||
203 | /* Send data. */ | ||
204 | for (i = 0; i < n; i++) { | ||
205 | /* TODO: the '\n' -> '\n\r' translation should be done at the | ||
206 | receiver. Remove it when the serial driver removes it. */ | ||
207 | if (s[i] == '\n') | ||
208 | early_putch('\r'); | ||
209 | early_putch(s[i]); | ||
210 | reset_watchdog(); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static struct console early_console_dev __initdata = { | ||
215 | .name = "early", | ||
216 | .write = early_console_write, | ||
217 | .flags = CON_PRINTBUFFER | CON_BOOT, | ||
218 | .index = -1 | ||
219 | }; |