1 /*-
2 * Copyright (c) 2008 John Hay. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD: stable/9/sys/boot/arm/ixp425/boot2/ixp425_board.c 215034 2010-11-09 10:59:09Z brucec $");
28 #include <sys/param.h>
29 #include <sys/ata.h>
30 #include <sys/linker_set.h>
31
32 #include <stdarg.h>
33
34 #include "lib.h"
35 #include "cf_ata.h"
36
37 #include <machine/armreg.h>
38 #include <arm/xscale/ixp425/ixp425reg.h>
39 #include <dev/ic/ns16550.h>
40
41 struct board_config {
42 const char *desc;
43 int (*probe)(int boardtype_hint);
44 void (*init)(void);
45 };
46 /* set of registered boards */
47 SET_DECLARE(boards, struct board_config);
48 #define BOARD_CONFIG(name, _desc) \
49 static struct board_config name##config = { \
50 .desc = _desc, \
51 .probe = name##_probe, \
52 .init = name##_init, \
53 }; \
54 DATA_SET(boards, name##config)
55
56 static u_int cputype;
57 #define cpu_is_ixp43x() (cputype == CPU_ID_IXP435)
58 static u_int8_t *ubase;
59
60 static u_int8_t uart_getreg(u_int8_t *, int);
61 static void uart_setreg(u_int8_t *, int, u_int8_t);
62
63 static void cf_init(void);
64 static void cf_clr(void);
65
66 #ifdef DEBUG
67 #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
68 #else
69 #define DPRINTF(fmt, ...)
70 #endif
71
72 const char *
board_init(void)73 board_init(void)
74 {
75 struct board_config **pbp;
76
77 cputype = cpu_id() & CPU_ID_CPU_MASK;
78
79 SET_FOREACH(pbp, boards)
80 /* XXX pass down redboot board type */
81 if ((*pbp)->probe(0)) {
82 (*pbp)->init();
83 return (*pbp)->desc;
84 }
85 /* XXX panic, unknown board type */
86 return "???";
87 }
88
89 /*
90 * This should be called just before starting the kernel. This is so
91 * that one can undo incompatible hardware settings.
92 */
93 void
clr_board(void)94 clr_board(void)
95 {
96 cf_clr();
97 }
98
99 /*
100 * General support functions.
101 */
102
103 /*
104 * DELAY should delay for the number of microseconds.
105 * The idea is that the inner loop should take 1us, so val is the
106 * number of usecs to delay.
107 */
108 void
DELAY(int val)109 DELAY(int val)
110 {
111 volatile int sub;
112 volatile int subsub;
113
114 sub = val;
115 while(sub) {
116 subsub = 3;
117 while(subsub)
118 subsub--;
119 sub--;
120 }
121 }
122
123 u_int32_t
swap32(u_int32_t a)124 swap32(u_int32_t a)
125 {
126 return (((a & 0xff) << 24) | ((a & 0xff00) << 8) |
127 ((a & 0xff0000) >> 8) | ((a & 0xff000000) >> 24));
128 }
129
130 u_int16_t
swap16(u_int16_t val)131 swap16(u_int16_t val)
132 {
133 return (val << 8) | (val >> 8);
134 }
135
136 /*
137 * uart related funcs
138 */
139 static u_int8_t
uart_getreg(u_int8_t * bas,int off)140 uart_getreg(u_int8_t *bas, int off)
141 {
142 return *((volatile u_int32_t *)(bas + (off << 2))) & 0xff;
143 }
144
145 static void
uart_setreg(u_int8_t * bas,int off,u_int8_t val)146 uart_setreg(u_int8_t *bas, int off, u_int8_t val)
147 {
148 *((volatile u_int32_t *)(bas + (off << 2))) = (u_int32_t)val;
149 }
150
151 int
getc(int seconds)152 getc(int seconds)
153 {
154 int c, delay, limit;
155
156 c = 0;
157 delay = 10000;
158 limit = seconds * 1000000/10000;
159 while ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == 0 && --limit)
160 DELAY(delay);
161
162 if ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == LSR_RXRDY)
163 c = uart_getreg(ubase, REG_DATA);
164
165 return c;
166 }
167
168 void
putchar(int ch)169 putchar(int ch)
170 {
171 int delay, limit;
172
173 delay = 500;
174 limit = 20;
175 while ((uart_getreg(ubase, REG_LSR) & LSR_THRE) == 0 && --limit)
176 DELAY(delay);
177 uart_setreg(ubase, REG_DATA, ch);
178
179 limit = 40;
180 while ((uart_getreg(ubase, REG_LSR) & LSR_TEMT) == 0 && --limit)
181 DELAY(delay);
182 }
183
184 void
xputchar(int ch)185 xputchar(int ch)
186 {
187 if (ch == '\n')
188 putchar('\r');
189 putchar(ch);
190 }
191
192 void
putstr(const char * str)193 putstr(const char *str)
194 {
195 while(*str)
196 xputchar(*str++);
197 }
198
199 void
puthex8(u_int8_t ch)200 puthex8(u_int8_t ch)
201 {
202 const char *hex = "0123456789abcdef";
203
204 putchar(hex[ch >> 4]);
205 putchar(hex[ch & 0xf]);
206 }
207
208 void
puthexlist(const u_int8_t * str,int length)209 puthexlist(const u_int8_t *str, int length)
210 {
211 while(length) {
212 puthex8(*str);
213 putchar(' ');
214 str++;
215 length--;
216 }
217 }
218
219 /*
220 *
221 * CF/IDE functions.
222 *
223 */
224
225 struct {
226 u_int64_t dsize;
227 u_int64_t total_secs;
228 u_int8_t heads;
229 u_int8_t sectors;
230 u_int32_t cylinders;
231
232 u_int32_t *cs1to;
233 u_int32_t *cs2to;
234
235 u_int8_t *cs1;
236 u_int8_t *cs2;
237
238 u_int32_t use_lba;
239 u_int32_t use_stream8;
240 u_int32_t debug;
241
242 u_int8_t status;
243 u_int8_t error;
244 } dskinf;
245
246 static void cfenable16(void);
247 static void cfdisable16(void);
248 static u_int8_t cfread8(u_int32_t off);
249 static u_int16_t cfread16(u_int32_t off);
250 static void cfreadstream8(void *buf, int length);
251 static void cfreadstream16(void *buf, int length);
252 static void cfwrite8(u_int32_t off, u_int8_t val);
253 static u_int8_t cfaltread8(u_int32_t off);
254 static void cfaltwrite8(u_int32_t off, u_int8_t val);
255 static int cfwait(u_int8_t mask);
256 static int cfaltwait(u_int8_t mask);
257 static int cfcmd(u_int32_t cmd, u_int32_t cylinder, u_int32_t head,
258 u_int32_t sector, u_int32_t count, u_int32_t feature);
259 static void cfreset(void);
260 #ifdef DEBUG
261 static int cfgetparams(void);
262 #endif
263 static void cfprintregs(void);
264
265 static void
cf_init(void)266 cf_init(void)
267 {
268 u_int8_t status;
269 #ifdef DEBUG
270 int rval;
271 #endif
272
273 /* NB: board init routines setup other parts of dskinf */
274 dskinf.use_stream8 = 0;
275 dskinf.use_lba = 0;
276 dskinf.debug = 1;
277
278 DPRINTF("cs1 %x, cs2 %x\n", dskinf.cs1, dskinf.cs2);
279
280 /* Setup the CF window */
281 *dskinf.cs1to |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
282 DPRINTF("t1 %x, ", *dskinf.cs1to);
283
284 *dskinf.cs2to |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
285 DPRINTF("t2 %x\n", *dskinf.cs2to);
286
287 /* Detect if there is a disk. */
288 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
289 DELAY(1000);
290 status = cfread8(CF_STATUS);
291 if (status != 0x50)
292 printf("cf-ata0 %x\n", (u_int32_t)status);
293 if (status == 0xff) {
294 printf("cf_ata0: No disk!\n");
295 return;
296 }
297
298 cfreset();
299
300 if (dskinf.use_stream8) {
301 DPRINTF("setting %d bit mode.\n", 8);
302 cfwrite8(CF_FEATURE, 0x01); /* Enable 8 bit transfers */
303 cfwrite8(CF_COMMAND, ATA_SETFEATURES);
304 cfaltwait(CF_S_READY);
305 }
306
307 #ifdef DEBUG
308 rval = cfgetparams();
309 if (rval)
310 return;
311 #endif
312 dskinf.use_lba = 1;
313 dskinf.debug = 0;
314 }
315
316 static void
cf_clr(void)317 cf_clr(void)
318 {
319 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
320 cfaltwait(CF_S_READY);
321 cfwrite8(CF_FEATURE, 0x81); /* Enable 8 bit transfers */
322 cfwrite8(CF_COMMAND, ATA_SETFEATURES);
323 cfaltwait(CF_S_READY);
324 }
325
326 static void
cfenable16(void)327 cfenable16(void)
328 {
329 u_int32_t val;
330
331 val = *dskinf.cs1to;
332 *dskinf.cs1to = val &~ EXP_BYTE_EN;
333 DELAY(100);
334 #if 0
335 DPRINTF("%s: cs1 timing reg %x\n", *dskinf.cs1to, __func__);
336 #endif
337 }
338
339 static void
cfdisable16(void)340 cfdisable16(void)
341 {
342 u_int32_t val;
343
344 DELAY(100);
345 val = *dskinf.cs1to;
346 *dskinf.cs1to = val | EXP_BYTE_EN;
347 #if 0
348 DPRINTF("%s: cs1 timing reg %x\n", *dskinf.cs1to, __func__);
349 #endif
350 }
351
352 static u_int8_t
cfread8(u_int32_t off)353 cfread8(u_int32_t off)
354 {
355 volatile u_int8_t *vp;
356
357 vp = (volatile u_int8_t *)(dskinf.cs1 + off);
358 return *vp;
359 }
360
361 static void
cfreadstream8(void * buf,int length)362 cfreadstream8(void *buf, int length)
363 {
364 u_int8_t *lbuf;
365 u_int8_t tmp;
366
367 lbuf = buf;
368 while (length) {
369 tmp = cfread8(CF_DATA);
370 *lbuf = tmp;
371 #ifdef DEBUG
372 if (dskinf.debug && (length > (512 - 32))) {
373 if ((length % 16) == 0)
374 xputchar('\n');
375 puthex8(tmp);
376 putchar(' ');
377 }
378 #endif
379 lbuf++;
380 length--;
381 }
382 #ifdef DEBUG
383 if (dskinf.debug)
384 xputchar('\n');
385 #endif
386 }
387
388 static u_int16_t
cfread16(u_int32_t off)389 cfread16(u_int32_t off)
390 {
391 volatile u_int16_t *vp;
392
393 vp = (volatile u_int16_t *)(dskinf.cs1 + off);
394 return swap16(*vp);
395 }
396
397 static void
cfreadstream16(void * buf,int length)398 cfreadstream16(void *buf, int length)
399 {
400 u_int16_t *lbuf;
401
402 length = length / 2;
403 cfenable16();
404 lbuf = buf;
405 while (length--) {
406 *lbuf = cfread16(CF_DATA);
407 lbuf++;
408 }
409 cfdisable16();
410 }
411
412 static void
cfwrite8(u_int32_t off,u_int8_t val)413 cfwrite8(u_int32_t off, u_int8_t val)
414 {
415 volatile u_int8_t *vp;
416
417 vp = (volatile u_int8_t *)(dskinf.cs1 + off);
418 *vp = val;
419 }
420
421 #if 0
422 static void
423 cfwrite16(u_int32_t off, u_int16_t val)
424 {
425 volatile u_int16_t *vp;
426
427 vp = (volatile u_int16_t *)(dskinf.cs1 + off);
428 *vp = val;
429 }
430 #endif
431
432 static u_int8_t
cfaltread8(u_int32_t off)433 cfaltread8(u_int32_t off)
434 {
435 volatile u_int8_t *vp;
436
437 off &= 0x0f;
438 vp = (volatile u_int8_t *)(dskinf.cs2 + off);
439 return *vp;
440 }
441
442 static void
cfaltwrite8(u_int32_t off,u_int8_t val)443 cfaltwrite8(u_int32_t off, u_int8_t val)
444 {
445 volatile u_int8_t *vp;
446
447 /*
448 * This is documented in the Intel appnote 302456.
449 */
450 off &= 0x0f;
451 vp = (volatile u_int8_t *)(dskinf.cs2 + off);
452 *vp = val;
453 }
454
455 static int
cfwait(u_int8_t mask)456 cfwait(u_int8_t mask)
457 {
458 u_int8_t status;
459 u_int32_t tout;
460
461 tout = 0;
462 while (tout <= 5000000) {
463 status = cfread8(CF_STATUS);
464 if (status == 0xff) {
465 printf("%s: master: no status, reselecting\n",
466 __func__);
467 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
468 DELAY(1);
469 status = cfread8(CF_STATUS);
470 }
471 if (status == 0xff)
472 return -1;
473 dskinf.status = status;
474 if (!(status & CF_S_BUSY)) {
475 if (status & CF_S_ERROR) {
476 dskinf.error = cfread8(CF_ERROR);
477 printf("%s: error, status 0x%x error 0x%x\n",
478 __func__, status, dskinf.error);
479 }
480 if ((status & mask) == mask) {
481 DPRINTF("%s: status 0x%x mask 0x%x tout %u\n",
482 __func__, status, mask, tout);
483 return (status & CF_S_ERROR);
484 }
485 }
486 if (tout > 1000) {
487 tout += 1000;
488 DELAY(1000);
489 } else {
490 tout += 10;
491 DELAY(10);
492 }
493 }
494 return -1;
495 }
496
497 static int
cfaltwait(u_int8_t mask)498 cfaltwait(u_int8_t mask)
499 {
500 u_int8_t status;
501 u_int32_t tout;
502
503 tout = 0;
504 while (tout <= 5000000) {
505 status = cfaltread8(CF_ALT_STATUS);
506 if (status == 0xff) {
507 printf("cfaltwait: master: no status, reselecting\n");
508 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
509 DELAY(1);
510 status = cfread8(CF_STATUS);
511 }
512 if (status == 0xff)
513 return -1;
514 dskinf.status = status;
515 if (!(status & CF_S_BUSY)) {
516 if (status & CF_S_ERROR)
517 dskinf.error = cfread8(CF_ERROR);
518 if ((status & mask) == mask) {
519 DPRINTF("cfaltwait: tout %u\n", tout);
520 return (status & CF_S_ERROR);
521 }
522 }
523 if (tout > 1000) {
524 tout += 1000;
525 DELAY(1000);
526 } else {
527 tout += 10;
528 DELAY(10);
529 }
530 }
531 return -1;
532 }
533
534 static int
cfcmd(u_int32_t cmd,u_int32_t cylinder,u_int32_t head,u_int32_t sector,u_int32_t count,u_int32_t feature)535 cfcmd(u_int32_t cmd, u_int32_t cylinder, u_int32_t head, u_int32_t sector,
536 u_int32_t count, u_int32_t feature)
537 {
538 if (cfwait(0) < 0) {
539 printf("cfcmd: timeout\n");
540 return -1;
541 }
542 cfwrite8(CF_FEATURE, feature);
543 cfwrite8(CF_CYL_L, cylinder);
544 cfwrite8(CF_CYL_H, cylinder >> 8);
545 if (dskinf.use_lba)
546 cfwrite8(CF_DRV_HEAD, CF_D_IBM | CF_D_LBA | head);
547 else
548 cfwrite8(CF_DRV_HEAD, CF_D_IBM | head);
549 cfwrite8(CF_SECT_NUM, sector);
550 cfwrite8(CF_SECT_CNT, count);
551 cfwrite8(CF_COMMAND, cmd);
552 return 0;
553 }
554
555 static void
cfreset(void)556 cfreset(void)
557 {
558 u_int8_t status;
559 u_int32_t tout;
560
561 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
562 DELAY(1);
563 #ifdef DEBUG
564 cfprintregs();
565 #endif
566 cfread8(CF_STATUS);
567 cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS | CF_A_RESET);
568 DELAY(10000);
569 cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS);
570 DELAY(10000);
571 cfread8(CF_ERROR);
572 DELAY(3000);
573
574 for (tout = 0; tout < 310000; tout++) {
575 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
576 DELAY(1);
577 status = cfread8(CF_STATUS);
578 if (!(status & CF_S_BUSY))
579 break;
580 DELAY(100);
581 }
582 DELAY(1);
583 if (status & CF_S_BUSY) {
584 cfprintregs();
585 printf("cfreset: Status stayed busy after reset.\n");
586 }
587 DPRINTF("cfreset: finished, tout %u\n", tout);
588 }
589
590 #ifdef DEBUG
591 static int
cfgetparams(void)592 cfgetparams(void)
593 {
594 u_int8_t *buf;
595
596 buf = (u_int8_t *)(0x170000);
597 p_memset((char *)buf, 0, 1024);
598 /* Select the drive. */
599 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
600 DELAY(1);
601 cfcmd(ATA_ATA_IDENTIFY, 0, 0, 0, 0, 0);
602 if (cfaltwait(CF_S_READY | CF_S_DSC | CF_S_DRQ)) {
603 printf("cfgetparams: ATA_IDENTIFY failed.\n");
604 return -1;
605 }
606 if (dskinf.use_stream8)
607 cfreadstream8(buf, 512);
608 else
609 cfreadstream16(buf, 512);
610 if (dskinf.debug)
611 cfprintregs();
612 #if 0
613 memcpy(&dskinf.ata_params, buf, sizeof(struct ata_params));
614 dskinf.cylinders = dskinf.ata_params.cylinders;
615 dskinf.heads = dskinf.ata_params.heads;
616 dskinf.sectors = dskinf.ata_params.sectors;
617 printf("dsk0: sec %x, hd %x, cyl %x, stat %x, err %x\n",
618 (u_int32_t)dskinf.ata_params.sectors,
619 (u_int32_t)dskinf.ata_params.heads,
620 (u_int32_t)dskinf.ata_params.cylinders,
621 (u_int32_t)dskinf.status,
622 (u_int32_t)dskinf.error);
623 #endif
624 dskinf.status = cfread8(CF_STATUS);
625 if (dskinf.debug)
626 printf("cfgetparams: ata_params * %x, stat %x\n",
627 (u_int32_t)buf, (u_int32_t)dskinf.status);
628 return 0;
629 }
630 #endif /* DEBUG */
631
632 static void
cfprintregs(void)633 cfprintregs(void)
634 {
635 u_int8_t rv;
636
637 putstr("cfprintregs: regs error ");
638 rv = cfread8(CF_ERROR);
639 puthex8(rv);
640 putstr(", count ");
641 rv = cfread8(CF_SECT_CNT);
642 puthex8(rv);
643 putstr(", sect ");
644 rv = cfread8(CF_SECT_NUM);
645 puthex8(rv);
646 putstr(", cyl low ");
647 rv = cfread8(CF_CYL_L);
648 puthex8(rv);
649 putstr(", cyl high ");
650 rv = cfread8(CF_CYL_H);
651 puthex8(rv);
652 putstr(", drv head ");
653 rv = cfread8(CF_DRV_HEAD);
654 puthex8(rv);
655 putstr(", status ");
656 rv = cfread8(CF_STATUS);
657 puthex8(rv);
658 putstr("\n");
659 }
660
661 int
avila_read(char * dest,unsigned source,unsigned length)662 avila_read(char *dest, unsigned source, unsigned length)
663 {
664 if (dskinf.use_lba == 0 && source == 0)
665 source++;
666 if (dskinf.debug)
667 printf("avila_read: 0x%x, sect %d num secs %d\n",
668 (u_int32_t)dest, source, length);
669 while (length) {
670 cfwait(CF_S_READY);
671 /* cmd, cyl, head, sect, count, feature */
672 cfcmd(ATA_READ, (source >> 8) & 0xffff, source >> 24,
673 source & 0xff, 1, 0);
674
675 cfwait(CF_S_READY | CF_S_DRQ | CF_S_DSC);
676 if (dskinf.use_stream8)
677 cfreadstream8(dest, 512);
678 else
679 cfreadstream16(dest, 512);
680 length--;
681 source++;
682 dest += 512;
683 }
684 return 0;
685 }
686
687 /*
688 * Gateworks Avila Support.
689 */
690 static int
avila_probe(int boardtype_hint)691 avila_probe(int boardtype_hint)
692 {
693 volatile u_int32_t *cs;
694 /*
695 * Redboot only configure the chip selects that are needed, so
696 * use that to figure out if it is an Avila or ADI board. The
697 * Avila boards use CS2 and ADI does not.
698 */
699 cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
700 return (*cs != 0);
701 }
702
703 static void
avila_init(void)704 avila_init(void)
705 {
706 /* Config the serial port. RedBoot should do the rest. */
707 ubase = (u_int8_t *)(IXP425_UART0_HWBASE);
708
709 dskinf.cs1to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS1_OFFSET);
710 dskinf.cs2to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
711 dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS1_HWBASE;
712 dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS2_HWBASE;
713
714 cf_init();
715 }
716 BOARD_CONFIG(avila, "Gateworks Avila");
717
718 /*
719 * Gateworks Cambria Support.
720 */
721 static int
cambria_probe(int boardtype_hint)722 cambria_probe(int boardtype_hint)
723 {
724 return cpu_is_ixp43x();
725 }
726
727 static void
cambria_init(void)728 cambria_init(void)
729 {
730 /* Config the serial port. RedBoot should do the rest. */
731 ubase = (u_int8_t *)(IXP425_UART0_HWBASE);
732
733 dskinf.cs1to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
734 dskinf.cs2to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS4_OFFSET);
735 dskinf.cs1 = (u_int8_t *)CAMBRIA_CFSEL0_HWBASE;
736 dskinf.cs2 = (u_int8_t *)CAMBRIA_CFSEL1_HWBASE;
737
738 cf_init();
739 }
740 BOARD_CONFIG(cambria, "Gateworks Cambria");
741
742 /*
743 * Pronghorn Metro Support.
744 */
745 static int
pronghorn_probe(int boardtype_hint)746 pronghorn_probe(int boardtype_hint)
747 {
748 volatile u_int32_t *cs;
749 /*
750 * Redboot only configure the chip selects that are needed, so
751 * use that to figure out if it is an Avila or ADI board. The
752 * Avila boards use CS2 and ADI does not.
753 */
754 cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
755 return (*cs == 0);
756 }
757
758 static void
pronghorn_init(void)759 pronghorn_init(void)
760 {
761 /* Config the serial port. RedBoot should do the rest. */
762 ubase = (u_int8_t *)(IXP425_UART1_HWBASE);
763
764 dskinf.cs1to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS3_OFFSET);
765 dskinf.cs2to = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS4_OFFSET);
766 dskinf.cs1 = (u_int8_t *)IXP425_EXP_BUS_CS3_HWBASE;
767 dskinf.cs2 = (u_int8_t *)IXP425_EXP_BUS_CS4_HWBASE;
768
769 cf_init();
770 }
771 BOARD_CONFIG(pronghorn, "Pronghorn Metro");
772