2 * Copyright (c) 2008 John Hay. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 #include <sys/param.h>
30 #include <sys/linker_set.h>
37 #include <machine/armreg.h>
38 #include <arm/xscale/ixp425/ixp425reg.h>
39 #include <dev/ic/ns16550.h>
43 int (*probe)(int boardtype_hint);
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 = { \
51 .probe = name##_probe, \
52 .init = name##_init, \
54 DATA_SET(boards, name##config)
57 #define cpu_is_ixp43x() (cputype == CPU_ID_IXP435)
58 static u_int8_t *ubase;
60 static u_int8_t uart_getreg(u_int8_t *, int);
61 static void uart_setreg(u_int8_t *, int, u_int8_t);
63 static void cf_init(void);
64 static void cf_clr(void);
67 #define DPRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
69 #define DPRINTF(fmt, ...)
75 struct board_config **pbp;
77 cputype = cpu_id() & CPU_ID_CPU_MASK;
79 SET_FOREACH(pbp, boards)
80 /* XXX pass down redboot board type */
81 if ((*pbp)->probe(0)) {
85 /* XXX panic, unknown board type */
90 * This should be called just before starting the kernel. This is so
91 * that one can undo incompatible hardware settings.
100 * General support functions.
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.
126 return (((a & 0xff) << 24) | ((a & 0xff00) << 8) |
127 ((a & 0xff0000) >> 8) | ((a & 0xff000000) >> 24));
131 swap16(u_int16_t val)
133 return (val << 8) | (val >> 8);
140 uart_getreg(u_int8_t *bas, int off)
142 return *((volatile u_int32_t *)(bas + (off << 2))) & 0xff;
146 uart_setreg(u_int8_t *bas, int off, u_int8_t val)
148 *((volatile u_int32_t *)(bas + (off << 2))) = (u_int32_t)val;
158 limit = seconds * 1000000/10000;
159 while ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == 0 && --limit)
162 if ((uart_getreg(ubase, REG_LSR) & LSR_RXRDY) == LSR_RXRDY)
163 c = uart_getreg(ubase, REG_DATA);
175 while ((uart_getreg(ubase, REG_LSR) & LSR_THRE) == 0 && --limit)
177 uart_setreg(ubase, REG_DATA, ch);
180 while ((uart_getreg(ubase, REG_LSR) & LSR_TEMT) == 0 && --limit)
193 putstr(const char *str)
202 const char *hex = "0123456789abcdef";
204 putchar(hex[ch >> 4]);
205 putchar(hex[ch & 0xf]);
209 puthexlist(const u_int8_t *str, int length)
227 u_int64_t total_secs;
239 u_int32_t use_stream8;
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);
261 static int cfgetparams(void);
263 static void cfprintregs(void);
273 /* NB: board init routines setup other parts of dskinf */
274 dskinf.use_stream8 = 0;
278 DPRINTF("cs1 %x, cs2 %x\n", dskinf.cs1, dskinf.cs2);
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);
284 *dskinf.cs2to |= (EXP_BYTE_EN | EXP_WR_EN | EXP_BYTE_RD16 | EXP_CS_EN);
285 DPRINTF("t2 %x\n", *dskinf.cs2to);
287 /* Detect if there is a disk. */
288 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
290 status = cfread8(CF_STATUS);
292 printf("cf-ata0 %x\n", (u_int32_t)status);
293 if (status == 0xff) {
294 printf("cf_ata0: No disk!\n");
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);
308 rval = cfgetparams();
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);
332 *dskinf.cs1to = val &~ EXP_BYTE_EN;
335 DPRINTF("%s: cs1 timing reg %x\n", *dskinf.cs1to, __func__);
346 *dskinf.cs1to = val | EXP_BYTE_EN;
348 DPRINTF("%s: cs1 timing reg %x\n", *dskinf.cs1to, __func__);
353 cfread8(u_int32_t off)
355 volatile u_int8_t *vp;
357 vp = (volatile u_int8_t *)(dskinf.cs1 + off);
362 cfreadstream8(void *buf, int length)
369 tmp = cfread8(CF_DATA);
372 if (dskinf.debug && (length > (512 - 32))) {
373 if ((length % 16) == 0)
389 cfread16(u_int32_t off)
391 volatile u_int16_t *vp;
393 vp = (volatile u_int16_t *)(dskinf.cs1 + off);
398 cfreadstream16(void *buf, int length)
406 *lbuf = cfread16(CF_DATA);
413 cfwrite8(u_int32_t off, u_int8_t val)
415 volatile u_int8_t *vp;
417 vp = (volatile u_int8_t *)(dskinf.cs1 + off);
423 cfwrite16(u_int32_t off, u_int16_t val)
425 volatile u_int16_t *vp;
427 vp = (volatile u_int16_t *)(dskinf.cs1 + off);
433 cfaltread8(u_int32_t off)
435 volatile u_int8_t *vp;
438 vp = (volatile u_int8_t *)(dskinf.cs2 + off);
443 cfaltwrite8(u_int32_t off, u_int8_t val)
445 volatile u_int8_t *vp;
448 * This is documented in the Intel appnote 302456.
451 vp = (volatile u_int8_t *)(dskinf.cs2 + off);
456 cfwait(u_int8_t mask)
462 while (tout <= 5000000) {
463 status = cfread8(CF_STATUS);
464 if (status == 0xff) {
465 printf("%s: master: no status, reselecting\n",
467 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
469 status = cfread8(CF_STATUS);
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);
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);
498 cfaltwait(u_int8_t mask)
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);
510 status = cfread8(CF_STATUS);
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);
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)
539 printf("cfcmd: timeout\n");
542 cfwrite8(CF_FEATURE, feature);
543 cfwrite8(CF_CYL_L, cylinder);
544 cfwrite8(CF_CYL_H, cylinder >> 8);
546 cfwrite8(CF_DRV_HEAD, CF_D_IBM | CF_D_LBA | head);
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);
561 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
567 cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS | CF_A_RESET);
569 cfaltwrite8(CF_ALT_DEV_CTR, CF_A_IDS);
574 for (tout = 0; tout < 310000; tout++) {
575 cfwrite8(CF_DRV_HEAD, CF_D_IBM);
577 status = cfread8(CF_STATUS);
578 if (!(status & CF_S_BUSY))
583 if (status & CF_S_BUSY) {
585 printf("cfreset: Status stayed busy after reset.\n");
587 DPRINTF("cfreset: finished, tout %u\n", tout);
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);
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");
606 if (dskinf.use_stream8)
607 cfreadstream8(buf, 512);
609 cfreadstream16(buf, 512);
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);
624 dskinf.status = cfread8(CF_STATUS);
626 printf("cfgetparams: ata_params * %x, stat %x\n",
627 (u_int32_t)buf, (u_int32_t)dskinf.status);
637 putstr("cfprintregs: regs error ");
638 rv = cfread8(CF_ERROR);
641 rv = cfread8(CF_SECT_CNT);
644 rv = cfread8(CF_SECT_NUM);
646 putstr(", cyl low ");
647 rv = cfread8(CF_CYL_L);
649 putstr(", cyl high ");
650 rv = cfread8(CF_CYL_H);
652 putstr(", drv head ");
653 rv = cfread8(CF_DRV_HEAD);
656 rv = cfread8(CF_STATUS);
662 avila_read(char *dest, unsigned source, unsigned length)
664 if (dskinf.use_lba == 0 && source == 0)
667 printf("avila_read: 0x%x, sect %d num secs %d\n",
668 (u_int32_t)dest, source, length);
671 /* cmd, cyl, head, sect, count, feature */
672 cfcmd(ATA_READ, (source >> 8) & 0xffff, source >> 24,
673 source & 0xff, 1, 0);
675 cfwait(CF_S_READY | CF_S_DRQ | CF_S_DSC);
676 if (dskinf.use_stream8)
677 cfreadstream8(dest, 512);
679 cfreadstream16(dest, 512);
688 * Gateworks Avila Support.
691 avila_probe(int boardtype_hint)
693 volatile u_int32_t *cs;
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.
699 cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
706 /* Config the serial port. RedBoot should do the rest. */
707 ubase = (u_int8_t *)(IXP425_UART0_HWBASE);
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;
716 BOARD_CONFIG(avila, "Gateworks Avila");
719 * Gateworks Cambria Support.
722 cambria_probe(int boardtype_hint)
724 return cpu_is_ixp43x();
730 /* Config the serial port. RedBoot should do the rest. */
731 ubase = (u_int8_t *)(IXP425_UART0_HWBASE);
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;
740 BOARD_CONFIG(cambria, "Gateworks Cambria");
743 * Pronghorn Metro Support.
746 pronghorn_probe(int boardtype_hint)
748 volatile u_int32_t *cs;
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.
754 cs = (u_int32_t *)(IXP425_EXP_HWBASE + EXP_TIMING_CS2_OFFSET);
761 /* Config the serial port. RedBoot should do the rest. */
762 ubase = (u_int8_t *)(IXP425_UART1_HWBASE);
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;
771 BOARD_CONFIG(pronghorn, "Pronghorn Metro");