diff options
author | aiju <aiju@phicode.de> | 2014-12-24 10:21:51 +0100 |
---|---|---|
committer | aiju <aiju@phicode.de> | 2014-12-24 10:21:51 +0100 |
commit | 7a3f0998a0ce7470d70c1a13bc4646abafdcc236 (patch) | |
tree | 9cea39d933719c0b82eb242ec286c25eed0d728c /sys/src/boot | |
parent | 6dafa424805d128fcd08c71dca3e3abdc40aa6c6 (diff) |
added zynq kernel
Diffstat (limited to 'sys/src/boot')
-rw-r--r-- | sys/src/boot/zynq/boothead.c | 71 | ||||
-rw-r--r-- | sys/src/boot/zynq/dat.h | 11 | ||||
-rw-r--r-- | sys/src/boot/zynq/ddr.s | 258 | ||||
-rw-r--r-- | sys/src/boot/zynq/fns.h | 13 | ||||
-rw-r--r-- | sys/src/boot/zynq/fsbl.s | 310 | ||||
-rw-r--r-- | sys/src/boot/zynq/main.c | 184 | ||||
-rw-r--r-- | sys/src/boot/zynq/mem.h | 107 | ||||
-rw-r--r-- | sys/src/boot/zynq/mkfile | 34 | ||||
-rw-r--r-- | sys/src/boot/zynq/mkfile.boothead | 9 | ||||
-rw-r--r-- | sys/src/boot/zynq/net.c | 591 | ||||
-rw-r--r-- | sys/src/boot/zynq/qspi.c | 45 |
11 files changed, 1633 insertions, 0 deletions
diff --git a/sys/src/boot/zynq/boothead.c b/sys/src/boot/zynq/boothead.c new file mode 100644 index 000000000..98aed00c7 --- /dev/null +++ b/sys/src/boot/zynq/boothead.c @@ -0,0 +1,71 @@ +#include <u.h> +#include <libc.h> + +char *data; +uchar head[0x8c0]; + +void +usage(void) +{ + fprint(2, "usage: %s file\n", argv0); + exits("usage"); +} + +void +u32(int n, u32int p) +{ + head[n] = p; + head[n+1] = p >> 8; + head[n+2] = p >> 16; + head[n+3] = p >> 24; +} + +u32int +gu32(int n) +{ + return head[n] | head[n+1] << 8 | head[n+2] << 16 | head[n+3] << 24; +} + +void +main(int argc, char **argv) +{ + int fd, sz, i; + u32int ck; + + ARGBEGIN { + default: + usage(); + } ARGEND; + + if(argc != 1) + usage(); + fd = open(argv[0], OREAD); + if(fd < 0) + sysfatal("open: %r"); + sz = seek(fd, 0, 2); + if(sz < 0) + sysfatal("seek: %r"); + data = malloc(sz); + if(data == nil) + sysfatal("malloc: %r"); + seek(fd, 0, 0); + if(readn(fd, data, sz) < sz) + sysfatal("read: %r"); + close(fd); + memset(head, 0, sizeof(head)); + + u32(0x20, 0xaa995566); + u32(0x24, 0x584C4E58); + u32(0x30, sizeof(head)); + u32(0x34, sz); + u32(0x40, sz); + ck = 0; + for(i = 0x20; i < 0x48; i += 4) + ck += gu32(i); + u32(0x48, ~ck); + u32(0xa0, -1); + + write(1, head, sizeof(head)); + write(1, data, sz); + exits(nil); +} diff --git a/sys/src/boot/zynq/dat.h b/sys/src/boot/zynq/dat.h new file mode 100644 index 000000000..81cb90749 --- /dev/null +++ b/sys/src/boot/zynq/dat.h @@ -0,0 +1,11 @@ +enum { + DHCPTIMEOUT = 2000, + ARPTIMEOUT = 1000, + TFTPTIMEOUT = 10000, + + TZERO = 0x80000, + CONFSIZE = 65536, + CONF = TZERO - CONFSIZE, +}; + +#define nelem(x) (sizeof(x)/sizeof(*(x))) diff --git a/sys/src/boot/zynq/ddr.s b/sys/src/boot/zynq/ddr.s new file mode 100644 index 000000000..28686f702 --- /dev/null +++ b/sys/src/boot/zynq/ddr.s @@ -0,0 +1,258 @@ +#define OUTPUT_EN (3<<9) +#define DCI_EN (7<<4) +#define INP_VREF (1<<1) +#define INP_DIFF (2<<1) + +TEXT ddriob(SB), $-4 + WORD $(OUTPUT_EN) // DDRIOB_ADDR0 + WORD $(OUTPUT_EN) // DDRIOB_ADDR1 + WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA0 + WORD $(OUTPUT_EN | DCI_EN | INP_VREF) // DDRIOB_DATA1 + WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF0 + WORD $(OUTPUT_EN | DCI_EN | INP_DIFF) // DDRIOB_DIFF1 + WORD $(OUTPUT_EN) // DDRIOB_CLOCK + WORD $0x0018C61C // DDRIOB_DRIVE_SLEW_ADDR + WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DATA + WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_DIFF + WORD $0x00F9861C // DDRIOB_DRIVE_SLEW_CLOCK + WORD $0xE60 // DDRIOB_DDR_CTRL + +TEXT ddrdata(SB), $-4 + WORD $0XF8006000 + WORD $0x0001FFFF + WORD $0x00000080 + WORD $0XF8006004 + WORD $0x1FFFFFFF + WORD $0x00081081 + WORD $0XF8006008 + WORD $0x03FFFFFF + WORD $0x03C0780F + WORD $0XF800600C + WORD $0x03FFFFFF + WORD $0x02001001 + WORD $0XF8006010 + WORD $0x03FFFFFF + WORD $0x00014001 + WORD $0XF8006014 + WORD $0x001FFFFF + WORD $0x0004281A + WORD $0XF8006018 + WORD $0xF7FFFFFF + WORD $0x44E458D2 + WORD $0XF800601C + WORD $0xFFFFFFFF + WORD $0x82023965 + WORD $0XF8006020 + WORD $0xFFFFFFFC + WORD $0x2B288290 + WORD $0XF8006024 + WORD $0x0FFFFFFF + WORD $0x0000003C + WORD $0XF8006028 + WORD $0x00003FFF + WORD $0x00002007 + WORD $0XF800602C + WORD $0xFFFFFFFF + WORD $0x00000008 + WORD $0XF8006030 + WORD $0xFFFFFFFF + WORD $0x00040970 + WORD $0XF8006034 + WORD $0x13FF3FFF + WORD $0x00011054 + WORD $0XF8006038 + WORD $0x00001FC3 + WORD $0x00000000 + WORD $0XF800603C + WORD $0x000FFFFF + WORD $0x00000777 + WORD $0XF8006040 + WORD $0xFFFFFFFF + WORD $0xFFF00000 + WORD $0XF8006044 + WORD $0x0FFFFFFF + WORD $0x0F666666 + WORD $0XF8006048 + WORD $0x3FFFFFFF + WORD $0x0003C248 + WORD $0XF8006050 + WORD $0xFF0F8FFF + WORD $0x77010800 + WORD $0XF8006058 + WORD $0x0001FFFF + WORD $0x00000101 + WORD $0XF800605C + WORD $0x0000FFFF + WORD $0x00005003 + WORD $0XF8006060 + WORD $0x000017FF + WORD $0x0000003E + WORD $0XF8006064 + WORD $0x00021FE0 + WORD $0x00020000 + WORD $0XF8006068 + WORD $0x03FFFFFF + WORD $0x00284545 + WORD $0XF800606C + WORD $0x0000FFFF + WORD $0x00001610 + WORD $0XF80060A0 + WORD $0x00FFFFFF + WORD $0x00008000 + WORD $0XF80060A4 + WORD $0xFFFFFFFF + WORD $0x10200802 + WORD $0XF80060A8 + WORD $0x0FFFFFFF + WORD $0x0690CB73 + WORD $0XF80060AC + WORD $0x000001FF + WORD $0x000001FE + WORD $0XF80060B0 + WORD $0x1FFFFFFF + WORD $0x04FFFFFF + WORD $0XF80060B4 + WORD $0x000007FF + WORD $0x00000200 + WORD $0XF80060B8 + WORD $0x01FFFFFF + WORD $0x0020006A + WORD $0XF80060C4 + WORD $0x00000003 + WORD $0x00000003 + WORD $0XF80060C4 + WORD $0x00000003 + WORD $0x00000000 + WORD $0XF80060C8 + WORD $0x000000FF + WORD $0x00000000 + WORD $0XF80060DC + WORD $0x00000001 + WORD $0x00000000 + WORD $0XF80060F0 + WORD $0x0000FFFF + WORD $0x00000000 + WORD $0XF80060F4 + WORD $0x0000000F + WORD $0x00000008 + WORD $0XF8006114 + WORD $0x000000FF + WORD $0x00000000 + WORD $0XF8006118 + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF800611C + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF8006120 + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF8006124 + WORD $0x7FFFFFFF + WORD $0x40000001 + WORD $0XF800612C + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006130 + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006134 + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006138 + WORD $0x000FFFFF + WORD $0x00000000 + WORD $0XF8006140 + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF8006144 + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF8006148 + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF800614C + WORD $0x000FFFFF + WORD $0x00000035 + WORD $0XF8006154 + WORD $0x000FFFFF + WORD $0x00000080 + WORD $0XF8006158 + WORD $0x000FFFFF + WORD $0x00000080 + WORD $0XF800615C + WORD $0x000FFFFF + WORD $0x00000080 + WORD $0XF8006160 + WORD $0x000FFFFF + WORD $0x00000075 + WORD $0XF8006168 + WORD $0x001FFFFF + WORD $0x000000EE + WORD $0XF800616C + WORD $0x001FFFFF + WORD $0x000000E4 + WORD $0XF8006170 + WORD $0x001FFFFF + WORD $0x000000FC + WORD $0XF8006174 + WORD $0x001FFFFF + WORD $0x000000F4 + WORD $0XF800617C + WORD $0x000FFFFF + WORD $0x000000C0 + WORD $0XF8006180 + WORD $0x000FFFFF + WORD $0x000000C0 + WORD $0XF8006184 + WORD $0x000FFFFF + WORD $0x000000C0 + WORD $0XF8006188 + WORD $0x000FFFFF + WORD $0x000000B5 + WORD $0XF8006190 + WORD $0xFFFFFFFF + WORD $0x10040080 + WORD $0XF8006194 + WORD $0x000FFFFF + WORD $0x00007D02 + WORD $0XF8006204 + WORD $0xFFFFFFFF + WORD $0x00000000 + WORD $0XF8006208 + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF800620C + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF8006210 + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF8006214 + WORD $0x000F03FF + WORD $0x000803FF + WORD $0XF8006218 + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF800621C + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF8006220 + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF8006224 + WORD $0x000F03FF + WORD $0x000003FF + WORD $0XF80062A8 + WORD $0x00000FF7 + WORD $0x00000000 + WORD $0XF80062AC + WORD $0xFFFFFFFF + WORD $0x00000000 + WORD $0XF80062B0 + WORD $0x003FFFFF + WORD $0x00005125 + WORD $0xF80062B4 + WORD $0x003FFFFF + WORD $0x000012A8 + WORD $0 diff --git a/sys/src/boot/zynq/fns.h b/sys/src/boot/zynq/fns.h new file mode 100644 index 000000000..48f0a3ff9 --- /dev/null +++ b/sys/src/boot/zynq/fns.h @@ -0,0 +1,13 @@ +void putc(int); +void puts(char *); +int netboot(void); +void puthex(u32int); +void memset(void *, char, int); +void memcpy(void *, void *, int); +void print(char *, ...); +u32int u32get(void *); +void jump(void *); +void sleep(int); +void timeren(int); +int timertrig(void); +void flash(void); diff --git a/sys/src/boot/zynq/fsbl.s b/sys/src/boot/zynq/fsbl.s new file mode 100644 index 000000000..4923cdf52 --- /dev/null +++ b/sys/src/boot/zynq/fsbl.s @@ -0,0 +1,310 @@ +#include "mem.h" + +#define Rb R10 +#define SET(R, V) MOVW $(V), R0 ; MOVW R0, (R)(Rb) +#define RMW(r, m, v) MOVW (r)(Rb), R0; BIC $(m), R0; ORR $(v), R0; MOVW R0, (r)(Rb) + +TEXT _start(SB), $-4 + WORD $0xea000006 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + MOVW $abort(SB), R15 + +TEXT reloc(SB), $-4 + MOVW $(1<<7|1<<6|0x13), R0 + MOVW R0, CPSR + MOVW $STACKTOP, R13 + MOVW $_start(SB), R0 + MCR CpMMU, 0, R0, C(12), C(0) + MOVW $SLCR_BASE, Rb + SET(SLCR_UNLOCK, UNLOCK_KEY) + MOVW $0, R0 + MCR 15, 0, R0, C(8), C(7), 0 + MCR 15, 0, R0, C(7), C(5), 0 + MCR 15, 0, R0, C(7), C(5), 6 + MOVW $0xc5047a, R1 + MCR 15, 0, R1, C(1), C(0), 0 + DSB + ISB + CMP.S $0, R15 + BL.LT reset(SB) + + MOVW $0xf, R1 + MOVW $0xffff0000, R3 + MOVW $0xe58a1910, R0 + MOVW R0, (R3) + MOVW $0xf57ff04f, R0 + MOVW R0, 4(R3) + MOVW $0xf57ff06f, R0 + MOVW R0, 8(R3) + MOVW $0xe28ef000, R0 + MOVW R0, 12(R3) + MOVW $reset(SB), R14 + DSB + ISB + MOVW R3, R15 + +TEXT reset(SB), $-4 + BL pllsetup(SB) + BL miosetup(SB) + BL ddrsetup(SB) + BL uartsetup(SB) + MOVW $SLCR_BASE, Rb + SET(SLCR_LOCK, LOCK_KEY) +// BL memtest(SB) + MOVW $setR12(SB), R12 + BL main(SB) + B abort(SB) + +TEXT pllsetup(SB), $0 + MOVW $SLCR_BASE, Rb + + SET(ARM_PLL_CFG, ARM_PLL_CFG_VAL) + SET(DDR_PLL_CFG, DDR_PLL_CFG_VAL) + SET(IO_PLL_CFG, IO_PLL_CFG_VAL) + + MOVW $(ARM_FDIV | PLL_BYPASS_FORCE), R0 + MOVW R0, ARM_PLL_CTRL(Rb) + ORR $(PLL_RESET), R4 + MOVW R4, ARM_PLL_CTRL(Rb) + MOVW R0, ARM_PLL_CTRL(Rb) + + MOVW $(DDR_FDIV | PLL_BYPASS_FORCE), R0 + MOVW R0, DDR_PLL_CTRL(Rb) + ORR $(PLL_RESET), R4 + MOVW R4, DDR_PLL_CTRL(Rb) + MOVW R0, DDR_PLL_CTRL(Rb) + + MOVW $(IO_FDIV | PLL_BYPASS_FORCE), R0 + MOVW R0, IO_PLL_CTRL(Rb) + ORR $(PLL_RESET), R4 + MOVW R4, IO_PLL_CTRL(Rb) + MOVW R0, IO_PLL_CTRL(Rb) + +_pllsetupl: + MOVW PLL_STATUS(Rb), R0 + AND $7, R0 + CMP.S $7, R0 + BNE _pllsetupl + + SET(ARM_PLL_CTRL, ARM_FDIV) + SET(DDR_PLL_CTRL, DDR_FDIV) + SET(IO_PLL_CTRL, IO_FDIV) + + SET(ARM_CLK_CTRL, 0x1f << 24 | CPU_DIV << 8) + SET(UART_CLK_CTRL, UART_DIV << 8 | 3) + SET(DDR_CLK_CTRL, DDR_DIV3 << 20 | DDR_DIV2 << 26 | 3) + SET(DCI_CLK_CTRL, DCI_DIV0 << 8 | DCI_DIV1 << 20 | 1) + SET(GEM0_RCLK_CTRL, 1) + SET(GEM1_RCLK_CTRL, 0) + SET(GEM0_CLK_CTRL, ETH_DIV0 << 8 | ETH_DIV1 << 20 | 1) + SET(GEM1_CLK_CTRL, 0) + SET(GPIOB_CTRL, VREF_SW_EN) + SET(APER_CLK_CTRL, LQSPI_CLK_EN | GPIO_CLK_EN | UART0_CLK_EN | UART1_CLK_EN | I2C0_CLK_EN | SDIO1_CLK_EN | GEM0_CLK_EN | USB0_CLK_EN | USB1_CLK_EN | DMA_CLK_EN) + SET(SMC_CLK_CTRL, 0x3C20) + SET(LQSPI_CLK_CTRL, QSPI_DIV << 8 | 1) + SET(SDIO_CLK_CTRL, SDIO_DIV << 8 | 2) + SET(SPI_CLK_CTRL, 0x3F00) + SET(CAN_CLK_CTRL, 0x501900) + SET(PCAP_CLK_CTRL, PCAP_DIV << 8 | 1) + RET + +TEXT miosetup(SB), $0 + MOVW $SLCR_BASE, Rb + SET(UART_RST_CTRL, 0xf) + SET(UART_RST_CTRL, 0) + + MOVW $miodata(SB), R1 + ADD $MIO_PIN_0, Rb, R2 + MOVW $54, R3 + BL copy(SB) + + MOVW $0, R0 + MOVW R0, MIO_MST_TRI0(Rb) + MOVW R0, MIO_MST_TRI1(Rb) + RET + +TEXT copy(SB), $0 +_copyl: + MOVW.P 4(R1), R0 + MOVW.P R0, 4(R2) + SUB.S $1, R3 + BNE _copyl + RET + +TEXT ddrsetup(SB), $0 + MOVW $SLCR_BASE, Rb + RMW(DDRIOB_DCI_CTRL, DCI_RESET, DCI_RESET) + RMW(DDRIOB_DCI_CTRL, DCI_RESET, 0) + RMW(DDRIOB_DCI_CTRL, DDRIOB_DCI_CTRL_MASK, DCI_NREF | DCI_ENABLE | DCI_RESET) + + MOVW $ddriob(SB), R1 + ADD $DDRIOB_ADDR0, Rb, R2 + MOVW $12, R3 + BL copy(SB) + + MOVW $ddrdata(SB), R1 +_ddrl1: + MOVW.P 4(R1), R2 + ORR.S $0, R2 + BEQ _ddrl2 + MOVW.P 4(R1), R3 + MOVW.P 4(R1), R4 + AND R3, R4 + MOVW (R2), R0 + BIC R3, R0 + ORR R4, R0 + MOVW R0, (R2) + B _ddrl1 +_ddrl2: + MOVW DDRIOB_DCI_STATUS(Rb), R0 + AND.S $(1<<13), R0 + BEQ _ddrl2 + MOVW $DDR_BASE, Rb + RMW(DDRC_CTRL, 0x1ffff, 0x81) +_ddrl4: + MOVW DDR_MODE_STS(Rb), R0 + AND.S $7, R0 + BEQ _ddrl4 + + MOVW $MP_BASE, Rb + SET(FILTER_START, 0) + RET + +TEXT memtest(SB), $0 + MOVW $0, R0 + ADD $(1024 * 1024 * 10), R0, R1 +_testl: + MOVW R0, (R0) + ADD $4, R0 + CMP.S R0, R1 + BNE _testl + MOVW $0, R0 +_testl2: + MOVW (R0), R2 + CMP.S R0, R2 + BNE _no + ADD $4, R0 + CMP.S R0, R1 + BNE _testl2 + MOVW $'.', R0 + BL putc(SB) + RET +_no: + MOVW $'!', R0 + BL putc(SB) + RET + +TEXT uartsetup(SB), $0 + MOVW $UART1_BASE, Rb + SET(UART_CTRL, 0x17) + SET(UART_MODE, 0x20) + SET(UART_SAMP, 15) + SET(UART_BAUD, 14) + RET + +TEXT putc(SB), $0 + MOVW $UART1_BASE, Rb + CMP.S $10, R0 + BNE _putcl + MOVW R0, R2 + MOVW $13, R0 + BL putc(SB) + MOVW R2, R0 +_putcl: + MOVW UART_STAT(Rb), R1 + AND.S $0x10, R1 + BNE _putcl + AND $0xFF, R0 + MOVW R0, UART_DATA(Rb) + RET + +TEXT jump(SB), $-4 + MOVW R0, R15 + +TEXT abort(SB), $0 + MOVW $'?', R0 + BL putc(SB) +_loop: + WFE + B _loop + +#define TRI 1 +#define LVCMOS18 (1<<9) +#define LVCMOS25 (2<<9) +#define LVCMOS33 (3<<9) +#define HSTL (4<<9) +#define PULLUP (1<<12) +#define NORECV (1<<13) +#define FAST (1<<8) +#define MUX(a, b, c, d) ((a)<<1 | (b)<<2 | (c)<<3 | (d)<<5) + +#define NO (TRI | LVCMOS33) +#define SPI (MUX(1, 0, 0, 0) | LVCMOS33) +#define UART (MUX(0, 0, 0, 7) | LVCMOS33) +#define SD (MUX(0, 0, 0, 4) | LVCMOS33) +#define ETX (MUX(1, 0, 0, 0) | HSTL | NORECV | PULLUP) +#define ERX (MUX(1, 0, 0, 0) | HSTL | TRI | PULLUP) +#define USB (MUX(0, 1, 0, 0) | LVCMOS18) +#define MDCLK (MUX(0, 0, 0, 4) | HSTL) +#define MDDATA (MUX(0, 0, 0, 4) | HSTL) + +TEXT miodata(SB), $-4 + WORD $NO // 0 + WORD $SPI // 1 + WORD $SPI // 2 + WORD $SPI // 3 + WORD $SPI // 4 + WORD $SPI // 5 + WORD $SPI // 6 + WORD $NO // 7 + WORD $UART // 8 + WORD $(UART|TRI) // 9 + WORD $SD // 10 + WORD $SD // 11 + WORD $SD // 12 + WORD $SD // 13 + WORD $SD // 14 + WORD $SD // 15 + WORD $ETX // 16 + WORD $ETX // 17 + WORD $ETX // 18 + WORD $ETX // 19 + WORD $ETX // 20 + WORD $ETX // 21 + WORD $ERX // 22 + WORD $ERX // 23 + WORD $ERX // 24 + WORD $ERX // 25 + WORD $ERX // 26 + WORD $ERX // 27 + WORD $USB // 28 + WORD $USB // 29 + WORD $USB // 30 + WORD $USB // 31 + WORD $USB // 32 + WORD $USB // 33 + WORD $USB // 34 + WORD $USB // 35 + WORD $USB // 36 + WORD $USB // 37 + WORD $USB // 38 + WORD $USB // 39 + WORD $USB // 40 + WORD $USB // 41 + WORD $USB // 42 + WORD $USB // 43 + WORD $USB // 44 + WORD $USB // 45 + WORD $USB // 46 + WORD $USB // 47 + WORD $USB // 48 + WORD $USB // 49 + WORD $USB // 50 + WORD $USB // 51 + WORD $MDCLK // 52 + WORD $MDDATA // 53 diff --git a/sys/src/boot/zynq/main.c b/sys/src/boot/zynq/main.c new file mode 100644 index 000000000..ffe2daddd --- /dev/null +++ b/sys/src/boot/zynq/main.c @@ -0,0 +1,184 @@ +#include <u.h> +#include <a.out.h> +#include "dat.h" +#include "fns.h" + +void +puts(char *s) +{ + while(*s) + putc(*s++); +} + +void +puthex(u32int u) +{ + static char *dig = "0123456789abcdef"; + int i; + + for(i = 0; i < 8; i++){ + putc(dig[u >> 28]); + u <<= 4; + } +} + +void +putdec(int n) +{ + if(n / 10 != 0) + putdec(n / 10); + putc(n % 10 + '0'); +} + +void +print(char *s, ...) +{ + va_list va; + int n; + u32int u; + + va_start(va, s); + while(*s) + if(*s == '%'){ + switch(*++s){ + case 's': + puts(va_arg(va, char *)); + break; + case 'x': + puthex(va_arg(va, u32int)); + break; + case 'd': + n = va_arg(va, int); + if(n < 0){ + putc('-'); + putdec(-n); + }else + putdec(n); + break; + case 'I': + u = va_arg(va, u32int); + putdec(u >> 24); + putc('.'); + putdec((uchar)(u >> 16)); + putc('.'); + putdec((uchar)(u >> 8)); + putc('.'); + putdec((uchar)u); + break; + case 0: + va_end(va); + return; + } + s++; + }else + putc(*s++); + va_end(va); +} + +void +memset(void *v, char c, int n) +{ + char *vc; + + vc = v; + while(n--) + *vc++ = c; +} + +void +memcpy(void *d, void *s, int n) +{ + char *cd, *cs; + + cd = d; + cs = s; + while(n--) + *cd++ = *cs++; +} + +void +run(void) +{ + ulong t, tr; + char *p, *d; + int n; + ulong *h; + + h = (ulong *) TZERO; + if(u32get(&h[0]) != E_MAGIC){ + print("invalid magic: %x != %x\n", u32get(&h[0]), E_MAGIC); + return; + } + t = u32get(&h[1]) + 0x20; + tr = t + 0xfff & ~0xfff; + if(t != tr){ + n = u32get(&h[2]); + p = (char *) (TZERO + t + n); + d = (char *) (TZERO + tr + n); + while(n--) + *--d = *--p; + } + p = (char *) (TZERO + tr + u32get(&h[2])); + memset(p, 0, u32get(&h[3])); + jump((void *) (u32get(&h[5]) & 0xfffffff)); +} + +enum { + TIMERVALL, + TIMERVALH, + TIMERCTL, + TIMERSTAT, + TIMERCOMPL, + TIMERCOMPH, +}; + +void +timeren(int n) +{ + ulong *r; + + r = (ulong *) 0xf8f00200; + if(n < 0){ + r[TIMERSTAT] |= 1; + r[TIMERCTL] = 0; + return; + } + r[TIMERCTL] = 0; + r[TIMERVALL] = 0; + r[TIMERVALH] = 0; + r[TIMERCOMPL] = 1000 * n; + r[TIMERCOMPH] = 0; + r[TIMERSTAT] |= 1; + r[TIMERCTL] = 100 << 8 | 3; +} + +int +timertrig(void) +{ + ulong *r; + + r = (ulong *) 0xf8f00200; + if((r[TIMERSTAT] & 1) != 0){ + r[TIMERCTL] = 0; + r[TIMERSTAT] |= 1; + return 1; + } + return 0; +} + +void +sleep(int n) +{ + timeren(n); + while(!timertrig()) + ; +} + +void +main(void) +{ + puts("Booting ...\n"); + if(netboot() > 0) + run(); + print("hjboot: ending\n"); +} diff --git a/sys/src/boot/zynq/mem.h b/sys/src/boot/zynq/mem.h new file mode 100644 index 000000000..9753fc346 --- /dev/null +++ b/sys/src/boot/zynq/mem.h @@ -0,0 +1,107 @@ +#define STACKTOP 0xFFFFFE00 + +#define ARM_FDIV (40 << PLL_FDIV_SH) +#define DDR_FDIV (32 << PLL_FDIV_SH) +#define IO_FDIV (30 << PLL_FDIV_SH) +#define PLL_CFG_VAL(CP, RES, CNT) ((CP)<<8 | (RES)<<4 | (CNT)<<12) +#define ARM_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 250) +#define DDR_PLL_CFG_VAL PLL_CFG_VAL(2, 2, 300) +#define IO_PLL_CFG_VAL PLL_CFG_VAL(2, 12, 325) +#define PLL_FDIV_SH 12 +#define PLL_BYPASS_FORCE 0x10 +#define PLL_RESET 0x01 + +#define CPU_DIV 2 +#define DDR_DIV3 2 +#define DDR_DIV2 3 +#define UART_DIV 40 +#define DCI_DIV0 20 +#define DCI_DIV1 5 +#define ETH_DIV0 8 +#define ETH_DIV1 1 +#define QSPI_DIV 5 +#define SDIO_DIV 10 +#define PCAP_DIV 5 +#define MDC_DIV 6 /* this value depends on CPU_1xCLK, see TRM GEM.net_cfg description */ + +#define SLCR_BASE 0xF8000000 +#define SLCR_LOCK 0x004 +#define LOCK_KEY 0x767B +#define SLCR_UNLOCK 0x008 +#define UNLOCK_KEY 0xDF0D + +#define ARM_PLL_CTRL 0x100 +#define DDR_PLL_CTRL 0x104 +#define IO_PLL_CTRL 0x108 +#define PLL_STATUS 0x10C +#define ARM_PLL_CFG 0x110 +#define DDR_PLL_CFG 0x114 +#define IO_PLL_CFG 0x118 +#define ARM_CLK_CTRL 0x120 +#define DDR_CLK_CTRL 0x124 +#define DCI_CLK_CTRL 0x128 +#define APER_CLK_CTRL 0x12C +#define GEM0_RCLK_CTRL 0x138 +#define GEM1_RCLK_CTRL 0x13C +#define GEM0_CLK_CTRL 0x140 +#define GEM1_CLK_CTRL 0x144 +#define SMC_CLK_CTRL 0x148 +#define LQSPI_CLK_CTRL 0x14C +#define SDIO_CLK_CTRL 0x150 +#define UART_CLK_CTRL 0x154 +#define SPI_CLK_CTRL 0x158 +#define CAN_CLK_CTRL 0x15C +#define PCAP_CLK_CTRL 0x168 +#define UART_RST_CTRL 0x228 +#define A9_CPU_RST_CTRL 0x244 + +#define LQSPI_CLK_EN (1<<23) +#define GPIO_CLK_EN (1<<22) +#define UART0_CLK_EN (1<<20) +#define UART1_CLK_EN (1<<21) +#define I2C0_CLK_EN (1<<18) +#define SDIO1_CLK_EN (1<<11) +#define GEM0_CLK_EN (1<<6) +#define USB1_CLK_EN (1<<3) +#define USB0_CLK_EN (1<<2) +#define DMA_CLK_EN (1<<0) + +#define MIO_PIN_0 0x00000700 +#define MIO_MST_TRI0 0x80C +#define MIO_MST_TRI1 0x810 +#define OCM_CFG 0x910 +#define GPIOB_CTRL 0xB00 +#define VREF_SW_EN (1<<11) +#define DDRIOB_ADDR0 0xB40 +#define DDRIOB_DCI_CTRL 0xB70 +#define DDRIOB_DCI_CTRL_MASK 0x1ffc3 +#define DDRIOB_DCI_STATUS 0xB74 +#define DCI_RESET 1 +#define DCI_NREF (1<<11) +#define DCI_ENABLE 2 + +#define DDR_BASE 0xF8006000 +#define DDRC_CTRL 0x0 +#define DDR_MODE_STS 0x54 + +#define UART1_BASE 0xE0001000 +#define UART_CTRL 0x0 +#define UART_MODE 0x4 +#define UART_BAUD 0x18 +#define UART_STAT 0x2C +#define UART_DATA 0x30 +#define UART_SAMP 0x34 + +#define QSPI_BASE 0xE000D000 +#define QSPI_CFG 0x0 +#define SPI_EN 0x4 +#define QSPI_TX 0x1c + +#define MP_BASE 0xF8F00000 +#define FILTER_START 0x40 + +#define CpMMU 15 + +#define DSB WORD $0xf57ff04f +#define ISB WORD $0xf57ff06f +#define WFE WORD $0xe320f002 diff --git a/sys/src/boot/zynq/mkfile b/sys/src/boot/zynq/mkfile new file mode 100644 index 000000000..fc8e84a63 --- /dev/null +++ b/sys/src/boot/zynq/mkfile @@ -0,0 +1,34 @@ +objtype=arm +</$objtype/mkfile +BIN=/arm +TARG=fsbl fsbl.img +CLEANFILES=boothead.$cputype +FSBLFILES=fsbl.$O ddr.$O main.$O net.$O div.$O qspi.$O + +all:V: $TARG + +clean:V: + rm -rf $TARG *.$O + +fsbl: $FSBLFILES + $LD -o $target -T0xfffc0000 -H6 -R4096 -l -s $prereq + +9fsbl: $FSBLFILES + $LD -o $target -T0xfffc0000 -l $prereq + +fsbl.img:D: fsbl boothead.$cputype + boothead.$cputype fsbl >fsbl.img + +boothead.$cputype:V: mkfile.boothead + @{objtype=$cputype mk -f $prereq all} + +div.$O: /sys/src/libc/arm/div.s + $AS /sys/src/libc/arm/div.s + +%.$O: dat.h fns.h mem.h + +%.$O: %.s + $AS $stem.s + +%.$O: %.c + $CC $CFLAGS $stem.c diff --git a/sys/src/boot/zynq/mkfile.boothead b/sys/src/boot/zynq/mkfile.boothead new file mode 100644 index 000000000..cadebcb78 --- /dev/null +++ b/sys/src/boot/zynq/mkfile.boothead @@ -0,0 +1,9 @@ +</$objtype/mkfile + +all:V: boothead.$objtype + +boothead.$objtype: boothead.$O + $LD $LDFLAGS -o $target $prereq + +%.$O: %.c + $CC $CFLAGS $stem.c diff --git a/sys/src/boot/zynq/net.c b/sys/src/boot/zynq/net.c new file mode 100644 index 000000000..f783958a0 --- /dev/null +++ b/sys/src/boot/zynq/net.c @@ -0,0 +1,591 @@ +#include <u.h> +#include "dat.h" +#include "fns.h" +#include "mem.h" + +enum { + ETHLEN = 1600, + UDPLEN = 576, + NRX = 64, + RXBASE = 128 * 1024 * 1024, + + ETHHEAD = 14, + IPHEAD = 20, + UDPHEAD = 8, + + BOOTREQ = 1, + DHCPDISCOVER = 1, + DHCPOFFER, + DHCPREQUEST, + DHCPDECLINE, +}; + +enum { + NET_CTRL, + NET_CFG, + NET_STATUS, + DMA_CFG = 4, + TX_STATUS, + RX_QBAR, + TX_QBAR, + RX_STATUS, + INTR_STATUS, + INTR_EN, + INTR_DIS, + INTR_MASK, + PHY_MAINT, + RX_PAUSEQ, + TX_PAUSEQ, + HASH_BOT = 32, + HASH_TOP, + SPEC_ADDR1_BOT, + SPEC_ADDR1_TOP, +}; + +enum { + MDCTRL, + MDSTATUS, + MDID1, + MDID2, + MDAUTOADV, + MDAUTOPART, + MDAUTOEX, + MDAUTONEXT, + MDAUTOLINK, + MDGCTRL, + MDGSTATUS, + MDPHYCTRL = 0x1f, +}; + +enum { + /* NET_CTRL */ + RXEN = 1<<2, + TXEN = 1<<3, + MDEN = 1<<4, + STARTTX = 1<<9, + /* NET_CFG */ + SPEED = 1<<0, + FDEN = 1<<1, + RX1536EN = 1<<8, + GIGE_EN = 1<<10, + RXCHKSUMEN = 1<<24, + /* NET_STATUS */ + PHY_IDLE = 1<<2, + /* DMA_CFG */ + TXCHKSUMEN = 1<<11, + /* TX_STATUS */ + TXCOMPL = 1<<5, + /* MDCTRL */ + MDRESET = 1<<15, + AUTONEG = 1<<12, + FULLDUP = 1<<8, + /* MDSTATUS */ + LINK = 1<<2, + /* MDGSTATUS */ + RECVOK = 3<<12, +}; + +typedef struct { + uchar edest[6]; + uchar esrc[6]; + ulong idest; + ulong isrc; + ushort dport, sport; + ushort len; + uchar data[UDPLEN]; +} udp; + +static ulong *eth0 = (ulong *) 0xe000b000; +static int phyaddr = 7; + +static u32int myip, dhcpip, tftpip, xid; +static uchar mac[6] = {0x0E, 0xA7, 0xDE, 0xAD, 0xBE, 0xEF}; +static uchar tmac[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static char file[128]; + +static udp ubuf, urbuf; +static uchar txbuf[ETHLEN]; +static ulong txdesc[4], *txact, *rxact; +static ulong rxdesc[NRX*2]; + +void +mdwrite(ulong *r, int reg, u16int val) +{ + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; + r[PHY_MAINT] = 1<<30 | 1<<28 | 1<<17 | phyaddr << 23 | reg << 18 | val; + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; +} + +u16int +mdread(ulong *r, int reg) +{ + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; + r[PHY_MAINT] = 1<<30 | 1<<29 | 1<<17 | phyaddr << 23 | reg << 18; + while((r[NET_STATUS] & PHY_IDLE) == 0) + ; + return r[PHY_MAINT]; +} + +void +ethinit(ulong *r) +{ + int v; + ulong *p; + ulong d; + + r[NET_CTRL] = 0; + r[RX_STATUS] = 0xf; + r[TX_STATUS] = 0xff; + r[INTR_DIS] = 0x7FFFEFF; + r[RX_QBAR] = r[TX_QBAR] = 0; + r[NET_CFG] = MDC_DIV << 18 | FDEN | SPEED | RX1536EN | GIGE_EN | RXCHKSUMEN; + r[SPEC_ADDR1_BOT] = mac[0] | mac[1] << 8 | mac[2] << 16 | mac[3] << 24; + r[SPEC_ADDR1_TOP] = mac[4] | mac[5] << 8; + r[DMA_CFG] = TXCHKSUMEN | 0x18 << 16 | 1 << 10 | 3 << 8 | 0x10; + + txdesc[0] = 0; + txdesc[1] = 1<<31; + txdesc[2] = 0; + txdesc[3] = 1<<31 | 1<<30; + txact = txdesc; + r[TX_QBAR] = (ulong) txdesc; + for(p = rxdesc, d = RXBASE; p < rxdesc + nelem(rxdesc); d += ETHLEN){ + *p++ = d; + *p++ = 0; + } + p[-2] |= 2; + rxact = rxdesc; + r[RX_QBAR] = (ulong) rxdesc; + + r[NET_CTRL] = MDEN; +// mdwrite(r, MDCTRL, MDRESET); + mdwrite(r, MDCTRL, AUTONEG); + if((mdread(r, MDSTATUS) & LINK) == 0){ + puts("Waiting for Link ...\n"); + while((mdread(r, MDSTATUS) & LINK) == 0) + ; + } + v = mdread(r, MDPHYCTRL); + if((v & 0x40) != 0){ + puts("1000BASE-T"); + while((mdread(r, MDGSTATUS) & RECVOK) != RECVOK) + ; + r[NET_CFG] |= GIGE_EN; + }else if((v & 0x20) != 0){ + puts("100BASE-TX"); + r[NET_CFG] = NET_CFG & ~GIGE_EN | SPEED; + }else if((v & 0x10) != 0){ + puts("10BASE-T"); + r[NET_CFG] = NET_CFG & ~(GIGE_EN | SPEED); + }else + puts("???"); + if((v & 0x08) != 0) + puts(" Full Duplex\n"); + else{ + puts(" Half Duplex\n"); + r[NET_CFG] &= ~FDEN; + } + r[NET_CTRL] |= TXEN | RXEN; +} + +u32int +u32get(void *pp) +{ + uchar *p; + + p = pp; + return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; +} + +uchar * +u32put(uchar *p, u32int v) +{ + p[0] = v >> 24; + p[1] = v >> 16; + p[2] = v >> 8; + p[3] = v; + return p + 4; +} + +void +ethtx(ulong *r, uchar *buf, int len) +{ + txact[0] = (ulong) buf; + txact[1] = 1<<15 | len; + if(txact == txdesc + nelem(txdesc) - 2){ + txact[1] |= 1<<30; + txact = txdesc; + }else + txact += 2; + r[TX_STATUS] = -1; + r[NET_CTRL] |= STARTTX; + while((r[TX_STATUS] & TXCOMPL) == 0) + ; +} + +void +udptx(ulong *r, udp *u) +{ + uchar *p, *q; + int n; + + p = q = txbuf; + memcpy(p, u->edest, 6); + memcpy(p + 6, u->esrc, 6); + q += 12; + *q++ = 8; + *q++ = 0; + + *q++ = 5 | 4 << 4; + *q++ = 0; + n = IPHEAD + UDPHEAD + u->len; + *q++ = n >> 8; + *q++ = n; + + *q++ = 0x13; + *q++ = 0x37; + *q++ = 1<<6; + *q++ = 0; + + *q++ = 1; + *q++ = 0x11; + *q++ = 0; + *q++ = 0; + q = u32put(q, u->isrc); + q = u32put(q, u->idest); + + *q++ = u->sport >> 8; + *q++ = u->sport; + *q++ = u->dport >> 8; + *q++ = u->dport; + n = UDPHEAD + u->len; + *q++ = n >> 8; + *q++ = n; + *q++ = 0; + *q++ = 0; + + memcpy(q, u->data, u->len); + ethtx(r, p, ETHHEAD + IPHEAD + UDPHEAD + u->len); +} + +void +dhcppkg(ulong *r, int t) +{ + uchar *p; + udp *u; + + u = &ubuf; + p = u->data; + *p++ = BOOTREQ; + *p++ = 1; + *p++ = 6; + *p++ = 0; + p = u32put(p, xid); + p = u32put(p, 0x8000); + memset(p, 0, 16); + u32put(p + 8, dhcpip); + p += 16; + memcpy(p, mac, 6); + p += 6; + memset(p, 0, 202); + p += 202; + *p++ = 99; + *p++ = 130; + *p++ = 83; + *p++ = 99; + + *p++ = 53; + *p++ = 1; + *p++ = t; + if(t == DHCPREQUEST){ + *p++ = 50; + *p++ = 4; + p = u32put(p, myip); + *p++ = 54; + *p++ = 4; + p = u32put(p, dhcpip); + } + + *p++ = 0xff; + + memset(u->edest, 0xff, 6); + memcpy(u->esrc, mac, 6); + u->sport = 68; + u->dport = 67; + u->idest = -1; + u->isrc = 0; + u->len = p - u->data; + udptx(r, u); +} + +uchar * +ethrx(void) +{ + while((*rxact & 1) == 0) + if(timertrig()) + return nil; + return (uchar *) (*rxact & ~3); +} + +void +ethnext(void) +{ + *rxact &= ~1; + if((*rxact & 2) != 0) + rxact = rxdesc; + else + rxact += 2; +} + +void +arp(int op, uchar *edest, ulong idest) +{ + uchar *p; + static uchar broad[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + p = txbuf; + if(edest == nil) + edest = broad; + memcpy(p, edest, 6); + memcpy(p + 6, mac, 6); + p[12] = 8; + p[13] = 6; + p += 14; + p = u32put(p, 0x00010800); + p = u32put(p, 0x06040000 | op); + memcpy(p, mac, 6); + p = u32put(p + 6, myip); + memcpy(p, edest, 6); + p = u32put(p + 6, idest); + ethtx(eth0, txbuf, p - txbuf); +} + +void +arpc(uchar *p) +{ + p += 14; + if(u32get(p) != 0x00010800 || p[4] != 6 || p[5] != 4 || p[6] != 0) + return; + switch(p[7]){ + case 1: + if(myip != 0 && u32get(p + 24) == myip) + arp(2, p + 8, u32get(p + 14)); + break; + case 2: + if(tftpip != 0 && u32get(p + 14) == tftpip) + memcpy(tmac, p + 8, 6); + break; + } +} + +udp * +udprx(void) +{ + uchar *p; + ulong v; + udp *u; + + u = &urbuf; + for(;; ethnext()){ + p = ethrx(); + if(p == nil) + return nil; + if(p[12] != 8) + continue; + if(p[13] == 6){ + arpc(p); + continue; + } + if(p[13] != 0) + continue; + p += ETHHEAD; + if((p[0] >> 4) != 4 || p[9] != 0x11) + continue; + v = u32get(p + 16); + if(v != (ulong) -1 && v != myip) + continue; + u->idest = v; + u->isrc = u32get(p + 12); + p += (p[0] & 0xf) << 2; + u->sport = p[0] << 8 | p[1]; + u->dport = p[2] << 8 | p[3]; + u->len = p[4] << 8 | p[5]; + if(u->len < 8) + continue; + u->len -= 8; + if(u->len >= sizeof(u->data)) + u->len = sizeof(u->data); + memcpy(u->data, p + 8, u->len); + ethnext(); + return u; + } +} + +void +arpreq(void) +{ + uchar *p; + + arp(1, nil, tftpip); + timeren(ARPTIMEOUT); + for(;; ethnext()){ + p = ethrx(); + if(p == nil){ + print("ARP timeout\n"); + timeren(ARPTIMEOUT); + arp(1, nil, tftpip); + } + if(p[12] != 8 || p[13] != 6) + continue; + arpc(p); + if(tmac[0] != 0xff) + break; + } + timeren(-1); +} + +void +dhcp(ulong *r) +{ + udp *u; + uchar *p; + uchar type; + + xid = 0xdeadbeef; + tftpip = 0; + dhcppkg(r, DHCPDISCOVER); + timeren(DHCPTIMEOUT); + for(;;){ + u = udprx(); + if(u == nil){ + timeren(DHCPTIMEOUT); + dhcppkg(r, DHCPDISCOVER); + print("DHCP timeout\n"); + } + p = u->data; + if(u->dport != 68 || p[0] != 2 || u32get(p + 4) != xid || u32get(p + 236) != 0x63825363) + continue; + p += 240; + type = 0; + dhcpip = 0; + for(; p < u->data + u->len && *p != 0xff; p += 2 + p[1]) + switch(*p){ + case 53: + type = p[2]; + break; + case 54: + dhcpip = u32get(p + 2); + break; + } + if(type != DHCPOFFER) + continue; + p = u->data; + if(p[108] == 0){ + print("Offer from %I for %I with no boot file\n", dhcpip, u32get(p + 16)); + continue; + } + myip = u32get(p + 16); + tftpip = u32get(p + 20); + memcpy(file, p + 108, 128); + print("Offer from %I for %I with boot file '%s' at %I\n", dhcpip, myip, file, tftpip); + break; + } + timeren(-1); + dhcppkg(r, DHCPREQUEST); +} + +udp * +tftppkg(void) +{ + udp *u; + + u = &ubuf; + memcpy(u->edest, tmac, 6); + memcpy(u->esrc, mac, 6); + u->idest = tftpip; + u->isrc = myip; + u->sport = 69; + u->dport = 69; + return u; +} + +void +tftp(ulong *r, char *q, uintptr base) +{ + udp *u, *v; + uchar *p; + int bn, len; + +restart: + u = tftppkg(); + p = u->data; + *p++ = 0; + *p++ = 1; + do + *p++ = *q; + while(*q++ != 0); + memcpy(p, "octet", 6); + p += 6; + u->len = p - u->data; + udptx(r, u); + timeren(TFTPTIMEOUT); + + for(;;){ + v = udprx(); + if(v == nil){ + print("TFTP timeout"); + goto restart; + } + if(v->dport != 69 || v->isrc != tftpip || v->idest != myip) + continue; + if(v->data[0] != 0) + continue; + switch(v->data[1]){ + case 3: + bn = v->data[2] << 8 | v->data[3]; + len = v->len - 4; + if(len < 0) + continue; + if(len > 512) + len = 512; + memcpy((char*)base + ((bn - 1) << 9), v->data + 4, len); + if((bn & 127) == 0) + putc('.'); + p = u->data; + *p++ = 0; + *p++ = 4; + *p++ = bn >> 8; + *p = bn; + u->len = 4; + udptx(r, u); + if(len < 512){ + putc(10); + timeren(-1); + return; + } + timeren(TFTPTIMEOUT); + break; + case 5: + v->data[v->len - 1] = 0; + print("TFTP error: %s\n", v->data + 4); + timeren(-1); + return; + } + } +} + +int +netboot(void) +{ + ethinit(eth0); + myip = 0; + dhcp(eth0); + arpreq(); + tftp(eth0, file, TZERO); + memset((void *) CONF, 0, CONFSIZE); + tftp(eth0, "/cfg/pxe/0ea7deadbeef", CONF); + return 1; +} diff --git a/sys/src/boot/zynq/qspi.c b/sys/src/boot/zynq/qspi.c new file mode 100644 index 000000000..6134592ce --- /dev/null +++ b/sys/src/boot/zynq/qspi.c @@ -0,0 +1,45 @@ +#include <u.h> +#include "dat.h" +#include "fns.h" + +enum { + QSPI_CFG, + QSPI_STATUS, + QSPI_EN = 5, + QSPI_TXD4 = 7, + QSPI_RXD, + QSPI_TXD1 = 32, + QSPI_TXD2, + QSPI_TXD3 +}; + +#define QSPI0 ((void *) 0xE000D000) + +static u32int +cmd(ulong *r, int sz, u32int c) +{ + if(sz == 4) + r[QSPI_TXD4] = c; + else + r[QSPI_TXD1 + sz - 1] = c; + r[QSPI_CFG] |= 1<<16; + while((r[QSPI_STATUS] & (1<<2|1<<4)) != (1<<2|1<<4)) + ; + return r[QSPI_RXD]; +} + +void +flash(void) +{ + ulong *r; + + r = QSPI0; + r[QSPI_CFG] = 1<<31 | 1<<19 | 3<<6 | 1<<15 | 1<<14 | 1<<10 | 1<<3 | 1; + r[QSPI_CFG] &= ~(1<<10); + r[QSPI_EN] = 1; + cmd(r, 1, 0x06); +// cmd(r, 3, 0xD8); + for(;;) + print("%x\n", cmd(r, 2, 0x05)); + +} |