diff options
Diffstat (limited to 'arch/powerpc/boot/cpm-serial.c')
-rw-r--r-- | arch/powerpc/boot/cpm-serial.c | 89 |
1 files changed, 68 insertions, 21 deletions
diff --git a/arch/powerpc/boot/cpm-serial.c b/arch/powerpc/boot/cpm-serial.c index 1f6225aad298..19dc15abe43d 100644 --- a/arch/powerpc/boot/cpm-serial.c +++ b/arch/powerpc/boot/cpm-serial.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include "types.h" | 11 | #include "types.h" |
12 | #include "io.h" | 12 | #include "io.h" |
13 | #include "ops.h" | 13 | #include "ops.h" |
14 | #include "page.h" | ||
14 | 15 | ||
15 | struct cpm_scc { | 16 | struct cpm_scc { |
16 | u32 gsmrl; | 17 | u32 gsmrl; |
@@ -42,6 +43,22 @@ struct cpm_param { | |||
42 | u16 tbase; | 43 | u16 tbase; |
43 | u8 rfcr; | 44 | u8 rfcr; |
44 | u8 tfcr; | 45 | u8 tfcr; |
46 | u16 mrblr; | ||
47 | u32 rstate; | ||
48 | u8 res1[4]; | ||
49 | u16 rbptr; | ||
50 | u8 res2[6]; | ||
51 | u32 tstate; | ||
52 | u8 res3[4]; | ||
53 | u16 tbptr; | ||
54 | u8 res4[6]; | ||
55 | u16 maxidl; | ||
56 | u16 idlc; | ||
57 | u16 brkln; | ||
58 | u16 brkec; | ||
59 | u16 brkcr; | ||
60 | u16 rmask; | ||
61 | u8 res5[4]; | ||
45 | }; | 62 | }; |
46 | 63 | ||
47 | struct cpm_bd { | 64 | struct cpm_bd { |
@@ -54,10 +71,10 @@ static void *cpcr; | |||
54 | static struct cpm_param *param; | 71 | static struct cpm_param *param; |
55 | static struct cpm_smc *smc; | 72 | static struct cpm_smc *smc; |
56 | static struct cpm_scc *scc; | 73 | static struct cpm_scc *scc; |
57 | struct cpm_bd *tbdf, *rbdf; | 74 | static struct cpm_bd *tbdf, *rbdf; |
58 | static u32 cpm_cmd; | 75 | static u32 cpm_cmd; |
59 | static u8 *muram_start; | 76 | static void *cbd_addr; |
60 | static u32 muram_offset; | 77 | static u32 cbd_offset; |
61 | 78 | ||
62 | static void (*do_cmd)(int op); | 79 | static void (*do_cmd)(int op); |
63 | static void (*enable_port)(void); | 80 | static void (*enable_port)(void); |
@@ -119,20 +136,25 @@ static int cpm_serial_open(void) | |||
119 | 136 | ||
120 | out_8(¶m->rfcr, 0x10); | 137 | out_8(¶m->rfcr, 0x10); |
121 | out_8(¶m->tfcr, 0x10); | 138 | out_8(¶m->tfcr, 0x10); |
122 | 139 | out_be16(¶m->mrblr, 1); | |
123 | rbdf = (struct cpm_bd *)muram_start; | 140 | out_be16(¶m->maxidl, 0); |
124 | rbdf->addr = (u8 *)(rbdf + 2); | 141 | out_be16(¶m->brkec, 0); |
142 | out_be16(¶m->brkln, 0); | ||
143 | out_be16(¶m->brkcr, 0); | ||
144 | |||
145 | rbdf = cbd_addr; | ||
146 | rbdf->addr = (u8 *)rbdf - 1; | ||
125 | rbdf->sc = 0xa000; | 147 | rbdf->sc = 0xa000; |
126 | rbdf->len = 1; | 148 | rbdf->len = 1; |
127 | 149 | ||
128 | tbdf = rbdf + 1; | 150 | tbdf = rbdf + 1; |
129 | tbdf->addr = (u8 *)(rbdf + 2) + 1; | 151 | tbdf->addr = (u8 *)rbdf - 2; |
130 | tbdf->sc = 0x2000; | 152 | tbdf->sc = 0x2000; |
131 | tbdf->len = 1; | 153 | tbdf->len = 1; |
132 | 154 | ||
133 | sync(); | 155 | sync(); |
134 | out_be16(¶m->rbase, muram_offset); | 156 | out_be16(¶m->rbase, cbd_offset); |
135 | out_be16(¶m->tbase, muram_offset + sizeof(struct cpm_bd)); | 157 | out_be16(¶m->tbase, cbd_offset + sizeof(struct cpm_bd)); |
136 | 158 | ||
137 | do_cmd(CPM_CMD_INIT_RX_TX); | 159 | do_cmd(CPM_CMD_INIT_RX_TX); |
138 | 160 | ||
@@ -175,9 +197,12 @@ static unsigned char cpm_serial_getc(void) | |||
175 | 197 | ||
176 | int cpm_console_init(void *devp, struct serial_console_data *scdp) | 198 | int cpm_console_init(void *devp, struct serial_console_data *scdp) |
177 | { | 199 | { |
178 | void *reg_virt[2]; | 200 | void *vreg[2]; |
179 | int is_smc = 0, is_cpm2 = 0, n; | 201 | u32 reg[2]; |
202 | int is_smc = 0, is_cpm2 = 0; | ||
180 | void *parent, *muram; | 203 | void *parent, *muram; |
204 | void *muram_addr; | ||
205 | unsigned long muram_offset, muram_size; | ||
181 | 206 | ||
182 | if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) { | 207 | if (dt_is_compatible(devp, "fsl,cpm1-smc-uart")) { |
183 | is_smc = 1; | 208 | is_smc = 1; |
@@ -201,19 +226,18 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp) | |||
201 | else | 226 | else |
202 | do_cmd = cpm1_cmd; | 227 | do_cmd = cpm1_cmd; |
203 | 228 | ||
204 | n = getprop(devp, "fsl,cpm-command", &cpm_cmd, 4); | 229 | if (getprop(devp, "fsl,cpm-command", &cpm_cmd, 4) < 4) |
205 | if (n < 4) | ||
206 | return -1; | 230 | return -1; |
207 | 231 | ||
208 | if (dt_get_virtual_reg(devp, reg_virt, 2) < 2) | 232 | if (dt_get_virtual_reg(devp, vreg, 2) < 2) |
209 | return -1; | 233 | return -1; |
210 | 234 | ||
211 | if (is_smc) | 235 | if (is_smc) |
212 | smc = reg_virt[0]; | 236 | smc = vreg[0]; |
213 | else | 237 | else |
214 | scc = reg_virt[0]; | 238 | scc = vreg[0]; |
215 | 239 | ||
216 | param = reg_virt[1]; | 240 | param = vreg[1]; |
217 | 241 | ||
218 | parent = get_parent(devp); | 242 | parent = get_parent(devp); |
219 | if (!parent) | 243 | if (!parent) |
@@ -227,17 +251,40 @@ int cpm_console_init(void *devp, struct serial_console_data *scdp) | |||
227 | return -1; | 251 | return -1; |
228 | 252 | ||
229 | /* For bootwrapper-compatible device trees, we assume that the first | 253 | /* For bootwrapper-compatible device trees, we assume that the first |
230 | * entry has at least 18 bytes, and that #address-cells/#data-cells | 254 | * entry has at least 128 bytes, and that #address-cells/#data-cells |
231 | * is one for both parent and child. | 255 | * is one for both parent and child. |
232 | */ | 256 | */ |
233 | 257 | ||
234 | if (dt_get_virtual_reg(muram, (void **)&muram_start, 1) < 1) | 258 | if (dt_get_virtual_reg(muram, &muram_addr, 1) < 1) |
235 | return -1; | 259 | return -1; |
236 | 260 | ||
237 | n = getprop(muram, "reg", &muram_offset, 4); | 261 | if (getprop(muram, "reg", reg, 8) < 8) |
238 | if (n < 4) | ||
239 | return -1; | 262 | return -1; |
240 | 263 | ||
264 | muram_offset = reg[0]; | ||
265 | muram_size = reg[1]; | ||
266 | |||
267 | /* Store the buffer descriptors at the end of the first muram chunk. | ||
268 | * For SMC ports on CPM2-based platforms, relocate the parameter RAM | ||
269 | * just before the buffer descriptors. | ||
270 | */ | ||
271 | |||
272 | cbd_offset = muram_offset + muram_size - 2 * sizeof(struct cpm_bd); | ||
273 | |||
274 | if (is_cpm2 && is_smc) { | ||
275 | u16 *smc_base = (u16 *)param; | ||
276 | u16 pram_offset; | ||
277 | |||
278 | pram_offset = cbd_offset - 64; | ||
279 | pram_offset = _ALIGN_DOWN(pram_offset, 64); | ||
280 | |||
281 | disable_port(); | ||
282 | out_be16(smc_base, pram_offset); | ||
283 | param = muram_addr - muram_offset + pram_offset; | ||
284 | } | ||
285 | |||
286 | cbd_addr = muram_addr - muram_offset + cbd_offset; | ||
287 | |||
241 | scdp->open = cpm_serial_open; | 288 | scdp->open = cpm_serial_open; |
242 | scdp->putc = cpm_serial_putc; | 289 | scdp->putc = cpm_serial_putc; |
243 | scdp->getc = cpm_serial_getc; | 290 | scdp->getc = cpm_serial_getc; |