mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
917 lines
22 KiB
Diff
917 lines
22 KiB
Diff
|
From fa51192b912d296b8eec10f7d44c6c17eb1dd368 Mon Sep 17 00:00:00 2001
|
||
|
From: Xiangfu <xiangfu@openmobilefree.net>
|
||
|
Date: Fri, 12 Oct 2012 09:47:39 +0800
|
||
|
Subject: [PATCH 2/6] qi_lb60: add software usbboot support
|
||
|
|
||
|
JZ4740 CPU have a internal ROM have such kind of code, that make
|
||
|
JZ4740 can boot from USB
|
||
|
|
||
|
usbboot.S can downloads user program from the USB port to internal
|
||
|
SRAM and branches to the internal SRAM to execute the program
|
||
|
|
||
|
Signed-off-by: Xiangfu <xiangfu@openmobilefree.net>
|
||
|
---
|
||
|
board/qi/qi_lb60/Makefile | 1 +
|
||
|
board/qi/qi_lb60/qi_lb60-spl.c | 20 +
|
||
|
board/qi/qi_lb60/usbboot.S | 838 ++++++++++++++++++++++++++++++++++++++++
|
||
|
3 files changed, 859 insertions(+)
|
||
|
create mode 100644 board/qi/qi_lb60/usbboot.S
|
||
|
|
||
|
diff --git a/board/qi/qi_lb60/Makefile b/board/qi/qi_lb60/Makefile
|
||
|
index e399246..6dd8c6f 100644
|
||
|
--- a/board/qi/qi_lb60/Makefile
|
||
|
+++ b/board/qi/qi_lb60/Makefile
|
||
|
@@ -23,6 +23,7 @@ include $(TOPDIR)/config.mk
|
||
|
LIB = $(obj)lib$(BOARD).o
|
||
|
|
||
|
ifeq ($(CONFIG_SPL_BUILD),y)
|
||
|
+SOBJS := usbboot.o
|
||
|
COBJS := $(BOARD)-spl.o
|
||
|
else
|
||
|
COBJS := $(BOARD).o
|
||
|
diff --git a/board/qi/qi_lb60/qi_lb60-spl.c b/board/qi/qi_lb60/qi_lb60-spl.c
|
||
|
index 3fe3fa3..aea459c 100644
|
||
|
--- a/board/qi/qi_lb60/qi_lb60-spl.c
|
||
|
+++ b/board/qi/qi_lb60/qi_lb60-spl.c
|
||
|
@@ -12,6 +12,24 @@
|
||
|
#include <asm/io.h>
|
||
|
#include <asm/jz4740.h>
|
||
|
|
||
|
+#define KEY_U_OUT (32 * 2 + 16)
|
||
|
+#define KEY_U_IN (32 * 3 + 19)
|
||
|
+
|
||
|
+extern void usb_boot(void);
|
||
|
+
|
||
|
+static void check_usb_boot(void)
|
||
|
+{
|
||
|
+ __gpio_as_input(KEY_U_IN);
|
||
|
+ __gpio_enable_pull(KEY_U_IN);
|
||
|
+ __gpio_as_output(KEY_U_OUT);
|
||
|
+ __gpio_clear_pin(KEY_U_OUT);
|
||
|
+
|
||
|
+ if (!__gpio_get_pin(KEY_U_IN)) {
|
||
|
+ puts("[U] pressed, goto USBBOOT mode\n");
|
||
|
+ usb_boot();
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
void nand_spl_boot(void)
|
||
|
{
|
||
|
__gpio_as_sdram_16bit_4720();
|
||
|
@@ -23,6 +41,8 @@ void nand_spl_boot(void)
|
||
|
pll_init();
|
||
|
sdram_init();
|
||
|
|
||
|
+ check_usb_boot();
|
||
|
+
|
||
|
nand_init();
|
||
|
|
||
|
puts("\nQi LB60 SPL: Starting U-Boot ...\n");
|
||
|
diff --git a/board/qi/qi_lb60/usbboot.S b/board/qi/qi_lb60/usbboot.S
|
||
|
new file mode 100644
|
||
|
index 0000000..c872266
|
||
|
--- /dev/null
|
||
|
+++ b/board/qi/qi_lb60/usbboot.S
|
||
|
@@ -0,0 +1,838 @@
|
||
|
+/*
|
||
|
+ * 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.9.5
|
||
|
|