U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
December 2008
- 172 participants
- 485 discussions

03 Apr '09
Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj(a)jcrosoft.com>
diff --git a/include/configs/integratorap.h b/include/configs/integratorap.h
index 6ce3b4d..d7f617f 100644
--- a/include/configs/integratorap.h
+++ b/include/configs/integratorap.h
@@ -143,7 +143,7 @@
* PCI definitions
*/
-/*#define CONFIG_PCI /--* include pci support */
+#ifdef CONFIG_PCI /* pci support */
#undef CONFIG_PCI_PNP
#define CONFIG_PCI_SCAN_SHOW 1 /* show pci devices on startup */
#define DEBUG
@@ -151,7 +151,6 @@
#define CONFIG_EEPRO100
#define CONFIG_SYS_RX_ETH_BUFFER 8 /* use 8 rx buffer on eepro100 */
-
#define INTEGRATOR_BOOT_ROM_BASE 0x20000000
#define INTEGRATOR_HDR0_SDRAM_BASE 0x80000000
@@ -279,6 +278,7 @@
#define INTEGRATOR_SC_PCIENABLE \
(INTEGRATOR_SC_BASE + INTEGRATOR_SC_PCIENABLE_OFFSET)
+#endif /* CONFIG_PCI */
/*-----------------------------------------------------------------------
* There are various dependencies on the core module (CM) fitted
* Users should refer to their CM user guide
--
1.5.6.5
2
1

03 Apr '09
[PATCH] IXP425: Add new IXP425 board emPC-A400
This patch adds support for the emPC-A400 CPU board from
Janz Automationssysteme. It will also apply to some
of the Janz emVIEW displays which are based on this CPU
board.
Besides of the board support, the patch includes
two features which are (up to now) private to this
port but might be of interrest to others.
1. Ability to download microcode to the NPE unit. This
code works without using the Intel Library (which
makes it smaller). This is good if you do not want
to do networking in u-boot, but want boot an NFS-rooted
linux system (where linux cannot load the microcode
by itself).
Refer to boards/empca400/cmd_npe.c
2. Ability to boot the IXP425 Windows-CE kernel. Refer
to boards/empca400/cmd_bootce.c.
The patch is against "latest" u-boot git-repository
Please (still) be patient if style of submission or patches are
offending.
Signed-off-by: Stefan Althoefer <stefan.althoefer(a)web.de>
----
diff -uprN u-boot-orig//board/empca400/cmd_bootce.c u-boot/board/empca400/cmd_bootce.c
--- u-boot-orig//board/empca400/cmd_bootce.c 1970-01-01 01:00:00.000000000 +0100
+++ u-boot/board/empca400/cmd_bootce.c 2008-12-03 11:58:03.000000000 +0100
@@ -0,0 +1,313 @@
+/*
+ * (C) Copyright 2008
+ * Janz Automationssysteme AG <www.janz.de>
+ * Stefan Althoefer <as(a)janz.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * cmd_bootce.c - boot Windows-CE kernel
+ *
+ * This is able to boot Windows-CE on the IXP425 platform.
+ * I believe it is not usable for other platforms, because of
+ * the special passing of parameters to the Win-CE kernel
+ * and due to some fixed loading addresses.
+ */
+#include <common.h>
+#include <command.h>
+#include <net.h>
+
+#define DRIVER_GLOBALS_PHYS 0x1f8000
+#define DRIVER_GLOBALS_SIZE 0x1000
+
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+typedef unsigned long DWORD;
+
+/*
+ * @struct EDBG_ADDR | Addressing info for the debug Ethernet subsystem
+ *
+ * For speed, all values are stored in net byte order (big endian). Use the
+ * htonl/ntohl/htons/ntohs macros to convert to/from local byte order.
+ */
+typedef struct _EDBG_ADDR {
+ DWORD dwIP; /* @field IP address (net byte order) */
+ USHORT wMAC[3]; /* @field Ethernet address (net byte order) */
+ USHORT wPort; /* @field UDP port # (net byte order) - only used if appropriate */
+
+} EDBG_ADDR;
+
+/* For debugging over ethernet. Controls debug messages, ethernet shell */
+/* and kernel debugger. Note that this struct should not be zeroed */
+/* out by OEMInit, as the eboot bootloader passes us state info. */
+typedef struct _DBG_ETH_GLOBALS
+{
+#define EBOOT_MAGIC_NUM 0x45424F54 /* "EBOT" */
+ DWORD EbootMagicNum; /* To detect if ether bootloader is present */
+ UCHAR etherEnabled; /* If non-zero, ethernet card present */
+ UCHAR etherFlags; /* Set by eboot loader. Controls which components */
+ /* are enabled over ether (see ethdbg.h) */
+ UCHAR ucEdbgAdapterType; /* Type of debug Ether adapter */
+ UCHAR ucEdbgIRQ; /* IRQ line to use for debug Ether adapter */
+
+ DWORD dwEdbgBaseAddr; /* Base I/O address for debug Ether adapter */
+ EDBG_ADDR TargetAddr; /* IP and ether address of Odo */
+ DWORD SubnetMask; /* Subnet mask */
+ EDBG_ADDR DownloadHostAddr; /* IP and ether address of host who started us */
+
+ /* The following addresses are assumed valid if the corresponding flag in */
+ /* etherFlags is set. */
+ EDBG_ADDR DbgHostAddr; /* IP/ether addr and UDP port of host receiving dbg msgs */
+ EDBG_ADDR KdbgHostAddr; /* IP/ether addr and UDP port of host running kernel debugger */
+ EDBG_ADDR PpshHostAddr; /* IP/ether addr and UDP port of host running ether text shell */
+ DWORD DHCPLeaseTime; /* DHCP lease duration in seconds. */
+ DWORD EdbgFlags; /* Information about ethernet system */
+ WORD KitlTransport; /* Transport for KITL communications. */
+ UCHAR fmtBuf[170];
+} DBG_ETH_GLOBALS;
+
+/* Un-initialized Miscellaneous */
+typedef struct _UNINIT_MISC_GLOBALS {
+ UINT CPUSteppingID; /* Contains the Current CPU ID (including stepping) */
+ UCHAR EbootDevice;
+ UCHAR reserved[3]; /* Reserved (for alignment purpose) */
+ WORD MACnpe0[3]; /* NPE0 mac address */
+ WORD MACnpe1[3]; /* NPE1 mac address */
+ WORD MACrndis[3]; /* RNDIS mac address */
+ UCHAR padding[230];
+} UNINIT_MISC_GLOBALS, *PUNINIT_MISC_GLOBALS;
+
+/* For ucEdbgAdapterType field */
+#define EDBG_ADAPTER_IXDP425NPE0 7
+#define EDBG_ADAPTER_IXDP425NPE1 8
+
+/* For EbootDevice field */
+#define BOOT_DEVICE_NONE 0
+#define BOOT_DEVICE_PCI 1
+#define BOOT_DEVICE_RTL BOOT_DEVICE_PCI
+#define BOOT_DEVICE_NPE_ETH0 2
+#define BOOT_DEVICE_NPE_ETH1 3
+
+/* for KitlTransport field */
+#define KTS_DEFAULT 0
+#define KTS_ETHER 1
+#define KTS_SERIAL 2
+#define KTS_NONE 63
+
+#define KTS_PASSIVE_MODE 0x40
+
+
+
+/* ---------------------------------------------------------------- */
+
+static inline unsigned int mswap32(unsigned int x)
+{
+ return (
+ ((x<<24) & 0xff000000) |
+ ((x<< 8) & 0x00ff0000) |
+ ((x>> 8) & 0x0000ff00) |
+ ((x>>24) & 0x000000ff) );
+}
+
+
+static inline unsigned short mswap16(unsigned short x)
+{
+ return (
+ ((x<< 8) & 0xff00) |
+ ((x>> 8) & 0x00ff) );
+}
+
+
+static int get_mac_from_env(USHORT *mac, char *env)
+{
+ char *pcTmp = getenv(env);
+ unsigned char addr[6];
+ char *pcEnd;
+ int i;
+
+ if( pcTmp != NULL ){
+ for (i = 0; i < 6; i++) {
+ addr[i] =
+ pcTmp ? simple_strtoul (pcTmp, &pcEnd, 16) : 0;
+ pcTmp = (*pcTmp) ? pcEnd + 1 : pcEnd;
+ }
+ }
+
+ mac[0] = mswap16(addr[0]+(addr[1]<<8));
+ mac[1] = mswap16(addr[2]+(addr[3]<<8));
+ mac[2] = mswap16(addr[4]+(addr[5]<<8));
+
+ return 0;
+}
+
+
+int do_bootce(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ int i;
+ volatile char *vpC;
+ char *net_addr;
+ int cross_boot;
+ int kernelSize;
+ char *kitltransport;
+ void (*theKernel)(void);
+
+ DBG_ETH_GLOBALS *pDbgEth;
+ UNINIT_MISC_GLOBALS *pUninitMiscGlobals;
+
+ /* Strip off cmd-name */
+ argc--, argv++;
+
+ cross_boot = 0;
+ if (getenv("crossboot"))
+ cross_boot = 1;
+
+ /* parse flags */
+ while ((argc>0) && (argv[0][0] == '-')) {
+ switch( argv[0][1] ){
+ case 'x':
+ cross_boot = 1;
+ argc--, argv++;
+ break;
+
+ default:
+ printf("%s: command error (unknown option flag)\n", __FUNCTION__);
+ return 1;
+ }
+ }
+
+
+ switch (argc) {
+ case 2:
+ theKernel = (void(*)(void)) simple_strtoul (argv[0], NULL, 16);
+ kernelSize = simple_strtoul (argv[1], NULL, 16);
+ break;
+ default:
+ printf("%s: command error (too few parameters)\n", __FUNCTION__);
+ return 1;
+ }
+
+ printf("%s: doing CE: %x, %x\n", __FUNCTION__, (int)theKernel, kernelSize);
+
+ /* Blank driver physical area */
+ vpC = (volatile char *)DRIVER_GLOBALS_PHYS;
+ i = 0;
+ while (i < DRIVER_GLOBALS_SIZE) {
+ *vpC++ = 0;
+ i++;
+ }
+
+ pUninitMiscGlobals = (UNINIT_MISC_GLOBALS *)(DRIVER_GLOBALS_PHYS+0x800);
+ pDbgEth = (DBG_ETH_GLOBALS *)(DRIVER_GLOBALS_PHYS+0x900);
+
+ pUninitMiscGlobals->EbootDevice = BOOT_DEVICE_NPE_ETH0; /* FIXME: From ENV */
+ get_mac_from_env(pUninitMiscGlobals->MACnpe0, "ethaddr");
+ if (getenv("eth1addr") != 0) {
+ get_mac_from_env(pUninitMiscGlobals->MACnpe1, "eth1addr");
+ } else {
+ /* Was used with early boards */
+ get_mac_from_env(pUninitMiscGlobals->MACnpe1, "ethaddr1");
+ }
+
+ pDbgEth->EbootMagicNum = mswap32(EBOOT_MAGIC_NUM);
+ pDbgEth->ucEdbgAdapterType = EDBG_ADAPTER_IXDP425NPE0; /* FIXME: From ENV */
+
+ net_addr = getenv("ipaddr");
+ if (net_addr == 0) {
+ printf("ipaddr not set\n");
+ return 1;
+ } else {
+ pDbgEth->TargetAddr.dwIP = string_to_ip(net_addr);
+ }
+ get_mac_from_env(pDbgEth->TargetAddr.wMAC, "ethaddr");
+
+ net_addr = getenv("serverip");
+ if (net_addr == 0) {
+ printf("serverip not set\n");
+ return 1;
+ } else {
+ pDbgEth->DownloadHostAddr.dwIP = string_to_ip(net_addr);
+ }
+
+ net_addr = getenv("netmask");
+ if (net_addr == 0) {
+ pDbgEth->SubnetMask = string_to_ip("255.255.255.0");
+ printf("using default netmask 255.255.255.0\n");
+ } else {
+ pDbgEth->SubnetMask = string_to_ip(net_addr);
+ }
+
+ if ((kitltransport=getenv("kitltransport")) != 0) {
+ pDbgEth->KitlTransport = mswap16(simple_strtoul (kitltransport, NULL, 16));
+ } else {
+ /* default. FIXME: This should be KTS_NONE? */
+ pDbgEth->KitlTransport = mswap16(KTS_ETHER);
+ }
+
+ if (cross_boot) {
+ volatile int *pk;
+ volatile int dummy;
+ unsigned long reg;
+ int ksize;
+
+ printf("cross endian\n");
+
+ /* swap the kernel code */
+ ksize = kernelSize;
+ pk = (int *)theKernel;
+ for (i=0; i<ksize/(sizeof(int)); i++) {
+ *pk = mswap32(*pk);
+ pk++;
+ }
+
+ /* read more data to flush the cache (hopefully we do not reach
+ end of RAM) */
+ for (i=0; i<64*1024; i++) {
+ dummy = *pk++;
+ }
+
+#if (__BYTE_ORDER == __BIG_ENDIAN)
+ /* turn off Big-Endian mode */
+ asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (reg));
+ reg &= ~(1<<7);
+ asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (reg));
+#else
+ /* turn on Big-Endian mode */
+ asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (reg));
+ reg |= (1<<7);
+ asm ("mcr p15, 0, %0, c1, c0, 0": :"r" (reg));
+#endif
+ }
+
+ theKernel();
+
+ return 0;
+}
+
+
+U_BOOT_CMD(
+ bootce, 4, 0, do_bootce,
+ "bootce - boot WinCE nk.nb0\n",
+ "[-x] <addr>\n"
+ " - boot WinCE nk.nb0 located at 'addr'. If '-x' is given, cross endian\n"
+ " boot will be performed (BE->LE)\n"
+);
+
2
1
This patch adds support for the PM9261 board of Ronetix GmbH (www.ronetix.at)
Signed-off-by: Ilko Iliev <iliev(a)ronetix.at>
---
MAKEALL | 1 +
Makefile | 3 +
board/ronetix/pm9261/Makefile | 60 +++++
board/ronetix/pm9261/config.mk | 1 +
board/ronetix/pm9261/pm9261.c | 352 +++++++++++++++++++++++++
board/ronetix/pm9261/pm9261_led.c | 79 ++++++
board/ronetix/pm9261/pm9261_lowlevel_init.S | 368 +++++++++++++++++++++++++++
board/ronetix/pm9261/pm9261_nand.c | 79 ++++++
board/ronetix/pm9261/pm9261_partition.c | 47 ++++
include/configs/pm9261.h | 266 ++++++++++++++++++++
10 files changed, 1265 insertions(+), 0 deletions(-)
mode change 100755 => 100644 MAKEALL
create mode 100644 board/ronetix/pm9261/Makefile
create mode 100644 board/ronetix/pm9261/config.mk
create mode 100644 board/ronetix/pm9261/pm9261.c
create mode 100644 board/ronetix/pm9261/pm9261_led.c
create mode 100644 board/ronetix/pm9261/pm9261_lowlevel_init.S
create mode 100644 board/ronetix/pm9261/pm9261_nand.c
create mode 100644 board/ronetix/pm9261/pm9261_partition.c
create mode 100644 include/configs/pm9261.h
diff --git a/MAKEALL b/MAKEALL
old mode 100755
new mode 100644
index a1df37b..09ba6d1
--- a/MAKEALL
+++ b/MAKEALL
@@ -545,6 +545,7 @@ LIST_at91=" \
kb9202 \
mp2usb \
m501sk \
+ pm9261 \
pm9263 \
"
diff --git a/Makefile b/Makefile
index 7d43159..0a5d3a9 100644
--- a/Makefile
+++ b/Makefile
@@ -2561,6 +2561,9 @@ at91cap9adk_config : unconfig
at91sam9260ek_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm926ejs at91sam9260ek atmel at91
+pm9261_config : unconfig
+ @$(MKCONFIG) $(@:_config=) arm arm926ejs pm9261 ronetix at91
+
pm9263_config : unconfig
@$(MKCONFIG) $(@:_config=) arm arm926ejs pm9263 ronetix at91
diff --git a/board/ronetix/pm9261/Makefile b/board/ronetix/pm9261/Makefile
new file mode 100644
index 0000000..48a42ea
--- /dev/null
+++ b/board/ronetix/pm9261/Makefile
@@ -0,0 +1,60 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd(a)denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian.pop(a)leadtechdesign.com>
+# Lead Tech Design <www.leadtechdesign.com>
+# Ilko Iliev <www.ronetix.at>
+#
+# 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$(BOARD).a
+
+COBJS-y += pm9261.o
+COBJS-y += pm9261_led.o
+COBJS-y += pm9261_partition.o
+COBJS-$(CONFIG_CMD_NAND) += pm9261_nand.o
+
+SOBJS := pm9261_lowlevel_init.o
+
+SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS-y) $(SOBJS))
+SOBJS := $(addprefix $(obj),$(SOBJS))
+
+$(LIB): $(obj).depend $(OBJS) $(SOBJS)
+ $(call cmd_link_o_target, $@, $(OBJS))
+
+clean:
+ rm -f $(SOBJS) $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak $(obj).depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/ronetix/pm9261/config.mk b/board/ronetix/pm9261/config.mk
new file mode 100644
index 0000000..7185419
--- /dev/null
+++ b/board/ronetix/pm9261/config.mk
@@ -0,0 +1 @@
+TEXT_BASE = 0x23f00000
\ No newline at end of file
diff --git a/board/ronetix/pm9261/pm9261.c b/board/ronetix/pm9261/pm9261.c
new file mode 100644
index 0000000..632eab1
--- /dev/null
+++ b/board/ronetix/pm9261/pm9261.c
@@ -0,0 +1,352 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stelian Pop <stelian.pop(a)leadtechdesign.com>
+ * Lead Tech Design <www.leadtechdesign.com>
+ * Ilko Iliev <www.ronetix.at>
+*
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/sizes.h>
+#include <asm/arch/at91sam9261.h>
+#include <asm/arch/at91sam9261_matrix.h>
+#include <asm/arch/at91sam9_smc.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_rstc.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/io.h>
+#include <lcd.h>
+#include <dataflash.h>
+#include <atmel_lcdc.h>
+#if defined(CONFIG_RESET_PHY_R) && defined(CONFIG_DRIVER_DM9000)
+#include <net.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* ------------------------------------------------------------------------- */
+/*
+ * Miscelaneous platform dependent initialisations
+ */
+
+static void pm9261_serial_hw_init(void)
+{
+#ifdef CONFIG_USART0
+ at91_set_A_periph(AT91_PIN_PC8, 1); /* TXD0 */
+ at91_set_A_periph(AT91_PIN_PC9, 0); /* RXD0 */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_US0);
+#endif
+
+#ifdef CONFIG_USART1
+ at91_set_A_periph(AT91_PIN_PC12, 1); /* TXD1 */
+ at91_set_A_periph(AT91_PIN_PC13, 0); /* RXD1 */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_US1);
+#endif
+
+#ifdef CONFIG_USART2
+ at91_set_A_periph(AT91_PIN_PC14, 1); /* TXD2 */
+ at91_set_A_periph(AT91_PIN_PC15, 0); /* RXD2 */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_US2);
+#endif
+
+#ifdef CONFIG_USART3 /* DBGU */
+ at91_set_A_periph(AT91_PIN_PA9, 0); /* DRXD */
+ at91_set_A_periph(AT91_PIN_PA10, 1); /* DTXD */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS);
+#endif
+}
+
+#ifdef CONFIG_CMD_NAND
+static void pm9261_nand_hw_init(void)
+{
+ unsigned long csa;
+
+ /* Enable CS3 */
+ csa = at91_sys_read(AT91_MATRIX_EBICSA);
+ at91_sys_write(AT91_MATRIX_EBICSA,
+ csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
+
+ /* Configure SMC CS3 for NAND/SmartMedia */
+ at91_sys_write(AT91_SMC_SETUP(3),
+ AT91_SMC_NWESETUP_(1) | AT91_SMC_NCS_WRSETUP_(0) |
+ AT91_SMC_NRDSETUP_(1) | AT91_SMC_NCS_RDSETUP_(0));
+ at91_sys_write(AT91_SMC_PULSE(3),
+ AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3) |
+ AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3));
+ at91_sys_write(AT91_SMC_CYCLE(3),
+ AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5));
+ at91_sys_write(AT91_SMC_MODE(3),
+ AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
+ AT91_SMC_EXNWMODE_DISABLE |
+#ifdef CFG_NAND_DBW_16
+ AT91_SMC_DBW_16 |
+#else /* CFG_NAND_DBW_8 */
+ AT91_SMC_DBW_8 |
+#endif
+ AT91_SMC_TDF_(2));
+
+ /* Configure RDY/BSY */
+ at91_set_gpio_input(AT91_PIN_PA16, 1);
+
+ /* Enable NandFlash */
+ at91_set_gpio_output(AT91_PIN_PC14, 1);
+
+ at91_set_A_periph(AT91_PIN_PC0, 0); /* NANDOE */
+ at91_set_A_periph(AT91_PIN_PC1, 0); /* NANDWE */
+}
+#endif
+
+#ifdef CONFIG_HAS_DATAFLASH
+static void pm9261_spi_hw_init(void)
+{
+ at91_set_A_periph(AT91_PIN_PA3, 0); /* SPI0_NPCS0 */
+
+ at91_set_A_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */
+ at91_set_A_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */
+ at91_set_A_periph(AT91_PIN_PA2, 0); /* SPI0_SPCK */
+
+ /* Enable clock */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9261_ID_SPI0);
+}
+#endif
+
+#ifdef CONFIG_DRIVER_DM9000
+static void pm9261_dm9000_hw_init(void)
+{
+ /* Configure SMC CS2 for DM9000 */
+ at91_sys_write(AT91_SMC_SETUP(2),
+ AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(0) |
+ AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(0));
+ at91_sys_write(AT91_SMC_PULSE(2),
+ AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(8) |
+ AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(8));
+ at91_sys_write(AT91_SMC_CYCLE(2),
+ AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
+ at91_sys_write(AT91_SMC_MODE(2),
+ AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
+ AT91_SMC_EXNWMODE_DISABLE |
+ AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16 |
+ AT91_SMC_TDF_(1));
+
+ /* Configure Interrupt pin as input, no pull-up */
+ at91_set_gpio_input(AT91_PIN_PA24, 0);
+}
+#endif
+
+#ifdef CONFIG_LCD
+vidinfo_t panel_info = {
+ vl_col: 240,
+ vl_row: 320,
+ vl_clk: 4965000,
+ vl_sync: ATMEL_LCDC_INVLINE_INVERTED |
+ ATMEL_LCDC_INVFRAME_INVERTED,
+ vl_bpix: 3,
+ vl_tft: 1,
+ vl_hsync_len: 5,
+ vl_left_margin: 1,
+ vl_right_margin:33,
+ vl_vsync_len: 1,
+ vl_upper_margin:1,
+ vl_lower_margin:0,
+ mmio: AT91SAM9261_LCDC_BASE,
+};
+
+void lcd_enable(void)
+{
+ at91_set_gpio_value(AT91_PIN_PA22, 0); /* power up */
+}
+
+void lcd_disable(void)
+{
+ at91_set_gpio_value(AT91_PIN_PA22, 1); /* power down */
+}
+
+static void pm9261_lcd_hw_init(void)
+{
+ at91_set_A_periph(AT91_PIN_PB1, 0); /* LCDHSYNC */
+ at91_set_A_periph(AT91_PIN_PB2, 0); /* LCDDOTCK */
+ at91_set_A_periph(AT91_PIN_PB3, 0); /* LCDDEN */
+ at91_set_A_periph(AT91_PIN_PB4, 0); /* LCDCC */
+ at91_set_A_periph(AT91_PIN_PB7, 0); /* LCDD2 */
+ at91_set_A_periph(AT91_PIN_PB8, 0); /* LCDD3 */
+ at91_set_A_periph(AT91_PIN_PB9, 0); /* LCDD4 */
+ at91_set_A_periph(AT91_PIN_PB10, 0); /* LCDD5 */
+ at91_set_A_periph(AT91_PIN_PB11, 0); /* LCDD6 */
+ at91_set_A_periph(AT91_PIN_PB12, 0); /* LCDD7 */
+ at91_set_A_periph(AT91_PIN_PB15, 0); /* LCDD10 */
+ at91_set_A_periph(AT91_PIN_PB16, 0); /* LCDD11 */
+ at91_set_A_periph(AT91_PIN_PB17, 0); /* LCDD12 */
+ at91_set_A_periph(AT91_PIN_PB18, 0); /* LCDD13 */
+ at91_set_A_periph(AT91_PIN_PB19, 0); /* LCDD14 */
+ at91_set_A_periph(AT91_PIN_PB20, 0); /* LCDD15 */
+ at91_set_B_periph(AT91_PIN_PB23, 0); /* LCDD18 */
+ at91_set_B_periph(AT91_PIN_PB24, 0); /* LCDD19 */
+ at91_set_B_periph(AT91_PIN_PB25, 0); /* LCDD20 */
+ at91_set_B_periph(AT91_PIN_PB26, 0); /* LCDD21 */
+ at91_set_B_periph(AT91_PIN_PB27, 0); /* LCDD22 */
+ at91_set_B_periph(AT91_PIN_PB28, 0); /* LCDD23 */
+
+ at91_sys_write(AT91_PMC_SCER, AT91_PMC_HCK1);
+
+ gd->fb_base = AT91SAM9261_SRAM_BASE;
+}
+
+#ifdef CONFIG_LCD_INFO
+#include <nand.h>
+#include <version.h>
+
+extern flash_info_t flash_info[];
+
+void lcd_show_board_info(void)
+{
+ ulong dram_size, nand_size, flash_size, dataflash_size;
+ int i;
+ char temp[32];
+
+ lcd_printf ("%s\n", U_BOOT_VERSION);
+ lcd_printf ("(C) 2008 Ronetix GmbH\n");
+ lcd_printf ("support(a)ronetix.at\n");
+ lcd_printf ("%s CPU at %s MHz",
+ AT91_CPU_NAME,
+ strmhz(temp, AT91_MAIN_CLOCK));
+
+ dram_size = 0;
+ for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
+ dram_size += gd->bd->bi_dram[i].size;
+
+ nand_size = 0;
+ for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++)
+ nand_size += nand_info[i].size;
+
+ flash_size = 0;
+ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++)
+ flash_size += flash_info[i].size;
+
+ dataflash_size = 0;
+ for (i = 0; i < CONFIG_SYS_MAX_DATAFLASH_BANKS; i++)
+ dataflash_size += (unsigned int) dataflash_info[i].Device.pages_number *
+ dataflash_info[i].Device.pages_size;
+
+ lcd_printf ("%ld MB SDRAM, %ld MB NAND\n%ld MB NOR Flash\n"
+ "%ld MB DataFlash\n",
+ dram_size >> 20,
+ nand_size >> 20,
+ flash_size >> 20,
+ dataflash_size >> 20);
+}
+#endif /* CONFIG_LCD_INFO */
+
+#endif /* CONFIG_LCD */
+
+int board_init(void)
+{
+ /* Enable Ctrlc */
+ console_init_f();
+
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9261_ID_PIOA);
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9261_ID_PIOC);
+
+ /* arch number of AT91SAM9261EK-Board */
+ gd->bd->bi_arch_number = MACH_TYPE_PM9261;
+
+ /* adress of boot parameters */
+ gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+
+ pm9261_serial_hw_init();
+#ifdef CONFIG_CMD_NAND
+ pm9261_nand_hw_init();
+#endif
+#ifdef CONFIG_HAS_DATAFLASH
+ pm9261_spi_hw_init();
+#endif
+#ifdef CONFIG_DRIVER_DM9000
+ pm9261_dm9000_hw_init();
+#endif
+#ifdef CONFIG_LCD
+ pm9261_lcd_hw_init();
+#endif
+ return 0;
+}
+
+int dram_init(void)
+{
+ gd->bd->bi_dram[0].start = PHYS_SDRAM;
+ gd->bd->bi_dram[0].size = PHYS_SDRAM_SIZE;
+ return 0;
+}
+
+#ifdef CONFIG_RESET_PHY_R
+void reset_phy(void)
+{
+#ifdef CONFIG_DRIVER_DM9000
+ /*
+ * Initialize ethernet HW addr prior to starting Linux,
+ * needed for nfsroot
+ */
+ eth_init(gd->bd);
+#endif
+}
+#endif
+
+#ifdef CONFIG_DISPLAY_BOARDINFO
+int checkboard (void)
+{
+ uint32_t reg, diva, divb, mula, mulb;
+ uint32_t val, mdiv, pres, usbdiv, crystal;
+ char buf[32];
+
+ reg = at91_sys_read(AT91_CKGR_PLLAR);
+ mula = ((reg >> 16) & 0x7FF) + 1;
+ diva = reg & 0xFF;
+
+ reg = at91_sys_read(AT91_CKGR_PLLBR);
+ mulb = ((reg >> 16) & 0x7FF) + 1;
+ divb = reg & 0xFF;
+ usbdiv = (reg >> 28) & 0x3;
+
+ reg = at91_sys_read(AT91_PMC_MCKR);
+ mdiv = (reg >> 8) & 3;
+ pres = (reg >> 2) & 7;
+
+#ifdef USE_CALCULATED_CRYSTAL_FREQ
+ reg = at91_sys_read(AT91_CKGR_MCFR);
+ val = (reg & 0xFFFF) * AT91_SLOW_CLOCK / 16;
+#else
+ crystal = PM9261_CRYSTAL;
+#endif
+
+ printf ("Board : Ronetix PM9261\n");
+ printf ("Crystal frequency: %8s MHz\n", strmhz(buf,crystal));
+
+ val = (crystal * mula) / diva;
+ printf ("CPU clock : %8s MHz\n", strmhz(buf, val));
+
+ val /= (1 << pres);
+ val /= (1 << mdiv);
+ printf ("Master clock : %8s MHz\n", strmhz(buf, val));
+
+ val = (crystal * mulb) / divb;
+ val /= (1 << usbdiv);
+ printf ("USB clock : %8s MHz\n", strmhz(buf, val) );
+
+ printf ("\n");
+ return 0;
+}
+#endif
diff --git a/board/ronetix/pm9261/pm9261_led.c b/board/ronetix/pm9261/pm9261_led.c
new file mode 100644
index 0000000..bf55512
--- /dev/null
+++ b/board/ronetix/pm9261/pm9261_led.c
@@ -0,0 +1,79 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stelian Pop <stelian.pop(a)leadtechdesign.com>
+ * Lead Tech Design <www.leadtechdesign.com>
+ * Ilko Iliev <www.ronetix.at>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/arch/at91sam9261.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/io.h>
+
+#define RED_LED AT91_PIN_PC12
+#define GREEN_LED AT91_PIN_PC13
+#define YELLOW_LED AT91_PIN_PC15
+
+void red_LED_on(void)
+{
+ at91_set_gpio_value(RED_LED, 1);
+}
+
+void red_LED_off(void)
+{
+ at91_set_gpio_value(RED_LED, 0);
+}
+
+void green_LED_on(void)
+{
+ at91_set_gpio_value(GREEN_LED, 0);
+}
+
+void green_LED_off(void)
+{
+ at91_set_gpio_value(GREEN_LED, 1);
+}
+
+void yellow_LED_on(void)
+{
+ at91_set_gpio_value(YELLOW_LED, 0);
+}
+
+void yellow_LED_off(void)
+{
+ at91_set_gpio_value(YELLOW_LED, 1);
+}
+
+
+void coloured_LED_init(void)
+{
+ /* Enable clock */
+ at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9261_ID_PIOC);
+
+ at91_set_gpio_output(RED_LED, 1);
+ at91_set_gpio_output(GREEN_LED, 1);
+ at91_set_gpio_output(YELLOW_LED, 1);
+
+ at91_set_gpio_value(RED_LED, 0);
+ at91_set_gpio_value(GREEN_LED, 1);
+ at91_set_gpio_value(YELLOW_LED, 1);
+}
diff --git a/board/ronetix/pm9261/pm9261_lowlevel_init.S b/board/ronetix/pm9261/pm9261_lowlevel_init.S
new file mode 100644
index 0000000..619844b
--- /dev/null
+++ b/board/ronetix/pm9261/pm9261_lowlevel_init.S
@@ -0,0 +1,368 @@
+/*
+ * Memory Setup stuff - taken from blob memsetup.S
+ *
+ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw(a)its.tudelft.nl) and
+ * Jan-Derk Bakker (J.D.Bakker(a)its.tudelft.nl)
+ *
+ * Modified for the Ronetix PM9261 board
+ * (C) Copyright 2008 Ronetix GmbH
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <version.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_pio.h>
+
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+
+#define SDRAM 0x20000000 /* address of the SDRAM */
+
+/* clocks */
+#define MOR_VAL 0x00002001 /* CKGR_MOR - enable main osc. */
+#define PLLAR_VAL (0x2000B000 | ((MASTER_PLL_MUL - 1)<< 16) | (MASTER_PLL_DIV))
+/* #define PLLAR_VAL 0x200CBF01 */ /* 239.616000 MHz for PCK */
+#define PLLBR_VAL 0x10483E0E /* 48.054857 MHz for USB) */
+
+#define MCKR_VAL 0x00000102 /* PCK/2 = MCK Master Clock from PLLA*/
+
+#define AT91_WDTC_WDMR 0xFFFFFD44 /* (WDTC) Watchdog Mode Register */
+#define WDTC_WDMR_VAL 0x3fff8fff /* disable watchdog */
+#define PIOC_PDR_VAL1 0xFFFF0000 /* define PDC[31:16] as DATA[31:16] */
+#define PIOC_PPUDR_VAL 0xFFFF0000 /* no pull-up for D[31:16] */
+#define MATRIX_EBICSA_VAL 0x10A /* EBI_CSA, no pull-ups for D[15:0],
+ CS1 SDRAM, CS3 NAND Flash */
+
+#define AT91_PIOC_PDR (AT91_BASE_SYS + AT91_PIOC + PIO_PDR)
+#define AT91_PIOC_PPUDR (AT91_BASE_SYS + AT91_PIOC + PIO_PUDR)
+#define AT91_PIOC_ASR (AT91_BASE_SYS + AT91_PIOC + PIO_ASR)
+#define AT91_PIOC_BSR (AT91_BASE_SYS + AT91_PIOC + PIO_BSR)
+#define AT91_PIOC_PER (AT91_BASE_SYS + AT91_PIOC + PIO_PER)
+#define AT91_PIOC_OER (AT91_BASE_SYS + AT91_PIOC + PIO_OER)
+#define AT91_PIOC_SODR (AT91_BASE_SYS + AT91_PIOC + PIO_SODR)
+#define AT91_MATRIX_EBICSA (0xFFFFEE30)
+
+#define AT91_SMC_CTRL0 (0xFFFFEC0C) /* (SMC) Control Register for CS 0 */
+#define AT91_SMC_CYCLE0 (0xFFFFEC08) /* (SMC) Cycle Register for CS 0 */
+#define AT91_SMC_SETUP0 (0xFFFFEC00) /* (SMC) Setup Register for CS 0 */
+#define AT91_SMC_PULSE0 (0xFFFFEC04) /* (SMC) Pulse Register for CS 0 */
+
+#define AT91_SMC_CTRL3 (0xFFFFEC3C) /* (SMC) Control Register for CS 0 */
+#define AT91_SMC_CYCLE3 (0xFFFFEC38) /* (SMC) Cycle Register for CS 0 */
+#define AT91_SMC_SETUP3 (0xFFFFEC30) /* (SMC) Setup Register for CS 0 */
+#define AT91_SMC_PULSE3 (0xFFFFEC34) /* (SMC) Pulse Register for CS 0 */
+
+#define AT91_SDRAMC_CR (0xFFFFEA08) /* (SDRAMC0) SDRAM Configuration Reg.*/
+#define AT91_SDRAMC_MR (0xFFFFEA00) /* (SDRAMC0) SDRAM Mode Register */
+#define AT91_SDRAMC_MDR (0xFFFFEA24) /* (SDRAMC0) SDRAM Memory Device Reg.*/
+#define AT91_SDRAMC_TR (0xFFFFEA04) /* (SDRAMC0) SDRAM Refresh Timer Reg.*/
+
+#define AT91_RSTC_RMR (0xFFFFFD08) /* (RSTC) Reset Mode Register */
+
+/* SDRAM */
+#define SDRC_MR_VAL1 0 /* SDRAMC_MR Mode register */
+#define SDRC_TR_VAL1 0x13C /* SDRAMC_TR - Refresh Timer register*/
+#define SDRC_CR_VAL 0x85237279 /* SDRAMC_CR - Configuration register*/
+#define SDRC_MDR_VAL 0 /* Memory Device Register -> SDRAM */
+#define SDRC_MR_VAL2 0x00000002 /* SDRAMC_MR */
+#define SDRAM_VAL1 0 /* SDRAM_BASE */
+#define SDRC_MR_VAL3 4 /* SDRC_MR */
+#define SDRAM_VAL2 0 /* SDRAM_BASE */
+#define SDRAM_VAL3 0 /* SDRAM_BASE */
+#define SDRAM_VAL4 0 /* SDRAM_BASE */
+#define SDRAM_VAL5 0 /* SDRAM_BASE */
+#define SDRAM_VAL6 0 /* SDRAM_BASE */
+#define SDRAM_VAL7 0 /* SDRAM_BASE */
+#define SDRAM_VAL8 0 /* SDRAM_BASE */
+#define SDRAM_VAL9 0 /* SDRAM_BASE */
+#define SDRC_MR_VAL4 3 /* SDRC_MR */
+#define SDRAM_VAL10 0 /* SDRAM_BASE */
+#define SDRC_MR_VAL5 0 /* SDRC_MR */
+#define SDRAM_VAL11 0 /* SDRAM_BASE */
+#define SDRC_TR_VAL2 1200 /* SDRAM_TR */
+#define SDRAM_VAL12 0 /* SDRAM_BASE */
+
+/* setup CS0 (NOR Flash) - 16-bit, 15 WS */
+#define SMC_SETUP0_VAL 0x0A0A0A0A /* SMC_SETUP */
+#define SMC_PULSE0_VAL 0x0B0B0B0B /* SMC_PULSE */
+#define SMC_CYCLE0_VAL 0x00160016 /* SMC_CYCLE */
+#define SMC_CTRL0_VAL 0x00161003 /* SMC_MODE */
+
+/* setup CS3 (NAND Flash) - 16-bit */
+#define SMC_SETUP3_VAL 0x03030303 /* SMC_SETUP */
+#define SMC_PULSE3_VAL 0x04040404 /* SMC_PULSE */
+#define SMC_CYCLE3_VAL 0x00080008 /* SMC_CYCLE */
+#define SMC_CTRL3_VAL 0x00161003 /* SMC_MODE */
+
+/* NAND FLash: configure PIOs in periph mode */
+#define PIOC_ASR_VAL 3 /* PIOC->ASR <- PC0 | PC1 */
+#define PIOC_BSR_VAL 0 /* PIOC->BSR */
+#define PIOC_PDR_VAL2 3 /* PIOC->PDR <- PC0 | PC1 */
+#define PIOC_PER_VAL 0x4000
+#define PIOC_OER_VAL 0x4000 /* PIOC->PER <- PC14 */
+#define PIOC_SODR_VAL 0x4000 /* PIOC->SODR, set PC14 to '1' */
+
+#define RSTC_RMR_VAL 0xA5000301 /* user reset enable */
+
+_TEXT_BASE:
+ .word TEXT_BASE
+
+.globl lowlevel_init
+lowlevel_init:
+
+ mov r5, pc /* r5 = POS1 + 4 current */
+POS1:
+ ldr r0, =POS1 /* r0 = POS1 compile */
+ ldr r2, _TEXT_BASE
+ sub r0, r0, r2 /* r0 = POS1-_TEXT_BASE (POS1 relative) */
+ sub r5, r5, r0 /* r0 = TEXT_BASE-1 */
+ sub r5, r5, #4 /* r1 = text base - current */
+
+ /* memory control configuration 1 */
+ ldr r0, =SMRDATA
+ ldr r2, =SMRDATA1
+ ldr r1, _TEXT_BASE
+ sub r0, r0, r1
+ sub r2, r2, r1
+ add r0, r0, r5
+ add r2, r2, r5
+0:
+ /* the address */
+ ldr r1, [r0], #4
+ /* the value */
+ ldr r3, [r0], #4
+ str r3, [r1]
+ cmp r2, r0
+ bne 0b
+
+/*-----------------------------------------------------------------------------
+;PMC Init Step 1.
+;------------------------------------------------------------------------------
+;- Check if the PLL is already initialized
+;----------------------------------------------------------------------------*/
+ ldr r1, =(AT91_BASE_SYS + AT91_PMC_MCKR)
+ ldr r0, [r1]
+ and r0, r0, #3
+ cmp r0, #0
+ bne setup_PLLB
+
+/*;---------------------------------------------------------------------------
+;- Enable the Main Oscillator
+;----------------------------------------------------------------------------*/
+ ldr r1, =(AT91_BASE_SYS + AT91_CKGR_MOR)
+ ldr r2, =(AT91_BASE_SYS + AT91_PMC_SR)
+ /* Main oscillator Enable register PMC_MOR: */
+ /* Enable main oscillator, OSCOUNT = 0xFF */
+ ldr r0, =0x0000FF01
+ str r0, [r1]
+
+ /* Reading the PMC Status to detect when the Main Oscillator is enabled */
+ mov r4, #AT91_PMC_MOSCS
+MOSCS_Loop:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_MOSCS
+ bne MOSCS_Loop
+
+/*-----------------------------------------------------------------------------
+;PMC Init Step 2.
+;------------------------------------------------------------------------------
+;- Setup PLLA
+;----------------------------------------------------------------------------*/
+ ldr r1, =(AT91_BASE_SYS + AT91_CKGR_PLLAR)
+ /* (18.432MHz/1)*13 = 239 MHz */
+ ldr r0, =PLLAR_VAL
+ str r0, [r1]
+
+ /* Reading the PMC Status register to detect when the PLLA is locked */
+ mov r4, #AT91_PMC_LOCKA
+MOSCS_Loop1:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_LOCKA
+ bne MOSCS_Loop1
+
+/*-----------------------------------------------------------------------------
+;PMC Init Step 3.
+;------------------------------------------------------------------------------
+;- Switch on the Main Oscillator 18.432 MHz
+;----------------------------------------------------------------------------*/
+ ldr r1, =(AT91_BASE_SYS + AT91_PMC_MCKR)
+
+ /* -Master Clock Controller register PMC_MCKR */
+ ldr r0, =0x102
+ str r0, [r1]
+
+ /* Reading the PMC Status to detect when the Master clock is ready */
+ mov r4, #AT91_PMC_MCKRDY
+MCKRDY_Loop:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_MCKRDY
+ bne MCKRDY_Loop
+
+/*-----------------------------------------------------------------------------
+;PMC Init Step 4.
+;------------------------------------------------------------------------------
+;- Setup PLLB
+;----------------------------------------------------------------------------*/
+setup_PLLB:
+ ldr r2, =(AT91_BASE_SYS + AT91_PMC_SR)
+ mov r4, #AT91_PMC_LOCKB
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_LOCKB
+ beq PLL_setup_end
+
+ ldr r1, =(AT91_BASE_SYS + AT91_CKGR_PLLBR)
+ /* 48.054857 MHz =18432000*72/14/2 for USB) */
+ ldr r0, =PLLBR_VAL
+ str r0, [r1]
+
+ /* Reading the PMC Status register to detect when the PLLB is locked */
+ mov r4, #AT91_PMC_LOCKB
+MOSCS_Loop2:
+ ldr r3, [r2]
+ and r3, r4, r3
+ cmp r3, #AT91_PMC_LOCKB
+ bne MOSCS_Loop2
+
+PLL_setup_end:
+
+ /* memory control configuration 2 */
+ ldr r0, =AT91_SDRAMC_TR
+ ldr r1, [r0]
+ cmp r1, #0
+ bne SDRAM_setup_end
+
+ ldr r0, =SMRDATA1
+ ldr r2, =SMRDATA2
+ ldr r1, _TEXT_BASE
+ sub r0, r0, r1
+ sub r2, r2, r1
+ add r0, r0, r5
+ add r2, r2, r5
+
+2:
+ /* the address */
+ ldr r1, [r0], #4
+ /* the value */
+ ldr r3, [r0], #4
+ str r3, [r1]
+ cmp r2, r0
+ bne 2b
+
+SDRAM_setup_end:
+ /* everything is fine now */
+ mov pc, lr
+
+ .ltorg
+
+SMRDATA:
+ .word AT91_WDTC_WDMR
+ .word WDTC_WDMR_VAL
+ .word AT91_PIOC_PDR
+ .word PIOC_PDR_VAL1
+ .word AT91_PIOC_PPUDR
+ .word PIOC_PPUDR_VAL
+ .word AT91_MATRIX_EBICSA
+ .word MATRIX_EBICSA_VAL
+
+ .word AT91_SMC_SETUP0
+ .word SMC_SETUP0_VAL
+ .word AT91_SMC_PULSE0
+ .word SMC_PULSE0_VAL
+ .word AT91_SMC_CYCLE0
+ .word SMC_CYCLE0_VAL
+ .word AT91_SMC_CTRL0
+ .word SMC_CTRL0_VAL
+ .word AT91_SMC_SETUP3
+ .word SMC_SETUP3_VAL
+ .word AT91_SMC_PULSE3
+ .word SMC_PULSE3_VAL
+ .word AT91_SMC_CYCLE3
+ .word SMC_CYCLE3_VAL
+ .word AT91_SMC_CTRL3
+ .word SMC_CTRL3_VAL
+
+ .word AT91_PIOC_ASR
+ .word PIOC_ASR_VAL
+ .word AT91_PIOC_BSR
+ .word PIOC_BSR_VAL
+ .word AT91_PIOC_PDR
+ .word PIOC_PDR_VAL2
+ .word AT91_PIOC_PER
+ .word PIOC_PER_VAL
+ .word AT91_PIOC_OER
+ .word PIOC_OER_VAL
+ .word AT91_PIOC_SODR
+ .word PIOC_SODR_VAL
+
+SMRDATA1:
+ .word AT91_SDRAMC_MR
+ .word SDRC_MR_VAL1
+ .word AT91_SDRAMC_TR
+ .word SDRC_TR_VAL1
+ .word AT91_SDRAMC_CR
+ .word SDRC_CR_VAL
+ .word AT91_SDRAMC_MDR
+ .word SDRC_MDR_VAL
+ .word AT91_SDRAMC_MR
+ .word SDRC_MR_VAL2
+ .word SDRAM
+ .word SDRAM_VAL1
+ .word AT91_SDRAMC_MR
+ .word SDRC_MR_VAL3
+ .word SDRAM
+ .word SDRAM_VAL2
+ .word SDRAM
+ .word SDRAM_VAL3
+ .word SDRAM
+ .word SDRAM_VAL4
+ .word SDRAM
+ .word SDRAM_VAL5
+ .word SDRAM
+ .word SDRAM_VAL6
+ .word SDRAM
+ .word SDRAM_VAL7
+ .word SDRAM
+ .word SDRAM_VAL8
+ .word SDRAM
+ .word SDRAM_VAL9
+ .word AT91_SDRAMC_MR
+ .word SDRC_MR_VAL4
+ .word SDRAM
+ .word SDRAM_VAL10
+ .word AT91_SDRAMC_MR
+ .word SDRC_MR_VAL5
+ .word SDRAM
+ .word SDRAM_VAL11
+ .word AT91_SDRAMC_TR
+ .word SDRC_TR_VAL2
+ .word SDRAM
+ .word SDRAM_VAL12
+ .word AT91_RSTC_RMR
+ .word RSTC_RMR_VAL
+
+SMRDATA2:
+ .word 0
+
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
diff --git a/board/ronetix/pm9261/pm9261_nand.c b/board/ronetix/pm9261/pm9261_nand.c
new file mode 100644
index 0000000..9c609f0
--- /dev/null
+++ b/board/ronetix/pm9261/pm9261_nand.c
@@ -0,0 +1,79 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stelian Pop <stelian.pop(a)leadtechdesign.com>
+ * Lead Tech Design <www.leadtechdesign.com>
+ * Ilko Iliev <www.ronetix.at>
+ *
+ * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/arch/at91sam9261.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91_pio.h>
+
+#include <nand.h>
+
+/*
+ * hardware specific access to control-lines
+ */
+#define MASK_ALE (1 << 22) /* our ALE is AD22 */
+#define MASK_CLE (1 << 21) /* our CLE is AD21 */
+
+static void pm9261_nand_hwcontrol(struct mtd_info *mtd,
+ int cmd, unsigned int ctrl)
+{
+ struct nand_chip *this = mtd->priv;
+
+ if (ctrl & NAND_CTRL_CHANGE) {
+ ulong IO_ADDR_W = (ulong) this->IO_ADDR_W;
+ IO_ADDR_W &= ~(MASK_ALE | MASK_CLE);
+
+ if (ctrl & NAND_CLE)
+ IO_ADDR_W |= MASK_CLE;
+ if (ctrl & NAND_ALE)
+ IO_ADDR_W |= MASK_ALE;
+
+ at91_set_gpio_value(AT91_PIN_PC14, !(ctrl & NAND_NCE));
+ this->IO_ADDR_W = (void *) IO_ADDR_W;
+ }
+
+ if (cmd != NAND_CMD_NONE)
+ writeb(cmd, this->IO_ADDR_W);
+}
+
+static int pm9261_nand_ready(struct mtd_info *mtd)
+{
+ return at91_get_gpio_value(AT91_PIN_PA16);
+}
+
+int board_nand_init(struct nand_chip *nand)
+{
+ nand->ecc.mode = NAND_ECC_SOFT;
+#ifdef CFG_NAND_DBW_16
+ nand->options = NAND_BUSWIDTH_16;
+#endif
+ nand->cmd_ctrl = pm9261_nand_hwcontrol;
+ nand->dev_ready = pm9261_nand_ready;
+ nand->chip_delay = 20;
+
+ return 0;
+}
diff --git a/board/ronetix/pm9261/pm9261_partition.c b/board/ronetix/pm9261/pm9261_partition.c
new file mode 100644
index 0000000..95ac398
--- /dev/null
+++ b/board/ronetix/pm9261/pm9261_partition.c
@@ -0,0 +1,47 @@
+/*
+ * (C) Copyright 2008
+ * Ulf Samuelsson <ulf(a)atmel.com>
+ * Ilko Iliev <www.ronetix.at>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+#include <common.h>
+#include <config.h>
+#include <asm/hardware.h>
+#include <dataflash.h>
+
+AT91S_DATAFLASH_INFO dataflash_info[CONFIG_SYS_MAX_DATAFLASH_BANKS];
+
+struct dataflash_addr cs[CONFIG_SYS_MAX_DATAFLASH_BANKS] = {
+ {CONFIG_SYS_DATAFLASH_LOGIC_ADDR_CS0, 0}, /* Logical adress, CS */
+};
+
+/*define the area offsets*/
+#ifdef CONFIG_SYS_USE_DATAFLASH
+dataflash_protect_t area_list[NB_DATAFLASH_AREA] = {
+ {0x00000000, 0x000041FF, FLAG_PROTECT_SET, 0, "Bootstrap"},
+ {0x00004200, 0x000083FF, FLAG_PROTECT_CLEAR, 0, "Environment"},
+ {0x00008400, 0x00041FFF, FLAG_PROTECT_SET, 0, "U-Boot"},
+ {0x00042000, 0x00251FFF, FLAG_PROTECT_CLEAR, 0, "Kernel"},
+ {0x00252000, 0xFFFFFFFF, FLAG_PROTECT_CLEAR, 0, "FS"},
+};
+#else
+dataflash_protect_t area_list[NB_DATAFLASH_AREA] = {
+ {0x00000000, 0xFFFFFFFF, FLAG_PROTECT_CLEAR, 0, ""},
+};
+
+#endif
diff --git a/include/configs/pm9261.h b/include/configs/pm9261.h
new file mode 100644
index 0000000..4c75caa
--- /dev/null
+++ b/include/configs/pm9261.h
@@ -0,0 +1,266 @@
+/*
+ * (C) Copyright 2007-2008
+ * Stelian Pop <stelian.pop(a)leadtechdesign.com>
+ * Lead Tech Design <www.leadtechdesign.com>
+ * Ilko Iliev <www.ronetix.at>
+ *
+ * Configuation settings for the RONETIX PM9261 board.
+ *
+ * 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
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/* ARM asynchronous clock */
+#define AT91_CPU_NAME "AT91SAM9261"
+
+#define CONFIG_DISPLAY_BOARDINFO
+
+#define PM9261_CRYSTAL 18432000
+#define MASTER_PLL_DIV 15
+#define MASTER_PLL_MUL 162
+#define MAIN_PLL_DIV 2
+
+#define AT91_MAIN_CLOCK (PM9261_CRYSTAL / MASTER_PLL_DIV * MASTER_PLL_MUL)
+#define AT91_MASTER_CLOCK (AT91_MAIN_CLOCK / MAIN_PLL_DIV)
+#define CONFIG_SYS_HZ 1000000 /* 1us resolution */
+
+#define AT91_SLOW_CLOCK 32768 /* slow clock */
+
+#define CONFIG_ARM926EJS 1 /* This is an ARM926EJS Core */
+#define CONFIG_AT91SAM9261 1 /* It's an Atmel AT91SAM9261 SoC*/
+#define CONFIG_PM9261 1 /* on a Ronetix PM9261 Board */
+#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */
+
+#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS 1
+#define CONFIG_INITRD_TAG 1
+
+#undef CONFIG_SKIP_LOWLEVEL_INIT
+#undef CONFIG_SKIP_RELOCATE_UBOOT
+
+/*
+ * Hardware drivers
+ */
+#define CONFIG_ATMEL_USART 1
+#undef CONFIG_USART0
+#undef CONFIG_USART1
+#undef CONFIG_USART2
+#define CONFIG_USART3 1 /* USART 3 is DBGU */
+
+/* LCD */
+#define CONFIG_LCD 1
+#define LCD_BPP LCD_COLOR8
+#define CONFIG_LCD_LOGO 1
+#undef LCD_TEST_PATTERN
+#define CONFIG_LCD_INFO 1
+#define CONFIG_LCD_INFO_BELOW_LOGO 1
+#define CONFIG_SYS_WHITE_ON_BLACK 1
+#define CONFIG_ATMEL_LCD 1
+#define CONFIG_ATMEL_LCD_BGR555 1
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV 1
+
+#define CONFIG_BOOTDELAY 3
+
+/*
+ * BOOTP options
+ */
+#define CONFIG_BOOTP_BOOTFILESIZE 1
+#define CONFIG_BOOTP_BOOTPATH 1
+#define CONFIG_BOOTP_GATEWAY 1
+#define CONFIG_BOOTP_HOSTNAME 1
+
+/*
+ * Command line configuration.
+ */
+#include <config_cmd_default.h>
+#undef CONFIG_CMD_BDI
+#undef CONFIG_CMD_IMI
+#undef CONFIG_CMD_AUTOSCRIPT
+#undef CONFIG_CMD_FPGA
+#undef CONFIG_CMD_LOADS
+#undef CONFIG_CMD_IMLS
+
+#define CONFIG_CMD_PING 1
+#define CONFIG_CMD_DHCP 1
+#define CONFIG_CMD_NAND 1
+#define CONFIG_CMD_USB 1
+
+/* SDRAM */
+#define CONFIG_NR_DRAM_BANKS 1
+#define PHYS_SDRAM 0x20000000
+#define PHYS_SDRAM_SIZE 0x04000000 /* 64 megs */
+
+/* DataFlash */
+#define CONFIG_HAS_DATAFLASH 1
+#define CONFIG_SYS_SPI_WRITE_TOUT (5*CONFIG_SYS_HZ)
+#define CONFIG_SYS_MAX_DATAFLASH_BANKS 1
+#define CONFIG_SYS_DATAFLASH_LOGIC_ADDR_CS0 0xC0000000 /* CS0 */
+#define CONFIG_SYS_DATAFLASH_LOGIC_ADDR_CS3 0xD0000000 /* CS3 */
+#define AT91_SPI_CLK 15000000
+#define DATAFLASH_TCSS (0x1a << 16)
+#define DATAFLASH_TCHS (0x1 << 24)
+
+/* NAND flash */
+#define NAND_MAX_CHIPS 1
+#define CONFIG_SYS_MAX_NAND_DEVICE 1
+#define CONFIG_SYS_NAND_BASE 0x40000000
+#define CONFIG_SYS_NAND_DBW_8 1
+#undef CONFIG_SYS_NAND_DBW_16
+
+/* NOR flash */
+#define CONFIG_SYS_FLASH_CFI 1
+#define CONFIG_FLASH_CFI_DRIVER 1
+#define PHYS_FLASH_1 0x10000000
+#define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1
+#define CONFIG_SYS_MAX_FLASH_SECT 256
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+
+/* Ethernet */
+#define CONFIG_DRIVER_DM9000 1
+#define CONFIG_DM9000_BASE 0x30000000
+#define DM9000_IO CONFIG_DM9000_BASE
+#define DM9000_DATA (CONFIG_DM9000_BASE + 4)
+#define CONFIG_DM9000_USE_16BIT 1
+#define CONFIG_NET_RETRY_COUNT 20
+#define CONFIG_RESET_PHY_R 1
+
+/* USB */
+#define CONFIG_USB_OHCI_NEW 1
+#define LITTLEENDIAN 1
+#define CONFIG_DOS_PARTITION 1
+#define CONFIG_SYS_USB_OHCI_CPU_INIT 1
+#define CONFIG_SYS_USB_OHCI_REGS_BASE 0x00500000 /* AT91SAM9261_UHP_BASE */
+#define CONFIG_SYS_USB_OHCI_SLOT_NAME "at91sam9261"
+#define CONFIG_SYS_USB_OHCI_MAX_ROOT_PORTS 2
+#define CONFIG_USB_STORAGE 1
+
+#define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */
+
+#define CONFIG_SYS_MEMTEST_START PHYS_SDRAM
+#define CONFIG_SYS_MEMTEST_END 0x23e00000
+
+#undef CONFIG_SYS_USE_DATAFLASH_CS0
+#undef CONFIG_SYS_USE_NANDFLASH
+#define CONFIG_SYS_USE_FLASH 1
+
+#ifdef CONFIG_SYS_USE_DATAFLASH_CS0
+
+/* bootstrap + u-boot + env + linux in dataflash on CS0 */
+#define CONFIG_ENV_IS_IN_DATAFLASH 1
+#define CONFIG_SYS_MONITOR_BASE (CONFIG_SYS_DATAFLASH_LOGIC_ADDR_CS0 + 0x8400)
+#define CONFIG_ENV_OFFSET 0x4200
+#define CONFIG_ENV_ADDR (CONFIG_SYS_DATAFLASH_LOGIC_ADDR_CS0 + CONFIG_ENV_OFFSET)
+#define CONFIG_ENV_SIZE 0x4200
+#define CONFIG_BOOTCOMMAND "cp.b 0xC0042000 0x22000000 0x210000; bootm"
+#define CONFIG_BOOTARGS "console=ttyS0,115200 " \
+ "root=/dev/mtdblock0 " \
+ "mtdparts=at91_nand:-(root) " \
+ "rw rootfstype=jffs2"
+
+#elif defined(CONFIG_SYS_USE_NANDFLASH) /* CONFIG_SYS_USE_NANDFLASH */
+
+/* bootstrap + u-boot + env + linux in nandflash */
+#define CONFIG_ENV_IS_IN_NAND 1
+#define CONFIG_ENV_OFFSET 0x60000
+#define CONFIG_ENV_OFFSET_REDUND 0x80000
+#define CONFIG_ENV_SIZE 0x20000 /* 1 sector = 128 kB */
+#define CONFIG_BOOTCOMMAND "nand read 0x22000000 0xA0000 0x200000; bootm"
+#define CONFIG_BOOTARGS "console=ttyS0,115200 " \
+ "root=/dev/mtdblock5 " \
+ "mtdparts=at91_nand:128k(bootstrap)ro," \
+ "256k(uboot)ro,128k(env1)ro," \
+ "128k(env2)ro,2M(linux),-(root) " \
+ "rw rootfstype=jffs2"
+
+#elif defined (CONFIG_SYS_USE_FLASH)
+
+#define CONFIG_ENV_IS_IN_FLASH 1
+#define CONFIG_ENV_OFFSET 0x40000
+#define CONFIG_ENV_SECT_SIZE 0x10000
+#define CONFIG_ENV_SIZE 0x10000
+#define CONFIG_ENV_OVERWRITE 1
+
+/* JFFS Partition offset set */
+#define CONFIG_SYS_JFFS2_FIRST_BANK 0
+#define CONFIG_SYS_JFFS2_NUM_BANKS 1
+
+/* 512k reserved for u-boot */
+#define CONFIG_SYS_JFFS2_FIRST_SECTOR 11
+
+#define CONFIG_BOOTCOMMAND "run flashboot"
+
+#define MTDIDS_DEFAULT "nor0=physmap-flash.0,nand0=nand"
+#define MTDPARTS_DEFAULT \
+ "mtdparts=physmap-flash.0:" \
+ "256k(u-boot)ro," \
+ "64k(u-boot-env)ro," \
+ "1408k(kernel)," \
+ "-(rootfs);" \
+ "nand:-(nand)"
+
+#define CONFIG_CON_ROT "fbcon=rotate:3 "
+#define CONFIG_BOOTARGS "root=/dev/mtdblock4 rootfstype=jffs2 " CONFIG_CON_ROT
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+ "mtdids=" MTDIDS_DEFAULT "\0" \
+ "mtdparts=" MTDPARTS_DEFAULT "\0" \
+ "partition=nand0,0\0" \
+ "ramargs=setenv bootargs $(bootargs) $(mtdparts)\0" \
+ "nfsargs=setenv bootargs root=/dev/nfs rw " \
+ CONFIG_CON_ROT \
+ "nfsroot=$(serverip):$(rootpath) $(mtdparts)\0" \
+ "addip=setenv bootargs $(bootargs) " \
+ "ip=$(ipaddr):$(serverip):$(gatewayip):$(netmask)"\
+ ":$(hostname):eth0:off\0" \
+ "ramboot=tftpboot 0x22000000 vmImage;" \
+ "run ramargs;run addip;bootm 22000000\0" \
+ "nfsboot=tftpboot 0x22000000 vmImage;" \
+ "run nfsargs;run addip;bootm 22000000\0" \
+ "flashboot=run ramargs;run addip;bootm 0x10050000\0" \
+ ""
+#else
+#error "Undefined memory device"
+#endif
+
+#define CONFIG_BAUDRATE 115200
+#define CONFIG_SYS_BAUDRATE_TABLE {115200 , 19200, 38400, 57600, 9600 }
+
+#define CONFIG_SYS_PROMPT "u-boot-pm9261> "
+#define CONFIG_SYS_CBSIZE 256
+#define CONFIG_SYS_MAXARGS 16
+#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_LONGHELP 1
+#define CONFIG_CMDLINE_EDITING 1
+
+#define ROUND(A, B) (((A) + (B)) & ~((B) - 1))
+/*
+ * Size of malloc() pool
+ */
+#define CONFIG_SYS_MALLOC_LEN ROUND(3 * CONFIG_ENV_SIZE + 128*1024, 0x1000)
+#define CONFIG_SYS_GBL_DATA_SIZE 128 /* 128 bytes for initial data */
+
+#define CONFIG_STACKSIZE (32*1024) /* regular stack */
+
+#ifdef CONFIG_USE_IRQ
+#error CONFIG_USE_IRQ not supported
+#endif
+
+#endif
--
1.5.2.2
2
1

[U-Boot] [PATCH] [ARM] Move machine specific code to board at s3c64xx (v2)
by Kyungmin Park 02 Apr '09
by Kyungmin Park 02 Apr '09
02 Apr '09
Move machine specific code to smdk6400.
Some board use OneNAND instead of NAND.
Some register MP0_CS_CFG[5:0] are controled by both h/w and s/w.
So it's better to use macro instead of hard-coded value.
Signed-off-by: Kyungmin Park <kyungmin.park(a)samsung.com>
---
diff --git a/board/samsung/smdk6400/lowlevel_init.S b/board/samsung/smdk6400/lowlevel_init.S
index e0119a7..47f72f6 100644
--- a/board/samsung/smdk6400/lowlevel_init.S
+++ b/board/samsung/smdk6400/lowlevel_init.S
@@ -104,6 +104,13 @@ lowlevel_init:
bl nand_asm_init
#endif
+ /* Memory subsystem address 0x7e00f120 */
+ ldr r0, =ELFIN_MEM_SYS_CFG
+
+ /* Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1 */
+ mov r1, #S3C64XX_MEM_SYS_CFG_NAND
+ str r1, [r0]
+
bl mem_ctrl_asm_init
/* Wakeup support. Don't know if it's going to be used, untested. */
diff --git a/cpu/arm1176/s3c64xx/cpu_init.S b/cpu/arm1176/s3c64xx/cpu_init.S
index 08bda99..32bb467 100644
--- a/cpu/arm1176/s3c64xx/cpu_init.S
+++ b/cpu/arm1176/s3c64xx/cpu_init.S
@@ -28,13 +28,6 @@
.globl mem_ctrl_asm_init
mem_ctrl_asm_init:
- /* Memory subsystem address 0x7e00f120 */
- ldr r0, =ELFIN_MEM_SYS_CFG
-
- /* Xm0CSn2 = NFCON CS0, Xm0CSn3 = NFCON CS1 */
- mov r1, #0xd
- str r1, [r0]
-
/* DMC1 base address 0x7e001000 */
ldr r0, =ELFIN_DMC1_BASE
diff --git a/include/s3c6400.h b/include/s3c6400.h
index fd3e99b..d3f136d 100644
--- a/include/s3c6400.h
+++ b/include/s3c6400.h
@@ -380,6 +380,11 @@
*/
#define ELFIN_MEM_SYS_CFG 0x7e00f120
+#define S3C64XX_MEM_SYS_CFG_16BIT (1 << 12)
+
+#define S3C64XX_MEM_SYS_CFG_NAND 0x0008
+#define S3C64XX_MEM_SYS_CFG_ONENAND S3C64XX_MEM_SYS_CFG_16BIT
+
#define GPACON (ELFIN_GPIO_BASE + GPACON_OFFSET)
#define GPADAT (ELFIN_GPIO_BASE + GPADAT_OFFSET)
#define GPAPUD (ELFIN_GPIO_BASE + GPAPUD_OFFSET)
2
4

26 Mar '09
Add command for changing Flex-OneNAND SLC / MLC boundary.
Signed-off-by: Rohit Hagargundgi <h.rohit(a)samsung.com>
---
common/cmd_onenand.c | 65 +++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 56 insertions(+), 9 deletions(-)
diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
index 8d87b78..2caae45 100644
--- a/common/cmd_onenand.c
+++ b/common/cmd_onenand.c
@@ -21,8 +21,35 @@
extern struct mtd_info onenand_mtd;
extern struct onenand_chip onenand_chip;
+/**
+ * do_set_boundary - [Flex-OneNAND] Set boundary of Flex-OneNAND
+ * @param mtd mtd information structure
+ * @param die die of device for which boundary will be set
+ * @param bdry new boundary value ie last SLC block of die
+ *
+ * Set boundary of Flex-OneNAND
+ */
+int do_set_boundary(struct mtd_info *mtd, unsigned die, unsigned bdry, int lock)
+{
+ struct onenand_chip *this = mtd->priv;
+
+ if (!FLEXONENAND(this)) {
+ printf("Flex-OneNAND not found.\n");
+ return -1;
+ }
+
+ if (die >= this->dies) {
+ printf("Invalid die index\n");
+ return -1;
+ }
+
+ return flexonenand_set_boundary(mtd, die, bdry, lock);
+}
+
int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
+ struct mtd_info *mtd = &onenand_mtd;
+ struct onenand_chip *this = mtd->priv;
int ret = 0;
switch (argc) {
@@ -57,10 +84,11 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
start = simple_strtoul(argv[2], NULL, 10);
end = simple_strtoul(argv[3], NULL, 10);
- start >>= onenand_chip.erase_shift;
- end >>= onenand_chip.erase_shift;
+ start = onenand_get_block(this, start, NULL);
+ end = onenand_get_block(this, end, NULL);
/* Don't include the end block */
- end--;
+ if (end > 0)
+ end--;
}
if (!end || end < 0)
@@ -69,8 +97,13 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
printf("Erase block from %lu to %lu\n", start, end);
for (block = start; block <= end; block++) {
- instr.addr = block << onenand_chip.erase_shift;
- instr.len = 1 << onenand_chip.erase_shift;
+ instr.addr = onenand_get_addr(this, block);
+ if (mtd->numeraseregions > 1) {
+ int i = flexonenand_region(mtd, instr.addr);
+ instr.len = mtd->eraseregions[i].erasesize;
+ } else
+ instr.len = mtd->erasesize;
+
ret = onenand_erase(&onenand_mtd, &instr);
if (ret) {
printf("erase failed %lu\n", block);
@@ -134,15 +167,15 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
ops.mode = MTD_OOB_PLACE;
- ofs = block << onenand_chip.erase_shift;
+ ofs = onenand_get_addr(this, block);
if (page)
ofs += page << onenand_chip.page_shift;
if (!len) {
if (oob)
- ops.ooblen = 64;
+ ops.ooblen = FLEXONENAND(this) ? 128 : 64;
else
- ops.len = 512;
+ ops.len = FLEXONENAND(this) ? 4096 : 512;
}
if (oob) {
@@ -158,6 +191,18 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
return 0;
}
+ if (strncmp(argv[1], "setboundary", 11) == 0) {
+ unsigned die = simple_strtoul(argv[2], NULL, 0);
+ unsigned bdry = simple_strtoul(argv[3], NULL, 0);
+ int lock = 0;
+
+ if (argc == 5 && strncmp(argv[4], "LOCK", 4) == 0)
+ lock = 1;
+
+ do_set_boundary(mtd, die, bdry, lock);
+ return 0;
+ }
+
break;
}
@@ -172,5 +217,7 @@ U_BOOT_CMD(
"onenand write addr ofs len - write data at ofs with len from addr\n"
"onenand erase saddr eaddr - erase block start addr to end addr\n"
"onenand block[.oob] addr block [page] [len] - "
- "read data with (block [, page]) to addr"
+ "read data with (block [, page]) to addr\n"
+ "onenand setboundary DIE BOUNDARY [LOCK] - "
+ "Change SLC boundary of Flex-OneNAND\n"
);
--
1.5.4.3
3
8
From: Brad Bozarth <bflinux(a)yumbrad.com>
Signed-off-by: Brad Bozarth <bflinux(a)yumbrad.com>
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
---
drivers/mtd/spi/atmel.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/mtd/spi/atmel.c b/drivers/mtd/spi/atmel.c
index 10fcf0c..581b710 100644
--- a/drivers/mtd/spi/atmel.c
+++ b/drivers/mtd/spi/atmel.c
@@ -52,6 +52,14 @@ to_atmel_spi_flash(struct spi_flash *flash)
static const struct atmel_spi_flash_params atmel_spi_flash_table[] = {
{
+ .idcode1 = 0x27,
+ .l2_page_size = 9,
+ .pages_per_block = 8,
+ .blocks_per_sector = 32,
+ .nr_sectors = 32,
+ .name = "AT45DB321D",
+ },
+ {
.idcode1 = 0x28,
.l2_page_size = 10,
.pages_per_block = 8,
--
1.6.0.6
5
9
This patch adds support for MLC OneNAND and Flex-OneNAND devices.
The differences are like this.
OneNAND features:
1. 2KB page
2. 64 pages per block.
3. Upto 4 writes to a page allowed.
4. 1 ECC register
5. OOB read and OOB write commands present.
MLC OneNAND has following changes against OneNAND:
1. 4KB page - both datarams are needed for a read, so no read-while-load
2. Only 1 write per page.
3. OOB read and OOB write commands absent.
Flex-OneNAND has all changes as MLC OneNAND plus some more:
1. Can configure some blocks of a die as SLC and rest as MLC
This configuration is in the form of SLC boundary which
indicates last SLC block on the die.
2. SLC blocks have 64 pages per block (block size is 256KB).
MLC blocks have 128 pages per block (block size is 512KB).
3. A single device is registered for Flex-OneNAND. This device
has erase regions. Each erase region has different block
size (either SLC or MLC).
4. 4 ECC registers.
5. LSB page recovery feature.
Signed-off-by: Rohit Hagargundgi <h.rohit(a)samsung.com>
---
drivers/mtd/onenand/onenand_base.c | 711 ++++++++++++++++++++++++++++++-----
drivers/mtd/onenand/onenand_bbt.c | 13 +-
drivers/mtd/onenand/onenand_uboot.c | 4 +-
include/linux/mtd/onenand.h | 15 +
include/linux/mtd/onenand_regs.h | 18 +-
include/onenand_uboot.h | 10 +
6 files changed, 672 insertions(+), 99 deletions(-)
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 9b7bf3a..ebda48a 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -45,6 +45,14 @@ static const unsigned char ffchars[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 48 */
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 64 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 80 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 96 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 112 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 128 */
};
/**
@@ -83,9 +91,11 @@ static int onenand_block_address(int device, int block)
if (device & ONENAND_DEVICE_IS_DDP) {
/* Device Flash Core select, NAND Flash Block Address */
int dfs = 0, density, mask;
+ int flex = device & DEVICE_IS_FLEXONENAND;
density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
- mask = (1 << (density + 6));
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ mask = (1 << (density + (flex ? 4 : 6)));
if (block & mask)
dfs = 1;
@@ -109,9 +119,11 @@ static int onenand_bufferram_address(int device, int block)
if (device & ONENAND_DEVICE_IS_DDP) {
/* Device BufferRAM Select */
int dbs = 0, density, mask;
+ int flex = device & DEVICE_IS_FLEXONENAND;
density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
- mask = (1 << (density + 6));
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ mask = (1 << (density + (flex ? 4 : 6)));
if (block & mask)
dbs = 1;
@@ -169,6 +181,91 @@ static int onenand_buffer_address(int dataram1, int sectors, int count)
}
/**
+ * flexonenand_get_block- For given address return block number and if slc
+ * @param this - OneNAND device structure
+ * @param addr - Address for which block number is needed
+ * @return isblkslc - Block is an SLC block or not
+ */
+static unsigned flexonenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc)
+{
+ unsigned boundary, blk, die = 0;
+
+ if (addr >= this->diesize[0]) {
+ die = 1;
+ addr -= this->diesize[0];
+ }
+
+ boundary = this->boundary[die];
+
+ blk = addr >> (this->erase_shift - 1);
+ if (blk > boundary)
+ blk = (blk + boundary + 1) >> 1;
+
+ if (isblkslc)
+ *isblkslc = (blk <= boundary) ? 1 : 0;
+
+ blk += die ? this->density_mask : 0;
+ return blk;
+}
+
+inline unsigned onenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc)
+{
+ if (!FLEXONENAND(this))
+ return addr >> this->erase_shift;
+ return flexonenand_get_block(this, addr, isblkslc);
+}
+
+/**
+ * flexonenand_get_addr - Return address of the block
+ * @this: OneNAND device structure
+ * @block: Block number on Flex-OneNAND
+ *
+ * Return address of the block
+ */
+static loff_t flexonenand_get_addr(struct onenand_chip *this, int block)
+{
+ loff_t ofs = 0;
+ int die = 0, boundary;
+
+ if (this->dies == 2 && block >= this->density_mask) {
+ block -= this->density_mask;
+ die = 1;
+ ofs = this->diesize[0];
+ }
+
+ boundary = this->boundary[die];
+ ofs += block << (this->erase_shift - 1);
+ if (block > (boundary + 1))
+ ofs += (block - boundary - 1) << (this->erase_shift - 1);
+ return ofs;
+}
+
+inline loff_t onenand_get_addr(struct onenand_chip *this, int block)
+{
+ if (!FLEXONENAND(this))
+ return block << this->erase_shift;
+ return flexonenand_get_addr(this, block);
+}
+
+/**
+ * flexonenand_region - [Flex-OneNAND] Return erase region of addr
+ * @param mtd MTD device structure
+ * @param addr address whose erase region needs to be identified
+ */
+inline int flexonenand_region(struct mtd_info *mtd, loff_t addr)
+{
+ int i;
+
+ for (i = 0; i < mtd->numeraseregions &&
+ addr >= mtd->eraseregions[i].offset; i++)
+ ;
+ i--;
+ return i;
+}
+
+/**
* onenand_command - [DEFAULT] Send command to OneNAND device
* @param mtd MTD device structure
* @param cmd the command to be sent
@@ -182,10 +279,12 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
size_t len)
{
struct onenand_chip *this = mtd->priv;
- int value, readcmd = 0;
+ int value;
int block, page;
+ unsigned slc = 0;
+
/* Now we use page size operation */
- int sectors = 4, count = 4;
+ int sectors = 0, count = 0;
/* Address translation */
switch (cmd) {
@@ -196,16 +295,30 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
page = -1;
break;
+ case FLEXONENAND_CMD_PI_ACCESS:
+ /* addr contains die index */
+ block = addr * this->density_mask;
+ page = -1;
+ break;
+
case ONENAND_CMD_ERASE:
case ONENAND_CMD_BUFFERRAM:
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(this, addr, NULL);
page = -1;
break;
+ case FLEXONENAND_CMD_READ_PI:
+ cmd = ONENAND_CMD_READ;
+ block = addr * this->density_mask;
+ page = 0;
+ break;
+
default:
- block = (int)(addr >> this->erase_shift);
- page = (int)(addr >> this->page_shift);
+ block = onenand_get_block(this, addr, &slc);
+ page = (int) (addr - onenand_get_addr(this, block)) >> this->page_shift;
page &= this->page_mask;
+ if (slc)
+ page &= (this->page_mask >> 1);
break;
}
@@ -216,8 +329,11 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
this->write_word(value,
this->base + ONENAND_REG_START_ADDRESS2);
- /* Switch to the next data buffer */
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (ONENAND_IS_MLC(this))
+ ONENAND_SET_BUFFERRAM0(this);
+ else
+ /* Switch to the next data buffer */
+ ONENAND_SET_NEXT_BUFFERRAM(this);
return 0;
}
@@ -227,6 +343,10 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
value = onenand_block_address(this->device_id, block);
this->write_word(value,
this->base + ONENAND_REG_START_ADDRESS1);
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this->device_id, block);
+ this->write_word(value,
+ this->base + ONENAND_REG_START_ADDRESS2);
}
if (page != -1) {
@@ -235,8 +355,10 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
switch (cmd) {
case ONENAND_CMD_READ:
case ONENAND_CMD_READOOB:
- dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
- readcmd = 1;
+ if (ONENAND_IS_MLC(this))
+ dataram = ONENAND_SET_BUFFERRAM0(this);
+ else
+ dataram = ONENAND_SET_NEXT_BUFFERRAM(this);
break;
default:
@@ -253,14 +375,6 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
value = onenand_buffer_address(dataram, sectors, count);
this->write_word(value, this->base + ONENAND_REG_START_BUFFER);
- if (readcmd) {
- /* Select DataRAM for DDP */
- value =
- onenand_bufferram_address(this->device_id, block);
- this->write_word(value,
- this->base +
- ONENAND_REG_START_ADDRESS2);
- }
}
/* Interrupt clear */
@@ -272,6 +386,28 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr,
}
/**
+ * onenand_read_ecc - return ecc status
+ * @param this onenand chip structure
+ */
+static inline int onenand_read_ecc(struct onenand_chip *this)
+{
+ int ecc, i, result = 0;
+
+ if (!FLEXONENAND(this))
+ return this->read_word(this->base + ONENAND_REG_ECC_STATUS);
+
+ for (i = 0; i < 4; i++) {
+ ecc = this->read_word(this->base + ((ONENAND_REG_ECC_STATUS + i) << 1));
+ if (likely(!ecc))
+ continue;
+ if (ecc & FLEXONENAND_UNCORRECTABLE_ERROR)
+ return ONENAND_ECC_2BIT_ALL;
+ }
+
+ return result;
+}
+
+/**
* onenand_wait - [DEFAULT] wait until the command is done
* @param mtd MTD device structure
* @param state state to select the max. timeout value
@@ -295,6 +431,15 @@ static int onenand_wait(struct mtd_info *mtd, int state)
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
+ if (interrupt & ONENAND_INT_READ) {
+ ecc = onenand_read_ecc(this);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ MTDDEBUG (MTD_DEBUG_LEVEL0,
+ "onenand_wait: ECC error = 0x%04x\n", ecc);
+ return -EBADMSG;
+ }
+ }
+
if (ctrl & ONENAND_CTRL_ERROR) {
MTDDEBUG (MTD_DEBUG_LEVEL0,
"onenand_wait: controller error = 0x%04x\n", ctrl);
@@ -307,15 +452,6 @@ static int onenand_wait(struct mtd_info *mtd, int state)
return -EIO;
}
- if (interrupt & ONENAND_INT_READ) {
- ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
- if (ecc & ONENAND_ECC_2BIT_ALL) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_wait: ECC error = 0x%04x\n", ecc);
- return -EBADMSG;
- }
- }
-
return 0;
}
@@ -433,10 +569,13 @@ static int onenand_check_bufferram(struct mtd_info *mtd, loff_t addr)
struct onenand_chip *this = mtd->priv;
int block, page;
int i;
+ unsigned slc = 0;
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(this, addr, &slc);
page = (int)(addr >> this->page_shift);
page &= this->page_mask;
+ if (slc)
+ page &= (this->page_mask >> 1);
i = ONENAND_CURRENT_BUFFERRAM(this);
@@ -462,10 +601,13 @@ static int onenand_update_bufferram(struct mtd_info *mtd, loff_t addr,
struct onenand_chip *this = mtd->priv;
int block, page;
int i;
+ unsigned slc = 0;
- block = (int)(addr >> this->erase_shift);
+ block = onenand_get_block(this, addr, &slc);
page = (int)(addr >> this->page_shift);
page &= this->page_mask;
+ if (slc)
+ page &= (this->page_mask >> 1);
/* Invalidate BufferRAM */
for (i = 0; i < MAX_BUFFERRAM; i++) {
@@ -573,6 +715,48 @@ static int onenand_transfer_auto_oob(struct mtd_info *mtd, uint8_t *buf,
}
/**
+ * onenand_recover_lsb - [Flex-OneNAND] Recover LSB page data
+ * @param mtd MTD device structure
+ * @param addr address to recover
+ * @param status return value from onenand_wait
+ *
+ * MLC NAND Flash cell has paired pages - LSB page and MSB page. LSB page has
+ * lower page address and MSB page has higher page address in paired pages.
+ * If power off occurs during MSB page program, the paired LSB page data can
+ * become corrupt. LSB page recovery read is a way to read LSB page though page
+ * data are corrupted. When uncorrectable error occurs as a result of LSB page
+ * read after power up, issue LSB page recovery read.
+ */
+static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned slc = 0;
+
+ /* Recovery is only for Flex-OneNAND */
+ if (!FLEXONENAND(this))
+ return status;
+
+ /* check if we failed due to uncorrectable error */
+ if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR)
+ return status;
+
+ /* check if address lies in MLC region */
+ onenand_get_block(this, addr, &slc);
+ if (slc)
+ return status;
+
+ /* We are attempting to reread, so decrement stats.failed
+ * which was incremented by onenand_wait due to read failure
+ */
+ printk(KERN_INFO "onenand_recover_lsb: Attempting to recover from uncorrectable read\n");
+ mtd->ecc_stats.failed--;
+
+ /* Issue the LSB page recovery command */
+ this->command(mtd, FLEXONENAND_CMD_RECOVER_LSB, addr, this->writesize);
+ return this->wait(mtd, FL_READING);
+}
+
+/**
* onenand_read_ops_nolock - [OneNAND Interface] OneNAND read main and/or out-of-band
* @param mtd MTD device structure
* @param from offset to read from
@@ -616,12 +800,14 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats;
/* Read-while-load method */
+ /* Note: We can't use this feature in MLC */
/* Do first load to bufferRAM */
if (read < len) {
if (!onenand_check_bufferram(mtd, from)) {
this->command(mtd, ONENAND_CMD_READ, from, writesize);
ret = this->wait(mtd, FL_READING);
+ ret = ret ? onenand_recover_lsb(mtd, from, ret) : ret;
onenand_update_bufferram(mtd, from, !ret);
if (ret == -EBADMSG)
ret = 0;
@@ -636,7 +822,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
while (!ret) {
/* If there is more to load then start next load */
from += thislen;
- if (read + thislen < len) {
+ if (!ONENAND_IS_MLC(this) && read + thislen < len) {
this->command(mtd, ONENAND_CMD_READ, from, writesize);
/*
* Chip boundary handling in DDP
@@ -669,6 +855,15 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
oobcolumn = 0;
}
+ if (ONENAND_IS_MLC(this) && (read + thislen < len)) {
+ this->command(mtd, ONENAND_CMD_READ, from, writesize);
+ ret = this->wait(mtd, FL_READING);
+ ret = ret ? onenand_recover_lsb(mtd, from, ret) : ret;
+ onenand_update_bufferram(mtd, from, !ret);
+ if (ret == -EBADMSG)
+ ret = 0;
+ }
+
/* See if we are done */
read += thislen;
if (read == len)
@@ -676,16 +871,19 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
/* Set up for next read from bufferRAM */
if (unlikely(boundary))
this->write_word(ONENAND_DDP_CHIP1, this->base + ONENAND_REG_START_ADDRESS2);
- ONENAND_SET_NEXT_BUFFERRAM(this);
+ if (!ONENAND_IS_MLC(this))
+ ONENAND_SET_NEXT_BUFFERRAM(this);
buf += thislen;
thislen = min_t(int, writesize, len - read);
column = 0;
- /* Now wait for load */
- ret = this->wait(mtd, FL_READING);
- onenand_update_bufferram(mtd, from, !ret);
- if (ret == -EBADMSG)
- ret = 0;
+ if (!ONENAND_IS_MLC(this)) {
+ /* Now wait for load */
+ ret = this->wait(mtd, FL_READING);
+ onenand_update_bufferram(mtd, from, !ret);
+ if (ret == -EBADMSG)
+ ret = 0;
+ }
}
/*
@@ -722,7 +920,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
size_t len = ops->ooblen;
mtd_oob_mode_t mode = ops->mode;
u_char *buf = ops->oobbuf;
- int ret = 0;
+ int ret = 0, readcmd;
from += ops->ooboffs;
@@ -755,15 +953,20 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from,
stats = mtd->ecc_stats;
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
while (read < len) {
thislen = oobsize - column;
thislen = min_t(int, thislen, len);
- this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+ this->command(mtd, readcmd, from, mtd->oobsize);
onenand_update_bufferram(mtd, from, 0);
ret = this->wait(mtd, FL_READING);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
+
if (ret && ret != -EBADMSG) {
printk(KERN_ERR "onenand_read_oob_nolock: read failed = 0x%x\n", ret);
break;
@@ -886,22 +1089,26 @@ static int onenand_bbt_wait(struct mtd_info *mtd, int state)
interrupt = this->read_word(this->base + ONENAND_REG_INTERRUPT);
ctrl = this->read_word(this->base + ONENAND_REG_CTRL_STATUS);
- /* Initial bad block case: 0x2400 or 0x0400 */
- if (ctrl & ONENAND_CTRL_ERROR) {
- printk(KERN_DEBUG "onenand_bbt_wait: controller error = 0x%04x\n", ctrl);
- return ONENAND_BBT_READ_ERROR;
- }
-
if (interrupt & ONENAND_INT_READ) {
- int ecc = this->read_word(this->base + ONENAND_REG_ECC_STATUS);
- if (ecc & ONENAND_ECC_2BIT_ALL)
+ int ecc = onenand_read_ecc(this);
+ if (ecc & ONENAND_ECC_2BIT_ALL) {
+ printk(KERN_INFO "onenand_bbt_wait: ecc error = 0x%04x"
+ ", controller = 0x%04x\n", ecc, ctrl);
return ONENAND_BBT_READ_ERROR;
+ }
} else {
printk(KERN_ERR "onenand_bbt_wait: read timeout!"
"ctrl=0x%04x intr=0x%04x\n", ctrl, interrupt);
return ONENAND_BBT_READ_FATAL_ERROR;
}
+ /* Initial bad block case: 0x2400 or 0x0400 */
+ if (ctrl & ONENAND_CTRL_ERROR) {
+ printk(KERN_DEBUG "onenand_bbt_wait: controller error"
+ " = 0x%04x\n", ctrl);
+ return ONENAND_BBT_READ_ERROR;
+ }
+
return 0;
}
@@ -918,7 +1125,7 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
{
struct onenand_chip *this = mtd->priv;
int read = 0, thislen, column;
- int ret = 0;
+ int ret = 0, readcmd;
size_t len = ops->ooblen;
u_char *buf = ops->oobbuf;
@@ -926,6 +1133,8 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
"onenand_bbt_read_oob: from = 0x%08x, len = %zi\n",
(unsigned int) from, len);
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
+
/* Initialize return value */
ops->oobretlen = 0;
@@ -945,11 +1154,14 @@ int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
thislen = mtd->oobsize - column;
thislen = min_t(int, thislen, len);
- this->command(mtd, ONENAND_CMD_READOOB, from, mtd->oobsize);
+ this->command(mtd, readcmd, from, mtd->oobsize);
onenand_update_bufferram(mtd, from, 0);
ret = onenand_bbt_wait(mtd, FL_READING);
+ if (unlikely(ret))
+ ret = onenand_recover_lsb(mtd, from, ret);
+
if (ret)
break;
@@ -987,9 +1199,11 @@ static int onenand_verify_oob(struct mtd_info *mtd, const u_char *buf, loff_t to
{
struct onenand_chip *this = mtd->priv;
u_char *oob_buf = this->oob_buf;
- int status, i;
+ int status, i, readcmd;
+
+ readcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_READ : ONENAND_CMD_READOOB;
- this->command(mtd, ONENAND_CMD_READOOB, to, mtd->oobsize);
+ this->command(mtd, readcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
status = this->wait(mtd, FL_READING);
if (status)
@@ -1167,7 +1381,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to,
oobbuf = this->oob_buf;
/* We send data to spare ram with oobsize
- * * to prevent byte access */
+ * to prevent byte access */
memset(oobbuf, 0xff, mtd->oobsize);
if (ops->mode == MTD_OOB_AUTO)
onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen);
@@ -1236,7 +1450,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
{
struct onenand_chip *this = mtd->priv;
int column, ret = 0, oobsize;
- int written = 0;
+ int written = 0, oobcmd;
u_char *oobbuf;
size_t len = ops->ooblen;
const u_char *buf = ops->oobbuf;
@@ -1280,6 +1494,8 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
oobbuf = this->oob_buf;
+ oobcmd = ONENAND_IS_MLC(this) ? ONENAND_CMD_PROG : ONENAND_CMD_PROGOOB;
+
/* Loop until all data write */
while (written < len) {
int thislen = min_t(int, oobsize, len - written);
@@ -1295,7 +1511,14 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to,
memcpy(oobbuf + column, buf, thislen);
this->write_bufferram(mtd, ONENAND_SPARERAM, oobbuf, 0, mtd->oobsize);
- this->command(mtd, ONENAND_CMD_PROGOOB, to, mtd->oobsize);
+ if (ONENAND_IS_MLC(this)) {
+ /* Set main area of DataRAM to 0xff*/
+ memset(this->page_buf, 0xff, mtd->writesize);
+ this->write_bufferram(mtd, ONENAND_DATARAM,
+ this->page_buf, 0, mtd->writesize);
+ }
+
+ this->command(mtd, oobcmd, to, mtd->oobsize);
onenand_update_bufferram(mtd, to, 0);
if (ONENAND_IS_2PLANE(this)) {
@@ -1422,34 +1645,50 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
{
struct onenand_chip *this = mtd->priv;
unsigned int block_size;
- loff_t addr;
- int len;
- int ret = 0;
-
- MTDDEBUG (MTD_DEBUG_LEVEL3,
- "onenand_erase: start = 0x%08x, len = %i\n",
- (unsigned int)instr->addr, (unsigned int)instr->len);
+ loff_t addr = instr->addr;
+ unsigned int len = instr->len;
+ int ret = 0, i;
+ struct mtd_erase_region_info *region = NULL;
+ unsigned int region_end = 0;
- block_size = (1 << this->erase_shift);
+ MTDDEBUG (MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n",
+ (unsigned int) addr, len);
- /* Start address must align on block boundary */
- if (unlikely(instr->addr & (block_size - 1))) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Unaligned address\n");
+ /* Do not allow erase past end of device */
+ if (unlikely((len + addr) > mtd->size)) {
+ MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: Erase past end of device\n");
return -EINVAL;
}
- /* Length must align on block boundary */
- if (unlikely(instr->len & (block_size - 1))) {
- MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Length not block aligned\n");
- return -EINVAL;
+ if (mtd->numeraseregions > 1) {
+ /* Find the eraseregion of this address */
+ i = flexonenand_region(mtd, addr);
+ region = &mtd->eraseregions[i];
+
+ block_size = region->erasesize;
+ region_end = region->offset + region->erasesize * region->numblocks;
+
+ /* Start address within region must align on block boundary.
+ * Erase region's start offset is always block start address.
+ */
+ if (unlikely((addr - region->offset) & (block_size - 1))) {
+ MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+ return -EINVAL;
+ }
+ } else {
+ block_size = 1 << this->erase_shift;
+
+ /* Start address must align on block boundary */
+ if (unlikely(addr & (block_size - 1))) {
+ MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: Unaligned address\n");
+ return -EINVAL;
+ }
}
- /* Do not allow erase past end of device */
- if (unlikely((instr->len + instr->addr) > mtd->size)) {
+ /* Length must align on block boundary */
+ if (unlikely(len & (block_size - 1))) {
MTDDEBUG (MTD_DEBUG_LEVEL0,
- "onenand_erase: Erase past end of device\n");
+ "onenand_erase: Length not block aligned\n");
return -EINVAL;
}
@@ -1459,9 +1698,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
onenand_get_device(mtd, FL_ERASING);
/* Loop throught the pages */
- len = instr->len;
- addr = instr->addr;
-
instr->state = MTD_ERASING;
while (len) {
@@ -1481,7 +1717,7 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
else
MTDDEBUG (MTD_DEBUG_LEVEL0, "onenand_erase: "
"Failed erase, block %d\n",
- (unsigned)(addr >> this->erase_shift));
+ onenand_get_block(this, addr, NULL));
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = addr;
goto erase_exit;
@@ -1489,6 +1725,22 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr)
len -= block_size;
addr += block_size;
+
+ if (addr == region_end) {
+ if (!len)
+ break;
+ region++;
+
+ block_size = region->erasesize;
+ region_end = region->offset + region->erasesize * region->numblocks;
+
+ if (len & (block_size - 1)) {
+ /* FIXME: This should be handled at MTD partitioning level. */
+ printk(KERN_ERR "onenand_erase: Unaligned address\n");
+ goto erase_exit;
+ }
+ }
+
}
instr->state = MTD_ERASE_DONE;
@@ -1581,8 +1833,8 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
struct onenand_chip *this = mtd->priv;
int start, end, block, value, status;
- start = ofs >> this->erase_shift;
- end = len >> this->erase_shift;
+ start = onenand_get_block(this, ofs, NULL);
+ end = onenand_get_block(this, ofs + len, NULL) - 1;
/* Continuous lock scheme */
if (this->options & ONENAND_CONT_LOCK) {
@@ -1590,7 +1842,7 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
this->write_word(start,
this->base + ONENAND_REG_START_BLOCK_ADDRESS);
/* Set end block address */
- this->write_word(end - 1,
+ this->write_word(end,
this->base + ONENAND_REG_END_BLOCK_ADDRESS);
/* Write unlock command */
this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
@@ -1612,7 +1864,17 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
}
/* Block lock scheme */
- for (block = start; block < end; block++) {
+ for (block = start; block < end + 1; block++) {
+ /* Set block address */
+ value = onenand_block_address(this->device_id, block);
+ this->write_word(value,
+ this->base + ONENAND_REG_START_ADDRESS1);
+
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this->device_id, block);
+ this->write_word(value,
+ this->base + ONENAND_REG_START_ADDRESS2);
+
/* Set start block address */
this->write_word(block,
this->base + ONENAND_REG_START_BLOCK_ADDRESS);
@@ -1650,15 +1912,18 @@ int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
*/
char * onenand_print_device_info(int device)
{
- int vcc, demuxed, ddp, density;
+ int vcc, demuxed, ddp, density, flexonenand;
char *dev_info = malloc(80);
vcc = device & ONENAND_DEVICE_VCC_MASK;
demuxed = device & ONENAND_DEVICE_IS_DEMUX;
ddp = device & ONENAND_DEVICE_IS_DDP;
density = device >> ONENAND_DEVICE_DENSITY_SHIFT;
- sprintf(dev_info, "%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
- demuxed ? "" : "Muxed ",
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ flexonenand = device & DEVICE_IS_FLEXONENAND;
+ sprintf(dev_info, "%s%sOneNAND%s %dMB %sV 16-bit (0x%02x)",
+ demuxed ? "" : "Muxed ",
+ flexonenand ? "Flex-" : "",
ddp ? "(DDP)" : "",
(16 << density), vcc ? "2.65/3.3" : "1.8", device);
@@ -1694,6 +1959,243 @@ static int onenand_check_maf(int manuf)
}
/**
+* flexonenand_get_boundary - Reads the SLC boundary
+* @param onenand_info - onenand info structure
+**/
+static int flexonenand_get_boundary(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned die, bdry;
+ int ret, syscfg, locked;
+
+ /* Disable ECC */
+ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
+ this->write_word((syscfg | 0x0100), this->base + ONENAND_REG_SYS_CFG1);
+
+ for (die = 0; die < this->dies; die++) {
+ this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
+ this->wait(mtd, FL_SYNCING);
+
+ this->command(mtd, FLEXONENAND_CMD_READ_PI, die, 0);
+ ret = this->wait(mtd, FL_READING);
+
+ bdry = this->read_word(this->base + ONENAND_DATARAM);
+ locked = bdry >> FLEXONENAND_PI_UNLOCK_SHIFT;
+ locked = (locked == 0x3) ? 0 : 1;
+ this->boundary[die] = bdry & FLEXONENAND_PI_MASK;
+
+ this->command(mtd, ONENAND_CMD_RESET, 0, 0);
+ ret = this->wait(mtd, FL_RESETING);
+
+ printk(KERN_INFO "Die %d boundary: %d%s\n", die,
+ this->boundary[die], locked ? "(Locked)" : "(Unlocked)");
+ }
+
+ /* Enable ECC */
+ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
+ return 0;
+}
+
+/**
+ * flexonenand_get_size - Fill up fields in onenand_chip
+ * boundary[], diesize[], mtd->size
+ * @param mtd - MTD device structure
+ */
+static void flexonenand_get_size(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ int die, ofs, i, eraseshift, density;
+ int blksperdie, maxbdry;
+
+ density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ blksperdie = ((16 << density) << 20) >> (this->erase_shift);
+ blksperdie >>= ONENAND_IS_DDP(this) ? 1 : 0;
+ maxbdry = blksperdie - 1;
+ eraseshift = this->erase_shift - 1;
+
+
+ mtd->numeraseregions = this->dies << 1;
+
+ /* This fills up the device boundary */
+ flexonenand_get_boundary(mtd);
+ die = ofs = 0;
+ i = -1;
+ for (; die < this->dies; die++) {
+ if (!die || this->boundary[die-1] != maxbdry) {
+ i++;
+ mtd->eraseregions[i].offset = ofs;
+ mtd->eraseregions[i].erasesize = 1 << eraseshift;
+ mtd->eraseregions[i].numblocks =
+ this->boundary[die] + 1;
+ ofs += mtd->eraseregions[i].numblocks << eraseshift;
+ eraseshift++;
+ } else {
+ mtd->numeraseregions -= 1;
+ mtd->eraseregions[i].numblocks +=
+ this->boundary[die] + 1;
+ ofs += (this->boundary[die] + 1) << (eraseshift - 1);
+ }
+ if (this->boundary[die] != maxbdry) {
+ i++;
+ mtd->eraseregions[i].offset = ofs;
+ mtd->eraseregions[i].erasesize = 1 << eraseshift;
+ mtd->eraseregions[i].numblocks = maxbdry ^
+ this->boundary[die];
+ ofs += mtd->eraseregions[i].numblocks << eraseshift;
+ eraseshift--;
+ } else
+ mtd->numeraseregions -= 1;
+ }
+
+ mtd->erasesize = 1 << (this->erase_shift);
+ if (mtd->numeraseregions == 1)
+ mtd->erasesize >>= 1;
+
+ printk(KERN_INFO "Device has %d eraseregions\n", mtd->numeraseregions);
+ for (i = 0; i < mtd->numeraseregions; i++)
+ printk(KERN_INFO "[offset: 0x%08x, erasesize: 0x%05x,"
+ " numblocks: %04u]\n", mtd->eraseregions[i].offset,
+ mtd->eraseregions[i].erasesize,
+ mtd->eraseregions[i].numblocks);
+
+ for (die = 0, mtd->size = 0; die < this->dies; die++) {
+ this->diesize[die] = (blksperdie << this->erase_shift);
+ this->diesize[die] -= (this->boundary[die] + 1)
+ << (this->erase_shift - 1);
+ mtd->size += this->diesize[die];
+ }
+}
+
+/**
+ * flexonenand_check_blocks_erased - Check if blocks are erased
+ * @param mtd_info - mtd info structure
+ * @param start - first erase block to check
+ * @param end - last erase block to check
+ *
+ * Converting an unerased block from MLC to SLC
+ * causes byte values to change. Since both data and its ECC
+ * have changed, reads on the block give uncorrectable error.
+ * This might lead to the block being detected as bad.
+ *
+ * Avoid this by ensuring that the block to be converted is
+ * erased.
+ */
+static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int start, int end)
+{
+ struct onenand_chip *this = mtd->priv;
+ int i, ret;
+ int block;
+ struct mtd_oob_ops ops = {
+ .mode = MTD_OOB_PLACE,
+ .ooboffs = 0,
+ .ooblen = mtd->oobsize,
+ .datbuf = NULL,
+ .oobbuf = this->oob_buf,
+ };
+ loff_t addr;
+
+ printk(KERN_DEBUG "Check blocks from %d to %d\n", start, end);
+
+ for (block = start; block <= end; block++) {
+ addr = flexonenand_get_addr(this, block);
+ if (onenand_block_isbad_nolock(mtd, addr, 0))
+ continue;
+
+ /*
+ * Since main area write results in ECC write to spare,
+ * it is sufficient to check only ECC bytes for change.
+ */
+ ret = onenand_read_oob_nolock(mtd, addr, &ops);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < mtd->oobsize; i++)
+ if (this->oob_buf[i] != 0xff)
+ break;
+
+ if (i != mtd->oobsize) {
+ printk(KERN_WARNING "Block %d not erased.\n", block);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * flexonenand_set_boundary - Writes the SLC boundary
+ * @param onenand_info - onenand info structure
+ */
+int flexonenand_set_boundary(struct mtd_info *mtd, int die,
+ int boundary, int lock)
+{
+ struct onenand_chip *this = mtd->priv;
+ int ret, density, blksperdie, old, new;
+ unsigned addr;
+
+ density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+
+ blksperdie = ((16 << density) << 20) >> this->erase_shift;
+ blksperdie >>= (this->device_id & ONENAND_DEVICE_IS_DDP) ? 1 : 0;
+
+ addr = die ? this->diesize[0] : 0;
+
+ if (boundary >= blksperdie) {
+ printk(KERN_ERR "Invalid boundary value.\n");
+ return -1;
+ }
+
+ if (this->boundary[die] == boundary)
+ return -1;
+
+ /* Check if converting blocks are erased */
+ old = this->boundary[die] + (die * this->density_mask);
+ new = boundary + (die * this->density_mask);
+ ret = flexonenand_check_blocks_erased(mtd, min(old, new) + 1, max(old, new));
+ if (ret) {
+ printk(KERN_ERR "flexonenand_set_boundary: Please erase blocks before boundary change\n");
+ return ret;
+ }
+
+ printk(KERN_INFO "Changing boundary: %d%s\n", boundary, lock ?
+ "(Locked)" : "(Unlocked)");
+ boundary &= FLEXONENAND_PI_MASK;
+ boundary |= lock ? 0 : (3 << FLEXONENAND_PI_UNLOCK_SHIFT);
+
+ this->command(mtd, FLEXONENAND_CMD_PI_ACCESS, die, 0);
+ this->wait(mtd, FL_SYNCING);
+
+ this->command(mtd, ONENAND_CMD_ERASE, addr, 0);
+ ret = this->wait(mtd, FL_ERASING);
+ if (ret) {
+ printk(KERN_ERR "flexonenand_set_boundary: Failed PI erase for Die %d\n", die);
+ goto out;
+ }
+
+
+ this->write_word(boundary, this->base + ONENAND_DATARAM);
+ this->command(mtd, ONENAND_CMD_PROG, addr, 0);
+ ret = this->wait(mtd, FL_WRITING);
+ if (ret) {
+ printk(KERN_ERR "flexonenand_set_boundary: Failed PI write for Die %d\n", die);
+ goto out;
+ }
+
+ this->command(mtd, FLEXONENAND_CMD_PI_UPDATE, die, 0);
+ ret = this->wait(mtd, FL_WRITING);
+out:
+ this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_REG_COMMAND);
+ this->wait(mtd, FL_RESETING);
+ if (!ret)
+ /* Recalculate device size on boundary change*/
+ flexonenand_get_size(mtd);
+
+ return ret;
+}
+
+/**
* onenand_probe - [OneNAND Interface] Probe the OneNAND device
* @param mtd MTD device structure
*
@@ -1727,42 +2229,64 @@ static int onenand_probe(struct mtd_info *mtd)
/* Read manufacturer and device IDs from Register */
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
+ this->technology = this->read_word(this->base + ONENAND_REG_TECHNOLOGY);
/* Check OneNAND device */
if (maf_id != bram_maf_id || dev_id != bram_dev_id)
return -ENXIO;
- /* FIXME : Current OneNAND MTD doesn't support Flex-OneNAND */
- if (dev_id & (1 << 9)) {
- printk("Not yet support Flex-OneNAND\n");
- return -ENXIO;
- }
-
/* Flash device information */
mtd->name = onenand_print_device_info(dev_id);
this->device_id = dev_id;
density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ density &= ONENAND_DEVICE_DENSITY_MASK;
+ if (FLEXONENAND(this)) {
+ this->dies = (dev_id & ONENAND_DEVICE_IS_DDP) ? 2 : 1;
+ /* Maximum possible erase regions */
+ mtd->numeraseregions = this->dies << 1;
+ mtd->eraseregions = malloc(sizeof(struct mtd_erase_region_info)
+ * (this->dies << 1));
+ if (!mtd->eraseregions)
+ return -ENOMEM;
+ }
+
+ /*
+ * For Flex-OneNAND, chipsize represents maximum possible device size.
+ * mtd->size represents the actual device size.
+ */
this->chipsize = (16 << density) << 20;
/* OneNAND page size & block size */
/* The data buffer size is equal to page size */
mtd->writesize =
this->read_word(this->base + ONENAND_REG_DATA_BUFFER_SIZE);
+ /* We use the full BufferRAM */
+ if (ONENAND_IS_MLC(this))
+ mtd->writesize <<= 1;
+
mtd->oobsize = mtd->writesize >> 5;
/* Pagers per block is always 64 in OneNAND */
mtd->erasesize = mtd->writesize << 6;
+ /* Flex-OneNAND always has 128 pages per block */
+ mtd->erasesize <<= FLEXONENAND(this) ? 1 : 0;
this->erase_shift = ffs(mtd->erasesize) - 1;
this->page_shift = ffs(mtd->writesize) - 1;
this->ppb_shift = (this->erase_shift - this->page_shift);
this->page_mask = (mtd->erasesize / mtd->writesize) - 1;
+ /* Set density mask. it is used for DDP */
+ if (ONENAND_IS_DDP(this))
+ this->density_mask = this->chipsize >> (this->erase_shift + 1);
/* It's real page size */
this->writesize = mtd->writesize;
/* REVIST: Multichip handling */
- mtd->size = this->chipsize;
+ if (FLEXONENAND(this))
+ flexonenand_get_size(mtd);
+ else
+ mtd->size = this->chipsize;
/* Version ID */
version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
@@ -1787,6 +2311,9 @@ static int onenand_probe(struct mtd_info *mtd)
mtd->block_isbad = onenand_block_isbad;
mtd->block_markbad = onenand_block_markbad;
+ if (FLEXONENAND(this))
+ this->options &= ~ONENAND_CONT_LOCK;
+
return 0;
}
diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c
index f6092b9..3cf1758 100644
--- a/drivers/mtd/onenand/onenand_bbt.c
+++ b/drivers/mtd/onenand/onenand_bbt.c
@@ -66,6 +66,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
struct bbm_info *bbm = this->bbm;
int i, j, numblocks, len, scanlen;
int startblock;
+ unsigned slc = 0;
loff_t from;
size_t readlen, ooblen;
struct mtd_oob_ops ops;
@@ -82,7 +83,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
/* Note that numblocks is 2 * (real numblocks) here;
* see i += 2 below as it makses shifting and masking less painful
*/
- numblocks = mtd->size >> (bbm->bbt_erase_shift - 1);
+ numblocks = this->chipsize >> (bbm->bbt_erase_shift - 1);
startblock = 0;
from = 0;
@@ -115,7 +116,11 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf,
}
}
i += 2;
- from += (1 << bbm->bbt_erase_shift);
+ onenand_get_block(this, from, &slc);
+ if (slc)
+ from += (1 << bbm->bbt_erase_shift) >> 1;
+ else
+ from += (1 << bbm->bbt_erase_shift);
}
return 0;
@@ -152,7 +157,7 @@ static int onenand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
uint8_t res;
/* Get block number * 2 */
- block = (int)(offs >> (bbm->bbt_erase_shift - 1));
+ block = (int) (onenand_get_block(this, offs, NULL) << 1);
res = (bbm->bbt[block >> 3] >> (block & 0x06)) & 0x03;
MTDDEBUG (MTD_DEBUG_LEVEL2,
@@ -191,7 +196,7 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
struct bbm_info *bbm = this->bbm;
int len, ret = 0;
- len = mtd->size >> (this->erase_shift + 2);
+ len = this->chipsize >> (this->erase_shift + 2);
/* Allocate memory (2bit per block) */
bbm->bbt = malloc(len);
if (!bbm->bbt) {
diff --git a/drivers/mtd/onenand/onenand_uboot.c b/drivers/mtd/onenand/onenand_uboot.c
index 08082f3..419db34 100644
--- a/drivers/mtd/onenand/onenand_uboot.c
+++ b/drivers/mtd/onenand/onenand_uboot.c
@@ -31,6 +31,8 @@ void onenand_init(void)
onenand_scan(&onenand_mtd, 1);
+ if (onenand_chip.device_id & DEVICE_IS_FLEXONENAND)
+ puts("Flex-");
puts("OneNAND: ");
- print_size(onenand_mtd.size, "\n");
+ print_size(onenand_chip.chipsize, "\n");
}
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 4467c2b..a1bb0fd 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -20,6 +20,7 @@
#include <linux/mtd/compat.h>
#include <linux/mtd/bbm.h>
+#define MAX_DIES 2
#define MAX_BUFFERRAM 2
#define MAX_ONENAND_PAGESIZE (2048 + 64)
@@ -43,8 +44,13 @@ struct onenand_bufferram {
/**
* struct onenand_chip - OneNAND Private Flash Chip Data
* @param base [BOARDSPECIFIC] address to access OneNAND
+ * @dies: [INTERN][FLEXONENAND] number of dies on chip
+ * @boundary: [INTERN][FLEXONENAND] Boundary of the dies
+ * @diesize: [INTERN][FLEXONENAND] Size of the dies
* @param chipsize [INTERN] the size of one chip for multichip arrays
* @param device_id [INTERN] device ID
+ * @technology [INTERN] describes the internal NAND array technology such as SLC or MLC.
+ * @density_mask: [INTERN] chip density, used for DDP devices
* @param verstion_id [INTERN] version ID
* @param options [BOARDSPECIFIC] various chip options. They can partly be set to inform onenand_scan about
* @param erase_shift [INTERN] number of address bits in a block
@@ -68,8 +74,13 @@ struct onenand_bufferram {
*/
struct onenand_chip {
void __iomem *base;
+ unsigned int dies;
+ unsigned int boundary[MAX_DIES];
+ unsigned int diesize[MAX_DIES];
unsigned int chipsize;
unsigned int device_id;
+ unsigned int technology;
+ unsigned int density_mask;
unsigned int options;
unsigned int erase_shift;
@@ -117,6 +128,8 @@ struct onenand_chip {
#define ONENAND_SET_BUFFERRAM0(this) (this->bufferram_index = 0)
#define ONENAND_SET_BUFFERRAM1(this) (this->bufferram_index = 1)
+#define FLEXONENAND(this) (this->device_id & DEVICE_IS_FLEXONENAND)
+#define ONENAND_IS_MLC(this) (this->technology & ONENAND_TECHNOLOGY_IS_MLC)
#define ONENAND_IS_DDP(this) \
(this->device_id & ONENAND_DEVICE_IS_DDP)
@@ -148,4 +161,6 @@ struct onenand_manufacturers {
int onenand_bbt_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops);
+unsigned onenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc);
#endif /* __LINUX_MTD_ONENAND_H */
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index a245e14..34977dc 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -67,6 +67,9 @@
/*
* Device ID Register F001h (R)
*/
+#define DEVICE_IS_FLEXONENAND (1 << 9)
+#define FLEXONENAND_PI_MASK (0x3ff)
+#define FLEXONENAND_PI_UNLOCK_SHIFT (14)
#define ONENAND_DEVICE_DENSITY_MASK (0xf)
#define ONENAND_DEVICE_DENSITY_SHIFT (4)
#define ONENAND_DEVICE_IS_DDP (1 << 3)
@@ -84,6 +87,11 @@
#define ONENAND_VERSION_PROCESS_SHIFT (8)
/*
+ * Technology Register F006h (R)
+ */
+#define ONENAND_TECHNOLOGY_IS_MLC (1 << 0)
+
+/*
* Start Address 1 F100h (R/W)
*/
#define ONENAND_DDP_SHIFT (15)
@@ -93,7 +101,7 @@
/*
* Start Address 8 F107h (R/W)
*/
-#define ONENAND_FPA_MASK (0x3f)
+#define ONENAND_FPA_MASK (0x7f)
#define ONENAND_FPA_SHIFT (2)
#define ONENAND_FSA_MASK (0x03)
@@ -105,7 +113,7 @@
#define ONENAND_BSA_BOOTRAM (0 << 2)
#define ONENAND_BSA_DATARAM0 (2 << 2)
#define ONENAND_BSA_DATARAM1 (3 << 2)
-#define ONENAND_BSC_MASK (0x03)
+#define ONENAND_BSC_MASK (0x07)
/*
* Command Register F220h (R/W)
@@ -122,9 +130,14 @@
#define ONENAND_CMD_ERASE (0x94)
#define ONENAND_CMD_RESET (0xF0)
#define ONENAND_CMD_READID (0x90)
+#define FLEXONENAND_CMD_RESET (0xF3)
+#define FLEXONENAND_CMD_PI_UPDATE (0x05)
+#define FLEXONENAND_CMD_PI_ACCESS (0x66)
+#define FLEXONENAND_CMD_RECOVER_LSB (0x05)
/* NOTE: Those are not *REAL* commands */
#define ONENAND_CMD_BUFFERRAM (0x1978)
+#define FLEXONENAND_CMD_READ_PI (0x1985)
/*
* System Configuration 1 Register F221h (R, R/W)
@@ -185,5 +198,6 @@
#define ONENAND_ECC_1BIT (1 << 0)
#define ONENAND_ECC_2BIT (1 << 1)
#define ONENAND_ECC_2BIT_ALL (0xAAAA)
+#define FLEXONENAND_UNCORRECTABLE_ERROR (0x1010)
#endif /* __ONENAND_REG_H */
diff --git a/include/onenand_uboot.h b/include/onenand_uboot.h
index e960257..53754ba 100644
--- a/include/onenand_uboot.h
+++ b/include/onenand_uboot.h
@@ -21,6 +21,7 @@ struct mtd_info;
struct erase_info;
extern struct mtd_info onenand_mtd;
+extern struct onenand_chip onenand_chip;
/* Functions */
extern void onenand_init(void);
@@ -36,4 +37,13 @@ extern int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
extern char *onenand_print_device_info(int device);
+extern unsigned onenand_get_block(struct onenand_chip *this, loff_t addr,
+ unsigned *isblkslc);
+
+extern loff_t onenand_get_addr(struct onenand_chip *this, int block);
+
+extern int flexonenand_region(struct mtd_info *mtd, loff_t addr);
+
+extern int flexonenand_set_boundary(struct mtd_info *mtd, int die,
+ int boundary, int lock);
#endif /* __UBOOT_ONENAND_H */
--
1.5.4.3
3
4

09 Mar '09
Hello,
AMCC PPC460EX canyonlands board with an FPGA PCIe end point:
u-boot sees the end point, but Linux does not:
U-Boot 1.3.3-00249-ga524e11 (Jun 30 2008 - 16:05:51)
CPU: AMCC PowerPC 460EX Rev. A at 800 MHz (PLB=200, OPB=100, EBC=100 MHz)
<...>
Board: Canyonlands - AMCC PPC460EX Evaluation Board, 2*PCIe, Rev. 16
<...>
PCIE1: successfully set as root-complex
02 00 2071 2071 00ff 00
Now, if I re-program the end-point FPGA during the u-boot boot
time-out, Linux will recognize the end-point.
Any takers on what I should start looking for?
Regards,
--
Leon
3
4

08 Mar '09
Add sanity check for the partitions.
Some special cases handled by the check are:
- A partition can span across erase regions.
- A region can have odd number of blocks.
Signed-off-by: Rohit Hagargundgi <h.rohit(a)samsung.com>
---
common/cmd_jffs2.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 59 insertions(+), 6 deletions(-)
diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c
index 791a572..5d2d69c 100644
--- a/common/cmd_jffs2.c
+++ b/common/cmd_jffs2.c
@@ -421,17 +421,70 @@ static int part_validate_onenand(struct mtdids *id, struct part_info *part)
#if defined(CONFIG_CMD_ONENAND)
/* info for OneNAND chips */
struct mtd_info *mtd;
+ int erasesize = 0;
mtd = &onenand_mtd;
- if ((unsigned long)(part->offset) % mtd->erasesize) {
- printf("%s%d: partition (%s) start offset"
- "alignment incorrect\n",
- MTD_DEV_TYPE(id->type), id->num, part->name);
- return 1;
+ if (mtd->numeraseregions > 1) {
+ int i, rgn, max = mtd->numeraseregions;
+ unsigned end = part->offset + part->size;
+ struct mtd_erase_region_info *regions = mtd->eraseregions;
+ unsigned portion_start, portion_end, region_end;
+
+ /* Find the first erase regions which is part of this
+ * partition.
+ */
+ i = flexonenand_region(mtd, part->offset);
+
+ /* Partition offset within region must align
+ * on region's erase size
+ */
+ if ((part->offset - regions[i].offset) % regions[i].erasesize) {
+ printf("%s%d: partition (%s) doesn't start on an erase"
+ " block boundary\n", MTD_DEV_TYPE(id->type),
+ id->num, part->name);
+ return 1;
+ }
+
+ erasesize = regions[i].erasesize;
+
+ /* A partition spanning across multiple erase regions has
+ * erase size equal to greatest erase size among the regions.
+ */
+ rgn = i;
+ for (; i < max && regions[i].offset < end; i++)
+ if (erasesize < regions[i].erasesize)
+ erasesize = regions[i].erasesize;
+
+ /* If partition spans many erase regions,
+ * the partition portion present in each region
+ * should be multiple of biggest erase size
+ */
+ for (i = rgn; i < max && regions[i].offset < end; i++) {
+ portion_start = max(regions[i].offset, part->offset);
+ region_end = regions[i].offset +
+ regions[i].erasesize * regions[i].numblocks;
+ portion_end = min(end, region_end);
+
+ if ((portion_end - portion_start) % erasesize) {
+ printf("%s%d: partition (%s) is not erase block"
+ " aligned within erase region\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
+ }
+ } else {
+ /* Single erase size */
+ erasesize = mtd->erasesize;
+ if ((unsigned long)(part->offset) % erasesize) {
+ printf("%s%d: partition (%s) start offset"
+ "alignment incorrect\n",
+ MTD_DEV_TYPE(id->type), id->num, part->name);
+ return 1;
+ }
}
- if (part->size % mtd->erasesize) {
+ if (part->size % erasesize) {
printf("%s%d: partition (%s) size alignment incorrect\n",
MTD_DEV_TYPE(id->type), id->num, part->name);
return 1;
--
1.5.4.3
1
1

08 Mar '09
Define and use CONFIG_ENV_ADDR_FLEX and CONFIG_ENV_SIZE_FLEX
for storing environment variables.
Signed-off-by: Rohit Hagargundgi <h.rohit(a)samsung.com>
---
common/env_onenand.c | 10 ++++++++++
include/configs/apollon.h | 2 ++
2 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/common/env_onenand.c b/common/env_onenand.c
index dbccc79..cd44781 100644
--- a/common/env_onenand.c
+++ b/common/env_onenand.c
@@ -58,11 +58,14 @@ uchar env_get_char_spec(int index)
void env_relocate_spec(void)
{
+ struct onenand_chip *this = &onenand_chip;
unsigned long env_addr;
int use_default = 0;
size_t retlen;
env_addr = CONFIG_ENV_ADDR;
+ if (FLEXONENAND(this))
+ env_addr = CONFIG_ENV_ADDR_FLEX;
/* Check OneNAND exist */
if (onenand_mtd.writesize)
@@ -89,6 +92,7 @@ void env_relocate_spec(void)
int saveenv(void)
{
+ struct onenand_chip *this = &onenand_chip;
unsigned long env_addr = CONFIG_ENV_ADDR;
struct erase_info instr = {
.callback = NULL,
@@ -96,6 +100,12 @@ int saveenv(void)
size_t retlen;
instr.len = CONFIG_ENV_SIZE;
+ if (FLEXONENAND(this)) {
+ env_addr = CONFIG_ENV_ADDR_FLEX;
+ instr.len = CONFIG_ENV_SIZE_FLEX;
+ instr.len <<= onenand_mtd.eraseregions[0].numblocks == 1 ?
+ 1 : 0;
+ }
instr.addr = env_addr;
instr.mtd = &onenand_mtd;
if (onenand_erase(&onenand_mtd, &instr)) {
diff --git a/include/configs/apollon.h b/include/configs/apollon.h
index dff47fc..0fcb22b 100644
--- a/include/configs/apollon.h
+++ b/include/configs/apollon.h
@@ -76,6 +76,7 @@
* Size of malloc() pool
*/
#define CONFIG_ENV_SIZE SZ_128K /* Total Size of Environment Sector */
+#define CONFIG_ENV_SIZE_FLEX SZ_256K
#define CONFIG_SYS_MALLOC_LEN (CONFIG_ENV_SIZE + SZ_1M)
/* bytes reserved for initial data */
#define CONFIG_SYS_GBL_DATA_SIZE 128
@@ -256,6 +257,7 @@
#define CONFIG_SYS_ONENAND_BASE 0x00000000
#define CONFIG_ENV_IS_IN_ONENAND 1
#define CONFIG_ENV_ADDR 0x00020000
+#define CONFIG_ENV_ADDR_FLEX 0x00040000
#ifdef CONFIG_SYS_USE_UBI
#define CONFIG_JFFS2_CMDLINE
--
1.5.4.3
1
1