]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/boot/arm/ixp425/boot2/ixp425_board.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / boot / arm / ixp425 / boot2 / ixp425_board.c
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$");
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 *
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
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
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
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
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
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
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
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
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
185 xputchar(int ch)
186 {
187         if (ch == '\n')
188                 putchar('\r');
189         putchar(ch);
190 }
191
192 void
193 putstr(const char *str)
194 {
195         while(*str)
196                 xputchar(*str++);
197 }
198
199 void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
722 cambria_probe(int boardtype_hint)
723 {
724         return cpu_is_ixp43x();
725 }
726
727 static 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
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
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");