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