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