summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2011-05-06 11:35:08 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2011-05-06 11:35:08 +0200
commit30eb4cdf17e5cc0d42bcda5de6a5dccecb06bcf0 (patch)
tree38ebcb0dc08fc4cd35065b7cf4ce776315e03543
parent3e19d858760a138cb8cba92a2395036bd70937e3 (diff)
parent64476d2177a53228319c4ab5b99cfb66ec8cc365 (diff)
downloadbarebox-30eb4cdf17e5cc0d42bcda5de6a5dccecb06bcf0.tar.gz
barebox-30eb4cdf17e5cc0d42bcda5de6a5dccecb06bcf0.tar.xz
Merge branch 'next'
-rw-r--r--arch/arm/Kconfig10
-rw-r--r--arch/arm/Makefile14
-rw-r--r--arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c2
-rw-r--r--arch/arm/boards/freescale-mx35-3-stack/3stack.c2
-rw-r--r--arch/arm/boards/karo-tx25/lowlevel.c1
-rw-r--r--arch/arm/boards/omap/Kconfig93
-rw-r--r--arch/arm/boards/omap/Makefile2
-rw-r--r--arch/arm/boards/omap/board-beagle.c44
-rw-r--r--arch/arm/boards/panda/Makefile1
-rw-r--r--arch/arm/boards/panda/board.c230
-rw-r--r--arch/arm/boards/panda/config.h1
-rw-r--r--arch/arm/boards/panda/env/config45
-rw-r--r--arch/arm/boards/panda/lowlevel.c121
-rw-r--r--arch/arm/boards/panda/mux.c257
-rw-r--r--arch/arm/boards/pcm049/Makefile1
-rw-r--r--arch/arm/boards/pcm049/board.c197
-rw-r--r--arch/arm/boards/pcm049/config.h1
-rw-r--r--arch/arm/boards/pcm049/env/bin/nand_bootstrap31
-rw-r--r--arch/arm/boards/pcm049/env/config53
-rw-r--r--arch/arm/boards/pcm049/lowlevel.c127
-rw-r--r--arch/arm/boards/pcm049/mux.c254
-rw-r--r--arch/arm/configs/omap3530_beagle_defconfig15
-rw-r--r--arch/arm/configs/omap3530_beagle_xload_defconfig38
-rw-r--r--arch/arm/configs/panda_defconfig60
-rw-r--r--arch/arm/configs/panda_xload_defconfig26
-rw-r--r--arch/arm/configs/pcm049_defconfig57
-rw-r--r--arch/arm/configs/pcm049_xload_defconfig40
-rw-r--r--arch/arm/cpu/Makefile4
-rw-r--r--arch/arm/cpu/cpu.c3
-rw-r--r--arch/arm/cpu/start.c16
-rw-r--r--arch/arm/include/asm/armlinux.h6
-rw-r--r--arch/arm/lib/Makefile5
-rw-r--r--arch/arm/lib/armlinux.c215
-rw-r--r--arch/arm/lib/barebox.lds.S1
-rw-r--r--arch/arm/lib/bootm.c92
-rw-r--r--arch/arm/lib/bootu.c38
-rw-r--r--arch/arm/lib/bootz.c100
-rw-r--r--arch/arm/mach-omap/Kconfig179
-rw-r--r--arch/arm/mach-omap/Makefile5
-rw-r--r--arch/arm/mach-omap/devices-gpmc-nand.c (renamed from arch/arm/boards/omap/devices-gpmc-nand.c)5
-rw-r--r--arch/arm/mach-omap/gpio.c146
-rw-r--r--arch/arm/mach-omap/include/mach/gpio.h46
-rw-r--r--arch/arm/mach-omap/include/mach/gpmc.h1
-rw-r--r--arch/arm/mach-omap/include/mach/gpmc_nand.h17
-rw-r--r--arch/arm/mach-omap/include/mach/omap4-clock.h320
-rw-r--r--arch/arm/mach-omap/include/mach/omap4-mux.h344
-rw-r--r--arch/arm/mach-omap/include/mach/omap4-silicon.h179
-rw-r--r--arch/arm/mach-omap/include/mach/silicon.h3
-rw-r--r--arch/arm/mach-omap/include/mach/syslib.h23
-rw-r--r--arch/arm/mach-omap/include/mach/xload.h16
-rw-r--r--arch/arm/mach-omap/omap-uart.c36
-rw-r--r--arch/arm/mach-omap/omap3_generic.c40
-rw-r--r--arch/arm/mach-omap/omap4_clock.c380
-rw-r--r--arch/arm/mach-omap/omap4_generic.c420
-rw-r--r--arch/arm/mach-omap/syslib.c20
-rw-r--r--arch/arm/mach-omap/xload.c54
-rw-r--r--arch/nios2/boards/generic/generic.c11
-rw-r--r--arch/nios2/lib/Makefile1
-rw-r--r--arch/nios2/lib/bootm.c83
-rw-r--r--commands/Kconfig27
-rw-r--r--commands/Makefile3
-rw-r--r--commands/cp.c3
-rw-r--r--commands/loadenv.c2
-rw-r--r--commands/nand.c258
-rw-r--r--commands/saveenv.c2
-rw-r--r--commands/usb.c41
-rw-r--r--common/Kconfig42
-rw-r--r--common/Makefile10
-rw-r--r--common/block.c263
-rw-r--r--common/command.c4
-rw-r--r--common/console.c10
-rw-r--r--common/console_simple.c2
-rw-r--r--common/dlmalloc.c50
-rw-r--r--common/dummy_malloc.c26
-rw-r--r--common/environment.c2
-rw-r--r--common/hush.c15
-rw-r--r--common/memory.c71
-rw-r--r--common/startup.c14
-rw-r--r--common/version.c13
-rw-r--r--drivers/ata/Kconfig5
-rw-r--r--drivers/ata/disk_drive.c199
-rw-r--r--drivers/mci/Kconfig12
-rw-r--r--drivers/mci/Makefile1
-rw-r--r--drivers/mci/mci-core.c54
-rw-r--r--drivers/mci/omap_hsmmc.c585
-rw-r--r--drivers/mtd/nand/Kconfig48
-rw-r--r--drivers/mtd/nand/Makefile10
-rw-r--r--drivers/mtd/nand/nand-bb.c291
-rw-r--r--drivers/mtd/nand/nand.c53
-rw-r--r--drivers/mtd/nand/nand.h31
-rw-r--r--drivers/mtd/nand/nand_base.c1321
-rw-r--r--drivers/mtd/nand/nand_bbt.c9
-rw-r--r--drivers/mtd/nand/nand_hwecc.c103
-rw-r--r--drivers/mtd/nand/nand_hwecc_syndrome.c225
-rw-r--r--drivers/mtd/nand/nand_ids.c145
-rw-r--r--drivers/mtd/nand/nand_omap_bch_decoder.c389
-rw-r--r--drivers/mtd/nand/nand_omap_gpmc.c508
-rw-r--r--drivers/mtd/nand/nand_swecc.c94
-rw-r--r--drivers/mtd/nand/nand_util.c858
-rw-r--r--drivers/mtd/nand/nand_write.c746
-rw-r--r--drivers/mtd/ubi/cdev.c12
-rw-r--r--drivers/net/Kconfig16
-rw-r--r--drivers/net/Makefile5
-rw-r--r--drivers/net/altera_tse.c579
-rw-r--r--drivers/net/altera_tse.h303
-rw-r--r--drivers/net/smc911x.c2
-rw-r--r--drivers/net/usb/Kconfig4
-rw-r--r--drivers/net/usb/Makefile1
-rw-r--r--drivers/net/usb/smsc95xx.c938
-rw-r--r--drivers/net/usb/smsc95xx.h256
-rw-r--r--drivers/serial/Kconfig5
-rw-r--r--drivers/serial/Makefile3
-rw-r--r--drivers/serial/serial_altera.c95
-rw-r--r--drivers/serial/serial_ns16550.c4
-rw-r--r--drivers/usb/core/usb.c21
-rw-r--r--fs/Kconfig2
-rw-r--r--fs/Makefile2
-rw-r--r--fs/cramfs/cramfs.c1
-rw-r--r--fs/devfs-core.c236
-rw-r--r--fs/devfs.c177
-rw-r--r--fs/fat/Kconfig15
-rw-r--r--fs/fat/Makefile1
-rw-r--r--fs/fat/diskio.h78
-rw-r--r--fs/fat/fat.c434
-rw-r--r--fs/fat/ff.c2761
-rw-r--r--fs/fat/ff.h239
-rw-r--r--fs/fat/ffconf.h145
-rw-r--r--fs/fat/integer.h28
-rw-r--r--fs/fs.c44
-rw-r--r--fs/ramfs.c1
-rw-r--r--include/asm-generic/sections.h3
-rw-r--r--include/block.h32
-rw-r--r--include/common.h1
-rw-r--r--include/driver.h10
-rw-r--r--include/environment.h15
-rw-r--r--include/fs.h7
-rw-r--r--include/kfifo.h2
-rw-r--r--include/libbb.h2
-rw-r--r--include/linux/mtd/compat.h46
-rw-r--r--include/linux/mtd/mtd.h4
-rw-r--r--include/malloc.h1
-rw-r--r--include/nand.h5
-rw-r--r--include/net.h8
-rw-r--r--include/usb/usb.h2
-rw-r--r--lib/copy_file.c15
-rw-r--r--lib/kfifo.c2
-rw-r--r--lib/libbb.c13
-rw-r--r--net/dhcp.c4
-rw-r--r--net/dns.c4
-rw-r--r--net/eth.c6
-rw-r--r--net/net.c17
-rw-r--r--net/netconsole.c4
-rw-r--r--net/nfs.c4
-rw-r--r--net/ping.c4
-rw-r--r--net/tftp.c4
-rw-r--r--scripts/.gitignore3
-rw-r--r--scripts/Makefile1
-rw-r--r--scripts/kallsyms.c6
-rw-r--r--scripts/omap_signGP.c313
159 files changed, 14313 insertions, 3710 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index aae0e992..6b2b4007 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -21,6 +21,11 @@ config ARM
config ARM_AMBA
bool
+config ARM_LINUX
+ bool
+ default y
+ depends on CMD_BOOTZ || CMD_BOOTU || CMD_BOOTM
+
menu "System Type"
choice
@@ -115,9 +120,14 @@ config ARM_OPTIMZED_STRING_FUNCTIONS
These functions work much faster than the normal versions but
increase your binary size.
+config ARM_EXCEPTIONS
+ bool "enable arm exception handling support"
+ default y
+
config ARM_UNWIND
bool "enable stack unwinding support"
depends on AEABI
+ depends on ARM_EXCEPTIONS
help
This option enables stack unwinding support in barebox
using the information automatically generated by the
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 697c783f..21d6157f 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -83,7 +83,11 @@ board-$(CONFIG_MACH_MMCCPU) := mmccpu
board-$(CONFIG_MACH_MX1ADS) := mx1ads
board-$(CONFIG_MACH_NOMADIK_8815NHK) := nhk8815
board-$(CONFIG_MACH_NXDB500) := netx
-board-$(CONFIG_ARCH_OMAP) := omap
+board-$(CONFIG_MACH_OMAP343xSDP) := omap
+board-$(CONFIG_MACH_BEAGLE) := omap
+board-$(CONFIG_MACH_OMAP3EVM) := omap
+board-$(CONFIG_MACH_PANDA) := panda
+board-$(CONFIG_MACH_PCM049) := pcm049
board-$(CONFIG_MACH_PCA100) := phycard-i.MX27
board-$(CONFIG_MACH_PCM037) := pcm037
board-$(CONFIG_MACH_PCM038) := pcm038
@@ -132,6 +136,14 @@ ifeq ($(machine-y),netx)
KBUILD_IMAGE := barebox.netx
endif
+barebox.bin.ift: barebox.bin
+ @echo " IFT " $@
+ $(Q)scripts/omap_signGP barebox.bin $(TEXT_BASE) 1
+
+ifeq ($(CONFIG_OMAP_BUILD_IFT),y)
+KBUILD_IMAGE := barebox.bin.ift
+endif
+
all: $(KBUILD_IMAGE)
archprepare: maketools
diff --git a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c
index 73bb2e10..f0eb0886 100644
--- a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c
+++ b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c
@@ -173,8 +173,6 @@ postcore_initcall(eukrea_cpuimx35_mmu_init);
static int eukrea_cpuimx35_devices_init(void)
{
- unsigned int tmp;
-
imx35_add_nand(&nand_info);
devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw");
diff --git a/arch/arm/boards/freescale-mx35-3-stack/3stack.c b/arch/arm/boards/freescale-mx35-3-stack/3stack.c
index 127bfb40..03960a4c 100644
--- a/arch/arm/boards/freescale-mx35-3-stack/3stack.c
+++ b/arch/arm/boards/freescale-mx35-3-stack/3stack.c
@@ -207,6 +207,8 @@ static int f3s_devices_init(void)
imx35_add_fec(&fec_info);
register_device(&smc911x_dev);
+ imx35_add_mmc0(NULL);
+
register_device(&sdram_dev);
imx35_add_fb(&ipu_fb_data);
diff --git a/arch/arm/boards/karo-tx25/lowlevel.c b/arch/arm/boards/karo-tx25/lowlevel.c
index 86319d72..868ba08d 100644
--- a/arch/arm/boards/karo-tx25/lowlevel.c
+++ b/arch/arm/boards/karo-tx25/lowlevel.c
@@ -72,7 +72,6 @@ static inline void __bare_init setup_sdram(uint32_t base, uint32_t esdctl,
void __bare_init __naked board_init_lowlevel(void)
{
uint32_t r;
- int i;
#ifdef CONFIG_NAND_IMX_BOOT
unsigned int *trg, *src;
#endif
diff --git a/arch/arm/boards/omap/Kconfig b/arch/arm/boards/omap/Kconfig
deleted file mode 100644
index d6120647..00000000
--- a/arch/arm/boards/omap/Kconfig
+++ /dev/null
@@ -1,93 +0,0 @@
-# OMAP based Board Specific Configuration file
-#
-# (C) Copyright 2008
-# OMAP Architecture specific features
-# Texas Instruments, <www.ti.com>
-# Nishanth Menon <x0nishan@ti.com>
-#
-# 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
-
-config ARCH_TEXT_BASE
- hex
- default 0x80e80000 if MACH_OMAP343xSDP
- default 0x80e80000 if MACH_BEAGLE
-
-menu "OMAP Platform Features"
-
-config BOARDINFO
- default "Texas Instrument's SDP343x" if MACH_OMAP343xSDP
- default "Texas Instrument's Beagle" if MACH_BEAGLE
- default "Texas Instrument's OMAP3EVM" if MACH_OMAP3EVM
-
-choice
- prompt "Select OMAP platform"
-
-config MACH_OMAP343xSDP
- bool "Texas Instrument's SDP343x"
- select MACH_HAS_LOWLEVEL_INIT
- select OMAP_CLOCK_ALL
- select HAS_OMAP_NAND
- help
- Say Y here if you are using SDP343x platform
-
-config MACH_BEAGLE
- bool "Texas Instrument's Beagle Board"
- select MACH_HAS_LOWLEVEL_INIT
- select OMAP_CLOCK_ALL
- select HAS_OMAP_NAND
- help
- Say Y here if you are using Beagle Board
-
-config MACH_OMAP3EVM
- bool "Texas Instrument's OMAP3 EVM"
- select MACH_HAS_LOWLEVEL_INIT
- select OMAP_CLOCK_ALL
- select HAS_OMAP_NAND
- help
- Say Y here if you are using OMAP3EVM
-
-endchoice
-
-if MACH_OMAP3EVM
- choice
- prompt "Select UART"
-
- config OMAP3EVM_UART1
- bool "Use UART1"
- depends on MACH_OMAP3EVM
- help
- Say Y here if you would like to use UART1 as console.
-
- config OMAP3EVM_UART3
- bool "Use UART3"
- depends on MACH_OMAP3EVM
- help
- Say Y here if you would like to use UART3 as console.
- endchoice
-endif
-
-config MACH_OMAP_ADVANCED_MUX
- bool "Enable advanced pin muxing"
- depends on MACH_OMAP343xSDP
- default n
- help
- Say Y here if you would like to have complete pin muxing to be
- done at boot time
-
-config HAS_OMAP_NAND
- bool
-
-endmenu
diff --git a/arch/arm/boards/omap/Makefile b/arch/arm/boards/omap/Makefile
index 1e74e241..8e0418cc 100644
--- a/arch/arm/boards/omap/Makefile
+++ b/arch/arm/boards/omap/Makefile
@@ -24,5 +24,3 @@ obj-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += platform.o
obj-$(CONFIG_MACH_OMAP343xSDP) += board-sdp343x.o
obj-$(CONFIG_MACH_BEAGLE) += board-beagle.o
obj-$(CONFIG_MACH_OMAP3EVM) += board-omap3evm.o
-obj-y += devices-gpmc-nand.o
-
diff --git a/arch/arm/boards/omap/board-beagle.c b/arch/arm/boards/omap/board-beagle.c
index 6de2cce7..ced3df74 100644
--- a/arch/arm/boards/omap/board-beagle.c
+++ b/arch/arm/boards/omap/board-beagle.c
@@ -56,6 +56,7 @@
#include <console.h>
#include <init.h>
#include <driver.h>
+#include <sizes.h>
#include <asm/io.h>
#include <ns16550.h>
#include <asm/armlinux.h>
@@ -72,6 +73,7 @@
#include <i2c/i2c.h>
#include <linux/err.h>
#include <usb/ehci.h>
+#include <mach/xload.h>
#include "board.h"
/******************** Board Boot Time *******************/
@@ -313,6 +315,13 @@ static struct i2c_board_info i2c_devices[] = {
},
};
+static struct device_d hsmmc_dev = {
+ .id = -1,
+ .name = "omap-hsmmc",
+ .map_base = 0x4809C000,
+ .size = SZ_4K,
+};
+
static int beagle_devices_init(void)
{
int ret;
@@ -332,7 +341,9 @@ static int beagle_devices_init(void)
/* WP is made high and WAIT1 active Low */
gpmc_generic_init(0x10);
#endif
- gpmc_generic_nand_devices_init(0, 16, 1);
+ gpmc_generic_nand_devices_init(0, 16, OMAP_ECC_HAMMING_CODE_HW_ROMCODE);
+
+ register_device(&hsmmc_dev);
armlinux_add_dram(&sdram_dev);
armlinux_set_bootparams((void *)0x80000100);
@@ -341,3 +352,34 @@ failed:
return ret;
}
device_initcall(beagle_devices_init);
+
+#ifdef CONFIG_SHELL_NONE
+
+int run_shell(void)
+{
+ int (*func)(void) = NULL;
+
+ switch (omap3_bootsrc()) {
+ case OMAP_BOOTSRC_MMC1:
+ printf("booting from MMC1\n");
+ func = omap_xload_boot_mmc();
+ break;
+ case OMAP_BOOTSRC_UNKNOWN:
+ printf("unknown boot source. Fall back to nand\n");
+ case OMAP_BOOTSRC_NAND:
+ printf("booting from NAND\n");
+ func = omap_xload_boot_nand(SZ_128K, SZ_256K);
+ break;
+ }
+
+ if (!func) {
+ printf("booting failed\n");
+ while (1);
+ }
+
+ shutdown_barebox();
+ func();
+
+ while (1);
+}
+#endif
diff --git a/arch/arm/boards/panda/Makefile b/arch/arm/boards/panda/Makefile
new file mode 100644
index 00000000..c55e26e0
--- /dev/null
+++ b/arch/arm/boards/panda/Makefile
@@ -0,0 +1 @@
+obj-y += board.o lowlevel.o mux.o
diff --git a/arch/arm/boards/panda/board.c b/arch/arm/boards/panda/board.c
new file mode 100644
index 00000000..ff05f9e2
--- /dev/null
+++ b/arch/arm/boards/panda/board.c
@@ -0,0 +1,230 @@
+#include <common.h>
+#include <console.h>
+#include <init.h>
+#include <fs.h>
+#include <driver.h>
+#include <asm/io.h>
+#include <ns16550.h>
+#include <asm/armlinux.h>
+#include <linux/stat.h>
+#include <generated/mach-types.h>
+#include <mach/silicon.h>
+#include <mach/sdrc.h>
+#include <mach/sys_info.h>
+#include <mach/syslib.h>
+#include <mach/control.h>
+#include <usb/ehci.h>
+#include <linux/err.h>
+#include <sizes.h>
+#include <asm/mmu.h>
+#include <mach/gpio.h>
+#include <environment.h>
+#include <mach/xload.h>
+
+static int board_revision;
+
+#define GPIO_HUB_POWER 1
+#define GPIO_HUB_NRESET_39 39
+#define GPIO_HUB_NRESET_62 62
+#define GPIO_BOARD_ID0 182
+#define GPIO_BOARD_ID1 101
+#define GPIO_BOARD_ID2 171
+
+static struct NS16550_plat serial_plat = {
+ .clock = 48000000, /* 48MHz (APLL96/2) */
+ .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
+ .reg_read = omap_uart_read,
+ .reg_write = omap_uart_write,
+};
+
+static struct device_d panda_serial_device = {
+ .id = -1,
+ .name = "serial_ns16550",
+ .map_base = OMAP44XX_UART3_BASE,
+ .size = 1024,
+ .platform_data = (void *)&serial_plat,
+};
+
+static int panda_console_init(void)
+{
+ /* Register the serial port */
+ return register_device(&panda_serial_device);
+}
+console_initcall(panda_console_init);
+
+static struct memory_platform_data sram_pdata = {
+ .name = "ram0",
+ .flags = DEVFS_RDWR,
+};
+
+static struct device_d sdram_dev = {
+ .id = -1,
+ .name = "mem",
+ .map_base = 0x80000000,
+ .size = SZ_1G,
+ .platform_data = &sram_pdata,
+};
+
+#ifdef CONFIG_MMU
+static int panda_mmu_init(void)
+{
+ mmu_init();
+
+ arm_create_section(0x80000000, 0x80000000, 256, PMD_SECT_DEF_CACHED);
+ arm_create_section(0x90000000, 0x80000000, 256, PMD_SECT_DEF_UNCACHED);
+
+ mmu_enable();
+
+ return 0;
+}
+device_initcall(panda_mmu_init);
+#endif
+
+static struct ehci_platform_data ehci_pdata = {
+ .flags = 0,
+ .hccr_offset = 0x0,
+ .hcor_offset = 0x10,
+};
+
+static struct device_d usbh_dev = {
+ .id = -1,
+ .name = "ehci",
+ .map_base = 0x4a064c00,
+ .size = 4 * 1024,
+ .platform_data = &ehci_pdata,
+};
+
+static void panda_ehci_init(void)
+{
+ u32 val;
+ int hub_nreset;
+
+ if (board_revision)
+ hub_nreset = GPIO_HUB_NRESET_62;
+ else
+ hub_nreset = GPIO_HUB_NRESET_39;
+
+ /* disable the power to the usb hub prior to init */
+ gpio_direction_output(GPIO_HUB_POWER, 0);
+ gpio_set_value(GPIO_HUB_POWER, 0);
+
+ /* reset phy+hub */
+ gpio_direction_output(hub_nreset, 0);
+ gpio_set_value(hub_nreset, 0);
+ gpio_set_value(hub_nreset, 1);
+ val = readl(0x4a009358);
+ val |= (1 << 24);
+ writel(val, 0x4a009358);
+ writel(0x7, 0x4a008180);
+ mdelay(10);
+
+ writel(0x00000014, 0x4a064010);
+ writel(0x8000001c, 0x4a064040);
+
+ /* enable power to hub */
+ gpio_set_value(GPIO_HUB_POWER, 1);
+
+ register_device(&usbh_dev);
+}
+
+static void __init panda_boardrev_init(void)
+{
+ board_revision = gpio_get_value(GPIO_BOARD_ID0);
+ board_revision |= (gpio_get_value(GPIO_BOARD_ID1)<<1);
+ board_revision |= (gpio_get_value(GPIO_BOARD_ID2)<<2);
+
+ pr_info("PandaBoard Revision: %03d\n", board_revision);
+}
+
+static struct device_d hsmmc_dev = {
+ .id = -1,
+ .name = "omap-hsmmc",
+ .map_base = 0x4809C100,
+ .size = SZ_4K,
+};
+
+static int panda_devices_init(void)
+{
+ panda_boardrev_init();
+
+ if (gpio_get_value(182)) {
+ /* enable software ioreq */
+ sr32(OMAP44XX_SCRM_AUXCLK3, 8, 1, 0x1);
+ /* set for sys_clk (38.4MHz) */
+ sr32(OMAP44XX_SCRM_AUXCLK3, 1, 2, 0x0);
+ /* set divisor to 2 */
+ sr32(OMAP44XX_SCRM_AUXCLK3, 16, 4, 0x1);
+ /* set the clock source to active */
+ sr32(OMAP44XX_SCRM_ALTCLKSRC, 0, 1, 0x1);
+ /* enable clocks */
+ sr32(OMAP44XX_SCRM_ALTCLKSRC, 2, 2, 0x3);
+ } else {
+ /* enable software ioreq */
+ sr32(OMAP44XX_SCRM_AUXCLK1, 8, 1, 0x1);
+ /* set for PER_DPLL */
+ sr32(OMAP44XX_SCRM_AUXCLK1, 1, 2, 0x2);
+ /* set divisor to 16 */
+ sr32(OMAP44XX_SCRM_AUXCLK1, 16, 4, 0xf);
+ /* set the clock source to active */
+ sr32(OMAP44XX_SCRM_ALTCLKSRC, 0, 1, 0x1);
+ /* enable clocks */
+ sr32(OMAP44XX_SCRM_ALTCLKSRC, 2, 2, 0x3);
+ }
+
+ register_device(&sdram_dev);
+ register_device(&hsmmc_dev);
+ panda_ehci_init();
+
+ armlinux_add_dram(&sdram_dev);
+ armlinux_set_bootparams((void *)0x80000100);
+ armlinux_set_architecture(MACH_TYPE_OMAP4_PANDA);
+
+ return 0;
+}
+device_initcall(panda_devices_init);
+
+#ifdef CONFIG_DEFAULT_ENVIRONMENT
+static int panda_env_init(void)
+{
+ struct stat s;
+ char *diskdev = "/dev/disk0.0";
+ int ret;
+
+ ret = stat(diskdev, &s);
+ if (ret) {
+ printf("no %s. using default env\n", diskdev);
+ return 0;
+ }
+
+ mkdir ("/boot", 0666);
+ ret = mount(diskdev, "fat", "/boot");
+ if (ret) {
+ printf("failed to mount %s\n", diskdev);
+ return 0;
+ }
+
+ default_environment_path = "/boot/bareboxenv";
+
+ return 0;
+}
+late_initcall(panda_env_init);
+#endif
+
+
+#ifdef CONFIG_SHELL_NONE
+int run_shell(void)
+{
+ int (*func)(void);
+
+ func = omap_xload_boot_mmc();
+ if (!func) {
+ printf("booting failed\n");
+ while (1);
+ }
+
+ shutdown_barebox();
+ func();
+
+ while (1);
+}
+#endif
diff --git a/arch/arm/boards/panda/config.h b/arch/arm/boards/panda/config.h
new file mode 100644
index 00000000..da84fa5f
--- /dev/null
+++ b/arch/arm/boards/panda/config.h
@@ -0,0 +1 @@
+/* nothing */
diff --git a/arch/arm/boards/panda/env/config b/arch/arm/boards/panda/env/config
new file mode 100644
index 00000000..363208e9
--- /dev/null
+++ b/arch/arm/boards/panda/env/config
@@ -0,0 +1,45 @@
+#!/bin/sh
+
+machine=panda
+user=
+
+# use 'dhcp' to do dhcp in barebox and in kernel
+# use 'none' if you want to skip kernel ip autoconfiguration
+ip=dhcp
+
+# or set your networking parameters here
+#eth0.ipaddr=a.b.c.d
+#eth0.netmask=a.b.c.d
+#eth0.gateway=a.b.c.d
+#eth0.serverip=a.b.c.d
+
+# can be either 'nfs', 'tftp', 'nor' or 'nand'
+kernel_loc=tftp
+# can be either 'net', 'nor', 'nand' or 'initrd'
+rootfs_loc=net
+
+# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo
+kernelimage_type=zimage
+kernelimage=zImage-$machine
+#kernelimage_type=uimage
+#kernelimage=uImage-$machine
+#kernelimage_type=raw
+#kernelimage=Image-$machine
+#kernelimage_type=raw_lzo
+#kernelimage=Image-${machine}.lzo
+
+if [ -n $user ]; then
+ kernelimage="$user"-"$kernelimage"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/$machine"
+ rootfsimage="$user"-"$rootfsimage"
+else
+ nfsroot="$eth0.serverip:/path/to/nfs/root"
+fi
+
+autoboot_timeout=3
+
+bootargs="console=ttyO2,115200"
+
+# set a fancy prompt (if support is compiled in)
+PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m "
+
diff --git a/arch/arm/boards/panda/lowlevel.c b/arch/arm/boards/panda/lowlevel.c
new file mode 100644
index 00000000..cc0c374a
--- /dev/null
+++ b/arch/arm/boards/panda/lowlevel.c
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2004-2009
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * 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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/io.h>
+#include <mach/omap4-mux.h>
+#include <mach/omap4-silicon.h>
+#include <mach/omap4-clock.h>
+#include <mach/syslib.h>
+#include <asm/barebox-arm.h>
+
+void set_muxconf_regs(void);
+
+static const struct ddr_regs ddr_regs_400_mhz_2cs = {
+ /* tRRD changed from 10ns to 12.5ns because of the tFAW requirement*/
+ .tim1 = 0x10eb0662,
+ .tim2 = 0x20370dd2,
+ .tim3 = 0x00b1c33f,
+ .phy_ctrl_1 = 0x849FF408,
+ .ref_ctrl = 0x00000618,
+ .config_init = 0x80000eb9,
+ .config_final = 0x80001ab9,
+ .zq_config = 0xD00b3215,
+ .mr1 = 0x83,
+ .mr2 = 0x4
+};
+
+#define I2C_SLAVE 0x12
+
+static int noinline scale_vcores(void)
+{
+ unsigned int rev = omap4_revision();
+
+ /* For VC bypass only VCOREx_CGF_FORCE is necessary and
+ * VCOREx_CFG_VOLTAGE changes can be discarded
+ */
+ writel(0, OMAP44XX_PRM_VC_CFG_I2C_MODE);
+ writel(0x6026, OMAP44XX_PRM_VC_CFG_I2C_CLK);
+
+ /* set VCORE1 force VSEL */
+ omap4_power_i2c_send((0x3A55 << 8) | I2C_SLAVE);
+
+ /* FIXME: set VCORE2 force VSEL, Check the reset value */
+ omap4_power_i2c_send((0x295B << 8) | I2C_SLAVE);
+
+ /* set VCORE3 force VSEL */
+ switch (rev) {
+ case OMAP4430_ES2_0:
+ omap4_power_i2c_send((0x2961 << 8) | I2C_SLAVE);
+ break;
+ case OMAP4430_ES2_1:
+ omap4_power_i2c_send((0x2A61 << 8) | I2C_SLAVE);
+ break;
+ }
+
+ return 0;
+}
+
+static void noinline panda_init_lowlevel(void)
+{
+ struct dpll_param core = OMAP4_CORE_DPLL_PARAM_38M4_DDR400;
+ struct dpll_param mpu = OMAP4_MPU_DPLL_PARAM_38M4_MPU600;
+ struct dpll_param iva = OMAP4_IVA_DPLL_PARAM_38M4;
+ struct dpll_param per = OMAP4_PER_DPLL_PARAM_38M4;
+ struct dpll_param abe = OMAP4_ABE_DPLL_PARAM_38M4;
+ struct dpll_param usb = OMAP4_USB_DPLL_PARAM_38M4;
+
+ writel(CM_SYS_CLKSEL_38M4, CM_SYS_CLKSEL);
+
+ /* Configure all DPLL's at 100% OPP */
+ omap4_configure_mpu_dpll(&mpu);
+ omap4_configure_iva_dpll(&iva);
+ omap4_configure_per_dpll(&per);
+ omap4_configure_abe_dpll(&abe);
+ omap4_configure_usb_dpll(&usb);
+
+ /* Enable all clocks */
+ omap4_enable_all_clocks();
+
+ set_muxconf_regs();
+
+ omap4_ddr_init(&ddr_regs_400_mhz_2cs, &core);
+
+ /* Set VCORE1 = 1.3 V, VCORE2 = VCORE3 = 1.21V */
+ scale_vcores();
+
+ board_init_lowlevel_return();
+}
+
+void board_init_lowlevel(void)
+{
+ u32 r;
+
+ if (get_pc() > 0x80000000)
+ return;
+
+ r = 0x4030d000;
+ __asm__ __volatile__("mov sp, %0" : : "r"(r));
+
+ panda_init_lowlevel();
+}
+
diff --git a/arch/arm/boards/panda/mux.c b/arch/arm/boards/panda/mux.c
new file mode 100644
index 00000000..a0310401
--- /dev/null
+++ b/arch/arm/boards/panda/mux.c
@@ -0,0 +1,257 @@
+#include <common.h>
+#include <init.h>
+#include <asm/io.h>
+#include <mach/omap4-silicon.h>
+#include <mach/omap4-mux.h>
+
+static const struct pad_conf_entry core_padconf_array[] = {
+ { GPMC_AD0, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat0 */ },
+ { GPMC_AD1, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat1 */ },
+ { GPMC_AD2, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat2 */ },
+ { GPMC_AD3, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat3 */ },
+ { GPMC_AD4, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat4 */ },
+ { GPMC_AD5, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat5 */ },
+ { GPMC_AD6, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat6 */ },
+ { GPMC_AD7, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_dat7 */ },
+ { GPMC_AD8, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M3 /* gpio_32 */ },
+ { GPMC_AD9, PTU | IEN | M3 /* gpio_33 */ },
+ { GPMC_AD10, PTU | IEN | M3 /* gpio_34 */ },
+ { GPMC_AD11, PTU | IEN | M3 /* gpio_35 */ },
+ { GPMC_AD12, PTU | IEN | M3 /* gpio_36 */ },
+ { GPMC_AD13, PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M3 /* gpio_37 */ },
+ { GPMC_AD14, PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M3 /* gpio_38 */ },
+ { GPMC_AD15, PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M3 /* gpio_39 */ },
+ { GPMC_A16, M3 /* gpio_40 */ },
+ { GPMC_A17, PTD | M3 /* gpio_41 */ },
+ { GPMC_A18, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row6 */ },
+ { GPMC_A19, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row7 */ },
+ { GPMC_A20, IEN | M3 /* gpio_44 */ },
+ { GPMC_A21, M3 /* gpio_45 */ },
+ { GPMC_A22, M3 /* gpio_46 */ },
+ { GPMC_A23, OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_col7 */ },
+ { GPMC_A24, PTD | M3 /* gpio_48 */ },
+ { GPMC_A25, PTD | M3 /* gpio_49 */ },
+ { GPMC_NCS0, M3 /* gpio_50 */ },
+ { GPMC_NCS1, IEN | M3 /* gpio_51 */ },
+ { GPMC_NCS2, IEN | M3 /* gpio_52 */ },
+ { GPMC_NCS3, IEN | M3 /* gpio_53 */ },
+ { GPMC_NWP, M3 /* gpio_54 */ },
+ { GPMC_CLK, PTD | M3 /* gpio_55 */ },
+ { GPMC_NADV_ALE, M3 /* gpio_56 */ },
+ { GPMC_NOE, PTU | IEN | OFF_EN | OFF_OUT_PTD | M1 /* sdmmc2_clk */ },
+ { GPMC_NWE, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* sdmmc2_cmd */ },
+ { GPMC_NBE0_CLE, M3 /* gpio_59 */ },
+ { GPMC_NBE1, PTD | M3 /* gpio_60 */ },
+ { GPMC_WAIT0, PTU | IEN | M3 /* gpio_61 */ },
+ { GPMC_WAIT1, PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M3 /* gpio_62 */ },
+ { C2C_DATA11, PTD | M3 /* gpio_100 */ },
+ { C2C_DATA12, PTD | IEN | M3 /* gpio_101 */ },
+ { C2C_DATA13, PTD | M3 /* gpio_102 */ },
+ { C2C_DATA14, M1 /* dsi2_te0 */ },
+ { C2C_DATA15, PTD | M3 /* gpio_104 */ },
+ { HDMI_HPD, M0 /* hdmi_hpd */ },
+ { HDMI_CEC, M0 /* hdmi_cec */ },
+ { HDMI_DDC_SCL, PTU | M0 /* hdmi_ddc_scl */ },
+ { HDMI_DDC_SDA, PTU | IEN | M0 /* hdmi_ddc_sda */ },
+ { CSI21_DX0, IEN | M0 /* csi21_dx0 */ },
+ { CSI21_DY0, IEN | M0 /* csi21_dy0 */ },
+ { CSI21_DX1, IEN | M0 /* csi21_dx1 */ },
+ { CSI21_DY1, IEN | M0 /* csi21_dy1 */ },
+ { CSI21_DX2, IEN | M0 /* csi21_dx2 */ },
+ { CSI21_DY2, IEN | M0 /* csi21_dy2 */ },
+ { CSI21_DX3, PTD | M7 /* csi21_dx3 */ },
+ { CSI21_DY3, PTD | M7 /* csi21_dy3 */ },
+ { CSI21_DX4, PTD | OFF_EN | OFF_PD | OFF_IN | M7 /* csi21_dx4 */ },
+ { CSI21_DY4, PTD | OFF_EN | OFF_PD | OFF_IN | M7 /* csi21_dy4 */ },
+ { CSI22_DX0, IEN | M0 /* csi22_dx0 */ },
+ { CSI22_DY0, IEN | M0 /* csi22_dy0 */ },
+ { CSI22_DX1, IEN | M0 /* csi22_dx1 */ },
+ { CSI22_DY1, IEN | M0 /* csi22_dy1 */ },
+ { CAM_SHUTTER, OFF_EN | OFF_PD | OFF_OUT_PTD | M0 /* cam_shutter */ },
+ { CAM_STROBE, OFF_EN | OFF_PD | OFF_OUT_PTD | M0 /* cam_strobe */ },
+ { CAM_GLOBALRESET, PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M3 /* gpio_83 */ },
+ { USBB1_ULPITLL_CLK, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_clk */ },
+ { USBB1_ULPITLL_STP, OFF_EN | OFF_OUT_PTD | M4 /* usbb1_ulpiphy_stp */ },
+ { USBB1_ULPITLL_DIR, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dir */ },
+ { USBB1_ULPITLL_NXT, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_nxt */ },
+ { USBB1_ULPITLL_DAT0, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat0 */ },
+ { USBB1_ULPITLL_DAT1, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat1 */ },
+ { USBB1_ULPITLL_DAT2, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat2 */ },
+ { USBB1_ULPITLL_DAT3, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat3 */ },
+ { USBB1_ULPITLL_DAT4, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat4 */ },
+ { USBB1_ULPITLL_DAT5, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat5 */ },
+ { USBB1_ULPITLL_DAT6, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat6 */ },
+ { USBB1_ULPITLL_DAT7, IEN | OFF_EN | OFF_PD | OFF_IN | M4 /* usbb1_ulpiphy_dat7 */ },
+ { USBB1_HSIC_DATA, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* usbb1_hsic_data */ },
+ { USBB1_HSIC_STROBE, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* usbb1_hsic_strobe */ },
+ { USBC1_ICUSB_DP, IEN | M0 /* usbc1_icusb_dp */ },
+ { USBC1_ICUSB_DM, IEN | M0 /* usbc1_icusb_dm */ },
+ { SDMMC1_CLK, PTU | OFF_EN | OFF_OUT_PTD | M0 /* sdmmc1_clk */ },
+ { SDMMC1_CMD, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_cmd */ },
+ { SDMMC1_DAT0, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat0 */ },
+ { SDMMC1_DAT1, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat1 */ },
+ { SDMMC1_DAT2, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat2 */ },
+ { SDMMC1_DAT3, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat3 */ },
+ { SDMMC1_DAT4, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat4 */ },
+ { SDMMC1_DAT5, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat5 */ },
+ { SDMMC1_DAT6, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat6 */ },
+ { SDMMC1_DAT7, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc1_dat7 */ },
+ { ABE_MCBSP2_CLKX, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_mcbsp2_clkx */ },
+ { ABE_MCBSP2_DR, IEN | OFF_EN | OFF_OUT_PTD | M0 /* abe_mcbsp2_dr */ },
+ { ABE_MCBSP2_DX, OFF_EN | OFF_OUT_PTD | M0 /* abe_mcbsp2_dx */ },
+ { ABE_MCBSP2_FSX, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_mcbsp2_fsx */ },
+ { ABE_MCBSP1_CLKX, IEN | M1 /* abe_slimbus1_clock */ },
+ { ABE_MCBSP1_DR, IEN | M1 /* abe_slimbus1_data */ },
+ { ABE_MCBSP1_DX, OFF_EN | OFF_OUT_PTD | M0 /* abe_mcbsp1_dx */ },
+ { ABE_MCBSP1_FSX, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_mcbsp1_fsx */ },
+ { ABE_PDM_UL_DATA, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_pdm_ul_data */ },
+ { ABE_PDM_DL_DATA, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_pdm_dl_data */ },
+ { ABE_PDM_FRAME, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_pdm_frame */ },
+ { ABE_PDM_LB_CLK, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_pdm_lb_clk */ },
+ { ABE_CLKS, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* abe_clks */ },
+ { ABE_DMIC_CLK1, M0 /* abe_dmic_clk1 */ },
+ { ABE_DMIC_DIN1, IEN | M0 /* abe_dmic_din1 */ },
+ { ABE_DMIC_DIN2, IEN | M0 /* abe_dmic_din2 */ },
+ { ABE_DMIC_DIN3, IEN | M0 /* abe_dmic_din3 */ },
+ { UART2_CTS, PTU | IEN | M0 /* uart2_cts */ },
+ { UART2_RTS, M0 /* uart2_rts */ },
+ { UART2_RX, PTU | IEN | M0 /* uart2_rx */ },
+ { UART2_TX, M0 /* uart2_tx */ },
+ { HDQ_SIO, M3 /* gpio_127 */ },
+ { I2C1_SCL, PTU | IEN | M0 /* i2c1_scl */ },
+ { I2C1_SDA, PTU | IEN | M0 /* i2c1_sda */ },
+ { I2C2_SCL, PTU | IEN | M0 /* i2c2_scl */ },
+ { I2C2_SDA, PTU | IEN | M0 /* i2c2_sda */ },
+ { I2C3_SCL, PTU | IEN | M0 /* i2c3_scl */ },
+ { I2C3_SDA, PTU | IEN | M0 /* i2c3_sda */ },
+ { I2C4_SCL, PTU | IEN | M0 /* i2c4_scl */ },
+ { I2C4_SDA, PTU | IEN | M0 /* i2c4_sda */ },
+ { MCSPI1_CLK, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi1_clk */ },
+ { MCSPI1_SOMI, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi1_somi */ },
+ { MCSPI1_SIMO, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi1_simo */ },
+ { MCSPI1_CS0, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi1_cs0 */ },
+ { MCSPI1_CS1, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M3 /* mcspi1_cs1 */ },
+ { MCSPI1_CS2, PTU | OFF_EN | OFF_OUT_PTU | M3 /* gpio_139 */ },
+ { MCSPI1_CS3, PTU | IEN | M3 /* gpio_140 */ },
+ { UART3_CTS_RCTX, PTU | IEN | M0 /* uart3_tx */ },
+ { UART3_RTS_SD, M0 /* uart3_rts_sd */ },
+ { UART3_RX_IRRX, IEN | M0 /* uart3_rx */ },
+ { UART3_TX_IRTX, M0 /* uart3_tx */ },
+ { SDMMC5_CLK, PTU | IEN | OFF_EN | OFF_OUT_PTD | M0 /* sdmmc5_clk */ },
+ { SDMMC5_CMD, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc5_cmd */ },
+ { SDMMC5_DAT0, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc5_dat0 */ },
+ { SDMMC5_DAT1, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc5_dat1 */ },
+ { SDMMC5_DAT2, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc5_dat2 */ },
+ { SDMMC5_DAT3, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* sdmmc5_dat3 */ },
+ { MCSPI4_CLK, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi4_clk */ },
+ { MCSPI4_SIMO, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi4_simo */ },
+ { MCSPI4_SOMI, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi4_somi */ },
+ { MCSPI4_CS0, PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* mcspi4_cs0 */ },
+ { UART4_RX, IEN | M0 /* uart4_rx */ },
+ { UART4_TX, M0 /* uart4_tx */ },
+ { USBB2_ULPITLL_CLK, IEN | M3 /* gpio_157 */ },
+ { USBB2_ULPITLL_STP, IEN | M5 /* dispc2_data23 */ },
+ { USBB2_ULPITLL_DIR, IEN | M5 /* dispc2_data22 */ },
+ { USBB2_ULPITLL_NXT, IEN | M5 /* dispc2_data21 */ },
+ { USBB2_ULPITLL_DAT0, IEN | M5 /* dispc2_data20 */ },
+ { USBB2_ULPITLL_DAT1, IEN | M5 /* dispc2_data19 */ },
+ { USBB2_ULPITLL_DAT2, IEN | M5 /* dispc2_data18 */ },
+ { USBB2_ULPITLL_DAT3, IEN | M5 /* dispc2_data15 */ },
+ { USBB2_ULPITLL_DAT4, IEN | M5 /* dispc2_data14 */ },
+ { USBB2_ULPITLL_DAT5, IEN | M5 /* dispc2_data13 */ },
+ { USBB2_ULPITLL_DAT6, IEN | M5 /* dispc2_data12 */ },
+ { USBB2_ULPITLL_DAT7, IEN | M5 /* dispc2_data11 */ },
+ { USBB2_HSIC_DATA, PTD | OFF_EN | OFF_OUT_PTU | M3 /* gpio_169 */ },
+ { USBB2_HSIC_STROBE, PTD | OFF_EN | OFF_OUT_PTU | M3 /* gpio_170 */ },
+ { UNIPRO_TX0, PTD | IEN | M3 /* gpio_171 */ },
+ { UNIPRO_TY0, OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_col1 */ },
+ { UNIPRO_TX1, OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_col2 */ },
+ { UNIPRO_TY1, OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_col3 */ },
+ { UNIPRO_TX2, PTU | IEN | M3 /* gpio_0 */ },
+ { UNIPRO_TY2, PTU | IEN | M3 /* gpio_1 */ },
+ { UNIPRO_RX0, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row0 */ },
+ { UNIPRO_RY0, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row1 */ },
+ { UNIPRO_RX1, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row2 */ },
+ { UNIPRO_RY1, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row3 */ },
+ { UNIPRO_RX2, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row4 */ },
+ { UNIPRO_RY2, PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1 /* kpd_row5 */ },
+ { USBA0_OTG_CE, PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M0 /* usba0_otg_ce */ },
+ { USBA0_OTG_DP, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* usba0_otg_dp */ },
+ { USBA0_OTG_DM, IEN | OFF_EN | OFF_PD | OFF_IN | M0 /* usba0_otg_dm */ },
+ { FREF_CLK1_OUT, M0 /* fref_clk1_out */ },
+ { FREF_CLK2_OUT, PTD | IEN | M3 /* gpio_182 */ },
+ { SYS_NIRQ1, PTU | IEN | M0 /* sys_nirq1 */ },
+ { SYS_NIRQ2, PTU | IEN | M0 /* sys_nirq2 */ },
+ { SYS_BOOT0, PTU | IEN | M3 /* gpio_184 */ },
+ { SYS_BOOT1, M3 /* gpio_185 */ },
+ { SYS_BOOT2, PTD | IEN | M3 /* gpio_186 */ },
+ { SYS_BOOT3, M3 /* gpio_187 */ },
+ { SYS_BOOT4, M3 /* gpio_188 */ },
+ { SYS_BOOT5, PTD | IEN | M3 /* gpio_189 */ },
+ { DPM_EMU0, IEN | M0 /* dpm_emu0 */ },
+ { DPM_EMU1, IEN | M0 /* dpm_emu1 */ },
+ { DPM_EMU2, IEN | M0 /* dpm_emu2 */ },
+ { DPM_EMU3, IEN | M5 /* dispc2_data10 */ },
+ { DPM_EMU4, IEN | M5 /* dispc2_data9 */ },
+ { DPM_EMU5, IEN | M5 /* dispc2_data16 */ },
+ { DPM_EMU6, IEN | M5 /* dispc2_data17 */ },
+ { DPM_EMU7, IEN | M5 /* dispc2_hsync */ },
+ { DPM_EMU8, IEN | M5 /* dispc2_pclk */ },
+ { DPM_EMU9, IEN | M5 /* dispc2_vsync */ },
+ { DPM_EMU10, IEN | M5 /* dispc2_de */ },
+ { DPM_EMU11, IEN | M5 /* dispc2_data8 */ },
+ { DPM_EMU12, IEN | M5 /* dispc2_data7 */ },
+ { DPM_EMU13, IEN | M5 /* dispc2_data6 */ },
+ { DPM_EMU14, IEN | M5 /* dispc2_data5 */ },
+ { DPM_EMU15, IEN | M5 /* dispc2_data4 */ },
+ { DPM_EMU16, M3 /* gpio_27 */ },
+ { DPM_EMU17, IEN | M5 /* dispc2_data2 */ },
+ { DPM_EMU18, IEN | M5 /* dispc2_data1 */ },
+ { DPM_EMU19, IEN | M5 /* dispc2_data0 */ },
+};
+
+static const struct pad_conf_entry wkup_padconf_array[] = {
+ { PAD0_SIM_IO, IEN | M0 /* sim_io */ },
+ { PAD1_SIM_CLK, M0 /* sim_clk */ },
+ { PAD0_SIM_RESET, M0 /* sim_reset */ },
+ { PAD1_SIM_CD, PTU | IEN | M0 /* sim_cd */ },
+ { PAD0_SIM_PWRCTRL, M0 /* sim_pwrctrl */ },
+ { PAD1_SR_SCL, PTU | IEN | M0 /* sr_scl */ },
+ { PAD0_SR_SDA, PTU | IEN | M0 /* sr_sda */ },
+ { PAD1_FREF_XTAL_IN, M0 /* # */ },
+ { PAD0_FREF_SLICER_IN, M0 /* fref_slicer_in */ },
+ { PAD1_FREF_CLK_IOREQ, M0 /* fref_clk_ioreq */ },
+ { PAD0_FREF_CLK0_OUT, M2 /* sys_drm_msecure */ },
+ { PAD1_FREF_CLK3_REQ, PTU | IEN | M0 /* # */ },
+ { PAD0_FREF_CLK3_OUT, M0 /* fref_clk3_out */ },
+ { PAD1_FREF_CLK4_REQ, PTU | IEN | M0 /* # */ },
+ { PAD0_FREF_CLK4_OUT, M0 /* # */ },
+ { PAD1_SYS_32K, IEN | M0 /* sys_32k */ },
+ { PAD0_SYS_NRESPWRON, M0 /* sys_nrespwron */ },
+ { PAD1_SYS_NRESWARM, M0 /* sys_nreswarm */ },
+ { PAD0_SYS_PWR_REQ, PTU | M0 /* sys_pwr_req */ },
+ { PAD1_SYS_PWRON_RESET, M3 /* gpio_wk29 */ },
+ { PAD0_SYS_BOOT6, IEN | M3 /* gpio_wk9 */ },
+ { PAD1_SYS_BOOT7, IEN | M3 /* gpio_wk10 */ },
+ { PAD1_FREF_CLK3_REQ, M3 /* gpio_wk30 */ },
+ { PAD1_FREF_CLK4_REQ, M3 /* gpio_wk7 */ },
+ { PAD0_FREF_CLK4_OUT, M3 /* gpio_wk8 */ },
+};
+
+static void do_set_mux(u32 base, struct pad_conf_entry const *array, int size)
+{
+ int i;
+ struct pad_conf_entry *pad = (struct pad_conf_entry *) array;
+
+ for (i = 0; i < size; i++, pad++)
+ writew(pad->val, base + pad->offset);
+}
+
+void set_muxconf_regs(void)
+{
+ do_set_mux(OMAP44XX_CONTROL_PADCONF_CORE, core_padconf_array,
+ ARRAY_SIZE(core_padconf_array));
+
+ do_set_mux(OMAP44XX_CONTROL_PADCONF_WKUP, wkup_padconf_array,
+ ARRAY_SIZE(wkup_padconf_array));
+}
diff --git a/arch/arm/boards/pcm049/Makefile b/arch/arm/boards/pcm049/Makefile
new file mode 100644
index 00000000..1bb7212a
--- /dev/null
+++ b/arch/arm/boards/pcm049/Makefile
@@ -0,0 +1 @@
+obj-y += board.o mux.o lowlevel.o
diff --git a/arch/arm/boards/pcm049/board.c b/arch/arm/boards/pcm049/board.c
new file mode 100644
index 00000000..a33a877f
--- /dev/null
+++ b/arch/arm/boards/pcm049/board.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix
+ *
+ * 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 <console.h>
+#include <init.h>
+#include <driver.h>
+#include <asm/io.h>
+#include <ns16550.h>
+#include <asm/armlinux.h>
+#include <generated/mach-types.h>
+#include <mach/silicon.h>
+#include <mach/sdrc.h>
+#include <mach/sys_info.h>
+#include <mach/syslib.h>
+#include <mach/control.h>
+#include <linux/err.h>
+#include <sizes.h>
+#include <partition.h>
+#include <nand.h>
+#include <asm/mmu.h>
+#include <mach/gpio.h>
+#include <mach/gpmc.h>
+#include <mach/gpmc_nand.h>
+#include <mach/xload.h>
+
+static struct NS16550_plat serial_plat = {
+ .clock = 48000000, /* 48MHz (APLL96/2) */
+ .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR,
+ .reg_read = omap_uart_read,
+ .reg_write = omap_uart_write,
+};
+
+static struct device_d pcm049_serial_device = {
+ .id = -1,
+ .name = "serial_ns16550",
+ .map_base = OMAP44XX_UART3_BASE,
+ .size = 1024,
+ .platform_data = (void *)&serial_plat,
+};
+
+static int pcm049_console_init(void)
+{
+ /* Register the serial port */
+ return register_device(&pcm049_serial_device);
+}
+console_initcall(pcm049_console_init);
+
+static struct memory_platform_data sram_pdata = {
+ .name = "sram0",
+ .flags = DEVFS_RDWR,
+};
+
+static struct device_d sram_dev = {
+ .id = -1,
+ .name = "mem",
+ .map_base = 0x40300000,
+ .size = 48 * 1024,
+ .platform_data = &sram_pdata,
+};
+
+static struct memory_platform_data sdram_pdata = {
+ .name = "ram0",
+ .flags = DEVFS_RDWR,
+};
+
+static struct device_d sdram_dev = {
+ .id = -1,
+ .name = "mem",
+ .map_base = 0x80000000,
+ .size = SZ_512M,
+ .platform_data = &sdram_pdata,
+};
+
+#ifdef CONFIG_MMU
+static int pcm049_mmu_init(void)
+{
+ mmu_init();
+
+ arm_create_section(0x80000000, 0x80000000, 256, PMD_SECT_DEF_CACHED);
+ /* warning: This shadows the second half of our ram */
+ arm_create_section(0x90000000, 0x80000000, 256, PMD_SECT_DEF_UNCACHED);
+
+ mmu_enable();
+
+ return 0;
+}
+device_initcall(pcm049_mmu_init);
+#endif
+
+static struct device_d hsmmc_dev = {
+ .id = -1,
+ .name = "omap-hsmmc",
+ .map_base = 0x4809C100,
+ .size = SZ_4K,
+};
+
+static struct device_d smc911x_dev = {
+ .id = -1,
+ .name = "smc911x",
+ .map_base = 0x2C000000,
+ .size = 0x4000,
+};
+
+static struct gpmc_config net_cfg = {
+ .cfg = {
+ 0x00001000, /* CONF1 */
+ 0x001e1e01, /* CONF2 */
+ 0x00080300, /* CONF3 */
+ 0x1c091c09, /* CONF4 */
+ 0x04181f1f, /* CONF5 */
+ 0x00000FCF, /* CONF6 */
+ },
+ .base = 0x2C000000,
+ .size = GPMC_SIZE_16M,
+};
+
+static void pcm049_network_init(void)
+{
+ gpmc_cs_config(5, &net_cfg);
+
+ register_device(&smc911x_dev);
+}
+
+static int pcm049_devices_init(void)
+{
+ register_device(&sdram_dev);
+ register_device(&sram_dev);
+ register_device(&hsmmc_dev);
+
+ pcm049_network_init();
+
+ gpmc_generic_nand_devices_init(0, 8, OMAP_ECC_BCH8_CODE_HW);
+
+#ifdef CONFIG_PARTITION
+ devfs_add_partition("nand0", 0x00000, SZ_128K, PARTITION_FIXED, "xload_raw");
+ dev_add_bb_dev("xload_raw", "xload");
+ devfs_add_partition("nand0", SZ_128K, SZ_256K, PARTITION_FIXED, "self_raw");
+ dev_add_bb_dev("self_raw", "self0");
+ devfs_add_partition("nand0", SZ_128K + SZ_256K, SZ_128K, PARTITION_FIXED, "env_raw");
+ dev_add_bb_dev("env_raw", "env0");
+#endif
+
+ armlinux_add_dram(&sdram_dev);
+ armlinux_set_bootparams((void *)0x80000100);
+ armlinux_set_architecture(MACH_TYPE_PCM049);
+
+ return 0;
+}
+device_initcall(pcm049_devices_init);
+
+#ifdef CONFIG_SHELL_NONE
+int run_shell(void)
+{
+ int (*func)(void) = NULL;
+
+ switch (omap4_bootsrc()) {
+ case OMAP_BOOTSRC_MMC1:
+ printf("booting from MMC1\n");
+ func = omap_xload_boot_mmc();
+ break;
+ case OMAP_BOOTSRC_UNKNOWN:
+ printf("unknown boot source. Fall back to nand\n");
+ case OMAP_BOOTSRC_NAND:
+ printf("booting from NAND\n");
+ func = omap_xload_boot_nand(SZ_128K, SZ_256K);
+ break;
+ }
+
+ if (!func) {
+ printf("booting failed\n");
+ while (1);
+ }
+
+ shutdown_barebox();
+ func();
+
+ while (1);
+}
+#endif
diff --git a/arch/arm/boards/pcm049/config.h b/arch/arm/boards/pcm049/config.h
new file mode 100644
index 00000000..da84fa5f
--- /dev/null
+++ b/arch/arm/boards/pcm049/config.h
@@ -0,0 +1 @@
+/* nothing */
diff --git a/arch/arm/boards/pcm049/env/bin/nand_bootstrap b/arch/arm/boards/pcm049/env/bin/nand_bootstrap
new file mode 100644
index 00000000..acd00dc9
--- /dev/null
+++ b/arch/arm/boards/pcm049/env/bin/nand_bootstrap
@@ -0,0 +1,31 @@
+
+echo "copying barebox to nand..."
+
+mci0.probe=1
+mkdir mnt
+
+mount /dev/disk0.0 fat /mnt
+if [ $? != 0 ]; then
+ echo "failed to mount mmc card"
+ exit 1
+fi
+
+if [ ! -f /mnt/mlo-nand.bin ]; then
+ echo "mlo-nand.bin not found on mmc card"
+ exit 1
+fi
+
+if [ ! -f /mnt/barebox.bin ]; then
+ echo "barebox.bin not found on mmc card"
+fi
+
+gpmc_nand0.eccmode=bch8_hw_romcode
+erase /dev/nand0.xload.bb
+cp /mnt/mlo-nand.bin /dev/nand0.xload.bb
+
+gpmc_nand0.eccmode=bch8_hw
+erase /dev/nand0.barebox.bb
+cp /mnt/barebox.bin /dev/nand0.barebox.bb
+
+echo "success"
+
diff --git a/arch/arm/boards/pcm049/env/config b/arch/arm/boards/pcm049/env/config
new file mode 100644
index 00000000..54b2e3dd
--- /dev/null
+++ b/arch/arm/boards/pcm049/env/config
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+machine=pcm049
+eth0.serverip=
+user=
+
+# use 'dhcp' to do dhcp in barebox and in kernel
+# use 'none' if you want to skip kernel ip autoconfiguration
+ip=dhcp
+
+# or set your networking parameters here
+#eth0.ipaddr=a.b.c.d
+#eth0.netmask=a.b.c.d
+#eth0.gateway=a.b.c.d
+#eth0.serverip=a.b.c.d
+
+# can be either 'nfs', 'tftp', 'nor' or 'nand'
+kernel_loc=tftp
+# can be either 'net', 'nor', 'nand' or 'initrd'
+rootfs_loc=net
+
+# can be either 'jffs2' or 'ubifs'
+rootfs_type=ubifs
+rootfsimage=root-${machine}.$rootfs_type
+
+# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo
+kernelimage_type=zimage
+kernelimage=zImage-$machine
+#kernelimage_type=uimage
+#kernelimage=uImage-$machine
+#kernelimage_type=raw
+#kernelimage=Image-$machine
+#kernelimage_type=raw_lzo
+#kernelimage=Image-${machine}.lzo
+
+if [ -n $user ]; then
+ kernelimage="$user"-"$kernelimage"
+ nfsroot="$eth0.serverip:/home/$user/nfsroot/$machine"
+ rootfsimage="$user"-"$rootfsimage"
+else
+ nfsroot="$eth0.serverip:/path/to/nfs/root"
+fi
+
+autoboot_timeout=3
+
+bootargs="console=ttyO2,115200"
+
+nand_parts="128k(xload)ro,256k(barebox),128k(bareboxenv),2M(kernel),-(root)"
+rootfs_mtdblock_nand=4
+
+# set a fancy prompt (if support is compiled in)
+PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m "
+
diff --git a/arch/arm/boards/pcm049/lowlevel.c b/arch/arm/boards/pcm049/lowlevel.c
new file mode 100644
index 00000000..e036ba74
--- /dev/null
+++ b/arch/arm/boards/pcm049/lowlevel.c
@@ -0,0 +1,127 @@
+/*
+ * (C) Copyright 2004-2009
+ * Texas Instruments, <www.ti.com>
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * 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
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/io.h>
+#include <mach/omap4-mux.h>
+#include <mach/omap4-silicon.h>
+#include <mach/omap4-clock.h>
+#include <mach/syslib.h>
+#include <asm/barebox-arm.h>
+
+void set_muxconf_regs(void);
+
+/* Erstmal 200Mhz... */
+static const struct ddr_regs ddr_regs_mt42L64M64_3_200_mhz = {
+ .tim1 = 0x0aa8d4e3,
+ .tim2 = 0x202e0b92,
+ .tim3 = 0x009da2b3,
+ .phy_ctrl_1 = 0x849FF404, /* mostly from elpida */
+ .ref_ctrl = 0x0000030c, /* from elpida 200MHz! */
+ .config_init = 0x80000eb1,
+ .config_final = 0x80000eb1,
+ .zq_config = 0x500b3215, /* mostly from elpida */
+ .mr1 = 0x23, /* from elpida 200MHz! */
+ .mr2 = 0x1 /* from elpida 200MHz! */
+};
+
+#define I2C_SLAVE 0x12
+
+static int noinline scale_vcores(void)
+{
+ unsigned int rev = omap4_revision();
+
+ /* For VC bypass only VCOREx_CGF_FORCE is necessary and
+ * VCOREx_CFG_VOLTAGE changes can be discarded
+ */
+ writel(0, OMAP44XX_PRM_VC_CFG_I2C_MODE);
+ writel(0x6026, OMAP44XX_PRM_VC_CFG_I2C_CLK);
+
+ /* set VCORE1 force VSEL */
+ omap4_power_i2c_send((0x3A55 << 8) | I2C_SLAVE);
+
+ /* FIXME: set VCORE2 force VSEL, Check the reset value */
+ omap4_power_i2c_send((0x295B << 8) | I2C_SLAVE);
+
+ /* set VCORE3 force VSEL */
+ switch (rev) {
+ case OMAP4430_ES2_0:
+ omap4_power_i2c_send((0x2961 << 8) | I2C_SLAVE);
+ break;
+ case OMAP4430_ES2_1:
+ omap4_power_i2c_send((0x2A61 << 8) | I2C_SLAVE);
+ break;
+ }
+
+ return 0;
+}
+
+static void noinline pcm049_init_lowlevel(void)
+{
+ struct dpll_param core = OMAP4_CORE_DPLL_PARAM_19M2_DDR200;
+ struct dpll_param mpu = OMAP4_MPU_DPLL_PARAM_19M2_MPU1000;
+ struct dpll_param iva = OMAP4_IVA_DPLL_PARAM_19M2;
+ struct dpll_param per = OMAP4_PER_DPLL_PARAM_19M2;
+ struct dpll_param abe = OMAP4_ABE_DPLL_PARAM_19M2;
+ struct dpll_param usb = OMAP4_USB_DPLL_PARAM_19M2;
+
+ set_muxconf_regs();
+
+ omap4_ddr_init(&ddr_regs_mt42L64M64_3_200_mhz, &core);
+
+ /* Set VCORE1 = 1.3 V, VCORE2 = VCORE3 = 1.21V */
+ scale_vcores();
+
+ writel(CM_SYS_CLKSEL_19M2, CM_SYS_CLKSEL);
+
+ /* Configure all DPLL's at 100% OPP */
+ omap4_configure_mpu_dpll(&mpu);
+ omap4_configure_iva_dpll(&iva);
+ omap4_configure_per_dpll(&per);
+ omap4_configure_abe_dpll(&abe);
+ omap4_configure_usb_dpll(&usb);
+
+ /* Enable all clocks */
+ omap4_enable_all_clocks();
+
+ sr32(0x4A30a31C, 8, 1, 0x1); /* enable software ioreq */
+ sr32(0x4A30a31C, 1, 2, 0x0); /* set for sys_clk (19.2MHz) */
+ sr32(0x4A30a31C, 16, 4, 0x0); /* set divisor to 1 */
+ sr32(0x4A30a110, 0, 1, 0x1); /* set the clock source to active */
+ sr32(0x4A30a110, 2, 2, 0x3); /* enable clocks */
+
+ board_init_lowlevel_return();
+}
+
+void board_init_lowlevel(void)
+{
+ u32 r;
+
+ if (get_pc() > 0x80000000)
+ return;
+
+ r = 0x4030d000;
+ __asm__ __volatile__("mov sp, %0" : : "r"(r));
+
+ pcm049_init_lowlevel();
+}
+
diff --git a/arch/arm/boards/pcm049/mux.c b/arch/arm/boards/pcm049/mux.c
new file mode 100644
index 00000000..d93d4589
--- /dev/null
+++ b/arch/arm/boards/pcm049/mux.c
@@ -0,0 +1,254 @@
+#include <common.h>
+#include <init.h>
+#include <asm/io.h>
+#include <mach/omap4-silicon.h>
+#include <mach/omap4-mux.h>
+
+static const struct pad_conf_entry core_padconf_array[] = {
+ {GPMC_AD0, (IEN | PTD | DIS | M0)}, /* gpmc_ad0 */
+ {GPMC_AD1, (IEN | PTD | DIS | M0)}, /* gpmc_ad1 */
+ {GPMC_AD2, (IEN | PTD | DIS | M0)}, /* gpmc_ad2 */
+ {GPMC_AD3, (IEN | PTD | DIS | M0)}, /* gpmc_ad3 */
+ {GPMC_AD4, (IEN | PTD | DIS | M0)}, /* gpmc_ad4 */
+ {GPMC_AD5, (IEN | PTD | DIS | M0)}, /* gpmc_ad5 */
+ {GPMC_AD6, (IEN | PTD | DIS | M0)}, /* gpmc_ad6 */
+ {GPMC_AD7, (IEN | PTD | DIS | M0)}, /* gpmc_ad7 */
+ {GPMC_AD8, (IEN | PTD | DIS | M0)}, /* gpmc_ad8 */
+ {GPMC_AD9, (IEN | PTD | DIS | M0)}, /* gpmc_ad9 */
+ {GPMC_AD10, (IEN | PTD | DIS | M0)}, /* gpmc_ad10 */
+ {GPMC_AD11, (IEN | PTD | DIS | M0)}, /* gpmc_ad11 */
+ {GPMC_AD12, (IEN | PTD | DIS | M0)}, /* gpmc_ad12 */
+ {GPMC_AD13, (IEN | PTD | DIS | M0)}, /* gpmc_ad13 */
+ {GPMC_AD14, (IEN | PTD | DIS | M0)}, /* gpmc_ad14 */
+ {GPMC_AD15, (IEN | PTD | DIS | M0)}, /* gpmc_ad15 */
+ {GPMC_A16, (IEN | PTD | DIS | M0)}, /* gpmc_a16 */
+ {GPMC_A17, (IEN | PTD | DIS | M0)}, /* gpmc_a17 */
+ {GPMC_A18, (IEN | PTD | DIS | M0)}, /* gpmc_a18 */
+ {GPMC_A19, (IEN | PTD | DIS | M0)}, /* gpmc_a19 */
+ {GPMC_A20, (IEN | PTD | DIS | M0)}, /* gpmc_a20 */
+ {GPMC_A21, (IEN | PTD | DIS | M0)}, /* gpmc_a21 */
+ {GPMC_A22, (IEN | PTD | DIS | M0)}, /* gpmc_a22 */
+ {GPMC_A23, (IEN | PTD | DIS | M0)}, /* gpmc_a23 */
+ {GPMC_A24, (IEN | PTD | DIS | M0)}, /* gpmc_a24 */
+ {GPMC_A25, (IEN | PTD | DIS | M0)}, /* gpmc_a25 */
+ {GPMC_NCS0, (IDIS | PTU | EN | M0)}, /* gpmc_nsc0 */
+ {GPMC_NCS1, (IDIS | PTU | EN | M0)}, /* gpmc_nsc1 */
+ {GPMC_NCS2, (SAFE_MODE)}, /* nc */
+ {GPMC_NCS3, (SAFE_MODE)}, /* nc */
+ {GPMC_NWP, (IEN | PTD | DIS | M0)}, /* gpmc_nwp */
+ {GPMC_CLK, (SAFE_MODE)}, /* nc */
+ {GPMC_NADV_ALE, (IDIS | PTD | DIS | M0)}, /* gpmc_ndav_ale */
+ {GPMC_NOE, (IDIS | PTD | DIS | M0)}, /* gpmc_noe */
+ {GPMC_NWE, (IDIS | PTD | DIS | M0)}, /* gpmc_nwe */
+ {GPMC_NBE0_CLE, (IDIS | PTD | DIS | M0)}, /* gpmc_nbe0_cle */
+ {GPMC_NBE1, (SAFE_MODE)}, /* nc */
+ {GPMC_WAIT0, (IEN | PTU | EN | M0)}, /* gpmc_wait0 */
+ {GPMC_WAIT1, (SAFE_MODE)}, /* nc */
+ {C2C_DATA11, (SAFE_MODE)}, /* nc */
+ {C2C_DATA12, (SAFE_MODE)}, /* nc */
+ {C2C_DATA13, (IDIS | PTU | EN | M0)}, /* gpmc_nsc5 */
+ {C2C_DATA14, (SAFE_MODE)}, /* nc */
+ {C2C_DATA15, (SAFE_MODE)}, /* nc */
+ {HDMI_HPD, (M0)}, /* hdmi_hpd */
+ {HDMI_CEC, (DIS | IEN | M3)}, /* gpio_64 */
+ {HDMI_DDC_SCL, (PTU | M0)}, /* hdmi_ddc_scl */
+ {HDMI_DDC_SDA, (PTU | IEN | M0)}, /* hdmi_ddc_sda */
+ {CSI21_DX0, (IEN | M0)}, /* csi21_dx0 */
+ {CSI21_DY0, (IEN | M0)}, /* csi21_dy0 */
+ {CSI21_DX1, (IEN | M0)}, /* csi21_dx1 */
+ {CSI21_DY1, (IEN | M0)}, /* csi21_dy1 */
+ {CSI21_DX2, (IEN | M0)}, /* csi21_dx2 */
+ {CSI21_DY2, (IEN | M0)}, /* csi21_dy2 */
+ {CSI21_DX3, (PTD | M7)}, /* csi21_dx3 */
+ {CSI21_DY3, (PTD | M7)}, /* csi21_dy3 */
+ {CSI21_DX4, (PTD | OFF_EN | OFF_PD | OFF_IN | M7)}, /* csi21_dx4 */
+ {CSI21_DY4, (PTD | OFF_EN | OFF_PD | OFF_IN | M7)}, /* csi21_dy4 */
+ {CSI22_DX0, (IEN | M0)}, /* csi22_dx0 */
+ {CSI22_DY0, (IEN | M0)}, /* csi22_dy0 */
+ {CSI22_DX1, (IEN | M0)}, /* csi22_dx1 */
+ {CSI22_DY1, (IEN | M0)}, /* csi22_dy1 */
+ {CAM_SHUTTER, (OFF_EN | OFF_PD | OFF_OUT_PTD | M0)}, /* cam_shutter */
+ {CAM_STROBE, (OFF_EN | OFF_PD | OFF_OUT_PTD | M0)}, /* cam_strobe */
+ {CAM_GLOBALRESET, (PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M3)}, /* gpio_83 */
+ {USBB1_ULPITLL_CLK, (PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M4)},/* usbb1_ulpiphy_clk */
+ {USBB1_ULPITLL_STP, (OFF_EN | OFF_OUT_PTD | M4)}, /* usbb1_ulpiphy_stp */
+ {USBB1_ULPITLL_DIR, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dir */
+ {USBB1_ULPITLL_NXT, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_nxt */
+ {USBB1_ULPITLL_DAT0, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat0 */
+ {USBB1_ULPITLL_DAT1, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat1 */
+ {USBB1_ULPITLL_DAT2, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat2 */
+ {USBB1_ULPITLL_DAT3, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat3 */
+ {USBB1_ULPITLL_DAT4, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat4 */
+ {USBB1_ULPITLL_DAT5, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat5 */
+ {USBB1_ULPITLL_DAT6, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat6 */
+ {USBB1_ULPITLL_DAT7, (IEN | OFF_EN | OFF_PD | OFF_IN | M4)}, /* usbb1_ulpiphy_dat7 */
+ {USBB1_HSIC_DATA, (DIS | IEN | M3)}, /* gpio_96 */
+ {USBB1_HSIC_STROBE, (DIS | IEN | M3)}, /* gpio_97 */
+ {USBC1_ICUSB_DP, (IEN | M0)}, /* usbc1_icusb_dp */
+ {USBC1_ICUSB_DM, (IEN | M0)}, /* usbc1_icusb_dm */
+ {SDMMC1_CLK, (PTU | OFF_EN | OFF_OUT_PTD | M0)}, /* sdmmc1_clk */
+ {SDMMC1_CMD, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_cmd */
+ {SDMMC1_DAT0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat0 */
+ {SDMMC1_DAT1, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat1 */
+ {SDMMC1_DAT2, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat2 */
+ {SDMMC1_DAT3, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat3 */
+ {SDMMC1_DAT4, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat4 */
+ {SDMMC1_DAT5, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat5 */
+ {SDMMC1_DAT6, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat6 */
+ {SDMMC1_DAT7, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc1_dat7 */
+ {ABE_MCBSP2_CLKX, (IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* abe_mcbsp2_clkx */
+ {ABE_MCBSP2_DR, (IEN | OFF_EN | OFF_OUT_PTD | M0)}, /* abe_mcbsp2_dr */
+ {ABE_MCBSP2_DX, (OFF_EN | OFF_OUT_PTD | M0)}, /* abe_mcbsp2_dx */
+ {ABE_MCBSP2_FSX, (IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* abe_mcbsp2_fsx */
+ {ABE_MCBSP1_CLKX, (DIS | IEN | M3)}, /* gpio_114 */
+ {ABE_MCBSP1_DR, (DIS | IEN | M3)}, /* gpio_115 */
+ {ABE_MCBSP1_DX, (DIS | IEN | M3)}, /* gpio_116 */
+ {ABE_MCBSP1_FSX, (DIS | IEN | M2)}, /* abe_mcasp_amutein */
+ {ABE_PDM_UL_DATA, (IEN | OFF_EN | OFF_OUT_PTD | M1)}, /* abe_mcbsp3_dr */
+ {ABE_PDM_DL_DATA, (OFF_EN | OFF_OUT_PTD | M1)}, /* abe_mcbsp3_dx */
+ {ABE_PDM_FRAME, (IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* abe_mcbsp3_clkx */
+ {ABE_PDM_LB_CLK, (IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* abe_mcbsp3_fsx */
+ {ABE_CLKS, (DIS | IEN | M3)}, /* gpio_118 */
+ {ABE_DMIC_CLK1, (SAFE_MODE)}, /* nc */
+ {ABE_DMIC_DIN1, (SAFE_MODE)}, /* nc */
+ {ABE_DMIC_DIN2, (SAFE_MODE)}, /* nc */
+ {ABE_DMIC_DIN3, (SAFE_MODE)}, /* nc */
+ {UART2_CTS, (PTU | IEN | M0)}, /* uart2_cts */
+ {UART2_RTS, (M0)}, /* uart2_rts */
+ {UART2_RX, (PTU | IEN | M0)}, /* uart2_rx */
+ {UART2_TX, (M0)}, /* uart2_tx */
+ {HDQ_SIO, (M0)}, /* hdq_sio */
+ {I2C1_SCL, (PTU | IEN | M0)}, /* i2c1_scl */
+ {I2C1_SDA, (PTU | IEN | M0)}, /* i2c1_sda */
+ {I2C2_SCL, (PTU | IEN | M1)}, /* uart1_rx */
+ {I2C2_SDA, (M1)}, /* uart1_tx */
+ {I2C3_SCL, (PTU | IEN | M0)}, /* i2c3_scl */
+ {I2C3_SDA, (PTU | IEN | M0)}, /* i2c3_sda */
+ {I2C4_SCL, (PTU | IEN | M0)}, /* i2c4_scl */
+ {I2C4_SDA, (PTU | IEN | M0)}, /* i2c4_sda */
+ {MCSPI1_CLK, (IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* mcspi1_clk */
+ {MCSPI1_SOMI, (IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* mcspi1_somi */
+ {MCSPI1_SIMO, (IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* mcspi1_simo */
+ {MCSPI1_CS0, (PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* mcspi1_cs0 */
+ {MCSPI1_CS1, (PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* mcspi1_cs1 */
+ {MCSPI1_CS2, (PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* mcspi1_cs2 */
+ {MCSPI1_CS3, (PTD | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* mcspi1_cs3 */
+ {UART3_CTS_RCTX, (PTU | IEN | M0)}, /* uart3_tx */
+ {UART3_RTS_SD, (M0)}, /* uart3_rts_sd */
+ {UART3_RX_IRRX, (IEN | M0)}, /* uart3_rx */
+ {UART3_TX_IRTX, (M0)}, /* uart3_tx */
+ {SDMMC5_CLK, (PTU | IEN | OFF_EN | OFF_OUT_PTD | M0)}, /* sdmmc5_clk */
+ {SDMMC5_CMD, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc5_cmd */
+ {SDMMC5_DAT0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc5_dat0 */
+ {SDMMC5_DAT1, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc5_dat1 */
+ {SDMMC5_DAT2, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc5_dat2 */
+ {SDMMC5_DAT3, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* sdmmc5_dat3 */
+ {MCSPI4_CLK, (SAFE_MODE)}, /* nc */
+ {MCSPI4_SIMO, (PTU | IEN | M3)}, /* gpio_152 */
+ {MCSPI4_SOMI, (PTU | IEN | M3)}, /* gpio_153 */
+ {MCSPI4_CS0, (SAFE_MODE)}, /* nc */
+ {UART4_RX, (IEN | M0)}, /* uart4_rx */
+ {UART4_TX, (M0)}, /* uart4_tx */
+ {USBB2_ULPITLL_CLK, (IEN | M3)}, /* gpio_157 */
+ {USBB2_ULPITLL_STP, (IEN | M5)}, /* dispc2_data23 */
+ {USBB2_ULPITLL_DIR, (IEN | M5)}, /* dispc2_data22 */
+ {USBB2_ULPITLL_NXT, (IEN | M5)}, /* dispc2_data21 */
+ {USBB2_ULPITLL_DAT0, (IEN | M5)}, /* dispc2_data20 */
+ {USBB2_ULPITLL_DAT1, (IEN | M5)}, /* dispc2_data19 */
+ {USBB2_ULPITLL_DAT2, (IEN | M5)}, /* dispc2_data18 */
+ {USBB2_ULPITLL_DAT3, (IEN | M5)}, /* dispc2_data15 */
+ {USBB2_ULPITLL_DAT4, (IEN | M5)}, /* dispc2_data14 */
+ {USBB2_ULPITLL_DAT5, (IEN | M5)}, /* dispc2_data13 */
+ {USBB2_ULPITLL_DAT6, (IEN | M5)}, /* dispc2_data12 */
+ {USBB2_ULPITLL_DAT7, (IEN | M5)}, /* dispc2_data11 */
+ {USBB2_HSIC_DATA, (SAFE_MODE)}, /* nc */
+ {USBB2_HSIC_STROBE, (SAFE_MODE)}, /* nc */
+ {UNIPRO_TX0, (OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_col0 */
+ {UNIPRO_TY0, (OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_col1 */
+ {UNIPRO_TX1, (OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_col2 */
+ {UNIPRO_TY1, (OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_col3 */
+ {UNIPRO_TX2, (OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_col4 */
+ {UNIPRO_TY2, (SAFE_MODE)}, /* nc */
+ {UNIPRO_RX0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_row0 */
+ {UNIPRO_RY0, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_row1 */
+ {UNIPRO_RX1, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_row2 */
+ {UNIPRO_RY1, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_row3 */
+ {UNIPRO_RX2, (PTU | IEN | OFF_EN | OFF_PD | OFF_IN | M1)}, /* kpd_row4 */
+ {UNIPRO_RY2, (DIS | IEN | M3)}, /* gpio_3 */
+ {USBA0_OTG_CE, (PTD | OFF_EN | OFF_PD | OFF_OUT_PTD | M0)}, /* usba0_otg_ce */
+ {USBA0_OTG_DP, (IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* usba0_otg_dp */
+ {USBA0_OTG_DM, (IEN | OFF_EN | OFF_PD | OFF_IN | M0)}, /* usba0_otg_dm */
+ {FREF_CLK1_OUT, (SAFE_MODE)}, /* nc */
+ {FREF_CLK2_OUT, (SAFE_MODE)}, /* nc */
+ {SYS_NIRQ1, (PTU | IEN | M0)}, /* sys_nirq1 */
+ {SYS_NIRQ2, (DIS | IEN | M3)}, /* gpio_183 */
+ {SYS_BOOT0, (PTU | IEN | M3)}, /* gpio_184 */
+ {SYS_BOOT1, (M3)}, /* gpio_185 */
+ {SYS_BOOT2, (PTD | IEN | M3)}, /* gpio_186 */
+ {SYS_BOOT3, (M3)}, /* gpio_187 */
+ {SYS_BOOT4, (M3)}, /* gpio_188 */
+ {SYS_BOOT5, (PTD | IEN | M3)}, /* gpio_189 */
+ {DPM_EMU0, (IEN | M0)}, /* dpm_emu0 */
+ {DPM_EMU1, (IEN | M0)}, /* dpm_emu1 */
+ {DPM_EMU2, (SAFE_MODE)}, /* nc */
+ {DPM_EMU3, (SAFE_MODE)}, /* nc */
+ {DPM_EMU4, (SAFE_MODE)}, /* nc */
+ {DPM_EMU5, (SAFE_MODE)}, /* nc */
+ {DPM_EMU6, (SAFE_MODE)}, /* nc */
+ {DPM_EMU7, (SAFE_MODE)}, /* nc */
+ {DPM_EMU8, (SAFE_MODE)}, /* nc */
+ {DPM_EMU9, (SAFE_MODE)}, /* nc */
+ {DPM_EMU10, (SAFE_MODE)}, /* nc */
+ {DPM_EMU11, (SAFE_MODE)}, /* nc */
+ {DPM_EMU12, (SAFE_MODE)}, /* nc */
+ {DPM_EMU13, (SAFE_MODE)}, /* nc */
+ {DPM_EMU14, (SAFE_MODE)}, /* nc */
+ {DPM_EMU15, (DIS | M3)}, /* gpio_26 */
+ {DPM_EMU16, (M1)}, /* dmtimer8_pwm_evt */
+ {DPM_EMU17, (M1)}, /* dmtimer9_pwm_evt */
+ {DPM_EMU18, (IEN | M3)}, /* gpio_190 */
+ {DPM_EMU19, (IEN | M3)}, /* gpio_191 */
+};
+
+static const struct pad_conf_entry wkup_padconf_array[] = {
+ {PAD0_SIM_IO, (IEN | M3)}, /* gpio_wk0 */
+ {PAD1_SIM_CLK, (IEN | M3)}, /* gpio_wk1 */
+ {PAD0_SIM_RESET, (IEN | M3)}, /* gpio_wk2 */
+ {PAD1_SIM_CD, (SAFE_MODE)}, /* should be gpio_wk3 but muxed with gpio_3*/
+ {PAD0_SIM_PWRCTRL, (IEN | M3)}, /* gpio_wk4 */
+ {PAD1_SR_SCL, (PTU | IEN | M0)}, /* sr_scl */
+ {PAD0_SR_SDA, (PTU | IEN | M0)}, /* sr_sda */
+ {PAD1_FREF_XTAL_IN, (M0)}, /* # */
+ {PAD0_FREF_SLICER_IN, (SAFE_MODE)}, /* nc */
+ {PAD1_FREF_CLK_IOREQ, (SAFE_MODE)}, /* nc */
+ {PAD0_FREF_CLK0_OUT, (M2)}, /* sys_drm_msecure */
+ {PAD1_FREF_CLK3_REQ, (SAFE_MODE)}, /* nc */
+ {PAD0_FREF_CLK3_OUT, (M0)}, /* fref_clk3_out */
+ {PAD1_FREF_CLK4_REQ, (M0)}, /* fref_clk4_req */
+ {PAD0_FREF_CLK4_OUT, (M0)}, /* fref_clk4_out */
+ {PAD1_SYS_32K, (IEN | M0)}, /* sys_32k */
+ {PAD0_SYS_NRESPWRON, (M0)}, /* sys_nrespwron */
+ {PAD1_SYS_NRESWARM, (M0)}, /* sys_nreswarm */
+ {PAD0_SYS_PWR_REQ, (PTU | M0)}, /* sys_pwr_req */
+ {PAD1_SYS_PWRON_RESET, (M0)}, /* sys_pwron_reset_out */
+ {PAD0_SYS_BOOT6, (IEN | M3)}, /* gpio_wk9 */
+ {PAD1_SYS_BOOT7, (IEN | M3)}, /* gpio_wk10 */
+};
+
+static void do_set_mux(u32 base, struct pad_conf_entry const *array, int size)
+{
+ int i;
+ struct pad_conf_entry *pad = (struct pad_conf_entry *) array;
+
+ for (i = 0; i < size; i++, pad++)
+ writew(pad->val, base + pad->offset);
+}
+
+void set_muxconf_regs(void)
+{
+ do_set_mux(OMAP44XX_CONTROL_PADCONF_CORE, core_padconf_array,
+ ARRAY_SIZE(core_padconf_array));
+
+ do_set_mux(OMAP44XX_CONTROL_PADCONF_WKUP, wkup_padconf_array,
+ ARRAY_SIZE(wkup_padconf_array));
+}
diff --git a/arch/arm/configs/omap3530_beagle_defconfig b/arch/arm/configs/omap3530_beagle_defconfig
index d4b87374..8a12154c 100644
--- a/arch/arm/configs/omap3530_beagle_defconfig
+++ b/arch/arm/configs/omap3530_beagle_defconfig
@@ -2,16 +2,19 @@ CONFIG_ARCH_OMAP=y
# CONFIG_OMAP3_COPY_CLOCK_SRAM is not set
CONFIG_MACH_BEAGLE=y
CONFIG_AEABI=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_ARM_UNWIND=y
CONFIG_TEXT_BASE=0x81000000
CONFIG_PROMPT="barebox> "
CONFIG_LONGHELP=y
CONFIG_GLOB=y
CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_HUSH_GETOPT=y
CONFIG_CMDLINE_EDITING=y
CONFIG_AUTO_COMPLETE=y
# CONFIG_TIMESTAMP is not set
CONFIG_PARTITION=y
-# CONFIG_DEFAULT_ENVIRONMENT is not set
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y
CONFIG_CMD_EDIT=y
CONFIG_CMD_SLEEP=y
CONFIG_CMD_SAVEENV=y
@@ -27,6 +30,7 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
+CONFIG_CMD_GPIO=y
CONFIG_CMD_UNLZO=y
CONFIG_CMD_I2C=y
CONFIG_NET=y
@@ -34,14 +38,15 @@ CONFIG_NET_DHCP=y
CONFIG_NET_NFS=y
CONFIG_NET_PING=y
CONFIG_NET_TFTP=y
+CONFIG_NET_TFTP_PUSH=y
CONFIG_DRIVER_SERIAL_NS16550=y
CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y
CONFIG_NET_USB=y
CONFIG_NET_USB_ASIX=y
+CONFIG_NET_USB_SMSC95XX=y
# CONFIG_SPI is not set
CONFIG_I2C=y
CONFIG_I2C_OMAP=y
-CONFIG_I2C_TWL4030=y
CONFIG_MTD=y
CONFIG_NAND=y
CONFIG_NAND_OMAP_GPMC=y
@@ -49,3 +54,9 @@ CONFIG_USB=y
CONFIG_USB_EHCI=y
CONFIG_USB_EHCI_OMAP=y
CONFIG_USB_TWL4030=y
+CONFIG_MCI=y
+CONFIG_MCI_OMAP_HSMMC=y
+CONFIG_I2C_TWL4030=y
+CONFIG_FS_FAT=y
+CONFIG_FS_FAT_WRITE=y
+CONFIG_FS_FAT_LFN=y
diff --git a/arch/arm/configs/omap3530_beagle_xload_defconfig b/arch/arm/configs/omap3530_beagle_xload_defconfig
new file mode 100644
index 00000000..58a23095
--- /dev/null
+++ b/arch/arm/configs/omap3530_beagle_xload_defconfig
@@ -0,0 +1,38 @@
+CONFIG_ARCH_OMAP=y
+# CONFIG_OMAP3_COPY_CLOCK_SRAM is not set
+CONFIG_OMAP_BUILD_IFT=y
+CONFIG_MACH_BEAGLE=y
+CONFIG_AEABI=y
+# CONFIG_CMD_ARM_CPUINFO is not set
+# CONFIG_ARM_EXCEPTIONS is not set
+CONFIG_TEXT_BASE=0x40200000
+CONFIG_MEMORY_LAYOUT_FIXED=y
+CONFIG_STACK_BASE=0x87BF7F10
+CONFIG_MALLOC_BASE=0x87BFFF10
+CONFIG_MALLOC_DUMMY=y
+CONFIG_PROMPT="X-load Beagle>"
+CONFIG_SHELL_NONE=y
+# CONFIG_ERRNO_MESSAGES is not set
+# CONFIG_TIMESTAMP is not set
+# CONFIG_CONSOLE_FULL is not set
+# CONFIG_DEFAULT_ENVIRONMENT is not set
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y
+# CONFIG_SPI is not set
+CONFIG_MTD=y
+CONFIG_NAND=y
+# CONFIG_NAND_WRITE is not set
+# CONFIG_NAND_ECC_SOFT is not set
+# CONFIG_NAND_ECC_HW_SYNDROME is not set
+# CONFIG_NAND_ECC_HW_NONE is not set
+# CONFIG_NAND_INFO is not set
+# CONFIG_NAND_BBT is not set
+# CONFIG_NAND_READ_OOB is not set
+CONFIG_NAND_OMAP_GPMC=y
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+# CONFIG_MCI_WRITE is not set
+CONFIG_MCI_OMAP_HSMMC=y
+# CONFIG_FS_RAMFS is not set
+# CONFIG_FS_DEVFS is not set
+CONFIG_FS_FAT=y
diff --git a/arch/arm/configs/panda_defconfig b/arch/arm/configs/panda_defconfig
new file mode 100644
index 00000000..38cc9582
--- /dev/null
+++ b/arch/arm/configs/panda_defconfig
@@ -0,0 +1,60 @@
+CONFIG_ARCH_OMAP=y
+CONFIG_ARCH_OMAP4=y
+CONFIG_AEABI=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_ARM_UNWIND=y
+CONFIG_MMU=y
+CONFIG_TEXT_BASE=0x8f000000
+CONFIG_MALLOC_SIZE=0x2000000
+CONFIG_KALLSYMS=y
+CONFIG_PROMPT="barebox> "
+CONFIG_LONGHELP=y
+CONFIG_GLOB=y
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_HUSH_GETOPT=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+# CONFIG_TIMESTAMP is not set
+CONFIG_PARTITION=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y
+CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/pcm049/env"
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_LOADB=y
+CONFIG_CMD_FLASH=y
+# CONFIG_CMD_BOOTM is not set
+CONFIG_CMD_RESET=y
+CONFIG_CMD_GO=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_PARTITION=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_UNLZO=y
+CONFIG_NET=y
+CONFIG_NET_DHCP=y
+CONFIG_NET_NFS=y
+CONFIG_NET_PING=y
+CONFIG_NET_TFTP=y
+CONFIG_NET_TFTP_PUSH=y
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y
+CONFIG_NET_USB=y
+CONFIG_NET_USB_SMSC95XX=y
+# CONFIG_SPI is not set
+CONFIG_MTD=y
+CONFIG_NAND=y
+CONFIG_NAND_OMAP_GPMC=y
+CONFIG_UBI=y
+CONFIG_USB=y
+CONFIG_USB_EHCI=y
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+CONFIG_MCI_OMAP_HSMMC=y
+CONFIG_FS_FAT=y
+CONFIG_FS_FAT_WRITE=y
+CONFIG_FS_FAT_LFN=y
diff --git a/arch/arm/configs/panda_xload_defconfig b/arch/arm/configs/panda_xload_defconfig
new file mode 100644
index 00000000..24452a67
--- /dev/null
+++ b/arch/arm/configs/panda_xload_defconfig
@@ -0,0 +1,26 @@
+CONFIG_ARCH_OMAP=y
+CONFIG_ARCH_OMAP4=y
+# CONFIG_OMAP_GPMC is not set
+CONFIG_OMAP_BUILD_IFT=y
+CONFIG_AEABI=y
+# CONFIG_CMD_ARM_CPUINFO is not set
+CONFIG_TEXT_BASE=0x40300000
+CONFIG_MEMORY_LAYOUT_FIXED=y
+CONFIG_STACK_BASE=0x8f000000
+CONFIG_MALLOC_BASE=0x84000000
+CONFIG_MALLOC_SIZE=0x2000000
+CONFIG_PROMPT="barebox> "
+CONFIG_SHELL_NONE=y
+# CONFIG_ERRNO_MESSAGES is not set
+# CONFIG_TIMESTAMP is not set
+# CONFIG_CONSOLE_FULL is not set
+CONFIG_PARTITION=y
+# CONFIG_DEFAULT_ENVIRONMENT is not set
+# CONFIG_COMMAND_SUPPORT is not set
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y
+# CONFIG_SPI is not set
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+CONFIG_MCI_OMAP_HSMMC=y
+CONFIG_FS_FAT=y
diff --git a/arch/arm/configs/pcm049_defconfig b/arch/arm/configs/pcm049_defconfig
new file mode 100644
index 00000000..ed20f1bb
--- /dev/null
+++ b/arch/arm/configs/pcm049_defconfig
@@ -0,0 +1,57 @@
+CONFIG_ARCH_OMAP=y
+CONFIG_ARCH_OMAP4=y
+CONFIG_MACH_PCM049=y
+CONFIG_AEABI=y
+CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
+CONFIG_ARM_UNWIND=y
+CONFIG_MMU=y
+CONFIG_TEXT_BASE=0x8f000000
+CONFIG_MALLOC_SIZE=0x2000000
+CONFIG_KALLSYMS=y
+CONFIG_PROMPT="barebox> "
+CONFIG_LONGHELP=y
+CONFIG_GLOB=y
+CONFIG_HUSH_FANCY_PROMPT=y
+CONFIG_HUSH_GETOPT=y
+CONFIG_CMDLINE_EDITING=y
+CONFIG_AUTO_COMPLETE=y
+# CONFIG_TIMESTAMP is not set
+CONFIG_PARTITION=y
+CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y
+CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/pcm049/env"
+CONFIG_CMD_EDIT=y
+CONFIG_CMD_SLEEP=y
+CONFIG_CMD_SAVEENV=y
+CONFIG_CMD_LOADENV=y
+CONFIG_CMD_EXPORT=y
+CONFIG_CMD_PRINTENV=y
+CONFIG_CMD_READLINE=y
+CONFIG_CMD_ECHO_E=y
+CONFIG_CMD_LOADB=y
+CONFIG_CMD_FLASH=y
+# CONFIG_CMD_BOOTM is not set
+CONFIG_CMD_RESET=y
+CONFIG_CMD_GO=y
+CONFIG_CMD_TIMEOUT=y
+CONFIG_CMD_PARTITION=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_UNLZO=y
+CONFIG_NET=y
+CONFIG_NET_DHCP=y
+CONFIG_NET_NFS=y
+CONFIG_NET_PING=y
+CONFIG_NET_TFTP=y
+CONFIG_NET_TFTP_PUSH=y
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y
+CONFIG_DRIVER_NET_SMC911X=y
+# CONFIG_SPI is not set
+CONFIG_MTD=y
+CONFIG_NAND=y
+CONFIG_NAND_OMAP_GPMC=y
+CONFIG_UBI=y
+CONFIG_MCI=y
+CONFIG_MCI_OMAP_HSMMC=y
+CONFIG_FS_FAT=y
+CONFIG_FS_FAT_WRITE=y
+CONFIG_FS_FAT_LFN=y
diff --git a/arch/arm/configs/pcm049_xload_defconfig b/arch/arm/configs/pcm049_xload_defconfig
new file mode 100644
index 00000000..7303c9a5
--- /dev/null
+++ b/arch/arm/configs/pcm049_xload_defconfig
@@ -0,0 +1,40 @@
+CONFIG_ARCH_OMAP=y
+CONFIG_ARCH_OMAP4=y
+CONFIG_OMAP_BUILD_IFT=y
+CONFIG_MACH_PCM049=y
+CONFIG_AEABI=y
+# CONFIG_CMD_ARM_CPUINFO is not set
+# CONFIG_ARM_EXCEPTIONS is not set
+CONFIG_MMU=y
+CONFIG_TEXT_BASE=0x40300000
+CONFIG_MEMORY_LAYOUT_FIXED=y
+CONFIG_STACK_BASE=0x8f000000
+CONFIG_MALLOC_BASE=0x84000000
+CONFIG_MALLOC_SIZE=0x2000000
+CONFIG_MALLOC_DUMMY=y
+CONFIG_PROMPT="barebox> "
+CONFIG_SHELL_NONE=y
+# CONFIG_ERRNO_MESSAGES is not set
+# CONFIG_TIMESTAMP is not set
+# CONFIG_CONSOLE_FULL is not set
+# CONFIG_DEFAULT_ENVIRONMENT is not set
+CONFIG_DRIVER_SERIAL_NS16550=y
+CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y
+# CONFIG_SPI is not set
+CONFIG_MTD=y
+CONFIG_NAND=y
+# CONFIG_NAND_WRITE is not set
+# CONFIG_NAND_ECC_SOFT is not set
+# CONFIG_NAND_ECC_HW_SYNDROME is not set
+# CONFIG_NAND_ECC_HW_NONE is not set
+# CONFIG_NAND_INFO is not set
+# CONFIG_NAND_BBT is not set
+# CONFIG_NAND_READ_OOB is not set
+CONFIG_NAND_OMAP_GPMC=y
+CONFIG_MCI=y
+CONFIG_MCI_STARTUP=y
+# CONFIG_MCI_WRITE is not set
+CONFIG_MCI_OMAP_HSMMC=y
+# CONFIG_FS_RAMFS is not set
+# CONFIG_FS_DEVFS is not set
+CONFIG_FS_FAT=y
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index 036768eb..e30ae1cc 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -1,6 +1,6 @@
obj-y += cpu.o
-obj-y += exceptions.o
-obj-y += interrupts.o
+obj-$(CONFIG_ARM_EXCEPTIONS) += exceptions.o
+obj-$(CONFIG_ARM_EXCEPTIONS) += interrupts.o
obj-y += start.o
#
diff --git a/arch/arm/cpu/cpu.c b/arch/arm/cpu/cpu.c
index 346f8dce..cf307890 100644
--- a/arch/arm/cpu/cpu.c
+++ b/arch/arm/cpu/cpu.c
@@ -97,7 +97,7 @@ void arch_shutdown(void)
* default setting we are running in barebox, there's no special preparation
* required.
*/
-
+#ifdef CONFIG_COMMAND
static int do_icache(struct command *cmdtp, int argc, char *argv[])
{
if (argc == 1) {
@@ -121,3 +121,4 @@ BAREBOX_CMD_START(icache)
.usage = "show/change icache status",
BAREBOX_CMD_HELP(cmd_icache_help)
BAREBOX_CMD_END
+#endif
diff --git a/arch/arm/cpu/start.c b/arch/arm/cpu/start.c
index e0fb7123..f20ce74a 100644
--- a/arch/arm/cpu/start.c
+++ b/arch/arm/cpu/start.c
@@ -31,6 +31,7 @@ void __naked __section(.text_entry) exception_vectors(void)
{
__asm__ __volatile__ (
"b reset\n" /* reset */
+#ifdef CONFIG_ARM_EXCEPTIONS
"ldr pc, =undefined_instruction\n" /* undefined instruction */
"ldr pc, =software_interrupt\n" /* software interrupt (SWI) */
"ldr pc, =prefetch_abort\n" /* prefetch abort */
@@ -38,6 +39,21 @@ void __naked __section(.text_entry) exception_vectors(void)
"ldr pc, =not_used\n" /* (reserved) */
"ldr pc, =irq\n" /* irq (interrupt) */
"ldr pc, =fiq\n" /* fiq (fast interrupt) */
+#else
+ "1: bne 1b\n" /* undefined instruction */
+ "1: bne 1b\n" /* software interrupt (SWI) */
+ "1: bne 1b\n" /* prefetch abort */
+ "1: bne 1b\n" /* data abort */
+ "1: bne 1b\n" /* (reserved) */
+ "1: bne 1b\n" /* irq (interrupt) */
+ "1: bne 1b\n" /* fiq (fast interrupt) */
+#endif
+ ".word 0x65726162\n" /* 'bare' */
+ ".word 0x00786f62\n" /* 'box' */
+ ".word _text\n" /* text base. If copied there,
+ * barebox can skip relocation
+ */
+ ".word _barebox_image_size\n" /* image size to copy */
);
}
diff --git a/arch/arm/include/asm/armlinux.h b/arch/arm/include/asm/armlinux.h
index 2765f0df..3cab209d 100644
--- a/arch/arm/include/asm/armlinux.h
+++ b/arch/arm/include/asm/armlinux.h
@@ -25,9 +25,13 @@ static inline void armlinux_set_revision(unsigned int rev)
{
}
-void armlinux_set_serial(u64 serial)
+static inline void armlinux_set_serial(u64 serial)
{
}
#endif
+struct image_data;
+
+void start_linux(void *adr, int swap, struct image_data *data);
+
#endif /* __ARCH_ARMLINUX_H */
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index 3a010838..9383ae14 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -1,4 +1,7 @@
-obj-y += armlinux.o
+obj-$(CONFIG_ARM_LINUX) += armlinux.o
+obj-$(CONFIG_CMD_BOOTM) += bootm.o
+obj-$(CONFIG_CMD_BOOTZ) += bootz.o
+obj-$(CONFIG_CMD_BOOTU) += bootu.o
obj-y += div0.o
obj-y += findbit.o
obj-y += arm.o
diff --git a/arch/arm/lib/armlinux.c b/arch/arm/lib/armlinux.c
index 9927b766..ce1cc6bc 100644
--- a/arch/arm/lib/armlinux.c
+++ b/arch/arm/lib/armlinux.c
@@ -215,162 +215,11 @@ void armlinux_set_serial(u64 serial)
system_serial = serial;
}
-#ifdef CONFIG_CMD_BOOTM
-static int do_bootm_linux(struct image_data *data)
+void start_linux(void *adr, int swap, struct image_data *data)
{
- void (*theKernel)(int zero, int arch, void *params);
- image_header_t *os_header = &data->os->header;
+ void (*kernel)(int zero, int arch, void *params) = adr;
- if (image_get_type(os_header) == IH_TYPE_MULTI) {
- printf("Multifile images not handled at the moment\n");
- return -1;
- }
-
- if (armlinux_architecture == 0) {
- printf("arm architecture not set. Please specify with -a option\n");
- return -1;
- }
-
- if (!armlinux_bootparams) {
- printf("Bootparams not set. Please fix your board code\n");
- return -1;
- }
-
- theKernel = (void *)image_get_ep(os_header);
-
- debug("## Transferring control to Linux (at address 0x%p) ...\n",
- theKernel);
-
- setup_tags(data, 0);
-
- if (relocate_image(data->os, (void *)image_get_load(os_header)))
- return -1;
-
- if (data->initrd)
- if (relocate_image(data->initrd, (void *)image_get_load(&data->initrd->header)))
- return -1;
-
- /* we assume that the kernel is in place */
- printf("\nStarting kernel %s...\n\n", data->initrd ? "with initrd " : "");
-
- shutdown_barebox();
- theKernel (0, armlinux_architecture, armlinux_bootparams);
-
- return -1;
-}
-
-static int image_handle_cmdline_parse(struct image_data *data, int opt,
- char *optarg)
-{
- int ret = 1;
-
- switch (opt) {
- case 'a':
- armlinux_architecture = simple_strtoul(optarg, NULL, 0);
- ret = 0;
- break;
- case 'R':
- system_rev = simple_strtoul(optarg, NULL, 0);
- ret = 0;
- break;
- default:
- break;
- }
-
- return ret;
-}
-
-static struct image_handler handler = {
- .cmdline_options = "a:R:",
- .cmdline_parse = image_handle_cmdline_parse,
- .help_string = " -a <arch> use architecture number <arch>\n"
- " -R <system_rev> use system revison <system_rev>\n",
-
- .bootm = do_bootm_linux,
- .image_type = IH_OS_LINUX,
-};
-
-static int armlinux_register_image_handler(void)
-{
- return register_image_handler(&handler);
-}
-
-late_initcall(armlinux_register_image_handler);
-#endif /* CONFIG_CMD_BOOTM */
-
-#ifdef CONFIG_CMD_BOOTZ
-struct zimage_header {
- u32 unused[9];
- u32 magic;
- u32 start;
- u32 end;
-};
-
-#define ZIMAGE_MAGIC 0x016F2818
-
-static int do_bootz(struct command *cmdtp, int argc, char *argv[])
-{
- void (*theKernel)(int zero, int arch, void *params);
- int fd, ret, swap = 0;
- struct zimage_header header;
- void *zimage;
- u32 end;
-
- if (argc != 2) {
- barebox_cmd_usage(cmdtp);
- return 1;
- }
-
- fd = open(argv[1], O_RDONLY);
- if (fd < 0) {
- perror("open");
- return 1;
- }
-
- ret = read(fd, &header, sizeof(header));
- if (ret < sizeof(header)) {
- printf("could not read %s\n", argv[1]);
- goto err_out;
- }
-
- switch (header.magic) {
-#ifdef CONFIG_BOOT_ENDIANNESS_SWITCH
- case swab32(ZIMAGE_MAGIC):
- swap = 1;
- /* fall through */
-#endif
- case ZIMAGE_MAGIC:
- break;
- default:
- printf("invalid magic 0x%08x\n", header.magic);
- goto err_out;
- }
-
- end = header.end;
-
- if (swap)
- end = swab32(end);
-
- zimage = xmalloc(end);
- memcpy(zimage, &header, sizeof(header));
-
- ret = read(fd, zimage + sizeof(header), end - sizeof(header));
- if (ret < end - sizeof(header)) {
- printf("could not read %s\n", argv[1]);
- goto err_out1;
- }
-
- if (swap) {
- void *ptr;
- for (ptr = zimage; ptr < zimage + end; ptr += 4)
- *(u32 *)ptr = swab32(*(u32 *)ptr);
- }
-
- theKernel = zimage;
-
- printf("loaded zImage from %s with size %d\n", argv[1], end);
-
- setup_tags(NULL, swap);
+ setup_tags(data, swap);
shutdown_barebox();
if (swap) {
@@ -380,61 +229,5 @@ static int do_bootz(struct command *cmdtp, int argc, char *argv[])
__asm__ __volatile__("mcr p15, 0, %0, c1, c0" :: "r" (reg));
}
- theKernel(0, armlinux_architecture, armlinux_bootparams);
-
- return 0;
-
-err_out1:
- free(zimage);
-err_out:
- close(fd);
-
- return 1;
+ kernel(0, armlinux_architecture, armlinux_bootparams);
}
-
-static const __maybe_unused char cmd_bootz_help[] =
-"Usage: bootz [FILE]\n"
-"Boot a Linux zImage\n";
-
-BAREBOX_CMD_START(bootz)
- .cmd = do_bootz,
- .usage = "bootz - start a zImage",
- BAREBOX_CMD_HELP(cmd_bootz_help)
-BAREBOX_CMD_END
-#endif /* CONFIG_CMD_BOOTZ */
-
-#ifdef CONFIG_CMD_BOOTU
-static int do_bootu(struct command *cmdtp, int argc, char *argv[])
-{
- void (*theKernel)(int zero, int arch, void *params) = NULL;
- int fd;
-
- if (argc != 2) {
- barebox_cmd_usage(cmdtp);
- return 1;
- }
-
- fd = open(argv[1], O_RDONLY);
- if (fd > 0)
- theKernel = (void *)memmap(fd, PROT_READ);
-
- if (!theKernel)
- theKernel = (void *)simple_strtoul(argv[1], NULL, 0);
-
- setup_tags(NULL, 0);
-
- shutdown_barebox();
- theKernel(0, armlinux_architecture, armlinux_bootparams);
-
- return 1;
-}
-
-static const __maybe_unused char cmd_bootu_help[] =
-"Usage: bootu <address>\n";
-
-BAREBOX_CMD_START(bootu)
- .cmd = do_bootu,
- .usage = "bootu - start a raw linux image",
- BAREBOX_CMD_HELP(cmd_bootu_help)
-BAREBOX_CMD_END
-#endif /* CONFIG_CMD_BOOTU */
diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S
index 7683f739..81a91236 100644
--- a/arch/arm/lib/barebox.lds.S
+++ b/arch/arm/lib/barebox.lds.S
@@ -93,4 +93,5 @@ SECTIONS
.bss : { *(.bss*) }
__bss_stop = .;
_end = .;
+ _barebox_image_size = __bss_start - _text;
}
diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c
new file mode 100644
index 00000000..b09fe70e
--- /dev/null
+++ b/arch/arm/lib/bootm.c
@@ -0,0 +1,92 @@
+#include <boot.h>
+#include <common.h>
+#include <command.h>
+#include <driver.h>
+#include <environment.h>
+#include <image.h>
+#include <zlib.h>
+#include <init.h>
+#include <fs.h>
+#include <linux/list.h>
+#include <xfuncs.h>
+#include <malloc.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <asm/byteorder.h>
+#include <asm/global_data.h>
+#include <asm/setup.h>
+#include <asm/barebox-arm.h>
+#include <asm/armlinux.h>
+#include <asm/system.h>
+
+static int do_bootm_linux(struct image_data *data)
+{
+ void (*theKernel)(int zero, int arch, void *params);
+ image_header_t *os_header = &data->os->header;
+
+ if (image_get_type(os_header) == IH_TYPE_MULTI) {
+ printf("Multifile images not handled at the moment\n");
+ return -1;
+ }
+
+ theKernel = (void *)image_get_ep(os_header);
+
+ debug("## Transferring control to Linux (at address 0x%p) ...\n",
+ theKernel);
+
+ if (relocate_image(data->os, (void *)image_get_load(os_header)))
+ return -1;
+
+ if (data->initrd)
+ if (relocate_image(data->initrd, (void *)image_get_load(&data->initrd->header)))
+ return -1;
+
+ /* we assume that the kernel is in place */
+ printf("\nStarting kernel %s...\n\n", data->initrd ? "with initrd " : "");
+
+ start_linux(theKernel, 0, data);
+
+ return -1;
+}
+
+static int image_handle_cmdline_parse(struct image_data *data, int opt,
+ char *optarg)
+{
+ int ret = 1;
+ int no;
+
+ switch (opt) {
+ case 'a':
+ no = simple_strtoul(optarg, NULL, 0);
+ armlinux_set_architecture(no);
+ ret = 0;
+ break;
+ case 'R':
+ no = simple_strtoul(optarg, NULL, 0);
+ armlinux_set_revision(no);
+ ret = 0;
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+static struct image_handler handler = {
+ .cmdline_options = "a:R:",
+ .cmdline_parse = image_handle_cmdline_parse,
+ .help_string = " -a <arch> use architecture number <arch>\n"
+ " -R <system_rev> use system revison <system_rev>\n",
+
+ .bootm = do_bootm_linux,
+ .image_type = IH_OS_LINUX,
+};
+
+static int armlinux_register_image_handler(void)
+{
+ return register_image_handler(&handler);
+}
+
+late_initcall(armlinux_register_image_handler);
diff --git a/arch/arm/lib/bootu.c b/arch/arm/lib/bootu.c
new file mode 100644
index 00000000..e97ded0e
--- /dev/null
+++ b/arch/arm/lib/bootu.c
@@ -0,0 +1,38 @@
+#include <common.h>
+#include <command.h>
+#include <fs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <asm/armlinux.h>
+
+static int do_bootu(struct command *cmdtp, int argc, char *argv[])
+{
+ int fd;
+ void *kernel = NULL;
+
+ if (argc != 2) {
+ barebox_cmd_usage(cmdtp);
+ return 1;
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd > 0)
+ kernel = (void *)memmap(fd, PROT_READ);
+
+ if (!kernel)
+ kernel = (void *)simple_strtoul(argv[1], NULL, 0);
+
+ start_linux(kernel, 0, NULL);
+
+ return 1;
+}
+
+static const __maybe_unused char cmd_bootu_help[] =
+"Usage: bootu <address>\n";
+
+BAREBOX_CMD_START(bootu)
+ .cmd = do_bootu,
+ .usage = "bootu - start a raw linux image",
+ BAREBOX_CMD_HELP(cmd_bootu_help)
+BAREBOX_CMD_END
+
diff --git a/arch/arm/lib/bootz.c b/arch/arm/lib/bootz.c
new file mode 100644
index 00000000..cd8f4958
--- /dev/null
+++ b/arch/arm/lib/bootz.c
@@ -0,0 +1,100 @@
+#include <common.h>
+#include <command.h>
+#include <fs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <asm/armlinux.h>
+#include <asm/system.h>
+
+struct zimage_header {
+ u32 unused[9];
+ u32 magic;
+ u32 start;
+ u32 end;
+};
+
+#define ZIMAGE_MAGIC 0x016F2818
+
+static int do_bootz(struct command *cmdtp, int argc, char *argv[])
+{
+ int fd, ret, swap = 0;
+ struct zimage_header header;
+ void *zimage;
+ u32 end;
+
+ if (argc != 2) {
+ barebox_cmd_usage(cmdtp);
+ return 1;
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ return 1;
+ }
+
+ ret = read(fd, &header, sizeof(header));
+ if (ret < sizeof(header)) {
+ printf("could not read %s\n", argv[1]);
+ goto err_out;
+ }
+
+ switch (header.magic) {
+#ifdef CONFIG_BOOT_ENDIANNESS_SWITCH
+ case swab32(ZIMAGE_MAGIC):
+ swap = 1;
+ /* fall through */
+#endif
+ case ZIMAGE_MAGIC:
+ break;
+ default:
+ printf("invalid magic 0x%08x\n", header.magic);
+ goto err_out;
+ }
+
+ end = header.end;
+
+ if (swap)
+ end = swab32(end);
+
+ zimage = xmalloc(end);
+ memcpy(zimage, &header, sizeof(header));
+
+ ret = read(fd, zimage + sizeof(header), end - sizeof(header));
+ if (ret < end - sizeof(header)) {
+ printf("could not read %s\n", argv[1]);
+ goto err_out1;
+ }
+
+ if (swap) {
+ void *ptr;
+ for (ptr = zimage; ptr < zimage + end; ptr += 4)
+ *(u32 *)ptr = swab32(*(u32 *)ptr);
+ }
+
+ printf("loaded zImage from %s with size %d\n", argv[1], end);
+
+ start_linux(zimage, swap, NULL);
+
+ return 0;
+
+err_out1:
+ free(zimage);
+err_out:
+ close(fd);
+
+ return 1;
+}
+
+static const __maybe_unused char cmd_bootz_help[] =
+"Usage: bootz [FILE]\n"
+"Boot a Linux zImage\n";
+
+BAREBOX_CMD_START(bootz)
+ .cmd = do_bootz,
+ .usage = "bootz - start a zImage",
+ BAREBOX_CMD_HELP(cmd_bootz_help)
+BAREBOX_CMD_END
+
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index 630405b1..f256310c 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -32,66 +32,159 @@ choice
config ARCH_OMAP3
bool "OMAP3"
select CPU_V7
+ select GENERIC_GPIO
select ARCH_HAS_LOWLEVEL_INIT
select OMAP_CLOCK_SOURCE_S32K
help
Say Y here if you are using Texas Instrument's OMAP343x based platform
+config ARCH_OMAP4
+ bool "OMAP4"
+ select CPU_V7
+ select GENERIC_GPIO
+ select OMAP_CLOCK_SOURCE_S32K
+ help
+ Say Y here if you are using Texas Instrument's OMAP4 based platform
+
endchoice
- ### Generic Clock configurations to be enabled by Mach - invisible to enable.
- config OMAP_CLOCK_UART
- bool
- config OMAP_CLOCK_UART2
- bool
- config OMAP_CLOCK_UART3
- bool
- config OMAP_CLOCK_I2C
- bool
-
- # Blind enable all possible clocks.. think twice before you do this.
- config OMAP_CLOCK_ALL
- bool
-
- config OMAP_CLOCK_SOURCE_S32K
- bool
-
- config OMAP3_CLOCK_CONFIG
- prompt "Clock Configuration"
- bool
- depends on ARCH_OMAP3
- default y
- help
- Say Y here if you like to have OMAP3 Clock configuration done.
-
- config OMAP3_COPY_CLOCK_SRAM
- prompt "SRAM copy of Clock code"
- bool
- depends on OMAP3_CLOCK_CONFIG
- default y
- help
- Say Y here if you like to have initial OMAP3 Clock configuration done from SRAM.
-
-config GPMC
+### Generic Clock configurations to be enabled by Mach - invisible to enable.
+config OMAP_CLOCK_UART
+ bool
+config OMAP_CLOCK_UART2
+ bool
+config OMAP_CLOCK_UART3
+ bool
+config OMAP_CLOCK_I2C
+ bool
+
+# Blind enable all possible clocks.. think twice before you do this.
+config OMAP_CLOCK_ALL
+ bool
+
+config OMAP_CLOCK_SOURCE_S32K
+ bool
+
+config OMAP3_CLOCK_CONFIG
+ prompt "Clock Configuration"
+ bool
+ depends on ARCH_OMAP3
+ default y
+ help
+ Say Y here if you like to have OMAP3 Clock configuration done.
+
+config OMAP3_COPY_CLOCK_SRAM
+ prompt "SRAM copy of Clock code"
+ bool
+ depends on OMAP3_CLOCK_CONFIG
+ default y
+ help
+ Say Y here if you like to have initial OMAP3 Clock configuration done from SRAM.
+
+config OMAP_GPMC
prompt "Support for GPMC configuration"
bool
- depends on (ARCH_OMAP2 || ARCH_OMAP3)
+ depends on (ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP4)
default y
help
Enable this if you use Texas Instrument's General purpose Memory
Controller(GPMC). GPMC allows you to configure devices such as NOR,
NAND, OneNAND etc.
-config GPIO
- prompt "Support for GPIO configuration"
+config OMAP_BUILD_IFT
+ prompt "build ift binary"
bool
- select GENERIC_GPIO
- depends on (ARCH_OMAP2 || ARCH_OMAP3)
- default y
+
+config ARCH_TEXT_BASE
+ hex
+ default 0x80e80000 if MACH_OMAP343xSDP
+ default 0x80e80000 if MACH_BEAGLE
+
+config BOARDINFO
+ default "Texas Instrument's SDP343x" if MACH_OMAP343xSDP
+ default "Texas Instrument's Beagle" if MACH_BEAGLE
+ default "Texas Instrument's OMAP3EVM" if MACH_OMAP3EVM
+ default "Texas Instrument's Panda" if MACH_PANDA
+ default "Phytec phyCORE pcm049" if MACH_PCM049
+
+choice
+ prompt "Select OMAP board"
+
+config MACH_OMAP343xSDP
+ bool "Texas Instrument's SDP343x"
+ select MACH_HAS_LOWLEVEL_INIT
+ select OMAP_CLOCK_ALL
+ select HAS_OMAP_NAND
+ depends on ARCH_OMAP3
+ help
+ Say Y here if you are using SDP343x platform
+
+config MACH_BEAGLE
+ bool "Texas Instrument's Beagle Board"
+ select MACH_HAS_LOWLEVEL_INIT
+ select OMAP_CLOCK_ALL
+ select HAVE_NOSHELL
+ select HAS_OMAP_NAND
+ depends on ARCH_OMAP3
+ help
+ Say Y here if you are using Beagle Board
+
+config MACH_OMAP3EVM
+ bool "Texas Instrument's OMAP3 EVM"
+ select MACH_HAS_LOWLEVEL_INIT
+ select OMAP_CLOCK_ALL
+ select HAS_OMAP_NAND
+ depends on ARCH_OMAP3
+ help
+ Say Y here if you are using OMAP3EVM
+
+config MACH_PANDA
+ bool "Texas Instrument's Panda Board"
+ select HAVE_MMU
+ select HAVE_NOSHELL
+ select MACH_HAS_LOWLEVEL_INIT
+ help
+ Say Y here if you are using OMAP4 Panda board
+
+config MACH_PCM049
+ bool "Phytec phyCORE pcm049"
+ select HAVE_MMU
+ select HAVE_NOSHELL
+ depends on ARCH_OMAP4
+ select MACH_HAS_LOWLEVEL_INIT
help
- Enable this if you use Texas Instrument's General Purpose IO
+ Say Y here if you are using Phytecs phyCORE pcm049 board
+ based on OMAP4
+
+endchoice
+
+if MACH_OMAP3EVM
+ choice
+ prompt "Select UART"
-# Get the board specific configurations
-source arch/arm/boards/omap/Kconfig
+ config OMAP3EVM_UART1
+ bool "Use UART1"
+ depends on MACH_OMAP3EVM
+ help
+ Say Y here if you would like to use UART1 as console.
+
+ config OMAP3EVM_UART3
+ bool "Use UART3"
+ depends on MACH_OMAP3EVM
+ help
+ Say Y here if you would like to use UART3 as console.
+ endchoice
+endif
+
+config MACH_OMAP_ADVANCED_MUX
+ bool "Enable advanced pin muxing"
+ depends on MACH_OMAP343xSDP
+ default n
+ help
+ Say Y here if you would like to have complete pin muxing to be
+ done at boot time
+
+config HAS_OMAP_NAND
+ bool
endmenu
diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
index 57bab998..a4b9a557 100644
--- a/arch/arm/mach-omap/Makefile
+++ b/arch/arm/mach-omap/Makefile
@@ -22,6 +22,7 @@
obj-$(CONFIG_ARCH_OMAP) += syslib.o
obj-$(CONFIG_OMAP_CLOCK_SOURCE_S32K) += s32k_clksource.o
obj-$(CONFIG_ARCH_OMAP3) += omap3_core.o omap3_generic.o
+obj-$(CONFIG_ARCH_OMAP4) += omap4_generic.o omap4_clock.o
obj-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock_core.o omap3_clock.o
-obj-$(CONFIG_GPMC) += gpmc.o
-obj-$(CONFIG_GPIO) += gpio.o
+obj-$(CONFIG_OMAP_GPMC) += gpmc.o devices-gpmc-nand.o
+obj-y += omap-uart.o gpio.o xload.o
diff --git a/arch/arm/boards/omap/devices-gpmc-nand.c b/arch/arm/mach-omap/devices-gpmc-nand.c
index 4369aa00..c2a2b0d1 100644
--- a/arch/arm/boards/omap/devices-gpmc-nand.c
+++ b/arch/arm/mach-omap/devices-gpmc-nand.c
@@ -84,7 +84,8 @@ static struct device_d gpmc_generic_nand_nand_device = {
*
* @return success/fail based on device funtion
*/
-int gpmc_generic_nand_devices_init(int cs, int width, int hwecc)
+int gpmc_generic_nand_devices_init(int cs, int width,
+ enum gpmc_ecc_mode eccmode)
{
nand_plat.cs = cs;
@@ -94,7 +95,7 @@ int gpmc_generic_nand_devices_init(int cs, int width, int hwecc)
nand_cfg.cfg[0] = GPMC_CONF1_VALx8;
nand_plat.device_width = width;
- nand_plat.plat_options = hwecc ? NAND_HWECC_ENABLE : 0;
+ nand_plat.ecc_mode = eccmode;
/* Configure GPMC CS before register */
gpmc_cs_config(nand_plat.cs, &nand_cfg);
diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/mach-omap/gpio.c
index 240ac8e2..b0bd8056 100644
--- a/arch/arm/mach-omap/gpio.c
+++ b/arch/arm/mach-omap/gpio.c
@@ -40,20 +40,45 @@
#include <asm/io.h>
#include <errno.h>
-static struct gpio_bank gpio_bank_34xx[6] = {
- { (void *)OMAP34XX_GPIO1_BASE, METHOD_GPIO_24XX },
- { (void *)OMAP34XX_GPIO2_BASE, METHOD_GPIO_24XX },
- { (void *)OMAP34XX_GPIO3_BASE, METHOD_GPIO_24XX },
- { (void *)OMAP34XX_GPIO4_BASE, METHOD_GPIO_24XX },
- { (void *)OMAP34XX_GPIO5_BASE, METHOD_GPIO_24XX },
- { (void *)OMAP34XX_GPIO6_BASE, METHOD_GPIO_24XX },
+#ifdef CONFIG_ARCH_OMAP3
+
+#define OMAP_GPIO_OE 0x0034
+#define OMAP_GPIO_DATAIN 0x0038
+#define OMAP_GPIO_DATAOUT 0x003c
+#define OMAP_GPIO_CLEARDATAOUT 0x0090
+#define OMAP_GPIO_SETDATAOUT 0x0094
+
+static void __iomem *gpio_bank[] = {
+ (void *)0x48310000,
+ (void *)0x49050000,
+ (void *)0x49052000,
+ (void *)0x49054000,
+ (void *)0x49056000,
+ (void *)0x49058000,
};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP4
+
+#define OMAP_GPIO_OE 0x0134
+#define OMAP_GPIO_DATAIN 0x0138
+#define OMAP_GPIO_DATAOUT 0x013c
+#define OMAP_GPIO_CLEARDATAOUT 0x0190
+#define OMAP_GPIO_SETDATAOUT 0x0194
+
+static void __iomem *gpio_bank[] = {
+ (void *)0x4a310000,
+ (void *)0x48055000,
+ (void *)0x48057000,
+ (void *)0x48059000,
+ (void *)0x4805b000,
+ (void *)0x4805d000,
+};
+#endif
-static struct gpio_bank *gpio_bank = &gpio_bank_34xx[0];
-
-static inline struct gpio_bank *get_gpio_bank(int gpio)
+static inline void __iomem *get_gpio_base(int gpio)
{
- return &gpio_bank[gpio >> 5];
+ return gpio_bank[gpio >> 5];
}
static inline int get_gpio_index(int gpio)
@@ -65,7 +90,7 @@ static inline int gpio_valid(int gpio)
{
if (gpio < 0)
return -1;
- if (gpio < 192)
+ if (gpio / 32 < ARRAY_SIZE(gpio_bank))
return 0;
return -1;
}
@@ -81,50 +106,35 @@ static int check_gpio(int gpio)
void gpio_set_value(unsigned gpio, int value)
{
- struct gpio_bank *bank;
- void *reg;
+ void __iomem *reg;
u32 l = 0;
if (check_gpio(gpio) < 0)
return;
- bank = get_gpio_bank(gpio);
- reg = bank->base;
-
- switch (bank->method) {
- case METHOD_GPIO_24XX:
- if (value)
- reg += OMAP24XX_GPIO_SETDATAOUT;
- else
- reg += OMAP24XX_GPIO_CLEARDATAOUT;
- l = 1 << get_gpio_index(gpio);
- break;
- default:
- printf("omap3-gpio unknown bank method %s %d\n",
- __FILE__, __LINE__);
- return;
- }
+
+ reg = get_gpio_base(gpio);
+
+ if (value)
+ reg += OMAP_GPIO_SETDATAOUT;
+ else
+ reg += OMAP_GPIO_CLEARDATAOUT;
+ l = 1 << get_gpio_index(gpio);
+
__raw_writel(l, reg);
}
int gpio_direction_input(unsigned gpio)
{
- struct gpio_bank *bank;
- void *reg;
+ void __iomem *reg;
u32 val;
if (check_gpio(gpio) < 0)
return -EINVAL;
- bank = get_gpio_bank(gpio);
- reg = bank->base;
+ reg = get_gpio_base(gpio);
+
+ reg += OMAP_GPIO_OE;
- switch (bank->method) {
- case METHOD_GPIO_24XX:
- reg += OMAP24XX_GPIO_OE;
- break;
- default:
- return -EINVAL;
- }
val = __raw_readl(reg);
val |= 1 << get_gpio_index(gpio);
__raw_writel(val, reg);
@@ -134,25 +144,16 @@ int gpio_direction_input(unsigned gpio)
int gpio_direction_output(unsigned gpio, int value)
{
- struct gpio_bank *bank;
- void *reg;
+ void __iomem *reg;
u32 val;
if (check_gpio(gpio) < 0)
return -EINVAL;
- bank = get_gpio_bank(gpio);
-
- reg = bank->base;
+ reg = get_gpio_base(gpio);
gpio_set_value(gpio, value);
- switch (bank->method) {
- case METHOD_GPIO_24XX:
- reg += OMAP24XX_GPIO_OE;
- break;
- default:
- return -EINVAL;
- }
+ reg += OMAP_GPIO_OE;
val = __raw_readl(reg);
val &= ~(1 << get_gpio_index(gpio));
@@ -163,44 +164,13 @@ int gpio_direction_output(unsigned gpio, int value)
int gpio_get_value(unsigned gpio)
{
- struct gpio_bank *bank;
- void *reg;
-
- if (check_gpio(gpio) < 0)
- return -EINVAL;
- bank = get_gpio_bank(gpio);
- reg = bank->base;
- switch (bank->method) {
- case METHOD_GPIO_24XX:
- reg += OMAP24XX_GPIO_DATAIN;
- break;
- default:
- return -EINVAL;
- }
- return (__raw_readl(reg)
- & (1 << get_gpio_index(gpio))) != 0;
-}
-
-static void _reset_gpio(int gpio)
-{
- gpio_direction_input(gpio);
-}
+ void __iomem *reg;
-int omap_request_gpio(int gpio)
-{
if (check_gpio(gpio) < 0)
return -EINVAL;
+ reg = get_gpio_base(gpio);
- return 0;
-}
-
-void omap_free_gpio(int gpio)
-{
- struct gpio_bank *bank;
-
- if (check_gpio(gpio) < 0)
- return;
- bank = get_gpio_bank(gpio);
+ reg += OMAP_GPIO_DATAIN;
- _reset_gpio(gpio);
+ return (__raw_readl(reg) & (1 << get_gpio_index(gpio))) != 0;
}
diff --git a/arch/arm/mach-omap/include/mach/gpio.h b/arch/arm/mach-omap/include/mach/gpio.h
index 9840b6e9..245f781e 100644
--- a/arch/arm/mach-omap/include/mach/gpio.h
+++ b/arch/arm/mach-omap/include/mach/gpio.h
@@ -38,52 +38,6 @@
#ifndef _GPIO_H
#define _GPIO_H
-#define OMAP24XX_GPIO_REVISION 0x0000
-#define OMAP24XX_GPIO_SYSCONFIG 0x0010
-#define OMAP24XX_GPIO_SYSSTATUS 0x0014
-#define OMAP24XX_GPIO_IRQSTATUS1 0x0018
-#define OMAP24XX_GPIO_IRQSTATUS2 0x0028
-#define OMAP24XX_GPIO_IRQENABLE2 0x002c
-#define OMAP24XX_GPIO_IRQENABLE1 0x001c
-#define OMAP24XX_GPIO_WAKE_EN 0x0020
-#define OMAP24XX_GPIO_CTRL 0x0030
-#define OMAP24XX_GPIO_OE 0x0034
-#define OMAP24XX_GPIO_DATAIN 0x0038
-#define OMAP24XX_GPIO_DATAOUT 0x003c
-#define OMAP24XX_GPIO_LEVELDETECT0 0x0040
-#define OMAP24XX_GPIO_LEVELDETECT1 0x0044
-#define OMAP24XX_GPIO_RISINGDETECT 0x0048
-#define OMAP24XX_GPIO_FALLINGDETECT 0x004c
-#define OMAP24XX_GPIO_DEBOUNCE_EN 0x0050
-#define OMAP24XX_GPIO_DEBOUNCE_VAL 0x0054
-#define OMAP24XX_GPIO_CLEARIRQENABLE1 0x0060
-#define OMAP24XX_GPIO_SETIRQENABLE1 0x0064
-#define OMAP24XX_GPIO_CLEARWKUENA 0x0080
-#define OMAP24XX_GPIO_SETWKUENA 0x0084
-#define OMAP24XX_GPIO_CLEARDATAOUT 0x0090
-#define OMAP24XX_GPIO_SETDATAOUT 0x0094
-
-struct gpio_bank {
- void *base;
- int method;
-};
-
-/* OMAP3 GPIO registers */
-#define OMAP34XX_GPIO1_BASE 0x48310000
-#define OMAP34XX_GPIO2_BASE 0x49050000
-#define OMAP34XX_GPIO3_BASE 0x49052000
-#define OMAP34XX_GPIO4_BASE 0x49054000
-#define OMAP34XX_GPIO5_BASE 0x49056000
-#define OMAP34XX_GPIO6_BASE 0x49058000
-
-#define METHOD_GPIO_24XX 4
-
-/* This is the interface */
-
-/* Request a gpio before using it */
-int omap_request_gpio(int gpio);
-/* Reset and free a gpio after using it */
-void omap_free_gpio(int gpio);
void gpio_set_value(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
diff --git a/arch/arm/mach-omap/include/mach/gpmc.h b/arch/arm/mach-omap/include/mach/gpmc.h
index a658cf00..3ddc5f5b 100644
--- a/arch/arm/mach-omap/include/mach/gpmc.h
+++ b/arch/arm/mach-omap/include/mach/gpmc.h
@@ -66,6 +66,7 @@
#define GPMC_ECC7_RESULT (0x218)
#define GPMC_ECC8_RESULT (0x21C)
#define GPMC_ECC9_RESULT (0x220)
+#define GPMC_ECC_BCH_RESULT_0 0x240
#define GPMC_CONFIG1_0 (0x60)
#define GPMC_CONFIG1_1 (0x90)
diff --git a/arch/arm/mach-omap/include/mach/gpmc_nand.h b/arch/arm/mach-omap/include/mach/gpmc_nand.h
index e23faabc..1bc52ffe 100644
--- a/arch/arm/mach-omap/include/mach/gpmc_nand.h
+++ b/arch/arm/mach-omap/include/mach/gpmc_nand.h
@@ -33,6 +33,14 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
+enum gpmc_ecc_mode {
+ OMAP_ECC_SOFT,
+ OMAP_ECC_HAMMING_CODE_HW_ROMCODE,
+ OMAP_ECC_BCH4_CODE_HW,
+ OMAP_ECC_BCH8_CODE_HW,
+ OMAP_ECC_BCH8_CODE_HW_ROMCODE,
+};
+
/** omap nand platform data structure */
struct gpmc_nand_platform_data {
/** Chip select you want to use */
@@ -46,6 +54,8 @@ struct gpmc_nand_platform_data {
* platform specific configs here
*/
unsigned short plat_options;
+ /** ecc mode to use */
+ enum gpmc_ecc_mode ecc_mode;
/** setup any special options */
unsigned int options;
/** set up device access as 8,16 as per GPMC config */
@@ -68,11 +78,6 @@ struct gpmc_nand_platform_data {
#define NAND_WAITPOL_HIGH (1 << 0)
#define NAND_WAITPOL_MASK (1 << 0)
-/** plat_options: hw ecc enabled */
-#define NAND_HWECC_ENABLE (1 << 1)
-/** plat_options: hw ecc disabled */
-#define NAND_HWECC_MASK (1 << 1)
-
-int gpmc_generic_nand_devices_init(int cs, int width, int hwecc);
+int gpmc_generic_nand_devices_init(int cs, int width, enum gpmc_ecc_mode);
#endif /* __ASM_OMAP_NAND_GPMC_H */
diff --git a/arch/arm/mach-omap/include/mach/omap4-clock.h b/arch/arm/mach-omap/include/mach/omap4-clock.h
new file mode 100644
index 00000000..0a31d09e
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/omap4-clock.h
@@ -0,0 +1,320 @@
+ /* PRCM */
+#define CM_SYS_CLKSEL 0x4a306110
+
+#define CM_SYS_CLKSEL_19M2 0x4
+#define CM_SYS_CLKSEL_38M4 0x7
+
+/* PRM.CKGEN module registers */
+#define CM_ABE_PLL_REF_CLKSEL 0x4a30610c
+
+
+/* PRM.WKUP_CM module registers */
+#define CM_WKUP_CLKSTCTRL 0x4a307800
+#define CM_WKUP_L4WKUP_CLKCTRL 0x4a307820
+#define CM_WKUP_WDT1_CLKCTRL 0x4a307828
+#define CM_WKUP_WDT2_CLKCTRL 0x4a307830
+#define CM_WKUP_GPIO1_CLKCTRL 0x4a307838
+#define CM_WKUP_TIMER1_CLKCTRL 0x4a307840
+#define CM_WKUP_TIMER12_CLKCTRL 0x4a307848
+#define CM_WKUP_SYNCTIMER_CLKCTRL 0x4a307850
+#define CM_WKUP_USIM_CLKCTRL 0x4a307858
+#define CM_WKUP_SARRAM_CLKCTRL 0x4a307860
+#define CM_WKUP_KEYBOARD_CLKCTRL 0x4a307878
+#define CM_WKUP_RTC_CLKCTRL 0x4a307880
+#define CM_WKUP_BANDGAP_CLKCTRL 0x4a307888
+
+/* CM1.CKGEN module registers */
+#define CM_CLKSEL_CORE 0x4a004100
+#define CM_CLKSEL_ABE 0x4a004108
+#define CM_DLL_CTRL 0x4a004110
+#define CM_CLKMODE_DPLL_CORE 0x4a004120
+#define CM_IDLEST_DPLL_CORE 0x4a004124
+#define CM_AUTOIDLE_DPLL_CORE 0x4a004128
+#define CM_CLKSEL_DPLL_CORE 0x4a00412c
+#define CM_DIV_M2_DPLL_CORE 0x4a004130
+#define CM_DIV_M3_DPLL_CORE 0x4a004134
+#define CM_DIV_M4_DPLL_CORE 0x4a004138
+#define CM_DIV_M5_DPLL_CORE 0x4a00413c
+#define CM_DIV_M6_DPLL_CORE 0x4a004140
+#define CM_DIV_M7_DPLL_CORE 0x4a004144
+#define CM_SSC_DELTAMSTEP_DPLL_CORE 0x4a004148
+#define CM_SSC_MODFREQDIV_DPLL_CORE 0x4a00414c
+#define CM_EMU_OVERRIDE_DPLL_CORE 0x4a004150
+#define CM_CLKMODE_DPLL_MPU 0x4a004160
+#define CM_IDLEST_DPLL_MPU 0x4a004164
+#define CM_AUTOIDLE_DPLL_MPU 0x4a004168
+#define CM_CLKSEL_DPLL_MPU 0x4a00416c
+#define CM_DIV_M2_DPLL_MPU 0x4a004170
+#define CM_SSC_DELTAMSTEP_DPLL_MPU 0x4a004188
+#define CM_SSC_MODFREQDIV_DPLL_MPU 0x4a00418c
+#define CM_BYPCLK_DPLL_MPU 0x4a00419c
+#define CM_CLKMODE_DPLL_IVA 0x4a0041a0
+#define CM_IDLEST_DPLL_IVA 0x4a0041a4
+#define CM_AUTOIDLE_DPLL_IVA 0x4a0041a8
+#define CM_CLKSEL_DPLL_IVA 0x4a0041ac
+#define CM_DIV_M4_DPLL_IVA 0x4a0041b8
+#define CM_DIV_M5_DPLL_IVA 0x4a0041bc
+#define CM_SSC_DELTAMSTEP_DPLL_IVA 0x4a0041c8
+#define CM_SSC_MODFREQDIV_DPLL_IVA 0x4a0041cc
+#define CM_BYPCLK_DPLL_IVA 0x4a0041dc
+#define CM_CLKMODE_DPLL_ABE 0x4a0041e0
+#define CM_IDLEST_DPLL_ABE 0x4a0041e4
+#define CM_AUTOIDLE_DPLL_ABE 0x4a0041e8
+#define CM_CLKSEL_DPLL_ABE 0x4a0041ec
+#define CM_DIV_M2_DPLL_ABE 0x4a0041f0
+#define CM_DIV_M3_DPLL_ABE 0x4a0041f4
+#define CM_SSC_DELTAMSTEP_DPLL_ABE 0x4a004208
+#define CM_SSC_MODFREQDIV_DPLL_ABE 0x4a00420c
+#define CM_CLKMODE_DPLL_DDRPHY 0x4a004220
+#define CM_IDLEST_DPLL_DDRPHY 0x4a004224
+#define CM_AUTOIDLE_DPLL_DDRPHY 0x4a004228
+#define CM_CLKSEL_DPLL_DDRPHY 0x4a00422c
+#define CM_DIV_M2_DPLL_DDRPHY 0x4a004230
+#define CM_DIV_M4_DPLL_DDRPHY 0x4a004238
+#define CM_DIV_M5_DPLL_DDRPHY 0x4a00423c
+#define CM_DIV_M6_DPLL_DDRPHY 0x4a004240
+#define CM_SSC_DELTAMSTEP_DPLL_DDRPHY 0x4a004248
+
+/* CM1.ABE register offsets */
+#define CM1_ABE_CLKSTCTRL 0x4a004500
+#define CM1_ABE_L4ABE_CLKCTRL 0x4a004520
+#define CM1_ABE_AESS_CLKCTRL 0x4a004528
+#define CM1_ABE_PDM_CLKCTRL 0x4a004530
+#define CM1_ABE_DMIC_CLKCTRL 0x4a004538
+#define CM1_ABE_MCASP_CLKCTRL 0x4a004540
+#define CM1_ABE_MCBSP1_CLKCTRL 0x4a004548
+#define CM1_ABE_MCBSP2_CLKCTRL 0x4a004550
+#define CM1_ABE_MCBSP3_CLKCTRL 0x4a004558
+#define CM1_ABE_SLIMBUS_CLKCTRL 0x4a004560
+#define CM1_ABE_TIMER5_CLKCTRL 0x4a004568
+#define CM1_ABE_TIMER6_CLKCTRL 0x4a004570
+#define CM1_ABE_TIMER7_CLKCTRL 0x4a004578
+#define CM1_ABE_TIMER8_CLKCTRL 0x4a004580
+#define CM1_ABE_WDT3_CLKCTRL 0x4a004588
+
+/* CM1.DSP register offsets */
+#define DSP_CLKSTCTRL 0x4a004400
+#define DSP_DSP_CLKCTRL 0x4a004420
+
+/* CM2.CKGEN module registers */
+#define CM_CLKSEL_DUCATI_ISS_ROOT 0x4a008100
+#define CM_CLKSEL_USB_60MHz 0x4a008104
+#define CM_SCALE_FCLK 0x4a008108
+#define CM_CORE_DVFS_PERF1 0x4a008110
+#define CM_CORE_DVFS_PERF2 0x4a008114
+#define CM_CORE_DVFS_PERF3 0x4a008118
+#define CM_CORE_DVFS_PERF4 0x4a00811c
+#define CM_CORE_DVFS_CURRENT 0x4a008124
+#define CM_IVA_DVFS_PERF_TESLA 0x4a008128
+#define CM_IVA_DVFS_PERF_IVAHD 0x4a00812c
+#define CM_IVA_DVFS_PERF_ABE 0x4a008130
+#define CM_IVA_DVFS_CURRENT 0x4a008138
+#define CM_CLKMODE_DPLL_PER 0x4a008140
+#define CM_IDLEST_DPLL_PER 0x4a008144
+#define CM_AUTOIDLE_DPLL_PER 0x4a008148
+#define CM_CLKSEL_DPLL_PER 0x4a00814c
+#define CM_DIV_M2_DPLL_PER 0x4a008150
+#define CM_DIV_M3_DPLL_PER 0x4a008154
+#define CM_DIV_M4_DPLL_PER 0x4a008158
+#define CM_DIV_M5_DPLL_PER 0x4a00815c
+#define CM_DIV_M6_DPLL_PER 0x4a008160
+#define CM_DIV_M7_DPLL_PER 0x4a008164
+#define CM_SSC_DELTAMSTEP_DPLL_PER 0x4a008168
+#define CM_SSC_MODFREQDIV_DPLL_PER 0x4a00816c
+#define CM_EMU_OVERRIDE_DPLL_PER 0x4a008170
+#define CM_CLKMODE_DPLL_USB 0x4a008180
+#define CM_IDLEST_DPLL_USB 0x4a008184
+#define CM_AUTOIDLE_DPLL_USB 0x4a008188
+#define CM_CLKSEL_DPLL_USB 0x4a00818c
+#define CM_DIV_M2_DPLL_USB 0x4a008190
+#define CM_SSC_DELTAMSTEP_DPLL_USB 0x4a0081a8
+#define CM_SSC_MODFREQDIV_DPLL_USB 0x4a0081ac
+#define CM_CLKDCOLDO_DPLL_USB 0x4a0081b4
+#define CM_CLKMODE_DPLL_UNIPRO 0x4a0081c0
+#define CM_IDLEST_DPLL_UNIPRO 0x4a0081c4
+#define CM_AUTOIDLE_DPLL_UNIPRO 0x4a0081c8
+#define CM_CLKSEL_DPLL_UNIPRO 0x4a0081cc
+#define CM_DIV_M2_DPLL_UNIPRO 0x4a0081d0
+#define CM_SSC_DELTAMSTEP_DPLL_UNIPRO 0x4a0081e8
+#define CM_SSC_MODFREQDIV_DPLL_UNIPRO 0x4a0081ec
+
+/* CM2.CORE module registers */
+#define CM_L3_1_CLKSTCTRL 0x4a008700
+#define CM_L3_1_DYNAMICDEP 0x4a008708
+#define CM_L3_1_L3_1_CLKCTRL 0x4a008720
+#define CM_L3_2_CLKSTCTRL 0x4a008800
+#define CM_L3_2_DYNAMICDEP 0x4a008808
+#define CM_L3_2_L3_2_CLKCTRL 0x4a008820
+#define CM_L3_2_GPMC_CLKCTRL 0x4a008828
+#define CM_L3_2_OCMC_RAM_CLKCTRL 0x4a008830
+#define CM_DUCATI_CLKSTCTRL 0x4a008900
+#define CM_DUCATI_STATICDEP 0x4a008904
+#define CM_DUCATI_DYNAMICDEP 0x4a008908
+#define CM_DUCATI_DUCATI_CLKCTRL 0x4a008920
+#define CM_SDMA_CLKSTCTRL 0x4a008a00
+#define CM_SDMA_STATICDEP 0x4a008a04
+#define CM_SDMA_DYNAMICDEP 0x4a008a08
+#define CM_SDMA_SDMA_CLKCTRL 0x4a008a20
+#define CM_MEMIF_CLKSTCTRL 0x4a008b00
+#define CM_MEMIF_DMM_CLKCTRL 0x4a008b20
+#define CM_MEMIF_EMIF_FW_CLKCTRL 0x4a008b28
+#define CM_MEMIF_EMIF_1_CLKCTRL 0x4a008b30
+#define CM_MEMIF_EMIF_2_CLKCTRL 0x4a008b38
+#define CM_MEMIF_DLL_CLKCTRL 0x4a008b40
+#define CM_MEMIF_EMIF_H1_CLKCTRL 0x4a008b50
+#define CM_MEMIF_EMIF_H2_CLKCTRL 0x4a008b58
+#define CM_MEMIF_DLL_H_CLKCTRL 0x4a008b60
+#define CM_D2D_CLKSTCTRL 0x4a008c00
+#define CM_D2D_STATICDEP 0x4a008c04
+#define CM_D2D_DYNAMICDEP 0x4a008c08
+#define CM_D2D_SAD2D_CLKCTRL 0x4a008c20
+#define CM_D2D_MODEM_ICR_CLKCTRL 0x4a008c28
+#define CM_D2D_SAD2D_FW_CLKCTRL 0x4a008c30
+#define CM_L4CFG_CLKSTCTRL 0x4a008d00
+#define CM_L4CFG_DYNAMICDEP 0x4a008d08
+#define CM_L4CFG_L4_CFG_CLKCTRL 0x4a008d20
+#define CM_L4CFG_HW_SEM_CLKCTRL 0x4a008d28
+#define CM_L4CFG_MAILBOX_CLKCTRL 0x4a008d30
+#define CM_L4CFG_SAR_ROM_CLKCTRL 0x4a008d38
+#define CM_L3INSTR_CLKSTCTRL 0x4a008e00
+#define CM_L3INSTR_L3_3_CLKCTRL 0x4a008e20
+#define CM_L3INSTR_L3_INSTR_CLKCTRL 0x4a008e28
+#define CM_L3INSTR_OCP_WP1_CLKCTRL 0x4a008e40
+
+/* CM2.L4PER register offsets */
+#define CM_L4PER_CLKSTCTRL 0x4a009400
+#define CM_L4PER_DYNAMICDEP 0x4a009408
+#define CM_L4PER_ADC_CLKCTRL 0x4a009420
+#define CM_L4PER_DMTIMER10_CLKCTRL 0x4a009428
+#define CM_L4PER_DMTIMER11_CLKCTRL 0x4a009430
+#define CM_L4PER_DMTIMER2_CLKCTRL 0x4a009438
+#define CM_L4PER_DMTIMER3_CLKCTRL 0x4a009440
+#define CM_L4PER_DMTIMER4_CLKCTRL 0x4a009448
+#define CM_L4PER_DMTIMER9_CLKCTRL 0x4a009450
+#define CM_L4PER_ELM_CLKCTRL 0x4a009458
+#define CM_L4PER_GPIO2_CLKCTRL 0x4a009460
+#define CM_L4PER_GPIO3_CLKCTRL 0x4a009468
+#define CM_L4PER_GPIO4_CLKCTRL 0x4a009470
+#define CM_L4PER_GPIO5_CLKCTRL 0x4a009478
+#define CM_L4PER_GPIO6_CLKCTRL 0x4a009480
+#define CM_L4PER_HDQ1W_CLKCTRL 0x4a009488
+#define CM_L4PER_HECC1_CLKCTRL 0x4a009490
+#define CM_L4PER_HECC2_CLKCTRL 0x4a009498
+#define CM_L4PER_I2C1_CLKCTRL 0x4a0094a0
+#define CM_L4PER_I2C2_CLKCTRL 0x4a0094a8
+#define CM_L4PER_I2C3_CLKCTRL 0x4a0094b0
+#define CM_L4PER_I2C4_CLKCTRL 0x4a0094b8
+#define CM_L4PER_L4PER_CLKCTRL 0x4a0094c0
+#define CM_L4PER_MCASP2_CLKCTRL 0x4a0094d0
+#define CM_L4PER_MCASP3_CLKCTRL 0x4a0094d8
+#define CM_L4PER_MCBSP4_CLKCTRL 0x4a0094e0
+#define CM_L4PER_MGATE_CLKCTRL 0x4a0094e8
+#define CM_L4PER_MCSPI1_CLKCTRL 0x4a0094f0
+#define CM_L4PER_MCSPI2_CLKCTRL 0x4a0094f8
+#define CM_L4PER_MCSPI3_CLKCTRL 0x4a009500
+#define CM_L4PER_MCSPI4_CLKCTRL 0x4a009508
+#define CM_L4PER_MMCSD3_CLKCTRL 0x4a009520
+#define CM_L4PER_MMCSD4_CLKCTRL 0x4a009528
+#define CM_L4PER_MSPROHG_CLKCTRL 0x4a009530
+#define CM_L4PER_SLIMBUS2_CLKCTRL 0x4a009538
+#define CM_L4PER_UART1_CLKCTRL 0x4a009540
+#define CM_L4PER_UART2_CLKCTRL 0x4a009548
+#define CM_L4PER_UART3_CLKCTRL 0x4a009550
+#define CM_L4PER_UART4_CLKCTRL 0x4a009558
+#define CM_L4PER_MMCSD5_CLKCTRL 0x4a009560
+#define CM_L4PER_I2C5_CLKCTRL 0x4a009568
+#define CM_L4SEC_CLKSTCTRL 0x4a009580
+#define CM_L4SEC_STATICDEP 0x4a009584
+#define CM_L4SEC_DYNAMICDEP 0x4a009588
+#define CM_L4SEC_AES1_CLKCTRL 0x4a0095a0
+#define CM_L4SEC_AES2_CLKCTRL 0x4a0095a8
+#define CM_L4SEC_DES3DES_CLKCTRL 0x4a0095b0
+#define CM_L4SEC_PKAEIP29_CLKCTRL 0x4a0095b8
+#define CM_L4SEC_RNG_CLKCTRL 0x4a0095c0
+#define CM_L4SEC_SHA2MD51_CLKCTRL 0x4a0095c8
+#define CM_L4SEC_CRYPTODMA_CLKCTRL 0x4a0095d8
+
+/* CM2.IVAHD */
+#define IVAHD_CLKSTCTRL 0x4a008f00
+#define IVAHD_IVAHD_CLKCTRL 0x4a008f20
+#define IVAHD_SL2_CLKCTRL 0x4a008f28
+
+/* CM2.L3INIT */
+#define CM_L3INIT_HSMMC1_CLKCTRL 0x4a009328
+#define CM_L3INIT_HSMMC2_CLKCTRL 0x4a009330
+#define CM_L3INIT_HSI_CLKCTRL 0x4a009338
+#define CM_L3INIT_UNIPRO1_CLKCTRL 0x4a009340
+#define CM_L3INIT_HSUSBHOST_CLKCTRL 0x4a009358
+#define CM_L3INIT_HSUSBOTG_CLKCTRL 0x4a009360
+#define CM_L3INIT_HSUSBTLL_CLKCTRL 0x4a009368
+#define CM_L3INIT_P1500_CLKCTRL 0x4a009378
+#define CM_L3INIT_FSUSB_CLKCTRL 0x4a0093d0
+#define CM_L3INIT_USBPHY_CLKCTRL 0x4a0093e0
+
+/* CM2.CAM */
+#define CM_CAM_CLKSTCTRL 0x4a009000
+#define CM_CAM_ISS_CLKCTRL 0x4a009020
+#define CM_CAM_FDIF_CLKCTRL 0x4a009028
+
+/* CM2.DSS */
+#define CM_DSS_CLKSTCTRL 0x4a009100
+#define CM_DSS_DSS_CLKCTRL 0x4a009120
+#define CM_DSS_DEISS_CLKCTRL 0x4a009128
+
+/* CM2.SGX */
+#define CM_SGX_CLKSTCTRL 0x4a009200
+#define CM_SGX_SGX_CLKCTRL 0x4a009220
+
+#define PLL_STOP 1 /* PER & IVA */
+#define PLL_MN_POWER_BYPASS 4
+#define PLL_LOW_POWER_BYPASS 5 /* MPU, IVA & CORE */
+#define PLL_FAST_RELOCK_BYPASS 6 /* CORE */
+#define PLL_LOCK 7 /* MPU, IVA, CORE & PER */
+
+/* Used to index into DPLL parameter tables */
+struct dpll_param {
+ unsigned int m;
+ unsigned int n;
+ unsigned int m2;
+ unsigned int m3;
+ unsigned int m4;
+ unsigned int m5;
+ unsigned int m6;
+ unsigned int m7;
+};
+
+#define OMAP4_MPU_DPLL_PARAM_19M2 {0x34, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+#define OMAP4_MPU_DPLL_PARAM_19M2_MPU600 {0x7d, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+#define OMAP4_MPU_DPLL_PARAM_19M2_MPU1000 {0x69, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+#define OMAP4_MPU_DPLL_PARAM_38M4 {0x1a, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+#define OMAP4_MPU_DPLL_PARAM_38M4_MPU600 {0x7d, 0x07, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+#define OMAP4_MPU_DPLL_PARAM_38M4_MPU1000 {0x69, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+#define OMAP4_IVA_DPLL_PARAM_19M2 {0x61, 0x01, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00}
+#define OMAP4_IVA_DPLL_PARAM_38M4 {0x61, 0x03, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00}
+
+#define OMAP4_PER_DPLL_PARAM_19M2 {0x28, 0x00, 0x08, 0x06, 0x0c, 0x09, 0x04, 0x05}
+#define OMAP4_PER_DPLL_PARAM_38M4 {0x14, 0x00, 0x08, 0x06, 0x0c, 0x09, 0x04, 0x05}
+
+#define OMAP4_ABE_DPLL_PARAM_19M2 {0x80, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}
+#define OMAP4_ABE_DPLL_PARAM_38M4 {0x40, 0x18, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}
+
+#define OMAP4_USB_DPLL_PARAM_19M2 {0x32, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0}
+#define OMAP4_USB_DPLL_PARAM_38M4 {0x32, 0x1, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0}
+
+#define OMAP4_CORE_DPLL_PARAM_19M2_DDR200 {0x7d, 0x02, 0x02, 0x05, 0x08, 0x04, 0x06, 0x05}
+#define OMAP4_CORE_DPLL_PARAM_19M2_DDR333 {0x410, 0x09, 0x03, 0x0c, 0x14, 0x0a, 0x0f, 0x0c}
+#define OMAP4_CORE_DPLL_PARAM_19M2_DDR400 {0x7d, 0x02, 0x01, 0x05, 0x08, 0x04, 0x06, 0x05}
+#define OMAP4_CORE_DPLL_PARAM_38M4_DDR200 {0x7d, 0x05, 0x02, 0x05, 0x08, 0x04, 0x06, 0x05}
+#define OMAP4_CORE_DPLL_PARAM_38M4_DDR400 {0x7d, 0x05, 0x01, 0x05, 0x08, 0x04, 0x06, 0x05}
+
+void omap4_configure_mpu_dpll(const struct dpll_param *dpll_param);
+void omap4_configure_iva_dpll(const struct dpll_param *dpll_param);
+void omap4_configure_per_dpll(const struct dpll_param *dpll_param);
+void omap4_configure_abe_dpll(const struct dpll_param *dpll_param);
+void omap4_configure_usb_dpll(const struct dpll_param *dpll_param);
+void omap4_configure_core_dpll_no_lock(const struct dpll_param *param);
+void omap4_lock_core_dpll(void);
+void omap4_lock_core_dpll_shadow(const struct dpll_param *param);
+void omap4_enable_all_clocks(void);
+
diff --git a/arch/arm/mach-omap/include/mach/omap4-mux.h b/arch/arm/mach-omap/include/mach/omap4-mux.h
new file mode 100644
index 00000000..019574b0
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/omap4-mux.h
@@ -0,0 +1,344 @@
+/*
+ * (C) Copyright 2004-2009
+ * Texas Instruments Incorporated
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Aneesh V <aneesh@ti.com>
+ * Balaji Krishnamoorthy <balajitk@ti.com>
+ *
+ * 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 _MUX_OMAP4_H_
+#define _MUX_OMAP4_H_
+
+#include <asm/types.h>
+
+struct pad_conf_entry {
+
+ u16 offset;
+
+ u16 val;
+
+} __attribute__ ((packed));
+
+#ifdef CONFIG_OFF_PADCONF
+#define OFF_PD (1 << 12)
+#define OFF_PU (3 << 12)
+#define OFF_OUT_PTD (0 << 10)
+#define OFF_OUT_PTU (2 << 10)
+#define OFF_IN (1 << 10)
+#define OFF_OUT (0 << 10)
+#define OFF_EN (1 << 9)
+#else
+#define OFF_PD (0 << 12)
+#define OFF_PU (0 << 12)
+#define OFF_OUT_PTD (0 << 10)
+#define OFF_OUT_PTU (0 << 10)
+#define OFF_IN (0 << 10)
+#define OFF_OUT (0 << 10)
+#define OFF_EN (0 << 9)
+#endif
+
+#define IEN (1 << 8)
+#define IDIS (0 << 8)
+#define PTU (3 << 3)
+#define PTD (1 << 3)
+#define EN (1 << 3)
+#define DIS (0 << 3)
+
+#define M0 0
+#define M1 1
+#define M2 2
+#define M3 3
+#define M4 4
+#define M5 5
+#define M6 6
+#define M7 7
+
+#define SAFE_MODE M7
+
+#ifdef CONFIG_OFF_PADCONF
+#define OFF_IN_PD (OFF_PD | OFF_IN | OFF_EN)
+#define OFF_IN_PU (OFF_PU | OFF_IN | OFF_EN)
+#define OFF_OUT_PD (OFF_OUT_PTD | OFF_OUT | OFF_EN)
+#define OFF_OUT_PU (OFF_OUT_PTU | OFF_OUT | OFF_EN)
+#else
+#define OFF_IN_PD 0
+#define OFF_IN_PU 0
+#define OFF_OUT_PD 0
+#define OFF_OUT_PU 0
+#endif
+
+#define CORE_REVISION 0x0000
+#define CORE_HWINFO 0x0004
+#define CORE_SYSCONFIG 0x0010
+#define GPMC_AD0 0x0040
+#define GPMC_AD1 0x0042
+#define GPMC_AD2 0x0044
+#define GPMC_AD3 0x0046
+#define GPMC_AD4 0x0048
+#define GPMC_AD5 0x004A
+#define GPMC_AD6 0x004C
+#define GPMC_AD7 0x004E
+#define GPMC_AD8 0x0050
+#define GPMC_AD9 0x0052
+#define GPMC_AD10 0x0054
+#define GPMC_AD11 0x0056
+#define GPMC_AD12 0x0058
+#define GPMC_AD13 0x005A
+#define GPMC_AD14 0x005C
+#define GPMC_AD15 0x005E
+#define GPMC_A16 0x0060
+#define GPMC_A17 0x0062
+#define GPMC_A18 0x0064
+#define GPMC_A19 0x0066
+#define GPMC_A20 0x0068
+#define GPMC_A21 0x006A
+#define GPMC_A22 0x006C
+#define GPMC_A23 0x006E
+#define GPMC_A24 0x0070
+#define GPMC_A25 0x0072
+#define GPMC_NCS0 0x0074
+#define GPMC_NCS1 0x0076
+#define GPMC_NCS2 0x0078
+#define GPMC_NCS3 0x007A
+#define GPMC_NWP 0x007C
+#define GPMC_CLK 0x007E
+#define GPMC_NADV_ALE 0x0080
+#define GPMC_NOE 0x0082
+#define GPMC_NWE 0x0084
+#define GPMC_NBE0_CLE 0x0086
+#define GPMC_NBE1 0x0088
+#define GPMC_WAIT0 0x008A
+#define GPMC_WAIT1 0x008C
+#define C2C_DATA11 0x008E
+#define C2C_DATA12 0x0090
+#define C2C_DATA13 0x0092
+#define C2C_DATA14 0x0094
+#define C2C_DATA15 0x0096
+#define HDMI_HPD 0x0098
+#define HDMI_CEC 0x009A
+#define HDMI_DDC_SCL 0x009C
+#define HDMI_DDC_SDA 0x009E
+#define CSI21_DX0 0x00A0
+#define CSI21_DY0 0x00A2
+#define CSI21_DX1 0x00A4
+#define CSI21_DY1 0x00A6
+#define CSI21_DX2 0x00A8
+#define CSI21_DY2 0x00AA
+#define CSI21_DX3 0x00AC
+#define CSI21_DY3 0x00AE
+#define CSI21_DX4 0x00B0
+#define CSI21_DY4 0x00B2
+#define CSI22_DX0 0x00B4
+#define CSI22_DY0 0x00B6
+#define CSI22_DX1 0x00B8
+#define CSI22_DY1 0x00BA
+#define CAM_SHUTTER 0x00BC
+#define CAM_STROBE 0x00BE
+#define CAM_GLOBALRESET 0x00C0
+#define USBB1_ULPITLL_CLK 0x00C2
+#define USBB1_ULPITLL_STP 0x00C4
+#define USBB1_ULPITLL_DIR 0x00C6
+#define USBB1_ULPITLL_NXT 0x00C8
+#define USBB1_ULPITLL_DAT0 0x00CA
+#define USBB1_ULPITLL_DAT1 0x00CC
+#define USBB1_ULPITLL_DAT2 0x00CE
+#define USBB1_ULPITLL_DAT3 0x00D0
+#define USBB1_ULPITLL_DAT4 0x00D2
+#define USBB1_ULPITLL_DAT5 0x00D4
+#define USBB1_ULPITLL_DAT6 0x00D6
+#define USBB1_ULPITLL_DAT7 0x00D8
+#define USBB1_HSIC_DATA 0x00DA
+#define USBB1_HSIC_STROBE 0x00DC
+#define USBC1_ICUSB_DP 0x00DE
+#define USBC1_ICUSB_DM 0x00E0
+#define SDMMC1_CLK 0x00E2
+#define SDMMC1_CMD 0x00E4
+#define SDMMC1_DAT0 0x00E6
+#define SDMMC1_DAT1 0x00E8
+#define SDMMC1_DAT2 0x00EA
+#define SDMMC1_DAT3 0x00EC
+#define SDMMC1_DAT4 0x00EE
+#define SDMMC1_DAT5 0x00F0
+#define SDMMC1_DAT6 0x00F2
+#define SDMMC1_DAT7 0x00F4
+#define ABE_MCBSP2_CLKX 0x00F6
+#define ABE_MCBSP2_DR 0x00F8
+#define ABE_MCBSP2_DX 0x00FA
+#define ABE_MCBSP2_FSX 0x00FC
+#define ABE_MCBSP1_CLKX 0x00FE
+#define ABE_MCBSP1_DR 0x0100
+#define ABE_MCBSP1_DX 0x0102
+#define ABE_MCBSP1_FSX 0x0104
+#define ABE_PDM_UL_DATA 0x0106
+#define ABE_PDM_DL_DATA 0x0108
+#define ABE_PDM_FRAME 0x010A
+#define ABE_PDM_LB_CLK 0x010C
+#define ABE_CLKS 0x010E
+#define ABE_DMIC_CLK1 0x0110
+#define ABE_DMIC_DIN1 0x0112
+#define ABE_DMIC_DIN2 0x0114
+#define ABE_DMIC_DIN3 0x0116
+#define UART2_CTS 0x0118
+#define UART2_RTS 0x011A
+#define UART2_RX 0x011C
+#define UART2_TX 0x011E
+#define HDQ_SIO 0x0120
+#define I2C1_SCL 0x0122
+#define I2C1_SDA 0x0124
+#define I2C2_SCL 0x0126
+#define I2C2_SDA 0x0128
+#define I2C3_SCL 0x012A
+#define I2C3_SDA 0x012C
+#define I2C4_SCL 0x012E
+#define I2C4_SDA 0x0130
+#define MCSPI1_CLK 0x0132
+#define MCSPI1_SOMI 0x0134
+#define MCSPI1_SIMO 0x0136
+#define MCSPI1_CS0 0x0138
+#define MCSPI1_CS1 0x013A
+#define MCSPI1_CS2 0x013C
+#define MCSPI1_CS3 0x013E
+#define UART3_CTS_RCTX 0x0140
+#define UART3_RTS_SD 0x0142
+#define UART3_RX_IRRX 0x0144
+#define UART3_TX_IRTX 0x0146
+#define SDMMC5_CLK 0x0148
+#define SDMMC5_CMD 0x014A
+#define SDMMC5_DAT0 0x014C
+#define SDMMC5_DAT1 0x014E
+#define SDMMC5_DAT2 0x0150
+#define SDMMC5_DAT3 0x0152
+#define MCSPI4_CLK 0x0154
+#define MCSPI4_SIMO 0x0156
+#define MCSPI4_SOMI 0x0158
+#define MCSPI4_CS0 0x015A
+#define UART4_RX 0x015C
+#define UART4_TX 0x015E
+#define USBB2_ULPITLL_CLK 0x0160
+#define USBB2_ULPITLL_STP 0x0162
+#define USBB2_ULPITLL_DIR 0x0164
+#define USBB2_ULPITLL_NXT 0x0166
+#define USBB2_ULPITLL_DAT0 0x0168
+#define USBB2_ULPITLL_DAT1 0x016A
+#define USBB2_ULPITLL_DAT2 0x016C
+#define USBB2_ULPITLL_DAT3 0x016E
+#define USBB2_ULPITLL_DAT4 0x0170
+#define USBB2_ULPITLL_DAT5 0x0172
+#define USBB2_ULPITLL_DAT6 0x0174
+#define USBB2_ULPITLL_DAT7 0x0176
+#define USBB2_HSIC_DATA 0x0178
+#define USBB2_HSIC_STROBE 0x017A
+#define UNIPRO_TX0 0x017C
+#define UNIPRO_TY0 0x017E
+#define UNIPRO_TX1 0x0180
+#define UNIPRO_TY1 0x0182
+#define UNIPRO_TX2 0x0184
+#define UNIPRO_TY2 0x0186
+#define UNIPRO_RX0 0x0188
+#define UNIPRO_RY0 0x018A
+#define UNIPRO_RX1 0x018C
+#define UNIPRO_RY1 0x018E
+#define UNIPRO_RX2 0x0190
+#define UNIPRO_RY2 0x0192
+#define USBA0_OTG_CE 0x0194
+#define USBA0_OTG_DP 0x0196
+#define USBA0_OTG_DM 0x0198
+#define FREF_CLK1_OUT 0x019A
+#define FREF_CLK2_OUT 0x019C
+#define SYS_NIRQ1 0x019E
+#define SYS_NIRQ2 0x01A0
+#define SYS_BOOT0 0x01A2
+#define SYS_BOOT1 0x01A4
+#define SYS_BOOT2 0x01A6
+#define SYS_BOOT3 0x01A8
+#define SYS_BOOT4 0x01AA
+#define SYS_BOOT5 0x01AC
+#define DPM_EMU0 0x01AE
+#define DPM_EMU1 0x01B0
+#define DPM_EMU2 0x01B2
+#define DPM_EMU3 0x01B4
+#define DPM_EMU4 0x01B6
+#define DPM_EMU5 0x01B8
+#define DPM_EMU6 0x01BA
+#define DPM_EMU7 0x01BC
+#define DPM_EMU8 0x01BE
+#define DPM_EMU9 0x01C0
+#define DPM_EMU10 0x01C2
+#define DPM_EMU11 0x01C4
+#define DPM_EMU12 0x01C6
+#define DPM_EMU13 0x01C8
+#define DPM_EMU14 0x01CA
+#define DPM_EMU15 0x01CC
+#define DPM_EMU16 0x01CE
+#define DPM_EMU17 0x01D0
+#define DPM_EMU18 0x01D2
+#define DPM_EMU19 0x01D4
+#define WAKEUPEVENT_0 0x01D8
+#define WAKEUPEVENT_1 0x01DC
+#define WAKEUPEVENT_2 0x01E0
+#define WAKEUPEVENT_3 0x01E4
+#define WAKEUPEVENT_4 0x01E8
+#define WAKEUPEVENT_5 0x01EC
+#define WAKEUPEVENT_6 0x01F0
+
+#define WKUP_REVISION 0x0000
+#define WKUP_HWINFO 0x0004
+#define WKUP_SYSCONFIG 0x0010
+#define PAD0_SIM_IO 0x0040
+#define PAD1_SIM_CLK 0x0042
+#define PAD0_SIM_RESET 0x0044
+#define PAD1_SIM_CD 0x0046
+#define PAD0_SIM_PWRCTRL 0x0048
+#define PAD1_SR_SCL 0x004A
+#define PAD0_SR_SDA 0x004C
+#define PAD1_FREF_XTAL_IN 0x004E
+#define PAD0_FREF_SLICER_IN 0x0050
+#define PAD1_FREF_CLK_IOREQ 0x0052
+#define PAD0_FREF_CLK0_OUT 0x0054
+#define PAD1_FREF_CLK3_REQ 0x0056
+#define PAD0_FREF_CLK3_OUT 0x0058
+#define PAD1_FREF_CLK4_REQ 0x005A
+#define PAD0_FREF_CLK4_OUT 0x005C
+#define PAD1_SYS_32K 0x005E
+#define PAD0_SYS_NRESPWRON 0x0060
+#define PAD1_SYS_NRESWARM 0x0062
+#define PAD0_SYS_PWR_REQ 0x0064
+#define PAD1_SYS_PWRON_RESET 0x0066
+#define PAD0_SYS_BOOT6 0x0068
+#define PAD1_SYS_BOOT7 0x006A
+#define PAD0_JTAG_NTRST 0x006C
+#define PAD1_JTAG_TCK 0x006D
+#define PAD0_JTAG_RTCK 0x0070
+#define PAD1_JTAG_TMS_TMSC 0x0072
+#define PAD0_JTAG_TDI 0x0074
+#define PAD1_JTAG_TDO 0x0076
+#define PADCONF_WAKEUPEVENT_0 0x007C
+#define CONTROL_SMART1NOPMIO_PADCONF_0 0x05A0
+#define CONTROL_SMART1NOPMIO_PADCONF_1 0x05A4
+#define PADCONF_MODE 0x05A8
+#define CONTROL_XTAL_OSCILLATOR 0x05AC
+#define CONTROL_CONTROL_I2C_2 0x0604
+#define CONTROL_CONTROL_JTAG 0x0608
+#define CONTROL_CONTROL_SYS 0x060C
+#define CONTROL_SPARE_RW 0x0614
+#define CONTROL_SPARE_R 0x0618
+#define CONTROL_SPARE_R_C0 0x061C
+
+#endif /* _MUX_OMAP4_H_ */
diff --git a/arch/arm/mach-omap/include/mach/omap4-silicon.h b/arch/arm/mach-omap/include/mach/omap4-silicon.h
new file mode 100644
index 00000000..db0dfdff
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/omap4-silicon.h
@@ -0,0 +1,179 @@
+/*
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Authors:
+ * Aneesh V <aneesh@ti.com>
+ *
+ * Derived from OMAP3 work by
+ * Richard Woodruff <r-woodruff2@ti.com>
+ * Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * 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 _OMAP4_H_
+#define _OMAP4_H_
+
+#if !(defined(__KERNEL_STRICT_NAMES) || defined(__ASSEMBLY__))
+#include <asm/types.h>
+#endif /* !(__KERNEL_STRICT_NAMES || __ASSEMBLY__) */
+
+/*
+ * L4 Peripherals - L4 Wakeup and L4 Core now
+ */
+#define OMAP44XX_L4_CORE_BASE 0x4A000000
+#define OMAP44XX_WAKEUP_L4_IO_BASE 0x4A300000
+#define OMAP44XX_L4_WKUP_BASE 0x4A300000
+#define OMAP44XX_L4_PER_BASE 0x48000000
+
+/* EMIF and DMM registers */
+#define OMAP44XX_EMIF1_BASE 0x4c000000
+#define OMAP44XX_EMIF2_BASE 0x4d000000
+
+#define OMAP44XX_DRAM_ADDR_SPACE_START 0x80000000
+#define OMAP44XX_DRAM_ADDR_SPACE_END 0xD0000000
+
+
+/* CONTROL */
+#define OMAP44XX_CTRL_BASE (OMAP44XX_L4_CORE_BASE + 0x2000)
+#define OMAP44XX_CONTROL_PADCONF_CORE (OMAP44XX_L4_CORE_BASE + 0x100000)
+#define OMAP44XX_CONTROL_PADCONF_WKUP (OMAP44XX_L4_CORE_BASE + 0x31E000)
+
+/* PRM */
+#define OMAP44XX_PRM_VC_VAL_BYPASS (OMAP44XX_WAKEUP_L4_IO_BASE + 0x7ba0)
+#define OMAP44XX_PRM_VC_CFG_I2C_MODE (OMAP44XX_WAKEUP_L4_IO_BASE + 0x7ba8)
+#define OMAP44XX_PRM_VC_CFG_I2C_CLK (OMAP44XX_WAKEUP_L4_IO_BASE + 0x7bac)
+
+/* IRQ */
+#define OMAP44XX_PRM_IRQSTATUS_MPU_A9 (OMAP44XX_WAKEUP_L4_IO_BASE + 0x6010)
+
+/* UART */
+#define OMAP44XX_UART1_BASE (OMAP44XX_L4_PER_BASE + 0x6a000)
+#define OMAP44XX_UART2_BASE (OMAP44XX_L4_PER_BASE + 0x6c000)
+#define OMAP44XX_UART3_BASE (OMAP44XX_L4_PER_BASE + 0x20000)
+
+/* General Purpose Timers */
+#define OMAP44XX_GPT1_BASE (OMAP44XX_L4_WKUP_BASE + 0x18000)
+#define OMAP44XX_GPT2_BASE (OMAP44XX_L4_PER_BASE + 0x32000)
+#define OMAP44XX_GPT3_BASE (OMAP44XX_L4_PER_BASE + 0x34000)
+
+/* Watchdog Timer2 - MPU watchdog */
+#define OMAP44XX_WDT2_BASE (OMAP44XX_L4_WKUP_BASE + 0x14000)
+
+#define OMAP44XX_SCRM_BASE 0x4a30a000
+#define OMAP44XX_SCRM_ALTCLKSRC (OMAP44XX_SCRM_BASE + 0x110)
+#define OMAP44XX_SCRM_AUXCLK1 (OMAP44XX_SCRM_BASE + 0x314)
+#define OMAP44XX_SCRM_AUXCLK3 (OMAP44XX_SCRM_BASE + 0x31c)
+
+/* 32KTIMER */
+#define OMAP_32KTIMER_BASE (OMAP44XX_L4_WKUP_BASE + 0x4000)
+
+/* GPMC */
+#define OMAP_GPMC_BASE 0x50000000
+
+/* DMM */
+#define OMAP44XX_DMM_BASE 0x4E000000
+#define DMM_LISA_MAP_BASE (OMAP44XX_DMM_BASE + 0x40)
+#define DMM_LISA_MAP_SYS_SIZE_MASK (7 << 20)
+#define DMM_LISA_MAP_SYS_SIZE_SHIFT 20
+#define DMM_LISA_MAP_SYS_ADDR_MASK (0xFF << 24)
+/*
+ * Hardware Register Details
+ */
+
+/* Watchdog Timer */
+#define WD_UNLOCK1 0xAAAA
+#define WD_UNLOCK2 0x5555
+
+/* GP Timer */
+#define TCLR_ST (0x1 << 0)
+#define TCLR_AR (0x1 << 1)
+#define TCLR_PRE (0x1 << 5)
+
+/*
+ * PRCM
+ */
+
+/* PRM */
+#define PRM_BASE 0x4A306000
+#define PRM_DEVICE_BASE (PRM_BASE + 0x1B00)
+
+#define PRM_RSTCTRL PRM_DEVICE_BASE
+#define PRM_RSTCTRL_RESET 0x01
+
+#ifndef __ASSEMBLY__
+
+struct s32ktimer {
+ unsigned char res[0x10];
+ unsigned int s32k_cr; /* 0x10 */
+};
+
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Non-secure SRAM Addresses
+ * Non-secure RAM starts at 0x40300000 for GP devices. But we keep SRAM_BASE
+ * at 0x40304000(EMU base) so that our code works for both EMU and GP
+ */
+#define NON_SECURE_SRAM_START 0x40304000
+#define NON_SECURE_SRAM_END 0x4030E000 /* Not inclusive */
+/* base address for indirect vectors (internal boot mode) */
+#define SRAM_ROM_VECT_BASE 0x4030D000
+/* Temporary SRAM stack used while low level init is done */
+#define LOW_LEVEL_SRAM_STACK NON_SECURE_SRAM_END
+
+/*
+ * OMAP4 real hardware:
+ * TODO: Change this to the IDCODE in the hw regsiter
+ */
+#define CPU_OMAP4430_ES10 1
+#define CPU_OMAP4430_ES20 2
+
+#define CM_DLL_CTRL 0x4a004110
+#define CM_MEMIF_EMIF_1_CLKCTRL 0x4a008b30
+#define CM_MEMIF_EMIF_2_CLKCTRL 0x4a008b38
+
+/* Silicon revisions */
+#define OMAP4430_SILICON_ID_INVALID 0
+#define OMAP4430_ES1_0 1
+#define OMAP4430_ES2_0 2
+#define OMAP4430_ES2_1 3
+#define OMAP4430_ES2_2 4
+
+struct ddr_regs {
+ u32 tim1;
+ u32 tim2;
+ u32 tim3;
+ u32 phy_ctrl_1;
+ u32 ref_ctrl;
+ u32 config_init;
+ u32 config_final;
+ u32 zq_config;
+ u8 mr1;
+ u8 mr2;
+};
+
+struct dpll_param;
+
+void omap4_ddr_init(const struct ddr_regs *, const struct dpll_param *);
+void omap4_power_i2c_send(u32);
+unsigned int omap4_revision(void);
+
+#endif
diff --git a/arch/arm/mach-omap/include/mach/silicon.h b/arch/arm/mach-omap/include/mach/silicon.h
index 22daa5c9..c2f0c412 100644
--- a/arch/arm/mach-omap/include/mach/silicon.h
+++ b/arch/arm/mach-omap/include/mach/silicon.h
@@ -25,6 +25,9 @@
#ifdef CONFIG_ARCH_OMAP3
#include <mach/omap3-silicon.h>
#endif
+#ifdef CONFIG_ARCH_OMAP4
+#include <mach/omap4-silicon.h>
+#endif
/* If Architecture specific init functions are present */
#ifdef CONFIG_ARCH_HAS_LOWLEVEL_INIT
diff --git a/arch/arm/mach-omap/include/mach/syslib.h b/arch/arm/mach-omap/include/mach/syslib.h
index c89f50b8..6a7044ad 100644
--- a/arch/arm/mach-omap/include/mach/syslib.h
+++ b/arch/arm/mach-omap/include/mach/syslib.h
@@ -30,9 +30,30 @@
*/
#ifndef __ASM_ARCH_OMAP_SYSLIB_H_
#define __ASM_ARCH_OMAP_SYSLIB_H_
+#include <asm/io.h>
/** System Independent functions */
-void sr32(u32 addr, u32 start_bit, u32 num_bits, u32 value);
+
+/**
+ * @brief clear & set a value in a bit range for a 32 bit address
+ *
+ * @param[in] addr Address to set/read from
+ * @param[in] start_bit Where to put the value
+ * @param[in] num_bits number of bits the value should be set
+ * @param[in] value the value to set
+ *
+ * @return void
+ */
+static inline void sr32(u32 addr, u32 start_bit, u32 num_bits, u32 value)
+{
+ u32 tmp, msk = 0;
+ msk = 1 << num_bits;
+ --msk;
+ tmp = readl(addr) & ~(msk << start_bit);
+ tmp |= value << start_bit;
+ writel(tmp, addr);
+}
+
u32 wait_on_value(u32 read_bit_mask, u32 match_value, u32 read_addr, u32 bound);
void sdelay(unsigned long loops);
diff --git a/arch/arm/mach-omap/include/mach/xload.h b/arch/arm/mach-omap/include/mach/xload.h
new file mode 100644
index 00000000..844b57f0
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/xload.h
@@ -0,0 +1,16 @@
+#ifndef _MACH_XLOAD_H
+#define _MACH_XLOAD_H
+
+void *omap_xload_boot_nand(int offset, int size);
+void *omap_xload_boot_mmc(void);
+
+enum omap_boot_src {
+ OMAP_BOOTSRC_UNKNOWN,
+ OMAP_BOOTSRC_MMC1,
+ OMAP_BOOTSRC_NAND,
+};
+
+enum omap_boot_src omap3_bootsrc(void);
+enum omap_boot_src omap4_bootsrc(void);
+
+#endif /* _MACH_XLOAD_H */
diff --git a/arch/arm/mach-omap/omap-uart.c b/arch/arm/mach-omap/omap-uart.c
new file mode 100644
index 00000000..477452d9
--- /dev/null
+++ b/arch/arm/mach-omap/omap-uart.c
@@ -0,0 +1,36 @@
+#include <common.h>
+#include <asm/io.h>
+
+/**
+ * @brief Uart port register read function for OMAP3
+ *
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return character read from register
+ */
+unsigned int omap_uart_read(unsigned long base, unsigned char reg_idx)
+{
+ unsigned int *reg_addr = (unsigned int *)base;
+ reg_addr += reg_idx;
+ return readb(reg_addr);
+}
+EXPORT_SYMBOL(omap_uart_read);
+
+/**
+ * @brief Uart port register write function for OMAP3
+ *
+ * @param val value to write
+ * @param base base address of UART
+ * @param reg_idx register index
+ *
+ * @return void
+ */
+void omap_uart_write(unsigned int val, unsigned long base,
+ unsigned char reg_idx)
+{
+ unsigned int *reg_addr = (unsigned int *)base;
+ reg_addr += reg_idx;
+ writeb(val, reg_addr);
+}
+EXPORT_SYMBOL(omap_uart_write);
diff --git a/arch/arm/mach-omap/omap3_generic.c b/arch/arm/mach-omap/omap3_generic.c
index 843143ba..661a971f 100644
--- a/arch/arm/mach-omap/omap3_generic.c
+++ b/arch/arm/mach-omap/omap3_generic.c
@@ -46,6 +46,7 @@
#include <mach/wdt.h>
#include <mach/sys_info.h>
#include <mach/syslib.h>
+#include <mach/xload.h>
/**
* @brief Reset the CPU
@@ -484,36 +485,15 @@ void a_init(void)
}
-/**
- * @brief Uart port register read function for OMAP3
- *
- * @param base base address of UART
- * @param reg_idx register index
- *
- * @return character read from register
- */
-unsigned int omap_uart_read(unsigned long base, unsigned char reg_idx)
-{
- unsigned int *reg_addr = (unsigned int *)base;
- reg_addr += reg_idx;
- return readb(reg_addr);
-}
-EXPORT_SYMBOL(omap_uart_read);
+#define OMAP3_TRACING_VECTOR1 0x4020ffb4
-/**
- * @brief Uart port register write function for OMAP3
- *
- * @param val value to write
- * @param base base address of UART
- * @param reg_idx register index
- *
- * @return void
- */
-void omap_uart_write(unsigned int val, unsigned long base,
- unsigned char reg_idx)
+enum omap_boot_src omap3_bootsrc(void)
{
- unsigned int *reg_addr = (unsigned int *)base;
- reg_addr += reg_idx;
- writeb(val, reg_addr);
+ u32 bootsrc = readl(OMAP3_TRACING_VECTOR1);
+
+ if (bootsrc & (1 << 2))
+ return OMAP_BOOTSRC_NAND;
+ if (bootsrc & (1 << 6))
+ return OMAP_BOOTSRC_MMC1;
+ return OMAP_BOOTSRC_UNKNOWN;
}
-EXPORT_SYMBOL(omap_uart_write);
diff --git a/arch/arm/mach-omap/omap4_clock.c b/arch/arm/mach-omap/omap4_clock.c
new file mode 100644
index 00000000..23a77d06
--- /dev/null
+++ b/arch/arm/mach-omap/omap4_clock.c
@@ -0,0 +1,380 @@
+#include <common.h>
+#include <mach/syslib.h>
+#include <asm/io.h>
+#include <mach/omap4-clock.h>
+
+#define LDELAY 12000000
+
+void omap4_configure_mpu_dpll(const struct dpll_param *dpll_param)
+{
+ /* Unlock the MPU dpll */
+ sr32(CM_CLKMODE_DPLL_MPU, 0, 3, PLL_MN_POWER_BYPASS);
+ wait_on_value((1 << 0), 0, CM_IDLEST_DPLL_MPU, LDELAY);
+
+ sr32(CM_AUTOIDLE_DPLL_MPU, 0, 3, 0x0); /* Disable DPLL autoidle */
+
+ /* Set M,N,M2 values */
+ sr32(CM_CLKSEL_DPLL_MPU, 8, 11, dpll_param->m);
+ sr32(CM_CLKSEL_DPLL_MPU, 0, 6, dpll_param->n);
+ sr32(CM_DIV_M2_DPLL_MPU, 0, 5, dpll_param->m2);
+ sr32(CM_DIV_M2_DPLL_MPU, 8, 1, 0x1);
+
+ /* Lock the mpu dpll */
+ sr32(CM_CLKMODE_DPLL_MPU, 0, 3, PLL_LOCK | 0x10);
+ wait_on_value((1 << 0), 1, CM_IDLEST_DPLL_MPU, LDELAY);
+}
+
+void omap4_configure_iva_dpll(const struct dpll_param *dpll_param)
+{
+ /* Unlock the IVA dpll */
+ sr32(CM_CLKMODE_DPLL_IVA, 0, 3, PLL_MN_POWER_BYPASS);
+ wait_on_value((1 << 0), 0, CM_IDLEST_DPLL_IVA, LDELAY);
+
+ /* CM_BYPCLK_DPLL_IVA = CORE_X2_CLK/2 */
+ sr32(CM_BYPCLK_DPLL_IVA, 0, 2, 0x1);
+
+ sr32(CM_AUTOIDLE_DPLL_IVA, 0, 3, 0x0); /* Disable DPLL autoidle */
+
+ /* Set M,N,M4,M5 */
+ sr32(CM_CLKSEL_DPLL_IVA, 8, 11, dpll_param->m);
+ sr32(CM_CLKSEL_DPLL_IVA, 0, 7, dpll_param->n);
+ sr32(CM_DIV_M4_DPLL_IVA, 0, 5, dpll_param->m4);
+ sr32(CM_DIV_M4_DPLL_IVA, 8, 1, 0x1);
+ sr32(CM_DIV_M5_DPLL_IVA, 0, 5, dpll_param->m5);
+ sr32(CM_DIV_M5_DPLL_IVA, 8, 1, 0x1);
+
+ /* Lock the iva dpll */
+ sr32(CM_CLKMODE_DPLL_IVA, 0, 3, PLL_LOCK);
+ wait_on_value((1 << 0), 1, CM_IDLEST_DPLL_IVA, LDELAY);
+}
+
+void omap4_configure_per_dpll(const struct dpll_param *dpll_param)
+{
+ /* Unlock the PER dpll */
+ sr32(CM_CLKMODE_DPLL_PER, 0, 3, PLL_MN_POWER_BYPASS);
+ wait_on_value((1 << 0), 0, CM_IDLEST_DPLL_PER, LDELAY);
+
+ /* Disable autoidle */
+ sr32(CM_AUTOIDLE_DPLL_PER, 0, 3, 0x0);
+
+ sr32(CM_CLKSEL_DPLL_PER, 8, 11, dpll_param->m);
+ sr32(CM_CLKSEL_DPLL_PER, 0, 6, dpll_param->n);
+ sr32(CM_DIV_M2_DPLL_PER, 0, 5, dpll_param->m2);
+ sr32(CM_DIV_M3_DPLL_PER, 0, 5, dpll_param->m3);
+ sr32(CM_DIV_M4_DPLL_PER, 0, 5, dpll_param->m4);
+ sr32(CM_DIV_M5_DPLL_PER, 0, 5, dpll_param->m5);
+ sr32(CM_DIV_M6_DPLL_PER, 0, 5, dpll_param->m6);
+ sr32(CM_DIV_M7_DPLL_PER, 0, 5, dpll_param->m7);
+
+ sr32(CM_DIV_M2_DPLL_PER, 8, 1, 0x1);
+ sr32(CM_DIV_M3_DPLL_PER, 8, 1, 0x1);
+ sr32(CM_DIV_M4_DPLL_PER, 8, 1, 0x1);
+ sr32(CM_DIV_M5_DPLL_PER, 8, 1, 0x1);
+ sr32(CM_DIV_M6_DPLL_PER, 8, 1, 0x1);
+ sr32(CM_DIV_M7_DPLL_PER, 8, 1, 0x1);
+
+ /* Lock the per dpll */
+ sr32(CM_CLKMODE_DPLL_PER, 0, 3, PLL_LOCK);
+ wait_on_value((1 << 0), 1, CM_IDLEST_DPLL_PER, LDELAY);
+
+ return;
+}
+
+void omap4_configure_abe_dpll(const struct dpll_param *dpll_param)
+{
+ /* Select sys_clk as ref clk for ABE dpll */
+ sr32(CM_ABE_PLL_REF_CLKSEL, 0, 32, 0x0);
+
+ /* Unlock the ABE dpll */
+ sr32(CM_CLKMODE_DPLL_ABE, 0, 3, PLL_MN_POWER_BYPASS);
+ wait_on_value((1 << 0), 0, CM_IDLEST_DPLL_ABE, LDELAY);
+
+ /* Disable autoidle */
+ sr32(CM_AUTOIDLE_DPLL_ABE, 0, 3, 0x0);
+
+ sr32(CM_CLKSEL_DPLL_ABE, 8, 11, dpll_param->m);
+ sr32(CM_CLKSEL_DPLL_ABE, 0, 6, dpll_param->n);
+
+ /* Force DPLL CLKOUTHIF to stay enabled */
+ sr32(CM_DIV_M2_DPLL_ABE, 0, 32, 0x500);
+ sr32(CM_DIV_M2_DPLL_ABE, 0, 5, dpll_param->m2);
+ sr32(CM_DIV_M2_DPLL_ABE, 8, 1, 0x1);
+ /* Force DPLL CLKOUTHIF to stay enabled */
+ sr32(CM_DIV_M3_DPLL_ABE, 0, 32, 0x100);
+ sr32(CM_DIV_M3_DPLL_ABE, 0, 5, dpll_param->m3);
+ sr32(CM_DIV_M3_DPLL_ABE, 8, 1, 0x1);
+
+ /* Lock the abe dpll */
+ sr32(CM_CLKMODE_DPLL_ABE, 0, 3, PLL_LOCK);
+ wait_on_value((1 << 0), 1, CM_IDLEST_DPLL_ABE, LDELAY);
+
+ return;
+}
+
+void omap4_configure_usb_dpll(const struct dpll_param *dpll_param)
+{
+ /* Select the 60Mhz clock 480/8 = 60*/
+ sr32(CM_CLKSEL_USB_60MHz, 0, 32, 0x1);
+
+ /* Unlock the USB dpll */
+ sr32(CM_CLKMODE_DPLL_USB, 0, 3, PLL_MN_POWER_BYPASS);
+ wait_on_value((1 << 0), 0, CM_IDLEST_DPLL_USB, LDELAY);
+
+ /* Disable autoidle */
+ sr32(CM_AUTOIDLE_DPLL_USB, 0, 3, 0x0);
+
+ sr32(CM_CLKSEL_DPLL_USB, 8, 11, dpll_param->m);
+ sr32(CM_CLKSEL_DPLL_USB, 0, 6, dpll_param->n);
+
+ /* Force DPLL CLKOUT to stay active */
+ sr32(CM_DIV_M2_DPLL_USB, 0, 32, 0x100);
+ sr32(CM_DIV_M2_DPLL_USB, 0, 5, dpll_param->m2);
+ sr32(CM_DIV_M2_DPLL_USB, 8, 1, 0x1);
+ sr32(CM_CLKDCOLDO_DPLL_USB, 8, 1, 0x1);
+
+ /* Lock the usb dpll */
+ sr32(CM_CLKMODE_DPLL_USB, 0, 3, PLL_LOCK);
+ wait_on_value((1 << 0), 1, CM_IDLEST_DPLL_USB, LDELAY);
+
+ /* force enable the CLKDCOLDO clock */
+ sr32(CM_CLKDCOLDO_DPLL_USB, 0, 32, 0x100);
+
+ return;
+}
+
+void omap4_configure_core_dpll_no_lock(const struct dpll_param *param)
+{
+ /* CORE_CLK=CORE_X2_CLK/2, L3_CLK=CORE_CLK/2, L4_CLK=L3_CLK/2 */
+ sr32(CM_CLKSEL_CORE, 0, 32, 0x110);
+
+ /* Unlock the CORE dpll */
+ sr32(CM_CLKMODE_DPLL_CORE, 0, 3, PLL_MN_POWER_BYPASS);
+ wait_on_value((1 << 0), 0, CM_IDLEST_DPLL_CORE, LDELAY);
+
+ /* Disable autoidle */
+ sr32(CM_AUTOIDLE_DPLL_CORE, 0, 3, 0x0);
+
+ sr32(CM_CLKSEL_DPLL_CORE, 8, 11, param->m);
+ sr32(CM_CLKSEL_DPLL_CORE, 0, 6, param->n);
+ sr32(CM_DIV_M2_DPLL_CORE, 0, 5, param->m2);
+ sr32(CM_DIV_M3_DPLL_CORE, 0, 5, param->m3);
+ sr32(CM_DIV_M4_DPLL_CORE, 0, 5, param->m4);
+ sr32(CM_DIV_M5_DPLL_CORE, 0, 5, param->m5);
+ sr32(CM_DIV_M6_DPLL_CORE, 0, 5, param->m6);
+ sr32(CM_DIV_M7_DPLL_CORE, 0, 5, param->m7);
+
+ sr32(CM_DIV_M2_DPLL_CORE, 8, 1, 0x1);
+ sr32(CM_DIV_M3_DPLL_CORE, 8, 1, 0x1);
+ sr32(CM_DIV_M4_DPLL_CORE, 8, 1, 0x1);
+ sr32(CM_DIV_M5_DPLL_CORE, 8, 1, 0x1);
+ sr32(CM_DIV_M6_DPLL_CORE, 8, 1, 0x0);
+ sr32(CM_DIV_M7_DPLL_CORE, 8, 1, 0x1);
+}
+
+void omap4_lock_core_dpll(void)
+{
+ /* Lock the core dpll */
+ sr32(CM_CLKMODE_DPLL_CORE, 0, 3, PLL_LOCK);
+ wait_on_value((1 << 0), 1, CM_IDLEST_DPLL_CORE, LDELAY);
+
+ return;
+}
+
+void omap4_lock_core_dpll_shadow(const struct dpll_param *param)
+{
+ /* Lock the core dpll using freq update method */
+ *(volatile int*)0x4A004120 = 10; //(CM_CLKMODE_DPLL_CORE)
+
+ /* CM_SHADOW_FREQ_CONFIG1: DLL_OVERRIDE = 1(hack), DLL_RESET = 1,
+ * DPLL_CORE_M2_DIV =1, DPLL_CORE_DPLL_EN = 0x7, FREQ_UPDATE = 1
+ */
+ *(volatile int*)0x4A004260 = 0x70D | (param->m2 << 11);
+
+ /* Wait for Freq_Update to get cleared: CM_SHADOW_FREQ_CONFIG1 */
+ while( ( (*(volatile int*)0x4A004260) & 0x1) == 0x1 );
+
+ /* Wait for DPLL to Lock : CM_IDLEST_DPLL_CORE */
+ wait_on_value((1 << 0), 1, CM_IDLEST_DPLL_CORE, LDELAY);
+}
+
+void omap4_enable_all_clocks(void)
+{
+ /* Enable Ducati clocks */
+ sr32(CM_DUCATI_DUCATI_CLKCTRL, 0, 32, 0x1);
+ sr32(CM_DUCATI_CLKSTCTRL, 0, 32, 0x2);
+
+ wait_on_value((1 << 8), (1 << 8), CM_DUCATI_CLKSTCTRL, LDELAY);
+
+ /* Enable ivahd and sl2 clocks */
+ sr32(IVAHD_IVAHD_CLKCTRL, 0, 32, 0x1);
+ sr32(IVAHD_SL2_CLKCTRL, 0, 32, 0x1);
+ sr32(IVAHD_CLKSTCTRL, 0, 32, 0x2);
+
+ wait_on_value((1 << 8), (1 << 8), IVAHD_CLKSTCTRL, LDELAY);
+
+ /* Enable Tesla clocks */
+ sr32(DSP_DSP_CLKCTRL, 0, 32, 0x1);
+ sr32(DSP_CLKSTCTRL, 0, 32, 0x2);
+
+ wait_on_value((1 << 8), (1 << 8), DSP_CLKSTCTRL, LDELAY);
+
+ /* wait for tesla to become accessible */
+
+ /* ABE clocks */
+ sr32(CM1_ABE_CLKSTCTRL, 0, 32, 0x3);
+ sr32(CM1_ABE_AESS_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_PDM_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_DMIC_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_MCASP_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_MCBSP1_CLKCTRL, 0, 32, 0x08000002);
+ sr32(CM1_ABE_MCBSP2_CLKCTRL, 0, 32, 0x08000002);
+ sr32(CM1_ABE_MCBSP3_CLKCTRL, 0, 32, 0x08000002);
+ sr32(CM1_ABE_SLIMBUS_CLKCTRL, 0, 32, 0xf02);
+ sr32(CM1_ABE_TIMER5_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_TIMER6_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_TIMER7_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_TIMER8_CLKCTRL, 0, 32, 0x2);
+ sr32(CM1_ABE_WDT3_CLKCTRL, 0, 32, 0x2);
+ /* Disable sleep transitions */
+ sr32(CM1_ABE_CLKSTCTRL, 0, 32, 0x0);
+
+ /* L4PER clocks */
+ sr32(CM_L4PER_CLKSTCTRL, 0, 32, 0x2);
+ sr32(CM_L4PER_DMTIMER10_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_DMTIMER10_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_DMTIMER11_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_DMTIMER11_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_DMTIMER2_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_DMTIMER2_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_DMTIMER3_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_DMTIMER3_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_DMTIMER4_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_DMTIMER4_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_DMTIMER9_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_DMTIMER9_CLKCTRL, LDELAY);
+
+ /* GPIO clocks */
+ sr32(CM_L4PER_GPIO2_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_GPIO2_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_GPIO3_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_GPIO3_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_GPIO4_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_GPIO4_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_GPIO5_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_GPIO5_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_GPIO6_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_GPIO6_CLKCTRL, LDELAY);
+
+ sr32(CM_L4PER_HDQ1W_CLKCTRL, 0, 32, 0x2);
+
+ /* I2C clocks */
+ sr32(CM_L4PER_I2C1_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_I2C1_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_I2C2_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_I2C2_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_I2C3_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_I2C3_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_I2C4_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_I2C4_CLKCTRL, LDELAY);
+
+ sr32(CM_L4PER_MCBSP4_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_MCBSP4_CLKCTRL, LDELAY);
+
+ /* MCSPI clocks */
+ sr32(CM_L4PER_MCSPI1_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_MCSPI1_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_MCSPI2_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_MCSPI2_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_MCSPI3_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_MCSPI3_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_MCSPI4_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_MCSPI4_CLKCTRL, LDELAY);
+
+ /* MMC clocks */
+ sr32(CM_L3INIT_HSMMC1_CLKCTRL, 0, 2, 0x2);
+ sr32(CM_L3INIT_HSMMC1_CLKCTRL, 24, 1, 0x1);
+ sr32(CM_L3INIT_HSMMC2_CLKCTRL, 0, 2, 0x2);
+ sr32(CM_L3INIT_HSMMC2_CLKCTRL, 24, 1, 0x1);
+ sr32(CM_L4PER_MMCSD3_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 18)|(1 << 17)|(1 << 16), 0, CM_L4PER_MMCSD3_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_MMCSD4_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 18)|(1 << 17)|(1 << 16), 0, CM_L4PER_MMCSD4_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_MMCSD5_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_MMCSD5_CLKCTRL, LDELAY);
+
+ /* UART clocks */
+ sr32(CM_L4PER_UART1_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_UART1_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_UART2_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_UART2_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_UART3_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_UART3_CLKCTRL, LDELAY);
+ sr32(CM_L4PER_UART4_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L4PER_UART4_CLKCTRL, LDELAY);
+
+ /* WKUP clocks */
+ sr32(CM_WKUP_GPIO1_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_WKUP_GPIO1_CLKCTRL, LDELAY);
+ sr32(CM_WKUP_TIMER1_CLKCTRL, 0, 32, 0x01000002);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_WKUP_TIMER1_CLKCTRL, LDELAY);
+
+ sr32(CM_WKUP_KEYBOARD_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_WKUP_KEYBOARD_CLKCTRL, LDELAY);
+
+ sr32(CM_SDMA_CLKSTCTRL, 0, 32, 0x0);
+ sr32(CM_MEMIF_CLKSTCTRL, 0, 32, 0x3);
+ sr32(CM_MEMIF_EMIF_1_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_MEMIF_EMIF_1_CLKCTRL, LDELAY);
+ sr32(CM_MEMIF_EMIF_2_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_MEMIF_EMIF_2_CLKCTRL, LDELAY);
+ sr32(CM_D2D_CLKSTCTRL, 0, 32, 0x3);
+ sr32(CM_L3_2_GPMC_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L3_2_GPMC_CLKCTRL, LDELAY);
+ sr32(CM_L3INSTR_L3_3_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L3INSTR_L3_3_CLKCTRL, LDELAY);
+ sr32(CM_L3INSTR_L3_INSTR_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L3INSTR_L3_INSTR_CLKCTRL, LDELAY);
+ sr32(CM_L3INSTR_OCP_WP1_CLKCTRL, 0, 32, 0x1);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_L3INSTR_OCP_WP1_CLKCTRL, LDELAY);
+
+ /* WDT clocks */
+ sr32(CM_WKUP_WDT2_CLKCTRL, 0, 32, 0x2);
+ wait_on_value((1 << 17)|(1 << 16), 0, CM_WKUP_WDT2_CLKCTRL, LDELAY);
+
+ /* Enable Camera clocks */
+ sr32(CM_CAM_CLKSTCTRL, 0, 32, 0x3);
+ sr32(CM_CAM_ISS_CLKCTRL, 0, 32, 0x102);
+ sr32(CM_CAM_FDIF_CLKCTRL, 0, 32, 0x2);
+ sr32(CM_CAM_CLKSTCTRL, 0, 32, 0x0);
+
+ /* Enable DSS clocks */
+ /* PM_DSS_PWRSTCTRL ON State and LogicState = 1 (Retention) */
+ __raw_writel(7, 0x4A307100); /* DSS_PRM */
+
+ sr32(CM_DSS_CLKSTCTRL, 0, 32, 0x2);
+ sr32(CM_DSS_DSS_CLKCTRL, 0, 32, 0xf02);
+ sr32(CM_DSS_DEISS_CLKCTRL, 0, 32, 0x2);
+
+ /* Check for DSS Clocks */
+ while ((__raw_readl(0x4A009100) & 0xF00) != 0xE00)
+ ;
+ /* Set HW_AUTO transition mode */
+ sr32(CM_DSS_CLKSTCTRL, 0, 32, 0x3);
+
+ /* Enable SGX clocks */
+ sr32(CM_SGX_CLKSTCTRL, 0, 32, 0x2);
+ sr32(CM_SGX_SGX_CLKCTRL, 0, 32, 0x2);
+ /* Check for SGX FCLK and ICLK */
+ while (__raw_readl(0x4A009200) != 0x302)
+ ;
+ /* Enable hsi/unipro/usb clocks */
+ sr32(CM_L3INIT_HSI_CLKCTRL, 0, 32, 0x1);
+ sr32(CM_L3INIT_UNIPRO1_CLKCTRL, 0, 32, 0x2);
+ sr32(CM_L3INIT_HSUSBHOST_CLKCTRL, 0, 32, 0x2);
+ sr32(CM_L3INIT_HSUSBOTG_CLKCTRL, 0, 32, 0x1);
+ sr32(CM_L3INIT_HSUSBTLL_CLKCTRL, 0, 32, 0x1);
+ sr32(CM_L3INIT_FSUSB_CLKCTRL, 0, 32, 0x2);
+ /* enable the 32K, 48M optional clocks and enable the module */
+ sr32(CM_L3INIT_USBPHY_CLKCTRL, 0, 32, 0x301);
+}
+
diff --git a/arch/arm/mach-omap/omap4_generic.c b/arch/arm/mach-omap/omap4_generic.c
new file mode 100644
index 00000000..313e5e99
--- /dev/null
+++ b/arch/arm/mach-omap/omap4_generic.c
@@ -0,0 +1,420 @@
+#include <common.h>
+#include <init.h>
+#include <mach/silicon.h>
+#include <asm/io.h>
+#include <mach/omap4-silicon.h>
+#include <mach/omap4-clock.h>
+#include <mach/syslib.h>
+#include <mach/xload.h>
+
+void __noreturn reset_cpu(unsigned long addr)
+{
+ writel(PRM_RSTCTRL_RESET, PRM_RSTCTRL);
+
+ while (1);
+}
+
+#define WATCHDOG_WSPR 0x48
+#define WATCHDOG_WWPS 0x34
+
+static void wait_for_command_complete(void)
+{
+ int pending = 1;
+
+ do {
+ pending = readl(OMAP44XX_WDT2_BASE + WATCHDOG_WWPS);
+ } while (pending);
+}
+
+/* EMIF */
+#define EMIF_MOD_ID_REV 0x0000
+#define EMIF_STATUS 0x0004
+#define EMIF_SDRAM_CONFIG 0x0008
+#define EMIF_LPDDR2_NVM_CONFIG 0x000C
+#define EMIF_SDRAM_REF_CTRL 0x0010
+#define EMIF_SDRAM_REF_CTRL_SHDW 0x0014
+#define EMIF_SDRAM_TIM_1 0x0018
+#define EMIF_SDRAM_TIM_1_SHDW 0x001C
+#define EMIF_SDRAM_TIM_2 0x0020
+#define EMIF_SDRAM_TIM_2_SHDW 0x0024
+#define EMIF_SDRAM_TIM_3 0x0028
+#define EMIF_SDRAM_TIM_3_SHDW 0x002C
+#define EMIF_LPDDR2_NVM_TIM 0x0030
+#define EMIF_LPDDR2_NVM_TIM_SHDW 0x0034
+#define EMIF_PWR_MGMT_CTRL 0x0038
+#define EMIF_PWR_MGMT_CTRL_SHDW 0x003C
+#define EMIF_LPDDR2_MODE_REG_DATA 0x0040
+#define EMIF_LPDDR2_MODE_REG_CFG 0x0050
+#define EMIF_L3_CONFIG 0x0054
+#define EMIF_L3_CFG_VAL_1 0x0058
+#define EMIF_L3_CFG_VAL_2 0x005C
+#define IODFT_TLGC 0x0060
+#define EMIF_PERF_CNT_1 0x0080
+#define EMIF_PERF_CNT_2 0x0084
+#define EMIF_PERF_CNT_CFG 0x0088
+#define EMIF_PERF_CNT_SEL 0x008C
+#define EMIF_PERF_CNT_TIM 0x0090
+#define EMIF_READ_IDLE_CTRL 0x0098
+#define EMIF_READ_IDLE_CTRL_SHDW 0x009c
+#define EMIF_ZQ_CONFIG 0x00C8
+#define EMIF_DDR_PHY_CTRL_1 0x00E4
+#define EMIF_DDR_PHY_CTRL_1_SHDW 0x00E8
+#define EMIF_DDR_PHY_CTRL_2 0x00EC
+
+#define DMM_LISA_MAP_0 0x0040
+#define DMM_LISA_MAP_1 0x0044
+#define DMM_LISA_MAP_2 0x0048
+#define DMM_LISA_MAP_3 0x004C
+
+#define MR0_ADDR 0
+#define MR1_ADDR 1
+#define MR2_ADDR 2
+#define MR4_ADDR 4
+#define MR10_ADDR 10
+#define MR16_ADDR 16
+#define REF_EN 0x40000000
+/* defines for MR1 */
+#define MR1_BL4 2
+#define MR1_BL8 3
+#define MR1_BL16 4
+
+#define MR1_BT_SEQ 0
+#define BT_INT 1
+
+#define MR1_WC 0
+#define MR1_NWC 1
+
+#define MR1_NWR3 1
+#define MR1_NWR4 2
+#define MR1_NWR5 3
+#define MR1_NWR6 4
+#define MR1_NWR7 5
+#define MR1_NWR8 6
+
+#define MR1_VALUE (MR1_NWR3 << 5) | (MR1_WC << 4) | (MR1_BT_SEQ << 3) \
+ | (MR1_BL8 << 0)
+
+/* defines for MR2 */
+#define MR2_RL3_WL1 1
+#define MR2_RL4_WL2 2
+#define MR2_RL5_WL2 3
+#define MR2_RL6_WL3 4
+
+/* defines for MR10 */
+#define MR10_ZQINIT 0xFF
+#define MR10_ZQRESET 0xC3
+#define MR10_ZQCL 0xAB
+#define MR10_ZQCS 0x56
+
+
+/* TODO: FREQ update method is not working so shadow registers programming
+ * is just for same of completeness. This would be safer if auto
+ * trasnitions are working
+ */
+#define FREQ_UPDATE_EMIF
+/* EMIF Needs to be configured@19.2 MHz and shadow registers
+ * should be programmed for new OPP.
+ */
+/* Elpida 2x2Gbit */
+#define SDRAM_CONFIG_INIT 0x80800EB1
+#define DDR_PHY_CTRL_1_INIT 0x849FFFF5
+#define READ_IDLE_CTRL 0x000501FF
+#define PWR_MGMT_CTRL 0x4000000f
+#define PWR_MGMT_CTRL_OPP100 0x4000000f
+#define ZQ_CONFIG 0x500b3215
+
+#define CS1_MR(mr) ((mr) | 0x80000000)
+
+static inline void delay(unsigned long loops)
+{
+ __asm__ volatile ("1:\n" "subs %0, %1, #1\n"
+ "bne 1b" : "=r" (loops) : "0"(loops));
+}
+
+int omap4_emif_config(unsigned int base, const struct ddr_regs *ddr_regs)
+{
+ /*
+ * set SDRAM CONFIG register
+ * EMIF_SDRAM_CONFIG[31:29] REG_SDRAM_TYPE = 4 for LPDDR2-S4
+ * EMIF_SDRAM_CONFIG[28:27] REG_IBANK_POS = 0
+ * EMIF_SDRAM_CONFIG[13:10] REG_CL = 3
+ * EMIF_SDRAM_CONFIG[6:4] REG_IBANK = 3 - 8 banks
+ * EMIF_SDRAM_CONFIG[3] REG_EBANK = 0 - CS0
+ * EMIF_SDRAM_CONFIG[2:0] REG_PAGESIZE = 2 - 512- 9 column
+ * JDEC specs - S4-2Gb --8 banks -- R0-R13, C0-c8
+ */
+ writel(readl(base + EMIF_LPDDR2_NVM_CONFIG) & 0xbfffffff,
+ base + EMIF_LPDDR2_NVM_CONFIG);
+ writel(ddr_regs->config_init, base + EMIF_SDRAM_CONFIG);
+
+ /* PHY control values */
+ writel(DDR_PHY_CTRL_1_INIT, base + EMIF_DDR_PHY_CTRL_1);
+ writel(ddr_regs->phy_ctrl_1, base + EMIF_DDR_PHY_CTRL_1_SHDW);
+
+ /*
+ * EMIF_READ_IDLE_CTRL
+ */
+ writel(READ_IDLE_CTRL, base + EMIF_READ_IDLE_CTRL);
+ writel(READ_IDLE_CTRL, base + EMIF_READ_IDLE_CTRL);
+
+ /*
+ * EMIF_SDRAM_TIM_1
+ */
+ writel(ddr_regs->tim1, base + EMIF_SDRAM_TIM_1);
+ writel(ddr_regs->tim1, base + EMIF_SDRAM_TIM_1_SHDW);
+
+ /*
+ * EMIF_SDRAM_TIM_2
+ */
+ writel(ddr_regs->tim2, base + EMIF_SDRAM_TIM_2);
+ writel(ddr_regs->tim2, base + EMIF_SDRAM_TIM_2_SHDW);
+
+ /*
+ * EMIF_SDRAM_TIM_3
+ */
+ writel(ddr_regs->tim3, base + EMIF_SDRAM_TIM_3);
+ writel(ddr_regs->tim3, base + EMIF_SDRAM_TIM_3_SHDW);
+
+ writel(ddr_regs->zq_config, base + EMIF_ZQ_CONFIG);
+
+ /*
+ * poll MR0 register (DAI bit)
+ * REG_CS[31] = 0 -- Mode register command to CS0
+ * REG_REFRESH_EN[30] = 1 -- Refresh enable after MRW
+ * REG_ADDRESS[7:0] = 00 -- Refresh enable after MRW
+ */
+
+ writel(MR0_ADDR, base + EMIF_LPDDR2_MODE_REG_CFG);
+
+ while (readl(base + EMIF_LPDDR2_MODE_REG_DATA) & 1)
+ ;
+
+ writel(CS1_MR(MR0_ADDR), base + EMIF_LPDDR2_MODE_REG_CFG);
+
+ while (readl(base + EMIF_LPDDR2_MODE_REG_DATA) & 1)
+ ;
+
+
+ /* set MR10 register */
+ writel(MR10_ADDR, base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(MR10_ZQINIT, base + EMIF_LPDDR2_MODE_REG_DATA);
+ writel(CS1_MR(MR10_ADDR), base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(MR10_ZQINIT, base + EMIF_LPDDR2_MODE_REG_DATA);
+
+ /* wait for tZQINIT=1us */
+ delay(10);
+
+ /* set MR1 register */
+ writel(MR1_ADDR, base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(ddr_regs->mr1, base + EMIF_LPDDR2_MODE_REG_DATA);
+ writel(CS1_MR(MR1_ADDR), base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(ddr_regs->mr1, base + EMIF_LPDDR2_MODE_REG_DATA);
+
+ /* set MR2 register RL=6 for OPP100 */
+ writel(MR2_ADDR, base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(ddr_regs->mr2, base + EMIF_LPDDR2_MODE_REG_DATA);
+ writel(CS1_MR(MR2_ADDR), base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(ddr_regs->mr2, base + EMIF_LPDDR2_MODE_REG_DATA);
+
+ /* Set SDRAM CONFIG register again here with final RL-WL value */
+ writel(ddr_regs->config_final, base + EMIF_SDRAM_CONFIG);
+ writel(ddr_regs->phy_ctrl_1, base + EMIF_DDR_PHY_CTRL_1);
+
+ /*
+ * EMIF_SDRAM_REF_CTRL
+ * refresh rate = DDR_CLK / reg_refresh_rate
+ * 3.9 uS = (400MHz) / reg_refresh_rate
+ */
+ writel(ddr_regs->ref_ctrl, base + EMIF_SDRAM_REF_CTRL);
+ writel(ddr_regs->ref_ctrl, base + EMIF_SDRAM_REF_CTRL_SHDW);
+
+ /* set MR16 register */
+ writel(MR16_ADDR | REF_EN, base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(0, base + EMIF_LPDDR2_MODE_REG_DATA);
+ writel(CS1_MR(MR16_ADDR | REF_EN),
+ base + EMIF_LPDDR2_MODE_REG_CFG);
+ writel(0, base + EMIF_LPDDR2_MODE_REG_DATA);
+
+ /* LPDDR2 init complete */
+
+ return 0;
+}
+
+static void reset_phy(unsigned int base)
+{
+ *(volatile int*)(base + IODFT_TLGC) |= (1 << 10);
+}
+
+void omap4_ddr_init(const struct ddr_regs *ddr_regs,
+ const struct dpll_param *core)
+{
+ unsigned int rev;
+ rev = omap4_revision();
+
+ if (rev == OMAP4430_ES2_0) {
+ writel(0x9e9e9e9e, 0x4A100638);
+ writel(0x9e9e9e9e, 0x4A10063c);
+ writel(0x9e9e9e9e, 0x4A100640);
+ writel(0x9e9e9e9e, 0x4A100648);
+ writel(0x9e9e9e9e, 0x4A10064c);
+ writel(0x9e9e9e9e, 0x4A100650);
+ /* LPDDR2IO set to NMOS PTV */
+ writel(0x00ffc000, 0x4A100704);
+ }
+
+ /*
+ * DMM Configuration
+ */
+
+ /* Both EMIFs 128 byte interleaved */
+ writel(0x80640300, OMAP44XX_DMM_BASE + DMM_LISA_MAP_0);
+
+ *(volatile int*)(OMAP44XX_DMM_BASE + DMM_LISA_MAP_2) = 0x00000000;
+ *(volatile int*)(OMAP44XX_DMM_BASE + DMM_LISA_MAP_3) = 0xFF020100;
+
+ /* DDR needs to be initialised @ 19.2 MHz
+ * So put core DPLL in bypass mode
+ * Configure the Core DPLL but don't lock it
+ */
+ omap4_configure_core_dpll_no_lock(core);
+
+ /* No IDLE: BUG in SDC */
+ sr32(CM_MEMIF_CLKSTCTRL, 0, 32, 0x2);
+ while(((*(volatile int*)CM_MEMIF_CLKSTCTRL) & 0x700) != 0x700);
+
+ *(volatile int*)(OMAP44XX_EMIF1_BASE + EMIF_PWR_MGMT_CTRL) = 0x0;
+ *(volatile int*)(OMAP44XX_EMIF2_BASE + EMIF_PWR_MGMT_CTRL) = 0x0;
+
+ omap4_emif_config(OMAP44XX_EMIF1_BASE, ddr_regs);
+ omap4_emif_config(OMAP44XX_EMIF2_BASE, ddr_regs);
+
+ /* Lock Core using shadow CM_SHADOW_FREQ_CONFIG1 */
+ omap4_lock_core_dpll_shadow(core);
+
+ /* Set DLL_OVERRIDE = 0 */
+ *(volatile int*)CM_DLL_CTRL = 0x0;
+
+ delay(200);
+
+ /* Check for DDR PHY ready for EMIF1 & EMIF2 */
+ while((((*(volatile int*)(OMAP44XX_EMIF1_BASE + EMIF_STATUS))&(0x04)) != 0x04) \
+ || (((*(volatile int*)(OMAP44XX_EMIF2_BASE + EMIF_STATUS))&(0x04)) != 0x04));
+
+ /* Reprogram the DDR PYHY Control register */
+ /* PHY control values */
+
+ sr32(CM_MEMIF_EMIF_1_CLKCTRL, 0, 32, 0x1);
+ sr32(CM_MEMIF_EMIF_2_CLKCTRL, 0, 32, 0x1);
+
+ /* Put the Core Subsystem PD to ON State */
+
+ /* No IDLE: BUG in SDC */
+ //sr32(CM_MEMIF_CLKSTCTRL, 0, 32, 0x2);
+ //while(((*(volatile int*)CM_MEMIF_CLKSTCTRL) & 0x700) != 0x700);
+ *(volatile int*)(OMAP44XX_EMIF1_BASE + EMIF_PWR_MGMT_CTRL) = 0x80000000;
+ *(volatile int*)(OMAP44XX_EMIF2_BASE + EMIF_PWR_MGMT_CTRL) = 0x80000000;
+
+ /*
+ * DMM : DMM_LISA_MAP_0(Section_0)
+ * [31:24] SYS_ADDR 0x80
+ * [22:20] SYS_SIZE 0x7 - 2Gb
+ * [19:18] SDRC_INTLDMM 0x1 - 128 byte
+ * [17:16] SDRC_ADDRSPC 0x0
+ * [9:8] SDRC_MAP 0x3
+ * [7:0] SDRC_ADDR 0X0
+ */
+ reset_phy(OMAP44XX_EMIF1_BASE);
+ reset_phy(OMAP44XX_EMIF2_BASE);
+
+ *((volatile int *)0x80000000) = 0;
+ *((volatile int *)0x80000080) = 0;
+}
+
+void omap4_power_i2c_send(u32 r)
+{
+ u32 val;
+
+ writel(r, OMAP44XX_PRM_VC_VAL_BYPASS);
+
+ val = readl(OMAP44XX_PRM_VC_VAL_BYPASS);
+ val |= 0x1000000;
+ writel(val, OMAP44XX_PRM_VC_VAL_BYPASS);
+
+ while (readl(OMAP44XX_PRM_VC_VAL_BYPASS) & 0x1000000)
+ ;
+
+ val = readl(OMAP44XX_PRM_IRQSTATUS_MPU_A9);
+ writel(val, OMAP44XX_PRM_IRQSTATUS_MPU_A9);
+}
+
+static unsigned int cortex_a9_rev(void)
+{
+
+ unsigned int i;
+
+ asm ("mrc p15, 0, %0, c0, c0, 0" : "=r" (i));
+
+ return i;
+}
+
+unsigned int omap4_revision(void)
+{
+ unsigned int chip_rev = 0;
+ unsigned int rev = cortex_a9_rev();
+
+ switch(rev) {
+ case 0x410FC091:
+ return OMAP4430_ES1_0;
+ case 0x411FC092:
+ chip_rev = (readl(OMAP44XX_CTRL_BASE + 0x204) >> 28) & 0xF;
+ if (chip_rev == 3)
+ return OMAP4430_ES2_1;
+ else if (chip_rev >= 4)
+ return OMAP4430_ES2_2;
+ else
+ return OMAP4430_ES2_0;
+ }
+ return OMAP4430_SILICON_ID_INVALID;
+}
+
+/*
+ * shutdown watchdog
+ */
+static int watchdog_init(void)
+{
+ void __iomem *wd2_base = (void *)OMAP44XX_WDT2_BASE;
+
+ writel(WD_UNLOCK1, wd2_base + WATCHDOG_WSPR);
+ wait_for_command_complete();
+ writel(WD_UNLOCK2, wd2_base + WATCHDOG_WSPR);
+
+ return 0;
+}
+late_initcall(watchdog_init);
+
+static int omap_vector_init(void)
+{
+ __asm__ __volatile__ (
+ "mov r0, #0;"
+ "mcr p15, #0, r0, c12, c0, #0;"
+ :
+ :
+ : "r0"
+ );
+
+ return 0;
+}
+core_initcall(omap_vector_init);
+
+#define OMAP4_TRACING_VECTOR3 0x4030d048
+
+enum omap_boot_src omap4_bootsrc(void)
+{
+ u32 bootsrc = readl(OMAP4_TRACING_VECTOR3);
+
+ if (bootsrc & (1 << 5))
+ return OMAP_BOOTSRC_MMC1;
+ if (bootsrc & (1 << 3))
+ return OMAP_BOOTSRC_NAND;
+ return OMAP_BOOTSRC_UNKNOWN;
+}
diff --git a/arch/arm/mach-omap/syslib.c b/arch/arm/mach-omap/syslib.c
index 2b25dc15..677de6a2 100644
--- a/arch/arm/mach-omap/syslib.c
+++ b/arch/arm/mach-omap/syslib.c
@@ -53,26 +53,6 @@ void sdelay(unsigned long loops)
}
/**
- * @brief clear & set a value in a bit range for a 32 bit address
- *
- * @param[in] addr Address to set/read from
- * @param[in] start_bit Where to put the value
- * @param[in] num_bits number of bits the value should be set
- * @param[in] value the value to set
- *
- * @return void
- */
-void sr32(u32 addr, u32 start_bit, u32 num_bits, u32 value)
-{
- u32 tmp, msk = 0;
- msk = 1 << num_bits;
- --msk;
- tmp = readl(addr) & ~(msk << start_bit);
- tmp |= value << start_bit;
- writel(tmp, addr);
-}
-
-/**
* @brief common routine to allow waiting for changes in volatile regs.
*
* @param[in] read_bit_mask the bit mask to read
diff --git a/arch/arm/mach-omap/xload.c b/arch/arm/mach-omap/xload.c
new file mode 100644
index 00000000..216b9b5a
--- /dev/null
+++ b/arch/arm/mach-omap/xload.c
@@ -0,0 +1,54 @@
+#include <common.h>
+#include <partition.h>
+#include <nand.h>
+#include <driver.h>
+#include <linux/mtd/mtd.h>
+#include <fs.h>
+#include <fcntl.h>
+#include <mach/xload.h>
+#include <sizes.h>
+
+void *omap_xload_boot_nand(int offset, int size)
+{
+ int ret;
+ void *to = xmalloc(size);
+ struct cdev *cdev;
+
+ devfs_add_partition("nand0", offset, size, PARTITION_FIXED, "x");
+ dev_add_bb_dev("x", "bbx");
+
+ cdev = cdev_open("bbx", O_RDONLY);
+ if (!cdev) {
+ printf("failed to open nand\n");
+ return NULL;
+ }
+
+ ret = cdev_read(cdev, to, size, 0, 0);
+ if (ret != size) {
+ printf("failed to read from nand\n");
+ return NULL;
+ }
+
+ return to;
+}
+
+void *omap_xload_boot_mmc(void)
+{
+ int ret;
+ void *buf;
+ int len;
+
+ ret = mount("disk0.0", "fat", "/");
+ if (ret) {
+ printf("mounting sd card failed with %d\n", ret);
+ return NULL;
+ }
+
+ buf = read_file("/barebox.bin", &len);
+ if (!buf) {
+ printf("could not read barebox.bin from sd card\n");
+ return NULL;
+ }
+
+ return buf;
+}
diff --git a/arch/nios2/boards/generic/generic.c b/arch/nios2/boards/generic/generic.c
index 99c855d2..7e939ce2 100644
--- a/arch/nios2/boards/generic/generic.c
+++ b/arch/nios2/boards/generic/generic.c
@@ -11,11 +11,14 @@ static struct device_d cfi_dev = {
.size = NIOS_SOPC_FLASH_SIZE,
};
+static int phy_address = 1;
+
static struct device_d mac_dev = {
- .id = -1,
- .name = "altera_tse",
- .map_base = NIOS_SOPC_TSE_BASE,
- .size = 0x00000400,
+ .id = -1,
+ .name = "altera_tse",
+ .map_base = NIOS_SOPC_TSE_BASE,
+ .size = 0x00000400,
+ .platform_data = &phy_address,
};
static struct memory_platform_data ram_pdata = {
diff --git a/arch/nios2/lib/Makefile b/arch/nios2/lib/Makefile
index 8776c61e..fc9d4d7d 100644
--- a/arch/nios2/lib/Makefile
+++ b/arch/nios2/lib/Makefile
@@ -2,5 +2,6 @@ obj-y += board.o
obj-y += libgcc.o
obj-y += clock.o
obj-y += cache.o
+obj-y += bootm.o
obj-$(CONFIG_EARLY_PRINTF) += early_printf.o
diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c
new file mode 100644
index 00000000..34e2bd26
--- /dev/null
+++ b/arch/nios2/lib/bootm.c
@@ -0,0 +1,83 @@
+/*
+ * barebox - bootm.c
+ *
+ * (C) Copyright 2011 - Franck JULLIEN <elec4fun@gmail.com>
+ *
+ * (C) Copyright 2003, Psyent Corporation <www.psyent.com>
+ * Scott McNutt <smcnutt@psyent.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <image.h>
+#include <environment.h>
+#include <init.h>
+#include <boot.h>
+#include <asm/cache.h>
+
+#define NIOS_MAGIC 0x534f494e /* enable command line and initrd passing */
+
+static int do_bootm_linux(struct image_data *idata)
+{
+ image_header_t *os_header = &idata->os->header;
+ void (*kernel)(int, int, int, const char *);
+ const char *commandline = getenv ("bootargs");
+
+ kernel = (void (*)(int, int, int, const char *))ntohl(os_header->ih_ep);
+
+#ifdef CONFIG_USE_IRQ
+ disable_interrupts();
+#endif
+
+ if (relocate_image(idata->os, (void *)ntohl(os_header->ih_load)))
+ return -1;
+
+ /* kernel parameters passing
+ * r4 : NIOS magic
+ * r5 : initrd start
+ * r6 : initrd end or fdt
+ * r7 : kernel command line
+ * fdt is passed to kernel via r6, the same as initrd_end. fdt will be
+ * verified with fdt magic. when both initrd and fdt are used at the
+ * same time, fdt must follow immediately after initrd.
+ */
+
+ /* flushes data and instruction caches before calling the kernel */
+ flush_cache_all();
+
+ kernel(NIOS_MAGIC, 0, 0, commandline);
+ /* does not return */
+
+ return 1;
+}
+
+static struct image_handler handler = {
+ .bootm = do_bootm_linux,
+ .image_type = IH_OS_LINUX,
+};
+
+int nios2_register_image_handler(void)
+{
+ return register_image_handler(&handler);
+}
+
+late_initcall(nios2_register_image_handler);
+
diff --git a/commands/Kconfig b/commands/Kconfig
index f137f473..f192d309 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -1,7 +1,14 @@
config REGINFO
bool
-menu "Commands "
+config COMMAND_SUPPORT
+ bool
+ depends on !SHELL_NONE
+ default y
+
+if COMMAND_SUPPORT
+
+menu "commands "
menu "scripting "
@@ -29,11 +36,13 @@ config CMD_LOADENV
prompt "loadenv"
config CMD_EXPORT
+ depends on ENVIRONMENT_VARIABLES
tristate
prompt "export"
config CMD_PRINTENV
tristate
+ depends on ENVIRONMENT_VARIABLES
prompt "printenv"
config CMD_READLINE
@@ -142,6 +151,12 @@ config CMD_UMOUNT
default y
prompt "umount"
+config CMD_NAND
+ tristate
+ default y
+ depends on NAND
+ prompt "nand"
+
endmenu
menu "console "
@@ -387,4 +402,14 @@ config CMD_LED_TRIGGER
The trigger command allows to control LED triggers from the command
line.
+config CMD_USB
+ bool
+ depends on USB
+ prompt "usb command"
+ default y
+ help
+ The usb command allows to rescan for USB devices.
+
endmenu
+
+endif
diff --git a/commands/Makefile b/commands/Makefile
index c89adcff..f7ef9a8a 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -37,7 +37,7 @@ obj-$(CONFIG_CMD_EXPORT) += export.o
obj-$(CONFIG_CMD_PRINTENV) += printenv.o
obj-$(CONFIG_CMD_SAVEENV) += saveenv.o
obj-$(CONFIG_CMD_LOADENV) += loadenv.o
-obj-$(CONFIG_NAND) += nand.o
+obj-$(CONFIG_CMD_NAND) += nand.o
obj-$(CONFIG_CMD_TRUE) += true.o
obj-$(CONFIG_CMD_FALSE) += false.o
obj-$(CONFIG_CMD_VERSION) += version.o
@@ -55,3 +55,4 @@ obj-$(CONFIG_CMD_PASSWD) += passwd.o
obj-$(CONFIG_CMD_LOGIN) += login.o
obj-$(CONFIG_CMD_LED) += led.o
obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o
+obj-$(CONFIG_CMD_USB) += usb.o
diff --git a/commands/cp.c b/commands/cp.c
index ae8719b2..34281052 100644
--- a/commands/cp.c
+++ b/commands/cp.c
@@ -31,6 +31,7 @@
#include <libbb.h>
#include <fs.h>
#include <malloc.h>
+#include <libgen.h>
/**
* @param[in] cmdtp FIXME
@@ -60,7 +61,7 @@ static int do_cp(struct command *cmdtp, int argc, char *argv[])
for (i = 1; i < argc - 1; i++) {
if (last_is_dir) {
char *dst;
- dst = concat_path_file(argv[argc - 1], argv[i]);
+ dst = concat_path_file(argv[argc - 1], basename(argv[i]));
ret = copy_file(argv[i], dst);
if (ret)
goto out;
diff --git a/commands/loadenv.c b/commands/loadenv.c
index c33c34fc..5568aced 100644
--- a/commands/loadenv.c
+++ b/commands/loadenv.c
@@ -36,7 +36,7 @@ static int do_loadenv(struct command *cmdtp, int argc, char *argv[])
else
dirname = argv[2];
if (argc < 2)
- filename = "/dev/env0";
+ filename = default_environment_path;
else
filename = argv[1];
printf("loading environment from %s\n", filename);
diff --git a/commands/nand.c b/commands/nand.c
index d3921b9f..88f242df 100644
--- a/commands/nand.c
+++ b/commands/nand.c
@@ -32,249 +32,6 @@
#include <fcntl.h>
#include <libgen.h>
-struct nand_bb {
- char *devname;
- char *name;
- int open;
- int needs_write;
-
- struct mtd_info_user info;
-
- size_t raw_size;
- size_t size;
- int fd;
- off_t offset;
- void *writebuf;
-
- struct cdev cdev;
-};
-
-static ssize_t nand_bb_read(struct cdev *cdev, void *buf, size_t count,
- unsigned long offset, ulong flags)
-{
- struct nand_bb *bb = cdev->priv;
- int ret, bytes = 0, now;
-
- debug("%s %d %d\n", __func__, offset, count);
-
- while(count) {
- ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)bb->offset);
- if (ret < 0)
- return ret;
-
- if (ret) {
- printf("skipping bad block at 0x%08lx\n", bb->offset);
- bb->offset += bb->info.erasesize;
- continue;
- }
-
- now = min(count, (size_t)(bb->info.erasesize -
- (bb->offset % bb->info.erasesize)));
- lseek(bb->fd, bb->offset, SEEK_SET);
- ret = read(bb->fd, buf, now);
- if (ret < 0)
- return ret;
- buf += now;
- count -= now;
- bb->offset += now;
- bytes += now;
- };
-
- return bytes;
-}
-
-/* Must be a multiple of the largest NAND page size */
-#define BB_WRITEBUF_SIZE 4096
-
-static int nand_bb_write_buf(struct nand_bb *bb, size_t count)
-{
- int ret, now;
- void *buf = bb->writebuf;
- int cur_ofs = bb->offset & ~(BB_WRITEBUF_SIZE - 1);
-
- while (count) {
- ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)cur_ofs);
- if (ret < 0)
- return ret;
-
- if (ret) {
- debug("skipping bad block at 0x%08x\n", cur_ofs);
- bb->offset += bb->info.erasesize;
- cur_ofs += bb->info.erasesize;
- continue;
- }
-
- now = min(count, (size_t)(bb->info.erasesize));
- lseek(bb->fd, cur_ofs, SEEK_SET);
- ret = write(bb->fd, buf, now);
- if (ret < 0)
- return ret;
- buf += now;
- count -= now;
- cur_ofs += now;
- };
-
- return 0;
-}
-
-static ssize_t nand_bb_write(struct cdev *cdev, const void *buf, size_t count,
- unsigned long offset, ulong flags)
-{
- struct nand_bb *bb = cdev->priv;
- int bytes = count, now, wroffs, ret;
-
- debug("%s offset: 0x%08x count: 0x%08x\n", __func__, offset, count);
-
- while (count) {
- wroffs = bb->offset % BB_WRITEBUF_SIZE;
- now = min((int)count, BB_WRITEBUF_SIZE - wroffs);
- memcpy(bb->writebuf + wroffs, buf, now);
-
- if (wroffs + now == BB_WRITEBUF_SIZE) {
- bb->needs_write = 0;
- ret = nand_bb_write_buf(bb, BB_WRITEBUF_SIZE);
- if (ret)
- return ret;
- } else {
- bb->needs_write = 1;
- }
-
- bb->offset += now;
- count -= now;
- buf += now;
- }
-
- return bytes;
-}
-
-static int nand_bb_erase(struct cdev *cdev, size_t count, unsigned long offset)
-{
- struct nand_bb *bb = cdev->priv;
-
- if (offset != 0) {
- printf("can only erase from beginning of device\n");
- return -EINVAL;
- }
-
- lseek(bb->fd, 0, SEEK_SET);
-
- return erase(bb->fd, bb->raw_size, 0);
-}
-
-static int nand_bb_open(struct cdev *cdev, struct filep *f)
-{
- struct nand_bb *bb = cdev->priv;
-
- if (bb->open)
- return -EBUSY;
-
- bb->open = 1;
- bb->offset = 0;
- bb->needs_write = 0;
- bb->writebuf = xmalloc(BB_WRITEBUF_SIZE);
-
- return 0;
-}
-
-static int nand_bb_close(struct cdev *cdev, struct filep *f)
-{
- struct nand_bb *bb = cdev->priv;
-
- if (bb->needs_write)
- nand_bb_write_buf(bb, bb->offset % BB_WRITEBUF_SIZE);
-
- bb->open = 0;
- free(bb->writebuf);
-
- return 0;
-}
-
-static int nand_bb_calc_size(struct nand_bb *bb)
-{
- ulong pos = 0;
- int ret;
-
- while (pos < bb->raw_size) {
- ret = ioctl(bb->fd, MEMGETBADBLOCK, (void *)pos);
- if (ret < 0)
- return ret;
- if (!ret)
- bb->cdev.size += bb->info.erasesize;
-
- pos += bb->info.erasesize;
- }
-
- return 0;
-}
-
-static struct file_operations nand_bb_ops = {
- .open = nand_bb_open,
- .close = nand_bb_close,
- .read = nand_bb_read,
- .write = nand_bb_write,
- .erase = nand_bb_erase,
-};
-
-/**
- * Add a bad block aware device ontop of another (NAND) device
- * @param[in] dev The device to add a partition on
- * @param[in] name Partition name (can be obtained with devinfo command)
- * @return The device representing the new partition.
- */
-int dev_add_bb_dev(char *path, const char *name)
-{
- struct nand_bb *bb;
- int ret = -ENOMEM;
- struct stat s;
-
- bb = xzalloc(sizeof(*bb));
- bb->devname = asprintf("/dev/%s", basename(path));
- if (!bb->devname)
- goto out1;
-
- if (name)
- bb->cdev.name = strdup(name);
- else
- bb->cdev.name = asprintf("%s.bb", basename(path));
-
- if (!bb->cdev.name)
- goto out2;
-
- ret = stat(bb->devname, &s);
- if (ret)
- goto out3;
-
- bb->raw_size = s.st_size;
-
- bb->fd = open(bb->devname, O_RDWR);
- if (bb->fd < 0) {
- ret = -ENODEV;
- goto out3;
- }
-
- ret = ioctl(bb->fd, MEMGETINFO, &bb->info);
- if (ret)
- goto out4;
-
- nand_bb_calc_size(bb);
- bb->cdev.ops = &nand_bb_ops;
- bb->cdev.priv = bb;
-
- devfs_create(&bb->cdev);
-
- return 0;
-
-out4:
- close(bb->fd);
-out3:
- free(bb->cdev.name);
-out2:
- free(bb->devname);
-out1:
- free(bb);
- return ret;
-}
-
#define NAND_ADD (1 << 0)
#define NAND_DEL (1 << 1)
#define NAND_MARKBAD (1 << 2)
@@ -282,7 +39,6 @@ out1:
static int do_nand(struct command *cmdtp, int argc, char *argv[])
{
int opt;
- struct nand_bb *bb;
int command = 0, badblock = 0;
while((opt = getopt(argc, argv, "adb:")) > 0) {
@@ -306,7 +62,7 @@ static int do_nand(struct command *cmdtp, int argc, char *argv[])
if (command & NAND_ADD) {
while (optind < argc) {
- if (dev_add_bb_dev(argv[optind], NULL))
+ if (dev_add_bb_dev(basename(argv[optind]), NULL))
return 1;
optind++;
@@ -315,17 +71,7 @@ static int do_nand(struct command *cmdtp, int argc, char *argv[])
if (command & NAND_DEL) {
while (optind < argc) {
- struct cdev *cdev;
-
- cdev = cdev_by_name(basename(argv[optind]));
- if (!cdev) {
- printf("no such device: %s\n", argv[optind]);
- return 1;
- }
- bb = cdev->priv;
- close(bb->fd);
- devfs_remove(cdev);
- free(bb);
+ dev_remove_bb_dev(basename(argv[optind]));
optind++;
}
}
diff --git a/commands/saveenv.c b/commands/saveenv.c
index 2f969fe7..11a9fee5 100644
--- a/commands/saveenv.c
+++ b/commands/saveenv.c
@@ -41,7 +41,7 @@ static int do_saveenv(struct command *cmdtp, int argc, char *argv[])
else
dirname = argv[2];
if (argc < 2)
- filename = "/dev/env0";
+ filename = default_environment_path;
else
filename = argv[1];
diff --git a/commands/usb.c b/commands/usb.c
new file mode 100644
index 00000000..0aac78ef
--- /dev/null
+++ b/commands/usb.c
@@ -0,0 +1,41 @@
+/*
+ * usb.c - rescan for USB devices
+ *
+ * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <common.h>
+#include <command.h>
+#include <usb/usb.h>
+
+static int do_usb(struct command *cmdtp, int argc, char *argv[])
+{
+ usb_rescan();
+
+ return 0;
+}
+
+static const __maybe_unused char cmd_usb_help[] =
+"Usage: usb\n"
+"(re-)detect USB devices\n";
+
+BAREBOX_CMD_START(usb)
+ .cmd = do_usb,
+ .usage = "(re-)detect USB devices",
+ BAREBOX_CMD_HELP(cmd_usb_help)
+BAREBOX_CMD_END
diff --git a/common/Kconfig b/common/Kconfig
index 9e30579a..7d2367b0 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -31,6 +31,15 @@ config ENV_HANDLING
config GENERIC_GPIO
bool
+config BLOCK
+ bool
+
+config BLOCK_WRITE
+ bool
+
+config HAVE_NOSHELL
+ bool
+
menu "General Settings "
config LOCALVERSION_AUTO
@@ -56,6 +65,9 @@ config LOCALVERSION_AUTO
config BOARDINFO
string
+config ENVIRONMENT_VARIABLES
+ bool "environment variables support"
+
menu "memory layout "
config HAVE_MMU
@@ -136,6 +148,22 @@ config EXPERIMENTAL
bool
prompt "Prompt for experimental code"
+choice
+ prompt "malloc implementation"
+
+config MALLOC_DLMALLOC
+ bool "dlmalloc"
+
+config MALLOC_DUMMY
+ bool "dummy malloc"
+ depends on SHELL_NONE
+ help
+ select this option to use a dummy malloc implementation. With this
+ memory is never freed. This is suitable for well tested noninteractive
+ environments only.
+
+endchoice
+
config MODULES
depends on HAS_MODULES
depends on EXPERIMENTAL
@@ -213,14 +241,26 @@ choice
config SHELL_HUSH
bool "hush parser"
+ select ENVIRONMENT_VARIABLES
+ select COMMAND_SUPPORT
help
Enable hush support. This is the most advanced shell available
for barebox.
config SHELL_SIMPLE
bool "Simple parser"
+ select ENVIRONMENT_VARIABLES
+ select COMMAND_SUPPORT
help
simple shell. No if/then, no return values from commands, no loops
+
+ config SHELL_NONE
+ depends on HAVE_NOSHELL
+ bool "no shell (noninteractive build)"
+ help
+ No shell at all. This means no shell is started and your board has
+ to provide a run_shell() function which is started at the end of
+ the barebox startup process.
endchoice
config GLOB
@@ -389,7 +429,7 @@ config DEFAULT_ENVIRONMENT
config DEFAULT_ENVIRONMENT_GENERIC
bool
depends on DEFAULT_ENVIRONMENT
- select SHELL_HUSH
+ depends on SHELL_HUSH
select HUSH_GETOPT
select CMD_CRC
select CMD_CRC_CMP
diff --git a/common/Makefile b/common/Makefile
index 6cc61435..9fed2ae5 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -6,14 +6,18 @@ obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_ENV_HANDLING) += environment.o
obj-$(CONFIG_AUTO_COMPLETE) += complete.o
obj-$(CONFIG_POLLER) += poller.o
+obj-$(CONFIG_BLOCK) += block.o
-obj-y += dlmalloc.o
+obj-y += memory.o
+obj-$(CONFIG_MALLOC_DLMALLOC) += dlmalloc.o
+obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o
obj-y += clock.o
-obj-y += command.o
+obj-y += version.o
+obj-$(CONFIG_COMMAND_SUPPORT) += command.o
obj-$(CONFIG_CONSOLE_FULL) += console.o
obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
obj-$(CONFIG_DIGEST) += digest.o
-obj-y += env.o
+obj-$(CONFIG_ENVIRONMENT_VARIABLES) += env.o
obj-$(CONFIG_CMD_BOOTM) += image.o
obj-y += startup.o
obj-y += misc.o
diff --git a/common/block.c b/common/block.c
new file mode 100644
index 00000000..24377c62
--- /dev/null
+++ b/common/block.c
@@ -0,0 +1,263 @@
+/*
+ * block.c - simple block layer
+ *
+ * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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 <block.h>
+#include <linux/err.h>
+
+#define BLOCKSIZE(blk) (1 << blk->blockbits)
+
+#define WRBUFFER_LAST(blk) (blk->wrblock + blk->wrbufblocks - 1)
+
+#ifdef CONFIG_BLOCK_WRITE
+static int writebuffer_flush(struct block_device *blk)
+{
+ if (!blk->wrbufblocks)
+ return 0;
+
+ blk->ops->write(blk, blk->wrbuf, blk->wrblock,
+ blk->wrbufblocks);
+
+ blk->wrbufblocks = 0;
+
+ return 0;
+}
+
+static int block_put(struct block_device *blk, const void *buf, int block)
+{
+ if (block >= blk->num_blocks)
+ return -EIO;
+
+ if (block < blk->wrblock || block > blk->wrblock + blk->wrbufblocks) {
+ writebuffer_flush(blk);
+ }
+
+ if (blk->wrbufblocks == 0) {
+ blk->wrblock = block;
+ blk->wrbufblocks = 1;
+ }
+
+ memcpy(blk->wrbuf + (block - blk->wrblock) * BLOCKSIZE(blk),
+ buf, BLOCKSIZE(blk));
+
+ if (block > WRBUFFER_LAST(blk))
+ blk->wrbufblocks++;
+
+ if (blk->wrbufblocks == blk->wrbufsize)
+ writebuffer_flush(blk);
+
+ return 0;
+}
+
+#else
+static int writebuffer_flush(struct block_device *blk)
+{
+ return 0;
+}
+#endif
+
+static void *block_get(struct block_device *blk, int block)
+{
+ int ret;
+ int num_blocks;
+
+ if (block >= blk->num_blocks)
+ return ERR_PTR(-EIO);
+
+ /* first look into write buffer */
+ if (block >= blk->wrblock && block <= WRBUFFER_LAST(blk))
+ return blk->wrbuf + (block - blk->wrblock) * BLOCKSIZE(blk);
+
+ /* then look into read buffer */
+ if (block >= blk->rdblock && block <= blk->rdblockend)
+ return blk->rdbuf + (block - blk->rdblock) * BLOCKSIZE(blk);
+
+ /*
+ * If none of the buffers above match read the block from
+ * the device
+ */
+ num_blocks = min(blk->rdbufsize, blk->num_blocks - block);
+
+ ret = blk->ops->read(blk, blk->rdbuf, block, num_blocks);
+ if (ret)
+ return ERR_PTR(ret);
+
+ blk->rdblock = block;
+ blk->rdblockend = block + num_blocks - 1;
+
+ return blk->rdbuf;
+}
+
+static ssize_t block_read(struct cdev *cdev, void *buf, size_t count,
+ unsigned long offset, unsigned long flags)
+{
+ struct block_device *blk = cdev->priv;
+ unsigned long mask = BLOCKSIZE(blk) - 1;
+ unsigned long block = offset >> blk->blockbits;
+ size_t icount = count;
+ int blocks;
+
+ if (offset & mask) {
+ size_t now = BLOCKSIZE(blk) - (offset & mask);
+ void *iobuf = block_get(blk, block);
+
+ now = min(count, now);
+
+ if (IS_ERR(iobuf))
+ return PTR_ERR(iobuf);
+
+ memcpy(buf, iobuf + (offset & mask), now);
+ buf += now;
+ count -= now;
+ block++;
+ }
+
+ blocks = count >> blk->blockbits;
+
+ while (blocks) {
+ void *iobuf = block_get(blk, block);
+
+ if (IS_ERR(iobuf))
+ return PTR_ERR(iobuf);
+
+ memcpy(buf, iobuf, BLOCKSIZE(blk));
+ buf += BLOCKSIZE(blk);
+ blocks--;
+ block++;
+ count -= BLOCKSIZE(blk);
+ }
+
+ if (count) {
+ void *iobuf = block_get(blk, block);
+
+ if (IS_ERR(iobuf))
+ return PTR_ERR(iobuf);
+
+ memcpy(buf, iobuf, count);
+ }
+
+ return icount;
+}
+
+#ifdef CONFIG_BLOCK_WRITE
+static ssize_t block_write(struct cdev *cdev, const void *buf, size_t count,
+ unsigned long offset, ulong flags)
+{
+ struct block_device *blk = cdev->priv;
+ unsigned long mask = BLOCKSIZE(blk) - 1;
+ unsigned long block = offset >> blk->blockbits;
+ size_t icount = count;
+ int blocks;
+
+ if (offset & mask) {
+ size_t now = BLOCKSIZE(blk) - (offset & mask);
+ void *iobuf = block_get(blk, block);
+
+ now = min(count, now);
+
+ if (IS_ERR(iobuf))
+ return PTR_ERR(iobuf);
+
+ memcpy(iobuf + (offset & mask), buf, now);
+ block_put(blk, iobuf, block);
+ buf += now;
+ count -= now;
+ block++;
+ }
+
+ blocks = count >> blk->blockbits;
+
+ while (blocks) {
+ block_put(blk, buf, block);
+ buf += BLOCKSIZE(blk);
+ blocks--;
+ block++;
+ count -= BLOCKSIZE(blk);
+ }
+
+ if (count) {
+ void *iobuf = block_get(blk, block);
+
+ if (IS_ERR(iobuf))
+ return PTR_ERR(iobuf);
+
+ memcpy(iobuf, buf, count);
+ block_put(blk, iobuf, block);
+ }
+
+ return icount;
+}
+#endif
+
+static int block_close(struct cdev *cdev)
+{
+ struct block_device *blk = cdev->priv;
+
+ return writebuffer_flush(blk);
+}
+
+static int block_flush(struct cdev *cdev)
+{
+ struct block_device *blk = cdev->priv;
+
+ return writebuffer_flush(blk);
+}
+
+struct file_operations block_ops = {
+ .read = block_read,
+#ifdef CONFIG_BLOCK_WRITE
+ .write = block_write,
+#endif
+ .close = block_close,
+ .flush = block_flush,
+ .lseek = dev_lseek_default,
+};
+
+int blockdevice_register(struct block_device *blk)
+{
+ size_t size = blk->num_blocks * BLOCKSIZE(blk);
+ int ret;
+
+ blk->cdev.size = size;
+ blk->cdev.dev = blk->dev;
+ blk->cdev.ops = &block_ops;
+ blk->cdev.priv = blk;
+ blk->rdbufsize = PAGE_SIZE >> blk->blockbits;
+ blk->rdbuf = xmalloc(PAGE_SIZE);
+ blk->rdblock = 1;
+ blk->rdblockend = 0;
+ blk->wrbufsize = PAGE_SIZE >> blk->blockbits;
+ blk->wrbuf = xmalloc(PAGE_SIZE);
+ blk->wrblock = 0;
+ blk->wrbufblocks = 0;
+
+ ret = devfs_create(&blk->cdev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int blockdevice_unregister(struct block_device *blk)
+{
+ return 0;
+}
+
diff --git a/common/command.c b/common/command.c
index f1aeeb9d..ab02ed53 100644
--- a/common/command.c
+++ b/common/command.c
@@ -33,12 +33,8 @@
#include <linux/list.h>
#include <init.h>
#include <complete.h>
-#include <generated/utsrelease.h>
#include <getopt.h>
-const char version_string[] =
- "barebox " UTS_RELEASE " (" __DATE__ " - " __TIME__ ")";
-
LIST_HEAD(command_list);
EXPORT_SYMBOL(command_list);
diff --git a/common/console.c b/common/console.c
index 5548a409..d33a249c 100644
--- a/common/console.c
+++ b/common/console.c
@@ -45,12 +45,6 @@ EXPORT_SYMBOL(console_list);
#define CONSOLE_INIT_EARLY 1
#define CONSOLE_INIT_FULL 2
-static void display_banner (void)
-{
- printf (RELOC("\n\n%s\n\n"), RELOC_VAR(version_string));
- printf(RELOC("Board: " CONFIG_BOARDINFO "\n"));
-}
-
static int __early_initdata initialized = 0;
static int console_std_set(struct device_d *dev, struct param_d *param,
@@ -169,7 +163,7 @@ int console_register(struct console_device *newcdev)
#ifndef CONFIG_HAS_EARLY_INIT
if (first)
- display_banner();
+ barebox_banner();
#endif
return 0;
@@ -420,7 +414,7 @@ void early_console_start(const char *name, int baudrate)
early_console_init(base, baudrate);
INITDATA(initialized) = CONSOLE_INIT_EARLY;
INITDATA(early_console_base) = base;
- display_banner();
+ barebox_banner();
}
}
diff --git a/common/console_simple.c b/common/console_simple.c
index 1b58deaf..7304d8ee 100644
--- a/common/console_simple.c
+++ b/common/console_simple.c
@@ -152,6 +152,8 @@ int console_register(struct console_device *newcdev)
console = newcdev;
console_list.prev = console_list.next = &newcdev->list;
newcdev->list.prev = newcdev->list.next = &console_list;
+
+ barebox_banner();
}
return 0;
}
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index ff63fbec..f9e1828c 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -882,56 +882,6 @@ static mbinptr av_[NAV * 2 + 2] = {
/* ----------------------------------------------------------------------- */
-/*
- * Begin and End of memory area for malloc(), and current "brk"
- */
-static ulong malloc_start;
-static ulong malloc_end;
-static ulong malloc_brk;
-
-ulong mem_malloc_start(void)
-{
- return malloc_start;
-}
-
-ulong mem_malloc_end(void)
-{
- return malloc_end;
-}
-
-void mem_malloc_init(void *start, void *end)
-{
- malloc_start = (ulong)start;
- malloc_end = (ulong)end;
- malloc_brk = malloc_start;
-}
-
-static void *sbrk_no_zero(ptrdiff_t increment)
-{
- ulong old = malloc_brk;
- ulong new = old + increment;
-
- if ((new < malloc_start) || (new > malloc_end))
- return NULL;
-
- malloc_brk = new;
-
- return (void *)old;
-}
-
-static void *sbrk(ptrdiff_t increment)
-{
- void *old = sbrk_no_zero(increment);
-
- /* Only clear increment, if valid address was returned */
- if (old != NULL)
- memset(old, 0, increment);
-
- return old;
-}
-
-/* ----------------------------------------------------------------------- */
-
/* Other static bookkeeping data */
/* variables holding tunable values */
diff --git a/common/dummy_malloc.c b/common/dummy_malloc.c
new file mode 100644
index 00000000..213e51d8
--- /dev/null
+++ b/common/dummy_malloc.c
@@ -0,0 +1,26 @@
+#include <common.h>
+#include <malloc.h>
+
+void *memalign(size_t alignment, size_t bytes)
+{
+ unsigned long mem = (unsigned long)sbrk(bytes + alignment);
+
+ mem = (mem + alignment) & ~(alignment - 1);
+
+ return (void *)mem;
+}
+
+void *malloc(size_t size)
+{
+ return memalign(8, size);
+}
+
+void free(void *ptr)
+{
+}
+
+void *realloc(void *ptr, size_t size)
+{
+ BUG();
+}
+
diff --git a/common/environment.c b/common/environment.c
index e5f24ec2..0fdbd03e 100644
--- a/common/environment.c
+++ b/common/environment.c
@@ -44,6 +44,8 @@
#define EXPORT_SYMBOL(x)
#endif
+char *default_environment_path = "/dev/env0";
+
int file_size_action(const char *filename, struct stat *statbuf,
void *userdata, int depth)
{
diff --git a/common/hush.c b/common/hush.c
index 77610bba..573bd3ef 100644
--- a/common/hush.c
+++ b/common/hush.c
@@ -121,6 +121,7 @@
#include <libbb.h>
#include <glob.h>
#include <getopt.h>
+#include <libbb.h>
#include <linux/list.h>
/*cmd_boot.c*/
@@ -361,20 +362,6 @@ static int b_addqchr(o_string *o, int ch, int quote)
return b_addchr(o, ch);
}
-/* belongs in utility.c */
-static char *simple_itoa(unsigned int i)
-{
- /* 21 digits plus null terminator, good for 64-bit or smaller ints */
- static char local[22];
- char *p = &local[21];
- *p-- = '\0';
- do {
- *p-- = '0' + i % 10;
- i /= 10;
- } while (i > 0);
- return p + 1;
-}
-
static int b_adduint(o_string *o, unsigned int i)
{
int r;
diff --git a/common/memory.c b/common/memory.c
new file mode 100644
index 00000000..8f4a7681
--- /dev/null
+++ b/common/memory.c
@@ -0,0 +1,71 @@
+/*
+ * memory.c
+ *
+ * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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>
+
+/*
+ * Begin and End of memory area for malloc(), and current "brk"
+ */
+static unsigned long malloc_start;
+static unsigned long malloc_end;
+static unsigned long malloc_brk;
+
+unsigned long mem_malloc_start(void)
+{
+ return malloc_start;
+}
+
+unsigned long mem_malloc_end(void)
+{
+ return malloc_end;
+}
+
+void mem_malloc_init(void *start, void *end)
+{
+ malloc_start = (unsigned long)start;
+ malloc_end = (unsigned long)end;
+ malloc_brk = malloc_start;
+}
+
+static void *sbrk_no_zero(ptrdiff_t increment)
+{
+ unsigned long old = malloc_brk;
+ unsigned long new = old + increment;
+
+ if ((new < malloc_start) || (new > malloc_end))
+ return NULL;
+
+ malloc_brk = new;
+
+ return (void *)old;
+}
+
+void *sbrk(ptrdiff_t increment)
+{
+ void *old = sbrk_no_zero(increment);
+
+ /* Only clear increment, if valid address was returned */
+ if (old != NULL)
+ memset(old, 0, increment);
+
+ return old;
+}
diff --git a/common/startup.c b/common/startup.c
index aa76cb75..00bc9a00 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -103,6 +103,7 @@ static int register_default_env(void)
device_initcall(register_default_env);
#endif
+#if defined CONFIG_FS_RAMFS && defined CONFIG_FS_DEVFS
static int mount_root(void)
{
mount("none", "ramfs", "/");
@@ -111,12 +112,15 @@ static int mount_root(void)
return 0;
}
fs_initcall(mount_root);
+#endif
void start_barebox (void)
{
initcall_t *initcall;
int result;
+#ifdef CONFIG_COMMAND_SUPPORT
struct stat s;
+#endif
#ifdef CONFIG_HAS_EARLY_INIT
/* We are running from RAM now, copy early initdata from
@@ -140,14 +144,16 @@ void start_barebox (void)
display_meminfo();
#ifdef CONFIG_ENV_HANDLING
- if (envfs_load("/dev/env0", "/env")) {
+ if (envfs_load(default_environment_path, "/env")) {
#ifdef CONFIG_DEFAULT_ENVIRONMENT
- printf("no valid environment found on /dev/env0. "
- "Using default environment\n");
+ printf("no valid environment found on %s. "
+ "Using default environment\n",
+ default_environment_path);
envfs_load("/dev/defaultenv", "/env");
#endif
}
#endif
+#ifdef CONFIG_COMMAND_SUPPORT
printf("running /env/bin/init...\n");
if (!stat("/env/bin/init", &s)) {
@@ -155,7 +161,7 @@ void start_barebox (void)
} else {
printf("not found\n");
}
-
+#endif
/* main_loop() can return to retry autoboot, if so just run it again. */
for (;;)
run_shell();
diff --git a/common/version.c b/common/version.c
new file mode 100644
index 00000000..945475fc
--- /dev/null
+++ b/common/version.c
@@ -0,0 +1,13 @@
+#include <common.h>
+#include <reloc.h>
+#include <generated/utsrelease.h>
+
+const char version_string[] =
+ "barebox " UTS_RELEASE " (" __DATE__ " - " __TIME__ ")";
+
+void barebox_banner (void)
+{
+ printf (RELOC("\n\n%s\n\n"), RELOC_VAR(version_string));
+ printf(RELOC("Board: " CONFIG_BOARDINFO "\n"));
+}
+
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index b43c975d..d7f4dcbf 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -1,4 +1,5 @@
menuconfig ATA
+ select BLOCK
bool "ATA "
help
Add support for ATA types of drives like harddisks and CDROMs.
@@ -7,6 +8,10 @@ if ATA
comment "drive types"
+config ATA_WRITE
+ select BLOCK_WRITE
+ bool "support writing to ATA drives"
+
config ATA_DISK
bool "disk drives"
help
diff --git a/drivers/ata/disk_drive.c b/drivers/ata/disk_drive.c
index a54429a5..23837691 100644
--- a/drivers/ata/disk_drive.c
+++ b/drivers/ata/disk_drive.c
@@ -36,6 +36,8 @@
#include <string.h>
#include <linux/kernel.h>
#include <malloc.h>
+#include <common.h>
+#include <block.h>
/**
* Description of one partition table entry (D*S type)
@@ -58,6 +60,7 @@ struct partition_entry {
* @param table partition table
* @return size in sectors
*/
+#ifdef CONFIG_ATA_BIOS
static unsigned long disk_guess_size(struct device_d *dev, struct partition_entry *table)
{
int part_order[4] = {0, 1, 2, 3};
@@ -81,6 +84,7 @@ static unsigned long disk_guess_size(struct device_d *dev, struct partition_entr
#endif
return size;
}
+#endif
/**
* Register partitions found on the drive
@@ -121,149 +125,35 @@ static int disk_register_partitions(struct device_d *dev, struct partition_entry
return 0;
}
-/**
- * Write some data to a disk
- * @param cdev the device to write to
- * @param _buf source of data
- * @param count byte count to write
- * @param offset where to write to disk
- * @param flags Ignored
- * @return Written bytes or negative value in case of failure
- */
-static ssize_t disk_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags)
-{
- struct device_d *dev = cdev->dev;
- struct ata_interface *intf = dev->platform_data;
- int rc;
- unsigned sep_count = offset & (SECTOR_SIZE - 1);
- ssize_t written = 0;
-
- /* starting at no sector boundary? */
- if (sep_count != 0) {
- uint8_t tmp_buf[SECTOR_SIZE];
- unsigned to_write = min(SECTOR_SIZE - sep_count, count);
-
- rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf);
- if (rc != 0) {
- dev_err(dev, "Cannot read data\n");
- return -1;
- }
- memcpy(&tmp_buf[sep_count], _buf, to_write);
- rc = intf->write(dev, offset / SECTOR_SIZE, 1, tmp_buf);
- if (rc != 0) {
- dev_err(dev, "Cannot write data\n");
- return -1;
- }
-
- _buf += to_write;
- offset += to_write;
- count -= to_write;
- written += to_write;
- }
-
- /* full sector part */
- sep_count = count / SECTOR_SIZE;
- if (sep_count) {
- rc = intf->write(dev, offset / SECTOR_SIZE, sep_count, _buf);
- if (rc != 0) {
- dev_err(dev, "Cannot write data\n");
- return -1;
- }
- _buf += sep_count * SECTOR_SIZE;
- offset += sep_count * SECTOR_SIZE;
- count -= sep_count * SECTOR_SIZE;
- written += sep_count * SECTOR_SIZE;
- }
-
- /* ending at no sector boundary? */
- if (count) {
- uint8_t tmp_buf[SECTOR_SIZE];
+struct ata_block_device {
+ struct block_device blk;
+ struct device_d *dev;
+ struct ata_interface *intf;
+};
- rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf);
- if (rc != 0) {
- dev_err(dev, "Cannot read data\n");
- return -1;
- }
- memcpy(tmp_buf, _buf, count);
- rc = intf->write(dev, offset / SECTOR_SIZE, 1, tmp_buf);
- if (rc != 0) {
- dev_err(dev, "Cannot write data\n");
- return -1;
- }
- written += count;
- }
+static int atablk_read(struct block_device *blk, void *buf, int block,
+ int num_blocks)
+{
+ struct ata_block_device *atablk = container_of(blk, struct ata_block_device, blk);
- return written;
+ return atablk->intf->read(atablk->dev, block, num_blocks, buf);
}
-/**
- * Read some data from a disk
- * @param cdev the device to read from
- * @param _buf destination of the data
- * @param count byte count to read
- * @param offset where to read from
- * @param flags Ignored
- * @return Read bytes or negative value in case of failure
- */
-static ssize_t disk_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags)
+#ifdef CONFIG_ATA_WRITE
+static int atablk_write(struct block_device *blk, const void *buf, int block,
+ int num_blocks)
{
- struct device_d *dev = cdev->dev;
- struct ata_interface *intf = dev->platform_data;
- int rc;
- unsigned sep_count = offset & (SECTOR_SIZE - 1);
- ssize_t read = 0;
-
- /* starting at no sector boundary? */
- if (sep_count != 0) {
- uint8_t tmp_buf[SECTOR_SIZE];
- unsigned to_read = min(SECTOR_SIZE - sep_count, count);
+ struct ata_block_device *atablk = container_of(blk, struct ata_block_device, blk);
- rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf);
- if (rc != 0) {
- dev_err(dev, "Cannot read data\n");
- return -1;
- }
- memcpy(_buf, &tmp_buf[sep_count], to_read);
- _buf += to_read;
- offset += to_read;
- count -= to_read;
- read += to_read;
- }
-
- /* full sector part */
- sep_count = count / SECTOR_SIZE;
- if (sep_count) {
- rc = intf->read(dev, offset / SECTOR_SIZE, sep_count, _buf);
- if (rc != 0) {
- dev_err(dev, "Cannot read data\n");
- return -1;
- }
- _buf += sep_count * SECTOR_SIZE;
- offset += sep_count * SECTOR_SIZE;
- count -= sep_count * SECTOR_SIZE;
- read += sep_count * SECTOR_SIZE;
- }
-
- /* ending at no sector boundary? */
- if (count) {
- uint8_t tmp_buf[SECTOR_SIZE];
-
- rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf);
- if (rc != 0) {
- dev_err(dev, "Cannot read data\n");
- return -1;
- }
- memcpy(_buf, tmp_buf, count);
- read += count;
- }
-
- return read;
+ return atablk->intf->write(atablk->dev, block, num_blocks, buf);
}
+#endif
-static struct file_operations disk_ops = {
- .read = disk_read,
- .write = disk_write,
- .lseek = dev_lseek_default,
+static struct block_device_ops ataops = {
+ .read = atablk_read,
+#ifdef CONFIG_ATA_WRITE
+ .write = atablk_write,
+#endif
};
/**
@@ -274,7 +164,7 @@ static int disk_probe(struct device_d *dev)
uint8_t *sector;
int rc;
struct ata_interface *intf = dev->platform_data;
- struct cdev *disk_cdev;
+ struct ata_block_device *atablk = xzalloc(sizeof(*atablk));
sector = xmalloc(SECTOR_SIZE);
@@ -285,9 +175,6 @@ static int disk_probe(struct device_d *dev)
goto on_error;
}
- /* It seems a valuable disk. Register it */
- disk_cdev = xzalloc(sizeof(struct cdev));
-
/*
* BIOS based disks needs special handling. Not the driver can
* enumerate the hardware, the BIOS did it already. To show the user
@@ -296,23 +183,26 @@ static int disk_probe(struct device_d *dev)
*/
#ifdef CONFIG_ATA_BIOS
if (strcmp(dev->driver->name, "biosdisk") == 0)
- disk_cdev->name = asprintf("biosdisk%d", dev->id);
+ atablk->blk.cdev.name = asprintf("biosdisk%d", dev->id);
else
#endif
- disk_cdev->name = asprintf("disk%d", dev->id);
+ atablk->blk.cdev.name = asprintf("disk%d", dev->id);
+#ifdef CONFIG_ATA_BIOS
/* On x86, BIOS based disks are coming without a valid .size field */
if (dev->size == 0) {
- /*
- * We need always the size of the drive, else its nearly impossible
- * to do anything with it (at least with the generic routines)
- */
- disk_cdev->size = 32;
- } else
- disk_cdev->size = dev->size;
- disk_cdev->ops = &disk_ops;
- disk_cdev->dev = dev;
- devfs_create(disk_cdev);
+ /* guess the size of this drive if not otherwise given */
+ dev->size = disk_guess_size(dev,
+ (struct partition_entry*)&sector[446]) * SECTOR_SIZE;
+ dev_info(dev, "Drive size guessed to %u kiB\n", dev->size / 1024);
+ }
+#endif
+ atablk->blk.num_blocks = dev->size / SECTOR_SIZE;
+ atablk->blk.ops = &ataops;
+ atablk->blk.blockbits = 9;
+ atablk->dev = dev;
+ atablk->intf = intf;
+ blockdevice_register(&atablk->blk);
if ((sector[510] != 0x55) || (sector[511] != 0xAA)) {
dev_info(dev, "No partition table found\n");
@@ -320,13 +210,6 @@ static int disk_probe(struct device_d *dev)
goto on_error;
}
- if (dev->size == 0) {
- /* guess the size of this drive if not otherwise given */
- dev->size = disk_guess_size(dev,
- (struct partition_entry*)&sector[446]) * SECTOR_SIZE;
- dev_info(dev, "Drive size guessed to %u kiB\n", dev->size / 1024);
- disk_cdev->size = dev->size;
- }
rc = disk_register_partitions(dev, (struct partition_entry*)&sector[446]);
diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig
index b11f2670..5d8adbdf 100644
--- a/drivers/mci/Kconfig
+++ b/drivers/mci/Kconfig
@@ -25,6 +25,11 @@ config MCI_INFO
This entry adds more info about the attached MCI card, when the
'devinfo' command is used on the mci device.
+config MCI_WRITE
+ bool "Support writing to MCI cards"
+ default y
+ select ATA_WRITE
+
comment "--- MCI host drivers ---"
config MCI_MXS
@@ -61,4 +66,11 @@ config MCI_IMX_ESDHC_PIO
help
mostly useful for debugging. Normally you should use DMA.
+config MCI_OMAP_HSMMC
+ bool "OMAP HSMMC"
+ depends on ARCH_OMAP4 || ARCH_OMAP3
+ help
+ Enable this entry to add support to read and write SD cards on a
+ OMAP4 based system.
+
endif
diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile
index f175bbac..2bb9a93b 100644
--- a/drivers/mci/Makefile
+++ b/drivers/mci/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_MCI_MXS) += mxs.o
obj-$(CONFIG_MCI_S3C) += s3c.o
obj-$(CONFIG_MCI_IMX) += imx.o
obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o
+obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o
diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index f3d975d6..a06c997e 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -106,6 +106,7 @@ static void *sector_buf;
* @param blocknum Block number to write
* @return Transaction status (0 on success)
*/
+#ifdef CONFIG_MCI_WRITE
static int mci_block_write(struct device_d *mci_dev, const void *src, unsigned blocknum)
{
struct mci *mci = GET_MCI_DATA(mci_dev);
@@ -132,6 +133,7 @@ static int mci_block_write(struct device_d *mci_dev, const void *src, unsigned b
return mci_send_cmd(mci_dev, &cmd, &data);
}
+#endif
/**
* Read one block of data from the card
@@ -597,6 +599,7 @@ static void mci_detect_version_from_csd(struct device_d *mci_dev)
{
struct mci *mci = GET_MCI_DATA(mci_dev);
int version;
+ char *vstr;
if (mci->version == MMC_VERSION_UNKNOWN) {
/* the version is coded in the bits 127:126 (left aligned) */
@@ -604,30 +607,31 @@ static void mci_detect_version_from_csd(struct device_d *mci_dev)
switch (version) {
case 0:
- printf("Detecting a 1.2 revision card\n");
+ vstr = "1.2";
mci->version = MMC_VERSION_1_2;
break;
case 1:
- printf("Detecting a 1.4 revision card\n");
+ vstr = "1.4";
mci->version = MMC_VERSION_1_4;
break;
case 2:
- printf("Detecting a 2.2 revision card\n");
+ vstr = "2.2";
mci->version = MMC_VERSION_2_2;
break;
case 3:
- printf("Detecting a 3.0 revision card\n");
+ vstr = "3.0";
mci->version = MMC_VERSION_3;
break;
case 4:
- printf("Detecting a 4.0 revision card\n");
+ vstr = "4.0";
mci->version = MMC_VERSION_4;
break;
default:
- printf("Unknow revision. Falling back to a 1.2 revision card\n");
+ vstr = "unknown, fallback to 1.2";
mci->version = MMC_VERSION_1_2;
break;
}
+ printf("detected card version %s\n", vstr);
}
}
@@ -680,7 +684,7 @@ static void mci_extract_max_tran_speed_from_csd(struct device_d *mci_dev)
unit = tran_speed_unit[(mci->csd[0] & 0x7)];
time = tran_speed_time[((mci->csd[0] >> 3) & 0xf)];
if ((unit == 0) || (time == 0)) {
- pr_warning("Unsupported 'TRAN_SPEED' unit/time value."
+ pr_debug("Unsupported 'TRAN_SPEED' unit/time value."
" Can't calculate card's max. transfer speed\n");
return;
}
@@ -798,13 +802,13 @@ static int mci_startup(struct device_d *mci_dev)
/* sanitiy? */
if (mci->read_bl_len > 512) {
mci->read_bl_len = 512;
- pr_warning("Limiting max. read block size down to %u\n",
+ pr_debug("Limiting max. read block size down to %u\n",
mci->read_bl_len);
}
if (mci->write_bl_len > 512) {
mci->write_bl_len = 512;
- pr_warning("Limiting max. write block size down to %u\n",
+ pr_debug("Limiting max. write block size down to %u\n",
mci->read_bl_len);
}
pr_debug("Read block length: %u, Write block length: %u\n",
@@ -944,6 +948,7 @@ static int sd_send_if_cond(struct device_d *mci_dev)
*
* This routine expects the buffer has the correct size to read all data!
*/
+#ifdef CONFIG_MCI_WRITE
static int mci_sd_write(struct device_d *disk_dev, uint64_t sector_start,
unsigned sector_count, const void *buffer)
{
@@ -952,11 +957,11 @@ static int mci_sd_write(struct device_d *disk_dev, uint64_t sector_start,
struct mci *mci = GET_MCI_DATA(mci_dev);
int rc;
- pr_debug("%s called: Write %u block(s), starting at %lu",
- __func__, sector_count, (unsigned)sector_count);
+ pr_debug("%s: Write %u block(s), starting at %u",
+ __func__, sector_count, (unsigned)sector_start);
if (mci->write_bl_len != 512) {
- pr_warning("MMC/SD block size is not 512 bytes (its %u bytes instead)\n",
+ pr_debug("MMC/SD block size is not 512 bytes (its %u bytes instead)\n",
mci->read_bl_len);
return -EINVAL;
}
@@ -964,13 +969,13 @@ static int mci_sd_write(struct device_d *disk_dev, uint64_t sector_start,
while (sector_count) {
/* size of the block number field in the MMC/SD command is 32 bit only */
if (sector_start > MAX_BUFFER_NUMBER) {
- pr_err("Cannot handle block number %llu. Too large!\n",
+ pr_debug("Cannot handle block number %llu. Too large!\n",
sector_start);
return -EINVAL;
}
rc = mci_block_write(mci_dev, buffer, sector_start);
if (rc != 0) {
- pr_err("Writing block %u failed with %d\n", (unsigned)sector_start, rc);
+ pr_debug("Writing block %u failed with %d\n", (unsigned)sector_start, rc);
return rc;
}
sector_count--;
@@ -980,6 +985,7 @@ static int mci_sd_write(struct device_d *disk_dev, uint64_t sector_start,
return 0;
}
+#endif
/**
* Read a chunk of sectors from media
@@ -999,11 +1005,11 @@ static int mci_sd_read(struct device_d *disk_dev, uint64_t sector_start,
struct mci *mci = GET_MCI_DATA(mci_dev);
int rc;
- pr_debug("%s called: Read %u block(s), starting at %lu to %08X\n",
- __func__, sector_count, (unsigned)sector_start, buffer);
+ pr_debug("%s: Read %u block(s), starting at %u\n",
+ __func__, sector_count, (unsigned)sector_start);
if (mci->read_bl_len != 512) {
- pr_warning("MMC/SD block size is not 512 bytes (its %u bytes instead)\n",
+ pr_debug("MMC/SD block size is not 512 bytes (its %u bytes instead)\n",
mci->read_bl_len);
return -EINVAL;
}
@@ -1017,7 +1023,7 @@ static int mci_sd_read(struct device_d *disk_dev, uint64_t sector_start,
}
rc = mci_read_block(mci_dev, buffer, (unsigned)sector_start, now);
if (rc != 0) {
- pr_err("Reading block %u failed with %d\n", (unsigned)sector_start, rc);
+ pr_debug("Reading block %u failed with %d\n", (unsigned)sector_start, rc);
return rc;
}
sector_count -= now;
@@ -1186,7 +1192,7 @@ static int mci_card_probe(struct device_d *mci_dev)
/* reset the card */
rc = mci_go_idle(mci_dev);
if (rc) {
- pr_warning("Cannot reset the SD/MMC card\n");
+ pr_warn("Cannot reset the SD/MMC card\n");
goto on_error;
}
@@ -1204,7 +1210,7 @@ static int mci_card_probe(struct device_d *mci_dev)
rc = mci_startup(mci_dev);
if (rc) {
- printf("Card's startup fails with %d\n", rc);
+ pr_debug("Card's startup fails with %d\n", rc);
goto on_error;
}
@@ -1218,7 +1224,9 @@ static int mci_card_probe(struct device_d *mci_dev)
disk_dev = xzalloc(sizeof(struct device_d) + sizeof(struct ata_interface));
p = (struct ata_interface*)&disk_dev[1];
+#ifdef CONFIG_MCI_WRITE
p->write = mci_sd_write;
+#endif
p->read = mci_sd_read;
p->priv = mci_dev;
@@ -1313,7 +1321,7 @@ static int mci_probe(struct device_d *mci_dev)
*/
rc = add_mci_parameter(mci_dev);
if (rc != 0) {
- pr_err("Failed to add 'probe' parameter to the MCI device\n");
+ pr_debug("Failed to add 'probe' parameter to the MCI device\n");
goto on_error;
}
}
@@ -1323,7 +1331,7 @@ static int mci_probe(struct device_d *mci_dev)
/* add params on demand */
rc = add_mci_parameter(mci_dev);
if (rc != 0) {
- pr_err("Failed to add 'probe' parameter to the MCI device\n");
+ pr_debug("Failed to add 'probe' parameter to the MCI device\n");
goto on_error;
}
#endif
@@ -1338,7 +1346,9 @@ on_error:
static struct driver_d mci_driver = {
.name = "mci",
.probe = mci_probe,
+#ifdef CONFIG_MCI_INFO
.info = mci_info,
+#endif
};
static int mci_init(void)
diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c
new file mode 100644
index 00000000..07992978
--- /dev/null
+++ b/drivers/mci/omap_hsmmc.c
@@ -0,0 +1,585 @@
+/*
+ * (C) Copyright 2008
+ * Texas Instruments, <www.ti.com>
+ * Sukumar Ghorai <s-ghorai@ti.com>
+ *
+ * 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's version 2 of
+ * the License.
+ *
+ * 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
+ */
+/* #define DEBUG */
+#include <config.h>
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <mci.h>
+#include <clock.h>
+#include <errno.h>
+#include <asm/io.h>
+
+struct hsmmc {
+ unsigned char res1[0x10];
+ unsigned int sysconfig; /* 0x10 */
+ unsigned int sysstatus; /* 0x14 */
+ unsigned char res2[0x14];
+ unsigned int con; /* 0x2C */
+ unsigned char res3[0xD4];
+ unsigned int blk; /* 0x104 */
+ unsigned int arg; /* 0x108 */
+ unsigned int cmd; /* 0x10C */
+ unsigned int rsp10; /* 0x110 */
+ unsigned int rsp32; /* 0x114 */
+ unsigned int rsp54; /* 0x118 */
+ unsigned int rsp76; /* 0x11C */
+ unsigned int data; /* 0x120 */
+ unsigned int pstate; /* 0x124 */
+ unsigned int hctl; /* 0x128 */
+ unsigned int sysctl; /* 0x12C */
+ unsigned int stat; /* 0x130 */
+ unsigned int ie; /* 0x134 */
+ unsigned char res4[0x8];
+ unsigned int capa; /* 0x140 */
+};
+
+/*
+ * OMAP HS MMC Bit definitions
+ */
+#define MMC_SOFTRESET (0x1 << 1)
+#define RESETDONE (0x1 << 0)
+#define NOOPENDRAIN (0x0 << 0)
+#define OPENDRAIN (0x1 << 0)
+#define OD (0x1 << 0)
+#define INIT_NOINIT (0x0 << 1)
+#define INIT_INITSTREAM (0x1 << 1)
+#define HR_NOHOSTRESP (0x0 << 2)
+#define STR_BLOCK (0x0 << 3)
+#define MODE_FUNC (0x0 << 4)
+#define DW8_1_4BITMODE (0x0 << 5)
+#define MIT_CTO (0x0 << 6)
+#define CDP_ACTIVEHIGH (0x0 << 7)
+#define WPP_ACTIVEHIGH (0x0 << 8)
+#define RESERVED_MASK (0x3 << 9)
+#define CTPL_MMC_SD (0x0 << 11)
+#define BLEN_512BYTESLEN (0x200 << 0)
+#define NBLK_STPCNT (0x0 << 16)
+#define DE_DISABLE (0x0 << 0)
+#define BCE_DISABLE (0x0 << 1)
+#define BCE_ENABLE (0x1 << 1)
+#define ACEN_DISABLE (0x0 << 2)
+#define DDIR_OFFSET (4)
+#define DDIR_MASK (0x1 << 4)
+#define DDIR_WRITE (0x0 << 4)
+#define DDIR_READ (0x1 << 4)
+#define MSBS_SGLEBLK (0x0 << 5)
+#define MSBS_MULTIBLK (0x1 << 5)
+#define RSP_TYPE_OFFSET (16)
+#define RSP_TYPE_MASK (0x3 << 16)
+#define RSP_TYPE_NORSP (0x0 << 16)
+#define RSP_TYPE_LGHT136 (0x1 << 16)
+#define RSP_TYPE_LGHT48 (0x2 << 16)
+#define RSP_TYPE_LGHT48B (0x3 << 16)
+#define CCCE_NOCHECK (0x0 << 19)
+#define CCCE_CHECK (0x1 << 19)
+#define CICE_NOCHECK (0x0 << 20)
+#define CICE_CHECK (0x1 << 20)
+#define DP_OFFSET (21)
+#define DP_MASK (0x1 << 21)
+#define DP_NO_DATA (0x0 << 21)
+#define DP_DATA (0x1 << 21)
+#define CMD_TYPE_NORMAL (0x0 << 22)
+#define INDEX_OFFSET (24)
+#define INDEX_MASK (0x3f << 24)
+#define INDEX(i) (i << 24)
+#define DATI_MASK (0x1 << 1)
+#define DATI_CMDDIS (0x1 << 1)
+#define DTW_1_BITMODE (0x0 << 1)
+#define DTW_4_BITMODE (0x1 << 1)
+#define DTW_8_BITMODE (0x1 << 5) /* CON[DW8]*/
+#define SDBP_PWROFF (0x0 << 8)
+#define SDBP_PWRON (0x1 << 8)
+#define SDVS_1V8 (0x5 << 9)
+#define SDVS_3V0 (0x6 << 9)
+#define ICE_MASK (0x1 << 0)
+#define ICE_STOP (0x0 << 0)
+#define ICS_MASK (0x1 << 1)
+#define ICS_NOTREADY (0x0 << 1)
+#define ICE_OSCILLATE (0x1 << 0)
+#define CEN_MASK (0x1 << 2)
+#define CEN_DISABLE (0x0 << 2)
+#define CEN_ENABLE (0x1 << 2)
+#define CLKD_OFFSET (6)
+#define CLKD_MASK (0x3FF << 6)
+#define DTO_MASK (0xF << 16)
+#define DTO_15THDTO (0xE << 16)
+#define SOFTRESETALL (0x1 << 24)
+#define CC_MASK (0x1 << 0)
+#define TC_MASK (0x1 << 1)
+#define BWR_MASK (0x1 << 4)
+#define BRR_MASK (0x1 << 5)
+#define ERRI_MASK (0x1 << 15)
+#define IE_CC (0x01 << 0)
+#define IE_TC (0x01 << 1)
+#define IE_BWR (0x01 << 4)
+#define IE_BRR (0x01 << 5)
+#define IE_CTO (0x01 << 16)
+#define IE_CCRC (0x01 << 17)
+#define IE_CEB (0x01 << 18)
+#define IE_CIE (0x01 << 19)
+#define IE_DTO (0x01 << 20)
+#define IE_DCRC (0x01 << 21)
+#define IE_DEB (0x01 << 22)
+#define IE_CERR (0x01 << 28)
+#define IE_BADA (0x01 << 29)
+
+#define VS30_3V0SUP (1 << 25)
+#define VS18_1V8SUP (1 << 26)
+
+/* Driver definitions */
+#define MMCSD_SECTOR_SIZE 512
+#define MMC_CARD 0
+#define SD_CARD 1
+#define BYTE_MODE 0
+#define SECTOR_MODE 1
+#define CLK_INITSEQ 0
+#define CLK_400KHZ 1
+#define CLK_MISC 2
+
+#define RSP_TYPE_NONE (RSP_TYPE_NORSP | CCCE_NOCHECK | CICE_NOCHECK)
+#define MMC_CMD0 (INDEX(0) | RSP_TYPE_NONE | DP_NO_DATA | DDIR_WRITE)
+
+/* Clock Configurations and Macros */
+#define MMC_CLOCK_REFERENCE 96 /* MHz */
+
+#define mmc_reg_out(addr, mask, val)\
+ writel((readl(addr) & (~(mask))) | ((val) & (mask)), (addr))
+
+struct omap_hsmmc {
+ struct mci_host mci;
+ struct device_d *dev;
+ struct hsmmc *base;
+};
+
+#define to_hsmmc(mci) container_of(mci, struct omap_hsmmc, mci)
+
+static int mmc_init_stream(struct omap_hsmmc *hsmmc)
+{
+ uint64_t start;
+ struct hsmmc *mmc_base = hsmmc->base;
+
+ writel(readl(&mmc_base->con) | INIT_INITSTREAM, &mmc_base->con);
+
+ writel(MMC_CMD0, &mmc_base->cmd);
+ start = get_time_ns();
+ while (!(readl(&mmc_base->stat) & CC_MASK)) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for cc!\n");
+ return -ETIMEDOUT;
+ }
+ }
+ writel(CC_MASK, &mmc_base->stat);
+ writel(MMC_CMD0, &mmc_base->cmd);
+
+ start = get_time_ns();
+ while (!(readl(&mmc_base->stat) & CC_MASK)) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for cc2!\n");
+ return -ETIMEDOUT;
+ }
+ }
+ writel(readl(&mmc_base->con) & ~INIT_INITSTREAM, &mmc_base->con);
+
+ return 0;
+}
+
+static int mmc_init_setup(struct mci_host *mci, struct device_d *dev)
+{
+ struct omap_hsmmc *hsmmc = to_hsmmc(mci);
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int reg_val;
+ unsigned int dsor;
+ uint64_t start;
+
+ writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET,
+ &mmc_base->sysconfig);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysstatus) & RESETDONE) == 0) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for cc2!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(readl(&mmc_base->sysctl) | SOFTRESETALL, &mmc_base->sysctl);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysctl) & SOFTRESETALL) != 0x0) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for softresetall!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(DTW_1_BITMODE | SDBP_PWROFF | SDVS_3V0, &mmc_base->hctl);
+ writel(readl(&mmc_base->capa) | VS30_3V0SUP | VS18_1V8SUP,
+ &mmc_base->capa);
+
+ reg_val = readl(&mmc_base->con) & RESERVED_MASK;
+
+ writel(CTPL_MMC_SD | reg_val | WPP_ACTIVEHIGH | CDP_ACTIVEHIGH |
+ MIT_CTO | DW8_1_4BITMODE | MODE_FUNC | STR_BLOCK |
+ HR_NOHOSTRESP | INIT_NOINIT | NOOPENDRAIN, &mmc_base->con);
+
+ dsor = 240;
+ mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
+ (ICE_STOP | DTO_15THDTO | CEN_DISABLE));
+ mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+ (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for ics!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+
+ writel(readl(&mmc_base->hctl) | SDBP_PWRON, &mmc_base->hctl);
+
+ writel(IE_BADA | IE_CERR | IE_DEB | IE_DCRC | IE_DTO | IE_CIE |
+ IE_CEB | IE_CCRC | IE_CTO | IE_BRR | IE_BWR | IE_TC | IE_CC,
+ &mmc_base->ie);
+
+ return mmc_init_stream(hsmmc);
+}
+
+static int mmc_read_data(struct omap_hsmmc *hsmmc, char *buf, unsigned int size)
+{
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int *output_buf = (unsigned int *)buf;
+ unsigned int mmc_stat;
+ unsigned int count;
+
+ /*
+ * Start Polled Read
+ */
+ count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
+ count /= 4;
+
+ while (size) {
+ uint64_t start = get_time_ns();
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for status!\n");
+ return -ETIMEDOUT;
+ }
+ } while (mmc_stat == 0);
+
+ if ((mmc_stat & ERRI_MASK) != 0)
+ return 1;
+
+ if (mmc_stat & BRR_MASK) {
+ unsigned int k;
+
+ writel(readl(&mmc_base->stat) | BRR_MASK,
+ &mmc_base->stat);
+ for (k = 0; k < count; k++) {
+ *output_buf = readl(&mmc_base->data);
+ output_buf++;
+ }
+ size -= (count*4);
+ }
+
+ if (mmc_stat & BWR_MASK)
+ writel(readl(&mmc_base->stat) | BWR_MASK,
+ &mmc_base->stat);
+
+ if (mmc_stat & TC_MASK) {
+ writel(readl(&mmc_base->stat) | TC_MASK,
+ &mmc_base->stat);
+ break;
+ }
+ }
+ return 0;
+}
+
+#ifdef CONFIG_MCI_WRITE
+static int mmc_write_data(struct omap_hsmmc *hsmmc, const char *buf, unsigned int size)
+{
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int *input_buf = (unsigned int *)buf;
+ unsigned int mmc_stat;
+ unsigned int count;
+
+ /*
+ * Start Polled Read
+ */
+ count = (size > MMCSD_SECTOR_SIZE) ? MMCSD_SECTOR_SIZE : size;
+ count /= 4;
+
+ while (size) {
+ uint64_t start = get_time_ns();
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for status!\n");
+ return -ETIMEDOUT;
+ }
+ } while (mmc_stat == 0);
+
+ if ((mmc_stat & ERRI_MASK) != 0)
+ return 1;
+
+ if (mmc_stat & BWR_MASK) {
+ unsigned int k;
+
+ writel(readl(&mmc_base->stat) | BWR_MASK,
+ &mmc_base->stat);
+ for (k = 0; k < count; k++) {
+ writel(*input_buf, &mmc_base->data);
+ input_buf++;
+ }
+ size -= (count * 4);
+ }
+
+ if (mmc_stat & BRR_MASK)
+ writel(readl(&mmc_base->stat) | BRR_MASK,
+ &mmc_base->stat);
+
+ if (mmc_stat & TC_MASK) {
+ writel(readl(&mmc_base->stat) | TC_MASK,
+ &mmc_base->stat);
+ break;
+ }
+ }
+ return 0;
+}
+#endif
+
+static int mmc_send_cmd(struct mci_host *mci, struct mci_cmd *cmd,
+ struct mci_data *data)
+{
+ struct omap_hsmmc *hsmmc = to_hsmmc(mci);
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int flags, mmc_stat;
+ uint64_t start;
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->pstate) & DATI_MASK) == DATI_CMDDIS) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for cmddis!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ writel(0xFFFFFFFF, &mmc_base->stat);
+ start = get_time_ns();
+ while (readl(&mmc_base->stat)) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for stat!\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ /*
+ * CMDREG
+ * CMDIDX[13:8] : Command index
+ * DATAPRNT[5] : Data Present Select
+ * ENCMDIDX[4] : Command Index Check Enable
+ * ENCMDCRC[3] : Command CRC Check Enable
+ * RSPTYP[1:0]
+ * 00 = No Response
+ * 01 = Length 136
+ * 10 = Length 48
+ * 11 = Length 48 Check busy after response
+ */
+ /* Delay added before checking the status of frq change
+ * retry not supported by mmc.c(core file)
+ */
+ if (cmd->cmdidx == SD_CMD_APP_SEND_SCR)
+ udelay(50000); /* wait 50 ms */
+
+ if (!(cmd->resp_type & MMC_RSP_PRESENT))
+ flags = 0;
+ else if (cmd->resp_type & MMC_RSP_136)
+ flags = RSP_TYPE_LGHT136 | CICE_NOCHECK;
+ else if (cmd->resp_type & MMC_RSP_BUSY)
+ flags = RSP_TYPE_LGHT48B;
+ else
+ flags = RSP_TYPE_LGHT48;
+
+ /* enable default flags */
+ flags = flags | (CMD_TYPE_NORMAL | CICE_NOCHECK | CCCE_NOCHECK |
+ MSBS_SGLEBLK | ACEN_DISABLE | BCE_DISABLE | DE_DISABLE);
+
+ if (cmd->resp_type & MMC_RSP_CRC)
+ flags |= CCCE_CHECK;
+ if (cmd->resp_type & MMC_RSP_OPCODE)
+ flags |= CICE_CHECK;
+
+ if (data) {
+ if ((cmd->cmdidx == MMC_CMD_READ_MULTIPLE_BLOCK) ||
+ (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)) {
+ flags |= (MSBS_MULTIBLK | BCE_ENABLE);
+ data->blocksize = 512;
+ writel(data->blocksize | (data->blocks << 16),
+ &mmc_base->blk);
+ } else
+ writel(data->blocksize | NBLK_STPCNT, &mmc_base->blk);
+
+ if (data->flags & MMC_DATA_READ)
+ flags |= (DP_DATA | DDIR_READ);
+ else
+ flags |= (DP_DATA | DDIR_WRITE);
+ }
+
+ writel(cmd->cmdarg, &mmc_base->arg);
+ writel((cmd->cmdidx << 24) | flags, &mmc_base->cmd);
+
+ start = get_time_ns();
+ do {
+ mmc_stat = readl(&mmc_base->stat);
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timeout: No status update\n");
+ return -ETIMEDOUT;
+ }
+ } while (!mmc_stat);
+
+ if ((mmc_stat & IE_CTO) != 0)
+ return -ETIMEDOUT;
+ else if ((mmc_stat & ERRI_MASK) != 0)
+ return -1;
+
+ if (mmc_stat & CC_MASK) {
+ writel(CC_MASK, &mmc_base->stat);
+ if (cmd->resp_type & MMC_RSP_PRESENT) {
+ if (cmd->resp_type & MMC_RSP_136) {
+ /* response type 2 */
+ cmd->response[3] = readl(&mmc_base->rsp10);
+ cmd->response[2] = readl(&mmc_base->rsp32);
+ cmd->response[1] = readl(&mmc_base->rsp54);
+ cmd->response[0] = readl(&mmc_base->rsp76);
+ } else
+ /* response types 1, 1b, 3, 4, 5, 6 */
+ cmd->response[0] = readl(&mmc_base->rsp10);
+ }
+ }
+
+ if (data && (data->flags & MMC_DATA_READ))
+ mmc_read_data(hsmmc, data->dest, data->blocksize * data->blocks);
+#ifdef CONFIG_MCI_WRITE
+ else if (data && (data->flags & MMC_DATA_WRITE))
+ mmc_write_data(hsmmc, data->src, data->blocksize * data->blocks);
+#endif
+ return 0;
+}
+
+static void mmc_set_ios(struct mci_host *mci, struct device_d *dev,
+ unsigned bus_width, unsigned clock)
+{
+ struct omap_hsmmc *hsmmc = to_hsmmc(mci);
+ struct hsmmc *mmc_base = hsmmc->base;
+ unsigned int dsor = 0;
+ uint64_t start;
+
+ /* configue bus width */
+ switch (bus_width) {
+ case 8:
+ writel(readl(&mmc_base->con) | DTW_8_BITMODE,
+ &mmc_base->con);
+ break;
+
+ case 4:
+ writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
+ &mmc_base->con);
+ writel(readl(&mmc_base->hctl) | DTW_4_BITMODE,
+ &mmc_base->hctl);
+ break;
+
+ case 1:
+ default:
+ writel(readl(&mmc_base->con) & ~DTW_8_BITMODE,
+ &mmc_base->con);
+ writel(readl(&mmc_base->hctl) & ~DTW_4_BITMODE,
+ &mmc_base->hctl);
+ break;
+ }
+
+ /* configure clock with 96Mhz system clock.
+ */
+ if (clock != 0) {
+ dsor = (MMC_CLOCK_REFERENCE * 1000000 / clock);
+ if ((MMC_CLOCK_REFERENCE * 1000000) / dsor > clock)
+ dsor++;
+ }
+
+ mmc_reg_out(&mmc_base->sysctl, (ICE_MASK | DTO_MASK | CEN_MASK),
+ (ICE_STOP | DTO_15THDTO | CEN_DISABLE));
+
+ mmc_reg_out(&mmc_base->sysctl, ICE_MASK | CLKD_MASK,
+ (dsor << CLKD_OFFSET) | ICE_OSCILLATE);
+
+ start = get_time_ns();
+ while ((readl(&mmc_base->sysctl) & ICS_MASK) == ICS_NOTREADY) {
+ if (is_timeout(start, SECOND)) {
+ dev_dbg(hsmmc->dev, "timedout waiting for ics!\n");
+ return;
+ }
+ }
+ writel(readl(&mmc_base->sysctl) | CEN_ENABLE, &mmc_base->sysctl);
+}
+
+static int omap_mmc_probe(struct device_d *dev)
+{
+ struct omap_hsmmc *hsmmc;
+
+ hsmmc = xzalloc(sizeof(*hsmmc));
+
+ hsmmc->dev = dev;
+ hsmmc->mci.send_cmd = mmc_send_cmd;
+ hsmmc->mci.set_ios = mmc_set_ios;
+ hsmmc->mci.init = mmc_init_setup;
+ hsmmc->mci.host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+ hsmmc->base = (struct hsmmc *)dev->map_base;
+
+ hsmmc->mci.voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
+
+ hsmmc->mci.f_min = 400000;
+ hsmmc->mci.f_max = 52000000;
+
+ mci_register(&hsmmc->mci);
+
+ return 0;
+}
+
+static struct driver_d omap_mmc_driver = {
+ .name = "omap-hsmmc",
+ .probe = omap_mmc_probe,
+};
+
+static int omap_mmc_init_driver(void)
+{
+ register_driver(&omap_mmc_driver);
+ return 0;
+}
+
+device_initcall(omap_mmc_init_driver);
+
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 12e1237e..126f7cc7 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -8,6 +8,52 @@ menuconfig NAND
if NAND
+config NAND_WRITE
+ bool
+ default y
+ prompt "Support writing to Nand"
+
+config NAND_ECC_SOFT
+ bool
+ default y
+ prompt "Support software ecc"
+
+config NAND_ECC_HW
+ bool
+ default y
+ prompt "Support hardware ecc"
+
+config NAND_ECC_HW_SYNDROME
+ bool
+ default y
+ prompt "Support syndrome hardware ecc controllers"
+
+config NAND_ECC_HW_NONE
+ bool
+ default y
+ prompt "Support skipping ecc support"
+
+config NAND_INFO
+ bool
+ default y
+ prompt "Nand vendor/size information"
+ help
+ Show informational strings about the vendor and nand flash type
+ during startup
+
+config NAND_BBT
+ bool
+ default y
+ prompt "support bad block tables"
+ help
+ Say y here to include support for bad block tables. This speeds
+ up the process of checking for bad blocks
+
+config NAND_READ_OOB
+ bool
+ default y
+ prompt "create a device for reading the OOB data"
+
config NAND_IMX
bool
prompt "i.MX NAND driver"
@@ -15,7 +61,7 @@ config NAND_IMX
config NAND_OMAP_GPMC
tristate "NAND Flash Support for GPMC based OMAP platforms"
- depends on ((ARCH_OMAP2 || ARCH_OMAP3) && GPMC)
+ depends on OMAP_GPMC
help
Support for NAND flash using GPMC. GPMC is a common memory
interface found on Texas Instrument's OMAP platforms
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index bac39e75..149cbbfa 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,13 +1,17 @@
# Generic NAND options
obj-$(CONFIG_NAND) += nand.o nand_ecc.o
+obj-$(CONFIG_NAND_WRITE) += nand_write.o
+obj-$(CONFIG_NAND_ECC_SOFT) += nand_ecc.o nand_swecc.o
+obj-$(CONFIG_NAND_ECC_HW) += nand_hwecc.o
+obj-$(CONFIG_NAND_ECC_HW_SYNDROME) += nand_hwecc_syndrome.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
-obj-$(CONFIG_NAND) += nand_base.o nand_bbt.o
+obj-$(CONFIG_NAND) += nand_base.o nand-bb.o
+obj-$(CONFIG_NAND_BBT) += nand_bbt.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_NOMADIK) += nomadik_nand.o
obj-$(CONFIG_NAND_IMX) += nand_imx.o
-obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o
+obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o nand_omap_bch_decoder.o
obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o
obj-$(CONFIG_NAND_S3C24X0) += nand_s3c2410.o
-#obj-$(CONFIG_NAND) += nand_util.o
diff --git a/drivers/mtd/nand/nand-bb.c b/drivers/mtd/nand/nand-bb.c
new file mode 100644
index 00000000..dbfb8e38
--- /dev/null
+++ b/drivers/mtd/nand/nand-bb.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <common.h>
+#include <command.h>
+#include <fs.h>
+#include <linux/stat.h>
+#include <errno.h>
+#include <malloc.h>
+#include <getopt.h>
+#include <xfuncs.h>
+#include <init.h>
+#include <ioctl.h>
+#include <nand.h>
+#include <linux/mtd/mtd-abi.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <linux/list.h>
+
+struct nand_bb {
+ char cdevname[MAX_DRIVER_NAME];
+ struct cdev *cdev_parent;
+ char *name;
+ int open;
+ int needs_write;
+
+ struct mtd_info_user info;
+
+ size_t raw_size;
+ size_t size;
+ off_t offset;
+ void *writebuf;
+
+ struct cdev cdev;
+
+ struct list_head list;
+};
+
+static ssize_t nand_bb_read(struct cdev *cdev, void *buf, size_t count,
+ unsigned long offset, ulong flags)
+{
+ struct nand_bb *bb = cdev->priv;
+ struct cdev *parent = bb->cdev_parent;
+ int ret, bytes = 0, now;
+
+ debug("%s %d %d\n", __func__, offset, count);
+
+ while(count) {
+ ret = cdev_ioctl(parent, MEMGETBADBLOCK, (void *)bb->offset);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ printf("skipping bad block at 0x%08lx\n", bb->offset);
+ bb->offset += bb->info.erasesize;
+ continue;
+ }
+
+ now = min(count, (size_t)(bb->info.erasesize -
+ (bb->offset % bb->info.erasesize)));
+ ret = cdev_read(parent, buf, now, bb->offset, 0);
+ if (ret < 0)
+ return ret;
+ buf += now;
+ count -= now;
+ bb->offset += now;
+ bytes += now;
+ };
+
+ return bytes;
+}
+
+/* Must be a multiple of the largest NAND page size */
+#define BB_WRITEBUF_SIZE 4096
+
+#ifdef CONFIG_NAND_WRITE
+static int nand_bb_write_buf(struct nand_bb *bb, size_t count)
+{
+ int ret, now;
+ struct cdev *parent = bb->cdev_parent;
+ void *buf = bb->writebuf;
+ int cur_ofs = bb->offset & ~(BB_WRITEBUF_SIZE - 1);
+
+ while (count) {
+ ret = cdev_ioctl(parent, MEMGETBADBLOCK, (void *)cur_ofs);
+ if (ret < 0)
+ return ret;
+
+ if (ret) {
+ debug("skipping bad block at 0x%08x\n", cur_ofs);
+ bb->offset += bb->info.erasesize;
+ cur_ofs += bb->info.erasesize;
+ continue;
+ }
+
+ now = min(count, (size_t)(bb->info.erasesize));
+ ret = cdev_write(parent, buf, now, cur_ofs, 0);
+ if (ret < 0)
+ return ret;
+ buf += now;
+ count -= now;
+ cur_ofs += now;
+ };
+
+ return 0;
+}
+
+static ssize_t nand_bb_write(struct cdev *cdev, const void *buf, size_t count,
+ unsigned long offset, ulong flags)
+{
+ struct nand_bb *bb = cdev->priv;
+ int bytes = count, now, wroffs, ret;
+
+ debug("%s offset: 0x%08x count: 0x%08x\n", __func__, offset, count);
+
+ while (count) {
+ wroffs = bb->offset % BB_WRITEBUF_SIZE;
+ now = min((int)count, BB_WRITEBUF_SIZE - wroffs);
+ memcpy(bb->writebuf + wroffs, buf, now);
+
+ if (wroffs + now == BB_WRITEBUF_SIZE) {
+ bb->needs_write = 0;
+ ret = nand_bb_write_buf(bb, BB_WRITEBUF_SIZE);
+ if (ret)
+ return ret;
+ } else {
+ bb->needs_write = 1;
+ }
+
+ bb->offset += now;
+ count -= now;
+ buf += now;
+ }
+
+ return bytes;
+}
+
+static int nand_bb_erase(struct cdev *cdev, size_t count, unsigned long offset)
+{
+ struct nand_bb *bb = cdev->priv;
+
+ if (offset != 0) {
+ printf("can only erase from beginning of device\n");
+ return -EINVAL;
+ }
+
+ return cdev_erase(bb->cdev_parent, bb->raw_size, 0);
+}
+#endif
+
+static int nand_bb_open(struct cdev *cdev)
+{
+ struct nand_bb *bb = cdev->priv;
+
+ if (bb->open)
+ return -EBUSY;
+
+ bb->open = 1;
+ bb->offset = 0;
+ bb->needs_write = 0;
+ bb->writebuf = xmalloc(BB_WRITEBUF_SIZE);
+
+ return 0;
+}
+
+static int nand_bb_close(struct cdev *cdev)
+{
+ struct nand_bb *bb = cdev->priv;
+
+#ifdef CONFIG_NAND_WRITE
+ if (bb->needs_write)
+ nand_bb_write_buf(bb, bb->offset % BB_WRITEBUF_SIZE);
+#endif
+ bb->open = 0;
+ free(bb->writebuf);
+
+ return 0;
+}
+
+static int nand_bb_calc_size(struct nand_bb *bb)
+{
+ ulong pos = 0;
+ int ret;
+
+ while (pos < bb->raw_size) {
+ ret = cdev_ioctl(bb->cdev_parent, MEMGETBADBLOCK, (void *)pos);
+ if (ret < 0)
+ return ret;
+ if (!ret)
+ bb->cdev.size += bb->info.erasesize;
+
+ pos += bb->info.erasesize;
+ }
+
+ return 0;
+}
+
+static struct file_operations nand_bb_ops = {
+ .open = nand_bb_open,
+ .close = nand_bb_close,
+ .read = nand_bb_read,
+#ifdef CONFIG_NAND_WRITE
+ .write = nand_bb_write,
+ .erase = nand_bb_erase,
+#endif
+};
+
+static LIST_HEAD(bb_list);
+
+/**
+ * Add a bad block aware device ontop of another (NAND) device
+ * @param[in] dev The device to add a partition on
+ * @param[in] name Partition name (can be obtained with devinfo command)
+ * @return The device representing the new partition.
+ */
+int dev_add_bb_dev(char *path, const char *name)
+{
+ struct nand_bb *bb;
+ int ret = -ENOMEM;
+
+ bb = xzalloc(sizeof(*bb));
+
+ bb->cdev_parent = cdev_open(path, O_RDWR);
+ if (!bb->cdev_parent)
+ goto out1;
+
+ if (name) {
+ strcpy(bb->cdevname, name);
+ } else {
+ strcpy(bb->cdevname, path);
+ strcat(bb->cdevname, ".bb");
+ }
+
+ bb->cdev.name = bb->cdevname;
+
+ bb->raw_size = bb->cdev_parent->size;
+
+ ret = cdev_ioctl(bb->cdev_parent, MEMGETINFO, &bb->info);
+ if (ret)
+ goto out4;
+
+ nand_bb_calc_size(bb);
+ bb->cdev.ops = &nand_bb_ops;
+ bb->cdev.priv = bb;
+
+ ret = devfs_create(&bb->cdev);
+ if (ret)
+ goto out4;
+
+ list_add_tail(&bb->list, &bb_list);
+
+ return 0;
+
+out4:
+ cdev_close(bb->cdev_parent);
+out1:
+ free(bb);
+ return ret;
+}
+
+int dev_remove_bb_dev(const char *name)
+{
+ struct nand_bb *bb;
+
+ list_for_each_entry(bb, &bb_list, list) {
+ if (!strcmp(bb->cdev.name, name)) {
+ devfs_remove(&bb->cdev);
+ cdev_close(bb->cdev_parent);
+ free(bb);
+ return 0;
+ }
+ }
+
+ return -ENODEV;
+}
diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c
index 08b5cc15..9423ac80 100644
--- a/drivers/mtd/nand/nand.c
+++ b/drivers/mtd/nand/nand.c
@@ -50,6 +50,7 @@ static ssize_t nand_read(struct cdev *cdev, void* buf, size_t count, ulong offs
#define NOTALIGNED(x) (x & (info->writesize - 1)) != 0
+#ifdef CONFIG_NAND_WRITE
static int all_ff(const void *buf, int len)
{
int i;
@@ -104,6 +105,7 @@ static ssize_t nand_write(struct cdev* cdev, const void *buf, size_t _count, ulo
out:
return ret ? ret : _count;
}
+#endif
static int nand_ioctl(struct cdev *cdev, int request, void *buf)
{
@@ -114,9 +116,11 @@ static int nand_ioctl(struct cdev *cdev, int request, void *buf)
case MEMGETBADBLOCK:
debug("MEMGETBADBLOCK: 0x%08lx\n", (off_t)buf);
return info->block_isbad(info, (off_t)buf);
+#ifdef CONFIG_NAND_WRITE
case MEMSETBADBLOCK:
debug("MEMSETBADBLOCK: 0x%08lx\n", (off_t)buf);
return info->block_markbad(info, (off_t)buf);
+#endif
case MEMGETINFO:
user->type = info->type;
user->flags = info->flags;
@@ -133,6 +137,7 @@ static int nand_ioctl(struct cdev *cdev, int request, void *buf)
return 0;
}
+#ifdef CONFIG_NAND_WRITE
static ssize_t nand_erase(struct cdev *cdev, size_t count, unsigned long offset)
{
struct mtd_info *info = cdev->priv;
@@ -162,6 +167,8 @@ static ssize_t nand_erase(struct cdev *cdev, size_t count, unsigned long offset)
return 0;
}
+#endif
+
#if 0
static char* mtd_get_size(struct device_d *, struct param_d *param)
{
@@ -171,12 +178,15 @@ static char* mtd_get_size(struct device_d *, struct param_d *param)
static struct file_operations nand_ops = {
.read = nand_read,
+#ifdef CONFIG_NAND_WRITE
.write = nand_write,
+ .erase = nand_erase,
+#endif
.ioctl = nand_ioctl,
.lseek = dev_lseek_default,
- .erase = nand_erase,
};
+#ifdef CONFIG_NAND_READ_OOB
static ssize_t nand_read_oob(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags)
{
struct mtd_info *info = cdev->priv;
@@ -208,9 +218,39 @@ static struct file_operations nand_ops_oob = {
.lseek = dev_lseek_default,
};
-int add_mtd_device(struct mtd_info *mtd)
+static int nand_init_oob_cdev(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
+
+ mtd->cdev_oob.ops = &nand_ops_oob;
+ mtd->cdev_oob.size = (mtd->size >> chip->page_shift) * mtd->oobsize;
+ mtd->cdev_oob.name = asprintf("nand_oob%d", mtd->class_dev.id);
+ mtd->cdev_oob.priv = mtd;
+ mtd->cdev_oob.dev = &mtd->class_dev;
+ devfs_create(&mtd->cdev_oob);
+
+ return 0;
+}
+
+static void nand_exit_oob_cdev(struct mtd_info *mtd)
+{
+ free(mtd->cdev_oob.name);
+}
+#else
+
+static int nand_init_oob_cdev(struct mtd_info *mtd)
+{
+ return 0;
+}
+
+static void nand_exit_oob_cdev(struct mtd_info *mtd)
+{
+ return;
+}
+#endif
+
+int add_mtd_device(struct mtd_info *mtd)
+{
char str[16];
strcpy(mtd->class_dev.name, "nand");
@@ -228,12 +268,7 @@ int add_mtd_device(struct mtd_info *mtd)
devfs_create(&mtd->cdev);
- mtd->cdev_oob.ops = &nand_ops_oob;
- mtd->cdev_oob.size = (mtd->size >> chip->page_shift) * mtd->oobsize;
- mtd->cdev_oob.name = asprintf("nand_oob%d", mtd->class_dev.id);
- mtd->cdev_oob.priv = mtd;
- mtd->cdev_oob.dev = &mtd->class_dev;
- devfs_create(&mtd->cdev_oob);
+ nand_init_oob_cdev(mtd);
return 0;
}
@@ -241,7 +276,7 @@ int add_mtd_device(struct mtd_info *mtd)
int del_mtd_device (struct mtd_info *mtd)
{
unregister_device(&mtd->class_dev);
- free(mtd->cdev_oob.name);
+ nand_exit_oob_cdev(mtd);
free(mtd->param_size.value);
free(mtd->cdev.name);
return 0;
diff --git a/drivers/mtd/nand/nand.h b/drivers/mtd/nand/nand.h
new file mode 100644
index 00000000..123258d7
--- /dev/null
+++ b/drivers/mtd/nand/nand.h
@@ -0,0 +1,31 @@
+#ifndef __NAND_H
+#define __NAND_H
+
+int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd);
+int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+ int page);
+int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs);
+int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
+ int allowbbt);
+int nand_block_isbad(struct mtd_info *mtd, loff_t offs);
+int nand_block_markbad(struct mtd_info *mtd, loff_t ofs);
+void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len);
+void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len);
+void single_erase_cmd(struct mtd_info *mtd, int page);
+void multi_erase_cmd(struct mtd_info *mtd, int page);
+void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf);
+int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int page, int cached, int raw);
+int nand_erase(struct mtd_info *mtd, struct erase_info *instr);
+int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const uint8_t *buf);
+int nand_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops);
+
+void nand_init_ecc_hw(struct nand_chip *chip);
+void nand_init_ecc_soft(struct nand_chip *chip);
+void nand_init_ecc_hw_syndrome(struct nand_chip *chip);
+
+#endif /* __NAND_H */
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 22d21277..5e122a10 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -43,6 +43,8 @@
#include <malloc.h>
#include <module.h>
+#include "nand.h"
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/* Define default oob placement schemes for large and small page devices */
@@ -75,12 +77,6 @@ static struct nand_ecclayout nand_oob_64 = {
.length = 38}}
};
-static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
- int new_state);
-
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops);
-
#define DEFINE_LED_TRIGGER(x)
#define DEFINE_LED_TRIGGER_GLOBAL(x)
#define led_trigger_register_simple(x, y) do {} while(0)
@@ -94,24 +90,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
DEFINE_LED_TRIGGER(nand_led_trigger);
/**
- * nand_release_device - [GENERIC] release chip
- * @mtd: MTD device structure
- *
- * Deselect, release chip lock and wake up anyone waiting on the device
- */
-static void nand_release_device(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
-
- /* De-select the NAND device */
- chip->select_chip(mtd, -1);
-
- /* Release the controller and the chip */
- chip->controller->active = NULL;
- chip->state = FL_READY;
-}
-
-/**
* nand_read_byte - [DEFAULT] read one byte from the chip
* @mtd: MTD device structure
*
@@ -172,23 +150,6 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
}
/**
- * nand_write_buf - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 8bit buswith
- */
-static void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *chip = mtd->priv;
-
- for (i = 0; i < len; i++)
- writeb(buf[i], chip->IO_ADDR_W);
-}
-
-/**
* nand_read_buf - [DEFAULT] read chip data into buffer
* @mtd: MTD device structure
* @buf: buffer to store date
@@ -225,26 +186,6 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
}
/**
- * nand_write_buf16 - [DEFAULT] write buffer to chip
- * @mtd: MTD device structure
- * @buf: data buffer
- * @len: number of bytes to write
- *
- * Default write function for 16bit buswith
- */
-static void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
- int i;
- struct nand_chip *chip = mtd->priv;
- u16 *p = (u16 *) buf;
- len >>= 1;
-
- for (i = 0; i < len; i++)
- writew(p[i], chip->IO_ADDR_W);
-
-}
-
-/**
* nand_read_buf16 - [DEFAULT] read chip data into buffer
* @mtd: MTD device structure
* @buf: buffer to store date
@@ -304,8 +245,6 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
if (getchip) {
chipnr = (int)(ofs >> chip->chip_shift);
- nand_get_device(chip, mtd, FL_READING);
-
/* Select the NAND device */
chip->select_chip(mtd, chipnr);
}
@@ -324,70 +263,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
res = 1;
}
- if (getchip)
- nand_release_device(mtd);
-
return res;
}
/**
- * nand_default_block_markbad - [DEFAULT] mark a block bad
- * @mtd: MTD device structure
- * @ofs: offset from device start
- *
- * This is the default implementation, which can be overridden by
- * a hardware specific driver.
-*/
-static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
- struct nand_chip *chip = mtd->priv;
- uint8_t buf[2] = { 0, 0 };
- int block, ret;
-
- /* Get block number */
- block = (int)(ofs >> chip->bbt_erase_shift);
- if (chip->bbt)
- chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
-
- /* Do we have a flash based bad block table ? */
- if (chip->options & NAND_USE_FLASH_BBT)
- ret = nand_update_bbt(mtd, ofs);
- else {
- /* We write two bytes, so we dont have to mess with 16 bit
- * access
- */
- nand_get_device(chip, mtd, FL_WRITING);
- ofs += mtd->oobsize;
- chip->ops.len = chip->ops.ooblen = 2;
- chip->ops.datbuf = NULL;
- chip->ops.oobbuf = buf;
- chip->ops.ooboffs = chip->badblockpos & ~0x01;
-
- ret = nand_do_write_oob(mtd, ofs, &chip->ops);
- nand_release_device(mtd);
- }
- if (!ret)
- mtd->ecc_stats.badblocks++;
-
- return ret;
-}
-
-/**
- * nand_check_wp - [GENERIC] check if the chip is write protected
- * @mtd: MTD device structure
- * Check, if the device is write protected
- *
- * The function expects, that the device is already selected
- */
-static int nand_check_wp(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
- /* Check the WP bit */
- chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
- return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
-}
-
-/**
* nand_block_checkbad - [GENERIC] Check if a block is marked bad
* @mtd: MTD device structure
* @ofs: offset from device start
@@ -397,16 +276,19 @@ static int nand_check_wp(struct mtd_info *mtd)
* Check, if the block is bad. Either by reading the bad block table or
* calling of the scan function.
*/
-static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
+int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
int allowbbt)
{
struct nand_chip *chip = mtd->priv;
+#ifdef CONFIG_NAND_BBT
if (!chip->bbt)
return chip->block_bad(mtd, ofs, getchip);
-
/* Return info from the table */
return nand_isbad_bbt(mtd, ofs, allowbbt);
+#else
+ return chip->block_bad(mtd, ofs, getchip);
+#endif
}
/*
@@ -652,32 +534,6 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
}
/**
- * nand_get_device - [GENERIC] Get chip for selected access
- * @chip: the nand chip descriptor
- * @mtd: MTD device structure
- * @new_state: the state which is requested
- *
- * Get the device and lock it for exclusive access
- */
-static int
-nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
-{
- retry:
- /* Hardware controller shared among independend devices */
- if (!chip->controller->active)
- chip->controller->active = chip;
-
- if (chip->controller->active == chip && chip->state == FL_READY) {
- chip->state = new_state;
- return 0;
- }
- if (new_state == FL_PM_SUSPENDED) {
- return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
- }
- goto retry;
-}
-
-/**
* nand_wait - [DEFAULT] wait until the command is done
* @mtd: MTD device structure
* @chip: NAND chip structure
@@ -739,150 +595,13 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- */
-static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *p = buf;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- uint8_t *ecc_code = chip->buffers->ecccode;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
-
- chip->ecc.read_page_raw(mtd, chip, buf);
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
- for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
- eccsteps = chip->ecc.steps;
- p = buf;
-
- for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- if (stat < 0)
- mtd->ecc_stats.failed++;
- else
- mtd->ecc_stats.corrected += stat;
- }
- return 0;
-}
-
-/**
- * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- *
- * Not for syndrome calculating ecc controllers which need a special oob layout
- */
-static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *p = buf;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- uint8_t *ecc_code = chip->buffers->ecccode;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- }
- chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
- for (i = 0; i < chip->ecc.total; i++)
- ecc_code[i] = chip->oob_poi[eccpos[i]];
-
- eccsteps = chip->ecc.steps;
- p = buf;
-
- for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
- if (stat < 0)
- mtd->ecc_stats.failed++;
- else
- mtd->ecc_stats.corrected += stat;
- }
- return 0;
-}
-
-/**
- * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: buffer to store read data
- *
- * The hw generator calculates the error syndrome automatically. Therefor
- * we need a special oob layout and handling.
- */
-static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *p = buf;
- uint8_t *oob = chip->oob_poi;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- int stat;
-
- chip->ecc.hwctl(mtd, NAND_ECC_READ);
- chip->read_buf(mtd, p, eccsize);
-
- if (chip->ecc.prepad) {
- chip->read_buf(mtd, oob, chip->ecc.prepad);
- oob += chip->ecc.prepad;
- }
-
- chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
- chip->read_buf(mtd, oob, eccbytes);
- stat = chip->ecc.correct(mtd, p, oob, NULL);
-
- if (stat < 0)
- mtd->ecc_stats.failed++;
- else
- mtd->ecc_stats.corrected += stat;
-
- oob += eccbytes;
-
- if (chip->ecc.postpad) {
- chip->read_buf(mtd, oob, chip->ecc.postpad);
- oob += chip->ecc.postpad;
- }
- }
-
- /* Calculate remaining oob bytes */
- i = mtd->oobsize - (oob - chip->oob_poi);
- if (i)
- chip->read_buf(mtd, oob, i);
-
- return 0;
-}
-
-/**
* nand_transfer_oob - [Internal] Transfer oob to client buffer
* @chip: nand chip structure
* @oob: oob destination address
* @ops: oob ops structure
* @len: size of oob to transfer
*/
+#ifdef CONFIG_NAND_READ_OOB
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
struct mtd_oob_ops *ops, size_t len)
{
@@ -923,6 +642,7 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
}
return NULL;
}
+#endif
/**
* nand_do_read_ops - [Internal] Read data with ECC
@@ -988,6 +708,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
buf += bytes;
+#ifdef CONFIG_NAND_READ_OOB
if (unlikely(oob)) {
/* Raw mode does data:oob:data:oob */
if (ops->mode != MTD_OOB_RAW) {
@@ -1002,7 +723,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
buf = nand_transfer_oob(chip,
buf, ops, mtd->oobsize);
}
-
+#endif
if (!(chip->options & NAND_NO_READRDY)) {
/*
* Apply delay or wait for ready/busy pin. Do
@@ -1081,8 +802,6 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
if (!len)
return 0;
- nand_get_device(chip, mtd, FL_READING);
-
chip->ops.len = len;
chip->ops.datbuf = buf;
chip->ops.oobbuf = NULL;
@@ -1091,8 +810,6 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
*retlen = chip->ops.retlen;
- nand_release_device(mtd);
-
return ret;
}
@@ -1103,7 +820,7 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
* @page: page number to read
* @sndcmd: flag whether to issue read command or not
*/
-static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
int page, int sndcmd)
{
if (sndcmd) {
@@ -1115,127 +832,6 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
- * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC
- * with syndromes
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @page: page number to read
- * @sndcmd: flag whether to issue read command or not
- */
-static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
- int page, int sndcmd)
-{
- uint8_t *buf = chip->oob_poi;
- int length = mtd->oobsize;
- int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
- int eccsize = chip->ecc.size;
- uint8_t *bufpoi = buf;
- int i, toread, sndrnd = 0, pos;
-
- chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
- for (i = 0; i < chip->ecc.steps; i++) {
- if (sndrnd) {
- pos = eccsize + i * (eccsize + chunk);
- if (mtd->writesize > 512)
- chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
- else
- chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
- } else
- sndrnd = 1;
- toread = min_t(int, length, chunk);
- chip->read_buf(mtd, bufpoi, toread);
- bufpoi += toread;
- length -= toread;
- }
- if (length > 0)
- chip->read_buf(mtd, bufpoi, length);
-
- return 1;
-}
-
-/**
- * nand_write_oob_std - [REPLACABLE] the most common OOB data write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @page: page number to write
- */
-static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
- int page)
-{
- int status = 0;
- const uint8_t *buf = chip->oob_poi;
- int length = mtd->oobsize;
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
- chip->write_buf(mtd, buf, length);
- /* Send command to program the OOB data */
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-
- status = chip->waitfunc(mtd, chip);
-
- return status & NAND_STATUS_FAIL ? -EIO : 0;
-}
-
-/**
- * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC
- * with syndrome - only for large page flash !
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @page: page number to write
- */
-static int nand_write_oob_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, int page)
-{
- int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
- int eccsize = chip->ecc.size, length = mtd->oobsize;
- int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
- const uint8_t *bufpoi = chip->oob_poi;
-
- /*
- * data-ecc-data-ecc ... ecc-oob
- * or
- * data-pad-ecc-pad-data-pad .... ecc-pad-oob
- */
- if (!chip->ecc.prepad && !chip->ecc.postpad) {
- pos = steps * (eccsize + chunk);
- steps = 0;
- } else
- pos = eccsize;
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
- for (i = 0; i < steps; i++) {
- if (sndcmd) {
- if (mtd->writesize <= 512) {
- uint32_t fill = 0xFFFFFFFF;
-
- len = eccsize;
- while (len > 0) {
- int num = min_t(int, len, 4);
- chip->write_buf(mtd, (uint8_t *)&fill,
- num);
- len -= num;
- }
- } else {
- pos = eccsize + i * (eccsize + chunk);
- chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
- }
- } else
- sndcmd = 1;
- len = min_t(int, length, chunk);
- chip->write_buf(mtd, bufpoi, len);
- bufpoi += len;
- length -= len;
- }
- if (length > 0)
- chip->write_buf(mtd, bufpoi, length);
-
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
-
- return status & NAND_STATUS_FAIL ? -EIO : 0;
-}
-
-/**
* nand_do_read_oob - [Intern] NAND read out-of-band
* @mtd: MTD device structure
* @from: offset to read from
@@ -1243,6 +839,7 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd,
*
* NAND read out-of-band data from the spare area
*/
+#ifdef CONFIG_NAND_READ_OOB
static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
@@ -1339,7 +936,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
static int nand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
- struct nand_chip *chip = mtd->priv;
int ret = -ENOSYS;
ops->retlen = 0;
@@ -1351,8 +947,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
return -EINVAL;
}
- nand_get_device(chip, mtd, FL_READING);
-
switch(ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_AUTO:
@@ -1369,742 +963,16 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
ret = nand_do_read_ops(mtd, from, ops);
out:
- nand_release_device(mtd);
return ret;
}
-
-
-/**
- * nand_write_page_raw - [Intern] raw page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- */
-static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
-{
- chip->write_buf(mtd, buf, mtd->writesize);
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-}
-
-/**
- * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- */
-static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- const uint8_t *p = buf;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
-
- /* Software ecc calculation */
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
-
- for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
- chip->ecc.write_page_raw(mtd, chip, buf);
-}
-
-/**
- * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- */
-static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- uint8_t *ecc_calc = chip->buffers->ecccalc;
- const uint8_t *p = buf;
- uint32_t *eccpos = chip->ecc.layout->eccpos;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- chip->write_buf(mtd, p, eccsize);
- chip->ecc.calculate(mtd, p, &ecc_calc[i]);
- }
-
- for (i = 0; i < chip->ecc.total; i++)
- chip->oob_poi[eccpos[i]] = ecc_calc[i];
-
- chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
-}
-
-/**
- * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
- * @mtd: mtd info structure
- * @chip: nand chip info structure
- * @buf: data buffer
- *
- * The hw generator calculates the error syndrome automatically. Therefor
- * we need a special oob layout and handling.
- */
-static void nand_write_page_syndrome(struct mtd_info *mtd,
- struct nand_chip *chip, const uint8_t *buf)
-{
- int i, eccsize = chip->ecc.size;
- int eccbytes = chip->ecc.bytes;
- int eccsteps = chip->ecc.steps;
- const uint8_t *p = buf;
- uint8_t *oob = chip->oob_poi;
-
- for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-
- chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
- chip->write_buf(mtd, p, eccsize);
-
- if (chip->ecc.prepad) {
- chip->write_buf(mtd, oob, chip->ecc.prepad);
- oob += chip->ecc.prepad;
- }
-
- chip->ecc.calculate(mtd, p, oob);
- chip->write_buf(mtd, oob, eccbytes);
- oob += eccbytes;
-
- if (chip->ecc.postpad) {
- chip->write_buf(mtd, oob, chip->ecc.postpad);
- oob += chip->ecc.postpad;
- }
- }
-
- /* Calculate remaining oob bytes */
- i = mtd->oobsize - (oob - chip->oob_poi);
- if (i)
- chip->write_buf(mtd, oob, i);
-}
-
-/**
- * nand_write_page - [REPLACEABLE] write one page
- * @mtd: MTD device structure
- * @chip: NAND chip descriptor
- * @buf: the data to write
- * @page: page number to write
- * @cached: cached programming
- * @raw: use _raw version of write_page
- */
-static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int page, int cached, int raw)
-{
- int status;
-
- chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-
- if (unlikely(raw))
- chip->ecc.write_page_raw(mtd, chip, buf);
- else
- chip->ecc.write_page(mtd, chip, buf);
-
- /*
- * Cached progamming disabled for now, Not sure if its worth the
- * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
- */
- cached = 0;
-
- if (!cached || !(chip->options & NAND_CACHEPRG)) {
-
- chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
- /*
- * See if operation failed and additional status checks are
- * available
- */
- if ((status & NAND_STATUS_FAIL) && (chip->errstat))
- status = chip->errstat(mtd, chip, FL_WRITING, status,
- page);
-
- if (status & NAND_STATUS_FAIL) {
- return -EIO;
- }
- } else {
- chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
- status = chip->waitfunc(mtd, chip);
- }
-
-#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
- /* Send command to read back the data */
- chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
-
- if (chip->verify_buf(mtd, buf, mtd->writesize))
- return -EIO;
#endif
- return 0;
-}
-
-/**
- * nand_fill_oob - [Internal] Transfer client buffer to oob
- * @chip: nand chip structure
- * @oob: oob data buffer
- * @ops: oob ops structure
- */
-static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
- struct mtd_oob_ops *ops)
-{
- size_t len = ops->ooblen;
-
- switch(ops->mode) {
-
- case MTD_OOB_PLACE:
- case MTD_OOB_RAW:
- memcpy(chip->oob_poi + ops->ooboffs, oob, len);
- return oob + len;
-
- case MTD_OOB_AUTO: {
- struct nand_oobfree *free = chip->ecc.layout->oobfree;
- uint32_t boffs = 0, woffs = ops->ooboffs;
- size_t bytes = 0;
-
- for(; free->length && len; free++, len -= bytes) {
- /* Write request not from offset 0 ? */
- if (unlikely(woffs)) {
- if (woffs >= free->length) {
- woffs -= free->length;
- continue;
- }
- boffs = free->offset + woffs;
- bytes = min_t(size_t, len,
- (free->length - woffs));
- woffs = 0;
- } else {
- bytes = min_t(size_t, len, free->length);
- boffs = free->offset;
- }
- memcpy(chip->oob_poi + boffs, oob, bytes);
- oob += bytes;
- }
- return oob;
- }
- default:
- BUG();
- }
- return NULL;
-}
-
-#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
-
-/**
- * nand_do_write_ops - [Internal] NAND write with ECC
- * @mtd: MTD device structure
- * @to: offset to write to
- * @ops: oob operations description structure
- *
- * NAND write with ECC
- */
-static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops)
-{
- int chipnr, realpage, page, blockmask, column;
- struct nand_chip *chip = mtd->priv;
- uint32_t writelen = ops->len;
- uint8_t *oob = ops->oobbuf;
- uint8_t *buf = ops->datbuf;
- int ret, subpage;
-
- ops->retlen = 0;
- if (!writelen)
- return 0;
-
- /* reject writes, which are not page aligned */
- if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
- printk(KERN_NOTICE "nand_write: "
- "Attempt to write not page aligned data\n");
- return -EINVAL;
- }
-
- column = to & (mtd->writesize - 1);
- subpage = column || (writelen & (mtd->writesize - 1));
-
- if (subpage && oob)
- return -EINVAL;
-
- chipnr = (int)(to >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
-
- /* Check, if it is write protected */
- if (nand_check_wp(mtd)) {
- return -EIO;
- }
-
- realpage = (int)(to >> chip->page_shift);
- page = realpage & chip->pagemask;
- blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
-
- /* Invalidate the page cache, when we write to the cached page */
- if (to <= (chip->pagebuf << chip->page_shift) &&
- (chip->pagebuf << chip->page_shift) < (to + ops->len))
- chip->pagebuf = -1;
-
- /* If we're not given explicit OOB data, let it be 0xFF */
- if (likely(!oob))
- memset(chip->oob_poi, 0xff, mtd->oobsize);
-
- while(1) {
- int bytes = mtd->writesize;
- int cached = writelen > bytes && page != blockmask;
- uint8_t *wbuf = buf;
-
- /* Partial page write ? */
- if (unlikely(column || writelen < (mtd->writesize - 1))) {
- cached = 0;
- bytes = min_t(int, bytes - column, (int) writelen);
- chip->pagebuf = -1;
- memset(chip->buffers->databuf, 0xff, mtd->writesize);
- memcpy(&chip->buffers->databuf[column], buf, bytes);
- wbuf = chip->buffers->databuf;
- }
-
- if (unlikely(oob))
- oob = nand_fill_oob(chip, oob, ops);
-
- ret = chip->write_page(mtd, chip, wbuf, page, cached,
- (ops->mode == MTD_OOB_RAW));
- if (ret)
- break;
-
- writelen -= bytes;
- if (!writelen)
- break;
-
- column = 0;
- buf += bytes;
- realpage++;
-
- page = realpage & chip->pagemask;
- /* Check, if we cross a chip boundary */
- if (!page) {
- chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
- }
- }
-
- ops->retlen = ops->len - writelen;
- if (unlikely(oob))
- ops->oobretlen = ops->ooblen;
- return ret;
-}
-
-/**
- * nand_write - [MTD Interface] NAND write with ECC
- * @mtd: MTD device structure
- * @to: offset to write to
- * @len: number of bytes to write
- * @retlen: pointer to variable to store the number of written bytes
- * @buf: the data to write
- *
- * NAND write with ECC
- */
-static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const uint8_t *buf)
-{
- struct nand_chip *chip = mtd->priv;
- int ret;
-
- /* Do not allow reads past end of device */
- if ((to + len) > mtd->size)
- return -EINVAL;
- if (!len)
- return 0;
-
- nand_get_device(chip, mtd, FL_WRITING);
-
- chip->ops.len = len;
- chip->ops.datbuf = (uint8_t *)buf;
- chip->ops.oobbuf = NULL;
-
- ret = nand_do_write_ops(mtd, to, &chip->ops);
-
- *retlen = chip->ops.retlen;
-
- nand_release_device(mtd);
-
- return ret;
-}
-
-/**
- * nand_do_write_oob - [MTD Interface] NAND write out-of-band
- * @mtd: MTD device structure
- * @to: offset to write to
- * @ops: oob operation description structure
- *
- * NAND write out-of-band
- */
-static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops)
-{
- int chipnr, page, status, len;
- struct nand_chip *chip = mtd->priv;
-
- MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
- (unsigned int)to, (int)ops->ooblen);
-
- if (ops->mode == MTD_OOB_AUTO)
- len = chip->ecc.layout->oobavail;
- else
- len = mtd->oobsize;
-
- /* Do not allow write past end of page */
- if ((ops->ooboffs + ops->ooblen) > len) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
- "Attempt to write past end of page\n");
- return -EINVAL;
- }
-
- if (unlikely(ops->ooboffs >= len)) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
- "Attempt to start write outside oob\n");
- return -EINVAL;
- }
-
- /* Do not allow reads past end of device */
- if (unlikely(to >= mtd->size ||
- ops->ooboffs + ops->ooblen >
- ((mtd->size >> chip->page_shift) -
- (to >> chip->page_shift)) * len)) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
- "Attempt write beyond end of device\n");
- return -EINVAL;
- }
-
- chipnr = (int)(to >> chip->chip_shift);
- chip->select_chip(mtd, chipnr);
-
- /* Shift to get page */
- page = (int)(to >> chip->page_shift);
-
- /*
- * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
- * of my DiskOnChip 2000 test units) will clear the whole data page too
- * if we don't do this. I have no clue why, but I seem to have 'fixed'
- * it in the doc2000 driver in August 1999. dwmw2.
- */
- chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
-
- /* Check, if it is write protected */
- if (nand_check_wp(mtd))
- return -EROFS;
-
- /* Invalidate the page cache, if we write to the cached page */
- if (page == chip->pagebuf)
- chip->pagebuf = -1;
-
- memset(chip->oob_poi, 0xff, mtd->oobsize);
- nand_fill_oob(chip, ops->oobbuf, ops);
- status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
- memset(chip->oob_poi, 0xff, mtd->oobsize);
-
- if (status)
- return status;
-
- ops->oobretlen = ops->ooblen;
-
- return 0;
-}
-
-/**
- * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
- * @mtd: MTD device structure
- * @to: offset to write to
- * @ops: oob operation description structure
- */
-static int nand_write_oob(struct mtd_info *mtd, loff_t to,
- struct mtd_oob_ops *ops)
-{
- struct nand_chip *chip = mtd->priv;
- int ret = -ENOSYS;
-
- ops->retlen = 0;
-
- /* Do not allow writes past end of device */
- if (ops->datbuf && (to + ops->len) > mtd->size) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
- "Attempt read beyond end of device\n");
- return -EINVAL;
- }
-
- nand_get_device(chip, mtd, FL_WRITING);
-
- switch(ops->mode) {
- case MTD_OOB_PLACE:
- case MTD_OOB_AUTO:
- case MTD_OOB_RAW:
- break;
-
- default:
- goto out;
- }
-
- if (!ops->datbuf)
- ret = nand_do_write_oob(mtd, to, ops);
- else
- ret = nand_do_write_ops(mtd, to, ops);
-
- out:
- nand_release_device(mtd);
- return ret;
-}
-
-/**
- * single_erease_cmd - [GENERIC] NAND standard block erase command function
- * @mtd: MTD device structure
- * @page: the page address of the block which will be erased
- *
- * Standard erase command for NAND chips
- */
-static void single_erase_cmd(struct mtd_info *mtd, int page)
-{
- struct nand_chip *chip = mtd->priv;
- /* Send commands to erase a block */
- chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
- chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
-}
-
-/**
- * multi_erease_cmd - [GENERIC] AND specific block erase command function
- * @mtd: MTD device structure
- * @page: the page address of the block which will be erased
- *
- * AND multi block erase command function
- * Erase 4 consecutive blocks
- */
-static void multi_erase_cmd(struct mtd_info *mtd, int page)
-{
- struct nand_chip *chip = mtd->priv;
- /* Send commands to erase a block */
- chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
- chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
- chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
- chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
- chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
-}
-
-/**
- * nand_erase - [MTD Interface] erase block(s)
- * @mtd: MTD device structure
- * @instr: erase instruction
- *
- * Erase one ore more blocks
- */
-static int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
-{
- return nand_erase_nand(mtd, instr, 0);
-}
-
-#define BBT_PAGE_MASK 0xffffff3f
-/**
- * nand_erase_nand - [Internal] erase block(s)
- * @mtd: MTD device structure
- * @instr: erase instruction
- * @allowbbt: allow erasing the bbt area
- *
- * Erase one ore more blocks
- */
-int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
- int allowbbt)
-{
- int page, len, status, pages_per_block, ret, chipnr;
- struct nand_chip *chip = mtd->priv;
- int rewrite_bbt[NAND_MAX_CHIPS]={0};
- unsigned int bbt_masked_page = 0xffffffff;
-
- MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
- (unsigned int)instr->addr, (unsigned int)instr->len);
-
- /* Start address must align on block boundary */
- if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
- return -EINVAL;
- }
-
- /* Length must align on block boundary */
- if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
- "Length not block aligned\n");
- return -EINVAL;
- }
-
- /* Do not allow erase past end of device */
- if ((instr->len + instr->addr) > mtd->size) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
- "Erase past end of device\n");
- return -EINVAL;
- }
-
- instr->fail_addr = 0xffffffff;
-
- /* Grab the lock and see if the device is available */
- nand_get_device(chip, mtd, FL_ERASING);
-
- /* Shift to get first page */
- page = (int)(instr->addr >> chip->page_shift);
- chipnr = (int)(instr->addr >> chip->chip_shift);
-
- /* Calculate pages in each block */
- pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
-
- /* Select the NAND device */
- chip->select_chip(mtd, chipnr);
-
- /* Check, if it is write protected */
- if (nand_check_wp(mtd)) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
- "Device is write protected!!!\n");
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
- }
-
- /*
- * If BBT requires refresh, set the BBT page mask to see if the BBT
- * should be rewritten. Otherwise the mask is set to 0xffffffff which
- * can not be matched. This is also done when the bbt is actually
- * erased to avoid recusrsive updates
- */
- if (chip->options & BBT_AUTO_REFRESH && !allowbbt)
- bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
-
- /* Loop through the pages */
- len = instr->len;
-
- instr->state = MTD_ERASING;
-
- while (len) {
- /*
- * heck if we have a bad block, we do not erase bad blocks !
- */
- if (nand_block_checkbad(mtd, ((loff_t) page) <<
- chip->page_shift, 0, allowbbt)) {
- printk(KERN_WARNING "nand_erase: attempt to erase a "
- "bad block at page 0x%08x\n", page);
- instr->state = MTD_ERASE_FAILED;
- goto erase_exit;
- }
-
- /*
- * Invalidate the page cache, if we erase the block which
- * contains the current cached page
- */
- if (page <= chip->pagebuf && chip->pagebuf <
- (page + pages_per_block))
- chip->pagebuf = -1;
-
- chip->erase_cmd(mtd, page & chip->pagemask);
-
- status = chip->waitfunc(mtd, chip);
-
- /*
- * See if operation failed and additional status checks are
- * available
- */
- if ((status & NAND_STATUS_FAIL) && (chip->errstat))
- status = chip->errstat(mtd, chip, FL_ERASING,
- status, page);
-
- /* See if block erase succeeded */
- if (status & NAND_STATUS_FAIL) {
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
- "Failed erase, page 0x%08x\n", page);
- instr->state = MTD_ERASE_FAILED;
- instr->fail_addr = (page << chip->page_shift);
- goto erase_exit;
- }
-
- /*
- * If BBT requires refresh, set the BBT rewrite flag to the
- * page being erased
- */
- if (bbt_masked_page != 0xffffffff &&
- (page & BBT_PAGE_MASK) == bbt_masked_page)
- rewrite_bbt[chipnr] = (page << chip->page_shift);
-
- /* Increment page address and decrement length */
- len -= (1 << chip->phys_erase_shift);
- page += pages_per_block;
-
- /* Check, if we cross a chip boundary */
- if (len && !(page & chip->pagemask)) {
- chipnr++;
- chip->select_chip(mtd, -1);
- chip->select_chip(mtd, chipnr);
-
- /*
- * If BBT requires refresh and BBT-PERCHIP, set the BBT
- * page mask to see if this BBT should be rewritten
- */
- if (bbt_masked_page != 0xffffffff &&
- (chip->bbt_td->options & NAND_BBT_PERCHIP))
- bbt_masked_page = chip->bbt_td->pages[chipnr] &
- BBT_PAGE_MASK;
- }
- }
- instr->state = MTD_ERASE_DONE;
-
- erase_exit:
-
- ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
-
- /* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
-
- /* Do call back function */
- if (!ret)
- mtd_erase_callback(instr);
-
- /*
- * If BBT requires refresh and erase was successful, rewrite any
- * selected bad block tables
- */
- if (bbt_masked_page == 0xffffffff || ret)
- return ret;
-
- for (chipnr = 0; chipnr < chip->numchips; chipnr++) {
- if (!rewrite_bbt[chipnr])
- continue;
- /* update the BBT for chip */
- MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
- "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
- chip->bbt_td->pages[chipnr]);
- nand_update_bbt(mtd, rewrite_bbt[chipnr]);
- }
-
- /* Return more or less happy */
- return ret;
-}
-
-/**
- * nand_sync - [MTD Interface] sync
- * @mtd: MTD device structure
- *
- * Sync is actually a wait for chip ready function
- */
-static void nand_sync(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
-
- MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
-
- /* Grab the lock and see if the device is available */
- nand_get_device(chip, mtd, FL_SYNCING);
- /* Release it and go back */
- nand_release_device(mtd);
-}
/**
* nand_block_isbad - [MTD Interface] Check if block at offset is bad
* @mtd: MTD device structure
* @offs: offset relative to mtd start
*/
-static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
+int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
{
/* Check for invalid offset */
if (offs > mtd->size)
@@ -2113,52 +981,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
return nand_block_checkbad(mtd, offs, 1, 0);
}
-/**
- * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
- * @mtd: MTD device structure
- * @ofs: offset relative to mtd start
- */
-static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
-{
- struct nand_chip *chip = mtd->priv;
- int ret;
-
- if ((ret = nand_block_isbad(mtd, ofs))) {
- /* If it was bad already, return success and do nothing. */
- if (ret > 0)
- return 0;
- return ret;
- }
-
- return chip->block_markbad(mtd, ofs);
-}
-
-/**
- * nand_suspend - [MTD Interface] Suspend the NAND flash
- * @mtd: MTD device structure
- */
-static int nand_suspend(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
-
- return nand_get_device(chip, mtd, FL_PM_SUSPENDED);
-}
-
-/**
- * nand_resume - [MTD Interface] Resume the NAND flash
- * @mtd: MTD device structure
- */
-static void nand_resume(struct mtd_info *mtd)
-{
- struct nand_chip *chip = mtd->priv;
-
- if (chip->state == FL_PM_SUSPENDED)
- nand_release_device(mtd);
- else
- printk(KERN_ERR "nand_resume() called for a chip which is not "
- "in suspended state\n");
-}
-
/*
* Set default functions
*/
@@ -2184,17 +1006,20 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
chip->read_word = nand_read_word;
if (!chip->block_bad)
chip->block_bad = nand_block_bad;
+#ifdef CONFIG_NAND_WRITE
if (!chip->block_markbad)
chip->block_markbad = nand_default_block_markbad;
if (!chip->write_buf)
chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
+#endif
if (!chip->read_buf)
chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
if (!chip->verify_buf)
chip->verify_buf = busw ? nand_verify_buf16 : nand_verify_buf;
+#ifdef CONFIG_NAND_BBT
if (!chip->scan_bbt)
chip->scan_bbt = nand_default_bbt;
-
+#endif
if (!chip->controller) {
chip->controller = &chip->hwcontrol;
}
@@ -2341,12 +1166,13 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize)
chip->options &= ~NAND_SAMSUNG_LP_OPTIONS;
+#ifdef CONFIG_NAND_WRITE
/* Check for AND chips with 4 page planes */
if (chip->options & NAND_4PAGE_ARRAY)
chip->erase_cmd = multi_erase_cmd;
else
chip->erase_cmd = single_erase_cmd;
-
+#endif
/* Do not replace user supplied command function ! */
if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
chip->cmdfunc = nand_command_lp;
@@ -2408,6 +1234,23 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips)
return 0;
}
+static void __maybe_unused nand_check_hwecc(struct mtd_info *mtd, struct nand_chip *chip)
+{
+ if ((!chip->ecc.calculate || !chip->ecc.correct ||
+ !chip->ecc.hwctl) &&
+ (!chip->ecc.read_page || !chip->ecc.write_page)) {
+ printk(KERN_WARNING "No ECC functions supplied, "
+ "Hardware ECC not possible\n");
+ BUG();
+ }
+
+ if (mtd->writesize < chip->ecc.size) {
+ printk(KERN_WARNING "%d byte HW ECC not possible on "
+ "%d byte page size\n",
+ chip->ecc.size, mtd->writesize);
+ BUG();
+ }
+}
/**
* nand_scan_tail - [NAND Interface] Scan for the NAND device
@@ -2452,8 +1295,10 @@ int nand_scan_tail(struct mtd_info *mtd)
}
}
+#ifdef CONFIG_NAND_WRITE
if (!chip->write_page)
chip->write_page = nand_write_page;
+#endif
/*
* check ECC mode, default to software if 3byte/512byte hardware ECC is
@@ -2461,71 +1306,42 @@ int nand_scan_tail(struct mtd_info *mtd)
*/
if (!chip->ecc.read_page_raw)
chip->ecc.read_page_raw = nand_read_page_raw;
+#ifdef CONFIG_NAND_WRITE
if (!chip->ecc.write_page_raw)
chip->ecc.write_page_raw = nand_write_page_raw;
-
+#endif
switch (chip->ecc.mode) {
+#ifdef CONFIG_NAND_ECC_HW
case NAND_ECC_HW:
- /* Use standard hwecc read page function ? */
- if (!chip->ecc.read_page)
- chip->ecc.read_page = nand_read_page_hwecc;
- if (!chip->ecc.write_page)
- chip->ecc.write_page = nand_write_page_hwecc;
- if (!chip->ecc.read_oob)
- chip->ecc.read_oob = nand_read_oob_std;
- if (!chip->ecc.write_oob)
- chip->ecc.write_oob = nand_write_oob_std;
-
+ nand_check_hwecc(mtd, chip);
+ nand_init_ecc_hw(chip);
+ break;
+#endif
+#ifdef CONFIG_NAND_ECC_HW_SYNDROME
case NAND_ECC_HW_SYNDROME:
- if ((!chip->ecc.calculate || !chip->ecc.correct ||
- !chip->ecc.hwctl) &&
- (!chip->ecc.read_page ||
- chip->ecc.read_page == nand_read_page_hwecc ||
- !chip->ecc.write_page ||
- chip->ecc.write_page == nand_write_page_hwecc)) {
- printk(KERN_WARNING "No ECC functions supplied, "
- "Hardware ECC not possible\n");
- BUG();
- }
- /* Use standard syndrome read/write page function ? */
- if (!chip->ecc.read_page)
- chip->ecc.read_page = nand_read_page_syndrome;
- if (!chip->ecc.write_page)
- chip->ecc.write_page = nand_write_page_syndrome;
- if (!chip->ecc.read_oob)
- chip->ecc.read_oob = nand_read_oob_syndrome;
- if (!chip->ecc.write_oob)
- chip->ecc.write_oob = nand_write_oob_syndrome;
-
- if (mtd->writesize >= chip->ecc.size)
- break;
- printk(KERN_WARNING "%d byte HW ECC not possible on "
- "%d byte page size, fallback to SW ECC\n",
- chip->ecc.size, mtd->writesize);
- chip->ecc.mode = NAND_ECC_SOFT;
-
+ nand_check_hwecc(mtd, chip);
+ nand_init_ecc_hw_syndrome(chip);
+ break;
+#endif
+#ifdef CONFIG_NAND_ECC_SOFT
case NAND_ECC_SOFT:
- chip->ecc.calculate = nand_calculate_ecc;
- chip->ecc.correct = nand_correct_data;
- chip->ecc.read_page = nand_read_page_swecc;
- chip->ecc.write_page = nand_write_page_swecc;
- chip->ecc.read_oob = nand_read_oob_std;
- chip->ecc.write_oob = nand_write_oob_std;
- chip->ecc.size = 256;
- chip->ecc.bytes = 3;
+ nand_init_ecc_soft(chip);
break;
-
+#endif
+#ifdef CONFIG_NAND_ECC_NONE
case NAND_ECC_NONE:
printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
"This is not recommended !!\n");
chip->ecc.read_page = nand_read_page_raw;
+#ifdef CONFIG_NAND_WRITE
chip->ecc.write_page = nand_write_page_raw;
- chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.write_oob = nand_write_oob_std;
+#endif
+ chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.size = mtd->writesize;
chip->ecc.bytes = 0;
break;
-
+#endif
default:
printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
chip->ecc.mode);
@@ -2583,28 +1399,33 @@ int nand_scan_tail(struct mtd_info *mtd)
/* Fill in remaining MTD driver data */
mtd->type = MTD_NANDFLASH;
mtd->flags = MTD_CAP_NANDFLASH;
+#ifdef CONFIG_NAND_WRITE
mtd->erase = nand_erase;
- mtd->read = nand_read;
mtd->write = nand_write;
- mtd->read_oob = nand_read_oob;
mtd->write_oob = nand_write_oob;
- mtd->sync = nand_sync;
+#endif
+ mtd->read = nand_read;
+#ifdef CONFIG_NAND_READ_OOB
+ mtd->read_oob = nand_read_oob;
+#endif
mtd->lock = NULL;
mtd->unlock = NULL;
- mtd->suspend = nand_suspend;
- mtd->resume = nand_resume;
mtd->block_isbad = nand_block_isbad;
+#ifdef CONFIG_NAND_WRITE
mtd->block_markbad = nand_block_markbad;
-
+#endif
/* propagate ecc.layout to mtd_info */
mtd->ecclayout = chip->ecc.layout;
/* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN)
return 0;
-
+#ifdef CONFIG_NAND_BBT
/* Build bad block table */
return chip->scan_bbt(mtd);
+#else
+ return 0;
+#endif
}
/**
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 4a6bf390..bf3a7dbc 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -557,6 +557,7 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt
* (Re)write the bad block table
*
*/
+#ifdef CONFIG_NAND_WRITE
static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
struct nand_bbt_descr *td, struct nand_bbt_descr *md,
int chipsel)
@@ -745,6 +746,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
"nand_bbt: Error while writing bad block table %d\n", res);
return res;
}
+#else
+static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
+ struct nand_bbt_descr *td, struct nand_bbt_descr *md,
+ int chipsel)
+{
+ return 0;
+}
+#endif
/**
* nand_memory_bbt - [GENERIC] create a memory based bad block table
diff --git a/drivers/mtd/nand/nand_hwecc.c b/drivers/mtd/nand/nand_hwecc.c
new file mode 100644
index 00000000..95b08d3a
--- /dev/null
+++ b/drivers/mtd/nand/nand_hwecc.c
@@ -0,0 +1,103 @@
+#include <common.h>
+#include <errno.h>
+#include <clock.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/err.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+#include "nand.h"
+
+/**
+ * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ *
+ * Not for syndrome calculating ecc controllers which need a special oob layout
+ */
+static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ }
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+ return 0;
+}
+
+/**
+ * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+#ifdef CONFIG_NAND_WRITE
+static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->write_buf(mtd, p, eccsize);
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+ }
+
+ for (i = 0; i < chip->ecc.total; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+#endif
+
+void nand_init_ecc_hw(struct nand_chip *chip)
+{
+ /* Use standard hwecc read page function ? */
+ if (!chip->ecc.read_page)
+ chip->ecc.read_page = nand_read_page_hwecc;
+#ifdef CONFIG_NAND_READ_OOB
+ if (!chip->ecc.read_oob)
+ chip->ecc.read_oob = nand_read_oob_std;
+#endif
+#ifdef CONFIG_NAND_WRITE
+ if (!chip->ecc.write_oob)
+ chip->ecc.write_oob = nand_write_oob_std;
+ if (!chip->ecc.write_page)
+ chip->ecc.write_page = nand_write_page_hwecc;
+#endif
+}
diff --git a/drivers/mtd/nand/nand_hwecc_syndrome.c b/drivers/mtd/nand/nand_hwecc_syndrome.c
new file mode 100644
index 00000000..9a661809
--- /dev/null
+++ b/drivers/mtd/nand/nand_hwecc_syndrome.c
@@ -0,0 +1,225 @@
+#include <common.h>
+#include <errno.h>
+#include <clock.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/err.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <module.h>
+
+/**
+ * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ *
+ * The hw generator calculates the error syndrome automatically. Therefor
+ * we need a special oob layout and handling.
+ */
+static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READ);
+ chip->read_buf(mtd, p, eccsize);
+
+ if (chip->ecc.prepad) {
+ chip->read_buf(mtd, oob, chip->ecc.prepad);
+ oob += chip->ecc.prepad;
+ }
+
+ chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
+ chip->read_buf(mtd, oob, eccbytes);
+ stat = chip->ecc.correct(mtd, p, oob, NULL);
+
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->read_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
+ }
+ }
+
+ /* Calculate remaining oob bytes */
+ i = mtd->oobsize - (oob - chip->oob_poi);
+ if (i)
+ chip->read_buf(mtd, oob, i);
+
+ return 0;
+}
+/**
+ * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ *
+ * The hw generator calculates the error syndrome automatically. Therefor
+ * we need a special oob layout and handling.
+ */
+#ifdef CONFIG_NAND_WRITE
+static void nand_write_page_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ const uint8_t *p = buf;
+ uint8_t *oob = chip->oob_poi;
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+
+ chip->ecc.hwctl(mtd, NAND_ECC_WRITE);
+ chip->write_buf(mtd, p, eccsize);
+
+ if (chip->ecc.prepad) {
+ chip->write_buf(mtd, oob, chip->ecc.prepad);
+ oob += chip->ecc.prepad;
+ }
+
+ chip->ecc.calculate(mtd, p, oob);
+ chip->write_buf(mtd, oob, eccbytes);
+ oob += eccbytes;
+
+ if (chip->ecc.postpad) {
+ chip->write_buf(mtd, oob, chip->ecc.postpad);
+ oob += chip->ecc.postpad;
+ }
+ }
+
+ /* Calculate remaining oob bytes */
+ i = mtd->oobsize - (oob - chip->oob_poi);
+ if (i)
+ chip->write_buf(mtd, oob, i);
+}
+#endif
+
+/**
+ * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC
+ * with syndromes
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to read
+ * @sndcmd: flag whether to issue read command or not
+ */
+static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
+ int page, int sndcmd)
+{
+ uint8_t *buf = chip->oob_poi;
+ int length = mtd->oobsize;
+ int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+ int eccsize = chip->ecc.size;
+ uint8_t *bufpoi = buf;
+ int i, toread, sndrnd = 0, pos;
+
+ chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
+ for (i = 0; i < chip->ecc.steps; i++) {
+ if (sndrnd) {
+ pos = eccsize + i * (eccsize + chunk);
+ if (mtd->writesize > 512)
+ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1);
+ else
+ chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page);
+ } else
+ sndrnd = 1;
+ toread = min_t(int, length, chunk);
+ chip->read_buf(mtd, bufpoi, toread);
+ bufpoi += toread;
+ length -= toread;
+ }
+ if (length > 0)
+ chip->read_buf(mtd, bufpoi, length);
+
+ return 1;
+}
+
+/**
+ * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC
+ * with syndrome - only for large page flash !
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
+ */
+#ifdef CONFIG_NAND_WRITE
+static int nand_write_oob_syndrome(struct mtd_info *mtd,
+ struct nand_chip *chip, int page)
+{
+ int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
+ int eccsize = chip->ecc.size, length = mtd->oobsize;
+ int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps;
+ const uint8_t *bufpoi = chip->oob_poi;
+
+ /*
+ * data-ecc-data-ecc ... ecc-oob
+ * or
+ * data-pad-ecc-pad-data-pad .... ecc-pad-oob
+ */
+ if (!chip->ecc.prepad && !chip->ecc.postpad) {
+ pos = steps * (eccsize + chunk);
+ steps = 0;
+ } else
+ pos = eccsize;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page);
+ for (i = 0; i < steps; i++) {
+ if (sndcmd) {
+ if (mtd->writesize <= 512) {
+ uint32_t fill = 0xFFFFFFFF;
+
+ len = eccsize;
+ while (len > 0) {
+ int num = min_t(int, len, 4);
+ chip->write_buf(mtd, (uint8_t *)&fill,
+ num);
+ len -= num;
+ }
+ } else {
+ pos = eccsize + i * (eccsize + chunk);
+ chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1);
+ }
+ } else
+ sndcmd = 1;
+ len = min_t(int, length, chunk);
+ chip->write_buf(mtd, bufpoi, len);
+ bufpoi += len;
+ length -= len;
+ }
+ if (length > 0)
+ chip->write_buf(mtd, bufpoi, length);
+
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+#endif
+
+void nand_init_ecc_hw_syndrome(struct nand_chip *chip)
+{
+ /* Use standard syndrome read/write page function ? */
+ if (!chip->ecc.read_page)
+ chip->ecc.read_page = nand_read_page_syndrome;
+ if (!chip->ecc.read_oob)
+ chip->ecc.read_oob = nand_read_oob_syndrome;
+#ifdef CONFIG_NAND_WRITE
+ if (!chip->ecc.write_page)
+ chip->ecc.write_page = nand_write_page_syndrome;
+ if (!chip->ecc.write_oob)
+ chip->ecc.write_oob = nand_write_oob_syndrome;
+#endif
+}
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index f95975c9..cb53fc61 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -12,6 +12,13 @@
*/
#include <common.h>
#include <linux/mtd/nand.h>
+
+#ifdef CONFIG_NAND_INFO
+#define __NANDSTR(str) str
+#else
+#define __NANDSTR(str) ""
+#endif
+
/*
* Chip ID list
*
@@ -26,47 +33,47 @@
struct nand_flash_dev nand_flash_ids[] = {
#ifdef CONFIG_MTD_NAND_MUSEUM_IDS
- {"NAND 1MiB 5V 8-bit", 0x6e, 256, 1, 0x1000, 0},
- {"NAND 2MiB 5V 8-bit", 0x64, 256, 2, 0x1000, 0},
- {"NAND 4MiB 5V 8-bit", 0x6b, 512, 4, 0x2000, 0},
- {"NAND 1MiB 3,3V 8-bit", 0xe8, 256, 1, 0x1000, 0},
- {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0},
- {"NAND 2MiB 3,3V 8-bit", 0xea, 256, 2, 0x1000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xd5, 512, 4, 0x2000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xe3, 512, 4, 0x2000, 0},
- {"NAND 4MiB 3,3V 8-bit", 0xe5, 512, 4, 0x2000, 0},
- {"NAND 8MiB 3,3V 8-bit", 0xd6, 512, 8, 0x2000, 0},
-
- {"NAND 8MiB 1,8V 8-bit", 0x39, 512, 8, 0x2000, 0},
- {"NAND 8MiB 3,3V 8-bit", 0xe6, 512, 8, 0x2000, 0},
- {"NAND 8MiB 1,8V 16-bit", 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
- {"NAND 8MiB 3,3V 16-bit", 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 1MiB 5V 8-bit"), 0x6e, 256, 1, 0x1000, 0},
+ {__NANDSTR("NAND 2MiB 5V 8-bit"), 0x64, 256, 2, 0x1000, 0},
+ {__NANDSTR("NAND 4MiB 5V 8-bit"), 0x6b, 512, 4, 0x2000, 0},
+ {__NANDSTR("NAND 1MiB 3,3V 8-bit"), 0xe8, 256, 1, 0x1000, 0},
+ {__NANDSTR("NAND 1MiB 3,3V 8-bit"), 0xec, 256, 1, 0x1000, 0},
+ {__NANDSTR("NAND 2MiB 3,3V 8-bit"), 0xea, 256, 2, 0x1000, 0},
+ {__NANDSTR("NAND 4MiB 3,3V 8-bit"), 0xd5, 512, 4, 0x2000, 0},
+ {__NANDSTR("NAND 4MiB 3,3V 8-bit"), 0xe3, 512, 4, 0x2000, 0},
+ {__NANDSTR("NAND 4MiB 3,3V 8-bit"), 0xe5, 512, 4, 0x2000, 0},
+ {__NANDSTR("NAND 8MiB 3,3V 8-bit"), 0xd6, 512, 8, 0x2000, 0},
+
+ {__NANDSTR("NAND 8MiB 1,8V 8-bit"), 0x39, 512, 8, 0x2000, 0},
+ {__NANDSTR("NAND 8MiB 3,3V 8-bit"), 0xe6, 512, 8, 0x2000, 0},
+ {__NANDSTR("NAND 8MiB 1,8V 16-bit"), 0x49, 512, 8, 0x2000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 8MiB 3,3V 16-bit"), 0x59, 512, 8, 0x2000, NAND_BUSWIDTH_16},
#endif
- {"NAND 16MiB 1,8V 8-bit", 0x33, 512, 16, 0x4000, 0},
- {"NAND 16MiB 3,3V 8-bit", 0x73, 512, 16, 0x4000, 0},
- {"NAND 16MiB 1,8V 16-bit", 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 16MiB 3,3V 16-bit", 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 16MiB 1,8V 8-bit"), 0x33, 512, 16, 0x4000, 0},
+ {__NANDSTR("NAND 16MiB 3,3V 8-bit"), 0x73, 512, 16, 0x4000, 0},
+ {__NANDSTR("NAND 16MiB 1,8V 16-bit"), 0x43, 512, 16, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 16MiB 3,3V 16-bit"), 0x53, 512, 16, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 32MiB 1,8V 8-bit", 0x35, 512, 32, 0x4000, 0},
- {"NAND 32MiB 3,3V 8-bit", 0x75, 512, 32, 0x4000, 0},
- {"NAND 32MiB 1,8V 16-bit", 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 32MiB 3,3V 16-bit", 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 32MiB 1,8V 8-bit"), 0x35, 512, 32, 0x4000, 0},
+ {__NANDSTR("NAND 32MiB 3,3V 8-bit"), 0x75, 512, 32, 0x4000, 0},
+ {__NANDSTR("NAND 32MiB 1,8V 16-bit"), 0x45, 512, 32, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 32MiB 3,3V 16-bit"), 0x55, 512, 32, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 64MiB 1,8V 8-bit", 0x36, 512, 64, 0x4000, 0},
- {"NAND 64MiB 3,3V 8-bit", 0x76, 512, 64, 0x4000, 0},
- {"NAND 64MiB 1,8V 16-bit", 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 64MiB 1,8V 8-bit"), 0x36, 512, 64, 0x4000, 0},
+ {__NANDSTR("NAND 64MiB 3,3V 8-bit"), 0x76, 512, 64, 0x4000, 0},
+ {__NANDSTR("NAND 64MiB 1,8V 16-bit"), 0x46, 512, 64, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 64MiB 3,3V 16-bit"), 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
- {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
- {"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
- {"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 128MiB 1,8V 8-bit"), 0x78, 512, 128, 0x4000, 0},
+ {__NANDSTR("NAND 128MiB 1,8V 8-bit"), 0x39, 512, 128, 0x4000, 0},
+ {__NANDSTR("NAND 128MiB 3,3V 8-bit"), 0x79, 512, 128, 0x4000, 0},
+ {__NANDSTR("NAND 128MiB 1,8V 16-bit"), 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 128MiB 1,8V 16-bit"), 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 128MiB 3,3V 16-bit"), 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {__NANDSTR("NAND 128MiB 3,3V 16-bit"), 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
- {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
+ {__NANDSTR("NAND 256MiB 3,3V 8-bit"), 0x71, 512, 256, 0x4000, 0},
/*
* These are the new chips with large page size. The pagesize and the
@@ -76,40 +83,40 @@ struct nand_flash_dev nand_flash_ids[] = {
#define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16)
/*512 Megabit */
- {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS},
- {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS},
- {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16},
- {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 64MiB 1,8V 8-bit"), 0xA2, 0, 64, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 64MiB 3,3V 8-bit"), 0xF2, 0, 64, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 64MiB 1,8V 16-bit"), 0xB2, 0, 64, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 64MiB 3,3V 16-bit"), 0xC2, 0, 64, 0, LP_OPTIONS16},
/* 1 Gigabit */
- {"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, LP_OPTIONS},
- {"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, LP_OPTIONS},
- {"NAND 128MiB 1,8V 16-bit", 0xB1, 0, 128, 0, LP_OPTIONS16},
- {"NAND 128MiB 3,3V 16-bit", 0xC1, 0, 128, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 128MiB 1,8V 8-bit"), 0xA1, 0, 128, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 128MiB 3,3V 8-bit"), 0xF1, 0, 128, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 128MiB 1,8V 16-bit"), 0xB1, 0, 128, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 128MiB 3,3V 16-bit"), 0xC1, 0, 128, 0, LP_OPTIONS16},
/* 2 Gigabit */
- {"NAND 256MiB 1,8V 8-bit", 0xAA, 0, 256, 0, LP_OPTIONS},
- {"NAND 256MiB 3,3V 8-bit", 0xDA, 0, 256, 0, LP_OPTIONS},
- {"NAND 256MiB 1,8V 16-bit", 0xBA, 0, 256, 0, LP_OPTIONS16},
- {"NAND 256MiB 3,3V 16-bit", 0xCA, 0, 256, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 256MiB 1,8V 8-bit"), 0xAA, 0, 256, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 256MiB 3,3V 8-bit"), 0xDA, 0, 256, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 256MiB 1,8V 16-bit"), 0xBA, 0, 256, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 256MiB 3,3V 16-bit"), 0xCA, 0, 256, 0, LP_OPTIONS16},
/* 4 Gigabit */
- {"NAND 512MiB 1,8V 8-bit", 0xAC, 0, 512, 0, LP_OPTIONS},
- {"NAND 512MiB 3,3V 8-bit", 0xDC, 0, 512, 0, LP_OPTIONS},
- {"NAND 512MiB 1,8V 16-bit", 0xBC, 0, 512, 0, LP_OPTIONS16},
- {"NAND 512MiB 3,3V 16-bit", 0xCC, 0, 512, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 512MiB 1,8V 8-bit"), 0xAC, 0, 512, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 512MiB 3,3V 8-bit"), 0xDC, 0, 512, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 512MiB 1,8V 16-bit"), 0xBC, 0, 512, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 512MiB 3,3V 16-bit"), 0xCC, 0, 512, 0, LP_OPTIONS16},
/* 8 Gigabit */
- {"NAND 1GiB 1,8V 8-bit", 0xA3, 0, 1024, 0, LP_OPTIONS},
- {"NAND 1GiB 3,3V 8-bit", 0xD3, 0, 1024, 0, LP_OPTIONS},
- {"NAND 1GiB 1,8V 16-bit", 0xB3, 0, 1024, 0, LP_OPTIONS16},
- {"NAND 1GiB 3,3V 16-bit", 0xC3, 0, 1024, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 1GiB 1,8V 8-bit"), 0xA3, 0, 1024, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 1GiB 3,3V 8-bit"), 0xD3, 0, 1024, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 1GiB 1,8V 16-bit"), 0xB3, 0, 1024, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 1GiB 3,3V 16-bit"), 0xC3, 0, 1024, 0, LP_OPTIONS16},
/* 16 Gigabit */
- {"NAND 2GiB 1,8V 8-bit", 0xA5, 0, 2048, 0, LP_OPTIONS},
- {"NAND 2GiB 3,3V 8-bit", 0xD5, 0, 2048, 0, LP_OPTIONS},
- {"NAND 2GiB 1,8V 16-bit", 0xB5, 0, 2048, 0, LP_OPTIONS16},
- {"NAND 2GiB 3,3V 16-bit", 0xC5, 0, 2048, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 2GiB 1,8V 8-bit"), 0xA5, 0, 2048, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 2GiB 3,3V 8-bit"), 0xD5, 0, 2048, 0, LP_OPTIONS},
+ {__NANDSTR("NAND 2GiB 1,8V 16-bit"), 0xB5, 0, 2048, 0, LP_OPTIONS16},
+ {__NANDSTR("NAND 2GiB 3,3V 16-bit"), 0xC5, 0, 2048, 0, LP_OPTIONS16},
/*
* Renesas AND 1 Gigabit. Those chips do not support extended id and
@@ -121,7 +128,7 @@ struct nand_flash_dev nand_flash_ids[] = {
* erased in one go There are more speed improvements for reads and
* writes possible, but not implemented now
*/
- {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000,
+ {__NANDSTR("AND 128MiB 3,3V 8-bit"), 0x01, 2048, 128, 0x4000,
NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY |
BBT_AUTO_REFRESH
},
@@ -133,15 +140,15 @@ struct nand_flash_dev nand_flash_ids[] = {
* Manufacturer ID list
*/
struct nand_manufacturers nand_manuf_ids[] = {
- {NAND_MFR_TOSHIBA, "Toshiba"},
- {NAND_MFR_SAMSUNG, "Samsung"},
- {NAND_MFR_FUJITSU, "Fujitsu"},
- {NAND_MFR_NATIONAL, "National"},
- {NAND_MFR_RENESAS, "Renesas"},
- {NAND_MFR_STMICRO, "ST Micro"},
- {NAND_MFR_HYNIX, "Hynix"},
- {NAND_MFR_MICRON, "Micron"},
- {NAND_MFR_AMD, "AMD"},
+ {NAND_MFR_TOSHIBA, __NANDSTR("Toshiba")},
+ {NAND_MFR_SAMSUNG, __NANDSTR("Samsung")},
+ {NAND_MFR_FUJITSU, __NANDSTR("Fujitsu")},
+ {NAND_MFR_NATIONAL, __NANDSTR("National")},
+ {NAND_MFR_RENESAS, __NANDSTR("Renesas")},
+ {NAND_MFR_STMICRO, __NANDSTR("ST Micro")},
+ {NAND_MFR_HYNIX, __NANDSTR("Hynix")},
+ {NAND_MFR_MICRON, __NANDSTR("Micron")},
+ {NAND_MFR_AMD, __NANDSTR("AMD")},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/nand_omap_bch_decoder.c b/drivers/mtd/nand/nand_omap_bch_decoder.c
new file mode 100644
index 00000000..356f71f0
--- /dev/null
+++ b/drivers/mtd/nand/nand_omap_bch_decoder.c
@@ -0,0 +1,389 @@
+/*
+ * drivers/mtd/nand/omap_omap_bch_decoder.c
+ *
+ * Whole BCH ECC Decoder (Post hardware generated syndrome decoding)
+ *
+ * Copyright (c) 2007 Texas Instruments
+ *
+ * Author: Sukumar Ghorai <s-ghorai@xxxxxx
+ * Michael Fillinger <m-fillinger@xxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+
+#define mm 13
+#define kk_shorten 4096
+#define nn 8191 /* Length of codeword, n = 2**mm - 1 */
+
+#define PPP 0x201B /* Primary Polynomial : x^13 + x^4 + x^3 + x + 1 */
+#define P 0x001B /* With omitted x^13 */
+#define POLY 12 /* degree of the primary Polynomial less one */
+
+/**
+ * mpy_mod_gf - GALOIS field multiplier
+ * Input : A(x), B(x)
+ * Output : A(x)*B(x) mod P(x)
+ */
+static unsigned int mpy_mod_gf(unsigned int a, unsigned int b)
+{
+ unsigned int R = 0;
+ unsigned int R1 = 0;
+ unsigned int k = 0;
+
+ for (k = 0; k < mm; k++) {
+
+ R = (R << 1) & 0x1FFE;
+ if (R1 == 1)
+ R ^= P;
+
+ if (((a >> (POLY - k)) & 1) == 1)
+ R ^= b;
+
+ if (k < POLY)
+ R1 = (R >> POLY) & 1;
+ }
+ return R;
+}
+
+/**
+ * chien - CHIEN search
+ *
+ * @location - Error location vector pointer
+ *
+ * Inputs : ELP(z)
+ * No. of found errors
+ * Size of input codeword
+ * Outputs : Up to 8 locations
+ * No. of errors
+ */
+static int chien(unsigned int select_4_8, int err_nums,
+ unsigned int err[], unsigned int *location)
+{
+ int i, count; /* Number of dectected errors */
+ /* Contains accumulation of evaluation at x^i (i:1->8) */
+ unsigned int gammas[8] = {0};
+ unsigned int alpha;
+ unsigned int bit, ecc_bits;
+ unsigned int elp_sum;
+
+ ecc_bits = (select_4_8 == 0) ? 52 : 104;
+
+ /* Start evaluation at Alpha**8192 and decreasing */
+ for (i = 0; i < 8; i++)
+ gammas[i] = err[i];
+
+ count = 0;
+ for (i = 1; (i <= nn) && (count < err_nums); i++) {
+
+ /* Result of evaluation at root */
+ elp_sum = 1 ^ gammas[0] ^ gammas[1] ^
+ gammas[2] ^ gammas[3] ^
+ gammas[4] ^ gammas[5] ^
+ gammas[6] ^ gammas[7];
+
+ alpha = PPP >> 1;
+ gammas[0] = mpy_mod_gf(gammas[0], alpha);
+ alpha = mpy_mod_gf(alpha, (PPP >> 1)); /* x alphha^-2 */
+ gammas[1] = mpy_mod_gf(gammas[1], alpha);
+ alpha = mpy_mod_gf(alpha, (PPP >> 1)); /* x alphha^-2 */
+ gammas[2] = mpy_mod_gf(gammas[2], alpha);
+ alpha = mpy_mod_gf(alpha, (PPP >> 1)); /* x alphha^-3 */
+ gammas[3] = mpy_mod_gf(gammas[3], alpha);
+ alpha = mpy_mod_gf(alpha, (PPP >> 1)); /* x alphha^-4 */
+ gammas[4] = mpy_mod_gf(gammas[4], alpha);
+ alpha = mpy_mod_gf(alpha, (PPP >> 1)); /* x alphha^-5 */
+ gammas[5] = mpy_mod_gf(gammas[5], alpha);
+ alpha = mpy_mod_gf(alpha, (PPP >> 1)); /* x alphha^-6 */
+ gammas[6] = mpy_mod_gf(gammas[6], alpha);
+ alpha = mpy_mod_gf(alpha, (PPP >> 1)); /* x alphha^-7 */
+ gammas[7] = mpy_mod_gf(gammas[7], alpha);
+
+ if (elp_sum == 0) {
+ /* calculate bit position in main data area */
+ bit = ((i-1) & ~7)|(7-((i-1) & 7));
+ if (i >= 2 * ecc_bits)
+ location[count++] =
+ kk_shorten - (bit - 2 * ecc_bits) - 1;
+ }
+ }
+
+ /* Failure: No. of detected errors != No. or corrected errors */
+ if (count != err_nums) {
+ count = -1;
+ printk(KERN_ERR "BCH decoding failed\n");
+ }
+ for (i = 0; i < count; i++)
+ pr_debug("%d ", location[i]);
+
+ return count;
+}
+
+/* synd : 16 Syndromes
+ * return: gamaas - Coefficients to the error polynomial
+ * return: : Number of detected errors
+*/
+static unsigned int berlekamp(unsigned int select_4_8,
+ unsigned int synd[], unsigned int err[])
+{
+ int loop, iteration;
+ unsigned int LL = 0; /* Detected errors */
+ unsigned int d = 0; /* Distance between Syndromes and ELP[n](z) */
+ unsigned int invd = 0; /* Inverse of d */
+ /* Intermediate ELP[n](z).
+ * Final ELP[n](z) is Error Location Polynomial
+ */
+ unsigned int gammas[16] = {0};
+ /* Intermediate normalized ELP[n](z) : D[n](z) */
+ unsigned int D[16] = {0};
+ /* Temporary value that holds an ELP[n](z) coefficient */
+ unsigned int next_gamma = 0;
+
+ int e = 0;
+ unsigned int sign = 0;
+ unsigned int u = 0;
+ unsigned int v = 0;
+ unsigned int C1 = 0, C2 = 0;
+ unsigned int ss = 0;
+ unsigned int tmp_v = 0, tmp_s = 0;
+ unsigned int tmp_poly;
+
+ /*-------------- Step 0 ------------------*/
+ for (loop = 0; loop < 16; loop++)
+ gammas[loop] = 0;
+ gammas[0] = 1;
+ D[1] = 1;
+
+ iteration = 0;
+ LL = 0;
+ while ((iteration < ((select_4_8+1)*2*4)) &&
+ (LL <= ((select_4_8+1)*4))) {
+
+ pr_debug("\nIteration.............%d\n", iteration);
+ d = 0;
+ /* Step: 0 */
+ for (loop = 0; loop <= LL; loop++) {
+ tmp_poly = mpy_mod_gf(
+ gammas[loop], synd[iteration - loop]);
+ d ^= tmp_poly;
+ pr_debug("%02d. s=0 LL=%x poly %x\n",
+ loop, LL, tmp_poly);
+ }
+
+ /* Step 1: 1 cycle only to perform inversion */
+ v = d << 1;
+ e = -1;
+ sign = 1;
+ ss = 0x2000;
+ invd = 0;
+ u = PPP;
+ for (loop = 0; (d != 0) && (loop <= (2 * POLY)); loop++) {
+ pr_debug("%02d. s=1 LL=%x poly NULL\n",
+ loop, LL);
+ C1 = (v >> 13) & 1;
+ C2 = C1 & sign;
+
+ sign ^= C2 ^ (e == 0);
+
+ tmp_v = v;
+ tmp_s = ss;
+
+ if (C1 == 1) {
+ v ^= u;
+ ss ^= invd;
+ }
+ v = (v << 1) & 0x3FFF;
+ if (C2 == 1) {
+ u = tmp_v;
+ invd = tmp_s;
+ e = -e;
+ }
+ invd >>= 1;
+ e--;
+ }
+
+ for (loop = 0; (d != 0) && (loop <= (iteration + 1)); loop++) {
+ /* Step 2
+ * Interleaved with Step 3, if L<(n-k)
+ * invd: Update of ELP[n](z) = ELP[n-1](z) - d.D[n-1](z)
+ */
+
+ /* Holds value of ELP coefficient until precedent
+ * value does not have to be used anymore
+ */
+ tmp_poly = mpy_mod_gf(d, D[loop]);
+ pr_debug("%02d. s=2 LL=%x poly %x\n",
+ loop, LL, tmp_poly);
+
+ next_gamma = gammas[loop] ^ tmp_poly;
+ if ((2 * LL) < (iteration + 1)) {
+ /* Interleaving with Step 3
+ * for parallelized update of ELP(z) and D(z)
+ */
+ } else {
+ /* Update of ELP(z) only -> stay in Step 2 */
+ gammas[loop] = next_gamma;
+ if (loop == (iteration + 1)) {
+ /* to step 4 */
+ break;
+ }
+ }
+
+ /* Step 3
+ * Always interleaved with Step 2 (case when L<(n-k))
+ * Update of D[n-1](z) = ELP[n-1](z)/d
+ */
+ D[loop] = mpy_mod_gf(gammas[loop], invd);
+ pr_debug("%02d. s=3 LL=%x poly %x\n",
+ loop, LL, D[loop]);
+
+ /* Can safely update ELP[n](z) */
+ gammas[loop] = next_gamma;
+
+ if (loop == (iteration + 1)) {
+ /* If update finished */
+ LL = iteration - LL + 1;
+ /* to step 4 */
+ break;
+ }
+ /* Else, interleaving to step 2*/
+ }
+
+ /* Step 4: Update D(z): i:0->L */
+ /* Final update of D[n](z) = D[n](z).z*/
+ for (loop = 0; loop < 15; loop++) /* Left Shift */
+ D[15 - loop] = D[14 - loop];
+
+ D[0] = 0;
+
+ iteration++;
+ } /* while */
+
+ /* Processing finished, copy ELP to final registers : 0->2t-1*/
+ for (loop = 0; loop < 8; loop++)
+ err[loop] = gammas[loop+1];
+
+ pr_debug("\n Err poly:");
+ for (loop = 0; loop < 8; loop++)
+ pr_debug("0x%x ", err[loop]);
+
+ return LL;
+}
+
+/*
+ * syndrome - Generate syndrome components from hw generate syndrome
+ * r(x) = c(x) + e(x)
+ * s(x) = c(x) mod g(x) + e(x) mod g(x) = e(x) mod g(x)
+ * so receiver checks if the syndrome s(x) = r(x) mod g(x) is equal to zero.
+ * unsigned int s[16]; - Syndromes
+ */
+static void syndrome(unsigned int select_4_8,
+ unsigned char *ecc, unsigned int syn[])
+{
+ unsigned int k, l, t;
+ unsigned int alpha_bit, R_bit;
+ int ecc_pos, ecc_min;
+
+ /* 2t-1 = 15 (for t=8) minimal polynomials of the first 15 powers of a
+ * primitive elemmants of GF(m); Even powers minimal polynomials are
+ * duplicate of odd powers' minimal polynomials.
+ * Odd powers of alpha (1 to 15)
+ */
+ unsigned int pow_alpha[8] = {0x0002, 0x0008, 0x0020, 0x0080,
+ 0x0200, 0x0800, 0x001B, 0x006C};
+
+ pr_debug("\n ECC[0..n]: ");
+ for (k = 0; k < 13; k++)
+ pr_debug("0x%x ", ecc[k]);
+
+ if (select_4_8 == 0) {
+ t = 4;
+ ecc_pos = 55; /* bits(52-bits): 55->4 */
+ ecc_min = 4;
+ } else {
+ t = 8;
+ ecc_pos = 103; /* bits: 103->0 */
+ ecc_min = 0;
+ }
+
+ /* total numbber of syndrom to be used is 2t */
+ /* Step1: calculate the odd syndrome(s) */
+ R_bit = ((ecc[ecc_pos/8] >> (7 - ecc_pos%8)) & 1);
+ ecc_pos--;
+ for (k = 0; k < t; k++)
+ syn[2 * k] = R_bit;
+
+ while (ecc_pos >= ecc_min) {
+ R_bit = ((ecc[ecc_pos/8] >> (7 - ecc_pos%8)) & 1);
+ ecc_pos--;
+
+ for (k = 0; k < t; k++) {
+ /* Accumulate value of x^i at alpha^(2k+1) */
+ if (R_bit == 1)
+ syn[2*k] ^= pow_alpha[k];
+
+ /* Compute a**(2k+1), using LSFR */
+ for (l = 0; l < (2 * k + 1); l++) {
+ alpha_bit = (pow_alpha[k] >> POLY) & 1;
+ pow_alpha[k] = (pow_alpha[k] << 1) & 0x1FFF;
+ if (alpha_bit == 1)
+ pow_alpha[k] ^= P;
+ }
+ }
+ }
+
+ /* Step2: calculate the even syndrome(s)
+ * Compute S(a), where a is an even power of alpha
+ * Evenry even power of primitive element has the same minimal
+ * polynomial as some odd power of elemets.
+ * And based on S(a^2) = S^2(a)
+ */
+ for (k = 0; k < t; k++)
+ syn[2*k+1] = mpy_mod_gf(syn[k], syn[k]);
+
+ pr_debug("\n Syndromes: ");
+ for (k = 0; k < 16; k++)
+ pr_debug("0x%x ", syn[k]);
+}
+
+/**
+ * decode_bch - BCH decoder for 4- and 8-bit error correction
+ *
+ * @ecc - ECC syndrome generated by hw BCH engine
+ * @err_loc - pointer to error location array
+ *
+ * This function does post sydrome generation (hw generated) decoding
+ * for:-
+ * Dimension of Galoise Field: m = 13
+ * Length of codeword: n = 2**m - 1
+ * Number of errors that can be corrected: 4- or 8-bits
+ * Length of information bit: kk = nn - rr
+ */
+int decode_bch(int select_4_8, unsigned char *ecc, unsigned int *err_loc)
+{
+ int no_of_err;
+ unsigned int syn[16] = {0,}; /* 16 Syndromes */
+ unsigned int err_poly[8] = {0,};
+ /* Coefficients to the error polynomial
+ * ELP(x) = 1 + err0.x + err1.x^2 + ... + err7.x^8
+ */
+
+ /* Decoding involes three steps
+ * 1. Compute the syndrom from the received codeword,
+ * 2. Find the error location polynomial from a set of equations
+ * derived from the syndrome,
+ * 3. Use the error location polynomial to identify errants bits,
+ *
+ * And correction done by bit flips using error location and expected
+ * to be outseide of this implementation.
+ */
+ syndrome(select_4_8, ecc, syn);
+ no_of_err = berlekamp(select_4_8, syn, err_poly);
+ if (no_of_err <= (4 << select_4_8))
+ no_of_err = chien(select_4_8, no_of_err, err_poly, err_loc);
+
+ return no_of_err;
+}
diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c
index 7c9bc320..fc485514 100644
--- a/drivers/mtd/nand/nand_omap_gpmc.c
+++ b/drivers/mtd/nand/nand_omap_gpmc.c
@@ -76,15 +76,15 @@
#include <mach/gpmc.h>
#include <mach/gpmc_nand.h>
-/* Enable me to get tons of debug messages -for use without jtag */
-#if 0
-#define gpmcnand_dbg(FORMAT, ARGS...) fprintf(stdout,\
- "gpmc_nand:%s:%d:Entry:"FORMAT"\n",\
- __func__, __LINE__, ARGS)
-#else
-#define gpmcnand_dbg(FORMAT, ARGS...)
-#endif
-#define gpmcnand_err(ARGS...) fprintf(stderr, "omapnand: " ARGS);
+int decode_bch(int select_4_8, unsigned char *ecc, unsigned int *err_loc);
+
+static char *ecc_mode_strings[] = {
+ "software",
+ "hamming_hw_romcode",
+ "bch4_hw",
+ "bch8_hw",
+ "bch8_hw_romcode",
+};
/** internal structure maintained for nand information */
struct gpmc_nand_info {
@@ -103,10 +103,21 @@ struct gpmc_nand_info {
unsigned inuse:1;
unsigned wait_pol:1;
unsigned char ecc_parity_pairs;
- unsigned int ecc_config;
+ enum gpmc_ecc_mode ecc_mode;
};
/* Typical BOOTROM oob layouts-requires hwecc **/
+static struct nand_ecclayout omap_oobinfo;
+/* Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks
+ */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr bb_descrip_flashbased = {
+ .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+ .offs = 0,
+ .len = 1,
+ .pattern = scan_ff_pattern,
+};
/** Large Page x8 NAND device Layout */
static struct nand_ecclayout ecc_lp_x8 = {
@@ -169,14 +180,14 @@ static int omap_dev_ready(struct mtd_info *mtd)
uint64_t start = get_time_ns();
unsigned long comp;
- gpmcnand_dbg("mtd=%x", (unsigned int)mtd);
+ debug("mtd=%x", (unsigned int)mtd);
/* What do we mean by assert and de-assert? */
comp = (oinfo->wait_pol == NAND_WAITPOL_HIGH) ?
oinfo->wait_mon_mask : 0x0;
while (1) {
/* Breakout condition */
if (is_timeout(start, oinfo->timeout)) {
- gpmcnand_err("timedout\n");
+ debug("timedout\n");
return -ETIMEDOUT;
}
/* if the wait is released, we are good to go */
@@ -201,7 +212,7 @@ static void gpmc_nand_wp(struct gpmc_nand_info *oinfo, int mode)
{
unsigned long config = readl(oinfo->gpmc_base + GPMC_CFG);
- gpmcnand_dbg("mode=%x", mode);
+ debug("mode=%x", mode);
if (mode)
config &= ~(NAND_WP_BIT); /* WP is ON */
else
@@ -226,7 +237,7 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- gpmcnand_dbg("mtd=%x nand=%x cmd=%x ctrl = %x", (unsigned int)mtd, nand,
+ debug("mtd=%x nand=%x cmd=%x ctrl = %x", (unsigned int)mtd, nand,
cmd, ctrl);
switch (ctrl) {
case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
@@ -260,12 +271,72 @@ static void omap_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
*/
static unsigned int gen_true_ecc(u8 *ecc_buf)
{
- gpmcnand_dbg("ecc_buf=%x 1, 2 3 = %x %x %x", (unsigned int)ecc_buf,
+ debug("ecc_buf=%x 1, 2 3 = %x %x %x", (unsigned int)ecc_buf,
ecc_buf[0], ecc_buf[1], ecc_buf[2]);
return ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xF0) << 20) |
((ecc_buf[2] & 0x0F) << 8);
}
+static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
+ uint8_t *ecc_code)
+{
+ struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
+ struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
+ unsigned int reg;
+ unsigned int val1 = 0x0, val2 = 0x0;
+ unsigned int val3 = 0x0, val4 = 0x0;
+ int i;
+ int ecc_size = 8;
+
+ switch (oinfo->ecc_mode) {
+ case OMAP_ECC_BCH4_CODE_HW:
+ ecc_size = 4;
+ /* fall through */
+ case OMAP_ECC_BCH8_CODE_HW:
+ case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
+ for (i = 0; i < 4; i++) {
+ /*
+ * Reading HW ECC_BCH_Results
+ * 0x240-0x24C, 0x250-0x25C, 0x260-0x26C, 0x270-0x27C
+ */
+ reg = GPMC_ECC_BCH_RESULT_0 + (0x10 * i);
+ val1 = readl(oinfo->gpmc_base + reg);
+ val2 = readl(oinfo->gpmc_base + reg + 4);
+ if (ecc_size == 8) {
+ val3 = readl(oinfo->gpmc_base +reg + 8);
+ val4 = readl(oinfo->gpmc_base + reg + 12);
+
+ *ecc_code++ = (val4 & 0xFF);
+ *ecc_code++ = ((val3 >> 24) & 0xFF);
+ *ecc_code++ = ((val3 >> 16) & 0xFF);
+ *ecc_code++ = ((val3 >> 8) & 0xFF);
+ *ecc_code++ = (val3 & 0xFF);
+ *ecc_code++ = ((val2 >> 24) & 0xFF);
+ }
+ *ecc_code++ = ((val2 >> 16) & 0xFF);
+ *ecc_code++ = ((val2 >> 8) & 0xFF);
+ *ecc_code++ = (val2 & 0xFF);
+ *ecc_code++ = ((val1 >> 24) & 0xFF);
+ *ecc_code++ = ((val1 >> 16) & 0xFF);
+ *ecc_code++ = ((val1 >> 8) & 0xFF);
+ *ecc_code++ = (val1 & 0xFF);
+ }
+ break;
+ case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
+ /* read ecc result */
+ val1 = readl(oinfo->gpmc_base + GPMC_ECC1_RESULT);
+ *ecc_code++ = val1; /* P128e, ..., P1e */
+ *ecc_code++ = val1 >> 16; /* P128o, ..., P1o */
+ /* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
+ *ecc_code++ = ((val1 >> 8) & 0x0f) | ((val1 >> 20) & 0xf0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* @brief Compares the ecc read from nand spare area with ECC
* registers values and corrects one bit error if it has occured
@@ -288,107 +359,302 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
unsigned char bit;
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
+ int ecc_type = OMAP_ECC_BCH8_CODE_HW;
+ int i, j, eccsize, eccflag, count;
+ unsigned int err_loc[8];
+ int blockCnt = 0;
+ int select_4_8;
- gpmcnand_dbg("mtd=%x dat=%x read_ecc=%x calc_ecc=%x", (unsigned int)mtd,
+ debug("mtd=%x dat=%x read_ecc=%x calc_ecc=%x", (unsigned int)mtd,
(unsigned int)dat, (unsigned int)read_ecc,
(unsigned int)calc_ecc);
- /* Regenerate the orginal ECC */
- orig_ecc = gen_true_ecc(read_ecc);
- new_ecc = gen_true_ecc(calc_ecc);
- /* Get the XOR of real ecc */
- res = orig_ecc ^ new_ecc;
- if (res) {
- /* Get the hamming width */
- hm = hweight32(res);
- /* Single bit errors can be corrected! */
- if (hm == oinfo->ecc_parity_pairs) {
- /* Correctable data! */
- parity_bits = res >> 16;
- bit = (parity_bits & 0x7);
- byte = (parity_bits >> 3) & 0x1FF;
- /* Flip the bit to correct */
- dat[byte] ^= (0x1 << bit);
-
- } else if (hm == 1) {
- gpmcnand_err("Ecc is wrong\n");
- /* ECC itself is corrupted */
- return 2;
- } else {
- gpmcnand_err("bad compare! failed\n");
- /* detected 2 bit error */
- return -1;
+ if ((nand->ecc.mode == NAND_ECC_HW) &&
+ (nand->ecc.size == 2048))
+ blockCnt = 4;
+ else
+ blockCnt = 1;
+
+ switch (oinfo->ecc_mode) {
+ case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
+ if (read_ecc[0] == 0xff && read_ecc[1] == 0xff &&
+ read_ecc[2] == 0xff && calc_ecc[0] == 0x0 &&
+ calc_ecc[1] == 0x0 && calc_ecc[0] == 0x0)
+ break;
+
+ /* Regenerate the orginal ECC */
+ orig_ecc = gen_true_ecc(read_ecc);
+ new_ecc = gen_true_ecc(calc_ecc);
+ /* Get the XOR of real ecc */
+ res = orig_ecc ^ new_ecc;
+ if (res) {
+ /* Get the hamming width */
+ hm = hweight32(res);
+ /* Single bit errors can be corrected! */
+ if (hm == oinfo->ecc_parity_pairs) {
+ /* Correctable data! */
+ parity_bits = res >> 16;
+ bit = (parity_bits & 0x7);
+ byte = (parity_bits >> 3) & 0x1FF;
+ /* Flip the bit to correct */
+ dat[byte] ^= (0x1 << bit);
+ } else if (hm == 1) {
+ printf("Ecc is wrong\n");
+ /* ECC itself is corrupted */
+ return 2;
+ } else {
+ printf("bad compare! failed\n");
+ /* detected 2 bit error */
+ return -1;
+ }
}
+ break;
+ case OMAP_ECC_BCH8_CODE_HW:
+ case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
+ eccsize = 13;
+ select_4_8 = 1;
+ /* fall through */
+ case OMAP_ECC_BCH4_CODE_HW:
+ if (ecc_type == OMAP_ECC_BCH4_CODE_HW) {
+ eccsize = 7;
+ select_4_8 = 0;
+ }
+
+ omap_calculate_ecc(mtd, dat, calc_ecc);
+ for (i = 0; i < blockCnt; i++) {
+ /* check if any ecc error */
+ eccflag = 0;
+ for (j = 0; (j < eccsize) && (eccflag == 0); j++)
+ if (calc_ecc[j] != 0)
+ eccflag = 1;
+
+ if (eccflag == 1) {
+ eccflag = 0;
+ for (j = 0; (j < eccsize) &&
+ (eccflag == 0); j++)
+ if (read_ecc[j] != 0xFF)
+ eccflag = 1;
+ }
+
+ count = 0;
+ if (eccflag == 1)
+ count = decode_bch(select_4_8, calc_ecc, err_loc);
+
+ for (j = 0; j < count; j++) {
+ if (err_loc[j] < 4096)
+ dat[err_loc[j] >> 3] ^=
+ 1 << (err_loc[j] & 7);
+ /* else, not interested to correct ecc */
+ }
+
+ calc_ecc = calc_ecc + eccsize;
+ read_ecc = read_ecc + eccsize;
+ dat += 512;
+ }
+ break;
+ default:
+ return -EINVAL;
}
- return 0;
-}
-/**
- * @brief Using noninverted ECC can be considered ugly since writing a blank
- * page ie. padding will clear the ECC bytes. This is no problem as long
- * nobody is trying to write data on the seemingly unused page. Reading
- * an erased page will produce an ECC mismatch between generated and read
- * ECC bytes that has to be dealt with separately.
- *
- * @param mtd - mtd info structure
- * @param dat data being written
- * @param ecc_code ecc code returned back to nand layer
- *
- * @return 0
- */
-static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
- uint8_t *ecc_code)
-{
- struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
- struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- unsigned int val;
- gpmcnand_dbg("mtd=%x dat=%x ecc_code=%x", (unsigned int)mtd,
- (unsigned int)dat, (unsigned int)ecc_code);
- debug("ecc 0 1 2 = %x %x %x", ecc_code[0], ecc_code[1], ecc_code[2]);
-
- /* Since we smartly tell mtd driver to use eccsize of 512, only
- * ECC Reg1 will be used.. we just read that */
- val = readl(oinfo->gpmc_base + GPMC_ECC1_RESULT);
- ecc_code[0] = val & 0xFF;
- ecc_code[1] = (val >> 16) & 0xFF;
- ecc_code[2] = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
-
- /* Stop reading anymore ECC vals and clear old results
- * enable will be called if more reads are required */
- writel(0x000, oinfo->gpmc_base + GPMC_ECC_CONFIG);
return 0;
}
-/*
- * omap_enable_ecc - This function enables the hardware ecc functionality
- * @param mtd - mtd info structure
- * @param mode - Read/Write mode
- */
static void omap_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
- gpmcnand_dbg("mtd=%x mode=%x", (unsigned int)mtd, mode);
- switch (mode) {
- case NAND_ECC_READ:
- case NAND_ECC_WRITE:
- /* Clear the ecc result registers
- * select ecc reg as 1
- */
- writel(0x101, oinfo->gpmc_base + GPMC_ECC_CONTROL);
+ unsigned int bch_mod = 0, bch_wrapmode = 0, eccsize1 = 0, eccsize0 = 0;
+ unsigned int ecc_conf_val = 0, ecc_size_conf_val = 0;
+ int dev_width = nand->options & NAND_BUSWIDTH_16 ? 1 : 0;
+ int ecc_size = nand->ecc.size;
+ int cs = 0;
+
+ switch (oinfo->ecc_mode) {
+ case OMAP_ECC_BCH4_CODE_HW:
+ if (mode == NAND_ECC_READ) {
+ eccsize1 = 0xD; eccsize0 = 0x48;
+ bch_mod = 0;
+ bch_wrapmode = 0x09;
+ } else {
+ eccsize1 = 0x20; eccsize0 = 0x00;
+ bch_mod = 0;
+ bch_wrapmode = 0x06;
+ }
+ break;
+ case OMAP_ECC_BCH8_CODE_HW:
+ case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
+ if (mode == NAND_ECC_READ) {
+ eccsize1 = 0x1A; eccsize0 = 0x18;
+ bch_mod = 1;
+ bch_wrapmode = 0x04;
+ } else {
+ eccsize1 = 0x20; eccsize0 = 0x00;
+ bch_mod = 1;
+ bch_wrapmode = 0x06;
+ }
+ break;
+ case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
+ eccsize1 = ((ecc_size >> 1) - 1) << 22;
+ break;
+ case OMAP_ECC_SOFT:
+ return;
+ }
+
+ /* clear ecc and enable bits */
+ if (oinfo->ecc_mode == OMAP_ECC_HAMMING_CODE_HW_ROMCODE) {
+ writel(0x00000101, oinfo->gpmc_base + GPMC_ECC_CONTROL);
/* Size 0 = 0xFF, Size1 is 0xFF - both are 512 bytes
* tell all regs to generate size0 sized regs
* we just have a single ECC engine for all CS
*/
- writel(0x3FCFF000, oinfo->gpmc_base +
- GPMC_ECC_SIZE_CONFIG);
- writel(oinfo->ecc_config, oinfo->gpmc_base +
- GPMC_ECC_CONFIG);
+ ecc_size_conf_val = 0x3FCFF000;
+ ecc_conf_val = (dev_width << 7) | (cs << 1) | (0x1);
+ } else {
+ writel(0x1, oinfo->gpmc_base + GPMC_ECC_CONTROL);
+ ecc_size_conf_val = (eccsize1 << 22) | (eccsize0 << 12);
+ ecc_conf_val = ((0x01 << 16) | (bch_mod << 12)
+ | (bch_wrapmode << 8) | (dev_width << 7)
+ | (0x03 << 4) | (cs << 1) | (0x1));
+ }
+
+ writel(ecc_size_conf_val, oinfo->gpmc_base + GPMC_ECC_SIZE_CONFIG);
+ writel(ecc_conf_val, oinfo->gpmc_base + GPMC_ECC_CONFIG);
+ writel(0x00000101, oinfo->gpmc_base + GPMC_ECC_CONTROL);
+}
+
+static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
+ enum gpmc_ecc_mode mode)
+{
+ struct mtd_info *minfo = &oinfo->minfo;
+ struct nand_chip *nand = &oinfo->nand;
+ int offset;
+ int i, j;
+
+ if (nand->options & NAND_BUSWIDTH_16)
+ nand->badblock_pattern = &bb_descrip_flashbased;
+ else
+ nand->badblock_pattern = NULL;
+
+ if (oinfo->nand.options & NAND_BUSWIDTH_16)
+ offset = 2;
+ else
+ offset = 1;
+
+ if (mode != OMAP_ECC_SOFT) {
+ nand->ecc.layout = &omap_oobinfo;
+ nand->ecc.calculate = omap_calculate_ecc;
+ nand->ecc.hwctl = omap_enable_hwecc;
+ nand->ecc.correct = omap_correct_data;
+ nand->ecc.read_page = NULL;
+ nand->ecc.write_page = NULL;
+ nand->ecc.read_oob = NULL;
+ nand->ecc.write_oob = NULL;
+ nand->ecc.mode = NAND_ECC_HW;
+ }
+
+ switch (mode) {
+ case OMAP_ECC_HAMMING_CODE_HW_ROMCODE:
+ oinfo->nand.ecc.bytes = 3;
+ oinfo->nand.ecc.size = 512;
+ oinfo->ecc_parity_pairs = 12;
+ if (oinfo->nand.options & NAND_BUSWIDTH_16) {
+ offset = 2;
+ } else {
+ offset = 1;
+ oinfo->nand.badblock_pattern = &bb_descrip_flashbased;
+ }
+ omap_oobinfo.eccbytes = 3 * (minfo->oobsize / 16);
+ for (i = 0; i < omap_oobinfo.eccbytes; i++)
+ omap_oobinfo.eccpos[i] = i + offset;
+ omap_oobinfo.oobfree->offset = offset + omap_oobinfo.eccbytes;
+ omap_oobinfo.oobfree->length = minfo->oobsize -
+ offset - omap_oobinfo.eccbytes;
+ break;
+ case OMAP_ECC_BCH4_CODE_HW:
+ oinfo->nand.ecc.bytes = 4 * 7;
+ oinfo->nand.ecc.size = 4 * 512;
+ omap_oobinfo.oobfree->offset = offset;
+ omap_oobinfo.oobfree->length = minfo->oobsize -
+ offset - omap_oobinfo.eccbytes;
+ offset = minfo->oobsize - oinfo->nand.ecc.bytes;
+ for (i = 0; i < oinfo->nand.ecc.bytes; i++)
+ omap_oobinfo.eccpos[i] = i + offset;
+ break;
+ case OMAP_ECC_BCH8_CODE_HW:
+ oinfo->nand.ecc.bytes = 4 * 13;
+ oinfo->nand.ecc.size = 4 * 512;
+ omap_oobinfo.oobfree->offset = offset;
+ omap_oobinfo.oobfree->length = minfo->oobsize -
+ offset - omap_oobinfo.eccbytes;
+ offset = minfo->oobsize - oinfo->nand.ecc.bytes;
+ for (i = 0; i < oinfo->nand.ecc.bytes; i++)
+ omap_oobinfo.eccpos[i] = i + offset;
+ break;
+ case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
+ /*
+ * Contradicting the datasheet the ecc checksum has to start
+ * at byte 2 in oob. I have no idea how the rom code can
+ * read this but it does.
+ */
+ dev_warn(oinfo->pdev, "using rom loader ecc mode. "
+ "You can write properly but not read it back\n");
+
+ oinfo->nand.ecc.bytes = 4 * 13;
+ oinfo->nand.ecc.size = 4 * 512;
+ omap_oobinfo.oobfree->length = 0;
+ j = 0;
+ for (i = 2; i < 15; i++)
+ omap_oobinfo.eccpos[j++] = i;
+ for (i = 16; i < 29; i++)
+ omap_oobinfo.eccpos[j++] = i;
+ for (i = 30; i < 43; i++)
+ omap_oobinfo.eccpos[j++] = i;
+ for (i = 44; i < 57; i++)
+ omap_oobinfo.eccpos[j++] = i;
break;
- default:
- gpmcnand_err("Error: Unrecognized Mode[%d]!\n", mode);
+ case OMAP_ECC_SOFT:
+ nand->ecc.layout = NULL;
+ nand->ecc.mode = NAND_ECC_SOFT;
break;
+ default:
+ return -EINVAL;
}
+
+ oinfo->ecc_mode = mode;
+
+ if (nand->buffers)
+ kfree(nand->buffers);
+
+ /* second phase scan */
+ if (nand_scan_tail(minfo))
+ return -ENXIO;
+
+ nand->options |= NAND_SKIP_BBTSCAN;
+
+ return 0;
+}
+
+static int omap_gpmc_eccmode_set(struct device_d *dev, struct param_d *param, const char *val)
+{
+ struct gpmc_nand_info *oinfo = dev->priv;
+ int i;
+
+ if (!val)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(ecc_mode_strings); i++)
+ if (!strcmp(ecc_mode_strings[i], val))
+ break;
+
+ if (i == ARRAY_SIZE(ecc_mode_strings)) {
+ dev_err(dev, "invalid ecc mode '%s'\n", val);
+ printf("valid modes:\n");
+ for (i = 0; i < ARRAY_SIZE(ecc_mode_strings); i++)
+ printf("%s\n", ecc_mode_strings[i]);
+ return -EINVAL;
+ }
+
+ return omap_gpmc_eccmode(oinfo, i);
}
/**
@@ -408,23 +674,19 @@ static int gpmc_nand_probe(struct device_d *pdev)
int err;
struct nand_ecclayout *layout, *lsp, *llp;
- gpmcnand_dbg("pdev=%x", (unsigned int)pdev);
pdata = (struct gpmc_nand_platform_data *)pdev->platform_data;
if (pdata == NULL) {
- gpmcnand_err("platform data missing\n");
+ dev_dbg(pdev, "platform data missing\n");
return -ENODEV;
}
- oinfo = calloc(1, sizeof(struct gpmc_nand_info));
- if (!oinfo) {
- gpmcnand_err("oinfo alloc failed!\n");
- return -ENOMEM;
- }
+ oinfo = xzalloc(sizeof(*oinfo));
/* fill up my data structures */
oinfo->pdev = pdev;
oinfo->pdata = pdata;
pdev->platform_data = (void *)oinfo;
+ pdev->priv = oinfo;
nand = &oinfo->nand;
nand->priv = (void *)oinfo;
@@ -433,7 +695,7 @@ static int gpmc_nand_probe(struct device_d *pdev)
minfo->priv = (void *)nand;
if (pdata->cs >= GPMC_NUM_CS) {
- gpmcnand_err("Invalid CS!\n");
+ dev_dbg(pdev, "Invalid CS!\n");
err = -EINVAL;
goto out_release_mem;
}
@@ -457,7 +719,7 @@ static int gpmc_nand_probe(struct device_d *pdev)
/* If we are 16 bit dev, our gpmc config tells us that */
if ((readl(cs_base) & 0x3000) == 0x1000) {
- debug("16 bit dev\n");
+ dev_dbg(pdev, "16 bit dev\n");
nand->options |= NAND_BUSWIDTH_16;
}
@@ -472,7 +734,7 @@ static int gpmc_nand_probe(struct device_d *pdev)
* until you get a failure or success
*/
if (pdata->wait_mon_pin > 4) {
- gpmcnand_err("Invalid wait monitoring pin\n");
+ dev_dbg(pdev, "Invalid wait monitoring pin\n");
err = -EINVAL;
goto out_release_mem;
}
@@ -502,7 +764,7 @@ static int gpmc_nand_probe(struct device_d *pdev)
if (pdata->nand_setup) {
err = pdata->nand_setup(pdata);
if (err) {
- gpmcnand_err("pdataform setup failed\n");
+ dev_dbg(pdev, "pdataform setup failed\n");
goto out_release_mem;
}
}
@@ -548,45 +810,25 @@ static int gpmc_nand_probe(struct device_d *pdev)
goto out_release_mem;
}
- if (pdata->plat_options & NAND_HWECC_ENABLE) {
- nand->ecc.layout = layout;
-
- /* Program how many columns we expect+
- * enable the cs we want and enable the engine
- */
- oinfo->ecc_config = (pdata->cs << 1) |
- ((nand->options & NAND_BUSWIDTH_16) ?
- (0x1 << 7) : 0x0) | 0x1;
- nand->ecc.hwctl = omap_enable_hwecc;
- nand->ecc.calculate = omap_calculate_ecc;
- nand->ecc.correct = omap_correct_data;
- nand->ecc.mode = NAND_ECC_HW;
- nand->ecc.size = 512;
- nand->ecc.bytes = 3;
- nand->ecc.steps = nand->ecc.layout->eccbytes / nand->ecc.bytes;
- oinfo->ecc_parity_pairs = 12;
- } else
- nand->ecc.mode = NAND_ECC_SOFT;
-
- /* second phase scan */
- if (nand_scan_tail(minfo)) {
- err = -ENXIO;
- goto out_release_mem;
- }
+ nand->options |= NAND_SKIP_BBTSCAN;
+ omap_gpmc_eccmode(oinfo, pdata->ecc_mode);
/* We are all set to register with the system now! */
err = add_mtd_device(minfo);
if (err) {
- gpmcnand_err("device registration failed\n");
+ dev_dbg(pdev, "device registration failed\n");
goto out_release_mem;
}
+
+ dev_add_param(pdev, "eccmode", omap_gpmc_eccmode_set, NULL, 0);
+
return 0;
out_release_mem:
if (oinfo)
free(oinfo);
- gpmcnand_err("Failed!!\n");
+ dev_dbg(pdev, "Failed!!\n");
return err;
}
diff --git a/drivers/mtd/nand/nand_swecc.c b/drivers/mtd/nand/nand_swecc.c
new file mode 100644
index 00000000..93511cbe
--- /dev/null
+++ b/drivers/mtd/nand/nand_swecc.c
@@ -0,0 +1,94 @@
+#include <common.h>
+#include <errno.h>
+#include <clock.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/err.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+#include "nand.h"
+
+/**
+ * nand_read_page_swecc - [REPLACABLE] software ecc based page read function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: buffer to store read data
+ */
+static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *p = buf;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ chip->ecc.read_page_raw(mtd, chip, buf);
+
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ for (i = 0; i < chip->ecc.total; i++)
+ ecc_code[i] = chip->oob_poi[eccpos[i]];
+
+ eccsteps = chip->ecc.steps;
+ p = buf;
+
+ for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+ int stat;
+
+ stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
+ if (stat < 0)
+ mtd->ecc_stats.failed++;
+ else
+ mtd->ecc_stats.corrected += stat;
+ }
+ return 0;
+}
+
+/**
+ * nand_write_page_swecc - [REPLACABLE] software ecc based page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+#ifdef CONFIG_NAND_WRITE
+static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ int i, eccsize = chip->ecc.size;
+ int eccbytes = chip->ecc.bytes;
+ int eccsteps = chip->ecc.steps;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ const uint8_t *p = buf;
+ uint32_t *eccpos = chip->ecc.layout->eccpos;
+
+ /* Software ecc calculation */
+ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
+ chip->ecc.calculate(mtd, p, &ecc_calc[i]);
+
+ for (i = 0; i < chip->ecc.total; i++)
+ chip->oob_poi[eccpos[i]] = ecc_calc[i];
+
+ chip->ecc.write_page_raw(mtd, chip, buf);
+}
+#endif
+
+void nand_init_ecc_soft(struct nand_chip *chip)
+{
+ chip->ecc.calculate = nand_calculate_ecc;
+ chip->ecc.correct = nand_correct_data;
+ chip->ecc.read_page = nand_read_page_swecc;
+ chip->ecc.read_oob = nand_read_oob_std;
+#ifdef CONFIG_NAND_WRITE
+ chip->ecc.write_page = nand_write_page_swecc;
+ chip->ecc.write_oob = nand_write_oob_std;
+#endif
+ chip->ecc.size = 256;
+ chip->ecc.bytes = 3;
+}
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
deleted file mode 100644
index d57294e6..00000000
--- a/drivers/mtd/nand/nand_util.c
+++ /dev/null
@@ -1,858 +0,0 @@
-/*
- * drivers/nand/nand_util.c
- *
- * Copyright (C) 2006 by Weiss-Electronic GmbH.
- * All rights reserved.
- *
- * @author: Guido Classen <clagix@gmail.com>
- * @descr: NAND Flash support
- * @references: borrowed heavily from Linux mtd-utils code:
- * flash_eraseall.c by Arcom Control System Ltd
- * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com)
- * and Thomas Gleixner (tglx@linutronix.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 version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- *
- */
-
-#include <common.h>
-#include <command.h>
-#include <watchdog.h>
-#include <malloc.h>
-
-#include <nand.h>
-//#include <jffs2/jffs2.h>
-
-typedef struct erase_info erase_info_t;
-typedef struct mtd_info mtd_info_t;
-
-/* support only for native endian JFFS2 */
-#define cpu_to_je16(x) (x)
-#define cpu_to_je32(x) (x)
-
-/*****************************************************************************/
-static int nand_block_bad_scrub(struct mtd_info *mtd, loff_t ofs, int getchip)
-{
- return 0;
-}
-
-/**
- * nand_erase_opts: - erase NAND flash with support for various options
- * (jffs2 formating)
- *
- * @param meminfo NAND device to erase
- * @param opts options, @see struct nand_erase_options
- * @return 0 in case of success
- *
- * This code is ported from flash_eraseall.c from Linux mtd utils by
- * Arcom Control System Ltd.
- */
-int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts)
-{
- struct jffs2_unknown_node cleanmarker;
- int clmpos = 0;
- int clmlen = 8;
- erase_info_t erase;
- ulong erase_length;
- int isNAND;
- int bbtest = 1;
- int result;
- int percent_complete = -1;
- int (*nand_block_bad_old)(struct mtd_info *, loff_t, int) = NULL;
- const char *mtd_device = meminfo->name;
-
- memset(&erase, 0, sizeof(erase));
-
- erase.mtd = meminfo;
- erase.len = meminfo->erasesize;
- erase.addr = opts->offset;
- erase_length = opts->length;
-
- isNAND = meminfo->type == MTD_NANDFLASH ? 1 : 0;
-
- if (opts->jffs2) {
- cleanmarker.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK);
- cleanmarker.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER);
- if (isNAND) {
- struct nand_oobinfo *oobinfo = &meminfo->oobinfo;
-
- /* check for autoplacement */
- if (oobinfo->useecc == MTD_NANDECC_AUTOPLACE) {
- /* get the position of the free bytes */
- if (!oobinfo->oobfree[0][1]) {
- printf(" Eeep. Autoplacement selected "
- "and no empty space in oob\n");
- return -1;
- }
- clmpos = oobinfo->oobfree[0][0];
- clmlen = oobinfo->oobfree[0][1];
- if (clmlen > 8)
- clmlen = 8;
- } else {
- /* legacy mode */
- switch (meminfo->oobsize) {
- case 8:
- clmpos = 6;
- clmlen = 2;
- break;
- case 16:
- clmpos = 8;
- clmlen = 8;
- break;
- case 64:
- clmpos = 16;
- clmlen = 8;
- break;
- }
- }
-
- cleanmarker.totlen = cpu_to_je32(8);
- } else {
- cleanmarker.totlen =
- cpu_to_je32(sizeof(struct jffs2_unknown_node));
- }
- cleanmarker.hdr_crc = cpu_to_je32(
- crc32_no_comp(0, (unsigned char *) &cleanmarker,
- sizeof(struct jffs2_unknown_node) - 4));
- }
-
- /* scrub option allows to erase badblock. To prevent internal
- * check from erase() method, set block check method to dummy
- * and disable bad block table while erasing.
- */
- if (opts->scrub) {
- struct nand_chip *priv_nand = meminfo->priv;
-
- nand_block_bad_old = priv_nand->block_bad;
- priv_nand->block_bad = nand_block_bad_scrub;
- /* we don't need the bad block table anymore...
- * after scrub, there are no bad blocks left!
- */
- if (priv_nand->bbt) {
- kfree(priv_nand->bbt);
- }
- priv_nand->bbt = NULL;
- }
-
- for (;
- erase.addr < opts->offset + erase_length;
- erase.addr += meminfo->erasesize) {
-
- WATCHDOG_RESET ();
-
- if (!opts->scrub && bbtest) {
- int ret = meminfo->block_isbad(meminfo, erase.addr);
- if (ret > 0) {
- if (!opts->quiet)
- printf("\rSkipping bad block at "
- "0x%08x "
- " \n",
- erase.addr);
- continue;
-
- } else if (ret < 0) {
- printf("\n%s: MTD get bad block failed: %d\n",
- mtd_device,
- ret);
- return -1;
- }
- }
-
- result = meminfo->erase(meminfo, &erase);
- if (result != 0) {
- printf("\n%s: MTD Erase failure: %d\n",
- mtd_device, result);
- continue;
- }
-
- /* format for JFFS2 ? */
- if (opts->jffs2) {
-
- /* write cleanmarker */
- if (isNAND) {
- size_t written;
- result = meminfo->write_oob(meminfo,
- erase.addr + clmpos,
- clmlen,
- &written,
- (unsigned char *)
- &cleanmarker);
- if (result != 0) {
- printf("\n%s: MTD writeoob failure: %d\n",
- mtd_device, result);
- continue;
- }
- } else {
- printf("\n%s: this erase routine only supports"
- " NAND devices!\n",
- mtd_device);
- }
- }
-
- if (!opts->quiet) {
- int percent = (int)
- ((unsigned long long)
- (erase.addr+meminfo->erasesize-opts->offset)
- * 100 / erase_length);
-
- /* output progress message only at whole percent
- * steps to reduce the number of messages printed
- * on (slow) serial consoles
- */
- if (percent != percent_complete) {
- percent_complete = percent;
-
- printf("\rErasing at 0x%x -- %3d%% complete.",
- erase.addr, percent);
-
- if (opts->jffs2 && result == 0)
- printf(" Cleanmarker written at 0x%x.",
- erase.addr);
- }
- }
- }
- if (!opts->quiet)
- printf("\n");
-
- if (nand_block_bad_old) {
- struct nand_chip *priv_nand = meminfo->priv;
-
- priv_nand->block_bad = nand_block_bad_old;
- priv_nand->scan_bbt(meminfo);
- }
-
- return 0;
-}
-
-#define MAX_PAGE_SIZE 2048
-#define MAX_OOB_SIZE 64
-
-/*
- * buffer array used for writing data
- */
-static unsigned char data_buf[MAX_PAGE_SIZE];
-static unsigned char oob_buf[MAX_OOB_SIZE];
-
-/* OOB layouts to pass into the kernel as default */
-static struct nand_oobinfo none_oobinfo = {
- .useecc = MTD_NANDECC_OFF,
-};
-
-static struct nand_oobinfo jffs2_oobinfo = {
- .useecc = MTD_NANDECC_PLACE,
- .eccbytes = 6,
- .eccpos = { 0, 1, 2, 3, 6, 7 }
-};
-
-static struct nand_oobinfo yaffs_oobinfo = {
- .useecc = MTD_NANDECC_PLACE,
- .eccbytes = 6,
- .eccpos = { 8, 9, 10, 13, 14, 15}
-};
-
-static struct nand_oobinfo autoplace_oobinfo = {
- .useecc = MTD_NANDECC_AUTOPLACE
-};
-
-/**
- * nand_write_opts: - write image to NAND flash with support for various options
- *
- * @param meminfo NAND device to erase
- * @param opts write options (@see nand_write_options)
- * @return 0 in case of success
- *
- * This code is ported from nandwrite.c from Linux mtd utils by
- * Steven J. Hill and Thomas Gleixner.
- */
-int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
-{
- int imglen = 0;
- int pagelen;
- int baderaseblock;
- int blockstart = -1;
- loff_t offs;
- int readlen;
- int oobinfochanged = 0;
- int percent_complete = -1;
- struct nand_oobinfo old_oobinfo;
- ulong mtdoffset = opts->offset;
- ulong erasesize_blockalign;
- u_char *buffer = opts->buffer;
- size_t written;
- int result;
-
- if (opts->pad && opts->writeoob) {
- printf("Can't pad when oob data is present.\n");
- return -1;
- }
-
- /* set erasesize to specified number of blocks - to match
- * jffs2 (virtual) block size */
- if (opts->blockalign == 0) {
- erasesize_blockalign = meminfo->erasesize;
- } else {
- erasesize_blockalign = meminfo->erasesize * opts->blockalign;
- }
-
- /* make sure device page sizes are valid */
- if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
- && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
- && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
- printf("Unknown flash (not normal NAND)\n");
- return -1;
- }
-
- /* read the current oob info */
- memcpy(&old_oobinfo, &meminfo->oobinfo, sizeof(old_oobinfo));
-
- /* write without ecc? */
- if (opts->noecc) {
- memcpy(&meminfo->oobinfo, &none_oobinfo,
- sizeof(meminfo->oobinfo));
- oobinfochanged = 1;
- }
-
- /* autoplace ECC? */
- if (opts->autoplace && (old_oobinfo.useecc != MTD_NANDECC_AUTOPLACE)) {
-
- memcpy(&meminfo->oobinfo, &autoplace_oobinfo,
- sizeof(meminfo->oobinfo));
- oobinfochanged = 1;
- }
-
- /* force OOB layout for jffs2 or yaffs? */
- if (opts->forcejffs2 || opts->forceyaffs) {
- struct nand_oobinfo *oobsel =
- opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
-
- if (meminfo->oobsize == 8) {
- if (opts->forceyaffs) {
- printf("YAFSS cannot operate on "
- "256 Byte page size\n");
- goto restoreoob;
- }
- /* Adjust number of ecc bytes */
- jffs2_oobinfo.eccbytes = 3;
- }
-
- memcpy(&meminfo->oobinfo, oobsel, sizeof(meminfo->oobinfo));
- }
-
- /* get image length */
- imglen = opts->length;
- pagelen = meminfo->oobblock
- + ((opts->writeoob != 0) ? meminfo->oobsize : 0);
-
- /* check, if file is pagealigned */
- if ((!opts->pad) && ((imglen % pagelen) != 0)) {
- printf("Input block length is not page aligned\n");
- goto restoreoob;
- }
-
- /* check, if length fits into device */
- if (((imglen / pagelen) * meminfo->oobblock)
- > (meminfo->size - opts->offset)) {
- printf("Image %d bytes, NAND page %d bytes, "
- "OOB area %u bytes, device size %u bytes\n",
- imglen, pagelen, meminfo->oobblock, meminfo->size);
- printf("Input block does not fit into device\n");
- goto restoreoob;
- }
-
- if (!opts->quiet)
- printf("\n");
-
- /* get data from input and write to the device */
- while (imglen && (mtdoffset < meminfo->size)) {
-
- WATCHDOG_RESET ();
-
- /*
- * new eraseblock, check for bad block(s). Stay in the
- * loop to be sure if the offset changes because of
- * a bad block, that the next block that will be
- * written to is also checked. Thus avoiding errors if
- * the block(s) after the skipped block(s) is also bad
- * (number of blocks depending on the blockalign
- */
- while (blockstart != (mtdoffset & (~erasesize_blockalign+1))) {
- blockstart = mtdoffset & (~erasesize_blockalign+1);
- offs = blockstart;
- baderaseblock = 0;
-
- /* check all the blocks in an erase block for
- * bad blocks */
- do {
- int ret = meminfo->block_isbad(meminfo, offs);
-
- if (ret < 0) {
- printf("Bad block check failed\n");
- goto restoreoob;
- }
- if (ret == 1) {
- baderaseblock = 1;
- if (!opts->quiet)
- printf("\rBad block at 0x%lx "
- "in erase block from "
- "0x%x will be skipped\n",
- (long) offs,
- blockstart);
- }
-
- if (baderaseblock) {
- mtdoffset = blockstart
- + erasesize_blockalign;
- }
- offs += erasesize_blockalign
- / opts->blockalign;
- } while (offs < blockstart + erasesize_blockalign);
- }
-
- readlen = meminfo->oobblock;
- if (opts->pad && (imglen < readlen)) {
- readlen = imglen;
- memset(data_buf + readlen, 0xff,
- meminfo->oobblock - readlen);
- }
-
- /* read page data from input memory buffer */
- memcpy(data_buf, buffer, readlen);
- buffer += readlen;
-
- if (opts->writeoob) {
- /* read OOB data from input memory block, exit
- * on failure */
- memcpy(oob_buf, buffer, meminfo->oobsize);
- buffer += meminfo->oobsize;
-
- /* write OOB data first, as ecc will be placed
- * in there*/
- result = meminfo->write_oob(meminfo,
- mtdoffset,
- meminfo->oobsize,
- &written,
- (unsigned char *)
- &oob_buf);
-
- if (result != 0) {
- printf("\nMTD writeoob failure: %d\n",
- result);
- goto restoreoob;
- }
- imglen -= meminfo->oobsize;
- }
-
- /* write out the page data */
- result = meminfo->write(meminfo,
- mtdoffset,
- meminfo->oobblock,
- &written,
- (unsigned char *) &data_buf);
-
- if (result != 0) {
- printf("writing NAND page at offset 0x%lx failed\n",
- mtdoffset);
- goto restoreoob;
- }
- imglen -= readlen;
-
- if (!opts->quiet) {
- int percent = (int)
- ((unsigned long long)
- (opts->length-imglen) * 100
- / opts->length);
- /* output progress message only at whole percent
- * steps to reduce the number of messages printed
- * on (slow) serial consoles
- */
- if (percent != percent_complete) {
- printf("\rWriting data at 0x%x "
- "-- %3d%% complete.",
- mtdoffset, percent);
- percent_complete = percent;
- }
- }
-
- mtdoffset += meminfo->oobblock;
- }
-
- if (!opts->quiet)
- printf("\n");
-
-restoreoob:
- if (oobinfochanged) {
- memcpy(&meminfo->oobinfo, &old_oobinfo,
- sizeof(meminfo->oobinfo));
- }
-
- if (imglen > 0) {
- printf("Data did not fit into device, due to bad blocks\n");
- return -1;
- }
-
- /* return happy */
- return 0;
-}
-
-/**
- * nand_read_opts: - read image from NAND flash with support for various options
- *
- * @param meminfo NAND device to erase
- * @param opts read options (@see struct nand_read_options)
- * @return 0 in case of success
- *
- */
-int nand_read_opts(nand_info_t *meminfo, const nand_read_options_t *opts)
-{
- int imglen = opts->length;
- int pagelen;
- int baderaseblock;
- int blockstart = -1;
- int percent_complete = -1;
- loff_t offs;
- size_t readlen;
- ulong mtdoffset = opts->offset;
- u_char *buffer = opts->buffer;
- int result;
-
- /* make sure device page sizes are valid */
- if (!(meminfo->oobsize == 16 && meminfo->oobblock == 512)
- && !(meminfo->oobsize == 8 && meminfo->oobblock == 256)
- && !(meminfo->oobsize == 64 && meminfo->oobblock == 2048)) {
- printf("Unknown flash (not normal NAND)\n");
- return -1;
- }
-
- pagelen = meminfo->oobblock
- + ((opts->readoob != 0) ? meminfo->oobsize : 0);
-
- /* check, if length is not larger than device */
- if (((imglen / pagelen) * meminfo->oobblock)
- > (meminfo->size - opts->offset)) {
- printf("Image %d bytes, NAND page %d bytes, "
- "OOB area %u bytes, device size %u bytes\n",
- imglen, pagelen, meminfo->oobblock, meminfo->size);
- printf("Input block is larger than device\n");
- return -1;
- }
-
- if (!opts->quiet)
- printf("\n");
-
- /* get data from input and write to the device */
- while (imglen && (mtdoffset < meminfo->size)) {
-
- WATCHDOG_RESET ();
-
- /*
- * new eraseblock, check for bad block(s). Stay in the
- * loop to be sure if the offset changes because of
- * a bad block, that the next block that will be
- * written to is also checked. Thus avoiding errors if
- * the block(s) after the skipped block(s) is also bad
- * (number of blocks depending on the blockalign
- */
- while (blockstart != (mtdoffset & (~meminfo->erasesize+1))) {
- blockstart = mtdoffset & (~meminfo->erasesize+1);
- offs = blockstart;
- baderaseblock = 0;
-
- /* check all the blocks in an erase block for
- * bad blocks */
- do {
- int ret = meminfo->block_isbad(meminfo, offs);
-
- if (ret < 0) {
- printf("Bad block check failed\n");
- return -1;
- }
- if (ret == 1) {
- baderaseblock = 1;
- if (!opts->quiet)
- printf("\rBad block at 0x%lx "
- "in erase block from "
- "0x%x will be skipped\n",
- (long) offs,
- blockstart);
- }
-
- if (baderaseblock) {
- mtdoffset = blockstart
- + meminfo->erasesize;
- }
- offs += meminfo->erasesize;
-
- } while (offs < blockstart + meminfo->erasesize);
- }
-
-
- /* read page data to memory buffer */
- result = meminfo->read(meminfo,
- mtdoffset,
- meminfo->oobblock,
- &readlen,
- (unsigned char *) &data_buf);
-
- if (result != 0) {
- printf("reading NAND page at offset 0x%lx failed\n",
- mtdoffset);
- return -1;
- }
-
- if (imglen < readlen) {
- readlen = imglen;
- }
-
- memcpy(buffer, data_buf, readlen);
- buffer += readlen;
- imglen -= readlen;
-
- if (opts->readoob) {
- result = meminfo->read_oob(meminfo,
- mtdoffset,
- meminfo->oobsize,
- &readlen,
- (unsigned char *)
- &oob_buf);
-
- if (result != 0) {
- printf("\nMTD readoob failure: %d\n",
- result);
- return -1;
- }
-
-
- if (imglen < readlen) {
- readlen = imglen;
- }
-
- memcpy(buffer, oob_buf, readlen);
-
- buffer += readlen;
- imglen -= readlen;
- }
-
- if (!opts->quiet) {
- int percent = (int)
- ((unsigned long long)
- (opts->length-imglen) * 100
- / opts->length);
- /* output progress message only at whole percent
- * steps to reduce the number of messages printed
- * on (slow) serial consoles
- */
- if (percent != percent_complete) {
- if (!opts->quiet)
- printf("\rReading data from 0x%x "
- "-- %3d%% complete.",
- mtdoffset, percent);
- percent_complete = percent;
- }
- }
-
- mtdoffset += meminfo->oobblock;
- }
-
- if (!opts->quiet)
- printf("\n");
-
- if (imglen > 0) {
- printf("Could not read entire image due to bad blocks\n");
- return -1;
- }
-
- /* return happy */
- return 0;
-}
-
-/******************************************************************************
- * Support for locking / unlocking operations of some NAND devices
- *****************************************************************************/
-
-#define NAND_CMD_LOCK 0x2a
-#define NAND_CMD_LOCK_TIGHT 0x2c
-#define NAND_CMD_UNLOCK1 0x23
-#define NAND_CMD_UNLOCK2 0x24
-#define NAND_CMD_LOCK_STATUS 0x7a
-
-/**
- * nand_lock: Set all pages of NAND flash chip to the LOCK or LOCK-TIGHT
- * state
- *
- * @param meminfo nand mtd instance
- * @param tight bring device in lock tight mode
- *
- * @return 0 on success, -1 in case of error
- *
- * The lock / lock-tight command only applies to the whole chip. To get some
- * parts of the chip lock and others unlocked use the following sequence:
- *
- * - Lock all pages of the chip using nand_lock(mtd, 0) (or the lockpre pin)
- * - Call nand_unlock() once for each consecutive area to be unlocked
- * - If desired: Bring the chip to the lock-tight state using nand_lock(mtd, 1)
- *
- * If the device is in lock-tight state software can't change the
- * current active lock/unlock state of all pages. nand_lock() / nand_unlock()
- * calls will fail. It is only posible to leave lock-tight state by
- * an hardware signal (low pulse on _WP pin) or by power down.
- */
-int nand_lock(nand_info_t *meminfo, int tight)
-{
- int ret = 0;
- int status;
- struct nand_chip *this = meminfo->priv;
-
- /* select the NAND device */
- this->select_chip(meminfo, 0);
-
- this->cmdfunc(meminfo,
- (tight ? NAND_CMD_LOCK_TIGHT : NAND_CMD_LOCK),
- -1, -1);
-
- /* call wait ready function */
- status = this->waitfunc(meminfo, this, FL_WRITING);
-
- /* see if device thinks it succeeded */
- if (status & 0x01) {
- ret = -1;
- }
-
- /* de-select the NAND device */
- this->select_chip(meminfo, -1);
- return ret;
-}
-
-/**
- * nand_get_lock_status: - query current lock state from one page of NAND
- * flash
- *
- * @param meminfo nand mtd instance
- * @param offset page address to query (muss be page aligned!)
- *
- * @return -1 in case of error
- * >0 lock status:
- * bitfield with the following combinations:
- * NAND_LOCK_STATUS_TIGHT: page in tight state
- * NAND_LOCK_STATUS_LOCK: page locked
- * NAND_LOCK_STATUS_UNLOCK: page unlocked
- *
- */
-int nand_get_lock_status(nand_info_t *meminfo, ulong offset)
-{
- int ret = 0;
- int chipnr;
- int page;
- struct nand_chip *this = meminfo->priv;
-
- /* select the NAND device */
- chipnr = (int)(offset >> this->chip_shift);
- this->select_chip(meminfo, chipnr);
-
-
- if ((offset & (meminfo->oobblock - 1)) != 0) {
- printf ("nand_get_lock_status: "
- "Start address must be beginning of "
- "nand page!\n");
- ret = -1;
- goto out;
- }
-
- /* check the Lock Status */
- page = (int)(offset >> this->page_shift);
- this->cmdfunc(meminfo, NAND_CMD_LOCK_STATUS, -1, page & this->pagemask);
-
- ret = this->read_byte(meminfo) & (NAND_LOCK_STATUS_TIGHT
- | NAND_LOCK_STATUS_LOCK
- | NAND_LOCK_STATUS_UNLOCK);
-
- out:
- /* de-select the NAND device */
- this->select_chip(meminfo, -1);
- return ret;
-}
-
-/**
- * nand_unlock: - Unlock area of NAND pages
- * only one consecutive area can be unlocked at one time!
- *
- * @param meminfo nand mtd instance
- * @param start start byte address
- * @param length number of bytes to unlock (must be a multiple of
- * page size nand->oobblock)
- *
- * @return 0 on success, -1 in case of error
- */
-int nand_unlock(nand_info_t *meminfo, ulong start, ulong length)
-{
- int ret = 0;
- int chipnr;
- int status;
- int page;
- struct nand_chip *this = meminfo->priv;
- printf ("nand_unlock: start: %08x, length: %d!\n",
- (int)start, (int)length);
-
- /* select the NAND device */
- chipnr = (int)(start >> this->chip_shift);
- this->select_chip(meminfo, chipnr);
-
- /* check the WP bit */
- this->cmdfunc(meminfo, NAND_CMD_STATUS, -1, -1);
- if ((this->read_byte(meminfo) & 0x80) == 0) {
- printf ("nand_unlock: Device is write protected!\n");
- ret = -1;
- goto out;
- }
-
- if ((start & (meminfo->oobblock - 1)) != 0) {
- printf ("nand_unlock: Start address must be beginning of "
- "nand page!\n");
- ret = -1;
- goto out;
- }
-
- if (length == 0 || (length & (meminfo->oobblock - 1)) != 0) {
- printf ("nand_unlock: Length must be a multiple of nand page "
- "size!\n");
- ret = -1;
- goto out;
- }
-
- /* submit address of first page to unlock */
- page = (int)(start >> this->page_shift);
- this->cmdfunc(meminfo, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
-
- /* submit ADDRESS of LAST page to unlock */
- page += (int)(length >> this->page_shift) - 1;
- this->cmdfunc(meminfo, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
-
- /* call wait ready function */
- status = this->waitfunc(meminfo, this, FL_WRITING);
- /* see if device thinks it succeeded */
- if (status & 0x01) {
- /* there was an error */
- ret = -1;
- goto out;
- }
-
- out:
- /* de-select the NAND device */
- this->select_chip(meminfo, -1);
- return ret;
-}
-
diff --git a/drivers/mtd/nand/nand_write.c b/drivers/mtd/nand/nand_write.c
new file mode 100644
index 00000000..89dc47b3
--- /dev/null
+++ b/drivers/mtd/nand/nand_write.c
@@ -0,0 +1,746 @@
+#include <common.h>
+#include <errno.h>
+#include <clock.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/err.h>
+#include <linux/mtd/nand_ecc.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <module.h>
+
+#include "nand.h"
+
+static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops);
+
+/**
+ * nand_write_buf - [DEFAULT] write buffer to chip
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 8bit buswith
+ */
+void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *chip = mtd->priv;
+
+ for (i = 0; i < len; i++)
+ writeb(buf[i], chip->IO_ADDR_W);
+}
+
+/**
+ * nand_write_buf16 - [DEFAULT] write buffer to chip
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ *
+ * Default write function for 16bit buswith
+ */
+void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ int i;
+ struct nand_chip *chip = mtd->priv;
+ u16 *p = (u16 *) buf;
+ len >>= 1;
+
+ for (i = 0; i < len; i++)
+ writew(p[i], chip->IO_ADDR_W);
+
+}
+
+/**
+ * nand_default_block_markbad - [DEFAULT] mark a block bad
+ * @mtd: MTD device structure
+ * @ofs: offset from device start
+ *
+ * This is the default implementation, which can be overridden by
+ * a hardware specific driver.
+ */
+int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ uint8_t buf[2] = { 0, 0 };
+ int block, ret;
+
+ /* Get block number */
+ block = (int)(ofs >> chip->bbt_erase_shift);
+ if (chip->bbt)
+ chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+
+ /* Do we have a flash based bad block table ? */
+ if (chip->options & NAND_USE_FLASH_BBT)
+ ret = nand_update_bbt(mtd, ofs);
+ else {
+ /* We write two bytes, so we dont have to mess with 16 bit
+ * access
+ */
+ ofs += mtd->oobsize;
+ chip->ops.len = chip->ops.ooblen = 2;
+ chip->ops.datbuf = NULL;
+ chip->ops.oobbuf = buf;
+ chip->ops.ooboffs = chip->badblockpos & ~0x01;
+
+ ret = nand_do_write_oob(mtd, ofs, &chip->ops);
+ }
+ if (!ret)
+ mtd->ecc_stats.badblocks++;
+
+ return ret;
+}
+
+/**
+ * nand_check_wp - [GENERIC] check if the chip is write protected
+ * @mtd: MTD device structure
+ * Check, if the device is write protected
+ *
+ * The function expects, that the device is already selected
+ */
+static int nand_check_wp(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ /* Check the WP bit */
+ chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+ return (chip->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
+}
+
+/**
+ * nand_write_oob_std - [REPLACABLE] the most common OOB data write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @page: page number to write
+ */
+int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ int status = 0;
+ const uint8_t *buf = chip->oob_poi;
+ int length = mtd->oobsize;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
+ chip->write_buf(mtd, buf, length);
+ /* Send command to program the OOB data */
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+
+ status = chip->waitfunc(mtd, chip);
+
+ return status & NAND_STATUS_FAIL ? -EIO : 0;
+}
+
+/**
+ * nand_write_page_raw - [Intern] raw page write function
+ * @mtd: mtd info structure
+ * @chip: nand chip info structure
+ * @buf: data buffer
+ */
+void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf)
+{
+ chip->write_buf(mtd, buf, mtd->writesize);
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+}
+
+/**
+ * nand_write_page - [REPLACEABLE] write one page
+ * @mtd: MTD device structure
+ * @chip: NAND chip descriptor
+ * @buf: the data to write
+ * @page: page number to write
+ * @cached: cached programming
+ * @raw: use _raw version of write_page
+ */
+int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int page, int cached, int raw)
+{
+ int status;
+
+ chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
+
+ if (unlikely(raw))
+ chip->ecc.write_page_raw(mtd, chip, buf);
+ else
+ chip->ecc.write_page(mtd, chip, buf);
+
+ /*
+ * Cached progamming disabled for now, Not sure if its worth the
+ * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s)
+ */
+ cached = 0;
+
+ if (!cached || !(chip->options & NAND_CACHEPRG)) {
+
+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+ /*
+ * See if operation failed and additional status checks are
+ * available
+ */
+ if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+ status = chip->errstat(mtd, chip, FL_WRITING, status,
+ page);
+
+ if (status & NAND_STATUS_FAIL) {
+ return -EIO;
+ }
+ } else {
+ chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
+ status = chip->waitfunc(mtd, chip);
+ }
+
+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE
+ /* Send command to read back the data */
+ chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page);
+
+ if (chip->verify_buf(mtd, buf, mtd->writesize))
+ return -EIO;
+#endif
+ return 0;
+}
+
+/**
+ * nand_fill_oob - [Internal] Transfer client buffer to oob
+ * @chip: nand chip structure
+ * @oob: oob data buffer
+ * @ops: oob ops structure
+ */
+static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
+ struct mtd_oob_ops *ops)
+{
+ size_t len = ops->ooblen;
+
+ switch(ops->mode) {
+
+ case MTD_OOB_PLACE:
+ case MTD_OOB_RAW:
+ memcpy(chip->oob_poi + ops->ooboffs, oob, len);
+ return oob + len;
+
+ case MTD_OOB_AUTO: {
+ struct nand_oobfree *free = chip->ecc.layout->oobfree;
+ uint32_t boffs = 0, woffs = ops->ooboffs;
+ size_t bytes = 0;
+
+ for(; free->length && len; free++, len -= bytes) {
+ /* Write request not from offset 0 ? */
+ if (unlikely(woffs)) {
+ if (woffs >= free->length) {
+ woffs -= free->length;
+ continue;
+ }
+ boffs = free->offset + woffs;
+ bytes = min_t(size_t, len,
+ (free->length - woffs));
+ woffs = 0;
+ } else {
+ bytes = min_t(size_t, len, free->length);
+ boffs = free->offset;
+ }
+ memcpy(chip->oob_poi + boffs, oob, bytes);
+ oob += bytes;
+ }
+ return oob;
+ }
+ default:
+ BUG();
+ }
+ return NULL;
+}
+
+#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
+
+/**
+ * nand_do_write_ops - [Internal] NAND write with ECC
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operations description structure
+ *
+ * NAND write with ECC
+ */
+int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ int chipnr, realpage, page, blockmask, column;
+ struct nand_chip *chip = mtd->priv;
+ uint32_t writelen = ops->len;
+ uint8_t *oob = ops->oobbuf;
+ uint8_t *buf = ops->datbuf;
+ int ret, subpage;
+
+ ops->retlen = 0;
+ if (!writelen)
+ return 0;
+
+ /* reject writes, which are not page aligned */
+ if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
+ printk(KERN_NOTICE "nand_write: "
+ "Attempt to write not page aligned data\n");
+ return -EINVAL;
+ }
+
+ column = to & (mtd->writesize - 1);
+ subpage = column || (writelen & (mtd->writesize - 1));
+
+ if (subpage && oob)
+ return -EINVAL;
+
+ chipnr = (int)(to >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
+
+ /* Check, if it is write protected */
+ if (nand_check_wp(mtd)) {
+ return -EIO;
+ }
+
+ realpage = (int)(to >> chip->page_shift);
+ page = realpage & chip->pagemask;
+ blockmask = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
+
+ /* Invalidate the page cache, when we write to the cached page */
+ if (to <= (chip->pagebuf << chip->page_shift) &&
+ (chip->pagebuf << chip->page_shift) < (to + ops->len))
+ chip->pagebuf = -1;
+
+ /* If we're not given explicit OOB data, let it be 0xFF */
+ if (likely(!oob))
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+
+ while(1) {
+ int bytes = mtd->writesize;
+ int cached = writelen > bytes && page != blockmask;
+ uint8_t *wbuf = buf;
+
+ /* Partial page write ? */
+ if (unlikely(column || writelen < (mtd->writesize - 1))) {
+ cached = 0;
+ bytes = min_t(int, bytes - column, (int) writelen);
+ chip->pagebuf = -1;
+ memset(chip->buffers->databuf, 0xff, mtd->writesize);
+ memcpy(&chip->buffers->databuf[column], buf, bytes);
+ wbuf = chip->buffers->databuf;
+ }
+
+ if (unlikely(oob))
+ oob = nand_fill_oob(chip, oob, ops);
+
+ ret = chip->write_page(mtd, chip, wbuf, page, cached,
+ (ops->mode == MTD_OOB_RAW));
+ if (ret)
+ break;
+
+ writelen -= bytes;
+ if (!writelen)
+ break;
+
+ column = 0;
+ buf += bytes;
+ realpage++;
+
+ page = realpage & chip->pagemask;
+ /* Check, if we cross a chip boundary */
+ if (!page) {
+ chipnr++;
+ chip->select_chip(mtd, -1);
+ chip->select_chip(mtd, chipnr);
+ }
+ }
+
+ ops->retlen = ops->len - writelen;
+ if (unlikely(oob))
+ ops->oobretlen = ops->ooblen;
+ return ret;
+}
+
+/**
+ * nand_write - [MTD Interface] NAND write with ECC
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @len: number of bytes to write
+ * @retlen: pointer to variable to store the number of written bytes
+ * @buf: the data to write
+ *
+ * NAND write with ECC
+ */
+int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const uint8_t *buf)
+{
+ struct nand_chip *chip = mtd->priv;
+ int ret;
+
+ /* Do not allow reads past end of device */
+ if ((to + len) > mtd->size)
+ return -EINVAL;
+ if (!len)
+ return 0;
+
+ chip->ops.len = len;
+ chip->ops.datbuf = (uint8_t *)buf;
+ chip->ops.oobbuf = NULL;
+
+ ret = nand_do_write_ops(mtd, to, &chip->ops);
+
+ *retlen = chip->ops.retlen;
+
+ return ret;
+}
+
+/**
+ * nand_do_write_oob - [MTD Interface] NAND write out-of-band
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
+ *
+ * NAND write out-of-band
+ */
+static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ int chipnr, page, status, len;
+ struct nand_chip *chip = mtd->priv;
+
+ MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
+ (unsigned int)to, (int)ops->ooblen);
+
+ if (ops->mode == MTD_OOB_AUTO)
+ len = chip->ecc.layout->oobavail;
+ else
+ len = mtd->oobsize;
+
+ /* Do not allow write past end of page */
+ if ((ops->ooboffs + ops->ooblen) > len) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
+ "Attempt to write past end of page\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(ops->ooboffs >= len)) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt to start write outside oob\n");
+ return -EINVAL;
+ }
+
+ /* Do not allow reads past end of device */
+ if (unlikely(to >= mtd->size ||
+ ops->ooboffs + ops->ooblen >
+ ((mtd->size >> chip->page_shift) -
+ (to >> chip->page_shift)) * len)) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt write beyond end of device\n");
+ return -EINVAL;
+ }
+
+ chipnr = (int)(to >> chip->chip_shift);
+ chip->select_chip(mtd, chipnr);
+
+ /* Shift to get page */
+ page = (int)(to >> chip->page_shift);
+
+ /*
+ * Reset the chip. Some chips (like the Toshiba TC5832DC found in one
+ * of my DiskOnChip 2000 test units) will clear the whole data page too
+ * if we don't do this. I have no clue why, but I seem to have 'fixed'
+ * it in the doc2000 driver in August 1999. dwmw2.
+ */
+ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+
+ /* Check, if it is write protected */
+ if (nand_check_wp(mtd))
+ return -EROFS;
+
+ /* Invalidate the page cache, if we write to the cached page */
+ if (page == chip->pagebuf)
+ chip->pagebuf = -1;
+
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+ nand_fill_oob(chip, ops->oobbuf, ops);
+ status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
+ memset(chip->oob_poi, 0xff, mtd->oobsize);
+
+ if (status)
+ return status;
+
+ ops->oobretlen = ops->ooblen;
+
+ return 0;
+}
+
+/**
+ * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band
+ * @mtd: MTD device structure
+ * @to: offset to write to
+ * @ops: oob operation description structure
+ */
+int nand_write_oob(struct mtd_info *mtd, loff_t to,
+ struct mtd_oob_ops *ops)
+{
+ int ret = -ENOSYS;
+
+ ops->retlen = 0;
+
+ /* Do not allow writes past end of device */
+ if (ops->datbuf && (to + ops->len) > mtd->size) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+ "Attempt read beyond end of device\n");
+ return -EINVAL;
+ }
+
+ switch(ops->mode) {
+ case MTD_OOB_PLACE:
+ case MTD_OOB_AUTO:
+ case MTD_OOB_RAW:
+ break;
+
+ default:
+ goto out;
+ }
+
+ if (!ops->datbuf)
+ ret = nand_do_write_oob(mtd, to, ops);
+ else
+ ret = nand_do_write_ops(mtd, to, ops);
+
+ out:
+ return ret;
+}
+
+/**
+ * single_erease_cmd - [GENERIC] NAND standard block erase command function
+ * @mtd: MTD device structure
+ * @page: the page address of the block which will be erased
+ *
+ * Standard erase command for NAND chips
+ */
+void single_erase_cmd(struct mtd_info *mtd, int page)
+{
+ struct nand_chip *chip = mtd->priv;
+ /* Send commands to erase a block */
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+}
+
+/**
+ * multi_erease_cmd - [GENERIC] AND specific block erase command function
+ * @mtd: MTD device structure
+ * @page: the page address of the block which will be erased
+ *
+ * AND multi block erase command function
+ * Erase 4 consecutive blocks
+ */
+void multi_erase_cmd(struct mtd_info *mtd, int page)
+{
+ struct nand_chip *chip = mtd->priv;
+ /* Send commands to erase a block */
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page++);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE1, -1, page);
+ chip->cmdfunc(mtd, NAND_CMD_ERASE2, -1, -1);
+}
+
+/**
+ * nand_erase - [MTD Interface] erase block(s)
+ * @mtd: MTD device structure
+ * @instr: erase instruction
+ *
+ * Erase one ore more blocks
+ */
+int nand_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ return nand_erase_nand(mtd, instr, 0);
+}
+
+#define BBT_PAGE_MASK 0xffffff3f
+/**
+ * nand_erase_nand - [Internal] erase block(s)
+ * @mtd: MTD device structure
+ * @instr: erase instruction
+ * @allowbbt: allow erasing the bbt area
+ *
+ * Erase one ore more blocks
+ */
+int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
+ int allowbbt)
+{
+ int page, len, status, pages_per_block, ret, chipnr;
+ struct nand_chip *chip = mtd->priv;
+ int rewrite_bbt[NAND_MAX_CHIPS]={0};
+ unsigned int bbt_masked_page = 0xffffffff;
+
+ MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
+ (unsigned int)instr->addr, (unsigned int)instr->len);
+
+ /* Start address must align on block boundary */
+ if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
+ return -EINVAL;
+ }
+
+ /* Length must align on block boundary */
+ if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Length not block aligned\n");
+ return -EINVAL;
+ }
+
+ /* Do not allow erase past end of device */
+ if ((instr->len + instr->addr) > mtd->size) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Erase past end of device\n");
+ return -EINVAL;
+ }
+
+ instr->fail_addr = 0xffffffff;
+
+ /* Shift to get first page */
+ page = (int)(instr->addr >> chip->page_shift);
+ chipnr = (int)(instr->addr >> chip->chip_shift);
+
+ /* Calculate pages in each block */
+ pages_per_block = 1 << (chip->phys_erase_shift - chip->page_shift);
+
+ /* Select the NAND device */
+ chip->select_chip(mtd, chipnr);
+
+ /* Check, if it is write protected */
+ if (nand_check_wp(mtd)) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Device is write protected!!!\n");
+ instr->state = MTD_ERASE_FAILED;
+ goto erase_exit;
+ }
+
+ /*
+ * If BBT requires refresh, set the BBT page mask to see if the BBT
+ * should be rewritten. Otherwise the mask is set to 0xffffffff which
+ * can not be matched. This is also done when the bbt is actually
+ * erased to avoid recusrsive updates
+ */
+ if (chip->options & BBT_AUTO_REFRESH && !allowbbt)
+ bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+
+ /* Loop through the pages */
+ len = instr->len;
+
+ instr->state = MTD_ERASING;
+
+ while (len) {
+ /*
+ * heck if we have a bad block, we do not erase bad blocks !
+ */
+ if (nand_block_checkbad(mtd, ((loff_t) page) <<
+ chip->page_shift, 0, allowbbt)) {
+ printk(KERN_WARNING "nand_erase: attempt to erase a "
+ "bad block at page 0x%08x\n", page);
+ instr->state = MTD_ERASE_FAILED;
+ goto erase_exit;
+ }
+
+ /*
+ * Invalidate the page cache, if we erase the block which
+ * contains the current cached page
+ */
+ if (page <= chip->pagebuf && chip->pagebuf <
+ (page + pages_per_block))
+ chip->pagebuf = -1;
+
+ chip->erase_cmd(mtd, page & chip->pagemask);
+
+ status = chip->waitfunc(mtd, chip);
+
+ /*
+ * See if operation failed and additional status checks are
+ * available
+ */
+ if ((status & NAND_STATUS_FAIL) && (chip->errstat))
+ status = chip->errstat(mtd, chip, FL_ERASING,
+ status, page);
+
+ /* See if block erase succeeded */
+ if (status & NAND_STATUS_FAIL) {
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+ "Failed erase, page 0x%08x\n", page);
+ instr->state = MTD_ERASE_FAILED;
+ instr->fail_addr = (page << chip->page_shift);
+ goto erase_exit;
+ }
+
+ /*
+ * If BBT requires refresh, set the BBT rewrite flag to the
+ * page being erased
+ */
+ if (bbt_masked_page != 0xffffffff &&
+ (page & BBT_PAGE_MASK) == bbt_masked_page)
+ rewrite_bbt[chipnr] = (page << chip->page_shift);
+
+ /* Increment page address and decrement length */
+ len -= (1 << chip->phys_erase_shift);
+ page += pages_per_block;
+
+ /* Check, if we cross a chip boundary */
+ if (len && !(page & chip->pagemask)) {
+ chipnr++;
+ chip->select_chip(mtd, -1);
+ chip->select_chip(mtd, chipnr);
+
+ /*
+ * If BBT requires refresh and BBT-PERCHIP, set the BBT
+ * page mask to see if this BBT should be rewritten
+ */
+ if (bbt_masked_page != 0xffffffff &&
+ (chip->bbt_td->options & NAND_BBT_PERCHIP))
+ bbt_masked_page = chip->bbt_td->pages[chipnr] &
+ BBT_PAGE_MASK;
+ }
+ }
+ instr->state = MTD_ERASE_DONE;
+
+ erase_exit:
+
+ ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
+
+ /* Do call back function */
+ if (!ret)
+ mtd_erase_callback(instr);
+
+ /*
+ * If BBT requires refresh and erase was successful, rewrite any
+ * selected bad block tables
+ */
+ if (bbt_masked_page == 0xffffffff || ret)
+ return ret;
+
+ for (chipnr = 0; chipnr < chip->numchips; chipnr++) {
+ if (!rewrite_bbt[chipnr])
+ continue;
+ /* update the BBT for chip */
+ MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
+ "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
+ chip->bbt_td->pages[chipnr]);
+ nand_update_bbt(mtd, rewrite_bbt[chipnr]);
+ }
+
+ /* Return more or less happy */
+ return ret;
+}
+
+/**
+ * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad
+ * @mtd: MTD device structure
+ * @ofs: offset relative to mtd start
+ */
+int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
+{
+ struct nand_chip *chip = mtd->priv;
+ int ret;
+
+ if ((ret = nand_block_isbad(mtd, ofs))) {
+ /* If it was bad already, return success and do nothing. */
+ if (ret > 0)
+ return 0;
+ return ret;
+ }
+
+ return chip->block_markbad(mtd, ofs);
+}
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 5520132c..96ae16e0 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -9,7 +9,6 @@ struct ubi_volume_cdev_priv {
struct ubi_device *ubi;
struct ubi_volume *vol;
int updating;
- unsigned long mode;
};
static ssize_t ubi_volume_cdev_read(struct cdev *cdev, void *buf, size_t size,
@@ -82,21 +81,16 @@ static ssize_t ubi_volume_cdev_write(struct cdev* cdev, const void *buf,
return err;
}
-static int ubi_volume_cdev_open(struct cdev *cdev, struct filep *f)
+static int ubi_volume_cdev_open(struct cdev *cdev)
{
struct ubi_volume_cdev_priv *priv = cdev->priv;
- /* only allow read or write, but not both */
- if ((f->flags & O_ACCMODE) == O_RDWR)
- return -EINVAL;
-
priv->updating = 0;
- priv->mode = f->flags & O_ACCMODE;
return 0;
}
-static int ubi_volume_cdev_close(struct cdev *cdev, struct filep *f)
+static int ubi_volume_cdev_close(struct cdev *cdev)
{
struct ubi_volume_cdev_priv *priv = cdev->priv;
struct ubi_volume *vol = priv->vol;
@@ -132,7 +126,7 @@ static off_t ubi_volume_cdev_lseek(struct cdev *cdev, off_t ofs)
struct ubi_volume_cdev_priv *priv = cdev->priv;
/* We can only update ubi volumes sequentially */
- if (priv->mode == O_WRONLY)
+ if (priv->updating)
return -EINVAL;
return ofs;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 64794171..19e35dbb 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -84,6 +84,22 @@ config DRIVER_NET_TAP
bool "tap Ethernet driver"
depends on LINUX
+config DRIVER_NET_TSE
+ depends on NIOS2
+ bool "Altera TSE ethernet driver"
+ select MIIDEV
+ help
+ This option enables support for the Altera TSE MAC.
+
+config TSE_USE_DEDICATED_DESC_MEM
+ depends on DRIVER_NET_TSE
+ bool "Altera TSE uses dedicated descriptor memory"
+ help
+ This option tells the TSE driver to use an onchip memory
+ to store SGDMA descriptors. Descriptor memory is not
+ reserved with a malloc but directly mapped to the memory
+ address (defined in config.h)
+
source "drivers/net/usb/Kconfig"
endmenu
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 96d3d327..f02618bd 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -1,7 +1,7 @@
-obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o
+obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o
obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o
obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o
-obj-$(CONFIG_DRIVER_NET_DM9000) += dm9000.o
+obj-$(CONFIG_DRIVER_NET_DM9000) += dm9000.o
obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o
obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o
obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o
@@ -11,3 +11,4 @@ obj-$(CONFIG_DRIVER_NET_MACB) += macb.o
obj-$(CONFIG_DRIVER_NET_TAP) += tap.o
obj-$(CONFIG_MIIDEV) += miidev.o
obj-$(CONFIG_NET_USB) += usb/
+obj-$(CONFIG_DRIVER_NET_TSE) += altera_tse.o
diff --git a/drivers/net/altera_tse.c b/drivers/net/altera_tse.c
new file mode 100644
index 00000000..d922a9aa
--- /dev/null
+++ b/drivers/net/altera_tse.c
@@ -0,0 +1,579 @@
+/*
+ * Altera TSE Network driver
+ *
+ * Copyright (C) 2008 Altera Corporation.
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright (C) 2011 Franck JULLIEN, <elec4fun@gmail.com>
+ *
+ * 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 <net.h>
+#include <miidev.h>
+#include <init.h>
+#include <clock.h>
+#include <linux/mii.h>
+
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#include "altera_tse.h"
+
+/* This is a generic routine that the SGDMA mode-specific routines
+ * call to populate a descriptor.
+ * arg1 :pointer to first SGDMA descriptor.
+ * arg2 :pointer to next SGDMA descriptor.
+ * arg3 :Address to where data to be written.
+ * arg4 :Address from where data to be read.
+ * arg5 :no of byte to transaction.
+ * arg6 :variable indicating to generate start of packet or not
+ * arg7 :read fixed
+ * arg8 :write fixed
+ * arg9 :read burst
+ * arg10 :write burst
+ * arg11 :atlantic_channel number
+ */
+static void alt_sgdma_construct_descriptor_burst(
+ struct alt_sgdma_descriptor *desc,
+ struct alt_sgdma_descriptor *next,
+ uint32_t *read_addr,
+ uint32_t *write_addr,
+ uint16_t length_or_eop,
+ uint8_t generate_eop,
+ uint8_t read_fixed,
+ uint8_t write_fixed_or_sop,
+ uint8_t read_burst,
+ uint8_t write_burst,
+ uint8_t atlantic_channel)
+{
+ uint32_t temp;
+
+ /*
+ * Mark the "next" descriptor as "not" owned by hardware. This prevents
+ * The SGDMA controller from continuing to process the chain. This is
+ * done as a single IO write to bypass cache, without flushing
+ * the entire descriptor, since only the 8-bit descriptor status must
+ * be flushed.
+ */
+ if (!next)
+ printf("Next descriptor not defined!!\n");
+
+ temp = readb(&next->descriptor_control);
+ writeb(temp & ~ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK,
+ &next->descriptor_control);
+
+ writel((uint32_t)read_addr, &desc->source);
+ writel((uint32_t)write_addr, &desc->destination);
+ writel((uint32_t)next, &desc->next);
+
+ writel(0, &desc->source_pad);
+ writel(0, &desc->destination_pad);
+ writel(0, &desc->next_pad);
+ writew(length_or_eop, &desc->bytes_to_transfer);
+ writew(0, &desc->actual_bytes_transferred);
+ writeb(0, &desc->descriptor_status);
+
+ /* SGDMA burst not currently supported */
+ writeb(0, &desc->read_burst);
+ writeb(0, &desc->write_burst);
+
+ /*
+ * Set the descriptor control block as follows:
+ * - Set "owned by hardware" bit
+ * - Optionally set "generate EOP" bit
+ * - Optionally set the "read from fixed address" bit
+ * - Optionally set the "write to fixed address bit (which serves
+ * serves as a "generate SOP" control bit in memory-to-stream mode).
+ * - Set the 4-bit atlantic channel, if specified
+ *
+ * Note this step is performed after all other descriptor information
+ * has been filled out so that, if the controller already happens to be
+ * pointing at this descriptor, it will not run (via the "owned by
+ * hardware" bit) until all other descriptor has been set up.
+ */
+
+ writeb((ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK) |
+ (generate_eop ? ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK : 0) |
+ (read_fixed ? ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK : 0) |
+ (write_fixed_or_sop ? ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK : 0) |
+ (atlantic_channel ? ((atlantic_channel & 0x0F) << 3) : 0),
+ &desc->descriptor_control);
+}
+
+static int alt_sgdma_do_sync_transfer(struct alt_sgdma_registers *dev,
+ struct alt_sgdma_descriptor *desc)
+{
+ uint32_t temp;
+ uint64_t start;
+ uint64_t tout;
+
+ /* Wait for any pending transfers to complete */
+ tout = ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT * MSECOND;
+
+ start = get_time_ns();
+
+ while (readl(&dev->status) & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (is_timeout(start, tout)) {
+ debug("Timeout waiting sgdma in do sync!\n");
+ break;
+ }
+ }
+
+ /*
+ * Clear any (previous) status register information
+ * that might occlude our error checking later.
+ */
+ writel(0xFF, &dev->status);
+
+ /* Point the controller at the descriptor */
+ writel((uint32_t)desc, &dev->next_descriptor_pointer);
+ debug("next desc in sgdma 0x%x\n", (uint32_t)dev->next_descriptor_pointer);
+
+ /*
+ * Set up SGDMA controller to:
+ * - Disable interrupt generation
+ * - Run once a valid descriptor is written to controller
+ * - Stop on an error with any particular descriptor
+ */
+ writel(ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK,
+ &dev->control);
+
+ /* Wait for the descriptor (chain) to complete */
+ debug("wait for sgdma....");
+ start = get_time_ns();
+
+ while (readl(&dev->status) & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (is_timeout(start, tout)) {
+ debug("Timeout waiting sgdma in do sync!\n");
+ break;
+ }
+ }
+
+ debug("done\n");
+
+ /* Clear Run */
+ temp = readl(&dev->control);
+ writel(temp & ~ALT_SGDMA_CONTROL_RUN_MSK, &dev->control);
+
+ /* Get & clear status register contents */
+ debug("tx sgdma status = 0x%x", readl(&dev->status));
+ writel(0xFF, &dev->status);
+
+ return 0;
+}
+
+static int alt_sgdma_do_async_transfer(struct alt_sgdma_registers *dev,
+ struct alt_sgdma_descriptor *desc)
+{
+ uint64_t start;
+ uint64_t tout;
+
+ /* Wait for any pending transfers to complete */
+ tout = ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT * MSECOND;
+
+ start = get_time_ns();
+
+ while (readl(&dev->status) & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (is_timeout(start, tout)) {
+ debug("Timeout waiting sgdma in do async!\n");
+ break;
+ }
+ }
+
+ /*
+ * Clear any (previous) status register information
+ * that might occlude our error checking later.
+ */
+ writel(0xFF, &dev->status);
+
+ /* Point the controller at the descriptor */
+ writel((uint32_t)desc, &dev->next_descriptor_pointer);
+
+ /*
+ * Set up SGDMA controller to:
+ * - Disable interrupt generation
+ * - Run once a valid descriptor is written to controller
+ * - Stop on an error with any particular descriptor
+ */
+ writel(ALT_SGDMA_CONTROL_RUN_MSK | ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK,
+ &dev->control);
+
+ return 0;
+}
+
+static int tse_get_ethaddr(struct eth_device *edev, unsigned char *m)
+{
+ struct altera_tse_priv *priv = edev->priv;
+ struct alt_tse_mac *mac_dev = priv->mac_dev;
+
+ m[5] = (readl(&mac_dev->mac_addr_1) >> 8) && 0xFF;
+ m[4] = (readl(&mac_dev->mac_addr_1)) && 0xFF;
+ m[3] = (readl(&mac_dev->mac_addr_0) >> 24) && 0xFF;
+ m[2] = (readl(&mac_dev->mac_addr_0) >> 16) && 0xFF;
+ m[1] = (readl(&mac_dev->mac_addr_0) >> 8) && 0xFF;
+ m[0] = (readl(&mac_dev->mac_addr_0)) && 0xFF;
+
+ return 0;
+}
+
+static int tse_set_ethaddr(struct eth_device *edev, unsigned char *m)
+{
+ struct altera_tse_priv *priv = edev->priv;
+ struct alt_tse_mac *mac_dev = priv->mac_dev;
+
+ debug("Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+
+ writel(m[3] << 24 | m[2] << 16 | m[1] << 8 | m[0], &mac_dev->mac_addr_0);
+ writel((m[5] << 8 | m[4]) & 0xFFFF, &mac_dev->mac_addr_1);
+
+ return 0;
+}
+
+static int tse_phy_read(struct mii_device *mdev, int phy_addr, int reg)
+{
+ struct eth_device *edev = mdev->edev;
+ struct alt_tse_mac *mac_dev;
+ uint32_t *mdio_regs;
+
+ mac_dev = (struct alt_tse_mac *)edev->iobase;
+ writel(phy_addr, &mac_dev->mdio_phy1_addr);
+
+ mdio_regs = (uint32_t *)&mac_dev->mdio_phy1;
+
+ return readl(&mdio_regs[reg]) & 0xFFFF;
+}
+
+static int tse_phy_write(struct mii_device *mdev, int phy_addr, int reg, int val)
+{
+ struct eth_device *edev = mdev->edev;
+ struct alt_tse_mac *mac_dev;
+ uint32_t *mdio_regs;
+
+ mac_dev = (struct alt_tse_mac *)edev->iobase;
+ writel(phy_addr, &mac_dev->mdio_phy1_addr);
+
+ mdio_regs = (uint32_t *)&mac_dev->mdio_phy1;
+
+ writel((uint32_t)val, &mdio_regs[reg]);
+
+ return 0;
+}
+
+static void tse_reset(struct eth_device *edev)
+{
+ /* stop sgdmas, disable tse receive */
+ struct altera_tse_priv *priv = edev->priv;
+ struct alt_tse_mac *mac_dev = priv->mac_dev;
+ struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;
+ struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
+ struct alt_sgdma_descriptor *rx_desc = (struct alt_sgdma_descriptor *)&priv->rx_desc[0];
+ struct alt_sgdma_descriptor *tx_desc = (struct alt_sgdma_descriptor *)&priv->tx_desc[0];
+ uint64_t start;
+ uint64_t tout;
+
+ tout = ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT * MSECOND;
+
+ /* clear rx desc & wait for sgdma to complete */
+ writeb(0, &rx_desc->descriptor_control);
+ writel(0, &rx_sgdma->control);
+
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);
+ mdelay(100);
+
+ start = get_time_ns();
+
+ while (readl(&rx_sgdma->status) & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (is_timeout(start, tout)) {
+ printf("Timeout waiting for rx sgdma!\n");
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &rx_sgdma->control);
+ break;
+ }
+ }
+
+ /* clear tx desc & wait for sgdma to complete */
+ writeb(0, &tx_desc->descriptor_control);
+ writel(0, &tx_sgdma->control);
+
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);
+ mdelay(100);
+
+ start = get_time_ns();
+
+ while (readl(&tx_sgdma->status) & ALT_SGDMA_STATUS_BUSY_MSK) {
+ if (is_timeout(start, tout)) {
+ printf("Timeout waiting for tx sgdma!\n");
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);
+ writel(ALT_SGDMA_CONTROL_SOFTWARERESET_MSK, &tx_sgdma->control);
+ break;
+ }
+ }
+
+ /* reset the mac */
+ writel(ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK |
+ ALTERA_TSE_CMD_SW_RESET_MSK, &mac_dev->command_config);
+
+ start = get_time_ns();
+ tout = ALT_TSE_SW_RESET_WATCHDOG_TOUT * MSECOND;
+
+ while (readl(&mac_dev->command_config) & ALTERA_TSE_CMD_SW_RESET_MSK) {
+ if (is_timeout(start, tout)) {
+ printf("TSEMAC SW reset bit never cleared!\n");
+ break;
+ }
+ }
+}
+
+static int tse_eth_open(struct eth_device *edev)
+{
+ struct altera_tse_priv *priv = edev->priv;
+
+ miidev_wait_aneg(priv->miidev);
+ miidev_print_status(priv->miidev);
+
+ return 0;
+}
+
+static int tse_eth_send(struct eth_device *edev, void *packet, int length)
+{
+
+ struct altera_tse_priv *priv = edev->priv;
+ struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
+ struct alt_sgdma_descriptor *tx_desc = (struct alt_sgdma_descriptor *)priv->tx_desc;
+
+ struct alt_sgdma_descriptor *tx_desc_cur = (struct alt_sgdma_descriptor *)&tx_desc[0];
+
+ flush_dcache_range((uint32_t)packet, (uint32_t)packet + length);
+ alt_sgdma_construct_descriptor_burst(
+ (struct alt_sgdma_descriptor *)&tx_desc[0],
+ (struct alt_sgdma_descriptor *)&tx_desc[1],
+ (uint32_t *)packet, /* read addr */
+ (uint32_t *)0, /* */
+ length, /* length or EOP ,will change for each tx */
+ 0x1, /* gen eop */
+ 0x0, /* read fixed */
+ 0x1, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+
+ alt_sgdma_do_sync_transfer(tx_sgdma, tx_desc_cur);
+
+ return 0;;
+}
+
+static void tse_eth_halt(struct eth_device *edev)
+{
+ struct altera_tse_priv *priv = edev->priv;
+ struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;
+ struct alt_sgdma_registers *tx_sgdma = priv->sgdma_tx;
+
+ writel(0, &rx_sgdma->control); /* Stop the controller and reset settings */
+ writel(0, &tx_sgdma->control); /* Stop the controller and reset settings */
+}
+
+static int tse_eth_rx(struct eth_device *edev)
+{
+ uint16_t packet_length = 0;
+
+ struct altera_tse_priv *priv = edev->priv;
+ struct alt_sgdma_descriptor *rx_desc = (struct alt_sgdma_descriptor *)priv->rx_desc;
+ struct alt_sgdma_descriptor *rx_desc_cur = &rx_desc[0];
+ struct alt_sgdma_registers *rx_sgdma = priv->sgdma_rx;
+
+ if (rx_desc_cur->descriptor_status &
+ ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK) {
+
+ packet_length = rx_desc->actual_bytes_transferred;
+ net_receive(NetRxPackets[0], packet_length);
+
+ /* Clear Run */
+ rx_sgdma->control = (rx_sgdma->control & (~ALT_SGDMA_CONTROL_RUN_MSK));
+
+ /* start descriptor again */
+ flush_dcache_range((uint32_t)(NetRxPackets[0]), (uint32_t)(NetRxPackets[0]) + PKTSIZE);
+ alt_sgdma_construct_descriptor_burst(
+ (struct alt_sgdma_descriptor *)&rx_desc[0],
+ (struct alt_sgdma_descriptor *)&rx_desc[1],
+ (uint32_t)0x0, /* read addr */
+ (uint32_t *)NetRxPackets[0], /* */
+ 0x0, /* length or EOP */
+ 0x0, /* gen eop */
+ 0x0, /* read fixed */
+ 0x0, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+
+ /* setup the sgdma */
+ alt_sgdma_do_async_transfer(priv->sgdma_rx, &rx_desc[0]);
+ }
+
+ return 0;
+}
+
+static int tse_init_dev(struct eth_device *edev)
+{
+ struct altera_tse_priv *priv = edev->priv;
+ struct alt_tse_mac *mac_dev = priv->mac_dev;
+ struct alt_sgdma_descriptor *tx_desc = priv->tx_desc;
+ struct alt_sgdma_descriptor *rx_desc = priv->rx_desc;
+ struct alt_sgdma_descriptor *rx_desc_cur;
+
+ rx_desc_cur = (struct alt_sgdma_descriptor *)&rx_desc[0];
+
+ tse_reset(edev);
+
+ /* need to create sgdma */
+ alt_sgdma_construct_descriptor_burst(
+ (struct alt_sgdma_descriptor *)&tx_desc[0],
+ (struct alt_sgdma_descriptor *)&tx_desc[1],
+ (uint32_t *)NULL, /* read addr */
+ (uint32_t *)0, /* */
+ 0, /* length or EOP ,will change for each tx */
+ 0x1, /* gen eop */
+ 0x0, /* read fixed */
+ 0x1, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+
+ flush_dcache_range((uint32_t)(NetRxPackets[0]), (uint32_t)(NetRxPackets[0]) + PKTSIZE);
+ alt_sgdma_construct_descriptor_burst(
+ (struct alt_sgdma_descriptor *)&rx_desc[0],
+ (struct alt_sgdma_descriptor *)&rx_desc[1],
+ (uint32_t)0x0, /* read addr */
+ (uint32_t *)NetRxPackets[0], /* */
+ 0x0, /* length or EOP */
+ 0x0, /* gen eop */
+ 0x0, /* read fixed */
+ 0x0, /* write fixed or sop */
+ 0x0, /* read burst */
+ 0x0, /* write burst */
+ 0x0 /* channel */
+ );
+
+ /* start rx async transfer */
+ alt_sgdma_do_async_transfer(priv->sgdma_rx, rx_desc_cur);
+
+ /* Initialize MAC registers */
+ writel(PKTSIZE, &mac_dev->max_frame_length);
+
+ /* NO Shift */
+ writel(0, &mac_dev->rx_cmd_stat);
+ writel(0, &mac_dev->tx_cmd_stat);
+
+ /* enable MAC */
+ writel(ALTERA_TSE_CMD_TX_ENA_MSK | ALTERA_TSE_CMD_RX_ENA_MSK, &mac_dev->command_config);
+
+ miidev_restart_aneg(priv->miidev);
+
+ return 0;
+}
+
+static int tse_probe(struct device_d *dev)
+{
+ struct altera_tse_priv *priv;
+ struct mii_device *miidev;
+ struct eth_device *edev;
+ struct alt_sgdma_descriptor *rx_desc;
+ struct alt_sgdma_descriptor *tx_desc;
+#ifndef CONFIG_TSE_USE_DEDICATED_DESC_MEM
+ uint32_t dma_handle;
+#endif
+ edev = xzalloc(sizeof(struct eth_device) + sizeof(struct altera_tse_priv));
+ miidev = xzalloc(sizeof(struct mii_device));
+
+ dev->type_data = edev;
+ edev->priv = (struct altera_tse_priv *)(edev + 1);
+
+ edev->iobase = dev->map_base;
+
+ priv = edev->priv;
+
+ edev->init = tse_init_dev;
+ edev->open = tse_eth_open;
+ edev->send = tse_eth_send;
+ edev->recv = tse_eth_rx;
+ edev->halt = tse_eth_halt;
+ edev->get_ethaddr = tse_get_ethaddr;
+ edev->set_ethaddr = tse_set_ethaddr;
+
+#ifdef CONFIG_TSE_USE_DEDICATED_DESC_MEM
+ tx_desc = (struct alt_sgdma_descriptor *)NIOS_SOPC_TSE_DESC_MEM_BASE;
+ rx_desc = tx_desc + 2;
+#else
+ tx_desc = dma_alloc_coherent(sizeof(*tx_desc) * (3 + PKTBUFSRX), &dma_handle);
+ rx_desc = tx_desc + 2;
+
+ if (!tx_desc) {
+ free(edev);
+ free(miidev);
+ return 0;
+ }
+#endif
+
+ memset(rx_desc, 0, (sizeof *rx_desc) * (PKTBUFSRX + 1));
+ memset(tx_desc, 0, (sizeof *tx_desc) * 2);
+
+ priv->mac_dev = (struct alt_tse_mac *)dev->map_base;
+ priv->sgdma_rx = (struct alt_sgdma_registers *)NIOS_SOPC_SGDMA_RX_BASE;
+ priv->sgdma_tx = (struct alt_sgdma_registers *)NIOS_SOPC_SGDMA_TX_BASE;
+ priv->rx_desc = rx_desc;
+ priv->tx_desc = tx_desc;
+
+ priv->miidev = miidev;
+
+ miidev->read = tse_phy_read;
+ miidev->write = tse_phy_write;
+ miidev->flags = 0;
+ miidev->edev = edev;
+
+ if (dev->platform_data != NULL)
+ miidev->address = *((int8_t *)(dev->platform_data));
+ else {
+ printf("No PHY address specified.\n");
+ return -ENODEV;
+ }
+
+ mii_register(miidev);
+
+ return eth_register(edev);
+}
+
+static struct driver_d altera_tse_driver = {
+ .name = "altera_tse",
+ .probe = tse_probe,
+};
+
+static int tse_init(void)
+{
+ register_driver(&altera_tse_driver);
+ return 0;
+}
+
+device_initcall(tse_init);
+
diff --git a/drivers/net/altera_tse.h b/drivers/net/altera_tse.h
new file mode 100644
index 00000000..c907c742
--- /dev/null
+++ b/drivers/net/altera_tse.h
@@ -0,0 +1,303 @@
+/*
+ * Altera 10/100/1000 triple speed ethernet mac
+ *
+ * Copyright (C) 2008 Altera Corporation.
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright (C) 2011 Franck JULLIEN <elec4fun@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ALTERA_TSE_H_
+#define _ALTERA_TSE_H_
+
+/* SGDMA Stuff */
+#define ALT_SGDMA_STATUS_ERROR_MSK (0x00000001)
+#define ALT_SGDMA_STATUS_EOP_ENCOUNTERED_MSK (0x00000002)
+#define ALT_SGDMA_STATUS_DESC_COMPLETED_MSK (0x00000004)
+#define ALT_SGDMA_STATUS_CHAIN_COMPLETED_MSK (0x00000008)
+#define ALT_SGDMA_STATUS_BUSY_MSK (0x00000010)
+
+#define ALT_SGDMA_CONTROL_IE_ERROR_MSK (0x00000001)
+#define ALT_SGDMA_CONTROL_IE_EOP_ENCOUNTERED_MSK (0x00000002)
+#define ALT_SGDMA_CONTROL_IE_DESC_COMPLETED_MSK (0x00000004)
+#define ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK (0x00000008)
+#define ALT_SGDMA_CONTROL_IE_GLOBAL_MSK (0x00000010)
+#define ALT_SGDMA_CONTROL_RUN_MSK (0x00000020)
+#define ALT_SGDMA_CONTROL_STOP_DMA_ER_MSK (0x00000040)
+#define ALT_SGDMA_CONTROL_IE_MAX_DESC_PROCESSED_MSK (0x00000080)
+#define ALT_SGDMA_CONTROL_MAX_DESC_PROCESSED_MSK (0x0000FF00)
+#define ALT_SGDMA_CONTROL_SOFTWARERESET_MSK (0x00010000)
+#define ALT_SGDMA_CONTROL_PARK_MSK (0x00020000)
+#define ALT_SGDMA_CONTROL_CLEAR_INTERRUPT_MSK (0x80000000)
+
+#define ALTERA_TSE_SGDMA_INTR_MASK (ALT_SGDMA_CONTROL_IE_CHAIN_COMPLETED_MSK \
+ | ALT_SGDMA_STATUS_DESC_COMPLETED_MSK \
+ | ALT_SGDMA_CONTROL_IE_GLOBAL_MSK)
+
+/*
+ * Descriptor control bit masks & offsets
+ *
+ * Note: The control byte physically occupies bits [31:24] in memory.
+ * The following bit-offsets are expressed relative to the LSB of
+ * the control register bitfield.
+ */
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_GENERATE_EOP_MSK (0x00000001)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_READ_FIXED_ADDRESS_MSK (0x00000002)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_WRITE_FIXED_ADDRESS_MSK (0x00000004)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_ATLANTIC_CHANNEL_MSK (0x00000008)
+#define ALT_SGDMA_DESCRIPTOR_CONTROL_OWNED_BY_HW_MSK (0x00000080)
+
+/*
+ * Descriptor status bit masks & offsets
+ *
+ * Note: The status byte physically occupies bits [23:16] in memory.
+ * The following bit-offsets are expressed relative to the LSB of
+ * the status register bitfield.
+ */
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_CRC_MSK (0x00000001)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_PARITY_MSK (0x00000002)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_OVERFLOW_MSK (0x00000004)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_SYNC_MSK (0x00000008)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_UEOP_MSK (0x00000010)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MEOP_MSK (0x00000020)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_E_MSOP_MSK (0x00000040)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_TERMINATED_BY_EOP_MSK (0x00000080)
+#define ALT_SGDMA_DESCRIPTOR_STATUS_ERROR_MSK (0x0000007F)
+
+/*
+ * The SGDMA controller buffer descriptor allocates
+ * 64 bits for each address. To support ANSI C, the
+ * struct implementing a descriptor places 32-bits
+ * of padding directly above each address; each pad must
+ * be cleared when initializing a descriptor.
+ */
+
+/*
+ * Buffer Descriptor data structure
+ *
+ */
+struct alt_sgdma_descriptor {
+ unsigned int *source; /* the address of data to be read. */
+ unsigned int source_pad;
+
+ unsigned int *destination; /* the address to write data */
+ unsigned int destination_pad;
+
+ unsigned int *next; /* the next descriptor in the list. */
+ unsigned int next_pad;
+
+ unsigned short bytes_to_transfer; /* the number of bytes to transfer */
+ unsigned char read_burst;
+ unsigned char write_burst;
+
+ unsigned short actual_bytes_transferred;/* bytes transferred by DMA */
+ unsigned char descriptor_status;
+ unsigned char descriptor_control;
+
+} __attribute__ ((packed, aligned(1)));
+
+/* SG-DMA Control/Status Slave registers map */
+
+struct alt_sgdma_registers {
+ unsigned int status;
+ unsigned int status_pad[3];
+ unsigned int control;
+ unsigned int control_pad[3];
+ unsigned int next_descriptor_pointer;
+ unsigned int descriptor_pad[3];
+};
+
+/* TSE Stuff */
+#define ALTERA_TSE_CMD_TX_ENA_MSK (0x00000001)
+#define ALTERA_TSE_CMD_RX_ENA_MSK (0x00000002)
+#define ALTERA_TSE_CMD_XON_GEN_MSK (0x00000004)
+#define ALTERA_TSE_CMD_ETH_SPEED_MSK (0x00000008)
+#define ALTERA_TSE_CMD_PROMIS_EN_MSK (0x00000010)
+#define ALTERA_TSE_CMD_PAD_EN_MSK (0x00000020)
+#define ALTERA_TSE_CMD_CRC_FWD_MSK (0x00000040)
+#define ALTERA_TSE_CMD_PAUSE_FWD_MSK (0x00000080)
+#define ALTERA_TSE_CMD_PAUSE_IGNORE_MSK (0x00000100)
+#define ALTERA_TSE_CMD_TX_ADDR_INS_MSK (0x00000200)
+#define ALTERA_TSE_CMD_HD_ENA_MSK (0x00000400)
+#define ALTERA_TSE_CMD_EXCESS_COL_MSK (0x00000800)
+#define ALTERA_TSE_CMD_LATE_COL_MSK (0x00001000)
+#define ALTERA_TSE_CMD_SW_RESET_MSK (0x00002000)
+#define ALTERA_TSE_CMD_MHASH_SEL_MSK (0x00004000)
+#define ALTERA_TSE_CMD_LOOPBACK_MSK (0x00008000)
+/* Bits (18:16) = address select */
+#define ALTERA_TSE_CMD_TX_ADDR_SEL_MSK (0x00070000)
+#define ALTERA_TSE_CMD_MAGIC_ENA_MSK (0x00080000)
+#define ALTERA_TSE_CMD_SLEEP_MSK (0x00100000)
+#define ALTERA_TSE_CMD_WAKEUP_MSK (0x00200000)
+#define ALTERA_TSE_CMD_XOFF_GEN_MSK (0x00400000)
+#define ALTERA_TSE_CMD_CNTL_FRM_ENA_MSK (0x00800000)
+#define ALTERA_TSE_CMD_NO_LENGTH_CHECK_MSK (0x01000000)
+#define ALTERA_TSE_CMD_ENA_10_MSK (0x02000000)
+#define ALTERA_TSE_CMD_RX_ERR_DISC_MSK (0x04000000)
+/* Bits (30..27) reserved */
+#define ALTERA_TSE_CMD_CNT_RESET_MSK (0x80000000)
+
+#define ALTERA_TSE_TX_CMD_STAT_TX_SHIFT16 (0x00040000)
+#define ALTERA_TSE_TX_CMD_STAT_OMIT_CRC (0x00020000)
+
+#define ALTERA_TSE_RX_CMD_STAT_RX_SHIFT16 (0x02000000)
+
+#define ALT_TSE_SW_RESET_WATCHDOG_CNTR 10000
+#define ALT_TSE_SGDMA_BUSY_WATCHDOG_CNTR 90000000
+
+#define ALT_TSE_SW_RESET_WATCHDOG_TOUT 1 /* ms */
+#define ALT_TSE_SGDMA_BUSY_WATCHDOG_TOUT 5 /* ms */
+
+struct alt_tse_mdio {
+ unsigned int control; /*PHY device operation control register */
+ unsigned int status; /*PHY device operation status register */
+ unsigned int phy_id1; /*Bits 31:16 of PHY identifier. */
+ unsigned int phy_id2; /*Bits 15:0 of PHY identifier. */
+ unsigned int auto_negotiation_advertisement;
+ unsigned int remote_partner_base_page_ability;
+
+ unsigned int reg6;
+ unsigned int reg7;
+ unsigned int reg8;
+ unsigned int reg9;
+ unsigned int rega;
+ unsigned int regb;
+ unsigned int regc;
+ unsigned int regd;
+ unsigned int rege;
+ unsigned int regf;
+ unsigned int reg10;
+ unsigned int reg11;
+ unsigned int reg12;
+ unsigned int reg13;
+ unsigned int reg14;
+ unsigned int reg15;
+ unsigned int reg16;
+ unsigned int reg17;
+ unsigned int reg18;
+ unsigned int reg19;
+ unsigned int reg1a;
+ unsigned int reg1b;
+ unsigned int reg1c;
+ unsigned int reg1d;
+ unsigned int reg1e;
+ unsigned int reg1f;
+};
+
+/* MAC register Space */
+
+struct alt_tse_mac {
+ unsigned int megacore_revision;
+ unsigned int scratch_pad;
+ unsigned int command_config;
+ unsigned int mac_addr_0;
+ unsigned int mac_addr_1;
+ unsigned int max_frame_length;
+ unsigned int pause_quanta;
+ unsigned int rx_sel_empty_threshold;
+ unsigned int rx_sel_full_threshold;
+ unsigned int tx_sel_empty_threshold;
+ unsigned int tx_sel_full_threshold;
+ unsigned int rx_almost_empty_threshold;
+ unsigned int rx_almost_full_threshold;
+ unsigned int tx_almost_empty_threshold;
+ unsigned int tx_almost_full_threshold;
+ unsigned int mdio_phy0_addr;
+ unsigned int mdio_phy1_addr;
+
+ /* only if 100/1000 BaseX PCS, reserved otherwise */
+ unsigned int reservedx44[5];
+
+ unsigned int reg_read_access_status;
+ unsigned int min_tx_ipg_length;
+
+ /* IEEE 802.3 oEntity Managed Object Support */
+ unsigned int aMACID_1; /*The MAC addresses */
+ unsigned int aMACID_2;
+ unsigned int aFramesTransmittedOK;
+ unsigned int aFramesReceivedOK;
+ unsigned int aFramesCheckSequenceErrors;
+ unsigned int aAlignmentErrors;
+ unsigned int aOctetsTransmittedOK;
+ unsigned int aOctetsReceivedOK;
+
+ /* IEEE 802.3 oPausedEntity Managed Object Support */
+ unsigned int aTxPAUSEMACCtrlFrames;
+ unsigned int aRxPAUSEMACCtrlFrames;
+
+ /* IETF MIB (MIB-II) Object Support */
+ unsigned int ifInErrors;
+ unsigned int ifOutErrors;
+ unsigned int ifInUcastPkts;
+ unsigned int ifInMulticastPkts;
+ unsigned int ifInBroadcastPkts;
+ unsigned int ifOutDiscards;
+ unsigned int ifOutUcastPkts;
+ unsigned int ifOutMulticastPkts;
+ unsigned int ifOutBroadcastPkts;
+
+ /* IETF RMON MIB Object Support */
+ unsigned int etherStatsDropEvent;
+ unsigned int etherStatsOctets;
+ unsigned int etherStatsPkts;
+ unsigned int etherStatsUndersizePkts;
+ unsigned int etherStatsOversizePkts;
+ unsigned int etherStatsPkts64Octets;
+ unsigned int etherStatsPkts65to127Octets;
+ unsigned int etherStatsPkts128to255Octets;
+ unsigned int etherStatsPkts256to511Octets;
+ unsigned int etherStatsPkts512to1023Octets;
+ unsigned int etherStatsPkts1024to1518Octets;
+
+ unsigned int etherStatsPkts1519toXOctets;
+ unsigned int etherStatsJabbers;
+ unsigned int etherStatsFragments;
+
+ unsigned int reservedxE4;
+
+ /*FIFO control register. */
+ unsigned int tx_cmd_stat;
+ unsigned int rx_cmd_stat;
+
+ unsigned int ipaccTxConf;
+ unsigned int ipaccRxConf;
+ unsigned int ipaccRxStat;
+ unsigned int ipaccRxStatSum;
+
+ /*Multicast address resolution table */
+ unsigned int hash_table[64];
+
+ /*Registers 0 to 31 within PHY device 0/1 */
+ struct alt_tse_mdio mdio_phy0;
+ struct alt_tse_mdio mdio_phy1;
+
+ /*4 Supplemental MAC Addresses */
+ unsigned int supp_mac_addr_0_0;
+ unsigned int supp_mac_addr_0_1;
+ unsigned int supp_mac_addr_1_0;
+ unsigned int supp_mac_addr_1_1;
+ unsigned int supp_mac_addr_2_0;
+ unsigned int supp_mac_addr_2_1;
+ unsigned int supp_mac_addr_3_0;
+ unsigned int supp_mac_addr_3_1;
+
+ unsigned int reservedx320[56];
+};
+
+struct altera_tse_priv {
+ struct alt_tse_mac *mac_dev;
+ struct alt_sgdma_registers *sgdma_rx;
+ struct alt_sgdma_registers *sgdma_tx;
+ unsigned int rx_sgdma_irq;
+ unsigned int tx_sgdma_irq;
+ unsigned int has_descriptor_mem;
+ unsigned int descriptor_mem_base;
+ unsigned int descriptor_mem_size;
+ struct alt_sgdma_descriptor *rx_desc;
+ struct alt_sgdma_descriptor *tx_desc;
+ struct mii_device *miidev;
+};
+
+#endif /* _ALTERA_TSE_H_ */
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index e5c0e7e0..dc5477b9 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -365,6 +365,7 @@
#define CHIP_9216 0x116a
#define CHIP_9217 0x117a
#define CHIP_9218 0x118a
+#define CHIP_9221 0x9221
struct smc911x_priv {
struct mii_device miidev;
@@ -385,6 +386,7 @@ static const struct chip_id chip_ids[] = {
{ CHIP_9216, "LAN9216" },
{ CHIP_9217, "LAN9217" },
{ CHIP_9218, "LAN9218" },
+ { CHIP_9221, "LAN9221" },
{ 0, NULL },
};
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 64826264..b53dcc7c 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -8,4 +8,8 @@ config NET_USB_ASIX
select MIIDEV
bool "Asix compatible"
+config NET_USB_SMSC95XX
+ select MIIDEV
+ bool "SMSC95xx"
+
endif
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index 555f8c2f..564e44de 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -1,2 +1,3 @@
obj-$(CONFIG_NET_USB) += usbnet.o
obj-$(CONFIG_NET_USB_ASIX) += asix.o
+obj-$(CONFIG_NET_USB_SMSC95XX) += smsc95xx.o
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
new file mode 100644
index 00000000..ae137fb9
--- /dev/null
+++ b/drivers/net/usb/smsc95xx.c
@@ -0,0 +1,938 @@
+/***************************************************************************
+ *
+ * Copyright (C) 2007-2008 SMSC
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *****************************************************************************/
+
+#include <common.h>
+#include <command.h>
+#include <init.h>
+#include <net.h>
+#include <usb/usb.h>
+#include <usb/usbnet.h>
+#include <malloc.h>
+#include <asm/byteorder.h>
+#include <errno.h>
+#include <miidev.h>
+#include "smsc95xx.h"
+
+#define SMSC_CHIPNAME "smsc95xx"
+#define SMSC_DRIVER_VERSION "1.0.4"
+#define HS_USB_PKT_SIZE (512)
+#define FS_USB_PKT_SIZE (64)
+#define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE)
+#define DEFAULT_FS_BURST_CAP_SIZE (6 * 1024 + 33 * FS_USB_PKT_SIZE)
+#define DEFAULT_BULK_IN_DELAY (0x00002000)
+#define MAX_SINGLE_PACKET_SIZE (2048)
+#define LAN95XX_EEPROM_MAGIC (0x9500)
+#define EEPROM_MAC_OFFSET (0x01)
+#define DEFAULT_TX_CSUM_ENABLE (1)
+#define DEFAULT_RX_CSUM_ENABLE (1)
+#define SMSC95XX_INTERNAL_PHY_ID (1)
+#define SMSC95XX_TX_OVERHEAD (8)
+#define SMSC95XX_TX_OVERHEAD_CSUM (12)
+
+#define ETH_ALEN 6
+#define NET_IP_ALIGN 2
+#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
+#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
+
+#define netdev_warn(x, fmt, arg...) printf(fmt, ##arg)
+#ifdef DEBUG
+#define netif_dbg(x, y, z, fmt, arg...) printf(fmt, ##arg)
+#else
+#define netif_dbg(x, y, z, fmt, arg...) do {} while(0)
+#endif
+
+#define FLOW_CTRL_RX 0x02
+
+struct smsc95xx_priv {
+ u32 mac_cr;
+ int use_tx_csum;
+ int use_rx_csum;
+};
+
+static int turbo_mode = 0;
+
+static int smsc95xx_read_reg(struct usbnet *dev, u32 index, u32 *data)
+{
+ int ret;
+
+ ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
+ USB_VENDOR_REQUEST_READ_REGISTER,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 00, index, data, 4, USB_CTRL_GET_TIMEOUT);
+
+ if (ret < 0)
+ netdev_warn(dev->net, "Failed to read register index 0x%08x\n", index);
+
+ le32_to_cpus(data);
+
+ debug("%s: 0x%08x 0x%08x\n", __func__, index, *data);
+
+ return ret;
+}
+
+static int smsc95xx_write_reg(struct usbnet *dev, u32 index, u32 data)
+{
+ int ret;
+
+ cpu_to_le32s(&data);
+
+ ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
+ USB_VENDOR_REQUEST_WRITE_REGISTER,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 00, index, &data, 4, USB_CTRL_SET_TIMEOUT);
+
+ if (ret < 0)
+ netdev_warn(dev->net, "Failed to write register index 0x%08x\n", index);
+
+ debug("%s: 0x%08x 0x%08x\n", __func__, index, data);
+
+ return ret;
+}
+
+/* Loop until the read is completed with timeout
+ * called with phy_mutex held */
+static int smsc95xx_phy_wait_not_busy(struct usbnet *dev)
+{
+ u32 val;
+ int timeout = 1000;
+
+ do {
+ smsc95xx_read_reg(dev, MII_ADDR, &val);
+ if (!(val & MII_BUSY_))
+ return 0;
+ udelay(100);
+ } while (--timeout);
+
+ return -EIO;
+}
+
+static int smsc95xx_mdio_read(struct mii_device *mdev, int phy_id, int idx)
+{
+ struct eth_device *eth = mdev->edev;
+ struct usbnet *dev = eth->priv;
+ u32 val, addr;
+
+ /* confirm MII not busy */
+ if (smsc95xx_phy_wait_not_busy(dev)) {
+ netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_read\n");
+ return -EIO;
+ }
+
+ /* set the address, index & direction (read from PHY) */
+ addr = (phy_id << 11) | (idx << 6) | MII_READ_;
+ smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+ if (smsc95xx_phy_wait_not_busy(dev)) {
+ netdev_warn(dev->net, "Timed out reading MII reg %02X\n", idx);
+ return -EIO;
+ }
+
+ smsc95xx_read_reg(dev, MII_DATA, &val);
+
+ return val & 0xffff;
+}
+
+static int smsc95xx_mdio_write(struct mii_device *mdev, int phy_id, int idx,
+ int regval)
+{
+ struct eth_device *eth = mdev->edev;
+ struct usbnet *dev = eth->priv;
+ u32 val, addr;
+
+ /* confirm MII not busy */
+ if (smsc95xx_phy_wait_not_busy(dev)) {
+ netdev_warn(dev->net, "MII is busy in smsc95xx_mdio_write\n");
+ return -EBUSY;
+ }
+
+ val = regval;
+ smsc95xx_write_reg(dev, MII_DATA, val);
+
+ /* set the address, index & direction (write to PHY) */
+ addr = (phy_id << 11) | (idx << 6) | MII_WRITE_;
+ smsc95xx_write_reg(dev, MII_ADDR, addr);
+
+ if (smsc95xx_phy_wait_not_busy(dev))
+ netdev_warn(dev->net, "Timed out writing MII reg %02X\n", idx);
+
+ return 0;
+}
+
+static int smsc95xx_wait_eeprom(struct usbnet *dev)
+{
+ int timeout = 1000;
+ u32 val;
+
+ do {
+ smsc95xx_read_reg(dev, E2P_CMD, &val);
+ if (!(val & E2P_CMD_BUSY_) || (val & E2P_CMD_TIMEOUT_))
+ break;
+ udelay(100);
+ } while (--timeout);
+
+ if (val & (E2P_CMD_TIMEOUT_ | E2P_CMD_BUSY_)) {
+ netdev_warn(dev->net, "EEPROM read operation timeout\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int smsc95xx_eeprom_confirm_not_busy(struct usbnet *dev)
+{
+ int timeout = 1000;
+ u32 val;
+
+ do {
+ smsc95xx_read_reg(dev, E2P_CMD, &val);
+
+ if (!(val & E2P_CMD_BUSY_))
+ return 0;
+ udelay(100);
+ } while (--timeout);
+
+ netdev_warn(dev->net, "EEPROM is busy\n");
+ return -EIO;
+}
+
+static int smsc95xx_read_eeprom(struct usbnet *dev, u32 offset, u32 length,
+ u8 *data)
+{
+ u32 val;
+ int i, ret;
+
+ ret = smsc95xx_eeprom_confirm_not_busy(dev);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < length; i++) {
+ val = E2P_CMD_BUSY_ | E2P_CMD_READ_ | (offset & E2P_CMD_ADDR_);
+ smsc95xx_write_reg(dev, E2P_CMD, val);
+
+ ret = smsc95xx_wait_eeprom(dev);
+ if (ret < 0)
+ return ret;
+
+ smsc95xx_read_reg(dev, E2P_DATA, &val);
+
+ data[i] = val & 0xFF;
+ offset++;
+ }
+
+ return 0;
+}
+
+#define GPIO_CFG_GPEN_ (0xff000000)
+#define GPIO_CFG_GPO0_EN_ (0x01000000)
+#define GPIO_CFG_GPTYPE (0x00ff0000)
+#define GPIO_CFG_GPO0_TYPE (0x00010000)
+#define GPIO_CFG_GPDIR_ (0x0000ff00)
+#define GPIO_CFG_GPO0_DIR_ (0x00000100)
+#define GPIO_CFG_GPDATA_ (0x000000ff)
+#define GPIO_CFG_GPO0_DATA_ (0x00000001)
+#define LED_GPIO_CFG_FDX_LED (0x00010000)
+#define LED_GPIO_CFG_GPBUF_08_ (0x00000100)
+#define LED_GPIO_CFG_GPDIR_08_ (0x00000010)
+#define LED_GPIO_CFG_GPDATA_08_ (0x00000001)
+#define LED_GPIO_CFG_GPCTL_LED_ (0x00000001)
+
+#if 0
+static int smsc95xx_enable_gpio(struct usbnet *dev, int gpio, int type)
+{
+ int ret = -1;
+ u32 val, reg;
+ int dir_shift, enable_shift, type_shift;
+
+ if (gpio < 8) {
+ reg = GPIO_CFG;
+ enable_shift = 24 + gpio;
+ type_shift = 16 + gpio;
+ dir_shift = 8 + gpio;
+ } else {
+ gpio -= 8;
+ reg = LED_GPIO_CFG;
+ enable_shift = 16 + gpio * 4;
+ type_shift = 8 + gpio;
+ dir_shift = 4 + gpio;
+ }
+
+ ret = smsc95xx_read_reg(dev, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ val &= ~(1 << enable_shift);
+
+ if (type)
+ val &= ~(1 << type_shift);
+ else
+ val |= (1 << type_shift);
+
+ val |= (1 << dir_shift);
+
+ ret = smsc95xx_write_reg(dev, reg, val);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int smsc95xx_gpio_set_value(struct usbnet *dev, int gpio, int value)
+{
+ int ret = -1;
+ u32 tmp, reg;
+
+ if (gpio > 10)
+ return -EINVAL;
+
+ smsc95xx_enable_gpio(dev, gpio, 0);
+
+ if (gpio < 8) {
+ reg = GPIO_CFG;
+ } else {
+ reg = LED_GPIO_CFG;
+ gpio -= 8;
+ }
+
+ ret = smsc95xx_read_reg(dev, reg, &tmp);
+ if (ret < 0)
+ return ret;
+
+ if (value)
+ tmp |= 1 << gpio;
+ else
+ tmp &= ~(1 << gpio);
+
+ ret = smsc95xx_write_reg(dev, reg, tmp);
+
+ return ret < 0 ? ret : 0;
+}
+#endif
+
+static void smsc95xx_set_multicast(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ u32 hash_hi = 0;
+ u32 hash_lo = 0;
+
+ netif_dbg(dev, drv, dev->net, "receive own packets only\n");
+ pdata->mac_cr &= ~(MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_);
+
+ /* Initiate async writes, as we can't wait for completion here */
+ smsc95xx_write_reg(dev, HASHH, hash_hi);
+ smsc95xx_write_reg(dev, HASHL, hash_lo);
+ smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+}
+
+/* Enable or disable Tx & Rx checksum offload engines */
+static int smsc95xx_set_csums(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ u32 read_buf;
+ int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read COE_CR: %d\n", ret);
+ return ret;
+ }
+
+ if (pdata->use_tx_csum)
+ read_buf |= Tx_COE_EN_;
+ else
+ read_buf &= ~Tx_COE_EN_;
+
+ if (pdata->use_rx_csum)
+ read_buf |= Rx_COE_EN_;
+ else
+ read_buf &= ~Rx_COE_EN_;
+
+ ret = smsc95xx_write_reg(dev, COE_CR, read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write COE_CR: %d\n", ret);
+ return ret;
+ }
+
+ netif_dbg(dev, hw, dev->net, "COE_CR = 0x%08x\n", read_buf);
+ return 0;
+}
+
+static int smsc95xx_set_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+ struct usbnet *udev = container_of(edev, struct usbnet, edev);
+
+ u32 addr_lo = adr[0] | adr[1] << 8 |
+ adr[2] << 16 | adr[3] << 24;
+ u32 addr_hi = adr[4] | adr[5] << 8;
+ int ret;
+
+ ret = smsc95xx_write_reg(udev, ADDRL, addr_lo);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write ADDRL: %d\n", ret);
+ return ret;
+ }
+
+ ret = smsc95xx_write_reg(udev, ADDRH, addr_hi);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write ADDRH: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int smsc95xx_get_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+ struct usbnet *udev = container_of(edev, struct usbnet, edev);
+
+ /* try reading mac address from EEPROM */
+ if (smsc95xx_read_eeprom(udev, EEPROM_MAC_OFFSET, ETH_ALEN,
+ adr) == 0) {
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/* starts the TX path */
+static void smsc95xx_start_tx_path(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ u32 reg_val;
+
+ /* Enable Tx at MAC */
+ pdata->mac_cr |= MAC_CR_TXEN_;
+
+ smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+
+ /* Enable Tx at SCSRs */
+ reg_val = TX_CFG_ON_;
+ smsc95xx_write_reg(dev, TX_CFG, reg_val);
+}
+
+/* Starts the Receive path */
+static void smsc95xx_start_rx_path(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+
+ pdata->mac_cr |= MAC_CR_RXEN_;
+
+ smsc95xx_write_reg(dev, MAC_CR, pdata->mac_cr);
+}
+
+static int smsc95xx_phy_initialize(struct usbnet *dev)
+{
+ int timeout = 0;
+ int phy_id = 1; /* FIXME */
+ uint16_t val, bmcr;
+
+ /* Initialize MII structure */
+ dev->miidev.read = smsc95xx_mdio_read;
+ dev->miidev.write = smsc95xx_mdio_write;
+ dev->miidev.address = 1; /* FIXME: asix_get_phy_addr(dev); */
+ dev->miidev.flags = 0;
+ dev->miidev.edev = &dev->edev;
+// dev->miidev.name = dev->edev.name;
+
+ /* reset phy and wait for reset to complete */
+ smsc95xx_mdio_write(&dev->miidev, phy_id, MII_BMCR, BMCR_RESET);
+
+ do {
+ udelay(10 * 1000);
+ bmcr = smsc95xx_mdio_read(&dev->miidev, phy_id, MII_BMCR);
+ timeout++;
+ } while ((bmcr & MII_BMCR) && (timeout < 100));
+
+ if (timeout >= 100) {
+ netdev_warn(dev->net, "timeout on PHY Reset");
+ return -EIO;
+ }
+
+ smsc95xx_mdio_write(&dev->miidev, phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP |
+ ADVERTISE_PAUSE_ASYM);
+
+ /* read to clear */
+ val = smsc95xx_mdio_read(&dev->miidev, phy_id, PHY_INT_SRC);
+
+ smsc95xx_mdio_write(&dev->miidev, phy_id, PHY_INT_MASK,
+ PHY_INT_MASK_DEFAULT_);
+
+ netif_dbg(dev, ifup, dev->net, "phy initialised successfully\n");
+ return 0;
+}
+
+static int smsc95xx_reset(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ u32 read_buf, write_buf, burst_cap = 0;
+ int ret = 0, timeout;
+
+ netif_dbg(dev, ifup, dev->net, "entering %s\n", __func__);
+
+ write_buf = HW_CFG_LRST_;
+ ret = smsc95xx_write_reg(dev, HW_CFG, write_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write HW_CFG_LRST_ bit in HW_CFG register, ret = %d\n",
+ ret);
+ return ret;
+ }
+
+ timeout = 0;
+ do {
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
+ udelay(1000 * 10);
+ timeout++;
+ } while ((read_buf & HW_CFG_LRST_) && (timeout < 100));
+
+ if (timeout >= 100) {
+ netdev_warn(dev->net, "timeout waiting for completion of Lite Reset\n");
+ return ret;
+ }
+
+ write_buf = PM_CTL_PHY_RST_;
+ ret = smsc95xx_write_reg(dev, PM_CTRL, write_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write PM_CTRL: %d\n", ret);
+ return ret;
+ }
+
+ timeout = 0;
+ do {
+ ret = smsc95xx_read_reg(dev, PM_CTRL, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read PM_CTRL: %d\n", ret);
+ return ret;
+ }
+ udelay(1000 * 10);
+ timeout++;
+ } while ((read_buf & PM_CTL_PHY_RST_) && (timeout < 100));
+
+ if (timeout >= 100) {
+ netdev_warn(dev->net, "timeout waiting for PHY Reset\n");
+ return ret;
+ }
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
+
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG : 0x%08x\n", read_buf);
+
+ read_buf |= HW_CFG_BIR_;
+
+ ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write HW_CFG_BIR_ bit in HW_CFG register, ret = %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG after writing HW_CFG_BIR_: 0x%08x\n",
+ read_buf);
+
+ if (!turbo_mode) {
+ burst_cap = 0;
+ dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE;
+ } else if (0) { /* highspeed */
+ burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE;
+ dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE;
+ } else {
+ burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE;
+ dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE;
+ }
+
+ netif_dbg(dev, ifup, dev->net,
+ "rx_urb_size=%ld\n", (ulong)dev->rx_urb_size);
+
+ ret = smsc95xx_write_reg(dev, BURST_CAP, burst_cap);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write BURST_CAP: %d\n", ret);
+ return ret;
+ }
+
+ ret = smsc95xx_read_reg(dev, BURST_CAP, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read BURST_CAP: %d\n", ret);
+ return ret;
+ }
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from BURST_CAP after writing: 0x%08x\n",
+ read_buf);
+
+ read_buf = DEFAULT_BULK_IN_DELAY;
+ ret = smsc95xx_write_reg(dev, BULK_IN_DLY, read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "ret = %d\n", ret);
+ return ret;
+ }
+
+ ret = smsc95xx_read_reg(dev, BULK_IN_DLY, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read BULK_IN_DLY: %d\n", ret);
+ return ret;
+ }
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from BULK_IN_DLY after writing: 0x%08x\n",
+ read_buf);
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG: 0x%08x\n", read_buf);
+
+ if (turbo_mode)
+ read_buf |= (HW_CFG_MEF_ | HW_CFG_BCE_);
+
+ read_buf &= ~HW_CFG_RXDOFF_;
+
+ /* set Rx data offset=2, Make IP header aligns on word boundary. */
+ read_buf |= NET_IP_ALIGN << 9;
+
+ ret = smsc95xx_write_reg(dev, HW_CFG, read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write HW_CFG register, ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read HW_CFG: %d\n", ret);
+ return ret;
+ }
+ netif_dbg(dev, ifup, dev->net,
+ "Read Value from HW_CFG after writing: 0x%08x\n", read_buf);
+
+ write_buf = 0xFFFFFFFF;
+ ret = smsc95xx_write_reg(dev, INT_STS, write_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write INT_STS register, ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ ret = smsc95xx_read_reg(dev, ID_REV, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read ID_REV: %d\n", ret);
+ return ret;
+ }
+ netif_dbg(dev, ifup, dev->net, "ID_REV = 0x%08x\n", read_buf);
+
+ /* Configure GPIO pins as LED outputs */
+ write_buf = LED_GPIO_CFG_SPD_LED | LED_GPIO_CFG_LNK_LED |
+ LED_GPIO_CFG_FDX_LED;
+ ret = smsc95xx_write_reg(dev, LED_GPIO_CFG, write_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write LED_GPIO_CFG register, ret=%d\n",
+ ret);
+ return ret;
+ }
+
+ /* Init Tx */
+ write_buf = 0;
+ ret = smsc95xx_write_reg(dev, FLOW, write_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write FLOW: %d\n", ret);
+ return ret;
+ }
+
+ read_buf = AFC_CFG_DEFAULT;
+ ret = smsc95xx_write_reg(dev, AFC_CFG, read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write AFC_CFG: %d\n", ret);
+ return ret;
+ }
+
+ /* Don't need mac_cr_lock during initialisation */
+ ret = smsc95xx_read_reg(dev, MAC_CR, &pdata->mac_cr);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read MAC_CR: %d\n", ret);
+ return ret;
+ }
+
+ /* Init Rx */
+ /* Set Vlan */
+ write_buf = (u32)ETH_P_8021Q;
+ ret = smsc95xx_write_reg(dev, VLAN1, write_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write VAN1: %d\n", ret);
+ return ret;
+ }
+
+ ret = smsc95xx_set_csums(dev);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to set csum offload: %d\n", ret);
+ return ret;
+ }
+
+ smsc95xx_set_multicast(dev);
+
+ if (smsc95xx_phy_initialize(dev) < 0)
+ return -EIO;
+
+ ret = smsc95xx_read_reg(dev, INT_EP_CTL, &read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to read INT_EP_CTL: %d\n", ret);
+ return ret;
+ }
+
+ /* enable PHY interrupts */
+ read_buf |= INT_EP_CTL_PHY_INT_;
+
+ ret = smsc95xx_write_reg(dev, INT_EP_CTL, read_buf);
+ if (ret < 0) {
+ netdev_warn(dev->net, "Failed to write INT_EP_CTL: %d\n", ret);
+ return ret;
+ }
+
+ smsc95xx_start_tx_path(dev);
+ smsc95xx_start_rx_path(dev);
+
+ netif_dbg(dev, ifup, dev->net, "%s: return 0\n", __func__);
+ return 0;
+}
+
+static struct usbnet *usbnet_global;
+
+static int smsc95xx_bind(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = NULL;
+ int ret;
+
+ printf(SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
+
+ ret = usbnet_get_endpoints(dev);
+ if (ret < 0) {
+ netdev_warn(dev->net, "usbnet_get_endpoints failed: %d\n", ret);
+ return ret;
+ }
+
+ dev->data[0] = (unsigned long)malloc(sizeof(struct smsc95xx_priv));
+
+ pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ if (!pdata) {
+ netdev_warn(dev->net, "Unable to allocate struct smsc95xx_priv\n");
+ return -ENOMEM;
+ }
+
+ pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE;
+ pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE;
+
+ /* Init all registers */
+ ret = smsc95xx_reset(dev);
+
+ dev->edev.get_ethaddr = smsc95xx_get_ethaddr;
+ dev->edev.set_ethaddr = smsc95xx_set_ethaddr;
+ mii_register(&dev->miidev);
+
+ return 0;
+}
+
+static void smsc95xx_unbind(struct usbnet *dev)
+{
+ struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
+ if (pdata) {
+ netif_dbg(dev, ifdown, dev->net, "free pdata\n");
+ free(pdata);
+ pdata = NULL;
+ dev->data[0] = 0;
+ }
+
+ usbnet_global = NULL;
+}
+
+static int smsc95xx_rx_fixup(struct usbnet *dev, void *buf, int len)
+{
+ while (len > 0) {
+ u32 header, align_count;
+ unsigned char *packet;
+ u16 size;
+
+ memcpy(&header, buf, sizeof(header));
+ le32_to_cpus(&header);
+ buf += 4 + NET_IP_ALIGN;
+ len -= 4 + NET_IP_ALIGN;
+ packet = buf;
+
+ /* get the packet length */
+ size = (u16)((header & RX_STS_FL_) >> 16);
+ align_count = (4 - ((size + NET_IP_ALIGN) % 4)) % 4;
+
+ if (header & RX_STS_ES_) {
+ netif_dbg(dev, rx_err, dev->net,
+ "Error header=0x%08x\n", header);
+ } else {
+ /* ETH_FRAME_LEN + 4(CRC) + 2(COE) + 4(Vlan) */
+ if (size > (ETH_FRAME_LEN + 12)) {
+ netif_dbg(dev, rx_err, dev->net,
+ "size err header=0x%08x\n", header);
+ return 0;
+ }
+
+ /* last frame in this batch */
+ if (len == size) {
+ net_receive(buf, len - 4);
+ return 1;
+ }
+
+ net_receive(packet, len - 4);
+ }
+
+ len -= size;
+
+ /* padding bytes before the next frame starts */
+ if (len)
+ len -= align_count;
+ }
+
+ if (len < 0) {
+ netdev_warn(dev->net, "invalid rx length<0 %d\n", len);
+ return 0;
+ }
+
+ return 1;
+}
+#if 0
+static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb)
+{
+ int len = skb->data - skb->head;
+ u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len);
+ u16 low_16 = (u16)(skb->csum_start - len);
+ return (high_16 << 16) | low_16;
+}
+#endif
+static int smsc95xx_tx_fixup(struct usbnet *dev,
+ void *buf, int len,
+ void *nbuf, int *nlen)
+{
+ u32 tx_cmd_a, tx_cmd_b;
+
+ tx_cmd_a = (u32)(len) | TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_;
+ cpu_to_le32s(&tx_cmd_a);
+ memcpy(nbuf, &tx_cmd_a, 4);
+
+ tx_cmd_b = (u32)(len);
+ cpu_to_le32s(&tx_cmd_b);
+ memcpy(nbuf + 4, &tx_cmd_b, 4);
+
+ memcpy(nbuf + 8, buf, len);
+
+ *nlen = len + 8;
+
+ return 0;
+}
+
+static struct driver_info smsc95xx_info = {
+ .description = "smsc95xx USB 2.0 Ethernet",
+ .bind = smsc95xx_bind,
+ .unbind = smsc95xx_unbind,
+ .rx_fixup = smsc95xx_rx_fixup,
+ .tx_fixup = smsc95xx_tx_fixup,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ /* SMSC9500 USB Ethernet Device */
+ USB_DEVICE(0x0424, 0x9500),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9505 USB Ethernet Device */
+ USB_DEVICE(0x0424, 0x9505),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9500A USB Ethernet Device */
+ USB_DEVICE(0x0424, 0x9E00),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9505A USB Ethernet Device */
+ USB_DEVICE(0x0424, 0x9E01),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9512/9514 USB Hub & Ethernet Device */
+ USB_DEVICE(0x0424, 0xec00),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9500 USB Ethernet Device (SAL10) */
+ USB_DEVICE(0x0424, 0x9900),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9505 USB Ethernet Device (SAL10) */
+ USB_DEVICE(0x0424, 0x9901),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9500A USB Ethernet Device (SAL10) */
+ USB_DEVICE(0x0424, 0x9902),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9505A USB Ethernet Device (SAL10) */
+ USB_DEVICE(0x0424, 0x9903),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9512/9514 USB Hub & Ethernet Device (SAL10) */
+ USB_DEVICE(0x0424, 0x9904),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9500A USB Ethernet Device (HAL) */
+ USB_DEVICE(0x0424, 0x9905),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9505A USB Ethernet Device (HAL) */
+ USB_DEVICE(0x0424, 0x9906),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9500 USB Ethernet Device (Alternate ID) */
+ USB_DEVICE(0x0424, 0x9907),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9500A USB Ethernet Device (Alternate ID) */
+ USB_DEVICE(0x0424, 0x9908),
+ .driver_info = &smsc95xx_info,
+ }, {
+ /* SMSC9512/9514 USB Hub & Ethernet Device (Alternate ID) */
+ USB_DEVICE(0x0424, 0x9909),
+ .driver_info = &smsc95xx_info,
+ },
+ { }, /* END */
+};
+
+static struct usb_driver smsc95xx_driver = {
+ .name = "smsc95xx",
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+};
+
+static int __init smsc95xx_init(void)
+{
+ return usb_driver_register(&smsc95xx_driver);
+}
+device_initcall(smsc95xx_init);
diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h
new file mode 100644
index 00000000..86bc4497
--- /dev/null
+++ b/drivers/net/usb/smsc95xx.h
@@ -0,0 +1,256 @@
+ /***************************************************************************
+ *
+ * Copyright (C) 2007-2008 SMSC
+ *
+ * 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 _SMSC95XX_H
+#define _SMSC95XX_H
+
+/* Tx command words */
+#define TX_CMD_A_DATA_OFFSET_ (0x001F0000)
+#define TX_CMD_A_FIRST_SEG_ (0x00002000)
+#define TX_CMD_A_LAST_SEG_ (0x00001000)
+#define TX_CMD_A_BUF_SIZE_ (0x000007FF)
+
+#define TX_CMD_B_CSUM_ENABLE (0x00004000)
+#define TX_CMD_B_ADD_CRC_DISABLE_ (0x00002000)
+#define TX_CMD_B_DISABLE_PADDING_ (0x00001000)
+#define TX_CMD_B_PKT_BYTE_LENGTH_ (0x000007FF)
+
+/* Rx status word */
+#define RX_STS_FF_ (0x40000000) /* Filter Fail */
+#define RX_STS_FL_ (0x3FFF0000) /* Frame Length */
+#define RX_STS_ES_ (0x00008000) /* Error Summary */
+#define RX_STS_BF_ (0x00002000) /* Broadcast Frame */
+#define RX_STS_LE_ (0x00001000) /* Length Error */
+#define RX_STS_RF_ (0x00000800) /* Runt Frame */
+#define RX_STS_MF_ (0x00000400) /* Multicast Frame */
+#define RX_STS_TL_ (0x00000080) /* Frame too long */
+#define RX_STS_CS_ (0x00000040) /* Collision Seen */
+#define RX_STS_FT_ (0x00000020) /* Frame Type */
+#define RX_STS_RW_ (0x00000010) /* Receive Watchdog */
+#define RX_STS_ME_ (0x00000008) /* Mii Error */
+#define RX_STS_DB_ (0x00000004) /* Dribbling */
+#define RX_STS_CRC_ (0x00000002) /* CRC Error */
+
+/* SCSRs */
+#define ID_REV (0x00)
+#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000)
+#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF)
+#define ID_REV_CHIP_ID_9500_ (0x9500)
+
+#define INT_STS (0x08)
+#define INT_STS_TX_STOP_ (0x00020000)
+#define INT_STS_RX_STOP_ (0x00010000)
+#define INT_STS_PHY_INT_ (0x00008000)
+#define INT_STS_TXE_ (0x00004000)
+#define INT_STS_TDFU_ (0x00002000)
+#define INT_STS_TDFO_ (0x00001000)
+#define INT_STS_RXDF_ (0x00000800)
+#define INT_STS_GPIOS_ (0x000007FF)
+
+#define RX_CFG (0x0C)
+#define RX_FIFO_FLUSH_ (0x00000001)
+
+#define TX_CFG (0x10)
+#define TX_CFG_ON_ (0x00000004)
+#define TX_CFG_STOP_ (0x00000002)
+#define TX_CFG_FIFO_FLUSH_ (0x00000001)
+
+#define HW_CFG (0x14)
+#define HW_CFG_BIR_ (0x00001000)
+#define HW_CFG_LEDB_ (0x00000800)
+#define HW_CFG_RXDOFF_ (0x00000600)
+#define HW_CFG_DRP_ (0x00000040)
+#define HW_CFG_MEF_ (0x00000020)
+#define HW_CFG_LRST_ (0x00000008)
+#define HW_CFG_PSEL_ (0x00000004)
+#define HW_CFG_BCE_ (0x00000002)
+#define HW_CFG_SRST_ (0x00000001)
+
+#define PM_CTRL (0x20)
+#define PM_CTL_DEV_RDY_ (0x00000080)
+#define PM_CTL_SUS_MODE_ (0x00000060)
+#define PM_CTL_SUS_MODE_0 (0x00000000)
+#define PM_CTL_SUS_MODE_1 (0x00000020)
+#define PM_CTL_SUS_MODE_2 (0x00000060)
+#define PM_CTL_PHY_RST_ (0x00000010)
+#define PM_CTL_WOL_EN_ (0x00000008)
+#define PM_CTL_ED_EN_ (0x00000004)
+#define PM_CTL_WUPS_ (0x00000003)
+#define PM_CTL_WUPS_NO_ (0x00000000)
+#define PM_CTL_WUPS_ED_ (0x00000001)
+#define PM_CTL_WUPS_WOL_ (0x00000002)
+#define PM_CTL_WUPS_MULTI_ (0x00000003)
+
+#define LED_GPIO_CFG (0x24)
+#define LED_GPIO_CFG_SPD_LED (0x01000000)
+#define LED_GPIO_CFG_LNK_LED (0x00100000)
+#define LED_GPIO_CFG_FDX_LED (0x00010000)
+
+#define GPIO_CFG (0x28)
+
+#define AFC_CFG (0x2C)
+
+/* Hi watermark = 15.5Kb (~10 mtu pkts) */
+/* low watermark = 3k (~2 mtu pkts) */
+/* backpressure duration = ~ 350us */
+/* Apply FC on any frame. */
+#define AFC_CFG_DEFAULT (0x00F830A1)
+
+#define E2P_CMD (0x30)
+#define E2P_CMD_BUSY_ (0x80000000)
+#define E2P_CMD_MASK_ (0x70000000)
+#define E2P_CMD_READ_ (0x00000000)
+#define E2P_CMD_EWDS_ (0x10000000)
+#define E2P_CMD_EWEN_ (0x20000000)
+#define E2P_CMD_WRITE_ (0x30000000)
+#define E2P_CMD_WRAL_ (0x40000000)
+#define E2P_CMD_ERASE_ (0x50000000)
+#define E2P_CMD_ERAL_ (0x60000000)
+#define E2P_CMD_RELOAD_ (0x70000000)
+#define E2P_CMD_TIMEOUT_ (0x00000400)
+#define E2P_CMD_LOADED_ (0x00000200)
+#define E2P_CMD_ADDR_ (0x000001FF)
+
+#define MAX_EEPROM_SIZE (512)
+
+#define E2P_DATA (0x34)
+#define E2P_DATA_MASK_ (0x000000FF)
+
+#define BURST_CAP (0x38)
+
+#define GPIO_WAKE (0x64)
+
+#define INT_EP_CTL (0x68)
+#define INT_EP_CTL_INTEP_ (0x80000000)
+#define INT_EP_CTL_MACRTO_ (0x00080000)
+#define INT_EP_CTL_TX_STOP_ (0x00020000)
+#define INT_EP_CTL_RX_STOP_ (0x00010000)
+#define INT_EP_CTL_PHY_INT_ (0x00008000)
+#define INT_EP_CTL_TXE_ (0x00004000)
+#define INT_EP_CTL_TDFU_ (0x00002000)
+#define INT_EP_CTL_TDFO_ (0x00001000)
+#define INT_EP_CTL_RXDF_ (0x00000800)
+#define INT_EP_CTL_GPIOS_ (0x000007FF)
+
+#define BULK_IN_DLY (0x6C)
+
+/* MAC CSRs */
+#define MAC_CR (0x100)
+#define MAC_CR_RXALL_ (0x80000000)
+#define MAC_CR_RCVOWN_ (0x00800000)
+#define MAC_CR_LOOPBK_ (0x00200000)
+#define MAC_CR_FDPX_ (0x00100000)
+#define MAC_CR_MCPAS_ (0x00080000)
+#define MAC_CR_PRMS_ (0x00040000)
+#define MAC_CR_INVFILT_ (0x00020000)
+#define MAC_CR_PASSBAD_ (0x00010000)
+#define MAC_CR_HFILT_ (0x00008000)
+#define MAC_CR_HPFILT_ (0x00002000)
+#define MAC_CR_LCOLL_ (0x00001000)
+#define MAC_CR_BCAST_ (0x00000800)
+#define MAC_CR_DISRTY_ (0x00000400)
+#define MAC_CR_PADSTR_ (0x00000100)
+#define MAC_CR_BOLMT_MASK (0x000000C0)
+#define MAC_CR_DFCHK_ (0x00000020)
+#define MAC_CR_TXEN_ (0x00000008)
+#define MAC_CR_RXEN_ (0x00000004)
+
+#define ADDRH (0x104)
+
+#define ADDRL (0x108)
+
+#define HASHH (0x10C)
+
+#define HASHL (0x110)
+
+#define MII_ADDR (0x114)
+#define MII_WRITE_ (0x02)
+#define MII_BUSY_ (0x01)
+#define MII_READ_ (0x00) /* ~of MII Write bit */
+
+#define MII_DATA (0x118)
+
+#define FLOW (0x11C)
+#define FLOW_FCPT_ (0xFFFF0000)
+#define FLOW_FCPASS_ (0x00000004)
+#define FLOW_FCEN_ (0x00000002)
+#define FLOW_FCBSY_ (0x00000001)
+
+#define VLAN1 (0x120)
+
+#define VLAN2 (0x124)
+
+#define WUFF (0x128)
+
+#define WUCSR (0x12C)
+
+#define COE_CR (0x130)
+#define Tx_COE_EN_ (0x00010000)
+#define Rx_COE_MODE_ (0x00000002)
+#define Rx_COE_EN_ (0x00000001)
+
+/* Vendor-specific PHY Definitions */
+
+/* Mode Control/Status Register */
+#define PHY_MODE_CTRL_STS (17)
+#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000)
+#define MODE_CTRL_STS_ENERGYON_ ((u16)0x0002)
+
+#define SPECIAL_CTRL_STS (27)
+#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ ((u16)0x8000)
+#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ ((u16)0x4000)
+#define SPECIAL_CTRL_STS_AMDIX_STATE_ ((u16)0x2000)
+
+#define PHY_INT_SRC (29)
+#define PHY_INT_SRC_ENERGY_ON_ ((u16)0x0080)
+#define PHY_INT_SRC_ANEG_COMP_ ((u16)0x0040)
+#define PHY_INT_SRC_REMOTE_FAULT_ ((u16)0x0020)
+#define PHY_INT_SRC_LINK_DOWN_ ((u16)0x0010)
+
+#define PHY_INT_MASK (30)
+#define PHY_INT_MASK_ENERGY_ON_ ((u16)0x0080)
+#define PHY_INT_MASK_ANEG_COMP_ ((u16)0x0040)
+#define PHY_INT_MASK_REMOTE_FAULT_ ((u16)0x0020)
+#define PHY_INT_MASK_LINK_DOWN_ ((u16)0x0010)
+#define PHY_INT_MASK_DEFAULT_ (PHY_INT_MASK_ANEG_COMP_ | \
+ PHY_INT_MASK_LINK_DOWN_)
+
+#define PHY_SPECIAL (31)
+#define PHY_SPECIAL_SPD_ ((u16)0x001C)
+#define PHY_SPECIAL_SPD_10HALF_ ((u16)0x0004)
+#define PHY_SPECIAL_SPD_10FULL_ ((u16)0x0014)
+#define PHY_SPECIAL_SPD_100HALF_ ((u16)0x0008)
+#define PHY_SPECIAL_SPD_100FULL_ ((u16)0x0018)
+
+/* USB Vendor Requests */
+#define USB_VENDOR_REQUEST_WRITE_REGISTER 0xA0
+#define USB_VENDOR_REQUEST_READ_REGISTER 0xA1
+#define USB_VENDOR_REQUEST_GET_STATS 0xA2
+
+/* Interrupt Endpoint status word bitfields */
+#define INT_ENP_TX_STOP_ ((u32)BIT(17))
+#define INT_ENP_RX_STOP_ ((u32)BIT(16))
+#define INT_ENP_PHY_INT_ ((u32)BIT(15))
+#define INT_ENP_TXE_ ((u32)BIT(14))
+#define INT_ENP_TDFU_ ((u32)BIT(13))
+#define INT_ENP_TDFO_ ((u32)BIT(12))
+#define INT_ENP_RXDF_ ((u32)BIT(11))
+
+#endif /* _SMSC95XX_H */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index ffd877a4..9e05f4be 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -43,6 +43,11 @@ config DRIVER_SERIAL_BLACKFIN
default y
bool "Blackfin serial driver"
+config DRIVER_SERIAL_ALTERA
+ depends on NIOS2
+ default y
+ bool "Altera serial driver"
+
config DRIVER_SERIAL_NS16550
default n
bool "NS16550 serial driver"
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 9f0e12b0..df9e705c 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -5,7 +5,7 @@
# serial_pl010.o
# serial_xuartlite.o
obj-$(CONFIG_DRIVER_SERIAL_ARM_DCC) += arm_dcc.o
-obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
+obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_DRIVER_SERIAL_IMX) += serial_imx.o
obj-$(CONFIG_DRIVER_SERIAL_STM378X) += stm-serial.o
obj-$(CONFIG_DRIVER_SERIAL_ATMEL) += atmel.o
@@ -16,3 +16,4 @@ obj-$(CONFIG_DRIVER_SERIAL_BLACKFIN) += serial_blackfin.o
obj-$(CONFIG_DRIVER_SERIAL_NS16550) += serial_ns16550.o
obj-$(CONFIG_DRIVER_SERIAL_PL010) += serial_pl010.o
obj-$(CONFIG_DRIVER_SERIAL_S3C24X0) += serial_s3c24x0.o
+obj-$(CONFIG_DRIVER_SERIAL_ALTERA) += serial_altera.o
diff --git a/drivers/serial/serial_altera.c b/drivers/serial/serial_altera.c
new file mode 100644
index 00000000..54c71781
--- /dev/null
+++ b/drivers/serial/serial_altera.c
@@ -0,0 +1,95 @@
+/*
+ * (C) Copyright 2011, Franck JULLIEN, <elec4fun@gmail.com>
+ *
+ * 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 <driver.h>
+#include <init.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/nios2-io.h>
+
+static int altera_serial_setbaudrate(struct console_device *cdev, int baudrate)
+{
+ struct nios_uart *uart = (struct nios_uart *)cdev->dev->map_base;
+ uint16_t div;
+
+ div = (CPU_FREQ / baudrate) - 1;
+ writew(div, &uart->divisor);
+
+ return 0;
+}
+
+static void altera_serial_putc(struct console_device *cdev, char c)
+{
+ struct nios_uart *uart = (struct nios_uart *)cdev->dev->map_base;
+
+ while ((readw(&uart->status) & NIOS_UART_TRDY) == 0);
+
+ writew(c, &uart->txdata);
+}
+
+static int altera_serial_tstc(struct console_device *cdev)
+{
+ struct nios_uart *uart = (struct nios_uart *)cdev->dev->map_base;
+
+ return readw(&uart->status) & NIOS_UART_RRDY;
+}
+
+static int altera_serial_getc(struct console_device *cdev)
+{
+ struct nios_uart *uart = (struct nios_uart *)cdev->dev->map_base;
+
+ while (altera_serial_tstc(cdev) == 0);
+
+ return readw(&uart->rxdata) & 0x000000FF;
+}
+
+static int altera_serial_probe(struct device_d *dev)
+{
+ struct console_device *cdev;
+
+ cdev = xmalloc(sizeof(struct console_device));
+ dev->type_data = cdev;
+ cdev->dev = dev;
+ cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
+ cdev->tstc = altera_serial_tstc;
+ cdev->putc = altera_serial_putc;
+ cdev->getc = altera_serial_getc;
+ cdev->setbrg = altera_serial_setbaudrate;
+
+ console_register(cdev);
+
+ return 0;
+}
+
+static struct driver_d altera_serial_driver = {
+ .name = "altera_serial",
+ .probe = altera_serial_probe,
+};
+
+static int altera_serial_init(void)
+{
+ return register_driver(&altera_serial_driver);
+}
+
+console_initcall(altera_serial_init);
+
diff --git a/drivers/serial/serial_ns16550.c b/drivers/serial/serial_ns16550.c
index 290619fe..ab172e74 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -211,9 +211,7 @@ static int ns16550_probe(struct device_d *dev)
if ((plat->reg_read == NULL) || (plat->reg_write == NULL))
return -EINVAL;
- cdev = calloc(1, sizeof(struct console_device));
- if (cdev == NULL)
- return -ENOMEM;
+ cdev = xzalloc(sizeof(*cdev));
dev->type_data = cdev;
cdev->dev = dev;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 76e033eb..df4e9e08 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -449,7 +449,7 @@ static struct usb_device *usb_alloc_new_device(void)
return usbdev;
}
-static int __usb_init(void)
+void usb_rescan(void)
{
struct usb_device *dev, *tmp;
struct usb_host *host;
@@ -477,27 +477,8 @@ static int __usb_init(void)
}
printf("%d USB Device(s) found\n", dev_index);
-
- return 0;
}
-static int do_usb(struct command *cmdtp, int argc, char *argv[])
-{
- __usb_init();
-
- return 0;
-}
-
-static const __maybe_unused char cmd_usb_help[] =
-"Usage: usb\n"
-"(re-)detect USB devices\n";
-
-BAREBOX_CMD_START(usb)
- .cmd = do_usb,
- .usage = "(re-)detect USB devices",
- BAREBOX_CMD_HELP(cmd_usb_help)
-BAREBOX_CMD_END
-
/*
* disables the asynch behaviour of the control message. This is used for data
* transfers that uses the exclusiv access to the control and bulk messages.
diff --git a/fs/Kconfig b/fs/Kconfig
index d05797ab..56c02da1 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -16,6 +16,8 @@ config FS_DEVFS
default y
prompt "devfs support"
+source fs/fat/Kconfig
+
config PARTITION_NEED_MTD
bool
diff --git a/fs/Makefile b/fs/Makefile
index 228af6eb..7cae2b6e 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -1,4 +1,6 @@
obj-$(CONFIG_FS_CRAMFS) += cramfs/
obj-$(CONFIG_FS_RAMFS) += ramfs.o
+obj-y += devfs-core.o
obj-$(CONFIG_FS_DEVFS) += devfs.o
+obj-$(CONFIG_FS_FAT) += fat/
obj-y += fs.o
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c
index 73a37591..b9ab50f4 100644
--- a/fs/cramfs/cramfs.c
+++ b/fs/cramfs/cramfs.c
@@ -456,7 +456,6 @@ static void cramfs_remove(struct device_d *dev)
}
static struct fs_driver_d cramfs_driver = {
- .type = FS_TYPE_CRAMFS,
.open = cramfs_open,
.close = cramfs_close,
.read = cramfs_read,
diff --git a/fs/devfs-core.c b/fs/devfs-core.c
new file mode 100644
index 00000000..519e18e6
--- /dev/null
+++ b/fs/devfs-core.c
@@ -0,0 +1,236 @@
+/*
+ * devfs.c - a device file system for barebox
+ *
+ * Copyright (c) 2011 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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 <driver.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ioctl.h>
+#include <linux/err.h>
+#include <linux/mtd/mtd.h>
+
+LIST_HEAD(cdev_list);
+
+struct cdev *cdev_by_name(const char *filename)
+{
+ struct cdev *cdev;
+
+ list_for_each_entry(cdev, &cdev_list, list) {
+ if (!strcmp(cdev->name, filename))
+ return cdev;
+ }
+ return NULL;
+}
+
+struct cdev *cdev_open(const char *name, unsigned long flags)
+{
+ struct cdev *cdev = cdev_by_name(name);
+ int ret;
+
+ if (!cdev)
+ return NULL;
+
+ if (cdev->ops->open) {
+ ret = cdev->ops->open(cdev);
+ if (ret)
+ return NULL;
+ }
+
+ return cdev;
+}
+
+void cdev_close(struct cdev *cdev)
+{
+ if (cdev->ops->close)
+ cdev->ops->close(cdev);
+}
+
+ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags)
+{
+ if (!cdev->ops->read)
+ return -ENOSYS;
+
+ return cdev->ops->read(cdev, buf, count, cdev->offset +offset, flags);
+}
+
+ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags)
+{
+ if (!cdev->ops->write)
+ return -ENOSYS;
+
+ return cdev->ops->write(cdev, buf, count, cdev->offset + offset, flags);
+}
+
+int cdev_flush(struct cdev *cdev)
+{
+ if (!cdev->ops->flush)
+ return 0;
+
+ return cdev->ops->flush(cdev);
+}
+
+static int partition_ioctl(struct cdev *cdev, int request, void *buf)
+{
+ size_t offset;
+ struct mtd_info_user *user = buf;
+
+ switch (request) {
+ case MEMSETBADBLOCK:
+ case MEMGETBADBLOCK:
+ offset = (off_t)buf;
+ offset += cdev->offset;
+ return cdev->ops->ioctl(cdev, request, (void *)offset);
+ case MEMGETINFO:
+ if (cdev->mtd) {
+ user->type = cdev->mtd->type;
+ user->flags = cdev->mtd->flags;
+ user->size = cdev->mtd->size;
+ user->erasesize = cdev->mtd->erasesize;
+ user->oobsize = cdev->mtd->oobsize;
+ user->mtd = cdev->mtd;
+ /* The below fields are obsolete */
+ user->ecctype = -1;
+ user->eccsize = 0;
+ return 0;
+ }
+ if (!cdev->ops->ioctl)
+ return -EINVAL;
+ return cdev->ops->ioctl(cdev, request, buf);
+ default:
+ return -EINVAL;
+ }
+}
+
+int cdev_ioctl(struct cdev *cdev, int request, void *buf)
+{
+ if (cdev->flags & DEVFS_IS_PARTITION)
+ return partition_ioctl(cdev, request, buf);
+
+ if (!cdev->ops->ioctl)
+ return -EINVAL;
+
+ return cdev->ops->ioctl(cdev, request, buf);
+}
+
+int cdev_erase(struct cdev *cdev, size_t count, unsigned long offset)
+{
+ if (!cdev->ops->erase)
+ return -ENOSYS;
+
+ return cdev->ops->erase(cdev, count, cdev->offset + offset);
+}
+
+int devfs_create(struct cdev *new)
+{
+ struct cdev *cdev;
+
+ cdev = cdev_by_name(new->name);
+ if (cdev)
+ return -EEXIST;
+
+ list_add_tail(&new->list, &cdev_list);
+ if (new->dev)
+ list_add_tail(&new->devices_list, &new->dev->cdevs);
+
+ return 0;
+}
+
+int devfs_remove(struct cdev *cdev)
+{
+ if (cdev->open)
+ return -EBUSY;
+
+ list_del(&cdev->list);
+ if (cdev->dev)
+ list_del(&cdev->devices_list);
+
+ return 0;
+}
+
+int devfs_add_partition(const char *devname, unsigned long offset, size_t size,
+ int flags, const char *name)
+{
+ struct cdev *cdev, *new;
+
+ cdev = cdev_by_name(name);
+ if (cdev)
+ return -EEXIST;
+
+ cdev = cdev_by_name(devname);
+ if (!cdev)
+ return -ENOENT;
+
+ if (offset + size > cdev->size)
+ return -EINVAL;
+
+ new = xzalloc(sizeof (*new));
+ new->name = strdup(name);
+ new->ops = cdev->ops;
+ new->priv = cdev->priv;
+ new->size = size;
+ new->offset = offset + cdev->offset;
+ new->dev = cdev->dev;
+ new->flags = flags | DEVFS_IS_PARTITION;
+
+#ifdef CONFIG_PARTITION_NEED_MTD
+ if (cdev->mtd) {
+ new->mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name);
+ if (IS_ERR(new->mtd)) {
+ int ret = PTR_ERR(new->mtd);
+ free(new);
+ return ret;
+ }
+ }
+#endif
+
+ devfs_create(new);
+
+ return 0;
+}
+
+int devfs_del_partition(const char *name)
+{
+ struct cdev *cdev;
+ int ret;
+
+ cdev = cdev_by_name(name);
+ if (!cdev)
+ return -ENOENT;
+
+ if (!(cdev->flags & DEVFS_IS_PARTITION))
+ return -EINVAL;
+ if (cdev->flags & DEVFS_PARTITION_FIXED)
+ return -EPERM;
+
+#ifdef CONFIG_PARTITION_NEED_MTD
+ if (cdev->mtd)
+ mtd_del_partition(cdev->mtd);
+#endif
+
+ ret = devfs_remove(cdev);
+ if (ret)
+ return ret;
+
+ free(cdev->name);
+ free(cdev);
+
+ return 0;
+}
diff --git a/fs/devfs.c b/fs/devfs.c
index 7019c8d9..07ca16c5 100644
--- a/fs/devfs.c
+++ b/fs/devfs.c
@@ -36,34 +36,7 @@
#include <linux/mtd/mtd-abi.h>
#include <partition.h>
-static LIST_HEAD(cdev_list);
-
-struct cdev *cdev_by_name(const char *filename)
-{
- struct cdev *cdev;
-
- list_for_each_entry(cdev, &cdev_list, list) {
- if (!strcmp(cdev->name, filename))
- return cdev;
- }
- return NULL;
-}
-
-ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags)
-{
- if (!cdev->ops->read)
- return -ENOSYS;
-
- return cdev->ops->read(cdev, buf, count, cdev->offset +offset, flags);
-}
-
-ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags)
-{
- if (!cdev->ops->write)
- return -ENOSYS;
-
- return cdev->ops->write(cdev, buf, count, cdev->offset + offset, flags);
-}
+extern struct list_head cdev_list;
static int devfs_read(struct device_d *_dev, FILE *f, void *buf, size_t size)
{
@@ -143,7 +116,7 @@ static int devfs_open(struct device_d *_dev, FILE *f, const char *filename)
f->inode = cdev;
if (cdev->ops->open) {
- ret = cdev->ops->open(cdev, f);
+ ret = cdev->ops->open(cdev);
if (ret)
return ret;
}
@@ -159,7 +132,7 @@ static int devfs_close(struct device_d *_dev, FILE *f)
int ret;
if (cdev->ops->close) {
- ret = cdev->ops->close(cdev, f);
+ ret = cdev->ops->close(cdev);
if (ret)
return ret;
}
@@ -169,49 +142,21 @@ static int devfs_close(struct device_d *_dev, FILE *f)
return 0;
}
-static int partition_ioctl(struct cdev *cdev, int request, void *buf)
+static int devfs_flush(struct device_d *_dev, FILE *f)
{
- size_t offset;
- struct mtd_info_user *user = buf;
-
- switch (request) {
- case MEMSETBADBLOCK:
- case MEMGETBADBLOCK:
- offset = (off_t)buf;
- offset += cdev->offset;
- return cdev->ops->ioctl(cdev, request, (void *)offset);
- case MEMGETINFO:
- if (cdev->mtd) {
- user->type = cdev->mtd->type;
- user->flags = cdev->mtd->flags;
- user->size = cdev->mtd->size;
- user->erasesize = cdev->mtd->erasesize;
- user->oobsize = cdev->mtd->oobsize;
- user->mtd = cdev->mtd;
- /* The below fields are obsolete */
- user->ecctype = -1;
- user->eccsize = 0;
- return 0;
- }
- if (!cdev->ops->ioctl)
- return -EINVAL;
- return cdev->ops->ioctl(cdev, request, buf);
- default:
- return -EINVAL;
- }
+ struct cdev *cdev = f->inode;
+
+ if (cdev->ops->flush)
+ return cdev->ops->flush(cdev);
+
+ return 0;
}
static int devfs_ioctl(struct device_d *_dev, FILE *f, int request, void *buf)
{
struct cdev *cdev = f->inode;
- if (cdev->flags & DEVFS_IS_PARTITION)
- return partition_ioctl(cdev, request, buf);
-
- if (!cdev->ops->ioctl)
- return -EINVAL;
-
- return cdev->ops->ioctl(cdev, request, buf);
+ return cdev_ioctl(cdev, request, buf);
}
static int devfs_truncate(struct device_d *dev, FILE *f, ulong size)
@@ -282,12 +227,12 @@ static void devfs_delete(struct device_d *dev)
}
static struct fs_driver_d devfs_driver = {
- .type = FS_TYPE_DEVFS,
.read = devfs_read,
.write = devfs_write,
.lseek = devfs_lseek,
.open = devfs_open,
.close = devfs_close,
+ .flush = devfs_flush,
.ioctl = devfs_ioctl,
.opendir = devfs_opendir,
.readdir = devfs_readdir,
@@ -312,101 +257,3 @@ static int devfs_init(void)
}
coredevice_initcall(devfs_init);
-
-int devfs_create(struct cdev *new)
-{
- struct cdev *cdev;
-
- cdev = cdev_by_name(new->name);
- if (cdev)
- return -EEXIST;
-
- list_add_tail(&new->list, &cdev_list);
- if (new->dev)
- list_add_tail(&new->devices_list, &new->dev->cdevs);
-
- return 0;
-}
-
-int devfs_remove(struct cdev *cdev)
-{
- if (cdev->open)
- return -EBUSY;
-
- list_del(&cdev->list);
- if (cdev->dev)
- list_del(&cdev->devices_list);
-
- return 0;
-}
-
-int devfs_add_partition(const char *devname, unsigned long offset, size_t size,
- int flags, const char *name)
-{
- struct cdev *cdev, *new;
-
- cdev = cdev_by_name(name);
- if (cdev)
- return -EEXIST;
-
- cdev = cdev_by_name(devname);
- if (!cdev)
- return -ENOENT;
-
- if (offset + size > cdev->size)
- return -EINVAL;
-
- new = xzalloc(sizeof (*new));
- new->name = strdup(name);
- new->ops = cdev->ops;
- new->priv = cdev->priv;
- new->size = size;
- new->offset = offset + cdev->offset;
- new->dev = cdev->dev;
- new->flags = flags | DEVFS_IS_PARTITION;
-
-#ifdef CONFIG_PARTITION_NEED_MTD
- if (cdev->mtd) {
- new->mtd = mtd_add_partition(cdev->mtd, offset, size, flags, name);
- if (IS_ERR(new->mtd)) {
- int ret = PTR_ERR(new->mtd);
- free(new);
- return ret;
- }
- }
-#endif
-
- devfs_create(new);
-
- return 0;
-}
-
-int devfs_del_partition(const char *name)
-{
- struct cdev *cdev;
- int ret;
-
- cdev = cdev_by_name(name);
- if (!cdev)
- return -ENOENT;
-
- if (!(cdev->flags & DEVFS_IS_PARTITION))
- return -EINVAL;
- if (cdev->flags & DEVFS_PARTITION_FIXED)
- return -EPERM;
-
-#ifdef CONFIG_PARTITION_NEED_MTD
- if (cdev->mtd)
- mtd_del_partition(cdev->mtd);
-#endif
-
- ret = devfs_remove(cdev);
- if (ret)
- return ret;
-
- free(cdev->name);
- free(cdev);
-
- return 0;
-}
-
diff --git a/fs/fat/Kconfig b/fs/fat/Kconfig
new file mode 100644
index 00000000..06997284
--- /dev/null
+++ b/fs/fat/Kconfig
@@ -0,0 +1,15 @@
+menuconfig FS_FAT
+ bool
+ prompt "FAT filesystem support"
+
+if FS_FAT
+
+config FS_FAT_WRITE
+ bool
+ prompt "FAT write support"
+
+config FS_FAT_LFN
+ bool
+ prompt "Support long filenames"
+
+endif
diff --git a/fs/fat/Makefile b/fs/fat/Makefile
new file mode 100644
index 00000000..efc89ec6
--- /dev/null
+++ b/fs/fat/Makefile
@@ -0,0 +1 @@
+obj-y += ff.o fat.o
diff --git a/fs/fat/diskio.h b/fs/fat/diskio.h
new file mode 100644
index 00000000..f0d29dc3
--- /dev/null
+++ b/fs/fat/diskio.h
@@ -0,0 +1,78 @@
+/*-----------------------------------------------------------------------
+/ Low level disk interface modlue include file
+/-----------------------------------------------------------------------*/
+
+#ifndef _DISKIO
+
+#define _READONLY 0 /* 1: Remove write functions */
+#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */
+
+#include "integer.h"
+
+
+/* Status of Disk Functions */
+typedef BYTE DSTATUS;
+
+/* Results of Disk Functions */
+typedef enum {
+ RES_OK = 0, /* 0: Successful */
+ RES_ERROR, /* 1: R/W Error */
+ RES_WRPRT, /* 2: Write Protected */
+ RES_NOTRDY, /* 3: Not Ready */
+ RES_PARERR /* 4: Invalid Parameter */
+} DRESULT;
+
+
+/*---------------------------------------*/
+/* Prototypes for disk control functions */
+
+int assign_drives (int, int);
+DSTATUS disk_initialize (FATFS *fatfs);
+DSTATUS disk_status (FATFS *fatfs);
+DRESULT disk_read (FATFS *fatfs, BYTE*, DWORD, BYTE);
+#if _READONLY == 0
+DRESULT disk_write (FATFS *fatfs, const BYTE*, DWORD, BYTE);
+#endif
+DRESULT disk_ioctl (FATFS *fatfs, BYTE, void*);
+
+
+
+/* Disk Status Bits (DSTATUS) */
+
+#define STA_NOINIT 0x01 /* Drive not initialized */
+#define STA_NODISK 0x02 /* No medium in the drive */
+#define STA_PROTECT 0x04 /* Write protected */
+
+
+/* Command code for disk_ioctrl fucntion */
+
+/* Generic command (defined for FatFs) */
+#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */
+#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */
+#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
+#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */
+#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */
+
+/* Generic command */
+#define CTRL_POWER 5 /* Get/Set power status */
+#define CTRL_LOCK 6 /* Lock/Unlock media removal */
+#define CTRL_EJECT 7 /* Eject media */
+
+/* MMC/SDC specific ioctl command */
+#define MMC_GET_TYPE 10 /* Get card type */
+#define MMC_GET_CSD 11 /* Get CSD */
+#define MMC_GET_CID 12 /* Get CID */
+#define MMC_GET_OCR 13 /* Get OCR */
+#define MMC_GET_SDSTAT 14 /* Get SD status */
+
+/* ATA/CF specific ioctl command */
+#define ATA_GET_REV 20 /* Get F/W revision */
+#define ATA_GET_MODEL 21 /* Get model name */
+#define ATA_GET_SN 22 /* Get serial number */
+
+/* NAND specific ioctl command */
+#define NAND_FORMAT 30 /* Create physical format */
+
+
+#define _DISKIO
+#endif
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
new file mode 100644
index 00000000..4219801b
--- /dev/null
+++ b/fs/fat/fat.c
@@ -0,0 +1,434 @@
+/*
+ * ramfs.c - a malloc based filesystem
+ *
+ * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
+ *
+ * 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * 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 <driver.h>
+#include <init.h>
+#include <malloc.h>
+#include <fs.h>
+#include <command.h>
+#include <errno.h>
+#include <linux/stat.h>
+#include <linux/ctype.h>
+#include <xfuncs.h>
+#include <fcntl.h>
+#include "ff.h"
+#include "integer.h"
+#include "diskio.h"
+
+struct fat_priv {
+ struct cdev *cdev;
+ FATFS fat;
+};
+
+/* ---------------------------------------------------------------*/
+
+DRESULT disk_read(FATFS *fat, BYTE *buf, DWORD sector, BYTE count)
+{
+ struct fat_priv *priv = fat->userdata;
+ int ret;
+
+ debug("%s: sector: %ld count: %d\n", __func__, sector, count);
+
+ ret = cdev_read(priv->cdev, buf, count << 9, sector * 512, 0);
+ if (ret != count << 9)
+ return ret;
+
+ return 0;
+}
+
+DRESULT disk_write(FATFS *fat, const BYTE *buf, DWORD sector, BYTE count)
+{
+ struct fat_priv *priv = fat->userdata;
+ int ret;
+
+ debug("%s: buf: %p sector: %ld count: %d\n",
+ __func__, buf, sector, count);
+
+ ret = cdev_write(priv->cdev, buf, count << 9, sector * 512, 0);
+ if (ret != count << 9)
+ return ret;
+
+ return 0;
+}
+
+DSTATUS disk_status(FATFS *fat)
+{
+ return 0;
+}
+
+DWORD get_fattime(void)
+{
+ return 0;
+}
+
+DRESULT disk_ioctl (FATFS *fat, BYTE command, void *buf)
+{
+ return 0;
+}
+
+WCHAR ff_convert(WCHAR src, UINT dir)
+{
+ if (src <= 0x80)
+ return src;
+ else
+ return '?';
+}
+
+WCHAR ff_wtoupper(WCHAR chr)
+{
+ if (chr <= 0x80)
+ return toupper(chr);
+ else
+ return '?';
+}
+
+/* ---------------------------------------------------------------*/
+
+#ifdef CONFIG_FS_FAT_WRITE
+static int fat_create(struct device_d *dev, const char *pathname, mode_t mode)
+{
+ struct fat_priv *priv = dev->priv;
+ FIL f_file;
+ int ret;
+
+ ret = f_open(&priv->fat, &f_file, pathname, FA_OPEN_ALWAYS);
+ if (ret)
+ return -EINVAL;
+
+ f_close(&f_file);
+
+ return 0;
+}
+
+static int fat_unlink(struct device_d *dev, const char *pathname)
+{
+ struct fat_priv *priv = dev->priv;
+ int ret;
+
+ ret = f_unlink(&priv->fat, pathname);
+ if (ret)
+ return ret;
+
+ cdev_flush(priv->cdev);
+
+ return 0;
+}
+
+static int fat_mkdir(struct device_d *dev, const char *pathname)
+{
+ struct fat_priv *priv = dev->priv;
+ int ret;
+
+ ret = f_mkdir(&priv->fat, pathname);
+ if (ret)
+ return ret;
+
+ cdev_flush(priv->cdev);
+
+ return 0;
+}
+
+static int fat_rmdir(struct device_d *dev, const char *pathname)
+{
+ struct fat_priv *priv = dev->priv;
+ int ret;
+
+ ret = f_unlink(&priv->fat, pathname);
+ if (ret)
+ return ret;
+
+ cdev_flush(priv->cdev);
+
+ return 0;
+}
+
+static int fat_write(struct device_d *_dev, FILE *f, const void *buf, size_t insize)
+{
+ FIL *f_file = f->inode;
+ int outsize;
+ int ret;
+
+ ret = f_write(f_file, buf, insize, &outsize);
+
+ debug("%s: %d %d %d %p\n", __func__, ret, insize, outsize, f_file);
+
+ if (ret)
+ return ret;
+ if (!outsize)
+ return -ENOSPC;
+
+ return outsize;
+}
+
+static int fat_truncate(struct device_d *dev, FILE *f, ulong size)
+{
+ FIL *f_file = f->inode;
+ unsigned long lastofs;
+ int ret;
+
+ lastofs = f_file->fptr;
+
+ ret = f_lseek(f_file, size);
+ if (ret)
+ return ret;
+
+ ret = f_truncate(f_file);
+ if (ret)
+ return ret;
+
+ ret = f_lseek(f_file, lastofs);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+#endif /* CONFIG_FS_FAT_WRITE */
+
+static int fat_open(struct device_d *dev, FILE *file, const char *filename)
+{
+ struct fat_priv *priv = dev->priv;
+ FIL *f_file;
+ int ret;
+ unsigned long flags = 0;
+
+ f_file = xzalloc(sizeof(*f_file));
+
+ switch (file->flags & O_ACCMODE) {
+ case O_RDONLY:
+ flags = FA_READ;
+ break;
+ case O_WRONLY:
+ flags = FA_WRITE;
+ break;
+ case O_RDWR:
+ flags = FA_READ | FA_WRITE;
+ break;
+ }
+
+ ret = f_open(&priv->fat, f_file, filename, flags);
+ if (ret) {
+ free(f_file);
+ return -EINVAL;
+ }
+
+ if (file->flags & O_APPEND) {
+ ret = f_lseek(f_file, f_file->fsize);
+ }
+
+ file->inode = f_file;
+ file->size = f_file->fsize;
+
+ return 0;
+}
+
+static int fat_close(struct device_d *dev, FILE *f)
+{
+ struct fat_priv *priv = dev->priv;
+ FIL *f_file = f->inode;
+
+ f_close(f_file);
+
+ free(f_file);
+
+ cdev_flush(priv->cdev);
+
+ return 0;
+}
+
+static int fat_read(struct device_d *_dev, FILE *f, void *buf, size_t insize)
+{
+ int ret;
+ FIL *f_file = f->inode;
+ int outsize;
+
+ ret = f_read(f_file, buf, insize, &outsize);
+
+ debug("%s: %d %d %d %p\n", __func__, ret, insize, outsize, f_file);
+
+ if (ret)
+ return ret;
+
+ return outsize;
+}
+
+static off_t fat_lseek(struct device_d *dev, FILE *f, off_t pos)
+{
+ FIL *f_file = f->inode;
+ int ret;
+
+ ret = f_lseek(f_file, pos);
+ if (ret)
+ return ret;
+
+ return pos;
+}
+
+static DIR* fat_opendir(struct device_d *dev, const char *pathname)
+{
+ struct fat_priv *priv = dev->priv;
+ DIR *dir;
+ FF_DIR *ff_dir;
+ int ret;
+
+ debug("%s: %s\n", __func__, pathname);
+
+ ff_dir = xzalloc(sizeof(*ff_dir));
+ if (pathname)
+ ret = f_opendir(&priv->fat, ff_dir, pathname);
+ else
+ ret = f_opendir(&priv->fat, ff_dir, "/");
+
+ if (ret)
+ return NULL;
+
+ dir = xzalloc(sizeof(*dir));
+
+ dir->priv = ff_dir;
+
+ return dir;
+}
+
+static struct dirent* fat_readdir(struct device_d *dev, DIR *dir)
+{
+ FF_DIR *ff_dir = dir->priv;
+ FILINFO finfo;
+ int ret;
+#ifdef CONFIG_FS_FAT_LFN
+ char name[PATH_MAX];
+#endif
+ memset(&finfo, 0, sizeof(finfo));
+#ifdef CONFIG_FS_FAT_LFN
+ finfo.lfname = name;
+ finfo.lfsize = PATH_MAX;
+#endif
+ ret = f_readdir(ff_dir, &finfo);
+ if (ret)
+ return NULL;
+
+ if (finfo.fname[0] == '\0')
+ return NULL;
+
+#ifdef CONFIG_FS_FAT_LFN
+ if (*finfo.lfname)
+ strcpy(dir->d.d_name, finfo.lfname);
+ else
+#endif
+ strcpy(dir->d.d_name, finfo.fname);
+
+ return &dir->d;
+}
+
+static int fat_closedir(struct device_d *dev, DIR *dir)
+{
+ FF_DIR *ff_dir = dir->priv;
+
+ free(ff_dir);
+ free(dir);
+
+ return 0;
+}
+
+static int fat_stat(struct device_d *dev, const char *filename, struct stat *s)
+{
+ struct fat_priv *priv = dev->priv;
+ FILINFO finfo;
+ int ret;
+
+ ret = f_stat(&priv->fat, filename, &finfo);
+ if (ret)
+ return ret;
+
+ s->st_size = finfo.fsize;
+ s->st_mode = S_IRWXU | S_IRWXG | S_IRWXO;
+
+ if (finfo.fattrib & AM_DIR)
+ s->st_mode |= S_IFDIR;
+ else
+ s->st_mode |= S_IFREG;
+
+ return 0;
+}
+
+static int fat_probe(struct device_d *dev)
+{
+ struct fs_device_d *fsdev = dev->type_data;
+ struct fat_priv *priv = xzalloc(sizeof(struct fat_priv));
+ char *backingstore = fsdev->backingstore;
+
+ dev->priv = priv;
+
+ if (!strncmp(backingstore , "/dev/", 5))
+ backingstore += 5;
+
+ priv->cdev = cdev_open(backingstore, O_RDWR);
+ if (!priv->cdev)
+ return -EINVAL;
+
+ priv->fat.userdata = priv;
+ f_mount(&priv->fat);
+
+ return 0;
+}
+
+static void fat_remove(struct device_d *dev)
+{
+ struct fat_priv *priv = dev->priv;
+
+ cdev_close(priv->cdev);
+
+ free(dev->priv);
+}
+
+static struct fs_driver_d fat_driver = {
+ .open = fat_open,
+ .close = fat_close,
+ .read = fat_read,
+ .lseek = fat_lseek,
+ .opendir = fat_opendir,
+ .readdir = fat_readdir,
+ .closedir = fat_closedir,
+ .stat = fat_stat,
+#ifdef CONFIG_FS_FAT_WRITE
+ .create = fat_create,
+ .unlink = fat_unlink,
+ .mkdir = fat_mkdir,
+ .rmdir = fat_rmdir,
+ .write = fat_write,
+ .truncate = fat_truncate,
+#endif
+ .flags = 0,
+ .drv = {
+ .probe = fat_probe,
+ .remove = fat_remove,
+ .name = "fat",
+ .type_data = &fat_driver,
+ }
+};
+
+static int fat_init(void)
+{
+ return register_fs_driver(&fat_driver);
+}
+
+coredevice_initcall(fat_init);
+
diff --git a/fs/fat/ff.c b/fs/fat/ff.c
new file mode 100644
index 00000000..bcd0a939
--- /dev/null
+++ b/fs/fat/ff.c
@@ -0,0 +1,2761 @@
+/*----------------------------------------------------------------------------/
+/ FatFs - FAT file system module R0.08b (C)ChaN, 2011
+/-----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following terms.
+/
+/ Copyright (C) 2011, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/ personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/-----------------------------------------------------------------------------/
+/ Feb 26,'06 R0.00 Prototype.
+/
+/ Apr 29,'06 R0.01 First stable version.
+/
+/ Jun 01,'06 R0.02 Added FAT12 support.
+/ Removed unbuffered mode.
+/ Fixed a problem on small (<32M) partition.
+/ Jun 10,'06 R0.02a Added a configuration option (_FS_MINIMUM).
+/
+/ Sep 22,'06 R0.03 Added f_rename().
+/ Changed option _FS_MINIMUM to _FS_MINIMIZE.
+/ Dec 11,'06 R0.03a Improved cluster scan algorithm to write files fast.
+/ Fixed f_mkdir() creates incorrect directory on FAT32.
+/
+/ Feb 04,'07 R0.04 Supported multiple drive system.
+/ Changed some interfaces for multiple drive system.
+/ Changed f_mountdrv() to f_mount().
+/ Added f_mkfs().
+/ Apr 01,'07 R0.04a Supported multiple partitions on a physical drive.
+/ Added a capability of extending file size to f_lseek().
+/ Added minimization level 3.
+/ Fixed an endian sensitive code in f_mkfs().
+/ May 05,'07 R0.04b Added a configuration option _USE_NTFLAG.
+/ Added FSInfo support.
+/ Fixed DBCS name can result FR_INVALID_NAME.
+/ Fixed short seek (<= csize) collapses the file object.
+/
+/ Aug 25,'07 R0.05 Changed arguments of f_read(), f_write() and f_mkfs().
+/ Fixed f_mkfs() on FAT32 creates incorrect FSInfo.
+/ Fixed f_mkdir() on FAT32 creates incorrect directory.
+/ Feb 03,'08 R0.05a Added f_truncate() and f_utime().
+/ Fixed off by one error at FAT sub-type determination.
+/ Fixed btr in f_read() can be mistruncated.
+/ Fixed cached sector is not flushed when create and close without write.
+/
+/ Apr 01,'08 R0.06 Added fputc(), fputs(), fprintf() and fgets().
+/ Improved performance of f_lseek() on moving to the same or following cluster.
+/
+/ Apr 01,'09 R0.07 Merged Tiny-FatFs as a configuration option. (_FS_TINY)
+/ Added long file name feature.
+/ Added multiple code page feature.
+/ Added re-entrancy for multitask operation.
+/ Added auto cluster size selection to f_mkfs().
+/ Added rewind option to f_readdir().
+/ Changed result code of critical errors.
+/ Renamed string functions to avoid name collision.
+/ Apr 14,'09 R0.07a Separated out OS dependent code on reentrant cfg.
+/ Added multiple sector size feature.
+/ Jun 21,'09 R0.07c Fixed f_unlink() can return 0 on error.
+/ Fixed wrong cache control in f_lseek().
+/ Added relative path feature.
+/ Added f_chdir() and f_chdrive().
+/ Added proper case conversion to extended char.
+/ Nov 03,'09 R0.07e Separated out configuration options from ff.h to ffconf.h.
+/ Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
+/ Fixed name matching error on the 13 char boundary.
+/ Added a configuration option, _LFN_UNICODE.
+/ Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
+/
+/ May 15,'10 R0.08 Added a memory configuration option. (_USE_LFN = 3)
+/ Added file lock feature. (_FS_SHARE)
+/ Added fast seek feature. (_USE_FASTSEEK)
+/ Changed some types on the API, XCHAR->TCHAR.
+/ Changed fname member in the FILINFO structure on Unicode cfg.
+/ String functions support UTF-8 encoding files on Unicode cfg.
+/ Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
+/ Added sector erase feature. (_USE_ERASE)
+/ Moved file lock semaphore table from fs object to the bss.
+/ Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
+/ Fixed f_mkfs() creates wrong FAT32 volume.
+/ Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
+/ f_lseek() reports required table size on creating CLMP.
+/ Extended format syntax of f_printf function.
+/ Ignores duplicated directory separators in given path names.
+/---------------------------------------------------------------------------*/
+
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <linux/ctype.h>
+#include "ff.h" /* FatFs configurations and declarations */
+#include "diskio.h" /* Declarations of low level disk I/O functions */
+
+#if _FATFS != 8237
+#error Wrong include file (ff.h).
+#endif
+
+/* Definitions on sector size */
+#if _MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096
+#error Wrong sector size.
+#endif
+#if _MAX_SS != 512
+#define SS(fs) ((fs)->ssize) /* Multiple sector size */
+#else
+#define SS(fs) 512U /* Fixed sector size */
+#endif
+
+#define ABORT(fs, res) { fp->flag |= FA__ERROR; return res; }
+
+/* Misc definitions */
+#define LD_CLUST(dir) (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO))
+#define ST_CLUST(dir,cl) {ST_WORD(dir+DIR_FstClusLO, cl); ST_WORD(dir+DIR_FstClusHI, (DWORD)cl>>16);}
+
+
+/* DBCS code ranges and SBCS extend char conversion table */
+
+/* Codepage 437 (US OEM) */
+#define _DF1S 0
+#define _EXCVT { \
+ 0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
+ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
+ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF, \
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF, \
+}
+
+#define IsDBCS1(c) 0
+#define IsDBCS2(c) 0
+
+/* Name status flags */
+#define NS 11 /* Index of name status byte in fn[] */
+#define NS_LOSS 0x01 /* Out of 8.3 format */
+#define NS_LFN 0x02 /* Force to create LFN entry */
+#define NS_LAST 0x04 /* Last segment */
+#define NS_BODY 0x08 /* Lower case flag (body) */
+#define NS_EXT 0x10 /* Lower case flag (ext) */
+#define NS_DOT 0x20 /* Dot entry */
+
+
+/* FAT sub-type boundaries */
+/* Note that the FAT spec by Microsoft says 4085 but Windows works with 4087! */
+#define MIN_FAT16 4086 /* Minimum number of clusters for FAT16 */
+#define MIN_FAT32 65526 /* Minimum number of clusters for FAT32 */
+
+
+/* FatFs refers the members in the FAT structures as byte array instead of
+/ structure member because the structure is not binary compatible between
+/ different platforms */
+
+#define BS_jmpBoot 0 /* Jump instruction (3) */
+#define BS_OEMName 3 /* OEM name (8) */
+#define BPB_BytsPerSec 11 /* Sector size [byte] (2) */
+#define BPB_SecPerClus 13 /* Cluster size [sector] (1) */
+#define BPB_RsvdSecCnt 14 /* Size of reserved area [sector] (2) */
+#define BPB_NumFATs 16 /* Number of FAT copies (1) */
+#define BPB_RootEntCnt 17 /* Number of root dir entries for FAT12/16 (2) */
+#define BPB_TotSec16 19 /* Volume size [sector] (2) */
+#define BPB_Media 21 /* Media descriptor (1) */
+#define BPB_FATSz16 22 /* FAT size [sector] (2) */
+#define BPB_SecPerTrk 24 /* Track size [sector] (2) */
+#define BPB_NumHeads 26 /* Number of heads (2) */
+#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
+#define BPB_TotSec32 32 /* Volume size [sector] (4) */
+#define BS_DrvNum 36 /* Physical drive number (2) */
+#define BS_BootSig 38 /* Extended boot signature (1) */
+#define BS_VolID 39 /* Volume serial number (4) */
+#define BS_VolLab 43 /* Volume label (8) */
+#define BS_FilSysType 54 /* File system type (1) */
+#define BPB_FATSz32 36 /* FAT size [sector] (4) */
+#define BPB_ExtFlags 40 /* Extended flags (2) */
+#define BPB_FSVer 42 /* File system version (2) */
+#define BPB_RootClus 44 /* Root dir first cluster (4) */
+#define BPB_FSInfo 48 /* Offset of FSInfo sector (2) */
+#define BPB_BkBootSec 50 /* Offset of backup boot sectot (2) */
+#define BS_DrvNum32 64 /* Physical drive number (2) */
+#define BS_BootSig32 66 /* Extended boot signature (1) */
+#define BS_VolID32 67 /* Volume serial number (4) */
+#define BS_VolLab32 71 /* Volume label (8) */
+#define BS_FilSysType32 82 /* File system type (1) */
+#define FSI_LeadSig 0 /* FSI: Leading signature (4) */
+#define FSI_StrucSig 484 /* FSI: Structure signature (4) */
+#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
+#define FSI_Nxt_Free 492 /* FSI: Last allocated cluster (4) */
+#define MBR_Table 446 /* MBR: Partition table offset (2) */
+#define SZ_PTE 16 /* MBR: Size of a partition table entry */
+#define BS_55AA 510 /* Boot sector signature (2) */
+
+#define DIR_Name 0 /* Short file name (11) */
+#define DIR_Attr 11 /* Attribute (1) */
+#define DIR_NTres 12 /* NT flag (1) */
+#define DIR_CrtTime 14 /* Created time (2) */
+#define DIR_CrtDate 16 /* Created date (2) */
+#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (2) */
+#define DIR_WrtTime 22 /* Modified time (2) */
+#define DIR_WrtDate 24 /* Modified date (2) */
+#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (2) */
+#define DIR_FileSize 28 /* File size (4) */
+#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
+#define LDIR_Attr 11 /* LFN attribute (1) */
+#define LDIR_Type 12 /* LFN type (1) */
+#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */
+#define LDIR_FstClusLO 26 /* Filled by zero (0) */
+#define SZ_DIR 32 /* Size of a directory entry */
+#define LLE 0x40 /* Last long entry flag in LDIR_Ord */
+#define DDE 0xE5 /* Deleted directory enrty mark in DIR_Name[0] */
+#define NDDE 0x05 /* Replacement of a character collides with DDE */
+
+#ifndef CONFIG_FS_FAT_LFN
+#define DEF_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) (dobj).fn = sfn
+#define FREE_BUF()
+
+#else
+static WCHAR LfnBuf[_MAX_LFN+1];
+#define DEF_NAMEBUF BYTE sfn[12]
+#define INIT_BUF(dobj) { (dobj).fn = sfn; (dobj).lfn = LfnBuf; }
+#define FREE_BUF()
+#endif
+
+/*
+ * Change window offset
+ */
+struct fat_sector {
+ DWORD sector;
+ struct list_head list;
+ unsigned char data[0];
+};
+
+#ifdef CONFIG_FS_FAT_WRITE
+static int push_fat_sector(FATFS *fs, DWORD sector)
+{
+ struct fat_sector *s;
+
+ list_for_each_entry(s, &fs->dirtylist, list) {
+ if (s->sector == sector) {
+ memcpy(s->data, fs->win, SS(fs));
+ return 0;
+ }
+ }
+
+ s = xmalloc(sizeof(*s) + SS(fs));
+ memcpy(s->data, fs->win, SS(fs));
+ s->sector = sector;
+ list_add_tail(&s->list, &fs->dirtylist);
+
+ return 0;
+}
+#endif
+
+static int get_fat_sector(FATFS *fs, DWORD sector)
+{
+ struct fat_sector *s;
+
+ list_for_each_entry(s, &fs->dirtylist, list) {
+ if (s->sector == sector) {
+ memcpy(fs->win, s->data, SS(fs));
+ return 0;
+ }
+ }
+
+ return disk_read(fs, fs->win, sector, 1);
+}
+
+#ifdef CONFIG_FS_FAT_WRITE
+static int flush_dirty_fat(FATFS *fs)
+{
+ struct fat_sector *s, *tmp;
+
+ list_for_each_entry_safe(s, tmp, &fs->dirtylist, list) {
+ disk_write(fs, s->data, s->sector, 1);
+ if (s->sector < (fs->fatbase + fs->fsize)) {
+ /* In FAT area */
+ BYTE nf;
+ DWORD wsect = s->sector;
+ /* Reflect the change to all FAT copies */
+ for (nf = fs->n_fats; nf > 1; nf--) {
+ wsect += fs->fsize;
+ disk_write(fs, s->data, wsect, 1);
+ }
+ }
+ list_del(&s->list);
+ free(s);
+ }
+
+ return 0;
+}
+#endif
+
+static int move_window (
+ FATFS *fs, /* File system object */
+ DWORD sector /* Sector number to make appearance in the fs->win[] */
+) /* Move to zero only writes back dirty window */
+{
+ DWORD wsect;
+ int ret;
+
+ wsect = fs->winsect;
+ if (wsect != sector) { /* Changed current window */
+#ifdef CONFIG_FS_FAT_WRITE
+ /* Write back dirty window if needed */
+ if (fs->wflag) {
+ ret = push_fat_sector(fs, wsect);
+ if (ret)
+ return ret;
+ fs->wflag = 0;
+ }
+#endif
+ if (sector) {
+ ret = get_fat_sector(fs, sector);
+ if (ret)
+ return ret;
+ fs->winsect = sector;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Clean-up cached data
+ */
+#ifdef CONFIG_FS_FAT_WRITE
+static
+int sync ( /* 0: successful, -EIO: failed */
+ FATFS *fs /* File system object */
+)
+{
+ int res;
+
+ res = move_window(fs, 0);
+ if (res == 0) {
+ /* Update FSInfo sector if needed */
+ if (fs->fs_type == FS_FAT32 && fs->fsi_flag) {
+ fs->winsect = 0;
+ /* Create FSInfo structure */
+ memset(fs->win, 0, 512);
+ ST_WORD(fs->win+BS_55AA, 0xAA55);
+ ST_DWORD(fs->win+FSI_LeadSig, 0x41615252);
+ ST_DWORD(fs->win+FSI_StrucSig, 0x61417272);
+ ST_DWORD(fs->win+FSI_Free_Count, fs->free_clust);
+ ST_DWORD(fs->win+FSI_Nxt_Free, fs->last_clust);
+ /* Write it into the FSInfo sector */
+ disk_write(fs, fs->win, fs->fsi_sector, 1);
+ fs->fsi_flag = 0;
+ }
+ /* Make sure that no pending write process in the physical drive */
+ if (disk_ioctl(fs, CTRL_SYNC, (void*)0) != RES_OK)
+ res = -EIO;
+ }
+
+ return res;
+}
+#endif
+
+/*
+ * Get sector# from cluster#
+ */
+DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to be converted */
+)
+{
+ clst -= 2;
+ if (clst >= (fs->n_fatent - 2))
+ return 0; /* Invalid cluster */
+ return clst * fs->csize + fs->database;
+}
+
+/*
+ * FAT access - Read value of a FAT entry
+ */
+DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, Else:Cluster status */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to get the link information */
+)
+{
+ UINT wc, bc;
+ BYTE *p;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) /* Chack range */
+ return 1;
+
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = (UINT)clst; bc += bc / 2;
+ if (move_window(fs, fs->fatbase + (bc / SS(fs))))
+ break;
+ wc = fs->win[bc % SS(fs)]; bc++;
+ if (move_window(fs, fs->fatbase + (bc / SS(fs))))
+ break;
+ wc |= fs->win[bc % SS(fs)] << 8;
+ return (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
+
+ case FS_FAT16 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))))
+ break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ return LD_WORD(p);
+
+ case FS_FAT32 :
+ if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))))
+ break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ return LD_DWORD(p) & 0x0FFFFFFF;
+ }
+
+ return 0xFFFFFFFF; /* An error occurred at the disk I/O layer */
+}
+
+
+
+
+/*
+ * FAT access - Change value of a FAT entry
+ */
+#ifdef CONFIG_FS_FAT_WRITE
+
+int put_fat (
+ FATFS *fs, /* File system object */
+ DWORD clst, /* Cluster# to be changed in range of 2 to fs->n_fatent - 1 */
+ DWORD val /* New value to mark the cluster */
+)
+{
+ UINT bc;
+ BYTE *p;
+ int res;
+
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = -ERESTARTSYS;
+
+ } else {
+ switch (fs->fs_type) {
+ case FS_FAT12 :
+ bc = clst; bc += bc / 2;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != 0)
+ break;
+ p = &fs->win[bc % SS(fs)];
+ *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
+ bc++;
+ fs->wflag = 1;
+ res = move_window(fs, fs->fatbase + (bc / SS(fs)));
+ if (res != 0)
+ break;
+ p = &fs->win[bc % SS(fs)];
+ *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
+ break;
+
+ case FS_FAT16 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
+ if (res != 0)
+ break;
+ p = &fs->win[clst * 2 % SS(fs)];
+ ST_WORD(p, (WORD)val);
+ break;
+
+ case FS_FAT32 :
+ res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
+ if (res != 0)
+ break;
+ p = &fs->win[clst * 4 % SS(fs)];
+ val |= LD_DWORD(p) & 0xF0000000;
+ ST_DWORD(p, val);
+ break;
+
+ default :
+ res = -ERESTARTSYS;
+ }
+ fs->wflag = 1;
+ }
+
+ return res;
+}
+#endif /* CONFIG_FS_FAT_WRITE */
+
+
+
+
+/*
+ * FAT handling - Remove a cluster chain
+ */
+#ifdef CONFIG_FS_FAT_WRITE
+static
+int remove_chain (
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to remove a chain from */
+)
+{
+ int res;
+ DWORD nxt;
+#if _USE_ERASE
+ DWORD scl = clst, ecl = clst, resion[2];
+#endif
+
+ if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
+ res = -ERESTARTSYS;
+
+ } else {
+ res = 0;
+ while (clst < fs->n_fatent) { /* Not a last link? */
+ nxt = get_fat(fs, clst); /* Get cluster status */
+ if (nxt == 0)
+ break; /* Empty cluster? */
+
+ if (nxt == 1) {
+ res = -ERESTARTSYS;
+ break; /* Internal error? */
+ }
+
+ if (nxt == 0xFFFFFFFF) {
+ res = -EIO;
+ break; /* Disk error? */
+ }
+
+ /* Mark the cluster "empty" */
+ res = put_fat(fs, clst, 0);
+ if (res != 0)
+ break;
+
+ if (fs->free_clust != 0xFFFFFFFF) { /* Update FSInfo */
+ fs->free_clust++;
+ fs->fsi_flag = 1;
+ }
+#if _USE_ERASE
+ if (ecl + 1 == nxt) { /* Next cluster is contiguous */
+ ecl = nxt;
+ } else {
+ /* End of contiguous clusters */
+ resion[0] = clust2sect(fs, scl); /* Start sector */
+ resion[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
+ disk_ioctl(fs, CTRL_ERASE_SECTOR, resion); /* Erase the block */
+ scl = ecl = nxt;
+ }
+#endif
+ clst = nxt; /* Next cluster */
+ }
+ }
+
+ return res;
+}
+#endif
+
+
+
+
+/*
+ * FAT handling - Stretch or Create a cluster chain
+ */
+#ifdef CONFIG_FS_FAT_WRITE
+static
+DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
+ FATFS *fs, /* File system object */
+ DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
+)
+{
+ DWORD cs, ncl, scl;
+ int res;
+
+
+ if (clst == 0) {
+ /* Create a new chain */
+ scl = fs->last_clust; /* Get suggested start point */
+ if (!scl || scl >= fs->n_fatent) scl = 1;
+ } else {
+ /* Stretch the current chain */
+ cs = get_fat(fs, clst); /* Check the cluster status */
+ if (cs < 2)
+ return 1; /* It is an invalid cluster */
+ if (cs < fs->n_fatent)
+ return cs; /* It is already followed by next cluster */
+ scl = clst;
+ }
+
+ ncl = scl; /* Start cluster */
+ for (;;) {
+ ncl++; /* Next cluster */
+ if (ncl >= fs->n_fatent) { /* Wrap around */
+ ncl = 2;
+ if (ncl > scl)
+ return 0; /* No free cluster */
+ }
+ cs = get_fat(fs, ncl); /* Get the cluster status */
+ if (cs == 0)
+ break; /* Found a free cluster */
+ if (cs == 0xFFFFFFFF || cs == 1)/* An error occurred */
+ return cs;
+ if (ncl == scl)
+ return 0; /* No free cluster */
+ }
+
+ /* Mark the new cluster "last link" */
+ res = put_fat(fs, ncl, 0x0FFFFFFF);
+ if (res == 0 && clst != 0) {
+ res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
+ }
+ if (res == 0) {
+ /* Update FSINFO */
+ fs->last_clust = ncl;
+ if (fs->free_clust != 0xFFFFFFFF) {
+ fs->free_clust--;
+ fs->fsi_flag = 1;
+ }
+ } else {
+ ncl = (res == -EIO) ? 0xFFFFFFFF : 1;
+ }
+
+ return ncl; /* Return new cluster number or error code */
+}
+#endif /* CONFIG_FS_FAT_WRITE */
+
+/*
+ * Directory handling - Set directory index
+ */
+static int dir_sdi (
+ FF_DIR *dj, /* Pointer to directory object */
+ WORD idx /* Directory index number */
+)
+{
+ DWORD clst;
+ WORD ic;
+
+ dj->index = idx;
+ clst = dj->sclust;
+
+ if (clst == 1 || clst >= dj->fs->n_fatent) /* Check start cluster range */
+ return -ERESTARTSYS;
+
+ if (!clst && dj->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
+ clst = dj->fs->dirbase;
+
+ if (clst == 0) {
+ /* Static table (root-dir in FAT12/16) */
+ dj->clust = clst;
+
+ if (idx >= dj->fs->n_rootdir)
+ /* Index is out of range */
+ return -ERESTARTSYS;
+
+ dj->sect = dj->fs->dirbase + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
+ } else {
+ /* Dynamic table (sub-dirs or root-dir in FAT32) */
+ ic = SS(dj->fs) / SZ_DIR * dj->fs->csize; /* Entries per cluster */
+ while (idx >= ic) { /* Follow cluster chain */
+ clst = get_fat(dj->fs, clst); /* Get next cluster */
+ if (clst == 0xFFFFFFFF)
+ return -EIO; /* Disk error */
+ if (clst < 2 || clst >= dj->fs->n_fatent)
+ /* Reached to end of table or int error */
+ return -ERESTARTSYS;
+ idx -= ic;
+ }
+ dj->clust = clst;
+ dj->sect = clust2sect(dj->fs, clst) + idx / (SS(dj->fs) / SZ_DIR); /* Sector# */
+ }
+
+ dj->dir = dj->fs->win + (idx % (SS(dj->fs) / SZ_DIR)) * SZ_DIR; /* Ptr to the entry in the sector */
+
+ return 0; /* Seek succeeded */
+}
+
+
+
+
+/*
+ * Directory handling - Move directory index next
+ */
+static int dir_next ( /* 0:Succeeded, FR_NO_FILE:End of table, FR_DENIED:EOT and could not stretch */
+ FF_DIR *dj, /* Pointer to directory object */
+ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
+)
+{
+ DWORD clst;
+ WORD i;
+
+
+ i = dj->index + 1;
+ if (!i || !dj->sect) /* Report EOT when index has reached 65535 */
+ return -ENOENT;
+
+ if (!(i % (SS(dj->fs) / SZ_DIR))) { /* Sector changed? */
+ dj->sect++; /* Next sector */
+
+ if (dj->clust == 0) {
+ /* Static table */
+ if (i >= dj->fs->n_rootdir) /* Report EOT when end of table */
+ return -ENOENT;
+ }
+ else {
+ /* Dynamic table */
+ if (((i / (SS(dj->fs) / SZ_DIR)) & (dj->fs->csize - 1)) == 0) { /* Cluster changed? */
+ clst = get_fat(dj->fs, dj->clust); /* Get next cluster */
+
+ if (clst <= 1)
+ return -ERESTARTSYS;
+
+ if (clst == 0xFFFFFFFF)
+ return -EIO;
+
+ if (clst >= dj->fs->n_fatent) { /* When it reached end of dynamic table */
+#ifdef CONFIG_FS_FAT_WRITE
+ BYTE c;
+
+ if (!stretch)
+ return -ENOENT; /* When do not stretch, report EOT */
+
+ clst = create_chain(dj->fs, dj->clust); /* Stretch cluster chain */
+
+ if (clst == 0)
+ return -ENOSPC; /* No free cluster */
+
+ if (clst == 1)
+ return -ERESTARTSYS;
+
+ if (clst == 0xFFFFFFFF)
+ return -EIO;
+
+ /* Clean-up stretched table */
+ if (move_window(dj->fs, 0))
+ return -EIO; /* Flush active window */
+
+ memset(dj->fs->win, 0, SS(dj->fs)); /* Clear window buffer */
+ dj->fs->winsect = clust2sect(dj->fs, clst); /* Cluster start sector */
+
+ for (c = 0; c < dj->fs->csize; c++) {
+ /* Fill the new cluster with 0 */
+ dj->fs->wflag = 1;
+ if (move_window(dj->fs, 0))
+ return -EIO;
+ dj->fs->winsect++;
+ }
+ dj->fs->winsect -= c; /* Rewind window address */
+#else
+ return -ENOENT; /* Report EOT */
+#endif
+ }
+ dj->clust = clst; /* Initialize data for new cluster */
+ dj->sect = clust2sect(dj->fs, clst);
+ }
+ }
+ }
+
+ dj->index = i;
+ dj->dir = dj->fs->win + (i % (SS(dj->fs) / SZ_DIR)) * SZ_DIR;
+
+ return 0;
+}
+
+/*
+ * LFN handling - Test/Pick/Fit an LFN segment from/to directory entry
+ */
+#ifdef CONFIG_FS_FAT_LFN
+
+/* Offset of LFN chars in the directory entry */
+static const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30};
+
+static int cmp_lfn ( /* 1:Matched, 0:Not matched */
+ WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
+ BYTE *dir /* Pointer to the directory entry containing a part of LFN */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+ /* Get offset in the LFN buffer */
+ i = ((dir[LDIR_Ord] & ~LLE) - 1) * 13;
+ s = 0; wc = 1;
+ do {
+ /* Pick an LFN character from the entry */
+ uc = LD_WORD(dir+LfnOfs[s]);
+ if (wc) {
+ /* Last char has not been processed */
+ wc = ff_wtoupper(uc);
+ if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
+ return 0; /* Not matched */
+ } else {
+ if (uc != 0xFFFF) return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Repeat until all chars in the entry are checked */
+
+ if ((dir[LDIR_Ord] & LLE) && wc && lfnbuf[i])
+ /* Last segment matched but different length */
+ return 0;
+
+ return 1; /* The part of LFN matched */
+}
+
+
+
+static
+int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
+ WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
+ BYTE *dir /* Pointer to the directory entry */
+)
+{
+ UINT i, s;
+ WCHAR wc, uc;
+
+ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
+
+ s = 0;
+ wc = 1;
+ do {
+ /* Pick an LFN character from the entry */
+ uc = LD_WORD(dir+LfnOfs[s]);
+ if (wc) {
+ /* Last char has not been processed */
+ if (i >= _MAX_LFN)
+ return 0; /* Buffer overflow? */
+ lfnbuf[i++] = wc = uc; /* Store it */
+ } else {
+ if (uc != 0xFFFF)
+ return 0; /* Check filler */
+ }
+ } while (++s < 13); /* Read all character in the entry */
+
+ if (dir[LDIR_Ord] & LLE) {
+ /* Put terminator if it is the last LFN part */
+ if (i >= _MAX_LFN)
+ return 0; /* Buffer overflow? */
+ lfnbuf[i] = 0;
+ }
+
+ return 1;
+}
+
+
+#ifdef CONFIG_FS_FAT_WRITE
+static
+void fit_lfn (
+ const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
+ BYTE *dir, /* Pointer to the directory entry */
+ BYTE ord, /* LFN order (1-20) */
+ BYTE sum /* SFN sum */
+)
+{
+ UINT i, s;
+ WCHAR wc;
+
+
+ dir[LDIR_Chksum] = sum; /* Set check sum */
+ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
+ dir[LDIR_Type] = 0;
+ ST_WORD(dir+LDIR_FstClusLO, 0);
+
+ i = (ord - 1) * 13; /* Get offset in the LFN buffer */
+ s = wc = 0;
+ do {
+ if (wc != 0xFFFF)
+ wc = lfnbuf[i++]; /* Get an effective char */
+ ST_WORD(dir + LfnOfs[s], wc); /* Put it */
+ if (!wc)
+ wc = 0xFFFF; /* Padding chars following last char */
+ } while (++s < 13);
+ if (wc == 0xFFFF || !lfnbuf[i])
+ ord |= LLE; /* Bottom LFN part is the start of LFN sequence */
+ dir[LDIR_Ord] = ord; /* Set the LFN order */
+}
+
+#endif
+#endif
+
+
+
+/*
+ * Create numbered name
+ */
+#ifdef CONFIG_FS_FAT_LFN
+void gen_numname (
+ BYTE *dst, /* Pointer to generated SFN */
+ const BYTE *src, /* Pointer to source SFN to be modified */
+ const WCHAR *lfn, /* Pointer to LFN */
+ WORD seq /* Sequence number */
+)
+{
+ BYTE ns[8], c;
+ UINT i, j;
+
+
+ memcpy(dst, src, 11);
+
+ if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
+ do {
+ seq = (seq >> 1) + (seq << 15) + (WORD) * lfn++;
+ } while (*lfn);
+ }
+
+ /* itoa (hexdecimal) */
+ i = 7;
+ do {
+ c = (seq % 16) + '0';
+ if (c > '9')
+ c += 7;
+ ns[i--] = c;
+ seq /= 16;
+ } while (seq);
+
+ ns[i] = '~';
+
+ /* Append the number */
+ for (j = 0; j < i && dst[j] != ' '; j++) {
+ if (IsDBCS1(dst[j])) {
+ if (j == i - 1)
+ break;
+ j++;
+ }
+ }
+
+ do {
+ dst[j++] = (i < 8) ? ns[i++] : ' ';
+ } while (j < 8);
+}
+#endif
+
+/*
+ * Calculate sum of an SFN
+ */
+#ifdef CONFIG_FS_FAT_LFN
+static BYTE sum_sfn (
+ const BYTE *dir /* Ptr to directory entry */
+)
+{
+ BYTE sum = 0;
+ UINT n = 11;
+
+ do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
+ return sum;
+}
+#endif
+
+/*
+ * Directory handling - Find an object in the directory
+ */
+
+static int dir_find (
+ FF_DIR *dj /* Pointer to the directory object linked to the file name */
+)
+{
+ int res;
+ BYTE c, *dir;
+#ifdef CONFIG_FS_FAT_LFN
+ BYTE a, ord, sum;
+#endif
+
+ res = dir_sdi(dj, 0); /* Rewind directory object */
+ if (res != 0)
+ return res;
+
+#ifdef CONFIG_FS_FAT_LFN
+ ord = sum = 0xFF;
+#endif
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != 0)
+ break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) {
+ /* Reached to end of table */
+ res = -ENOENT;
+ break;
+ }
+#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == DDE || ((a & AM_VOL) && a != AM_LFN)) {
+ /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) {
+ /* An LFN entry is found */
+ if (dj->lfn) {
+ if (c & LLE) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLE; ord = c; /* LFN start order */
+ dj->lfn_idx = dj->index;
+ }
+ /* Check validity of the LFN entry and compare it with given name */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ }
+ } else {
+ /* An SFN entry is found */
+ if (!ord && sum == sum_sfn(dir))
+ break; /* LFN matched? */
+
+ /* Reset LFN sequence */
+ ord = 0xFF;
+ dj->lfn_idx = 0xFFFF;
+ if (!(dj->fn[NS] & NS_LOSS) && !memcmp(dir, dj->fn, 11))
+ break; /* SFN matched? */
+ }
+ }
+#else /* Non LFN configuration */
+ if (!(dir[DIR_Attr] & AM_VOL) && !memcmp(dir, dj->fn, 11)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == 0);
+
+ return res;
+}
+
+
+
+
+/*
+ * Read an object from the directory
+ */
+static int dir_read (
+ FF_DIR *dj /* Pointer to the directory object that pointing the entry to be read */
+)
+{
+ int res;
+ BYTE c, *dir;
+#ifdef CONFIG_FS_FAT_LFN
+ BYTE a, ord = 0xFF, sum = 0xFF;
+#endif
+
+ res = -ENOENT;
+ while (dj->sect) {
+ res = move_window(dj->fs, dj->sect);
+ if (res != 0)
+ break;
+ dir = dj->dir; /* Ptr to the directory entry of current index */
+ c = dir[DIR_Name];
+ if (c == 0) {
+ /* Reached to end of table */
+ res = -ENOENT;
+ break;
+ }
+#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */
+ a = dir[DIR_Attr] & AM_MASK;
+ if (c == DDE || c == '.' || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
+ ord = 0xFF;
+ } else {
+ if (a == AM_LFN) {
+ /* An LFN entry is found */
+ if (c & LLE) { /* Is it start of LFN sequence? */
+ sum = dir[LDIR_Chksum];
+ c &= ~LLE; ord = c;
+ dj->lfn_idx = dj->index;
+ }
+ /* Check LFN validity and capture it */
+ ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dj->lfn, dir)) ? ord - 1 : 0xFF;
+ } else {
+ /* An SFN entry is found */
+ if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
+ dj->lfn_idx = 0xFFFF; /* It has no LFN. */
+ break;
+ }
+ }
+#else /* Non LFN configuration */
+ if (c != DDE && c != '.' && !(dir[DIR_Attr] & AM_VOL)) /* Is it a valid entry? */
+ break;
+#endif
+ res = dir_next(dj, 0); /* Next entry */
+ if (res != 0)
+ break;
+ }
+
+ if (res != 0)
+ dj->sect = 0;
+
+ return res;
+}
+
+/*
+ * Register an object to the directory
+ */
+#ifdef CONFIG_FS_FAT_WRITE
+static
+int dir_register ( /* 0:Successful, FR_DENIED:No free entry or too many SFN collision, -EIO:Disk error */
+ FF_DIR *dj /* Target directory with object name to be created */
+)
+{
+ int res;
+ BYTE c, *dir;
+#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */
+ WORD n, ne, is;
+ BYTE sn[12], *fn, sum;
+ WCHAR *lfn;
+
+
+ fn = dj->fn; lfn = dj->lfn;
+ memcpy(sn, fn, 12);
+
+ if (sn[NS] & NS_LOSS) {
+ /* When LFN is out of 8.3 format, generate a numbered name */
+ fn[NS] = 0; dj->lfn = 0; /* Find only SFN */
+ for (n = 1; n < 100; n++) {
+ gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
+ res = dir_find(dj); /* Check if the name collides with existing SFN */
+ if (res != 0)
+ break;
+ }
+ if (n == 100)
+ return -ENOSPC; /* Abort if too many collisions */
+ if (res != -ENOENT)
+ return res; /* Abort if the result is other than 'not collided' */
+ fn[NS] = sn[NS]; dj->lfn = lfn;
+ }
+
+ if (sn[NS] & NS_LFN) {
+ /* When LFN is to be created, reserve an SFN + LFN entries. */
+ for (ne = 0; lfn[ne]; ne++);
+ ne = (ne + 25) / 13;
+ } else {
+ /* Otherwise reserve only an SFN entry. */
+ ne = 1;
+ }
+
+ /* Reserve contiguous entries */
+ res = dir_sdi(dj, 0);
+ if (res != 0)
+ return res;
+ n = is = 0;
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != 0)
+ break;
+ c = *dj->dir; /* Check the entry status */
+ if (c == DDE || c == 0) { /* Is it a blank entry? */
+ if (n == 0)
+ is = dj->index; /* First index of the contiguous entry */
+ if (++n == ne)
+ break; /* A contiguous entry that required count is found */
+ } else {
+ n = 0; /* Not a blank entry. Restart to search */
+ }
+ res = dir_next(dj, 1); /* Next entry with table stretch */
+ } while (res == 0);
+
+ if (res == 0 && ne > 1) {
+ /* Initialize LFN entry if needed */
+ res = dir_sdi(dj, is);
+ if (res == 0) {
+ sum = sum_sfn(dj->fn); /* Sum of the SFN tied to the LFN */
+ ne--;
+ do {
+ /* Store LFN entries in bottom first */
+ res = move_window(dj->fs, dj->sect);
+ if (res != 0)
+ break;
+ fit_lfn(dj->lfn, dj->dir, (BYTE)ne, sum);
+ dj->fs->wflag = 1;
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == 0 && --ne);
+ }
+ }
+
+#else /* Non LFN configuration */
+ res = dir_sdi(dj, 0);
+ if (res == 0) {
+ do { /* Find a blank entry for the SFN */
+ res = move_window(dj->fs, dj->sect);
+ if (res != 0)
+ break;
+ c = *dj->dir;
+ if (c == DDE || c == 0)
+ break; /* Is it a blank entry? */
+ res = dir_next(dj, 1); /* Next entry with table stretch */
+ } while (res == 0);
+ }
+#endif
+
+ if (res == 0) { /* Initialize the SFN entry */
+ res = move_window(dj->fs, dj->sect);
+ if (res == 0) {
+ dir = dj->dir;
+ memset(dir, 0, SZ_DIR); /* Clean the entry */
+ memcpy(dir, dj->fn, 11); /* Put SFN */
+#ifdef CONFIG_FS_FAT_LFN
+ dir[DIR_NTres] = *(dj->fn+NS) & (NS_BODY | NS_EXT); /* Put NT flag */
+#endif
+ dj->fs->wflag = 1;
+ }
+ }
+
+ return res;
+}
+#endif /* CONFIG_FS_FAT_WRITE */
+
+/*
+ * Remove an object from the directory
+ */
+#if defined CONFIG_FS_FAT_WRITE
+static int dir_remove ( /* 0: Successful, -EIO: A disk error */
+ FF_DIR *dj /* Directory object pointing the entry to be removed */
+)
+{
+ int res;
+#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */
+ WORD i;
+
+ i = dj->index; /* SFN index */
+ /* Goto the SFN or top of the LFN entries */
+ res = dir_sdi(dj, (WORD)((dj->lfn_idx == 0xFFFF) ? i : dj->lfn_idx));
+ if (res == 0) {
+ do {
+ res = move_window(dj->fs, dj->sect);
+ if (res != 0)
+ break;
+ *dj->dir = DDE; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ if (dj->index >= i)
+ break; /* When reached SFN, all entries of the object has been deleted. */
+ res = dir_next(dj, 0); /* Next entry */
+ } while (res == 0);
+ if (res == -ENOENT)
+ res = -ERESTARTSYS;
+ }
+
+#else /* Non LFN configuration */
+ res = dir_sdi(dj, dj->index);
+ if (res == 0) {
+ res = move_window(dj->fs, dj->sect);
+ if (res == 0) {
+ *dj->dir = DDE; /* Mark the entry "deleted" */
+ dj->fs->wflag = 1;
+ }
+ }
+#endif
+
+ return res;
+}
+#endif /* CONFIG_FS_FAT_WRITE */
+
+/*
+ * Pick a segment and create the object name in directory form
+ */
+static int create_name (
+ FF_DIR *dj, /* Pointer to the directory object */
+ const TCHAR **path /* Pointer to pointer to the segment in the path string */
+)
+{
+#ifdef _EXCVT
+ static const BYTE excvt[] = _EXCVT; /* Upper conversion table for extended chars */
+#endif
+
+#ifdef CONFIG_FS_FAT_LFN /* LFN configuration */
+ BYTE b, cf;
+ WCHAR w, *lfn;
+ UINT i, ni, si, di;
+ const TCHAR *p;
+
+ /* Create LFN in Unicode */
+ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */
+ lfn = dj->lfn;
+ si = di = 0;
+ for (;;) {
+ w = p[si++]; /* Get a character */
+ if (w < ' ' || w == '/' || w == '\\')
+ break; /* Break on end of segment */
+ if (di >= _MAX_LFN) /* Reject too long name */
+ return -ENAMETOOLONG;
+#if !_LFN_UNICODE
+ w &= 0xFF;
+ if (IsDBCS1(w)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ b = (BYTE)p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(b))
+ return -ENAMETOOLONG; /* Reject invalid sequence */
+ w = (w << 8) + b; /* Create a DBC */
+ }
+ w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
+ if (!w) return -ENAMETOOLONG; /* Reject invalid code */
+#endif
+ if (w < 0x80 && strchr("\"*:<>\?|\x7F", w)) /* Reject illegal chars for LFN */
+ return -ENAMETOOLONG;
+ lfn[di++] = w; /* Store the Unicode char */
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+ while (di) { /* Strip trailing spaces and dots */
+ w = lfn[di-1];
+ if (w != ' ' && w != '.')
+ break;
+ di--;
+ }
+ if (!di) return -EINVAL; /* Reject nul string */
+
+ lfn[di] = 0; /* LFN is created */
+
+ /* Create SFN in directory form */
+ memset(dj->fn, ' ', 11);
+ for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++) ; /* Strip leading spaces and dots */
+ if (si) cf |= NS_LOSS | NS_LFN;
+ while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
+
+ b = i = 0; ni = 8;
+ for (;;) {
+ w = lfn[si++]; /* Get an LFN char */
+ if (!w)
+ break; /* Break on end of the LFN */
+ if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
+ cf |= NS_LOSS | NS_LFN;
+ continue;
+ }
+
+ if (i >= ni || si == di) { /* Extension or end of SFN */
+ if (ni == 11) { /* Long extension */
+ cf |= NS_LOSS | NS_LFN;
+ break;
+ }
+ if (si != di)
+ cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
+ if (si > di)
+ break; /* No extension */
+ si = di; i = 8; ni = 11;/* Enter extension section */
+ b <<= 2;
+ continue;
+ }
+
+ if (w >= 0x80) { /* Non ASCII char */
+#ifdef _EXCVT
+ w = ff_convert(w, 0); /* Unicode -> OEM code */
+ if (w)
+ w = excvt[w - 0x80]; /* Convert extended char to upper (SBCS) */
+#else
+ w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
+#endif
+ cf |= NS_LFN; /* Force create LFN entry */
+ }
+
+ if (_DF1S && w >= 0x100) { /* Double byte char (always false on SBCS cfg) */
+ if (i >= ni - 1) {
+ cf |= NS_LOSS | NS_LFN; i = ni;
+ continue;
+ }
+ dj->fn[i++] = (BYTE)(w >> 8);
+ } else { /* Single byte char */
+ if (!w || strchr("+,;=[]", w)) { /* Replace illegal chars for SFN */
+ w = '_'; cf |= NS_LOSS | NS_LFN;/* Lossy conversion */
+ } else {
+ if (isupper(w)) {
+ b |= 2;
+ } else {
+ if (islower(w)) {
+ b |= 1; w -= 0x20;
+ }
+ }
+ }
+ }
+ dj->fn[i++] = (BYTE)w;
+ }
+
+ if (dj->fn[0] == DDE)
+ dj->fn[0] = NDDE; /* If the first char collides with deleted mark, replace it with 0x05 */
+
+ if (ni == 8) b <<= 2;
+ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
+ cf |= NS_LFN;
+ if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended char, NT flags are created */
+ if ((b & 0x03) == 0x01)
+ cf |= NS_EXT; /* NT flag (Extension has only small capital) */
+ if ((b & 0x0C) == 0x04)
+ cf |= NS_BODY; /* NT flag (Filename has only small capital) */
+ }
+
+ dj->fn[NS] = cf; /* SFN is created */
+
+ return 0;
+
+#else /* Non-LFN configuration */
+ BYTE b, c, d, *sfn;
+ UINT ni, si, i;
+ const char *p;
+
+ /* Create file name in directory form */
+ for (p = *path; *p == '/' || *p == '\\'; p++); /* Strip duplicated separator */
+ sfn = dj->fn;
+ memset(sfn, ' ', 11);
+ si = i = b = 0; ni = 8;
+ for (;;) {
+ c = (BYTE)p[si++];
+ if (c <= ' ' || c == '/' || c == '\\') break; /* Break on end of segment */
+ if (c == '.' || i >= ni) {
+ if (ni != 8 || c != '.')
+ return -EINVAL;
+ i = 8; ni = 11;
+ b <<= 2; continue;
+ }
+ if (c >= 0x80) { /* Extended char? */
+ b |= 3; /* Eliminate NT flag */
+#ifdef _EXCVT
+ c = excvt[c-0x80]; /* Upper conversion (SBCS) */
+#else
+#if !_DF1S /* ASCII only cfg */
+ return -EINVAL;
+#endif
+#endif
+ }
+ if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
+ d = (BYTE)p[si++]; /* Get 2nd byte */
+ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
+ return -EINVAL;
+ sfn[i++] = c;
+ sfn[i++] = d;
+ } else { /* Single byte code */
+ if (strchr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
+ return -EINVAL;
+ if (isupper(c)) {
+ b |= 2;
+ } else {
+ if (islower(c)) {
+ b |= 1; c -= 0x20;
+ }
+ }
+ sfn[i++] = c;
+ }
+ }
+ *path = &p[si]; /* Return pointer to the next segment */
+ c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
+
+ if (!i)
+ return -EINVAL; /* Reject nul string */
+ if (sfn[0] == DDE)
+ sfn[0] = NDDE; /* When first char collides with DDE, replace it with 0x05 */
+
+ if (ni == 8)
+ b <<= 2;
+ if ((b & 0x03) == 0x01)
+ c |= NS_EXT; /* NT flag (Name extension has only small capital) */
+ if ((b & 0x0C) == 0x04)
+ c |= NS_BODY; /* NT flag (Name body has only small capital) */
+
+ sfn[NS] = c; /* Store NT flag, File name is created */
+
+ return 0;
+#endif
+}
+
+/*
+ * Get file information from directory entry
+ */
+static void get_fileinfo ( /* No return code */
+ FF_DIR *dj, /* Pointer to the directory object */
+ FILINFO *fno /* Pointer to the file information to be filled */
+)
+{
+ UINT i;
+ BYTE nt, *dir;
+ TCHAR *p, c;
+
+
+ p = fno->fname;
+ if (dj->sect) {
+ dir = dj->dir;
+ nt = dir[DIR_NTres]; /* NT flag */
+ for (i = 0; i < 8; i++) { /* Copy name body */
+ c = dir[i];
+ if (c == ' ')
+ break;
+ if (c == NDDE)
+ c = (TCHAR)DDE;
+#ifdef CONFIG_FS_FAT_LFN
+ if ((nt & NS_BODY) && isupper(c))
+ c += 0x20;
+#endif
+#if _LFN_UNICODE
+ if (IsDBCS1(c) && i < 7 && IsDBCS2(dir[i+1]))
+ c = (c << 8) | dir[++i];
+ c = ff_convert(c, 1);
+ if (!c) c = '?';
+#endif
+ *p++ = c;
+ }
+ if (dir[8] != ' ') { /* Copy name extension */
+ *p++ = '.';
+ for (i = 8; i < 11; i++) {
+ c = dir[i];
+ if (c == ' ')
+ break;
+#ifdef CONFIG_FS_FAT_LFN
+ if ((nt & NS_EXT) && isupper(c))
+ c += 0x20;
+#endif
+#if _LFN_UNICODE
+ if (IsDBCS1(c) && i < 10 && IsDBCS2(dir[i+1]))
+ c = (c << 8) | dir[++i];
+ c = ff_convert(c, 1);
+ if (!c)
+ c = '?';
+#endif
+ *p++ = c;
+ }
+ }
+ fno->fattrib = dir[DIR_Attr]; /* Attribute */
+ fno->fsize = LD_DWORD(dir+DIR_FileSize); /* Size */
+ fno->fdate = LD_WORD(dir+DIR_WrtDate); /* Date */
+ fno->ftime = LD_WORD(dir+DIR_WrtTime); /* Time */
+ }
+ *p = 0; /* Terminate SFN str by a \0 */
+
+#ifdef CONFIG_FS_FAT_LFN
+ if (fno->lfname && fno->lfsize) {
+ TCHAR *tp = fno->lfname;
+ WCHAR w, *lfn;
+
+ i = 0;
+ if (dj->sect && dj->lfn_idx != 0xFFFF) {/* Get LFN if available */
+ lfn = dj->lfn;
+ while ((w = *lfn++) != 0) { /* Get an LFN char */
+#if !_LFN_UNICODE
+ w = ff_convert(w, 0); /* Unicode -> OEM conversion */
+ if (!w) {
+ /* Could not convert, no LFN */
+ i = 0;
+ break;
+ }
+ /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
+ if (_DF1S && w >= 0x100)
+ tp[i++] = (TCHAR)(w >> 8);
+#endif
+ if (i >= fno->lfsize - 1) { i = 0; break; } /* Buffer overflow, no LFN */
+ tp[i++] = (TCHAR)w;
+ }
+ }
+ tp[i] = 0; /* Terminate the LFN str by a \0 */
+ }
+#endif
+}
+
+/*
+ * Follow a file path
+ */
+static
+int follow_path ( /* 0(0): successful, !=0: error code */
+ FF_DIR *dj, /* Directory object to return last directory and found object */
+ const TCHAR *path /* Full-path string to find a file or directory */
+)
+{
+ int res;
+ BYTE *dir, ns;
+
+ if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
+ path++;
+ dj->sclust = 0; /* Start from the root dir */
+
+ if ((UINT)*path < ' ') {
+ /* Nul path means the start directory itself */
+ res = dir_sdi(dj, 0);
+ dj->dir = 0;
+ return res;
+ }
+
+ /* Follow path */
+ for (;;) {
+ res = create_name(dj, &path); /* Get a segment */
+ if (res != 0)
+ break;
+ res = dir_find(dj); /* Find it */
+ ns = *(dj->fn+NS);
+ if (res != 0) { /* Failed to find the object */
+ if (res != -ENOENT)
+ break; /* Abort if any hard error occured */
+ /* Object not found */
+ if (!(ns & NS_LAST))
+ res = -ENOENT;
+ break;
+ }
+ if (ns & NS_LAST)
+ break; /* Last segment match. Function completed. */
+ dir = dj->dir; /* There is next segment. Follow the sub directory */
+ if (!(dir[DIR_Attr] & AM_DIR)) { /* Cannot follow because it is a file */
+ res = -ENOTDIR;
+ break;
+ }
+ dj->sclust = LD_CLUST(dir);
+ }
+
+ return res;
+}
+
+/*
+ * Load boot record and check if it is an FAT boot record
+ */
+static int check_fs ( /* 0:The FAT BR, 1:Valid BR but not an FAT, 2:Not a BR, 3:Disk error */
+ FATFS *fs, /* File system object */
+ DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
+)
+{
+ int ret;
+
+ /* Load boot record */
+ ret = disk_read(fs, fs->win, sect, 1);
+ if (ret)
+ return ret;
+ /* Check record signature (always placed at offset 510 even if the sector size is>512) */
+ if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55)
+ return -ENODEV;
+
+ /* Check "FAT" string */
+ if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146)
+ return 0;
+
+ if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146)
+ return 0;
+
+ return -ENODEV;
+}
+
+/*
+ * Check if the file system object is valid or not
+ */
+static int chk_mounted ( /* 0(0): successful, !=0: any error occurred */
+ FATFS *fs, /* Pointer to pointer to the found file system object */
+ BYTE chk_wp /* !=0: Check media write protection for write access */
+)
+{
+ BYTE fmt, b;
+ DWORD bsect, fasize, tsect, sysect, nclst, szbfat;
+ WORD nrsv;
+
+ INIT_LIST_HEAD(&fs->dirtylist);
+
+ /* The logical drive must be mounted. */
+ /* Following code attempts to mount a volume. (analyze BPB and initialize the fs object) */
+
+ fs->fs_type = 0; /* Clear the file system object */
+#if _MAX_SS != 512 /* Get disk sector size (variable sector size cfg only) */
+ if (disk_ioctl(fs, GET_SECTOR_SIZE, &fs->ssize) != RES_OK)
+ return -EIO;
+#endif
+ /* Search FAT partition on the drive. Supports only generic partitionings, FDISK and SFD. */
+ fmt = check_fs(fs, bsect = 0); /* Check sector 0 if it is a VBR */
+ if (fmt)
+ return fmt; /* No FAT volume is found */
+
+ /* Following code initializes the file system object */
+
+ /* (BPB_BytsPerSec must be equal to the physical sector size) */
+ if (LD_WORD(fs->win+BPB_BytsPerSec) != SS(fs))
+ return -EINVAL;
+
+ /* Number of sectors per FAT */
+ fasize = LD_WORD(fs->win+BPB_FATSz16);
+ if (!fasize)
+ fasize = LD_DWORD(fs->win+BPB_FATSz32);
+ fs->fsize = fasize;
+
+ /* Number of FAT copies */
+ fs->n_fats = b = fs->win[BPB_NumFATs];
+ if (b != 1 && b != 2)
+ return -EINVAL; /* (Must be 1 or 2) */
+
+ /* Number of sectors for FAT area */
+ fasize *= b;
+
+ /* Number of sectors per cluster */
+ fs->csize = b = fs->win[BPB_SecPerClus];
+ if (!b || (b & (b - 1)))
+ return -EINVAL; /* (Must be power of 2) */
+
+ /* Number of root directory entries */
+ fs->n_rootdir = LD_WORD(fs->win+BPB_RootEntCnt);
+ if (fs->n_rootdir % (SS(fs) / SZ_DIR))
+ return -EINVAL; /* (BPB_RootEntCnt must be sector aligned) */
+
+ /* Number of sectors on the volume */
+ tsect = LD_WORD(fs->win+BPB_TotSec16);
+ if (!tsect) tsect = LD_DWORD(fs->win+BPB_TotSec32);
+
+ /* Number of reserved sectors */
+ nrsv = LD_WORD(fs->win+BPB_RsvdSecCnt);
+ if (!nrsv)
+ return -EINVAL; /* (BPB_RsvdSecCnt must not be 0) */
+
+ /* Determine the FAT sub type */
+ /* RSV+FAT+FF_DIR */
+ sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIR);
+ if (tsect < sysect)
+ return -EINVAL; /* (Invalid volume size) */
+
+ /* Number of clusters */
+ nclst = (tsect - sysect) / fs->csize;
+ if (!nclst)
+ return -EINVAL; /* (Invalid volume size) */
+ fmt = FS_FAT12;
+ if (nclst >= MIN_FAT16)
+ fmt = FS_FAT16;
+ if (nclst >= MIN_FAT32)
+ fmt = FS_FAT32;
+
+ /* Boundaries and Limits */
+ /* Number of FAT entries */
+ fs->n_fatent = nclst + 2;
+ /* Data start sector */
+ fs->database = bsect + sysect;
+ /* FAT start sector */
+ fs->fatbase = bsect + nrsv;
+ if (fmt == FS_FAT32) {
+ if (fs->n_rootdir)
+ return -EINVAL; /* (BPB_RootEntCnt must be 0) */
+ /* Root directory start cluster */
+ fs->dirbase = LD_DWORD(fs->win+BPB_RootClus);
+ /* (Required FAT size) */
+ szbfat = fs->n_fatent * 4;
+ } else {
+ if (!fs->n_rootdir)
+ return -EINVAL;/* (BPB_RootEntCnt must not be 0) */
+ /* Root directory start sector */
+ fs->dirbase = fs->fatbase + fasize;
+ /* (Required FAT size) */
+ szbfat = (fmt == FS_FAT16) ?
+ fs->n_fatent * 2 : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
+ }
+ /* (BPB_FATSz must not be less than required) */
+ if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs))
+ return -EINVAL;
+
+#ifdef CONFIG_FS_FAT_WRITE
+ /* Initialize cluster allocation information */
+ fs->free_clust = 0xFFFFFFFF;
+ fs->last_clust = 0;
+
+ /* Get fsinfo if available */
+ if (fmt == FS_FAT32) {
+ fs->fsi_flag = 0;
+ fs->fsi_sector = bsect + LD_WORD(fs->win+BPB_FSInfo);
+ if (disk_read(fs, fs->win, fs->fsi_sector, 1) == RES_OK &&
+ LD_WORD(fs->win+BS_55AA) == 0xAA55 &&
+ LD_DWORD(fs->win+FSI_LeadSig) == 0x41615252 &&
+ LD_DWORD(fs->win+FSI_StrucSig) == 0x61417272) {
+ fs->last_clust = LD_DWORD(fs->win+FSI_Nxt_Free);
+ fs->free_clust = LD_DWORD(fs->win+FSI_Free_Count);
+ }
+ }
+#endif
+ fs->fs_type = fmt; /* FAT sub-type */
+ fs->winsect = 0; /* Invalidate sector cache */
+ fs->wflag = 0;
+
+ return 0;
+}
+
+/*
+ * Mount/Unmount a Logical Drive
+ */
+int f_mount (
+ FATFS *fs /* Pointer to new file system object (NULL for unmount)*/
+)
+{
+ fs->fs_type = 0; /* Clear new fs object */
+
+ chk_mounted(fs, 0);
+
+ return 0;
+}
+
+/*
+ * Open or Create a File
+ */
+int f_open (
+ FATFS *fatfs,
+ FIL *fp, /* Pointer to the blank file object */
+ const TCHAR *path, /* Pointer to the file name */
+ BYTE mode /* Access mode and file open mode flags */
+)
+{
+ int res = 0;
+ FF_DIR dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+
+ fp->fs = 0; /* Clear file object */
+
+#ifdef CONFIG_FS_FAT_WRITE
+ mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
+ dj.fs = fatfs;
+#else
+ mode &= FA_READ;
+ dj.fs = fatfs;
+#endif
+ INIT_BUF(dj);
+ if (res == 0)
+ res = follow_path(&dj, path); /* Follow the file path */
+ dir = dj.dir;
+
+#ifdef CONFIG_FS_FAT_WRITE /* R/W configuration */
+ if (res == 0) {
+ if (!dir) /* Current dir itself */
+ res = -EISDIR;
+ }
+ /* Create or Open a file */
+ if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
+ DWORD dw, cl;
+
+ if (res != 0) { /* No file, create new */
+ if (res == -ENOENT) /* There is no file to open, create a new entry */
+ res = dir_register(&dj);
+ mode |= FA_CREATE_ALWAYS; /* File is created */
+ dir = dj.dir; /* New entry */
+ } else { /* Any object is already existing */
+ if (dir[DIR_Attr] & AM_RDO) {
+ res = -EROFS;
+ } else if (dir[DIR_Attr] & AM_DIR) { /* Cannot overwrite it (R/O or FF_DIR) */
+ res = -EISDIR;
+ } else {
+ if (mode & FA_CREATE_NEW) /* Cannot create as new file */
+ res = -EEXIST;
+ }
+ }
+ if (res == 0 && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
+ dw = get_fattime(); /* Created time */
+ ST_DWORD(dir+DIR_CrtTime, dw);
+ dir[DIR_Attr] = 0; /* Reset attribute */
+ ST_DWORD(dir+DIR_FileSize, 0); /* size = 0 */
+ cl = LD_CLUST(dir); /* Get start cluster */
+ ST_CLUST(dir, 0); /* cluster = 0 */
+ dj.fs->wflag = 1;
+ if (cl) { /* Remove the cluster chain if exist */
+ dw = dj.fs->winsect;
+ res = remove_chain(dj.fs, cl);
+ if (res == 0) {
+ dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
+ res = move_window(dj.fs, dw);
+ }
+ }
+ }
+ } else { /* Open an existing file */
+ if (res == 0) { /* Follow succeeded */
+ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
+ res = -EISDIR;
+ } else {
+ if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
+ res = -EROFS;
+ }
+ }
+ }
+ if (res == 0) {
+ if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
+ mode |= FA__WRITTEN;
+ fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
+ fp->dir_ptr = dir;
+ }
+
+#else /* R/O configuration */
+ if (res == 0) { /* Follow succeeded */
+ if (!dir) { /* Current dir itself */
+ res = -EISDIR;
+ } else {
+ if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
+ res = -EISDIR;
+ }
+ }
+#endif
+ FREE_BUF();
+
+ if (res == 0) {
+ fp->flag = mode; /* File access mode */
+ fp->sclust = LD_CLUST(dir); /* File start cluster */
+ fp->fsize = LD_DWORD(dir+DIR_FileSize); /* File size */
+ fp->fptr = 0; /* File pointer */
+ fp->dsect = 0;
+ fp->fs = dj.fs;
+ }
+
+ return res;
+}
+
+
+
+
+/*
+ * Read File
+ */
+int f_read (
+ FIL *fp, /* Pointer to the file object */
+ void *buff, /* Pointer to data buffer */
+ UINT btr, /* Number of bytes to read */
+ UINT *br /* Pointer to number of bytes read */
+)
+{
+ DWORD clst, sect, remain;
+ UINT rcnt, cc;
+ BYTE csect, *rbuff = buff;
+
+ *br = 0; /* Initialize byte counter */
+
+ if (fp->flag & FA__ERROR) /* Aborted file? */
+ return -ERESTARTSYS;
+ if (!(fp->flag & FA_READ)) /* Check access mode */
+ return -EROFS;
+ remain = fp->fsize - fp->fptr;
+ if (btr > remain)
+ btr = (UINT)remain; /* Truncate btr by remaining bytes */
+
+ /* Repeat until all data read */
+ for ( ; btr; rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
+ if ((fp->fptr % SS(fp->fs)) == 0) { /* On the sector boundary? */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
+ if (!csect) { /* On the cluster boundary? */
+ if (fp->fptr == 0) { /* On the top of the file? */
+ clst = fp->sclust; /* Follow from the origin */
+ } else { /* Middle or end of the file */
+ clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */
+ }
+ if (clst < 2)
+ ABORT(fp->fs, -ERESTARTSYS);
+ if (clst == 0xFFFFFFFF)
+ ABORT(fp->fs, -EIO);
+ fp->clust = clst; /* Update current cluster */
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect)
+ ABORT(fp->fs, -ERESTARTSYS);
+ sect += csect;
+ cc = btr / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) { /* Read maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_read(fp->fs, rbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, -EIO);
+#if defined CONFIG_FS_FAT_WRITE
+ /* Replace one of the read sectors with cached data if it contains a dirty sector */
+ if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
+ memcpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
+#endif
+ rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+ if (fp->dsect != sect) { /* Load data sector if not in cache */
+#ifdef CONFIG_FS_FAT_WRITE
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, -EIO);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, -EIO);
+ }
+ fp->dsect = sect;
+ }
+ rcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
+ if (rcnt > btr)
+ rcnt = btr;
+ memcpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
+ }
+
+ return 0;
+}
+
+
+
+
+#ifdef CONFIG_FS_FAT_WRITE
+/*
+ * Write File
+ */
+int f_write (
+ FIL *fp, /* Pointer to the file object */
+ const void *buff, /* Pointer to the data to be written */
+ UINT btw, /* Number of bytes to write */
+ UINT *bw /* Pointer to number of bytes written */
+)
+{
+ DWORD clst, sect;
+ UINT wcnt, cc;
+ const BYTE *wbuff = buff;
+ BYTE csect;
+
+ *bw = 0; /* Initialize byte counter */
+
+ if (fp->flag & FA__ERROR) /* Aborted file? */
+ return -ERESTARTSYS;
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ return -EROFS;
+ if ((DWORD)(fp->fsize + btw) < fp->fsize)
+ btw = 0; /* File size cannot reach 4GB */
+
+ /* Repeat until all data written */
+ for ( ; btw; wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
+ /* On the sector boundary? */
+ if ((fp->fptr % SS(fp->fs)) == 0) {
+ /* Sector offset in the cluster */
+ csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1));
+ /* On the cluster boundary? */
+ if (!csect) {
+ /* On the top of the file? */
+ if (fp->fptr == 0) {
+ clst = fp->sclust; /* Follow from the origin */
+ if (clst == 0) /* When no cluster is allocated, */
+ /* Create a new cluster chain */
+ fp->sclust = clst = create_chain(fp->fs, 0);
+ } else {
+ /* Middle or end of the file */
+ /* Follow or stretch cluster chain on the FAT */
+ clst = create_chain(fp->fs, fp->clust);
+ }
+ if (clst == 0)
+ break; /* Could not allocate a new cluster (disk full) */
+ if (clst == 1)
+ ABORT(fp->fs, -ERESTARTSYS);
+ if (clst == 0xFFFFFFFF)
+ ABORT(fp->fs, -EIO);
+ fp->clust = clst; /* Update current cluster */
+ }
+ if (fp->flag & FA__DIRTY) { /* Write-back sector cache */
+ printf("wr sector cache\n");
+ if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, -EIO);
+ fp->flag &= ~FA__DIRTY;
+ }
+ sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
+ if (!sect)
+ ABORT(fp->fs, -ERESTARTSYS);
+ sect += csect;
+ cc = btw / SS(fp->fs); /* When remaining bytes >= sector size, */
+ if (cc) {
+ /* Write maximum contiguous sectors directly */
+ if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
+ cc = fp->fs->csize - csect;
+ if (disk_write(fp->fs, wbuff, sect, (BYTE)cc) != RES_OK)
+ ABORT(fp->fs, -EIO);
+ if (fp->dsect - sect < cc) {
+ /* Refill sector cache if it gets invalidated by the direct write */
+ memcpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
+ fp->flag &= ~FA__DIRTY;
+ }
+ wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
+ continue;
+ }
+ if (fp->dsect != sect) {
+ /* Fill sector cache with file data */
+ if (fp->fptr < fp->fsize &&
+ disk_read(fp->fs, fp->buf, sect, 1) != RES_OK)
+ ABORT(fp->fs, -EIO);
+ }
+
+ fp->dsect = sect;
+ }
+ /* Put partial sector into file I/O buffer */
+ wcnt = SS(fp->fs) - (fp->fptr % SS(fp->fs));
+ if (wcnt > btw)
+ wcnt = btw;
+ memcpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
+ fp->flag |= FA__DIRTY;
+ }
+
+ if (fp->fptr > fp->fsize)
+ fp->fsize = fp->fptr; /* Update file size if needed */
+
+ fp->flag |= FA__WRITTEN; /* Set file change flag */
+
+ return 0;
+}
+
+/*
+ * Synchronize the File Object
+ */
+int f_sync (
+ FIL *fp /* Pointer to the file object */
+)
+{
+ int res;
+ DWORD tim;
+ BYTE *dir;
+
+ /* Has the file been written? */
+ if (!(fp->flag & FA__WRITTEN))
+ return 0;
+
+ if (fp->flag & FA__DIRTY) {
+ if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK)
+ return -EIO;
+ fp->flag &= ~FA__DIRTY;
+ }
+
+ /* Update the directory entry */
+ res = move_window(fp->fs, fp->dir_sect);
+ if (res)
+ return res;
+
+ dir = fp->dir_ptr;
+ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
+ ST_DWORD(dir+DIR_FileSize, fp->fsize); /* Update file size */
+ ST_CLUST(dir, fp->sclust); /* Update start cluster */
+ tim = get_fattime(); /* Update updated time */
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ fp->flag &= ~FA__WRITTEN;
+ fp->fs->wflag = 1;
+ res = sync(fp->fs);
+
+ flush_dirty_fat(fp->fs);
+
+ return res;
+}
+
+#endif /* CONFIG_FS_FAT_WRITE */
+
+/*
+ * Close File
+ */
+int f_close (
+ FIL *fp /* Pointer to the file object to be closed */
+)
+{
+#ifndef CONFIG_FS_FAT_WRITE
+ fp->fs = 0; /* Discard file object */
+ return 0;
+#else
+ int res;
+
+ /* Flush cached data */
+ res = f_sync(fp);
+ if (res == 0)
+ fp->fs = 0; /* Discard file object */
+ return res;
+#endif
+}
+
+/*
+ * Seek File R/W Pointer
+ */
+int f_lseek (
+ FIL *fp, /* Pointer to the file object */
+ DWORD ofs /* File pointer from top of file */
+)
+{
+ DWORD clst, bcs, nsect, ifptr;
+ int res = 0;
+
+ if (fp->flag & FA__ERROR) /* Check abort flag */
+ return -ERESTARTSYS;
+
+ if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
+#ifdef CONFIG_FS_FAT_WRITE
+ && !(fp->flag & FA_WRITE)
+#endif
+ ) ofs = fp->fsize;
+
+ ifptr = fp->fptr;
+ fp->fptr = nsect = 0;
+ if (ofs) {
+ bcs = (DWORD)fp->fs->csize * SS(fp->fs); /* Cluster size (byte) */
+ if (ifptr > 0 &&
+ (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
+ fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
+ ofs -= fp->fptr;
+ clst = fp->clust;
+ } else { /* When seek to back cluster, */
+ clst = fp->sclust; /* start from the first cluster */
+#ifdef CONFIG_FS_FAT_WRITE
+ if (clst == 0) { /* If no cluster chain, create a new chain */
+ clst = create_chain(fp->fs, 0);
+ if (clst == 1)
+ ABORT(fp->fs, -ERESTARTSYS);
+ if (clst == 0xFFFFFFFF)
+ ABORT(fp->fs, -EIO);
+ fp->sclust = clst;
+ }
+#endif
+ fp->clust = clst;
+ }
+ if (clst != 0) {
+ while (ofs > bcs) { /* Cluster following loop */
+#ifdef CONFIG_FS_FAT_WRITE
+ if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
+ /* Force stretch if in write mode */
+ clst = create_chain(fp->fs, clst);
+ /* When disk gets full, clip file size */
+ if (clst == 0) {
+ ofs = bcs;
+ break;
+ }
+ } else
+#endif
+ /* Follow cluster chain if not in write mode */
+ clst = get_fat(fp->fs, clst);
+ if (clst == 0xFFFFFFFF)
+ ABORT(fp->fs, -EIO);
+ if (clst <= 1 || clst >= fp->fs->n_fatent)
+ ABORT(fp->fs, -ERESTARTSYS);
+ fp->clust = clst;
+ fp->fptr += bcs;
+ ofs -= bcs;
+ }
+ fp->fptr += ofs;
+ if (ofs % SS(fp->fs)) {
+ nsect = clust2sect(fp->fs, clst); /* Current sector */
+ if (!nsect)
+ ABORT(fp->fs, -ERESTARTSYS);
+ nsect += ofs / SS(fp->fs);
+ }
+ }
+ }
+ if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */
+#ifdef CONFIG_FS_FAT_WRITE
+ if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fp->fs, fp->buf, fp->dsect, 1) != RES_OK)
+ ABORT(fp->fs, -EIO);
+ fp->flag &= ~FA__DIRTY;
+ }
+#endif
+ if (disk_read(fp->fs, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */
+ ABORT(fp->fs, -EIO);
+ fp->dsect = nsect;
+ }
+#ifdef CONFIG_FS_FAT_WRITE
+ if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */
+ fp->fsize = fp->fptr;
+ fp->flag |= FA__WRITTEN;
+ }
+#endif
+
+ return res;
+}
+
+/*
+ * Create a Directroy Object
+ */
+int f_opendir (
+ FATFS *fatfs,
+ FF_DIR *dj, /* Pointer to directory object to create */
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ int res;
+ DEF_NAMEBUF;
+
+ dj->fs = fatfs;
+
+ INIT_BUF(*dj);
+ res = follow_path(dj, path); /* Follow the path to the directory */
+ FREE_BUF();
+
+ if (res)
+ return res;
+
+ if (dj->dir) {
+ /* It is not the root dir */
+ if (dj->dir[DIR_Attr] & AM_DIR) {
+ /* The object is a directory */
+ dj->sclust = LD_CLUST(dj->dir);
+ } else {
+ /* The object is not a directory */
+ return -ENOTDIR;
+ }
+ }
+
+ res = dir_sdi(dj, 0); /* Rewind dir */
+
+ return res;
+}
+
+
+
+
+/*
+ * Read Directory Entry in Sequense
+ */
+int f_readdir (
+ FF_DIR *dj, /* Pointer to the open directory object */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ int res;
+ DEF_NAMEBUF;
+
+ if (!fno) {
+ res = dir_sdi(dj, 0); /* Rewind the directory object */
+ return res;
+ }
+
+ INIT_BUF(*dj);
+ res = dir_read(dj); /* Read an directory item */
+ if (res == -ENOENT) { /* Reached end of dir */
+ dj->sect = 0;
+ res = 0;
+ goto out;
+ }
+
+ /* A valid entry is found */
+ get_fileinfo(dj, fno); /* Get the object information */
+ res = dir_next(dj, 0); /* Increment index for next */
+ if (res == -ENOENT) {
+ dj->sect = 0;
+ res = 0;
+ }
+out:
+ FREE_BUF();
+
+ return res;
+}
+
+/*
+ * Get File Status
+ */
+int f_stat (
+ FATFS *fatfs,
+ const TCHAR *path, /* Pointer to the file path */
+ FILINFO *fno /* Pointer to file information to return */
+)
+{
+ int res;
+ FF_DIR dj;
+ DEF_NAMEBUF;
+
+ dj.fs = fatfs;
+
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == 0) { /* Follow completed */
+ if (dj.dir) /* Found an object */
+ get_fileinfo(&dj, fno);
+ else /* It is root dir */
+ res = -ENOENT;
+ }
+ FREE_BUF();
+
+ return res;
+}
+
+#ifdef CONFIG_FS_FAT_WRITE
+/*
+ * Get Number of Free Clusters
+ */
+int f_getfree (
+ FATFS *fatfs,
+ const TCHAR *path, /* Pointer to the logical drive number (root dir) */
+ DWORD *nclst /* Pointer to the variable to return number of free clusters */
+)
+{
+ int res = 0;
+ DWORD n, clst, sect, stat;
+ UINT i;
+ BYTE fat, *p;
+
+
+ /* If free_clust is valid, return it without full cluster scan */
+ if (fatfs->free_clust <= fatfs->n_fatent - 2) {
+ *nclst = fatfs->free_clust;
+ return 0;
+ }
+
+ /* Get number of free clusters */
+ fat = fatfs->fs_type;
+ n = 0;
+ if (fat == FS_FAT12) {
+ clst = 2;
+ do {
+ stat = get_fat(fatfs, clst);
+ if (stat == 0xFFFFFFFF) {
+ res = -EIO;
+ break;
+ }
+ if (stat == 1) {
+ res = -ERESTARTSYS;
+ break;
+ }
+ if (stat == 0) n++;
+ } while (++clst < fatfs->n_fatent);
+ } else {
+ clst = fatfs->n_fatent;
+ sect = fatfs->fatbase;
+ i = 0; p = 0;
+ do {
+ if (!i) {
+ res = move_window(fatfs, sect++);
+ if (res != 0) break;
+ p = fatfs->win;
+ i = SS(fatfs);
+ }
+ if (fat == FS_FAT16) {
+ if (LD_WORD(p) == 0) n++;
+ p += 2; i -= 2;
+ } else {
+ if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++;
+ p += 4; i -= 4;
+ }
+ } while (--clst);
+ }
+ fatfs->free_clust = n;
+ if (fat == FS_FAT32)
+ fatfs->fsi_flag = 1;
+ *nclst = n;
+
+ return res;
+}
+
+/*
+ * Truncate File
+ */
+int f_truncate (
+ FIL *fp /* Pointer to the file object */
+)
+{
+ int res = 0;
+ DWORD ncl;
+
+ if (fp->flag & FA__ERROR) { /* Check abort flag */
+ return -ERESTARTSYS;
+ } else {
+ if (!(fp->flag & FA_WRITE)) /* Check access mode */
+ return -EROFS;
+ }
+
+ if (fp->fsize <= fp->fptr)
+ return 0;
+
+ fp->fsize = fp->fptr; /* Set file size to current R/W point */
+ fp->flag |= FA__WRITTEN;
+ if (fp->fptr == 0) {
+ /* When set file size to zero, remove entire cluster chain */
+ res = remove_chain(fp->fs, fp->sclust);
+ fp->sclust = 0;
+ } else {
+ /* When truncate a part of the file, remove remaining clusters */
+ ncl = get_fat(fp->fs, fp->clust);
+ if (ncl == 0xFFFFFFFF)
+ return -EIO;
+ if (ncl == 1)
+ return -ERESTARTSYS;
+ if (ncl < fp->fs->n_fatent) {
+ res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
+ if (res)
+ return res;
+ res = remove_chain(fp->fs, ncl);
+ }
+ }
+
+ return res;
+}
+
+/*
+ * Delete a File or Directory
+ */
+int f_unlink (
+ FATFS *fatfs,
+ const TCHAR *path /* Pointer to the file or directory path */
+)
+{
+ int res;
+ FF_DIR dj, sdj;
+ BYTE *dir;
+ DWORD dclst;
+ DEF_NAMEBUF;
+
+ dj.fs = fatfs;
+
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res)
+ goto out;
+
+ if (dj.fn[NS] & NS_DOT) {
+ res = -EINVAL; /* Cannot remove dot entry */
+ goto out;
+ }
+
+ /* The object is accessible */
+ dir = dj.dir;
+ if (!dir) {
+ res = -EINVAL; /* Cannot remove the start directory */
+ goto out;
+ }
+
+ if (dir[DIR_Attr] & AM_RDO) {
+ res = -EROFS; /* Cannot remove R/O object */
+ goto out;
+ }
+
+ dclst = LD_CLUST(dir);
+ if (dir[DIR_Attr] & AM_DIR) { /* Is it a sub-dir? */
+ if (dclst < 2) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+ memcpy(&sdj, &dj, sizeof(FF_DIR)); /* Check if the sub-dir is empty or not */
+ sdj.sclust = dclst;
+ res = dir_sdi(&sdj, 2); /* Exclude dot entries */
+ if (res)
+ goto out;
+
+ res = dir_read(&sdj);
+ if (res == 0) {
+ res = -ENOTEMPTY; /* Not empty dir */
+ goto out;
+ }
+ if (res == -ENOENT)
+ res = 0; /* Empty */
+ if (res)
+ goto out;
+ }
+
+ res = dir_remove(&dj); /* Remove the directory entry */
+ if (res)
+ goto out;
+
+ if (dclst) {
+ /* Remove the cluster chain if exist */
+ res = remove_chain(dj.fs, dclst);
+ if (res)
+ goto out;
+ }
+
+ res = sync(dj.fs);
+
+out:
+ FREE_BUF();
+
+ return res;
+}
+
+/*
+ * Create a Directory
+ */
+int f_mkdir (
+ FATFS *fatfs,
+ const TCHAR *path /* Pointer to the directory path */
+)
+{
+ int res;
+ FF_DIR dj;
+ BYTE *dir, n;
+ DWORD dsc, dcl, pcl, tim = get_fattime();
+ DEF_NAMEBUF;
+
+ dj.fs = fatfs;
+
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ if (res == 0) {
+ res = -EEXIST; /* Any object with same name is already existing */
+ goto out;
+ }
+
+ if (res != -ENOENT)
+ goto out;
+
+ dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
+ if (dcl == 0) {
+ res = -ENOSPC; /* No space to allocate a new cluster */
+ goto out;
+ }
+ if (dcl == 1) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ if (dcl == 0xFFFFFFFF) {
+ res = -EIO;
+ goto out;
+ }
+
+ /* Flush FAT */
+ res = move_window(dj.fs, 0);
+ if (res)
+ goto out;
+
+ /* Initialize the new directory table */
+ dsc = clust2sect(dj.fs, dcl);
+ dir = dj.fs->win;
+ memset(dir, 0, SS(dj.fs));
+ memset(dir+DIR_Name, ' ', 8+3); /* Create "." entry */
+ dir[DIR_Name] = '.';
+ dir[DIR_Attr] = AM_DIR;
+ ST_DWORD(dir+DIR_WrtTime, tim);
+ ST_CLUST(dir, dcl);
+ memcpy(dir+SZ_DIR, dir, SZ_DIR); /* Create ".." entry */
+ dir[33] = '.'; pcl = dj.sclust;
+ if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
+ pcl = 0;
+ ST_CLUST(dir+SZ_DIR, pcl);
+ for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
+ dj.fs->winsect = dsc++;
+ dj.fs->wflag = 1;
+ res = move_window(dj.fs, 0);
+ if (res != 0)
+ goto out;
+ memset(dir, 0, SS(dj.fs));
+ }
+
+ res = dir_register(&dj); /* Register the object to the directoy */
+ if (res) {
+ remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
+ goto out;
+ }
+
+ dir = dj.dir;
+ dir[DIR_Attr] = AM_DIR; /* Attribute */
+ ST_DWORD(dir+DIR_WrtTime, tim); /* Created time */
+ ST_CLUST(dir, dcl); /* Table start cluster */
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+
+out:
+ FREE_BUF();
+
+ return res;
+}
+
+/*
+ * Change Attribute
+ */
+int f_chmod (
+ FATFS *fatfs,
+ const TCHAR *path, /* Pointer to the file path */
+ BYTE value, /* Attribute bits */
+ BYTE mask /* Attribute mask to change */
+)
+{
+ int res;
+ FF_DIR dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+ dj.fs = fatfs;
+
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (res == 0 && (dj.fn[NS] & NS_DOT))
+ res = -ENOENT;
+ if (res == 0) {
+ dir = dj.dir;
+ if (!dir) { /* Is it a root directory? */
+ res = -EINVAL;
+ } else { /* File or sub directory */
+ mask &= AM_RDO|AM_HID|AM_SYS|AM_ARC; /* Valid attribute mask */
+ dir[DIR_Attr] = (value & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+
+ return res;
+}
+
+/*
+ * Change Timestamp
+ */
+int f_utime (
+ FATFS *fatfs,
+ const TCHAR *path, /* Pointer to the file/directory name */
+ const FILINFO *fno /* Pointer to the time stamp to be set */
+)
+{
+ int res;
+ FF_DIR dj;
+ BYTE *dir;
+ DEF_NAMEBUF;
+
+ dj.fs = fatfs;
+
+ INIT_BUF(dj);
+ res = follow_path(&dj, path); /* Follow the file path */
+ FREE_BUF();
+ if (res == 0 && (dj.fn[NS] & NS_DOT))
+ res = -ENOENT;
+ if (res == 0) {
+ dir = dj.dir;
+ if (!dir) { /* Root directory */
+ res = -EINVAL;
+ } else { /* File or sub-directory */
+ ST_WORD(dir+DIR_WrtTime, fno->ftime);
+ ST_WORD(dir+DIR_WrtDate, fno->fdate);
+ dj.fs->wflag = 1;
+ res = sync(dj.fs);
+ }
+ }
+
+ return res;
+}
+
+/*
+ * Rename File/Directory
+ */
+int f_rename (
+ FATFS *fatfs,
+ const TCHAR *path_old, /* Pointer to the old name */
+ const TCHAR *path_new /* Pointer to the new name */
+)
+{
+ int res;
+ FF_DIR djo, djn;
+ BYTE buf[21], *dir;
+ DWORD dw;
+ DEF_NAMEBUF;
+
+ djo.fs = fatfs;
+
+ djn.fs = djo.fs;
+ INIT_BUF(djo);
+ res = follow_path(&djo, path_old); /* Check old object */
+ if (res == 0 && (djo.fn[NS] & NS_DOT)) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if (res)
+ goto out;
+
+ /* Old object is found */
+ if (!djo.dir) { /* Is root dir? */
+ res = -EINVAL;
+ goto out;
+ }
+
+ memcpy(buf, djo.dir+DIR_Attr, 21); /* Save the object information except for name */
+ memcpy(&djn, &djo, sizeof(FF_DIR)); /* Check new object */
+ res = follow_path(&djn, path_new);
+ if (res == 0) {
+ res = -EEXIST; /* The new object name is already existing */
+ goto out;
+ }
+
+ if (res != -ENOENT)
+ goto out;
+
+ /* It ia a valid path and no name collision */
+
+ res = dir_register(&djn); /* Register the new entry */
+ if (res)
+ goto out;
+
+ dir = djn.dir; /* Copy object information except for name */
+ memcpy(dir+13, buf+2, 19);
+ dir[DIR_Attr] = buf[0] | AM_ARC;
+ djo.fs->wflag = 1;
+ /* Update .. entry in the directory if needed */
+ if (djo.sclust != djn.sclust && (dir[DIR_Attr] & AM_DIR)) {
+ dw = clust2sect(djn.fs, LD_CLUST(dir));
+ if (!dw) {
+ res = -ERESTARTSYS;
+ goto out;
+ }
+
+ res = move_window(djn.fs, dw);
+ if (res)
+ goto out;
+ dir = djn.fs->win+SZ_DIR; /* .. entry */
+ if (dir[1] == '.') {
+ dw = (djn.fs->fs_type == FS_FAT32 && djn.sclust == djn.fs->dirbase) ? 0 : djn.sclust;
+ ST_CLUST(dir, dw);
+ djn.fs->wflag = 1;
+ }
+ }
+
+ res = dir_remove(&djo); /* Remove old entry */
+ if (res)
+ goto out;
+
+ res = sync(djo.fs);
+
+out:
+ FREE_BUF();
+
+ return res;
+}
+#endif /* CONFIG_FS_FAT_WRITE */
diff --git a/fs/fat/ff.h b/fs/fat/ff.h
new file mode 100644
index 00000000..e86ca3aa
--- /dev/null
+++ b/fs/fat/ff.h
@@ -0,0 +1,239 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module include file R0.08b (C)ChaN, 2011
+/----------------------------------------------------------------------------/
+/ FatFs module is a generic FAT file system module for small embedded systems.
+/ This is a free software that opened for education, research and commercial
+/ developments under license policy of following trems.
+/
+/ Copyright (C) 2011, ChaN, all right reserved.
+/
+/ * The FatFs module is a free software and there is NO WARRANTY.
+/ * No restriction on use. You can use, modify and redistribute it for
+/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
+/ * Redistributions of source code must retain the above copyright notice.
+/
+/----------------------------------------------------------------------------*/
+
+#ifndef _FATFS
+#define _FATFS 8237 /* Revision ID */
+
+#include <asm/unaligned.h>
+#include <linux/list.h>
+
+#include "integer.h" /* Basic integer types */
+#include "ffconf.h" /* FatFs configuration options */
+
+#if _FATFS != _FFCONF
+#error Wrong configuration file (ffconf.h).
+#endif
+
+/* Type of path name strings on FatFs API */
+
+#if _LFN_UNICODE /* Unicode string */
+#ifndef CONFIG_FS_FAT_LFN
+#error _LFN_UNICODE must be 0 in non-LFN cfg.
+#endif
+#ifndef _INC_TCHAR
+typedef WCHAR TCHAR;
+#define _T(x) L ## x
+#define _TEXT(x) L ## x
+#endif
+
+#else /* ANSI/OEM string */
+#ifndef _INC_TCHAR
+typedef char TCHAR;
+#define _T(x) x
+#define _TEXT(x) x
+#endif
+
+#endif
+
+
+
+/* File system object structure (FATFS) */
+
+typedef struct {
+ BYTE fs_type; /* FAT sub-type (0:Not mounted) */
+ BYTE drv; /* Physical drive number */
+ BYTE csize; /* Sectors per cluster (1,2,4...128) */
+ BYTE n_fats; /* Number of FAT copies (1,2) */
+ BYTE wflag; /* win[] dirty flag (1:must be written back) */
+ BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
+ WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
+#if _MAX_SS != 512
+ WORD ssize; /* Bytes per sector (512,1024,2048,4096) */
+#endif
+#ifdef CONFIG_FS_FAT_WRITE
+ DWORD last_clust; /* Last allocated cluster */
+ DWORD free_clust; /* Number of free clusters */
+ DWORD fsi_sector; /* fsinfo sector (FAT32) */
+#endif
+ DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */
+ DWORD fsize; /* Sectors per FAT */
+ DWORD fatbase; /* FAT start sector */
+ DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
+ DWORD database; /* Data start sector */
+ DWORD winsect; /* Current sector appearing in the win[] */
+ BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
+ void *userdata; /* User data, ff core does not touch this */
+ struct list_head dirtylist;
+} FATFS;
+
+
+
+/* File object structure (FIL) */
+
+typedef struct {
+ FATFS* fs; /* Pointer to the owner file system object */
+ BYTE flag; /* File status flags */
+ BYTE pad1;
+ DWORD fptr; /* File read/write pointer (0 on file open) */
+ DWORD fsize; /* File size */
+ DWORD sclust; /* File start cluster (0 when fsize==0) */
+ DWORD clust; /* Current cluster */
+ DWORD dsect; /* Current data sector */
+#ifdef CONFIG_FS_FAT_WRITE
+ DWORD dir_sect; /* Sector containing the directory entry */
+ BYTE* dir_ptr; /* Ponter to the directory entry in the window */
+#endif
+#if _USE_FASTSEEK
+ DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */
+#endif
+#if _FS_SHARE
+ UINT lockid; /* File lock ID (index of file semaphore table) */
+#endif
+#if !_FS_TINY
+ BYTE buf[_MAX_SS]; /* File data read/write buffer */
+#endif
+} FIL;
+
+
+
+/* Directory object structure (DIR) */
+
+typedef struct {
+ FATFS* fs; /* Pointer to the owner file system object */
+ WORD index; /* Current read/write index number */
+ DWORD sclust; /* Table start cluster (0:Root dir) */
+ DWORD clust; /* Current cluster */
+ DWORD sect; /* Current sector */
+ BYTE* dir; /* Pointer to the current SFN entry in the win[] */
+ BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
+#ifdef CONFIG_FS_FAT_LFN
+ WCHAR* lfn; /* Pointer to the LFN working buffer */
+ WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
+#endif
+} FF_DIR;
+
+
+
+/* File status structure (FILINFO) */
+
+typedef struct {
+ DWORD fsize; /* File size */
+ WORD fdate; /* Last modified date */
+ WORD ftime; /* Last modified time */
+ BYTE fattrib; /* Attribute */
+ TCHAR fname[13]; /* Short file name (8.3 format) */
+#ifdef CONFIG_FS_FAT_LFN
+ TCHAR* lfname; /* Pointer to the LFN buffer */
+ UINT lfsize; /* Size of LFN buffer in TCHAR */
+#endif
+} FILINFO;
+
+/*--------------------------------------------------------------*/
+/* FatFs module application interface */
+
+int f_mount (FATFS*); /* Mount/Unmount a logical drive */
+int f_open (FATFS*, FIL*, const TCHAR*, BYTE); /* Open or create a file */
+int f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
+int f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
+int f_close (FIL*); /* Close an open file object */
+int f_opendir (FATFS*, FF_DIR*, const TCHAR*); /* Open an existing directory */
+int f_readdir (FF_DIR*, FILINFO*); /* Read a directory item */
+int f_stat (FATFS*, const TCHAR*, FILINFO*); /* Get file status */
+int f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
+int f_getfree (FATFS*, const TCHAR*, DWORD*); /* Get number of free clusters on the drive */
+int f_truncate (FIL*); /* Truncate file */
+int f_sync (FIL*); /* Flush cached data of a writing file */
+int f_unlink (FATFS*, const TCHAR*); /* Delete an existing file or directory */
+int f_mkdir (FATFS*, const TCHAR*); /* Create a new directory */
+int f_chmod (FATFS*, const TCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */
+int f_utime (FATFS*, const TCHAR*, const FILINFO*); /* Change timestamp of the file/dir */
+int f_rename (FATFS*, const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
+int f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
+int f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */
+int f_chdrive (BYTE); /* Change current drive */
+int f_chdir (const TCHAR*); /* Change current directory */
+int f_getcwd (TCHAR*, UINT); /* Get current directory */
+int f_putc (TCHAR, FIL*); /* Put a character to the file */
+int f_puts (const TCHAR*, FIL*); /* Put a string to the file */
+int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */
+TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */
+
+#ifndef EOF
+#define EOF (-1)
+#endif
+
+#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
+#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
+#define f_tell(fp) ((fp)->fptr)
+#define f_size(fp) ((fp)->fsize)
+
+/*--------------------------------------------------------------*/
+/* Additional user defined functions */
+
+/* RTC function */
+DWORD get_fattime (void);
+
+/* Unicode support functions */
+WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */
+WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */
+
+/*--------------------------------------------------------------*/
+/* Flags and offset address */
+
+
+/* File access control and file status flags (FIL.flag) */
+
+#define FA_READ 0x01
+#define FA_OPEN_EXISTING 0x00
+#define FA__ERROR 0x80
+
+#define FA_WRITE 0x02
+#define FA_CREATE_NEW 0x04
+#define FA_CREATE_ALWAYS 0x08
+#define FA_OPEN_ALWAYS 0x10
+#define FA__WRITTEN 0x20
+#define FA__DIRTY 0x40
+
+/* FAT sub type (FATFS.fs_type) */
+
+#define FS_FAT12 1
+#define FS_FAT16 2
+#define FS_FAT32 3
+
+
+/* File attribute bits for directory entry */
+
+#define AM_RDO 0x01 /* Read only */
+#define AM_HID 0x02 /* Hidden */
+#define AM_SYS 0x04 /* System */
+#define AM_VOL 0x08 /* Volume label */
+#define AM_LFN 0x0F /* LFN entry */
+#define AM_DIR 0x10 /* Directory */
+#define AM_ARC 0x20 /* Archive */
+#define AM_MASK 0x3F /* Mask of defined bits */
+
+
+/* Fast seek function */
+#define CREATE_LINKMAP 0xFFFFFFFF
+
+/* Multi-byte word access macros */
+
+#define LD_WORD(ptr) get_unaligned_le16(ptr)
+#define LD_DWORD(ptr) get_unaligned_le32(ptr)
+#define ST_WORD(ptr,val) put_unaligned_le16(val, ptr)
+#define ST_DWORD(ptr,val) put_unaligned_le32(val, ptr)
+
+#endif /* _FATFS */
diff --git a/fs/fat/ffconf.h b/fs/fat/ffconf.h
new file mode 100644
index 00000000..2f6a6c15
--- /dev/null
+++ b/fs/fat/ffconf.h
@@ -0,0 +1,145 @@
+/*---------------------------------------------------------------------------/
+/ FatFs - FAT file system module configuration file R0.08b (C)ChaN, 2011
+/----------------------------------------------------------------------------/
+/
+/ CAUTION! Do not forget to make clean the project after any changes to
+/ the configuration options.
+/
+/----------------------------------------------------------------------------*/
+#ifndef _FFCONF
+#define _FFCONF 8237 /* Revision ID */
+
+
+/*---------------------------------------------------------------------------/
+/ Function and Buffer Configurations
+/----------------------------------------------------------------------------*/
+
+#define _FS_TINY 0 /* 0:Normal or 1:Tiny */
+/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
+/ object instead of the sector buffer in the individual file object for file
+/ data transfer. This reduces memory consumption 512 bytes each file object. */
+
+#define _USE_STRFUNC 0 /* 0:Disable or 1/2:Enable */
+/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
+
+
+#define _USE_MKFS 0 /* 0:Disable or 1:Enable */
+/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
+
+
+#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */
+/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
+
+
+#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */
+/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ Locale and Namespace Configurations
+/----------------------------------------------------------------------------*/
+
+#define _CODE_PAGE 932
+/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
+/ Incorrect setting of the code page can cause a file open failure.
+/
+/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows)
+/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
+/ 949 - Korean (DBCS, OEM, Windows)
+/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
+/ 1250 - Central Europe (Windows)
+/ 1251 - Cyrillic (Windows)
+/ 1252 - Latin 1 (Windows)
+/ 1253 - Greek (Windows)
+/ 1254 - Turkish (Windows)
+/ 1255 - Hebrew (Windows)
+/ 1256 - Arabic (Windows)
+/ 1257 - Baltic (Windows)
+/ 1258 - Vietnam (OEM, Windows)
+/ 437 - U.S. (OEM)
+/ 720 - Arabic (OEM)
+/ 737 - Greek (OEM)
+/ 775 - Baltic (OEM)
+/ 850 - Multilingual Latin 1 (OEM)
+/ 858 - Multilingual Latin 1 + Euro (OEM)
+/ 852 - Latin 2 (OEM)
+/ 855 - Cyrillic (OEM)
+/ 866 - Russian (OEM)
+/ 857 - Turkish (OEM)
+/ 862 - Hebrew (OEM)
+/ 874 - Thai (OEM, Windows)
+/ 1 - ASCII only (Valid for non LFN cfg.)
+*/
+
+#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
+
+#define ff_memalloc xzalloc
+#define ff_memfree free
+/* The _USE_LFN option switches the LFN support.
+/
+/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
+/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
+/ 2: Enable LFN with dynamic working buffer on the STACK.
+/ 3: Enable LFN with dynamic working buffer on the HEAP.
+/
+/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
+/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
+/ to the project. When enable to use heap, memory control functions
+/ ff_memalloc() and ff_memfree() must be added to the project. */
+
+
+#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
+/* To switch the character code set on FatFs API to Unicode,
+/ enable LFN feature and set _LFN_UNICODE to 1. */
+
+/*---------------------------------------------------------------------------/
+/ Physical Drive Configurations
+/----------------------------------------------------------------------------*/
+
+#define _VOLUMES 1
+/* Number of volumes (logical drives) to be used. */
+
+
+#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
+/* Maximum sector size to be handled.
+/ Always set 512 for memory card and hard disk but a larger value may be
+/ required for on-board flash memory, floppy disk and optical disk.
+/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size
+/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
+
+#define _USE_ERASE 0 /* 0:Disable or 1:Enable */
+/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
+/ should be added to the disk_ioctl functio. */
+
+
+
+/*---------------------------------------------------------------------------/
+/ System Configurations
+/----------------------------------------------------------------------------*/
+
+#define _WORD_ACCESS 0 /* 0 or 1 */
+/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
+/ option defines which access method is used to the word data on the FAT volume.
+/
+/ 0: Byte-by-byte access.
+/ 1: Word access. Do not choose this unless following condition is met.
+/
+/ When the byte order on the memory is big-endian or address miss-aligned word
+/ access results incorrect behavior, the _WORD_ACCESS must be set to 0.
+/ If it is not the case, the value can also be set to 1 to improve the
+/ performance and code size. */
+
+
+/* A header file that defines sync object types on the O/S, such as
+/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
+
+#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
+#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
+
+#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */
+/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
+ defines how many files can be opened simultaneously. */
+
+
+#endif /* _FFCONFIG */
diff --git a/fs/fat/integer.h b/fs/fat/integer.h
new file mode 100644
index 00000000..04956aa7
--- /dev/null
+++ b/fs/fat/integer.h
@@ -0,0 +1,28 @@
+/*-------------------------------------------*/
+/* Integer type definitions for FatFs module */
+/*-------------------------------------------*/
+
+#ifndef _INTEGER
+#define _INTEGER
+
+/* These types must be 16-bit, 32-bit or larger integer */
+typedef int INT;
+typedef unsigned int UINT;
+
+/* These types must be 8-bit integer */
+typedef char CHAR;
+typedef unsigned char UCHAR;
+typedef unsigned char BYTE;
+
+/* These types must be 16-bit integer */
+typedef short SHORT;
+typedef unsigned short USHORT;
+typedef unsigned short WORD;
+typedef unsigned short WCHAR;
+
+/* These types must be 32-bit integer */
+typedef long LONG;
+typedef unsigned long ULONG;
+typedef unsigned long DWORD;
+
+#endif
diff --git a/fs/fs.c b/fs/fs.c
index f684d455..e71d5a29 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -30,6 +30,7 @@
#include <xfuncs.h>
#include <init.h>
#include <module.h>
+#include <libbb.h>
void *read_file(const char *filename, size_t *size)
{
@@ -536,6 +537,26 @@ ssize_t write(int fd, const void *buf, size_t count)
}
EXPORT_SYMBOL(write);
+int flush(int fd)
+{
+ struct device_d *dev;
+ struct fs_driver_d *fsdrv;
+ FILE *f = &files[fd];
+
+ if (check_fd(fd))
+ return errno;
+
+ dev = f->dev;
+
+ fsdrv = (struct fs_driver_d *)dev->driver->type_data;
+ if (fsdrv->flush)
+ errno = fsdrv->flush(dev, f);
+ else
+ errno = 0;
+
+ return errno;
+}
+
off_t lseek(int fildes, off_t offset, int whence)
{
struct device_d *dev;
@@ -759,25 +780,22 @@ int mount(const char *device, const char *fsname, const char *_path)
if (!device) {
printf("need a device for driver %s\n", fsname);
errno = -ENODEV;
- free(fsdev);
- goto out;
+ goto out1;
}
}
- sprintf(fsdev->dev.name, "%s", fsname);
+ safe_strncpy(fsdev->dev.name, fsname, MAX_DRIVER_NAME);
fsdev->dev.type_data = fsdev;
fsdev->dev.id = get_free_deviceid(fsdev->dev.name);
if ((ret = register_device(&fsdev->dev))) {
- free(fsdev);
errno = ret;
- goto out;
+ goto out1;
}
if (!fsdev->dev.driver) {
/* driver didn't accept the device. Bail out */
- free(fsdev);
errno = -EINVAL;
- goto out;
+ goto out2;
}
if (parent_device)
@@ -787,7 +805,7 @@ int mount(const char *device, const char *fsname, const char *_path)
/* add mtab entry */
entry = &fsdev->mtab;
- sprintf(entry->path, "%s", path);
+ safe_strncpy(entry->path, path, PATH_MAX);
entry->dev = dev;
entry->parent_device = parent_device;
entry->next = NULL;
@@ -801,6 +819,16 @@ int mount(const char *device, const char *fsname, const char *_path)
e->next = entry;
}
errno = 0;
+
+ free(path);
+ return 0;
+
+out2:
+ unregister_device(&fsdev->dev);
+out1:
+ if (fsdev->backingstore)
+ free(fsdev->backingstore);
+ free(fsdev);
out:
free(path);
return errno;
diff --git a/fs/ramfs.c b/fs/ramfs.c
index 91001f13..db417e13 100644
--- a/fs/ramfs.c
+++ b/fs/ramfs.c
@@ -543,7 +543,6 @@ static void ramfs_remove(struct device_d *dev)
}
static struct fs_driver_d ramfs_driver = {
- .type = FS_TYPE_RAMFS,
.create = ramfs_create,
.unlink = ramfs_unlink,
.open = ramfs_open,
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index c5d60a9d..1f48fb8c 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -4,5 +4,8 @@
extern char _text[], _stext[], _etext[];
extern char __bss_start[], __bss_stop[];
extern char _end[];
+extern void *_barebox_image_size;
+
+#define barebox_image_size (unsigned int)&_barebox_image_size
#endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/block.h b/include/block.h
new file mode 100644
index 00000000..aaab4e3b
--- /dev/null
+++ b/include/block.h
@@ -0,0 +1,32 @@
+#ifndef __BLOCK_H
+#define __BLOCK_H
+
+#include <driver.h>
+
+struct block_device;
+
+struct block_device_ops {
+ int (*read)(struct block_device *, void *buf, int block, int num_blocks);
+ int (*write)(struct block_device *, const void *buf, int block, int num_blocks);
+};
+
+struct block_device {
+ struct device_d *dev;
+ struct block_device_ops *ops;
+ int blockbits;
+ int num_blocks;
+ void *rdbuf; /* read buffer */
+ int rdbufsize;
+ int rdblock; /* start block in read buffer */
+ int rdblockend; /* end block in read buffer */
+ void *wrbuf; /* write buffer */
+ int wrblock; /* start block in write buffer */
+ int wrbufblocks; /* number of blocks currently in write buffer */
+ int wrbufsize; /* size of write buffer in blocks */
+ struct cdev cdev;
+};
+
+int blockdevice_register(struct block_device *blk);
+int blockdevice_unregister(struct block_device *blk);
+
+#endif /* __BLOCK_H */
diff --git a/include/common.h b/include/common.h
index 35ad7b99..491bc980 100644
--- a/include/common.h
+++ b/include/common.h
@@ -219,6 +219,7 @@ int run_shell(void);
int memory_display(char *addr, ulong offs, ulong nbytes, int size);
extern const char version_string[];
+void barebox_banner(void);
#define IOMEM(addr) ((void __force __iomem *)(addr))
diff --git a/include/driver.h b/include/driver.h
index b9edca0e..6a4d45e3 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -290,8 +290,9 @@ struct file_operations {
int (*ioctl)(struct cdev*, int, void *);
off_t (*lseek)(struct cdev*, off_t);
- int (*open)(struct cdev*, struct filep*);
- int (*close)(struct cdev*, struct filep*);
+ int (*open)(struct cdev*);
+ int (*close)(struct cdev*);
+ int (*flush)(struct cdev*);
int (*erase)(struct cdev*, size_t count, unsigned long offset);
int (*protect)(struct cdev*, size_t count, unsigned long offset, int prot);
int (*memmap)(struct cdev*, void **map, int flags);
@@ -314,8 +315,13 @@ struct cdev {
int devfs_create(struct cdev *);
int devfs_remove(struct cdev *);
struct cdev *cdev_by_name(const char *filename);
+struct cdev *cdev_open(const char *name, unsigned long flags);
+void cdev_close(struct cdev *cdev);
+int cdev_flush(struct cdev *cdev);
ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags);
ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags);
+int cdev_ioctl(struct cdev *cdev, int cmd, void *buf);
+int cdev_erase(struct cdev *cdev, size_t count, unsigned long offset);
#define DEVFS_PARTITION_FIXED (1 << 0)
#define DEVFS_PARTITION_READONLY (1 << 1)
diff --git a/include/environment.h b/include/environment.h
index 21a7ffa0..da032e21 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -44,12 +44,27 @@ struct env_context *get_current_context(void);
char *var_val(struct variable_d *);
char *var_name(struct variable_d *);
+#ifdef CONFIG_ENVIRONMENT_VARIABLES
const char *getenv(const char *);
int setenv(const char *, const char *);
+#else
+static inline char *getenv(const char *var)
+{
+ return NULL;
+}
+
+static inline int setenv(const char *var, const char *val)
+{
+ return 0;
+}
+#endif
int env_pop_context(void);
int env_push_context(void);
+/* defaults to /dev/env0 */
+extern char *default_environment_path;
+
int envfs_load(char *filename, char *dirname);
int envfs_save(char *filename, char *dirname);
diff --git a/include/fs.h b/include/fs.h
index 4c03978a..97d5995c 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -3,10 +3,6 @@
#include <driver.h>
-#define FS_TYPE_CRAMFS 1
-#define FS_TYPE_RAMFS 2
-#define FS_TYPE_DEVFS 3
-
#define PATH_MAX 1024 /* include/linux/limits.h */
struct partition;
@@ -41,7 +37,6 @@ typedef struct filep {
#define FS_DRIVER_NO_DEV 1
struct fs_driver_d {
- ulong type;
char *name;
int (*probe) (struct device_d *dev);
int (*mkdir)(struct device_d *dev, const char *pathname);
@@ -58,6 +53,7 @@ struct fs_driver_d {
int (*close)(struct device_d *dev, FILE *f);
int (*read)(struct device_d *dev, FILE *f, void *buf, size_t size);
int (*write)(struct device_d *dev, FILE *f, const void *buf, size_t size);
+ int (*flush)(struct device_d *dev, FILE *f);
off_t (*lseek)(struct device_d *dev, FILE *f, off_t pos);
struct dir* (*opendir)(struct device_d *dev, const char *pathname);
@@ -103,6 +99,7 @@ int open(const char *pathname, int flags, ...);
int creat(const char *pathname, mode_t mode);
int unlink(const char *pathname);
int close(int fd);
+int flush(int fd);
int stat(const char *filename, struct stat *s);
int read(int fd, void *buf, size_t count);
int ioctl(int fd, int request, void *buf);
diff --git a/include/kfifo.h b/include/kfifo.h
index 6f8be10f..3eb03cb1 100644
--- a/include/kfifo.h
+++ b/include/kfifo.h
@@ -43,7 +43,7 @@ void kfifo_free(struct kfifo *fifo);
* bytes copied.
*/
unsigned int kfifo_put(struct kfifo *fifo,
- unsigned char *buffer, unsigned int len);
+ const unsigned char *buffer, unsigned int len);
/**
* kfifo_get - gets some data from the FIFO
diff --git a/include/libbb.h b/include/libbb.h
index 4151230c..09629695 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -30,4 +30,6 @@ int copy_file(const char *src, const char *dst);
int process_escape_sequence(const char *source, char *dest, int destlen);
+char *simple_itoa(unsigned int i);
+
#endif /* __LIBBB_H */
diff --git a/include/linux/mtd/compat.h b/include/linux/mtd/compat.h
deleted file mode 100644
index a99d86e6..00000000
--- a/include/linux/mtd/compat.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef _LINUX_COMPAT_H_
-#define _LINUX_COMPAT_H_
-
-#define __user
-#define __iomem
-
-#define ndelay(x) udelay(1)
-
-#define printk printf
-
-#define KERN_EMERG
-#define KERN_ALERT
-#define KERN_CRIT
-#define KERN_ERR
-#define KERN_WARNING
-#define KERN_NOTICE
-#define KERN_INFO
-#define KERN_DEBUG
-
-#define kmalloc(size, flags) malloc(size)
-#define kfree(ptr) free(ptr)
-
-/*
- * ..and if you can't take the strict
- * types, you can specify one yourself.
- *
- * Or not use min/max at all, of course.
- */
-#define min_t(type,x,y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-#define max_t(type,x,y) \
- ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
-
-#ifndef BUG
-#define BUG() do { \
- printf("barebox BUG at %s:%d!\n", __FILE__, __LINE__); \
-} while (0)
-
-#define BUG_ON(condition) do { if (condition) BUG(); } while(0)
-#endif /* BUG */
-
-#define likely(x) __builtin_expect(!!(x), 1)
-#define unlikely(x) __builtin_expect(!!(x), 0)
-
-#define PAGE_SIZE 4096
-#endif
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 01980f37..29591e26 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -178,10 +178,6 @@ struct mtd_info {
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
- /* Power Management functions */
- int (*suspend) (struct mtd_info *mtd);
- void (*resume) (struct mtd_info *mtd);
-
/* Bad block management functions */
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
diff --git a/include/malloc.h b/include/malloc.h
index 4b0567ed..7b9b062a 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -18,6 +18,7 @@ size_t malloc_usable_size(void*);
void malloc_stats(void);
int mallopt(int, int);
struct mallinfo mallinfo(void);
+void *sbrk(ptrdiff_t increment);
#endif
diff --git a/include/nand.h b/include/nand.h
index 05358d02..b1762dfa 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -6,10 +6,15 @@ struct nand_bb;
#ifdef CONFIG_NAND
int dev_add_bb_dev(char *filename, const char *name);
+int dev_remove_bb_dev(const char *name);
#else
static inline int dev_add_bb_dev(char *filename, const char *name) {
return 0;
}
+static inline int dev_remove_bb_dev(const char *name)
+{
+ return 0;
+}
#endif
#endif /* __NAND_H__ */
diff --git a/include/net.h b/include/net.h
index 33d8a32f..31bf6a23 100644
--- a/include/net.h
+++ b/include/net.h
@@ -363,7 +363,7 @@ static inline int is_valid_ether_addr(const u8 *addr)
return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr);
}
-typedef void rx_handler_f(char *packet, unsigned int len);
+typedef void rx_handler_f(void *ctx, char *packet, unsigned int len);
void eth_set_current(struct eth_device *eth);
struct eth_device *eth_get_current(void);
@@ -388,6 +388,7 @@ struct net_connection {
struct list_head list;
rx_handler_f *handler;
int proto;
+ void *priv;
};
static inline char *net_alloc_packet(void)
@@ -396,9 +397,10 @@ static inline char *net_alloc_packet(void)
}
struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
- rx_handler_f *handler);
+ rx_handler_f *handler, void *ctx);
-struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler);
+struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler,
+ void *ctx);
void net_unregister(struct net_connection *con);
diff --git a/include/usb/usb.h b/include/usb/usb.h
index 1e4d750c..6ef99774 100644
--- a/include/usb/usb.h
+++ b/include/usb/usb.h
@@ -252,6 +252,8 @@ int usb_clear_halt(struct usb_device *dev, int pipe);
int usb_string(struct usb_device *dev, int index, char *buf, size_t size);
int usb_set_interface(struct usb_device *dev, int interface, int alternate);
+void usb_rescan(void);
+
/* big endian -> little endian conversion */
/* some CPUs are already little endian e.g. the ARM920T */
#define __swap_16(x) \
diff --git a/lib/copy_file.c b/lib/copy_file.c
index 70835319..809befe3 100644
--- a/lib/copy_file.c
+++ b/lib/copy_file.c
@@ -17,6 +17,7 @@ int copy_file(const char *src, const char *dst)
int srcfd = 0, dstfd = 0;
int r, w;
int ret = 1;
+ void *buf;
rw_buf = xmalloc(RW_BUF_SIZE);
@@ -40,10 +41,16 @@ int copy_file(const char *src, const char *dst)
}
if (!r)
break;
- w = write(dstfd, rw_buf, r);
- if (w < 0) {
- perror("write");
- goto out;
+
+ buf = rw_buf;
+ while (r) {
+ w = write(dstfd, buf, r);
+ if (w < 0) {
+ perror("write");
+ goto out;
+ }
+ buf += w;
+ r -= w;
}
}
diff --git a/lib/kfifo.c b/lib/kfifo.c
index bf5cee1d..27d44e9b 100644
--- a/lib/kfifo.c
+++ b/lib/kfifo.c
@@ -96,7 +96,7 @@ void kfifo_free(struct kfifo *fifo)
*
*/
unsigned int kfifo_put(struct kfifo *fifo,
- unsigned char *buffer, unsigned int len)
+ const unsigned char *buffer, unsigned int len)
{
unsigned int l;
diff --git a/lib/libbb.c b/lib/libbb.c
index 4d532f61..3d022026 100644
--- a/lib/libbb.c
+++ b/lib/libbb.c
@@ -114,3 +114,16 @@ char * safe_strncpy(char *dst, const char *src, size_t size)
}
EXPORT_SYMBOL(safe_strncpy);
+char *simple_itoa(unsigned int i)
+{
+ /* 21 digits plus null terminator, good for 64-bit or smaller ints */
+ static char local[22];
+ char *p = &local[21];
+ *p-- = '\0';
+ do {
+ *p-- = '0' + i % 10;
+ i /= 10;
+ } while (i > 0);
+ return p + 1;
+}
+EXPORT_SYMBOL(simple_itoa);
diff --git a/net/dhcp.c b/net/dhcp.c
index 0771964b..d1781bc6 100644
--- a/net/dhcp.c
+++ b/net/dhcp.c
@@ -381,7 +381,7 @@ static void dhcp_send_request_packet(struct bootp *bp_offer)
/*
* Handle DHCP received packets.
*/
-static void dhcp_handler(char *packet, unsigned int len)
+static void dhcp_handler(void *ctx, char *packet, unsigned int len)
{
char *pkt = net_eth_to_udp_payload(packet);
struct udphdr *udp = net_eth_to_udphdr(packet);
@@ -439,7 +439,7 @@ static int do_dhcp(struct command *cmdtp, int argc, char *argv[])
{
int ret;
- dhcp_con = net_udp_new(0xffffffff, PORT_BOOTPS, dhcp_handler);
+ dhcp_con = net_udp_new(0xffffffff, PORT_BOOTPS, dhcp_handler, NULL);
if (IS_ERR(dhcp_con)) {
ret = PTR_ERR(dhcp_con);
goto out;
diff --git a/net/dns.c b/net/dns.c
index 1ee270b6..4db5bbcf 100644
--- a/net/dns.c
+++ b/net/dns.c
@@ -116,7 +116,7 @@ static int dns_send(char *name)
return ret;
}
-static void dns_handler(char *packet, unsigned len)
+static void dns_handler(void *ctx, char *packet, unsigned len)
{
struct header *header;
unsigned char *p, *e, *s;
@@ -211,7 +211,7 @@ IPaddr_t resolv(char *host)
debug("resolving host %s via nameserver %s\n", host, getenv("nameserver"));
- dns_con = net_udp_new(ip, DNS_PORT, dns_handler);
+ dns_con = net_udp_new(ip, DNS_PORT, dns_handler, NULL);
if (IS_ERR(dns_con))
return PTR_ERR(dns_con);
dns_timer_start = get_time_ns();
diff --git a/net/eth.c b/net/eth.c
index 0251e592..c5b346c2 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -167,8 +167,10 @@ int eth_register(struct eth_device *edev)
if (edev->get_ethaddr(edev, ethaddr) == 0) {
ethaddr_to_string(ethaddr, ethaddr_str);
- dev_info(dev, "got MAC address from EEPROM: %s\n", ethaddr_str);
- dev_set_param(dev, "ethaddr", ethaddr_str);
+ if (is_valid_ether_addr(ethaddr)) {
+ dev_info(dev, "got MAC address from EEPROM: %s\n", ethaddr_str);
+ dev_set_param(dev, "ethaddr", ethaddr_str);
+ }
}
if (!eth_current) {
diff --git a/net/net.c b/net/net.c
index 74953571..f1ab667b 100644
--- a/net/net.c
+++ b/net/net.c
@@ -343,7 +343,8 @@ void net_set_gateway(IPaddr_t gw)
static LIST_HEAD(connection_list);
-static struct net_connection *net_new(IPaddr_t dest, rx_handler_f *handler)
+static struct net_connection *net_new(IPaddr_t dest, rx_handler_f *handler,
+ void *ctx)
{
struct eth_device *edev = eth_get_current();
struct net_connection *con;
@@ -366,6 +367,7 @@ static struct net_connection *net_new(IPaddr_t dest, rx_handler_f *handler)
con = xzalloc(sizeof(*con));
con->packet = xmemalign(32, PKTSIZE);
+ con->priv = ctx;
memset(con->packet, 0, PKTSIZE);
con->et = (struct ethernet *)con->packet;
@@ -402,9 +404,9 @@ out:
}
struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
- rx_handler_f *handler)
+ rx_handler_f *handler, void *ctx)
{
- struct net_connection *con = net_new(dest, handler);
+ struct net_connection *con = net_new(dest, handler, ctx);
if (IS_ERR(con))
return con;
@@ -417,9 +419,10 @@ struct net_connection *net_udp_new(IPaddr_t dest, uint16_t dport,
return con;
}
-struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler)
+struct net_connection *net_icmp_new(IPaddr_t dest, rx_handler_f *handler,
+ void *ctx)
{
- struct net_connection *con = net_new(dest, handler);
+ struct net_connection *con = net_new(dest, handler, ctx);
if (IS_ERR(con))
return con;
@@ -564,7 +567,7 @@ static int net_handle_udp(unsigned char *pkt, int len)
port = ntohs(udp->uh_dport);
list_for_each_entry(con, &connection_list, list) {
if (con->proto == IPPROTO_UDP && port == ntohs(con->udp->uh_sport)) {
- con->handler(pkt, len);
+ con->handler(con->priv, pkt, len);
return 0;
}
}
@@ -579,7 +582,7 @@ static int net_handle_icmp(unsigned char *pkt, int len)
list_for_each_entry(con, &connection_list, list) {
if (con->proto == IPPROTO_ICMP) {
- con->handler(pkt, len);
+ con->handler(con->priv, pkt, len);
return 0;
}
}
diff --git a/net/netconsole.c b/net/netconsole.c
index fda524e1..2ac3e643 100644
--- a/net/netconsole.c
+++ b/net/netconsole.c
@@ -50,7 +50,7 @@ struct nc_priv {
static struct nc_priv *g_priv;
-static void nc_handler(char *pkt, unsigned len)
+static void nc_handler(void *ctx, char *pkt, unsigned len)
{
struct nc_priv *priv = g_priv;
unsigned char *packet = net_eth_to_udp_payload(pkt);
@@ -65,7 +65,7 @@ static int nc_init(void)
if (priv->con)
net_unregister(priv->con);
- priv->con = net_udp_new(priv->ip, priv->port, nc_handler);
+ priv->con = net_udp_new(priv->ip, priv->port, nc_handler, NULL);
if (IS_ERR(priv->con)) {
int ret = PTR_ERR(priv->con);
priv->con = NULL;
diff --git a/net/nfs.c b/net/nfs.c
index 4ca1d6e5..0a4b787e 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -562,7 +562,7 @@ static int nfs_read_reply(unsigned char *pkt, unsigned len)
Interfaces of barebox
**************************************************************************/
-static void nfs_handler(char *packet, unsigned len)
+static void nfs_handler(void *ctx, char *packet, unsigned len)
{
char *pkt = net_eth_to_udp_payload(packet);
int ret;
@@ -689,7 +689,7 @@ static int do_nfs(struct command *cmdtp, int argc, char *argv[])
return 1;
}
- nfs_con = net_udp_new(net_get_serverip(), 0, nfs_handler);
+ nfs_con = net_udp_new(net_get_serverip(), 0, nfs_handler, NULL);
if (IS_ERR(nfs_con)) {
nfs_err = PTR_ERR(nfs_con);
goto err_udp;
diff --git a/net/ping.c b/net/ping.c
index d414784e..8aad7af7 100644
--- a/net/ping.c
+++ b/net/ping.c
@@ -40,7 +40,7 @@ static int ping_send(void)
return net_icmp_send(ping_con, 9);
}
-static void ping_handler(char *pkt, unsigned len)
+static void ping_handler(void *ctx, char *pkt, unsigned len)
{
IPaddr_t tmp;
struct iphdr *ip = net_eth_to_iphdr(pkt);
@@ -66,7 +66,7 @@ static int do_ping(struct command *cmdtp, int argc, char *argv[])
return 1;
}
- ping_con = net_icmp_new(net_ping_ip, ping_handler);
+ ping_con = net_icmp_new(net_ping_ip, ping_handler, NULL);
if (IS_ERR(ping_con)) {
ret = PTR_ERR(ping_con);
goto out;
diff --git a/net/tftp.c b/net/tftp.c
index 0f38b6b9..ee114680 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -141,7 +141,7 @@ static int tftp_send(void)
return ret;
}
-static void tftp_handler(char *packet, unsigned len)
+static void tftp_handler(void *ctx, char *packet, unsigned len)
{
uint16_t proto;
uint16_t *s;
@@ -314,7 +314,7 @@ static int do_tftpb(struct command *cmdtp, int argc, char *argv[])
return 1;
}
- tftp_con = net_udp_new(net_get_serverip(), TFTP_PORT, tftp_handler);
+ tftp_con = net_udp_new(net_get_serverip(), TFTP_PORT, tftp_handler, NULL);
if (IS_ERR(tftp_con)) {
tftp_err = PTR_ERR(tftp_con);
goto out_close;
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 26317b28..11fd2df3 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -2,4 +2,5 @@ bareboxenv
bin2c
mkimage
kallsyms
-
+gen_netx_image
+omap_signGP
diff --git a/scripts/Makefile b/scripts/Makefile
index be8e3e05..d6ea48ca 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -9,6 +9,7 @@ hostprogs-y += bin2c
hostprogs-y += mkimage
hostprogs-y += bareboxenv
hostprogs-$(CONFIG_ARCH_NETX) += gen_netx_image
+hostprogs-$(CONFIG_ARCH_OMAP) += omap_signGP
always := $(hostprogs-y) $(hostprogs-m)
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index 1f11d848..b3591a91 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -76,10 +76,8 @@ static int read_symbol(FILE *in, struct sym_entry *s)
rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
if (rc != 3) {
- if (rc != EOF) {
- /* skip line */
- fgets(str, 500, in);
- }
+ if (rc != EOF && fgets(str, 500, in) == NULL)
+ fprintf(stderr, "Read error or end of file.\n");
return -1;
}
diff --git a/scripts/omap_signGP.c b/scripts/omap_signGP.c
new file mode 100644
index 00000000..d20d3570
--- /dev/null
+++ b/scripts/omap_signGP.c
@@ -0,0 +1,313 @@
+/**
+ * signGP.c - Read the x-load.bin file and write out the x-load.bin.ift file
+ *
+ * The signed image is the original pre-pended with the size of the image
+ * and the load address. If not entered on command line, file name is
+ * assumed to be x-load.bin in current directory and load address is
+ * 0x40200800.
+ *
+ * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 of
+ * the License as published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <malloc.h>
+#include <linux/types.h>
+
+#undef CH_WITH_CHRAM
+struct chsettings {
+ __u32 section_key;
+ __u8 valid;
+ __u8 version;
+ __u16 reserved;
+ __u32 flags;
+} __attribute__ ((__packed__));
+
+/* __u32 cm_clksel_core;
+ __u32 reserved1;
+ __u32 cm_autoidle_dpll_mpu;
+ __u32 cm_clksel_dpll_mpu;
+ __u32 cm_div_m2_dpll_mpu;
+ __u32 cm_autoidle_dpll_core;
+ __u32 cm_clksel_dpll_core;
+ __u32 cm_div_m2_dpll_core;
+ __u32 cm_div_m3_dpll_core;
+ __u32 cm_div_m4_dpll_core;
+ __u32 cm_div_m5_dpll_core;
+ __u32 cm_div_m6_dpll_core;
+ __u32 cm_div_m7_dpll_core;
+ __u32 cm_autoidle_dpll_per;
+ __u32 cm_clksel_dpll_per;
+ __u32 cm_div_m2_dpll_per;
+ __u32 cm_div_m3_dpll_per;
+ __u32 cm_div_m4_dpll_per;
+ __u32 cm_div_m5_dpll_per;
+ __u32 cm_div_m6_dpll_per;
+ __u32 cm_div_m7_dpll_per;
+ __u32 cm_autoidle_dpll_usb;
+ __u32 cm_clksel_dpll_usb;
+ __u32 cm_div_m2_dpll_usb;
+}*/
+
+struct gp_header {
+ __u32 size;
+ __u32 load_addr;
+} __attribute__ ((__packed__));
+
+struct ch_toc {
+ __u32 section_offset;
+ __u32 section_size;
+ __u8 unused[12];
+ __u8 section_name[12];
+} __attribute__ ((__packed__));
+
+struct chram {
+ /* CHRAM */
+ __u32 section_key_chr;
+ __u8 section_disable_chr;
+ __u8 pad_chr[3];
+ /* EMIF1 */
+ __u32 config_emif1;
+ __u32 refresh_emif1;
+ __u32 tim1_emif1;
+ __u32 tim2_emif1;
+ __u32 tim3_emif1;
+ __u32 pwrControl_emif1;
+ __u32 phy_cntr1_emif1;
+ __u32 phy_cntr2_emif1;
+ __u8 modereg1_emif1;
+ __u8 modereg2_emif1;
+ __u8 modereg3_emif1;
+ __u8 pad_emif1;
+ /* EMIF2 */
+ __u32 config_emif2;
+ __u32 refresh_emif2;
+ __u32 tim1_emif2;
+ __u32 tim2_emif2;
+ __u32 tim3_emif2;
+ __u32 pwrControl_emif2;
+ __u32 phy_cntr1_emif2;
+ __u32 phy_cntr2_emif2;
+ __u8 modereg1_emif2;
+ __u8 modereg2_emif2;
+ __u8 modereg3_emif2;
+ __u8 pad_emif2;
+
+ __u32 dmm_lisa_map;
+ __u8 flags;
+ __u8 pad[3];
+} __attribute__ ((__packed__));
+
+
+struct ch_chsettings_chram {
+ struct ch_toc toc_chsettings;
+ struct ch_toc toc_chram;
+ struct ch_toc toc_terminator;
+ struct chsettings section_chsettings;
+ struct chram section_chram;
+ __u8 padding1[512 -
+ (sizeof(struct ch_toc) * 3 +
+ sizeof(struct chsettings) + sizeof(struct chram))];
+ /* struct gp_header gpheader; */
+} __attribute__ ((__packed__));
+
+struct ch_chsettings_nochram {
+ struct ch_toc toc_chsettings;
+ struct ch_toc toc_terminator;
+ struct chsettings section_chsettings;
+ __u8 padding1[512 -
+ (sizeof(struct ch_toc) * 2 +
+ sizeof(struct chsettings))];
+ /* struct gp_header gpheader; */
+} __attribute__ ((__packed__));
+
+
+#ifdef CH_WITH_CHRAM
+static const struct ch_chsettings_chram config_header = {
+ /* CHSETTINGS TOC */
+ {sizeof(struct ch_toc) * 4,
+ sizeof(struct chsettings),
+ "",
+ {"CHSETTINGS"}
+ },
+ /* CHRAM TOC */
+ {sizeof(struct ch_toc) * 4 + sizeof(struct chsettings),
+ sizeof(struct chram),
+ "",
+ {"CHRAM"}
+ },
+ /* toc terminator */
+ {0xFFFFFFFF,
+ 0xFFFFFFFF,
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF}
+ },
+ /* CHSETTINGS section */
+ {
+ 0xC0C0C0C1,
+ 0,
+ 1,
+ 0,
+ 0},
+ /* CHRAM section */
+ {
+ 0xc0c0c0c2,
+ 0x01,
+ {0x00, 0x00, 0x00},
+
+ /* EMIF1 */
+ 0x80800eb2,
+ 0x00000010,
+ 0x110d1624,
+ 0x3058161b,
+ 0x030060b2,
+ 0x00000200,
+ 0x901ff416,
+ 0x00000000,
+ 0x23,
+ 0x01,
+ 0x02,
+ 0x00,
+
+ /* EMIF2 */
+ 0x80800eb2,
+ 0x000002ba,
+ 0x110d1624,
+ 0x3058161b,
+ 0x03006542,
+ 0x00000200,
+ 0x901ff416,
+ 0x00000000,
+ 0x23,
+ 0x01,
+ 0x02,
+ 0x00,
+
+ /* LISA map */
+ 0x80700100,
+ 0x05,
+ {0x00, 0x00, 0x00},
+ },
+ ""
+};
+#else
+static struct ch_chsettings_nochram config_header
+ __attribute__((section(".config_header"))) = {
+ /* CHSETTINGS TOC */
+ {(sizeof(struct ch_toc)) * 2,
+ sizeof(struct chsettings),
+ "",
+ {"CHSETTINGS"}
+ },
+ /* toc terminator */
+ {0xFFFFFFFF,
+ 0xFFFFFFFF,
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF},
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF}
+ },
+ /* CHSETTINGS section */
+ {
+ 0xC0C0C0C1,
+ 0,
+ 1,
+ 0,
+ 0},
+ ""
+};
+#endif
+
+
+#define err(...) do { int save_errno = errno; \
+ fprintf(stderr, __VA_ARGS__); \
+ errno = save_errno; \
+ } while (0);
+#define pdie(func, ...) do { perror(func); exit(1); } while (0);
+
+int main(int argc, char *argv[])
+{
+ int i;
+ char ifname[FILENAME_MAX], ofname[FILENAME_MAX], ch;
+ FILE *ifile, *ofile;
+ unsigned long loadaddr, len;
+ struct stat sinfo;
+ int ch_add = 0;
+
+
+ /* Default to x-load.bin and 0x40200800. */
+ strcpy(ifname, "x-load.bin");
+ loadaddr = 0x40200800;
+
+ if ((argc == 2) || (argc == 3) || (argc == 4))
+ strcpy(ifname, argv[1]);
+
+ if ((argc == 3) || (argc == 4))
+ loadaddr = strtoul(argv[2], NULL, 16);
+
+ if (argc == 4)
+ ch_add = strtoul(argv[3], NULL, 16);
+
+ /* Form the output file name. */
+ strcpy(ofname, ifname);
+ strcat(ofname, ".ift");
+
+ /* Open the input file. */
+ ifile = fopen(ifname, "rb");
+ if (ifile == NULL) {
+ err("Cannot open %s\n", ifname);
+ pdie("fopen");
+ }
+
+ /* Get file length. */
+ stat(ifname, &sinfo);
+ len = sinfo.st_size;
+
+ /* Open the output file and write it. */
+ ofile = fopen(ofname, "wb");
+ if (ofile == NULL) {
+ fclose(ifile);
+ err("Cannot open %s\n", ofname);
+ pdie("fopen");
+ }
+
+ if (ch_add)
+ if (fwrite(&config_header, 1, 512, ofile) <= 0)
+ pdie("fwrite");
+
+ if (fwrite(&len, 1, 4, ofile) <= 0)
+ pdie("fwrite");
+ if (fwrite(&loadaddr, 1, 4, ofile) <= 0)
+ pdie("fwrite");
+ for (i = 0; i < len; i++) {
+ if (fread(&ch, 1, 1, ifile) <= 0)
+ pdie("fread");
+ if (fwrite(&ch, 1, 1, ofile) <= 0)
+ pdie("fwrite");
+ }
+
+ if (fclose(ifile))
+ perror("warning: fclose");
+ if (fclose(ofile))
+ perror("warning: fclose");
+
+ return 0;
+}