[U-Boot] [PATCH v4 1/7] those files are jz4740 base files

Xiangfu Liu
2010-12-08T06:20:43Z

Signed-off-by: Xiangfu Liu <xiangfu@openmobilefree.net>
---
arch/mips/cpu/xburst/Makefile | 50 +++
arch/mips/cpu/xburst/config.mk | 33 ++
arch/mips/cpu/xburst/cpu.c | 160 ++++++++
arch/mips/cpu/xburst/jz4740.c | 266 ++++++++++++
arch/mips/cpu/xburst/jz_serial.c | 128 ++++++
arch/mips/cpu/xburst/start.S | 164 ++++++++
arch/mips/cpu/xburst/start_spl.S | 63 +++
arch/mips/cpu/xburst/timer.c | 172 ++++++++
arch/mips/cpu/xburst/usbboot.S | 841 ++++++++++++++++++++++++++++++++++++++
9 files changed, 1877 insertions(+), 0 deletions(-)
create mode 100644 arch/mips/cpu/xburst/Makefile
create mode 100644 arch/mips/cpu/xburst/config.mk
create mode 100644 arch/mips/cpu/xburst/cpu.c
create mode 100644 arch/mips/cpu/xburst/jz4740.c
create mode 100644 arch/mips/cpu/xburst/jz_serial.c
create mode 100644 arch/mips/cpu/xburst/start.S
create mode 100644 arch/mips/cpu/xburst/start_spl.S
create mode 100644 arch/mips/cpu/xburst/timer.c
create mode 100644 arch/mips/cpu/xburst/usbboot.S

diff --git a/arch/mips/cpu/xburst/Makefile b/arch/mips/cpu/xburst/Makefile
new file mode 100644
index 0000000..a9a6e77
--- /dev/null
+++ b/arch/mips/cpu/xburst/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(CPU).o
+
+START = start.o
+SOBJS-y =
+COBJS-y = cpu.o timer.o jz_serial.o
+
+COBJS-$(CONFIG_JZ4740) += jz4740.o
+
+SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(START) $(LIB)
+
+$(LIB): $(OBJS)
+ $(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/mips/cpu/xburst/config.mk b/arch/mips/cpu/xburst/config.mk
new file mode 100644
index 0000000..fc9b255
--- /dev/null
+++ b/arch/mips/cpu/xburst/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2003
+# Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+v=$(shell $(AS) --version | grep 'GNU assembler' | egrep -o '2\.[0-9\.]+' | cut -d. -f2)
+MIPSFLAGS:=$(shell \
+if [ "$v" -lt "14" ]; then \
+ echo "-mcpu=4kc"; \
+else \
+ echo "-march=4kc -mtune=4kc"; \
+fi)
+
+MIPSFLAGS += -mabicalls -mips32
+
+PLATFORM_CPPFLAGS += $(MIPSFLAGS)
diff --git a/arch/mips/cpu/xburst/cpu.c b/arch/mips/cpu/xburst/cpu.c
new file mode 100644
index 0000000..22261cf
--- /dev/null
+++ b/arch/mips/cpu/xburst/cpu.c
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <netdev.h>
+#include <asm/mipsregs.h>
+#include <asm/cacheops.h>
+#include <asm/reboot.h>
+#include <asm/io.h>
+#include <asm/jz4740.h>
+
+#define cache_op(op,addr) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips3\n\t \n" \
+ " cache %0, %1 \n" \
+ " .set pop \n" \
+ : \
+ : "i" (op), "R" (*(unsigned char *)(addr)))
+
+#if !defined (CONFIG_NAND_SPL) && !defined (CONFIG_MSC_SPL)
+
+void __attribute__((weak)) _machine_restart(void)
+{
+ __wdt_select_extalclk();
+ __wdt_select_clk_div64();
+ __wdt_set_data(100);
+ __wdt_set_count(0);
+ __tcu_start_wdt_clock();
+ __wdt_start();
+
+ while(1);
+}
+
+int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char const *argv[])
+{
+ _machine_restart();
+
+ fprintf(stderr, "*** reset failed ***\n");
+ return 0;
+}
+
+void flush_cache(ulong start_addr, ulong size)
+{
+ unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+ unsigned long addr = start_addr & ~(lsize - 1);
+ unsigned long aend = (start_addr + size - 1) & ~(lsize - 1);
+
+ while (1) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ cache_op(Hit_Invalidate_I, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+}
+
+void flush_dcache_range(ulong start_addr, ulong stop)
+{
+ unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+ unsigned long addr = start_addr & ~(lsize - 1);
+ unsigned long aend = (stop - 1) & ~(lsize - 1);
+
+ while (1) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+}
+
+void invalidate_dcache_range(ulong start_addr, ulong stop)
+{
+ unsigned long lsize = CONFIG_SYS_CACHELINE_SIZE;
+ unsigned long addr = start_addr & ~(lsize - 1);
+ unsigned long aend = (stop - 1) & ~(lsize - 1);
+
+ while (1) {
+ cache_op(Hit_Invalidate_D, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+}
+
+void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, u32 low1)
+{
+ write_c0_entrylo0(low0);
+ write_c0_pagemask(pagemask);
+ write_c0_entrylo1(low1);
+ write_c0_entryhi(hi);
+ write_c0_index(index);
+ tlb_write_indexed();
+}
+
+#endif /* !CONFIG_NAND_SPL !CONFIG_MSC_SPL */
+
+void flush_icache_all(void)
+{
+ u32 addr, t = 0;
+
+ asm volatile ("mtc0 $0, $28"); /* Clear Taglo */
+ asm volatile ("mtc0 $0, $29"); /* Clear TagHi */
+
+ for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_ICACHE_SIZE;
+ addr += CONFIG_SYS_CACHELINE_SIZE) {
+ cache_op(Index_Store_Tag_I, addr);
+ }
+
+ /* invalidate btb */
+ asm volatile (
+ ".set mips32\n\t"
+ "mfc0 %0, $16, 7\n\t"
+ "nop\n\t"
+ "ori %0,2\n\t"
+ "mtc0 %0, $16, 7\n\t"
+ ".set mips2\n\t"
+ :
+ : "r" (t));
+}
+
+void flush_dcache_all(void)
+{
+ u32 addr;
+
+ for (addr = KSEG0; addr < KSEG0 + CONFIG_SYS_DCACHE_SIZE;
+ addr += CONFIG_SYS_CACHELINE_SIZE) {
+ cache_op(Index_Writeback_Inv_D, addr);
+ }
+
+ asm volatile ("sync");
+}
+
+void flush_cache_all(void)
+{
+ flush_dcache_all();
+ flush_icache_all();
+}
diff --git a/arch/mips/cpu/xburst/jz4740.c b/arch/mips/cpu/xburst/jz4740.c
new file mode 100644
index 0000000..4fd9e5a
--- /dev/null
+++ b/arch/mips/cpu/xburst/jz4740.c
@@ -0,0 +1,266 @@
+/*
+ * Jz4740 common routines
+ *
+ * Copyright (c) 2006
+ * Ingenic Semiconductor, <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/jz4740.h>
+
+void enable_interrupts(void)
+{
+}
+
+int disable_interrupts(void)
+{
+ return 0;
+}
+
+/* PLL output clock = EXTAL * NF / (NR * NO)
+ * NF = FD + 2, NR = RD + 2
+ * NO = 1 (if OD = 0), NO = 2 (if OD = 1 or 2), NO = 4 (if OD = 3)
+ */
+void pll_init(void)
+{
+ register unsigned int cfcr, plcr1;
+ int n2FR[33] = {
+ 0, 0, 1, 2, 3, 0, 4, 0, 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0,
+ 9
+ };
+ int div[5] = {1, 3, 3, 3, 3}; /* divisors of I:S:P:L:M */
+ int nf, pllout2;
+
+ cfcr = CPM_CPCCR_CLKOEN |
+ CPM_CPCCR_PCS |
+ (n2FR[div[0]] << CPM_CPCCR_CDIV_BIT) |
+ (n2FR[div[1]] << CPM_CPCCR_HDIV_BIT) |
+ (n2FR[div[2]] << CPM_CPCCR_PDIV_BIT) |
+ (n2FR[div[3]] << CPM_CPCCR_MDIV_BIT) |
+ (n2FR[div[4]] << CPM_CPCCR_LDIV_BIT);
+
+ pllout2 = (cfcr & CPM_CPCCR_PCS) ?
+ CONFIG_SYS_CPU_SPEED : (CONFIG_SYS_CPU_SPEED / 2);
+
+ /* Init USB Host clock, pllout2 must be n*48MHz */
+ writel((pllout2 / 48000000 - 1), CPM_UHCCDR);
+
+ nf = CONFIG_SYS_CPU_SPEED * 2 / CONFIG_SYS_EXTAL;
+ plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */
+ (0 << CPM_CPPCR_PLLN_BIT) | /* RD=0, NR=2 */
+ (0 << CPM_CPPCR_PLLOD_BIT) | /* OD=0, NO=1 */
+ (0x20 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */
+ CPM_CPPCR_PLLEN; /* enable PLL */
+
+ /* init PLL */
+ writel(cfcr, CPM_CPCCR);
+ writel(plcr1, CPM_CPPCR);
+}
+
+
+void sdram_init(void)
+{
+ register unsigned int dmcr0, dmcr, sdmode, tmp, cpu_clk, mem_clk, ns;
+
+ unsigned int cas_latency_sdmr[2] = {
+ EMC_SDMR_CAS_2,
+ EMC_SDMR_CAS_3,
+ };
+
+ unsigned int cas_latency_dmcr[2] = {
+ 1 << EMC_DMCR_TCL_BIT, /* CAS latency is 2 */
+ 2 << EMC_DMCR_TCL_BIT /* CAS latency is 3 */
+ };
+
+ int div[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ cpu_clk = CONFIG_SYS_CPU_SPEED;
+ mem_clk = cpu_clk *
+ div[__cpm_get_cdiv()] / div[__cpm_get_mdiv()];
+
+ writel(0, EMC_BCR); /* Disable bus release */
+ writew(0, EMC_RTCSR); /* Disable clock for counting */
+
+ /* Fault DMCR value for mode register setting*/
+#define SDRAM_ROW0 11
+#define SDRAM_COL0 8
+#define SDRAM_BANK40 0
+
+ dmcr0 = ((SDRAM_ROW0 - 11) << EMC_DMCR_RA_BIT) |
+ ((SDRAM_COL0 - 8) << EMC_DMCR_CA_BIT) |
+ (SDRAM_BANK40 << EMC_DMCR_BA_BIT) |
+ (SDRAM_BW16 << EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN |
+ cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)];
+
+ /* Basic DMCR value */
+ dmcr = ((SDRAM_ROW - 11) << EMC_DMCR_RA_BIT) |
+ ((SDRAM_COL - 8) << EMC_DMCR_CA_BIT) |
+ (SDRAM_BANK4 << EMC_DMCR_BA_BIT) |
+ (SDRAM_BW16 << EMC_DMCR_BW_BIT) | EMC_DMCR_EPIN |
+ cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)];
+
+ /* SDRAM timimg */
+ ns = 1000000000 / mem_clk;
+ tmp = SDRAM_TRAS/ns;
+ if (tmp < 4)
+ tmp = 4;
+ if (tmp > 11)
+ tmp = 11;
+ dmcr |= ((tmp-4) << EMC_DMCR_TRAS_BIT);
+ tmp = SDRAM_RCD/ns;
+
+ if (tmp > 3)
+ tmp = 3;
+ dmcr |= (tmp << EMC_DMCR_RCD_BIT);
+ tmp = SDRAM_TPC/ns;
+
+ if (tmp > 7)
+ tmp = 7;
+ dmcr |= (tmp << EMC_DMCR_TPC_BIT);
+ tmp = SDRAM_TRWL/ns;
+
+ if (tmp > 3)
+ tmp = 3;
+ dmcr |= (tmp << EMC_DMCR_TRWL_BIT);
+ tmp = (SDRAM_TRAS + SDRAM_TPC)/ns;
+
+ if (tmp > 14)
+ tmp = 14;
+ dmcr |= (((tmp + 1) >> 1) << EMC_DMCR_TRC_BIT);
+
+ /* SDRAM mode value */
+ sdmode = EMC_SDMR_BT_SEQ |
+ EMC_SDMR_OM_NORMAL |
+ EMC_SDMR_BL_4 |
+ cas_latency_sdmr[((SDRAM_CASL == 3) ? 1 : 0)];
+
+ /* Stage 1. Precharge all banks by writing
+ * SDMR with DMCR.MRSET=0 */
+ writel(dmcr, EMC_DMCR);
+ writeb(0, EMC_SDMR0 | sdmode);
+
+ /* Wait for precharge, > 200us */
+ tmp = (cpu_clk / 1000000) * 1000;
+ while (tmp--)
+ ;
+
+ /* Stage 2. Enable auto-refresh */
+ writel(dmcr | EMC_DMCR_RFSH, EMC_DMCR);
+
+ tmp = SDRAM_TREF / ns;
+ tmp = tmp/64 + 1;
+ if (tmp > 0xff)
+ tmp = 0xff;
+ writew(tmp, EMC_RTCOR);
+ writew(0, EMC_RTCNT);
+ /* Divisor is 64, CKO/64 */
+ writew(EMC_RTCSR_CKS_64, EMC_RTCSR);
+
+ /* Wait for number of auto-refresh cycles */
+ tmp = (cpu_clk / 1000000) * 1000;
+ while (tmp--)
+ ;
+
+ /* Stage 3. Mode Register Set */
+ writel(dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET, EMC_DMCR);
+ writeb(0, EMC_SDMR0 | sdmode);
+
+ /* Set back to basic DMCR value */
+ writel(dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET, EMC_DMCR);
+
+ /* everything is ok now */
+}
+
+#ifndef CONFIG_NAND_SPL
+DECLARE_GLOBAL_DATA_PTR;
+
+static void calc_clocks(void)
+{
+
+ unsigned int pllout;
+ unsigned int div[10] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32};
+
+ pllout = __cpm_get_pllout();
+
+ gd->cpu_clk = pllout / div[__cpm_get_cdiv()];
+ gd->sys_clk = pllout / div[__cpm_get_hdiv()];
+ gd->per_clk = pllout / div[__cpm_get_pdiv()];
+ gd->mem_clk = pllout / div[__cpm_get_mdiv()];
+ gd->dev_clk = CONFIG_SYS_EXTAL;
+}
+
+static void rtc_init(void)
+{
+ while ( !__rtc_write_ready())
+ ;
+
+ __rtc_enable_alarm(); /* enable alarm */
+
+ while ( !__rtc_write_ready())
+ ;
+
+ writel(0x00007fff, RTC_RGR); /* type value */
+
+ while ( !__rtc_write_ready())
+ ;
+
+ writel(0x0000ffe0, RTC_HWFCR); /* Power on delay 2s */
+
+ while ( !__rtc_write_ready())
+ ;
+
+ writel(0x00000fe0, RTC_HRCR); /* reset delay 125ms */
+}
+
+/* U-Boot common routines */
+phys_size_t initdram(int board_type)
+{
+ u32 dmcr;
+ u32 rows, cols, dw, banks;
+ ulong size;
+
+ dmcr = readl(EMC_DMCR);
+ rows = 11 + ((dmcr & EMC_DMCR_RA_MASK) >> EMC_DMCR_RA_BIT);
+ cols = 8 + ((dmcr & EMC_DMCR_CA_MASK) >> EMC_DMCR_CA_BIT);
+ dw = (dmcr & EMC_DMCR_BW) ? 2 : 4;
+ banks = (dmcr & EMC_DMCR_BA) ? 4 : 2;
+
+ size = (1 << (rows + cols)) * dw * banks;
+
+ return size;
+}
+
+/*
+ * jz4740 board init routine
+ */
+int jzsoc_init(void)
+{
+#ifndef CONFIG_NAND_U_BOOT
+ pll_init(); /* init PLL */
+ sdram_init(); /* init sdram memory */
+#endif
+ calc_clocks(); /* calc the clocks */
+ rtc_init(); /* init rtc on any reset: */
+
+ return 0;
+}
+
+#endif /* CONFIG_NAND_SPL */
diff --git a/arch/mips/cpu/xburst/jz_serial.c b/arch/mips/cpu/xburst/jz_serial.c
new file mode 100644
index 0000000..59e3267
--- /dev/null
+++ b/arch/mips/cpu/xburst/jz_serial.c
@@ -0,0 +1,128 @@
+/*
+ * Jz47xx UART support
+ *
+ * Hardcoded to UART 0 for now
+ * Options also hardcoded to 8N1
+ *
+ * Copyright (c) 2005
+ * Ingenic Semiconductor, <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/jz4740.h>
+
+/*
+ * serial_init - initialize a channel
+ *
+ * This routine initializes the number of data bits, parity
+ * and set the selected baud rate. Interrupts are disabled.
+ * Set the modem control signals if the option is selected.
+ *
+ * RETURNS: N/A
+ */
+int serial_init (void)
+{
+#if !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL)
+ volatile u8 *uart_fcr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_FCR);
+ volatile u8 *uart_lcr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_LCR);
+ volatile u8 *uart_ier = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_IER);
+ volatile u8 *uart_sircr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_SIRCR);
+
+ /* Disable port interrupts while changing hardware */
+ *uart_ier = 0;
+
+ /* Disable UART unit function */
+ *uart_fcr = ~UART_FCR_UUE;
+
+ /* Set both receiver and transmitter in UART mode (not SIR) */
+ *uart_sircr = ~(SIRCR_RSIRE | SIRCR_TSIRE);
+
+ /* Set databits, stopbits and parity. (8-bit data, 1 stopbit, no parity) */
+ *uart_lcr = UART_LCR_WLEN_8 | UART_LCR_STOP_1;
+
+ /* Set baud rate */
+ serial_setbrg();
+
+ /* Enable UART unit, enable and clear FIFO */
+ *uart_fcr = UART_FCR_UUE | UART_FCR_FE | UART_FCR_TFLS | UART_FCR_RFLS;
+#endif
+ return 0;
+}
+
+void serial_setbrg (void)
+{
+ volatile u8 *uart_lcr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_LCR);
+ volatile u8 *uart_dlhr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_DLHR);
+ volatile u8 *uart_dllr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_DLLR);
+ u32 baud_div, tmp;
+
+ baud_div = CONFIG_SYS_EXTAL / 16 / CONFIG_BAUDRATE;
+
+ tmp = *uart_lcr;
+ tmp |= UART_LCR_DLAB;
+ *uart_lcr = tmp;
+
+ *uart_dlhr = (baud_div >> 8) & 0xff;
+ *uart_dllr = baud_div & 0xff;
+
+ tmp &= ~UART_LCR_DLAB;
+ *uart_lcr = tmp;
+}
+
+void serial_putc (const char c)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_LSR);
+ volatile u8 *uart_tdr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_TDR);
+
+ if (c == '\n') serial_putc ('\r');
+
+ /* Wait for fifo to shift out some bytes */
+ while (!((*uart_lsr & (UART_LSR_TDRQ | UART_LSR_TEMT)) == 0x60))
+ ;
+
+ *uart_tdr = (u8)c;
+}
+
+void serial_puts (const char *s)
+{
+ while (*s)
+ serial_putc (*s++);
+}
+
+int serial_getc (void)
+{
+ volatile u8 *uart_rdr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_RDR);
+
+ while (!serial_tstc())
+ ;
+
+ return *uart_rdr;
+}
+
+int serial_tstc (void)
+{
+ volatile u8 *uart_lsr = (volatile u8 *)(CONFIG_SYS_UART_BASE + OFF_LSR);
+
+ if (*uart_lsr & UART_LSR_DR)
+ return (1);
+
+ return 0;
+}
+
diff --git a/arch/mips/cpu/xburst/start.S b/arch/mips/cpu/xburst/start.S
new file mode 100644
index 0000000..d999881
--- /dev/null
+++ b/arch/mips/cpu/xburst/start.S
@@ -0,0 +1,164 @@
+/*
+ * Startup Code for MIPS32 XBURST CPU-core
+ *
+ * Copyright (c) 2010 Xiangfu Liu <xiangfu@sharism.cc>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/cacheops.h>
+
+#include <asm/jz4740.h>
+
+ .set noreorder
+
+ .globl _start
+ .text
+_start:
+ /* Initialize GOT pointer.
+ */
+ bal 1f
+ nop
+ .word _GLOBAL_OFFSET_TABLE_
+1:
+ lw gp, 0(ra)
+ li sp, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET
+
+ la t9, board_init_f
+ jr t9
+ nop
+
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ * a0 = addr_sp
+ * a1 = gd
+ * a2 = destination address
+ */
+ .globl relocate_code
+ .ent relocate_code
+relocate_code:
+ move sp, a0 /* Set new stack pointer */
+
+ li t0, CONFIG_SYS_MONITOR_BASE
+ la t3, in_ram
+ lw t2, -12(t3) /* t2 <-- uboot_end_data */
+ move t1, a2
+
+ /*
+ * Fix GOT pointer:
+ * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address
+ */
+ move t6, gp
+ sub gp, CONFIG_SYS_MONITOR_BASE
+ add gp, a2 /* gp now adjusted */
+ sub t6, gp, t6 /* t6 <-- relocation offset*/
+
+ /*
+ * t0 = source address
+ * t1 = target address
+ * t2 = source end address
+ */
+1:
+ lw t3, 0(t0)
+ sw t3, 0(t1)
+ addu t0, 4
+ ble t0, t2, 1b
+ addu t1, 4 /* delay slot */
+
+ /* If caches were enabled, we would have to flush them here.
+ * flush d-cache */
+ .set push
+ li t0, KSEG0
+ addi t1, t0, CONFIG_SYS_DCACHE_SIZE
+2:
+ cache Index_Writeback_Inv_D, 0(t0)
+ bne t0, t1, 2b
+ addi t0, CONFIG_SYS_CACHELINE_SIZE
+
+ sync
+
+ /* flush i-cache */
+ li t0, KSEG0
+ addi t1, t0, CONFIG_SYS_ICACHE_SIZE
+3:
+ cache Index_Invalidate_I, 0(t0)
+ bne t0, t1, 3b
+ addi t0, CONFIG_SYS_CACHELINE_SIZE
+
+ /* Invalidate BTB */
+ mfc0 t0, CP0_CONFIG, 7
+ nop
+ ori t0, 2
+ mtc0 t0, CP0_CONFIG, 7
+ nop
+
+ .set pop
+
+ /* Jump to where we've relocated ourselves.
+ */
+ addi t0, a2, in_ram - _start
+ jr t0
+ nop
+
+ .word uboot_end_data
+ .word uboot_end
+ .word num_got_entries
+
+in_ram:
+ /* Now we want to update GOT */
+ lw t3, -4(t0) /* t3 <-- num_got_entries */
+ addi t4, gp, 8 /* Skipping first two entries. */
+ li t2, 2
+1:
+ lw t1, 0(t4)
+ beqz t1, 2f
+ add t1, t6
+ sw t1, 0(t4)
+2:
+ addi t2, 1
+ blt t2, t3, 1b
+ addi t4, 4 /* delay slot */
+
+ /* Clear BSS */
+ lw t1, -12(t0) /* t1 <-- uboot_end_data */
+ lw t2, -8(t0) /* t2 <-- uboot_end */
+ add t1, t6 /* adjust pointers */
+ add t2, t6
+
+ sub t1, 4
+1: addi t1, 4
+ bltl t1, t2, 1b
+ sw zero, 0(t1) /* delay slot */
+
+ move a0, a1
+ la t9, board_init_r
+ jr t9
+ move a1, a2 /* delay slot */
+
+ .end relocate_code
+
diff --git a/arch/mips/cpu/xburst/start_spl.S b/arch/mips/cpu/xburst/start_spl.S
new file mode 100644
index 0000000..f775e3a
--- /dev/null
+++ b/arch/mips/cpu/xburst/start_spl.S
@@ -0,0 +1,63 @@
+/*
+ * Startup Code for MIPS32 XBURST CPU-core
+ *
+ * Copyright (c) 2010 Xiangfu Liu <xiangfu@sharism.cc>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/cacheops.h>
+
+#include <asm/jz4740.h>
+
+ .set noreorder
+
+ .globl _start
+ .text
+_start:
+ .word JZ4740_NANDBOOT_CFG /* fetched during NAND Boot */
+reset:
+ /*
+ * STATUS register
+ * CU0=UM=EXL=IE=0, BEV=ERL=1, IP2~7=1
+ */
+ li t0, 0x0040FC04
+ mtc0 t0, CP0_STATUS
+ /* CAUSE register
+ * IV=1, use the specical interrupt vector (0x200) */
+ li t1, 0x00800000
+ mtc0 t1, CP0_CAUSE
+
+ bal 1f
+ nop
+ .word _GLOBAL_OFFSET_TABLE_
+1:
+ move gp, ra
+ lw t1, 0(ra)
+ move gp, t1
+
+ la sp, 0x80004000
+ la t9, nand_boot
+ j t9
+ nop
diff --git a/arch/mips/cpu/xburst/timer.c b/arch/mips/cpu/xburst/timer.c
new file mode 100644
index 0000000..c8926c1
--- /dev/null
+++ b/arch/mips/cpu/xburst/timer.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2006
+ * Ingenic Semiconductor, <jlwei@ingenic.cn>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <common.h>
+
+#include <asm/io.h>
+#include <asm/jz4740.h>
+
+/*
+ * Timer routines
+ */
+#define TIMER_CHAN 0
+#define TIMER_FDATA 0xffff /* Timer full data value */
+#define TIMER_HZ CONFIG_SYS_HZ
+
+static ulong timestamp;
+static ulong lastdec;
+
+void reset_timer_masked (void);
+ulong get_timer_masked (void);
+void udelay_masked (unsigned long usec);
+
+/*
+ * timer without interrupts
+ */
+int timer_init(void)
+{
+ writew(TCU_TCSR_PRESCALE256 | TCU_TCSR_EXT_EN,
+ TCU_TCSR(TIMER_CHAN));
+
+ writew(0, TCU_TCNT(TIMER_CHAN));
+ writew(0, TCU_TDHR(TIMER_CHAN));
+ writew(TIMER_FDATA, TCU_TDFR(TIMER_CHAN));
+
+ writel((1 << TIMER_CHAN) | (1 << (TIMER_CHAN + 16)),
+ TCU_TMSR); /* mask irqs */
+ writel((1 << TIMER_CHAN), TCU_TSCR);/* enable timer clock */
+ writeb((1 << TIMER_CHAN), TCU_TESR); /* start counting up */
+
+ lastdec = 0;
+ timestamp = 0;
+
+ return 0;
+}
+
+void reset_timer(void)
+{
+ reset_timer_masked ();
+}
+
+ulong get_timer(ulong base)
+{
+ return get_timer_masked () - base;
+}
+
+void set_timer(ulong t)
+{
+ timestamp = t;
+}
+
+void __udelay (unsigned long usec)
+{
+ ulong tmo,tmp;
+
+ /* normalize */
+ if (usec >= 1000) {
+ tmo = usec / 1000;
+ tmo *= TIMER_HZ;
+ tmo /= 1000;
+ } else {
+ if (usec >= 1) {
+ tmo = usec * TIMER_HZ;
+ tmo /= (1000 * 1000);
+ } else
+ tmo = 1;
+ }
+
+ /* check for rollover during this delay */
+ tmp = get_timer (0);
+ if ((tmp + tmo) < tmp )
+ reset_timer_masked(); /* timer would roll over */
+ else
+ tmo += tmp;
+
+ while (get_timer_masked () < tmo)
+ ;
+}
+
+void reset_timer_masked (void)
+{
+ /* reset time */
+ lastdec = readw(TCU_TCNT(TIMER_CHAN));
+ timestamp = 0;
+}
+
+ulong get_timer_masked (void)
+{
+ ulong now = readw(TCU_TCNT(TIMER_CHAN));
+
+ if (lastdec <= now)
+ timestamp += (now - lastdec);/* normal mode */
+ else
+ timestamp += TIMER_FDATA + now - lastdec;/* we have an overflow ... */
+
+ lastdec = now;
+
+ return timestamp;
+}
+
+void udelay_masked (unsigned long usec)
+{
+ ulong tmo;
+ ulong endtime;
+ signed long diff;
+
+ /* normalize */
+ if (usec >= 1000) {
+ tmo = usec / 1000;
+ tmo *= TIMER_HZ;
+ tmo /= 1000;
+ } else {
+ if (usec > 1) {
+ tmo = usec * TIMER_HZ;
+ tmo /= (1000*1000);
+ } else {
+ tmo = 1;
+ }
+ }
+
+ endtime = get_timer_masked () + tmo;
+
+ do {
+ ulong now = get_timer_masked ();
+ diff = endtime - now;
+ } while (diff >= 0);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On MIPS it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+ return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On MIPS it returns the number of timer ticks per second.
+ */
+ulong get_tbclk (void)
+{
+ return TIMER_HZ;
+}
diff --git a/arch/mips/cpu/xburst/usbboot.S b/arch/mips/cpu/xburst/usbboot.S
new file mode 100644
index 0000000..97fcbbf
--- /dev/null
+++ b/arch/mips/cpu/xburst/usbboot.S
@@ -0,0 +1,841 @@
+/*
+ * for jz4740 usb boot
+ *
+ * Copyright (c) 2009 Author: <jlwei@ingenic.cn>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+ .set noreorder
+ .globl usb_boot
+ .text
+
+/*
+ * Both NAND and USB boot load data to D-Cache first, then transfer
+ * data from D-Cache to I-Cache, and jump to execute the code in I-Cache.
+ * So init caches first and then dispatch to a proper boot routine.
+ */
+
+.macro load_addr reg addr
+ li \reg, 0x80000000
+ addiu \reg, \reg, \addr
+ la $2, usbboot_begin
+ subu \reg, \reg, $2
+.endm
+
+usb_boot:
+ /* Initialize PLL: set ICLK to 84MHz and HCLK to 42MHz. */
+ la $9, 0xB0000000 /* CPCCR: Clock Control Register */
+ la $8, 0x42041110 /* I:S:M:P=1:2:2:2 */
+ sw $8, 0($9)
+
+ la $9, 0xB0000010 /* CPPCR: PLL Control Register */
+ la $8, 0x06000120 /* M=12 N=0 D=0 CLK=12*(M+2)/(N+2) */
+ sw $8, 0($9)
+
+ mtc0 $0, $26 /* CP0_ERRCTL, restore WST reset state */
+ nop
+
+ mtc0 $0, $16 /* CP0_CONFIG */
+ nop
+
+ /* Relocate code to beginning of the ram */
+
+ la $2, usbboot_begin
+ la $3, usbboot_end
+ li $4, 0x80000000
+
+1:
+ lw $5, 0($2)
+ sw $5, 0($4)
+ addiu $2, $2, 4
+ bne $2, $3, 1b
+ addiu $4, $4, 4
+
+ li $2, 0x80000000
+ ori $3, $2, 0
+ addiu $3, $3, usbboot_end
+ la $4, usbboot_begin
+ subu $3, $3, $4
+
+
+2:
+ cache 0x0, 0($2) /* Index_Invalidate_I */
+ cache 0x1, 0($2) /* Index_Writeback_Inv_D */
+ addiu $2, $2, 32
+ subu $4, $3, $2
+ bgtz $4, 2b
+ nop
+
+ load_addr $3, usb_boot_return
+
+ jr $3
+
+usbboot_begin:
+
+init_caches:
+ li $2, 3 /* cacheable for kseg0 access */
+ mtc0 $2, $16 /* CP0_CONFIG */
+ nop
+
+ li $2, 0x20000000 /* enable idx-store-data cache insn */
+ mtc0 $2, $26 /* CP0_ERRCTL */
+
+ ori $2, $28, 0 /* start address */
+ ori $3, $2, 0x3fe0 /* end address, total 16KB */
+ mtc0 $0, $28, 0 /* CP0_TAGLO */
+ mtc0 $0, $28, 1 /* CP0_DATALO */
+cache_clear_a_line:
+ cache 0x8, 0($2) /* Index_Store_Tag_I */
+ cache 0x9, 0($2) /* Index_Store_Tag_D */
+ bne $2, $3, cache_clear_a_line
+ addiu $2, $2, 32 /* increment CACHE_LINE_SIZE */
+
+ ori $2, $28, 0 /* start address */
+ ori $3, $2, 0x3fe0 /* end address, total 16KB */
+ la $4, 0x1ffff000 /* physical address and 4KB page mask */
+cache_alloc_a_line:
+ and $5, $2, $4
+ ori $5, $5, 1 /* V bit of the physical tag */
+ mtc0 $5, $28, 0 /* CP0_TAGLO */
+ cache 0x8, 0($2) /* Index_Store_Tag_I */
+ cache 0x9, 0($2) /* Index_Store_Tag_D */
+ bne $2, $3, cache_alloc_a_line
+ addiu $2, $2, 32 /* increment CACHE_LINE_SIZE */
+
+ nop
+ nop
+ nop
+ /*
+ * Transfer data from dcache to icache, then jump to icache.
+ * Input parameters:
+ * $19: data length in bytes
+ * $20: jump target address
+ */
+xfer_d2i:
+
+ ori $8, $20, 0
+ addu $9, $8, $19 /* total 16KB */
+
+1:
+ cache 0x0, 0($8) /* Index_Invalidate_I */
+ cache 0x1, 0($8) /* Index_Writeback_Inv_D */
+ bne $8, $9, 1b
+ addiu $8, $8, 32
+
+ /* flush write-buffer */
+ sync
+
+ /* Invalidate BTB */
+ mfc0 $8, $16, 7 /* CP0_CONFIG */
+ nop
+ ori $8, 2
+ mtc0 $8, $16, 7
+ nop
+
+ /* Overwrite config to disable ram initalisation */
+ li $2, 0xff
+ sb $2, 20($20)
+
+ jalr $20
+ nop
+
+icache_return:
+ /*
+ * User code can return to here after executing itself in
+ * icache, by jumping to $31.
+ */
+ b usb_boot_return
+ nop
+
+
+usb_boot_return:
+ /* Enable the USB PHY */
+ la $9, 0xB0000024 /* CPM_SCR */
+ lw $8, 0($9)
+ ori $8, 0x40 /* USBPHY_ENABLE */
+ sw $8, 0($9)
+
+ /* Initialize USB registers */
+ la $27, 0xb3040000 /* USB registers base address */
+
+ sb $0, 0x0b($27) /* INTRUSBE: disable common USB interrupts */
+ sh $0, 0x06($27) /* INTRINE: disable EPIN interrutps */
+ sh $0, 0x08($27) /* INTROUTE: disable EPOUT interrutps */
+
+ li $9, 0x61
+ sb $9, 0x01($27) /* POWER: HSENAB | SUSPENDM | SOFTCONN */
+
+ /* Initialize USB states */
+ li $22, 0 /* set EP0 to IDLE state */
+ li $23, 1 /* no data stage */
+
+ /* Main loop of polling the usb commands */
+usb_command_loop:
+ lbu $9, 0x0a($27) /* read INTRUSB */
+ andi $9, 0x04 /* check USB_INTR_RESET */
+ beqz $9, check_intr_ep0in
+ nop
+
+ /* 1. Handle USB reset interrupt */
+handle_reset_intr:
+ lbu $9, 0x01($27) /* read POWER */
+ andi $9, 0x10 /* test HS_MODE */
+ bnez $9, _usb_set_maxpktsize
+ li $9, 512 /* max packet size of HS mode */
+ li $9, 64 /* max packet size of FS mode */
+
+_usb_set_maxpktsize:
+ li $8, 1
+ sb $8, 0x0e($27) /* set INDEX 1 */
+
+ sh $9, 0x10($27) /* INMAXP */
+ sb $0, 0x13($27) /* INCSRH */
+ sh $9, 0x14($27) /* OUTMAXP */
+ sb $0, 0x17($27) /* OUTCSRH */
+
+_usb_flush_fifo:
+ li $8, 0x48 /* INCSR_CDT && INCSR_FF */
+ sb $8, 0x12($27) /* INCSR */
+ li $8, 0x90 /* OUTCSR_CDT && OUTCSR_FF */
+ sb $8, 0x16($27) /* OUTCSR */
+
+ li $22, 0 /* set EP0 to IDLE state */
+ li $23, 1 /* no data stage */
+
+ /* 2. Check and handle EP0 interrupt */
+check_intr_ep0in:
+ lhu $10, 0x02($27) /* read INTRIN */
+ andi $9, $10, 0x1 /* check EP0 interrupt */
+ beqz $9, check_intr_ep1in
+ nop
+
+handle_ep0_intr:
+ sb $0, 0x0e($27) /* set INDEX 0 */
+ lbu $11, 0x12($27) /* read CSR0 */
+
+ andi $9, $11, 0x04 /* check SENTSTALL */
+ beqz $9, _ep0_setupend
+ nop
+
+_ep0_sentstall:
+ andi $9, $11, 0xdb
+ sb $9, 0x12($27) /* clear SENDSTALL and SENTSTALL */
+ li $22, 0 /* set EP0 to IDLE state */
+
+_ep0_setupend:
+ andi $9, $11, 0x10 /* check SETUPEND */
+ beqz $9, ep0_idle_state
+ nop
+
+ ori $9, $11, 0x80
+ sb $9, 0x12($27) /* set SVDSETUPEND */
+ li $22, 0 /* set EP0 to IDLE state */
+
+ep0_idle_state:
+ bnez $22, ep0_tx_state
+ nop
+
+ /* 2.1 Handle EP0 IDLE state interrupt */
+ andi $9, $11, 0x01 /* check OUTPKTRDY */
+ beqz $9, check_intr_ep1in
+ nop
+
+ /* Read 8-bytes setup packet from the FIFO */
+ lw $25, 0x20($27) /* first word of setup packet */
+ lw $26, 0x20($27) /* second word of setup packet */
+
+ andi $9, $25, 0x60 /* bRequestType & USB_TYPE_MASK */
+ beqz $9, _ep0_std_req
+ nop
+
+ /* 2.1.1 Vendor-specific setup request */
+_ep0_vend_req:
+ li $22, 0 /* set EP0 to IDLE state */
+ li $23, 1 /* NoData = 1 */
+
+ andi $9, $25, 0xff00 /* check bRequest */
+ srl $9, $9, 8
+ beqz $9, __ep0_get_cpu_info
+ sub $8, $9, 0x1
+ beqz $8, __ep0_set_data_address
+ sub $8, $9, 0x2
+ beqz $8, __ep0_set_data_length
+ sub $8, $9, 0x3
+ beqz $8, __ep0_flush_caches
+ sub $8, $9, 0x4
+ beqz $8, __ep0_prog_start1
+ sub $8, $9, 0x5
+ beqz $8, __ep0_prog_start2
+ nop
+ b _ep0_idle_state_fini /* invalid request */
+ nop
+
+__ep0_get_cpu_info:
+ load_addr $20, cpu_info_data /* data pointer to transfer */
+ li $21, 8 /* bytes left to transfer */
+ li $22, 1 /* set EP0 to TX state */
+ li $23, 0 /* NoData = 0 */
+
+ b _ep0_idle_state_fini
+ nop
+
+__ep0_set_data_address:
+ li $9, 0xffff0000
+ and $9, $25, $9
+ andi $8, $26, 0xffff
+ or $20, $9, $8 /* data address of next transfer */
+
+ b _ep0_idle_state_fini
+ nop
+
+__ep0_set_data_length:
+ li $9, 0xffff0000
+ and $9, $25, $9
+ andi $8, $26, 0xffff
+ or $21, $9, $8 /* data length of next transfer */
+
+ li $9, 0x48 /* SVDOUTPKTRDY and DATAEND */
+ sb $9, 0x12($27) /* CSR0 */
+
+ /* We must write packet to FIFO before EP1-IN interrupt here. */
+ b handle_epin1_intr
+ nop
+
+__ep0_flush_caches:
+ /* Flush dcache and invalidate icache. */
+ li $8, 0x80000000
+ addi $9, $8, 0x3fe0 /* total 16KB */
+
+1:
+ cache 0x0, 0($8) /* Index_Invalidate_I */
+ cache 0x1, 0($8) /* Index_Writeback_Inv_D */
+ bne $8, $9, 1b
+ addiu $8, $8, 32
+
+ /* flush write-buffer */
+ sync
+
+ /* Invalidate BTB */
+ mfc0 $8, $16, 7 /* CP0_CONFIG */
+ nop
+ ori $8, 2
+ mtc0 $8, $16, 7
+ nop
+
+ b _ep0_idle_state_fini
+ nop
+
+__ep0_prog_start1:
+ li $9, 0x48 /* SVDOUTPKTRDY and DATAEND */
+ sb $9, 0x12($27) /* CSR0 */
+
+ li $9, 0xffff0000
+ and $9, $25, $9
+ andi $8, $26, 0xffff
+ or $20, $9, $8 /* target address */
+
+ b xfer_d2i
+ li $19, 0x2000 /* 16KB data length */
+
+__ep0_prog_start2:
+ li $9, 0x48 /* SVDOUTPKTRDY and DATAEND */
+ sb $9, 0x12($27) /* CSR0 */
+
+ li $9, 0xffff0000
+ and $9, $25, $9
+ andi $8, $26, 0xffff
+ or $20, $9, $8 /* target address */
+
+ jalr $20 /* jump, and place the return address in $31 */
+ nop
+
+__ep0_prog_start2_return:
+ /* User code can return to here after executing itself, by jumping to $31. */
+ b usb_boot_return
+ nop
+
+ /* 2.1.2 Standard setup request */
+_ep0_std_req:
+ andi $12, $25, 0xff00 /* check bRequest */
+ srl $12, $12, 8
+ sub $9, $12, 0x05 /* check USB_REQ_SET_ADDRESS */
+ bnez $9, __ep0_req_set_config
+ nop
+
+ /* Handle USB_REQ_SET_ADDRESS */
+__ep0_req_set_addr:
+ srl $9, $25, 16 /* get wValue */
+ sb $9, 0x0($27) /* set FADDR */
+ li $23, 1 /* NoData = 1 */
+ b _ep0_idle_state_fini
+ nop
+
+__ep0_req_set_config:
+ sub $9, $12, 0x09 /* check USB_REQ_SET_CONFIGURATION */
+ bnez $9, __ep0_req_get_desc
+ nop
+
+ /* Handle USB_REQ_SET_CONFIGURATION */
+ li $23, 1 /* NoData = 1 */
+ b _ep0_idle_state_fini
+ nop
+
+__ep0_req_get_desc:
+ sub $9, $12, 0x06 /* check USB_REQ_GET_DESCRIPTOR */
+ bnez $9, _ep0_idle_state_fini
+ li $23, 1 /* NoData = 1 */
+
+ /* Handle USB_REQ_GET_DESCRIPTOR */
+ li $23, 0 /* NoData = 0 */
+
+ srl $9, $25, 24 /* wValue >> 8 */
+ sub $8, $9, 0x01 /* check USB_DT_DEVICE */
+ beqz $8, ___ep0_get_dev_desc
+ srl $21, $26, 16 /* get wLength */
+ sub $8, $9, 0x02 /* check USB_DT_CONFIG */
+ beqz $8, ___ep0_get_conf_desc
+ sub $8, $9, 0x03 /* check USB_DT_STRING */
+ beqz $8, ___ep0_get_string_desc
+ sub $8, $9, 0x06 /* check USB_DT_DEVICE_QUALIFIER */
+ beqz $8, ___ep0_get_dev_qualifier
+ nop
+ b _ep0_idle_state_fini
+ nop
+
+___ep0_get_dev_desc:
+ load_addr $20, device_desc /* data pointer */
+ li $22, 1 /* set EP0 to TX state */
+ sub $8, $21, 18
+ blez $8, _ep0_idle_state_fini /* wLength <= 18 */
+ nop
+ li $21, 18 /* max length of device_desc */
+ b _ep0_idle_state_fini
+ nop
+
+___ep0_get_dev_qualifier:
+ load_addr $20, dev_qualifier /* data pointer */
+ li $22, 1 /* set EP0 to TX state */
+ sub $8, $21, 10
+ blez $8, _ep0_idle_state_fini /* wLength <= 10 */
+ nop
+ li $21, 10 /* max length of dev_qualifier */
+ b _ep0_idle_state_fini
+ nop
+
+___ep0_get_conf_desc:
+ load_addr $20, config_desc_fs /* data pointer of FS mode */
+ lbu $8, 0x01($27) /* read POWER */
+ andi $8, 0x10 /* test HS_MODE */
+ beqz $8, ___ep0_get_conf_desc2
+ nop
+ load_addr $20, config_desc_hs /* data pointer of HS mode */
+
+___ep0_get_conf_desc2:
+ li $22, 1 /* set EP0 to TX state */
+ sub $8, $21, 32
+ blez $8, _ep0_idle_state_fini /* wLength <= 32 */
+ nop
+ li $21, 32 /* max length of config_desc */
+ b _ep0_idle_state_fini
+ nop
+
+___ep0_get_string_desc:
+ li $22, 1 /* set EP0 to TX state */
+
+ srl $9, $25, 16 /* wValue & 0xff */
+ andi $9, 0xff
+
+ sub $8, $9, 1
+ beqz $8, ___ep0_get_string_manufacture
+ sub $8, $9, 2
+ beqz $8, ___ep0_get_string_product
+ nop
+
+___ep0_get_string_lang_ids:
+ load_addr $20, string_lang_ids /* data pointer */
+ b _ep0_idle_state_fini
+ li $21, 4 /* data length */
+
+___ep0_get_string_manufacture:
+ load_addr $20, string_manufacture /* data pointer */
+ b _ep0_idle_state_fini
+ li $21, 16 /* data length */
+
+___ep0_get_string_product:
+ load_addr $20, string_product /* data pointer */
+ b _ep0_idle_state_fini
+ li $21, 46 /* data length */
+
+_ep0_idle_state_fini:
+ li $9, 0x40 /* SVDOUTPKTRDY */
+ beqz $23, _ep0_idle_state_fini2
+ nop
+ ori $9, $9, 0x08 /* DATAEND */
+_ep0_idle_state_fini2:
+ sb $9, 0x12($27) /* CSR0 */
+ beqz $22, check_intr_ep1in
+ nop
+
+ /* 2.2 Handle EP0 TX state interrupt */
+ep0_tx_state:
+ sub $9, $22, 1
+ bnez $9, check_intr_ep1in
+ nop
+
+ sub $9, $21, 64 /* max packetsize */
+ blez $9, _ep0_tx_state2 /* data count <= 64 */
+ ori $19, $21, 0
+ li $19, 64
+
+_ep0_tx_state2:
+ beqz $19, _ep0_tx_state3 /* send ZLP */
+ ori $18, $19, 0 /* record bytes to be transferred */
+ sub $21, $21, $19 /* decrement data count */
+
+_ep0_fifo_write_loop:
+ lbu $9, 0($20) /* read data */
+ sb $9, 0x20($27) /* load FIFO */
+ sub $19, $19, 1 /* decrement counter */
+ bnez $19, _ep0_fifo_write_loop
+ addi $20, $20, 1 /* increment data pointer */
+
+ sub $9, $18, 64 /* max packetsize */
+ beqz $9, _ep0_tx_state4
+ nop
+
+_ep0_tx_state3:
+ /* transferred bytes < max packetsize */
+ li $9, 0x0a /* set INPKTRDY and DATAEND */
+ sb $9, 0x12($27) /* CSR0 */
+ li $22, 0 /* set EP0 to IDLE state */
+ b check_intr_ep1in
+ nop
+
+_ep0_tx_state4:
+ /* transferred bytes == max packetsize */
+ li $9, 0x02 /* set INPKTRDY */
+ sb $9, 0x12($27) /* CSR0 */
+ b check_intr_ep1in
+ nop
+
+ /* 3. Check and handle EP1 BULK-IN interrupt */
+check_intr_ep1in:
+ andi $9, $10, 0x2 /* check EP1 IN interrupt */
+ beqz $9, check_intr_ep1out
+ nop
+
+handle_epin1_intr:
+ li $9, 1
+ sb $9, 0x0e($27) /* set INDEX 1 */
+ lbu $9, 0x12($27) /* read INCSR */
+
+ andi $8, $9, 0x2 /* check INCSR_FFNOTEMPT */
+ bnez $8, _epin1_tx_state4
+ nop
+
+_epin1_write_fifo:
+ lhu $9, 0x10($27) /* get INMAXP */
+ sub $8, $21, $9
+ blez $8, _epin1_tx_state1 /* bytes left <= INMAXP */
+ ori $19, $21, 0
+ ori $19, $9, 0
+
+_epin1_tx_state1:
+ beqz $19, _epin1_tx_state4 /* No data */
+ nop
+
+ sub $21, $21, $19 /* decrement data count */
+
+ srl $5, $19, 2 /* # of word */
+ andi $6, $19, 0x3 /* # of byte */
+ beqz $5, _epin1_tx_state2
+ nop
+
+_epin1_fifo_write_word:
+ lw $9, 0($20) /* read data from source address */
+ sw $9, 0x24($27) /* write FIFO */
+ sub $5, $5, 1 /* decrement counter */
+ bnez $5, _epin1_fifo_write_word
+ addiu $20, $20, 4 /* increment dest address */
+
+_epin1_tx_state2:
+ beqz $6, _epin1_tx_state3
+ nop
+
+_epin1_fifo_write_byte:
+ lbu $9, 0($20) /* read data from source address */
+ sb $9, 0x24($27) /* write FIFO */
+ sub $6, $6, 1 /* decrement counter */
+ bnez $6, _epin1_fifo_write_byte
+ addiu $20, $20, 1 /* increment dest address */
+
+_epin1_tx_state3:
+ li $9, 0x1
+ sb $9, 0x12($27) /* INCSR, set INPKTRDY */
+
+_epin1_tx_state4:
+
+ /* 4. Check and handle EP1 BULK-OUT interrupt */
+check_intr_ep1out:
+ lhu $9, 0x04($27) /* read INTROUT */
+ andi $9, 0x2
+ beqz $9, check_status_next
+ nop
+
+handle_epout1_intr:
+ li $9, 1
+ sb $9, 0x0e($27) /* set INDEX 1 */
+
+ lbu $9, 0x16($27) /* read OUTCSR */
+ andi $9, 0x1 /* check OUTPKTRDY */
+ beqz $9, check_status_next
+ nop
+
+_epout1_read_fifo:
+ lhu $19, 0x18($27) /* read OUTCOUNT */
+ srl $5, $19, 2 /* # of word */
+ andi $6, $19, 0x3 /* # of byte */
+ beqz $5, _epout1_rx_state1
+ nop
+
+_epout1_fifo_read_word:
+ lw $9, 0x24($27) /* read FIFO */
+ sw $9, 0($20) /* store to dest address */
+ sub $5, $5, 1 /* decrement counter */
+ bnez $5, _epout1_fifo_read_word
+ addiu $20, $20, 4 /* increment dest address */
+
+_epout1_rx_state1:
+ beqz $6, _epout1_rx_state2
+ nop
+
+_epout1_fifo_read_byte:
+ lbu $9, 0x24($27) /* read FIFO */
+ sb $9, 0($20) /* store to dest address */
+ sub $6, $6, 1 /* decrement counter */
+ bnez $6, _epout1_fifo_read_byte
+ addiu $20, $20, 1 /* increment dest address */
+
+_epout1_rx_state2:
+ sb $0, 0x16($27) /* clear OUTPKTRDY */
+
+check_status_next:
+ b usb_command_loop
+ nop
+
+/* Device/Configuration/Interface/Endpoint/String Descriptors */
+
+ .align 2
+device_desc:
+ .byte 0x12 /* bLength */
+ .byte 0x01 /* bDescriptorType */
+ .byte 0x00 /* bcdUSB */
+ .byte 0x02 /* bcdUSB */
+ .byte 0x00 /* bDeviceClass */
+ .byte 0x00 /* bDeviceSubClass */
+ .byte 0x00 /* bDeviceProtocol */
+ .byte 0x40 /* bMaxPacketSize0 */
+ .byte 0x1a /* idVendor */
+ .byte 0x60 /* idVendor */
+ .byte 0x40 /* idProduct */
+ .byte 0x47 /* idProduct */
+ .byte 0x00 /* bcdDevice */
+ .byte 0x01 /* bcdDevice */
+ .byte 0x01 /* iManufacturer */
+ .byte 0x02 /* iProduct */
+ .byte 0x00 /* iSerialNumber */
+ .byte 0x01 /* bNumConfigurations */
+
+ .align 2
+dev_qualifier:
+ .byte 0x0a /* bLength */
+ .byte 0x06 /* bDescriptorType */
+ .byte 0x00 /* bcdUSB */
+ .byte 0x02 /* bcdUSB */
+ .byte 0x00 /* bDeviceClass */
+ .byte 0x00 /* bDeviceSubClass */
+ .byte 0x00 /* bDeviceProtocol */
+ .byte 0x40 /* bMaxPacketSize0 */
+ .byte 0x01 /* bNumConfigurations */
+ .byte 0x00 /* bRESERVED */
+
+ .align 2
+config_desc_hs:
+ .byte 0x09 /* bLength */
+ .byte 0x02 /* bDescriptorType */
+ .byte 0x20 /* wTotalLength */
+ .byte 0x00 /* wTotalLength */
+ .byte 0x01 /* bNumInterfaces */
+ .byte 0x01 /* bConfigurationValue */
+ .byte 0x00 /* iConfiguration */
+ .byte 0xc0 /* bmAttributes */
+ .byte 0x01 /* MaxPower */
+intf_desc_hs:
+ .byte 0x09 /* bLength */
+ .byte 0x04 /* bDescriptorType */
+ .byte 0x00 /* bInterfaceNumber */
+ .byte 0x00 /* bAlternateSetting */
+ .byte 0x02 /* bNumEndpoints */
+ .byte 0xff /* bInterfaceClass */
+ .byte 0x00 /* bInterfaceSubClass */
+ .byte 0x50 /* bInterfaceProtocol */
+ .byte 0x00 /* iInterface */
+ep1_desc_hs:
+ .byte 0x07 /* bLength */
+ .byte 0x05 /* bDescriptorType */
+ .byte 0x01 /* bEndpointAddress */
+ .byte 0x02 /* bmAttributes */
+ .byte 0x00 /* wMaxPacketSize */
+ .byte 0x02 /* wMaxPacketSize */
+ .byte 0x00 /* bInterval */
+ep2_desc_hs:
+ .byte 0x07 /* bLength */
+ .byte 0x05 /* bDescriptorType */
+ .byte 0x81 /* bEndpointAddress */
+ .byte 0x02 /* bmAttributes */
+ .byte 0x00 /* wMaxPacketSize */
+ .byte 0x02 /* wMaxPacketSize */
+ .byte 0x00 /* bInterval */
+
+ .align 2
+config_desc_fs:
+ .byte 0x09 /* bLength */
+ .byte 0x02 /* bDescriptorType */
+ .byte 0x20 /* wTotalLength */
+ .byte 0x00 /* wTotalLength */
+ .byte 0x01 /* bNumInterfaces */
+ .byte 0x01 /* bConfigurationValue */
+ .byte 0x00 /* iConfiguration */
+ .byte 0xc0 /* bmAttributes */
+ .byte 0x01 /* MaxPower */
+intf_desc_fs:
+ .byte 0x09 /* bLength */
+ .byte 0x04 /* bDescriptorType */
+ .byte 0x00 /* bInterfaceNumber */
+ .byte 0x00 /* bAlternateSetting */
+ .byte 0x02 /* bNumEndpoints */
+ .byte 0xff /* bInterfaceClass */
+ .byte 0x00 /* bInterfaceSubClass */
+ .byte 0x50 /* bInterfaceProtocol */
+ .byte 0x00 /* iInterface */
+ep1_desc_fs:
+ .byte 0x07 /* bLength */
+ .byte 0x05 /* bDescriptorType */
+ .byte 0x01 /* bEndpointAddress */
+ .byte 0x02 /* bmAttributes */
+ .byte 0x40 /* wMaxPacketSize */
+ .byte 0x00 /* wMaxPacketSize */
+ .byte 0x00 /* bInterval */
+ep2_desc_fs:
+ .byte 0x07 /* bLength */
+ .byte 0x05 /* bDescriptorType */
+ .byte 0x81 /* bEndpointAddress */
+ .byte 0x02 /* bmAttributes */
+ .byte 0x40 /* wMaxPacketSize */
+ .byte 0x00 /* wMaxPacketSize */
+ .byte 0x00 /* bInterval */
+
+ .align 2
+string_lang_ids:
+ .byte 0x04
+ .byte 0x03
+ .byte 0x09
+ .byte 0x04
+
+ .align 2
+string_manufacture:
+ .byte 0x10
+ .byte 0x03
+ .byte 0x49
+ .byte 0x00
+ .byte 0x6e
+ .byte 0x00
+ .byte 0x67
+ .byte 0x00
+ .byte 0x65
+ .byte 0x00
+ .byte 0x6e
+ .byte 0x00
+ .byte 0x69
+ .byte 0x00
+ .byte 0x63
+ .byte 0x00
+
+ .align 2
+string_product:
+ .byte 0x2e
+ .byte 0x03
+ .byte 0x4a
+ .byte 0x00
+ .byte 0x5a
+ .byte 0x00
+ .byte 0x34
+ .byte 0x00
+ .byte 0x37
+ .byte 0x00
+ .byte 0x34
+ .byte 0x00
+ .byte 0x30
+ .byte 0x00
+ .byte 0x20
+ .byte 0x00
+ .byte 0x55
+ .byte 0x00
+ .byte 0x53
+ .byte 0x00
+ .byte 0x42
+ .byte 0x00
+ .byte 0x20
+ .byte 0x00
+ .byte 0x42
+ .byte 0x00
+ .byte 0x6f
+ .byte 0x00
+ .byte 0x6f
+ .byte 0x00
+ .byte 0x74
+ .byte 0x00
+ .byte 0x20
+ .byte 0x00
+ .byte 0x44
+ .byte 0x00
+ .byte 0x65
+ .byte 0x00
+ .byte 0x76
+ .byte 0x00
+ .byte 0x69
+ .byte 0x00
+ .byte 0x63
+ .byte 0x00
+ .byte 0x65
+ .byte 0x00
+
+ .align 2
+cpu_info_data:
+ .byte 0x4a
+ .byte 0x5a
+ .byte 0x34
+ .byte 0x37
+ .byte 0x34
+ .byte 0x30
+ .byte 0x56
+ .byte 0x31
+usbboot_end:
+
+ .set reorder
--
1.7.0.4