From patchwork Wed Dec 8 06:20:43 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xiangfu Liu X-Patchwork-Id: 74639 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id 43B02B70DF for ; Wed, 8 Dec 2010 17:22:29 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 1D198280C1; Wed, 8 Dec 2010 07:22:26 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id jgIb5TeYRVGT; Wed, 8 Dec 2010 07:22:25 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 7C261280B3; Wed, 8 Dec 2010 07:22:23 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 5E7FB280B3 for ; Wed, 8 Dec 2010 07:22:20 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id krdZbFBdNSmk for ; Wed, 8 Dec 2010 07:22:16 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-pw0-f44.google.com (mail-pw0-f44.google.com [209.85.160.44]) by theia.denx.de (Postfix) with ESMTP id 088AB280B1 for ; Wed, 8 Dec 2010 07:22:13 +0100 (CET) Received: by pwi7 with SMTP id 7so203888pwi.3 for ; Tue, 07 Dec 2010 22:22:12 -0800 (PST) Received: by 10.142.128.18 with SMTP id a18mr2011497wfd.267.1291789331499; Tue, 07 Dec 2010 22:22:11 -0800 (PST) Received: from localhost.localdomain ([124.205.34.122]) by mx.google.com with ESMTPS id y42sm351042wfd.10.2010.12.07.22.21.51 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 07 Dec 2010 22:22:09 -0800 (PST) From: Xiangfu Liu To: u-boot@lists.denx.de Date: Wed, 8 Dec 2010 14:20:43 +0800 Message-Id: <1291789249-4287-2-git-send-email-xiangfu@openmobilefree.net> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1291789249-4287-1-git-send-email-xiangfu@openmobilefree.net> References: <1291789249-4287-1-git-send-email-xiangfu@openmobilefree.net> Subject: [U-Boot] [PATCH v4 1/7] those files are jz4740 base files X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.9 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de Signed-off-by: Xiangfu Liu --- 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@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, +# +# 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, + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#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, + * + * 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 +#include +#include +#include + +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, + * + * 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 +#include +#include +#include + +/* + * 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 + * + * 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 +#include +#include +#include +#include +#include + +#include + + .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 + * + * 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 +#include +#include +#include +#include +#include + +#include + + .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, + * + * 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 +#include + +#include +#include + +/* + * 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: + * + * 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