aboutsummaryrefslogtreecommitdiffstats
path: root/package/boot/uboot-xburst/patches
diff options
context:
space:
mode:
authorMirko Vogt <mirko@openwrt.org>2013-01-07 14:10:01 +0000
committerMirko Vogt <mirko@openwrt.org>2013-01-07 14:10:01 +0000
commit12a6622bd938614b9758d20d136c78a0c67e7155 (patch)
tree7d85ef4c53b7d36975b36a83369786d622f8c268 /package/boot/uboot-xburst/patches
parentc86485210ba6136bc90fc2708611ae5a609b6bf1 (diff)
downloadupstream-12a6622bd938614b9758d20d136c78a0c67e7155.tar.gz
upstream-12a6622bd938614b9758d20d136c78a0c67e7155.tar.bz2
upstream-12a6622bd938614b9758d20d136c78a0c67e7155.zip
This patch updates uboot-xburst from 2009.11 to 2012.10-rc2 - Ingenic SoC support went upstream
Summary: * remove all files/* (since merged to upstream) * patches on nand-spl, mmc and lcd driver Thanks a lot to Xiangfu Liu! Signed-off-by: Xiangfu Liu <xiangfu@sharism.cc> SVN-Revision: 35034
Diffstat (limited to 'package/boot/uboot-xburst/patches')
-rw-r--r--package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch894
-rw-r--r--package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch916
-rw-r--r--package/boot/uboot-xburst/patches/0003-add-mmc-support.patch1664
-rw-r--r--package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch200
-rw-r--r--package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch847
-rw-r--r--package/boot/uboot-xburst/patches/0006-enable-silent-console.patch60
-rw-r--r--package/boot/uboot-xburst/patches/001-xburst.patch1669
-rw-r--r--package/boot/uboot-xburst/patches/005-i2c.patch13
-rw-r--r--package/boot/uboot-xburst/patches/009-n516.patch23
-rw-r--r--package/boot/uboot-xburst/patches/010-sakc.patch32
10 files changed, 4581 insertions, 1737 deletions
diff --git a/package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch b/package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch
new file mode 100644
index 0000000000..e770243528
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0001-qi_lb60-add-nand-spl-support.patch
@@ -0,0 +1,894 @@
+From 0329cf7965956a5a7044827e0ce88ae8d5150e54 Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Fri, 12 Oct 2012 09:46:58 +0800
+Subject: [PATCH 1/6] qi_lb60: add nand spl support
+
+ The JZ4740 CPU can load 8KB from two different addresses:
+ 1. the normal area up to 8KB starting from NAND flash address 0x00000000
+ 2. the backup area up to 8KB starting from NAND flash address 0x00002000
+
+Signed-off-by: Xiangfu <xiangfu@openmobilefree.net>
+---
+ Makefile | 12 +++
+ arch/mips/cpu/xburst/Makefile | 7 +-
+ arch/mips/cpu/xburst/cpu.c | 4 +
+ arch/mips/cpu/xburst/jz4740.c | 82 +++++++----------
+ arch/mips/cpu/xburst/spl/Makefile | 47 ++++++++++
+ arch/mips/cpu/xburst/spl/start.S | 63 +++++++++++++
+ board/qi/qi_lb60/Makefile | 4 +
+ board/qi/qi_lb60/qi_lb60-spl.c | 30 +++++++
+ board/qi/qi_lb60/qi_lb60.c | 8 +-
+ board/qi/qi_lb60/u-boot-spl.lds | 61 +++++++++++++
+ drivers/mtd/nand/jz4740_nand.c | 39 ++++++++-
+ include/configs/qi_lb60.h | 175 ++++++++++++++++++-------------------
+ 12 files changed, 386 insertions(+), 146 deletions(-)
+ create mode 100644 arch/mips/cpu/xburst/spl/Makefile
+ create mode 100644 arch/mips/cpu/xburst/spl/start.S
+ create mode 100644 board/qi/qi_lb60/qi_lb60-spl.c
+ create mode 100644 board/qi/qi_lb60/u-boot-spl.lds
+
+diff --git a/Makefile b/Makefile
+index 34d9075..a22778e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -393,6 +393,10 @@ ALL-y += $(obj)u-boot-nodtb-tegra.bin
+ endif
+ endif
+
++ifeq ($(CPU),xburst)
++ALL-y += $(obj)u-boot-xburst.bin
++endif
++
+ all: $(ALL-y) $(SUBDIR_EXAMPLES)
+
+ $(obj)u-boot.dtb: $(obj)u-boot
+@@ -506,6 +510,14 @@ $(obj)u-boot-nodtb-tegra.bin: $(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
+ endif
+ endif
+
++ifeq ($(CPU),xburst)
++$(obj)u-boot-xburst.bin: $(obj)spl/u-boot-spl.bin $(obj)u-boot.bin
++ dd if=$(obj)spl/u-boot-spl.bin of=$(obj)spl/u-boot-pad.bin conv=sync bs=8192 count=1
++ dd if=$(obj)spl/u-boot-spl.bin of=$(obj)spl/u-boot-pad.bin conv=sync,notrunc oflag=append bs=8192 count=1
++ tr '\0' '\377' < /dev/zero | dd of=$(obj)spl/u-boot-pad.bin conv=sync,notrunc oflag=append bs=16384 count=1
++ cat $(obj)spl/u-boot-pad.bin u-boot.bin > $@
++endif
++
+ ifeq ($(CONFIG_SANDBOX),y)
+ GEN_UBOOT = \
+ cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
+diff --git a/arch/mips/cpu/xburst/Makefile b/arch/mips/cpu/xburst/Makefile
+index b1f2ae4..ec35e55 100644
+--- a/arch/mips/cpu/xburst/Makefile
++++ b/arch/mips/cpu/xburst/Makefile
+@@ -24,9 +24,12 @@ include $(TOPDIR)/config.mk
+
+ LIB = $(obj)lib$(CPU).o
+
++COBJS-y = cpu.o jz_serial.o
++
++ifneq ($(CONFIG_SPL_BUILD),y)
+ START = start.o
+-SOBJS-y =
+-COBJS-y = cpu.o timer.o jz_serial.o
++COBJS-y += timer.o
++endif
+
+ COBJS-$(CONFIG_JZ4740) += jz4740.o
+
+diff --git a/arch/mips/cpu/xburst/cpu.c b/arch/mips/cpu/xburst/cpu.c
+index ddcbfaa..1432838 100644
+--- a/arch/mips/cpu/xburst/cpu.c
++++ b/arch/mips/cpu/xburst/cpu.c
+@@ -42,6 +42,8 @@
+ : \
+ : "i" (op), "R" (*(unsigned char *)(addr)))
+
++#ifndef CONFIG_SPL_BUILD
++
+ void __attribute__((weak)) _machine_restart(void)
+ {
+ struct jz4740_wdt *wdt = (struct jz4740_wdt *)JZ4740_WDT_BASE;
+@@ -109,6 +111,8 @@ void invalidate_dcache_range(ulong start_addr, ulong stop)
+ cache_op(Hit_Invalidate_D, addr);
+ }
+
++#endif
++
+ void flush_icache_all(void)
+ {
+ u32 addr, t = 0;
+diff --git a/arch/mips/cpu/xburst/jz4740.c b/arch/mips/cpu/xburst/jz4740.c
+index c0b9817..8816aa3 100644
+--- a/arch/mips/cpu/xburst/jz4740.c
++++ b/arch/mips/cpu/xburst/jz4740.c
+@@ -32,31 +32,19 @@ 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)
+ {
+ struct jz4740_cpm *cpm = (struct jz4740_cpm *)JZ4740_CPM_BASE;
+
+- 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;
++ register unsigned int cfcr, plcr;
++ unsigned 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);
++ (0 << CPM_CPCCR_CDIV_BIT) |
++ (2 << CPM_CPCCR_HDIV_BIT) |
++ (2 << CPM_CPCCR_PDIV_BIT) |
++ (2 << CPM_CPCCR_MDIV_BIT) |
++ (2 << CPM_CPCCR_LDIV_BIT);
+
+ pllout2 = (cfcr & CPM_CPCCR_PCS) ?
+ CONFIG_SYS_CPU_SPEED : (CONFIG_SYS_CPU_SPEED / 2);
+@@ -65,15 +53,18 @@ void pll_init(void)
+ writel(pllout2 / 48000000 - 1, &cpm->uhccdr);
+
+ nf = CONFIG_SYS_CPU_SPEED * 2 / CONFIG_SYS_EXTAL;
+- plcr1 = ((nf - 2) << CPM_CPPCR_PLLM_BIT) | /* FD */
++ plcr = ((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 */
++ (0x32 << CPM_CPPCR_PLLST_BIT) | /* PLL stable time */
+ CPM_CPPCR_PLLEN; /* enable PLL */
+
+ /* init PLL */
+ writel(cfcr, &cpm->cpccr);
+- writel(plcr1, &cpm->cppcr);
++ writel(plcr, &cpm->cppcr);
++
++ while (!(readl(&cpm->cppcr) & CPM_CPPCR_PLLS))
++ ;
+ }
+
+ void sdram_init(void)
+@@ -92,26 +83,12 @@ void sdram_init(void)
+ 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()];
++ mem_clk = 84000000;
+
+ 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) |
+@@ -128,31 +105,31 @@ void sdram_init(void)
+ if (tmp > 11)
+ tmp = 11;
+ dmcr |= (tmp - 4) << EMC_DMCR_TRAS_BIT;
+- tmp = SDRAM_RCD / ns;
+
++ tmp = SDRAM_RCD / ns;
+ if (tmp > 3)
+ tmp = 3;
+ dmcr |= tmp << EMC_DMCR_RCD_BIT;
+- tmp = SDRAM_TPC / ns;
+
++ tmp = SDRAM_TPC / ns;
+ if (tmp > 7)
+ tmp = 7;
+ dmcr |= tmp << EMC_DMCR_TPC_BIT;
+- tmp = SDRAM_TRWL / ns;
+
++ tmp = SDRAM_TRWL / ns;
+ if (tmp > 3)
+ tmp = 3;
+ dmcr |= tmp << EMC_DMCR_TRWL_BIT;
+- tmp = (SDRAM_TRAS + SDRAM_TPC) / ns;
+
++ 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 |
++ 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 */
+@@ -172,8 +149,8 @@ void sdram_init(void)
+ 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 */
+@@ -182,13 +159,17 @@ void sdram_init(void)
+ ;
+
+ /* Stage 3. Mode Register Set */
++ dmcr0 = (11 << EMC_DMCR_RA_BIT) |
++ (8 << EMC_DMCR_CA_BIT) |
++ (0 << EMC_DMCR_BA_BIT) |
++ EMC_DMCR_EPIN |
++ (SDRAM_BW16 << EMC_DMCR_BW_BIT) |
++ cas_latency_dmcr[((SDRAM_CASL == 3) ? 1 : 0)];
+ writel(dmcr0 | EMC_DMCR_RFSH | EMC_DMCR_MRSET, &emc->dmcr);
+ writeb(0, JZ4740_EMC_SDMR0 | sdmode);
+
+ /* Set back to basic DMCR value */
+ writel(dmcr | EMC_DMCR_RFSH | EMC_DMCR_MRSET, &emc->dmcr);
+-
+- /* everything is ok now */
+ }
+
+ DECLARE_GLOBAL_DATA_PTR;
+@@ -232,9 +213,10 @@ void rtc_init(void)
+ phys_size_t initdram(int board_type)
+ {
+ struct jz4740_emc *emc = (struct jz4740_emc *)JZ4740_EMC_BASE;
+- u32 dmcr;
+- u32 rows, cols, dw, banks;
+- ulong size;
++
++ unsigned int dmcr;
++ unsigned int rows, cols, dw, banks;
++ unsigned long size;
+
+ dmcr = readl(&emc->dmcr);
+ rows = 11 + ((dmcr & EMC_DMCR_RA_MASK) >> EMC_DMCR_RA_BIT);
+diff --git a/arch/mips/cpu/xburst/spl/Makefile b/arch/mips/cpu/xburst/spl/Makefile
+new file mode 100644
+index 0000000..f45e8c8
+--- /dev/null
++++ b/arch/mips/cpu/xburst/spl/Makefile
+@@ -0,0 +1,47 @@
++#
++# Copyright (C) 2011 Xiangfu Liu <xiangfu@openmobilefree.net>
++#
++# 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 =
++
++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/spl/start.S b/arch/mips/cpu/xburst/spl/start.S
+new file mode 100644
+index 0000000..e31c4c8
+--- /dev/null
++++ b/arch/mips/cpu/xburst/spl/start.S
+@@ -0,0 +1,63 @@
++/*
++ * Copyright (c) 2010 Xiangfu Liu <xiangfu@openmobilefree.net>
++ *
++ * 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_spl_boot
++ j t9
++ nop
+diff --git a/board/qi/qi_lb60/Makefile b/board/qi/qi_lb60/Makefile
+index 5dae11b..e399246 100644
+--- a/board/qi/qi_lb60/Makefile
++++ b/board/qi/qi_lb60/Makefile
+@@ -22,7 +22,11 @@ include $(TOPDIR)/config.mk
+
+ LIB = $(obj)lib$(BOARD).o
+
++ifeq ($(CONFIG_SPL_BUILD),y)
++COBJS := $(BOARD)-spl.o
++else
+ COBJS := $(BOARD).o
++endif
+
+ SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
+ OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
+diff --git a/board/qi/qi_lb60/qi_lb60-spl.c b/board/qi/qi_lb60/qi_lb60-spl.c
+new file mode 100644
+index 0000000..3fe3fa3
+--- /dev/null
++++ b/board/qi/qi_lb60/qi_lb60-spl.c
+@@ -0,0 +1,30 @@
++/*
++ * Authors: Xiangfu Liu <xiangfu@openmobilefree.cc>
++ *
++ * 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.
++ */
++
++#include <common.h>
++#include <nand.h>
++#include <asm/io.h>
++#include <asm/jz4740.h>
++
++void nand_spl_boot(void)
++{
++ __gpio_as_sdram_16bit_4720();
++ __gpio_as_uart0();
++ __gpio_jtag_to_uart0();
++
++ serial_init();
++
++ pll_init();
++ sdram_init();
++
++ nand_init();
++
++ puts("\nQi LB60 SPL: Starting U-Boot ...\n");
++ nand_boot();
++}
+diff --git a/board/qi/qi_lb60/qi_lb60.c b/board/qi/qi_lb60/qi_lb60.c
+index d975209..3bd4e2f 100644
+--- a/board/qi/qi_lb60/qi_lb60.c
++++ b/board/qi/qi_lb60/qi_lb60.c
+@@ -1,5 +1,5 @@
+ /*
+- * Authors: Xiangfu Liu <xiangfu@sharism.cc>
++ * Authors: Xiangfu Liu <xiangfu@openmobilefree.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -97,8 +97,10 @@ int board_early_init_f(void)
+ /* U-Boot common routines */
+ int checkboard(void)
+ {
+- printf("Board: Qi LB60 (Ingenic XBurst Jz4740 SoC, Speed %ld MHz)\n",
+- gd->cpu_clk / 1000000);
++ printf("Board: Qi LB60 (Ingenic XBurst Jz4740 SoC)\n");
++ printf(" CPU: %ld\n", gd->cpu_clk);
++ printf(" MEM: %ld\n", gd->mem_clk);
++ printf(" DEV: %ld\n", gd->dev_clk);
+
+ return 0;
+ }
+diff --git a/board/qi/qi_lb60/u-boot-spl.lds b/board/qi/qi_lb60/u-boot-spl.lds
+new file mode 100644
+index 0000000..930537f
+--- /dev/null
++++ b/board/qi/qi_lb60/u-boot-spl.lds
+@@ -0,0 +1,61 @@
++/*
++ * (C) Copyright 2012 Xiangfu Liu <xiangfu@openmobilefree.net>
++ *
++ * 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
++ */
++
++OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradlittlemips", "elf32-tradlittlemips")
++
++OUTPUT_ARCH(mips)
++ENTRY(_start)
++SECTIONS
++{
++ . = 0x80000000;
++ . = ALIGN(4);
++ .text :
++ {
++ *(.text)
++ }
++
++ . = ALIGN(4);
++ .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
++
++ . = ALIGN(4);
++ .data : { *(.data) }
++
++ . = ALIGN(4);
++ .sdata : { *(.sdata) }
++
++ _gp = ALIGN(16);
++
++ __got_start = .;
++ .got : { *(.got) }
++ __got_end = .;
++
++ . = .;
++ __u_boot_cmd_start = .;
++ .u_boot_cmd : { *(.u_boot_cmd) }
++ __u_boot_cmd_end = .;
++
++ uboot_end_data = .;
++ num_got_entries = (__got_end - __got_start) >> 2;
++
++ . = ALIGN(4);
++ .sbss : { *(.sbss) }
++ .bss : { *(.bss) }
++ uboot_end = .;
++}
++ASSERT(uboot_end <= 0x80002000, "NAND bootstrap too big");
+diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
+index 3ec34f3..24a4921 100644
+--- a/drivers/mtd/nand/jz4740_nand.c
++++ b/drivers/mtd/nand/jz4740_nand.c
+@@ -15,6 +15,9 @@
+ #include <asm/io.h>
+ #include <asm/jz4740.h>
+
++#ifdef CONFIG_SPL_BUILD
++#define printf(s) puts(s)
++#endif
+ #define JZ_NAND_DATA_ADDR ((void __iomem *)0xB8000000)
+ #define JZ_NAND_CMD_ADDR (JZ_NAND_DATA_ADDR + 0x8000)
+ #define JZ_NAND_ADDR_ADDR (JZ_NAND_DATA_ADDR + 0x10000)
+@@ -176,7 +179,7 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ for (k = 0; k < 9; k++)
+ writeb(read_ecc[k], &emc->nfpar[k]);
+ }
+- /* Set PRDY */
++
+ writel(readl(&emc->nfecr) | EMC_NFECR_PRDY, &emc->nfecr);
+
+ /* Wait for completion */
+@@ -184,7 +187,7 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ status = readl(&emc->nfints);
+ } while (!(status & EMC_NFINTS_DECF));
+
+- /* disable ecc */
++ /* Disable ECC */
+ writel(readl(&emc->nfecr) & ~EMC_NFECR_ECCE, &emc->nfecr);
+
+ /* Check decoding */
+@@ -192,7 +195,7 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ return 0;
+
+ if (status & EMC_NFINTS_UNCOR) {
+- printf("uncorrectable ecc\n");
++ printf("JZ4740 uncorrectable ECC\n");
+ return -1;
+ }
+
+@@ -230,6 +233,32 @@ static int jz_nand_rs_correct_data(struct mtd_info *mtd, u_char *dat,
+ return errcnt;
+ }
+
++#ifdef CONFIG_SPL_BUILD
++static void jz_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++ int i;
++ struct nand_chip *this = mtd->priv;
++
++#if (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R3) || \
++ (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B16R2)
++ for (i = 0; i < len; i += 2)
++ buf[i] = readw(this->IO_ADDR_R);
++#elif (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R3) || \
++ (JZ4740_NANDBOOT_CFG == JZ4740_NANDBOOT_B8R2)
++ for (i = 0; i < len; i++)
++ buf[i] = readb(this->IO_ADDR_R);
++#else
++ #error JZ4740_NANDBOOT_CFG not defined or wrong
++#endif
++}
++
++static uint8_t jz_nand_read_byte(struct mtd_info *mtd)
++{
++ struct nand_chip *this = mtd->priv;
++ return readb(this->IO_ADDR_R);
++}
++#endif
++
+ /*
+ * Main initialization routine
+ */
+@@ -254,6 +283,10 @@ int board_nand_init(struct nand_chip *nand)
+ nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE;
+ nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES;
+ nand->ecc.layout = &qi_lb60_ecclayout_2gb;
++#ifdef CONFIG_SPL_BUILD
++ nand->read_byte = jz_nand_read_byte;
++ nand->read_buf = jz_nand_read_buf;
++#endif
+ nand->chip_delay = 50;
+ nand->options = NAND_USE_FLASH_BBT;
+
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 4bb5bbc..7bff444 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -1,5 +1,5 @@
+ /*
+- * Authors: Xiangfu Liu <xiangfu.z@gmail.com>
++ * Authors: Xiangfu Liu <xiangfu@openmobilefree.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+@@ -14,7 +14,6 @@
+ #define CONFIG_SYS_LITTLE_ENDIAN
+ #define CONFIG_JZSOC /* Jz SoC */
+ #define CONFIG_JZ4740 /* Jz4740 SoC */
+-#define CONFIG_NAND_JZ4740
+
+ #define CONFIG_SYS_CPU_SPEED 336000000 /* CPU clock: 336 MHz */
+ #define CONFIG_SYS_EXTAL 12000000 /* EXTAL freq: 12 MHz */
+@@ -24,24 +23,43 @@
+ #define CONFIG_SYS_UART_BASE JZ4740_UART0_BASE /* Base of the UART channel */
+ #define CONFIG_BAUDRATE 57600
+
++#define CONFIG_BOOTP_MASK (CONFIG_BOOTP_DEFAUL)
++#define CONFIG_BOOTDELAY 0
++#define CONFIG_BOOTARGS "mem=32M console=tty0 console=ttyS0,57600n8 ubi.mtd=2 rootfstype=ubifs root=ubi0:rootfs rw rootwait"
++#define CONFIG_BOOTCOMMAND "nand read 0x80600000 0x400000 0x280000;bootm"
++
++/*
++ * Miscellaneous configurable options
++ */
++#define CONFIG_SYS_SDRAM_BASE 0x80000000 /* Cached addr */
++#define CONFIG_SYS_INIT_SP_OFFSET 0x400000
++#define CONFIG_SYS_LOAD_ADDR 0x80600000
++#define CONFIG_SYS_MEMTEST_START 0x80100000
++#define CONFIG_SYS_MEMTEST_END 0x80A00000
++#define CONFIG_SYS_TEXT_BASE 0x80100000
++#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
++
++#define CONFIG_SYS_MALLOC_LEN (4 * 1024 * 1024)
++#define CONFIG_SYS_BOOTPARAMS_LEN (128 * 1024)
++
++#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */
++#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
++
++#define CONFIG_SYS_LONGHELP
++#define CONFIG_SYS_MAXARGS 16
++#define CONFIG_SYS_PROMPT "NanoNote# "
++
+ #define CONFIG_SKIP_LOWLEVEL_INIT
+ #define CONFIG_BOARD_EARLY_INIT_F
+ #define CONFIG_SYS_NO_FLASH
+ #define CONFIG_SYS_FLASH_BASE 0 /* init flash_base as 0 */
+-#define CONFIG_ENV_OVERWRITE
+-
+-#define CONFIG_BOOTP_MASK (CONFIG_BOOTP_DEFAUL)
+-#define CONFIG_BOOTDELAY 0
+-#define CONFIG_BOOTARGS "mem=32M console=tty0 console=ttyS0,57600n8 ubi.mtd=2 rootfstype=ubifs root=ubi0:rootfs rw rootwait"
+-#define CONFIG_BOOTCOMMAND "nand read 0x80600000 0x400000 0x200000;bootm"
+
+ /*
+- * Command line configuration.
++ * Command line configuration
+ */
+ #define CONFIG_CMD_BOOTD /* bootd */
+ #define CONFIG_CMD_CONSOLE /* coninfo */
+ #define CONFIG_CMD_ECHO /* echo arguments */
+-
+ #define CONFIG_CMD_LOADB /* loadb */
+ #define CONFIG_CMD_LOADS /* loads */
+ #define CONFIG_CMD_MEMORY /* md mm nm mw cp cmp crc base loop mtest */
+@@ -58,45 +76,16 @@
+ #define CONFIG_LOADS_ECHO 1 /* echo on for serial download */
+
+ /*
+- * Miscellaneous configurable options
+- */
+-#define CONFIG_SYS_MAXARGS 16
+-#define CONFIG_SYS_LONGHELP
+-#define CONFIG_SYS_PROMPT "NanoNote# "
+-#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */
+-#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+-
+-#define CONFIG_SYS_MALLOC_LEN (4 * 1024 * 1024)
+-#define CONFIG_SYS_BOOTPARAMS_LEN (128 * 1024)
+-
+-#define CONFIG_SYS_SDRAM_BASE 0x80000000 /* Cached addr */
+-#define CONFIG_SYS_INIT_SP_OFFSET 0x400000
+-#define CONFIG_SYS_LOAD_ADDR 0x80600000
+-#define CONFIG_SYS_MEMTEST_START 0x80100000
+-#define CONFIG_SYS_MEMTEST_END 0x80800000
+-
+-/*
+- * Environment
++ * NAND driver configuration
+ */
+-#define CONFIG_ENV_IS_IN_NAND /* use NAND for environment vars */
+-
+-#define CONFIG_SYS_NAND_5_ADDR_CYCLE
+-/*
+- * if board nand flash is 1GB, set to 1
+- * if board nand flash is 2GB, set to 2
+- * for change the PAGE_SIZE and BLOCK_SIZE
+- * will delete when there is no 1GB flash
+- */
+-#define NANONOTE_NAND_SIZE 2
+-
+-#define CONFIG_SYS_NAND_PAGE_SIZE (2048 * NANONOTE_NAND_SIZE)
+-#define CONFIG_SYS_NAND_BLOCK_SIZE (256 * NANONOTE_NAND_SIZE << 10)
+-/* nand bad block was marked at this page in a block, start from 0 */
++#define CONFIG_NAND_JZ4740
++#define CONFIG_SYS_NAND_PAGE_SIZE 4096
++#define CONFIG_SYS_NAND_BLOCK_SIZE (512 << 10)
++/* NAND bad block was marked at this page in a block, start from 0 */
+ #define CONFIG_SYS_NAND_BADBLOCK_PAGE 127
+ #define CONFIG_SYS_NAND_PAGE_COUNT 128
+ #define CONFIG_SYS_NAND_BAD_BLOCK_POS 0
+-/* ECC offset position in oob area, default value is 6 if it isn't defined */
+-#define CONFIG_SYS_NAND_ECC_POS (6 * NANONOTE_NAND_SIZE)
++#define CONFIG_SYS_NAND_ECC_POS 12
+ #define CONFIG_SYS_NAND_ECCSIZE 512
+ #define CONFIG_SYS_NAND_ECCBYTES 9
+ #define CONFIG_SYS_NAND_ECCPOS \
+@@ -115,10 +104,9 @@
+ #define CONFIG_SYS_ONENAND_BASE CONFIG_SYS_NAND_BASE
+ #define CONFIG_SYS_MAX_NAND_DEVICE 1
+ #define CONFIG_SYS_NAND_SELECT_DEVICE 1 /* nand driver supports mutipl.*/
+-#define CONFIG_NAND_SPL_TEXT_BASE 0x80000000
+
+ /*
+- * IPL (Initial Program Loader, integrated inside CPU)
++ * IPL (Initial Program Loader, integrated inside Ingenic Xburst JZ4740 CPU)
+ * Will load first 8k from NAND (SPL) into cache and execute it from there.
+ *
+ * SPL (Secondary Program Loader)
+@@ -130,77 +118,88 @@
+ * NUB (NAND U-Boot)
+ * This NAND U-Boot (NUB) is a special U-Boot version which can be started
+ * from RAM. Therefore it mustn't (re-)configure the SDRAM controller.
+- *
+ */
++
++/*
++ * NAND SPL configuration
++ */
++#define CONFIG_SPL
++#define CONFIG_SPL_LIBGENERIC_SUPPORT
++#define CONFIG_SPL_LIBCOMMON_SUPPORT
++#define CONFIG_SPL_NAND_LOAD
++#define CONFIG_SPL_NAND_SIMPLE
++#define CONFIG_SPL_NAND_SUPPORT
++#define CONFIG_SPL_TEXT_BASE 0x80000000
++#define CONFIG_SPL_START_S_PATH "arch/mips/cpu/xburst/spl"
++
++#define CONFIG_SYS_NAND_5_ADDR_CYCLE
++#define CONFIG_SYS_NAND_HW_ECC_OOBFIRST
++#define JZ4740_NANDBOOT_CFG JZ4740_NANDBOOT_B8R3
++
+ #define CONFIG_SYS_NAND_U_BOOT_DST 0x80100000 /* Load NUB to this addr */
+ #define CONFIG_SYS_NAND_U_BOOT_START CONFIG_SYS_NAND_U_BOOT_DST
+-/* Start NUB from this addr*/
++ /* Start NUB from this addr */
++#define CONFIG_SYS_NAND_U_BOOT_OFFS (32 << 10) /* Offset of NUB */
++#define CONFIG_SYS_NAND_U_BOOT_SIZE (256 << 10) /* Size of NUB */
+
+ /*
+- * Define the partitioning of the NAND chip (only RAM U-Boot is needed here)
++ * Environment configuration
+ */
+-#define CONFIG_SYS_NAND_U_BOOT_OFFS (256 << 10) /* Offset to RAM U-Boot image */
+-#define CONFIG_SYS_NAND_U_BOOT_SIZE (512 << 10) /* Size of RAM U-Boot image */
+-
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_IS_IN_NAND
+ #define CONFIG_ENV_SIZE (4 << 10)
+ #define CONFIG_ENV_OFFSET \
+ (CONFIG_SYS_NAND_BLOCK_SIZE + CONFIG_SYS_NAND_U_BOOT_SIZE)
+ #define CONFIG_ENV_OFFSET_REDUND \
+ (CONFIG_ENV_OFFSET + CONFIG_SYS_NAND_BLOCK_SIZE)
+
+-#define CONFIG_SYS_TEXT_BASE 0x80100000
+-#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE
+-
+ /*
+- * SDRAM Info.
++ * CPU cache configuration
+ */
+-#define CONFIG_NR_DRAM_BANKS 1
++#define CONFIG_SYS_DCACHE_SIZE 16384
++#define CONFIG_SYS_ICACHE_SIZE 16384
++#define CONFIG_SYS_CACHELINE_SIZE 32
+
+ /*
+- * Cache Configuration
++ * SDRAM configuration
+ */
+-#define CONFIG_SYS_DCACHE_SIZE 16384
+-#define CONFIG_SYS_ICACHE_SIZE 16384
+-#define CONFIG_SYS_CACHELINE_SIZE 32
++#define CONFIG_NR_DRAM_BANKS 1
++
++#define SDRAM_BW16 1 /* Data bus width: 0-32bit, 1-16bit */
++#define SDRAM_BANK4 1 /* Banks each chip: 0-2bank, 1-4bank */
++#define SDRAM_ROW 13 /* Row address: 11 to 13 */
++#define SDRAM_COL 9 /* Column address: 8 to 12 */
++#define SDRAM_CASL 2 /* CAS latency: 2 or 3 */
++#define SDRAM_TRAS 45 /* RAS# Active Time */
++#define SDRAM_RCD 20 /* RAS# to CAS# Delay */
++#define SDRAM_TPC 20 /* RAS# Precharge Time */
++#define SDRAM_TRWL 7 /* Write Latency Time */
++#define SDRAM_TREF 15625 /* Refresh period: 8192 cycles/64ms */
+
+ /*
+- * GPIO definition
++ * GPIO configuration
+ */
+-#define GPIO_LCD_CS (2 * 32 + 21)
+-#define GPIO_AMP_EN (3 * 32 + 4)
++#define GPIO_LCD_CS (2 * 32 + 21)
++#define GPIO_AMP_EN (3 * 32 + 4)
+
+-#define GPIO_SDPW_EN (3 * 32 + 2)
+-#define GPIO_SD_DETECT (3 * 32 + 0)
++#define GPIO_SDPW_EN (3 * 32 + 2)
++#define GPIO_SD_DETECT (3 * 32 + 0)
+
+-#define GPIO_BUZZ_PWM (3 * 32 + 27)
+-#define GPIO_USB_DETECT (3 * 32 + 28)
++#define GPIO_BUZZ_PWM (3 * 32 + 27)
++#define GPIO_USB_DETECT (3 * 32 + 28)
+
+-#define GPIO_AUDIO_POP (1 * 32 + 29)
+-#define GPIO_COB_TEST (1 * 32 + 30)
++#define GPIO_AUDIO_POP (1 * 32 + 29)
++#define GPIO_COB_TEST (1 * 32 + 30)
+
+ #define GPIO_KEYOUT_BASE (2 * 32 + 10)
+-#define GPIO_KEYIN_BASE (3 * 32 + 18)
+-#define GPIO_KEYIN_8 (3 * 32 + 26)
++#define GPIO_KEYIN_BASE (3 * 32 + 18)
++#define GPIO_KEYIN_8 (3 * 32 + 26)
+
+-#define GPIO_SD_CD_N GPIO_SD_DETECT /* SD Card insert detect */
++#define GPIO_SD_CD_N GPIO_SD_DETECT /* SD Card insert detect */
+ #define GPIO_SD_VCC_EN_N GPIO_SDPW_EN /* SD Card Power Enable */
+
+ #define SPEN GPIO_LCD_CS /* LCDCS :Serial command enable */
+ #define SPDA (2 * 32 + 22) /* LCDSCL:Serial command clock input */
+ #define SPCK (2 * 32 + 23) /* LCDSDA:Serial command data input */
+
+-/* SDRAM paramters */
+-#define SDRAM_BW16 1 /* Data bus width: 0-32bit, 1-16bit */
+-#define SDRAM_BANK4 1 /* Banks each chip: 0-2bank, 1-4bank */
+-#define SDRAM_ROW 13 /* Row address: 11 to 13 */
+-#define SDRAM_COL 9 /* Column address: 8 to 12 */
+-#define SDRAM_CASL 2 /* CAS latency: 2 or 3 */
+-
+-/* SDRAM Timings, unit: ns */
+-#define SDRAM_TRAS 45 /* RAS# Active Time */
+-#define SDRAM_RCD 20 /* RAS# to CAS# Delay */
+-#define SDRAM_TPC 20 /* RAS# Precharge Time */
+-#define SDRAM_TRWL 7 /* Write Latency Time */
+-#define SDRAM_TREF 15625 /* Refresh period: 8192 cycles/64ms */
+-
+ #endif
+--
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch b/package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch
new file mode 100644
index 0000000000..feaf297b7c
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0002-qi_lb60-add-software-usbboot-support.patch
@@ -0,0 +1,916 @@
+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
+
diff --git a/package/boot/uboot-xburst/patches/0003-add-mmc-support.patch b/package/boot/uboot-xburst/patches/0003-add-mmc-support.patch
new file mode 100644
index 0000000000..e9baa7c373
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0003-add-mmc-support.patch
@@ -0,0 +1,1664 @@
+From bd36739e77669e8df45c38f6acfe2cea511534d9 Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 18:19:41 +0800
+Subject: [PATCH 3/6] add mmc support
+
+---
+ arch/mips/include/asm/jz4740.h | 166 ++++++
+ board/qi/qi_lb60/qi_lb60.c | 9 +-
+ drivers/mmc/Makefile | 1 +
+ drivers/mmc/jz_mmc.c | 1179 ++++++++++++++++++++++++++++++++++++++++
+ drivers/mmc/jz_mmc.h | 176 ++++++
+ include/configs/qi_lb60.h | 9 +
+ include/mmc.h | 40 ++
+ 7 files changed, 1578 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mmc/jz_mmc.c
+ create mode 100644 drivers/mmc/jz_mmc.h
+
+diff --git a/arch/mips/include/asm/jz4740.h b/arch/mips/include/asm/jz4740.h
+index 7a7cfff..68287fb 100644
+--- a/arch/mips/include/asm/jz4740.h
++++ b/arch/mips/include/asm/jz4740.h
+@@ -1146,5 +1146,171 @@ extern void sdram_init(void);
+ extern void calc_clocks(void);
+ extern void rtc_init(void);
+
++/*************************************************************************
++ * MSC
++ *************************************************************************/
++#define REG8(addr) *((volatile u8 *)(addr))
++#define REG16(addr) *((volatile u16 *)(addr))
++#define REG32(addr) *((volatile u32 *)(addr))
++
++#define CPM_BASE 0xB0000000
++#define CPM_CPCCR (CPM_BASE+0x00)
++#define CPM_MSCCDR (CPM_BASE+0x68)
++#define REG_CPM_MSCCDR REG32(CPM_MSCCDR)
++#define REG_CPM_CPCCR REG32(CPM_CPCCR)
++
++#define MSC_BASE 0xB0021000
++
++#define MSC_STRPCL (MSC_BASE + 0x000)
++#define MSC_STAT (MSC_BASE + 0x004)
++#define MSC_CLKRT (MSC_BASE + 0x008)
++#define MSC_CMDAT (MSC_BASE + 0x00C)
++#define MSC_RESTO (MSC_BASE + 0x010)
++#define MSC_RDTO (MSC_BASE + 0x014)
++#define MSC_BLKLEN (MSC_BASE + 0x018)
++#define MSC_NOB (MSC_BASE + 0x01C)
++#define MSC_SNOB (MSC_BASE + 0x020)
++#define MSC_IMASK (MSC_BASE + 0x024)
++#define MSC_IREG (MSC_BASE + 0x028)
++#define MSC_CMD (MSC_BASE + 0x02C)
++#define MSC_ARG (MSC_BASE + 0x030)
++#define MSC_RES (MSC_BASE + 0x034)
++#define MSC_RXFIFO (MSC_BASE + 0x038)
++#define MSC_TXFIFO (MSC_BASE + 0x03C)
++
++#define REG_MSC_STRPCL REG16(MSC_STRPCL)
++#define REG_MSC_STAT REG32(MSC_STAT)
++#define REG_MSC_CLKRT REG16(MSC_CLKRT)
++#define REG_MSC_CMDAT REG32(MSC_CMDAT)
++#define REG_MSC_RESTO REG16(MSC_RESTO)
++#define REG_MSC_RDTO REG16(MSC_RDTO)
++#define REG_MSC_BLKLEN REG16(MSC_BLKLEN)
++#define REG_MSC_NOB REG16(MSC_NOB)
++#define REG_MSC_SNOB REG16(MSC_SNOB)
++#define REG_MSC_IMASK REG16(MSC_IMASK)
++#define REG_MSC_IREG REG16(MSC_IREG)
++#define REG_MSC_CMD REG8(MSC_CMD)
++#define REG_MSC_ARG REG32(MSC_ARG)
++#define REG_MSC_RES REG16(MSC_RES)
++#define REG_MSC_RXFIFO REG32(MSC_RXFIFO)
++#define REG_MSC_TXFIFO REG32(MSC_TXFIFO)
++
++/* MSC Clock and Control Register (MSC_STRPCL) */
++
++#define MSC_STRPCL_EXIT_MULTIPLE (1 << 7)
++#define MSC_STRPCL_EXIT_TRANSFER (1 << 6)
++#define MSC_STRPCL_START_READWAIT (1 << 5)
++#define MSC_STRPCL_STOP_READWAIT (1 << 4)
++#define MSC_STRPCL_RESET (1 << 3)
++#define MSC_STRPCL_START_OP (1 << 2)
++#define MSC_STRPCL_CLOCK_CONTROL_BIT 0
++#define MSC_STRPCL_CLOCK_CONTROL_MASK (0x3 << MSC_STRPCL_CLOCK_CONTROL_BIT)
++ #define MSC_STRPCL_CLOCK_CONTROL_STOP (0x1 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Stop MMC/SD clock */
++ #define MSC_STRPCL_CLOCK_CONTROL_START (0x2 << MSC_STRPCL_CLOCK_CONTROL_BIT) /* Start MMC/SD clock */
++
++/* MSC Status Register (MSC_STAT) */
++
++#define MSC_STAT_IS_RESETTING (1 << 15)
++#define MSC_STAT_SDIO_INT_ACTIVE (1 << 14)
++#define MSC_STAT_PRG_DONE (1 << 13)
++#define MSC_STAT_DATA_TRAN_DONE (1 << 12)
++#define MSC_STAT_END_CMD_RES (1 << 11)
++#define MSC_STAT_DATA_FIFO_AFULL (1 << 10)
++#define MSC_STAT_IS_READWAIT (1 << 9)
++#define MSC_STAT_CLK_EN (1 << 8)
++#define MSC_STAT_DATA_FIFO_FULL (1 << 7)
++#define MSC_STAT_DATA_FIFO_EMPTY (1 << 6)
++#define MSC_STAT_CRC_RES_ERR (1 << 5)
++#define MSC_STAT_CRC_READ_ERROR (1 << 4)
++#define MSC_STAT_CRC_WRITE_ERROR_BIT 2
++#define MSC_STAT_CRC_WRITE_ERROR_MASK (0x3 << MSC_STAT_CRC_WRITE_ERROR_BIT)
++ #define MSC_STAT_CRC_WRITE_ERROR_NO (0 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No error on transmission of data */
++ #define MSC_STAT_CRC_WRITE_ERROR (1 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* Card observed erroneous transmission of data */
++ #define MSC_STAT_CRC_WRITE_ERROR_NOSTS (2 << MSC_STAT_CRC_WRITE_ERROR_BIT) /* No CRC status is sent back */
++#define MSC_STAT_TIME_OUT_RES (1 << 1)
++#define MSC_STAT_TIME_OUT_READ (1 << 0)
++
++/* MSC Bus Clock Control Register (MSC_CLKRT) */
++
++#define MSC_CLKRT_CLK_RATE_BIT 0
++#define MSC_CLKRT_CLK_RATE_MASK (0x7 << MSC_CLKRT_CLK_RATE_BIT)
++ #define MSC_CLKRT_CLK_RATE_DIV_1 (0x0 << MSC_CLKRT_CLK_RATE_BIT) /* CLK_SRC */
++ #define MSC_CLKRT_CLK_RATE_DIV_2 (0x1 << MSC_CLKRT_CLK_RATE_BIT) /* 1/2 of CLK_SRC */
++ #define MSC_CLKRT_CLK_RATE_DIV_4 (0x2 << MSC_CLKRT_CLK_RATE_BIT) /* 1/4 of CLK_SRC */
++ #define MSC_CLKRT_CLK_RATE_DIV_8 (0x3 << MSC_CLKRT_CLK_RATE_BIT) /* 1/8 of CLK_SRC */
++ #define MSC_CLKRT_CLK_RATE_DIV_16 (0x4 << MSC_CLKRT_CLK_RATE_BIT) /* 1/16 of CLK_SRC */
++ #define MSC_CLKRT_CLK_RATE_DIV_32 (0x5 << MSC_CLKRT_CLK_RATE_BIT) /* 1/32 of CLK_SRC */
++ #define MSC_CLKRT_CLK_RATE_DIV_64 (0x6 << MSC_CLKRT_CLK_RATE_BIT) /* 1/64 of CLK_SRC */
++ #define MSC_CLKRT_CLK_RATE_DIV_128 (0x7 << MSC_CLKRT_CLK_RATE_BIT) /* 1/128 of CLK_SRC */
++
++/* MSC Command Sequence Control Register (MSC_CMDAT) */
++
++#define MSC_CMDAT_IO_ABORT (1 << 11)
++#define MSC_CMDAT_BUS_WIDTH_BIT 9
++#define MSC_CMDAT_BUS_WIDTH_MASK (0x3 << MSC_CMDAT_BUS_WIDTH_BIT)
++#define MSC_CMDAT_BUS_WIDTH_1BIT (0x0 << MSC_CMDAT_BUS_WIDTH_BIT)
++#define MSC_CMDAT_BUS_WIDTH_4BIT (0x2 << MSC_CMDAT_BUS_WIDTH_BIT)
++#define MSC_CMDAT_DMA_EN (1 << 8)
++#define MSC_CMDAT_INIT (1 << 7)
++#define MSC_CMDAT_BUSY (1 << 6)
++#define MSC_CMDAT_STREAM_BLOCK (1 << 5)
++#define MSC_CMDAT_WRITE (1 << 4)
++#define MSC_CMDAT_READ (0 << 4)
++#define MSC_CMDAT_DATA_EN (1 << 3)
++#define MSC_CMDAT_RESPONSE_BIT 0
++#define MSC_CMDAT_RESPONSE_MASK (0x7 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_NONE (0x0 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R1 (0x1 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R2 (0x2 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R3 (0x3 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R4 (0x4 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R5 (0x5 << MSC_CMDAT_RESPONSE_BIT)
++#define MSC_CMDAT_RESPONSE_R6 (0x6 << MSC_CMDAT_RESPONSE_BIT)
++
++/* MSC Interrupts Mask Register (MSC_IMASK) */
++#define MSC_IMASK_SDIO (1 << 7)
++#define MSC_IMASK_TXFIFO_WR_REQ (1 << 6)
++#define MSC_IMASK_RXFIFO_RD_REQ (1 << 5)
++#define MSC_IMASK_END_CMD_RES (1 << 2)
++#define MSC_IMASK_PRG_DONE (1 << 1)
++#define MSC_IMASK_DATA_TRAN_DONE (1 << 0)
++
++
++/* MSC Interrupts Status Register (MSC_IREG) */
++#define MSC_IREG_SDIO (1 << 7)
++#define MSC_IREG_TXFIFO_WR_REQ (1 << 6)
++#define MSC_IREG_RXFIFO_RD_REQ (1 << 5)
++#define MSC_IREG_END_CMD_RES (1 << 2)
++#define MSC_IREG_PRG_DONE (1 << 1)
++#define MSC_IREG_DATA_TRAN_DONE (1 << 0)
++
++static __inline__ unsigned int __cpm_get_pllout2(void)
++{
++ if (REG_CPM_CPCCR & CPM_CPCCR_PCS)
++ return __cpm_get_pllout();
++ else
++ return __cpm_get_pllout()/2;
++}
++
++static inline void __cpm_select_msc_clk(int sd)
++{
++ unsigned int pllout2 = __cpm_get_pllout2();
++ unsigned int div = 0;
++
++ if (sd) {
++ div = pllout2 / 24000000;
++ }
++ else {
++ div = pllout2 / 16000000;
++ }
++
++ REG_CPM_MSCCDR = div - 1;
++}
++#define __msc_reset() \
++do { \
++ REG_MSC_STRPCL = MSC_STRPCL_RESET; \
++ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \
++} while (0)
++
+ #endif /* !__ASSEMBLY__ */
+ #endif /* __JZ4740_H__ */
+diff --git a/board/qi/qi_lb60/qi_lb60.c b/board/qi/qi_lb60/qi_lb60.c
+index 3bd4e2f..a2ba648 100644
+--- a/board/qi/qi_lb60/qi_lb60.c
++++ b/board/qi/qi_lb60/qi_lb60.c
+@@ -40,8 +40,13 @@ static void gpio_init(void)
+ __gpio_clear_pin(GPIO_KEYOUT_BASE + i);
+ }
+
+- __gpio_as_input(GPIO_KEYIN_8);
+- __gpio_enable_pull(GPIO_KEYIN_8);
++ if (__gpio_get_pin(GPIO_KEYIN_BASE + 2) == 0){
++ printf("[S] pressed, enable UART0\n");
++ __gpio_as_uart0();
++ } else {
++ __gpio_as_input(GPIO_KEYIN_8);
++ __gpio_enable_pull(GPIO_KEYIN_8);
++ }
+
+ /* enable the TP4, TP5 as UART0 */
+ __gpio_jtag_to_uart0();
+diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
+index 565ba6a..3c717b1 100644
+--- a/drivers/mmc/Makefile
++++ b/drivers/mmc/Makefile
+@@ -47,6 +47,7 @@ COBJS-$(CONFIG_SDHCI) += sdhci.o
+ COBJS-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+ COBJS-$(CONFIG_SH_MMCIF) += sh_mmcif.o
+ COBJS-$(CONFIG_TEGRA_MMC) += tegra_mmc.o
++COBJS-$(CONFIG_JZ4740_MMC) += jz_mmc.o
+
+ COBJS := $(COBJS-y)
+ SRCS := $(COBJS:.o=.c)
+diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c
+new file mode 100644
+index 0000000..642cecc
+--- /dev/null
++++ b/drivers/mmc/jz_mmc.c
+@@ -0,0 +1,1179 @@
++/*
++ * (C) Copyright 2003
++ * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net
++ *
++ * 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 <common.h>
++#include <part.h>
++#include <mmc.h>
++
++#include <asm/io.h>
++#include <asm/jz4740.h>
++#include "jz_mmc.h"
++
++static int sd2_0 = 0;
++static int mmc_ready = 0;
++static int use_4bit; /* Use 4-bit data bus */
++/*
++ * MMC Events
++ */
++#define MMC_EVENT_NONE 0x00 /* No events */
++#define MMC_EVENT_RX_DATA_DONE 0x01 /* Rx data done */
++#define MMC_EVENT_TX_DATA_DONE 0x02 /* Tx data done */
++#define MMC_EVENT_PROG_DONE 0x04 /* Programming is done */
++
++
++#define MMC_IRQ_MASK() \
++do { \
++ REG_MSC_IMASK = 0xffff; \
++ REG_MSC_IREG = 0xffff; \
++} while (0)
++
++/*
++ * GPIO definition
++ */
++#if defined(CONFIG_SAKC)
++
++#define __msc_init_io() \
++do { \
++ __gpio_as_input(GPIO_SD_CD_N); \
++} while (0)
++
++#else
++#define __msc_init_io() \
++do { \
++ __gpio_as_output(GPIO_SD_VCC_EN_N); \
++ __gpio_as_input(GPIO_SD_CD_N); \
++} while (0)
++
++#define __msc_enable_power() \
++do { \
++ __gpio_clear_pin(GPIO_SD_VCC_EN_N); \
++} while (0)
++
++#define __msc_disable_power() \
++do { \
++ __gpio_set_pin(GPIO_SD_VCC_EN_N); \
++} while (0)
++
++#endif /* CONFIG_SAKE */
++
++#define __msc_card_detected() \
++({ \
++ int detected = 1; \
++ __gpio_as_input(GPIO_SD_CD_N); \
++ __gpio_disable_pull(GPIO_SD_CD_N); \
++ if (!__gpio_get_pin(GPIO_SD_CD_N)) \
++ detected = 0; \
++ detected; \
++})
++
++/*
++ * Local functions
++ */
++
++extern int
++fat_register_device(block_dev_desc_t *dev_desc, int part_no);
++
++static block_dev_desc_t mmc_dev;
++
++block_dev_desc_t * mmc_get_dev(int dev)
++{
++ return ((block_dev_desc_t *)&mmc_dev);
++}
++
++/* Stop the MMC clock and wait while it happens */
++static inline int jz_mmc_stop_clock(void)
++{
++ int timeout = 1000;
++
++ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_STOP;
++
++ while (timeout && (REG_MSC_STAT & MSC_STAT_CLK_EN)) {
++ timeout--;
++ if (timeout == 0)
++ return MMC_ERROR_TIMEOUT;
++ udelay(1);
++ }
++ return MMC_NO_ERROR;
++}
++
++/* Start the MMC clock and operation */
++static inline int jz_mmc_start_clock(void)
++{
++ REG_MSC_STRPCL = MSC_STRPCL_CLOCK_CONTROL_START | MSC_STRPCL_START_OP;
++ return MMC_NO_ERROR;
++}
++
++static inline u32 jz_mmc_calc_clkrt(int is_sd, u32 rate)
++{
++ u32 clkrt = 0;
++ u32 clk_src = is_sd ? 24000000 : 16000000;
++
++ while (rate < clk_src) {
++ clkrt ++;
++ clk_src >>= 1;
++ }
++
++ return clkrt;
++}
++
++/* Set the MMC clock frequency */
++void jz_mmc_set_clock(int sd, u32 rate)
++{
++ jz_mmc_stop_clock();
++
++ /* Select clock source of MSC */
++ __cpm_select_msc_clk(sd);
++
++ /* Set clock dividor of MSC */
++ REG_MSC_CLKRT = jz_mmc_calc_clkrt(sd, rate);
++}
++
++static int jz_mmc_check_status(struct mmc_request *request)
++{
++ u32 status = REG_MSC_STAT;
++
++ /* Checking for response or data timeout */
++ if (status & (MSC_STAT_TIME_OUT_RES | MSC_STAT_TIME_OUT_READ)) {
++ printf("MMC/SD timeout, MMC_STAT 0x%x CMD %d\n", status, request->cmd);
++ return MMC_ERROR_TIMEOUT;
++ }
++
++ /* Checking for CRC error */
++ if (status & (MSC_STAT_CRC_READ_ERROR | MSC_STAT_CRC_WRITE_ERROR | MSC_STAT_CRC_RES_ERR)) {
++ printf("MMC/CD CRC error, MMC_STAT 0x%x\n", status);
++ return MMC_ERROR_CRC;
++ }
++
++ return MMC_NO_ERROR;
++}
++
++/* Obtain response to the command and store it to response buffer */
++static void jz_mmc_get_response(struct mmc_request *request)
++{
++ int i;
++ u8 *buf;
++ u32 data;
++
++ debug("fetch response for request %d, cmd %d\n",
++ request->rtype, request->cmd);
++
++ buf = request->response;
++ request->result = MMC_NO_ERROR;
++
++ switch (request->rtype) {
++ case RESPONSE_R1: case RESPONSE_R1B: case RESPONSE_R6:
++ case RESPONSE_R3: case RESPONSE_R4: case RESPONSE_R5:
++ {
++ data = REG_MSC_RES;
++ buf[0] = (data >> 8) & 0xff;
++ buf[1] = data & 0xff;
++ data = REG_MSC_RES;
++ buf[2] = (data >> 8) & 0xff;
++ buf[3] = data & 0xff;
++ data = REG_MSC_RES;
++ buf[4] = data & 0xff;
++
++ debug("request %d, response [%02x %02x %02x %02x %02x]\n",
++ request->rtype, buf[0], buf[1], buf[2], buf[3], buf[4]);
++ break;
++ }
++ case RESPONSE_R2_CID: case RESPONSE_R2_CSD:
++ {
++ for (i = 0; i < 16; i += 2) {
++ data = REG_MSC_RES;
++ buf[i] = (data >> 8) & 0xff;
++ buf[i+1] = data & 0xff;
++ }
++ debug("request %d, response [", request->rtype);
++#if CONFIG_MMC_DEBUG_VERBOSE > 2
++ if (g_mmc_debug >= 3) {
++ int n;
++ for (n = 0; n < 17; n++)
++ printk("%02x ", buf[n]);
++ printk("]\n");
++ }
++#endif
++ break;
++ }
++ case RESPONSE_NONE:
++ debug("No response\n");
++ break;
++
++ default:
++ debug("unhandled response type for request %d\n", request->rtype);
++ break;
++ }
++}
++
++static int jz_mmc_receive_data(struct mmc_request *req)
++{
++ u32 stat, timeout, data, cnt;
++ u8 *buf = req->buffer;
++ u32 wblocklen = (u32)(req->block_len + 3) >> 2; /* length in word */
++
++ timeout = 0x3ffffff;
++
++ while (timeout) {
++ timeout--;
++ stat = REG_MSC_STAT;
++
++ if (stat & MSC_STAT_TIME_OUT_READ)
++ return MMC_ERROR_TIMEOUT;
++ else if (stat & MSC_STAT_CRC_READ_ERROR)
++ return MMC_ERROR_CRC;
++ else if (!(stat & MSC_STAT_DATA_FIFO_EMPTY)
++ || (stat & MSC_STAT_DATA_FIFO_AFULL)) {
++ /* Ready to read data */
++ break;
++ }
++ udelay(1);
++ }
++ if (!timeout)
++ return MMC_ERROR_TIMEOUT;
++
++ /* Read data from RXFIFO. It could be FULL or PARTIAL FULL */
++ cnt = wblocklen;
++ while (cnt) {
++ data = REG_MSC_RXFIFO;
++ {
++ *buf++ = (u8)(data >> 0);
++ *buf++ = (u8)(data >> 8);
++ *buf++ = (u8)(data >> 16);
++ *buf++ = (u8)(data >> 24);
++ }
++ cnt --;
++ while (cnt && (REG_MSC_STAT & MSC_STAT_DATA_FIFO_EMPTY))
++ ;
++ }
++ return MMC_NO_ERROR;
++}
++
++static int jz_mmc_transmit_data(struct mmc_request *req)
++{
++#if 0
++ u32 nob = req->nob;
++ u32 wblocklen = (u32)(req->block_len + 3) >> 2; /* length in word */
++ u8 *buf = req->buffer;
++ u32 *wbuf = (u32 *)buf;
++ u32 waligned = (((u32)buf & 0x3) == 0); /* word aligned ? */
++ u32 stat, timeout, data, cnt;
++
++ for (nob; nob >= 1; nob--) {
++ timeout = 0x3FFFFFF;
++
++ while (timeout) {
++ timeout--;
++ stat = REG_MSC_STAT;
++
++ if (stat & (MSC_STAT_CRC_WRITE_ERROR | MSC_STAT_CRC_WRITE_ERROR_NOSTS))
++ return MMC_ERROR_CRC;
++ else if (!(stat & MSC_STAT_DATA_FIFO_FULL)) {
++ /* Ready to write data */
++ break;
++ }
++
++ udelay(1);
++ }
++
++ if (!timeout)
++ return MMC_ERROR_TIMEOUT;
++
++ /* Write data to TXFIFO */
++ cnt = wblocklen;
++ while (cnt) {
++ while (REG_MSC_STAT & MSC_STAT_DATA_FIFO_FULL)
++ ;
++
++ if (waligned) {
++ REG_MSC_TXFIFO = *wbuf++;
++ }
++ else {
++ data = *buf++ | (*buf++ << 8) | (*buf++ << 16) | (*buf++ << 24);
++ REG_MSC_TXFIFO = data;
++ }
++
++ cnt--;
++ }
++ }
++#endif
++ return MMC_NO_ERROR;
++}
++
++
++/*
++ * Name: int jz_mmc_exec_cmd()
++ * Function: send command to the card, and get a response
++ * Input: struct mmc_request *req : MMC/SD request
++ * Output: 0: right >0: error code
++ */
++int jz_mmc_exec_cmd(struct mmc_request *request)
++{
++ u32 cmdat = 0, events = 0;
++ int retval, timeout = 0x3fffff;
++
++ /* Indicate we have no result yet */
++ request->result = MMC_NO_RESPONSE;
++ if (request->cmd == MMC_CIM_RESET) {
++ /* On reset, 1-bit bus width */
++ use_4bit = 0;
++
++ /* Reset MMC/SD controller */
++ __msc_reset();
++
++ /* On reset, drop MMC clock down */
++ jz_mmc_set_clock(0, MMC_CLOCK_SLOW);
++
++ /* On reset, stop MMC clock */
++ jz_mmc_stop_clock();
++ }
++ if (request->cmd == MMC_CMD_SEND_OP_COND) {
++ debug("Have an MMC card\n");
++ /* always use 1bit for MMC */
++ use_4bit = 0;
++ }
++ if (request->cmd == SET_BUS_WIDTH) {
++ if (request->arg == 0x2) {
++ printf("Use 4-bit bus width\n");
++ use_4bit = 1;
++ } else {
++ printf("Use 1-bit bus width\n");
++ use_4bit = 0;
++ }
++ }
++
++ /* stop clock */
++ jz_mmc_stop_clock();
++
++ /* mask all interrupts */
++ REG_MSC_IMASK = 0xffff;
++
++ /* clear status */
++ REG_MSC_IREG = 0xffff;
++
++ /* use 4-bit bus width when possible */
++ if (use_4bit)
++ cmdat |= MSC_CMDAT_BUS_WIDTH_4BIT;
++
++ /* Set command type and events */
++ switch (request->cmd) {
++ /* MMC core extra command */
++ case MMC_CIM_RESET:
++ cmdat |= MSC_CMDAT_INIT; /* Initialization sequence sent prior to command */
++ break;
++
++ /* bc - broadcast - no response */
++ case MMC_CMD_GO_IDLE_STATE:
++ case MMC_CMD_SET_DSR:
++ break;
++
++ /* bcr - broadcast with response */
++ case MMC_CMD_SEND_OP_COND:
++ case MMC_CMD_ALL_SEND_CID:
++ case MMC_GO_IRQ_STATE:
++ break;
++
++ /* adtc - addressed with data transfer */
++ case MMC_READ_DAT_UNTIL_STOP:
++ case MMC_CMD_READ_SINGLE_BLOCK:
++ case MMC_CMD_READ_MULTIPLE_BLOCK:
++ case SD_CMD_APP_SEND_SCR:
++ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_READ;
++ events = MMC_EVENT_RX_DATA_DONE;
++ break;
++
++ case MMC_WRITE_DAT_UNTIL_STOP:
++ case MMC_CMD_WRITE_SINGLE_BLOCK:
++ case MMC_CMD_WRITE_MULTIPLE_BLOCK:
++ case MMC_PROGRAM_CID:
++ case MMC_PROGRAM_CSD:
++ case MMC_SEND_WRITE_PROT:
++ case MMC_GEN_CMD:
++ case MMC_LOCK_UNLOCK:
++ cmdat |= MSC_CMDAT_DATA_EN | MSC_CMDAT_WRITE;
++ events = MMC_EVENT_TX_DATA_DONE | MMC_EVENT_PROG_DONE;
++
++ break;
++
++ case MMC_CMD_STOP_TRANSMISSION:
++ events = MMC_EVENT_PROG_DONE;
++ break;
++
++ /* ac - no data transfer */
++ default:
++ break;
++ }
++
++ /* Set response type */
++ switch (request->rtype) {
++ case RESPONSE_NONE:
++ break;
++
++ case RESPONSE_R1B:
++ cmdat |= MSC_CMDAT_BUSY;
++ /*FALLTHRU*/
++ case RESPONSE_R1:
++ cmdat |= MSC_CMDAT_RESPONSE_R1;
++ break;
++ case RESPONSE_R2_CID:
++ case RESPONSE_R2_CSD:
++ cmdat |= MSC_CMDAT_RESPONSE_R2;
++ break;
++ case RESPONSE_R3:
++ cmdat |= MSC_CMDAT_RESPONSE_R3;
++ break;
++ case RESPONSE_R4:
++ cmdat |= MSC_CMDAT_RESPONSE_R4;
++ break;
++ case RESPONSE_R5:
++ cmdat |= MSC_CMDAT_RESPONSE_R5;
++ break;
++ case RESPONSE_R6:
++ cmdat |= MSC_CMDAT_RESPONSE_R6;
++ break;
++ default:
++ break;
++ }
++
++ /* Set command index */
++ if (request->cmd == MMC_CIM_RESET) {
++ REG_MSC_CMD = MMC_CMD_GO_IDLE_STATE;
++ } else {
++ REG_MSC_CMD = request->cmd;
++ }
++
++ /* Set argument */
++ REG_MSC_ARG = request->arg;
++
++ /* Set block length and nob */
++ if (request->cmd == SD_CMD_APP_SEND_SCR) { /* get SCR from DataFIFO */
++ REG_MSC_BLKLEN = 8;
++ REG_MSC_NOB = 1;
++ } else {
++ REG_MSC_BLKLEN = request->block_len;
++ REG_MSC_NOB = request->nob;
++ }
++
++ /* Set command */
++ REG_MSC_CMDAT = cmdat;
++
++ debug("Send cmd %d cmdat: %x arg: %x resp %d\n", request->cmd,
++ cmdat, request->arg, request->rtype);
++
++ /* Start MMC/SD clock and send command to card */
++ jz_mmc_start_clock();
++
++ /* Wait for command completion */
++ while (timeout-- && !(REG_MSC_STAT & MSC_STAT_END_CMD_RES))
++ ;
++
++ if (timeout == 0)
++ return MMC_ERROR_TIMEOUT;
++
++ REG_MSC_IREG = MSC_IREG_END_CMD_RES; /* clear flag */
++
++ /* Check for status */
++ retval = jz_mmc_check_status(request);
++ if (retval) {
++ return retval;
++ }
++
++ /* Complete command with no response */
++ if (request->rtype == RESPONSE_NONE) {
++ return MMC_NO_ERROR;
++ }
++
++ /* Get response */
++ jz_mmc_get_response(request);
++
++ /* Start data operation */
++ if (events & (MMC_EVENT_RX_DATA_DONE | MMC_EVENT_TX_DATA_DONE)) {
++ if (events & MMC_EVENT_RX_DATA_DONE) {
++ if (request->cmd == SD_CMD_APP_SEND_SCR) {
++ /* SD card returns SCR register as data.
++ MMC core expect it in the response buffer,
++ after normal response. */
++ request->buffer = (u8 *)((u32)request->response + 5);
++ }
++ jz_mmc_receive_data(request);
++ }
++
++ if (events & MMC_EVENT_TX_DATA_DONE) {
++ jz_mmc_transmit_data(request);
++ }
++
++ /* Wait for Data Done */
++ while (!(REG_MSC_IREG & MSC_IREG_DATA_TRAN_DONE))
++ ;
++ REG_MSC_IREG = MSC_IREG_DATA_TRAN_DONE; /* clear status */
++ }
++
++ /* Wait for Prog Done event */
++ if (events & MMC_EVENT_PROG_DONE) {
++ while (!(REG_MSC_IREG & MSC_IREG_PRG_DONE))
++ ;
++ REG_MSC_IREG = MSC_IREG_PRG_DONE; /* clear status */
++ }
++
++ /* Command completed */
++
++ return MMC_NO_ERROR; /* return successfully */
++}
++
++int mmc_block_read(u8 *dst, ulong src, ulong len)
++{
++
++ struct mmc_request request;
++ struct mmc_response_r1 r1;
++ int retval = 0;
++
++ if (len == 0)
++ goto exit;
++
++ mmc_simple_cmd(&request, MMC_CMD_SEND_STATUS, mmcinfo.rca, RESPONSE_R1);
++ retval = mmc_unpack_r1(&request, &r1, 0);
++ if (retval && (retval != MMC_ERROR_STATE_MISMATCH))
++ goto exit;
++
++ mmc_simple_cmd(&request, MMC_CMD_SET_BLOCKLEN, len, RESPONSE_R1);
++ if (retval = mmc_unpack_r1(&request, &r1, 0))
++ goto exit;
++
++ if (!sd2_0)
++ src *= mmcinfo.block_len;
++
++ mmc_send_cmd(&request, MMC_CMD_READ_SINGLE_BLOCK, src, 1, len, RESPONSE_R1, dst);
++ if (retval = mmc_unpack_r1(&request, &r1, 0))
++ goto exit;
++
++exit:
++ return retval;
++}
++
++ulong mmc_bread(int dev_num, ulong blkstart, ulong blkcnt, ulong *dst)
++{
++ if (!mmc_ready) {
++ printf("Please initial the MMC first\n");
++ return -1;
++ }
++
++ int i = 0;
++ ulong dst_tmp = dst;
++
++ for (i = 0; i < blkcnt; i++) {
++ if ((mmc_block_read((uchar *)(dst_tmp), blkstart, mmcinfo.block_len)) < 0)
++ return -1;
++
++ dst_tmp += mmcinfo.block_len;
++ blkstart++;
++ }
++
++ return i;
++}
++
++int mmc_select_card(void)
++{
++ struct mmc_request request;
++ struct mmc_response_r1 r1;
++ int retval;
++
++ mmc_simple_cmd(&request, MMC_CMD_SELECT_CARD, mmcinfo.rca, RESPONSE_R1B);
++ retval = mmc_unpack_r1(&request, &r1, 0);
++ if (retval) {
++ return retval;
++ }
++
++ if (mmcinfo.sd) {
++ mmc_simple_cmd(&request, MMC_CMD_APP_CMD, mmcinfo.rca, RESPONSE_R1);
++ retval = mmc_unpack_r1(&request,&r1,0);
++ if (retval) {
++ return retval;
++ }
++#if defined(MMC_BUS_WIDTH_1BIT)
++ mmc_simple_cmd(&request, SET_BUS_WIDTH, 1, RESPONSE_R1);
++#else
++ mmc_simple_cmd(&request, SET_BUS_WIDTH, 2, RESPONSE_R1);
++#endif
++ retval = mmc_unpack_r1(&request,&r1,0);
++ if (retval) {
++ return retval;
++ }
++ }
++ return 0;
++}
++
++/*
++ * Configure card
++ */
++static void mmc_configure_card(void)
++{
++ u32 rate;
++
++ /* Get card info */
++ if (sd2_0)
++ mmcinfo.block_num = (mmcinfo.csd.c_size + 1) << 10;
++ else
++ mmcinfo.block_num = (mmcinfo.csd.c_size + 1) * (1 << (mmcinfo.csd.c_size_mult + 2));
++
++ mmcinfo.block_len = 1 << mmcinfo.csd.read_bl_len;
++
++ mmc_dev.if_type = IF_TYPE_SD;
++ mmc_dev.part_type = PART_TYPE_DOS;
++ mmc_dev.dev = 0;
++ mmc_dev.lun = 0;
++ mmc_dev.type = 0;
++ mmc_dev.blksz = mmcinfo.block_len;
++ mmc_dev.lba = mmcinfo.block_num;
++ mmc_dev.removable = 0;
++
++ printf("%s Detected: %lu blocks of %lu bytes\n",
++ sd2_0 == 1 ? "SDHC" : "SD",
++ mmc_dev.lba,
++ mmc_dev.blksz);
++
++ /* Fix the clock rate */
++ rate = mmc_tran_speed(mmcinfo.csd.tran_speed);
++ if (rate < MMC_CLOCK_SLOW)
++ rate = MMC_CLOCK_SLOW;
++ if ((mmcinfo.sd == 0) && (rate > MMC_CLOCK_FAST))
++ rate = MMC_CLOCK_FAST;
++ if ((mmcinfo.sd) && (rate > SD_CLOCK_FAST))
++ rate = SD_CLOCK_FAST;
++
++ debug("%s: block_len=%d block_num=%d rate=%d\n",
++ __func__, mmcinfo.block_len, mmcinfo.block_num, rate);
++
++ jz_mmc_set_clock(mmcinfo.sd, rate);
++}
++
++/*
++ * State machine routines to initialize card(s)
++ */
++
++/*
++ CIM_SINGLE_CARD_ACQ (frequency at 400 kHz)
++ --- Must enter from GO_IDLE_STATE ---
++ 1. SD_SEND_OP_COND (SD Card) [CMD55] + [CMD41]
++ 2. SEND_OP_COND (Full Range) [CMD1] {optional}
++ 3. SEND_OP_COND (Set Range ) [CMD1]
++ If busy, delay and repeat step 2
++ 4. ALL_SEND_CID [CMD2]
++ If timeout, set an error (no cards found)
++ 5. SET_RELATIVE_ADDR [CMD3]
++ 6. SEND_CSD [CMD9]
++ 7. SET_DSR [CMD4] Only call this if (csd.dsr_imp).
++ 8. Set clock frequency (check available in csd.tran_speed)
++ */
++
++#define MMC_INIT_DOING 0
++#define MMC_INIT_PASSED 1
++#define MMC_INIT_FAILED 2
++
++static int mmc_init_card_state(struct mmc_request *request)
++{
++ struct mmc_response_r1 r1;
++ struct mmc_response_r3 r3;
++ int retval;
++ int ocr = 0x40300000;
++ int limit_41 = 0;
++
++ switch (request->cmd) {
++ case MMC_CMD_GO_IDLE_STATE: /* No response to parse */
++ if (mmcinfo.sd)
++ mmc_simple_cmd(request, 8, 0x1aa, RESPONSE_R1);
++ else
++ mmc_simple_cmd(request, MMC_CMD_SEND_OP_COND, MMC_OCR_ARG, RESPONSE_R3);
++ break;
++
++ case 8:
++ retval = mmc_unpack_r1(request,&r1,mmcinfo.state);
++ mmc_simple_cmd(request, MMC_CMD_APP_CMD, 0, RESPONSE_R1);
++ break;
++
++ case MMC_CMD_APP_CMD:
++ retval = mmc_unpack_r1(request,&r1,mmcinfo.state);
++ if (retval & (limit_41 < 100)) {
++ debug("%s: unable to MMC_APP_CMD error=%d (%s)\n",
++ __func__, retval, mmc_result_to_string(retval));
++ limit_41++;
++ mmc_simple_cmd(request, SD_CMD_APP_SEND_OP_COND, ocr, RESPONSE_R3);
++ } else if (limit_41 < 100) {
++ limit_41++;
++ mmc_simple_cmd(request, SD_CMD_APP_SEND_OP_COND, ocr, RESPONSE_R3);
++ } else{
++ /* reset the card to idle*/
++ mmc_simple_cmd(request, MMC_CMD_GO_IDLE_STATE, 0, RESPONSE_NONE);
++ mmcinfo.sd = 0;
++ }
++ break;
++
++ case SD_CMD_APP_SEND_OP_COND:
++ retval = mmc_unpack_r3(request, &r3);
++ if (retval) {
++ debug("%s: try MMC card\n", __func__);
++ mmc_simple_cmd(request, SD_CMD_APP_SEND_OP_COND, MMC_OCR_ARG, RESPONSE_R3);
++ break;
++ }
++
++ debug("%s: read ocr value = 0x%08x\n", __func__, r3.ocr);
++
++ if(!(r3.ocr & MMC_CARD_BUSY || ocr == 0)){
++ udelay(50000);
++ mmc_simple_cmd(request, MMC_CMD_APP_CMD, 0, RESPONSE_R1);
++ } else {
++ mmcinfo.sd = 1; /* SD Card ready */
++ mmcinfo.state = CARD_STATE_READY;
++ mmc_simple_cmd(request, MMC_CMD_ALL_SEND_CID, 0, RESPONSE_R2_CID);
++ }
++ break;
++
++ case MMC_CMD_SEND_OP_COND:
++ retval = mmc_unpack_r3(request, &r3);
++ if (retval) {
++ debug("%s: failed SEND_OP_COND error=%d (%s)\n",
++ __func__, retval, mmc_result_to_string(retval));
++ return MMC_INIT_FAILED;
++ }
++
++ debug("%s: read ocr value = 0x%08x\n", __func__, r3.ocr);
++ if (!(r3.ocr & MMC_CARD_BUSY)) {
++ mmc_simple_cmd(request, MMC_CMD_SEND_OP_COND, MMC_OCR_ARG, RESPONSE_R3);
++ } else {
++ mmcinfo.sd = 0; /* MMC Card ready */
++ mmcinfo.state = CARD_STATE_READY;
++ mmc_simple_cmd(request, MMC_CMD_ALL_SEND_CID, 0, RESPONSE_R2_CID);
++ }
++ break;
++
++ case MMC_CMD_ALL_SEND_CID:
++ retval = mmc_unpack_cid( request, &mmcinfo.cid );
++ /*FIXME:ignore CRC error for CMD2/CMD9/CMD10 */
++ if ( retval && (retval != MMC_ERROR_CRC)) {
++ debug("mmc_init_card_state: unable to ALL_SEND_CID error=%d (%s)\n",
++ retval, mmc_result_to_string(retval));
++ return MMC_INIT_FAILED;
++ }
++ mmcinfo.state = CARD_STATE_IDENT;
++ if(mmcinfo.sd)
++ mmc_simple_cmd(request, MMC_CMD_SET_RELATIVE_ADDR, 0, RESPONSE_R6);
++ else
++ mmc_simple_cmd(request, MMC_CMD_SET_RELATIVE_ADDR, ID_TO_RCA(mmcinfo.id) << 16, RESPONSE_R1);
++ break;
++
++ case MMC_CMD_SET_RELATIVE_ADDR:
++ if (mmcinfo.sd) {
++ retval = mmc_unpack_r6(request, &r1, mmcinfo.state, &mmcinfo.rca);
++ mmcinfo.rca = mmcinfo.rca << 16;
++ debug("%s: Get RCA from SD: 0x%04x Status: %x\n",
++ __func__, mmcinfo.rca, r1.status);
++ } else {
++ retval = mmc_unpack_r1(request,&r1,mmcinfo.state);
++ mmcinfo.rca = ID_TO_RCA(mmcinfo.id) << 16;
++ }
++ if (retval) {
++ debug("%s: unable to SET_RELATIVE_ADDR error=%d (%s)\n",
++ __func__, retval, mmc_result_to_string(retval));
++ return MMC_INIT_FAILED;
++ }
++
++ mmcinfo.state = CARD_STATE_STBY;
++ mmc_simple_cmd(request, MMC_CMD_SEND_CSD, mmcinfo.rca, RESPONSE_R2_CSD);
++
++ break;
++
++ case MMC_CMD_SEND_CSD:
++ retval = mmc_unpack_csd(request, &mmcinfo.csd);
++ mmc_ready = 1;
++ /*FIXME:ignore CRC error for CMD2/CMD9/CMD10 */
++ if (retval && (retval != MMC_ERROR_CRC)) {
++ debug("%s: unable to SEND_CSD error=%d (%s)\n",
++ __func__, retval, mmc_result_to_string(retval));
++ return MMC_INIT_FAILED;
++ }
++ if (mmcinfo.csd.dsr_imp) {
++ debug("%s: driver doesn't support setting DSR\n", __func__);
++ }
++ mmc_configure_card();
++ return MMC_INIT_PASSED;
++
++ default:
++ debug("%s: error! Illegal last cmd %d\n", __func__, request->cmd);
++ return MMC_INIT_FAILED;
++ }
++
++ return MMC_INIT_DOING;
++}
++
++int mmc_init_card(void)
++{
++ struct mmc_request request;
++ int retval;
++
++ mmc_simple_cmd(&request, MMC_CIM_RESET, 0, RESPONSE_NONE); /* reset card */
++ mmc_simple_cmd(&request, MMC_CMD_GO_IDLE_STATE, 0, RESPONSE_NONE);
++ mmcinfo.sd = 1; /* assuming a SD card */
++
++ while ((retval = mmc_init_card_state(&request)) == MMC_INIT_DOING)
++ ;
++
++ if (retval == MMC_INIT_PASSED)
++ return MMC_NO_ERROR;
++ else
++ return MMC_NO_RESPONSE;
++}
++
++int mmc_legacy_init(int verbose)
++{
++ if (!__msc_card_detected())
++ return 1;
++
++ /* Step-1: init GPIO */
++ __gpio_as_msc();
++ __msc_init_io();
++
++ /* Step-2: turn on power of card */
++#if !defined(CONFIG_SAKC)
++ __msc_enable_power();
++#endif
++
++ /* Step-3: Reset MSC Controller. */
++ __msc_reset();
++
++ /* Step-3: mask all IRQs. */
++ MMC_IRQ_MASK();
++
++ /* Step-4: stop MMC/SD clock */
++ jz_mmc_stop_clock();
++ mmc_init_card();
++ mmc_select_card();
++
++ mmc_dev.block_read = mmc_bread;
++ fat_register_device(&mmc_dev,1); /* partitions start counting with 1 */
++
++ return 0;
++}
++
++/*
++ * Debugging functions
++ */
++static char * mmc_result_strings[] = {
++ "NO_RESPONSE",
++ "NO_ERROR",
++ "ERROR_OUT_OF_RANGE",
++ "ERROR_ADDRESS",
++ "ERROR_BLOCK_LEN",
++ "ERROR_ERASE_SEQ",
++ "ERROR_ERASE_PARAM",
++ "ERROR_WP_VIOLATION",
++ "ERROR_CARD_IS_LOCKED",
++ "ERROR_LOCK_UNLOCK_FAILED",
++ "ERROR_COM_CRC",
++ "ERROR_ILLEGAL_COMMAND",
++ "ERROR_CARD_ECC_FAILED",
++ "ERROR_CC",
++ "ERROR_GENERAL",
++ "ERROR_UNDERRUN",
++ "ERROR_OVERRUN",
++ "ERROR_CID_CSD_OVERWRITE",
++ "ERROR_STATE_MISMATCH",
++ "ERROR_HEADER_MISMATCH",
++ "ERROR_TIMEOUT",
++ "ERROR_CRC",
++ "ERROR_DRIVER_FAILURE",
++};
++
++char * mmc_result_to_string(int i)
++{
++ return mmc_result_strings[i+1];
++}
++
++static char * card_state_strings[] = {
++ "empty",
++ "idle",
++ "ready",
++ "ident",
++ "stby",
++ "tran",
++ "data",
++ "rcv",
++ "prg",
++ "dis",
++};
++
++static inline char * card_state_to_string(int i)
++{
++ return card_state_strings[i+1];
++}
++
++/*
++ * Utility functions
++ */
++
++#define PARSE_U32(_buf,_index) \
++ (((u32)_buf[_index]) << 24) | (((u32)_buf[_index+1]) << 16) | \
++ (((u32)_buf[_index+2]) << 8) | ((u32)_buf[_index+3]);
++
++#define PARSE_U16(_buf,_index) \
++ (((u16)_buf[_index]) << 8) | ((u16)_buf[_index+1]);
++
++int mmc_unpack_csd(struct mmc_request *request, struct mmc_csd *csd)
++{
++ u8 *buf = request->response;
++ int num = 0;
++
++ if (request->result)
++ return request->result;
++
++ if (buf[0] != 0x3f)
++ return MMC_ERROR_HEADER_MISMATCH;
++
++ csd->csd_structure = (buf[1] & 0xc0) >> 6;
++ if (csd->csd_structure)
++ sd2_0 = 1;
++ else
++ sd2_0 = 0;
++
++ switch (csd->csd_structure) {
++ case 0 :/* Version 1.01-1.10
++ * Version 2.00/Standard Capacity */
++ csd->taac = buf[2];
++ csd->nsac = buf[3];
++ csd->tran_speed = buf[4];
++ csd->ccc = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4);
++ csd->read_bl_len = buf[6] & 0x0f;
++ /* for support 2GB card*/
++ if (csd->read_bl_len >= 10)
++ {
++ num = csd->read_bl_len - 9;
++ csd->read_bl_len = 9;
++ }
++
++ csd->read_bl_partial = (buf[7] & 0x80) ? 1 : 0;
++ csd->write_blk_misalign = (buf[7] & 0x40) ? 1 : 0;
++ csd->read_blk_misalign = (buf[7] & 0x20) ? 1 : 0;
++ csd->dsr_imp = (buf[7] & 0x10) ? 1 : 0;
++ csd->c_size = ((((u16)buf[7]) & 0x03) << 10) | (((u16)buf[8]) << 2) | (((u16)buf[9]) & 0xc0) >> 6;
++
++ if (num)
++ csd->c_size = csd->c_size << num;
++
++
++ csd->vdd_r_curr_min = (buf[9] & 0x38) >> 3;
++ csd->vdd_r_curr_max = buf[9] & 0x07;
++ csd->vdd_w_curr_min = (buf[10] & 0xe0) >> 5;
++ csd->vdd_w_curr_max = (buf[10] & 0x1c) >> 2;
++ csd->c_size_mult = ((buf[10] & 0x03) << 1) | ((buf[11] & 0x80) >> 7);
++ csd->sector_size = (buf[11] & 0x7c) >> 2;
++ csd->erase_grp_size = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5);
++ csd->wp_grp_size = buf[12] & 0x1f;
++ csd->wp_grp_enable = (buf[13] & 0x80) ? 1 : 0;
++ csd->default_ecc = (buf[13] & 0x60) >> 5;
++ csd->r2w_factor = (buf[13] & 0x1c) >> 2;
++ csd->write_bl_len = ((buf[13] & 0x03) << 2) | ((buf[14] & 0xc0) >> 6);
++ if (csd->write_bl_len >= 10)
++ csd->write_bl_len = 9;
++
++ csd->write_bl_partial = (buf[14] & 0x20) ? 1 : 0;
++ csd->file_format_grp = (buf[15] & 0x80) ? 1 : 0;
++ csd->copy = (buf[15] & 0x40) ? 1 : 0;
++ csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0;
++ csd->tmp_write_protect = (buf[15] & 0x10) ? 1 : 0;
++ csd->file_format = (buf[15] & 0x0c) >> 2;
++ csd->ecc = buf[15] & 0x03;
++ break;
++ case 1 : /* Version 2.00/High Capacity */
++ csd->taac = 0;
++ csd->nsac = 0;
++ csd->tran_speed = buf[4];
++ csd->ccc = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4);
++
++ csd->read_bl_len = 9;
++ csd->read_bl_partial = 0;
++ csd->write_blk_misalign = 0;
++ csd->read_blk_misalign = 0;
++ csd->dsr_imp = (buf[7] & 0x10) ? 1 : 0;
++ csd->c_size = ((((u16)buf[8]) & 0x3f) << 16) | (((u16)buf[9]) << 8) | ((u16)buf[10]) ;
++ csd->sector_size = 0x7f;
++ csd->erase_grp_size = 0;
++ csd->wp_grp_size = 0;
++ csd->wp_grp_enable = 0;
++ csd->default_ecc = (buf[13] & 0x60) >> 5;
++ csd->r2w_factor = 4;/* Unused */
++ csd->write_bl_len = 9;
++
++ csd->write_bl_partial = 0;
++ csd->file_format_grp = 0;
++ csd->copy = (buf[15] & 0x40) ? 1 : 0;
++ csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0;
++ csd->tmp_write_protect = (buf[15] & 0x10) ? 1 : 0;
++ csd->file_format = 0;
++ csd->ecc = buf[15] & 0x03;
++ }
++
++ return 0;
++}
++
++int mmc_unpack_r1(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state)
++{
++ u8 *buf = request->response;
++
++ if (request->result)
++ return request->result;
++
++ r1->cmd = buf[0];
++ r1->status = PARSE_U32(buf,1);
++
++ debug("mmc_unpack_r1: cmd=%d status=%08x\n", r1->cmd, r1->status);
++
++ if (R1_STATUS(r1->status)) {
++ if (r1->status & R1_OUT_OF_RANGE) return MMC_ERROR_OUT_OF_RANGE;
++ if (r1->status & R1_ADDRESS_ERROR) return MMC_ERROR_ADDRESS;
++ if (r1->status & R1_BLOCK_LEN_ERROR) return MMC_ERROR_BLOCK_LEN;
++ if (r1->status & R1_ERASE_SEQ_ERROR) return MMC_ERROR_ERASE_SEQ;
++ if (r1->status & R1_ERASE_PARAM) return MMC_ERROR_ERASE_PARAM;
++ if (r1->status & R1_WP_VIOLATION) return MMC_ERROR_WP_VIOLATION;
++ /*if (r1->status & R1_CARD_IS_LOCKED) return MMC_ERROR_CARD_IS_LOCKED; */
++ if (r1->status & R1_LOCK_UNLOCK_FAILED) return MMC_ERROR_LOCK_UNLOCK_FAILED;
++ if (r1->status & R1_COM_CRC_ERROR) return MMC_ERROR_COM_CRC;
++ if (r1->status & R1_ILLEGAL_COMMAND) return MMC_ERROR_ILLEGAL_COMMAND;
++ if (r1->status & R1_CARD_ECC_FAILED) return MMC_ERROR_CARD_ECC_FAILED;
++ if (r1->status & R1_CC_ERROR) return MMC_ERROR_CC;
++ if (r1->status & R1_ERROR) return MMC_ERROR_GENERAL;
++ if (r1->status & R1_UNDERRUN) return MMC_ERROR_UNDERRUN;
++ if (r1->status & R1_OVERRUN) return MMC_ERROR_OVERRUN;
++ if (r1->status & R1_CID_CSD_OVERWRITE) return MMC_ERROR_CID_CSD_OVERWRITE;
++ }
++
++ if (buf[0] != request->cmd)
++ return MMC_ERROR_HEADER_MISMATCH;
++
++ /* This should be last - it's the least dangerous error */
++
++ return 0;
++}
++
++int mmc_unpack_scr(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, u32 *scr)
++{
++ u8 *buf = request->response;
++ if (request->result)
++ return request->result;
++
++ *scr = PARSE_U32(buf, 5); /* Save SCR returned by the SD Card */
++ return mmc_unpack_r1(request, r1, state);
++
++}
++
++int mmc_unpack_r6(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, int *rca)
++{
++ u8 *buf = request->response;
++
++ if (request->result)
++ return request->result;
++
++ *rca = PARSE_U16(buf,1); /* Save RCA returned by the SD Card */
++
++ *(buf+1) = 0;
++ *(buf+2) = 0;
++
++ return mmc_unpack_r1(request, r1, state);
++}
++
++int mmc_unpack_cid(struct mmc_request *request, struct mmc_cid *cid)
++{
++ int i;
++ u8 *buf = request->response;
++
++ if (request->result)
++ return request->result;
++
++ cid->mid = buf[1];
++ cid->oid = PARSE_U16(buf,2);
++ for (i = 0 ; i < 5 ; i++)
++ cid->pnm[i] = buf[4+i];
++ cid->pnm[6] = 0;
++ cid->prv = buf[10];
++ cid->psn = PARSE_U32(buf,10);
++ cid->mdt = buf[15];
++
++ printf("Man %02x OEM 0x%04x \"%s\" %d.%d 0x%08x "
++ "Date %02u/%04u\n",
++ cid->mid,
++ cid->oid,
++ cid->pnm,
++ cid->prv >> 4,
++ cid->prv & 0xf,
++ cid->psn,
++ cid->mdt & 0xf,
++ (cid->mdt >> 4) + 2000);
++
++ if (buf[0] != 0x3f)
++ return MMC_ERROR_HEADER_MISMATCH;
++ return 0;
++}
++
++int mmc_unpack_r3(struct mmc_request *request, struct mmc_response_r3 *r3)
++{
++ u8 *buf = request->response;
++
++ if (request->result)
++ return request->result;
++
++ r3->ocr = PARSE_U32(buf,1);
++ debug("mmc_unpack_r3: ocr=%08x\n", r3->ocr);
++
++ if (buf[0] != 0x3f) return MMC_ERROR_HEADER_MISMATCH;
++ return 0;
++}
++
++#define KBPS 1
++#define MBPS 1000
++
++static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 };
++static u32 ts_mul[] = { 0, 1000, 1200, 1300, 1500, 2000, 2500, 3000,
++ 3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 };
++
++u32 mmc_tran_speed(u8 ts)
++{
++ u32 rate = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3];
++
++ if (rate <= 0) {
++ debug("%s: error - unrecognized speed 0x%02x\n", __func__, ts);
++ return 1;
++ }
++
++ return rate;
++}
++
++void mmc_send_cmd(struct mmc_request *request, int cmd, u32 arg,
++ u16 nob, u16 block_len, enum mmc_rsp_t rtype, u8 *buffer)
++{
++ request->cmd = cmd;
++ request->arg = arg;
++ request->rtype = rtype;
++ request->nob = nob;
++ request->block_len = block_len;
++ request->buffer = buffer;
++ request->cnt = nob * block_len;
++
++ jz_mmc_exec_cmd(request);
++}
+diff --git a/drivers/mmc/jz_mmc.h b/drivers/mmc/jz_mmc.h
+new file mode 100644
+index 0000000..936c514
+--- /dev/null
++++ b/drivers/mmc/jz_mmc.h
+@@ -0,0 +1,176 @@
++/*
++ * linux/drivers/mmc/jz_mmc.h
++ *
++ * Author: Vladimir Shebordaev, Igor Oblakov
++ * Copyright: MontaVista Software Inc.
++ *
++ * $Id: jz_mmc.h,v 1.3 2007-06-15 08:04:20 jlwei Exp $
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++#ifndef __MMC_JZMMC_H__
++#define __MMC_JZMMC_H__
++
++#define ID_TO_RCA(x) ((x)+1)
++#define MMC_OCR_ARG 0x00ff8000 /* Argument of OCR */
++
++/* Standard MMC/SD clock speeds */
++#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */
++#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */
++#define SD_CLOCK_FAST 24000000 /* 24 MHz for SD Cards */
++
++/* Use negative numbers to disambiguate */
++#define MMC_CIM_RESET -1
++#define SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
++
++#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
++#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
++#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
++#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
++#define R1_ERASE_PARAM (1 << 27) /* ex, c */
++#define R1_WP_VIOLATION (1 << 26) /* erx, c */
++#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
++#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
++#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
++#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
++#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
++#define R1_CC_ERROR (1 << 20) /* erx, c */
++#define R1_ERROR (1 << 19) /* erx, c */
++#define R1_UNDERRUN (1 << 18) /* ex, c */
++#define R1_OVERRUN (1 << 17) /* ex, c */
++#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
++#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
++#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
++#define R1_ERASE_RESET (1 << 13) /* sr, c */
++#define R1_STATUS(x) (x & 0xFFFFE000)
++
++#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
++
++#define MMC_PROGRAM_CID 26 /* adtc R1 */
++#define MMC_PROGRAM_CSD 27 /* adtc R1 */
++
++#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
++#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */
++#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
++#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
++#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
++#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
++
++
++enum mmc_result_t {
++ MMC_NO_RESPONSE = -1,
++ MMC_NO_ERROR = 0,
++ MMC_ERROR_OUT_OF_RANGE,
++ MMC_ERROR_ADDRESS,
++ MMC_ERROR_BLOCK_LEN,
++ MMC_ERROR_ERASE_SEQ,
++ MMC_ERROR_ERASE_PARAM,
++ MMC_ERROR_WP_VIOLATION,
++ MMC_ERROR_CARD_IS_LOCKED,
++ MMC_ERROR_LOCK_UNLOCK_FAILED,
++ MMC_ERROR_COM_CRC,
++ MMC_ERROR_ILLEGAL_COMMAND,
++ MMC_ERROR_CARD_ECC_FAILED,
++ MMC_ERROR_CC,
++ MMC_ERROR_GENERAL,
++ MMC_ERROR_UNDERRUN,
++ MMC_ERROR_OVERRUN,
++ MMC_ERROR_CID_CSD_OVERWRITE,
++ MMC_ERROR_STATE_MISMATCH,
++ MMC_ERROR_HEADER_MISMATCH,
++ MMC_ERROR_TIMEOUT,
++ MMC_ERROR_CRC,
++ MMC_ERROR_DRIVER_FAILURE,
++};
++
++enum card_state {
++ CARD_STATE_EMPTY = -1,
++ CARD_STATE_IDLE = 0,
++ CARD_STATE_READY = 1,
++ CARD_STATE_IDENT = 2,
++ CARD_STATE_STBY = 3,
++ CARD_STATE_TRAN = 4,
++ CARD_STATE_DATA = 5,
++ CARD_STATE_RCV = 6,
++ CARD_STATE_PRG = 7,
++ CARD_STATE_DIS = 8,
++};
++
++enum mmc_rsp_t {
++ RESPONSE_NONE = 0,
++ RESPONSE_R1 = 1,
++ RESPONSE_R1B = 2,
++ RESPONSE_R2_CID = 3,
++ RESPONSE_R2_CSD = 4,
++ RESPONSE_R3 = 5,
++ RESPONSE_R4 = 6,
++ RESPONSE_R5 = 7,
++ RESPONSE_R6 = 8,
++};
++
++struct mmc_response_r1 {
++ u8 cmd;
++ u32 status;
++};
++
++struct mmc_response_r3 {
++ u32 ocr;
++};
++
++/* the information structure of MMC/SD Card */
++struct mmc_info {
++ int id; /* Card index */
++ int sd; /* MMC or SD card */
++ int rca; /* RCA */
++ u32 scr; /* SCR 63:32*/
++ int flags; /* Ejected, inserted */
++ enum card_state state; /* empty, ident, ready, whatever */
++
++ /* Card specific information */
++ struct mmc_cid cid;
++ struct mmc_csd csd;
++ u32 block_num;
++ u32 block_len;
++ u32 erase_unit;
++};
++
++struct mmc_info mmcinfo;
++
++struct mmc_request {
++ int index; /* Slot index - used for CS lines */
++ int cmd; /* Command to send */
++ u32 arg; /* Argument to send */
++ enum mmc_rsp_t rtype; /* Response type expected */
++
++ /* Data transfer (these may be modified at the low level) */
++ u16 nob; /* Number of blocks to transfer*/
++ u16 block_len; /* Block length */
++ u8 *buffer; /* Data buffer */
++ u32 cnt; /* Data length, for PIO */
++
++ /* Results */
++ u8 response[18]; /* Buffer to store response - CRC is optional */
++ enum mmc_result_t result;
++};
++
++char * mmc_result_to_string(int);
++int mmc_unpack_csd(struct mmc_request *request, struct mmc_csd *csd);
++int mmc_unpack_r1(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state);
++int mmc_unpack_r6(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, int *rca);
++int mmc_unpack_scr(struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state, u32 *scr);
++int mmc_unpack_cid(struct mmc_request *request, struct mmc_cid *cid);
++int mmc_unpack_r3(struct mmc_request *request, struct mmc_response_r3 *r3);
++
++void mmc_send_cmd(struct mmc_request *request, int cmd, u32 arg,
++ u16 nob, u16 block_len, enum mmc_rsp_t rtype, u8 *buffer);
++u32 mmc_tran_speed(u8 ts);
++void jz_mmc_set_clock(int sd, u32 rate);
++
++static inline void mmc_simple_cmd(struct mmc_request *request, int cmd, u32 arg, enum mmc_rsp_t rtype)
++{
++ mmc_send_cmd( request, cmd, arg, 0, 0, rtype, 0);
++}
++
++#endif /* __MMC_JZMMC_H__ */
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 7bff444..7b33be0 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -31,6 +31,15 @@
+ /*
+ * Miscellaneous configurable options
+ */
++#define CONFIG_JZ4740_MMC
++#define CONFIG_MMC 1
++#define CONFIG_FAT 1
++#define CONFIG_DOS_PARTITION 1
++#define CONFIG_CMD_MMC
++#define CONFIG_CMD_FAT
++#define CONFIG_CMD_EXT2
++
++
+ #define CONFIG_SYS_SDRAM_BASE 0x80000000 /* Cached addr */
+ #define CONFIG_SYS_INIT_SP_OFFSET 0x400000
+ #define CONFIG_SYS_LOAD_ADDR 0x80600000
+diff --git a/include/mmc.h b/include/mmc.h
+index a13e2bd..3c4761c 100644
+--- a/include/mmc.h
++++ b/include/mmc.h
+@@ -283,4 +283,44 @@ struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode);
+ int mmc_legacy_init(int verbose);
+ #endif
+
++struct mmc_csd
++{
++ u8 csd_structure:2,
++ spec_vers:4,
++ rsvd1:2;
++ u8 taac;
++ u8 nsac;
++ u8 tran_speed;
++ u16 ccc:12,
++ read_bl_len:4;
++ u32 c_size:22;
++ u64 read_bl_partial:1,
++ write_blk_misalign:1,
++ read_blk_misalign:1,
++ dsr_imp:1,
++ rsvd2:2,
++ vdd_r_curr_min:3,
++ vdd_r_curr_max:3,
++ vdd_w_curr_min:3,
++ vdd_w_curr_max:3,
++ c_size_mult:3,
++ sector_size:5,
++ erase_grp_size:5,
++ wp_grp_size:5,
++ wp_grp_enable:1,
++ default_ecc:2,
++ r2w_factor:3,
++ write_bl_len:4,
++ write_bl_partial:1,
++ rsvd3:5;
++ u8 file_format_grp:1,
++ copy:1,
++ perm_write_protect:1,
++ tmp_write_protect:1,
++ file_format:2,
++ ecc:2;
++ u8 crc:7;
++ u8 one:1;
++};
++
+ #endif /* _MMC_H_ */
+--
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch b/package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch
new file mode 100644
index 0000000000..73e03243c3
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0004-add-more-boot-options-F1-F2-F3-F4-M-S.patch
@@ -0,0 +1,200 @@
+From c52b6168979d03fc31205444c3278c537787472a Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 18:39:55 +0800
+Subject: [PATCH 4/6] add more boot options(F1/F2/F3/F4/M/S)
+
+---
+ arch/mips/include/asm/global_data.h | 3 +++
+ arch/mips/lib/bootm.c | 17 ++++++++++++++++-
+ board/qi/qi_lb60/qi_lb60.c | 26 +++++++++++++++++++++++---
+ common/main.c | 21 +++++++++++++++++++--
+ include/configs/qi_lb60.h | 32 ++++++++++++++++++++++++++++++++
+ 5 files changed, 93 insertions(+), 6 deletions(-)
+
+diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
+index 6e2cdc7..cd03d7e 100644
+--- a/arch/mips/include/asm/global_data.h
++++ b/arch/mips/include/asm/global_data.h
+@@ -59,6 +59,9 @@ typedef struct global_data {
+ unsigned long env_valid; /* Checksum of Environment valid? */
+ void **jt; /* jump table */
+ char env_buf[32]; /* buffer for getenv() before reloc. */
++#if defined(CONFIG_NANONOTE)
++ unsigned long boot_option;
++#endif
+ } gd_t;
+
+ #include <asm-generic/global_data_flags.h>
+diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c
+index 608c1a7..e00416b 100644
+--- a/arch/mips/lib/bootm.c
++++ b/arch/mips/lib/bootm.c
+@@ -47,10 +47,25 @@ int do_bootm_linux(int flag, int argc, char * const argv[],
+ bootm_headers_t *images)
+ {
+ void (*theKernel) (int, char **, char **, int *);
+- char *commandline = getenv("bootargs");
++ char *commandline;
+ char env_buf[12];
+ char *cp;
+
++#if defined(CONFIG_NANONOTE)
++ if (gd->boot_option & BOOT_FROM_MEMCARD)
++ commandline = getenv ("bootargsfromsd");
++ else if (gd->boot_option & BOOT_WITH_F1)
++ commandline = getenv ("bootargsf1");
++ else if (gd->boot_option & BOOT_WITH_F2)
++ commandline = getenv ("bootargsf2");
++ else if (gd->boot_option & BOOT_WITH_F3)
++ commandline = getenv ("bootargsf3");
++ else if (gd->boot_option & BOOT_WITH_F4)
++ commandline = getenv ("bootargsf4");
++ else
++#endif
++ commandline = getenv ("bootargs");
++
+ if ((flag != 0) && (flag != BOOTM_STATE_OS_GO))
+ return 1;
+
+diff --git a/board/qi/qi_lb60/qi_lb60.c b/board/qi/qi_lb60/qi_lb60.c
+index a2ba648..d622219 100644
+--- a/board/qi/qi_lb60/qi_lb60.c
++++ b/board/qi/qi_lb60/qi_lb60.c
+@@ -15,7 +15,7 @@ DECLARE_GLOBAL_DATA_PTR;
+
+ static void gpio_init(void)
+ {
+- unsigned int i;
++ unsigned int i, j;
+
+ /* Initialize NAND Flash Pins */
+ __gpio_as_nand();
+@@ -42,14 +42,34 @@ static void gpio_init(void)
+
+ if (__gpio_get_pin(GPIO_KEYIN_BASE + 2) == 0){
+ printf("[S] pressed, enable UART0\n");
++ gd->boot_option |= BOOT_WITH_ENABLE_UART;
+ __gpio_as_uart0();
+ } else {
+ __gpio_as_input(GPIO_KEYIN_8);
+ __gpio_enable_pull(GPIO_KEYIN_8);
+ }
+
+- /* enable the TP4, TP5 as UART0 */
+- __gpio_jtag_to_uart0();
++ if (__gpio_get_pin(GPIO_KEYIN_BASE + 3) == 0) {
++ printf("[M] pressed, boot from memory card\n");
++ gd->boot_option |= BOOT_FROM_MEMCARD;
++ __gpio_jtag_to_uart0();
++ }
++
++ for (j = 0; j < 4; j++) {
++ for (i = 0; i < 4; i++)
++ __gpio_set_pin(GPIO_KEYOUT_BASE + i);
++
++ __gpio_clear_pin(GPIO_KEYOUT_BASE + j);
++
++ if (__gpio_get_pin(GPIO_KEYIN_BASE) == 0) {
++ printf("[F%d] pressed", (j + 1));
++ gd->boot_option |= (1 << (j + 2));
++ /* BOOT_WITH_F1 (1 << 2) */
++ /* BOOT_WITH_F2 (1 << 3) */
++ /* BOOT_WITH_F3 (1 << 4) */
++ /* BOOT_WITH_F4 (1 << 5) */
++ }
++ }
+
+ __gpio_as_output(GPIO_AUDIO_POP);
+ __gpio_set_pin(GPIO_AUDIO_POP);
+diff --git a/common/main.c b/common/main.c
+index 9507cec..dbfb7ca 100644
+--- a/common/main.c
++++ b/common/main.c
+@@ -355,7 +355,11 @@ void main_loop (void)
+ #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
+ s = getenv ("bootdelay");
+ bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
+-
++#if defined(CONFIG_NANONOTE)
++ DECLARE_GLOBAL_DATA_PTR;
++ if (gd->boot_option & BOOT_WITH_ENABLE_UART)
++ bootdelay = 3;
++# endif
+ debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
+
+ #if defined(CONFIG_MENU_SHOW)
+@@ -379,7 +383,20 @@ void main_loop (void)
+ }
+ else
+ #endif /* CONFIG_BOOTCOUNT_LIMIT */
+- s = getenv ("bootcmd");
++#if defined(CONFIG_NANONOTE)
++ if (gd->boot_option & BOOT_FROM_MEMCARD)
++ s = getenv ("bootcmdfromsd");
++ else if (gd->boot_option & BOOT_WITH_F1)
++ s = getenv ("bootcmdf1");
++ else if (gd->boot_option & BOOT_WITH_F2)
++ s = getenv ("bootcmdf2");
++ else if (gd->boot_option & BOOT_WITH_F3)
++ s = getenv ("bootcmdf3");
++ else if (gd->boot_option & BOOT_WITH_F4)
++ s = getenv ("bootcmdf4");
++ else
++#endif
++ s = getenv ("bootcmd");
+
+ debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
+
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 7b33be0..52b370c 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -31,6 +31,7 @@
+ /*
+ * Miscellaneous configurable options
+ */
++#define CONFIG_NANONOTE
+ #define CONFIG_JZ4740_MMC
+ #define CONFIG_MMC 1
+ #define CONFIG_FAT 1
+@@ -39,6 +40,37 @@
+ #define CONFIG_CMD_FAT
+ #define CONFIG_CMD_EXT2
+
++#define CONFIG_CMD_UBIFS
++#define CONFIG_CMD_UBI
++#define CONFIG_MTD_PARTITIONS
++#define CONFIG_MTD_DEVICE
++#define CONFIG_CMD_MTDPARTS
++#define CONFIG_CMD_UBI
++#define CONFIG_CMD_UBIFS
++#define CONFIG_LZO
++#define CONFIG_RBTREE
++
++#define MTDIDS_DEFAULT "nand0=jz4740-nand"
++#define MTDPARTS_DEFAULT "mtdparts=jz4740-nand:4M@0(uboot)ro,4M@4M(kernel)ro,512M@8M(rootfs)ro,-(data)ro"
++
++#define BOOT_FROM_MEMCARD 1
++#define BOOT_WITH_ENABLE_UART (1 << 1) /* Vaule for global_data.h gd->boot_option */
++#define BOOT_WITH_F1 (1 << 2)
++#define BOOT_WITH_F2 (1 << 3)
++#define BOOT_WITH_F3 (1 << 4)
++#define BOOT_WITH_F4 (1 << 5)
++
++#define CONFIG_EXTRA_ENV_SETTINGS \
++ "bootcmdfromsd=mmc init; ext2load mmc 0 0x80600000 /boot/uImage; bootm;\0" \
++ "bootargsfromsd=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p1 rw rootwait\0" \
++ "bootcmdf1=mmc init; ext2load mmc 0:1 0x80600000 /boot/uImage; bootm;\0" \
++ "bootargsf1=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p1 rw rootwait\0" \
++ "bootcmdf2=mmc init; ext2load mmc 0:2 0x80600000 /boot/uImage; bootm;\0" \
++ "bootargsf2=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p2 rw rootwait\0" \
++ "bootcmdf3=mmc init; ext2load mmc 0:3 0x80600000 /boot/uImage; bootm;\0" \
++ "bootargsf3=mem=32M console=tty0 console=ttyS0,57600n8 rootfstype=ext2 root=/dev/mmcblk0p3 rw rootwait\0" \
++ "bootcmdf4=mtdparts default;ubi part rootfs;ubifsmount rootfs;ubifsload 0x80600000 /boot/uImage; bootm;\0" \
++ "bootargsf4=mem=32M console=tty0 console=ttyS0,57600n8 ubi.mtd=2 rootfstype=ubifs root=ubi0:rootfs rw rootwait"
+
+ #define CONFIG_SYS_SDRAM_BASE 0x80000000 /* Cached addr */
+ #define CONFIG_SYS_INIT_SP_OFFSET 0x400000
+--
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch b/package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch
new file mode 100644
index 0000000000..2c550f7205
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0005-add-nanonote-lcd-support.patch
@@ -0,0 +1,847 @@
+From ca8c5216cfd3ad3fda9867ed2d157ae5a209834b Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 22:05:27 +0800
+Subject: [PATCH 5/6] add nanonote lcd support
+
+---
+ arch/mips/include/asm/global_data.h | 1 +
+ arch/mips/include/asm/jz4740.h | 90 ++++++++
+ arch/mips/lib/board.c | 6 +
+ common/lcd.c | 9 +-
+ drivers/video/Makefile | 1 +
+ drivers/video/nanonote_gpm940b0.c | 400 +++++++++++++++++++++++++++++++++++
+ drivers/video/nanonote_gpm940b0.h | 135 ++++++++++++
+ include/configs/qi_lb60.h | 7 +
+ include/lcd.h | 52 ++++-
+ 9 files changed, 697 insertions(+), 4 deletions(-)
+ create mode 100644 drivers/video/nanonote_gpm940b0.c
+ create mode 100644 drivers/video/nanonote_gpm940b0.h
+
+diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
+index cd03d7e..7cec2de 100644
+--- a/arch/mips/include/asm/global_data.h
++++ b/arch/mips/include/asm/global_data.h
+@@ -44,6 +44,7 @@ typedef struct global_data {
+ unsigned long per_clk; /* Peripheral bus clock */
+ unsigned long mem_clk; /* Memory bus clock */
+ unsigned long dev_clk; /* Device clock */
++ unsigned long fb_base; /* base address of framebuffer */
+ /* "static data" needed by most of timer.c */
+ unsigned long tbl;
+ unsigned long lastinc;
+diff --git a/arch/mips/include/asm/jz4740.h b/arch/mips/include/asm/jz4740.h
+index 68287fb..13724a2 100644
+--- a/arch/mips/include/asm/jz4740.h
++++ b/arch/mips/include/asm/jz4740.h
+@@ -1312,5 +1312,95 @@ do { \
+ while (REG_MSC_STAT & MSC_STAT_IS_RESETTING); \
+ } while (0)
+
++/*************************************************************************
++ * LCD (LCD Controller)
++ *************************************************************************/
++#define REG32(addr) *((volatile u32 *)(addr))
++
++#define CPM_BASE 0xB0000000
++#define CPM_CPCCR (CPM_BASE+0x00)
++#define REG_CPM_CPCCR REG32(CPM_CPCCR)
++
++#define LCD_BASE 0xB3050000
++#define LCD_CFG (LCD_BASE + 0x00) /* LCD Configure Register */
++#define LCD_VSYNC (LCD_BASE + 0x04) /* Vertical Synchronize Register */
++#define LCD_HSYNC (LCD_BASE + 0x08) /* Horizontal Synchronize Register */
++#define LCD_VAT (LCD_BASE + 0x0c) /* Virtual Area Setting Register */
++#define LCD_DAH (LCD_BASE + 0x10) /* Display Area Horizontal Start/End Point */
++#define LCD_DAV (LCD_BASE + 0x14) /* Display Area Vertical Start/End Point */
++#define LCD_PS (LCD_BASE + 0x18) /* PS Signal Setting */
++#define LCD_CLS (LCD_BASE + 0x1c) /* CLS Signal Setting */
++#define LCD_SPL (LCD_BASE + 0x20) /* SPL Signal Setting */
++#define LCD_REV (LCD_BASE + 0x24) /* REV Signal Setting */
++#define LCD_CTRL (LCD_BASE + 0x30) /* LCD Control Register */
++#define LCD_STATE (LCD_BASE + 0x34) /* LCD Status Register */
++#define LCD_IID (LCD_BASE + 0x38) /* Interrupt ID Register */
++#define LCD_DA0 (LCD_BASE + 0x40) /* Descriptor Address Register 0 */
++#define LCD_SA0 (LCD_BASE + 0x44) /* Source Address Register 0 */
++#define LCD_FID0 (LCD_BASE + 0x48) /* Frame ID Register 0 */
++#define LCD_CMD0 (LCD_BASE + 0x4c) /* DMA Command Register 0 */
++#define LCD_DA1 (LCD_BASE + 0x50) /* Descriptor Address Register 1 */
++#define LCD_SA1 (LCD_BASE + 0x54) /* Source Address Register 1 */
++#define LCD_FID1 (LCD_BASE + 0x58) /* Frame ID Register 1 */
++#define LCD_CMD1 (LCD_BASE + 0x5c) /* DMA Command Register 1 */
++
++#define REG_LCD_CFG REG32(LCD_CFG)
++#define REG_LCD_VSYNC REG32(LCD_VSYNC)
++#define REG_LCD_HSYNC REG32(LCD_HSYNC)
++#define REG_LCD_VAT REG32(LCD_VAT)
++#define REG_LCD_DAH REG32(LCD_DAH)
++#define REG_LCD_DAV REG32(LCD_DAV)
++#define REG_LCD_PS REG32(LCD_PS)
++#define REG_LCD_CLS REG32(LCD_CLS)
++#define REG_LCD_SPL REG32(LCD_SPL)
++#define REG_LCD_REV REG32(LCD_REV)
++#define REG_LCD_CTRL REG32(LCD_CTRL)
++#define REG_LCD_STATE REG32(LCD_STATE)
++#define REG_LCD_IID REG32(LCD_IID)
++#define REG_LCD_DA0 REG32(LCD_DA0)
++#define REG_LCD_SA0 REG32(LCD_SA0)
++#define REG_LCD_FID0 REG32(LCD_FID0)
++#define REG_LCD_CMD0 REG32(LCD_CMD0)
++#define REG_LCD_DA1 REG32(LCD_DA1)
++#define REG_LCD_SA1 REG32(LCD_SA1)
++#define REG_LCD_FID1 REG32(LCD_FID1)
++#define REG_LCD_CMD1 REG32(LCD_CMD1)
++
++#define LCD_CTRL_BPP_BIT 0 /* Bits Per Pixel */
++#define LCD_CTRL_BPP_MASK (0x07 << LCD_CTRL_BPP_BIT)
++ #define LCD_CTRL_BPP_1 (0 << LCD_CTRL_BPP_BIT) /* 1 bpp */
++ #define LCD_CTRL_BPP_2 (1 << LCD_CTRL_BPP_BIT) /* 2 bpp */
++ #define LCD_CTRL_BPP_4 (2 << LCD_CTRL_BPP_BIT) /* 4 bpp */
++ #define LCD_CTRL_BPP_8 (3 << LCD_CTRL_BPP_BIT) /* 8 bpp */
++ #define LCD_CTRL_BPP_16 (4 << LCD_CTRL_BPP_BIT) /* 15/16 bpp */
++ #define LCD_CTRL_BPP_18_24 (5 << LCD_CTRL_BPP_BIT) /* 18/24/32 bpp */
++
++#define LCD_CTRL_BST_BIT 28 /* Burst Length Selection */
++#define LCD_CTRL_BST_MASK (0x03 << LCD_CTRL_BST_BIT)
++ #define LCD_CTRL_BST_4 (0 << LCD_CTRL_BST_BIT) /* 4-word */
++ #define LCD_CTRL_BST_8 (1 << LCD_CTRL_BST_BIT) /* 8-word */
++ #define LCD_CTRL_BST_16 (2 << LCD_CTRL_BST_BIT) /* 16-word */
++#define LCD_CTRL_RGB565 (0 << 27) /* RGB565 mode */
++#define LCD_CTRL_RGB555 (1 << 27) /* RGB555 mode */
++#define LCD_CTRL_OFUP (1 << 26) /* Output FIFO underrun protection enable */
++#define LCD_CTRL_FRC_BIT 24 /* STN FRC Algorithm Selection */
++#define LCD_CTRL_FRC_MASK (0x03 << LCD_CTRL_FRC_BIT)
++ #define LCD_CTRL_FRC_16 (0 << LCD_CTRL_FRC_BIT) /* 16 grayscale */
++ #define LCD_CTRL_FRC_4 (1 << LCD_CTRL_FRC_BIT) /* 4 grayscale */
++ #define LCD_CTRL_FRC_2 (2 << LCD_CTRL_FRC_BIT) /* 2 grayscale */
++
++#define CPM_LPCDR (CPM_BASE+0x64)
++#define CPM_CLKGR (CPM_BASE+0x20)
++#define REG_CPM_LPCDR REG32(CPM_LPCDR)
++#define REG_CPM_CLKGR REG32(CPM_CLKGR)
++
++#define __cpm_start_tcu() (REG_CPM_CLKGR &= ~CPM_CLKGR_TCU)
++#define __cpm_stop_lcd() (REG_CPM_CLKGR |= CPM_CLKGR_LCD)
++#define __cpm_set_pixdiv(v) \
++ (REG_CPM_LPCDR = (REG_CPM_LPCDR & ~CPM_LPCDR_PIXDIV_MASK) | ((v) << (CPM_LPCDR_PIXDIV_BIT)))
++#define __cpm_set_ldiv(v) \
++ (REG_CPM_CPCCR = (REG_CPM_CPCCR & ~CPM_CPCCR_LDIV_MASK) | ((v) << (CPM_CPCCR_LDIV_BIT)))
++#define __cpm_start_lcd() (REG_CPM_CLKGR &= ~CPM_CLKGR_LCD)
++
+ #endif /* !__ASSEMBLY__ */
+ #endif /* __JZ4740_H__ */
+diff --git a/arch/mips/lib/board.c b/arch/mips/lib/board.c
+index b14b33e..c2e64d9 100644
+--- a/arch/mips/lib/board.c
++++ b/arch/mips/lib/board.c
+@@ -172,6 +172,12 @@ void board_init_f(ulong bootflag)
+ addr &= ~(4096 - 1);
+ debug("Top of RAM usable for U-Boot at: %08lx\n", addr);
+
++#ifdef CONFIG_LCD
++ /* reserve memory for LCD display (always full pages) */
++ addr = lcd_setmem (addr);
++ gd->fb_base = addr;
++#endif /* CONFIG_LCD */
++
+ /* Reserve memory for U-Boot code, data & bss
+ * round down to next 16 kB limit
+ */
+diff --git a/common/lcd.c b/common/lcd.c
+index b6be800..af1281a 100644
+--- a/common/lcd.c
++++ b/common/lcd.c
+@@ -263,6 +263,13 @@ static void lcd_drawchars(ushort x, ushort y, uchar *str, int count)
+ lcd_color_fg : lcd_color_bg;
+ bits <<= 1;
+ }
++#elif LCD_BPP == LCD_COLOR32
++ uint *m = (uint *)d;
++ for (c=0; c<32; ++c) {
++ *m++ = (bits & 0x80) ?
++ lcd_color_fg : lcd_color_bg;
++ bits <<= 1;
++ }
+ #endif
+ }
+ #if LCD_BPP == LCD_MONOCHROME
+@@ -509,7 +516,7 @@ static inline ushort *configuration_get_cmap(void)
+ return (ushort *)&(cp->lcd_cmap[255 * sizeof(ushort)]);
+ #elif defined(CONFIG_ATMEL_LCD)
+ return (ushort *)(panel_info.mmio + ATMEL_LCDC_LUT(0));
+-#elif !defined(CONFIG_ATMEL_HLCD) && !defined(CONFIG_EXYNOS_FB)
++#elif !defined(CONFIG_ATMEL_HLCD) && !defined(CONFIG_EXYNOS_FB) && !defined(CONFIG_VIDEO_GPM940B0)
+ return panel_info.cmap;
+ #else
+ #if defined(CONFIG_LCD_LOGO)
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index ebb6da8..03625bc 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -50,6 +50,7 @@ COBJS-$(CONFIG_VIDEO_SED13806) += sed13806.o
+ COBJS-$(CONFIG_VIDEO_SM501) += sm501.o
+ COBJS-$(CONFIG_VIDEO_SMI_LYNXEM) += smiLynxEM.o videomodes.o
+ COBJS-$(CONFIG_VIDEO_VCXK) += bus_vcxk.o
++COBJS-$(CONFIG_VIDEO_GPM940B0) += nanonote_gpm940b0.o
+
+ COBJS := $(sort $(COBJS-y))
+ SRCS := $(COBJS:.o=.c)
+diff --git a/drivers/video/nanonote_gpm940b0.c b/drivers/video/nanonote_gpm940b0.c
+new file mode 100644
+index 0000000..11efb72
+--- /dev/null
++++ b/drivers/video/nanonote_gpm940b0.c
+@@ -0,0 +1,400 @@
++/*
++ * JzRISC lcd controller
++ *
++ * Xiangfu Liu <xiangfu@sharism.cc>
++ *
++ * 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 <lcd.h>
++
++#include <asm/io.h> /* virt_to_phys() */
++#include <asm/jz4740.h>
++
++#include "nanonote_gpm940b0.h"
++
++#define align2(n) (n)=((((n)+1)>>1)<<1)
++#define align4(n) (n)=((((n)+3)>>2)<<2)
++#define align8(n) (n)=((((n)+7)>>3)<<3)
++
++struct jzfb_info {
++ unsigned int cfg; /* panel mode and pin usage etc. */
++ unsigned int w;
++ unsigned int h;
++ unsigned int bpp; /* bit per pixel */
++ unsigned int fclk; /* frame clk */
++ unsigned int hsw; /* hsync width, in pclk */
++ unsigned int vsw; /* vsync width, in line count */
++ unsigned int elw; /* end of line, in pclk */
++ unsigned int blw; /* begin of line, in pclk */
++ unsigned int efw; /* end of frame, in line count */
++ unsigned int bfw; /* begin of frame, in line count */
++};
++
++static struct jzfb_info jzfb = {
++ MODE_8BIT_SERIAL_TFT | PCLK_N | HSYNC_N | VSYNC_N,
++ 320, 240, 32, 70, 1, 1, 273, 140, 1, 20
++};
++
++vidinfo_t panel_info = {
++ 320, 240, LCD_BPP,
++};
++
++void *lcd_base;
++void *lcd_console_address;
++int lcd_line_length;
++int lcd_color_fg;
++int lcd_color_bg;
++short console_col;
++short console_row;
++
++static int jz_lcd_init_mem(void *lcdbase, vidinfo_t *vid)
++{
++ u_long palette_mem_size;
++ struct jz_fb_info *fbi = &vid->jz_fb;
++ int fb_size = vid->vl_row * (vid->vl_col * NBITS (vid->vl_bpix)) / 8;
++
++ fbi->screen = (u_long)lcdbase;
++ fbi->palette_size = 256;
++ palette_mem_size = fbi->palette_size * sizeof(u16);
++
++ debug("jz_lcd.c palette_mem_size = 0x%08lx\n", (u_long) palette_mem_size);
++ /* locate palette and descs at end of page following fb */
++ fbi->palette = (u_long)lcdbase + fb_size + PAGE_SIZE - palette_mem_size;
++
++ return 0;
++}
++
++static void jz_lcd_desc_init(vidinfo_t *vid)
++{
++ struct jz_fb_info * fbi;
++ fbi = &vid->jz_fb;
++ fbi->dmadesc_fblow = (struct jz_fb_dma_descriptor *)((unsigned int)fbi->palette - 3*16);
++ fbi->dmadesc_fbhigh = (struct jz_fb_dma_descriptor *)((unsigned int)fbi->palette - 2*16);
++ fbi->dmadesc_palette = (struct jz_fb_dma_descriptor *)((unsigned int)fbi->palette - 1*16);
++
++ #define BYTES_PER_PANEL (vid->vl_col * vid->vl_row * NBITS(vid->vl_bpix) / 8)
++
++ /* populate descriptors */
++ fbi->dmadesc_fblow->fdadr = virt_to_phys(fbi->dmadesc_fblow);
++ fbi->dmadesc_fblow->fsadr = virt_to_phys((void *)(fbi->screen + BYTES_PER_PANEL));
++ fbi->dmadesc_fblow->fidr = 0;
++ fbi->dmadesc_fblow->ldcmd = BYTES_PER_PANEL / 4 ;
++
++ fbi->fdadr1 = virt_to_phys(fbi->dmadesc_fblow); /* only used in dual-panel mode */
++
++ fbi->dmadesc_fbhigh->fsadr = virt_to_phys((void *)fbi->screen);
++ fbi->dmadesc_fbhigh->fidr = 0;
++ fbi->dmadesc_fbhigh->ldcmd = BYTES_PER_PANEL / 4; /* length in word */
++
++ fbi->dmadesc_palette->fsadr = virt_to_phys((void *)fbi->palette);
++ fbi->dmadesc_palette->fidr = 0;
++ fbi->dmadesc_palette->ldcmd = (fbi->palette_size * 2)/4 | (1<<28);
++
++ if(NBITS(vid->vl_bpix) < 12) {
++ /* assume any mode with <12 bpp is palette driven */
++ fbi->dmadesc_palette->fdadr = virt_to_phys(fbi->dmadesc_fbhigh);
++ fbi->dmadesc_fbhigh->fdadr = virt_to_phys(fbi->dmadesc_palette);
++ /* flips back and forth between pal and fbhigh */
++ fbi->fdadr0 = virt_to_phys(fbi->dmadesc_palette);
++ } else {
++ /* palette shouldn't be loaded in true-color mode */
++ fbi->dmadesc_fbhigh->fdadr = virt_to_phys((void *)fbi->dmadesc_fbhigh);
++ fbi->fdadr0 = virt_to_phys(fbi->dmadesc_fbhigh); /* no pal just fbhigh */
++ }
++}
++
++static int jz_lcd_hw_init(vidinfo_t *vid)
++{
++ struct jz_fb_info *fbi = &vid->jz_fb;
++ unsigned int val = 0;
++ unsigned int pclk;
++ unsigned int stnH;
++ int pll_div;
++
++ /* Setting Control register */
++ switch (jzfb.bpp) {
++ case 1:
++ val |= LCD_CTRL_BPP_1;
++ break;
++ case 2:
++ val |= LCD_CTRL_BPP_2;
++ break;
++ case 4:
++ val |= LCD_CTRL_BPP_4;
++ break;
++ case 8:
++ val |= LCD_CTRL_BPP_8;
++ break;
++ case 15:
++ val |= LCD_CTRL_RGB555;
++ case 16:
++ val |= LCD_CTRL_BPP_16;
++ break;
++ case 17 ... 32:
++ val |= LCD_CTRL_BPP_18_24; /* target is 4bytes/pixel */
++ break;
++
++ default:
++ printf("jz_lcd.c The BPP %d is not supported\n", jzfb.bpp);
++ val |= LCD_CTRL_BPP_16;
++ break;
++ }
++
++ switch (jzfb.cfg & MODE_MASK) {
++ case MODE_STN_MONO_DUAL:
++ case MODE_STN_COLOR_DUAL:
++ case MODE_STN_MONO_SINGLE:
++ case MODE_STN_COLOR_SINGLE:
++ switch (jzfb.bpp) {
++ case 1:
++ /* val |= LCD_CTRL_PEDN; */
++ case 2:
++ val |= LCD_CTRL_FRC_2;
++ break;
++ case 4:
++ val |= LCD_CTRL_FRC_4;
++ break;
++ case 8:
++ default:
++ val |= LCD_CTRL_FRC_16;
++ break;
++ }
++ break;
++ }
++
++ val |= LCD_CTRL_BST_16; /* Burst Length is 16WORD=64Byte */
++ val |= LCD_CTRL_OFUP; /* OutFIFO underrun protect */
++
++ switch (jzfb.cfg & MODE_MASK) {
++ case MODE_STN_MONO_DUAL:
++ case MODE_STN_COLOR_DUAL:
++ case MODE_STN_MONO_SINGLE:
++ case MODE_STN_COLOR_SINGLE:
++ switch (jzfb.cfg & STN_DAT_PINMASK) {
++ case STN_DAT_PIN1:
++ /* Do not adjust the hori-param value. */
++ break;
++ case STN_DAT_PIN2:
++ align2(jzfb.hsw);
++ align2(jzfb.elw);
++ align2(jzfb.blw);
++ break;
++ case STN_DAT_PIN4:
++ align4(jzfb.hsw);
++ align4(jzfb.elw);
++ align4(jzfb.blw);
++ break;
++ case STN_DAT_PIN8:
++ align8(jzfb.hsw);
++ align8(jzfb.elw);
++ align8(jzfb.blw);
++ break;
++ }
++ break;
++ }
++
++ REG_LCD_CTRL = val;
++
++ switch (jzfb.cfg & MODE_MASK) {
++ case MODE_STN_MONO_DUAL:
++ case MODE_STN_COLOR_DUAL:
++ case MODE_STN_MONO_SINGLE:
++ case MODE_STN_COLOR_SINGLE:
++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) ||
++ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
++ stnH = jzfb.h >> 1;
++ else
++ stnH = jzfb.h;
++
++ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
++ REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw);
++
++ /* Screen setting */
++ REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw);
++ REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w);
++ REG_LCD_DAV = (0 << 16) | (stnH);
++
++ /* AC BIAs signal */
++ REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw);
++
++ break;
++
++ case MODE_TFT_GEN:
++ case MODE_TFT_SHARP:
++ case MODE_TFT_CASIO:
++ case MODE_TFT_SAMSUNG:
++ case MODE_8BIT_SERIAL_TFT:
++ case MODE_TFT_18BIT:
++ REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
++ REG_LCD_HSYNC = (0 << 16) | jzfb.hsw;
++ REG_LCD_DAV =((jzfb.vsw+jzfb.bfw) << 16) | (jzfb.vsw +jzfb.bfw+jzfb.h);
++ REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w );
++ REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) \
++ | (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw);
++ break;
++ }
++
++ switch (jzfb.cfg & MODE_MASK) {
++ case MODE_TFT_SAMSUNG:
++ {
++ unsigned int total, tp_s, tp_e, ckv_s, ckv_e;
++ unsigned int rev_s, rev_e, inv_s, inv_e;
++
++ pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *
++ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
++
++ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;
++ tp_s = jzfb.blw + jzfb.w + 1;
++ tp_e = tp_s + 1;
++ ckv_s = tp_s - pclk/(1000000000/4100);
++ ckv_e = tp_s + total;
++ rev_s = tp_s - 11; /* -11.5 clk */
++ rev_e = rev_s + total;
++ inv_s = tp_s;
++ inv_e = inv_s + total;
++ REG_LCD_CLS = (tp_s << 16) | tp_e;
++ REG_LCD_PS = (ckv_s << 16) | ckv_e;
++ REG_LCD_SPL = (rev_s << 16) | rev_e;
++ REG_LCD_REV = (inv_s << 16) | inv_e;
++ jzfb.cfg |= STFT_REVHI | STFT_SPLHI;
++ break;
++ }
++ case MODE_TFT_SHARP:
++ {
++ unsigned int total, cls_s, cls_e, ps_s, ps_e;
++ unsigned int spl_s, spl_e, rev_s, rev_e;
++ total = jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw;
++ spl_s = 1;
++ spl_e = spl_s + 1;
++ cls_s = 0;
++ cls_e = total - 60; /* > 4us (pclk = 80ns) */
++ ps_s = cls_s;
++ ps_e = cls_e;
++ rev_s = total - 40; /* > 3us (pclk = 80ns) */
++ rev_e = rev_s + total;
++ jzfb.cfg |= STFT_PSHI;
++ REG_LCD_SPL = (spl_s << 16) | spl_e;
++ REG_LCD_CLS = (cls_s << 16) | cls_e;
++ REG_LCD_PS = (ps_s << 16) | ps_e;
++ REG_LCD_REV = (rev_s << 16) | rev_e;
++ break;
++ }
++ case MODE_TFT_CASIO:
++ break;
++ }
++
++ /* Configure the LCD panel */
++ REG_LCD_CFG = jzfb.cfg;
++
++ /* Timing setting */
++ __cpm_stop_lcd();
++
++ val = jzfb.fclk; /* frame clk */
++ if ( (jzfb.cfg & MODE_MASK) != MODE_8BIT_SERIAL_TFT) {
++ pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *
++ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
++ } else {
++ /* serial mode: Hsync period = 3*Width_Pixel */
++ pclk = val * (jzfb.w*3 + jzfb.hsw + jzfb.elw + jzfb.blw) *
++ (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */
++ }
++
++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
++ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
++ pclk = (pclk * 3);
++
++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
++ ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||
++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
++ pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4);
++
++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
++ pclk >>= 1;
++
++ pll_div = (REG_CPM_CPCCR & CPM_CPCCR_PCS); /* clock source,0:pllout/2 1: pllout */
++ pll_div = pll_div ? 1 : 2;
++ val = (__cpm_get_pllout() / pll_div) / pclk;
++ val--;
++ if (val > 0x1ff) {
++ printf("CPM_LPCDR too large, set it to 0x1ff\n");
++ val = 0x1ff;
++ }
++ __cpm_set_pixdiv(val);
++
++ val = pclk * 3 ; /* LCDClock > 2.5*Pixclock */
++ if (val > 150000000) {
++ printf("Warning: LCDClock=%d\n, LCDClock must less or equal to 150MHz.\n", val);
++ printf("Change LCDClock to 150MHz\n");
++ val = 150000000;
++ }
++ val = (__cpm_get_pllout() / pll_div) / val;
++ val--;
++ if (val > 0x1f) {
++ printf("CPM_CPCCR.LDIV too large, set it to 0x1f\n");
++ val = 0x1f;
++ }
++ __cpm_set_ldiv( val );
++ REG_CPM_CPCCR |= CPM_CPCCR_CE ; /* update divide */
++
++ __cpm_start_lcd();
++ udelay(1000);
++
++ REG_LCD_DA0 = fbi->fdadr0; /* frame descripter*/
++
++ if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
++ ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
++ REG_LCD_DA1 = fbi->fdadr1; /* frame descripter*/
++
++ return 0;
++}
++
++void lcd_ctrl_init (void *lcdbase)
++{
++ __lcd_display_pin_init();
++ __lcd_display_on() ;
++
++ jz_lcd_init_mem(lcdbase, &panel_info);
++ jz_lcd_desc_init(&panel_info);
++ jz_lcd_hw_init(&panel_info);
++
++}
++
++/*
++ * Before enabled lcd controller, lcd registers should be configured correctly.
++ */
++void lcd_enable (void)
++{
++ REG_LCD_CTRL &= ~(1<<4); /* LCDCTRL.DIS */
++ REG_LCD_CTRL |= 1<<3; /* LCDCTRL.ENA*/
++}
++
++void lcd_disable (void)
++{
++ REG_LCD_CTRL |= (1<<4);
++}
++
++void lcd_setcolreg (ushort regno, ushort red, ushort green, ushort blue)
++{
++}
++
++void lcd_initcolregs (void)
++{
++}
+diff --git a/drivers/video/nanonote_gpm940b0.h b/drivers/video/nanonote_gpm940b0.h
+new file mode 100644
+index 0000000..efe491e
+--- /dev/null
++++ b/drivers/video/nanonote_gpm940b0.h
+@@ -0,0 +1,135 @@
++/*
++ * JzRISC lcd controller
++ *
++ * Xiangfu Liu <xiangfu@sharism.cc>
++ *
++ * 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
++ */
++
++#ifndef __QI_LB60_GPM940B0_H__
++#define __QI_LB60_GPM940B0_H__
++
++struct lcd_desc{
++ unsigned int next_desc; /* LCDDAx */
++ unsigned int databuf; /* LCDSAx */
++ unsigned int frame_id; /* LCDFIDx */
++ unsigned int cmd; /* LCDCMDx */
++};
++
++#define MODE_MASK 0x0f
++#define MODE_TFT_GEN 0x00
++#define MODE_TFT_SHARP 0x01
++#define MODE_TFT_CASIO 0x02
++#define MODE_TFT_SAMSUNG 0x03
++#define MODE_CCIR656_NONINT 0x04
++#define MODE_CCIR656_INT 0x05
++#define MODE_STN_COLOR_SINGLE 0x08
++#define MODE_STN_MONO_SINGLE 0x09
++#define MODE_STN_COLOR_DUAL 0x0a
++#define MODE_STN_MONO_DUAL 0x0b
++#define MODE_8BIT_SERIAL_TFT 0x0c
++
++#define MODE_TFT_18BIT (1<<7)
++
++#define STN_DAT_PIN1 (0x00 << 4)
++#define STN_DAT_PIN2 (0x01 << 4)
++#define STN_DAT_PIN4 (0x02 << 4)
++#define STN_DAT_PIN8 (0x03 << 4)
++#define STN_DAT_PINMASK STN_DAT_PIN8
++
++#define STFT_PSHI (1 << 15)
++#define STFT_CLSHI (1 << 14)
++#define STFT_SPLHI (1 << 13)
++#define STFT_REVHI (1 << 12)
++
++#define SYNC_MASTER (0 << 16)
++#define SYNC_SLAVE (1 << 16)
++
++#define DE_P (0 << 9)
++#define DE_N (1 << 9)
++
++#define PCLK_P (0 << 10)
++#define PCLK_N (1 << 10)
++
++#define HSYNC_P (0 << 11)
++#define HSYNC_N (1 << 11)
++
++#define VSYNC_P (0 << 8)
++#define VSYNC_N (1 << 8)
++
++#define DATA_NORMAL (0 << 17)
++#define DATA_INVERSE (1 << 17)
++
++
++/* Jz LCDFB supported I/O controls. */
++#define FBIOSETBACKLIGHT 0x4688
++#define FBIODISPON 0x4689
++#define FBIODISPOFF 0x468a
++#define FBIORESET 0x468b
++#define FBIOPRINT_REG 0x468c
++
++/*
++ * LCD panel specific definition
++ */
++#define MODE (0xc9) /* 8bit serial RGB */
++
++#define __spi_write_reg1(reg, val) \
++do { \
++ unsigned char no; \
++ unsigned short value; \
++ unsigned char a=reg; \
++ unsigned char b=val; \
++ __gpio_set_pin(SPEN); \
++ __gpio_set_pin(SPCK); \
++ __gpio_clear_pin(SPDA); \
++ __gpio_clear_pin(SPEN); \
++ value=((a<<8)|(b&0xFF)); \
++ for(no=0;no<16;no++) \
++ { \
++ __gpio_clear_pin(SPCK); \
++ if((value&0x8000)==0x8000) \
++ __gpio_set_pin(SPDA); \
++ else \
++ __gpio_clear_pin(SPDA); \
++ __gpio_set_pin(SPCK); \
++ value=(value<<1); \
++ } \
++ __gpio_set_pin(SPEN); \
++} while (0)
++
++#define __lcd_display_pin_init() \
++do { \
++ __cpm_start_tcu(); \
++ __gpio_as_output(SPEN); /* use SPDA */ \
++ __gpio_as_output(SPCK); /* use SPCK */ \
++ __gpio_as_output(SPDA); /* use SPDA */ \
++} while (0)
++
++#define __lcd_display_on() \
++do { \
++ __spi_write_reg1(0x05, 0x1e); \
++ __spi_write_reg1(0x05, 0x5e); \
++ __spi_write_reg1(0x07, 0x8d); \
++ __spi_write_reg1(0x13, 0x01); \
++ __spi_write_reg1(0x05, 0x5f); \
++} while (0)
++
++#define __lcd_display_off() \
++do { \
++ __spi_write_reg1(0x05, 0x5e); \
++} while (0)
++
++#endif /* __QI_LB60_GPM940B0_H__ */
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index 52b370c..d3e78ad 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -32,6 +32,13 @@
+ * Miscellaneous configurable options
+ */
+ #define CONFIG_NANONOTE
++
++#define CONFIG_LCD
++#define CONFIG_SYS_WHITE_ON_BLACK
++#define LCD_BPP LCD_COLOR32
++#define CONFIG_VIDEO_GPM940B0
++
++
+ #define CONFIG_JZ4740_MMC
+ #define CONFIG_MMC 1
+ #define CONFIG_FAT 1
+diff --git a/include/lcd.h b/include/lcd.h
+index 42070d7..6de5482 100644
+--- a/include/lcd.h
++++ b/include/lcd.h
+@@ -263,8 +263,44 @@ typedef struct vidinfo {
+
+ void init_panel_info(vidinfo_t *vid);
+
+-#else
++#elif defined(CONFIG_JZSOC)
++/*
++ * LCD controller stucture for JZSOC: JZ4740
++ */
++struct jz_fb_dma_descriptor {
++ u_long fdadr; /* Frame descriptor address register */
++ u_long fsadr; /* Frame source address register */
++ u_long fidr; /* Frame ID register */
++ u_long ldcmd; /* Command register */
++};
++
++/*
++ * Jz LCD info
++ */
++struct jz_fb_info {
++
++ u_long fdadr0; /* physical address of frame/palette descriptor */
++ u_long fdadr1; /* physical address of frame descriptor */
++
++ /* DMA descriptors */
++ struct jz_fb_dma_descriptor * dmadesc_fblow;
++ struct jz_fb_dma_descriptor * dmadesc_fbhigh;
++ struct jz_fb_dma_descriptor * dmadesc_palette;
++ u_long screen; /* address of frame buffer */
++ u_long palette; /* address of palette memory */
++ u_int palette_size;
++};
++typedef struct vidinfo {
++ ushort vl_col; /* Number of columns (i.e. 640) */
++ ushort vl_row; /* Number of rows (i.e. 480) */
++ u_char vl_bpix; /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8 */
++
++ struct jz_fb_info jz_fb;
++} vidinfo_t;
++
++extern vidinfo_t panel_info;
+
++#else
+ typedef struct vidinfo {
+ ushort vl_col; /* Number of columns (i.e. 160) */
+ ushort vl_row; /* Number of rows (i.e. 100) */
+@@ -318,6 +354,7 @@ void lcd_show_board_info(void);
+ #define LCD_COLOR4 2
+ #define LCD_COLOR8 3
+ #define LCD_COLOR16 4
++#define LCD_COLOR32 5
+
+ /*----------------------------------------------------------------------*/
+ #if defined(CONFIG_LCD_INFO_BELOW_LOGO)
+@@ -369,7 +406,7 @@ void lcd_show_board_info(void);
+ # define CONSOLE_COLOR_GREY 14
+ # define CONSOLE_COLOR_WHITE 15 /* Must remain last / highest */
+
+-#else
++#elif LCD_BPP == LCD_COLOR16
+
+ /*
+ * 16bpp color definitions
+@@ -377,6 +414,15 @@ void lcd_show_board_info(void);
+ # define CONSOLE_COLOR_BLACK 0x0000
+ # define CONSOLE_COLOR_WHITE 0xffff /* Must remain last / highest */
+
++#elif LCD_BPP == LCD_COLOR32
++/*
++ * 18,24,32 bpp color definitions
++ */
++# define CONSOLE_COLOR_BLACK 0x00000000
++# define CONSOLE_COLOR_WHITE 0xffffffff /* Must remain last / highest */
++
++#else
++
+ #endif /* color definitions */
+
+ /************************************************************************/
+@@ -406,7 +452,7 @@ void lcd_show_board_info(void);
+ #if LCD_BPP == LCD_MONOCHROME
+ # define COLOR_MASK(c) ((c) | (c) << 1 | (c) << 2 | (c) << 3 | \
+ (c) << 4 | (c) << 5 | (c) << 6 | (c) << 7)
+-#elif (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16)
++#elif (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16) || (LCD_BPP == LCD_COLOR32)
+ # define COLOR_MASK(c) (c)
+ #else
+ # error Unsupported LCD BPP.
+--
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/0006-enable-silent-console.patch b/package/boot/uboot-xburst/patches/0006-enable-silent-console.patch
new file mode 100644
index 0000000000..ebd6a6a7bf
--- /dev/null
+++ b/package/boot/uboot-xburst/patches/0006-enable-silent-console.patch
@@ -0,0 +1,60 @@
+From 5eb4d4c598f2806bd1b3d1140e917bfead7851ad Mon Sep 17 00:00:00 2001
+From: Xiangfu <xiangfu@openmobilefree.net>
+Date: Wed, 10 Oct 2012 23:51:26 +0800
+Subject: [PATCH 6/6] enable silent console
+
+---
+ common/console.c | 16 ++++++++++++++++
+ include/configs/qi_lb60.h | 2 ++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/common/console.c b/common/console.c
+index 1177f7d..e8a2078 100644
+--- a/common/console.c
++++ b/common/console.c
+@@ -685,6 +685,14 @@ done:
+
+ gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
+
++#ifdef CONFIG_SILENT_CONSOLE
++ /* Check one more time the contents of the silent environment
++ * variable, because if the environment is loaded from NAND it was
++ * not available when console_init_f() was called */
++ if (getenv("silent") != NULL)
++ gd->flags |= GD_FLG_SILENT;
++#endif
++
+ stdio_print_current_devices();
+
+ #ifdef CONFIG_SYS_CONSOLE_ENV_OVERWRITE
+@@ -760,6 +768,14 @@ int console_init_r(void)
+
+ gd->flags |= GD_FLG_DEVINIT; /* device initialization completed */
+
++#ifdef CONFIG_SILENT_CONSOLE
++ /* Check one more time the contents of the silent environment
++ * variable, because if the environment is loaded from NAND it was
++ * not available when console_init_f() was called */
++ if (getenv("silent") != NULL)
++ gd->flags |= GD_FLG_SILENT;
++#endif
++
+ stdio_print_current_devices();
+
+ /* Setting environment variables */
+diff --git a/include/configs/qi_lb60.h b/include/configs/qi_lb60.h
+index d3e78ad..a3534ff 100644
+--- a/include/configs/qi_lb60.h
++++ b/include/configs/qi_lb60.h
+@@ -102,6 +102,8 @@
+ #define CONFIG_SYS_NO_FLASH
+ #define CONFIG_SYS_FLASH_BASE 0 /* init flash_base as 0 */
+
++#define CONFIG_SILENT_CONSOLE 1 /* Enable silent console */
++
+ /*
+ * Command line configuration
+ */
+--
+1.7.9.5
+
diff --git a/package/boot/uboot-xburst/patches/001-xburst.patch b/package/boot/uboot-xburst/patches/001-xburst.patch
deleted file mode 100644
index be833305e8..0000000000
--- a/package/boot/uboot-xburst/patches/001-xburst.patch
+++ /dev/null
@@ -1,1669 +0,0 @@
-this patch include the u-boot2009.11 change files
-
-From: Xiangfu Liu <xiangfu@sharism.cc>
-
-
----
-
- Makefile | 10 +
- common/env_common.c | 2
- common/lcd.c | 45 ++++
- common/main.c | 4
- cpu/mips/Makefile | 4
- cpu/mips/cache.S | 280 ++++++++++----------------
- cpu/mips/config.mk | 6 -
- cpu/mips/cpu.c | 75 +++++++
- cpu/mips/start.S | 432 ++++++++++++++++++++++++++++++++--------
- drivers/mtd/nand/nand_base.c | 88 ++++++++
- examples/standalone/mips.lds | 2
- include/asm-mips/addrspace.h | 2
- include/asm-mips/global_data.h | 11 +
- include/lcd.h | 56 +++++
- lib_mips/board.c | 18 +-
- lib_mips/bootm.c | 7 +
- lib_mips/time.c | 4
- 20 files changed, 800 insertions(+), 333 deletions(-)
-
-
-diff --git a/Makefile b/Makefile
-index f06a97c..a318eb4 100644
---- a/Makefile
-+++ b/Makefile
-@@ -3439,6 +3439,22 @@ qemu_mips_config : unconfig
- @$(MKCONFIG) -a qemu-mips mips mips qemu-mips
-
- #########################################################################
-+## MIPS32 Jz47XX
-+#########################################################################
-+qi_lb60_config : unconfig
-+ @echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
-+ @echo "Compile NAND boot image for QI LB60"
-+ @$(MKCONFIG) -a qi_lb60 mips mips nanonote
-+ @echo "TEXT_BASE = 0x80100000" > $(obj)board/nanonote/config.tmp
-+ @echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
-+
-+avt2_config : unconfig
-+ @echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
-+ @echo "Compile NAND boot image for AVT2"
-+ @$(MKCONFIG) -a avt2 mips mips nanonote
-+ @echo "TEXT_BASE = 0x80100000" > $(obj)board/nanonote/config.tmp
-+ @echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
-+#########################################################################
- ## MIPS64 5Kc
- #########################################################################
-
-diff --git a/common/env_common.c b/common/env_common.c
-index 439a4a9..6cfe30b 100644
---- a/common/env_common.c
-+++ b/common/env_common.c
-@@ -134,7 +134,10 @@ uchar default_environment[] = {
- "pcidelay=" MK_STR(CONFIG_PCI_BOOTDELAY) "\0"
- #endif
--#ifdef CONFIG_EXTRA_ENV_SETTINGS
-- CONFIG_EXTRA_ENV_SETTINGS
-+#ifdef CONFIG_BOOTARGSFROMSD
-+ "bootargsfromsd=" CONFIG_BOOTARGSFROMSD "\0"
-+#endif
-+#ifdef CONFIG_BOOTCOMMANDFROMSD
-+ "bootcmdfromsd=" CONFIG_BOOTCOMMANDFROMSD "\0"
- #endif
- "\0"
- };
-diff --git a/common/lcd.c b/common/lcd.c
-index 4e31618..ddd5aa8 100644
---- a/common/lcd.c
-+++ b/common/lcd.c
-@@ -64,7 +64,9 @@
- #ifdef CONFIG_LCD_LOGO
- # include <bmp_logo.h> /* Get logo data, width and height */
- # if (CONSOLE_COLOR_WHITE >= BMP_LOGO_OFFSET)
--# error Default Color Map overlaps with Logo Color Map
-+# ifndef CONFIG_JzRISC /* JzRISC core */
-+# error Default Color Map overlaps with Logo Color Map
-+# endif
- # endif
- #endif
-
-@@ -249,6 +251,14 @@ static void lcd_drawchars (ushort x, ushort y, uchar *str, int count)
- lcd_color_fg : lcd_color_bg;
- bits <<= 1;
- }
-+#elif LCD_BPP == LCD_COLOR32
-+ uint *m = (uint *)d;
-+ for (c=0; c<32; ++c) {
-+ *m++ = (bits & 0x80) ?
-+ lcd_color_fg : lcd_color_bg;
-+ //d+=4;
-+ bits <<= 1;
-+ }
- #endif
- }
- #if LCD_BPP == LCD_MONOCHROME
-@@ -315,6 +325,9 @@ static void test_pattern (void)
- }
- #endif /* LCD_TEST_PATTERN */
-
-+#ifdef CONFIG_JzRISC /* JzRISC core */
-+extern int flush_cache_all(void);
-+#endif
-
- /************************************************************************/
- /* ** GENERIC Initialization Routines */
-@@ -381,6 +394,7 @@ static int lcd_clear (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
- COLOR_MASK(lcd_getbgcolor()),
- lcd_line_length*panel_info.vl_row);
- #endif
-+
- /* Paint the logo and retrieve LCD base address */
- debug ("[LCD] Drawing the logo...\n");
- lcd_console_address = lcd_logo ();
-@@ -458,6 +472,8 @@ static void lcd_setfgcolor (int color)
- {
- #ifdef CONFIG_ATMEL_LCD
- lcd_color_fg = color;
-+#elif LCD_BPP == LCD_COLOR32
-+ lcd_color_fg = color & 0xFFFFFFFF;
- #else
- lcd_color_fg = color & 0x0F;
- #endif
-@@ -469,6 +485,8 @@ static void lcd_setbgcolor (int color)
- {
- #ifdef CONFIG_ATMEL_LCD
- lcd_color_bg = color;
-+#elif LCD_BPP == LCD_COLOR32
-+ lcd_color_bg = color & 0xFFFFFFFF;
- #else
- lcd_color_bg = color & 0x0F;
- #endif
-@@ -507,6 +525,7 @@ void bitmap_plot (int x, int y)
- uchar *bmap;
- uchar *fb;
- ushort *fb16;
-+ uint *fb32;
- #if defined(CONFIG_PXA250)
- struct pxafb_info *fbi = &panel_info.pxa;
- #elif defined(CONFIG_MPC823)
-@@ -567,13 +586,25 @@ void bitmap_plot (int x, int y)
- }
- }
- else { /* true color mode */
-- fb16 = (ushort *)(lcd_base + y * lcd_line_length + x);
-- for (i=0; i<BMP_LOGO_HEIGHT; ++i) {
-- for (j=0; j<BMP_LOGO_WIDTH; j++) {
-- fb16[j] = bmp_logo_palette[(bmap[j])];
-+ if(NBITS(panel_info.vl_bpix) == 16){
-+ fb16 = (ushort *)(lcd_base + y * lcd_line_length + x);
-+ for (i=0; i<BMP_LOGO_HEIGHT; ++i) {
-+ for (j=0; j<BMP_LOGO_WIDTH; j++) {
-+ fb16[j] = bmp_logo_palette[(bmap[j])];
- }
-- bmap += BMP_LOGO_WIDTH;
-- fb16 += panel_info.vl_col;
-+ bmap += BMP_LOGO_WIDTH;
-+ fb16 += panel_info.vl_col;
-+ }
-+ }
-+ else{
-+ fb32 = (uint *)(lcd_base + y * lcd_line_length + x);
-+ for (i=0; i<BMP_LOGO_HEIGHT; ++i) {
-+ for (j=0; j<BMP_LOGO_WIDTH; j++) {
-+ fb32[j] = bmp_logo_palette[(bmap[j])];
-+ }
-+ bmap += BMP_LOGO_WIDTH;
-+ fb32 += panel_info.vl_col;
-+ }
- }
- }
-
-diff --git a/common/main.c b/common/main.c
-index 10d8904..ff11ad7 100644
---- a/common/main.c
-+++ b/common/main.c
-@@ -372,7 +372,9 @@ void main_loop (void)
- #if defined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
- s = getenv ("bootdelay");
- bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
--
-+ DECLARE_GLOBAL_DATA_PTR;
-+ if (gd->boot_option == 5)
-+ bootdelay = gd->boot_option;
- debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
-
- # ifdef CONFIG_BOOT_RETRY_TIME
-@@ -393,7 +395,9 @@ void main_loop (void)
- }
- else
- #endif /* CONFIG_BOOTCOUNT_LIMIT */
-- s = getenv ("bootcmd");
-+ s = gd->boot_option == 1 ?
-+ getenv ("bootcmdfromsd"):
-+ getenv ("bootcmd") ;
-
- debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>");
-
-diff --git a/cpu/mips/Makefile b/cpu/mips/Makefile
-index 28a1cbb..5207bc5 100644
---- a/cpu/mips/Makefile
-+++ b/cpu/mips/Makefile
-@@ -33,6 +33,9 @@ SOBJS-$(CONFIG_INCA_IP) += incaip_wdt.o
- COBJS-$(CONFIG_INCA_IP) += asc_serial.o incaip_clock.o
- COBJS-$(CONFIG_PURPLE) += asc_serial.o
- COBJS-$(CONFIG_SOC_AU1X00) += au1x00_eth.o au1x00_serial.o au1x00_usb_ohci.o
-+COBJS-$(CONFIG_JZSOC) += jz4740.o jz_serial.o jz_mmc.o jz4740_nand.o
-+COBJS-$(CONFIG_NANONOTE) += nanonote_gpm940b0.o
-+
-
- SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
- OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
-diff --git a/cpu/mips/cache.S b/cpu/mips/cache.S
-index ff4f11c..cb3baff 100644
---- a/cpu/mips/cache.S
-+++ b/cpu/mips/cache.S
-@@ -23,32 +23,19 @@
- */
-
- #include <config.h>
--#include <asm/asm.h>
-+#include <version.h>
- #include <asm/regdef.h>
- #include <asm/mipsregs.h>
- #include <asm/addrspace.h>
- #include <asm/cacheops.h>
-
--#define RA t8
-+#ifndef CONFIG_JzRISC
-
--/*
-- * 16kB is the maximum size of instruction and data caches on MIPS 4K,
-- * 64kB is on 4KE, 24K, 5K, etc. Set bigger size for convenience.
-- *
-- * Note that the above size is the maximum size of primary cache. U-Boot
-- * doesn't have L2 cache support for now.
-- */
--#define MIPS_MAX_CACHE_SIZE 0x10000
--
--#define INDEX_BASE CKSEG0
-+ /* 16KB is the maximum size of instruction and data caches on
-+ * MIPS 4K.
-+ */
-+#define MIPS_MAX_CACHE_SIZE 0x4000
-
-- .macro cache_op op addr
-- .set push
-- .set noreorder
-- .set mips3
-- cache \op, 0(\addr)
-- .set pop
-- .endm
-
- /*
- * cacheop macro to automate cache operations
-@@ -119,79 +106,7 @@
- #define icacheop(kva, n, cacheSize, cacheLineSize, op) \
- icacheopn(kva, n, cacheSize, cacheLineSize, 1, (op))
-
-- .macro f_fill64 dst, offset, val
-- LONG_S \val, (\offset + 0 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 1 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 2 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 3 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 4 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 5 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 6 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 7 * LONGSIZE)(\dst)
--#if LONGSIZE == 4
-- LONG_S \val, (\offset + 8 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 9 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 10 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 11 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 12 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 13 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 14 * LONGSIZE)(\dst)
-- LONG_S \val, (\offset + 15 * LONGSIZE)(\dst)
--#endif
-- .endm
--
--/*
-- * mips_init_icache(uint PRId, ulong icache_size, unchar icache_linesz)
-- */
--LEAF(mips_init_icache)
-- blez a1, 9f
-- mtc0 zero, CP0_TAGLO
-- /* clear tag to invalidate */
-- PTR_LI t0, INDEX_BASE
-- PTR_ADDU t1, t0, a1
--1: cache_op Index_Store_Tag_I t0
-- PTR_ADDU t0, a2
-- bne t0, t1, 1b
-- /* fill once, so data field parity is correct */
-- PTR_LI t0, INDEX_BASE
--2: cache_op Fill t0
-- PTR_ADDU t0, a2
-- bne t0, t1, 2b
-- /* invalidate again - prudent but not strictly neccessary */
-- PTR_LI t0, INDEX_BASE
--1: cache_op Index_Store_Tag_I t0
-- PTR_ADDU t0, a2
-- bne t0, t1, 1b
--9: jr ra
-- END(mips_init_icache)
--
- /*
-- * mips_init_dcache(uint PRId, ulong dcache_size, unchar dcache_linesz)
-- */
--LEAF(mips_init_dcache)
-- blez a1, 9f
-- mtc0 zero, CP0_TAGLO
-- /* clear all tags */
-- PTR_LI t0, INDEX_BASE
-- PTR_ADDU t1, t0, a1
--1: cache_op Index_Store_Tag_D t0
-- PTR_ADDU t0, a2
-- bne t0, t1, 1b
-- /* load from each line (in cached space) */
-- PTR_LI t0, INDEX_BASE
--2: LONG_L zero, 0(t0)
-- PTR_ADDU t0, a2
-- bne t0, t1, 2b
-- /* clear all tags */
-- PTR_LI t0, INDEX_BASE
--1: cache_op Index_Store_Tag_D t0
-- PTR_ADDU t0, a2
-- bne t0, t1, 1b
--9: jr ra
-- END(mips_init_dcache)
--
--/*******************************************************************************
--*
- * mips_cache_reset - low level initialisation of the primary caches
- *
- * This routine initialises the primary caches to ensure that they
-@@ -204,112 +119,129 @@ LEAF(mips_init_dcache)
- * a source of parity.
- *
- * RETURNS: N/A
--*
- */
--NESTED(mips_cache_reset, 0, ra)
-- move RA, ra
-+ .globl mips_cache_reset
-+ .ent mips_cache_reset
-+mips_cache_reset:
-+
- li t2, CONFIG_SYS_ICACHE_SIZE
- li t3, CONFIG_SYS_DCACHE_SIZE
- li t4, CONFIG_SYS_CACHELINE_SIZE
- move t5, t4
-
-+
- li v0, MIPS_MAX_CACHE_SIZE
-
-- /*
-- * Now clear that much memory starting from zero.
-+ /* Now clear that much memory starting from zero.
- */
-- PTR_LI a0, CKSEG1
-- PTR_ADDU a1, a0, v0
--2: PTR_ADDIU a0, 64
-- f_fill64 a0, -64, zero
-- bne a0, a1, 2b
--
-- /*
-- * The caches are probably in an indeterminate state,
-- * so we force good parity into them by doing an
-- * invalidate, load/fill, invalidate for each line.
-+
-+ li a0, KSEG1
-+ addu a1, a0, v0
-+
-+2: sw zero, 0(a0)
-+ sw zero, 4(a0)
-+ sw zero, 8(a0)
-+ sw zero, 12(a0)
-+ sw zero, 16(a0)
-+ sw zero, 20(a0)
-+ sw zero, 24(a0)
-+ sw zero, 28(a0)
-+ addu a0, 32
-+ bltu a0, a1, 2b
-+
-+ /* Set invalid tag.
- */
-
-- /*
-- * Assume bottom of RAM will generate good parity for the cache.
-+ mtc0 zero, CP0_TAGLO
-+
-+ /*
-+ * The caches are probably in an indeterminate state,
-+ * so we force good parity into them by doing an
-+ * invalidate, load/fill, invalidate for each line.
-+ */
-+
-+ /* Assume bottom of RAM will generate good parity for the cache.
- */
-
-- /*
-- * Initialize the I-cache first,
-+ li a0, K0BASE
-+ move a2, t2 # icacheSize
-+ move a3, t4 # icacheLineSize
-+ move a1, a2
-+ icacheopn(a0,a1,a2,a3,121,(Index_Store_Tag_I,Fill))
-+
-+ /* To support Orion/R4600, we initialise the data cache in 3 passes.
- */
-- move a1, t2
-- move a2, t4
-- PTR_LA t7, mips_init_icache
-- jalr t7
-
-- /*
-- * then initialize D-cache.
-+ /* 1: initialise dcache tags.
- */
-- move a1, t3
-- move a2, t5
-- PTR_LA t7, mips_init_dcache
-- jalr t7
-
-- jr RA
-- END(mips_cache_reset)
-+ li a0, K0BASE
-+ move a2, t3 # dcacheSize
-+ move a3, t5 # dcacheLineSize
-+ move a1, a2
-+ icacheop(a0,a1,a2,a3,Index_Store_Tag_D)
-
--/*******************************************************************************
--*
--* dcache_status - get cache status
--*
--* RETURNS: 0 - cache disabled; 1 - cache enabled
--*
--*/
--LEAF(dcache_status)
-- mfc0 t0, CP0_CONFIG
-- li t1, CONF_CM_UNCACHED
-- andi t0, t0, CONF_CM_CMASK
-- move v0, zero
-- beq t0, t1, 2f
-- li v0, 1
--2: jr ra
-- END(dcache_status)
--
--/*******************************************************************************
--*
-+ /* 2: fill dcache.
-+ */
-+
-+ li a0, K0BASE
-+ move a2, t3 # dcacheSize
-+ move a3, t5 # dcacheLineSize
-+ move a1, a2
-+ icacheopn(a0,a1,a2,a3,1lw,(dummy))
-+
-+ /* 3: clear dcache tags.
-+ */
-+
-+ li a0, K0BASE
-+ move a2, t3 # dcacheSize
-+ move a3, t5 # dcacheLineSize
-+ move a1, a2
-+ icacheop(a0,a1,a2,a3,Index_Store_Tag_D)
-+
-+ j ra
-+ .end mips_cache_reset
-+
-+
-+/*
-+ * dcache_status - get cache status
-+ *
-+ * RETURNS: 0 - cache disabled; 1 - cache enabled
-+ */
-+ .globl dcache_status
-+ .ent dcache_status
-+dcache_status:
-+
-+ mfc0 v0, CP0_CONFIG
-+ andi v0, v0, 1
-+ j ra
-+
-+ .end dcache_status
-+
-+/*
- * dcache_disable - disable cache
- *
- * RETURNS: N/A
--*
- */
--LEAF(dcache_disable)
-+ .globl dcache_disable
-+ .ent dcache_disable
-+dcache_disable:
-+
- mfc0 t0, CP0_CONFIG
- li t1, -8
- and t0, t0, t1
- ori t0, t0, CONF_CM_UNCACHED
-- mtc0 t0, CP0_CONFIG
-- jr ra
-- END(dcache_disable)
-+ mtc0 t0, CP0_CONFIG
-+ j ra
-
--/*******************************************************************************
--*
--* dcache_enable - enable cache
--*
--* RETURNS: N/A
--*
--*/
--LEAF(dcache_enable)
-- mfc0 t0, CP0_CONFIG
-- ori t0, CONF_CM_CMASK
-- xori t0, CONF_CM_CMASK
-- ori t0, CONF_CM_CACHABLE_NONCOHERENT
-- mtc0 t0, CP0_CONFIG
-- jr ra
-- END(dcache_enable)
--
--#ifdef CONFIG_SYS_INIT_RAM_LOCK_MIPS
--/*******************************************************************************
--*
--* mips_cache_lock - lock RAM area pointed to by a0 in cache.
--*
--* RETURNS: N/A
--*
--*/
-+ .end dcache_disable
-+
-+
-+/*
-+ * mips_cache_lock - lock RAM area pointed to by a0 in cache.
-+ *
-+ * RETURNS: N/A
-+ */
- #if defined(CONFIG_PURPLE)
- # define CACHE_LOCK_SIZE (CONFIG_SYS_DCACHE_SIZE/2)
- #else
-@@ -318,14 +250,14 @@ LEAF(dcache_enable)
- .globl mips_cache_lock
- .ent mips_cache_lock
- mips_cache_lock:
-- li a1, CKSEG0 - CACHE_LOCK_SIZE
-+ li a1, K0BASE - CACHE_LOCK_SIZE
- addu a0, a1
- li a2, CACHE_LOCK_SIZE
- li a3, CONFIG_SYS_CACHELINE_SIZE
- move a1, a2
- icacheop(a0,a1,a2,a3,0x1d)
-
-- jr ra
--
-+ j ra
- .end mips_cache_lock
--#endif /* CONFIG_SYS_INIT_RAM_LOCK_MIPS */
-+
-+#endif /* CONFIG_JzRISC */
-diff --git a/cpu/mips/config.mk b/cpu/mips/config.mk
-index a173c54..8d27e52 100644
---- a/cpu/mips/config.mk
-+++ b/cpu/mips/config.mk
-@@ -25,15 +25,15 @@ MIPSFLAGS:=$(shell \
- if [ "$v" -lt "14" ]; then \
- echo "-mcpu=4kc"; \
- else \
-- echo "-march=4kc -mtune=4kc"; \
-+ echo "-march=4kc -mtune=r4600"; \
- fi)
-
- ifneq (,$(findstring 4KCle,$(CROSS_COMPILE)))
- ENDIANNESS = -EL
- else
--ENDIANNESS = -EB
-+#ENDIANNESS = -EB
- endif
-
--MIPSFLAGS += $(ENDIANNESS)
-+MIPSFLAGS += $(ENDIANNESS) -mabicalls -mips32 -O2
-
- PLATFORM_CPPFLAGS += $(MIPSFLAGS)
-diff --git a/cpu/mips/cpu.c b/cpu/mips/cpu.c
-index d5a1604..48e1cea 100644
---- a/cpu/mips/cpu.c
-+++ b/cpu/mips/cpu.c
-@@ -28,6 +28,12 @@
- #include <asm/cacheops.h>
- #include <asm/reboot.h>
-
-+#ifdef CONFIG_JZ4740
-+#include <asm/jz4740.h>
-+#endif
-+
-+#if !defined (CONFIG_NAND_SPL) && !defined (CONFIG_MSC_SPL)
-+
- #define cache_op(op,addr) \
- __asm__ __volatile__( \
- " .set push \n" \
-@@ -40,6 +46,19 @@
-
- void __attribute__((weak)) _machine_restart(void)
- {
-+#ifdef CONFIG_JZ4740
-+ __wdt_select_extalclk();
-+ __wdt_select_clk_div64();
-+ __wdt_set_data(100);
-+ __wdt_set_count(0);
-+ __tcu_start_wdt_clock();
-+ __wdt_start();
-+ while(1);
-+#endif
-+#if defined(CONFIG_JzRISC)
-+ void (*f)(void) = (void *) 0xbfc00000;
-+ f();
-+#endif
- }
-
- int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
-@@ -110,3 +129,59 @@ int cpu_eth_init(bd_t *bis)
- #endif
- return 0;
- }
-+
-+#endif /* !CONFIG_NAND_SPL !CONFIG_MSC_SPL */
-+
-+#ifdef CONFIG_JzRISC
-+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) {
-+ asm volatile (
-+ ".set mips3\n\t"
-+ " cache %0, 0(%1)\n\t"
-+ ".set mips2\n\t"
-+ :
-+ : "I" (Index_Store_Tag_I), "r"(addr));
-+ }
-+
-+ /* invalicate 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) {
-+ asm volatile (
-+ ".set mips3\n\t"
-+ " cache %0, 0(%1)\n\t"
-+ ".set mips2\n\t"
-+ :
-+ : "I" (Index_Writeback_Inv_D), "r"(addr));
-+ }
-+
-+ asm volatile ("sync");
-+}
-+
-+void flush_cache_all(void)
-+{
-+ flush_dcache_all();
-+ flush_icache_all();
-+}
-+#endif /* CONFIG_JzRISC */
-diff --git a/cpu/mips/start.S b/cpu/mips/start.S
-index 57db589..fa6e352 100644
---- a/cpu/mips/start.S
-+++ b/cpu/mips/start.S
-@@ -23,32 +23,33 @@
- */
-
- #include <config.h>
-+#include <version.h>
- #include <asm/regdef.h>
- #include <asm/mipsregs.h>
-+#include <asm/addrspace.h>
-+#include <asm/cacheops.h>
-
-- /*
-- * For the moment disable interrupts, mark the kernel mode and
-- * set ST0_KX so that the CPU does not spit fire when using
-- * 64-bit addresses.
-- */
-- .macro setup_c0_status set clr
-- .set push
-- mfc0 t0, CP0_STATUS
-- or t0, ST0_CU0 | \set | 0x1f | \clr
-- xor t0, 0x1f | \clr
-- mtc0 t0, CP0_STATUS
-- .set noreorder
-- sll zero, 3 # ehb
-- .set pop
-- .endm
--
-- .macro setup_c0_status_reset
--#ifdef CONFIG_64BIT
-- setup_c0_status ST0_KX 0
--#else
-- setup_c0_status 0 0
-+#ifdef CONFIG_JZ4730
-+#include <asm/jz4730.h>
-+#endif
-+
-+#ifdef CONFIG_JZ4740
-+#include <asm/jz4740.h>
-+#endif
-+
-+#ifdef CONFIG_JZ4750
-+#include <asm/jz4750.h>
-+#endif
-+
-+#ifdef CONFIG_JZ4750D
-+#include <asm/jz4750d.h>
-+#endif
-+
-+#if defined(CONFIG_JZ4750) || defined(CONFIG_JZ4750D)
-+#define JZ4750_NANDBOOT_CFG0 (0x55555500 | (CFG_NAND_BW8*0xff))
-+#define JZ4750_NANDBOOT_CFG1 0x55555555
-+#define JZ4750_NANDBOOT_CFG2 ((CFG_NAND_PAGE_SIZE==2048)&0xff0000) | ((CFG_NAND_PAGE_SIZE!=512)&0xff00) | ((CFG_NAND_ROW_CYCLE==3)&0xff)
- #endif
-- .endm
-
- #define RVECENT(f,n) \
- b f; nop
-@@ -61,6 +62,28 @@
- .globl _start
- .text
- _start:
-+#if defined(CONFIG_JZ4740)
-+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_NAND_U_BOOT)
-+ .word JZ4740_NORBOOT_CFG /* fetched during NOR Boot */
-+#else
-+#if defined(CONFIG_NAND_SPL)
-+ .word JZ4740_NANDBOOT_CFG /* fetched during NAND Boot */
-+#endif
-+#endif
-+#endif /* CONFIG_JZ4740 */
-+#if defined(CONFIG_JZ4750) || defined(CONFIG_JZ4750D)
-+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_NAND_U_BOOT)
-+ .word JZ4750_NORBOOT_CFG /* fetched during NOR Boot */
-+#else
-+#if defined(CONFIG_NAND_SPL) && !defined(CONFIG_MSC_SPL)
-+ /* First three words fetched by CPU during NAND Boot */
-+ .word JZ4750_NANDBOOT_CFG0
-+ .word JZ4750_NANDBOOT_CFG1
-+ .word JZ4750_NANDBOOT_CFG2
-+#endif
-+#endif
-+#endif /* CONFIG_JZ4750 || CONFIG_JZ4750D */
-+#if !defined(CONFIG_JzRISC)
- RVECENT(reset,0) /* U-boot entry point */
- RVECENT(reset,1) /* software reboot */
- #if defined(CONFIG_INCA_IP)
-@@ -213,7 +236,7 @@ _start:
- .word 0x00000000
- .word 0x03e00008
- .word 0x00000000
-- .word 0x00000000
-+ .word 0x00000000
- /* 0xbfc00428 */
- .word 0xdc870000
- .word 0xfca70000
-@@ -224,74 +247,192 @@ _start:
- .word 0x00000000
- .word 0x03e00008
- .word 0x00000000
-- .word 0x00000000
-+ .word 0x00000000
- #endif /* CONFIG_PURPLE */
- .align 4
-+#endif /* CONFIG_JzRISC */
-+
- reset:
-
-+#if !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL)
-+
-+#ifdef CONFIG_JZ4730
-+
-+ /* Disable interrupts */
-+ la t0, INTC_IMR
-+ li t1, 0xffffffff
-+ sw t1, 0(t0)
-+
-+ /*
-+ * Clear SCR.HGP
-+ */
-+ la t0, CPM_SCR
-+ lw t1, 0(t0)
-+ ori t1, 0x8
-+ xori t1, 0x8
-+ sw t1, 0(t0)
-+
-+ /*
-+ * Set usb port0 as host
-+ */
-+ la t0, HARB_HAPOR
-+ lw t1, 0(t0)
-+ ori t1, HARB_HAPOR_UCHSEL
-+ sw t1, 0(t0)
-+
-+ /*
-+ * Check reset status
-+ */
-+ la t0, CPM_RSTR
-+ lw t1, 0(t0)
-+ andi t1, 0x4
-+ bnez t1, resume_from_hibernate
-+ nop
-+#endif /* CONFIG_JZ4730 */
-+
-+#ifndef CONFIG_NAND_SPL
- /* Clear watch registers.
- */
- mtc0 zero, CP0_WATCHLO
- mtc0 zero, CP0_WATCHHI
-+#endif
-
-- /* WP(Watch Pending), SW0/1 should be cleared. */
-- mtc0 zero, CP0_CAUSE
-+ /* STATUS register */
-+#ifdef CONFIG_JzRISC
-+ /*
-+ * CU0=UM=EXL=IE=0, BEV=ERL=1, IP2~7=1
-+ */
-+ li t0, 0x0040FC04
-+ mtc0 t0, CP0_STATUS
-+#else
-+#ifdef CONFIG_TB0229
-+ li k0, ST0_CU0
-+#else
-+ mfc0 k0, CP0_STATUS
-+#endif
-+ li k1, ~ST0_IE
-+ and k0, k1
-+ mtc0 k0, CP0_STATUS
-+#endif
-
-- setup_c0_status_reset
-+ /* CAUSE register */
-+#ifdef CONFIG_JzRISC
-+ /* IV=1, use the specical interrupt vector (0x200) */
-+ li t1, 0x00800000
-+ mtc0 t1, CP0_CAUSE
-+#else
-+ mtc0 zero, CP0_CAUSE
-+#endif
-
-+#ifndef CONFIG_JzRISC
- /* Init Timer */
- mtc0 zero, CP0_COUNT
- mtc0 zero, CP0_COMPARE
-+#endif
-
--#if !defined(CONFIG_SKIP_LOWLEVEL_INIT)
-+#endif /* !defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SPL) */
-+
-+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_NAND_U_BOOT)
- /* CONFIG0 register */
- li t0, CONF_CM_UNCACHED
- mtc0 t0, CP0_CONFIG
--#endif /* !CONFIG_SKIP_LOWLEVEL_INIT */
-+#endif
-
-- /* Initialize $gp.
-+ /* Initialize GOT pointer.
-+ */
-+ bal 1f
-+ nop
-+ .word _GLOBAL_OFFSET_TABLE_
-+ 1:
-+ move gp, ra
-+ lw t1, 0(ra)
-+ move gp, t1
-+
-+#ifdef CONFIG_INCA_IP
-+ /* Disable INCA-IP Watchdog.
- */
-- bal 1f
-+ la t9, disable_incaip_wdt
-+ jalr t9
- nop
-- .word _gp
--1:
-- lw gp, 0(ra)
-+#endif
-
--#if !defined(CONFIG_SKIP_LOWLEVEL_INIT)
-+/* JzRISC will init external memory in board_init_f,
-+ which uses cache as stack and calls into C code. */
-+#ifndef CONFIG_JzRISC
- /* Initialize any external memory.
- */
-- la t9, lowlevel_init
-- jalr t9
-+ la t9, lowlevel_init
-+ jalr t9
- nop
-+#endif
-
-+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_NAND_U_BOOT)
- /* Initialize caches...
- */
-- la t9, mips_cache_reset
-- jalr t9
-+#ifdef CONFIG_JzRISC
-+ .set mips32
-+ mtc0 zero, CP0_TAGLO
-+ mtc0 zero, CP0_TAGHI
-+
-+ li t0, K0BASE
-+ ori t1, t0, CONFIG_SYS_DCACHE_SIZE
-+1:
-+ cache Index_Store_Tag_D, 0(t0)
-+ bne t0, t1, 1b
-+ addiu t0, t0, CONFIG_SYS_CACHELINE_SIZE
-+
-+ li t0, K0BASE
-+ ori t1, t0, CONFIG_SYS_ICACHE_SIZE
-+2:
-+ cache Index_Store_Tag_I, 0(t0)
-+ bne t0, t1, 2b
-+ addiu t0, t0, CONFIG_SYS_CACHELINE_SIZE
-+
-+ /* Invalidate BTB */
-+ mfc0 t0, CP0_CONFIG, 7
-+ nop
-+ ori t0, 2
-+ mtc0 t0, CP0_CONFIG, 7
- nop
-
-+ .set mips2
-+#else
-+ la t9, mips_cache_reset
-+ jalr t9
-+ nop
-+#endif
-+
- /* ... and enable them.
- */
- li t0, CONF_CM_CACHABLE_NONCOHERENT
- mtc0 t0, CP0_CONFIG
--#endif /* !CONFIG_SKIP_LOWLEVEL_INIT */
-+ nop
-+
-+#endif /* !defined(CONFIG_NAND_SPL) && !defined(CONFIG_NAND_U_BOOT) */
-
- /* Set up temporary stack.
- */
--#ifdef CONFIG_SYS_INIT_RAM_LOCK_MIPS
-+#ifndef CONFIG_JzRISC
- li a0, CONFIG_SYS_INIT_SP_OFFSET
-- la t9, mips_cache_lock
-- jalr t9
-+ la t9, mips_cache_lock
-+ jalr t9
- nop
- #endif
-
-+#ifdef CONFIG_NAND_SPL
-+ la sp, 0x80004000
-+ la t9, nand_boot
-+ j t9
-+ nop
-+#else
- li t0, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET
- la sp, 0(t0)
-
- la t9, board_init_f
-- jr t9
-+ j t9
- nop
-
-+
- /*
- * void relocate_code (addr_sp, gd, addr_moni)
- *
-@@ -305,37 +446,28 @@ reset:
- .globl relocate_code
- .ent relocate_code
- relocate_code:
-- move sp, a0 /* Set new stack pointer */
-+ move sp, a0 /* Set new stack pointer */
-
-- li t0, CONFIG_SYS_MONITOR_BASE
-+ li t0, TEXT_BASE
- la t3, in_ram
- lw t2, -12(t3) /* t2 <-- uboot_end_data */
- move t1, a2
-- move s2, a2 /* s2 <-- destination address */
-
- /*
-- * Fix $gp:
-+ * Fix GOT pointer:
- *
-- * New $gp = (Old $gp - CONFIG_SYS_MONITOR_BASE) + Destination Address
-+ * New GOT-PTR = (old GOT-PTR - TEXT_BASE) + Destination Address
- */
- move t6, gp
-- sub gp, CONFIG_SYS_MONITOR_BASE
-- add gp, a2 /* gp now adjusted */
-- sub s1, gp, t6 /* s1 <-- relocation offset */
-+ sub gp, TEXT_BASE
-+ add gp, a2 /* gp now adjusted */
-+ sub t6, gp, t6 /* t6 <-- relocation offset */
-
- /*
- * t0 = source address
- * t1 = target address
- * t2 = source end address
- */
--
-- /*
-- * Save destination address and size for later usage in flush_cache()
-- */
-- move s0, a1 /* save gd in s0 */
-- move a0, t1 /* a0 <-- destination addr */
-- sub a1, t2, t0 /* a1 <-- size */
--
- /* On the purple board we copy the code earlier in a special way
- * in order to solve flash problems
- */
-@@ -345,47 +477,61 @@ relocate_code:
- sw t3, 0(t1)
- addu t0, 4
- ble t0, t2, 1b
-- addu t1, 4 /* delay slot */
-+ addu t1, 4 /* delay slot */
- #endif
-
- /* If caches were enabled, we would have to flush them here.
- */
--
-- /* a0 & a1 are already set up for flush_cache(start, size) */
-- la t9, flush_cache
-- jalr t9
-+#ifdef CONFIG_JzRISC
-+ /* flush d-cache */
-+ .set mips32
-+ 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 mips0
-+#endif
-+
- /* Jump to where we've relocated ourselves.
- */
-- addi t0, s2, in_ram - _start
-- jr t0
-+ addi t0, a2, in_ram - _start
-+ j t0
- nop
-
-- .word _gp
-- .word _GLOBAL_OFFSET_TABLE_
- .word uboot_end_data
- .word uboot_end
- .word num_got_entries
-
- in_ram:
-- /*
-- * Now we want to update GOT.
-- *
-- * GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
-- * generated by GNU ld. Skip these reserved entries from relocation.
-+ /* Now we want to update GOT.
- */
- lw t3, -4(t0) /* t3 <-- num_got_entries */
-- lw t4, -16(t0) /* t4 <-- _GLOBAL_OFFSET_TABLE_ */
-- lw t5, -20(t0) /* t5 <-- _gp */
-- sub t4, t5 /* compute offset*/
-- add t4, t4, gp /* t4 now holds relocated _GLOBAL_OFFSET_TABLE_ */
-- addi t4, t4, 8 /* Skipping first two entries. */
-+ addi t4, gp, 8 /* Skipping first two entries. */
- li t2, 2
- 1:
- lw t1, 0(t4)
- beqz t1, 2f
-- add t1, s1
-+ add t1, t6
- sw t1, 0(t4)
- 2:
- addi t2, 1
-@@ -396,26 +542,134 @@ in_ram:
- */
- lw t1, -12(t0) /* t1 <-- uboot_end_data */
- lw t2, -8(t0) /* t2 <-- uboot_end */
-- add t1, s1 /* adjust pointers */
-- add t2, s1
-+ add t1, t6 /* adjust pointers */
-+ add t2, t6
-
- sub t1, 4
--1:
-- addi t1, 4
-+1: addi t1, 4
- bltl t1, t2, 1b
- sw zero, 0(t1) /* delay slot */
-
-- move a0, s0 /* a0 <-- gd */
-+ move a0, a1
- la t9, board_init_r
-- jr t9
-- move a1, s2 /* delay slot */
-+ j t9
-+ move a1, a2 /* delay slot */
-
- .end relocate_code
-
-+#endif /* CONFIG_NAND_SPL */
-+
-+#if !defined(CONFIG_JzRISC)
- /* Exception handlers.
- */
- romReserved:
-- b romReserved
-+ b romReserved
-
- romExcHandle:
-- b romExcHandle
-+ b romExcHandle
-+#endif
-+
-+#ifdef CONFIG_JZ4730
-+
-+/* These are the runtime values, modify them according to your platform. */
-+#define PLCR1_VAL 0x1b000520
-+#define CFCR_VAL 0x0c526220
-+
-+#define DMCR_VAL0 0x042a3211
-+#define DMCR_VAL1 0x05aa3211 /*(DMCR_VAL0|EMC_DMCR_RFSH|EMC_DMCR_MRSET)*/
-+
-+#define RTCOR_VAL 0x10
-+#define RTCSR_VAL 0x83
-+
-+ /*
-+ * cpu was reset from hibernate mode
-+ */
-+resume_from_hibernate:
-+ /*
-+ * Init PLL
-+ */
-+ la t0, 0xB0000000 /* CFCR */
-+ li t1, CFCR_VAL
-+ sw t1, 0(t0)
-+
-+ la t0, 0xB0000010 /* PLCR1 */
-+ li t1, PLCR1_VAL
-+ sw t1, 0(t0)
-+ nop;nop;nop;nop
-+
-+ /* Init caches */
-+ .set mips32
-+ mtc0 zero, CP0_TAGLO
-+ mtc0 zero, CP0_TAGHI
-+
-+ li t0, K0BASE
-+ ori t1, t0, CONFIG_SYS_DCACHE_SIZE
-+1:
-+ cache Index_Store_Tag_D, 0(t0)
-+ cache Index_Store_Tag_I, 0(t0)
-+ bne t0, t1, 1b
-+ addiu t0, t0, CONFIG_SYS_CACHELINE_SIZE
-+
-+ /*
-+ * Init SDRAM
-+ */
-+ la t0, 0xB0010070 /* GPALR2 */
-+ lw t1, 0(t0)
-+ li t2, 0x3FFFFFFF
-+ and t1, t2
-+ li t2, 0x40000000
-+ or t1, t2
-+ sw t1, 0(t0)
-+
-+ la t0, 0xB0010074 /* GPAUR2 */
-+ lw t1, 0(t0)
-+ li t2, 0xFFFF0000
-+ and t1, t2
-+ li t2, 0x00005555
-+ or t1, t2
-+ sw t1, 0(t0)
-+
-+ la t0, 0xB3010000 /* EMC base address */
-+
-+ li t1, DMCR_VAL0 /* DMCR */
-+ sw t1, 0x80(t0)
-+
-+ li t1, RTCOR_VAL
-+ sh t1, 0x8c(t0) /* RTCOR */
-+
-+ li t1, RTCSR_VAL
-+ sh t1, 0x84(t0) /* RTCSR */
-+
-+ /* precharge all chip-selects */
-+ ori t1, t0, 0xa088
-+ sb $0, 0(t1)
-+ ori t1, t0, 0xb088
-+ sb $0, 0(t1)
-+
-+ /* delay about 200us */
-+ li t1, 0x20000
-+1:
-+ bnez t1, 1b
-+ sub t1, 1
-+
-+ la t1, DMCR_VAL1 /* DMCR */
-+ sw t1, 0x80(t0)
-+
-+ /* write sdram mode register for each chip-select */
-+ ori t1, t0, 0xa088
-+ sb $0, 0(t1)
-+ ori t1, t0, 0xb088
-+ sb $0, 0(t1)
-+
-+ /*
-+ * jump to resume entry point
-+ */
-+ la t0, CPM_SPR
-+ lw t1, 0(t0)
-+ li t0, 0x80000000
-+ or t0, t1
-+
-+ j t0
-+ nop
-+
-+#endif /* CONFIG_JZ4730 */
-diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
-index 426bb95..6e5fbd3 100644
---- a/drivers/mtd/nand/nand_base.c
-+++ b/drivers/mtd/nand/nand_base.c
-@@ -109,6 +109,22 @@ static struct nand_ecclayout nand_oob_16 = {
- . length = 8}}
- };
-
-+#if defined(CONFIG_JZ4740)
-+static struct nand_ecclayout nand_oob_64 = {
-+ .eccbytes = 36,
-+ .eccpos = {
-+ 6, 7, 8, 9, 10, 11, 12, 13,
-+ 14, 15, 16, 17, 18, 19, 20, 21,
-+ 22, 23, 24, 25, 26, 27, 28, 29,
-+ 30, 31, 32, 33, 34, 35, 36, 37,
-+ 38, 39, 40, 41},
-+ .oobfree ={
-+ {.offset = 2,
-+ .length = 4},
-+ {.offset = 42,
-+ .length = 22}}
-+};
-+#else
- static struct nand_ecclayout nand_oob_64 = {
- .eccbytes = 24,
- .eccpos = {
-@@ -119,6 +135,7 @@ static struct nand_ecclayout nand_oob_64 = {
- {.offset = 2,
- .length = 38}}
- };
-+#endif
-
- static struct nand_ecclayout nand_oob_128 = {
- .eccbytes = 48,
-@@ -1116,6 +1133,60 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd,
- }
-
- /**
-+ * nand_read_page_hwecc_rs - [REPLACABLE] hardware rs ecc based page read function
-+ * @mtd: mtd info structure
-+ * @chip: nand chip info structure
-+ * @buf: buffer to store read data
-+ *
-+ * Not for syndrome calculating ecc controllers which need a special oob layout
-+ */
-+static int nand_read_page_hwecc_rs(struct mtd_info *mtd, struct nand_chip *chip,
-+ uint8_t *buf)
-+{
-+ int i, eccsize = chip->ecc.size;
-+ int eccbytes = chip->ecc.bytes;
-+ int eccsteps = chip->ecc.steps;
-+ uint8_t *p = buf;
-+ uint8_t *ecc_calc = chip->buffers->ecccalc;
-+ uint8_t *ecc_code = chip->buffers->ecccode;
-+ uint32_t *eccpos = chip->ecc.layout->eccpos;
-+ uint32_t page;
-+ uint8_t flag = 0;
-+
-+ page = (buf[3]<<24) + (buf[2]<<16) + (buf[1]<<8) + buf[0];
-+
-+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
-+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-+
-+ for (i = 0; i < chip->ecc.total; i++) {
-+ ecc_code[i] = chip->oob_poi[CONFIG_SYS_NAND_ECC_POS + i];
-+ if (ecc_code[i] != 0xff)
-+ flag = 1;
-+ }
-+
-+ eccsteps = chip->ecc.steps;
-+ p = buf;
-+
-+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, 0x00, -1);
-+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-+ int stat;
-+ if (flag) {
-+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
-+ chip->read_buf(mtd, p, eccsize);
-+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
-+ if (stat < 0)
-+ mtd->ecc_stats.failed++;
-+ else
-+ mtd->ecc_stats.corrected += stat;
-+ }
-+ else {
-+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
-+ chip->read_buf(mtd, p, eccsize);
-+ }
-+ }
-+ return 0;
-+}
-+/**
- * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
- * @mtd: mtd info structure
- * @chip: nand chip info structure
-@@ -1271,9 +1342,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
- bufpoi, page);
- else if (!aligned && NAND_SUBPAGE_READ(chip) && !oob)
- ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi);
-- else
-+ else {
-+#if defined(CONFIG_JZ4740)
-+ bufpoi[0] = (uint8_t)page;
-+ bufpoi[1] = (uint8_t)(page >> 8);
-+ bufpoi[2] = (uint8_t)(page >> 16);
-+ bufpoi[3] = (uint8_t)(page >> 24);
-+#endif
-+
- ret = chip->ecc.read_page(mtd, chip, bufpoi,
- page);
-+ }
- if (ret < 0)
- break;
-
-@@ -2791,8 +2870,13 @@ int nand_scan_tail(struct mtd_info *mtd)
-
- case NAND_ECC_HW:
- /* Use standard hwecc read page function ? */
-- if (!chip->ecc.read_page)
-+ if (!chip->ecc.read_page) {
-+#if defined(CONFIG_JZ4740)
-+ chip->ecc.read_page = nand_read_page_hwecc_rs;
-+#else
- chip->ecc.read_page = nand_read_page_hwecc;
-+#endif
-+ }
- if (!chip->ecc.write_page)
- chip->ecc.write_page = nand_write_page_hwecc;
- if (!chip->ecc.read_oob)
-diff --git a/examples/standalone/mips.lds b/examples/standalone/mips.lds
-index 717b201..d4a45f8 100644
---- a/examples/standalone/mips.lds
-+++ b/examples/standalone/mips.lds
-@@ -23,8 +23,8 @@
-
- /*
- OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-bigmips")
--*/
- OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradbigmips")
-+*/
- OUTPUT_ARCH(mips)
- SECTIONS
- {
-diff --git a/include/asm-mips/addrspace.h b/include/asm-mips/addrspace.h
-index 3a1e6d6..2ee6920 100644
---- a/include/asm-mips/addrspace.h
-+++ b/include/asm-mips/addrspace.h
-@@ -131,7 +131,7 @@
- * Returns the uncached address of a sdram address
- */
- #ifndef __ASSEMBLY__
--#if defined(CONFIG_SOC_AU1X00) || defined(CONFIG_TB0229)
-+#if defined(CONFIG_SOC_AU1X00) || defined(CONFIG_TB0229) || defined(CONFIG_JzRISC)
- /* We use a 36 bit physical address map here and
- cannot access physical memory directly from core */
- #define UNCACHED_SDRAM(a) (((unsigned long)(a)) | 0x20000000)
-diff --git a/include/asm-mips/global_data.h b/include/asm-mips/global_data.h
-index b2c4891..23f597e 100644
---- a/include/asm-mips/global_data.h
-+++ b/include/asm-mips/global_data.h
-@@ -39,6 +39,17 @@
- typedef struct global_data {
- bd_t *bd;
- unsigned long flags;
-+#if defined(CONFIG_JZSOC)
-+ /* There are other clocks in the Jz47xx or Jz5730*/
-+ unsigned long cpu_clk; /* CPU core clock */
-+ unsigned long sys_clk; /* System bus clock */
-+ unsigned long per_clk; /* Peripheral bus clock */
-+ unsigned long mem_clk; /* Memory bus clock */
-+ unsigned long dev_clk; /* Device clock */
-+ unsigned long fb_base; /* base address of framebuffer */
-+ unsigned long boot_option; /* 1: boot from sd
-+ * 5: boot delay for 5 secs*/
-+#endif
- unsigned long baudrate;
- unsigned long have_console; /* serial_init() was called */
- phys_size_t ram_size; /* RAM size */
-diff --git a/include/lcd.h b/include/lcd.h
-index 1f85daa..997e246 100644
---- a/include/lcd.h
-+++ b/include/lcd.h
-@@ -181,8 +181,44 @@ typedef struct vidinfo {
- u_long mmio; /* Memory mapped registers */
- } vidinfo_t;
-
--#else
-+#elif defined(CONFIG_JZSOC)
-+/*
-+ * LCD controller stucture for JZSOC: JZ4730 JZ4740
-+ */
-+struct jz_fb_dma_descriptor {
-+ u_long fdadr; /* Frame descriptor address register */
-+ u_long fsadr; /* Frame source address register */
-+ u_long fidr; /* Frame ID register */
-+ u_long ldcmd; /* Command register */
-+};
-
-+/*
-+ * Jz LCD info
-+ */
-+struct jz_fb_info {
-+
-+ u_long fdadr0; /* physical address of frame/palette descriptor */
-+ u_long fdadr1; /* physical address of frame descriptor */
-+
-+ /* DMA descriptors */
-+ struct jz_fb_dma_descriptor * dmadesc_fblow;
-+ struct jz_fb_dma_descriptor * dmadesc_fbhigh;
-+ struct jz_fb_dma_descriptor * dmadesc_palette;
-+ u_long screen; /* address of frame buffer */
-+ u_long palette; /* address of palette memory */
-+ u_int palette_size;
-+};
-+typedef struct vidinfo {
-+ ushort vl_col; /* Number of columns (i.e. 640) */
-+ ushort vl_row; /* Number of rows (i.e. 480) */
-+ u_char vl_bpix; /* Bits per pixel, 0 = 1, 1 = 2, 2 = 4, 3 = 8 */
-+
-+ struct jz_fb_info jz_fb;
-+} vidinfo_t;
-+
-+extern vidinfo_t panel_info;
-+
-+#else
- typedef struct vidinfo {
- ushort vl_col; /* Number of columns (i.e. 160) */
- ushort vl_row; /* Number of rows (i.e. 100) */
-@@ -194,7 +230,7 @@ typedef struct vidinfo {
- void *priv; /* Pointer to driver-specific data */
- } vidinfo_t;
-
--#endif /* CONFIG_MPC823, CONFIG_PXA250 or CONFIG_MCC200 or CONFIG_ATMEL_LCD */
-+#endif /* CONFIG_MPC823, CONFIG_PXA250, CONFIG_MCC200 or CONFIG_JZ4740 */
-
- extern vidinfo_t panel_info;
-
-@@ -234,6 +270,7 @@ void lcd_show_board_info(void);
- #define LCD_COLOR4 2
- #define LCD_COLOR8 3
- #define LCD_COLOR16 4
-+#define LCD_COLOR32 5
-
- /*----------------------------------------------------------------------*/
- #if defined(CONFIG_LCD_INFO_BELOW_LOGO)
-@@ -285,13 +322,22 @@ void lcd_show_board_info(void);
- # define CONSOLE_COLOR_GREY 14
- # define CONSOLE_COLOR_WHITE 15 /* Must remain last / highest */
-
--#else
-+#elif LCD_BPP == LCD_COLOR16
-
- /*
- * 16bpp color definitions
- */
- # define CONSOLE_COLOR_BLACK 0x0000
--# define CONSOLE_COLOR_WHITE 0xffff /* Must remain last / highest */
-+# define CONSOLE_COLOR_WHITE 0xffff /* Must remain last / highest */
-+
-+#elif LCD_BPP == LCD_COLOR32
-+/*
-+ * 18,24,32 bpp color definitions
-+ */
-+# define CONSOLE_COLOR_BLACK 0x00000000
-+# define CONSOLE_COLOR_WHITE 0xffffffff /* Must remain last / highest */
-+
-+#else
-
- #endif /* color definitions */
-
-@@ -322,7 +368,7 @@ void lcd_show_board_info(void);
- #if LCD_BPP == LCD_MONOCHROME
- # define COLOR_MASK(c) ((c) | (c) << 1 | (c) << 2 | (c) << 3 | \
- (c) << 4 | (c) << 5 | (c) << 6 | (c) << 7)
--#elif (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16)
-+#elif (LCD_BPP == LCD_COLOR8) || (LCD_BPP == LCD_COLOR16) || (LCD_BPP == LCD_COLOR32)
- # define COLOR_MASK(c) (c)
- #else
- # error Unsupported LCD BPP.
-diff --git a/lib_mips/board.c b/lib_mips/board.c
-index b2d113e..87cb12d 100644
---- a/lib_mips/board.c
-+++ b/lib_mips/board.c
-@@ -49,6 +49,10 @@ DECLARE_GLOBAL_DATA_PTR;
-
- #undef DEBUG
-
-+#if defined(CONFIG_JZSOC)
-+extern int jz_board_init(void);
-+#endif
-+
- extern int timer_init(void);
-
- extern int incaip_set_cpuclk(void);
-@@ -78,7 +82,6 @@ int __board_early_init_f(void)
- }
- int board_early_init_f(void) __attribute__((weak, alias("__board_early_init_f")));
-
--
- static int init_func_ram (void)
- {
- #ifdef CONFIG_BOARD_TYPES
-@@ -98,7 +101,6 @@ static int init_func_ram (void)
-
- static int display_banner(void)
- {
--
- printf ("\n\n%s\n\n", version_string);
- return (0);
- }
-@@ -147,6 +149,9 @@ static int init_baudrate (void)
- typedef int (init_fnc_t) (void);
-
- init_fnc_t *init_sequence[] = {
-+#if defined(CONFIG_JZSOC)
-+ jz_board_init, /* init gpio/clocks/dram etc. */
-+#endif
- board_early_init_f,
- timer_init,
- env_init, /* initialize environment */
-@@ -162,7 +167,6 @@ init_fnc_t *init_sequence[] = {
- NULL,
- };
-
--
- void board_init_f(ulong bootflag)
- {
- gd_t gd_data, *id;
-@@ -202,6 +206,12 @@ void board_init_f(ulong bootflag)
- addr &= ~(4096 - 1);
- debug ("Top of RAM usable for U-Boot at: %08lx\n", addr);
-
-+#ifdef CONFIG_LCD
-+ /* reserve memory for LCD display (always full pages) */
-+ addr = lcd_setmem (addr);
-+ gd->fb_base = addr;
-+#endif /* CONFIG_LCD */
-+
- /* Reserve memory for U-Boot code, data & bss
- * round down to next 16 kB limit
- */
-@@ -349,9 +359,9 @@ void board_init_r (gd_t *id, ulong dest_addr)
- size = flash_init();
- display_flash_config (size);
- bd->bi_flashsize = size;
-+ bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
- #endif
-
-- bd->bi_flashstart = CONFIG_SYS_FLASH_BASE;
- #if CONFIG_SYS_MONITOR_BASE == CONFIG_SYS_FLASH_BASE
- bd->bi_flashoffset = monitor_flash_len; /* reserved area for U-Boot */
- #else
-diff --git a/lib_mips/bootm.c b/lib_mips/bootm.c
-index 54af24c..64bcad9 100644
---- a/lib_mips/bootm.c
-+++ b/lib_mips/bootm.c
-@@ -46,7 +46,9 @@ static void linux_env_set (char * env_name, char * env_val);
- int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
- {
- void (*theKernel) (int, char **, char **, int *);
-- char *commandline = getenv ("bootargs");
-+ char *commandline = gd->boot_option == 1 ?
-+ getenv ("bootargsfromsd") :
-+ getenv ("bootargs");
- char env_buf[12];
- char *cp;
-
-@@ -98,6 +100,9 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images)
- }
-
- /* we assume that the kernel is in place */
-+ if (gd->boot_option == 1)
-+ printf ("\n *** Booting from mircoSD ***\n");
-+
- printf ("\nStarting kernel ...\n\n");
-
- theKernel (linux_argc, linux_argv, linux_env, 0);
-diff --git a/lib_mips/time.c b/lib_mips/time.c
-index 07e356d..4654bf4 100644
---- a/lib_mips/time.c
-+++ b/lib_mips/time.c
-@@ -24,6 +24,8 @@
- #include <common.h>
- #include <asm/mipsregs.h>
-
-+#ifndef CONFIG_JzRISC
-+
- static unsigned long timestamp;
-
- /* how many counter cycles in a jiffy */
-@@ -96,3 +98,5 @@ ulong get_tbclk(void)
- {
- return CONFIG_SYS_HZ;
- }
-+
-+#endif /* !CONFIG_JzRISC */
-
diff --git a/package/boot/uboot-xburst/patches/005-i2c.patch b/package/boot/uboot-xburst/patches/005-i2c.patch
deleted file mode 100644
index b8ad22f0e1..0000000000
--- a/package/boot/uboot-xburst/patches/005-i2c.patch
+++ /dev/null
@@ -1,13 +0,0 @@
-diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
-index ef32f13..4e234b4 100644
---- a/drivers/i2c/Makefile
-+++ b/drivers/i2c/Makefile
-@@ -36,6 +36,7 @@ COBJS-$(CONFIG_DRIVER_S3C24X0_I2C) += s3c24x0_i2c.o
- COBJS-$(CONFIG_S3C44B0_I2C) += s3c44b0_i2c.o
- COBJS-$(CONFIG_SOFT_I2C) += soft_i2c.o
- COBJS-$(CONFIG_TSI108_I2C) += tsi108_i2c.o
-+COBJS-$(CONFIG_JZSOC_I2C) += jz_i2c.o
-
- COBJS := $(COBJS-y)
- SRCS := $(COBJS:.o=.c)
-
diff --git a/package/boot/uboot-xburst/patches/009-n516.patch b/package/boot/uboot-xburst/patches/009-n516.patch
deleted file mode 100644
index 49eaf3da44..0000000000
--- a/package/boot/uboot-xburst/patches/009-n516.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-diff --git a/Makefile b/Makefile
-index ed848f5..04cd32e 100644
---- a/Makefile
-+++ b/Makefile
-@@ -3448,6 +3448,18 @@ pavo_nand_config : unconfig
- @echo "TEXT_BASE = 0x80100000" > $(obj)board/qi_lb60/config.tmp
- @echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
-
-+n516_config : unconfig
-+ @ >include/config.h
-+ @echo "#define CONFIG_N516 1" >>include/config.h
-+ @./mkconfig -a n516 mips mips n516
-+
-+n516_nand_config : unconfig
-+ @echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
-+ @echo "Compile NAND boot image for n516"
-+ @./mkconfig -a n516 mips mips n516
-+ @echo "TEXT_BASE = 0x80100000" > $(obj)board/n516/config.tmp
-+ @echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
-+
- #########################################################################
- ## MIPS64 5Kc
- #########################################################################
diff --git a/package/boot/uboot-xburst/patches/010-sakc.patch b/package/boot/uboot-xburst/patches/010-sakc.patch
deleted file mode 100644
index 2ec82b7dc1..0000000000
--- a/package/boot/uboot-xburst/patches/010-sakc.patch
+++ /dev/null
@@ -1,32 +0,0 @@
-diff --git a/Makefile b/Makefile
-index a318eb4..7d14b8b 100644
---- a/Makefile
-+++ b/Makefile
-@@ -3448,6 +3448,13 @@ qi_lb60_config : unconfig
- @echo "TEXT_BASE = 0x80100000" > $(obj)board/n516/config.tmp
- @echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
-
-+sakc_config : unconfig
-+ @echo "#define CONFIG_NAND_U_BOOT" > $(obj)include/config.h
-+ @echo "Compile NAND boot image for SAKC"
-+ @$(MKCONFIG) -a sakc mips mips sakc
-+ @echo "TEXT_BASE = 0x80100000" > $(obj)board/sakc/config.tmp
-+ @echo "CONFIG_NAND_U_BOOT = y" >> $(obj)include/config.mk
-+
- #########################################################################
- ## MIPS64 5Kc
- #########################################################################
-diff --git a/cpu/mips/Makefile b/cpu/mips/Makefile
-index 33afb66..a177653 100644
---- a/cpu/mips/Makefile
-+++ b/cpu/mips/Makefile
-@@ -35,7 +35,7 @@ COBJS-$(CONFIG_PURPLE) += asc_serial.o
- COBJS-$(CONFIG_JZSOC) += jz_serial.o jz_i2c.o jz_mmc.o
- COBJS-$(CONFIG_JZ4740) += jz4740.o jz4740_nand.o
- COBJS-$(CONFIG_NANONOTE) += nanonote_gpm940b0.o
--
-+COBJS-$(CONFIG_SAKC) += nanonote_gpm940b0.o
-
- SRCS := $(START:.o=.S) $(SOBJS-y:.o=.S) $(COBJS-y:.o=.c)
- OBJS := $(addprefix $(obj),$(SOBJS-y) $(COBJS-y))
-