diff --git a/Documentation/barebox-main.dox b/Documentation/barebox-main.dox index 01c45c1..fb780e6 100644 --- a/Documentation/barebox-main.dox +++ b/Documentation/barebox-main.dox @@ -117,9 +117,9 @@ @a barebox usually needs an environment for storing the configuration data. You can generate an environment using the example environment contained -in board/sandbox/env: +in arch/sanbox/board/env: -@code # ./scripts/bareboxenv -s -p 0x10000 board/sandbox/env/ env.bin @endcode +@code # ./scripts/bareboxenv -s -p 0x10000 arch/sanbox/board/env/ env.bin @endcode To get some files to play with you can generate a cramfs image: diff --git a/Makefile b/Makefile index 5618c85..8a09f32 100644 --- a/Makefile +++ b/Makefile @@ -851,11 +851,11 @@ $(Q)$(create-symlink) include/config.h: include/config/auto.conf - @echo ' SYMLINK $@ -> board/$(board-y)/config.h' + @echo ' SYMLINK $@ -> $(BOARD)/config.h' ifneq ($(KBUILD_SRC),) - $(Q)ln -fsn $(srctree)/board/$(board-y)/config.h $@ + $(Q)ln -fsn $(srctree)/$(BOARD)/config.h $@ else - @ln -fsn ../board/$(board-y)/config.h $@ + @ln -fsn ../$(BOARD)/config.h $@ endif # Generate some files diff --git a/TODO b/TODO index 08a7d99..6350799 100644 --- a/TODO +++ b/TODO @@ -33,7 +33,6 @@ [-] Cleanup cpu/*. Many functions there are not cpu specific. For example the cache functions for arm are common for most arm processors. (done for ARM) (I will check this for m68k arch - csc 21.03.2008 19:56:24) -[ ] Board support should go to arch/*/boards/* [ ] Move SoC specific header files from include/ to include/asm/arch/ [ ] Several .c/.h files do not have GNU/copyright headers. [ ] The cramfs driver currently uses direct memory accesses instead of read(). @@ -108,4 +107,4 @@ be any key, ctrl-c or a certain string. Maybe like this: countdown -m msg -t timeout -x [ctrl-c|anykey|string] If done, remove the corresponding stuff from common/main.c - +[X] Board support should go to arch/*/boards/* diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 1c9f24e..8b4d64c 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -77,6 +77,7 @@ board-$(CONFIG_MACH_PCM043) := pcm043 board-$(CONFIG_MACH_PM9263) := pm9263 board-$(CONFIG_MACH_SCB9328) := scb9328 +board-$(CONFIG_MACH_NESO) := guf-neso machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y)) @@ -117,7 +118,7 @@ PHONY += maketools ifneq ($(board-y),) -BOARD := board/$(board-y)/ +BOARD := arch/arm/boards/$(board-y)/ else BOARD := endif diff --git a/arch/arm/boards/a9m2410/Makefile b/arch/arm/boards/a9m2410/Makefile new file mode 100644 index 0000000..63026f0 --- /dev/null +++ b/arch/arm/boards/a9m2410/Makefile @@ -0,0 +1,3 @@ + +obj-y += lowlevel_init.o +obj-y += a9m2410.o diff --git a/arch/arm/boards/a9m2410/a9m2410.c b/arch/arm/boards/a9m2410/a9m2410.c new file mode 100644 index 0000000..f327f82 --- /dev/null +++ b/arch/arm/boards/a9m2410/a9m2410.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2009 Juergen Beisert, 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 + * + */ + +/** + * @file + * @brief a9m2410 Specific Board Initialization routines + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "ram", + .map_base = CS6_BASE, + .platform_data = &ram_pdata, +}; + +// {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0}, +static struct s3c24x0_nand_platform_data nand_info = { + .nand_timing = CALC_NFCONF_TIMING(A9M2410_TACLS, A9M2410_TWRPH0, A9M2410_TWRPH1) +}; + +static struct device_d nand_dev = { + .name = "s3c24x0_nand", + .map_base = S3C24X0_NAND_BASE, + .platform_data = &nand_info, +}; + +/* + * SMSC 91C111 network controller on the baseboard + * connected to CS line 1 and interrupt line + * GPIO3, data width is 32 bit + */ +static struct device_d network_dev = { + .name = "smc91c111", + .map_base = CS1_BASE + 0x300, + .size = 16, +}; + +static int a9m2410_devices_init(void) +{ + uint32_t reg; + + /* + * detect the current memory size + * Note: On this card the second SDRAM page is not used + */ + reg = readl(BANKSIZE); + + switch (reg &= 0x7) { + case 0: + sdram_dev.size = 32 * 1024 * 1024; + break; + case 1: + sdram_dev.size = 64 * 1024 * 1024; + break; + case 2: + sdram_dev.size = 128 * 1024 * 1024; + break; + case 4: + sdram_dev.size = 2 * 1024 * 1024; + break; + case 5: + sdram_dev.size = 4 * 1024 * 1024; + break; + case 6: + sdram_dev.size = 8 * 1024 * 1024; + break; + case 7: + sdram_dev.size = 16 * 1024 * 1024; + break; + } + + /* ---------- configure the GPIOs ------------- */ + writel(0x007FFFFF, GPACON); + writel(0x00000000, GPCCON); + writel(0x00000000, GPCUP); + writel(0x00000000, GPDCON); + writel(0x00000000, GPDUP); + writel(0xAAAAAAAA, GPECON); + writel(0x0000E03F, GPEUP); + writel(0x00000000, GPBCON); /* all inputs */ + writel(0x00000007, GPBUP); /* pullup disabled for GPB0..3 */ + writel(0x00009000, GPFCON); /* GPF7 CLK_INT#, GPF6 Debug-LED */ + writel(0x000000FF, GPFUP); + writel(readl(GPGDAT) | 0x0010, GPGDAT); /* switch off LCD backlight */ + writel(0xFF00A938, GPGCON); /* switch off USB device */ + writel(0x0000F000, GPGUP); + writel(readl(GPHDAT) | 0x100, GPHDAT); /* switch BOOTINT/GPIO_ON# to high */ + writel(0x000007FF, GPHUP); + writel(0x0029FAAA, GPHCON); + /* + * USB port1 normal, USB port0 normal, USB1 pads for device + * PCLK output on CLKOUT0, UPLL CLK output on CLKOUT1, + * 2nd SDRAM bank off (only bank 1 is used) + */ + writel(0x40140, MISCCR); + + /* ----------- configure the access to the outer space ---------- */ + reg = readl(BWSCON); + + /* CS#1 to access the network controller */ + reg &= ~0xf0; + reg |= 0xe0; + writel(0x1350, BANKCON1); + + /* CS#2 to the dual 16550 UART */ + reg &= ~0xf00; + reg |= 0x400; + writel(0x0d50, BANKCON2); + + writel(reg, BWSCON); + + /* release the reset signal to the network and UART device */ + reg = readl(MISCCR); + reg |= 0x10000; + writel(reg, MISCCR); + + /* ----------- the devices the boot loader should work with -------- */ + register_device(&nand_dev); + register_device(&sdram_dev); + register_device(&network_dev); + +#ifdef CONFIG_NAND + /* ----------- add some vital partitions -------- */ + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); +#endif + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)sdram_dev.map_base + 0x100); + armlinux_set_architecture(MACH_TYPE_A9M2410); + + return 0; +} + +device_initcall(a9m2410_devices_init); + +#ifdef CONFIG_S3C24XX_NAND_BOOT +void __bare_init nand_boot(void) +{ + s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0, 512); +} +#endif + +static struct device_d a9m2410_serial_device = { + .name = "s3c24x0_serial", + .map_base = UART1_BASE, + .size = UART1_SIZE, +}; + +static int a9m2410_console_init(void) +{ + register_device(&a9m2410_serial_device); + return 0; +} + +console_initcall(a9m2410_console_init); + +/** @page a9m2410 DIGI's a9m2410 + +This CPU card is based on a Samsung S3C2410 CPU. The card is shipped with: + +- S3C2410\@200 MHz (ARM920T/ARMv4T) +- 12MHz crystal reference +- SDRAM 32 MiB + - Samsung K4M563233E-EE1H + - 2M x 32Bit x 4 Banks Mobile SDRAM + - 90 pin FBGA + - CL3\@133MHz, CL2\@100MHz (CAS/RAS delay 19ns) + - four banks + - 32 bit data bits + - row address size is 11 + - Row cycle time: 69ns + - collumn address size is 9 bits + - Extended temperature range (-25�C...85�C) + - 64ms refresh period (4k) +- NAND Flash 32 MiB + - Samsung KM29U256T + - 32MiB 3,3V 8-bit + - ID: 0xEC, 0x75, 0x??, 0xBD + - 30ns/40ns/20ns +- I2C interface, 100KHz and 400KHz + - Real Time Clock + - Dallas DS1337 + - address 0x68 + - EEPROM + - ST M24LC64 + - address 0x50 + - 16bit addressing +- LCD interface +- Touch Screen interface +- Camera interface +- I2S interface +- AC97 Audio-CODEC interface +- SD card interface +- 3 serial RS232 interfaces +- Host and device USB interface, USB1.1 compliant +- Ethernet interface + - 10Mbps, Cirrus Logic, CS8900A (on the CPU card) or + - 10/100Mbps, SMSC 91C111 (on the baseboard) +- SPI interface +- JTAG interface + +How to get the binary image: + +Using the default configuration: + +@code +make ARCH=arm a9m2410_defconfig +@endcode + +Build the binary image: + +@code +make ARCH=arm CROSS_COMPILE=armv4compiler +@endcode + +@note replace the armv4compiler with your ARM v4 cross compiler. +*/ diff --git a/arch/arm/boards/a9m2410/config.h b/arch/arm/boards/a9m2410/config.h new file mode 100644 index 0000000..87b05fc --- /dev/null +++ b/arch/arm/boards/a9m2410/config.h @@ -0,0 +1,122 @@ +/** + * @file + * @brief Global defintions for the ARM S3C2410 based a9m2410 CPU card + */ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/** + * The external clock reference is a 12.0MHz crystal + */ +#define S3C24XX_CLOCK_REFERENCE 12000000 + +/** + * Define the main clock configuration to be used in register CLKDIVN + * + * We must limit the frequency of the connected SDRAMs with the clock ratio + * setup to 1:2:4. This will result into FCLK:HCLK:PCLK = 200Mhz:100MHz:50MHz + */ +#define BOARD_SPECIFIC_CLKDIVN 0x003 + +/** + * Define the MPLL configuration to be used in register MPLLCON + * + * We want the MPLL to run at 202.80MHz + */ +#define BOARD_SPECIFIC_MPLL ((0xA1 << 12) + (3 << 4) + 1) + +/** + * Define the UPLL configuration to be used in register UPLLCON + * + * We want the UPLL to run at 48.0MHz + */ +#define BOARD_SPECIFIC_UPLL ((0x78 << 12) + (2 << 4) + 3) + +/* + * SDRAM configuration for Samsung K4M563233E + * - 2M x 32Bit x 4 Banks Mobile SDRAM + * - 90 pin FBGA + * - CL2@100MHz + */ +/* + * SDRAM uses 32bit width + */ +#define BOARD_SPECIFIC_BWSCON ((0x02 << 24) + (0x02 << 28)) +/* + * 32MiB SDRAM in bank6 + * - MT = 11 (= sync dram type) + * - Trcd = 00 (= CL2) + * - SCAN = 01 (= 9 bit collumns) + */ +#define BOARD_SPECIFIC_BANKCON6 ((0x3 << 15) + (0x0 << 2) + 0x1) +/* + * No memory in bank7 + */ +#define BOARD_SPECIFIC_BANKCON7 ((0x3 << 15) + (0x0 << 2) + 0x1) +/* + * SDRAM refresh settings + * - REFEN = 1 (= refresh enabled) + * - TREFMD = 0 (= auto refresh) + * - Trp = 00 (= 2 RAS precharge clocks) + * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) + * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = 489 + */ +#define BOARD_SPECIFIC_REFRESH ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x1 << 18) + 489) +/* + * SDRAM banksize + * - BURST_EN = 1 (= burst mode enabled) + * - SCKE_EN = 1 (= SDRAM SCKE enabled) + * - SCLK_EN = 1 (= clock active only during accesses) + * - BK67MAP = 000 (= 32MiB) + */ +#define BOARD_SPECIFIC_BANKSIZE ((1 << 7) + (1 << 5) + (0 << 4) + 0) +/* + * SDRAM mode register bank6 + * CL = 010 (= 2 clocks) + */ +#define BOARD_SPECIFIC_MRSRB6 (0x2 << 4) +/* + * SDRAM mode register bank7 + * CL = 010 (= 2 clocks) + */ +#define BOARD_SPECIFIC_MRSRB7 (0x2 << 4) + +/* + * Flash access timings + * Tacls = 0ns (but 20ns data setup time) + * Twrph0 = 25ns (write) 35ns (read) + * Twrph1 = 10ns (10ns data hold time) + * Read cycle time = 50ns + * + * Assumed HCLK is 100MHz + * Tacls = 1 (-> 20ns) + * Twrph0 = 3 (-> 40ns) + * Twrph1 = 1 (-> 20ns) + * Cycle time = 80ns + */ +#define A9M2410_TACLS 1 +#define A9M2410_TWRPH0 3 +#define A9M2410_TWRPH1 1 + +/* needed in the generic NAND boot code only */ +#ifdef CONFIG_S3C24XX_NAND_BOOT +# define BOARD_DEFAULT_NAND_TIMING CALC_NFCONF_TIMING(A9M2410_TACLS, A9M2410_TWRPH0, A9M2410_TWRPH1) +#endif + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/a9m2410/env/bin/_update b/arch/arm/boards/a9m2410/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/a9m2410/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/a9m2410/env/bin/boot b/arch/arm/boards/a9m2410/env/bin/boot new file mode 100644 index 0000000..59fa60e --- /dev/null +++ b/arch/arm/boards/a9m2410/env/bin/boot @@ -0,0 +1,38 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + root=nand + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xnand ]; then + bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=\"NAND 32MiB 3,3V 8-bit:$nand_parts\"" + +if [ x$kernel = xnet ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/a9m2410/env/bin/hush_hack b/arch/arm/boards/a9m2410/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/a9m2410/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/a9m2410/env/bin/init b/arch/arm/boards/a9m2410/env/bin/init new file mode 100644 index 0000000..5ae44dd --- /dev/null +++ b/arch/arm/boards/a9m2410/env/bin/init @@ -0,0 +1,34 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type update_root [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/a9m2410/env/bin/update_kernel b/arch/arm/boards/a9m2410/env/bin/update_kernel new file mode 100644 index 0000000..c43a557 --- /dev/null +++ b/arch/arm/boards/a9m2410/env/bin/update_kernel @@ -0,0 +1,13 @@ +#!/bin/sh + +. /env/config + +part=/dev/nand0.kernel.bb + +if [ x$1 = x ]; then + image=$uimage +else + image=$1 +fi + +. /env/bin/_update $image diff --git a/arch/arm/boards/a9m2410/env/bin/update_root b/arch/arm/boards/a9m2410/env/bin/update_root new file mode 100644 index 0000000..34139e5 --- /dev/null +++ b/arch/arm/boards/a9m2410/env/bin/update_root @@ -0,0 +1,11 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = x ]; then + image=$jffs2 +else + image=$1 +fi + +. /env/bin/_update $image diff --git a/arch/arm/boards/a9m2410/env/config b/arch/arm/boards/a9m2410/env/config new file mode 100644 index 0000000..79150ce --- /dev/null +++ b/arch/arm/boards/a9m2410/env/config @@ -0,0 +1,26 @@ +#!/bin/sh + +# can be either 'net' or 'nand'' +kernel=net +root=net + +uimage=uImage-a9m2410 +jffs2=root-a9m2410.jffs2 + +autoboot_timeout=3 + +nfsroot="/nfsexport/OSELAS.BSP-Hesch-TMU-1/platform-FS_A9M2410/root" +bootargs="console=ttySAC0,38400" + +nand_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" +rootpart_nand="/dev/mtdblock3" + +# use 'dhcp' to do dhcp in barebox and in kernel +#ip=dhcp + +# or set your networking parameters here +eth0.ipaddr=192.168.42.31 +eth0.netmask=255.255.0.0 +eth0.gateway=192.168.23.1 +eth0.serverip=192.168.23.2 +eth0.ethaddr=00:04:f3:00:06:35 diff --git a/arch/arm/boards/a9m2410/lowlevel_init.S b/arch/arm/boards/a9m2410/lowlevel_init.S new file mode 100644 index 0000000..461b93c --- /dev/null +++ b/arch/arm/boards/a9m2410/lowlevel_init.S @@ -0,0 +1,37 @@ +/* + * + */ + +#include +#include + + .section ".text_bare_init.board_init_lowlevel","ax" + +.globl board_init_lowlevel +board_init_lowlevel: + + mov r10, lr /* save the link register */ + + bl s3c24x0_disable_wd + + /* skip everything here if we are already running from SDRAM */ + cmp pc, #S3C24X0_SDRAM_BASE + blo 1f + cmp pc, #S3C24X0_SDRAM_END + bhs 1f + + mov pc, r10 + +/* we are running from NOR or NAND/SRAM memory. Do further initialisation */ +1: + bl s3c24x0_pll_init + + bl s3c24x0_sdram_init + +#ifdef CONFIG_S3C24XX_NAND_BOOT + mov lr, r10 /* restore the link register */ +/* up to here we are running from the internal SRAM area */ + b s3c24x0_nand_boot /* does return directly to our caller into SDRAM */ +#else + mov pc, r10 +#endif diff --git a/arch/arm/boards/a9m2440/Makefile b/arch/arm/boards/a9m2440/Makefile new file mode 100644 index 0000000..779e83d --- /dev/null +++ b/arch/arm/boards/a9m2440/Makefile @@ -0,0 +1,4 @@ + +obj-y += lowlevel_init.o +obj-y += a9m2440.o +obj-$(CONFIG_MACH_A9M2410DEV) += a9m2410dev.o diff --git a/arch/arm/boards/a9m2440/a9m2410dev.c b/arch/arm/boards/a9m2440/a9m2410dev.c new file mode 100644 index 0000000..1220bd9 --- /dev/null +++ b/arch/arm/boards/a9m2440/a9m2410dev.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2009 Juergen Beisert + * + * 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 + * + */ + +/** + * @file + * @brief a9m2410dev Baseboad specific initialization routines + * + */ + +#include +#include +#include +#include +#include + +/** + * Initialize the CPU to be able to work with the a9m2410dev evaluation board + */ +int a9m2410dev_devices_init(void) +{ + unsigned int reg; + + /* ---------- configure the GPIOs ------------- */ + writel(0x007FFFFF, GPACON); + writel(0x00000000, GPCCON); + writel(0x00000000, GPCUP); + writel(0x00000000, GPDCON); + writel(0x00000000, GPDUP); + writel(0xAAAAAAAA, GPECON); + writel(0x0000E03F, GPEUP); + writel(0x00000000, GPBCON); /* all inputs */ + writel(0x00000007, GPBUP); /* pullup disabled for GPB0..3 */ + writel(0x00009000, GPFCON); /* GPF7 CLK_INT#, GPF6 Debug-LED */ + writel(0x000000FF, GPFUP); + writel(readl(GPGDAT) | 0x1010, GPGDAT); /* switch off IDLE_SW#, switch off LCD backlight */ + writel(0x0100A93A, GPGCON); /* switch on USB device */ + writel(0x0000F000, GPGUP); + writel(0x0029FAAA, GPHCON); + + writel((1 << 12) | (0 << 11), GPJDAT); + writel(0x0016aaaa, GPJCON); + writel(~((0<<12)| (1<<11)), GPJUP); + + writel((0 << 12) | (0 << 11), GPJDAT); + writel(0x0016aaaa, GPJCON); + writel(0x00001fff, GPJUP); + + writel(0x00000000, DSC0); + writel(0x00000000, DSC1); + + /* + * USB port1 normal, USB port0 normal, USB1 pads for device + * PCLK output on CLKOUT0, UPLL CLK output on CLKOUT1, + */ + writel((readl(MISCCR) & ~0xFFFF) | 0x0140, MISCCR); + + /* ----------- configure the access to the outer space ---------- */ + reg = readl(BWSCON); + + /* CS#1 to access the network controller */ + reg &= ~0xf0; + reg |= 0xe0; + writel(0x1350, BANKCON1); + + /* CS#2 to the dual 16550 UART */ + reg &= ~0xf00; + reg |= 0x400; + writel(0x0d50, BANKCON2); + + writel(reg, BWSCON); + + /* release the reset signal to the network and UART device */ + reg = readl(MISCCR); + reg |= 0x10000; + writel(reg, MISCCR); + + return 0; +} diff --git a/arch/arm/boards/a9m2440/a9m2440.c b/arch/arm/boards/a9m2440/a9m2440.c new file mode 100644 index 0000000..2567f5e --- /dev/null +++ b/arch/arm/boards/a9m2440/a9m2440.c @@ -0,0 +1,271 @@ +/* + * Copyright (C) 2009 Juergen Beisert, 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 + * + */ + +/** + * @file + * @brief a9m2440 Specific Board Initialization routines + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "baseboards.h" + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = CS6_BASE, + .platform_data = &ram_pdata, +}; + +static struct s3c24x0_nand_platform_data nand_info = { + .nand_timing = CALC_NFCONF_TIMING(A9M2440_TACLS, A9M2440_TWRPH0, A9M2440_TWRPH1) +}; + +static struct device_d nand_dev = { + .name = "s3c24x0_nand", + .map_base = S3C24X0_NAND_BASE, + .platform_data = &nand_info, +}; + +/* + * cs8900 network controller onboard + * Connected to CS line 5 + A24 and interrupt line EINT9, + * data width is 16 bit + */ +static struct device_d network_dev = { + .name = "cs8900", + .map_base = CS5_BASE + (1 << 24) + 0x300, + .size = 16, +}; + +static int a9m2440_check_for_ram(uint32_t addr) +{ + uint32_t tmp1, tmp2; + int rc = 0; + + tmp1 = readl(addr); + tmp2 = readl(addr + sizeof(uint32_t)); + + writel(0xaaaaaaaa, addr); + writel(0x55555555, addr + sizeof(uint32_t)); + if ((readl(addr) != 0xaaaaaaaa) || (readl(addr + sizeof(uint32_t)) != 0x55555555)) + rc = 1; /* seems no RAM */ + + writel(0x55555555, addr); + writel(0xaaaaaaaa, addr + sizeof(uint32_t)); + if ((readl(addr) != 0x55555555) || (readl(addr + sizeof(uint32_t)) != 0xaaaaaaaa)) + rc = 1; /* seems no RAM */ + + writel(tmp1, addr); + writel(tmp2, addr + sizeof(uint32_t)); + + return rc; +} + +static void a9m2440_disable_second_sdram_bank(void) +{ + writel(readl(BANKCON7) & ~(0x3 << 15),BANKCON7); + writel(readl(MISCCR) | (1 << 18), MISCCR); /* disable clock */ +} + +static int a9m2440_devices_init(void) +{ + uint32_t reg; + + /* + * The special SDRAM setup code for this machine will always enable + * both SDRAM banks. But the second SDRAM device may not exists! + * So we must check here, if the second bank is populated to get the + * correct RAM size. + */ + switch (readl(BANKSIZE) & 0x7) { + case 0: + if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 32 * 1024 * 1024)) + a9m2440_disable_second_sdram_bank(); + break; + case 1: + if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 64 * 1024 * 1024)) + a9m2440_disable_second_sdram_bank(); + break; + case 2: + if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 128 * 1024 * 1024)) + a9m2440_disable_second_sdram_bank(); + break; + case 4: + case 5: + case 6: /* not supported on this machine */ + break; + default: + if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 16 * 1024 * 1024)) + a9m2440_disable_second_sdram_bank(); + break; + } + + sdram_dev.size = s3c24x0_get_memory_size(); + + /* ----------- configure the access to the outer space ---------- */ + reg = readl(BWSCON); + + /* CS#5 to access the network controller */ + reg &= ~0x00f00000; + reg |= 0x00d00000; /* 16 bit */ + writel(0x1f4c, BANKCON5); + + writel(reg, BWSCON); + +#ifdef CONFIG_MACH_A9M2410DEV + a9m2410dev_devices_init(); +#endif + + /* release the reset signal to external devices */ + reg = readl(MISCCR); + reg |= 0x10000; + writel(reg, MISCCR); + + /* ----------- the devices the boot loader should work with -------- */ + register_device(&nand_dev); + register_device(&sdram_dev); + register_device(&network_dev); + +#ifdef CONFIG_NAND + /* ----------- add some vital partitions -------- */ + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); +#endif + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)sdram_dev.map_base + 0x100); + armlinux_set_architecture(MACH_TYPE_A9M2440); + + return 0; +} + +device_initcall(a9m2440_devices_init); + +#ifdef CONFIG_S3C24XX_NAND_BOOT +void __bare_init nand_boot(void) +{ + s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0, 512); +} +#endif + +static struct device_d a9m2440_serial_device = { + .name = "s3c24x0_serial", + .map_base = UART1_BASE, + .size = UART1_SIZE, +}; + +static int a9m2440_console_init(void) +{ + register_device(&a9m2440_serial_device); + return 0; +} + +console_initcall(a9m2440_console_init); + +/** @page a9m2440 DIGI's a9m2440 + +This CPU card is based on a Samsung S3C2440 CPU. The card is shipped with: + +- S3C2440\@400 MHz or 533 MHz (ARM920T/ARMv4T) +- 16.9344 MHz crystal reference +- SDRAM 32/64/128 MiB + - Samsung K4M563233E-EE1H (one or two devices for 32 MiB or 64 MiB) + - 2M x 32bit x 4 Banks Mobile SDRAM + - CL2\@100 MHz (CAS/RAS delay 19ns) + - 105 MHz max + - collumn address size is 9 bits + - Row cycle time: 69ns + - Samsung K4M513233C-DG75 (one or two devices for 64 MiB or 128 MiB) + - 4M x 32bit x 4 Banks Mobile SDRAM + - CL2\@100MHz (CAS/RAS delay 18ns) + - 111 MHz max + - collumn address size is 9 bits + - Row cycle time: 63ns + - 64ms refresh period (4k) + - 90 pin FBGA + - 32 bit data bits + - Extended temperature range (-25�C...85�C) +- NAND Flash 32/64/128 MiB + - Samsung KM29U512T (NAND01GW3A0AN6) + - 64 MiB 3,3V 8-bit + - ID: 0xEC, 0x76, 0x??, 0xBD + - Samsung KM29U256T + - 32 MiB 3,3V 8-bit + - ID: 0xEC, 0x75, 0x??, 0xBD + - ST Micro + - 128 MiB 3,3V 8-bit + - ID: 0x20, 0x79 + - 30ns/40ns/20ns +- I2C interface, 100 KHz and 400 KHz + - Real Time Clock + - Dallas DS1337 + - address 0x68 + - EEPROM + - ST M24LC64 + - address 0x50 + - 16bit addressing +- LCD interface +- Touch Screen interface +- Camera interface +- I2S interface +- AC97 Audio-CODEC interface +- SD card interface +- 3 serial RS232 interfaces +- Host and device USB interface, USB1.1 compliant +- Ethernet interface + - 10Mbps, Cirrus Logic, CS8900A (on the CPU card) +- SPI interface +- JTAG interface + +How to get the binary image: + +Using the default configuration: + +@code +make ARCH=arm a9m2440_defconfig +@endcode + +Build the binary image: + +@code +make ARCH=arm CROSS_COMPILE=armv4compiler +@endcode + +@note replace the armv4compiler with your ARM v4 cross compiler. + +*/ diff --git a/arch/arm/boards/a9m2440/baseboards.h b/arch/arm/boards/a9m2440/baseboards.h new file mode 100644 index 0000000..ec80312 --- /dev/null +++ b/arch/arm/boards/a9m2440/baseboards.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2009 Juergen Beisert + * + * 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 + * + */ + +#ifdef CONFIG_MACH_A9M2410DEV +extern int a9m2410dev_devices_init(void); +#endif diff --git a/arch/arm/boards/a9m2440/config.h b/arch/arm/boards/a9m2440/config.h new file mode 100644 index 0000000..43cb6ab --- /dev/null +++ b/arch/arm/boards/a9m2440/config.h @@ -0,0 +1,73 @@ +/** + * @file + * @brief Global defintions for the ARM S3C2440 based a9m2440 CPU card + */ +/* This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/** + * The external clock reference is a 16.9344 MHz crystal + */ +#define S3C24XX_CLOCK_REFERENCE 16934400 + +/** + * Define the main clock configuration to be used in register CLKDIVN + * + * We must limit the frequency of the connected SDRAMs with the clock ratio + * setup to 1:4:8. This will result into FCLK:HCLK:PCLK = 400Mhz:100MHz:50MHz + */ +#define BOARD_SPECIFIC_CLKDIVN 0x05 + +/** + * Define the MPLL configuration to be used in register MPLLCON + * + * We want the MPLL to run at 399.65 MHz + */ +#define BOARD_SPECIFIC_MPLL ((0x6e << 12) + (3 << 4) + 1) + +/** + * Define the UPLL configuration to be used in register UPLLCON + * + * We want the UPLL to run at 47.98 MHz + */ +#define BOARD_SPECIFIC_UPLL ((0x3c << 12) + (4 << 4) + 2) + +/* + * Flash access timings + * Tacls = 0ns (but 20ns data setup time) + * Twrph0 = 25ns (write) 35ns (read) + * Twrph1 = 10ns (10ns data hold time) + * Read cycle time = 50ns + * + * Assumed HCLK is 100MHz + * Tacls = 1 (-> 20ns) + * Twrph0 = 3 (-> 40ns) + * Twrph1 = 1 (-> 20ns) + * Cycle time = 80ns + */ +#define A9M2440_TACLS 1 +#define A9M2440_TWRPH0 3 +#define A9M2440_TWRPH1 1 + +/* needed in the generic NAND boot code only */ +#ifdef CONFIG_S3C24XX_NAND_BOOT +# define BOARD_DEFAULT_NAND_TIMING CALC_NFCONF_TIMING(A9M2440_TACLS, A9M2440_TWRPH0, A9M2440_TWRPH1) +#endif + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/a9m2440/env/bin/_update b/arch/arm/boards/a9m2440/env/bin/_update new file mode 100644 index 0000000..b10682e --- /dev/null +++ b/arch/arm/boards/a9m2440/env/bin/_update @@ -0,0 +1,34 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/a9m2440/env/bin/boot b/arch/arm/boards/a9m2440/env/bin/boot new file mode 100644 index 0000000..86e22cf --- /dev/null +++ b/arch/arm/boards/a9m2440/env/bin/boot @@ -0,0 +1,40 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + root=nand + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$root = xnand ]; then + bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" +fi +if [ x$root = xnet ]; then + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" + if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" + else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" + fi +fi + +bootargs="$bootargs mtdparts=\"NAND 32MiB 3,3V 8-bit:$nand_parts\"" + +bootargs="$bootargs cs89x0_media=rj45 cs89x0_mac=$eth0.ethaddr" + +if [ x$kernel = xnet ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/a9m2440/env/bin/hush_hack b/arch/arm/boards/a9m2440/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/a9m2440/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/a9m2440/env/bin/init b/arch/arm/boards/a9m2440/env/bin/init new file mode 100644 index 0000000..5ae44dd --- /dev/null +++ b/arch/arm/boards/a9m2440/env/bin/init @@ -0,0 +1,34 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type update_root [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/a9m2440/env/bin/update_kernel b/arch/arm/boards/a9m2440/env/bin/update_kernel new file mode 100644 index 0000000..c43a557 --- /dev/null +++ b/arch/arm/boards/a9m2440/env/bin/update_kernel @@ -0,0 +1,13 @@ +#!/bin/sh + +. /env/config + +part=/dev/nand0.kernel.bb + +if [ x$1 = x ]; then + image=$uimage +else + image=$1 +fi + +. /env/bin/_update $image diff --git a/arch/arm/boards/a9m2440/env/bin/update_root b/arch/arm/boards/a9m2440/env/bin/update_root new file mode 100644 index 0000000..46cbca5 --- /dev/null +++ b/arch/arm/boards/a9m2440/env/bin/update_root @@ -0,0 +1,13 @@ +#!/bin/sh + +. /env/config + +part=/dev/nand0.root.bb + +if [ x$1 = x ]; then + image=$jffs2 +else + image=$1 +fi + +. /env/bin/_update $image diff --git a/arch/arm/boards/a9m2440/env/config b/arch/arm/boards/a9m2440/env/config new file mode 100644 index 0000000..936c35f --- /dev/null +++ b/arch/arm/boards/a9m2440/env/config @@ -0,0 +1,26 @@ +#!/bin/sh + +# can be either 'net' or 'nand'' +kernel=net +root=net + +uimage=uImage-a9m2440 +jffs2=root-a9m2440.jffs2 + +autoboot_timeout=3 + +nfsroot="/nfsexport/OSELAS.BSP-Hesch-TMU-1/platform-FS_A9M2440/root" +bootargs="console=ttySAC0,38400" + +nand_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" +rootpart_nand="/dev/mtdblock3" + +# use 'dhcp' to do dhcp in barebox and in kernel +#ip=dhcp + +# or set your networking parameters here +eth0.ipaddr=192.168.42.32 +eth0.netmask=255.255.0.0 +eth0.gateway=192.168.23.1 +eth0.serverip=192.168.23.2 +eth0.ethaddr=00:04:f3:00:06:35 diff --git a/arch/arm/boards/a9m2440/lowlevel_init.S b/arch/arm/boards/a9m2440/lowlevel_init.S new file mode 100644 index 0000000..4b5c596 --- /dev/null +++ b/arch/arm/boards/a9m2440/lowlevel_init.S @@ -0,0 +1,240 @@ +/* + * + */ + +#include +#include + + .section ".text_bare_init.board_init_lowlevel","ax" + +/* + * To be able to setup the SDRAM interface correctly, we need some + * external information about the connected SDRAM devices. + * + * When we set GPH8, we can read at GPB: + * Bit 0..1: Memory device size -> 00=16M, 01=64M, 10=32M, 11=128M + * Bit 2: CL setting + * + * Some remarks: The CL setting seems useless. It always signals a CL3 + * requirement, but the SDRAM types I found on the cards are supporting + * CL2 @ 100 MHz. But also these SDRAM types are only support 105 MHz max. + * So, we never need CL3 because we can't run the CPU at 533 MHz (which + * implies an 133 MHz SDRAM clock). + * All devices are connected via 32 bit databus + * + * Note: I was able to check the 32 MiB and 64 MiB configuration only. I didn't + * had access to a 16 MiB nor 128 MiB config. + * + */ + +sdram_init: + /* + * Read the configuration. After reset until any GPIO port is + * configured yet, these pins show external settings, to detect + * the SDRAM size. + */ + ldr r1, =GPBDAT + ldr r4, [r1] + and r4, r4, #0x3 + + ldr r1, =S3C24X0_MEMCTL_BASE + /* configure both SDRAM areas with 32 bit data bus width */ + ldr r0, =((0x2 << 24) + (0x2 << 28)) + str r0, [r1], #0x1c /* post add register offset for bank6 */ + + /* + * With the configuration we simply need to calculate an offset into + * our table with the predefined SDRAM settings + */ + adr r0, SDRAMDATA + mov r2, #6*4 /* # of bytes per table entry */ + mul r3, r4, r2 + add r0, r0, r3 /* start address of the entry */ + + /* + * store the table entry data into the registers + */ +1: + ldr r3, [r0], #4 + str r3, [r1], #4 + subs r2, r2, #4 + bne 1b + +/* TODO: Check if the second bank is populated, and switch it off if not */ + + mov pc, lr + +/* + * we need 4 sets of memory settings per main CPU clock speed + * + * 400MHz main speed: + * - 16 MiB in the first bank, maybe 16 MiB in the second bank (untested!) + * - 32 MiB in the first bank, maybe 32 MiB in the second bank (CL=2) + * - 64 MiB in the first bank, maybe 64 MiB in the second bank (CL=2) + * - 128 MiB in the first bank, maybe 128 MiB in the second bank (untested!) + * + * Note: SDRAM clock runs at 100MHz + */ + +SDRAMDATA: +/* --------------------------- 16 MiB @ 100MHz --------------------------- */ + /* + * - MT = 11 (= sync dram type) + * - Trcd = 01 (= CL3) + * - SCAN = 00 (= 8 bit collumns) + */ + .word ((0x3 << 15) + (0x1 << 2) + (0x0)) + .word ((0x3 << 15) + (0x1 << 2) + (0x0)) + /* + * SDRAM refresh settings + * - REFEN = 1 (= refresh enabled) + * - TREFMD = 0 (= auto refresh) + * - Trp = 00 (= 2 RAS precharge clocks) + * - Tsrc = 11 (= 7 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) + * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = FIXME + */ + .word ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x3 << 18) + 468) + /* + * SDRAM banksize + * - BURST_EN = 0 (= burst mode disabled) + * - SCKE_EN = 1 (= SDRAM SCKE enabled) + * - SCLK_EN = 1 (= clock active only during accesses) + * - BK67MAP = 010 (= 128MiB) FIXME????? + */ + .word ((0 << 7) + (1 << 5) + (1 << 4) + 2) + /* + * SDRAM mode register + * CL = 010 (= 2 clocks) + */ + .word (0x2 << 4) + .word (0x2 << 4) + +/* ------------- one or two banks with 64 MiB @ 100MHz -------------------- */ + + /* + * - MT = 11 (= sync dram type) + * - Trcd = 00 (= CL2) + * - SCAN = 01 (= 9 bit collumns) + */ + .word ((0x3 << 15) + (0x0 << 2) + (0x1)) + .word ((0x3 << 15) + (0x0 << 2) + (0x1)) + /* + * SDRAM refresh settings + * - REFEN = 1 (= refresh enabled) + * - TREFMD = 0 (= auto refresh) + * - Trp = 00 (= 2 RAS precharge clocks) + * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) + * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = 489 + */ + .word ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x1 << 18) + 489) + /* + * SDRAM banksize + * - BURST_EN = 1 (= burst mode enabled) + * - SCKE_EN = 1 (= SDRAM SCKE enabled) + * - SCLK_EN = 1 (= clock active only during accesses) + * - BK67MAP = 001 (= 64 MiB) + */ + .word ((1 << 7) + (1 << 5) + (1 << 4) + 1) + /* + * SDRAM mode register + * CL = 010 (= 2 clocks) + */ + .word (0x2 << 4) + .word (0x2 << 4) + +/* ------------- one or two banks with 32 MiB @ 100MHz -------------------- */ + + /* + * - MT = 11 (= sync dram type) + * - Trcd = 00 (= CL2) + * - SCAN = 01 (= 9 bit collumns) + */ + .word ((0x3 << 15) + (0x0 << 2) + (0x1)) + .word ((0x3 << 15) + (0x0 << 2) + (0x1)) + /* + * SDRAM refresh settings + * - REFEN = 1 (= refresh enabled) + * - TREFMD = 0 (= auto refresh) + * - Trp = 00 (= 2 RAS precharge clocks) + * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) + * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = 489 + */ + .word ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x1 << 18) + 489) + /* + * SDRAM banksize + * - BURST_EN = 1 (= burst mode enabled) + * - SCKE_EN = 1 (= SDRAM SCKE enabled) + * - SCLK_EN = 1 (= clock active only during accesses) + * - BK67MAP = 000 (= 32 MiB) + */ + .word ((1 << 7) + (1 << 5) + (1 << 4) + 0) + /* + * SDRAM mode register + * CL = 010 (= 2 clocks) + */ + .word (0x2 << 4) + .word (0x2 << 4) + +/* ------------ one or two banks with 128 MiB @ 100MHz -------------------- */ + + /* + * - MT = 11 (= sync dram type) + * - Trcd = 00 (= CL2) + * - SCAN = 01 (= 9 bit collumns) + */ + .word ((0x3 << 15) + (0x0 << 2) + (0x1)) + .word ((0x3 << 15) + (0x0 << 2) + (0x1)) + /* + * SDRAM refresh settings + * - REFEN = 1 (= refresh enabled) + * - TREFMD = 0 (= auto refresh) + * - Trp = 00 (= 2 RAS precharge clocks) + * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) + * - Refrsh = 2^11 + 1 - 100 * 7.5 = 2049 - FIXME = 1259 + */ + .word ((0x1 << 23) + (0x0 << 22) + (0x1 << 20) + (0x3 << 18) + 1259) + /* + * SDRAM banksize + * - BURST_EN = 0 (= burst mode disabled) + * - SCKE_EN = 1 (= SDRAM SCKE enabled) + * - SCLK_EN = 1 (= clock active only during accesses) + * - BK67MAP = 010 (= 128MiB) + */ + .word (0x32) + /* + * SDRAM mode register + * CL = 010 (= 2 clocks) + */ + .word (0x2 << 4) + .word (0x2 << 4) + +/* ------------------------------------------------------------------------ */ + +.globl board_init_lowlevel +board_init_lowlevel: + + mov r10, lr /* save the link register */ + + bl s3c24x0_disable_wd + + /* skip everything here if we are already running from SDRAM */ + cmp pc, #S3C24X0_SDRAM_BASE + blo 1f + cmp pc, #S3C24X0_SDRAM_END + bhs 1f + + mov pc, r10 + +/* we are running from NOR or NAND/SRAM memory. Do further initialisation */ +1: + bl s3c24x0_pll_init + + bl sdram_init + +#ifdef CONFIG_S3C24XX_NAND_BOOT + mov lr, r10 /* restore the link register */ +/* up to here we are running from the internal SRAM area */ + b s3c24x0_nand_boot /* does return directly to our caller into SDRAM */ +#else + mov pc, r10 +#endif diff --git a/arch/arm/boards/at91sam9260ek/Makefile b/arch/arm/boards/at91sam9260ek/Makefile new file mode 100644 index 0000000..73ef72e --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/Makefile @@ -0,0 +1,2 @@ +obj-y += lowlevel_init.o +obj-y += init.o diff --git a/arch/arm/boards/at91sam9260ek/config.h b/arch/arm/boards/at91sam9260ek/config.h new file mode 100644 index 0000000..afd8563 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/config.h @@ -0,0 +1,6 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/at91sam9260ek/env/bin/_update b/arch/arm/boards/at91sam9260ek/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/at91sam9260ek/env/bin/boot b/arch/arm/boards/at91sam9260ek/env/bin/boot new file mode 100644 index 0000000..ed6f11a --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/boot @@ -0,0 +1,38 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xflash ]; then + root=flash + kernel=flash +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xflash ]; then + bootargs="$bootargs root=$rootpart rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=192.168.23.111:$nfsroot" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage + bootm uImage +else + bootm /dev/nor0.kernel +fi + diff --git a/arch/arm/boards/at91sam9260ek/env/bin/init b/arch/arm/boards/at91sam9260ek/env/bin/init new file mode 100644 index 0000000..b8d8399 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/init @@ -0,0 +1,19 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type udate_root [] to update rootfs into flash" + echo + exit +fi + +boot \ No newline at end of file diff --git a/arch/arm/boards/at91sam9260ek/env/bin/pcidmaloop b/arch/arm/boards/at91sam9260ek/env/bin/pcidmaloop new file mode 100644 index 0000000..24e76cb --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/pcidmaloop @@ -0,0 +1,14 @@ +pci stat +pci stat -c +while true; do + pci readm 32 0xA1000000 32 -s + pci readm 32 0xA2000000 256 -s + pci dmatx 2000 a2000100 128 -s + pci writem 32 0xa2000100 0x12345678 4 -s + pci readm 32 0xA3000000 256 -s + pci dmatx 2000 a3000040 128 -s + pci writem 32 0xa3000100 0x12345678 4 -s + pci readm 32 0xA4000000 16 -s + pci dmatx 2000 a4000080 4 -s + pci writem 32 0xa4000080 0x12345678 4 -s +done diff --git a/arch/arm/boards/at91sam9260ek/env/bin/pciloop b/arch/arm/boards/at91sam9260ek/env/bin/pciloop new file mode 100644 index 0000000..4a804f9 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/pciloop @@ -0,0 +1,13 @@ +pci stat +pci stat -c +while true; do + pci readm 32 0xA1000000 32 -s + pci readm 32 0xA2000000 256 -s + pci writem 32 0xa2000100 0x12345678 4 -s + pci readm 32 0xA3000000 256 -s + pci writem 32 0xa3000100 0x12345678 4 -s + pci readm 32 0xA4000000 16 -s + pci writem 32 0xa4000080 0x12345678 4 -s + +# pci dmatx 2000 a3000040 128 -s +done diff --git a/arch/arm/boards/at91sam9260ek/env/bin/update_kernel b/arch/arm/boards/at91sam9260ek/env/bin/update_kernel new file mode 100644 index 0000000..1ad95fc --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/update_kernel @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$uimage +part=/dev/nor0.kernel + +. /env/bin/_update $1 diff --git a/arch/arm/boards/at91sam9260ek/env/bin/update_root b/arch/arm/boards/at91sam9260ek/env/bin/update_root new file mode 100644 index 0000000..b757a5b --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/update_root @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 +part=/dev/nor0.root + +. /env/bin/_update $1 diff --git a/arch/arm/boards/at91sam9260ek/env/config b/arch/arm/boards/at91sam9260ek/env/config new file mode 100644 index 0000000..71d6f88 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/config @@ -0,0 +1,20 @@ +#!/bin/sh + +# can be either 'net' or 'flash' +kernel=net +root=net + +# use 'dhcp' todo dhcp in barebox and in kernel +ip=dhcp + +# +# setup default ethernet address +# +eth0.serverip=192.168.23.108 + +uimage=uImage-at91sam9260ek + +autoboot_timeout=3 + +nfsroot="/home/jbe/pengutronix/bsp/OSELAS.BSP-Phytec-phyCORE-i.MX27-trunk/root,v3" +bootargs="console=ttyS0,115200 rw init=/bin/sh" diff --git a/arch/arm/boards/at91sam9260ek/init.c b/arch/arm/boards/at91sam9260ek/init.c new file mode 100644 index 0000000..9fd7525 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/init.c @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct atmel_nand_data nand_pdata = { + .ale = 21, + .cle = 22, +/* .det_pin = ... not connected */ + .ecc_base = (void __iomem *)(AT91_BASE_SYS + AT91_ECC), + .ecc_mode = NAND_ECC_HW, + .rdy_pin = AT91_PIN_PC13, + .enable_pin = AT91_PIN_PC14, +#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16) + .bus_width_16 = 1, +#else + .bus_width_16 = 0, +#endif +}; + +static struct sam9_smc_config ek_nand_smc_config = { + .ncs_read_setup = 0, + .nrd_setup = 1, + .ncs_write_setup = 0, + .nwe_setup = 1, + + .ncs_read_pulse = 3, + .nrd_pulse = 3, + .ncs_write_pulse = 3, + .nwe_pulse = 3, + + .read_cycle = 5, + .write_cycle = 5, + + .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, + .tdf_cycles = 2, +}; + +static void ek_add_device_nand(void) +{ + /* setup bus-width (8 or 16) */ + if (nand_pdata.bus_width_16) + ek_nand_smc_config.mode |= AT91_SMC_DBW_16; + else + ek_nand_smc_config.mode |= AT91_SMC_DBW_8; + + /* configure chip-select 3 (NAND) */ + sam9_smc_configure(3, &ek_nand_smc_config); + + at91_add_device_nand(&nand_pdata); +} + +static struct at91_ether_platform_data macb_pdata = { + .flags = AT91SAM_ETHER_RMII, + .phy_addr = 0, +}; + +static void at91sam9260ek_phy_reset(void) +{ + unsigned long rstc; + at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_EMAC); + + at91_set_gpio_input(AT91_PIN_PA14, 0); + at91_set_gpio_input(AT91_PIN_PA15, 0); + at91_set_gpio_input(AT91_PIN_PA17, 0); + at91_set_gpio_input(AT91_PIN_PA25, 0); + at91_set_gpio_input(AT91_PIN_PA26, 0); + at91_set_gpio_input(AT91_PIN_PA28, 0); + + rstc = at91_sys_read(AT91_RSTC_MR) & AT91_RSTC_ERSTL; + + /* Need to reset PHY -> 500ms reset */ + at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | + (AT91_RSTC_ERSTL & (0x0d << 8)) | + AT91_RSTC_URSTEN); + + at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_EXTRST); + + /* Wait for end hardware reset */ + while (!(at91_sys_read(AT91_RSTC_SR) & AT91_RSTC_NRSTL)); + + /* Restore NRST value */ + at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | + (rstc) | + AT91_RSTC_URSTEN); +} + +static int at91sam9260ek_devices_init(void) +{ + ek_add_device_nand(); + at91sam9260ek_phy_reset(); + at91_add_device_eth(&macb_pdata); + + at91_add_device_sdram(64 * 1024 * 1024); + armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); + armlinux_set_architecture(MACH_TYPE_AT91SAM9260EK); + + devfs_add_partition("nand0", 0x00000, 0x80000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + devfs_add_partition("nand0", 0x40000, 0x40000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + + return 0; +} + +device_initcall(at91sam9260ek_devices_init); + +static int at91sam9260ek_console_init(void) +{ + at91_register_uart(0, 0); + return 0; +} + +console_initcall(at91sam9260ek_console_init); diff --git a/arch/arm/boards/at91sam9260ek/lowlevel_init.S b/arch/arm/boards/at91sam9260ek/lowlevel_init.S new file mode 100644 index 0000000..4961682 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/lowlevel_init.S @@ -0,0 +1,26 @@ +/* + * Board specific setup info + * + * + * 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 + */ + +.globl board_init_lowlevel +board_init_lowlevel: + mov pc, lr diff --git a/arch/arm/boards/at91sam9263ek/Makefile b/arch/arm/boards/at91sam9263ek/Makefile new file mode 100644 index 0000000..eb072c0 --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/Makefile @@ -0,0 +1 @@ +obj-y += init.o diff --git a/arch/arm/boards/at91sam9263ek/config.h b/arch/arm/boards/at91sam9263ek/config.h new file mode 100644 index 0000000..9cc8af2 --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/config.h @@ -0,0 +1,110 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#define AT91_MASTER_CLOCK 100000000 /* peripheral = main / 2 */ + +#define MASTER_PLL_MUL 171 +#define MASTER_PLL_DIV 14 + +/* clocks */ +#define CONFIG_SYS_MOR_VAL \ + (AT91_PMC_MOSCEN | \ + (255 << 8)) /* Main Oscillator Start-up Time */ +#define CONFIG_SYS_PLLAR_VAL \ + (AT91_PMC_PLLA_WR_ERRATA | /* Bit 29 must be 1 when prog */ \ + AT91_PMC_OUT | \ + AT91_PMC_PLLCOUNT | /* PLL Counter */ \ + (2 << 28) | /* PLL Clock Frequency Range */ \ + ((MASTER_PLL_MUL - 1) << 16) | (MASTER_PLL_DIV)) + +/* PCK/2 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR1_VAL \ + (AT91_PMC_CSS_SLOW | \ + AT91_PMC_PRES_1 | \ + AT91SAM9_PMC_MDIV_2 | \ + AT91_PMC_PDIV_1) +/* PCK/2 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR2_VAL \ + (AT91_PMC_CSS_PLLA | \ + AT91_PMC_PRES_1 | \ + AT91SAM9_PMC_MDIV_2 | \ + AT91_PMC_PDIV_1) + +/* define PDC[31:16] as DATA[31:16] */ +#define CONFIG_SYS_PIOD_PDR_VAL1 0xFFFF0000 +/* no pull-up for D[31:16] */ +#define CONFIG_SYS_PIOD_PPUDR_VAL 0xFFFF0000 +/* EBI0_CSA, CS1 SDRAM, CS3 NAND Flash, 3.3V memories */ +#define CONFIG_SYS_MATRIX_EBI0CSA_VAL \ + (AT91_MATRIX_EBI0_DBPUC | AT91_MATRIX_EBI0_VDDIOMSEL_3_3V | \ + AT91_MATRIX_EBI0_CS1A_SDRAMC) + +/* SDRAM */ +/* SDRAMC_MR Mode register */ +#define CONFIG_SYS_SDRC_MR_VAL1 0 +/* SDRAMC_TR - Refresh Timer register */ +#define CONFIG_SYS_SDRC_TR_VAL1 0x13C +/* SDRAMC_CR - Configuration register*/ +#define CONFIG_SYS_SDRC_CR_VAL \ + (AT91_SDRAMC_NC_9 | \ + AT91_SDRAMC_NR_13 | \ + AT91_SDRAMC_NB_4 | \ + AT91_SDRAMC_CAS_3 | \ + AT91_SDRAMC_DBW_32 | \ + (1 << 8) | /* Write Recovery Delay */ \ + (7 << 12) | /* Row Cycle Delay */ \ + (2 << 16) | /* Row Precharge Delay */ \ + (2 << 20) | /* Row to Column Delay */ \ + (5 << 24) | /* Active to Precharge Delay */ \ + (1 << 28)) /* Exit Self Refresh to Active Delay */ + +/* Memory Device Register -> SDRAM */ +#define CONFIG_SYS_SDRC_MDR_VAL AT91_SDRAMC_MD_SDRAM +#define CONFIG_SYS_SDRC_MR_VAL2 AT91_SDRAMC_MODE_PRECHARGE +#define CONFIG_SYS_SDRAM_VAL1 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL3 AT91_SDRAMC_MODE_REFRESH +#define CONFIG_SYS_SDRAM_VAL2 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL3 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL4 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL5 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL6 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL7 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL8 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL9 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL4 AT91_SDRAMC_MODE_LMR +#define CONFIG_SYS_SDRAM_VAL10 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL5 AT91_SDRAMC_MODE_NORMAL +#define CONFIG_SYS_SDRAM_VAL11 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_TR_VAL2 1200 /* SDRAM_TR */ +#define CONFIG_SYS_SDRAM_VAL12 0 /* SDRAM_BASE */ + +/* setup SMC0, CS0 (NOR Flash) - 16-bit, 15 WS */ +#define CONFIG_SYS_SMC0_SETUP0_VAL \ + (AT91_SMC_NWESETUP_(10) | AT91_SMC_NCS_WRSETUP_(10) | \ + AT91_SMC_NRDSETUP_(10) | AT91_SMC_NCS_RDSETUP_(10)) +#define CONFIG_SYS_SMC0_PULSE0_VAL \ + (AT91_SMC_NWEPULSE_(11) | AT91_SMC_NCS_WRPULSE_(11) | \ + AT91_SMC_NRDPULSE_(11) | AT91_SMC_NCS_RDPULSE_(11)) +#define CONFIG_SYS_SMC0_CYCLE0_VAL \ + (AT91_SMC_NWECYCLE_(22) | AT91_SMC_NRDCYCLE_(22)) +#define CONFIG_SYS_SMC0_MODE0_VAL \ + (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ + AT91_SMC_DBW_16 | \ + AT91_SMC_TDFMODE | \ + AT91_SMC_TDF_(6)) + +/* user reset enable */ +#define CONFIG_SYS_RSTC_RMR_VAL \ + (AT91_RSTC_KEY | \ + AT91_RSTC_PROCRST | \ + AT91_RSTC_RSTTYP_WAKEUP | \ + AT91_RSTC_RSTTYP_WATCHDOG) + +/* Disable Watchdog */ +#define CONFIG_SYS_WDTC_WDMR_VAL \ + (AT91_WDT_WDIDLEHLT | AT91_WDT_WDDBGHLT | \ + AT91_WDT_WDV | \ + AT91_WDT_WDDIS | \ + AT91_WDT_WDD) + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/at91sam9263ek/env/bin/_update b/arch/arm/boards/at91sam9263ek/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/at91sam9263ek/env/bin/boot b/arch/arm/boards/at91sam9263ek/env/bin/boot new file mode 100644 index 0000000..533dea7 --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/bin/boot @@ -0,0 +1,47 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + root=nand + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$1 = xnor ]; then + root=nor + kernel=nor +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xnand ]; then + bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" +elif [ x$root = xnor ]; then + bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +elif [ $kernel = nor ]; then + bootm /dev/nor0.kernel +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/at91sam9263ek/env/bin/hush_hack b/arch/arm/boards/at91sam9263ek/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/at91sam9263ek/env/bin/init b/arch/arm/boards/at91sam9263ek/env/bin/init new file mode 100644 index 0000000..eaa298d --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/bin/init @@ -0,0 +1,38 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nor0 ]; then + addpart /dev/nor0 $nor_parts +fi + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel nor [] to update kernel into flash" + echo "type update_root nor [] to update rootfs into flash" + echo "type update_barebox_xmodem nor to update barebox into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/at91sam9263ek/env/bin/update_barebox_xmodem b/arch/arm/boards/at91sam9263ek/env/bin/update_barebox_xmodem new file mode 100644 index 0000000..39818b5 --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/bin/update_barebox_xmodem @@ -0,0 +1,26 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + part=/dev/nand0.barebox +elif [ x$1 = xnor ]; then + part=/dev/nor0.barebox +else + echo "usage: $0 nor|nand" + exit 1 +fi + +loadb -f barebox.bin -c + +unprotect $part +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing barebox.bin to $part" +echo +cp barebox.bin $part +crc32 -f barebox.bin +crc32 -f $part diff --git a/arch/arm/boards/at91sam9263ek/env/bin/update_kernel b/arch/arm/boards/at91sam9263ek/env/bin/update_kernel new file mode 100644 index 0000000..05c822d --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/bin/update_kernel @@ -0,0 +1,15 @@ +#!/bin/sh + +. /env/config + +image=$uimage +if [ x$1 = xnand ]; then + part=/dev/nand0.kernel.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.kernel +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/arch/arm/boards/at91sam9263ek/env/bin/update_root b/arch/arm/boards/at91sam9263ek/env/bin/update_root new file mode 100644 index 0000000..a751372 --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/bin/update_root @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 +if [ x$1 = xnand ]; then + part=/dev/nand0.root.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.root +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 + diff --git a/arch/arm/boards/at91sam9263ek/env/config b/arch/arm/boards/at91sam9263ek/env/config new file mode 100644 index 0000000..4b322ad --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/env/config @@ -0,0 +1,28 @@ +#!/bin/sh + +# can be either 'net', 'nor' or 'nand'' +kernel=net +root=net + +uimage=uImage +jffs2=root.jffs2 + +autoboot_timeout=3 + +nfsroot="" +bootargs="console=ttyS0,115200" + +nor_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" +rootpart_nor="/dev/mtdblock3" + +#nand_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" +#rootpart_nand="/dev/mtdblock7" + +# use 'dhcp' to do dhcp in barebox and in kernel +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=192.168.23.1 diff --git a/arch/arm/boards/at91sam9263ek/init.c b/arch/arm/boards/at91sam9263ek/init.c new file mode 100644 index 0000000..21803ca --- /dev/null +++ b/arch/arm/boards/at91sam9263ek/init.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD + * + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct atmel_nand_data nand_pdata = { + .ale = 21, + .cle = 22, +/* .det_pin = ... not connected */ + .ecc_base = (void __iomem *)(AT91_BASE_SYS + AT91_ECC0), + .ecc_mode = NAND_ECC_HW, + .rdy_pin = AT91_PIN_PA22, + .enable_pin = AT91_PIN_PD15, +#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16) + .bus_width_16 = 1, +#else + .bus_width_16 = 0, +#endif +}; + +static struct sam9_smc_config ek_nand_smc_config = { + .ncs_read_setup = 0, + .nrd_setup = 1, + .ncs_write_setup = 0, + .nwe_setup = 1, + + .ncs_read_pulse = 3, + .nrd_pulse = 3, + .ncs_write_pulse = 3, + .nwe_pulse = 3, + + .read_cycle = 5, + .write_cycle = 5, + + .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, + .tdf_cycles = 2, +}; + +static void ek_add_device_nand(void) +{ + /* setup bus-width (8 or 16) */ + if (nand_pdata.bus_width_16) + ek_nand_smc_config.mode |= AT91_SMC_DBW_16; + else + ek_nand_smc_config.mode |= AT91_SMC_DBW_8; + + /* configure chip-select 3 (NAND) */ + sam9_smc_configure(3, &ek_nand_smc_config); + + at91_add_device_nand(&nand_pdata); +} + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = AT91_CHIPSELECT_0, + .size = 8 * 1024 * 1024, +}; + +static struct at91_ether_platform_data macb_pdata = { + .flags = AT91SAM_ETHER_RMII, + .phy_addr = 0, +}; + +static int at91sam9263ek_devices_init(void) +{ + /* + * PB27 enables the 50MHz oscillator for Ethernet PHY + * 1 - enable + * 0 - disable + */ + at91_set_gpio_output(AT91_PIN_PB27, 1); + at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ + + /* Enable clock */ + at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); + + at91_add_device_sdram(64 * 1024 * 1024); + ek_add_device_nand(); + at91_add_device_eth(&macb_pdata); + register_device(&cfi_dev); + +#if defined(CONFIG_DRIVER_CFI) || defined(CONFIG_DRIVER_CFI_OLD) + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self"); + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); +#elif defined(CONFIG_NAND_ATMEL) + devfs_add_partition("nand0", 0x00000, 0x80000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + devfs_add_partition("nand0", 0x40000, 0x40000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); +#endif + + armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); + armlinux_set_architecture(MACH_TYPE_AT91SAM9263EK); + + return 0; +} + +device_initcall(at91sam9263ek_devices_init); + +static int at91sam9263ek_console_init(void) +{ + at91_register_uart(0, 0); + return 0; +} + +console_initcall(at91sam9263ek_console_init); diff --git a/arch/arm/boards/edb93xx/Makefile b/arch/arm/boards/edb93xx/Makefile new file mode 100644 index 0000000..e19cd7b --- /dev/null +++ b/arch/arm/boards/edb93xx/Makefile @@ -0,0 +1,2 @@ + +obj-y += edb93xx.o flash_cfg.o pll_cfg.o sdram_cfg.o diff --git a/arch/arm/boards/edb93xx/config.h b/arch/arm/boards/edb93xx/config.h new file mode 100644 index 0000000..6ae9a40e --- /dev/null +++ b/arch/arm/boards/edb93xx/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/edb93xx/early_udelay.h b/arch/arm/boards/edb93xx/early_udelay.h new file mode 100644 index 0000000..185283d --- /dev/null +++ b/arch/arm/boards/edb93xx/early_udelay.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * 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 + +/* delay execution before timers are initialized */ +static inline void early_udelay(uint32_t usecs) +{ + /* loop takes 4 cycles at 5.0ns (fastest case, running at 200MHz) */ + register uint32_t loops = usecs * (1000 / 20); + + __asm__ volatile ("1:\n" + "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0" (loops)); +} diff --git a/arch/arm/boards/edb93xx/edb93xx.c b/arch/arm/boards/edb93xx/edb93xx.c new file mode 100644 index 0000000..b0078a5 --- /dev/null +++ b/arch/arm/boards/edb93xx/edb93xx.c @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "edb93xx.h" + +#define DEVCFG_U1EN (1 << 18) + +/* + * Up to 32MiB NOR type flash, connected to + * CS line 6, data width is 16 bit + */ +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0x60000000, + .size = EDB93XX_CFI_FLASH_SIZE, +}; + +static struct memory_platform_data ram_dev_pdata0 = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram0_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK0_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK0_SIZE, + .platform_data = &ram_dev_pdata0, +}; + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) +static struct memory_platform_data ram_dev_pdata1 = { + .name = "ram1", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram1_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK1_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK1_SIZE, + .platform_data = &ram_dev_pdata1, +}; +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) +static struct memory_platform_data ram_dev_pdata2 = { + .name = "ram2", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram2_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK2_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK2_SIZE, + .platform_data = &ram_dev_pdata2, +}; +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) +static struct memory_platform_data ram_dev_pdata3 = { + .name = "ram3", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram3_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK3_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK3_SIZE, + .platform_data = &ram_dev_pdata3, +}; +#endif + +static struct device_d eth_dev = { + .name = "ep93xx_eth", +}; + +static int ep93xx_devices_init(void) +{ + register_device(&cfi_dev); + + /* + * Create partitions that should be + * not touched by any regular user + */ + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); + + protect_file("/dev/env0", 1); + + register_device(&sdram0_dev); +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + register_device(&sdram1_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + register_device(&sdram2_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + register_device(&sdram3_dev); +#endif + + armlinux_add_dram(&sdram0_dev); +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + armlinux_add_dram(&sdram1_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + armlinux_add_dram(&sdram2_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + armlinux_add_dram(&sdram3_dev); +#endif + + register_device(ð_dev); + + armlinux_set_bootparams((void *)CONFIG_EP93XX_SDRAM_BANK0_BASE + 0x100); + + armlinux_set_architecture(MACH_TYPE); + + return 0; +} + +device_initcall(ep93xx_devices_init); + +static struct device_d edb93xx_serial_device = { + .name = "pl010_serial", + .map_base = UART1_BASE, + .size = 4096, +}; + +static int edb93xx_console_init(void) +{ + struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; + + /* + * set UARTBAUD bit to drive UARTs with 14.7456MHz instead of + * 14.7456/2 MHz + */ + uint32_t value = readl(&syscon->pwrcnt); + value |= SYSCON_PWRCNT_UART_BAUD; + writel(value, &syscon->pwrcnt); + + /* Enable UART1 */ + value = readl(&syscon->devicecfg); + value |= DEVCFG_U1EN; + writel(0xAA, &syscon->sysswlock); + writel(value, &syscon->devicecfg); + + register_device(&edb93xx_serial_device); + + return 0; +} + +console_initcall(edb93xx_console_init); diff --git a/arch/arm/boards/edb93xx/edb93xx.dox b/arch/arm/boards/edb93xx/edb93xx.dox new file mode 100644 index 0000000..3964d55 --- /dev/null +++ b/arch/arm/boards/edb93xx/edb93xx.dox @@ -0,0 +1,108 @@ +/** @page edb9301 Cirrus Logic EDB9301 + +This boards is based on a Cirrus Logic EP9301 CPU. The board is shipped with: + +- 16MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM on CS3 +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec + +*/ + +/** @page edb9302 Cirrus Logic EDB9302 + +This board is based on a Cirrus Logic EP9302 CPU. The board is shipped with: + +- 16MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM on CS3 +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec + +*/ + +/** @page edb9302a Cirrus Logic EDB9302A + +This board is based on a Cirrus Logic EP9302 CPU. The board is shipped with: + +- 16MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM on CS0 +- 512kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec + +*/ + +/** @page edb9307 Cirrus Logic EDB9307 + +This board is based on a Cirrus Logic EP9307 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS3 +- 512kiB asynchronous SRAM +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9307a Cirrus Logic EDB9307A + +This board is based on a Cirrus Logic EP9307 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS0 +- 512kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9312 Cirrus Logic EDB9312 + +This board is based on a Cirrus Logic EP9312 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS3 +- 512kiB asynchronous SRAM +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9315 Cirrus Logic EDB9315 + +This board is based on a Cirrus Logic EP9315 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS3 +- 512kiB asynchronous SRAM +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9315a Cirrus Logic EDB9315A + +This board is based on a Cirrus Logic EP9315 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS0 +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ \ No newline at end of file diff --git a/arch/arm/boards/edb93xx/edb93xx.h b/arch/arm/boards/edb93xx/edb93xx.h new file mode 100644 index 0000000..5e5c6f5 --- /dev/null +++ b/arch/arm/boards/edb93xx/edb93xx.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * 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 + */ + +#if defined(CONFIG_MACH_EDB9301) +#define MACH_TYPE MACH_TYPE_EDB9301 +#elif defined(CONFIG_MACH_EDB9302) +#define MACH_TYPE MACH_TYPE_EDB9302 +#elif defined(CONFIG_MACH_EDB9302A) +#define MACH_TYPE MACH_TYPE_EDB9302A +#elif defined(CONFIG_MACH_EDB9307) +#define MACH_TYPE MACH_TYPE_EDB9307 +#elif defined(CONFIG_MACH_EDB9307A) +#define MACH_TYPE MACH_TYPE_EDB9307A +#elif defined(CONFIG_MACH_EDB9312) +#define MACH_TYPE MACH_TYPE_EDB9312 +#elif defined(CONFIG_MACH_EDB9315) +#define MACH_TYPE MACH_TYPE_EDB9315 +#elif defined(CONFIG_MACH_EDB9315A) +#define MACH_TYPE MACH_TYPE_EDB9315A +#endif + +#if defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) || \ + defined(CONFIG_MACH_EDB9302A) +#define EDB93XX_CFI_FLASH_SIZE (16 * 1024 * 1024) +#elif defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) || \ + defined(CONFIG_MACH_EDB9312) || defined(CONFIG_MACH_EDB9315) || \ + defined(CONFIG_MACH_EDB9315A) +#define EDB93XX_CFI_FLASH_SIZE (32 * 1024 * 1024) +#endif diff --git a/arch/arm/boards/edb93xx/env/bin/boot b/arch/arm/boards/edb93xx/env/bin/boot new file mode 100644 index 0000000..143f3d0 --- /dev/null +++ b/arch/arm/boards/edb93xx/env/bin/boot @@ -0,0 +1,48 @@ +#!/bin/sh + +. /env/config + +if [ x${rootfs_boot_media} = xflash ]; +then + rootfs_img=/dev/nor0.rootfs_${active_cfg} + + if [ x${active_cfg} = x1 ]; + then + rootfs_blkdev=/dev/mtdblock4 + cfg_1_ro="ro" + cfg_2_ro="" + else + rootfs_blkdev=/dev/mtdblock6 + cfg_1_ro="" + cfg_2_ro="ro" + fi + + bootargs_rootfs="root=${rootfs_blkdev} rootfstype=squashfs ro" +elif [ x${rootfs_boot_media} = xnet ]; +then + bootargs_rootfs="root=/dev/nfs nfsroot=${eth0.serverip}:/srv/nfs/${board},v3,nolock,tcp ip=${eth0.ipaddr}" +else + echo "ERROR: \$rootfs_boot_media invalid: ${rootfs_boot_media}" + exit 1 +fi + +if [ x${kernel_boot_media} = xflash ]; +then + kernel_img=/dev/nor0.kernel_${active_cfg} +elif [ x${kernel_boot_media} = xnet ]; +then + cd / + tftp ${board}/kernel.img || exit 1 + kernel_img=/kernel.img +else + echo "ERROR: \$kernel_boot_media invalid: ${kernel_boot_media}" + exit 1 +fi + +source /env/bin/set_nor_parts + +bootargs_mtd="mtdparts=physmap-flash.0:${nor_parts}" + +bootargs="${bootargs_common} ${bootargs_mtd} ${bootargs_rootfs}" + +bootm ${kernel_img} \ No newline at end of file diff --git a/arch/arm/boards/edb93xx/env/bin/flash_partition b/arch/arm/boards/edb93xx/env/bin/flash_partition new file mode 100644 index 0000000..ded40aa --- /dev/null +++ b/arch/arm/boards/edb93xx/env/bin/flash_partition @@ -0,0 +1,22 @@ +#!/bin/sh + +if [ $# != 2 ]; +then + echo "Usage: $0 " + exit 1 +fi + +image=$1 +partition=$2 + +echo "Unlocking ${partition}" +unprotect ${partition} + +echo "Erasing ${partition}" +erase ${partition} + +echo "Flashing ${image} to ${partition}" +cp ${image} ${partition} + +echo "Locking ${partition}" +protect ${partition} diff --git a/arch/arm/boards/edb93xx/env/bin/init b/arch/arm/boards/edb93xx/env/bin/init new file mode 100644 index 0000000..c6b5aed --- /dev/null +++ b/arch/arm/boards/edb93xx/env/bin/init @@ -0,0 +1,19 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + +# add partitions to barebox +. /env/bin/set_nor_parts +addpart /dev/nor0 ${nor_parts} + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + exit +fi + +boot \ No newline at end of file diff --git a/arch/arm/boards/edb93xx/env/bin/set_nor_parts b/arch/arm/boards/edb93xx/env/bin/set_nor_parts new file mode 100644 index 0000000..38321fa --- /dev/null +++ b/arch/arm/boards/edb93xx/env/bin/set_nor_parts @@ -0,0 +1,3 @@ +#!/bin/sh + +nor_parts="256k(barebox)ro,128k(env_boot),128k(env_boot.bak),1664k(kernel_1)${cfg_1_ro},6144k(rootfs_1)${cfg_1_ro},1664k(kernel_2)${cfg_2_ro},6144k(rootfs_2)${cfg_2_ro},128k(cfg_app),128k(cfg_app.bak)" \ No newline at end of file diff --git a/arch/arm/boards/edb93xx/env/bin/update_kernel b/arch/arm/boards/edb93xx/env/bin/update_kernel new file mode 100644 index 0000000..3e4b9b0 --- /dev/null +++ b/arch/arm/boards/edb93xx/env/bin/update_kernel @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +if [ $# != 1 ]; +then + echo "Usage: $0 <1/2>" + exit 1 +fi + +partition=/dev/nor0.kernel_$1 + +cd / +tftp ${board}/kernel.img || exit 1 + +flash_partition kernel.img ${partition} diff --git a/arch/arm/boards/edb93xx/env/bin/update_rootfs b/arch/arm/boards/edb93xx/env/bin/update_rootfs new file mode 100644 index 0000000..52a3699 --- /dev/null +++ b/arch/arm/boards/edb93xx/env/bin/update_rootfs @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +if [ $# != 1 ]; +then + echo "Usage: $0 <1/2>" + exit 1 +fi + +partition=/dev/nor0.rootfs_$1 + +cd / +tftp ${board}/rootfs.img || exit 1 + +flash_partition rootfs.img ${partition} diff --git a/arch/arm/boards/edb93xx/env/config b/arch/arm/boards/edb93xx/env/config new file mode 100644 index 0000000..47ab209 --- /dev/null +++ b/arch/arm/boards/edb93xx/env/config @@ -0,0 +1,16 @@ +#!/bin/sh + +eth0.ipaddr=192.168.0.50 +eth0.netmask=255.255.0.0 +eth0.serverip=192.168.0.8 +eth0.ethaddr=80:81:82:83:84:85 + +board=edb9301 +autoboot_timeout=3 +active_cfg=1 +bootargs_common="console=ttyAM0,115200" + +# valid media: flash/net +kernel_boot_media=flash +rootfs_boot_media=flash + diff --git a/arch/arm/boards/edb93xx/flash_cfg.c b/arch/arm/boards/edb93xx/flash_cfg.c new file mode 100644 index 0000000..91a6a4e --- /dev/null +++ b/arch/arm/boards/edb93xx/flash_cfg.c @@ -0,0 +1,38 @@ +/* + * Flash setup for Cirrus edb93xx boards + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#define SMC_BCR6_VALUE (2 << SMC_BCR_IDCY_SHIFT | 5 << SMC_BCR_WST1_SHIFT | \ + SMC_BCR_BLE | 2 << SMC_BCR_WST2_SHIFT | \ + 1 << SMC_BCR_MW_SHIFT) + +void flash_cfg(void) +{ + struct smc_regs *smc = (struct smc_regs *)SMC_BASE; + + writel(SMC_BCR6_VALUE, &smc->bcr6); +} diff --git a/arch/arm/boards/edb93xx/pll_cfg.c b/arch/arm/boards/edb93xx/pll_cfg.c new file mode 100644 index 0000000..a687af0 --- /dev/null +++ b/arch/arm/boards/edb93xx/pll_cfg.c @@ -0,0 +1,58 @@ +/* + * PLL setup for Cirrus edb93xx boards + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2006 Dominic Rath + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "pll_cfg.h" +#include "early_udelay.h" + +void pll_cfg(void) +{ + struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; + + /* setup PLL1 */ + writel(CLKSET1_VAL, &syscon->clkset1); + + /* + * flush the pipeline + * writing to CLKSET1 causes the EP93xx to enter standby for between + * 8 ms to 16 ms, until PLL1 stabilizes + */ + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + + /* setup PLL2 */ + writel(CLKSET2_VAL, &syscon->clkset2); + + /* + * the user's guide recommends to wait at least 1 ms for PLL2 to + * stabilize + */ + early_udelay(1000); +} diff --git a/arch/arm/boards/edb93xx/pll_cfg.h b/arch/arm/boards/edb93xx/pll_cfg.h new file mode 100644 index 0000000..503507a --- /dev/null +++ b/arch/arm/boards/edb93xx/pll_cfg.h @@ -0,0 +1,72 @@ +/* + * PLL register values for Cirrus edb93xx boards + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#if defined(CONFIG_MACH_EDB9301) +/* + * fclk_div: 2, nbyp1: 1, hclk_div: 5, pclk_div: 2 + * pll1_x1: 294912000.000000, pll1_x2ip: 36864000.000000, + * pll1_x2: 331776000.000000, pll1_out: 331776000.000000 + */ +#define CLKSET1_VAL (7 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ + 8 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ + 19 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ + 1 << SYSCON_CLKSET1_PCLK_DIV_SHIFT | \ + 3 << SYSCON_CLKSET1_HCLK_DIV_SHIFT | \ + SYSCON_CLKSET1_NBYP1 | \ + 1 << SYSCON_CLKSET1_FCLK_DIV_SHIFT) +#elif defined(CONFIG_MACH_EDB9302) || defined(CONFIG_MACH_EDB9302A) || \ + defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) || \ + defined CONFIG_MACH_EDB9312 || defined(CONFIG_MACH_EDB9315) ||\ + defined(CONFIG_MACH_EDB9315A) +/* + * fclk_div: 2, nbyp1: 1, hclk_div: 4, pclk_div: 2 + * pll1_x1: 3096576000.000000, pll1_x2ip: 129024000.000000, + * pll1_x2: 3999744000.000000, pll1_out: 1999872000.000000 + */ +#define CLKSET1_VAL (23 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ + 30 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ + 20 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ + 1 << SYSCON_CLKSET1_PCLK_DIV_SHIFT | \ + 2 << SYSCON_CLKSET1_HCLK_DIV_SHIFT | \ + SYSCON_CLKSET1_NBYP1 | \ + 1 << SYSCON_CLKSET1_FCLK_DIV_SHIFT) +#else +#error "Undefined board" +#endif + +/* + * usb_div: 4, nbyp2: 1, pll2_en: 1 + * pll2_x1: 368640000.000000, pll2_x2ip: 15360000.000000, + * pll2_x2: 384000000.000000, pll2_out: 192000000.000000 + */ +#define CLKSET2_VAL (23 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ + 24 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ + 24 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ + 1 << SYSCON_CLKSET_PLL_PS_SHIFT | \ + SYSCON_CLKSET2_PLL2_EN | \ + SYSCON_CLKSET2_NBYP2 | \ + 3 << SYSCON_CLKSET2_USB_DIV_SHIFT) diff --git a/arch/arm/boards/edb93xx/sdram_cfg.c b/arch/arm/boards/edb93xx/sdram_cfg.c new file mode 100644 index 0000000..3d4fe08 --- /dev/null +++ b/arch/arm/boards/edb93xx/sdram_cfg.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2006 Dominic Rath + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "sdram_cfg.h" +#include "early_udelay.h" + +#define PROGRAM_MODE_REG(bank) (*(volatile uint32_t *) \ + (SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank | SDRAM_MODE_REG_VAL)) + +#define PRECHARGE_BANK(bank) (*(volatile uint32_t *) \ + (SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank)) = 0 + +static void precharge_all_banks(void); +static void setup_refresh_timer(void); +static void program_mode_registers(void); + +void sdram_cfg(void) +{ + struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; + + writel(SDRAM_DEVCFG_VAL, &sdram->SDRAM_DEVCFG_REG); + + /* Issue continous NOP commands */ + writel(GLCONFIG_INIT | GLCONFIG_MRS | GLCONFIG_CKE, &sdram->glconfig); + + early_udelay(200); + + precharge_all_banks(); + + setup_refresh_timer(); + + program_mode_registers(); + + /* Select normal operation mode */ + writel(GLCONFIG_CKE, &sdram->glconfig); +} + +static void precharge_all_banks(void) +{ + struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; + + /* Issue PRECHARGE ALL commands */ + writel(GLCONFIG_INIT | GLCONFIG_CKE, &sdram->glconfig); + + /* + * Errata of most EP93xx revisions say that PRECHARGE ALL isn't always + * issued. + * + * Cirrus proposes a workaround which consists in performing a read from + * each bank to force the precharge. This causes some boards to hang. + * Writing to the SDRAM banks instead of reading has the same + * side-effect (the SDRAM controller issues the necessary precharges), + * but is known to work on all supported boards + */ + + PRECHARGE_BANK(0); + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + PRECHARGE_BANK(1); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + PRECHARGE_BANK(2); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + PRECHARGE_BANK(3); +#endif +} + +static void setup_refresh_timer(void) +{ + struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; + + /* Load refresh timer with 10 to issue refresh every 10 cycles */ + writel(0x0a, &sdram->refrshtimr); + + /* + * Wait at least 80 clock cycles to provide 8 refresh cycles + * to all SDRAMs + */ + early_udelay(1); + + /* + * Program refresh timer with normal value + * We need 8192 refresh cycles every 64ms + * at 15ns (HCLK >= 66MHz) per cycle: + * 64ms / 8192 = 7.8125us + * 7.8125us / 15ns = 520 (0x208) + */ + /* + * TODO: redboot uses 0x1e0 for the slowest possible device + * but i don't understand how this value is calculated + */ + writel(0x208, &sdram->refrshtimr); +} + +static void program_mode_registers(void) +{ + struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; + + /* Select mode register update mode */ + writel(GLCONFIG_MRS | GLCONFIG_CKE, &sdram->glconfig); + + PROGRAM_MODE_REG(0); + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + PROGRAM_MODE_REG(1); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + PROGRAM_MODE_REG(2); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + PROGRAM_MODE_REG(3); +#endif +} diff --git a/arch/arm/boards/edb93xx/sdram_cfg.h b/arch/arm/boards/edb93xx/sdram_cfg.h new file mode 100644 index 0000000..c57b76e --- /dev/null +++ b/arch/arm/boards/edb93xx/sdram_cfg.h @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2006 Dominic Rath + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#define SDRAM_BASE_ADDR CONFIG_EP93XX_SDRAM_BANK0_BASE + +#ifdef CONFIG_EP93XX_SDCE0_PHYS_OFFSET +#define SDRAM_DEVCFG_REG devcfg0 +#elif defined(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) +#define SDRAM_DEVCFG_REG devcfg3 +#else +#error "SDRAM bank configuration" +#endif + +#if defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) ||\ + defined(CONFIG_MACH_EDB9302A) +/* + * 1x Samsung K4S561632C-TC/L75 4M x 16bit x 4 banks SDRAM + * + * CLK cycle time min: + * @ CAS latency = 3: 7.5ns + * @ CAS latency = 2: 10ns + * We're running at 66MHz (EDB9301) / 100Mhz (EDB9302(a)) external + * bus speed (HCLK), with a cycle time of 15ns / 10ns, so it's safe + * to use CAS latency = 2 + * + * RAS-to-CAS delay min: + * 20ns + * At 15ns/10ns cycle time, we use RAS-to-CAS delay = 2 + * + * SROMLL = 1: Swap BA[1:0] with A[13:12], making the SDRAM appear + * as four blocks of 8MB size, instead of eight blocks of 4MB size: + * + * EDB9301/EDB9302: + * + * 0x00000000 - 0x007fffff + * 0x01000000 - 0x017fffff + * 0x04000000 - 0x047fffff + * 0x05000000 - 0x057fffff + * + * + * EDB9302a: + * + * 0xc0000000 - 0xc07fffff + * 0xc1000000 - 0xc17fffff + * 0xc4000000 - 0xc47fffff + * 0xc5000000 - 0xc57fffff + * + * BANKCOUNT = 1: This is a device with four banks + */ + +#define SDRAM_DEVCFG_VAL (SDRAM_DEVCFG_BANKCOUNT | \ + SDRAM_DEVCFG_SROMLL | \ + SDRAM_DEVCFG_CASLAT_2 | \ + SDRAM_DEVCFG_RASTOCAS_2 | \ + SDRAM_DEVCFG_EXTBUSWIDTH) + +/* + * 16 bit ext. bus + * + * A[22:09] is output as SYA[13:0] + * CAS latency: 2 + * Burst type: sequential + * Burst length: 8 (required for 16 bit ext. bus) + * SYA[13:0] = 0x0023 + */ +#define SDRAM_MODE_REG_VAL 0x4600 + +#define SDRAM_BANK_SEL_0 0x00000000 /* A[22:21] = b00 */ +#define SDRAM_BANK_SEL_1 0x00200000 /* A[22:21] = b01 */ +#define SDRAM_BANK_SEL_2 0x00400000 /* A[22:21] = b10 */ +#define SDRAM_BANK_SEL_3 0x00600000 /* A[22:21] = b11 */ + +#elif defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) ||\ + defined CONFIG_MACH_EDB9312 || defined(CONFIG_MACH_EDB9315) ||\ + defined(CONFIG_MACH_EDB9315A) +/* + * 2x Samsung K4S561632C-TC/L75 4M x 16bit x 4 banks SDRAM + * + * CLK cycle time min: + * @ CAS latency = 3: 7.5ns + * @ CAS latency = 2: 10ns + * We're running at 100MHz (10ns cycle time) external bus speed (HCLK), + * so it's safe to use CAS latency = 2 + * + * RAS-to-CAS delay min: + * 20ns + * At 10ns cycle time, we use RAS-to-CAS delay = 2 + * + * EDB9307, EDB9312, EDB9315: + * + * 0x00000000 - 0x01ffffff + * 0x04000000 - 0x05ffffff + * + * + * EDB9307a, EDB9315a: + * + * 0xc0000000 - 0xc1ffffff + * 0xc4000000 - 0xc5ffffff + */ + +#define SDRAM_DEVCFG_VAL (SDRAM_DEVCFG_BANKCOUNT | \ + SDRAM_DEVCFG_SROMLL | \ + SDRAM_DEVCFG_CASLAT_2 | \ + SDRAM_DEVCFG_RASTOCAS_2) + +/* + * 32 bit ext. bus + * + * A[23:10] is output as SYA[13:0] + * CAS latency: 2 + * Burst type: sequential + * Burst length: 4 + * SYA[13:0] = 0x0022 + */ +#define SDRAM_MODE_REG_VAL 0x8800 + +#define SDRAM_BANK_SEL_0 0x00000000 /* A[23:22] = b00 */ +#define SDRAM_BANK_SEL_1 0x00400000 /* A[23:22] = b01 */ +#define SDRAM_BANK_SEL_2 0x00800000 /* A[23:22] = b10 */ +#define SDRAM_BANK_SEL_3 0x00c00000 /* A[23:22] = b11 */ +#endif diff --git a/arch/arm/boards/eukrea_cpuimx25/Makefile b/arch/arm/boards/eukrea_cpuimx25/Makefile new file mode 100644 index 0000000..406c6f3 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/Makefile @@ -0,0 +1,24 @@ +# +# (C) 2010 Eukrea Electromatique, Eric Bénard +# +# 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 +# + +obj-y += lowlevel.o +obj-y += eukrea_cpuimx25.o diff --git a/arch/arm/boards/eukrea_cpuimx25/config.h b/arch/arm/boards/eukrea_cpuimx25/config.h new file mode 100644 index 0000000..efff909 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/config.h @@ -0,0 +1,27 @@ +/* + * (c) 2010 Eukrea Electromatique, Eric Bénard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define CONFIG_MX25_HCLK_FREQ 24000000 + +#endif + +/* nothing to do here yet */ diff --git a/arch/arm/boards/eukrea_cpuimx25/env/bin/_update b/arch/arm/boards/eukrea_cpuimx25/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/eukrea_cpuimx25/env/bin/boot b/arch/arm/boards/eukrea_cpuimx25/env/bin/boot new file mode 100644 index 0000000..2d9b3af --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/env/bin/boot @@ -0,0 +1,53 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xjffS2 ]; then + root=jffs2 + kernel=nand +fi + +if [ x$1 = xubifs ]; then + root=ubifs + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + if [ x$ip = xoff ]; then + bootargs="$bootargs ip=off" + else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" + fi +fi + +if [ x$root = xjffs2 ]; then + bootargs="$bootargs root=/dev/mtdblock$rootpartnum_nand rootfstype=jffs2" +fi + +if [ x$root = xubifs ]; then + bootargs="$bootargs root=ubi0:$ubiroot ubi.mtd=$rootpartnum_nand rootfstype=ubifs" +fi + +if [ x$root = xnet ]; then + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=mxc_nand:$nand_parts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/eukrea_cpuimx25/env/bin/hush_hack b/arch/arm/boards/eukrea_cpuimx25/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/eukrea_cpuimx25/env/bin/init b/arch/arm/boards/eukrea_cpuimx25/env/bin/init new file mode 100644 index 0000000..335d7ae --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/env/bin/init @@ -0,0 +1,41 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -f /env/logo.bmp ]; then + bmp /env/logo.bmp +elif [ -f /env/logo.bmp.lzo ]; then + unlzo /env/logo.bmp.lzo /logo.bmp + bmp /logo.bmp +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" + saveenv +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type update_root [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/eukrea_cpuimx25/env/bin/update_kernel b/arch/arm/boards/eukrea_cpuimx25/env/bin/update_kernel new file mode 100644 index 0000000..c2d2cc3 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/env/bin/update_kernel @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$uimage +part=/dev/nand0.kernel.bb + +. /env/bin/_update $1 diff --git a/arch/arm/boards/eukrea_cpuimx25/env/bin/update_root b/arch/arm/boards/eukrea_cpuimx25/env/bin/update_root new file mode 100644 index 0000000..dd89a5a --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/env/bin/update_root @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$rootfs +part=/dev/nand0.root.bb + +. /env/bin/_update $1 diff --git a/arch/arm/boards/eukrea_cpuimx25/env/config b/arch/arm/boards/eukrea_cpuimx25/env/config new file mode 100644 index 0000000..9217ca1 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/env/config @@ -0,0 +1,27 @@ +#!/bin/sh + +# can be either 'net' or 'jffs2' or 'ubifs' +kernel=nand +root=ubifs + +basedir=cpuimx25 +uimage=$basedir/uImage +rootfs=$basedir/rootfs + +autoboot_timeout=1 + +nfsroot="" +bootargs="console=ttymxc0,115200" + +nand_parts="256k(barebox)ro,128k(bareboxenv),2176k(kernel),-(root)" +rootpartnum_nand=3 +ubiroot="eukrea-cpuimx25-rootfs" + +# use 'dhcp' to do dhcp in barebox and in kernel +ip=off + +# 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 diff --git a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c new file mode 100644 index 0000000..caeb46e --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c @@ -0,0 +1,273 @@ +/* + * (C) 2009 Pengutronix, Sascha Hauer + * (c) 2010 Eukrea Electromatique, Eric Bénard + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long _stext; + +void __naked __flash_header_start go(void) +{ + __asm__ __volatile__("b exception_vectors\n"); +} + +struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { + { .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000004, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92100000, }, + { .ptr_type = 1, .addr = 0x80000400, .val = 0x12344321, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0xa2100000, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2100000, }, + { .ptr_type = 1, .addr = 0x80000033, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x81000000, .val = 0xff, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216080, }, + { .ptr_type = 4, .addr = 0xb8001004, .val = 0x00295729, }, + { .ptr_type = 4, .addr = 0x53f80008, .val = 0x20034000, }, +}; + +struct imx_flash_header __flash_header_0x400 eukrea_cpuimx25_header = { + .app_code_jump_vector = TEXT_BASE + 0x2000, + .app_code_barker = APP_CODE_BARKER, + .app_code_csf = 0, + .dcd_ptr_ptr = TEXT_BASE + 0x400 + offsetof(struct imx_flash_header, dcd), + .super_root_key = 0, + .dcd = TEXT_BASE + 0x400 + offsetof(struct imx_flash_header, dcd_barker), + .app_dest = TEXT_BASE, + .dcd_barker = DCD_BARKER, + .dcd_block_len = sizeof(dcd_entry), +}; + +extern unsigned long __bss_start; + +unsigned long __image_len_0x400 barebox_len = 0x40000; + +static struct fec_platform_data fec_info = { + .xcv_type = RMII, + .phy_addr = 1, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = IMX_FEC_BASE, + .platform_data = &fec_info, +}; + +static struct memory_platform_data sdram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram0_dev = { + .name = "mem", + .map_base = IMX_SDRAM_CS0, + .size = 64 * 1024 * 1024, + .platform_data = &sdram_pdata, +}; + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = IMX_NFC_BASE, + .platform_data = &nand_info, +}; + +static struct imx_fb_videomode imxfb_mode = { + .mode = { + .name = "CMO-QVGA", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = KHZ2PICOS(6500), + .hsync_len = 30, + .left_margin = 38, + .right_margin = 20, + .vsync_len = 3, + .upper_margin = 15, + .lower_margin = 4, + }, + .pcr = 0xCAD08B80, + .bpp = 16, +}; + +static struct imx_fb_platform_data eukrea_cpuimx25_fb_data = { + .mode = &imxfb_mode, + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x80040060, +}; + + +static struct device_d imxfb_dev = { + .name = "imxfb", + .map_base = 0x53fbc000, + .size = 0x1000, + .platform_data = &eukrea_cpuimx25_fb_data, +}; + +#ifdef CONFIG_MMU +static void eukrea_cpuimx25_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + + mmu_enable(); +} +#else +static void eukrea_cpuimx25_mmu_init(void) +{ +} +#endif + +static struct pad_desc eukrea_cpuimx25_pads[] = { + MX25_PAD_FEC_MDC__MDC, + MX25_PAD_FEC_MDIO__MDIO, + MX25_PAD_FEC_RDATA0__RDATA0, + MX25_PAD_FEC_RDATA1__RDATA1, + MX25_PAD_FEC_RX_DV__RX_DV, + MX25_PAD_FEC_TDATA0__TDATA0, + MX25_PAD_FEC_TDATA1__TDATA1, + MX25_PAD_FEC_TX_CLK__TX_CLK, + MX25_PAD_FEC_TX_EN__TX_EN, + /* UART1 */ + MX25_PAD_UART1_RXD__RXD_MUX, + MX25_PAD_UART1_TXD__TXD_MUX, + MX25_PAD_UART1_RTS__RTS, + MX25_PAD_UART1_CTS__CTS, + /* LCDC */ + MX25_PAD_LD0__LCDC_LD0, + MX25_PAD_LD1__LCDC_LD1, + MX25_PAD_LD2__LCDC_LD2, + MX25_PAD_LD3__LCDC_LD3, + MX25_PAD_LD4__LCDC_LD4, + MX25_PAD_LD5__LCDC_LD5, + MX25_PAD_LD6__LCDC_LD6, + MX25_PAD_LD7__LCDC_LD7, + MX25_PAD_LD8__LCDC_LD8, + MX25_PAD_LD9__LCDC_LD9, + MX25_PAD_LD10__LCDC_LD10, + MX25_PAD_LD11__LCDC_LD11, + MX25_PAD_LD12__LCDC_LD12, + MX25_PAD_LD13__LCDC_LD13, + MX25_PAD_LD14__LCDC_LD14, + MX25_PAD_LD15__LCDC_LD15, + MX25_PAD_GPIO_E__LCDC_LD16, + MX25_PAD_GPIO_F__LCDC_LD17, + MX25_PAD_LSCLK__LCDC_LSCLK, + MX25_PAD_OE_ACD__LCDC_OE_ACD, + MX25_PAD_VSYNC__LCDC_VSYN, + MX25_PAD_HSYNC__LCDC_HSYN, + /* BACKLIGHT CONTROL */ + MX25_PAD_PWM__GPIO26, +}; + +static int eukrea_cpuimx25_devices_init(void) +{ + eukrea_cpuimx25_mmu_init(); + + mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx25_pads, + ARRAY_SIZE(eukrea_cpuimx25_pads)); + register_device(&fec_dev); + + nand_info.width = 1; + register_device(&nand_dev); + + devfs_add_partition("nand0", 0x00000, 0x40000, + PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x40000, 0x20000, + PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + + register_device(&sdram0_dev); + + /* enable LCD */ + gpio_direction_output(26, 1); + gpio_set_value(26, 1); + + register_device(&imxfb_dev); + + armlinux_add_dram(&sdram0_dev); + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_EUKREA_CPUIMX25); + + return 0; +} + +device_initcall(eukrea_cpuimx25_devices_init); + +static struct device_d eukrea_cpuimx25_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 16 * 1024, +}; + +static int eukrea_cpuimx25_console_init(void) +{ + writel(0x03010101, IMX_CCM_BASE + CCM_PCDR3); + register_device(&eukrea_cpuimx25_serial_device); + return 0; +} + +console_initcall(eukrea_cpuimx25_console_init); + +#ifdef CONFIG_NAND_IMX_BOOT +void __bare_init nand_boot(void) +{ + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); +} +#endif + +static int eukrea_cpuimx25_core_setup(void) +{ + writel(0x01010103, IMX_CCM_BASE + CCM_PCDR2); + return 0; + +} +core_initcall(eukrea_cpuimx25_core_setup); diff --git a/arch/arm/boards/eukrea_cpuimx25/lowlevel.c b/arch/arm/boards/eukrea_cpuimx25/lowlevel.c new file mode 100644 index 0000000..b9d3ce5 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx25/lowlevel.c @@ -0,0 +1,130 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * (c) 2010 Eukrea Electromatique, Eric Bénard + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __bare_init __naked insdram(void) +{ + uint32_t r; + + /* setup a stack to be able to call imx_nand_load_image() */ + r = STACK_BASE + STACK_SIZE - 12; + __asm__ __volatile__("mov sp, %0" : : "r"(r)); + + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); + + board_init_lowlevel_return(); +} + +#define MX25_CCM_MCR 0x64 +#define MX25_CCM_CGR0 0x0c +#define MX25_CCM_CGR1 0x10 +#define MX25_CCM_CGR2 0x14 + +void __bare_init __naked board_init_lowlevel(void) +{ + uint32_t r; + unsigned int *trg, *src; + int i; + + /* AIPS setup - Only setup MPROTx registers. The PACR default values are good. + * Set all MPROTx to be non-bufferable, trusted for R/W, + * not forced to user-mode. + */ + writel(0x77777777, 0x43f00000); + writel(0x77777777, 0x43f00004); + writel(0x77777777, 0x53f00000); + writel(0x77777777, 0x53f00004); + + /* MAX (Multi-Layer AHB Crossbar Switch) setup + * MPR - priority for MX25 is (SDHC2/SDMA)>USBOTG>RTIC>IAHB>DAHB + */ + writel(0x00002143, 0x43f04000); + writel(0x00002143, 0x43f04100); + writel(0x00002143, 0x43f04200); + writel(0x00002143, 0x43f04300); + writel(0x00002143, 0x43f04400); + /* SGPCR - always park on last master */ + writel(0x10, 0x43f04010); + writel(0x10, 0x43f04110); + writel(0x10, 0x43f04210); + writel(0x10, 0x43f04310); + writel(0x10, 0x43f04410); + /* MGPCR - restore default values */ + writel(0x0, 0x43f04800); + writel(0x0, 0x43f04900); + writel(0x0, 0x43f04a00); + writel(0x0, 0x43f04b00); + writel(0x0, 0x43f04c00); + + /* Configure M3IF registers + * M3IF Control Register (M3IFCTL) for MX25 + * MRRP[0] = LCDC on priority list (1 << 0) = 0x00000001 + * MRRP[1] = MAX1 not on priority list (0 << 1) = 0x00000000 + * MRRP[2] = MAX0 not on priority list (0 << 2) = 0x00000000 + * MRRP[3] = USB HOST not on priority list (0 << 3) = 0x00000000 + * MRRP[4] = SDMA not on priority list (0 << 4) = 0x00000000 + * MRRP[5] = SD/ATA/FEC not on priority list (0 << 5) = 0x00000000 + * MRRP[6] = SCMFBC not on priority list (0 << 6) = 0x00000000 + * MRRP[7] = CSI not on priority list (0 << 7) = 0x00000000 + * ---------- + * 0x00000001 + */ + writel(0x1, 0xb8003000); + + /* enable all the clocks */ + writel(0x038A81A2, IMX_CCM_BASE + MX25_CCM_CGR0); + writel(0x24788F00, IMX_CCM_BASE + MX25_CCM_CGR1); + writel(0x00004438, IMX_CCM_BASE + MX25_CCM_CGR2); + writel(0x00, IMX_CCM_BASE + MX25_CCM_MCR); + +#ifdef CONFIG_NAND_IMX_BOOT + /* skip NAND boot if not running from NFC space */ + r = get_pc(); + if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x1000) + board_init_lowlevel_return(); + + src = (unsigned int *)IMX_NFC_BASE; + trg = (unsigned int *)TEXT_BASE; + + /* Move ourselves out of NFC SRAM */ + for (i = 0; i < 0x1000 / sizeof(int); i++) + *trg++ = *src++; + + /* Jump to SDRAM */ + r = (unsigned int)&insdram; + __asm__ __volatile__("mov pc, %0" : : "r"(r)); +#else + board_init_lowlevel_return(); +#endif +} diff --git a/arch/arm/boards/eukrea_cpuimx27/Makefile b/arch/arm/boards/eukrea_cpuimx27/Makefile new file mode 100644 index 0000000..5d958fa --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/Makefile @@ -0,0 +1,3 @@ + +obj-y += lowlevel_init.o +obj-y += eukrea_cpuimx27.o diff --git a/arch/arm/boards/eukrea_cpuimx27/config.h b/arch/arm/boards/eukrea_cpuimx27/config.h new file mode 100644 index 0000000..ec6f212 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/config.h @@ -0,0 +1,26 @@ +/* + * 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 + */ + +/** + * @file + * @brief Global defintions for the ARM Eukrea cpuimx27 board + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/eukrea_cpuimx27/env/bin/_update b/arch/arm/boards/eukrea_cpuimx27/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/eukrea_cpuimx27/env/bin/boot b/arch/arm/boards/eukrea_cpuimx27/env/bin/boot new file mode 100644 index 0000000..7272e56 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/env/bin/boot @@ -0,0 +1,51 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + root=nand + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$1 = xnor ]; then + root=nor + kernel=nor +fi + +if [ x$root = xnet ]; then + if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" + else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" + fi +else + bootargs="$bootargs ip=off" +fi + +if [ x$root = xnand ]; then + bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" +elif [ x$root = xnor ]; then + bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts;mxc_nand:$nand_parts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +elif [ $kernel = nor ]; then + bootm /dev/nor0.kernel +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/eukrea_cpuimx27/env/bin/hush_hack b/arch/arm/boards/eukrea_cpuimx27/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/eukrea_cpuimx27/env/bin/init b/arch/arm/boards/eukrea_cpuimx27/env/bin/init new file mode 100644 index 0000000..3bfd194 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/env/bin/init @@ -0,0 +1,37 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nor0 ]; then + addpart /dev/nor0 $nor_parts +fi + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel nand|nor [] to update kernel into flash" + echo "type update_root nand|nor [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/eukrea_cpuimx27/env/bin/update_kernel b/arch/arm/boards/eukrea_cpuimx27/env/bin/update_kernel new file mode 100644 index 0000000..05c822d --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/env/bin/update_kernel @@ -0,0 +1,15 @@ +#!/bin/sh + +. /env/config + +image=$uimage +if [ x$1 = xnand ]; then + part=/dev/nand0.kernel.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.kernel +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/arch/arm/boards/eukrea_cpuimx27/env/bin/update_root b/arch/arm/boards/eukrea_cpuimx27/env/bin/update_root new file mode 100644 index 0000000..eaf36eb --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/env/bin/update_root @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +image=$uimage +if [ x$1 = xnand ]; then + part=/dev/nand0.root.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.root +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 + diff --git a/arch/arm/boards/eukrea_cpuimx27/env/config b/arch/arm/boards/eukrea_cpuimx27/env/config new file mode 100644 index 0000000..505ada3 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/env/config @@ -0,0 +1,31 @@ +#!/bin/sh + +# can be either 'net', 'nor' or 'nand'' +kernel=nor +root=nor + +uimage=mx27/uImage +jffs2=mx27/rootfs.jffs2 + +autoboot_timeout=1 + +# DVI-SVGA DVI-VGA CMO-QVGA +video="CMO-QVGA" +bootargs="console=ttymxc0,115200 fec_mac=$eth0.ethaddr video=mxcfb:$video" + +nor_parts="256k(barebox)ro,128k(bareboxenv),2176k(kernel),-(root)" +rootpart_nor="/dev/mtdblock3" + +nand_parts="-(nand)" +rootpart_nand="" + +nfsroot="" + +# use 'dhcp' to do dhcp in barebox and in kernel +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 diff --git a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c new file mode 100644 index 0000000..1937d21 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c @@ -0,0 +1,370 @@ +/* + * Copyright (C) 2009 Eric Benard, Eukrea Electromatique + * Based on pcm038.c which is : + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0xC0000000, + .size = 32 * 1024 * 1024, +}; +#ifdef CONFIG_EUKREA_CPUIMX27_NOR_64MB +static struct device_d cfi_dev1 = { + .name = "cfi_flash", + .map_base = 0xC2000000, + .size = 32 * 1024 * 1024, +}; +#endif + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +#if defined CONFIG_EUKREA_CPUIMX27_SDRAM_256MB +#define SDRAM0 256 +#elif defined CONFIG_EUKREA_CPUIMX27_SDRAM_128MB +#define SDRAM0 128 +#endif + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0xa0000000, + .size = SDRAM0 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, + .phy_addr = 1, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = 0x1002b000, + .platform_data = &fec_info, +}; + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = 0xd8000000, + .platform_data = &nand_info, +}; + +#ifdef CONFIG_DRIVER_SERIAL_NS16550 +unsigned int quad_uart_read(unsigned long base, unsigned char reg_idx) +{ + unsigned int reg_addr = (unsigned int)base; + reg_addr += reg_idx << 1; + return 0xff & readw(reg_addr); +} +EXPORT_SYMBOL(quad_uart_read); + +void quad_uart_write(unsigned int val, unsigned long base, + unsigned char reg_idx) +{ + unsigned int reg_addr = (unsigned int)base; + reg_addr += reg_idx << 1; + writew(0xff & val, reg_addr); +} +EXPORT_SYMBOL(quad_uart_write); + +static struct NS16550_plat quad_uart_serial_plat = { + .clock = 14745600, + .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR, + .reg_read = quad_uart_read, + .reg_write = quad_uart_write, +}; + +#ifdef CONFIG_EUKREA_CPUIMX27_QUART1 +#define QUART_OFFSET 0x200000 +#elif defined CONFIG_EUKREA_CPUIMX27_QUART2 +#define QUART_OFFSET 0x400000 +#elif defined CONFIG_EUKREA_CPUIMX27_QUART3 +#define QUART_OFFSET 0x800000 +#elif defined CONFIG_EUKREA_CPUIMX27_QUART4 +#define QUART_OFFSET 0x1000000 +#endif + +static struct device_d quad_uart_serial_device = { + .name = "serial_ns16550", + .map_base = IMX_CS3_BASE + QUART_OFFSET, + .size = 0xF, + .platform_data = (void *)&quad_uart_serial_plat, +}; +#endif + +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO("lp3972", 0x34), + }, +}; + +static struct device_d i2c_dev = { + .name = "i2c-imx", + .map_base = IMX_I2C1_BASE, +}; + +#ifdef CONFIG_MMU +static void eukrea_cpuimx27_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0xa0000000, 0xa0000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0xb0000000, 0xa0000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + +#if TEXT_BASE & (0x100000 - 1) +#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary +#else + arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); +#endif + mmu_enable(); +} +#else +static void eukrea_cpuimx27_mmu_init(void) +{ +} +#endif + +#ifdef CONFIG_DRIVER_VIDEO_IMX +static struct imx_fb_videomode imxfb_mode = { + .mode = { + .name = "CMO-QVGA", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = 156000, + .hsync_len = 30, + .left_margin = 38, + .right_margin = 20, + .vsync_len = 3, + .upper_margin = 15, + .lower_margin = 4, + }, + .pcr = 0xFAD08B80, + .bpp = 16,}; + +static struct imx_fb_platform_data eukrea_cpuimx27_fb_data = { + .mode = &imxfb_mode, + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, +}; + +static struct device_d imxfb_dev = { + .name = "imxfb", + .map_base = 0x10021000, + .size = 0x1000, + .platform_data = &eukrea_cpuimx27_fb_data, +}; +#endif + +static int eukrea_cpuimx27_devices_init(void) +{ + char *envdev = "no"; + int i; + + unsigned int mode[] = { + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC | GPIO_PUEN, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, +#ifdef CONFIG_DRIVER_SERIAL_IMX + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, +#endif +#ifdef CONFIG_DRIVER_VIDEO_IMX + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA31_PF_OE_ACD, + GPIO_PORTE | 5 | GPIO_GPIO | GPIO_OUT, +#endif + }; + + eukrea_cpuimx27_mmu_init(); + + /* configure 16 bit nor flash on cs0 */ + CS0U = 0x00008F03; + CS0L = 0xA0330D01; + CS0A = 0x002208C0; + + /* initialize gpios */ + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + + register_device(&cfi_dev); +#ifdef CONFIG_EUKREA_CPUIMX27_NOR_64MB + register_device(&cfi_dev1); +#endif + register_device(&nand_dev); + register_device(&sdram_dev); + + PCCR0 |= PCCR0_I2C1_EN; + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + register_device(&i2c_dev); + + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); + protect_file("/dev/env0", 1); + envdev = "NOR"; + + printf("Using environment in %s Flash\n", envdev); + +#ifdef CONFIG_DRIVER_VIDEO_IMX + register_device(&imxfb_dev); + gpio_direction_output(GPIO_PORTE | 5, 0); + gpio_set_value(GPIO_PORTE | 5, 1); +#endif + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0xa0000100); + armlinux_set_architecture(MACH_TYPE_CPUIMX27); + + return 0; +} + +device_initcall(eukrea_cpuimx27_devices_init); + +#ifdef CONFIG_DRIVER_SERIAL_IMX +static struct device_d eukrea_cpuimx27_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; +#endif + +static int eukrea_cpuimx27_console_init(void) +{ +#ifdef CONFIG_DRIVER_SERIAL_IMX + register_device(&eukrea_cpuimx27_serial_device); +#endif + /* configure 8 bit UART on cs3 */ + FMCR &= ~0x2; + CS3U = 0x0000D603; + CS3L = 0x0D1D0D01; + CS3A = 0x00D20000; +#ifdef CONFIG_DRIVER_SERIAL_NS16550 + register_device(&quad_uart_serial_device); +#endif + return 0; +} + +console_initcall(eukrea_cpuimx27_console_init); + +static int eukrea_cpuimx27_late_init(void) +{ +#ifdef CONFIG_DRIVER_I2C_LP3972 + struct i2c_client *client; + u8 reg[1]; +#endif + console_flush(); + register_device(&fec_dev); + +#ifdef CONFIG_DRIVER_I2C_LP3972 + client = lp3972_get_client(); + if (!client) + return -ENODEV; + reg[0] = 0xa0; + i2c_write_reg(client, 0x39, reg, sizeof(reg)); +#endif + return 0; +} + +late_initcall(eukrea_cpuimx27_late_init); + +#ifdef CONFIG_NAND_IMX_BOOT +void __bare_init nand_boot(void) +{ + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); +} +#endif + diff --git a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.dox b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.dox new file mode 100644 index 0000000..6c2bfed --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.dox @@ -0,0 +1,11 @@ +/** @page eukrea_cpuimx27 Eukrea's CPUIMX27 + +This CPU card is based on a Freescale i.MX27 CPU. The card is shipped with: + +- up to 64MiB NOR type Flash Memory +- up to 256MiB synchronous dynamic RAM +- up to 512MiB NAND type Flash Memory +- MII 10/100 ethernet PHY +- optional 16554 Quad UART on CS3 + +*/ diff --git a/arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S b/arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S new file mode 100644 index 0000000..5295a8a --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx27/lowlevel_init.S @@ -0,0 +1,141 @@ +#include +#include + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +#if defined CONFIG_EUKREA_CPUIMX27_SDRAM_256MB +#define ROWS0 ESDCTL_ROW14 +#define CFG0 0x0029572D +#elif defined CONFIG_EUKREA_CPUIMX27_SDRAM_128MB +#define ROWS0 ESDCTL_ROW13 +#define CFG0 0x00095728 +#endif + +#define ESDCTL0_VAL (ESDCTL0_SDE | ROWS0 | ESDCTL0_COL10) + +.macro sdram_init + /* + * DDR on CSD0 + */ + writel(0x0000000C, ESDMISC) /* Enable DDR SDRAM operation */ + + writel(0x55555555, DSCR(3)) /* Set the driving strength */ + writel(0x55555555, DSCR(5)) + writel(0x55555555, DSCR(6)) + writel(0x00005005, DSCR(7)) + writel(0x15555555, DSCR(8)) + + writel(0x00000004, ESDMISC) /* Initial reset */ + writel(CFG0, ESDCFG0) + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_PRECHARGE, ESDCTL0) /* precharge CSD0 all banks */ + writel(0x00000000, 0xA0000F00) /* CSD0 precharge address (A10 = 1) */ + writel(ESDCTL0_VAL | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0) + + ldr r0, =0xa0000f00 + mov r1, #0 + mov r2, #8 +1: + str r1, [r0] + subs r2, #1 + bne 1b + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0) + ldr r0, =0xA0000033 + mov r1, #0xda + strb r1, [r0] +#if defined CONFIG_EUKREA_CPUIMX27_SDRAM_256MB + ldr r0, =0xA2000000 +#elif defined CONFIG_EUKREA_CPUIMX27_SDRAM_128MB + ldr r0, =0xA1000000 +#endif + mov r1, #0xff + strb r1, [r0] + writel(ESDCTL0_VAL | ESDCTL0_DSIZ_31_0 | ESDCTL0_REF4 | ESDCTL0_BL | ESDCTL0_SMODE_NORMAL, ESDCTL0) +.endm + + .section ".text_bare_init","ax" + +.globl board_init_lowlevel +board_init_lowlevel: + + mov r10, lr + + /* ahb lite ip interface */ + writel(0x20040304, AIPI1_PSR0) + writel(0xDFFBFCFB, AIPI1_PSR1) + writel(0x00000000, AIPI2_PSR0) + writel(0xFFFFFFFF, AIPI2_PSR1) + + /* disable mpll/spll */ + ldr r0, =CSCR + ldr r1, [r0] + bic r1, r1, #0x03 + str r1, [r0] + + /* + * pll clock initialization - see section 3.4.3 of the i.MX27 manual + */ + writel(0x00331C23, MPCTL0) /* MPLL = 399 MHz */ + writel(0x040C2403, SPCTL0) /* SPLL = 240 MHz */ + writel(0x33F38107 | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR) + + /* add some delay here */ + mov r1, #0x1000 +1: subs r1, r1, #0x1 + bne 1b + + /* clock gating enable */ + writel(0x00050f08, GPCR) + + /* peripheral clock divider */ + writel(0x130400c3, PCDR0) /* FIXME */ + writel(0x09030208, PCDR1) /* PERDIV1=08 @133 MHz */ + /* PERDIV1=04 @266 MHz */ + + /* skip sdram initialization if we run from ram */ + cmp pc, #0xa0000000 + bls 1f + cmp pc, #0xc0000000 + bhi 1f + + mov pc,r10 +1: + sdram_init + +#ifdef CONFIG_NAND_IMX_BOOT + ldr sp, =0xa0f00000 /* Setup a temporary stack in SDRAM */ + + ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ + ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ + + /* skip NAND boot if not running from NFC space */ + cmp pc, r0 + bls ret + cmp pc, r2 + bhi ret + + /* Move ourselves out of NFC SRAM */ + ldr r1, =TEXT_BASE + +copy_loop: + ldmia r0!, {r3-r9} /* copy from source address [r0] */ + stmia r1!, {r3-r9} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + + ldr pc, =1f /* Jump to SDRAM */ +1: + bl nand_boot /* Load barebox from NAND Flash */ + + ldr r1, =IMX_NFC_BASE - TEXT_BASE + sub r10, r10, r1 /* adjust return address from NFC SRAM */ + /* to SDRAM */ + +#endif /* CONFIG_NAND_IMX_BOOT */ + +ret: + mov pc,r10 diff --git a/arch/arm/boards/eukrea_cpuimx35/Makefile b/arch/arm/boards/eukrea_cpuimx35/Makefile new file mode 100644 index 0000000..32ffe42 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/Makefile @@ -0,0 +1,25 @@ +# +# (C) Copyright 2007 Juergen Beisert +# +# 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 +# + +obj-y += lowlevel.o +obj-y += eukrea_cpuimx35.o +obj-$(CONFIG_ARCH_IMX_INTERNAL_BOOT) += flash_header.o diff --git a/arch/arm/boards/eukrea_cpuimx35/config.h b/arch/arm/boards/eukrea_cpuimx35/config.h new file mode 100644 index 0000000..bfd3b39 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/config.h @@ -0,0 +1,23 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define CONFIG_MX35_HCLK_FREQ 24000000 + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/eukrea_cpuimx35/env/bin/_update b/arch/arm/boards/eukrea_cpuimx35/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/eukrea_cpuimx35/env/bin/boot b/arch/arm/boards/eukrea_cpuimx35/env/bin/boot new file mode 100644 index 0000000..fca5b8c --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/env/bin/boot @@ -0,0 +1,52 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xjffS2 ]; then + root=jffs2 + kernel=nand +fi + +if [ x$1 = xubifs ]; then + root=ubifs + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + if [ x$ip = xoff ]; then + bootargs="$bootargs ip=off" + else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" + fi +fi + +if [ x$root = xjffs2 ]; then + bootargs="$bootargs root=/dev/mtdblock$rootpartnum_nand rootfstype=jffs2" +fi + +if [ x$root = xubifs ]; then + bootargs="$bootargs root=ubi0:$ubiroot ubi.mtd=$rootpartnum_nand rootfstype=ubifs" +fi + +if [ x$root = xnet ]; then + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=mxc_nand:$nand_parts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm /dev/nand0.kernel.bb +fi diff --git a/arch/arm/boards/eukrea_cpuimx35/env/bin/hush_hack b/arch/arm/boards/eukrea_cpuimx35/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/eukrea_cpuimx35/env/bin/init b/arch/arm/boards/eukrea_cpuimx35/env/bin/init new file mode 100644 index 0000000..90007cd --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/env/bin/init @@ -0,0 +1,45 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -f /env/logo.bmp ]; then + fb0.enable=1 + bmp /env/logo.bmp + gpio_direction_out 1 1 +elif [ -f /env/logo.bmp.lzo ]; then + unlzo /env/logo.bmp.lzo /logo.bmp + fb0.enable=1 + bmp /logo.bmp + gpio_direction_out 1 1 +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" + saveenv +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type update_root [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/eukrea_cpuimx35/env/bin/update_kernel b/arch/arm/boards/eukrea_cpuimx35/env/bin/update_kernel new file mode 100644 index 0000000..c2d2cc3 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/env/bin/update_kernel @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$uimage +part=/dev/nand0.kernel.bb + +. /env/bin/_update $1 diff --git a/arch/arm/boards/eukrea_cpuimx35/env/bin/update_root b/arch/arm/boards/eukrea_cpuimx35/env/bin/update_root new file mode 100644 index 0000000..dd89a5a --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/env/bin/update_root @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$rootfs +part=/dev/nand0.root.bb + +. /env/bin/_update $1 diff --git a/arch/arm/boards/eukrea_cpuimx35/env/config b/arch/arm/boards/eukrea_cpuimx35/env/config new file mode 100644 index 0000000..df2079f --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/env/config @@ -0,0 +1,27 @@ +#!/bin/sh + +# can be either 'net' or 'nand'' +kernel=nand +root=ubifs + +basedir=cpuimx35 +uimage=$basedir/uImage +rootfs=$basedir/rootfs + +autoboot_timeout=1 + +nfsroot="" +bootargs="console=ttymxc0,115200" + +nand_parts="256k(barebox)ro,128k(bareboxenv),2176k(kernel),-(root)" +rootpartnum_nand=3 +ubiroot="eukrea-cpuimx35-rootfs" + +# use 'dhcp' to do dhcp in barebox and in kernel +ip=off + +# 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 diff --git a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c new file mode 100644 index 0000000..d41d9b5 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2007 Sascha Hauer, Pengutronix + * 2009 Marc Kleine-Budde, Pengutronix + * (c) 2010 Eukrea Electromatique, Eric Bénard + * + * 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 + * + * Derived from: + * + * * mx35_3stack.c - board file for uboot-v1 + * Copyright (C) 2007, Guennadi Liakhovetski + * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, + .phy_addr = 0x1F, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = IMX_FEC_BASE, + .platform_data = &fec_info, +}; + +static struct memory_platform_data sdram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = IMX_SDRAM_CS0, + .size = 128 * 1024 * 1024, + .platform_data = &sdram_pdata, +}; + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = IMX_NFC_BASE, + .platform_data = &nand_info, +}; + +static struct fb_videomode imxfb_mode = { + .name = "CMO_QVGA", + .refresh = 60, + .xres = 320, + .yres = 240, + .pixclock = KHZ2PICOS(7000), + .left_margin = 68, + .right_margin = 20, + .upper_margin = 15, + .lower_margin = 4, + .hsync_len = 30, + .vsync_len = 3, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static void eukrea_cpuimx35_enable_display(int enable) +{ + gpio_direction_output(4, enable); +} + +static struct imx_ipu_fb_platform_data ipu_fb_data = { + .mode = &imxfb_mode, + .bpp = 16, + .enable = eukrea_cpuimx35_enable_display, +}; + +static struct device_d imxfb_dev = { + .name = "imx-ipu-fb", + .map_base = 0x53fc0000, + .size = 0x1000, + .platform_data = &ipu_fb_data, +}; + +#ifdef CONFIG_MMU +static int eukrea_cpuimx35_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + +#if TEXT_BASE & (0x100000 - 1) +#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary +#else + arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); +#endif + mmu_enable(); + +#ifdef CONFIG_CACHE_L2X0 + l2x0_init((void __iomem *)0x30000000, 0x00030024, 0x00000000); +#endif + return 0; +} +postcore_initcall(eukrea_cpuimx35_mmu_init); +#endif + +static int eukrea_cpuimx35_devices_init(void) +{ + register_device(&nand_dev); + + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + + register_device(&fec_dev); + + register_device(&sdram_dev); + register_device(&imxfb_dev); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_EUKREA_CPUIMX35); + + return 0; +} + +device_initcall(eukrea_cpuimx35_devices_init); + +static struct device_d eukrea_cpuimx35_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static struct pad_desc eukrea_cpuimx35_pads[] = { + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + + MX35_PAD_RXD1__UART1_RXD_MUX, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_CTS1__UART1_CTS, + + MX35_PAD_LD23__GPIO3_29, + MX35_PAD_CONTRAST__GPIO1_1, + MX35_PAD_D3_CLS__GPIO1_4, +}; + +static int eukrea_cpuimx35_console_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads, + ARRAY_SIZE(eukrea_cpuimx35_pads)); + + /* screen default on to prevent flicker */ + gpio_direction_output(4, 1); + /* backlight default off */ + gpio_direction_output(1, 0); + /* led default off */ + gpio_direction_output(32 * 2 + 29, 1); + + register_device(&eukrea_cpuimx35_serial_device); + return 0; +} + +console_initcall(eukrea_cpuimx35_console_init); + +static int eukrea_cpuimx35_core_init(void) +{ + u32 reg; + + /* enable clock for I2C1 and FEC */ + reg = readl(IMX_CCM_BASE + CCM_CGR1); + reg |= 0x3 << CCM_CGR1_FEC_SHIFT; + reg = writel(reg, IMX_CCM_BASE + CCM_CGR1); + + /* AIPS setup - Only setup MPROTx registers. The PACR default values are good.*/ + /* + * Set all MPROTx to be non-bufferable, trusted for R/W, + * not forced to user-mode. + */ + writel(0x77777777, IMX_AIPS1_BASE); + writel(0x77777777, IMX_AIPS1_BASE + 0x4); + writel(0x77777777, IMX_AIPS2_BASE); + writel(0x77777777, IMX_AIPS2_BASE + 0x4); + + /* + * Clear the on and off peripheral modules Supervisor Protect bit + * for SDMA to access them. Did not change the AIPS control registers + * (offset 0x20) access type + */ + writel(0x0, IMX_AIPS1_BASE + 0x40); + writel(0x0, IMX_AIPS1_BASE + 0x44); + writel(0x0, IMX_AIPS1_BASE + 0x48); + writel(0x0, IMX_AIPS1_BASE + 0x4C); + reg = readl(IMX_AIPS1_BASE + 0x50); + reg &= 0x00FFFFFF; + writel(reg, IMX_AIPS1_BASE + 0x50); + + writel(0x0, IMX_AIPS2_BASE + 0x40); + writel(0x0, IMX_AIPS2_BASE + 0x44); + writel(0x0, IMX_AIPS2_BASE + 0x48); + writel(0x0, IMX_AIPS2_BASE + 0x4C); + reg = readl(IMX_AIPS2_BASE + 0x50); + reg &= 0x00FFFFFF; + writel(reg, IMX_AIPS2_BASE + 0x50); + + /* MAX (Multi-Layer AHB Crossbar Switch) setup */ + + /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ +#define MAX_PARAM1 0x00302154 + writel(MAX_PARAM1, IMX_MAX_BASE + 0x000); /* for S0 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x100); /* for S1 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x200); /* for S2 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x300); /* for S3 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x400); /* for S4 */ + + /* SGPCR - always park on last master */ + writel(0x10, IMX_MAX_BASE + 0x10); /* for S0 */ + writel(0x10, IMX_MAX_BASE + 0x110); /* for S1 */ + writel(0x10, IMX_MAX_BASE + 0x210); /* for S2 */ + writel(0x10, IMX_MAX_BASE + 0x310); /* for S3 */ + writel(0x10, IMX_MAX_BASE + 0x410); /* for S4 */ + + /* MGPCR - restore default values */ + writel(0x0, IMX_MAX_BASE + 0x800); /* for M0 */ + writel(0x0, IMX_MAX_BASE + 0x900); /* for M1 */ + writel(0x0, IMX_MAX_BASE + 0xa00); /* for M2 */ + writel(0x0, IMX_MAX_BASE + 0xb00); /* for M3 */ + writel(0x0, IMX_MAX_BASE + 0xc00); /* for M4 */ + writel(0x0, IMX_MAX_BASE + 0xd00); /* for M5 */ + + /* + * M3IF Control Register (M3IFCTL) + * MRRP[0] = L2CC0 not on priority list (0 << 0) = 0x00000000 + * MRRP[1] = MAX1 not on priority list (0 << 0) = 0x00000000 + * MRRP[2] = L2CC1 not on priority list (0 << 0) = 0x00000000 + * MRRP[3] = USB not on priority list (0 << 0) = 0x00000000 + * MRRP[4] = SDMA not on priority list (0 << 0) = 0x00000000 + * MRRP[5] = GPU not on priority list (0 << 0) = 0x00000000 + * MRRP[6] = IPU1 on priority list (1 << 6) = 0x00000040 + * MRRP[7] = IPU2 not on priority list (0 << 0) = 0x00000000 + * ------------ + * 0x00000040 + */ + writel(0x40, IMX_M3IF_BASE); + + return 0; +} + +core_initcall(eukrea_cpuimx35_core_init); + +#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) +#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) + +static int do_cpufreq(struct command *cmdtp, int argc, char *argv[]) +{ + unsigned long freq; + + if (argc != 2) + return COMMAND_ERROR_USAGE; + + freq = simple_strtoul(argv[1], NULL, 0); + + switch (freq) { + case 399: + writel(MPCTL_PARAM_399, IMX_CCM_BASE + CCM_MPCTL); + break; + case 532: + writel(MPCTL_PARAM_532, IMX_CCM_BASE + CCM_MPCTL); + break; + default: + return COMMAND_ERROR_USAGE; + } + + printf("Switched CPU frequency to %dMHz\n", freq); + + return 0; +} + +static const __maybe_unused char cmd_cpufreq_help[] = +"Usage: cpufreq 399|532\n" +"\n" +"Set CPU frequency to MHz\n"; + +BAREBOX_CMD_START(cpufreq) + .cmd = do_cpufreq, + .usage = "adjust CPU frequency", + BAREBOX_CMD_HELP(cmd_cpufreq_help) +BAREBOX_CMD_END diff --git a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.dox b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.dox new file mode 100644 index 0000000..cbdf69d --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.dox @@ -0,0 +1,4 @@ +/** @page eukrea_cpuimx35 Eukrea's CPUIMX35 + + +*/ diff --git a/arch/arm/boards/eukrea_cpuimx35/flash_header.c b/arch/arm/boards/eukrea_cpuimx35/flash_header.c new file mode 100644 index 0000000..78f51f6 --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/flash_header.c @@ -0,0 +1,41 @@ +#include +#include + +void __naked __flash_header_start go(void) +{ + __asm__ __volatile__("b exception_vectors\n"); +} + +struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { + { .ptr_type = 4, .addr = 0x53F80004, .val = 0x00821000, }, + { .ptr_type = 4, .addr = 0x53F80004, .val = 0x00821000, }, + { .ptr_type = 4, .addr = 0xB8001010, .val = 0x00000004, }, + { .ptr_type = 4, .addr = 0xB8001010, .val = 0x0000000C, }, + { .ptr_type = 4, .addr = 0xB8001004, .val = 0x0009572B, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0x92220000, }, + { .ptr_type = 1, .addr = 0x80000400, .val = 0xda, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0xA2220000, }, + { .ptr_type = 1, .addr = 0x80000000, .val = 0x87654321, }, + { .ptr_type = 1, .addr = 0x80000000, .val = 0x87654321, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0xB2220000, }, + { .ptr_type = 1, .addr = 0x80000033, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x82000000, .val = 0xda, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0x82224080, }, + { .ptr_type = 4, .addr = 0xB8001010, .val = 0x00000004, }, +}; + +#define APP_DEST 0x80000000 + +struct imx_flash_header __flash_header_0x400 eukrea_cpuimx35_header = { + .app_code_jump_vector = APP_DEST + 0x1000, + .app_code_barker = APP_CODE_BARKER, + .app_code_csf = 0, + .dcd_ptr_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd), + .super_root_key = 0, + .dcd = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd_barker), + .app_dest = APP_DEST, + .dcd_barker = DCD_BARKER, + .dcd_block_len = sizeof (dcd_entry), +}; + +unsigned long __image_len_0x400 barebox_len = 0x40000; diff --git a/arch/arm/boards/eukrea_cpuimx35/lowlevel.c b/arch/arm/boards/eukrea_cpuimx35/lowlevel.c new file mode 100644 index 0000000..aad334d --- /dev/null +++ b/arch/arm/boards/eukrea_cpuimx35/lowlevel.c @@ -0,0 +1,169 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Assuming 24MHz input clock */ +#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) +#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) +#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) + +#ifdef CONFIG_NAND_IMX_BOOT +static void __bare_init __naked insdram(void) +{ + uint32_t r; + + /* Speed up NAND controller by adjusting the NFC divider */ + r = readl(IMX_CCM_BASE + CCM_PDR4); + r &= ~(0xf << 28); + r |= 0x1 << 28; + writel(r, IMX_CCM_BASE + CCM_PDR4); + + /* setup a stack to be able to call imx_nand_load_image() */ + r = STACK_BASE + STACK_SIZE - 12; + __asm__ __volatile__("mov sp, %0" : : "r"(r)); + + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); + + board_init_lowlevel_return(); +} +#endif + +void __bare_init __naked board_init_lowlevel(void) +{ + uint32_t r, s; + unsigned long ccm_base = IMX_CCM_BASE; +#ifdef CONFIG_NAND_IMX_BOOT + unsigned int *trg, *src; + int i; +#endif + + r = get_cr(); + r |= CR_Z; /* Flow prediction (Z) */ + r |= CR_U; /* unaligned accesses */ + r |= CR_FI; /* Low Int Latency */ + + __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1":"=r"(s)); + s |= 0x7; + __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1" : : "r"(s)); + + set_cr(r); + + r = 0; + __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); + + /* + * Branch predicition is now enabled. Flush the BTAC to ensure a valid + * starting point. Don't flush BTAC while it is disabled to avoid + * ARM1136 erratum 408023. + */ + __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 6" : : "r"(r)); + + /* invalidate I cache and D cache */ + __asm__ __volatile__("mcr p15, 0, %0, c7, c7, 0" : : "r"(r)); + + /* invalidate TLBs */ + __asm__ __volatile__("mcr p15, 0, %0, c8, c7, 0" : : "r"(r)); + + /* Drain the write buffer */ + __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4" : : "r"(r)); + + /* Also setup the Peripheral Port Remap register inside the core */ + r = 0x40000015; /* start from AIPS 2GB region */ + __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); + + /* + * End of ARM1136 init + */ + + writel(0x003F4208, ccm_base + CCM_CCMR); + + /* Set MPLL , arm clock and ahb clock*/ + writel(MPCTL_PARAM_532, ccm_base + CCM_MPCTL); + + writel(PPCTL_PARAM_300, ccm_base + CCM_PPCTL); + writel(0x00001000, ccm_base + CCM_PDR0); + + r = readl(ccm_base + CCM_CGR0); + r |= 0x00300000; + writel(r, ccm_base + CCM_CGR0); + + r = readl(ccm_base + CCM_CGR1); + r |= 0x00000C00; + r |= 0x00000003; + writel(r, ccm_base + CCM_CGR1); + + r = readl(IMX_L2CC_BASE + L2X0_AUX_CTRL); + r |= 0x1000; + writel(r, IMX_L2CC_BASE + L2X0_AUX_CTRL); + + /* Skip SDRAM initialization if we run from RAM */ + r = get_pc(); + if (r > 0x80000000 && r < 0x90000000) + board_init_lowlevel_return(); + + /* Init Mobile DDR */ + writel(0x00000004, ESDMISC); + writel(0x0000000C, ESDMISC); + writel(0x0009572B, ESDCFG0); + writel(0x92220000, ESDCTL0); + writeb(0xda, IMX_SDRAM_CS0 + 0x400); + writel(0xA2220000, ESDCTL0); + writel(0x87654321, IMX_SDRAM_CS0); + writel(0x87654321, IMX_SDRAM_CS0); + writel(0xB2220000, ESDCTL0); + writeb(0xda, IMX_SDRAM_CS0 + 0x33); + writeb(0xda, IMX_SDRAM_CS0 + 0x2000000); + writel(0x82224080, ESDCTL0); + writel(0x00000004, ESDMISC); + +#ifdef CONFIG_NAND_IMX_BOOT + /* skip NAND boot if not running from NFC space */ + r = get_pc(); + if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x1000) + board_init_lowlevel_return(); + + src = (unsigned int *)IMX_NFC_BASE; + trg = (unsigned int *)TEXT_BASE; + + /* Move ourselves out of NFC SRAM */ + for (i = 0; i < 0x1000 / sizeof(int); i++) + *trg++ = *src++; + + /* Jump to SDRAM */ + r = (unsigned int)&insdram; + __asm__ __volatile__("mov pc, %0" : : "r"(r)); +#else + board_init_lowlevel_return(); +#endif +} + diff --git a/arch/arm/boards/freescale-mx25-3-stack/3stack.c b/arch/arm/boards/freescale-mx25-3-stack/3stack.c new file mode 100644 index 0000000..a77a02d --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/3stack.c @@ -0,0 +1,354 @@ +/* + * (C) 2009 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long _stext; + +void __naked __flash_header_start go(void) +{ + __asm__ __volatile__("b exception_vectors\n"); +} + +struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { + { .ptr_type = 4, .addr = 0xb8002050, .val = 0x0000d843, }, + { .ptr_type = 4, .addr = 0xb8002054, .val = 0x22252521, }, + { .ptr_type = 4, .addr = 0xb8002058, .val = 0x22220a00, }, +#if defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_64MB_DDR2 + { .ptr_type = 4, .addr = 0xb8001004, .val = 0x0076e83a, }, + { .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000304, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92210000, }, + { .ptr_type = 4, .addr = 0x80000f00, .val = 0x12344321, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2210000, }, + { .ptr_type = 1, .addr = 0x82000000, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x83000000, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x81000400, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x80000333, .val = 0xda, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92210000, }, + { .ptr_type = 4, .addr = 0x80000400, .val = 0x12344321, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0xa2210000, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2210000, }, + { .ptr_type = 1, .addr = 0x80000233, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x81000780, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x81000400, .val = 0xda, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216080, }, +#elif defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_128MB_MDDR + { .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000004, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92100000, }, + { .ptr_type = 1, .addr = 0x80000400, .val = 0x21, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0xa2100000, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2100000, }, + { .ptr_type = 1, .addr = 0x80000033, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x81000000, .val = 0xff, }, + { .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216880, }, + { .ptr_type = 4, .addr = 0xb8001004, .val = 0x00295729, }, +#else +#error "Unsupported SDRAM type" +#endif + { .ptr_type = 4, .addr = 0x53f80008, .val = 0x20034000, }, +}; + +#define APP_DEST 0x80000000 + +struct imx_flash_header __flash_header_0x400 mx25_3ds_header = { + .app_code_jump_vector = APP_DEST + 0x1000, + .app_code_barker = APP_CODE_BARKER, + .app_code_csf = 0, + .dcd_ptr_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd), + .super_root_key = 0, + .dcd = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd_barker), + .app_dest = APP_DEST, + .dcd_barker = DCD_BARKER, + .dcd_block_len = sizeof (dcd_entry), +}; + +extern unsigned long __bss_start; + +unsigned long __image_len_0x400 barebox_len = 0x40000; + +static struct fec_platform_data fec_info = { + .xcv_type = RMII, + .phy_addr = 1, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = IMX_FEC_BASE, + .platform_data = &fec_info, +}; + +static struct memory_platform_data sdram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram0_dev = { + .name = "mem", + .map_base = IMX_SDRAM_CS0, +#if defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_64MB_DDR2 + .size = 64 * 1024 * 1024, +#elif defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_128MB_MDDR + .size = 128 * 1024 * 1024, +#else +#error "Unsupported SDRAM type" +#endif + .platform_data = &sdram_pdata, +}; + +static struct memory_platform_data sram_pdata = { + .name = "sram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sram0_dev = { + .name = "mem", + .map_base = 0x78000000, + .size = 128 * 1024, + .platform_data = &sram_pdata, +}; + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = IMX_NFC_BASE, + .platform_data = &nand_info, +}; + +#ifdef CONFIG_USB +static void imx25_usb_init(void) +{ + unsigned int tmp; + + /* Host 2 */ + tmp = readl(IMX_OTG_BASE + 0x600); + tmp &= ~(3 << 21); + tmp |= (2 << 21) | (1 << 4) | (1 << 5); + writel(tmp, IMX_OTG_BASE + 0x600); + + tmp = readl(IMX_OTG_BASE + 0x584); + tmp |= 3 << 30; + writel(tmp, IMX_OTG_BASE + 0x584); + + /* Set to Host mode */ + tmp = readl(IMX_OTG_BASE + 0x5a8); + writel(tmp | 0x3, IMX_OTG_BASE + 0x5a8); +} + +static struct device_d usbh2_dev = { + .name = "ehci", + .map_base = IMX_OTG_BASE + 0x400, + .size = 0x200, +}; +#endif + +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO("mc34704", 0x54), + }, +}; + +static struct device_d i2c_dev = { + .name = "i2c-imx", + .map_base = IMX_I2C1_BASE, +}; + +static int imx25_3ds_pmic_init(void) +{ + struct mc34704 *pmic; + + pmic = mc34704_get(); + if (pmic == NULL) + return -EIO; + + return mc34704_reg_write(pmic, 0x2, 0x9); +} + +static int imx25_3ds_fec_init(void) +{ + int ret; + + ret = imx25_3ds_pmic_init(); + if (ret < 0) + return ret; + + /* + * Set up the FEC_RESET_B and FEC_ENABLE GPIO pins. + * Assert FEC_RESET_B, then power up the PHY by asserting + * FEC_ENABLE, at the same time lifting FEC_RESET_B. + * + * FEC_RESET_B: gpio2[3] is ALT 5 mode of pin A17 + * FEC_ENABLE_B: gpio4[8] is ALT 5 mode of pin D12 + */ + writel(0x8, IMX_IOMUXC_BASE + 0x0238); /* open drain */ + writel(0x0, IMX_IOMUXC_BASE + 0x028C); /* cmos, no pu/pd */ + +#define FEC_ENABLE_GPIO 35 +#define FEC_RESET_B_GPIO 104 + + /* make the pins output */ + gpio_direction_output(FEC_ENABLE_GPIO, 0); /* drop PHY power */ + gpio_direction_output(FEC_RESET_B_GPIO, 0); /* assert reset */ + udelay(2); + + /* turn on power & lift reset */ + gpio_set_value(FEC_ENABLE_GPIO, 1); + gpio_set_value(FEC_RESET_B_GPIO, 1); + + return 0; +} +late_initcall(imx25_3ds_fec_init); + +static int imx25_devices_init(void) +{ +#ifdef CONFIG_USB + /* USB does not work yet. Don't know why. Maybe + * the CPLD has to be initialized. + */ + imx25_usb_init(); + register_device(&usbh2_dev); +#endif + + register_device(&fec_dev); + + if (readl(IMX_CCM_BASE + CCM_RCSR) & (1 << 14)) + nand_info.width = 2; + + register_device(&nand_dev); + + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + + register_device(&sdram0_dev); + register_device(&sram0_dev); + + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + register_device(&i2c_dev); + + armlinux_add_dram(&sdram0_dev); + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_MX25_3DS); + + return 0; +} + +device_initcall(imx25_devices_init); + +static struct device_d imx25_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 16 * 1024, +}; + +static struct pad_desc imx25_pads[] = { + MX25_PAD_FEC_MDC__MDC, + MX25_PAD_FEC_MDIO__MDIO, + MX25_PAD_FEC_RDATA0__RDATA0, + MX25_PAD_FEC_RDATA1__RDATA1, + MX25_PAD_FEC_RX_DV__RX_DV, + MX25_PAD_FEC_TDATA0__TDATA0, + MX25_PAD_FEC_TDATA1__TDATA1, + MX25_PAD_FEC_TX_CLK__TX_CLK, + MX25_PAD_FEC_TX_EN__TX_EN, + MX25_PAD_POWER_FAIL__POWER_FAIL_INT, + MX25_PAD_A17__GPIO3, + MX25_PAD_D12__GPIO8, + /* UART1 */ + MX25_PAD_UART1_RXD__RXD_MUX, + MX25_PAD_UART1_TXD__TXD_MUX, + MX25_PAD_UART1_RTS__RTS, + MX25_PAD_UART1_CTS__CTS, + /* USBH2 */ + MX25_PAD_D9__USBH2_PWR, + MX25_PAD_D8__USBH2_OC, + MX25_PAD_LD0__USBH2_CLK, + MX25_PAD_LD1__USBH2_DIR, + MX25_PAD_LD2__USBH2_STP, + MX25_PAD_LD3__USBH2_NXT, + MX25_PAD_LD4__USBH2_DATA0, + MX25_PAD_LD5__USBH2_DATA1, + MX25_PAD_LD6__USBH2_DATA2, + MX25_PAD_LD7__USBH2_DATA3, + MX25_PAD_HSYNC__USBH2_DATA4, + MX25_PAD_VSYNC__USBH2_DATA5, + MX25_PAD_LSCLK__USBH2_DATA6, + MX25_PAD_OE_ACD__USBH2_DATA7, + /* i2c */ + MX25_PAD_I2C1_CLK__SCL, + MX25_PAD_I2C1_DAT__SDA, +}; + +static int imx25_console_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(imx25_pads, ARRAY_SIZE(imx25_pads)); + + writel(0x03010101, 0x53f80024); + + register_device(&imx25_serial_device); + return 0; +} + +console_initcall(imx25_console_init); + +#ifdef CONFIG_NAND_IMX_BOOT +void __bare_init nand_boot(void) +{ + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); +} +#endif + +static int imx25_core_setup(void) +{ + writel(0x01010103, IMX_CCM_BASE + CCM_PCDR2); + return 0; + +} +core_initcall(imx25_core_setup); + diff --git a/arch/arm/boards/freescale-mx25-3-stack/Makefile b/arch/arm/boards/freescale-mx25-3-stack/Makefile new file mode 100644 index 0000000..ab853e0 --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/Makefile @@ -0,0 +1,24 @@ +# +# (C) Copyright 2007 Juergen Beisert +# +# 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 +# + +obj-y += lowlevel_init.o +obj-y += 3stack.o diff --git a/arch/arm/boards/freescale-mx25-3-stack/config.h b/arch/arm/boards/freescale-mx25-3-stack/config.h new file mode 100644 index 0000000..f35e8a0 --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/config.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2007 Juergen Beisert + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * Definitions related to passing arguments to kernel. + */ + +#define CONFIG_MX25_HCLK_FREQ 24000000 + +#endif + +/* nothing to do here yet */ diff --git a/arch/arm/boards/freescale-mx25-3-stack/env/bin/_update b/arch/arm/boards/freescale-mx25-3-stack/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/freescale-mx25-3-stack/env/bin/boot b/arch/arm/boards/freescale-mx25-3-stack/env/bin/boot new file mode 100644 index 0000000..7bbff2d --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/env/bin/boot @@ -0,0 +1,47 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + root=nand + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$1 = xnor ]; then + root=nor + kernel=nor +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xnand ]; then + bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" +elif [ x$root = xnor ]; then + bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts;mxc_nand:$nand_parts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +elif [ $kernel = nor ]; then + bootm /dev/nor0.kernel +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/freescale-mx25-3-stack/env/bin/hush_hack b/arch/arm/boards/freescale-mx25-3-stack/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/freescale-mx25-3-stack/env/bin/init b/arch/arm/boards/freescale-mx25-3-stack/env/bin/init new file mode 100644 index 0000000..0600b9e --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/env/bin/init @@ -0,0 +1,30 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nor0 ]; then + addpart /dev/nor0 $nor_parts +fi + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel nand|nor [] to update kernel into flash" + echo "type update_root nand|nor [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/freescale-mx25-3-stack/env/bin/update_kernel b/arch/arm/boards/freescale-mx25-3-stack/env/bin/update_kernel new file mode 100644 index 0000000..05c822d --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/env/bin/update_kernel @@ -0,0 +1,15 @@ +#!/bin/sh + +. /env/config + +image=$uimage +if [ x$1 = xnand ]; then + part=/dev/nand0.kernel.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.kernel +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/arch/arm/boards/freescale-mx25-3-stack/env/bin/update_root b/arch/arm/boards/freescale-mx25-3-stack/env/bin/update_root new file mode 100644 index 0000000..eaf36eb --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/env/bin/update_root @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +image=$uimage +if [ x$1 = xnand ]; then + part=/dev/nand0.root.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.root +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 + diff --git a/arch/arm/boards/freescale-mx25-3-stack/env/config b/arch/arm/boards/freescale-mx25-3-stack/env/config new file mode 100644 index 0000000..a5e492e --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/env/config @@ -0,0 +1,29 @@ +#!/bin/sh + +# can be either 'net', 'nor' or 'nand'' +kernel=net +root=net + +uimage=uImage-pcm043 +jffs2=root-pcm043.jffs2 + +autoboot_timeout=3 + +nfsroot="/ptx/work/octopus/rsc/svn/oselas/bsp/phytec/phyCORE-i.MX27/OSELAS.BSP-Phytec-phyCORE-i.MX27-trunk/root" +bootargs="console=ttymxc0,115200" + +nor_parts="256k(barebox)ro,128k(bareboxenv),2048k(kernel),-(root)" +rootpart_nor="/dev/mtdblock3" + +nand_parts="256k(barebox)ro,128k(bareboxenv),2048k(kernel),108416k(root),-(kernel1)" +rootpart_nand="/dev/mtdblock7" + +# use 'dhcp' to do dhcp in barebox and in kernel +#ip=dhcp + +# or set your networking parameters here +eth0.ipaddr=192.168.3.11 +eth0.netmask=255.255.255.0 +#eth0.gateway=a.b.c.d +eth0.serverip=192.168.3.10 +eth0.ethaddr=00:50:c2:8c:e6:0e diff --git a/arch/arm/boards/freescale-mx25-3-stack/lowlevel_init.S b/arch/arm/boards/freescale-mx25-3-stack/lowlevel_init.S new file mode 100644 index 0000000..73bb147 --- /dev/null +++ b/arch/arm/boards/freescale-mx25-3-stack/lowlevel_init.S @@ -0,0 +1,253 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +#define writeb(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + strb r1, [r0]; + +/* Assuming 24MHz input clock */ +#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) +#define MPCTL_PARAM_532 (IMX_PLL_PD(1) | IMX_PLL_MFD(0) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) +#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) + +.section ".text_bare_init","ax" + +ARM_PPMRR: .word 0x40000015 +L2CACHE_PARAM: .word 0x00030024 +CCM_CCMR_W: .word 0x003F4208 +CCM_PDR0_W: .word 0x00801000 +MPCTL_PARAM_399_W: .word MPCTL_PARAM_399 +MPCTL_PARAM_532_W: .word MPCTL_PARAM_532 +PPCTL_PARAM_W: .word PPCTL_PARAM_300 +CCM_BASE_ADDR_W: .word IMX_CCM_BASE + +.globl board_init_lowlevel +board_init_lowlevel: + mov r10, lr + +#define MX25_CCM_MCR 0x64 + + ldr r0, CCM_BASE_ADDR_W + /* default CLKO to 1/32 of the ARM core */ + ldr r1, [r0, #MX25_CCM_MCR] + bic r1, r1, #0x00F00000 + bic r1, r1, #0x7F000000 + mov r2, #0x5F000000 + add r2, r2, #0x00200000 + orr r1, r1, r2 + str r1, [r0, #MX25_CCM_MCR] + + /* enable all the clocks */ + writel(0x1FFFFFFF, IMX_CCM_BASE + CCM_CGCR0) + writel(0xFFFFFFFF, IMX_CCM_BASE + CCM_CGCR1) + writel(0x000FDFFF, IMX_CCM_BASE + CCM_CGCR2) + writel(0x0000FEFF, IMX_CCM_BASE + MX25_CCM_MCR) + + /* Skip SDRAM initialization if we run from RAM */ + cmp pc, #0x80000000 + bls 1f + cmp pc, #0x90000000 + bhi 1f + + mov pc, lr + +1: + ldr r0, ESDCTL_BASE_W + mov r3, #0x2000 + str r3, [r0, #0x0] + str r3, [r0, #0x8] + + mov r12, #0x00 + mov r2, #0x1 /* mDDR */ + mov r1, #IMX_SDRAM_CS0 + bl setup_sdram_bank +// cmp r3, #0x0 +// orreq r12, r12, #1 +// eorne r2, r2, #0x1 +// blne setup_sdram_bank + + ldr r3, ESDCTL_DELAY5 + str r3, [r0, #0x30] + +#ifdef CONFIG_NAND_IMX_BOOT + ldr sp, =0xa0f00000 /* Setup a temporary stack in SDRAM */ + + ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ + ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ + + /* skip NAND boot if not running from NFC space */ + cmp pc, r0 + bls ret + cmp pc, r2 + bhi ret + + /* Move ourselves out of NFC SRAM */ + ldr r1, =TEXT_BASE + +copy_loop: + ldmia r0!, {r3-r9} /* copy from source address [r0] */ + stmia r1!, {r3-r9} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + + ldr pc, =1f /* Jump to SDRAM */ +1: + bl nand_boot /* Load barebox from NAND Flash */ + + ldr r1, =IMX_NFC_BASE - TEXT_BASE + sub r10, r10, r1 /* adjust return address from NFC SRAM */ + /* to SDRAM */ + +#endif /* CONFIG_NAND_IMX_BOOT */ + +ret: + mov pc, r10 + +/* + * r0: control base, r1: ram bank base + * r2: ddr type(0:DDR2, 1:MDDR) r3, r4: working + */ +setup_sdram_bank: + mov r3, #0xE /* 0xA + 0x4 */ + tst r2, #0x1 + orreq r3, r3, #0x300 /* DDR2 */ + str r3, [r0, #0x10] + bic r3, r3, #0x00A + str r3, [r0, #0x10] + beq 2f + + mov r3, #0x20000 +1: subs r3, r3, #1 + bne 1b + +2: adr r4, ESDCTL_CONFIG + tst r2, #0x1 + ldreq r3, [r4, #0x0] + ldrne r3, [r4, #0x4] + cmp r1, #IMX_SDRAM_CS1 + strlo r3, [r0, #0x4] + strhs r3, [r0, #0xC] + + ldr r3, ESDCTL_0x92220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, RAM_PARAM1_MDDR + strb r3, [r1, r4] + + tst r2, #0x1 + bne skip_set_mode + + cmp r1, #IMX_SDRAM_CS1 + ldr r3, ESDCTL_0xB2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, RAM_PARAM4_MDDR + strb r3, [r1, r4] + ldr r4, RAM_PARAM5_MDDR + strb r3, [r1, r4] + ldr r4, RAM_PARAM3_MDDR + strb r3, [r1, r4] + ldr r4, RAM_PARAM2_MDDR + strb r3, [r1, r4] + + ldr r3, ESDCTL_0x92220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, RAM_PARAM1_MDDR + strb r3, [r1, r4] + +skip_set_mode: + cmp r1, #IMX_SDRAM_CS1 + ldr r3, ESDCTL_0xA2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + strb r3, [r1] + strb r3, [r1] + + ldr r3, ESDCTL_0xB2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + adr r4, RAM_PARAM6_MDDR + tst r2, #0x1 + ldreq r4, [r4, #0x0] + ldrne r4, [r4, #0x4] + mov r3, #0xDA + strb r3, [r1, r4] + ldreq r4, RAM_PARAM7_MDDR + streqb r3, [r1, r4] + adr r4, RAM_PARAM3_MDDR + ldreq r4, [r4, #0x0] + ldrne r4, [r4, #0x4] + strb r3, [r1, r4] + + cmp r1, #IMX_SDRAM_CS1 + ldr r3, ESDCTL_0x82226080 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + + tst r2, #0x1 + moveq r4, #0x20000 + movne r4, #0x200 +1: subs r4, r4, #1 + bne 1b + + str r3, [r1, #0x100] + ldr r4, [r1, #0x100] + cmp r3, r4 + movne r3, #1 + moveq r3, #0 + + mov pc, lr + +RAM_PARAM1_MDDR: .word 0x00000400 +RAM_PARAM2_MDDR: .word 0x00000333 +RAM_PARAM3_MDDR: .word 0x02000400 + .word 0x02000000 +RAM_PARAM4_MDDR: .word 0x04000000 +RAM_PARAM5_MDDR: .word 0x06000000 +RAM_PARAM6_MDDR: .word 0x00000233 + .word 0x00000033 +RAM_PARAM7_MDDR: .word 0x02000780 +ESDCTL_0x92220000: .word 0x92210000 +ESDCTL_0xA2220000: .word 0xA2210000 +ESDCTL_0xB2220000: .word 0xB2210000 +ESDCTL_0x82226080: .word 0x82216080 +ESDCTL_CONFIG: .word 0x007FFC3F + .word 0x007FFC3F +ESDCTL_DELAY5: .word 0x00F49F00 +ESDCTL_BASE_W: .word IMX_ESD_BASE + diff --git a/arch/arm/boards/freescale-mx35-3-stack/3stack.c b/arch/arm/boards/freescale-mx35-3-stack/3stack.c new file mode 100644 index 0000000..9a66976 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/3stack.c @@ -0,0 +1,498 @@ +/* + * Copyright (C) 2007 Sascha Hauer, Pengutronix + * 2009 Marc Kleine-Budde, 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 + * + * Derived from: + * + * * mx35_3stack.c - board file for uboot-v1 + * Copyright (C) 2007, Guennadi Liakhovetski + * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* Board rev for the PDK 3stack */ +#define MX35PDK_BOARD_REV_1 0 +#define MX35PDK_BOARD_REV_2 1 + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = IMX_CS0_BASE, + .size = 64 * 1024 * 1024, +}; + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, + .phy_addr = 0x1F, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = IMX_FEC_BASE, + .platform_data = &fec_info, +}; + +static struct memory_platform_data sdram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = IMX_SDRAM_CS0, + .size = 128 * 1024 * 1024, + .platform_data = &sdram_pdata, +}; + +struct imx_nand_platform_data nand_info = { + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = IMX_NFC_BASE, + .platform_data = &nand_info, +}; + +static struct device_d smc911x_dev = { + .name = "smc911x", + .map_base = IMX_CS5_BASE, + .size = IMX_CS5_RANGE, +}; + +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO("mc13892", 0x08), + }, { + I2C_BOARD_INFO("mc9sdz60", 0x69), + }, +}; + +static struct device_d i2c_dev = { + .name = "i2c-imx", + .map_base = IMX_I2C1_BASE, +}; + +/* + * Generic display, shipped with the PDK + */ +static struct fb_videomode CTP_CLAA070LC0ACW = { + /* 800x480 @ 60 Hz */ + .name = "CTP-CLAA070LC0ACW", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = KHZ2PICOS(27000), + .left_margin = 50, + .right_margin = 50, /* whole line should have 900 clocks */ + .upper_margin = 10, + .lower_margin = 10, /* whole frame should have 500 lines */ + .hsync_len = 1, /* note: DE only display */ + .vsync_len = 1, /* note: DE only display */ + .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; + +static struct imx_ipu_fb_platform_data ipu_fb_data = { + .mode = &CTP_CLAA070LC0ACW, + .bpp = 16, +}; + +static struct device_d imxfb_dev = { + .name = "imx-ipu-fb", + .map_base = 0x53fc0000, + .size = 0x1000, + .platform_data = &ipu_fb_data, +}; + +/* + * Revision to be passed to kernel. The kernel provided + * by freescale relies on this. + * + * C --> CPU type + * S --> Silicon revision + * B --> Board rev + * + * 31 20 16 12 8 4 0 + * | Cmaj | Cmin | B | Smaj | Smin| + * + * e.g 0x00035120 --> i.MX35, Cpu silicon rev 2.0, Board rev 2 +*/ +static unsigned int imx35_3ds_system_rev = 0x00035000; + +static void set_silicon_rev( int rev) +{ + imx35_3ds_system_rev = imx35_3ds_system_rev | (rev & 0xFF); +} + +static void set_board_rev(int rev) +{ + imx35_3ds_system_rev = (imx35_3ds_system_rev & ~(0xF << 8)) | (rev & 0xF) << 8; +} + + +static int f3s_devices_init(void) +{ + uint32_t reg; + + /* CS0: Nor Flash */ + writel(0x0000cf03, CSCR_U(0)); + writel(0x10000d03, CSCR_L(0)); + writel(0x00720900, CSCR_A(0)); + + reg = readl(IMX_CCM_BASE + CCM_RCSR); + /* some fuses provide us vital information about connected hardware */ + if (reg & 0x20000000) + nand_info.width = 2; /* 16 bit */ + else + nand_info.width = 1; /* 8 bit */ + + /* + * This platform supports NOR and NAND + */ + register_device(&nand_dev); + register_device(&cfi_dev); + + switch ((reg >> 25) & 0x3) { + case 0x01: /* NAND is the source */ + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + devfs_add_partition("nand0", 0x40000, 0x80000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + break; + + case 0x00: /* NOR is the source */ + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x80000, PARTITION_FIXED, "env0"); + protect_file("/dev/env0", 1); + break; + } + + set_silicon_rev(imx_silicon_revision()); + + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + register_device(&i2c_dev); + + register_device(&fec_dev); + register_device(&smc911x_dev); + + register_device(&sdram_dev); + register_device(&imxfb_dev); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_MX35_3DS); + + return 0; +} + +device_initcall(f3s_devices_init); + +static int f3s_enable_display(void) +{ + /* Enable power to the LCD. (bit 6 hi.) */ + mc9sdz60_set_bits(mc9sdz60_get(), MC9SDZ60_REG_GPIO_1, 0x40, 0x40); + + return 0; +} + +late_initcall(f3s_enable_display); + +static struct device_d f3s_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static struct pad_desc f3s_pads[] = { + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + + MX35_PAD_RXD1__UART1_RXD_MUX, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_CTS1__UART1_CTS, + + MX35_PAD_I2C1_CLK__I2C1_SCL, + MX35_PAD_I2C1_DAT__I2C1_SDA, + + MX35_PAD_WDOG_RST__GPIO1_6, + MX35_PAD_COMPARE__GPIO1_5, + + /* Display */ + MX35_PAD_LD0__IPU_DISPB_DAT_0, + MX35_PAD_LD1__IPU_DISPB_DAT_1, + MX35_PAD_LD2__IPU_DISPB_DAT_2, + MX35_PAD_LD3__IPU_DISPB_DAT_3, + MX35_PAD_LD4__IPU_DISPB_DAT_4, + MX35_PAD_LD5__IPU_DISPB_DAT_5, + MX35_PAD_LD6__IPU_DISPB_DAT_6, + MX35_PAD_LD7__IPU_DISPB_DAT_7, + MX35_PAD_LD8__IPU_DISPB_DAT_8, + MX35_PAD_LD9__IPU_DISPB_DAT_9, + MX35_PAD_LD10__IPU_DISPB_DAT_10, + MX35_PAD_LD11__IPU_DISPB_DAT_11, + MX35_PAD_LD12__IPU_DISPB_DAT_12, + MX35_PAD_LD13__IPU_DISPB_DAT_13, + MX35_PAD_LD14__IPU_DISPB_DAT_14, + MX35_PAD_LD15__IPU_DISPB_DAT_15, + MX35_PAD_LD16__IPU_DISPB_DAT_16, + MX35_PAD_LD17__IPU_DISPB_DAT_17, + MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC, + MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK, + MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY, + MX35_PAD_CONTRAST__IPU_DISPB_CONTR, + MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC, + MX35_PAD_D3_REV__IPU_DISPB_D3_REV, + MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS, +}; + +static int f3s_console_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(f3s_pads, ARRAY_SIZE(f3s_pads)); + + register_device(&f3s_serial_device); + return 0; +} + +console_initcall(f3s_console_init); + +static int f3s_core_init(void) +{ + u32 reg; + + writel(0x0000D843, CSCR_U(5)); /* CS5: smc9117 */ + writel(0x22252521, CSCR_L(5)); + writel(0x22220A00, CSCR_A(5)); + + /* enable clock for I2C1 and FEC */ + reg = readl(IMX_CCM_BASE + CCM_CGR1); + reg |= 0x3 << CCM_CGR1_FEC_SHIFT; + reg |= 0x3 << CCM_CGR1_I2C1_SHIFT; + reg = writel(reg, IMX_CCM_BASE + CCM_CGR1); + + /* AIPS setup - Only setup MPROTx registers. The PACR default values are good.*/ + /* + * Set all MPROTx to be non-bufferable, trusted for R/W, + * not forced to user-mode. + */ + writel(0x77777777, IMX_AIPS1_BASE); + writel(0x77777777, IMX_AIPS1_BASE + 0x4); + writel(0x77777777, IMX_AIPS2_BASE); + writel(0x77777777, IMX_AIPS2_BASE + 0x4); + + /* + * Clear the on and off peripheral modules Supervisor Protect bit + * for SDMA to access them. Did not change the AIPS control registers + * (offset 0x20) access type + */ + writel(0x0, IMX_AIPS1_BASE + 0x40); + writel(0x0, IMX_AIPS1_BASE + 0x44); + writel(0x0, IMX_AIPS1_BASE + 0x48); + writel(0x0, IMX_AIPS1_BASE + 0x4C); + reg = readl(IMX_AIPS1_BASE + 0x50); + reg &= 0x00FFFFFF; + writel(reg, IMX_AIPS1_BASE + 0x50); + + writel(0x0, IMX_AIPS2_BASE + 0x40); + writel(0x0, IMX_AIPS2_BASE + 0x44); + writel(0x0, IMX_AIPS2_BASE + 0x48); + writel(0x0, IMX_AIPS2_BASE + 0x4C); + reg = readl(IMX_AIPS2_BASE + 0x50); + reg &= 0x00FFFFFF; + writel(reg, IMX_AIPS2_BASE + 0x50); + + /* MAX (Multi-Layer AHB Crossbar Switch) setup */ + + /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ +#define MAX_PARAM1 0x00302154 + writel(MAX_PARAM1, IMX_MAX_BASE + 0x000); /* for S0 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x100); /* for S1 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x200); /* for S2 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x300); /* for S3 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x400); /* for S4 */ + + /* SGPCR - always park on last master */ + writel(0x10, IMX_MAX_BASE + 0x10); /* for S0 */ + writel(0x10, IMX_MAX_BASE + 0x110); /* for S1 */ + writel(0x10, IMX_MAX_BASE + 0x210); /* for S2 */ + writel(0x10, IMX_MAX_BASE + 0x310); /* for S3 */ + writel(0x10, IMX_MAX_BASE + 0x410); /* for S4 */ + + /* MGPCR - restore default values */ + writel(0x0, IMX_MAX_BASE + 0x800); /* for M0 */ + writel(0x0, IMX_MAX_BASE + 0x900); /* for M1 */ + writel(0x0, IMX_MAX_BASE + 0xa00); /* for M2 */ + writel(0x0, IMX_MAX_BASE + 0xb00); /* for M3 */ + writel(0x0, IMX_MAX_BASE + 0xc00); /* for M4 */ + writel(0x0, IMX_MAX_BASE + 0xd00); /* for M5 */ + + return 0; +} + +core_initcall(f3s_core_init); + +static int f3s_get_rev(struct mc13892 *mc13892) +{ + u32 rev; + int err; + + err = mc13892_reg_read(mc13892, MC13892_REG_IDENTIFICATION, &rev); + if (err) + return err; + + dev_info(&mc13892->client->dev, "revision: 0x%x\n", rev); + if (rev == 0x00ffffff) + return -ENODEV; + + return ((rev >> 6) & 0x7) ? MX35PDK_BOARD_REV_2 : MX35PDK_BOARD_REV_1; +} + +static int f3s_pmic_init_v2(struct mc13892 *mc13892) +{ + int err = 0; + + /* COMPARE pin (GPIO1_5) as output and set high */ + gpio_direction_output( 32*0 + 5 , 1); + + err |= mc13892_set_bits(mc13892, MC13892_REG_SETTING_0, 0x03, 0x03); + err |= mc13892_set_bits(mc13892, MC13892_REG_MODE_0, 0x01, 0x01); + if (err) + dev_err(&mc13892->client->dev, + "Init sequence failed, the system might not be working!\n"); + + return err; +} + +static int f3s_pmic_init_all(struct mc9sdz60 *mc9sdz60) +{ + int err = 0; + + err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_GPIO_1, 0x04, 0x04); + + err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_RESET_1, 0x80, 0x00); + mdelay(200); + err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_RESET_1, 0x80, 0x80); + + if (err) + dev_err(&mc9sdz60->client->dev, + "Init sequence failed, the system might not be working!\n"); + + return err; +} + +static int f3s_pmic_init(void) +{ + struct mc13892 *mc13892; + struct mc9sdz60 *mc9sdz60; + int rev; + + mc13892 = mc13892_get(); + if (!mc13892) { + printf("FAILED to get mc13892 handle!\n"); + return 0; + } + + rev = f3s_get_rev(mc13892); + switch (rev) { + case MX35PDK_BOARD_REV_1: + break; + case MX35PDK_BOARD_REV_2: + f3s_pmic_init_v2(mc13892); + break; + default: + printf("FAILED to identify board revision!\n"); + return 0; + } + + set_board_rev(rev); + printf("i.MX35 PDK CPU board version %d.\n", rev ); + + mc9sdz60 = mc9sdz60_get(); + if (!mc9sdz60) { + printf("FAILED to get mc9sdz60 handle!\n"); + return 0; + } + + f3s_pmic_init_all(mc9sdz60); + + armlinux_set_revision(imx35_3ds_system_rev); + + return 0; +} + +late_initcall(f3s_pmic_init); + +#ifdef CONFIG_NAND_IMX_BOOT +void __bare_init nand_boot(void) +{ + /* + * The driver is able to detect NAND's pagesize by CPU internal + * fuses or external pull ups. But not the blocksize... + */ + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); +} +#endif diff --git a/arch/arm/boards/freescale-mx35-3-stack/3stack.dox b/arch/arm/boards/freescale-mx35-3-stack/3stack.dox new file mode 100644 index 0000000..15c5b6e --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/3stack.dox @@ -0,0 +1,4 @@ +/** @page the3stack Freescale MX35 3-Stack Board + + +*/ diff --git a/arch/arm/boards/freescale-mx35-3-stack/Makefile b/arch/arm/boards/freescale-mx35-3-stack/Makefile new file mode 100644 index 0000000..a8ea4a3 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/Makefile @@ -0,0 +1,4 @@ + +obj-y += lowlevel_init.o +obj-y += 3stack.o +obj-$(CONFIG_ARCH_IMX_INTERNAL_BOOT) += flash_header.o diff --git a/arch/arm/boards/freescale-mx35-3-stack/board-mx35_3stack.h b/arch/arm/boards/freescale-mx35-3-stack/board-mx35_3stack.h new file mode 100644 index 0000000..c18066a --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/board-mx35_3stack.h @@ -0,0 +1,107 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * (C) Copyright 2008 Freescale Semiconductor, Inc. + * + * 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 __BOARD_MX35_3STACK_H +#define __BOARD_MX35_3STACK_H + +#define UNALIGNED_ACCESS_ENABLE +#define LOW_INT_LATENCY_ENABLE +#define BRANCH_PREDICTION_ENABLE + +#define L2CC_AUX_CTL_CONFIG 0x00030024 + +#define AIPS_MPR_CONFIG 0x77777777 +#define AIPS_OPACR_CONFIG 0x00000000 + +/* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ +#define MAX_MPR_CONFIG 0x00302154 +/* SGPCR - always park on last master */ +#define MAX_SGPCR_CONFIG 0x00000010 +/* MGPCR - restore default values */ +#define MAX_MGPCR_CONFIG 0x00000000 + +/* + * M3IF Control Register (M3IFCTL) + * MRRP[0] = L2CC0 not on priority list (0 << 0) = 0x00000000 + * MRRP[1] = L2CC1 not on priority list (0 << 0) = 0x00000000 + * MRRP[2] = MBX not on priority list (0 << 0) = 0x00000000 + * MRRP[3] = MAX1 not on priority list (0 << 0) = 0x00000000 + * MRRP[4] = SDMA not on priority list (0 << 0) = 0x00000000 + * MRRP[5] = MPEG4 not on priority list (0 << 0) = 0x00000000 + * MRRP[6] = IPU1 on priority list (1 << 6) = 0x00000040 + * MRRP[7] = IPU2 not on priority list (0 << 0) = 0x00000000 + * ------------ + * 0x00000040 + */ +#define M3IF_CONFIG 0x00000040 + +#define DBG_BASE_ADDR WEIM_CTRL_CS5 +#define DBG_CSCR_U_CONFIG 0x0000D843 +#define DBG_CSCR_L_CONFIG 0x22252521 +#define DBG_CSCR_A_CONFIG 0x22220A00 + +#define CCM_CCMR_CONFIG 0x003F4208 +#define CCM_PDR0_CONFIG 0x00821000 + +#define PLL_BRM_OFFSET 31 +#define PLL_PD_OFFSET 26 +#define PLL_MFD_OFFSET 16 +#define PLL_MFI_OFFSET 10 + +#define _PLL_BRM(x) ((x) << PLL_BRM_OFFSET) +#define _PLL_PD(x) (((x) - 1) << PLL_PD_OFFSET) +#define _PLL_MFD(x) (((x) - 1) << PLL_MFD_OFFSET) +#define _PLL_MFI(x) ((x) << PLL_MFI_OFFSET) +#define _PLL_MFN(x) (x) +#define _PLL_SETTING(brm, pd, mfd, mfi, mfn) \ + (_PLL_BRM(brm) | _PLL_PD(pd) | _PLL_MFD(mfd) | _PLL_MFI(mfi) |\ + _PLL_MFN(mfn)) + +#define CCM_MPLL_532_HZ _PLL_SETTING(1, 1, 12, 11, 1) +#define CCM_MPLL_399_HZ _PLL_SETTING(0, 1, 16, 8, 5) +#define CCM_PPLL_300_HZ _PLL_SETTING(0, 1, 4, 6, 1) + +/*MEMORY SETING*/ +#define ESDCTL_0x92220000 0x92220000 +#define ESDCTL_0xA2220000 0xA2220000 +#define ESDCTL_0xB2220000 0xB2220000 +#define ESDCTL_0x82228080 0x82228080 + +#define ESDCTL_PRECHARGE 0x00000400 + +#define ESDCTL_MDDR_CONFIG 0x007FFC3F +#define ESDCTL_MDDR_MR 0x00000033 +#define ESDCTL_MDDR_EMR 0x02000000 + +#define ESDCTL_DDR2_CONFIG 0x007FFC3F +#define ESDCTL_DDR2_EMR2 0x04000000 +#define ESDCTL_DDR2_EMR3 0x06000000 +#define ESDCTL_DDR2_EN_DLL 0x02000400 +#define ESDCTL_DDR2_RESET_DLL 0x00000333 +#define ESDCTL_DDR2_MR 0x00000233 +#define ESDCTL_DDR2_OCD_DEFAULT 0x02000780 + +#define ESDCTL_DELAY_LINE5 0x00F49F00 +#endif /* __BOARD_MX35_3STACK_H */ diff --git a/arch/arm/boards/freescale-mx35-3-stack/config.h b/arch/arm/boards/freescale-mx35-3-stack/config.h new file mode 100644 index 0000000..c724a57 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/config.h @@ -0,0 +1,28 @@ +/* + * 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 + */ + +/** + * @file + * @brief Global defintions for the Freescale i.MX35 3-stack board + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define CONFIG_MX35_HCLK_FREQ 24000000 + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/bin/_update b/arch/arm/boards/freescale-mx35-3-stack/env/bin/_update new file mode 100644 index 0000000..ddd6b84 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/env/bin/_update @@ -0,0 +1,39 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "Server did not reply! Update aborted." + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +echo +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part + +protect $part diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/bin/boot b/arch/arm/boards/freescale-mx35-3-stack/env/bin/boot new file mode 100644 index 0000000..fb2fe61 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/env/bin/boot @@ -0,0 +1,57 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + rootfs_loc=nand + kernel_loc=nand +elif [ x$1 = xnor ]; then + rootfs_loc=nor + kernel_loc=nor +elif [ x$1 = xnet ]; then + rootfs_loc=net + kernel_loc=net +fi + + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +elif [ x$ip != xno ]; then + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + + +if [ $rootfs_loc != net ]; then + if [ x$rootfs_loc = xnand ]; then + rootfs_mtdblock=$rootfs_mtdblock_nand + else + rootfs_mtdblock=$rootfs_mtdblock_nor + fi + + + if [ $rootfs_type = ubifs ]; then + bootargs="$bootargs root=ubi0:root ubi.mtd=$rootfs_mtdblock" + else + bootargs="$bootargs root=/dev/mtdblock$rootfs_mtdblock" + fi + + bootargs="$bootargs rootfstype=$rootfs_type" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + + +bootargs="$bootargs mtdparts=\"physmap-flash.0:$nor_parts;mxc_nand:$nand_parts\"" + +if [ $kernel_loc = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $kernel uImage || exit 1 + bootm uImage +elif [ $kernel_loc = nor ]; then + bootm /dev/nor0.kernel +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/bin/hush_hack b/arch/arm/boards/freescale-mx35-3-stack/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/bin/init b/arch/arm/boards/freescale-mx35-3-stack/env/bin/init new file mode 100644 index 0000000..c982f22 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/env/bin/init @@ -0,0 +1,38 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nor0 ]; then + addpart /dev/nor0 $nor_parts +fi + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" + saveenv +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel nand|nor [] to update kernel into flash" + echo "type update_rootfs nand|nor [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/bin/update_kernel b/arch/arm/boards/freescale-mx35-3-stack/env/bin/update_kernel new file mode 100644 index 0000000..63ad11a --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/env/bin/update_kernel @@ -0,0 +1,15 @@ +#!/bin/sh + +. /env/config +image=$kernel + +if [ x$1 = xnand ]; then + part=/dev/nand0.kernel.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.kernel +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/bin/update_rootfs b/arch/arm/boards/freescale-mx35-3-stack/env/bin/update_rootfs new file mode 100644 index 0000000..53dd2ca --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/env/bin/update_rootfs @@ -0,0 +1,20 @@ +#!/bin/sh + +. /env/config + +if [ $rootfs_type = ubifs ]; then + image=${rootfs}.ubi +else + image=${rootfs}.$rootfs_type +fi + +if [ x$1 = xnand ]; then + part=/dev/nand0.root.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.root +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/config b/arch/arm/boards/freescale-mx35-3-stack/env/config new file mode 100644 index 0000000..51195f7 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/env/config @@ -0,0 +1,35 @@ +#!/bin/sh + +# use 'dhcp' to do dhcp in barebox and in kernel +# use 'no' if you don't want to pass the ip from barebox to the kernel +#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 'net', 'nor' or 'nand'' +kernel_loc=nand +rootfs_loc=nand + +# can be either 'jffs2', or 'ubifs' +rootfs_type=ubifs + +kernel=uImage-mx35-3-stack +rootfs=root-mx35-3-stack +envimage=u-boot-v2-environment-mx35-3-stack + +autoboot_timeout=3 + +nfsroot="/path/to/nfs/root" +bootargs="console=ttymxc0,115200" + +bootargs="$bootargs video=mx3fb:CTP-CLAA070LC0ACW" + +nor_parts="256k(barebox)ro,512k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nor=3 + +nand_parts="256k(barebox)ro,512k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nand=7 diff --git a/arch/arm/boards/freescale-mx35-3-stack/flash_header.c b/arch/arm/boards/freescale-mx35-3-stack/flash_header.c new file mode 100644 index 0000000..171c499 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/flash_header.c @@ -0,0 +1,49 @@ +#include +#include + +extern unsigned long _stext; + +void __naked __flash_header_start go(void) +{ + __asm__ __volatile__("b exception_vectors\n"); +} + +struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { + { .ptr_type = 4, .addr = 0xb8002050, .val = 0x0000d843, }, + { .ptr_type = 4, .addr = 0xB8002054, .val = 0x22252521, }, + { .ptr_type = 4, .addr = 0xB8002058, .val = 0x22220a00, }, + { .ptr_type = 4, .addr = 0xB8001010, .val = 0x00000304, }, + { .ptr_type = 4, .addr = 0xB8001010, .val = 0x0000030C, }, + { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc3f, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0x92220000, }, + { .ptr_type = 4, .addr = 0x80000400, .val = 0x12345678, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0xA2220000, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, + { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0xB2220000, }, + { .ptr_type = 1, .addr = 0x80000233, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x82000780, .val = 0xda, }, + { .ptr_type = 1, .addr = 0x82000400, .val = 0xda, }, + { .ptr_type = 4, .addr = 0xB8001000, .val = 0x82226080, }, + { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc3f, }, + { .ptr_type = 4, .addr = 0xB800100C, .val = 0x007ffc3f, }, + { .ptr_type = 4, .addr = 0xB8001010, .val = 0x00000304, }, + { .ptr_type = 4, .addr = 0xB8001008, .val = 0x00002000, }, +}; + +#define APP_DEST 0x80000000 + +struct imx_flash_header __flash_header_0x400 flash_header = { + .app_code_jump_vector = APP_DEST + 0x1000, + .app_code_barker = APP_CODE_BARKER, + .app_code_csf = 0, + .dcd_ptr_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd), + .super_root_key = 0, + .dcd = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd_barker), + .app_dest = APP_DEST, + .dcd_barker = DCD_BARKER, + .dcd_block_len = sizeof (dcd_entry), +}; + +unsigned long __image_len_0x400 barebox_len = 0x40000; + diff --git a/arch/arm/boards/freescale-mx35-3-stack/lowlevel_init.S b/arch/arm/boards/freescale-mx35-3-stack/lowlevel_init.S new file mode 100644 index 0000000..1680579 --- /dev/null +++ b/arch/arm/boards/freescale-mx35-3-stack/lowlevel_init.S @@ -0,0 +1,283 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include "board-mx35_3stack.h" + +#define CSD0_BASE_ADDR 0x80000000 +#define ESDCTL_BASE_ADDR 0xB8001000 +#define CSD1_BASE_ADDR 0x90000000 + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +#define writeb(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + strb r1, [r0]; + +/* Assuming 24MHz input clock */ +#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) +#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) +#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) + + .section ".text_bare_init","ax" + +ARM_PPMRR: .word 0x40000015 +L2CACHE_PARAM: .word 0x00030024 +CCM_CCMR_W: .word 0x003F4208 +CCM_PDR0_W: .word 0x00001000 +MPCTL_PARAM_399_W: .word MPCTL_PARAM_399 +MPCTL_PARAM_532_W: .word MPCTL_PARAM_532 +PPCTL_PARAM_W: .word PPCTL_PARAM_300 +CCM_BASE_ADDR_W: .word IMX_CCM_BASE + +.globl board_init_lowlevel +board_init_lowlevel: + mov r10, lr + + mrc 15, 0, r1, c1, c0, 0 + + mrc 15, 0, r0, c1, c0, 1 + orr r0, r0, #7 + mcr 15, 0, r0, c1, c0, 1 + + orr r1, r1, #(1 << 11) /* Flow prediction (Z) */ + orr r1, r1, #(1 << 22) /* unaligned accesses */ + orr r1, r1, #(1 << 21) /* Low Int Latency */ + + mcr 15, 0, r1, c1, c0, 0 + + mov r0, #0 + mcr 15, 0, r0, c15, c2, 4 + + /* + * Branch predicition is now enabled. Flush the BTAC to ensure a valid + * starting point. Don't flush BTAC while it is disabled to avoid + * ARM1136 erratum 408023. + */ + mov r0, #0 + mcr p15, 0, r0, c7, c5, 6 /* flush entire BTAC */ + + mov r0, #0 + mcr 15, 0, r0, c7, c7, 0 /* invalidate I cache and D cache */ + mcr 15, 0, r0, c8, c7, 0 /* invalidate TLBs */ + mcr 15, 0, r0, c7, c10, 4 /* Drain the write buffer */ + + /* Also setup the Peripheral Port Remap register inside the core */ + ldr r0, ARM_PPMRR /* start from AIPS 2GB region */ + mcr p15, 0, r0, c15, c2, 4 + +/* + * End of ARM1136 init + */ + ldr r0, CCM_BASE_ADDR_W + + ldr r2, CCM_CCMR_W + str r2, [r0, #CCM_CCMR] + + ldr r3, MPCTL_PARAM_532_W /* consumer path*/ + + /* Set MPLL, arm clock and ahb clock */ + str r3, [r0, #CCM_MPCTL] + + ldr r1, PPCTL_PARAM_W + str r1, [r0, #CCM_PPCTL] + + ldr r1, CCM_PDR0_W + str r1, [r0, #CCM_PDR0] + + ldr r1, [r0, #CCM_CGR0] + orr r1, r1, #0x00300000 + str r1, [r0, #CCM_CGR0] + + ldr r1, [r0, #CCM_CGR1] + orr r1, r1, #0x00000C00 + orr r1, r1, #0x00000003 + str r1, [r0, #CCM_CGR1] + + /* Skip SDRAM initialization if we run from RAM */ + cmp pc, #0x80000000 + bls 1f + cmp pc, #0x90000000 + bhi 1f + + mov pc, r10 + +1: + ldr r0, =ESDCTL_BASE_ADDR + mov r3, #0x2000 + str r3, [r0, #0x0] + str r3, [r0, #0x8] + + /* ip(r12) has used to save lr register in upper calling */ + mov fp, lr + + mov r5, #0x00 + mov r2, #0x00 + mov r1, #CSD0_BASE_ADDR + bl setup_sdram_bank + cmp r3, #0x0 + orreq r5, r5, #1 + eorne r2, r2, #0x1 + blne setup_sdram_bank + + mov lr, fp + + ldr r3, =ESDCTL_DELAY_LINE5 + str r3, [r0, #0x30] + +#ifdef CONFIG_NAND_IMX_BOOT + ldr sp, =TEXT_BASE - 4 /* Setup a temporary stack in SDRAM */ + + ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ + ldr r2, =IMX_NFC_BASE + 0x800 /* end of NFC SRAM */ + + /* skip NAND boot if not running from NFC space */ + cmp pc, r0 + blo ret + cmp pc, r2 + bhs ret + + /* Move ourselves out of NFC SRAM */ + ldr r1, =TEXT_BASE + +copy_loop: + ldmia r0!, {r3-r9} /* copy from source address [r0] */ + stmia r1!, {r3-r9} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + + ldr pc, =1f /* Jump to SDRAM */ +1: + bl nand_boot /* Load barebox from NAND Flash */ + + /* rebase the return address */ + ldr r1, =IMX_NFC_BASE - TEXT_BASE + sub r10, r10, r1 /* adjust return address from NFC SRAM */ +ret: +#endif /* CONFIG_NAND_IMX_BOOT */ + + mov pc, r10 + +/* + * r0: ESDCTL control base, r1: sdram slot base + * r2: DDR type (0: DDR2, 1: MDDR) r3, r4: working base + */ +setup_sdram_bank: + mov r3, #0xE /* 0xA + 0x4 */ + tst r2, #0x1 + orreq r3, r3, #0x300 /* DDR2 */ + str r3, [r0, #0x10] + bic r3, r3, #0x00A + str r3, [r0, #0x10] + beq 2f + + mov r3, #0x20000 +1: subs r3, r3, #1 + bne 1b + +2: tst r2, #0x1 + ldreq r3, =ESDCTL_DDR2_CONFIG + ldrne r3, =ESDCTL_MDDR_CONFIG + cmp r1, #CSD1_BASE_ADDR + strlo r3, [r0, #0x4] + strhs r3, [r0, #0xC] + + ldr r3, =ESDCTL_0x92220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, =ESDCTL_PRECHARGE + strb r3, [r1, r4] + + tst r2, #0x1 + bne skip_set_mode + + cmp r1, #CSD1_BASE_ADDR + ldr r3, =ESDCTL_0xB2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, =ESDCTL_DDR2_EMR2 + strb r3, [r1, r4] + ldr r4, =ESDCTL_DDR2_EMR3 + strb r3, [r1, r4] + ldr r4, =ESDCTL_DDR2_EN_DLL + strb r3, [r1, r4] + ldr r4, =ESDCTL_DDR2_RESET_DLL + strb r3, [r1, r4] + + ldr r3, =ESDCTL_0x92220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, =ESDCTL_PRECHARGE + strb r3, [r1, r4] + +skip_set_mode: + cmp r1, #CSD1_BASE_ADDR + ldr r3, =ESDCTL_0xA2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + strb r3, [r1] + strb r3, [r1] + + ldr r3, =ESDCTL_0xB2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + tst r2, #0x1 + ldreq r4, =ESDCTL_DDR2_MR + ldrne r4, =ESDCTL_MDDR_MR + mov r3, #0xDA + strb r3, [r1, r4] + ldreq r4, =ESDCTL_DDR2_OCD_DEFAULT + streqb r3, [r1, r4] + ldreq r4, =ESDCTL_DDR2_EN_DLL + ldrne r4, =ESDCTL_MDDR_EMR + strb r3, [r1, r4] + + cmp r1, #CSD1_BASE_ADDR + ldr r3, =ESDCTL_0x82228080 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + + tst r2, #0x1 + moveq r4, #0x20000 + movne r4, #0x200 +1: subs r4, r4, #1 + bne 1b + + str r3, [r1, #0x100] + ldr r4, [r1, #0x100] + cmp r3, r4 + movne r3, #1 + moveq r3, #0 + + mov pc, lr diff --git a/arch/arm/boards/guf-neso/Makefile b/arch/arm/boards/guf-neso/Makefile new file mode 100644 index 0000000..2b6eb02 --- /dev/null +++ b/arch/arm/boards/guf-neso/Makefile @@ -0,0 +1,5 @@ + +obj-y += lowlevel.o +obj-y += board.o +obj-y += pll_init.o + diff --git a/arch/arm/boards/guf-neso/board.c b/arch/arm/boards/guf-neso/board.c new file mode 100644 index 0000000..2f53d34 --- /dev/null +++ b/arch/arm/boards/guf-neso/board.c @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2010 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +/* two pins are controlling the CS signals to the USB phys */ +#define USBH2_PHY_CS_GPIO (GPIO_PORTF + 20) +#define OTG_PHY_CS_GPIO (GPIO_PORTF + 19) + +/* two pins are controlling the display and its backlight */ +#define LCD_POWER_GPIO (GPIO_PORTF + 18) +#define BACKLIGHT_POWER_GPIO (GPIO_PORTE + 5) + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0xa0000000, + .size = 128 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, + .phy_addr = 31, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = 0x1002b000, + .platform_data = &fec_info, +}; + +static struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = 0xd8000000, + .platform_data = &nand_info, +}; + +static struct imx_fb_videomode imxfb_mode = { + .mode = { + .name = "CPT CLAA070LC0JCT", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = KHZ2PICOS(27000), + .hsync_len = 1, /* DE only sync */ + .left_margin = 50, + .right_margin = 50, + .vsync_len = 1, /* DE only sync */ + .upper_margin = 10, + .lower_margin = 10, + }, + /* + * - TFT style panel + * - clk enabled while idle + * - clock inverted + * - data not inverted + * - data enable high active + */ + .pcr = PCR_TFT | + PCR_COLOR | + PCR_PBSIZ_8 | + PCR_BPIX_16 | + PCR_CLKPOL | + PCR_SCLK_SEL | + PCR_LPPOL | + PCR_FLMPOL, + .bpp = 16, /* TODO 32 bit does not work: The 'green' component is lacking in this mode */ +}; + +static void neso_fb_enable(int enable) +{ + gpio_direction_output(LCD_POWER_GPIO, enable); + gpio_direction_output(BACKLIGHT_POWER_GPIO, enable); +} + +static struct imx_fb_platform_data neso_fb_data = { + .mode = &imxfb_mode, + .pwmr = 0x00000000, /* doesn't matter */ + .lscr1 = 0x00120300, /* doesn't matter */ + /* dynamic mode -> using the reset values (as recommended in the datasheet) */ + .dmacr = (0 << 31) | (4 << 16) | 96, + .enable = neso_fb_enable, + .framebuffer_ovl = (void *)0xa7f00000, +}; + +static struct device_d imxfb_dev = { + .name = "imxfb", + .map_base = 0x10021000, + .size = 0x1000, + .platform_data = &neso_fb_data, +}; + +#ifdef CONFIG_USB + +static struct device_d usbh2_dev = { + .name = "ehci", + .map_base = IMX_OTG_BASE + 0x400, + .size = 0x200, +}; + +static void neso_usbh_init(void) +{ + uint32_t temp; + + temp = readl(IMX_OTG_BASE + 0x600); + temp &= ~((3 << 21) | 1); + temp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20) | (1<<11); + writel(temp, IMX_OTG_BASE + 0x600); + + temp = readl(IMX_OTG_BASE + 0x584); + temp &= ~(3 << 30); + temp |= 2 << 30; + writel(temp, IMX_OTG_BASE + 0x584); + + mdelay(10); + + gpio_set_value(USBH2_PHY_CS_GPIO, 0); + mdelay(10); + isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x570), 1); +} +#endif + +#ifdef CONFIG_MMU +static void neso_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0xa0000000, 0xa0000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0xb0000000, 0xa0000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + +#if TEXT_BASE & (0x100000 - 1) +#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary +#else + arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); +#endif + mmu_enable(); +} +#else +static void neso_mmu_init(void) +{ +} +#endif + +static int neso_devices_init(void) +{ + int i; + + unsigned int mode[] = { + /* UART1 */ + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + /* FEC */ + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + + /* SSI1 connected in AC97 style */ + PC20_PF_SSI1_FS, + PC21_PF_SSI1_RXD, + PC22_PF_SSI1_TXD, + PC23_PF_SSI1_CLK, + + /* LED 1 */ + (GPIO_PORTB | 15 | GPIO_GPIO | GPIO_OUT), + /* LED 2 */ + (GPIO_PORTB | 16 | GPIO_GPIO | GPIO_OUT), + /* CTOUCH reset */ + (GPIO_PORTB | 17 | GPIO_GPIO | GPIO_OUT), + /* CTOUCH IRQ */ + (GPIO_PORTB | 14 | GPIO_GPIO | GPIO_IN), + /* RTC IRQ */ + (GPIO_PORTF | 14 | GPIO_GPIO | GPIO_IN), + /* SD change card detection */ + (GPIO_PORTF | 17 | GPIO_GPIO | GPIO_IN), + /* SDHC1*/ + PE18_PF_SD1_D0, + PE19_PF_SD1_D1, + PE20_PF_SD1_D2, + PE21_PF_SD1_D3, + PE22_PF_SD1_CMD, + PE23_PF_SD1_CLK, + /* I2C1 */ + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, + /* I2C2, for CTOUCH */ + PC5_PF_I2C2_SDA, + PC6_PF_I2C2_SCL, + + /* Connected to: Both USB phys and ethernet phy FIXME 1 = RESET? */ + PE17_PF_RESET_OUT, + + /* USB host */ + (USBH2_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT), + PA0_PF_USBH2_CLK, + PA1_PF_USBH2_DIR, + PA3_PF_USBH2_NXT, + PA4_PF_USBH2_STP, + PD22_AF_USBH2_DATA0, + PD24_AF_USBH2_DATA1, + PD23_AF_USBH2_DATA2, + PD20_AF_USBH2_DATA3, + PD19_AF_USBH2_DATA4, + PD26_AF_USBH2_DATA5, + PD21_AF_USBH2_DATA6, + PA2_PF_USBH2_DATA7, + + /* USB OTG */ + (OTG_PHY_CS_GPIO | GPIO_GPIO | GPIO_OUT), + PE24_PF_USBOTG_CLK, + PE2_PF_USBOTG_DIR, + PE0_PF_USBOTG_NXT, + PE1_PF_USBOTG_STP, + PC9_PF_USBOTG_DATA0, + PC11_PF_USBOTG_DATA1, + PC10_PF_USBOTG_DATA2, + PC13_PF_USBOTG_DATA3, + PC12_PF_USBOTG_DATA4, + PC7_PF_USBOTG_DATA5, + PC8_PF_USBOTG_DATA6, + PE25_PF_USBOTG_DATA7, + + /* Display signals */ + (LCD_POWER_GPIO | GPIO_GPIO | GPIO_OUT), /* LCD power: 1 = LCD on */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA31_PF_OE_ACD, /* DE */ + + /* Backlight PWM (Use as gpio) */ + (BACKLIGHT_POWER_GPIO | GPIO_GPIO | GPIO_OUT), + }; + + /* reset the chip select lines to the USB/OTG phys to avoid any hang */ + gpio_direction_output(OTG_PHY_CS_GPIO, 1); + gpio_direction_output(USBH2_PHY_CS_GPIO, 1); + + + neso_mmu_init(); + + /* initialize gpios */ + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + + register_device(&nand_dev); + register_device(&sdram_dev); + register_device(&imxfb_dev); + +#ifdef CONFIG_USB + neso_usbh_init(); + register_device(&usbh2_dev); +#endif + + register_device(&fec_dev); + + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x40000, 0x80000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0xa0000100); + armlinux_set_architecture(MACH_TYPE_NESO); + + return 0; +} + +device_initcall(neso_devices_init); + +static struct device_d neso_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static int neso_console_init(void) +{ + register_device(&neso_serial_device); + + return 0; +} + +console_initcall(neso_console_init); + +extern void *neso_pll_init, *neso_pll_init_end; + +static int neso_pll(void) +{ + void *vram = (void *)0xffff4c00; + void (*pllfunc)(void) = vram; + + printf("initialising PLLs\n"); + + memcpy(vram, &neso_pll_init, 0x100); + + console_flush(); + + pllfunc(); + + /* clock gating enable */ + GPCR = 0x00050f08; + + PCDR0 = 0x130410c3; + PCDR1 = 0x09030911; + + /* Clocks have changed. Notify clients */ + clock_notifier_call_chain(); + + return 0; +} + +late_initcall(neso_pll); + diff --git a/arch/arm/boards/guf-neso/config.h b/arch/arm/boards/guf-neso/config.h new file mode 100644 index 0000000..c2f5e7c --- /dev/null +++ b/arch/arm/boards/guf-neso/config.h @@ -0,0 +1,26 @@ +/* + * 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 + */ + +/** + * @file + * @brief Global defintions for the ARM i.MX27 based pcm038 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/guf-neso/env/config b/arch/arm/boards/guf-neso/env/config new file mode 100644 index 0000000..6327e69 --- /dev/null +++ b/arch/arm/boards/guf-neso/env/config @@ -0,0 +1,53 @@ +#!/bin/sh + +machine=guf-neso +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 'net', 'nor' or 'nand' +kernel_loc=net +# 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=ttymxc0,115200" + +nand_parts="256k(barebox)ro,512k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nand=3 + +# 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/guf-neso/lowlevel.c b/arch/arm/boards/guf-neso/lowlevel.c new file mode 100644 index 0000000..0c376f2 --- /dev/null +++ b/arch/arm/boards/guf-neso/lowlevel.c @@ -0,0 +1,117 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __bare_init __naked insdram(void) +{ + uint32_t r; + + PCCR1 |= PCCR1_NFC_BAUDEN; + + /* setup a stack to be able to call imx_nand_load_image() */ + r = STACK_BASE + STACK_SIZE - 12; + __asm__ __volatile__("mov sp, %0" : : "r"(r)); + + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); + + board_init_lowlevel_return(); +} + +#define ESDCTL0_VAL (ESDCTL0_SDE | ESDCTL0_ROW13 | ESDCTL0_COL10) + +void __bare_init __naked board_init_lowlevel(void) +{ + uint32_t r; + int i; + unsigned int *trg, *src; + + /* ahb lite ip interface */ + AIPI1_PSR0 = 0x20040304; + AIPI1_PSR1 = 0xDFFBFCFB; + AIPI2_PSR0 = 0x00000000; + AIPI2_PSR1 = 0xFFFFFFFF; + + /* Skip SDRAM initialization if we run from RAM */ + r = get_pc(); + if (r > 0xa0000000 && r < 0xb0000000) + board_init_lowlevel_return(); + + /* + * DDR on CSD0 + */ + writel(0x00000008, ESDMISC); /* Enable DDR SDRAM operation */ + + DSCR(3) = 0x55555555; /* Set the driving strength */ + DSCR(5) = 0x55555555; + DSCR(6) = 0x55555555; + DSCR(7) = 0x00005005; + DSCR(8) = 0x15555555; + + writel(0x00000004, ESDMISC); /* Initial reset */ + writel(0x006ac73a, ESDCFG0); + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_PRECHARGE, ESDCTL0); /* precharge CSD0 all banks */ + writel(0x00000000, 0xA0000F00); /* CSD0 precharge address (A10 = 1) */ + writel(ESDCTL0_VAL | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0); + + for (i = 0; i < 8; i++) + writel(0, 0xa0000f00); + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0); + + writeb(0xda, 0xa0000033); + writeb(0xff, 0xa1000000); + writel(ESDCTL0_VAL | ESDCTL0_DSIZ_31_0 | ESDCTL0_REF4 | + ESDCTL0_BL | ESDCTL0_SMODE_NORMAL, ESDCTL0); + +#ifdef CONFIG_NAND_IMX_BOOT + /* skip NAND boot if not running from NFC space */ + r = get_pc(); + if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x800) + board_init_lowlevel_return(); + + src = (unsigned int *)IMX_NFC_BASE; + trg = (unsigned int *)TEXT_BASE; + + /* Move ourselves out of NFC SRAM */ + for (i = 0; i < 0x800 / sizeof(int); i++) + *trg++ = *src++; + + /* Jump to SDRAM */ + r = (unsigned int)&insdram; + __asm__ __volatile__("mov pc, %0" : : "r"(r)); +#else + board_init_lowlevel_return(); +#endif +} + diff --git a/arch/arm/boards/guf-neso/pll_init.S b/arch/arm/boards/guf-neso/pll_init.S new file mode 100644 index 0000000..87e5312 --- /dev/null +++ b/arch/arm/boards/guf-neso/pll_init.S @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +#define CSCR_VAL CSCR_USB_DIV(3) | \ + CSCR_SD_CNT(3) | \ + CSCR_MSHC_SEL | \ + CSCR_H264_SEL | \ + CSCR_SSI1_SEL | \ + CSCR_SSI2_SEL | \ + CSCR_MCU_SEL | \ + CSCR_ARM_SRC_MPLL | \ + CSCR_SP_SEL | \ + CSCR_ARM_DIV(0) | \ + CSCR_FPM_EN | \ + CSCR_SPEN | \ + CSCR_MPEN | \ + CSCR_AHB_DIV(1) + +ENTRY(neso_pll_init) + + writel(IMX_PLL_PD(0) | + IMX_PLL_MFD(51) | + IMX_PLL_MFI(7) | + IMX_PLL_MFN(35), MPCTL0) /* 399 MHz */ + + writel(IMX_PLL_PD(1) | + IMX_PLL_MFD(12) | + IMX_PLL_MFI(9) | + IMX_PLL_MFN(3), SPCTL0) /* SPLL = 2 * 26 * 4.61538 MHz = 240 MHz */ + + writel(CSCR_VAL | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR) + + ldr r2, =16000 +1: + subs r2, r2, #1 + nop + bcs 1b + + mov pc, lr +ENDPROC(neso_pll_init) + diff --git a/arch/arm/boards/imx21ads/Makefile b/arch/arm/boards/imx21ads/Makefile new file mode 100644 index 0000000..7993fde --- /dev/null +++ b/arch/arm/boards/imx21ads/Makefile @@ -0,0 +1,2 @@ +obj-y += lowlevel_init.o +obj-y += imx21ads.o diff --git a/arch/arm/boards/imx21ads/config.h b/arch/arm/boards/imx21ads/config.h new file mode 100644 index 0000000..edfb29f --- /dev/null +++ b/arch/arm/boards/imx21ads/config.h @@ -0,0 +1,26 @@ +/* + * 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 + */ + +/** + * @file + * @brief Global defintions for the ARM i.MX21 based imx21ads + **/ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/imx21ads/env/bin/init b/arch/arm/boards/imx21ads/env/bin/init new file mode 100644 index 0000000..224a6b4 --- /dev/null +++ b/arch/arm/boards/imx21ads/env/bin/init @@ -0,0 +1 @@ +# Dummy Init environment script diff --git a/arch/arm/boards/imx21ads/imx21ads.c b/arch/arm/boards/imx21ads/imx21ads.c new file mode 100644 index 0000000..5e88af4 --- /dev/null +++ b/arch/arm/boards/imx21ads/imx21ads.c @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2009 Ivo Clarysse + * + * Based on imx27ads.c, + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MX21ADS_IO_REG 0xCC800000 +#define MX21ADS_IO_LCDON (1 << 9) + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0xC8000000, + .size = 32 * 1024 * 1024, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0xc0000000, + .size = 64 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = 0xDF003000, + .platform_data = &nand_info, +}; + +static struct device_d cs8900_dev = { + .name = "cs8900", + .map_base = IMX_CS1_BASE, + // IRQ is connected to UART3_RTS +}; + +/* Sharp LQ035Q7DB02 QVGA display */ +static struct imx_fb_videomode imx_fb_modedata = { + .mode = { + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 188679, + .left_margin = 6, + .right_margin = 16, + .upper_margin = 8, + .lower_margin = 10, + .hsync_len = 2, + .vsync_len = 1, + .sync = 0, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, + }, + .pcr = 0xfb108bc7, + .bpp = 16, +}; + +static struct imx_fb_platform_data imx_fb_data = { + .mode = &imx_fb_modedata, + .cmap_greyscale = 0, + .cmap_inverse = 0, + .cmap_static = 0, + .pwmr = 0x00a903ff, + .lscr1 = 0x00120300, + .dmacr = 0x00020008, +}; + +static struct device_d imxfb_dev = { + .name = "imxfb", + .map_base = 0x10021000, + .size = 0x1000, + .platform_data = &imx_fb_data, +}; + +static int imx21ads_timing_init(void) +{ + u32 temp; + + /* Configure External Interface Module */ + /* CS0: burst flash */ + CS0U = 0x00003E00; + CS0L = 0x00000E01; + + /* CS1: Ethernet controller, external UART, memory-mapped I/O (16-bit) */ + CS1U = 0x00002000; + CS1L = 0x11118501; + + /* CS2: disable (not available, since CSD0 in use) */ + CS2U = 0x0; + CS2L = 0x0; + + /* CS3: disable */ + CS3U = 0x0; + CS3L = 0x0; + /* CS4: disable */ + CS4U = 0x0; + CS4L = 0x0; + /* CS5: disable */ + CS5U = 0x0; + CS5L = 0x0; + + temp = PCDR0; + temp &= ~0xF000; + temp |= 0xA000; /* Set NFC divider; 0xA yields 24.18MHz */ + PCDR0 = temp; + + return 0; +} + +core_initcall(imx21ads_timing_init); + +static int mx21ads_devices_init(void) +{ + int i; + unsigned int mode[] = { + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA24_PF_REV, + PA25_PF_CLS, + PA26_PF_PS, + PA27_PF_SPL_SPR, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + }; + + /* initizalize gpios */ + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + + register_device(&cfi_dev); + register_device(&sdram_dev); + register_device(&nand_dev); + register_device(&cs8900_dev); + register_device(&imxfb_dev); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0xc0000100); + armlinux_set_architecture(MACH_TYPE_MX21ADS); + + return 0; +} + +device_initcall(mx21ads_devices_init); + +static int mx21ads_enable_display(void) +{ + u16 tmp; + + tmp = readw(MX21ADS_IO_REG); + tmp |= MX21ADS_IO_LCDON; + writew(tmp, MX21ADS_IO_REG); + return 0; +} + +late_initcall(mx21ads_enable_display); + +static struct device_d mx21ads_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static int mx21ads_console_init(void) +{ + register_device(&mx21ads_serial_device); + return 0; +} + +console_initcall(mx21ads_console_init); + +#ifdef CONFIG_NAND_IMX_BOOT +void __bare_init nand_boot(void) +{ + PCCR0 |= PCCR0_NFC_EN; + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); +} +#endif + diff --git a/arch/arm/boards/imx21ads/imx21ads.dox b/arch/arm/boards/imx21ads/imx21ads.dox new file mode 100644 index 0000000..9f11ffa --- /dev/null +++ b/arch/arm/boards/imx21ads/imx21ads.dox @@ -0,0 +1,5 @@ +/** @page imx21ads Freescale i.MX21ads + +This is the Freescale evaluation board for the i.MX21 Processor + +*/ diff --git a/arch/arm/boards/imx21ads/lowlevel_init.S b/arch/arm/boards/imx21ads/lowlevel_init.S new file mode 100644 index 0000000..607da27 --- /dev/null +++ b/arch/arm/boards/imx21ads/lowlevel_init.S @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2010 Jaccon Bastiaansen + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + + .section ".text_bare_init","ax" + +.globl board_init_lowlevel +board_init_lowlevel: + +/* Save lr, because it is overwritten by the calls to mem_delay. */ + mov r10, lr + +/* + * Initialize the AHB-Lite IP Interface (AIPI) module (to enable access to + * on chip peripherals) as described in section 7.2 of rev3 of the i.MX21 + * reference manual. + */ + ldr r0, =AIPI1_PSR0 + ldr r1, =0x00040304 + str r1, [r0] + ldr r0, =AIPI1_PSR1 + ldr r1, =0xfffbfcfb + str r1, [r0] + + ldr r0, =AIPI2_PSR0 + ldr r1, =0x3ffc0000 + str r1, [r0] + ldr r0, =AIPI2_PSR1 + ldr r1, =0xffffffff + str r1, [r0] + +/* + * Configure CPU core clock (266MHz), peripheral clock (133MHz) and enable + * the clock to peripherals. + */ + ldr r0, =CSCR + ldr r1, =0x17180607 + str r1, [r0] + + ldr r0, =PCCR1 + ldr r1, =0x0e000000 + str r1, [r0] + + +/* + * SDRAM and SDRAM controller configuration + */ + + /* + * CSD1 not required, because the MX21ADS board only contains 64Mbyte. + * CS3 can therefore be made available. + */ + ldr r0, =FMCR + ldr r1, =0xffffffc9 + str r1, [r0] + + /* Skip SDRAM initialization if we run from RAM */ + cmp pc, #0xc0000000 + bls 1f + cmp pc, #0xc8000000 + bhi 1f + + mov pc, r10 +1: + + /* Precharge */ + ldr r0, =SDCTL0 + ldr r1, =0x92120300 + str r1, [r0] + ldr r2, =0xc0200000 + ldr r1, [r2] + + bl mem_delay + + /* Auto refresh */ + ldr r1, =0xa2120300 + str r1, [r0] + ldr r2, =0xc0000000 + ldr r1, [r2] + ldr r1, [r2] + ldr r1, [r2] + ldr r1, [r2] + ldr r1, [r2] + ldr r1, [r2] + ldr r1, [r2] + ldr r1, [r2] + + /* Set mode register */ + ldr r1, =0xB2120300 + str r1, [r0] + ldr r1, =0xC0119800 + ldr r2, [r1] + + bl mem_delay + + /* Back to Normal Mode */ + ldr r1, =0x8212F339 + str r1, [r0] + + /* Set NFC_CLK to 24MHz */ + ldr r0, =PCDR0 + ldr r1, =0x6419a007 + str r1, [r0] + +#ifdef CONFIG_NAND_IMX_BOOT + ldr sp, =TEXT_BASE - 4 /* Setup a temporary stack in SDRAM */ + + ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ + ldr r2, =IMX_NFC_BASE + 0x800 /* end of NFC SRAM */ + + /* skip NAND boot if not running from NFC space */ + cmp pc, r0 + bls ret + cmp pc, r2 + bhi ret + + /* Move ourselves out of NFC SRAM */ + ldr r1, =TEXT_BASE + +copy_loop: + ldmia r0!, {r3-r9} /* copy from source address [r0] */ + stmia r1!, {r3-r9} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + + ldr pc, =1f /* Jump to SDRAM */ +1: + bl nand_boot /* Load barebox from NAND Flash */ + + ldr r1, =IMX_NFC_BASE - TEXT_BASE + sub r10, r10, r1 /* adjust return address from NFC */ + /* SRAM to SDRAM */ +#endif /* CONFIG_NAND_IMX_BOOT */ + +ret: + mov pc, r10 + +/* + * spin for a while. we need to wait at least 200 usecs. + */ +mem_delay: + mov r4, #0x4000 +spin: subs r4, r4, #1 + bne spin + mov pc, lr + diff --git a/arch/arm/boards/imx27ads/Makefile b/arch/arm/boards/imx27ads/Makefile new file mode 100644 index 0000000..bdc905f --- /dev/null +++ b/arch/arm/boards/imx27ads/Makefile @@ -0,0 +1,3 @@ + +obj-y += lowlevel_init.o +obj-y += imx27ads.o diff --git a/arch/arm/boards/imx27ads/config.h b/arch/arm/boards/imx27ads/config.h new file mode 100644 index 0000000..b54a3c5 --- /dev/null +++ b/arch/arm/boards/imx27ads/config.h @@ -0,0 +1,26 @@ +/* + * 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 + */ + +/** + * @file + * @brief Global defintions for the Freescale imx27ads ARM board + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/imx27ads/env/bin/_update b/arch/arm/boards/imx27ads/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/imx27ads/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/imx27ads/env/bin/boot b/arch/arm/boards/imx27ads/env/bin/boot new file mode 100644 index 0000000..3859dc1 --- /dev/null +++ b/arch/arm/boards/imx27ads/env/bin/boot @@ -0,0 +1,38 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xflash ]; then + root=flash + kernel=flash +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xflash ]; then + bootargs="$bootargs root=$rootpart rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm /dev/nor0.kernel +fi + diff --git a/arch/arm/boards/imx27ads/env/bin/init b/arch/arm/boards/imx27ads/env/bin/init new file mode 100644 index 0000000..48e2139 --- /dev/null +++ b/arch/arm/boards/imx27ads/env/bin/init @@ -0,0 +1,20 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +addpart /dev/nor0 $mtdparts + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type udate_root [] to update rootfs into flash" + echo + exit +fi + +boot \ No newline at end of file diff --git a/arch/arm/boards/imx27ads/env/bin/update_kernel b/arch/arm/boards/imx27ads/env/bin/update_kernel new file mode 100644 index 0000000..1ad95fc --- /dev/null +++ b/arch/arm/boards/imx27ads/env/bin/update_kernel @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$uimage +part=/dev/nor0.kernel + +. /env/bin/_update $1 diff --git a/arch/arm/boards/imx27ads/env/bin/update_root b/arch/arm/boards/imx27ads/env/bin/update_root new file mode 100644 index 0000000..b757a5b --- /dev/null +++ b/arch/arm/boards/imx27ads/env/bin/update_root @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 +part=/dev/nor0.root + +. /env/bin/_update $1 diff --git a/arch/arm/boards/imx27ads/env/config b/arch/arm/boards/imx27ads/env/config new file mode 100644 index 0000000..f18a86b --- /dev/null +++ b/arch/arm/boards/imx27ads/env/config @@ -0,0 +1,25 @@ +#!/bin/sh + +# can be either 'net' or 'flash' +kernel=net +root=net + +# use 'dhcp' todo dhcp in barebox and in kernel +ip=dhcp + +eth0.ipaddr=192.168.23.164 +eth0.netmask=255.255.255.0 +eth0.gateway=192.168.23.2 +eth0.serverip=192.168.23.2 + +uimage=uImage-mx27ads +jffs2=root-mx27ads.jffs2 + +autoboot_timeout=3 + +nfsroot="/tmp/imx27ads" +bootargs="console=ttymxc0,115200" + +mtdparts="128k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" +rootpart="/dev/mtdblock3" + diff --git a/arch/arm/boards/imx27ads/imx27ads.c b/arch/arm/boards/imx27ads/imx27ads.c new file mode 100644 index 0000000..6f31520 --- /dev/null +++ b/arch/arm/boards/imx27ads/imx27ads.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0xC0000000, + .size = 32 * 1024 * 1024, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0xa0000000, + .size = 128 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, + .phy_addr = 1, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = 0x1002b000, + .platform_data = &fec_info, +}; + +static int imx27ads_timing_init(void) +{ + /* configure cpld on cs4 */ + CS4U = 0x0000DCF6; + CS4L = 0x444A4541; + CS4A = 0x44443302; + + /* configure synchronous mode for + * 16 bit nor flash on cs0 */ + CS0U = 0x0000CC03; + CS0L = 0xa0330D01; + CS0A = 0x00220800; + + writew(0x00f0, 0xc0000000); + writew(0x00aa, 0xc0000aaa); + writew(0x0055, 0xc0000554); + writew(0x00d0, 0xc0000aaa); + writew(0x66ca, 0xc0000aaa); + writew(0x00f0, 0xc0000000); + + CS0U = 0x23524E80; + CS0L = 0x10000D03; + CS0A = 0x00720900; + + /* Select FEC data through data path */ + writew(0x0020, IMX_CS4_BASE + 0x10); + + /* Enable CPLD FEC data path */ + writew(0x0010, IMX_CS4_BASE + 0x14); + + return 0; +} + +core_initcall(imx27ads_timing_init); + +static int mx27ads_devices_init(void) +{ + int i; + unsigned int mode[] = { + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC | GPIO_PUEN, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + }; + + /* initizalize gpios */ + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + + register_device(&cfi_dev); + register_device(&sdram_dev); + register_device(&fec_dev); + + devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x20000, 0x20000, PARTITION_FIXED, "env0"); + protect_file("/dev/env0", 1); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0xa0000100); + armlinux_set_architecture(MACH_TYPE_MX27ADS); + + return 0; +} + +device_initcall(mx27ads_devices_init); + +static struct device_d mx27ads_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static int mx27ads_console_init(void) +{ + register_device(&mx27ads_serial_device); + return 0; +} + +console_initcall(mx27ads_console_init); + diff --git a/arch/arm/boards/imx27ads/imx27ads.dox b/arch/arm/boards/imx27ads/imx27ads.dox new file mode 100644 index 0000000..e14d8e3 --- /dev/null +++ b/arch/arm/boards/imx27ads/imx27ads.dox @@ -0,0 +1,5 @@ +/** @page imx27ads Freescale i.MX27ads + +This is the Freescale evaluation board for the i.MX27 Processor + +*/ diff --git a/arch/arm/boards/imx27ads/lowlevel_init.S b/arch/arm/boards/imx27ads/lowlevel_init.S new file mode 100644 index 0000000..df12aea --- /dev/null +++ b/arch/arm/boards/imx27ads/lowlevel_init.S @@ -0,0 +1,172 @@ +/* + * For clock initialization, see chapter 3 of the "MCIMX27 Multimedia + * Applications Processor Reference Manual, Rev. 0.2". + * + */ + +#include +#include + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +#define CRM_PLL_PCTL_PARAM(pd, fd, fi, fn) (((pd-1)<<26) + ((fd-1)<<16) + (fi<<10) + (fn<<0)) + +.macro sdram_init_sha + /* + * DDR on CSD0 + */ + writel(0x00000008, 0xD8001010) + writel(0x55555555, 0x10027828) + writel(0x55555555, 0x10027830) + writel(0x55555555, 0x10027834) + writel(0x00005005, 0x10027838) + writel(0x15555555, 0x1002783C) + writel(0x00000004, 0xD8001010) + writel(0x006ac73a, 0xD8001004) + writel(0x92100000, 0xD8001000) + writel(0x00000000, 0xA0000F00) + writel(0xA2100000, 0xD8001000) + writel(0x00000000, 0xA0000F00) + writel(0x00000000, 0xA0000F00) + writel(0x00000000, 0xA0000F00) + writel(0x00000000, 0xA0000F00) + writel(0xA2200000, 0xD8001000) + writel(0x00000000, 0xA0000F00) + writel(0x00000000, 0xA0000F00) + writel(0x00000000, 0xA0000F00) + writel(0x00000000, 0xA0000F00) + writel(0xb2100000, 0xD8001000) + ldr r0, =0xA0000033 + mov r1, #0xda + strb r1, [r0] + ldr r0, =0xA1000000 + mov r1, #0xff + strb r1, [r0] + writel(0x82226080, 0xD8001000) +.endm + +.macro sdram_init_mx27_manual + /* + * sdram init sequence, as defined in 18.5.4 of the i.MX27 reference manual + */ +1: + ldr r2, =ESD_ESDCTL0 /* base address of registers */ + ldr r3, =PRE_ALL_CMD /* SMODE=001 */ + str r3,(r2,#0x0) /* put CSD0 in precharge command mode */ + ldr r4, =SDRAM_CSD0 /* CSD0 precharge address (A10=1) */ + str r1,(r4,#0x0) /* precharge CSD0 all banks */ + ldr r3, =AUTO_REF_CMD /* SMODE=010 */ + str r3,(r2,#0x0) /* put array 0 in auto-refresh mode */ + ldr r4, =SDRAM_CSD0_BASE /* CSD0 base address */ + ldr r6,=0x7 /* load loop counter */ +1: ldr r5,(r4,#0x0) /* run auto-refresh cycle to array 0 */ + subs r6,r6,#1 /* decrease counter value */ + bne 1b + ldr r3, =SET_MODE_REG_CMD /* SMODE=011 */ + str r3,(r2,#0x0) /* setup CSD0 for mode register write */ + ldr r3, =MODE_REG_VAL0 /* array 0 mode register value */ + ldrb r5,(r3,#0x0) /* New mode register value on address bus */ + ldr r3, =NORMAL_MODE /* SMODE=000 */ + str r3,(r2,#0x0) /* setup CSD0 for normal operation */ + +ESD_ESDCTL0 .long 0xD8001000 // system/external device dependent data +SDRAM_CSD0 .long 0x00000000 // system/external device dependent data +SDRAM_CSD0_BASE .long 0x00000000 // system/external device dependent data +PRE_ALL_CMD .long 0x00000000 // system/external device dependent data (SMODE=001) +AUTO_REF_CMD .long 0x00000000 // system/external device dependent data (SMODE=010) +SET_MODE_REG_CMD .long 0x00000000 // system/external device dependent data (SMODE=011) +MODE_REG_VAL0 .long 0x00000000 // system/external device dependent data +NORMAL_MODE .long 0x00000000 // system/external device dependent data (SMODE=000) +.endm + +.macro sdram_init_barebox + /* configure 16 bit nor flash on cs0 */ + writel(0x0000CC03, 0xd8002000) + writel(0xa0330D01, 0xd8002004) + writel(0x00220800, 0xd8002008) + + /* ddr on csd0 - initial reset */ + writel(0x00000008, 0xD8001010) + + /* configure ddr on csd0 - wait 5000 cycles */ + writel(0x00000004, 0xD8001010) + writel(0x006ac73a, 0xD8001004) + writel(0x92100000, 0xD8001000) + writel(0x12344321, 0xA0000f00) + writel(0xa2100000, 0xD8001000) + writel(0x12344321, 0xA0000000) + writel(0x12344321, 0xA0000000) + writel(0xb2100000, 0xD8001000) + ldr r0, =0xA0000033 + mov r1, #0xda + strb r1, [r0] + ldr r0, =0xA1000000 + mov r1, #0xff + strb r1, [r0] + writel(0x82226080, 0xD8001000) + writel(0xDEADBEEF, 0xA0000000) + writel(0x0000000c, 0xD8001010) +.endm + +.globl board_init_lowlevel +board_init_lowlevel: + + mov r10, lr + + /* ahb lite ip interface */ + writel(0x20040304, AIPI1_PSR0) + writel(0xDFFBFCFB, AIPI1_PSR1) + writel(0x00000000, AIPI2_PSR0) + writel(0xFFFFFFFF, AIPI2_PSR1) + + /* disable mpll/spll */ + ldr r0, =CSCR + ldr r1, [r0] + bic r1, r1, #0x03 + str r1, [r0] + + /* + * pll clock initialization - see section 3.4.3 of the i.MX27 manual + * + * FIXME: Using the 399*2 MHz values from table 3-8 doens't work + * with 1.2 V core voltage! Find out if this is + * documented somewhere. + */ + writel(0x00191403, MPCTL0) /* MPLL = 199.5*2 MHz */ + writel(0x040C2403, SPCTL0) /* SPLL = FIXME (needs review) */ + + /* + * ARM clock = (399 MHz / 2) / (ARM divider = 1) = 200 MHz + * AHB clock = (399 MHz / 3) / (AHB divider = 2) = 66.5 MHz + * System clock (HCLK) = 133 MHz + */ + writel(0x33F30307 | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR) + + /* add some delay here */ + mov r1, #0x1000 +1: subs r1, r1, #0x1 + bne 1b + + /* clock gating enable */ + writel(0x00050f08, GPCR) + + /* peripheral clock divider */ + writel(0x23C8F403, PCDR0) /* FIXME */ + writel(0x09030913, PCDR1) /* PERDIV1=08 @133 MHz */ + /* PERDIV1=04 @266 MHz * + * / + /* skip sdram initialization if we run from ram */ + cmp pc, #0xa0000000 + bls 1f + cmp pc, #0xc0000000 + bhi 1f + + mov pc,r10 +1: + sdram_init_sha + + mov pc,r10 + diff --git a/arch/arm/boards/mmccpu/Makefile b/arch/arm/boards/mmccpu/Makefile new file mode 100644 index 0000000..eb072c0 --- /dev/null +++ b/arch/arm/boards/mmccpu/Makefile @@ -0,0 +1 @@ +obj-y += init.o diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h new file mode 100644 index 0000000..1133b8f --- /dev/null +++ b/arch/arm/boards/mmccpu/config.h @@ -0,0 +1,141 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#define AT91_MASTER_CLOCK 99532800 /* peripheral = main / 2 */ + +/* values */ +#define MASTER_PLL_MUL 54 +#define MASTER_PLL_DIV 4 + +/* clocks */ +#define CONFIG_SYS_MOR_VAL \ + (AT91_PMC_MOSCEN | \ + (255 << 8)) /* Main Oscillator Start-up Time */ +#define CONFIG_SYS_PLLAR_VAL \ + (AT91_PMC_PLLA_WR_ERRATA | /* Bit 29 must be 1 when prog */ \ + AT91_PMC_OUT | \ + AT91_PMC_PLLCOUNT | /* PLL Counter */ \ + (2 << 28) | /* PLL Clock Frequency Range */ \ + ((MASTER_PLL_MUL - 1) << 16) | (MASTER_PLL_DIV)) + +/* PCK/2 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR1_VAL \ + (AT91_PMC_CSS_SLOW | \ + AT91_PMC_PRES_1 | \ + AT91SAM9_PMC_MDIV_2 | \ + AT91_PMC_PDIV_1) +/* PCK/2 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR2_VAL \ + (AT91_PMC_CSS_PLLA | \ + AT91_PMC_PRES_1 | \ + AT91SAM9_PMC_MDIV_2 | \ + AT91_PMC_PDIV_1) + +/* define PDC[31:16] as DATA[31:16] */ +#define CONFIG_SYS_PIOD_PDR_VAL1 0xFFFF0000 +/* no pull-up for D[31:16] */ +#define CONFIG_SYS_PIOD_PPUDR_VAL 0xFFFF0000 +/* EBI0_CSA, CS1 SDRAM, CS3 NAND Flash, 1.8V memories */ +#define CONFIG_SYS_MATRIX_EBI0CSA_VAL \ + (AT91_MATRIX_EBI0_DBPUC | AT91_MATRIX_EBI0_VDDIOMSEL_1_8V | \ + AT91_MATRIX_EBI0_CS1A_SDRAMC | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA) + +/* SDRAM */ +/* SDRAMC_MR Mode register */ +#define CONFIG_SYS_SDRC_MR_VAL1 0 +/* SDRAMC_TR - Refresh Timer register */ +#define CONFIG_SYS_SDRC_TR_VAL1 0x13c +/* SDRAMC_CR - Configuration register*/ +#define CONFIG_SYS_SDRC_CR_VAL \ + (AT91_SDRAMC_NC_9 | \ + AT91_SDRAMC_NR_13 | \ + AT91_SDRAMC_NB_4 | \ + AT91_SDRAMC_CAS_3 | \ + AT91_SDRAMC_DBW_32 | \ + (2 << 8) | /* tWR - Write Recovery Delay */ \ + (8 << 12) | /* tRC - Row Cycle Delay */ \ + (2 << 16) | /* tRP - Row Precharge Delay */ \ + (2 << 20) | /* tRCD - Row to Column Delay */ \ + (5 << 24) | /* tRAS - Active to Precharge Delay */ \ + (12 << 28)) /* tXSR - Exit Self Refresh to Active Delay */ + +/* Memory Device Register -> SDRAM */ +#define CONFIG_SYS_SDRC_MDR_VAL AT91_SDRAMC_MD_SDRAM +#define CONFIG_SYS_SDRC_MR_VAL2 AT91_SDRAMC_MODE_PRECHARGE +#define CONFIG_SYS_SDRAM_VAL1 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL3 AT91_SDRAMC_MODE_REFRESH +#define CONFIG_SYS_SDRAM_VAL2 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL3 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL4 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL5 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL6 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL7 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL8 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL9 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL4 AT91_SDRAMC_MODE_LMR +#define CONFIG_SYS_SDRAM_VAL10 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL5 AT91_SDRAMC_MODE_NORMAL +#define CONFIG_SYS_SDRAM_VAL11 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_TR_VAL2 780 /* SDRAM_TR */ +#define CONFIG_SYS_SDRAM_VAL12 0 /* SDRAM_BASE */ + +/* setup CS0 (NOR Flash) - 16-bit */ +#if 1 +#define CONFIG_SYS_SMC0_SETUP0_VAL \ + (AT91_SMC_NWESETUP_(3) | AT91_SMC_NCS_WRSETUP_(2) | \ + AT91_SMC_NRDSETUP_(8) | AT91_SMC_NCS_RDSETUP_(0)) +#define CONFIG_SYS_SMC0_PULSE0_VAL \ + (AT91_SMC_NWEPULSE_(5) | AT91_SMC_NCS_WRPULSE_(7) | \ + AT91_SMC_NRDPULSE_(5) | AT91_SMC_NCS_RDPULSE_(13)) +#define CONFIG_SYS_SMC0_CYCLE0_VAL \ + (AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16)) +#define CONFIG_SYS_SMC0_MODE0_VAL \ + (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ + AT91_SMC_DBW_16 | \ + AT91_SMC_TDFMODE | \ + AT91_SMC_TDF_(6)) +#elif 0 /* slow setup */ +#define CONFIG_SYS_SMC0_SETUP0_VAL \ + (AT91_SMC_NWESETUP_(3) | AT91_SMC_NCS_WRSETUP_(2) | \ + AT91_SMC_NRDSETUP_(8) | AT91_SMC_NCS_RDSETUP_(0)) +#define CONFIG_SYS_SMC0_PULSE0_VAL \ + (AT91_SMC_NWEPULSE_(5) | AT91_SMC_NCS_WRPULSE_(7) | \ + AT91_SMC_NRDPULSE_(5) | AT91_SMC_NCS_RDPULSE_(13)) +#define CONFIG_SYS_SMC0_CYCLE0_VAL \ + (AT91_SMC_NWECYCLE_(0xd00) | AT91_SMC_NRDCYCLE_(0xd00)) +#define CONFIG_SYS_SMC0_MODE0_VAL \ + (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ + AT91_SMC_DBW_16 | \ + AT91_SMC_TDFMODE | \ + AT91_SMC_TDF_(1)) +#else /* RONETIX' original values */ +#define CONFIG_SYS_SMC0_SETUP0_VAL \ + (AT91_SMC_NWESETUP_(10) | AT91_SMC_NCS_WRSETUP_(10) | \ + AT91_SMC_NRDSETUP_(10) | AT91_SMC_NCS_RDSETUP_(10)) +#define CONFIG_SYS_SMC0_PULSE0_VAL \ + (AT91_SMC_NWEPULSE_(11) | AT91_SMC_NCS_WRPULSE_(11) | \ + AT91_SMC_NRDPULSE_(11) | AT91_SMC_NCS_RDPULSE_(11)) +#define CONFIG_SYS_SMC0_CYCLE0_VAL \ + (AT91_SMC_NWECYCLE_(22) | AT91_SMC_NRDCYCLE_(22)) +#define CONFIG_SYS_SMC0_MODE0_VAL \ + (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ + AT91_SMC_DBW_16 | \ + AT91_SMC_TDFMODE | \ + AT91_SMC_TDF_(6)) +#endif + +/* user reset enable */ +#define CONFIG_SYS_RSTC_RMR_VAL \ + (AT91_RSTC_KEY | \ + AT91_RSTC_PROCRST | \ + AT91_RSTC_RSTTYP_WAKEUP | \ + AT91_RSTC_RSTTYP_WATCHDOG) + +/* Disable Watchdog */ +#define CONFIG_SYS_WDTC_WDMR_VAL \ + (AT91_WDT_WDIDLEHLT | AT91_WDT_WDDBGHLT | \ + AT91_WDT_WDV | \ + AT91_WDT_WDDIS | \ + AT91_WDT_WDD) + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/mmccpu/env/bin/_update b/arch/arm/boards/mmccpu/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/mmccpu/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/mmccpu/env/bin/boot b/arch/arm/boards/mmccpu/env/bin/boot new file mode 100644 index 0000000..533dea7 --- /dev/null +++ b/arch/arm/boards/mmccpu/env/bin/boot @@ -0,0 +1,47 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + root=nand + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$1 = xnor ]; then + root=nor + kernel=nor +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xnand ]; then + bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" +elif [ x$root = xnor ]; then + bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +elif [ $kernel = nor ]; then + bootm /dev/nor0.kernel +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/mmccpu/env/bin/hush_hack b/arch/arm/boards/mmccpu/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/mmccpu/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/mmccpu/env/bin/init b/arch/arm/boards/mmccpu/env/bin/init new file mode 100644 index 0000000..ac84bd5 --- /dev/null +++ b/arch/arm/boards/mmccpu/env/bin/init @@ -0,0 +1,37 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nor0 ]; then + addpart /dev/nor0 $nor_parts +fi + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel nor [] to update kernel into flash" + echo "type update_root nor [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/mmccpu/env/bin/update_kernel b/arch/arm/boards/mmccpu/env/bin/update_kernel new file mode 100644 index 0000000..05c822d --- /dev/null +++ b/arch/arm/boards/mmccpu/env/bin/update_kernel @@ -0,0 +1,15 @@ +#!/bin/sh + +. /env/config + +image=$uimage +if [ x$1 = xnand ]; then + part=/dev/nand0.kernel.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.kernel +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/arch/arm/boards/mmccpu/env/bin/update_root b/arch/arm/boards/mmccpu/env/bin/update_root new file mode 100644 index 0000000..a751372 --- /dev/null +++ b/arch/arm/boards/mmccpu/env/bin/update_root @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 +if [ x$1 = xnand ]; then + part=/dev/nand0.root.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.root +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 + diff --git a/arch/arm/boards/mmccpu/env/config b/arch/arm/boards/mmccpu/env/config new file mode 100644 index 0000000..5367cd9 --- /dev/null +++ b/arch/arm/boards/mmccpu/env/config @@ -0,0 +1,30 @@ +#!/bin/sh + +# can be either 'net', 'nor' or 'nand'' +kernel=nor +root=nor + +uimage=uImage-mmccpu +jffs2=root-mmccpu.jffs2 + +autoboot_timeout=3 + +nfsroot="/home/kschwinne/src/pengutronix/OSELAS.BSP-Bucyrus-Grabowski-trunk/platform-Bucyrus-mmccpu/root" + +bootargs="console=ttyS0,115200 mmccpu=p299" + +#nor_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" +nor_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),10240k(root),10240k(rootbu),-(data)" +rootpart_nor="/dev/mtdblock3" + +#nand_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" +#rootpart_nand="/dev/mtdblock7" + +# use 'dhcp' to do dhcp in barebox and in kernel +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 diff --git a/arch/arm/boards/mmccpu/init.c b/arch/arm/boards/mmccpu/init.c new file mode 100644 index 0000000..e010a83 --- /dev/null +++ b/arch/arm/boards/mmccpu/init.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = AT91_CHIPSELECT_0, + .size = 0, /* zero means autodetect size */ +}; + +static struct at91_ether_platform_data macb_pdata = { + .flags = AT91SAM_ETHER_MII | AT91SAM_ETHER_FORCE_LINK, + .phy_addr = 4, +}; + +static int mmccpu_devices_init(void) +{ + /* + * PB27 enables the 50MHz oscillator for Ethernet PHY + * 1 - enable + * 0 - disable + */ + at91_set_gpio_output(AT91_PIN_PB27, 1); + at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ + + /* Enable clock */ + at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); + + at91_add_device_sdram(128 * 1024 * 1024); + at91_add_device_eth(&macb_pdata); + register_device(&cfi_dev); + + devfs_add_partition("nor0", 0x00000, 256 * 1024, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 128 * 1024, PARTITION_FIXED, "env0"); + + armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); + armlinux_set_architecture(MACH_TYPE_MMCCPU); + + return 0; +} + +device_initcall(mmccpu_devices_init); + +static int mmccpu_console_init(void) +{ + at91_register_uart(0, 0); + return 0; +} + +console_initcall(mmccpu_console_init); diff --git a/arch/arm/boards/netx/Makefile b/arch/arm/boards/netx/Makefile new file mode 100644 index 0000000..8b33fec --- /dev/null +++ b/arch/arm/boards/netx/Makefile @@ -0,0 +1,2 @@ +obj-y += netx.o platform.o + diff --git a/arch/arm/boards/netx/config.h b/arch/arm/boards/netx/config.h new file mode 100644 index 0000000..ca15136 --- /dev/null +++ b/arch/arm/boards/netx/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/netx/netx.c b/arch/arm/boards/netx/netx.c new file mode 100644 index 0000000..d6bfcca --- /dev/null +++ b/arch/arm/boards/netx/netx.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2004 Sascha Hauer, Synertronixx GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0xC0000000, + .size = 32 * 1024 * 1024, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0x80000000, + .size = 64 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +struct netx_eth_platform_data eth0_data = { + .xcno = 0, +}; + +static struct device_d netx_eth_dev0 = { + .name = "netx-eth", + .platform_data = ð0_data, +}; + +struct netx_eth_platform_data eth1_data = { + .xcno = 1, +}; + +static struct device_d netx_eth_dev1 = { + .name = "netx-eth", + .platform_data = ð1_data, +}; + +static int netx_devices_init(void) { + register_device(&cfi_dev); + register_device(&sdram_dev); + register_device(&netx_eth_dev0); + register_device(&netx_eth_dev1); + + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + + /* Do not overwrite primary env for now */ + devfs_add_partition("nor0", 0xc0000, 0x80000, PARTITION_FIXED, "env0"); + + protect_file("/dev/env0", 1); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_NXDB500); + + return 0; +} + +device_initcall(netx_devices_init); + +static struct device_d netx_serial_device = { + .name = "netx_serial", + .map_base = NETX_PA_UART0, + .size = 0x40, +}; + +static int netx_console_init(void) +{ + /* configure gpio for serial */ + *(volatile unsigned long *)(0x00100800) = 2; + *(volatile unsigned long *)(0x00100804) = 2; + *(volatile unsigned long *)(0x00100808) = 2; + *(volatile unsigned long *)(0x0010080c) = 2; + + register_device(&netx_serial_device); + return 0; +} + +console_initcall(netx_console_init); + diff --git a/arch/arm/boards/netx/netx.dox b/arch/arm/boards/netx/netx.dox new file mode 100644 index 0000000..e22c5e8 --- /dev/null +++ b/arch/arm/boards/netx/netx.dox @@ -0,0 +1,9 @@ +/** @page netx Hilscher's NetX card family + +This CPU card is based on a Hilscher's NetX ARM CPU. The card is shipped +in various incarnations: + +Specific to this CPU is, it does not require any setup code to bring the +SDRAM up and working. This is done in a pre bootloader. + +*/ \ No newline at end of file diff --git a/arch/arm/boards/netx/platform.S b/arch/arm/boards/netx/platform.S new file mode 100644 index 0000000..4961682 --- /dev/null +++ b/arch/arm/boards/netx/platform.S @@ -0,0 +1,26 @@ +/* + * Board specific setup info + * + * + * 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 + */ + +.globl board_init_lowlevel +board_init_lowlevel: + mov pc, lr diff --git a/arch/arm/boards/omap/Kconfig b/arch/arm/boards/omap/Kconfig new file mode 100644 index 0000000..d612064 --- /dev/null +++ b/arch/arm/boards/omap/Kconfig @@ -0,0 +1,93 @@ +# OMAP based Board Specific Configuration file +# +# (C) Copyright 2008 +# OMAP Architecture specific features +# Texas Instruments, +# Nishanth Menon +# +# 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 new file mode 100644 index 0000000..1e74e24 --- /dev/null +++ b/arch/arm/boards/omap/Makefile @@ -0,0 +1,28 @@ +# OMAP Board Specific Makefile +# +# (C) Copyright 2008 +# OMAP Architecture specific features +# Texas Instruments, +# Nishanth Menon +# +# 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 + +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 new file mode 100644 index 0000000..a4cbf31 --- /dev/null +++ b/arch/arm/boards/omap/board-beagle.c @@ -0,0 +1,274 @@ +/* + * (C) Copyright 2008 + * Texas Instruments, + * Raghavendra KH + * + * 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 + */ + +/** + * @file + * @brief Beagle Specific Board Initialization routines + */ + +/** + * @page ti_beagle Texas Instruments Beagle Board + * + * FileName: arch/arm/boards/omap/board-beagle.c + * + * Beagle Board from Texas Instruments as described here: + * http://www.beagleboard.org + * + * This board is based on OMAP3530. + * More on OMAP3530 (including documentation can be found here): + * http://focus.ti.com/docs/prod/folders/print/omap3530.html + * + * This file provides initialization in two stages: + * @li boot time initialization - do basics required to get SDRAM working. + * This is run from SRAM - so no case constructs and global vars can be used. + * @li run time initialization - this is for the rest of the initializations + * such as flash, uart etc. + * + * Boot time initialization includes: + * @li SDRAM initialization. + * @li Pin Muxing relevant for Beagle. + * + * Run time initialization includes + * @li serial @ref serial_ns16550.c driver device definition + * + * Originally from arch/arm/boards/omap/board-sdp343x.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "board.h" + +/******************** Board Boot Time *******************/ + +/** + * @brief Do the SDRC initialization for 128Meg Micron DDR for CS0 + * + * @return void + */ +static void sdrc_init(void) +{ + /* SDRAM software reset */ + /* No idle ack and RESET enable */ + writel(0x1A, SDRC_REG(SYSCONFIG)); + sdelay(100); + /* No idle ack and RESET disable */ + writel(0x18, SDRC_REG(SYSCONFIG)); + + /* SDRC Sharing register */ + /* 32-bit SDRAM on data lane [31:0] - CS0 */ + /* pin tri-stated = 1 */ + writel(0x00000100, SDRC_REG(SHARING)); + + /* ----- SDRC Registers Configuration --------- */ + /* SDRC_MCFG0 register */ + writel(0x02584099, SDRC_REG(MCFG_0)); + + /* SDRC_RFR_CTRL0 register */ + writel(0x54601, SDRC_REG(RFR_CTRL_0)); + + /* SDRC_ACTIM_CTRLA0 register */ + writel(0xA29DB4C6, SDRC_REG(ACTIM_CTRLA_0)); + + /* SDRC_ACTIM_CTRLB0 register */ + writel(0x12214, SDRC_REG(ACTIM_CTRLB_0)); + + /* Disble Power Down of CKE due to 1 CKE on combo part */ + writel(0x00000081, SDRC_REG(POWER)); + + /* SDRC_MANUAL command register */ + /* NOP command */ + writel(0x00000000, SDRC_REG(MANUAL_0)); + /* Precharge command */ + writel(0x00000001, SDRC_REG(MANUAL_0)); + /* Auto-refresh command */ + writel(0x00000002, SDRC_REG(MANUAL_0)); + /* Auto-refresh command */ + writel(0x00000002, SDRC_REG(MANUAL_0)); + + /* SDRC MR0 register Burst length=4 */ + writel(0x00000032, SDRC_REG(MR_0)); + + /* SDRC DLLA control register */ + writel(0x0000000A, SDRC_REG(DLLA_CTRL)); + + return; +} + +/** + * @brief Do the pin muxing required for Board operation. + * We enable ONLY the pins we require to set. OMAP provides pins which do not + * have alternate modes. Such pins done need to be set. + * + * See @ref MUX_VAL for description of the muxing mode. + * + * @return void + */ +static void mux_config(void) +{ + /* SDRC_D0 - SDRC_D31 default mux mode is mode0 */ + + /* GPMC */ + MUX_VAL(CP(GPMC_A1), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A2), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A3), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A4), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A5), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A6), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A7), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A8), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A9), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A10), (IDIS | PTD | DIS | M0)); + + /* D0-D7 default mux mode is mode0 */ + MUX_VAL(CP(GPMC_D8), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D9), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D10), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D11), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D12), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D13), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D14), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D15), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_CLK), (IDIS | PTD | DIS | M0)); + /* GPMC_NADV_ALE default mux mode is mode0 */ + /* GPMC_NOE default mux mode is mode0 */ + /* GPMC_NWE default mux mode is mode0 */ + /* GPMC_NBE0_CLE default mux mode is mode0 */ + MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NBE1), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); + /* GPMC_WAIT0 default mux mode is mode0 */ + MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)); + + /* SERIAL INTERFACE */ + MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); + MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | DIS | M0)); + /* I2C1_SCL default mux mode is mode0 */ + /* I2C1_SDA default mux mode is mode0 */ +} + +/** + * @brief The basic entry point for board initialization. + * + * This is called as part of machine init (after arch init). + * This is again called with stack in SRAM, so not too many + * constructs possible here. + * + * @return void + */ +void board_init(void) +{ + int in_sdram = running_in_sdram(); + + mux_config(); + /* Dont reconfigure SDRAM while running in SDRAM! */ + if (!in_sdram) + sdrc_init(); +} + +/******************** Board Run Time *******************/ + +#ifdef CONFIG_DRIVER_SERIAL_NS16550 + +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 beagle_serial_device = { + .name = "serial_ns16550", + .map_base = OMAP_UART3_BASE, + .size = 1024, + .platform_data = (void *)&serial_plat, +}; + +/** + * @brief UART serial port initialization - remember to enable COM clocks in + * arch + * + * @return result of device registration + */ +static int beagle_console_init(void) +{ + /* Register the serial port */ + return register_device(&beagle_serial_device); +} +console_initcall(beagle_console_init); +#endif /* CONFIG_DRIVER_SERIAL_NS16550 */ + +static struct memory_platform_data sram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0x80000000, + .size = 128 * 1024 * 1024, + .platform_data = &sram_pdata, +}; + +static int beagle_devices_init(void) +{ + int ret; + + ret = register_device(&sdram_dev); + if (ret) + goto failed; + +#ifdef CONFIG_GPMC + /* WP is made high and WAIT1 active Low */ + gpmc_generic_init(0x10); +#endif + gpmc_generic_nand_devices_init(0, 16, 1); + + armlinux_add_dram(&sdram_dev); +failed: + return ret; +} +device_initcall(beagle_devices_init); diff --git a/arch/arm/boards/omap/board-omap3evm.c b/arch/arm/boards/omap/board-omap3evm.c new file mode 100644 index 0000000..619ea94 --- /dev/null +++ b/arch/arm/boards/omap/board-omap3evm.c @@ -0,0 +1,275 @@ +/** + * @file + * @brief Board Initialization routines for OMAP3EVM. + * + * FileName: arch/arm/boards/omap/board-omap3evm.c + * + * This board is based on OMAP3530. + * More on OMAP3530 (including documentation can be found here): + * http://focus.ti.com/docs/prod/folders/print/omap3530.html + * + * This file provides initialization in two stages: + * @li Boot time initialization - just get SDRAM working. + * This is run from SRAM - so no case constructs and global vars can be used. + * @li Run time initialization - this is for the rest of the initializations + * such as flash, uart etc. + * + * Boot time initialization includes: + * @li SDRAM initialization. + * @li Pin Muxing relevant for the EVM. + * + * Run time initialization includes + * @li serial @ref serial_ns16550.c driver device definition + * + * Originally from arch/arm/boards/omap/board-beagle.c + */ + +/* + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ + * Sanjeev Premi + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "board.h" + + +/* + * Boot-time initialization(s) + */ + +/** + * @brief Initialize the SDRC module + * + * @return void + */ +static void sdrc_init(void) +{ + /* SDRAM software reset */ + /* No idle ack and RESET enable */ + writel(0x1A, SDRC_REG(SYSCONFIG)); + sdelay(100); + /* No idle ack and RESET disable */ + writel(0x18, SDRC_REG(SYSCONFIG)); + + /* SDRC Sharing register */ + /* 32-bit SDRAM on data lane [31:0] - CS0 */ + /* pin tri-stated = 1 */ + writel(0x00000100, SDRC_REG(SHARING)); + + /* ----- SDRC Registers Configuration --------- */ + /* SDRC_MCFG0 register */ + writel(0x02584099, SDRC_REG(MCFG_0)); + + /* SDRC_RFR_CTRL0 register */ + writel(0x54601, SDRC_REG(RFR_CTRL_0)); + + /* SDRC_ACTIM_CTRLA0 register */ + writel(0xA29DB4C6, SDRC_REG(ACTIM_CTRLA_0)); + + /* SDRC_ACTIM_CTRLB0 register */ + writel(0x12214, SDRC_REG(ACTIM_CTRLB_0)); + + /* Disble Power Down of CKE due to 1 CKE on combo part */ + writel(0x00000081, SDRC_REG(POWER)); + + /* SDRC_MANUAL command register */ + /* NOP command */ + writel(0x00000000, SDRC_REG(MANUAL_0)); + /* Precharge command */ + writel(0x00000001, SDRC_REG(MANUAL_0)); + /* Auto-refresh command */ + writel(0x00000002, SDRC_REG(MANUAL_0)); + /* Auto-refresh command */ + writel(0x00000002, SDRC_REG(MANUAL_0)); + + /* SDRC MR0 register Burst length=4 */ + writel(0x00000032, SDRC_REG(MR_0)); + + /* SDRC DLLA control register */ + writel(0x0000000A, SDRC_REG(DLLA_CTRL)); + + return; +} + +/** + * @brief Do the necessary pin muxing required for OMAP3EVM. Some pins in OMAP3 + * do not have alternate modes. We don't program these pins. + * + * See @ref MUX_VAL for description of the muxing mode. + * + * @return void + */ +static void mux_config(void) +{ + /* + * SDRC + * - SDRC_D0-SDRC_D31: Default MUX mode is mode0. + */ + + /* + * GPMC + * - GPMC_D0-GPMC_D7: Default MUX mode is mode0. + * - GPMC_NADV_ALE: Default MUX mode is mode0. + * - GPMC_NOE: Default MUX mode is mode0. + * - GPMC_NWE: Default MUX mode is mode0. + * - GPMC_WAIT0: Default MUX mode is mode0. + */ + MUX_VAL(CP(GPMC_A1), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A2), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A3), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A4), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A5), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A6), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A7), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A8), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A9), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_A10), (IDIS | PTD | DIS | M0)); + + MUX_VAL(CP(GPMC_D8), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D9), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D10), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D11), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D12), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D13), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D14), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_D15), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_CLK), (IDIS | PTD | DIS | M0)); + + MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NBE1), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); + + MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)); + + /* + * Serial Interface + */ +#if defined(CONFIG_OMAP3EVM_UART1) + MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(UART1_CTS), (IEN | PTU | DIS | M0)); + MUX_VAL(CP(UART1_RX), (IEN | PTD | DIS | M0)); +#elif defined(CONFIG_OMAP3EVM_UART3) + MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); + MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); +#endif +} + +/** + * @brief The basic entry point for board initialization. + * + * This is called as part of machine init (after arch init). + * This is again called with stack in SRAM, so not too many + * constructs possible here. + * + * @return void + */ +void board_init(void) +{ + int in_sdram = running_in_sdram(); + + mux_config(); + /* Dont reconfigure SDRAM while running in SDRAM! */ + if (!in_sdram) + sdrc_init(); +} + +/* + * Run-time initialization(s) + */ + +#ifdef CONFIG_DRIVER_SERIAL_NS16550 + +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 omap3evm_serial_device = { + .name = "serial_ns16550", +#if defined(CONFIG_OMAP3EVM_UART1) + .map_base = OMAP_UART1_BASE, +#elif defined(CONFIG_OMAP3EVM_UART3) + .map_base = OMAP_UART3_BASE, +#endif + .size = 1024, + .platform_data = (void *)&serial_plat, +}; + +/** + * @brief Initialize the serial port to be used as console. + * + * @return result of device registration + */ +static int omap3evm_init_console(void) +{ + return register_device(&omap3evm_serial_device); +} +console_initcall(omap3evm_init_console); +#endif /* CONFIG_DRIVER_SERIAL_NS16550 */ + +static struct memory_platform_data sram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0x80000000, + .size = 128 * 1024 * 1024, + .platform_data = &sram_pdata, +}; + +static int omap3evm_init_devices(void) +{ + int ret; + + ret = register_device(&sdram_dev); + if (ret) + goto failed; + +#ifdef CONFIG_GPMC + /* + * WP is made high and WAIT1 active Low + */ + gpmc_generic_init(0x10); +#endif + + armlinux_add_dram(&sdram_dev); + +failed: + return ret; +} +device_initcall(omap3evm_init_devices); diff --git a/arch/arm/boards/omap/board-sdp343x.c b/arch/arm/boards/omap/board-sdp343x.c new file mode 100644 index 0000000..32d1a42 --- /dev/null +++ b/arch/arm/boards/omap/board-sdp343x.c @@ -0,0 +1,672 @@ +/* + * (C) Copyright 2006-2008 + * Texas Instruments, + * Nishanth Menon + * + * 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 + */ + +/** + * @file + * @brief SDP3430 Specific Board Initialization routines + */ + +/** + * @page ti_SDP3430 Texas Instruments SDP3430 + * + * FileName: arch/arm/boards/omap/board-sdp343x.c + * + * SDP3430 from Texas Instruments as described here: + * http://www.ti.com/omap3430_devplatform + * This file provides initialization in two stages: + * @li boot time initialization - do basics required to get SDRAM working. + * This is run from SRAM - so no case constructs and global vars can be used. + * @li run time initialization - this is for the rest of the initializations + * such as flash, uart etc. + * + * Boot time initialization includes: + * @li SDRAM initialization. + * @li Pin Muxing relevant for SDP3430. + * + * Run time initialization includes + * @li serial @ref serial_ns16550.c driver device definition + * + * Originally from http://linux.omap.com/pub/bootloader/3430sdp/u-boot-v1.tar.gz + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "board.h" + +/******************** Board Boot Time *******************/ +static void sdrc_init(void); +static void mux_config(void); + +/** + * @brief The basic entry point for board initialization. + * + * This is called as part of machine init (after arch init). + * This is again called with stack in SRAM, so not too many + * constructs possible here. + * + * @return void + */ +void board_init(void) +{ + int in_sdram = running_in_sdram(); + mux_config(); + if (!in_sdram) + sdrc_init(); +} + +/** + * @brief Do the SDRC initialization for 128Meg Infenion DDR for CS0 + * + * @return void + */ +static void sdrc_init(void) +{ + /* Issue SDRC Soft reset */ + writel(0x12, SDRC_REG(SYSCONFIG)); + /* Wait until Reset complete */ + while ((readl(SDRC_REG(STATUS)) & 0x1) == 0); + /* SDRC to normal mode */ + writel(0x10, SDRC_REG(SYSCONFIG)); + /* SDRC Sharing register */ + /* 32-bit SDRAM on data lane [31:0] - CS0 */ + /* pin tri-stated = 1 */ + writel(0x00000100, SDRC_REG(SHARING)); + + /* ----- SDRC_REG(CS0 Configuration --------- */ + /* SDRC_REG(MCFG0 register */ + writel(0x02584019, SDRC_REG(MCFG_0)); + + /* SDRC_REG(RFR_CTRL0 register */ + writel(0x0003DE01, SDRC_REG(RFR_CTRL_0)); + + /* SDRC_REG(ACTIM_CTRLA0 register */ + writel(0X5A9A4486, SDRC_REG(ACTIM_CTRLA_0)); + + /* SDRC_REG(ACTIM_CTRLB0 register */ + writel(0x00000010, SDRC_REG(ACTIM_CTRLB_0)); + + /* Disble Power Down of CKE cuz of 1 CKE on combo part */ + writel(0x00000081, SDRC_REG(POWER)); + + /* SDRC_REG(Manual command register */ + /* NOP command */ + writel(0x00000000, SDRC_REG(MANUAL_0)); + /* Precharge command */ + writel(0x00000001, SDRC_REG(MANUAL_0)); + /* Auto-refresh command */ + writel(0x00000002, SDRC_REG(MANUAL_0)); + /* Auto-refresh command */ + writel(0x00000002, SDRC_REG(MANUAL_0)); + + /* SDRC MR0 register */ + /* CAS latency = 3 */ + /* Write Burst = Read Burst */ + /* Serial Mode */ + writel(0x00000032, SDRC_REG(MR_0)); /* Burst length =4 */ + + /* SDRC DLLA control register */ + /* Enable DLL A */ + writel(0x0000000A, SDRC_REG(DLLA_CTRL)); + + /* wait until DLL is locked */ + while ((readl(SDRC_REG(DLLA_STATUS)) & 0x4) == 0); + return; +} + +/** + * @brief Do the pin muxing required for Board operation. + * + * See @ref MUX_VAL for description of the muxing mode. Since some versions + * of Linux depend on all pin muxing being done at barebox level, we may need to + * enable CONFIG_MACH_OMAP_ADVANCED_MUX to enable the full fledged pin muxing. + * + * @return void + */ +static void mux_config(void) +{ + /* Essential MUX Settings */ + MUX_VAL(CP(SDRC_D0), (IEN | PTD | DIS | M0)); /* SDRC_D0 */ + MUX_VAL(CP(SDRC_D1), (IEN | PTD | DIS | M0)); /* SDRC_D1 */ + MUX_VAL(CP(SDRC_D2), (IEN | PTD | DIS | M0)); /* SDRC_D2 */ + MUX_VAL(CP(SDRC_D3), (IEN | PTD | DIS | M0)); /* SDRC_D3 */ + MUX_VAL(CP(SDRC_D4), (IEN | PTD | DIS | M0)); /* SDRC_D4 */ + MUX_VAL(CP(SDRC_D5), (IEN | PTD | DIS | M0)); /* SDRC_D5 */ + MUX_VAL(CP(SDRC_D6), (IEN | PTD | DIS | M0)); /* SDRC_D6 */ + MUX_VAL(CP(SDRC_D7), (IEN | PTD | DIS | M0)); /* SDRC_D7 */ + MUX_VAL(CP(SDRC_D8), (IEN | PTD | DIS | M0)); /* SDRC_D8 */ + MUX_VAL(CP(SDRC_D9), (IEN | PTD | DIS | M0)); /* SDRC_D9 */ + MUX_VAL(CP(SDRC_D10), (IEN | PTD | DIS | M0)); /* SDRC_D10 */ + MUX_VAL(CP(SDRC_D11), (IEN | PTD | DIS | M0)); /* SDRC_D11 */ + MUX_VAL(CP(SDRC_D12), (IEN | PTD | DIS | M0)); /* SDRC_D12 */ + MUX_VAL(CP(SDRC_D13), (IEN | PTD | DIS | M0)); /* SDRC_D13 */ + MUX_VAL(CP(SDRC_D14), (IEN | PTD | DIS | M0)); /* SDRC_D14 */ + MUX_VAL(CP(SDRC_D15), (IEN | PTD | DIS | M0)); /* SDRC_D15 */ + MUX_VAL(CP(SDRC_D16), (IEN | PTD | DIS | M0)); /* SDRC_D16 */ + MUX_VAL(CP(SDRC_D17), (IEN | PTD | DIS | M0)); /* SDRC_D17 */ + MUX_VAL(CP(SDRC_D18), (IEN | PTD | DIS | M0)); /* SDRC_D18 */ + MUX_VAL(CP(SDRC_D19), (IEN | PTD | DIS | M0)); /* SDRC_D19 */ + MUX_VAL(CP(SDRC_D20), (IEN | PTD | DIS | M0)); /* SDRC_D20 */ + MUX_VAL(CP(SDRC_D21), (IEN | PTD | DIS | M0)); /* SDRC_D21 */ + MUX_VAL(CP(SDRC_D22), (IEN | PTD | DIS | M0)); /* SDRC_D22 */ + MUX_VAL(CP(SDRC_D23), (IEN | PTD | DIS | M0)); /* SDRC_D23 */ + MUX_VAL(CP(SDRC_D24), (IEN | PTD | DIS | M0)); /* SDRC_D24 */ + MUX_VAL(CP(SDRC_D25), (IEN | PTD | DIS | M0)); /* SDRC_D25 */ + MUX_VAL(CP(SDRC_D26), (IEN | PTD | DIS | M0)); /* SDRC_D26 */ + MUX_VAL(CP(SDRC_D27), (IEN | PTD | DIS | M0)); /* SDRC_D27 */ + MUX_VAL(CP(SDRC_D28), (IEN | PTD | DIS | M0)); /* SDRC_D28 */ + MUX_VAL(CP(SDRC_D29), (IEN | PTD | DIS | M0)); /* SDRC_D29 */ + MUX_VAL(CP(SDRC_D30), (IEN | PTD | DIS | M0)); /* SDRC_D30 */ + MUX_VAL(CP(SDRC_D31), (IEN | PTD | DIS | M0)); /* SDRC_D31 */ + MUX_VAL(CP(SDRC_CLK), (IEN | PTD | DIS | M0)); /* SDRC_CLK */ + MUX_VAL(CP(SDRC_DQS0), (IEN | PTD | DIS | M0)); /* SDRC_DQS0 */ + MUX_VAL(CP(SDRC_DQS1), (IEN | PTD | DIS | M0)); /* SDRC_DQS1 */ + MUX_VAL(CP(SDRC_DQS2), (IEN | PTD | DIS | M0)); /* SDRC_DQS2 */ + MUX_VAL(CP(SDRC_DQS3), (IEN | PTD | DIS | M0)); /* SDRC_DQS3 */ + /* GPMC */ + MUX_VAL(CP(GPMC_A1), (IDIS | PTD | DIS | M0)); /* GPMC_A1 */ + MUX_VAL(CP(GPMC_A2), (IDIS | PTD | DIS | M0)); /* GPMC_A2 */ + MUX_VAL(CP(GPMC_A3), (IDIS | PTD | DIS | M0)); /* GPMC_A3 */ + MUX_VAL(CP(GPMC_A4), (IDIS | PTD | DIS | M0)); /* GPMC_A4 */ + MUX_VAL(CP(GPMC_A5), (IDIS | PTD | DIS | M0)); /* GPMC_A5 */ + MUX_VAL(CP(GPMC_A6), (IDIS | PTD | DIS | M0)); /* GPMC_A6 */ + MUX_VAL(CP(GPMC_A7), (IDIS | PTD | DIS | M0)); /* GPMC_A7 */ + MUX_VAL(CP(GPMC_A8), (IDIS | PTD | DIS | M0)); /* GPMC_A8 */ + MUX_VAL(CP(GPMC_A9), (IDIS | PTD | DIS | M0)); /* GPMC_A9 */ + MUX_VAL(CP(GPMC_A10), (IDIS | PTD | DIS | M0)); /* GPMC_A10 */ + MUX_VAL(CP(GPMC_D0), (IEN | PTD | DIS | M0)); /* GPMC_D0 */ + MUX_VAL(CP(GPMC_D1), (IEN | PTD | DIS | M0)); /* GPMC_D1 */ + MUX_VAL(CP(GPMC_D2), (IEN | PTD | DIS | M0)); /* GPMC_D2 */ + MUX_VAL(CP(GPMC_D3), (IEN | PTD | DIS | M0)); /* GPMC_D3 */ + MUX_VAL(CP(GPMC_D4), (IEN | PTD | DIS | M0)); /* GPMC_D4 */ + MUX_VAL(CP(GPMC_D5), (IEN | PTD | DIS | M0)); /* GPMC_D5 */ + MUX_VAL(CP(GPMC_D6), (IEN | PTD | DIS | M0)); /* GPMC_D6 */ + MUX_VAL(CP(GPMC_D7), (IEN | PTD | DIS | M0)); /* GPMC_D7 */ + MUX_VAL(CP(GPMC_D8), (IEN | PTD | DIS | M0)); /* GPMC_D8 */ + MUX_VAL(CP(GPMC_D9), (IEN | PTD | DIS | M0)); /* GPMC_D9 */ + MUX_VAL(CP(GPMC_D10), (IEN | PTD | DIS | M0)); /* GPMC_D10 */ + MUX_VAL(CP(GPMC_D11), (IEN | PTD | DIS | M0)); /* GPMC_D11 */ + MUX_VAL(CP(GPMC_D12), (IEN | PTD | DIS | M0)); /* GPMC_D12 */ + MUX_VAL(CP(GPMC_D13), (IEN | PTD | DIS | M0)); /* GPMC_D13 */ + MUX_VAL(CP(GPMC_D14), (IEN | PTD | DIS | M0)); /* GPMC_D14 */ + MUX_VAL(CP(GPMC_D15), (IEN | PTD | DIS | M0)); /* GPMC_D15 */ + MUX_VAL(CP(GPMC_NCS0), (IDIS | PTU | EN | M0)); /* GPMC_NCS0 */ + MUX_VAL(CP(GPMC_NCS1), (IDIS | PTU | EN | M0)); /* GPMC_NCS1 */ + MUX_VAL(CP(GPMC_NCS2), (IDIS | PTU | EN | M0)); /* GPMC_NCS2 */ + MUX_VAL(CP(GPMC_NCS3), (IDIS | PTU | EN | M0)); /* GPMC_NCS3 */ + /* GPIO_55 - FLASH_DIS */ + MUX_VAL(CP(GPMC_NCS4), (IEN | PTU | EN | M4)); + /* GPIO_56 - TORCH_EN */ + MUX_VAL(CP(GPMC_NCS5), (IDIS | PTD | DIS | M4)); + /* GPIO_57 - AGPS SLP */ + MUX_VAL(CP(GPMC_NCS6), (IEN | PTD | DIS | M4)); + /* GPMC_58 - WLAN_IRQ */ + MUX_VAL(CP(GPMC_NCS7), (IEN | PTU | EN | M4)); + MUX_VAL(CP(GPMC_CLK), (IDIS | PTD | DIS | M0)); /* GPMC_CLK */ + /* GPMC_NADV_ALE */ + MUX_VAL(CP(GPMC_NADV_ALE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NOE), (IDIS | PTD | DIS | M0)); /* GPMC_NOE */ + MUX_VAL(CP(GPMC_NWE), (IDIS | PTD | DIS | M0)); /* GPMC_NWE */ + /* GPMC_NBE0_CLE */ + MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NBE1), (IEN | PTD | DIS | M4)); /* GPIO_61 -BT_SHUTDN */ + MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); /* GPMC_NWP */ + MUX_VAL(CP(GPMC_WAIT0), (IEN | PTU | EN | M0)); /* GPMC_WAIT0 */ + MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)); /* GPMC_WAIT1 */ + MUX_VAL(CP(GPMC_WAIT2), (IEN | PTU | EN | M4)); /* GPIO_64 */ + MUX_VAL(CP(GPMC_WAIT3), (IEN | PTU | EN | M4)); /* GPIO_65 */ + + /* SERIAL INTERFACE */ + /* UART3_CTS_RCTX */ + MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); + /* UART3_RTS_SD */ + MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); + /* UART3_RX_IRRX */ + MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); + /* UART3_TX_IRTX */ + MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); + /* HSUSB0_CLK */ + MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | DIS | M0)); + /* HSUSB0_STP */ + MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN | M0)); + /* HSUSB0_DIR */ + MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | DIS | M0)); + /* HSUSB0_NXT */ + MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA0 */ + MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA1 */ + MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA2 */ + MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA3 */ + MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA4 */ + MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA5 */ + MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA6 */ + MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | DIS | M0)); + /* HSUSB0_DATA7 */ + MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(I2C1_SCL), (IEN | PTU | EN | M0)); /* I2C1_SCL */ + MUX_VAL(CP(I2C1_SDA), (IEN | PTU | EN | M0)); /* I2C1_SDA */ +#ifdef CONFIG_MACH_OMAP_ADVANCED_MUX + /* DSS */ + MUX_VAL(CP(DSS_PCLK), (IDIS | PTD | DIS | M0)); /* DSS_PCLK */ + MUX_VAL(CP(DSS_HSYNC), (IDIS | PTD | DIS | M0)); /* DSS_HSYNC */ + MUX_VAL(CP(DSS_VSYNC), (IDIS | PTD | DIS | M0)); /* DSS_VSYNC */ + MUX_VAL(CP(DSS_ACBIAS), (IDIS | PTD | DIS | M0)); /* DSS_ACBIAS */ + MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | DIS | M0)); /* DSS_DATA0 */ + MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | DIS | M0)); /* DSS_DATA1 */ + MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | DIS | M0)); /* DSS_DATA2 */ + MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | DIS | M0)); /* DSS_DATA3 */ + MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | DIS | M0)); /* DSS_DATA4 */ + MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | DIS | M0)); /* DSS_DATA5 */ + MUX_VAL(CP(DSS_DATA6), (IDIS | PTD | DIS | M0)); /* DSS_DATA6 */ + MUX_VAL(CP(DSS_DATA7), (IDIS | PTD | DIS | M0)); /* DSS_DATA7 */ + MUX_VAL(CP(DSS_DATA8), (IDIS | PTD | DIS | M0)); /* DSS_DATA8 */ + MUX_VAL(CP(DSS_DATA9), (IDIS | PTD | DIS | M0)); /* DSS_DATA9 */ + MUX_VAL(CP(DSS_DATA10), (IDIS | PTD | DIS | M0)); /* DSS_DATA10 */ + MUX_VAL(CP(DSS_DATA11), (IDIS | PTD | DIS | M0)); /* DSS_DATA11 */ + MUX_VAL(CP(DSS_DATA12), (IDIS | PTD | DIS | M0)); /* DSS_DATA12 */ + MUX_VAL(CP(DSS_DATA13), (IDIS | PTD | DIS | M0)); /* DSS_DATA13 */ + MUX_VAL(CP(DSS_DATA14), (IDIS | PTD | DIS | M0)); /* DSS_DATA14 */ + MUX_VAL(CP(DSS_DATA15), (IDIS | PTD | DIS | M0)); /* DSS_DATA15 */ + MUX_VAL(CP(DSS_DATA16), (IDIS | PTD | DIS | M0)); /* DSS_DATA16 */ + MUX_VAL(CP(DSS_DATA17), (IDIS | PTD | DIS | M0)); /* DSS_DATA17 */ + MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | DIS | M0)); /* DSS_DATA18 */ + MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | DIS | M0)); /* DSS_DATA19 */ + MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | DIS | M0)); /* DSS_DATA20 */ + MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | DIS | M0)); /* DSS_DATA21 */ + MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | DIS | M0)); /* DSS_DATA22 */ + MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | DIS | M0)); /* DSS_DATA23 */ + /* CAMERA */ + MUX_VAL(CP(CAM_HS), (IEN | PTU | EN | M0)); /* CAM_HS */ + MUX_VAL(CP(CAM_VS), (IEN | PTU | EN | M0)); /* CAM_VS */ + MUX_VAL(CP(CAM_XCLKA), (IDIS | PTD | DIS | M0)); /* CAM_XCLKA */ + MUX_VAL(CP(CAM_PCLK), (IEN | PTU | EN | M0)); /* CAM_PCLK */ + /* GPIO_98 - CAM_RESET */ + MUX_VAL(CP(CAM_FLD), (IDIS | PTD | DIS | M4)); + MUX_VAL(CP(CAM_D0), (IEN | PTD | DIS | M0)); /* CAM_D0 */ + MUX_VAL(CP(CAM_D1), (IEN | PTD | DIS | M0)); /* CAM_D1 */ + MUX_VAL(CP(CAM_D2), (IEN | PTD | DIS | M0)); /* CAM_D2 */ + MUX_VAL(CP(CAM_D3), (IEN | PTD | DIS | M0)); /* CAM_D3 */ + MUX_VAL(CP(CAM_D4), (IEN | PTD | DIS | M0)); /* CAM_D4 */ + MUX_VAL(CP(CAM_D5), (IEN | PTD | DIS | M0)); /* CAM_D5 */ + MUX_VAL(CP(CAM_D6), (IEN | PTD | DIS | M0)); /* CAM_D6 */ + MUX_VAL(CP(CAM_D7), (IEN | PTD | DIS | M0)); /* CAM_D7 */ + MUX_VAL(CP(CAM_D8), (IEN | PTD | DIS | M0)); /* CAM_D8 */ + MUX_VAL(CP(CAM_D9), (IEN | PTD | DIS | M0)); /* CAM_D9 */ + MUX_VAL(CP(CAM_D10), (IEN | PTD | DIS | M0)); /* CAM_D10 */ + MUX_VAL(CP(CAM_D11), (IEN | PTD | DIS | M0)); /* CAM_D11 */ + MUX_VAL(CP(CAM_XCLKB), (IDIS | PTD | DIS | M0)); /* CAM_XCLKB */ + MUX_VAL(CP(CAM_WEN), (IEN | PTD | DIS | M4)); /* GPIO_167 */ + MUX_VAL(CP(CAM_STROBE), (IDIS | PTD | DIS | M0)); /* CAM_STROBE */ + MUX_VAL(CP(CSI2_DX0), (IEN | PTD | DIS | M0)); /* CSI2_DX0 */ + MUX_VAL(CP(CSI2_DY0), (IEN | PTD | DIS | M0)); /* CSI2_DY0 */ + MUX_VAL(CP(CSI2_DX1), (IEN | PTD | DIS | M0)); /* CSI2_DX1 */ + MUX_VAL(CP(CSI2_DY1), (IEN | PTD | DIS | M0)); /* CSI2_DY1 */ + /* AUDIO INTERFACE */ + MUX_VAL(CP(MCBSP2_FSX), (IEN | PTD | DIS | M0)); /* MCBSP2_FSX */ + /* MCBSP2_CLKX */ + MUX_VAL(CP(MCBSP2_CLKX), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(MCBSP2_DR), (IEN | PTD | DIS | M0)); /* MCBSP2_DR */ + MUX_VAL(CP(MCBSP2_DX), (IDIS | PTD | DIS | M0)); /* MCBSP2_DX */ + /* EXPANSION CARD */ + MUX_VAL(CP(MMC1_CLK), (IDIS | PTU | EN | M0)); /* MMC1_CLK */ + MUX_VAL(CP(MMC1_CMD), (IEN | PTU | EN | M0)); /* MMC1_CMD */ + MUX_VAL(CP(MMC1_DAT0), (IEN | PTU | EN | M0)); /* MMC1_DAT0 */ + MUX_VAL(CP(MMC1_DAT1), (IEN | PTU | EN | M0)); /* MMC1_DAT1 */ + MUX_VAL(CP(MMC1_DAT2), (IEN | PTU | EN | M0)); /* MMC1_DAT2 */ + MUX_VAL(CP(MMC1_DAT3), (IEN | PTU | EN | M0)); /* MMC1_DAT3 */ + MUX_VAL(CP(MMC1_DAT4), (IEN | PTU | EN | M0)); /* MMC1_DAT4 */ + MUX_VAL(CP(MMC1_DAT5), (IEN | PTU | EN | M0)); /* MMC1_DAT5 */ + MUX_VAL(CP(MMC1_DAT6), (IEN | PTU | EN | M0)); /* MMC1_DAT6 */ + MUX_VAL(CP(MMC1_DAT7), (IEN | PTU | EN | M0)); /* MMC1_DAT7 */ + /* WIRELESS LAN */ + MUX_VAL(CP(MMC2_CLK), (IEN | PTD | DIS | M0)); /* MMC2_CLK */ + MUX_VAL(CP(MMC2_CMD), (IEN | PTU | EN | M0)); /* MMC2_CMD */ + MUX_VAL(CP(MMC2_DAT0), (IEN | PTU | EN | M0)); /* MMC2_DAT0 */ + MUX_VAL(CP(MMC2_DAT1), (IEN | PTU | EN | M0)); /* MMC2_DAT1 */ + MUX_VAL(CP(MMC2_DAT2), (IEN | PTU | EN | M0)); /* MMC2_DAT2 */ + MUX_VAL(CP(MMC2_DAT3), (IEN | PTU | EN | M0)); /* MMC2_DAT3 */ + /* MMC2_DIR_DAT0 */ + MUX_VAL(CP(MMC2_DAT4), (IDIS | PTD | DIS | M1)); + /* MMC2_DIR_DAT1 */ + MUX_VAL(CP(MMC2_DAT5), (IDIS | PTD | DIS | M1)); + /* MMC2_DIR_CMD */ + MUX_VAL(CP(MMC2_DAT6), (IDIS | PTD | DIS | M1)); + /* MMC2_CLKIN */ + MUX_VAL(CP(MMC2_DAT7), (IEN | PTU | EN | M1)); + /* BLUETOOTH */ + /* MCBSP3_DX */ + MUX_VAL(CP(MCBSP3_DX), (IDIS | PTD | DIS | M0)); + /* MCBSP3_DR */ + MUX_VAL(CP(MCBSP3_DR), (IEN | PTD | DIS | M0)); + /* MCBSP3_CLKX */ + MUX_VAL(CP(MCBSP3_CLKX), (IEN | PTD | DIS | M0)); + /* MCBSP3_FSX */ + MUX_VAL(CP(MCBSP3_FSX), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(UART2_CTS), (IEN | PTU | EN | M0)); /* UART2_CTS */ + MUX_VAL(CP(UART2_RTS), (IDIS | PTD | DIS | M0)); /* UART2_RTS */ + MUX_VAL(CP(UART2_TX), (IDIS | PTD | DIS | M0)); /* UART2_TX */ + MUX_VAL(CP(UART2_RX), (IEN | PTD | DIS | M0)); /* UART2_RX */ + /* MODEM INTERFACE */ + MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)); /* UART1_TX */ + MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)); /* UART1_RTS */ + MUX_VAL(CP(UART1_CTS), (IEN | PTU | DIS | M0)); /* UART1_CTS */ + MUX_VAL(CP(UART1_RX), (IEN | PTD | DIS | M0)); /* UART1_RX */ + /* SSI1_DAT_RX */ + MUX_VAL(CP(MCBSP4_CLKX), (IEN | PTD | DIS | M1)); + MUX_VAL(CP(MCBSP4_DR), (IEN | PTD | DIS | M1)); /* SSI1_FLAG_RX */ + MUX_VAL(CP(MCBSP4_DX), (IEN | PTD | DIS | M1)); /* SSI1_RDY_RX */ + MUX_VAL(CP(MCBSP4_FSX), (IEN | PTD | DIS | M1)); /* SSI1_WAKE */ + /* MCBSP1_CLKR */ + MUX_VAL(CP(MCBSP1_CLKR), (IEN | PTD | DIS | M0)); + /* GPIO_157 - BT_WKUP */ + MUX_VAL(CP(MCBSP1_FSR), (IDIS | PTU | EN | M4)); + /* MCBSP1_DX */ + MUX_VAL(CP(MCBSP1_DX), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(MCBSP1_DR), (IEN | PTD | DIS | M0)); /* MCBSP1_DR */ + /* MCBSP_CLKS */ + MUX_VAL(CP(MCBSP_CLKS), (IEN | PTU | DIS | M0)); + /* MCBSP1_FSX */ + MUX_VAL(CP(MCBSP1_FSX), (IEN | PTD | DIS | M0)); + /* MCBSP1_CLKX */ + MUX_VAL(CP(MCBSP1_CLKX), (IEN | PTD | DIS | M0)); + /* SERIAL INTERFACE */ + MUX_VAL(CP(I2C2_SCL), (IEN | PTU | EN | M0)); /* I2C2_SCL */ + MUX_VAL(CP(I2C2_SDA), (IEN | PTU | EN | M0)); /* I2C2_SDA */ + MUX_VAL(CP(I2C3_SCL), (IEN | PTU | EN | M0)); /* I2C3_SCL */ + MUX_VAL(CP(I2C3_SDA), (IEN | PTU | EN | M0)); /* I2C3_SDA */ + MUX_VAL(CP(I2C4_SCL), (IEN | PTU | EN | M0)); /* I2C4_SCL */ + MUX_VAL(CP(I2C4_SDA), (IEN | PTU | EN | M0)); /* I2C4_SDA */ + MUX_VAL(CP(HDQ_SIO), (IEN | PTU | EN | M0)); /* HDQ_SIO */ + /* MCSPI1_CLK */ + MUX_VAL(CP(MCSPI1_CLK), (IEN | PTD | DIS | M0)); + /* MCSPI1_SIMO */ + MUX_VAL(CP(MCSPI1_SIMO), (IEN | PTD | DIS | M0)); + /* MCSPI1_SOMI */ + MUX_VAL(CP(MCSPI1_SOMI), (IEN | PTD | DIS | M0)); + /* MCSPI1_CS0 */ + MUX_VAL(CP(MCSPI1_CS0), (IEN | PTD | EN | M0)); + /* MCSPI1_CS1 */ + MUX_VAL(CP(MCSPI1_CS1), (IDIS | PTD | EN | M0)); + /* GPIO_176-NOR_DPD */ + MUX_VAL(CP(MCSPI1_CS2), (IDIS | PTD | DIS | M4)); + /* MCSPI1_CS3 */ + MUX_VAL(CP(MCSPI1_CS3), (IEN | PTD | EN | M0)); + /* MCSPI2_CLK */ + MUX_VAL(CP(MCSPI2_CLK), (IEN | PTD | DIS | M0)); + /* MCSPI2_SIMO */ + MUX_VAL(CP(MCSPI2_SIMO), (IEN | PTD | DIS | M0)); + /* MCSPI2_SOMI */ + MUX_VAL(CP(MCSPI2_SOMI), (IEN | PTD | DIS | M0)); + /* MCSPI2_CS0 */ + MUX_VAL(CP(MCSPI2_CS0), (IEN | PTD | EN | M0)); + /* MCSPI2_CS1 */ + MUX_VAL(CP(MCSPI2_CS1), (IEN | PTD | EN | M0)); + + /* CONTROL AND DEBUG */ + MUX_VAL(CP(SYS_32K), (IEN | PTD | DIS | M0)); /* SYS_32K */ + MUX_VAL(CP(SYS_CLKREQ), (IEN | PTD | DIS | M0)); /* SYS_CLKREQ */ + MUX_VAL(CP(SYS_NIRQ), (IEN | PTU | EN | M0)); /* SYS_NIRQ */ + MUX_VAL(CP(SYS_BOOT0), (IEN | PTD | DIS | M4)); /* GPIO_2 - PEN_IRQ */ + MUX_VAL(CP(SYS_BOOT1), (IEN | PTD | DIS | M4)); /* GPIO_3 */ + MUX_VAL(CP(SYS_BOOT2), (IEN | PTD | DIS | M4)); /* GPIO_4 - MMC1_WP */ + MUX_VAL(CP(SYS_BOOT3), (IEN | PTD | DIS | M4)); /* GPIO_5 - LCD_ENVDD */ + MUX_VAL(CP(SYS_BOOT4), (IEN | PTD | DIS | M4)); /* GPIO_6 - LAN_INTR0 */ + MUX_VAL(CP(SYS_BOOT5), (IEN | PTD | DIS | M4)); /* GPIO_7 - MMC2_WP */ + /* GPIO_8-LCD_ENBKL */ + MUX_VAL(CP(SYS_BOOT6), (IDIS | PTD | DIS | M4)); + /* SYS_OFF_MODE */ + MUX_VAL(CP(SYS_OFF_MODE), (IEN | PTD | DIS | M0)); + /* SYS_CLKOUT1 */ + MUX_VAL(CP(SYS_CLKOUT1), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(SYS_CLKOUT2), (IEN | PTU | EN | M4)); /* GPIO_186 */ + MUX_VAL(CP(JTAG_NTRST), (IEN | PTD | DIS | M0)); /* JTAG_NTRST */ + MUX_VAL(CP(JTAG_TCK), (IEN | PTD | DIS | M0)); /* JTAG_TCK */ + MUX_VAL(CP(JTAG_TMS), (IEN | PTD | DIS | M0)); /* JTAG_TMS */ + MUX_VAL(CP(JTAG_TDI), (IEN | PTD | DIS | M0)); /* JTAG_TDI */ + MUX_VAL(CP(JTAG_EMU0), (IEN | PTD | DIS | M0)); /* JTAG_EMU0 */ + MUX_VAL(CP(JTAG_EMU1), (IEN | PTD | DIS | M0)); /* JTAG_EMU1 */ + /* HSUSB1_TLL_STP */ + MUX_VAL(CP(ETK_CLK_ES2), (IDIS | PTU | EN | M0)); + /* HSUSB1_TLL_CLK */ + MUX_VAL(CP(ETK_CTL_ES2), (IDIS | PTD | DIS | M0)); + /* HSUSB1_TLL_DATA0 */ + MUX_VAL(CP(ETK_D0_ES2), (IEN | PTD | DIS | M1)); + /* MCSPI3_CS0 */ + MUX_VAL(CP(ETK_D1_ES2), (IEN | PTD | DIS | M1)); + /* HSUSB1_TLL_DATA2 */ + MUX_VAL(CP(ETK_D2_ES2), (IEN | PTD | EN | M1)); + /* HSUSB1_TLL_DATA7 */ + MUX_VAL(CP(ETK_D3_ES2), (IEN | PTD | DIS | M1)); + /* HSUSB1_TLL_DATA4 */ + MUX_VAL(CP(ETK_D4_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB1_TLL_DATA5 */ + MUX_VAL(CP(ETK_D5_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB1_TLL_DATA6 */ + MUX_VAL(CP(ETK_D6_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB1_TLL_DATA3 */ + MUX_VAL(CP(ETK_D7_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB1_TLL_DIR */ + MUX_VAL(CP(ETK_D8_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB1_TLL_NXT */ + MUX_VAL(CP(ETK_D9_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB2_TLL_CLK */ + MUX_VAL(CP(ETK_D10_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB2_TLL_STP */ + MUX_VAL(CP(ETK_D11_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB2_TLL_DIR */ + MUX_VAL(CP(ETK_D12_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB2_TLL_NXT */ + MUX_VAL(CP(ETK_D13_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB2_TLL_DATA0 */ + MUX_VAL(CP(ETK_D14_ES2), (IEN | PTD | DIS | M0)); + /* HSUSB2_TLL_DATA1 */ + MUX_VAL(CP(ETK_D15_ES2), (IEN | PTD | DIS | M0)); + + /* DIE TO DIE */ + MUX_VAL(CP(D2D_MCAD0), (IEN | PTD | EN | M0)); /* D2D_MCAD0 */ + MUX_VAL(CP(D2D_MCAD1), (IEN | PTD | EN | M0)); /* D2D_MCAD1 */ + MUX_VAL(CP(D2D_MCAD2), (IEN | PTD | EN | M0)); /* D2D_MCAD2 */ + MUX_VAL(CP(D2D_MCAD3), (IEN | PTD | EN | M0)); /* D2D_MCAD3 */ + MUX_VAL(CP(D2D_MCAD4), (IEN | PTD | EN | M0)); /* D2D_MCAD4 */ + MUX_VAL(CP(D2D_MCAD5), (IEN | PTD | EN | M0)); /* D2D_MCAD5 */ + MUX_VAL(CP(D2D_MCAD6), (IEN | PTD | EN | M0)); /* D2D_MCAD6 */ + MUX_VAL(CP(D2D_MCAD7), (IEN | PTD | EN | M0)); /* D2D_MCAD7 */ + MUX_VAL(CP(D2D_MCAD8), (IEN | PTD | EN | M0)); /* D2D_MCAD8 */ + MUX_VAL(CP(D2D_MCAD9), (IEN | PTD | EN | M0)); /* D2D_MCAD9 */ + MUX_VAL(CP(D2D_MCAD10), (IEN | PTD | EN | M0)); /* D2D_MCAD10 */ + MUX_VAL(CP(D2D_MCAD11), (IEN | PTD | EN | M0)); /* D2D_MCAD11 */ + MUX_VAL(CP(D2D_MCAD12), (IEN | PTD | EN | M0)); /* D2D_MCAD12 */ + MUX_VAL(CP(D2D_MCAD13), (IEN | PTD | EN | M0)); /* D2D_MCAD13 */ + MUX_VAL(CP(D2D_MCAD14), (IEN | PTD | EN | M0)); /* D2D_MCAD14 */ + MUX_VAL(CP(D2D_MCAD15), (IEN | PTD | EN | M0)); /* D2D_MCAD15 */ + MUX_VAL(CP(D2D_MCAD16), (IEN | PTD | EN | M0)); /* D2D_MCAD16 */ + MUX_VAL(CP(D2D_MCAD17), (IEN | PTD | EN | M0)); /* D2D_MCAD17 */ + MUX_VAL(CP(D2D_MCAD18), (IEN | PTD | EN | M0)); /* D2D_MCAD18 */ + MUX_VAL(CP(D2D_MCAD19), (IEN | PTD | EN | M0)); /* D2D_MCAD19 */ + MUX_VAL(CP(D2D_MCAD20), (IEN | PTD | EN | M0)); /* D2D_MCAD20 */ + MUX_VAL(CP(D2D_MCAD21), (IEN | PTD | EN | M0)); /* D2D_MCAD21 */ + MUX_VAL(CP(D2D_MCAD22), (IEN | PTD | EN | M0)); /* D2D_MCAD22 */ + MUX_VAL(CP(D2D_MCAD23), (IEN | PTD | EN | M0)); /* D2D_MCAD23 */ + MUX_VAL(CP(D2D_MCAD24), (IEN | PTD | EN | M0)); /* D2D_MCAD24 */ + MUX_VAL(CP(D2D_MCAD25), (IEN | PTD | EN | M0)); /* D2D_MCAD25 */ + MUX_VAL(CP(D2D_MCAD26), (IEN | PTD | EN | M0)); /* D2D_MCAD26 */ + MUX_VAL(CP(D2D_MCAD27), (IEN | PTD | EN | M0)); /* D2D_MCAD27 */ + MUX_VAL(CP(D2D_MCAD28), (IEN | PTD | EN | M0)); /* D2D_MCAD28 */ + MUX_VAL(CP(D2D_MCAD29), (IEN | PTD | EN | M0)); /* D2D_MCAD29 */ + MUX_VAL(CP(D2D_MCAD30), (IEN | PTD | EN | M0)); /* D2D_MCAD30 */ + MUX_VAL(CP(D2D_MCAD31), (IEN | PTD | EN | M0)); /* D2D_MCAD31 */ + MUX_VAL(CP(D2D_MCAD32), (IEN | PTD | EN | M0)); /* D2D_MCAD32 */ + MUX_VAL(CP(D2D_MCAD33), (IEN | PTD | EN | M0)); /* D2D_MCAD33 */ + MUX_VAL(CP(D2D_MCAD34), (IEN | PTD | EN | M0)); /* D2D_MCAD34 */ + MUX_VAL(CP(D2D_MCAD35), (IEN | PTD | EN | M0)); /* D2D_MCAD35 */ + MUX_VAL(CP(D2D_MCAD36), (IEN | PTD | EN | M0)); /* D2D_MCAD36 */ + /* D2D_CLK26MI */ + MUX_VAL(CP(D2D_CLK26MI), (IEN | PTD | DIS | M0)); + /* D2D_NRESPWRON */ + MUX_VAL(CP(D2D_NRESPWRON), (IEN | PTD | EN | M0)); + /* D2D_NRESWARM */ + MUX_VAL(CP(D2D_NRESWARM), (IEN | PTU | EN | M0)); + /* D2D_ARM9NIRQ */ + MUX_VAL(CP(D2D_ARM9NIRQ), (IEN | PTD | DIS | M0)); + /* D2D_UMA2P6FIQ */ + MUX_VAL(CP(D2D_UMA2P6FIQ), (IEN | PTD | DIS | M0)); + /* D2D_SPINT */ + MUX_VAL(CP(D2D_SPINT), (IEN | PTD | EN | M0)); + /* D2D_FRINT */ + MUX_VAL(CP(D2D_FRINT), (IEN | PTD | EN | M0)); + /* D2D_DMAREQ0 */ + MUX_VAL(CP(D2D_DMAREQ0), (IEN | PTD | DIS | M0)); + /* D2D_DMAREQ1 */ + MUX_VAL(CP(D2D_DMAREQ1), (IEN | PTD | DIS | M0)); + /* D2D_DMAREQ2 */ + MUX_VAL(CP(D2D_DMAREQ2), (IEN | PTD | DIS | M0)); + /* D2D_DMAREQ3 */ + MUX_VAL(CP(D2D_DMAREQ3), (IEN | PTD | DIS | M0)); + /* D2D_N3GTRST */ + MUX_VAL(CP(D2D_N3GTRST), (IEN | PTD | DIS | M0)); + /* D2D_N3GTDI */ + MUX_VAL(CP(D2D_N3GTDI), (IEN | PTD | DIS | M0)); + /* D2D_N3GTDO */ + MUX_VAL(CP(D2D_N3GTDO), (IEN | PTD | DIS | M0)); + /* D2D_N3GTMS */ + MUX_VAL(CP(D2D_N3GTMS), (IEN | PTD | DIS | M0)); + /* D2D_N3GTCK */ + MUX_VAL(CP(D2D_N3GTCK), (IEN | PTD | DIS | M0)); + /* D2D_N3GRTCK */ + MUX_VAL(CP(D2D_N3GRTCK), (IEN | PTD | DIS | M0)); + /* D2D_MSTDBY */ + MUX_VAL(CP(D2D_MSTDBY), (IEN | PTU | EN | M0)); + /* D2D_SWAKEUP */ + MUX_VAL(CP(D2D_SWAKEUP), (IEN | PTD | EN | M0)); + /* D2D_IDLEREQ */ + MUX_VAL(CP(D2D_IDLEREQ), (IEN | PTD | DIS | M0)); + /* D2D_IDLEACK */ + MUX_VAL(CP(D2D_IDLEACK), (IEN | PTU | EN | M0)); + /* D2D_MWRITE */ + MUX_VAL(CP(D2D_MWRITE), (IEN | PTD | DIS | M0)); + /* D2D_SWRITE */ + MUX_VAL(CP(D2D_SWRITE), (IEN | PTD | DIS | M0)); + /* D2D_MREAD */ + MUX_VAL(CP(D2D_MREAD), (IEN | PTD | DIS | M0)); + /* D2D_SREAD */ + MUX_VAL(CP(D2D_SREAD), (IEN | PTD | DIS | M0)); + /* D2D_MBUSFLAG */ + MUX_VAL(CP(D2D_MBUSFLAG), (IEN | PTD | DIS | M0)); + /* D2D_SBUSFLAG */ + MUX_VAL(CP(D2D_SBUSFLAG), (IEN | PTD | DIS | M0)); + /* SDRC_CKE0 */ + MUX_VAL(CP(SDRC_CKE0), (IDIS | PTU | EN | M0)); + /* SDRC_CKE1 NOT USED */ + MUX_VAL(CP(SDRC_CKE1), (IDIS | PTD | DIS | M7)); +#endif /* CONFIG_MACH_OMAP_ADVANCED_MUX */ +} + +/******************** Board Run Time *******************/ + +/*-----------------------CONSOLE Devices -----------------------------------*/ + +#ifdef CONFIG_DRIVER_SERIAL_NS16550 + +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 sdp3430_serial_device = { + .name = "serial_ns16550", + .map_base = OMAP_UART3_BASE, + .size = 1024, + .platform_data = (void *)&serial_plat, +}; + +/** + * @brief UART serial port initialization - remember to enable COM clocks in arch + * + * @return result of device registration + */ +static int sdp3430_console_init(void) +{ + /* Register the serial port */ + return register_device(&sdp3430_serial_device); +} + +console_initcall(sdp3430_console_init); +#endif /* CONFIG_DRIVER_SERIAL_NS16550 */ + +/*------------------------- FLASH Devices -----------------------------------*/ +static int sdp3430_flash_init(void) +{ +#ifdef CONFIG_GPMC + /* WP is made high and WAIT1 active Low */ + gpmc_generic_init(0x10); +#endif + return 0; +} + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +struct device_d sdram_dev = { + .name = "mem", + .map_base = 0x80000000, + .size = 128 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +/*-----------------------Generic Devices Initialization ---------------------*/ + +static int sdp3430_devices_init(void) +{ + int ret; + ret = register_device(&sdram_dev); + if (ret) + goto failed; + ret = sdp3430_flash_init(); + if (ret) + goto failed; + + armlinux_add_dram(&sdram_dev); +failed: + return ret; +} + +device_initcall(sdp3430_devices_init); diff --git a/arch/arm/boards/omap/board.h b/arch/arm/boards/omap/board.h new file mode 100644 index 0000000..cf231a2 --- /dev/null +++ b/arch/arm/boards/omap/board.h @@ -0,0 +1,35 @@ +/** + * @file + * @brief exported generic APIs which various board files implement + * + * FileName: arch/arm/boards/omap/board.h + * + * This file will not contain any board specific implementations. + */ +/* + * (C) Copyright 2008 + * Texas Instruments, + * Raghavendra KH + * + * 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 __BOARD_OMAP_H_ +#define __BOARD_OMAP_H_ + +/** Generic Board initialization called from platform.S */ +void board_init(void); + +#endif /* __BOARD_OMAP_H_ */ diff --git a/arch/arm/boards/omap/config.h b/arch/arm/boards/omap/config.h new file mode 100644 index 0000000..29d2ee2 --- /dev/null +++ b/arch/arm/boards/omap/config.h @@ -0,0 +1,33 @@ +/** + * @file + * @brief provide a wrapper for standard malloc and stack size defines + * + * FileName: arch/arm/boards/omap/config.h + * + * Standard defines should be configurable for us to move Stack and malloc + * areas around this defines some basics for that + */ +/* + * (C) Copyright 2006-2008 + * Texas Instruments, + * Nishanth Menon + * + * 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 __MACH_OMAP_CONFIG_H +#define __MACH_OMAP_CONFIG_H + +#endif /* __MACH_OMAP_CONFIG_H */ diff --git a/arch/arm/boards/omap/devices-gpmc-nand.c b/arch/arm/boards/omap/devices-gpmc-nand.c new file mode 100644 index 0000000..ac23e9d --- /dev/null +++ b/arch/arm/boards/omap/devices-gpmc-nand.c @@ -0,0 +1,101 @@ +/** + * @file + * @brief GPMC specific NAND devices + * + * FileName: arch/arm/boards/omap/devices-gpmc-nand.c + * + * GPMC NAND Devices such as those from Micron, Samsung are listed here + */ +/* + * (C) Copyright 2006-2008 + * Texas Instruments, + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define GPMC_CONF1_VALx8 0x00000800 +#define GPMC_CONF1_VALx16 0x00001800 +/* Set up the generic params */ + +/** GPMC timing for our nand device */ +static struct gpmc_config nand_cfg = { + .cfg = { + 0, /*CONF1 */ + 0x00141400, /*CONF2 */ + 0x00141400, /*CONF3 */ + 0x0F010F01, /*CONF4 */ + 0x010C1414, /*CONF5 */ +#ifdef CONFIG_ARCH_OMAP3 + /* Additional bits in OMAP3 */ + 0x1F040000 | +#endif + 0x00000A80, /*CONF6 */ + }, + + /* Nand: dont care about base address */ + .base = 0x28000000, + /* GPMC address map as small as possible */ + .size = GPMC_SIZE_16M, +}; + +/** NAND platform specific settings settings */ +static struct gpmc_nand_platform_data nand_plat = { + .cs = 0, + .max_timeout = MSECOND, + .wait_mon_pin = 0, + .priv = (void *)&nand_cfg, +}; + +/** NAND device definition */ +static struct device_d gpmc_generic_nand_nand_device = { + .name = "gpmc_nand", + .map_base = OMAP_GPMC_BASE, + .size = 1024 * 4, /* GPMC size */ + .platform_data = (void *)&nand_plat, +}; + +/** + * @brief gpmc_generic_nand_devices_init - init generic nand device + * + * @return success/fail based on device funtion + */ +int gpmc_generic_nand_devices_init(int cs, int width, int hwecc) +{ + nand_plat.cs = cs; + + if (width == 16) + nand_cfg.cfg[0] = GPMC_CONF1_VALx16; + else + nand_cfg.cfg[0] = GPMC_CONF1_VALx8; + + nand_plat.device_width = width; + nand_plat.plat_options = hwecc ? NAND_HWECC_ENABLE : 0; + + /* Configure GPMC CS before register */ + gpmc_cs_config(nand_plat.cs, &nand_cfg); + return register_device(&gpmc_generic_nand_nand_device); +} diff --git a/arch/arm/boards/omap/env/bin/init b/arch/arm/boards/omap/env/bin/init new file mode 100644 index 0000000..224a6b4 --- /dev/null +++ b/arch/arm/boards/omap/env/bin/init @@ -0,0 +1 @@ +# Dummy Init environment script diff --git a/arch/arm/boards/omap/platform.S b/arch/arm/boards/omap/platform.S new file mode 100644 index 0000000..77b7eed --- /dev/null +++ b/arch/arm/boards/omap/platform.S @@ -0,0 +1,65 @@ +/** + * @file + * @brief Wrapper to call board level initialization routine + * + * FileName: arch/arm/boards/omap/platform.S + * + * board_init_lowlevel is defined here. This calls board_init which + * is linked to the binary - the board_init only has a SRAM stack. + * so it needs to be careful about the usage of global variables + * and the likes. Enabled only if CONFIG_MACH_DO_LOWLEVEL_INIT is + * defined + */ +/* + * (C) Copyright 2006-2008 + * Texas Instruments, + * Nishanth Menon + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#ifdef CONFIG_MACH_DO_LOWLEVEL_INIT +/** + * @fn void board_init_lowlevel(void) + * + * @brief This provides a assembly wrapper setting up SRAM before calling + * board_init + * + * @return void + */ +.globl board_init_lowlevel +board_init_lowlevel: + /* Setup a temporary stack so that we can call C functions + * Yes. this might have been already done by arch code. + * No harm in being a bit redundant to avoid future complications + */ + ldr sp, SRAM_STACK + str ip, [sp] /* stash old link register */ + str lr, [sp] /* stash current link register */ + mov ip, lr /* save link reg across call */ + /* Do the pin muxes, sdram init etc..board-xxx.c */ + bl board_init + ldr lr, [sp] /* restore current link register */ + ldr ip, [sp] /* restore save ip */ + /* back to arch calling code */ + mov pc, lr +SRAM_STACK: + .word OMAP_SRAM_STACK + +#endif /* CONFIG_MACH_DO_LOWLEVEL_INIT */ diff --git a/arch/arm/boards/pcm037/Makefile b/arch/arm/boards/pcm037/Makefile new file mode 100644 index 0000000..7d36b77 --- /dev/null +++ b/arch/arm/boards/pcm037/Makefile @@ -0,0 +1,24 @@ +# +# (C) Copyright 2007 Juergen Beisert +# +# 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 +# + +obj-y += lowlevel_init.o +obj-y += pcm037.o diff --git a/arch/arm/boards/pcm037/config.h b/arch/arm/boards/pcm037/config.h new file mode 100644 index 0000000..5495d03 --- /dev/null +++ b/arch/arm/boards/pcm037/config.h @@ -0,0 +1,35 @@ +/* + * (C) Copyright 2007 Juergen Beisert + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * Definitions related to passing arguments to kernel. + */ + +/* #define CONFIG_SYSPLL_CLK_FREQ 26000000 */ + +/* FIXME */ +#define CONFIG_MX31_HCLK_FREQ 26000000 +#define CONFIG_MX31_CLK32 32000 + +#endif + +/* nothing to do here yet */ diff --git a/arch/arm/boards/pcm037/env/config b/arch/arm/boards/pcm037/env/config new file mode 100644 index 0000000..bf15620 --- /dev/null +++ b/arch/arm/boards/pcm037/env/config @@ -0,0 +1,56 @@ +#!/bin/sh + +machine=pcm037 +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 'net', 'nor' or 'nand' +kernel_loc=net +# 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=ttymxc0,115200" + +nor_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nor=3 + +nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nand=7 + +# 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/pcm037/lowlevel_init.S b/arch/arm/boards/pcm037/lowlevel_init.S new file mode 100644 index 0000000..8988db2 --- /dev/null +++ b/arch/arm/boards/pcm037/lowlevel_init.S @@ -0,0 +1,167 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +#define writeb(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + strb r1, [r0]; + +.macro DELAY loops + ldr r2, =\loops +1: + subs r2, r2, #1 + nop + bcs 1b +.endm + + .section ".text_bare_init","ax" + +.globl board_init_lowlevel +board_init_lowlevel: + + mov r10, lr + writel(IPU_CONF_DI_EN, IPU_CONF) + writel(0x074B0BF5, IMX_CCM_BASE + CCM_CCMR) + + DELAY 0x40000 + + writel(0x074B0BF5 | CCMR_MPE, IMX_CCM_BASE + CCM_CCMR) + writel((0x074B0BF5 | CCMR_MPE) & ~CCMR_MDS, IMX_CCM_BASE + CCM_CCMR) + + writel(PDR0_CSI_PODF(0xff1) | \ + PDR0_PER_PODF(7) | \ + PDR0_HSP_PODF(3) | \ + PDR0_NFC_PODF(5) | \ + PDR0_IPG_PODF(1) | \ + PDR0_MAX_PODF(3) | \ + PDR0_MCU_PODF(0), \ + IMX_CCM_BASE + CCM_PDR0) + + writel(IMX_PLL_PD(0) | IMX_PLL_MFD(0xe) | IMX_PLL_MFI(9) | IMX_PLL_MFN(0xd), IMX_CCM_BASE + CCM_MPCTL) + writel(IMX_PLL_PD(1) | IMX_PLL_MFD(0x43) | IMX_PLL_MFI(12) | IMX_PLL_MFN(1), IMX_CCM_BASE + CCM_SPCTL) + + /* Configure IOMUXC + * Clears 0x43fa_c26c - 0x43fa_c2dc with 0, except 0x43fa_c278 (untouched), 0x43fa_c27c (set to 0x1000) and 0x43fa_c280 (untouched) + * (behaviour copied by sha, source unknown) + */ + mov r1, #0; + ldr r0, =0x43FAC26C + str r1, [r0], #4 + str r1, [r0], #4 + str r1, [r0], #0x10 + + ldr r2, =0x43FAC2DC +clear_iomux: + str r1, [r0], #4 + cmp r0, r2 + bls clear_iomux + writel(0x1000, 0x43FAC27C )/* CS2 CSD0) */ + + /* Skip SDRAM initialization if we run from RAM */ + cmp pc, #0x80000000 + blo 1f + cmp pc, #0x90000000 + bhs 1f + + mov pc, r10 +1: + +#if defined CONFIG_PCM037_SDRAM_BANK0_128MB +#define ROWS0 ESDCTL0_ROW13 +#elif defined CONFIG_PCM037_SDRAM_BANK0_256MB +#define ROWS0 ESDCTL0_ROW14 +#endif + writel(0x00000004, ESDMISC) + writel(0x006ac73a, ESDCFG0) + writel(0x90100000 | ROWS0, ESDCTL0) + writel(0x12344321, IMX_SDRAM_CS0 + 0xf00) + writel(0xa0100000 | ROWS0, ESDCTL0) + writel(0x12344321, IMX_SDRAM_CS0) + writel(0x12344321, IMX_SDRAM_CS0) + writel(0xb0100000 | ROWS0, ESDCTL0) + writeb(0xda, IMX_SDRAM_CS0 + 0x33) + writeb(0xff, IMX_SDRAM_CS0 + 0x01000000) + writel(0x80226080 | ROWS0, ESDCTL0) + writel(0xDEADBEEF, IMX_SDRAM_CS0) + writel(0x0000000c, ESDMISC) + +#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE +#if defined CONFIG_PCM037_SDRAM_BANK1_128MB +#define ROWS1 ESDCTL0_ROW13 +#elif defined CONFIG_PCM037_SDRAM_BANK1_256MB +#define ROWS1 ESDCTL0_ROW14 +#endif + writel(0x006ac73a, ESDCFG1) + writel(0x90100000 | ROWS1, ESDCTL1) + writel(0x12344321, IMX_SDRAM_CS1 + 0xf00) + writel(0xa0100000 | ROWS1, ESDCTL1) + writel(0x12344321, IMX_SDRAM_CS1) + writel(0x12344321, IMX_SDRAM_CS1) + writel(0xb0100000 | ROWS1, ESDCTL1) + writeb(0xda, IMX_SDRAM_CS1 + 0x33) + writeb(0xff, IMX_SDRAM_CS1 + 0x01000000) + writel(0x80226080 | ROWS1, ESDCTL1) + writel(0xDEADBEEF, IMX_SDRAM_CS1) + writel(0x0000000c, ESDMISC) +#endif + +#ifdef CONFIG_NAND_IMX_BOOT + ldr sp, =0x80f00000 /* Setup a temporary stack in SDRAM */ + + ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ + ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ + + /* skip NAND boot if not running from NFC space */ + cmp pc, r0 + blo ret + cmp pc, r2 + bhs ret + + /* Move ourselves out of NFC SRAM */ + ldr r1, =TEXT_BASE + +copy_loop: + ldmia r0!, {r3-r9} /* copy from source address [r0] */ + stmia r1!, {r3-r9} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + + ldr pc, =1f /* Jump to SDRAM */ +1: + bl nand_boot /* Load barebox from NAND Flash */ + + ldr r1, =IMX_NFC_BASE - TEXT_BASE + sub r10, r10, r1 /* adjust return address from NFC SRAM */ +ret: +#endif /* CONFIG_NAND_IMX_BOOT */ + + mov pc, r10 + diff --git a/arch/arm/boards/pcm037/pcm037.c b/arch/arm/boards/pcm037/pcm037.c new file mode 100644 index 0000000..2e6968b --- /dev/null +++ b/arch/arm/boards/pcm037/pcm037.c @@ -0,0 +1,340 @@ +/* + * (C) 2007 Pengutronix, Sascha Hauer + * + * 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 + * + * Board support for Phytec's, i.MX31 based CPU card, called: PCM037 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Up to 32MiB NOR type flash, connected to + * CS line 0, data width is 16 bit + */ +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = IMX_CS0_BASE, + .size = 32 * 1024 * 1024, /* area size */ +}; + +/* + * up to 2MiB static RAM type memory, connected + * to CS4, data width is 16 bit + */ +static struct memory_platform_data sram_dev_pdata0 = { + .name = "sram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sram_dev = { + .name = "mem", + .map_base = IMX_CS4_BASE, + .size = IMX_CS4_RANGE, /* area size */ + .platform_data = &sram_dev_pdata0, +}; + +/* + * SMSC 9217 network controller + * connected to CS line 1 and interrupt line + * GPIO3, data width is 16 bit + */ +static struct device_d network_dev = { + .name = "smc911x", + .map_base = IMX_CS1_BASE, + .size = IMX_CS1_RANGE, /* area size */ +}; + +#if defined CONFIG_PCM037_SDRAM_BANK0_128MB +#define SDRAM0 128 +#elif defined CONFIG_PCM037_SDRAM_BANK0_256MB +#define SDRAM0 256 +#endif + +static struct memory_platform_data ram_dev_pdata0 = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram0_dev = { + .name = "mem", + .map_base = IMX_SDRAM_CS0, + .size = SDRAM0 * 1024 * 1024, /* fix size */ + .platform_data = &ram_dev_pdata0, +}; + +#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE + +#if defined CONFIG_PCM037_SDRAM_BANK1_128MB +#define SDRAM1 128 +#elif defined CONFIG_PCM037_SDRAM_BANK1_256MB +#define SDRAM1 256 +#endif + +static struct memory_platform_data ram_dev_pdata1 = { + .name = "ram1", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram1_dev = { + .name = "mem", + .map_base = IMX_SDRAM_CS1, + .size = SDRAM1 * 1024 * 1024, /* fix size */ + .platform_data = &ram_dev_pdata1, +}; +#endif + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = 0xB8000000, + .platform_data = &nand_info, +}; + +#ifdef CONFIG_USB +static struct device_d usbotg_dev = { + .name = "ehci", + .map_base = IMX_OTG_BASE, + .size = 0x200, +}; + +static struct device_d usbh2_dev = { + .name = "ehci", + .map_base = IMX_OTG_BASE + 0x400, + .size = 0x200, +}; + +static void pcm037_usb_init(void) +{ + u32 tmp; + + /* enable clock */ + tmp = readl(0x53f80000); + tmp |= (1 << 9); + writel(tmp, 0x53f80000); + + /* Host 1 */ + tmp = readl(IMX_OTG_BASE + 0x600); + tmp &= ~((3 << 21) | 1); + tmp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 11) | (1 << 20); + writel(tmp, IMX_OTG_BASE + 0x600); + + tmp = readl(IMX_OTG_BASE + 0x184); + tmp &= ~(3 << 30); + tmp |= 2 << 30; + writel(tmp, IMX_OTG_BASE + 0x184); + + imx_iomux_mode(MX31_PIN_USBOTG_DATA0__USBOTG_DATA0); + imx_iomux_mode(MX31_PIN_USBOTG_DATA1__USBOTG_DATA1); + imx_iomux_mode(MX31_PIN_USBOTG_DATA2__USBOTG_DATA2); + imx_iomux_mode(MX31_PIN_USBOTG_DATA3__USBOTG_DATA3); + imx_iomux_mode(MX31_PIN_USBOTG_DATA4__USBOTG_DATA4); + imx_iomux_mode(MX31_PIN_USBOTG_DATA5__USBOTG_DATA5); + imx_iomux_mode(MX31_PIN_USBOTG_DATA6__USBOTG_DATA6); + imx_iomux_mode(MX31_PIN_USBOTG_DATA7__USBOTG_DATA7); + imx_iomux_mode(MX31_PIN_USBOTG_CLK__USBOTG_CLK); + imx_iomux_mode(MX31_PIN_USBOTG_DIR__USBOTG_DIR); + imx_iomux_mode(MX31_PIN_USBOTG_NXT__USBOTG_NXT); + imx_iomux_mode(MX31_PIN_USBOTG_STP__USBOTG_STP); + + mdelay(50); + isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x170), 1); + + /* Host 2 */ + tmp = readl(IOMUXC_BASE + 0x8); + tmp |= 1 << 11; + writel(tmp, IOMUXC_BASE + 0x8); + + imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_CLK, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DIR, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_NXT, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_STP, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DATA0, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DATA1, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_STXD3, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_SRXD3, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_SCK3, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_SFS3, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_STXD6, IOMUX_CONFIG_FUNC)); + imx_iomux_mode(IOMUX_MODE(MX31_PIN_SRXD6, IOMUX_CONFIG_FUNC)); + +#define H2_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) + imx_iomux_set_pad(MX31_PIN_USBH2_CLK, H2_PAD_CFG); + imx_iomux_set_pad(MX31_PIN_USBH2_DIR, H2_PAD_CFG); + imx_iomux_set_pad(MX31_PIN_USBH2_NXT, H2_PAD_CFG); + imx_iomux_set_pad(MX31_PIN_USBH2_STP, H2_PAD_CFG); + imx_iomux_set_pad(MX31_PIN_USBH2_DATA0, H2_PAD_CFG); /* USBH2_DATA0 */ + imx_iomux_set_pad(MX31_PIN_USBH2_DATA1, H2_PAD_CFG); /* USBH2_DATA1 */ + imx_iomux_set_pad(MX31_PIN_SRXD6, H2_PAD_CFG); /* USBH2_DATA2 */ + imx_iomux_set_pad(MX31_PIN_STXD6, H2_PAD_CFG); /* USBH2_DATA3 */ + imx_iomux_set_pad(MX31_PIN_SFS3, H2_PAD_CFG); /* USBH2_DATA4 */ + imx_iomux_set_pad(MX31_PIN_SCK3, H2_PAD_CFG); /* USBH2_DATA5 */ + imx_iomux_set_pad(MX31_PIN_SRXD3, H2_PAD_CFG); /* USBH2_DATA6 */ + imx_iomux_set_pad(MX31_PIN_STXD3, H2_PAD_CFG); /* USBH2_DATA7 */ + + tmp = readl(IMX_OTG_BASE + 0x600); + tmp &= ~((3 << 21) | 1); + tmp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20); + writel(tmp, IMX_OTG_BASE + 0x600); + + tmp = readl(IMX_OTG_BASE + 0x584); + tmp &= ~(3 << 30); + tmp |= 2 << 30; + writel(tmp, IMX_OTG_BASE + 0x584); + + mdelay(50); + isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x570), 1); + + /* Set to Host mode */ + tmp = readl(IMX_OTG_BASE + 0x1a8); + writel(tmp | 0x3, IMX_OTG_BASE + 0x1a8); + +} +#endif + +#ifdef CONFIG_MMU +static void pcm037_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + +#if TEXT_BASE & (0x100000 - 1) +#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary +#else + arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); +#endif + mmu_enable(); + +#ifdef CONFIG_CACHE_L2X0 + l2x0_init((void __iomem *)0x30000000, 0x00030024, 0x00000000); +#endif +} +#else +static void pcm037_mmu_init(void) +{ +} +#endif + +static int imx31_devices_init(void) +{ + pcm037_mmu_init(); + + __REG(CSCR_U(0)) = 0x0000cf03; /* CS0: Nor Flash */ + __REG(CSCR_L(0)) = 0x10000d03; + __REG(CSCR_A(0)) = 0x00720900; + + __REG(CSCR_U(1)) = 0x0000df06; /* CS1: Network Controller */ + __REG(CSCR_L(1)) = 0x444a4541; + __REG(CSCR_A(1)) = 0x44443302; + + __REG(CSCR_U(4)) = 0x0000d843; /* CS4: SRAM */ + __REG(CSCR_L(4)) = 0x22252521; + __REG(CSCR_A(4)) = 0x22220a00; + + __REG(CSCR_U(5)) = 0x0000DCF6; /* CS5: SJA1000 */ + __REG(CSCR_L(5)) = 0x444A0301; + __REG(CSCR_A(5)) = 0x44443302; + + register_device(&cfi_dev); + + /* + * Create partitions that should be + * not touched by any regular user + */ + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); /* ourself */ + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); /* environment */ + + protect_file("/dev/env0", 1); + + register_device(&sram_dev); + register_device(&nand_dev); + register_device(&network_dev); + + register_device(&sdram0_dev); +#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE + register_device(&sdram1_dev); +#endif +#ifdef CONFIG_USB + pcm037_usb_init(); + register_device(&usbotg_dev); + register_device(&usbh2_dev); +#endif + + armlinux_add_dram(&sdram0_dev); +#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE + armlinux_add_dram(&sdram1_dev); +#endif + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_PCM037); + + return 0; +} + +device_initcall(imx31_devices_init); + +static struct device_d imx31_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 16 * 1024, +}; + +static int imx31_console_init(void) +{ + /* init gpios for serial port */ + imx_iomux_mode(MX31_PIN_RXD1__RXD1); + imx_iomux_mode(MX31_PIN_TXD1__TXD1); + imx_iomux_mode(MX31_PIN_CTS1__CTS1); + imx_iomux_mode(MX31_PIN_RTS1__RTS1); + + register_device(&imx31_serial_device); + return 0; +} + +console_initcall(imx31_console_init); + +#ifdef CONFIG_NAND_IMX_BOOT +void __bare_init nand_boot(void) +{ + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); +} +#endif diff --git a/arch/arm/boards/pcm037/pcm037.dox b/arch/arm/boards/pcm037/pcm037.dox new file mode 100644 index 0000000..b2afdd6 --- /dev/null +++ b/arch/arm/boards/pcm037/pcm037.dox @@ -0,0 +1,11 @@ +/** @page pcm037 Phytec's phyCORE-i.MX31 + +This CPU card is based on a Freescale i.MX31 CPU. The card is shipped with: + +- up to 64MiB NOR type Flash Memory +- up to 2MiB static RAM +- 64MiB NAND type Flash Memory +- SMSC 9217 network controller +- 128MiB synchronous dynamic RAM + +*/ diff --git a/arch/arm/boards/pcm038/Makefile b/arch/arm/boards/pcm038/Makefile new file mode 100644 index 0000000..a681dda --- /dev/null +++ b/arch/arm/boards/pcm038/Makefile @@ -0,0 +1,3 @@ + +obj-y += lowlevel.o pll_init.o +obj-y += pcm038.o diff --git a/arch/arm/boards/pcm038/config.h b/arch/arm/boards/pcm038/config.h new file mode 100644 index 0000000..c2f5e7c --- /dev/null +++ b/arch/arm/boards/pcm038/config.h @@ -0,0 +1,26 @@ +/* + * 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 + */ + +/** + * @file + * @brief Global defintions for the ARM i.MX27 based pcm038 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/pcm038/env/config b/arch/arm/boards/pcm038/env/config new file mode 100644 index 0000000..a8be5c9 --- /dev/null +++ b/arch/arm/boards/pcm038/env/config @@ -0,0 +1,56 @@ +#!/bin/sh + +machine=pcm038 +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 'net', 'nor' or 'nand' +kernel_loc=net +# 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=ttymxc0,115200" + +nor_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nor=3 + +nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nand=7 + +# 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/pcm038/lowlevel.c b/arch/arm/boards/pcm038/lowlevel.c new file mode 100644 index 0000000..0c376f2 --- /dev/null +++ b/arch/arm/boards/pcm038/lowlevel.c @@ -0,0 +1,117 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void __bare_init __naked insdram(void) +{ + uint32_t r; + + PCCR1 |= PCCR1_NFC_BAUDEN; + + /* setup a stack to be able to call imx_nand_load_image() */ + r = STACK_BASE + STACK_SIZE - 12; + __asm__ __volatile__("mov sp, %0" : : "r"(r)); + + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); + + board_init_lowlevel_return(); +} + +#define ESDCTL0_VAL (ESDCTL0_SDE | ESDCTL0_ROW13 | ESDCTL0_COL10) + +void __bare_init __naked board_init_lowlevel(void) +{ + uint32_t r; + int i; + unsigned int *trg, *src; + + /* ahb lite ip interface */ + AIPI1_PSR0 = 0x20040304; + AIPI1_PSR1 = 0xDFFBFCFB; + AIPI2_PSR0 = 0x00000000; + AIPI2_PSR1 = 0xFFFFFFFF; + + /* Skip SDRAM initialization if we run from RAM */ + r = get_pc(); + if (r > 0xa0000000 && r < 0xb0000000) + board_init_lowlevel_return(); + + /* + * DDR on CSD0 + */ + writel(0x00000008, ESDMISC); /* Enable DDR SDRAM operation */ + + DSCR(3) = 0x55555555; /* Set the driving strength */ + DSCR(5) = 0x55555555; + DSCR(6) = 0x55555555; + DSCR(7) = 0x00005005; + DSCR(8) = 0x15555555; + + writel(0x00000004, ESDMISC); /* Initial reset */ + writel(0x006ac73a, ESDCFG0); + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_PRECHARGE, ESDCTL0); /* precharge CSD0 all banks */ + writel(0x00000000, 0xA0000F00); /* CSD0 precharge address (A10 = 1) */ + writel(ESDCTL0_VAL | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0); + + for (i = 0; i < 8; i++) + writel(0, 0xa0000f00); + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0); + + writeb(0xda, 0xa0000033); + writeb(0xff, 0xa1000000); + writel(ESDCTL0_VAL | ESDCTL0_DSIZ_31_0 | ESDCTL0_REF4 | + ESDCTL0_BL | ESDCTL0_SMODE_NORMAL, ESDCTL0); + +#ifdef CONFIG_NAND_IMX_BOOT + /* skip NAND boot if not running from NFC space */ + r = get_pc(); + if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x800) + board_init_lowlevel_return(); + + src = (unsigned int *)IMX_NFC_BASE; + trg = (unsigned int *)TEXT_BASE; + + /* Move ourselves out of NFC SRAM */ + for (i = 0; i < 0x800 / sizeof(int); i++) + *trg++ = *src++; + + /* Jump to SDRAM */ + r = (unsigned int)&insdram; + __asm__ __volatile__("mov pc, %0" : : "r"(r)); +#else + board_init_lowlevel_return(); +#endif +} + diff --git a/arch/arm/boards/pcm038/pcm038.c b/arch/arm/boards/pcm038/pcm038.c new file mode 100644 index 0000000..03794fc --- /dev/null +++ b/arch/arm/boards/pcm038/pcm038.c @@ -0,0 +1,423 @@ +/* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0xC0000000, + .size = 32 * 1024 * 1024, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0xa0000000, + .size = 128 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +static struct memory_platform_data sram_pdata = { + .name = "sram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sram_dev = { + .name = "mem", + .map_base = 0xc8000000, + .size = 512 * 1024, /* Can be up to 2MiB */ + .platform_data = &sram_pdata, +}; + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, + .phy_addr = 1, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = 0x1002b000, + .platform_data = &fec_info, +}; + +static int pcm038_spi_cs[] = {GPIO_PORTD + 28}; + +static struct spi_imx_master pcm038_spi_0_data = { + .chipselect = pcm038_spi_cs, + .num_chipselect = ARRAY_SIZE(pcm038_spi_cs), +}; + +static struct device_d spi_dev = { + .name = "imx_spi", + .map_base = 0x1000e000, + .platform_data = &pcm038_spi_0_data, +}; + +static struct spi_board_info pcm038_spi_board_info[] = { + { + .name = "mc13783", + .max_speed_hz = 3000000, + .bus_num = 0, + .chip_select = 0, + } +}; + +static struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = 0xd8000000, + .platform_data = &nand_info, +}; + +static struct imx_fb_videomode imxfb_mode = { + .mode = { + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 188679, /* in ps (5.3MHz) */ + .hsync_len = 7, + .left_margin = 5, + .right_margin = 16, + .vsync_len = 1, + .upper_margin = 7, + .lower_margin = 9, + }, + /* + * - HSYNC active high + * - VSYNC active high + * - clk notenabled while idle + * - clock not inverted + * - data not inverted + * - data enable low active + * - enable sharp mode + */ + .pcr = 0xF00080C0, + .bpp = 16, +}; + +static struct imx_fb_platform_data pcm038_fb_data = { + .mode = &imxfb_mode, + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00020010, +}; + +static struct device_d imxfb_dev = { + .name = "imxfb", + .map_base = 0x10021000, + .size = 0x1000, + .platform_data = &pcm038_fb_data, +}; + +#ifdef CONFIG_USB +static struct device_d usbh2_dev = { + .name = "ehci", + .map_base = IMX_OTG_BASE + 0x400, + .size = 0x200, +}; + +static void pcm038_usbh_init(void) +{ + uint32_t temp; + + temp = readl(IMX_OTG_BASE + 0x600); + temp &= ~((3 << 21) | 1); + temp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20); + writel(temp, IMX_OTG_BASE + 0x600); + + temp = readl(IMX_OTG_BASE + 0x584); + temp &= ~(3 << 30); + temp |= 2 << 30; + writel(temp, IMX_OTG_BASE + 0x584); + + mdelay(10); + + isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x570), 1); +} +#endif + +#ifdef CONFIG_MMU +static void pcm038_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0xa0000000, 0xa0000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0xb0000000, 0xa0000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + +#if TEXT_BASE & (0x100000 - 1) +#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary +#else + arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); +#endif + mmu_enable(); +} +#else +static void pcm038_mmu_init(void) +{ +} +#endif + +static int pcm038_devices_init(void) +{ + int i; + char *envdev; + + unsigned int mode[] = { + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC | GPIO_PUEN, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + PD25_PF_CSPI1_RDY, + GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT, + PD29_PF_CSPI1_SCLK, + PD30_PF_CSPI1_MISO, + PD31_PF_CSPI1_MOSI, + /* display */ + PA5_PF_LSCLK, + PA6_PF_LD0, + PA7_PF_LD1, + PA8_PF_LD2, + PA9_PF_LD3, + PA10_PF_LD4, + PA11_PF_LD5, + PA12_PF_LD6, + PA13_PF_LD7, + PA14_PF_LD8, + PA15_PF_LD9, + PA16_PF_LD10, + PA17_PF_LD11, + PA18_PF_LD12, + PA19_PF_LD13, + PA20_PF_LD14, + PA21_PF_LD15, + PA22_PF_LD16, + PA23_PF_LD17, + PA24_PF_REV, + PA25_PF_CLS, + PA26_PF_PS, + PA27_PF_SPL_SPR, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA30_PF_CONTRAST, + PA31_PF_OE_ACD, + /* USB host 2 */ + PA0_PF_USBH2_CLK, + PA1_PF_USBH2_DIR, + PA2_PF_USBH2_DATA7, + PA3_PF_USBH2_NXT, + PA4_PF_USBH2_STP, + PD19_AF_USBH2_DATA4, + PD20_AF_USBH2_DATA3, + PD21_AF_USBH2_DATA6, + PD22_AF_USBH2_DATA0, + PD23_AF_USBH2_DATA2, + PD24_AF_USBH2_DATA1, + PD26_AF_USBH2_DATA5, + }; + + pcm038_mmu_init(); + + /* configure 16 bit nor flash on cs0 */ + CS0U = 0x0000CC03; + CS0L = 0xa0330D01; + CS0A = 0x00220800; + + /* configure SRAM on cs1 */ + CS1U = 0x0000d843; + CS1L = 0x22252521; + CS1A = 0x22220a00; + + /* configure SJA1000 on cs4 */ + CS4U = 0x0000DCF6; + CS4L = 0x444A0301; + CS4A = 0x44443302; + + /* initizalize gpios */ + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + + PCCR0 |= PCCR0_CSPI1_EN; + PCCR1 |= PCCR1_PERCLK2_EN; + + gpio_direction_output(GPIO_PORTD | 28, 0); + gpio_set_value(GPIO_PORTD | 28, 0); + spi_register_board_info(pcm038_spi_board_info, ARRAY_SIZE(pcm038_spi_board_info)); + register_device(&spi_dev); + + register_device(&cfi_dev); + register_device(&nand_dev); + register_device(&sdram_dev); + register_device(&sram_dev); + register_device(&imxfb_dev); + +#ifdef CONFIG_USB + pcm038_usbh_init(); + register_device(&usbh2_dev); +#endif + + /* Register the fec device after the PLL re-initialisation + * as the fec depends on the (now higher) ipg clock + */ + register_device(&fec_dev); + + switch ((GPCR & GPCR_BOOT_MASK) >> GPCR_BOOT_SHIFT) { + case GPCR_BOOT_8BIT_NAND_2k: + case GPCR_BOOT_16BIT_NAND_2k: + case GPCR_BOOT_16BIT_NAND_512: + case GPCR_BOOT_8BIT_NAND_512: + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + envdev = "NAND"; + break; + default: + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); + protect_file("/dev/env0", 1); + + envdev = "NOR"; + } + + printf("Using environment in %s Flash\n", envdev); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0xa0000100); + armlinux_set_architecture(MACH_TYPE_PCM038); + + return 0; +} + +device_initcall(pcm038_devices_init); + +static struct device_d pcm038_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static int pcm038_console_init(void) +{ + /* bring PLLs to reset default */ + MPCTL0 = 0x00211803; + SPCTL0 = 0x1002700c; + CSCR = 0x33fc1307; + + register_device(&pcm038_serial_device); + + return 0; +} + +console_initcall(pcm038_console_init); + +extern void *pcm038_pll_init, *pcm038_pll_init_end; + +static int pcm038_power_init(void) +{ + int ret; + void *vram = 0xffff4c00; + void (*pllfunc)(void) = vram; + + printf("initialising PLLs: 0x%p 0x%p\n", &pcm038_pll_init); + + memcpy(vram, &pcm038_pll_init, 0x100); + + console_flush(); + + ret = pmic_power(); + if (ret) { + printf("Failed to initialize PMIC. Will continue with low CPU speed\n"); + return 0; + } + + /* wait for good power level */ + udelay(100000); + + pllfunc(); + + /* clock gating enable */ + GPCR = 0x00050f08; + + PCDR0 = 0x130410c3; + PCDR1 = 0x09030911; + + /* Clocks have changed. Notify clients */ + clock_notifier_call_chain(); + + return 0; +} + +late_initcall(pcm038_power_init); + diff --git a/arch/arm/boards/pcm038/pcm038.dox b/arch/arm/boards/pcm038/pcm038.dox new file mode 100644 index 0000000..9b17674 --- /dev/null +++ b/arch/arm/boards/pcm038/pcm038.dox @@ -0,0 +1,8 @@ +/** @page pcm038 Phytec's phyCORE-i.MX27 + +This CPU card is based on a Freescale i.MX27 CPU. The card is shipped with: + +- up to 32MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM + +*/ diff --git a/arch/arm/boards/pcm038/pll_init.S b/arch/arm/boards/pcm038/pll_init.S new file mode 100644 index 0000000..0c1ff13 --- /dev/null +++ b/arch/arm/boards/pcm038/pll_init.S @@ -0,0 +1,48 @@ +#include +#include +#include +#include + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +#define CSCR_VAL CSCR_USB_DIV(3) | \ + CSCR_SD_CNT(3) | \ + CSCR_MSHC_SEL | \ + CSCR_H264_SEL | \ + CSCR_SSI1_SEL | \ + CSCR_SSI2_SEL | \ + CSCR_MCU_SEL | \ + CSCR_ARM_SRC_MPLL | \ + CSCR_SP_SEL | \ + CSCR_ARM_DIV(0) | \ + CSCR_FPM_EN | \ + CSCR_SPEN | \ + CSCR_MPEN | \ + CSCR_AHB_DIV(1) + +ENTRY(pcm038_pll_init) + + writel(IMX_PLL_PD(0) | + IMX_PLL_MFD(51) | + IMX_PLL_MFI(7) | + IMX_PLL_MFN(35), MPCTL0) /* 399 MHz */ + + writel(IMX_PLL_PD(1) | + IMX_PLL_MFD(12) | + IMX_PLL_MFI(9) | + IMX_PLL_MFN(3), SPCTL0) /* SPLL = 2 * 26 * 4.61538 MHz = 240 MHz */ + + writel(CSCR_VAL | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR) + + ldr r2, =16000 +1: + subs r2, r2, #1 + nop + bcs 1b + + mov pc, lr +ENDPROC(pcm038_pll_init) + diff --git a/arch/arm/boards/pcm043/Makefile b/arch/arm/boards/pcm043/Makefile new file mode 100644 index 0000000..6753bbe --- /dev/null +++ b/arch/arm/boards/pcm043/Makefile @@ -0,0 +1,24 @@ +# +# (C) Copyright 2007 Juergen Beisert +# +# 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 +# + +obj-y += lowlevel.o +obj-y += pcm043.o diff --git a/arch/arm/boards/pcm043/config.h b/arch/arm/boards/pcm043/config.h new file mode 100644 index 0000000..0e3b175 --- /dev/null +++ b/arch/arm/boards/pcm043/config.h @@ -0,0 +1,31 @@ +/* + * (C) Copyright 2007 Juergen Beisert + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * Definitions related to passing arguments to kernel. + */ + +#define CONFIG_MX35_HCLK_FREQ 24000000 + +#endif + +/* nothing to do here yet */ diff --git a/arch/arm/boards/pcm043/env/config b/arch/arm/boards/pcm043/env/config new file mode 100644 index 0000000..212b6a9 --- /dev/null +++ b/arch/arm/boards/pcm043/env/config @@ -0,0 +1,58 @@ +#!/bin/sh + +machine=pcm043 +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 'net', 'nor' or 'nand' +kernel_loc=net +# 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=ttymxc0,115200" + +bootargs="$bootargs video=mx3fb:CTP-CLAA070LC0ACW" + +nor_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nor=3 + +nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nand=7 + +# 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/pcm043/lowlevel.c b/arch/arm/boards/pcm043/lowlevel.c new file mode 100644 index 0000000..9eff5a6 --- /dev/null +++ b/arch/arm/boards/pcm043/lowlevel.c @@ -0,0 +1,214 @@ +/* + * + * (c) 2007 Pengutronix, Sascha Hauer + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Assuming 24MHz input clock */ +#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) +#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) +#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) + +static void __bare_init __naked insdram(void) +{ + uint32_t r; + + /* Speed up NAND controller by adjusting the NFC divider */ + r = readl(IMX_CCM_BASE + CCM_PDR4); + r &= ~(0xf << 28); + r |= 0x1 << 28; + writel(r, IMX_CCM_BASE + CCM_PDR4); + + /* setup a stack to be able to call imx_nand_load_image() */ + r = STACK_BASE + STACK_SIZE - 12; + __asm__ __volatile__("mov sp, %0" : : "r"(r)); + + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); + + board_init_lowlevel_return(); +} + +void __bare_init __naked board_init_lowlevel(void) +{ + uint32_t r, s; + unsigned long ccm_base = IMX_CCM_BASE; + unsigned long iomuxc_base = IMX_IOMUXC_BASE; + unsigned int *trg, *src; + int i; + + r = get_cr(); + r |= CR_Z; /* Flow prediction (Z) */ + r |= CR_U; /* unaligned accesses */ + r |= CR_FI; /* Low Int Latency */ + + __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1":"=r"(s)); + s |= 0x7; + __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1" : : "r"(s)); + + set_cr(r); + + r = 0; + __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); + + /* + * Branch predicition is now enabled. Flush the BTAC to ensure a valid + * starting point. Don't flush BTAC while it is disabled to avoid + * ARM1136 erratum 408023. + */ + __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 6" : : "r"(r)); + + /* invalidate I cache and D cache */ + __asm__ __volatile__("mcr p15, 0, %0, c7, c7, 0" : : "r"(r)); + + /* invalidate TLBs */ + __asm__ __volatile__("mcr p15, 0, %0, c8, c7, 0" : : "r"(r)); + + /* Drain the write buffer */ + __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4" : : "r"(r)); + + /* Also setup the Peripheral Port Remap register inside the core */ + r = 0x40000015; /* start from AIPS 2GB region */ + __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); + + /* + * End of ARM1136 init + */ + + writel(0x003F4208, ccm_base + CCM_CCMR); + + /* Set MPLL , arm clock and ahb clock*/ + writel(MPCTL_PARAM_532, ccm_base + CCM_MPCTL); + + writel(PPCTL_PARAM_300, ccm_base + CCM_PPCTL); + writel(0x00001000, ccm_base + CCM_PDR0); + + r = readl(ccm_base + CCM_CGR0); + r |= 0x00300000; + writel(r, ccm_base + CCM_CGR0); + + r = readl(ccm_base + CCM_CGR1); + r |= 0x00000C00; + r |= 0x00000003; + writel(r, ccm_base + CCM_CGR1); + + r = readl(IMX_L2CC_BASE + L2X0_AUX_CTRL); + r |= 0x1000; + writel(r, IMX_L2CC_BASE + L2X0_AUX_CTRL); + + /* Skip SDRAM initialization if we run from RAM */ + r = get_pc(); + if (r > 0x80000000 && r < 0x90000000) + board_init_lowlevel_return(); + + /* Set DDR Type to SDRAM, drive strength workaround * + * 0x00000000 MDDR * + * 0x00000800 3,3V SDRAM */ + + r = 0x00000800; + writel(r, iomuxc_base + 0x794); + writel(r, iomuxc_base + 0x798); + writel(r, iomuxc_base + 0x79c); + writel(r, iomuxc_base + 0x7a0); + writel(r, iomuxc_base + 0x7a4); + + /* MDDR init, enable mDDR*/ + writel(0x00000304, ESDMISC); /* was 0x00000004 */ + + /* set timing paramters */ + writel(0x00255417, ESDCFG0); + /* select Precharge-All mode */ + writel(0x92220000, ESDCTL0); + /* Precharge-All */ + writel(0x12345678, IMX_SDRAM_CS0 + 0x400); + + /* select Load-Mode-Register mode */ + writel(0xB8001000, ESDCTL0); + /* Load reg EMR2 */ + writeb(0xda, 0x84000000); + /* Load reg EMR3 */ + writeb(0xda, 0x86000000); + /* Load reg EMR1 -- enable DLL */ + writeb(0xda, 0x82000400); + /* Load reg MR -- reset DLL */ + writeb(0xda, 0x80000333); + + /* select Precharge-All mode */ + writel(0x92220000, ESDCTL0); + /* Precharge-All */ + writel(0x12345678, IMX_SDRAM_CS0 + 0x400); + + /* select Manual-Refresh mode */ + writel(0xA2220000, ESDCTL0); + /* Manual-Refresh 2 times */ + writel(0x87654321, IMX_SDRAM_CS0); + writel(0x87654321, IMX_SDRAM_CS0); + + /* select Load-Mode-Register mode */ + writel(0xB2220000, ESDCTL0); + /* Load reg MR -- CL3, BL8, end DLL reset */ + writeb(0xda, 0x80000233); + /* Load reg EMR1 -- OCD default */ + writeb(0xda, 0x82000780); + /* Load reg EMR1 -- OCD exit */ + writeb(0xda, 0x82000400); + + /* select normal-operation mode + * DSIZ32-bit, BL8, COL10-bit, ROW13-bit + * disable PWT & PRCT + * disable Auto-Refresh */ + writel(0x82220080, ESDCTL0); + + /* enable Auto-Refresh */ + writel(0x82228080, ESDCTL0); + /* enable Auto-Refresh */ + writel(0x00002000, ESDCTL1); + +#ifdef CONFIG_NAND_IMX_BOOT + /* skip NAND boot if not running from NFC space */ + r = get_pc(); + if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x800) + board_init_lowlevel_return(); + + src = (unsigned int *)IMX_NFC_BASE; + trg = (unsigned int *)TEXT_BASE; + + /* Move ourselves out of NFC SRAM */ + for (i = 0; i < 0x800 / sizeof(int); i++) + *trg++ = *src++; + + /* Jump to SDRAM */ + r = (unsigned int)&insdram; + __asm__ __volatile__("mov pc, %0" : : "r"(r)); +#else + board_init_lowlevel_return(); +#endif +} + diff --git a/arch/arm/boards/pcm043/pcm043.c b/arch/arm/boards/pcm043/pcm043.c new file mode 100644 index 0000000..dd178ed --- /dev/null +++ b/arch/arm/boards/pcm043/pcm043.c @@ -0,0 +1,392 @@ +/* + * (C) 2007 Pengutronix, Sascha Hauer + * (C) 2009 Pengutronix, Juergen Beisert + * + * 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 + * + * Board support for Phytec's, i.MX35 based CPU card, called: PCM043 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CYG_MACRO_START +#define CYG_MACRO_END +#define ARM_MMU_FIRST_LEVEL_SECTION_ID 0x2 +#define ARM_MMU_FIRST_LEVEL_DESCRIPTOR_ADDRESS(ttb_base, table_index) \ + (unsigned long *)((unsigned long)(ttb_base) + ((table_index) << 2)) + +/* + * Up to 32MiB NOR type flash, connected to + * CS line 0, data width is 16 bit + */ +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = IMX_CS0_BASE, + .size = 32 * 1024 * 1024, /* area size */ +}; + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = IMX_FEC_BASE, + .platform_data = &fec_info, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram0_dev = { + .name = "mem", + .map_base = IMX_SDRAM_CS0, + .size = 128 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, + .flash_bbt = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = IMX_NFC_BASE, + .platform_data = &nand_info, +}; + +#ifdef CONFIG_PCM043_DISPLAY_SHARP +static const struct fb_videomode pcm043_fb_mode = { + /* 240x320 @ 60 Hz */ + .name = "Sharp-LQ035Q7", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 185925, + .left_margin = 9, + .right_margin = 16, + .upper_margin = 7, + .lower_margin = 9, + .hsync_len = 1, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; +#else +static const struct fb_videomode pcm043_fb_mode = { + /* 240x320 @ 60 Hz */ + .name = "TX090", + .refresh = 60, + .xres = 240, + .yres = 320, + .pixclock = 38255, + .left_margin = 144, + .right_margin = 0, + .upper_margin = 7, + .lower_margin = 40, + .hsync_len = 96, + .vsync_len = 1, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, + .vmode = FB_VMODE_NONINTERLACED, + .flag = 0, +}; +#endif + +static struct imx_ipu_fb_platform_data ipu_fb_data = { + .mode = &pcm043_fb_mode, + .bpp = 16, +}; + +static struct device_d imx_ipu_fb_dev = { + .name = "imx-ipu-fb", + .map_base = 0x53fc0000, + .size = 0x1000, + .platform_data = &ipu_fb_data, +}; + +#ifdef CONFIG_MMU +static int pcm043_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + +#if TEXT_BASE & (0x100000 - 1) +#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary +#else + arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); +#endif + + mmu_enable(); + +#ifdef CONFIG_CACHE_L2X0 + l2x0_init((void __iomem *)0x30000000, 0x00030024, 0x00000000); +#endif + return 0; +} +postcore_initcall(pcm043_mmu_init); +#endif + +static int imx35_devices_init(void) +{ + uint32_t reg; + + /* CS0: Nor Flash */ + writel(0x0000cf03, CSCR_U(0)); + writel(0x10000d03, CSCR_L(0)); + writel(0x00720900, CSCR_A(0)); + + reg = readl(IMX_CCM_BASE + CCM_RCSR); + /* some fuses provide us vital information about connected hardware */ + if (reg & 0x20000000) + nand_info.width = 2; /* 16 bit */ + else + nand_info.width = 1; /* 8 bit */ + + register_device(&fec_dev); + /* + * This platform supports NOR and NAND + */ + register_device(&nand_dev); + register_device(&cfi_dev); + + if ((reg & 0xc00) == 0x800) { /* reset mode: external boot */ + switch ( (reg >> 25) & 0x3) { + case 0x01: /* NAND is the source */ + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + break; + + case 0x00: /* NOR is the source */ + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); /* ourself */ + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); /* environment */ + protect_file("/dev/env0", 1); + break; + } + } + + register_device(&sdram0_dev); + register_device(&imx_ipu_fb_dev); + + armlinux_add_dram(&sdram0_dev); + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_PCM043); + + return 0; +} + +device_initcall(imx35_devices_init); + +static struct device_d imx35_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 16 * 1024, +}; + +static struct pad_desc pcm043_pads[] = { + MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, + MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, + MX35_PAD_FEC_RX_DV__FEC_RX_DV, + MX35_PAD_FEC_COL__FEC_COL, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_TX_EN__FEC_TX_EN, + MX35_PAD_FEC_MDC__FEC_MDC, + MX35_PAD_FEC_MDIO__FEC_MDIO, + MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, + MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, + MX35_PAD_FEC_CRS__FEC_CRS, + MX35_PAD_FEC_RDATA0__FEC_RDATA_0, + MX35_PAD_FEC_TDATA0__FEC_TDATA_0, + MX35_PAD_FEC_RDATA1__FEC_RDATA_1, + MX35_PAD_FEC_TDATA1__FEC_TDATA_1, + MX35_PAD_FEC_RDATA2__FEC_RDATA_2, + MX35_PAD_FEC_TDATA2__FEC_TDATA_2, + MX35_PAD_FEC_RDATA3__FEC_RDATA_3, + MX35_PAD_FEC_TDATA3__FEC_TDATA_3, + MX35_PAD_RXD1__UART1_RXD_MUX, + MX35_PAD_TXD1__UART1_TXD_MUX, + MX35_PAD_RTS1__UART1_RTS, + MX35_PAD_CTS1__UART1_CTS, + MX35_PAD_I2C1_CLK__I2C1_SCL, + MX35_PAD_I2C1_DAT__I2C1_SDA +}; + +static int imx35_console_init(void) +{ + mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads)); + + register_device(&imx35_serial_device); + return 0; +} + +console_initcall(imx35_console_init); + +static int pcm043_core_setup(void) +{ + u32 tmp; + + /* AIPS setup - Only setup MPROTx registers. The PACR default values are good.*/ + /* + * Set all MPROTx to be non-bufferable, trusted for R/W, + * not forced to user-mode. + */ + writel(0x77777777, IMX_AIPS1_BASE); + writel(0x77777777, IMX_AIPS1_BASE + 0x4); + writel(0x77777777, IMX_AIPS2_BASE); + writel(0x77777777, IMX_AIPS2_BASE + 0x4); + + /* + * Clear the on and off peripheral modules Supervisor Protect bit + * for SDMA to access them. Did not change the AIPS control registers + * (offset 0x20) access type + */ + writel(0x0, IMX_AIPS1_BASE + 0x40); + writel(0x0, IMX_AIPS1_BASE + 0x44); + writel(0x0, IMX_AIPS1_BASE + 0x48); + writel(0x0, IMX_AIPS1_BASE + 0x4C); + tmp = readl(IMX_AIPS1_BASE + 0x50); + tmp &= 0x00FFFFFF; + writel(tmp, IMX_AIPS1_BASE + 0x50); + + writel(0x0, IMX_AIPS2_BASE + 0x40); + writel(0x0, IMX_AIPS2_BASE + 0x44); + writel(0x0, IMX_AIPS2_BASE + 0x48); + writel(0x0, IMX_AIPS2_BASE + 0x4C); + tmp = readl(IMX_AIPS2_BASE + 0x50); + tmp &= 0x00FFFFFF; + writel(tmp, IMX_AIPS2_BASE + 0x50); + + /* MAX (Multi-Layer AHB Crossbar Switch) setup */ + + /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ +#define MAX_PARAM1 0x00302154 + writel(MAX_PARAM1, IMX_MAX_BASE + 0x0); /* for S0 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x100); /* for S1 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x200); /* for S2 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x300); /* for S3 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x400); /* for S4 */ + + /* SGPCR - always park on last master */ + writel(0x10, IMX_MAX_BASE + 0x10); /* for S0 */ + writel(0x10, IMX_MAX_BASE + 0x110); /* for S1 */ + writel(0x10, IMX_MAX_BASE + 0x210); /* for S2 */ + writel(0x10, IMX_MAX_BASE + 0x310); /* for S3 */ + writel(0x10, IMX_MAX_BASE + 0x410); /* for S4 */ + + /* MGPCR - restore default values */ + writel(0x0, IMX_MAX_BASE + 0x800); /* for M0 */ + writel(0x0, IMX_MAX_BASE + 0x900); /* for M1 */ + writel(0x0, IMX_MAX_BASE + 0xa00); /* for M2 */ + writel(0x0, IMX_MAX_BASE + 0xb00); /* for M3 */ + writel(0x0, IMX_MAX_BASE + 0xc00); /* for M4 */ + writel(0x0, IMX_MAX_BASE + 0xd00); /* for M5 */ + + writel(0x0000DCF6, CSCR_U(0)); /* CS0: NOR Flash */ + writel(0x444A4541, CSCR_L(0)); + writel(0x44443302, CSCR_A(0)); + + /* + * M3IF Control Register (M3IFCTL) + * MRRP[0] = L2CC0 not on priority list (0 << 0) = 0x00000000 + * MRRP[1] = MAX1 not on priority list (0 << 0) = 0x00000000 + * MRRP[2] = L2CC1 not on priority list (0 << 0) = 0x00000000 + * MRRP[3] = USB not on priority list (0 << 0) = 0x00000000 + * MRRP[4] = SDMA not on priority list (0 << 0) = 0x00000000 + * MRRP[5] = GPU not on priority list (0 << 0) = 0x00000000 + * MRRP[6] = IPU1 on priority list (1 << 6) = 0x00000040 + * MRRP[7] = IPU2 not on priority list (0 << 0) = 0x00000000 + * ------------ + * 0x00000040 + */ + writel(0x40, IMX_M3IF_BASE); + + return 0; +} + +core_initcall(pcm043_core_setup); + +#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) +#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) + +static int do_cpufreq(struct command *cmdtp, int argc, char *argv[]) +{ + unsigned long freq; + + if (argc != 2) + return COMMAND_ERROR_USAGE; + + freq = simple_strtoul(argv[1], NULL, 0); + + switch (freq) { + case 399: + writel(MPCTL_PARAM_399, IMX_CCM_BASE + CCM_MPCTL); + break; + case 532: + writel(MPCTL_PARAM_532, IMX_CCM_BASE + CCM_MPCTL); + break; + default: + return COMMAND_ERROR_USAGE; + } + + printf("Switched CPU frequency to %dMHz\n", freq); + + return 0; +} + +static const __maybe_unused char cmd_cpufreq_help[] = +"Usage: cpufreq 399|532\n" +"\n" +"Set CPU frequency to MHz\n"; + +BAREBOX_CMD_START(cpufreq) + .cmd = do_cpufreq, + .usage = "adjust CPU frequency", + BAREBOX_CMD_HELP(cmd_cpufreq_help) +BAREBOX_CMD_END + diff --git a/arch/arm/boards/pcm043/pcm043.dox b/arch/arm/boards/pcm043/pcm043.dox new file mode 100644 index 0000000..c6715ff --- /dev/null +++ b/arch/arm/boards/pcm043/pcm043.dox @@ -0,0 +1,28 @@ +/** @page pcm043 Phytec's phyCORE-i.MX35 + +This CPU card is based on a Freescale i.MX35 CPU. The card is shipped with: + + +FIXME: +- up to 64 MiB NOR type Flash Memory +- up to 2 MiB static RAM +- 1 GiB or 2 GiB NAND type Flash Memory + - Micron NAND 1 GiB 3,3V 8-bit + - 256 kiB block size + - ? kiB page size + - Manufacturer ID: 0x2c + - Device ID: 0xd3 + - Samsung K9K8G08, 1 GiB + - 128 kiB block size + - 2 kiB page size + - Manufacturer ID: ? + - Device ID: ? + - ST NAND08G, 1 GiB + - 128 kiB block size + - 2 kiB page size + - Manufacturer ID: ? + - Device ID: ? +- 128MiB synchronous dynamic RAM + + +*/ diff --git a/arch/arm/boards/phycard-i.MX27/Makefile b/arch/arm/boards/phycard-i.MX27/Makefile new file mode 100644 index 0000000..fd52350 --- /dev/null +++ b/arch/arm/boards/phycard-i.MX27/Makefile @@ -0,0 +1,3 @@ + +obj-y += lowlevel_init.o +obj-y += pca100.o diff --git a/arch/arm/boards/phycard-i.MX27/config.h b/arch/arm/boards/phycard-i.MX27/config.h new file mode 100644 index 0000000..c2f5e7c --- /dev/null +++ b/arch/arm/boards/phycard-i.MX27/config.h @@ -0,0 +1,26 @@ +/* + * 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 + */ + +/** + * @file + * @brief Global defintions for the ARM i.MX27 based pcm038 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/phycard-i.MX27/env/config b/arch/arm/boards/phycard-i.MX27/env/config new file mode 100644 index 0000000..d0670de --- /dev/null +++ b/arch/arm/boards/phycard-i.MX27/env/config @@ -0,0 +1,54 @@ +#!/bin/sh + +machine=pca100 +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 'net', 'nor' or 'nand' +kernel_loc=net +# 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=ttymxc0,115200" + +nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nand=7 + +# 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/phycard-i.MX27/lowlevel_init.S b/arch/arm/boards/phycard-i.MX27/lowlevel_init.S new file mode 100644 index 0000000..9349581 --- /dev/null +++ b/arch/arm/boards/phycard-i.MX27/lowlevel_init.S @@ -0,0 +1,129 @@ +/* + * For clock initialization, see chapter 3 of the "MCIMX27 Multimedia + * Applications Processor Reference Manual, Rev. 0.2". + * + */ + +#include +#include +#include + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + + +#define ESDCTL0_VAL (ESDCTL0_SDE | ESDCTL0_ROW13 | ESDCTL0_COL10) + +.macro sdram_init + /* + * DDR on CSD0 + */ + writel(0x00000008, ESDMISC) /* Enable DDR SDRAM operation */ + + writel(0x55555555, DSCR(3)) /* Set the driving strength */ + writel(0x55555555, DSCR(5)) + writel(0x55555555, DSCR(6)) + writel(0x00005005, DSCR(7)) + writel(0x15555555, DSCR(8)) + + writel(0x00000004, ESDMISC) /* Initial reset */ + writel(0x006ac73a, ESDCFG0) + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_PRECHARGE, ESDCTL0) /* precharge CSD0 all banks */ + writel(0x00000000, 0xA0000F00) /* CSD0 precharge address (A10 = 1) */ + writel(ESDCTL0_VAL | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0) + + ldr r0, =0xa0000f00 + mov r1, #0 + mov r2, #8 +1: + str r1, [r0] + subs r2, #1 + bne 1b + + writel(ESDCTL0_VAL | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0) + ldr r0, =0xA0000033 + mov r1, #0xda + strb r1, [r0] + ldr r0, =0xA1000000 + mov r1, #0xff + strb r1, [r0] + writel(ESDCTL0_VAL | ESDCTL0_DSIZ_31_0 | ESDCTL0_REF4 | ESDCTL0_BL | ESDCTL0_SMODE_NORMAL, ESDCTL0) +.endm + + .section ".text_bare_init","ax" + +.globl board_init_lowlevel +board_init_lowlevel: + + mov r10, lr + + /* ahb lite ip interface */ + writel(0x20040304, AIPI1_PSR0) + writel(0xDFFBFCFB, AIPI1_PSR1) + writel(0x00000000, AIPI2_PSR0) + writel(0xFFFFFFFF, AIPI2_PSR1) + + /* skip sdram initialization if we run from ram */ + cmp pc, #0xa0000000 + bls 1f + cmp pc, #0xc0000000 + bhi 1f + + mov pc,r10 + +1: + writel(IMX_PLL_PD(0) | + IMX_PLL_MFD(51) | + IMX_PLL_MFI(7) | + IMX_PLL_MFN(35), MPCTL0) /* 399 MHz */ + + writel(IMX_PLL_PD(1) | + IMX_PLL_MFD(12) | + IMX_PLL_MFI(9) | + IMX_PLL_MFN(3), SPCTL0) /* SPLL = 2 * 26 * 4.61538 MHz = 240 MHz */ + + writel(CSCR_MPLL_RESTART | CSCR_SPLL_RESTART | CSCR_ARM_SRC_MPLL | + CSCR_MCU_SEL | CSCR_SP_SEL | CSCR_FPM_EN | CSCR_MPEN | + CSCR_SPEN | CSCR_ARM_DIV(0) | CSCR_AHB_DIV(1) | CSCR_USB_DIV(3) | + CSCR_SD_CNT(3) | CSCR_SSI2_SEL | CSCR_SSI1_SEL | CSCR_H264_SEL | + CSCR_MSHC_SEL, CSCR) + + sdram_init + +#ifdef CONFIG_NAND_IMX_BOOT + ldr sp, =0xa0f00000 /* Setup a temporary stack in SDRAM */ + + ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ + ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ + + /* skip NAND boot if not running from NFC space */ + cmp pc, r0 + bls ret + cmp pc, r2 + bhi ret + + /* Move ourselves out of NFC SRAM */ + ldr r1, =TEXT_BASE + +copy_loop: + ldmia r0!, {r3-r9} /* copy from source address [r0] */ + stmia r1!, {r3-r9} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop + + ldr pc, =1f /* Jump to SDRAM */ +1: + bl nand_boot /* Load barebox from NAND Flash */ + + ldr r1, =IMX_NFC_BASE - TEXT_BASE + sub r10, r10, r1 /* adjust return address from NFC SRAM */ + /* to SDRAM */ + +#endif /* CONFIG_NAND_IMX_BOOT */ + +ret: + mov pc,r10 + diff --git a/arch/arm/boards/phycard-i.MX27/pca100.c b/arch/arm/boards/phycard-i.MX27/pca100.c new file mode 100644 index 0000000..ce59960 --- /dev/null +++ b/arch/arm/boards/phycard-i.MX27/pca100.c @@ -0,0 +1,239 @@ + /* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0xa0000000, + .size = 128 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +static struct fec_platform_data fec_info = { + .xcv_type = MII100, + .phy_addr = 1, +}; + +static struct device_d fec_dev = { + .name = "fec_imx", + .map_base = 0x1002b000, + .platform_data = &fec_info, +}; + +struct imx_nand_platform_data nand_info = { + .width = 1, + .hw_ecc = 1, +}; + +static struct device_d nand_dev = { + .name = "imx_nand", + .map_base = 0xd8000000, + .platform_data = &nand_info, +}; + +#ifdef CONFIG_USB +static struct device_d usbh2_dev = { + .name = "ehci", + .map_base = IMX_OTG_BASE + 0x400, + .size = 0x200, +}; + +static void pca100_usbh_init(void) +{ + uint32_t temp; + + temp = readl(IMX_OTG_BASE + 0x600); + temp &= ~((3 << 21) | 1); + temp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 11) | (1 << 20); + writel(temp, IMX_OTG_BASE + 0x600); + + temp = readl(IMX_OTG_BASE + 0x584); + temp &= ~(3 << 30); + temp |= 2 << 30; + writel(temp, IMX_OTG_BASE + 0x584); + + mdelay(10); + + gpio_direction_output(GPIO_PORTB + 24, 0); + + mdelay(10); + + isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x570), 1); +} +#endif + +#ifdef CONFIG_MMU +static void pca100_mmu_init(void) +{ + mmu_init(); + + arm_create_section(0xa0000000, 0xa0000000, 128, PMD_SECT_DEF_CACHED); + arm_create_section(0xb0000000, 0xa0000000, 128, PMD_SECT_DEF_UNCACHED); + + setup_dma_coherent(0x10000000); + +#if TEXT_BASE & (0x100000 - 1) +#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary +#else + arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); +#endif + mmu_enable(); +} +#else +static void pca100_mmu_init(void) +{ +} +#endif + +static int pca100_devices_init(void) +{ + int i; + struct device_d *nand; + + unsigned int mode[] = { + PD0_AIN_FEC_TXD0, + PD1_AIN_FEC_TXD1, + PD2_AIN_FEC_TXD2, + PD3_AIN_FEC_TXD3, + PD4_AOUT_FEC_RX_ER, + PD5_AOUT_FEC_RXD1, + PD6_AOUT_FEC_RXD2, + PD7_AOUT_FEC_RXD3, + PD8_AF_FEC_MDIO, + PD9_AIN_FEC_MDC | GPIO_PUEN, + PD10_AOUT_FEC_CRS, + PD11_AOUT_FEC_TX_CLK, + PD12_AOUT_FEC_RXD0, + PD13_AOUT_FEC_RX_DV, + PD14_AOUT_FEC_RX_CLK, + PD15_AOUT_FEC_COL, + PD16_AIN_FEC_TX_ER, + PF23_AIN_FEC_TX_EN, + PE12_PF_UART1_TXD, + PE13_PF_UART1_RXD, + PE14_PF_UART1_CTS, + PE15_PF_UART1_RTS, + PD25_PF_CSPI1_RDY, + PD26_PF_CSPI1_SS2, + PD27_PF_CSPI1_SS1, + PD28_PF_CSPI1_SS0, + PD29_PF_CSPI1_SCLK, + PD30_PF_CSPI1_MISO, + PD31_PF_CSPI1_MOSI, + /* USB host 2 */ + PA0_PF_USBH2_CLK, + PA1_PF_USBH2_DIR, + PA2_PF_USBH2_DATA7, + PA3_PF_USBH2_NXT, + PA4_PF_USBH2_STP, + PD19_AF_USBH2_DATA4, + PD20_AF_USBH2_DATA3, + PD21_AF_USBH2_DATA6, + PD22_AF_USBH2_DATA0, + PD23_AF_USBH2_DATA2, + PD24_AF_USBH2_DATA1, + PD26_AF_USBH2_DATA5, + }; + + /* disable the usb phys */ + imx_gpio_mode((GPIO_PORTB | 23) | GPIO_GPIO | GPIO_IN); + gpio_direction_output(GPIO_PORTB + 23, 1); + imx_gpio_mode((GPIO_PORTB | 24) | GPIO_GPIO | GPIO_IN); + gpio_direction_output(GPIO_PORTB + 24, 1); + + /* initizalize gpios */ + for (i = 0; i < ARRAY_SIZE(mode); i++) + imx_gpio_mode(mode[i]); + + register_device(&nand_dev); + register_device(&sdram_dev); + register_device(&fec_dev); + + PCCR1 |= PCCR1_PERCLK2_EN; + +#ifdef CONFIG_USB + pca100_usbh_init(); + register_device(&usbh2_dev); +#endif + + nand = get_device_by_name("nand0"); + devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0xa0000100); + armlinux_set_architecture(2149); + + return 0; +} + +device_initcall(pca100_devices_init); + +static struct device_d pca100_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static int pca100_console_init(void) +{ + pca100_mmu_init(); + register_device(&pca100_serial_device); + return 0; +} + +console_initcall(pca100_console_init); + +#ifdef CONFIG_NAND_IMX_BOOT +void __bare_init nand_boot(void) +{ + imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); +} +#endif + diff --git a/arch/arm/boards/phycard-i.MX27/pca100.dox b/arch/arm/boards/phycard-i.MX27/pca100.dox new file mode 100644 index 0000000..9b17674 --- /dev/null +++ b/arch/arm/boards/phycard-i.MX27/pca100.dox @@ -0,0 +1,8 @@ +/** @page pcm038 Phytec's phyCORE-i.MX27 + +This CPU card is based on a Freescale i.MX27 CPU. The card is shipped with: + +- up to 32MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM + +*/ diff --git a/arch/arm/boards/pm9263/Makefile b/arch/arm/boards/pm9263/Makefile new file mode 100644 index 0000000..eb072c0 --- /dev/null +++ b/arch/arm/boards/pm9263/Makefile @@ -0,0 +1 @@ +obj-y += init.o diff --git a/arch/arm/boards/pm9263/config.h b/arch/arm/boards/pm9263/config.h new file mode 100644 index 0000000..9a9c5cd --- /dev/null +++ b/arch/arm/boards/pm9263/config.h @@ -0,0 +1,126 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ + +#define MASTER_PLL_DIV 6 +#define MASTER_PLL_MUL 65 +#define MAIN_PLL_DIV 2 /* 2 or 4 */ + +/* clocks */ +#define CONFIG_SYS_MOR_VAL \ + (AT91_PMC_MOSCEN | \ + (255 << 8)) /* Main Oscillator Start-up Time */ +#define CONFIG_SYS_PLLAR_VAL \ + (AT91_PMC_PLLA_WR_ERRATA | /* Bit 29 must be 1 when prog */ \ + AT91_PMC_OUT | \ + AT91_PMC_PLLCOUNT | /* PLL Counter */ \ + (2 << 28) | /* PLL Clock Frequency Range */ \ + ((MASTER_PLL_MUL - 1) << 16) | (MASTER_PLL_DIV)) + +#if (MAIN_PLL_DIV == 2) +/* PCK/2 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR1_VAL \ + (AT91_PMC_CSS_SLOW | \ + AT91_PMC_PRES_1 | \ + AT91SAM9_PMC_MDIV_2 | \ + AT91_PMC_PDIV_1) +/* PCK/2 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR2_VAL \ + (AT91_PMC_CSS_PLLA | \ + AT91_PMC_PRES_1 | \ + AT91SAM9_PMC_MDIV_2 | \ + AT91_PMC_PDIV_1) +#else +/* PCK/4 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR1_VAL \ + (AT91_PMC_CSS_SLOW | \ + AT91_PMC_PRES_1 | \ + AT91RM9200_PMC_MDIV_3 | \ + AT91_PMC_PDIV_1) +/* PCK/4 = MCK Master Clock from PLLA */ +#define CONFIG_SYS_MCKR2_VAL \ + (AT91_PMC_CSS_PLLA | \ + AT91_PMC_PRES_1 | \ + AT91RM9200_PMC_MDIV_3 | \ + AT91_PMC_PDIV_1) +#endif +/* define PDC[31:16] as DATA[31:16] */ +#define CONFIG_SYS_PIOD_PDR_VAL1 0xFFFF0000 +/* no pull-up for D[31:16] */ +#define CONFIG_SYS_PIOD_PPUDR_VAL 0xFFFF0000 +/* EBI0_CSA, CS1 SDRAM, CS3 NAND Flash, 3.3V memories */ +#define CONFIG_SYS_MATRIX_EBI0CSA_VAL \ + (AT91_MATRIX_EBI0_DBPUC | AT91_MATRIX_EBI0_VDDIOMSEL_3_3V | \ + AT91_MATRIX_EBI0_CS1A_SDRAMC) + +/* SDRAM */ +/* SDRAMC_MR Mode register */ +#define CONFIG_SYS_SDRC_MR_VAL1 0 +/* SDRAMC_TR - Refresh Timer register */ +#define CONFIG_SYS_SDRC_TR_VAL1 0x3AA +/* SDRAMC_CR - Configuration register*/ +#define CONFIG_SYS_SDRC_CR_VAL \ + (AT91_SDRAMC_NC_9 | \ + AT91_SDRAMC_NR_13 | \ + AT91_SDRAMC_NB_4 | \ + AT91_SDRAMC_CAS_2 | \ + AT91_SDRAMC_DBW_32 | \ + (2 << 8) | /* tWR - Write Recovery Delay */ \ + (7 << 12) | /* tRC - Row Cycle Delay */ \ + (2 << 16) | /* tRP - Row Precharge Delay */ \ + (2 << 20) | /* tRCD - Row to Column Delay */ \ + (5 << 24) | /* tRAS - Active to Precharge Delay */ \ + (8 << 28)) /* tXSR - Exit Self Refresh to Active Delay */ + +/* Memory Device Register -> SDRAM */ +#define CONFIG_SYS_SDRC_MDR_VAL AT91_SDRAMC_MD_SDRAM +#define CONFIG_SYS_SDRC_MR_VAL2 AT91_SDRAMC_MODE_PRECHARGE +#define CONFIG_SYS_SDRAM_VAL1 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL3 AT91_SDRAMC_MODE_REFRESH +#define CONFIG_SYS_SDRAM_VAL2 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL3 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL4 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL5 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL6 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL7 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL8 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRAM_VAL9 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL4 AT91_SDRAMC_MODE_LMR +#define CONFIG_SYS_SDRAM_VAL10 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_MR_VAL5 AT91_SDRAMC_MODE_NORMAL +#define CONFIG_SYS_SDRAM_VAL11 0 /* SDRAM_BASE */ +#define CONFIG_SYS_SDRC_TR_VAL2 1200 /* SDRAM_TR */ +#define CONFIG_SYS_SDRAM_VAL12 0 /* SDRAM_BASE */ + +/* setup SMC0, CS0 (NOR Flash) - 16-bit, 15 WS */ +#define CONFIG_SYS_SMC0_SETUP0_VAL \ + (AT91_SMC_NWESETUP_(10) | AT91_SMC_NCS_WRSETUP_(10) | \ + AT91_SMC_NRDSETUP_(10) | AT91_SMC_NCS_RDSETUP_(10)) +#define CONFIG_SYS_SMC0_PULSE0_VAL \ + (AT91_SMC_NWEPULSE_(11) | AT91_SMC_NCS_WRPULSE_(11) | \ + AT91_SMC_NRDPULSE_(11) | AT91_SMC_NCS_RDPULSE_(11)) +#define CONFIG_SYS_SMC0_CYCLE0_VAL \ + (AT91_SMC_NWECYCLE_(22) | AT91_SMC_NRDCYCLE_(22)) +#define CONFIG_SYS_SMC0_MODE0_VAL \ + (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ + AT91_SMC_DBW_16 | \ + AT91_SMC_TDFMODE | \ + AT91_SMC_TDF_(6)) + +/* user reset enable */ +#define CONFIG_SYS_RSTC_RMR_VAL \ + (AT91_RSTC_KEY | \ + AT91_RSTC_PROCRST | \ + AT91_RSTC_RSTTYP_WAKEUP | \ + AT91_RSTC_RSTTYP_WATCHDOG) + +/* Disable Watchdog */ +#define CONFIG_SYS_WDTC_WDMR_VAL \ + (AT91_WDT_WDIDLEHLT | AT91_WDT_WDDBGHLT | \ + AT91_WDT_WDV | \ + AT91_WDT_WDDIS | \ + AT91_WDT_WDD) + + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/pm9263/env/bin/_update b/arch/arm/boards/pm9263/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/arm/boards/pm9263/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/arm/boards/pm9263/env/bin/boot b/arch/arm/boards/pm9263/env/bin/boot new file mode 100644 index 0000000..533dea7 --- /dev/null +++ b/arch/arm/boards/pm9263/env/bin/boot @@ -0,0 +1,47 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xnand ]; then + root=nand + kernel=nand +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$1 = xnor ]; then + root=nor + kernel=nor +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xnand ]; then + bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" +elif [ x$root = xnor ]; then + bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +elif [ $kernel = nor ]; then + bootm /dev/nor0.kernel +else + bootm /dev/nand0.kernel.bb +fi + diff --git a/arch/arm/boards/pm9263/env/bin/hush_hack b/arch/arm/boards/pm9263/env/bin/hush_hack new file mode 100644 index 0000000..5fffa92 --- /dev/null +++ b/arch/arm/boards/pm9263/env/bin/hush_hack @@ -0,0 +1 @@ +nand -a /dev/nand0.* diff --git a/arch/arm/boards/pm9263/env/bin/init b/arch/arm/boards/pm9263/env/bin/init new file mode 100644 index 0000000..02f5cd4 --- /dev/null +++ b/arch/arm/boards/pm9263/env/bin/init @@ -0,0 +1,37 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +if [ -e /dev/nor0 ]; then + addpart /dev/nor0 $nor_parts +fi + +if [ -e /dev/nand0 ]; then + addpart /dev/nand0 $nand_parts + + # Uh, oh, hush first expands wildcards and then starts executing + # commands. What a bug! + source /env/bin/hush_hack +fi + +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" +fi + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel nor [] to update kernel into flash" + echo "type update_root nor [] to update rootfs into flash" + echo + exit +fi + +boot diff --git a/arch/arm/boards/pm9263/env/bin/update_kernel b/arch/arm/boards/pm9263/env/bin/update_kernel new file mode 100644 index 0000000..05c822d --- /dev/null +++ b/arch/arm/boards/pm9263/env/bin/update_kernel @@ -0,0 +1,15 @@ +#!/bin/sh + +. /env/config + +image=$uimage +if [ x$1 = xnand ]; then + part=/dev/nand0.kernel.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.kernel +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/arch/arm/boards/pm9263/env/bin/update_root b/arch/arm/boards/pm9263/env/bin/update_root new file mode 100644 index 0000000..a751372 --- /dev/null +++ b/arch/arm/boards/pm9263/env/bin/update_root @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 +if [ x$1 = xnand ]; then + part=/dev/nand0.root.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.root +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 + diff --git a/arch/arm/boards/pm9263/env/config b/arch/arm/boards/pm9263/env/config new file mode 100644 index 0000000..7513291 --- /dev/null +++ b/arch/arm/boards/pm9263/env/config @@ -0,0 +1,28 @@ +#!/bin/sh + +# can be either 'net', 'nor' or 'nand'' +kernel=net +root=net + +uimage=uImage-PM9263 +jffs2=root-PM9263.jffs2 + +autoboot_timeout=3 + +nfsroot="/ptx/work/octopus/mkl/bucyrus/OSELAS.BSP-Bucyrus-Grabowski-trunk/platform-Ronetix-PM9263/root" +bootargs="console=ttyS0,115200" + +nor_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" +rootpart_nor="/dev/mtdblock3" + +#nand_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" +#rootpart_nand="/dev/mtdblock7" + +# use 'dhcp' to do dhcp in barebox and in kernel +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=192.168.23.1 diff --git a/arch/arm/boards/pm9263/init.c b/arch/arm/boards/pm9263/init.c new file mode 100644 index 0000000..88b91ea --- /dev/null +++ b/arch/arm/boards/pm9263/init.c @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct atmel_nand_data nand_pdata = { + .ale = 21, + .cle = 22, +/* .det_pin = ... not connected */ + .ecc_base = (void __iomem *)(AT91_BASE_SYS + AT91_ECC0), + .ecc_mode = NAND_ECC_HW, + .rdy_pin = AT91_PIN_PB30, + .enable_pin = AT91_PIN_PD15, +#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16) + .bus_width_16 = 1, +#else + .bus_width_16 = 0, +#endif +}; + +static struct sam9_smc_config pm_nand_smc_config = { + .ncs_read_setup = 1, + .nrd_setup = 1, + .ncs_write_setup = 1, + .nwe_setup = 1, + + .ncs_read_pulse = 3, + .nrd_pulse = 3, + .ncs_write_pulse = 3, + .nwe_pulse = 3, + + .read_cycle = 5, + .write_cycle = 5, + + .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, + .tdf_cycles = 2, +}; + +static void pm_add_device_nand(void) +{ + /* setup bus-width (8 or 16) */ + if (nand_pdata.bus_width_16) + pm_nand_smc_config.mode |= AT91_SMC_DBW_16; + else + pm_nand_smc_config.mode |= AT91_SMC_DBW_8; + + /* configure chip-select 3 (NAND) */ + sam9_smc_configure(3, &pm_nand_smc_config); + + at91_add_device_nand(&nand_pdata); +} + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = AT91_CHIPSELECT_0, + .size = 4 * 1024 * 1024, +}; + +static struct at91_ether_platform_data macb_pdata = { + .flags = AT91SAM_ETHER_RMII, + .phy_addr = 0, +}; + +static int pm9263_devices_init(void) +{ + /* + * PB27 enables the 50MHz oscillator for Ethernet PHY + * 1 - enable + * 0 - disable + */ + at91_set_gpio_output(AT91_PIN_PB27, 1); + at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ + + /* Enable clock */ + at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); + + at91_add_device_sdram(64 * 1024 * 1024); + pm_add_device_nand(); + at91_add_device_eth(&macb_pdata); + register_device(&cfi_dev); + + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x10000, PARTITION_FIXED, "env0"); + + armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); + armlinux_set_architecture(MACH_TYPE_PM9263); + + return 0; +} + +device_initcall(pm9263_devices_init); + +static int pm9263_console_init(void) +{ + at91_register_uart(0, 0); + return 0; +} + +console_initcall(pm9263_console_init); diff --git a/arch/arm/boards/scb9328/Makefile b/arch/arm/boards/scb9328/Makefile new file mode 100644 index 0000000..db6fd7e --- /dev/null +++ b/arch/arm/boards/scb9328/Makefile @@ -0,0 +1,3 @@ + +obj-y += lowlevel_init.o +obj-y += scb9328.o diff --git a/arch/arm/boards/scb9328/config.h b/arch/arm/boards/scb9328/config.h new file mode 100644 index 0000000..cc22b7a --- /dev/null +++ b/arch/arm/boards/scb9328/config.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2003 ETC s.r.o. + * + * 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 + * + * Written by Peter Figuli , 2003. + * + * 2003/13/06 Initial MP10 Support copied from wepep250 + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#define CONFIG_SYSPLL_CLK_FREQ 16000000 + +#endif /* __CONFIG_H */ + diff --git a/arch/arm/boards/scb9328/env/bin/init b/arch/arm/boards/scb9328/env/bin/init new file mode 100644 index 0000000..416669f --- /dev/null +++ b/arch/arm/boards/scb9328/env/bin/init @@ -0,0 +1,3 @@ + +echo running init + diff --git a/arch/arm/boards/scb9328/lowlevel_init.S b/arch/arm/boards/scb9328/lowlevel_init.S new file mode 100644 index 0000000..5b02428 --- /dev/null +++ b/arch/arm/boards/scb9328/lowlevel_init.S @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2004 Sascha Hauer, Synertronixx GmbH + * + * 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 + +#define CPU200 + +#ifdef CPU200 +#define CFG_MPCTL0_VAL 0x00321431 +#else +#define CFG_MPCTL0_VAL 0x040e200e +#endif + +#define BUS72 + +#ifdef BUS72 +#define CFG_SPCTL0_VAL 0x04002400 +#endif + +#ifdef BUS96 +#define CFG_SPCTL0_VAL 0x04001800 +#endif + +#ifdef BUS64 +#define CFG_SPCTL0_VAL 0x08001800 +#endif + +/* Das ist der BCLK Divider, der aus der System PLL + BCLK und HCLK erzeugt: + 31 | xxxx xxxx xxxx xxxx xx10 11xx xxxx xxxx | 0 + 0x2f008403 : 192MHz/2=96MHz, 144MHz/2=72MHz PRESC=1->BCLKDIV=2 + 0x2f008803 : 192MHz/3=64MHz, 240MHz/3=80MHz PRESC=1->BCLKDIV=2 + 0x2f001003 : 192MHz/5=38,4MHz + 0x2f000003 : 64MHz/1 + Bit 22: SPLL Restart + Bit 21: MPLL Restart */ + +#ifdef BUS64 +#define CFG_CSCR_VAL 0x2f030003 +#endif + +#ifdef BUS72 +#define CFG_CSCR_VAL 0x2f030403 +#endif +/* Bit[0:3] contain PERCLK1DIV for UART 1 + 0x000b00b ->b<- -> 192MHz/12=16MHz + 0x000b00b ->8<- -> 144MHz/09=16MHz + 0x000b00b ->3<- -> 64MHz/4=16MHz */ + +#ifdef BUS96 +#define CFG_PCDR_VAL 0x000b00b5 +#endif + +#ifdef BUS64 +#define CFG_PCDR_VAL 0x000b00b3 +#endif + +#ifdef BUS72 +#define CFG_PCDR_VAL 0x000b00b8 +#endif + +#define writel(val, reg) \ + ldr r0, =reg; \ + ldr r1, =val; \ + str r1, [r0]; + +.globl board_init_lowlevel +board_init_lowlevel: + + mov r10, lr + + /* Change PERCLK1DIV to 14 ie 14+1 */ + writel(CFG_PCDR_VAL, PCDR) + + /* set MCU PLL Control Register 0 */ + writel(CFG_MPCTL0_VAL, MPCTL0) + + /* set mpll restart bit */ + ldr r0, =CSCR + ldr r1, [r0] + orr r1,r1,#(1<<21) + str r1, [r0] + + mov r2,#0x10 +1: + mov r3,#0x2000 +2: + subs r3,r3,#1 + bne 2b + + subs r2,r2,#1 + bne 1b + + /* set System PLL Control Register 0 */ + writel(CFG_SPCTL0_VAL, SPCTL0) + + /* set spll restart bit */ + ldr r0, =CSCR + ldr r1, [r0] + orr r1,r1,#(1<<22) + str r1, [r0] + + mov r2,#0x10 +1: + mov r3,#0x2000 +2: + subs r3,r3,#1 + bne 2b + + subs r2,r2,#1 + bne 1b + + writel(CFG_CSCR_VAL, CSCR) + +/* I have now read the ARM920 DataSheet back-to-Back, and have stumbled upon + *this..... + * + * It would appear that from a Cold-Boot the ARM920T enters "FastBus" mode CP15 + * register 1, this stops it using the output of the PLL and thus runs at the + * slow rate. Unless you place the Core into "Asynch" mode, the CPU will never + * use the value set in the CM_OSC registers...regardless of what you set it + * too! Thus, although i thought i was running at 140MHz, i'm actually running + * at 40!.. + + * Slapping this into my bootloader does the trick... + + * MRC p15,0,r0,c1,c0,0 ; read core configuration register + * ORR r0,r0,#0xC0000000 ; set asynchronous clocks and not fastbus mode + * MCR p15,0,r0,c1,c0,0 ; write modified value to core configuration + * register + */ + MRC p15,0,r0,c1,c0,0 + ORR r0,r0,#0xC0000000 + MCR p15,0,r0,c1,c0,0 + + /* Skip SDRAM initialization if we run from RAM */ + cmp pc, #0x08000000 + bls 1f + cmp pc, #0x09000000 + bhi 1f + + mov pc,r10 + +1: + +/* SDRAM Setup */ + + writel(0x910a8200, SDCTL0) /* Precharge cmd, CAS = 2 */ + writel(0x0, 0x08200000) /* Issue Precharge all Command */ + writel(0xa10a8200, SDCTL0) /* Autorefresh cmd, CAS = 2 */ + + ldr r0, =0x08000000 + ldr r1, =0x0 /* Issue AutoRefresh Command */ + str r1, [r0] + str r1, [r0] + str r1, [r0] + str r1, [r0] + str r1, [r0] + str r1, [r0] + str r1, [r0] + str r1, [r0] + + writel(0xb10a8300, SDCTL0) + writel(0x0, 0x08223000) /* CAS Latency 2, issue Mode Register Command, Burst Length = 8 */ + writel(0x810a8200, SDCTL0) /* Set to Normal Mode CAS 2 */ + + mov pc,r10 diff --git a/arch/arm/boards/scb9328/scb9328.c b/arch/arm/boards/scb9328/scb9328.c new file mode 100644 index 0000000..e781393 --- /dev/null +++ b/arch/arm/boards/scb9328/scb9328.c @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2004 Sascha Hauer, Synertronixx GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .name = "cfi_flash", + + .map_base = 0x10000000, + .size = 16 * 1024 * 1024, +}; + +static struct memory_platform_data sdram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0x08000000, + .size = 16 * 1024 * 1024, + .platform_data = &sdram_pdata, +}; + +static struct dm9000_platform_data dm9000_data = { + .iobase = 0x16000000, + .iodata = 0x16000004, + .buswidth = DM9000_WIDTH_16, +}; + +static struct device_d dm9000_dev = { + .name = "dm9000", + .map_base = 0x16000000, + .size = 8, + .platform_data = &dm9000_data, +}; + +static int scb9328_devices_init(void) { + + imx_gpio_mode(PA23_PF_CS5); + +/* CS3 becomes CS3 by clearing reset default bit 1 in FMCR */ + FMCR = 0x1; + + CS0U = 0x000F2000; + CS0L = 0x11110d01; + + CS1U = 0x000F0a00; + CS1L = 0x11110601; + CS2U = 0x0; + CS2L = 0x0; + CS3U = 0x000FFFFF; + CS3L = 0x00000303; + CS4U = 0x000F0a00; + CS4L = 0x11110301; + CS5U = 0x00008400; + CS5L = 0x00000D03; + + register_device(&cfi_dev); + register_device(&sdram_dev); + register_device(&dm9000_dev); + + devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); + protect_file("/dev/env0", 1); + + armlinux_add_dram(&sdram_dev); + armlinux_set_bootparams((void *)0x08000100); + armlinux_set_architecture(MACH_TYPE_SCB9328); + + return 0; +} + +device_initcall(scb9328_devices_init); + +static struct device_d scb9328_serial_device = { + .name = "imx_serial", + .map_base = IMX_UART1_BASE, + .size = 4096, +}; + +static int scb9328_console_init(void) +{ + /* init gpios for serial port */ + imx_gpio_mode(PC11_PF_UART1_TXD); + imx_gpio_mode(PC12_PF_UART1_RXD); + + register_device(&scb9328_serial_device); + return 0; +} + +console_initcall(scb9328_console_init); + diff --git a/arch/arm/boards/scb9328/scb9328.dox b/arch/arm/boards/scb9328/scb9328.dox new file mode 100644 index 0000000..75bc7c8 --- /dev/null +++ b/arch/arm/boards/scb9328/scb9328.dox @@ -0,0 +1,9 @@ +/** @page scb9328 Synertronixx's scb9328 + +This CPU card is based on a Freescale i.MX1 CPU. The card is shipped with: + +- up to 16MiB NOR type Flash Memory +- 16MiB synchronous dynamic RAM +- DM9000 network controller + +*/ diff --git a/arch/arm/configs/a9m2410_defconfig b/arch/arm/configs/a9m2410_defconfig index 9429a37..9e888fc 100644 --- a/arch/arm/configs/a9m2410_defconfig +++ b/arch/arm/configs/a9m2410_defconfig @@ -100,7 +100,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/a9m2410/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/a9m2410/env" # # Debugging diff --git a/arch/arm/configs/a9m2440_defconfig b/arch/arm/configs/a9m2440_defconfig index 1fcabbb..f69dcfd 100644 --- a/arch/arm/configs/a9m2440_defconfig +++ b/arch/arm/configs/a9m2440_defconfig @@ -101,7 +101,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/a9m2440/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/a9m2440/env" # # Debugging diff --git a/arch/arm/configs/at91sam9260ek_defconfig b/arch/arm/configs/at91sam9260ek_defconfig index 61df756..b40485b 100644 --- a/arch/arm/configs/at91sam9260ek_defconfig +++ b/arch/arm/configs/at91sam9260ek_defconfig @@ -89,7 +89,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/at91sam9260ek/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/at91sam9260ek/env" # # Debugging diff --git a/arch/arm/configs/at91sam9263ek_defconfig b/arch/arm/configs/at91sam9263ek_defconfig index eb47856..d423c2f 100644 --- a/arch/arm/configs/at91sam9263ek_defconfig +++ b/arch/arm/configs/at91sam9263ek_defconfig @@ -93,7 +93,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/at91sam9263ek/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/at91sam9263ek/env" # # Debugging diff --git a/arch/arm/configs/edb93xx_defconfig b/arch/arm/configs/edb93xx_defconfig index d6b4b19..d8fe23f 100644 --- a/arch/arm/configs/edb93xx_defconfig +++ b/arch/arm/configs/edb93xx_defconfig @@ -103,7 +103,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/edb93xx/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/edb93xx/env" # # Debugging diff --git a/arch/arm/configs/eukrea_cpuimx25_defconfig b/arch/arm/configs/eukrea_cpuimx25_defconfig index 574d322..14f06c2 100644 --- a/arch/arm/configs/eukrea_cpuimx25_defconfig +++ b/arch/arm/configs/eukrea_cpuimx25_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# barebox version: 2010.05.0 -# Wed Jun 2 01:04:00 2010 +# barebox version: 2010.07.0 +# Thu Jul 29 09:54:50 2010 # # CONFIG_BOARD_LINKER_SCRIPT is not set CONFIG_GENERIC_LINKER_SCRIPT=y @@ -108,7 +108,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/eukrea_cpuimx25/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/eukrea_cpuimx25/env" # # Debugging @@ -169,6 +169,7 @@ # flash # CONFIG_CMD_FLASH=y +# CONFIG_CMD_UBI is not set # # booting @@ -193,10 +194,12 @@ CONFIG_CMD_UNLZO=y CONFIG_NET=y CONFIG_NET_DHCP=y -# CONFIG_NET_RARP is not set # CONFIG_NET_NFS is not set CONFIG_NET_PING=y CONFIG_NET_TFTP=y +# CONFIG_NET_TFTP_PUSH is not set +# CONFIG_NET_NETCONSOLE is not set +# CONFIG_NET_RESOLV is not set # # Drivers @@ -227,12 +230,14 @@ # flash drivers # # CONFIG_DRIVER_CFI is not set +CONFIG_MTD=y CONFIG_NAND=y CONFIG_NAND_IMX=y CONFIG_NAND_IMX_BOOT=y # CONFIG_MTD_NAND_VERIFY_WRITE is not set # CONFIG_MTD_NAND_ECC_SMC is not set CONFIG_MTD_NAND_IDS=y +# CONFIG_UBI is not set # CONFIG_ATA is not set # CONFIG_USB is not set # CONFIG_USB_GADGET is not set diff --git a/arch/arm/configs/eukrea_cpuimx27_defconfig b/arch/arm/configs/eukrea_cpuimx27_defconfig index a1cf1ad..c7f6b78 100644 --- a/arch/arm/configs/eukrea_cpuimx27_defconfig +++ b/arch/arm/configs/eukrea_cpuimx27_defconfig @@ -118,7 +118,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/eukrea_cpuimx27/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/eukrea_cpuimx27/env" # # Debugging diff --git a/arch/arm/configs/eukrea_cpuimx35_defconfig b/arch/arm/configs/eukrea_cpuimx35_defconfig index ff6547f..7c5b49a 100644 --- a/arch/arm/configs/eukrea_cpuimx35_defconfig +++ b/arch/arm/configs/eukrea_cpuimx35_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# barebox version: 2010.06.0 -# Mon Jun 7 18:25:47 2010 +# barebox version: 2010.07.0 +# Wed Jul 28 21:46:15 2010 # # CONFIG_BOARD_LINKER_SCRIPT is not set CONFIG_GENERIC_LINKER_SCRIPT=y @@ -110,7 +110,8 @@ CONFIG_CONSOLE_ACTIVATE_FIRST=y # CONFIG_OF_FLAT_TREE is not set # CONFIG_PARTITION is not set -# CONFIG_DEFAULT_ENVIRONMENT is not set +CONFIG_DEFAULT_ENVIRONMENT=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/eukrea_cpuimx35/env" # # Debugging @@ -170,7 +171,8 @@ # # flash # -# CONFIG_CMD_FLASH is not set +CONFIG_CMD_FLASH=y +# CONFIG_CMD_UBI is not set # # booting @@ -195,10 +197,12 @@ CONFIG_CMD_UNLZO=y CONFIG_NET=y CONFIG_NET_DHCP=y -# CONFIG_NET_RARP is not set # CONFIG_NET_NFS is not set CONFIG_NET_PING=y CONFIG_NET_TFTP=y +# CONFIG_NET_TFTP_PUSH is not set +# CONFIG_NET_NETCONSOLE is not set +# CONFIG_NET_RESOLV is not set # # Drivers @@ -229,12 +233,14 @@ # flash drivers # # CONFIG_DRIVER_CFI is not set +CONFIG_MTD=y CONFIG_NAND=y CONFIG_NAND_IMX=y -# CONFIG_NAND_IMX_BOOT is not set +CONFIG_NAND_IMX_BOOT=y # CONFIG_MTD_NAND_VERIFY_WRITE is not set # CONFIG_MTD_NAND_ECC_SMC is not set CONFIG_MTD_NAND_IDS=y +# CONFIG_UBI is not set # CONFIG_ATA is not set # CONFIG_USB is not set # CONFIG_USB_GADGET is not set diff --git a/arch/arm/configs/freescale_mx25_3stack_defconfig b/arch/arm/configs/freescale_mx25_3stack_defconfig index d308e5b..fd7dd42 100644 --- a/arch/arm/configs/freescale_mx25_3stack_defconfig +++ b/arch/arm/configs/freescale_mx25_3stack_defconfig @@ -106,7 +106,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/freescale-mx25-3-stack/env/" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/freescale-mx25-3-stack/env/" # # Debugging diff --git a/arch/arm/configs/freescale_mx35_3stack_defconfig b/arch/arm/configs/freescale_mx35_3stack_defconfig index 17a2fdc..4321fbc 100644 --- a/arch/arm/configs/freescale_mx35_3stack_defconfig +++ b/arch/arm/configs/freescale_mx35_3stack_defconfig @@ -105,7 +105,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/freescale-mx35-3-stack/env/" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/freescale-mx35-3-stack/env/" # # Debugging diff --git a/arch/arm/configs/mmccpu_defconfig b/arch/arm/configs/mmccpu_defconfig index 2b80a30..a8c41e7 100644 --- a/arch/arm/configs/mmccpu_defconfig +++ b/arch/arm/configs/mmccpu_defconfig @@ -93,7 +93,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/mmccpu/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/mmccpu/env" # # Debugging diff --git a/arch/arm/configs/mx21ads_defconfig b/arch/arm/configs/mx21ads_defconfig index 99a8714..99b5ed6 100644 --- a/arch/arm/configs/mx21ads_defconfig +++ b/arch/arm/configs/mx21ads_defconfig @@ -104,7 +104,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/imx21ads/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/imx21ads/env" # # Debugging diff --git a/arch/arm/configs/mx27ads_defconfig b/arch/arm/configs/mx27ads_defconfig index 71880c0..a1bf3f9 100644 --- a/arch/arm/configs/mx27ads_defconfig +++ b/arch/arm/configs/mx27ads_defconfig @@ -108,7 +108,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/imx27ads/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/imx27ads/env" # # Debugging diff --git a/arch/arm/configs/neso_defconfig b/arch/arm/configs/neso_defconfig new file mode 100644 index 0000000..3f2a978 --- /dev/null +++ b/arch/arm/configs/neso_defconfig @@ -0,0 +1,264 @@ +# +# Automatically generated make config: don't edit +# barebox version: 2010.06.0 +# Mon Jun 21 14:06:11 2010 +# +# CONFIG_BOARD_LINKER_SCRIPT is not set +CONFIG_GENERIC_LINKER_SCRIPT=y +CONFIG_ARM=y + +# +# System Type +# +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_AT91RM9200 is not set +# CONFIG_ARCH_EP93XX is not set +CONFIG_ARCH_IMX=y +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_S3C24xx is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM926T=y +CONFIG_CPU_32v5=y + +# +# processor features +# +CONFIG_ARCH_TEXT_BASE=0xa7e00000 +CONFIG_BOARDINFO="Garz+Fricke Neso" +CONFIG_ARCH_HAS_FEC_IMX=y + +# +# Freescale i.MX System-on-Chip +# +# CONFIG_ARCH_IMX1 is not set +# CONFIG_ARCH_IMX21 is not set +# CONFIG_ARCH_IMX25 is not set +CONFIG_ARCH_IMX27=y +# CONFIG_ARCH_IMX31 is not set +# CONFIG_ARCH_IMX35 is not set +# CONFIG_MACH_EUKREA_CPUIMX27 is not set +# CONFIG_MACH_IMX27ADS is not set +# CONFIG_MACH_PCA100 is not set +# CONFIG_MACH_PCM038 is not set +CONFIG_MACH_NESO=y + +# +# Board specific settings +# + +# +# i.MX specific settings +# +CONFIG_IMX_CLKO=y +CONFIG_AEABI=y + +# +# Arm specific settings +# +CONFIG_CMD_ARM_CPUINFO=y +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_GREGORIAN_CALENDER=y +CONFIG_HAS_KALLSYMS=y +CONFIG_HAS_MODULES=y +CONFIG_CMD_MEMORY=y +CONFIG_ENV_HANDLING=y +CONFIG_GENERIC_GPIO=y + +# +# General Settings +# +CONFIG_LOCALVERSION_AUTO=y + +# +# memory layout +# +CONFIG_HAVE_MMU=y +CONFIG_MMU=y +CONFIG_HAVE_CONFIGURABLE_TEXT_BASE=y +CONFIG_TEXT_BASE=0xa7e00000 +CONFIG_HAVE_CONFIGURABLE_MEMORY_LAYOUT=y +CONFIG_MEMORY_LAYOUT_DEFAULT=y +# CONFIG_MEMORY_LAYOUT_FIXED is not set +CONFIG_STACK_SIZE=0x8000 +CONFIG_MALLOC_SIZE=0x1000000 +# CONFIG_BROKEN is not set +# CONFIG_EXPERIMENTAL is not set +CONFIG_MACH_HAS_LOWLEVEL_INIT=y +CONFIG_MACH_DO_LOWLEVEL_INIT=y +CONFIG_PROMPT="barebox:" +CONFIG_BAUDRATE=115200 +CONFIG_LONGHELP=y +CONFIG_CBSIZE=1024 +CONFIG_MAXARGS=16 +CONFIG_SHELL_HUSH=y +# CONFIG_SHELL_SIMPLE is not set +CONFIG_GLOB=y +CONFIG_PROMPT_HUSH_PS2="> " +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_DYNAMIC_CRC_TABLE=y +CONFIG_ERRNO_MESSAGES=y +CONFIG_TIMESTAMP=y +CONFIG_CONSOLE_FULL=y +CONFIG_CONSOLE_ACTIVATE_FIRST=y +# CONFIG_OF_FLAT_TREE is not set +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv board/guf-neso/env" + +# +# Debugging +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_FLASH_NOISE is not set +# CONFIG_ENABLE_PARTITION_NOISE is not set +# CONFIG_ENABLE_DEVICE_NOISE is not set + +# +# Commands +# + +# +# scripting +# +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_TRUE=y +CONFIG_CMD_FALSE=y + +# +# file commands +# +CONFIG_CMD_LS=y +CONFIG_CMD_RM=y +CONFIG_CMD_CAT=y +CONFIG_CMD_MKDIR=y +CONFIG_CMD_RMDIR=y +CONFIG_CMD_CP=y +CONFIG_CMD_PWD=y +CONFIG_CMD_CD=y +CONFIG_CMD_MOUNT=y +CONFIG_CMD_UMOUNT=y + +# +# console +# +CONFIG_CMD_CLEAR=y +CONFIG_CMD_ECHO=y +CONFIG_CMD_ECHO_E=y + +# +# memory +# +# CONFIG_CMD_LOADB is not set +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_CRC=y +CONFIG_CMD_MTEST=y +# CONFIG_CMD_MTEST_ALTERNATIVE is not set + +# +# flash +# +CONFIG_CMD_FLASH=y + +# +# booting +# +CONFIG_CMD_BOOTM=y +# CONFIG_CMD_BOOTM_ZLIB is not set +# CONFIG_CMD_BOOTM_BZLIB is not set +# CONFIG_CMD_BOOTM_SHOW_TYPE is not set +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_BOOTU=y +# CONFIG_CMD_LINUX16 is not set +CONFIG_CMD_RESET=y +CONFIG_CMD_GO=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_TEST=y +CONFIG_CMD_VERSION=y +CONFIG_CMD_HELP=y +CONFIG_CMD_DEVINFO=y +CONFIG_CMD_BMP=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_NET_NETCONSOLE=y +CONFIG_NET_RESOLV=y + +# +# Drivers +# + +# +# serial drivers +# +# CONFIG_DRIVER_SERIAL_ARM_DCC is not set +CONFIG_DRIVER_SERIAL_IMX=y +# CONFIG_DRIVER_SERIAL_NS16550 is not set +CONFIG_MIIPHY=y + +# +# Network drivers +# +# CONFIG_DRIVER_NET_SMC911X is not set +# CONFIG_DRIVER_NET_SMC91111 is not set +CONFIG_DRIVER_NET_FEC_IMX=y +CONFIG_NET_USB=y +CONFIG_NET_USB_ASIX=y +# CONFIG_NET_USB_SMSC95XX is not set + +# +# SPI drivers +# +CONFIG_SPI=y +CONFIG_DRIVER_SPI_IMX=y +CONFIG_DRIVER_SPI_MC13783=y +# CONFIG_I2C is not set + +# +# flash drivers +# +# CONFIG_DRIVER_CFI is not set +CONFIG_NAND=y +CONFIG_NAND_IMX=y +CONFIG_NAND_IMX_BOOT=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=y +# CONFIG_ATA is not set +CONFIG_USB=y +CONFIG_USB_EHCI=y +CONFIG_USB_ULPI=y +CONFIG_USB_ISP1504=y +# CONFIG_USB_GADGET is not set +CONFIG_VIDEO=y +CONFIG_DRIVER_VIDEO_IMX=y +CONFIG_IMXFB_DRIVER_VIDEO_IMX_OVERLAY=y + +# +# Filesystem support +# +# CONFIG_FS_CRAMFS is not set +CONFIG_FS_RAMFS=y +CONFIG_FS_DEVFS=y +CONFIG_CRC32=y +# CONFIG_GENERIC_FIND_NEXT_BIT is not set +CONFIG_PROCESS_ESCAPE_SEQUENCE=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/pca100_defconfig b/arch/arm/configs/pca100_defconfig index 68f37d0..accc6ef 100644 --- a/arch/arm/configs/pca100_defconfig +++ b/arch/arm/configs/pca100_defconfig @@ -109,7 +109,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv board/phycard-i.MX27/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv arch/arm/boards/phycard-i.MX27/env" # # Debugging diff --git a/arch/arm/configs/pcm037_defconfig b/arch/arm/configs/pcm037_defconfig index 5a4ac70..bb67995 100644 --- a/arch/arm/configs/pcm037_defconfig +++ b/arch/arm/configs/pcm037_defconfig @@ -111,7 +111,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv board/pcm037/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv arch/arm/boards/pcm037/env" # # Debugging diff --git a/arch/arm/configs/pcm038_defconfig b/arch/arm/configs/pcm038_defconfig index a449a99..2925c9c 100644 --- a/arch/arm/configs/pcm038_defconfig +++ b/arch/arm/configs/pcm038_defconfig @@ -109,7 +109,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv board/pcm038/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv arch/arm/boards/pcm038/env" # # Debugging diff --git a/arch/arm/configs/pcm043_defconfig b/arch/arm/configs/pcm043_defconfig index e5c2d40..31c65f1 100644 --- a/arch/arm/configs/pcm043_defconfig +++ b/arch/arm/configs/pcm043_defconfig @@ -113,7 +113,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv board/pcm043/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv arch/arm/boards/pcm043/env" # # Debugging diff --git a/arch/arm/configs/pm9263_defconfig b/arch/arm/configs/pm9263_defconfig index cde5cbe..d5ee46a 100644 --- a/arch/arm/configs/pm9263_defconfig +++ b/arch/arm/configs/pm9263_defconfig @@ -93,7 +93,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/pm9263/env/" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/pm9263/env/" # # Debugging diff --git a/arch/arm/configs/scb9328_defconfig b/arch/arm/configs/scb9328_defconfig index 6638234..7dc56dd 100644 --- a/arch/arm/configs/scb9328_defconfig +++ b/arch/arm/configs/scb9328_defconfig @@ -105,7 +105,7 @@ # CONFIG_OF_FLAT_TREE is not set # CONFIG_PARTITION is not set CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/scb9328/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/scb9328/env" # # Debugging diff --git a/arch/arm/include/asm/barebox-arm.h b/arch/arm/include/asm/barebox-arm.h index 5f0bb73..7bb1af1 100644 --- a/arch/arm/include/asm/barebox-arm.h +++ b/arch/arm/include/asm/barebox-arm.h @@ -32,7 +32,7 @@ /* cpu/.../cpu.c */ int cleanup_before_linux(void); -/* board/.../... */ +/* arch/board(s)/.../... */ int board_init(void); int dram_init (void); diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 0cf6334..afee3d1 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -16,6 +16,7 @@ default 0x87f00000 if MACH_PCM037 default 0x87f00000 if MACH_PCM043 default 0x08f80000 if MACH_SCB9328 + default 0xa7e00000 if MACH_NESO config BOARDINFO default "Eukrea CPUIMX25" if MACH_EUKREA_CPUIMX25 @@ -30,6 +31,7 @@ default "Phytec phyCORE-i.MX31" if MACH_PCM037 default "Phytec phyCORE-i.MX35" if MACH_PCM043 default "Synertronixx scb9328" if MACH_SCB9328 + default "Garz+Fricke Neso" if MACH_NESO config ARCH_HAS_FEC_IMX bool @@ -195,6 +197,14 @@ Say Y here if you are using Phytec's phyCORE-i.MX27 (pcm038) equipped with a Freescale i.MX27 Processor +config MACH_NESO + bool "Garz+Fricke Neso" + select MACH_HAS_LOWLEVEL_INIT + select HAVE_MMU + help + Say Y here if you are using the Garz+Fricke Neso board equipped + with a Freescale i.MX27 Processor + endchoice endif diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig index 99b9f9d..158639e 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -39,20 +39,6 @@ endchoice -config OMAP_CONFIG_STACKSIZE - prompt "STACKSIZE" - hex - default 0x00020000 - help - Select the Stack Size when defaults are used - -config OMAP_MALLOC_LEN - prompt "MALLOC LENGTH" - hex - default 0x00001000 - help - Select the Malloc Length when defaults are used - ### Generic Clock configurations to be enabled by Mach - invisible to enable. config OMAP_CLOCK_UART bool @@ -97,6 +83,6 @@ NAND, OneNAND etc. # Get the board specific configurations -source board/omap/Kconfig +source arch/arm/boards/omap/Kconfig endmenu diff --git a/arch/arm/mach-omap/arch-omap.dox b/arch/arm/mach-omap/arch-omap.dox index 01e45f2..df16b7b 100644 --- a/arch/arm/mach-omap/arch-omap.dox +++ b/arch/arm/mach-omap/arch-omap.dox @@ -39,7 +39,7 @@ Code is Organized into three main directories: @li arch/arm/mach-omap -contains files for ALL peripherals which are present on board with very few exceptions. We will come to these exceptions in later sections. @li include/asm-arm/arch-omap - contains files for ALL OMAP on-silicon peripherals. No Board specific files here please! -@li board/omap - contains files for ALL boards using OMAP processors. +@li arch/arm/boards/omap - contains files for ALL boards using OMAP processors. @section mach_omap arch/arm/mach-omap directory guidelines It is rather simple: All common peripherals should be isolated as separate driver libraries as far as possible. Exceptions such as clock configuration code may be isolated by the following naming convention: omapX_function_name.[cS], where X belongs to the OMAP variant. The exception is for devices who have existing code locations - potentially drivers/i2c/busses and the like. @@ -52,7 +52,7 @@ include/asm-arm/arch-omap/silicon.h contains includes for omapX-silicon.h which defines the base addresses for the peripherals on that platform. the usual convention is to use #define OMAP_SOMETHING_BASE to allow re-use. -@section board_omap board/omap directory guidelines +@section board_omap arch/arm/boards/omap directory guidelines All Board specific files go here. In u-boot, we always had to use common config file which is shared by other drivers to get serial, ethernet baseaddress etc.. we can easily use the device_d structure to handle it with @a barebox. This is more like programming for Linux kernel - it is pretty easy. Each specific board file has board-XYZ.c and potentially and equivalent h file. @@ -66,7 +66,7 @@ Once this is past, the code returns back to arm common code (cpu/start-arm.S). Here Instruction and Data caches are disabled. The execution proceeds to normal board initialization. @section board_boot The board boot path -If the proper CONFIG_MACH_DO_LOWLEVEL_INIT flag is setup, board_init_lowlevel is called. This again would call a common file board/omap/platform.S which setups a temporary SRAM stack and bumps the control to board_init. +If the proper CONFIG_MACH_DO_LOWLEVEL_INIT flag is setup, board_init_lowlevel is called. This again would call a common file arch/arm/boards/omap/platform.S which setups a temporary SRAM stack and bumps the control to board_init. Every Board in OMAP platform can potentially define a board_init and enable defconfig in arch/arm/configs directory. The responsibility here is to setup OMAP for board configurations - this includes SDRAM configuration and pin muxing configuration. Once this is complete, @a barebox boot process proceeds by calling init functions and finally entering shell prompt @@ -87,7 +87,7 @@ device_initcall(my_board_devices_init); @endcode -You may probably be interested in calling console_initcall to get a console.. Modify board/omap/Kconfig to add your OMAP board, create a defconfig, do a make C=2 to enable sparse warnings, you can potentially have a binary done in no time! if you remember to put doxygen comments in your code, you can do a make docs and get the documentation done too.. +You may probably be interested in calling console_initcall to get a console.. Modify arch/arm/boards/omap/Kconfig to add your OMAP board, create a defconfig, do a make C=2 to enable sparse warnings, you can potentially have a binary done in no time! if you remember to put doxygen comments in your code, you can do a make docs and get the documentation done too.. */ diff --git a/arch/arm/mach-omap/include/mach/gpmc_nand.h b/arch/arm/mach-omap/include/mach/gpmc_nand.h index c6c51d5..e23faab 100644 --- a/arch/arm/mach-omap/include/mach/gpmc_nand.h +++ b/arch/arm/mach-omap/include/mach/gpmc_nand.h @@ -68,54 +68,11 @@ #define NAND_WAITPOL_HIGH (1 << 0) #define NAND_WAITPOL_MASK (1 << 0) -#ifdef CONFIG_NAND_OMAP_GPMC_HWECC /** plat_options: hw ecc enabled */ #define NAND_HWECC_ENABLE (1 << 1) -#endif /** plat_options: hw ecc disabled */ -#define NAND_HWECC_DISABLE (0 << 1) #define NAND_HWECC_MASK (1 << 1) -/* Typical BOOTROM oob layouts-requires hwecc **/ -#ifdef CONFIG_NAND_OMAP_GPMC_HWECC -/** Large Page x8 NAND device Layout */ -#define GPMC_NAND_ECC_LP_x8_LAYOUT {\ - .eccbytes = 12,\ - .eccpos = {1, 2, 3, 4, 5, 6, 7, 8,\ - 9, 10, 11, 12},\ - .oobfree = {\ - {.offset = 60,\ - .length = 2 } } \ -} - -/** Large Page x16 NAND device Layout */ -#define GPMC_NAND_ECC_LP_x16_LAYOUT {\ - .eccbytes = 12,\ - .eccpos = {2, 3, 4, 5, 6, 7, 8, 9,\ - 10, 11, 12, 13},\ - .oobfree = {\ - {.offset = 60,\ - .length = 2 } } \ -} - -/** Small Page x8 NAND device Layout */ -#define GPMC_NAND_ECC_SP_x8_LAYOUT {\ - .eccbytes = 3,\ - .eccpos = {1, 2, 3},\ - .oobfree = {\ - {.offset = 14,\ - .length = 2 } } \ -} - -/** Small Page x16 NAND device Layout */ -#define GPMC_NAND_ECC_SP_x16_LAYOUT {\ - .eccbytes = 3,\ - .eccpos = {2, 3, 4},\ - .oobfree = {\ - {.offset = 14,\ - .length = 2 } } \ -} - -#endif /* CONFIG_NAND_OMAP_GPMC_HWECC */ +int gpmc_generic_nand_devices_init(int cs, int width, int hwecc); #endif /* __ASM_OMAP_NAND_GPMC_H */ diff --git a/arch/arm/mach-s3c24xx/generic.c b/arch/arm/mach-s3c24xx/generic.c index 372904f..46b5c50 100644 --- a/arch/arm/mach-s3c24xx/generic.c +++ b/arch/arm/mach-s3c24xx/generic.c @@ -244,8 +244,8 @@ @section s3c24xx_boards Boards using S3C24xx Processors -@li @subpage board/a9m2410/a9m2410.c -@li @subpage board/a9m2440/a9m2440.c +@li @subpage arch/arm/boards/a9m2410/a9m2410.c +@li @subpage arch/arm/boards/a9m2440/a9m2440.c @section s3c24xx_arch Documentation for S3C24xx Architectures Files diff --git a/arch/blackfin/Makefile b/arch/blackfin/Makefile index dbb9081..902268d 100644 --- a/arch/blackfin/Makefile +++ b/arch/blackfin/Makefile @@ -22,7 +22,7 @@ ifneq ($(board-y),) -BOARD := board/$(board-y)/ +BOARD := arch/blackfin/boards/$(board-y)/ else BOARD := endif diff --git a/arch/blackfin/boards/ipe337/Makefile b/arch/blackfin/boards/ipe337/Makefile new file mode 100644 index 0000000..172dfb6 --- /dev/null +++ b/arch/blackfin/boards/ipe337/Makefile @@ -0,0 +1,4 @@ +obj-y += ipe337.o +obj-y += cmd_alternate.o + +extra-y += barebox.lds diff --git a/arch/blackfin/boards/ipe337/barebox.lds.S b/arch/blackfin/boards/ipe337/barebox.lds.S new file mode 100644 index 0000000..4299b82 --- /dev/null +++ b/arch/blackfin/boards/ipe337/barebox.lds.S @@ -0,0 +1,87 @@ +/* + * barebox - barebox.lds.S + * + * Copyright (c) 2005-2007 Analog Device Inc. + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +OUTPUT_ARCH("bfin") +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +/* +MEMORY +{ + ram : ORIGIN = (0x2000000), LENGTH = (256 * 1024) + l1_code : ORIGIN = 0xFFA00000, LENGTH = 0xC000 + l1_data : ORIGIN = 0xFF900000, LENGTH = 0x4000 +} +*/ + +SECTIONS +{ + . = TEXT_BASE; + + . = ALIGN(4); + .text : + { + __stext = .; + __text = .; + _text = .; + *(.text_entry) + *(.text) + } + + . = ALIGN(4); + .rodata : { *(.rodata) } + + __etext = .; /* End of text and rodata section */ + + . = ALIGN(4); + .data : { *(.data) } + + . = ALIGN(4); + .got : { *(.got) } + + . = .; + ___barebox_cmd_start = .; + .barebox_cmd : { BAREBOX_CMDS } + ___barebox_cmd_end = .; + + ___barebox_initcalls_start = .; + .barebox_initcalls : { INITCALLS } + ___barebox_initcalls_end = .; + + ___usymtab_start = .; + __usymtab : { BAREBOX_SYMS } + ___usymtab_end = .; + + . = ALIGN(4); + __bss_start = .; + .bss : { *(.bss) } + _end = .; +} + diff --git a/arch/blackfin/boards/ipe337/cmd_alternate.c b/arch/blackfin/boards/ipe337/cmd_alternate.c new file mode 100644 index 0000000..2883c77 --- /dev/null +++ b/arch/blackfin/boards/ipe337/cmd_alternate.c @@ -0,0 +1,56 @@ +#include +#include +#include +#include +#include + +#define MAGIC 0x19691228 + +static int do_alternate(struct command *cmdtp, int argc, char *argv[]) +{ + void *buf; + size_t size; + ulong *ptr, val = 0, bitcount = 0; + + if (argc != 2) + return COMMAND_ERROR_USAGE; + + buf = read_file(argv[1], &size); + if (!buf) + return 1; + + ptr = buf; + if ((*ptr) != MAGIC) { + printf("Wrong magic! Expected 0x%08x, got 0x%08x.\n", MAGIC, *ptr); + return 1; + } + + ptr++; + + while ((ulong)ptr <= (ulong)buf + size && !(val = *ptr++)) + bitcount += 32; + + if (val) { + do { + if (val & 1) + break; + bitcount++; + } while (val >>= 1); + } + + printf("Bitcount : %d\n", bitcount); + + free(buf); + return (bitcount & 1) ? 3 : 2; +} + +static const __maybe_unused char cmd_alternate_help[] = +"Usage: alternate " +"\n"; + +BAREBOX_CMD_START(alternate) + .cmd = do_alternate, + .usage = "count zero bits in a file", + BAREBOX_CMD_HELP(cmd_alternate_help) +BAREBOX_CMD_END + diff --git a/arch/blackfin/boards/ipe337/config.h b/arch/blackfin/boards/ipe337/config.h new file mode 100644 index 0000000..aa25d07 --- /dev/null +++ b/arch/blackfin/boards/ipe337/config.h @@ -0,0 +1,46 @@ + +#ifndef __CONFIG_H +#define __CONFIG_H + +/* + * Clock settings + */ + +/* CONFIG_CLKIN_HZ is any value in Hz */ +#if defined(CONFIG_MACH_IPE337_V1) +#define CONFIG_CLKIN_HZ 25000000 +#elif defined(CONFIG_MACH_IPE337_V2) +#define CONFIG_CLKIN_HZ 40000000 +#else +#error "Unknown IPE337 revision" +#endif + +/* CONFIG_CLKIN_HALF controls what is passed to PLL 0=CLKIN */ +/* 1=CLKIN/2 */ +#define CONFIG_CLKIN_HALF 0 +/* CONFIG_PLL_BYPASS controls if the PLL is used 0=don't bypass */ +/* 1=bypass PLL */ +#define CONFIG_PLL_BYPASS 0 +/* CONFIG_VCO_MULT controls what the multiplier of the PLL is. */ +/* Values can range from 1-64 */ +#define CONFIG_VCO_MULT 10 /* POR default */ +/* CONFIG_CCLK_DIV controls what the core clock divider is */ +/* Values can be 1, 2, 4, or 8 ONLY */ +#define CONFIG_CCLK_DIV 1 /* POR default */ +/* CONFIG_SCLK_DIV controls what the peripheral clock divider is */ +/* Values can range from 1-15 */ +#define CONFIG_SCLK_DIV 5 /* POR default */ + +/* Frequencies selected: 400MHz CCLK / 80MHz SCLK ^= 12.5ns cycle time*/ + +#define AMGCTLVAL 0x1F + +/* no need for speed, currently, leave at defaults */ +#define AMBCTL0VAL 0xFFC2FFC2 +#define AMBCTL1VAL 0xFFC2FFC2 + +#define CONFIG_MEM_MT48LC16M16A2TG_75 1 +#define CONFIG_MEM_ADD_WDTH 9 /* 8, 9, 10, 11 */ +#define CONFIG_MEM_SIZE 64 /* 128, 64, 32, 16 */ + +#endif /* __CONFIG_H */ diff --git a/arch/blackfin/boards/ipe337/env/bin/_alternate b/arch/blackfin/boards/ipe337/env/bin/_alternate new file mode 100644 index 0000000..10ae213 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/_alternate @@ -0,0 +1,9 @@ +#!/bin/sh + +. /env/config + +alternate $ageing +if [ $? -lt 2 ]; then + echo "Error when accesing ageing-partition!" + exit 1 +fi diff --git a/arch/blackfin/boards/ipe337/env/bin/_update b/arch/blackfin/boards/ipe337/env/bin/_update new file mode 100644 index 0000000..5419ece --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/_update @@ -0,0 +1,37 @@ +#!/bin/sh + +if [ $# = 1 ]; then + image=$1 +fi + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "Erasing partition $part" +erase $part + +echo +echo "Flashing $image to $part" +tftp $image $part + +protect $part diff --git a/arch/blackfin/boards/ipe337/env/bin/boot b/arch/blackfin/boards/ipe337/env/bin/boot new file mode 100644 index 0000000..62807d2 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/boot @@ -0,0 +1,54 @@ +#!/bin/sh + +. /env/config + +alternate $ageing +ret=$? + +if [ $ret = 0 ]; then + echo "Error when accesing ageing-partition!" + exit 1 +elif [ $ret = 2 ]; then + act_kernel=/dev/nor0.kernel0 + act_rootfs=/dev/mtdblock5 +else + act_kernel=/dev/nor0.kernel1 + act_rootfs=/dev/mtdblock6 +fi +echo "-> Active kernel: $act_kernel" +echo "-> Active system: $act_rootfs" +echo + +if [ x$1 = xflash ]; then + root=flash + kernel=flash +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xflash ]; then + bootargs="$bootargs root=$act_rootfs rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm $act_kernel +fi diff --git a/arch/blackfin/boards/ipe337/env/bin/init b/arch/blackfin/boards/ipe337/env/bin/init new file mode 100644 index 0000000..e864dc5 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/init @@ -0,0 +1,24 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +addpart /dev/nor0 $mtdparts + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "Type update_kernel [] to update kernel into flash." + echo "Type update_system [] to update rootfs into flash." + echo "Type update_application [] to update applications into flash." + echo "Type update_persistent [] to update persistent into flash." + echo "Type update_bareboxenv [] to update bareboxenv into flash (use with care!)." + echo "Type reset_ageing to initialize the ageing partittion (use with care!)." + echo + exit +fi + +boot diff --git a/arch/blackfin/boards/ipe337/env/bin/magic.bin b/arch/blackfin/boards/ipe337/env/bin/magic.bin new file mode 100644 index 0000000..f8bff39 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/magic.bin @@ -0,0 +1 @@ +(i \ No newline at end of file diff --git a/arch/blackfin/boards/ipe337/env/bin/reset_ageing b/arch/blackfin/boards/ipe337/env/bin/reset_ageing new file mode 100644 index 0000000..2c95ae7 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/reset_ageing @@ -0,0 +1,27 @@ +#!/bin/sh + +. /env/config + +image=/env/bin/magic.bin +part=$ageing + +if [ \! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +unprotect $part + +echo +echo "Erasing partition $part" +erase $part + +echo +echo "Creating magic" +cp $image $part + +echo +echo "Testing partition" +. /env/bin/_alternate + +protect $part diff --git a/arch/blackfin/boards/ipe337/env/bin/update_application b/arch/blackfin/boards/ipe337/env/bin/update_application new file mode 100644 index 0000000..46ad210 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/update_application @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$appimage +part=/dev/nor0.application + +. /env/bin/_update $1 diff --git a/arch/blackfin/boards/ipe337/env/bin/update_bareboxenv b/arch/blackfin/boards/ipe337/env/bin/update_bareboxenv new file mode 100644 index 0000000..b0a32c6 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/update_bareboxenv @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$envimage +part=/dev/nor0.bareboxenv + +. /env/bin/_update $1 diff --git a/arch/blackfin/boards/ipe337/env/bin/update_kernel b/arch/blackfin/boards/ipe337/env/bin/update_kernel new file mode 100644 index 0000000..d5c210e --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/update_kernel @@ -0,0 +1,19 @@ +#!/bin/sh + +. /env/config + +image=$uimage + +alternate $ageing +ret=$? + +if [ $ret = 0 ]; then + echo "Error when accesing ageing-partition!" + exit 1 +elif [ $ret = 2 ]; then + part=/dev/nor0.kernel0 +else + part=/dev/nor0.kernel1 +fi + +. /env/bin/_update $1 diff --git a/arch/blackfin/boards/ipe337/env/bin/update_persistent b/arch/blackfin/boards/ipe337/env/bin/update_persistent new file mode 100644 index 0000000..a869b22 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/update_persistent @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$perimage +part=/dev/nor0.persistent + +. /env/bin/_update $1 diff --git a/arch/blackfin/boards/ipe337/env/bin/update_system b/arch/blackfin/boards/ipe337/env/bin/update_system new file mode 100644 index 0000000..598fc10 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/bin/update_system @@ -0,0 +1,19 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 + +alternate $ageing +ret=$? + +if [ $ret = 0 ]; then + echo "Error when accesing ageing-partition!" + exit 1 +elif [ $ret = 2 ]; then + part=/dev/nor0.system0 +else + part=/dev/nor0.system1 +fi + +. /env/bin/_update $1 diff --git a/arch/blackfin/boards/ipe337/env/config b/arch/blackfin/boards/ipe337/env/config new file mode 100644 index 0000000..7c5ee76 --- /dev/null +++ b/arch/blackfin/boards/ipe337/env/config @@ -0,0 +1,27 @@ +#!/bin/sh + +# can be either 'net' or 'flash' +kernel=net +root=net + +# use 'dhcp' todo dhcp in barebox and in kernel +#ip=dhcp + +eth0.ipaddr=192.168.23.164 +eth0.netmask=255.255.255.0 +eth0.gateway=192.168.23.2 +eth0.serverip=192.168.23.2 + +uimage=uImage-bfin +jffs2=root-bfin.jffs2 +appimage=apps-bfin +perimage=pers-bfin +envimage=uEnv-bfin + +autoboot_timeout=1 + +nfsroot="/ptx/work/octopus/wsa/svn/OSELAS.BSP-Pipetronix-ipe337-trunk/root" +bootargs="console=ttyBF0,115200" + +mtdparts="128k(barebox)ro,128k(bareboxenv),128k(ageing),1280k(kernel0),1280k(kernel1),8704k(system0),8704k(system1),8320k(application),4096k(persistent)" +ageing=/dev/nor0.ageing diff --git a/arch/blackfin/boards/ipe337/ipe337.c b/arch/blackfin/boards/ipe337/ipe337.c new file mode 100644 index 0000000..269e774 --- /dev/null +++ b/arch/blackfin/boards/ipe337/ipe337.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include +#include + +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0x20000000, + .size = 32 * 1024 * 1024, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = 0x0, + .size = 128 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +static struct device_d smc911x_dev = { + .name = "smc911x", + .map_base = 0x24000000, + .size = 4096, +}; + +static int ipe337_devices_init(void) { + register_device(&cfi_dev); + register_device(&sdram_dev); + + /* Reset smc911x */ + *pFIO0_DIR = (1<<12); + *pFIO0_FLAG_C = (1<<12); + mdelay(100); + *pFIO0_FLAG_S = (1<<12); + + register_device(&smc911x_dev); + + devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x20000, 0x20000, PARTITION_FIXED, "env0"); + + protect_file("/dev/env0", 1); + + return 0; +} + +device_initcall(ipe337_devices_init); + +static struct device_d blackfin_serial_device = { + .name = "blackfin_serial", + .map_base = 0, + .size = 4096, +}; + +static int blackfin_console_init(void) +{ + register_device(&blackfin_serial_device); + + return 0; +} + +console_initcall(blackfin_console_init); + diff --git a/arch/blackfin/boards/ipe337/ipe337.dox b/arch/blackfin/boards/ipe337/ipe337.dox new file mode 100644 index 0000000..4d7925a --- /dev/null +++ b/arch/blackfin/boards/ipe337/ipe337.dox @@ -0,0 +1,10 @@ +/** @page ipe337 ipe337 + +This CPU card is based on an Analog Device Blackfin CPU. The card is shipped +with: + +- 32MiB NOR type Flash Memory +- 128MiB synchronous dynamic RAM +- SMSC9xxx network controller + +*/ \ No newline at end of file diff --git a/arch/blackfin/configs/ipe337_defconfig b/arch/blackfin/configs/ipe337_defconfig index fd4ff66..33fd2fc 100644 --- a/arch/blackfin/configs/ipe337_defconfig +++ b/arch/blackfin/configs/ipe337_defconfig @@ -55,7 +55,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/ipe337/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/blackin/boards/ipe337/env" # # Debugging diff --git a/arch/m68k/Makefile b/arch/m68k/Makefile index f377325..ec70028 100644 --- a/arch/m68k/Makefile +++ b/arch/m68k/Makefile @@ -63,7 +63,7 @@ ifneq ($(board-y),) -BOARD := board/$(board-y)/ +BOARD := arch/m68k/boards/$(board-y)/ else BOARD := endif diff --git a/arch/m68k/boards/kp_ukd_r1_num/Makefile b/arch/m68k/boards/kp_ukd_r1_num/Makefile new file mode 100644 index 0000000..65f2a02 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/Makefile @@ -0,0 +1,31 @@ +# +# (C) Copyright 2007 Carsten Schlote +# See file CREDITS for list of people who contributed to this project. +# +# This file is part of barebox. +# +# barebox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# barebox 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 barebox. If not, see . +# + +# The build system allows to split everything into distinct files covering an +# separate issue. Use that! + +# Board specific callbacks and initialisations + +obj-y += lowlevel_init.o +obj-y += highlevel_init.o +obj-y += kp_ukd_r1_num.o + +obj-y += pci-stubs.o + diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/bin/_update b/arch/m68k/boards/kp_ukd_r1_num/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/bin/boot b/arch/m68k/boards/kp_ukd_r1_num/env/bin/boot new file mode 100644 index 0000000..c9fcbac --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/bin/boot @@ -0,0 +1,38 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xflash ]; then + root=flash + kernel=flash +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xflash ]; then + bootargs="$bootargs root=$rootpart rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm /dev/nor0.kernel +fi + diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/bin/init b/arch/m68k/boards/kp_ukd_r1_num/env/bin/init new file mode 100644 index 0000000..48e2139 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/bin/init @@ -0,0 +1,20 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +addpart /dev/nor0 $mtdparts + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type udate_root [] to update rootfs into flash" + echo + exit +fi + +boot \ No newline at end of file diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/bin/pcidmaloop b/arch/m68k/boards/kp_ukd_r1_num/env/bin/pcidmaloop new file mode 100644 index 0000000..24e76cb --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/bin/pcidmaloop @@ -0,0 +1,14 @@ +pci stat +pci stat -c +while true; do + pci readm 32 0xA1000000 32 -s + pci readm 32 0xA2000000 256 -s + pci dmatx 2000 a2000100 128 -s + pci writem 32 0xa2000100 0x12345678 4 -s + pci readm 32 0xA3000000 256 -s + pci dmatx 2000 a3000040 128 -s + pci writem 32 0xa3000100 0x12345678 4 -s + pci readm 32 0xA4000000 16 -s + pci dmatx 2000 a4000080 4 -s + pci writem 32 0xa4000080 0x12345678 4 -s +done diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/bin/pciloop b/arch/m68k/boards/kp_ukd_r1_num/env/bin/pciloop new file mode 100644 index 0000000..4a804f9 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/bin/pciloop @@ -0,0 +1,13 @@ +pci stat +pci stat -c +while true; do + pci readm 32 0xA1000000 32 -s + pci readm 32 0xA2000000 256 -s + pci writem 32 0xa2000100 0x12345678 4 -s + pci readm 32 0xA3000000 256 -s + pci writem 32 0xa3000100 0x12345678 4 -s + pci readm 32 0xA4000000 16 -s + pci writem 32 0xa4000080 0x12345678 4 -s + +# pci dmatx 2000 a3000040 128 -s +done diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/bin/update_kernel b/arch/m68k/boards/kp_ukd_r1_num/env/bin/update_kernel new file mode 100644 index 0000000..1ad95fc --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/bin/update_kernel @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$uimage +part=/dev/nor0.kernel + +. /env/bin/_update $1 diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/bin/update_root b/arch/m68k/boards/kp_ukd_r1_num/env/bin/update_root new file mode 100644 index 0000000..b757a5b --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/bin/update_root @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 +part=/dev/nor0.root + +. /env/bin/_update $1 diff --git a/arch/m68k/boards/kp_ukd_r1_num/env/config b/arch/m68k/boards/kp_ukd_r1_num/env/config new file mode 100644 index 0000000..14958ba --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/env/config @@ -0,0 +1,32 @@ +#!/bin/sh + +# can be either 'net' or 'flash' +kernel=net +root=net + +# use 'dhcp' todo dhcp in barebox and in kernel +ip=dhcp + +# +# setup default ethernet address +# +eth0.ipaddr=192.168.0.99 +eth0.netmask=255.255.255.0 +eth0.gateway=192.168.0.110 +eth0.serverip=192.168.0.110 + +uimage=uImage-mcf5475 +jffs2=root-mcf5475-ptx.jffs2 + +autoboot_timeout=3 + +#nfsroot="/home/cschlote/src/bitshrine/ltib/rootfs" +nfsroot="/home/cschlote/src/pengutronics/ptxdist-project-KP-UKD/root-debug,v3" +bootargs="console=ttyS0 rw initcall_debug debug" + +# +# setup the partitions in the main flash +# +mtdparts=512k(self),256k(env),3M(kernel),-(root) +rootpart="/dev/mtdblock3" + diff --git a/arch/m68k/boards/kp_ukd_r1_num/highlevel_init.c b/arch/m68k/boards/kp_ukd_r1_num/highlevel_init.c new file mode 100644 index 0000000..3a88cd6 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/highlevel_init.c @@ -0,0 +1,124 @@ +/* + * (C) 2007,2008 konzeptpark, Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + +/** @file + * @brief This file contains high-level init functions. + * + */ +#include +#include +#include +#include + +static void board_gpio_init(void) +{ + /* + * Enable Ethernet signals so that, if a cable is plugged into + * the ports, the lines won't be floating and potentially cause + * erroneous transmissions + */ + MCF_GPIO_PAR_FECI2CIRQ = 0 + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDC_EMDC + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDIO_EMDIO + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MII + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E17 + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDC + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDIO + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MII + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E07; +} + + +static void board_psc_init(void) +{ +#if (CFG_EARLY_UART_PORT == 0) + MCF_GPIO_PAR_PSC0 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC0_PAR_CTS0_CTS + | MCF_GPIO_PAR_PSC0_PAR_RTS0_RTS +#endif + | MCF_GPIO_PAR_PSC0_PAR_TXD0 + | MCF_GPIO_PAR_PSC0_PAR_RXD0); +#elif (CFG_EARLY_UART_PORT == 1) + MCF_GPIO_PAR_PSC1 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC1_PAR_CTS1_CTS + | MCF_GPIO_PAR_PSC1_PAR_RTS1_RTS +#endif + | MCF_GPIO_PAR_PSC1_PAR_TXD1 + | MCF_GPIO_PAR_PSC1_PAR_RXD1); +#elif (CFG_EARLY_UART_PORT == 2) + MCF_GPIO_PAR_PSC2 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC2_PAR_CTS2_CTS + | MCF_GPIO_PAR_PSC2_PAR_RTS2_RTS +#endif + | MCF_GPIO_PAR_PSC2_PAR_TXD2 + | MCF_GPIO_PAR_PSC2_PAR_RXD2); +#elif (CFG_EARLY_UART_PORT == 3) + MCF_GPIO_PAR_PSC3 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC3_PAR_CTS3_CTS + | MCF_GPIO_PAR_PSC3_PAR_RTS3_RTS +#endif + | MCF_GPIO_PAR_PSC3_PAR_TXD3 + | MCF_GPIO_PAR_PSC3_PAR_RXD3); +#else +#error "Invalid CFG_EARLY_UART_PORT setting" +#endif + + /* Put PSC in UART mode */ + MCF_PSC_SICR(CFG_EARLY_UART_PORT) = MCF_PSC_SICR_SIM_UART; + + /* Call generic UART initialization */ +// mcf5xxx_uart_init(DBUG_UART_PORT, board_get_baud()); +} + + +/** Do board specific early init + * + * @note We run at link address now, you can now call other code + */ +void board_init_highlevel(void) +{ + /* Initialize platform specific GPIOs */ + board_gpio_init(); + + /* Init UART GPIOs and Modes */ + board_psc_init(); + + /* Setup the early init data */ +#ifdef CONFIG_HAS_EARLY_INIT + early_init(); +#endif + /* Configure the early debug output facility */ +#ifdef CONFIG_DEBUG_LL + early_debug_init(); +#endif +} + +/** Provide address of early debug low-level output + * + * @todo Should return real address for UART register map. + */ +void *get_early_console_base(const char *name) +{ + return (void*)1 + CFG_EARLY_UART_PORT; +} diff --git a/arch/m68k/boards/kp_ukd_r1_num/kp_ukd_r1_num.c b/arch/m68k/boards/kp_ukd_r1_num/kp_ukd_r1_num.c new file mode 100644 index 0000000..9bf1713 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/kp_ukd_r1_num.c @@ -0,0 +1,153 @@ +/* + * (C) 2007 konzeptpark, Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + + +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include + +/* + * Return board clock in MHz FIXME move to clocks file + */ +ulong mcfv4e_get_bus_clk(void) +{ + return CFG_SYSTEM_CORE_CLOCK; +} +/* + * Up to 64MiB NOR type flash, connected to + * CS line 0, data width is 32 bit + */ +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = CFG_FLASH_ADDRESS, + .size = CFG_FLASH_SIZE, +}; + +/* + * up to 2MiB static RAM type memory, connected + * to CS4, data width is 16 bit + */ +//static struct device_d sram_dev = { +// .name = "sram", +//FIXME .map_base = IMX_CS4_BASE, +//FIXME .size = IMX_CS4_RANGE, /* area size */ +//}; + +/* + * ?MiB NAND type flash, data width 8 bit + */ +//static struct device_d nand_dev = { +// .name = "cfi_flash_nand", +// .map_base = 0xfc000000, /* FIXME */ +// .size = 32 * 1024 * 1024, /* FIXME */ +//}; + + +/* + * Build in FastEthernetControllers (FECs) + */ +static struct fec_platform_data fec_info = { + .xcv_type = MII100, +}; + +static struct device_d network_dev0 = { + .name = "fec_mcf54xx", + .map_base = MCF_FEC_ADDR(0), + .size = MCF_FEC_SIZE(0), /* area size */ + .platform_data = &fec_info, +}; +static struct device_d network_dev1 = { + .name = "fec_mcf54xx", + .map_base = MCF_FEC_ADDR(1), + .size = MCF_FEC_SIZE(1), /* area size */ + .platform_data = &fec_info, +}; + +/* + * 128MiB of SDRAM, data width is 32 bit + */ +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .map_base = CFG_SDRAM_ADDRESS, + .size = CFG_SDRAM_SIZE, + .platform_data = &ram_pdata, +}; + +static int mcfv4e_devices_init(void) +{ + printf("Setting up board devices...\n"); + + /* setup pins for I2C2 (for EEPROM, RTC) */ +//FIXME imx_gpio_mode(MUX_CSPI2_MOSI_I2C2_SCL); +//FIXME imx_gpio_mode(MUX_CSPI2_MISO_I2C2_SCL); + + register_device(&cfi_dev); + + /* + * Create partitions that should be + * not touched by any regular user + */ + devfs_add_partition("nor0", 0x00000, 0x80000, PARTITION_FIXED, "self0"); /* ourself */ + devfs_add_partition("nor0", 0x80000, 0x40000, PARTITION_FIXED, "env0"); /* environment */ + protect_file("/dev/env0", 1); + + //register_device(&sram_dev); + //register_device(&nand_dev); + + register_device(&network_dev0); + //register_device(&network_dev1); + + register_device(&sdram_dev); + + return 0; +} + +device_initcall(mcfv4e_devices_init); + +static struct device_d mcfv4e_serial_device = { + .name = "mcfv4e_serial", + .map_base = 1+CFG_EARLY_UART_PORT, + .size = 16 * 1024, +}; + +static int mcfv4e_console_init(void) +{ + /* init gpios for serial port */ + + /* Already set in lowlevel_init.c */ + + register_device(&mcfv4e_serial_device); + return 0; +} + +console_initcall(mcfv4e_console_init); + diff --git a/arch/m68k/boards/kp_ukd_r1_num/kp_ukd_r1_num.dox b/arch/m68k/boards/kp_ukd_r1_num/kp_ukd_r1_num.dox new file mode 100644 index 0000000..ca0fcbc --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/kp_ukd_r1_num.dox @@ -0,0 +1,13 @@ +/** @page kp_ukd_r1 konzeptpark MCB2 Prototype Board + +This target is based on a PhyTec PhyCore MCF54x5 NUM CPU. The card is shipped with: + +- up to 64MiB NOR type Flash Memory +- 128MiB synchronous dynamic RAM +- PCI USB 2.0 Host +- PCCard Controller +- MiniPCI Parallel +- MiniPCIe (USB lane only) +- ... + +*/ diff --git a/arch/m68k/boards/kp_ukd_r1_num/lowlevel_init.c b/arch/m68k/boards/kp_ukd_r1_num/lowlevel_init.c new file mode 100644 index 0000000..b3de505 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/lowlevel_init.c @@ -0,0 +1,183 @@ +/* + * (C) 2007 konzeptpark, Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + +/** @file + * @brief This file contains ... + * + */ +#include +#include +#include + +/** Initialize board specific very early inits + * + * @note This code is not allowed to call other code - just init + * your Chipselects and SDRAM stuff here! + */ +void board_init_lowlevel(void) +{ + /* + * The phyCORE-MCF548x has a 32MB or 64MB boot flash. + * The is a CF Card and ControlRegs on CS1 and CS2 + */ + + /* Setup SysGlue Chip-Select */ + MCF_FBCS_CSAR5 = MCF_FBCS_CSAR_BA(CFG_SYSGLUE_ADDRESS); + + MCF_FBCS_CSCR5 = (MCF_FBCS_CSCR_PS_32 + | MCF_FBCS_CSCR_AA + | MCF_FBCS_CSCR_ASET(1) + | MCF_FBCS_CSCR_WS(CFG_SYSGLUE_WAIT_STATES)); + + MCF_FBCS_CSMR5 = (MCF_FBCS_CSMR_BAM_16M + | MCF_FBCS_CSMR_V); + + /* Setup boot flash chip-select */ + MCF_FBCS_CSAR0 = MCF_FBCS_CSAR_BA(CFG_FLASH_ADDRESS); + + MCF_FBCS_CSCR0 = (MCF_FBCS_CSCR_PS_32 + | MCF_FBCS_CSCR_AA + | MCF_FBCS_CSCR_ASET(1) + | MCF_FBCS_CSCR_WS(CFG_FLASH_WAIT_STATES)); + + MCF_FBCS_CSMR0 = (MCF_FBCS_CSMR_BAM_32M + | MCF_FBCS_CSMR_V); + + /* + * Check to see if the SDRAM has already been initialized + * by a run control tool + */ + if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) + { + /* + * Basic configuration and initialization + */ + // 0x000002AA + MCF_SDRAMC_SDRAMDS = (0 + | MCF_SDRAMC_SDRAMDS_SB_E(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_C(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_A(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_S(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_D(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + ); + + // 0x0000001A + MCF_SDRAMC_CS0CFG = (0 + | MCF_SDRAMC_CSnCFG_CSBA(CFG_SDRAM_ADDRESS) + | MCF_SDRAMC_CSnCFG_CSSZ(MCF_SDRAMC_CSnCFG_CSSZ_128MBYTE) + ); + + MCF_SDRAMC_CS1CFG = 0; + MCF_SDRAMC_CS2CFG = 0; + MCF_SDRAMC_CS3CFG = 0; + + // 0x73611730 + MCF_SDRAMC_SDCFG1 = (0 + | MCF_SDRAMC_SDCFG1_SRD2RW((unsigned int)((CFG_SDRAM_CASL + CFG_SDRAM_BL / 2 + 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_SWT2RD((unsigned int) (CFG_SDRAM_TWR + 1)) + | MCF_SDRAMC_SDCFG1_RDLAT((unsigned int)((CFG_SDRAM_CASL * 2) + 2)) + | MCF_SDRAMC_SDCFG1_ACT2RW((unsigned int)(((CFG_SDRAM_TRCD / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_PRE2ACT((unsigned int)(((CFG_SDRAM_TRP / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_REF2ACT((unsigned int)(((CFG_SDRAM_TRFC / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_WTLAT(3) + ); + + // 0x46770000 + MCF_SDRAMC_SDCFG2 = (0 + | MCF_SDRAMC_SDCFG2_BRD2PRE(CFG_SDRAM_BL / 2) + | MCF_SDRAMC_SDCFG2_BWT2RW(CFG_SDRAM_BL / 2 + CFG_SDRAM_TWR) + | MCF_SDRAMC_SDCFG2_BRD2WT(7) + | MCF_SDRAMC_SDCFG2_BL(CFG_SDRAM_BL - 1) + ); + + /* + * Precharge and enable write to SDMR + */ + // 0xE10B0002 + MCF_SDRAMC_SDCR = (0 + | MCF_SDRAMC_SDCR_MODE_EN + | MCF_SDRAMC_SDCR_CKE + | MCF_SDRAMC_SDCR_DDR + | MCF_SDRAMC_SDCR_MUX(1) // 13 x 10 x 2 ==> MUX=1 + | MCF_SDRAMC_SDCR_RCNT((int)(((CFG_SDRAM_TREFI / (CFG_SYSTEM_CORE_PERIOD * 64)) - 1) + 0.5)) + | MCF_SDRAMC_SDCR_IPALL + ); + + /* + * Write extended mode register + */ + // 0x40010000 + MCF_SDRAMC_SDMR = (0 + | MCF_SDRAMC_SDMR_BNKAD_LEMR + | MCF_SDRAMC_SDMR_AD(0x0) + | MCF_SDRAMC_SDMR_CMD + ); + + /* + * Write mode register and reset DLL + */ + // 0x048d0000 + MCF_SDRAMC_SDMR = (0 + | MCF_SDRAMC_SDMR_BNKAD_LMR + | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_RESET_DLL | CFG_SDRAM_MOD) + | MCF_SDRAMC_SDMR_CMD + ); + + /* + * Execute a PALL command + */ + // 0xE10B0002 + MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL; + + /* + * Perform two REF cycles + */ + // 0xE10B0004 + MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; + MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; + + /* + * Write mode register and clear reset DLL + */ + // 0x008D0000 + MCF_SDRAMC_SDMR = (0 + | MCF_SDRAMC_SDMR_BNKAD_LMR + | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_MOD) + | MCF_SDRAMC_SDMR_CMD + ); + + /* + * Enable auto refresh and lock SDMR + */ + // 0x610B0000 + MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN; + + // 0x710B0F00 + MCF_SDRAMC_SDCR |= (0 + | MCF_SDRAMC_SDCR_REF + | MCF_SDRAMC_SDCR_DQS_OE(0xF) + ); + } +} + +/** @file + * + * Target specific early chipselect and SDRAM init. + */ diff --git a/arch/m68k/boards/kp_ukd_r1_num/pci-stubs.c b/arch/m68k/boards/kp_ukd_r1_num/pci-stubs.c new file mode 100644 index 0000000..b7ab7c7 --- /dev/null +++ b/arch/m68k/boards/kp_ukd_r1_num/pci-stubs.c @@ -0,0 +1,41 @@ +/* + * (C) 2007,2008 Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + +/** @file + * @brief This file contains callbacks for the PCI subsystem + * + */ +#include +#include + + +/** Returns mapping from PCI slot to CPU irq for the target board + * @return Coldfire IRQ vector number, or -1 for no irq + */ +int mcfv4e_pci_gethostirq(uint8_t slot, uint8_t irqpin) +{ + int rc = -1; + switch (slot) + { + case 16 : break; + case 17 ... 21 : rc = 64 + 7; break; // Eport IRQ7 + } + return rc; +} diff --git a/arch/m68k/boards/phycore_mcf54xx/Makefile b/arch/m68k/boards/phycore_mcf54xx/Makefile new file mode 100644 index 0000000..054123f --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/Makefile @@ -0,0 +1,31 @@ +# +# (C) Copyright 2007 Carsten Schlote +# See file CREDITS for list of people who contributed to this project. +# +# This file is part of barebox. +# +# barebox is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# barebox 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 barebox. If not, see . +# + +# The build system allows to split everything into distinct files covering an +# separate issue. Use that! + +# Board specific callbacks and initialisations + +obj-y += lowlevel_init.o +obj-y += highlevel_init.o +obj-y += phyCore_MCF54xx.o + +obj-y += pci-stubs.o + diff --git a/arch/m68k/boards/phycore_mcf54xx/env/bin/_update b/arch/m68k/boards/phycore_mcf54xx/env/bin/_update new file mode 100644 index 0000000..014bce3 --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/bin/_update @@ -0,0 +1,36 @@ +#!/bin/sh + +if [ -z "$part" -o -z "$image" ]; then + echo "define \$part and \$image" + exit 1 +fi + +if [ ! -e "$part" ]; then + echo "Partition $part does not exist" + exit 1 +fi + +if [ $# = 1 ]; then + image=$1 +fi + +if [ x$ip = xdhcp ]; then + dhcp +fi + +ping $eth0.serverip +if [ $? -ne 0 ] ; then + echo "update aborted" + exit 1 +fi + +unprotect $part + +echo +echo "erasing partition $part" +erase $part + +echo +echo "flashing $image to $part" +echo +tftp $image $part diff --git a/arch/m68k/boards/phycore_mcf54xx/env/bin/boot b/arch/m68k/boards/phycore_mcf54xx/env/bin/boot new file mode 100644 index 0000000..c9fcbac --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/bin/boot @@ -0,0 +1,38 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xflash ]; then + root=flash + kernel=flash +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xflash ]; then + bootargs="$bootargs root=$rootpart rootfstype=jffs2" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot" +fi + +bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootm /dev/nor0.kernel +fi + diff --git a/arch/m68k/boards/phycore_mcf54xx/env/bin/init b/arch/m68k/boards/phycore_mcf54xx/env/bin/init new file mode 100644 index 0000000..48e2139 --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/bin/init @@ -0,0 +1,20 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config +addpart /dev/nor0 $mtdparts + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + echo + echo "type update_kernel [] to update kernel into flash" + echo "type udate_root [] to update rootfs into flash" + echo + exit +fi + +boot \ No newline at end of file diff --git a/arch/m68k/boards/phycore_mcf54xx/env/bin/pcidmaloop b/arch/m68k/boards/phycore_mcf54xx/env/bin/pcidmaloop new file mode 100644 index 0000000..24e76cb --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/bin/pcidmaloop @@ -0,0 +1,14 @@ +pci stat +pci stat -c +while true; do + pci readm 32 0xA1000000 32 -s + pci readm 32 0xA2000000 256 -s + pci dmatx 2000 a2000100 128 -s + pci writem 32 0xa2000100 0x12345678 4 -s + pci readm 32 0xA3000000 256 -s + pci dmatx 2000 a3000040 128 -s + pci writem 32 0xa3000100 0x12345678 4 -s + pci readm 32 0xA4000000 16 -s + pci dmatx 2000 a4000080 4 -s + pci writem 32 0xa4000080 0x12345678 4 -s +done diff --git a/arch/m68k/boards/phycore_mcf54xx/env/bin/pciloop b/arch/m68k/boards/phycore_mcf54xx/env/bin/pciloop new file mode 100644 index 0000000..4a804f9 --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/bin/pciloop @@ -0,0 +1,13 @@ +pci stat +pci stat -c +while true; do + pci readm 32 0xA1000000 32 -s + pci readm 32 0xA2000000 256 -s + pci writem 32 0xa2000100 0x12345678 4 -s + pci readm 32 0xA3000000 256 -s + pci writem 32 0xa3000100 0x12345678 4 -s + pci readm 32 0xA4000000 16 -s + pci writem 32 0xa4000080 0x12345678 4 -s + +# pci dmatx 2000 a3000040 128 -s +done diff --git a/arch/m68k/boards/phycore_mcf54xx/env/bin/update_kernel b/arch/m68k/boards/phycore_mcf54xx/env/bin/update_kernel new file mode 100644 index 0000000..1ad95fc --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/bin/update_kernel @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$uimage +part=/dev/nor0.kernel + +. /env/bin/_update $1 diff --git a/arch/m68k/boards/phycore_mcf54xx/env/bin/update_root b/arch/m68k/boards/phycore_mcf54xx/env/bin/update_root new file mode 100644 index 0000000..b757a5b --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/bin/update_root @@ -0,0 +1,8 @@ +#!/bin/sh + +. /env/config + +image=$jffs2 +part=/dev/nor0.root + +. /env/bin/_update $1 diff --git a/arch/m68k/boards/phycore_mcf54xx/env/config b/arch/m68k/boards/phycore_mcf54xx/env/config new file mode 100644 index 0000000..5855062 --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/env/config @@ -0,0 +1,32 @@ +#!/bin/sh + +# can be either 'net' or 'flash' +kernel=net +root=net + +# use 'dhcp' todo dhcp in barebox and in kernel +ip=dhcp + +# +# setup default ethernet address +# +eth0.ipaddr=192.168.0.99 +eth0.netmask=255.255.255.0 +eth0.gateway=192.168.0.110 +eth0.serverip=192.168.0.110 + +uimage=uImage-mcf5485 +jffs2=root-mcf5485-ptx.jffs2 + +autoboot_timeout=3 + +#nfsroot="/home/cschlote/src/bitshrine/ltib/rootfs" +nfsroot="/home/cschlote/src/pengutronics/ptxdist-project-KP-UKD/root-debug,v3" +bootargs="console=ttyS0 rw initcall_debug debug" + +# +# setup the partitions in the main flash +# +mtdparts=512k(self),256k(env),3M(kernel),-(root) +rootpart="/dev/mtdblock3" + diff --git a/arch/m68k/boards/phycore_mcf54xx/highlevel_init.c b/arch/m68k/boards/phycore_mcf54xx/highlevel_init.c new file mode 100644 index 0000000..3a88cd6 --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/highlevel_init.c @@ -0,0 +1,124 @@ +/* + * (C) 2007,2008 konzeptpark, Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + +/** @file + * @brief This file contains high-level init functions. + * + */ +#include +#include +#include +#include + +static void board_gpio_init(void) +{ + /* + * Enable Ethernet signals so that, if a cable is plugged into + * the ports, the lines won't be floating and potentially cause + * erroneous transmissions + */ + MCF_GPIO_PAR_FECI2CIRQ = 0 + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDC_EMDC + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDIO_EMDIO + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MII + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E17 + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDC + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDIO + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MII + | MCF_GPIO_PAR_FECI2CIRQ_PAR_E07; +} + + +static void board_psc_init(void) +{ +#if (CFG_EARLY_UART_PORT == 0) + MCF_GPIO_PAR_PSC0 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC0_PAR_CTS0_CTS + | MCF_GPIO_PAR_PSC0_PAR_RTS0_RTS +#endif + | MCF_GPIO_PAR_PSC0_PAR_TXD0 + | MCF_GPIO_PAR_PSC0_PAR_RXD0); +#elif (CFG_EARLY_UART_PORT == 1) + MCF_GPIO_PAR_PSC1 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC1_PAR_CTS1_CTS + | MCF_GPIO_PAR_PSC1_PAR_RTS1_RTS +#endif + | MCF_GPIO_PAR_PSC1_PAR_TXD1 + | MCF_GPIO_PAR_PSC1_PAR_RXD1); +#elif (CFG_EARLY_UART_PORT == 2) + MCF_GPIO_PAR_PSC2 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC2_PAR_CTS2_CTS + | MCF_GPIO_PAR_PSC2_PAR_RTS2_RTS +#endif + | MCF_GPIO_PAR_PSC2_PAR_TXD2 + | MCF_GPIO_PAR_PSC2_PAR_RXD2); +#elif (CFG_EARLY_UART_PORT == 3) + MCF_GPIO_PAR_PSC3 = (0 +#ifdef HARDWARE_FLOW_CONTROL + | MCF_GPIO_PAR_PSC3_PAR_CTS3_CTS + | MCF_GPIO_PAR_PSC3_PAR_RTS3_RTS +#endif + | MCF_GPIO_PAR_PSC3_PAR_TXD3 + | MCF_GPIO_PAR_PSC3_PAR_RXD3); +#else +#error "Invalid CFG_EARLY_UART_PORT setting" +#endif + + /* Put PSC in UART mode */ + MCF_PSC_SICR(CFG_EARLY_UART_PORT) = MCF_PSC_SICR_SIM_UART; + + /* Call generic UART initialization */ +// mcf5xxx_uart_init(DBUG_UART_PORT, board_get_baud()); +} + + +/** Do board specific early init + * + * @note We run at link address now, you can now call other code + */ +void board_init_highlevel(void) +{ + /* Initialize platform specific GPIOs */ + board_gpio_init(); + + /* Init UART GPIOs and Modes */ + board_psc_init(); + + /* Setup the early init data */ +#ifdef CONFIG_HAS_EARLY_INIT + early_init(); +#endif + /* Configure the early debug output facility */ +#ifdef CONFIG_DEBUG_LL + early_debug_init(); +#endif +} + +/** Provide address of early debug low-level output + * + * @todo Should return real address for UART register map. + */ +void *get_early_console_base(const char *name) +{ + return (void*)1 + CFG_EARLY_UART_PORT; +} diff --git a/arch/m68k/boards/phycore_mcf54xx/lowlevel_init.c b/arch/m68k/boards/phycore_mcf54xx/lowlevel_init.c new file mode 100644 index 0000000..2837e3e --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/lowlevel_init.c @@ -0,0 +1,194 @@ +/* + * (C) 2007 konzeptpark, Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + +/** @file + * @brief This file contains ... + * + */ +#include +#include +#include + +/** Initialize board specific very early inits + * + * @note This code is not allowed to call other code - just init + * your Chipselects and SDRAM stuff here! + */ +void board_init_lowlevel(void) +{ + /* + * The phyCORE-MCF548x has a 32MB or 64MB boot flash. + * The is a CF Card and ControlRegs on CS1 and CS2 + */ + + /* Setup SysGlue Chip-Select for user IOs */ + MCF_FBCS_CSAR2 = MCF_FBCS_CSAR_BA(CFG_XPLD_ADDRESS); + + MCF_FBCS_CSCR2 = (MCF_FBCS_CSCR_PS_16 + | MCF_FBCS_CSCR_AA + | MCF_FBCS_CSCR_ASET(1) + | MCF_FBCS_CSCR_WS(CFG_XPLD_WAIT_STATES)); + + MCF_FBCS_CSMR2 = (MCF_FBCS_CSMR_BAM_16M + | MCF_FBCS_CSMR_V); + + /* Setup SysGlue Chip-Select for CFCARD */ + MCF_FBCS_CSAR1 = MCF_FBCS_CSAR_BA(CFG_CFCARD_ADDRESS); + + MCF_FBCS_CSCR1 = (MCF_FBCS_CSCR_PS_16 + | MCF_FBCS_CSCR_AA + | MCF_FBCS_CSCR_ASET(1) + | MCF_FBCS_CSCR_WS(CFG_CFCARD_WAIT_STATES)); + + MCF_FBCS_CSMR1 = (MCF_FBCS_CSMR_BAM_16M + | MCF_FBCS_CSMR_V); + + /* Setup boot flash chip-select */ + MCF_FBCS_CSAR0 = MCF_FBCS_CSAR_BA(CFG_FLASH_ADDRESS); + + MCF_FBCS_CSCR0 = (MCF_FBCS_CSCR_PS_32 + | MCF_FBCS_CSCR_AA + | MCF_FBCS_CSCR_ASET(1) + | MCF_FBCS_CSCR_WS(CFG_FLASH_WAIT_STATES)); + + MCF_FBCS_CSMR0 = (MCF_FBCS_CSMR_BAM_32M + | MCF_FBCS_CSMR_V); + + /* + * Check to see if the SDRAM has already been initialized + * by a run control tool + */ + if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) + { + /* + * Basic configuration and initialization + */ + // 0x000002AA + MCF_SDRAMC_SDRAMDS = (0 + | MCF_SDRAMC_SDRAMDS_SB_E(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_C(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_A(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_S(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + | MCF_SDRAMC_SDRAMDS_SB_D(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) + ); + + // 0x0000001A + MCF_SDRAMC_CS0CFG = (0 + | MCF_SDRAMC_CSnCFG_CSBA(CFG_SDRAM_ADDRESS) + | MCF_SDRAMC_CSnCFG_CSSZ(MCF_SDRAMC_CSnCFG_CSSZ_128MBYTE) + ); + + MCF_SDRAMC_CS1CFG = 0; + MCF_SDRAMC_CS2CFG = 0; + MCF_SDRAMC_CS3CFG = 0; + + // 0x73611730 + MCF_SDRAMC_SDCFG1 = (0 + | MCF_SDRAMC_SDCFG1_SRD2RW((unsigned int)((CFG_SDRAM_CASL + CFG_SDRAM_BL / 2 + 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_SWT2RD((unsigned int) (CFG_SDRAM_TWR + 1)) + | MCF_SDRAMC_SDCFG1_RDLAT((unsigned int)((CFG_SDRAM_CASL * 2) + 2)) + | MCF_SDRAMC_SDCFG1_ACT2RW((unsigned int)(((CFG_SDRAM_TRCD / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_PRE2ACT((unsigned int)(((CFG_SDRAM_TRP / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_REF2ACT((unsigned int)(((CFG_SDRAM_TRFC / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) + | MCF_SDRAMC_SDCFG1_WTLAT(3) + ); + + // 0x46770000 + MCF_SDRAMC_SDCFG2 = (0 + | MCF_SDRAMC_SDCFG2_BRD2PRE(CFG_SDRAM_BL / 2) + | MCF_SDRAMC_SDCFG2_BWT2RW(CFG_SDRAM_BL / 2 + CFG_SDRAM_TWR) + | MCF_SDRAMC_SDCFG2_BRD2WT(7) + | MCF_SDRAMC_SDCFG2_BL(CFG_SDRAM_BL - 1) + ); + + /* + * Precharge and enable write to SDMR + */ + // 0xE10B0002 + MCF_SDRAMC_SDCR = (0 + | MCF_SDRAMC_SDCR_MODE_EN + | MCF_SDRAMC_SDCR_CKE + | MCF_SDRAMC_SDCR_DDR + | MCF_SDRAMC_SDCR_MUX(1) // 13 x 10 x 2 ==> MUX=1 + | MCF_SDRAMC_SDCR_RCNT((int)(((CFG_SDRAM_TREFI / (CFG_SYSTEM_CORE_PERIOD * 64)) - 1) + 0.5)) + | MCF_SDRAMC_SDCR_IPALL + ); + + /* + * Write extended mode register + */ + // 0x40010000 + MCF_SDRAMC_SDMR = (0 + | MCF_SDRAMC_SDMR_BNKAD_LEMR + | MCF_SDRAMC_SDMR_AD(0x0) + | MCF_SDRAMC_SDMR_CMD + ); + + /* + * Write mode register and reset DLL + */ + // 0x048d0000 + MCF_SDRAMC_SDMR = (0 + | MCF_SDRAMC_SDMR_BNKAD_LMR + | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_RESET_DLL | CFG_SDRAM_MOD) + | MCF_SDRAMC_SDMR_CMD + ); + + /* + * Execute a PALL command + */ + // 0xE10B0002 + MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL; + + /* + * Perform two REF cycles + */ + // 0xE10B0004 + MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; + MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; + + /* + * Write mode register and clear reset DLL + */ + // 0x008D0000 + MCF_SDRAMC_SDMR = (0 + | MCF_SDRAMC_SDMR_BNKAD_LMR + | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_MOD) + | MCF_SDRAMC_SDMR_CMD + ); + + /* + * Enable auto refresh and lock SDMR + */ + // 0x610B0000 + MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN; + + // 0x710B0F00 + MCF_SDRAMC_SDCR |= (0 + | MCF_SDRAMC_SDCR_REF + | MCF_SDRAMC_SDCR_DQS_OE(0xF) + ); + } +} + +/** @file + * + * Target specific early chipselect and SDRAM init. + */ \ No newline at end of file diff --git a/arch/m68k/boards/phycore_mcf54xx/pci-stubs.c b/arch/m68k/boards/phycore_mcf54xx/pci-stubs.c new file mode 100644 index 0000000..b7ab7c7 --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/pci-stubs.c @@ -0,0 +1,41 @@ +/* + * (C) 2007,2008 Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + +/** @file + * @brief This file contains callbacks for the PCI subsystem + * + */ +#include +#include + + +/** Returns mapping from PCI slot to CPU irq for the target board + * @return Coldfire IRQ vector number, or -1 for no irq + */ +int mcfv4e_pci_gethostirq(uint8_t slot, uint8_t irqpin) +{ + int rc = -1; + switch (slot) + { + case 16 : break; + case 17 ... 21 : rc = 64 + 7; break; // Eport IRQ7 + } + return rc; +} diff --git a/arch/m68k/boards/phycore_mcf54xx/phyCore_MCF54xx.c b/arch/m68k/boards/phycore_mcf54xx/phyCore_MCF54xx.c new file mode 100644 index 0000000..3bc2d12 --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/phyCore_MCF54xx.c @@ -0,0 +1,134 @@ +/* + * (C) 2007 konzeptpark, Carsten Schlote + * See file CREDITS for list of people who contributed to this project. + * + * This file is part of barebox. + * + * barebox is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * barebox 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 barebox. If not, see . + */ + +/** @file + * @brief This file contains ... + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Return board clock in MHz FIXME move to clocks file + */ +ulong mcfv4e_get_bus_clk(void) +{ + return CFG_SYSTEM_CORE_CLOCK; +} + +/* + * Up to 64MiB NOR type flash, connected to + * CS line 0, data width is 32 bit + */ +static struct device_d cfi_dev = +{ + .name = "cfi_flash", + .map_base = CFG_FLASH_ADDRESS, + .size = CFG_FLASH_SIZE, +}; + +/* + * Build in FastEthernetControllers (FECs) + */ +static struct fec_platform_data fec_info = +{ + .xcv_type = MII100, +}; + +static struct device_d network_dev0 = +{ + .name = "fec_mcf54xx", + .map_base = MCF_FEC_ADDR(0), + .size = MCF_FEC_SIZE(0), /* area size */ + .platform_data = &fec_info, +}; +static struct device_d network_dev1 = +{ + .name = "fec_mcf54xx", + .map_base = MCF_FEC_ADDR(1), + .size = MCF_FEC_SIZE(1), /* area size */ + .platform_data = &fec_info, +}; + +/* + * 128MiB of SDRAM, data width is 32 bit + */ +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = +{ + .name = "mem", + .map_base = CFG_SDRAM_ADDRESS, + .size = CFG_SDRAM_SIZE, + .platform_data = &ram_pdata, +}; + +static int mcfv4e_devices_init(void) +{ + printf("FIXME - setup board devices...\n"); + + register_device(&cfi_dev); + + /* + * Create partitions that should be + * not touched by any regular user + */ + devfs_add_partition("nor0", 0x00000, 0x80000, PARTITION_FIXED, "self0"); /* ourself */ + devfs_add_partition("nor0", 0x80000, 0x40000, PARTITION_FIXED, "env0"); /* environment */ + protect_file("/dev/env0", 1); + + register_device(&network_dev0); + //register_device(&network_dev1); + + register_device(&sdram_dev); + + return 0; +} + +device_initcall(mcfv4e_devices_init); + +static struct device_d mcfv4e_serial_device = +{ + .name = "mcfv4e_serial", + .map_base = 1 + CFG_EARLY_UART_PORT, + .size = 16 * 1024, +}; + +static int mcfv4e_console_init(void) +{ + /* init gpios for serial port */ + + /* Already set in lowlevel_init.c */ + + register_device(&mcfv4e_serial_device); + return 0; +} + +console_initcall(mcfv4e_console_init); diff --git a/arch/m68k/boards/phycore_mcf54xx/phyCore_MCF54xx.dox b/arch/m68k/boards/phycore_mcf54xx/phyCore_MCF54xx.dox new file mode 100644 index 0000000..36dd0ad --- /dev/null +++ b/arch/m68k/boards/phycore_mcf54xx/phyCore_MCF54xx.dox @@ -0,0 +1,14 @@ + +/** @page phycore_mcf54xx Phytec's phyCORE-MCF54x5 + +This target is based on a PhyTec PhyCore MCF54x5 CPU module. The card is shipped with: + +- up to 64MiB NOR type Flash Memory +- 128MiB synchronous dynamic RAM +- PCI USB 2.0 Host +- PCCard Controller +- MiniPCI Parallel +- MiniPCIe (USB lane only) +- ... + +*/ diff --git a/arch/m68k/configs/phycore_kpukdr1_5475num_defconfig b/arch/m68k/configs/phycore_kpukdr1_5475num_defconfig index ba21a00..bb91152 100644 --- a/arch/m68k/configs/phycore_kpukdr1_5475num_defconfig +++ b/arch/m68k/configs/phycore_kpukdr1_5475num_defconfig @@ -71,7 +71,7 @@ CONFIG_EARLY_CONSOLE_BAUDRATE=115200 # CONFIG_OF_FLAT_TREE is not set CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/kp_ukd_r1_num/env/" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/m68k/boards/kp_ukd_r1_num/env/" # # Debugging diff --git a/arch/m68k/configs/phycore_mcf54xx_defconfig b/arch/m68k/configs/phycore_mcf54xx_defconfig index 34ca73f..f64ca8b 100644 --- a/arch/m68k/configs/phycore_mcf54xx_defconfig +++ b/arch/m68k/configs/phycore_mcf54xx_defconfig @@ -71,7 +71,7 @@ CONFIG_EARLY_CONSOLE_BAUDRATE=115200 # CONFIG_OF_FLAT_TREE is not set CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/phycore_mcf54xx/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/m68k/boards/phycore_mcf54xx/env" # # Debugging diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile index c24d3c3..46d64e5 100644 --- a/arch/ppc/Makefile +++ b/arch/ppc/Makefile @@ -35,7 +35,7 @@ ifneq ($(board-y),) -BOARD := board/$(board-y)/ +BOARD := arch/ppc/boards/$(board-y)/ else BOARD := endif diff --git a/arch/ppc/boards/pcm030/Makefile b/arch/ppc/boards/pcm030/Makefile new file mode 100644 index 0000000..e7d744b --- /dev/null +++ b/arch/ppc/boards/pcm030/Makefile @@ -0,0 +1,2 @@ +obj-y += pcm030.o +extra-y += barebox.lds diff --git a/arch/ppc/boards/pcm030/barebox.lds.S b/arch/ppc/boards/pcm030/barebox.lds.S new file mode 100644 index 0000000..ab99335 --- /dev/null +++ b/arch/ppc/boards/pcm030/barebox.lds.S @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +OUTPUT_ARCH("powerpc") +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + . = TEXT_BASE; + + /* Read-only sections, merged into text segment: */ + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + arch/ppc/mach-mpc5xxx/start.o (.text) + *(.text*) + *(.got1*) + . = ALIGN(16); + *(.rodata*) + *(.rodata1*) + *(.rodata.str1.4) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _etext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + + .data : + { + *(.data*) + *(.data1*) + *(.sdata*) + *(.sdata2*) + *(.dynamic*) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __barebox_cmd_start = .; + .barebox_cmd : { BAREBOX_CMDS } + __barebox_cmd_end = .; + + __barebox_initcalls_start = .; + .barebox_initcalls : { INITCALLS } + __barebox_initcalls_end = .; + __initcall_entries = (__barebox_initcalls_end - __barebox_initcalls_start) >> 2; + + __usymtab_start = .; + __usymtab : { BAREBOX_SYMS } + __usymtab_end = .; + + __early_init_data_begin = .; + .early_init_data : { *(.early_init_data) } + __early_init_data_end = .; + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __init_size = __init_end - _start; + + __bss_start = .; + .bss : + { + *(.sbss*) *(.scommon*) + *(.dynbss*) + *(.bss*) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/arch/ppc/boards/pcm030/config.h b/arch/ppc/boards/pcm030/config.h new file mode 100644 index 0000000..a772ee6 --- /dev/null +++ b/arch/ppc/boards/pcm030/config.h @@ -0,0 +1,110 @@ +/* + * (C) Copyright 2003-2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2006 + * Eric Schumann, Phytec Messatechnik GmbH + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#include + +/* #define DEBUG */ + +/*------------------------------------------------------------------------------------------------------------------------------------------------------ +High Level Configuration Options +(easy to change) + ------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CONFIG_MPC5200_DDR 1 /* (with DDR-SDRAM) */ +#define CFG_MPC5XXX_CLKIN 33333333 /* ... running at 33.333333MHz */ +#define BOOTFLAG_COLD 0x01 /* Normal Power-On: Boot from FLASH */ +#define BOOTFLAG_WARM 0x02 /* Software reboot */ + +/*------------------------------------------------------------------------------------------------------------------------------------------------------ +Serial console configuration + ------------------------------------------------------------------------------------------------------------------------------------------------------*/ + +#if (TEXT_BASE == 0xFF000000) /* Boot low */ +#define CFG_LOWBOOT 1 +#endif +/* RAMBOOT will be defined automatically in memory section */ + +/*------------------------------------------------------------------------------------------------------------------------------------------------------ +IPB Bus clocking configuration. + ------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CFG_IPBSPEED_133 /* define for 133MHz speed */ +#if defined(CFG_IPBSPEED_133) +/* + * PCI Bus clocking configuration + * + * Actually a PCI Clock of 66 MHz is only set (in cpu_init.c) if + * CFG_IPBSPEED_133 is defined. This is because a PCI Clock of 66 MHz yet hasn't + * been tested with a IPB Bus Clock of 66 MHz. + */ +#define CFG_PCISPEED_66 /* define for 66MHz speed */ +#else +#undef CFG_PCISPEED_66 /* for 33MHz speed */ +#endif + +/* we only use CS-Boot */ +#define CFG_BOOTCS_START 0xFF000000 +#define CFG_BOOTCS_SIZE 0x01000000 + +#if CONFIG_MACH_PHYCORE_MPC5200B_TINY_REV == 1 +#define CFG_BOOTCS_CFG 0x0008FD00 +#else +#define CFG_BOOTCS_CFG 0x00083800 +#endif + +/*------------------------------------------------------------------------------------------------------------------------------------------------------ + Memory map + ------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CFG_MBAR 0xF0000000 /* MBAR hast to be switched by other bootloader or debugger config */ +#define CFG_SDRAM_BASE 0x00000000 + +/* Use SRAM until RAM will be available */ +#define CFG_INIT_RAM_ADDR MPC5XXX_SRAM +#define CFG_INIT_RAM_SIZE MPC5XXX_SRAM_SIZE /* End of used area in DPRAM */ +#define CONFIG_EARLY_INITDATA_SIZE 0x100 + +#define CFG_BOOTMAPSZ (8 << 20) /* Initial Memory map for Linux */ + +/*------------------------------------------------------------------------------------------------------------------------------------------------------ + GPIO configuration + ------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CFG_GPS_PORT_CONFIG 0x00558c10 /* PSC6=UART, PSC3=UART ; Ether=100MBit with MD */ + +/*------------------------------------------------------------------------------------------------------------------------------------------------------ + Various low-level settings + ------------------------------------------------------------------------------------------------------------------------------------------------------*/ +#define CFG_HID0_INIT HID0_ICE | HID0_ICFI +#define CFG_HID0_FINAL HID0_ICE + +#define CFG_CS_BURST 0x00000000 +#define CFG_CS_DEADCYCLE 0x33333333 + +#define OF_CPU "PowerPC,5200@0" +#define OF_TBCLK CFG_MPC5XXX_CLKIN +#define OF_SOC "soc5200@f0000000" + +#endif /* __CONFIG_H */ diff --git a/arch/ppc/boards/pcm030/mt46v32m16-75.h b/arch/ppc/boards/pcm030/mt46v32m16-75.h new file mode 100644 index 0000000..4d191f1 --- /dev/null +++ b/arch/ppc/boards/pcm030/mt46v32m16-75.h @@ -0,0 +1,46 @@ +/* + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * Eric Schumann, Phytec Messtechnik + * adapted for mt46v32m16-75 DDR-RAM + * + * 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 + */ + +#define SDRAM_DDR 1 /* is DDR */ + +/* Settings for XLB = 132 MHz */ +#define SDRAM_MODE 0x018D0000 +#define SDRAM_EMODE 0x40090000 +#define SDRAM_CONTROL 0x715f0f00 +#define SDRAM_CONFIG1 0x73722930 +#define SDRAM_CONFIG2 0x47770000 + + +/* Settings for XLB = 99 MHz */ +/* +#define SDRAM_MODE 0x008D0000 +#define SDRAM_EMODE 0x40090000 +#define SDRAM_CONTROL 0x714b0f00 +#define SDRAM_CONFIG1 0x63611730 +#define SDRAM_CONFIG2 0x47670000 +*/ + +#define SDRAM_TAPDELAY 0x10000000 /* reserved Bit in MPC5200 B3-Step */ diff --git a/arch/ppc/boards/pcm030/pcm030.c b/arch/ppc/boards/pcm030/pcm030.c new file mode 100644 index 0000000..f3845ad --- /dev/null +++ b/arch/ppc/boards/pcm030/pcm030.c @@ -0,0 +1,235 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * (C) Copyright 2006 + * Eric Schumann, Phytec Messtechnik GmbH + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0xff000000, + .size = 16 * 1024 * 1024, +}; + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +struct device_d sdram_dev = { + .name = "mem", + .map_base = 0x0, + .size = 64 * 1024 * 1024, + .platform_data = &ram_pdata, +}; + +static struct mpc5xxx_fec_platform_data fec_info = { + .xcv_type = MII100, +}; + +struct device_d eth_dev = { + .name = "fec_mpc5xxx", + .map_base = MPC5XXX_FEC, + .platform_data = &fec_info, +}; + +static int devices_init (void) +{ + register_device(&cfi_dev); + register_device(&sdram_dev); + register_device(ð_dev); + + devfs_add_partition("nor0", 0x00f00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x00f60000, 0x20000, PARTITION_FIXED, "env0"); + + return 0; +} + +device_initcall(devices_init); + +static struct device_d psc3 = { + .name = "mpc5xxx_serial", + .map_base = MPC5XXX_PSC3, + .size = 4096, +}; + +static struct device_d psc6 = { + .name = "mpc5xxx_serial", + .map_base = MPC5XXX_PSC6, + .size = 4096, +}; + +static int console_init(void) +{ + register_device(&psc3); + register_device(&psc6); + return 0; +} + +console_initcall(console_init); + +void *get_early_console_base(const char *name) +{ + if (!strcmp(name, RELOC("psc3"))) + return (void *)MPC5XXX_PSC3; + if (!strcmp(name, RELOC("psc6"))) + return (void *)MPC5XXX_PSC6; + return NULL; +} + +#include "mt46v32m16-75.h" + +static void sdram_start (int hi_addr) +{ + long hi_addr_bit = hi_addr ? 0x01000000 : 0; + + /* unlock mode register */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000000 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + +#if SDRAM_DDR + /* set mode register: extended mode */ + *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_EMODE; + __asm__ volatile ("sync"); + + /* set mode register: reset DLL */ + *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE | 0x04000000; + __asm__ volatile ("sync"); +#endif + + /* precharge all banks */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* auto refresh */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000004 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* set mode register */ + *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE; + __asm__ volatile ("sync"); + + /* normal operation */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | hi_addr_bit; + __asm__ volatile ("sync"); +} + +/* + * ATTENTION: Although partially referenced initdram does NOT make real use + * use of CFG_SDRAM_BASE. The code does not work if CFG_SDRAM_BASE + * is something else than 0x00000000. + */ + +long int initdram (int board_type) +{ + ulong dramsize = 0; + ulong dramsize2 = 0; + + ulong test1, test2; + + if ((ulong)RELOC(initdram) > (2 << 30)) { + /* setup SDRAM chip selects */ + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x0000001b;/* 256MB at 0x0 */ + *(vu_long *)MPC5XXX_SDRAM_CS1CFG = 0x10000000;/* disabled */ + __asm__ volatile ("sync"); + + /* setup config registers */ + *(vu_long *)MPC5XXX_SDRAM_CONFIG1 = SDRAM_CONFIG1; + *(vu_long *)MPC5XXX_SDRAM_CONFIG2 = SDRAM_CONFIG2; + __asm__ volatile ("sync"); + +#if SDRAM_DDR && SDRAM_TAPDELAY + /* set tap delay */ + *(vu_long *)MPC5XXX_CDM_PORCFG = SDRAM_TAPDELAY; + __asm__ volatile ("sync"); +#endif + + /* find RAM size using SDRAM CS0 only */ + sdram_start(0); + test1 = get_ram_size((ulong *)CFG_SDRAM_BASE, 0x10000000); + sdram_start(1); + test2 = get_ram_size((ulong *)CFG_SDRAM_BASE, 0x10000000); + if (test1 > test2) { + sdram_start(0); + dramsize = test1; + } else { + dramsize = test2; + } + + /* memory smaller than 1MB is impossible */ + if (dramsize < (1 << 20)) { + dramsize = 0; + } + + /* set SDRAM CS0 size according to the amount of RAM found */ + if (dramsize > 0) { + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x13 + __builtin_ffs(dramsize >> 20) - 1; + } else { + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ + } + } else + puts(RELOC("skipping sdram initialization\n")); + + /* retrieve size of memory connected to SDRAM CS0 */ + dramsize = *(vu_long *)MPC5XXX_SDRAM_CS0CFG & 0xFF; + if (dramsize >= 0x13) { + dramsize = (1 << (dramsize - 0x13)) << 20; + } else { + dramsize = 0; + } + + /* retrieve size of memory connected to SDRAM CS1 */ + dramsize2 = *(vu_long *)MPC5XXX_SDRAM_CS1CFG & 0xFF; + if (dramsize2 >= 0x13) { + dramsize2 = (1 << (dramsize2 - 0x13)) << 20; + } else { + dramsize2 = 0; + } + + return dramsize + dramsize2; +} + +#if defined(CONFIG_OF_FLAT_TREE) && defined(CONFIG_OF_BOARD_SETUP) +void +ft_board_setup(void *blob, bd_t *bd) +{ + ft_cpu_setup(blob, bd); +} +#endif + diff --git a/arch/ppc/boards/pcm030/pcm030.dox b/arch/ppc/boards/pcm030/pcm030.dox new file mode 100644 index 0000000..b9ada83 --- /dev/null +++ b/arch/ppc/boards/pcm030/pcm030.dox @@ -0,0 +1,8 @@ +/** @page pcm030 Phytec's phyCORE-MPC5200B-tiny + +This CPU card is based on a Freescale MPC5200B CPU. The card is shipped with: + +- up to 16MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM + +*/ diff --git a/arch/sandbox/Makefile b/arch/sandbox/Makefile index 6b8942e..4ca17ed 100644 --- a/arch/sandbox/Makefile +++ b/arch/sandbox/Makefile @@ -3,8 +3,10 @@ machine-y := sandbox -board-y := sandbox -lds-y := board/sandbox/barebox.lds +board-y := arch/sandbox/board +BOARD := $(board-y)/ +lds-y := $(BOARD)/barebox.lds + TEXT_BASE = $(CONFIG_TEXT_BASE) @@ -62,6 +64,6 @@ -Wl,--start-group $(barebox-common) -Wl,--end-group \ -lrt -lpthread -common-y += board/sandbox/ arch/sandbox/os/ +common-y += $(BOARD) arch/sandbox/os/ -CLEAN_FILES += board/sandbox/barebox.lds +CLEAN_FILES += $(BOARD)/barebox.lds diff --git a/arch/sandbox/board/.gitignore b/arch/sandbox/board/.gitignore new file mode 100644 index 0000000..d116578 --- /dev/null +++ b/arch/sandbox/board/.gitignore @@ -0,0 +1 @@ +barebox.lds diff --git a/arch/sandbox/board/Makefile b/arch/sandbox/board/Makefile new file mode 100644 index 0000000..8abe5dd --- /dev/null +++ b/arch/sandbox/board/Makefile @@ -0,0 +1,9 @@ +obj-y += board.o +obj-y += clock.o +obj-y += hostfile.o +obj-y += console.o + +CPPFLAGS_barebox.lds = -U$(SUBARCH) -DELF_ARCH=$(ELF_ARCH) \ + -DELF_FORMAT="$(ELF_FORMAT)" +extra-y += barebox.lds + diff --git a/arch/sandbox/board/barebox.lds.S b/arch/sandbox/board/barebox.lds.S new file mode 100644 index 0000000..53e9f60 --- /dev/null +++ b/arch/sandbox/board/barebox.lds.S @@ -0,0 +1,229 @@ +#include + +OUTPUT_FORMAT(ELF_FORMAT) +OUTPUT_ARCH(ELF_ARCH) +ENTRY(_start) + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = 0x400000); . = 0x400000 + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rel.dyn : + { + *(.rel.init) + *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) + *(.rel.fini) + *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) + *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) + *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) + *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) + *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) + *(.rel.ctors) + *(.rel.dtors) + *(.rel.got) + *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) + *(.rel.ldata .rel.ldata.* .rel.gnu.linkonce.l.*) + *(.rel.lbss .rel.lbss.* .rel.gnu.linkonce.lb.*) + *(.rel.lrodata .rel.lrodata.* .rel.gnu.linkonce.lr.*) + } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : + { + KEEP (*(.init)) + } =0x90909090 + .plt : { *(.plt) } + .text : + { + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + } =0x90909090 + .fini : + { + KEEP (*(.fini)) + } =0x90909090 + + . = ALIGN(64); + __barebox_initcalls_start = .; + __barebox_initcalls : { INITCALLS } + __barebox_initcalls_end = .; + . = ALIGN(64); + __barebox_cmd_start = .; + __barebox_cmd : { BAREBOX_CMDS } + __barebox_cmd_end = .; + + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + /* Thread Local Storage sections */ + .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) } + . = DATA_SEGMENT_RELRO_END (24, .); + .got.plt : { *(.got.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we don't + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /DISCARD/ : { *(.note.GNU-stack) } +} + diff --git a/arch/sandbox/board/board.c b/arch/sandbox/board/board.c new file mode 100644 index 0000000..84017eb --- /dev/null +++ b/arch/sandbox/board/board.c @@ -0,0 +1,42 @@ +/* + * board.c + * + * Copyright (c) 2007 Sascha Hauer , 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 +#include +#include +#include +#include +#include + +static struct device_d tap_device = { + .name = "tap", +}; + +static int devices_init(void) +{ + register_device(&tap_device); + + return 0; +} + +device_initcall(devices_init); + diff --git a/arch/sandbox/board/clock.c b/arch/sandbox/board/clock.c new file mode 100644 index 0000000..b150864 --- /dev/null +++ b/arch/sandbox/board/clock.c @@ -0,0 +1,48 @@ +/* + * clock.c - wrapper between a barebox clocksource and linux + * + * Copyright (c) 2007 Sascha Hauer , 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 +#include +#include +#include + +static uint64_t linux_clocksource_read(void) +{ + return linux_get_time(); +} + +static struct clocksource cs = { + .read = linux_clocksource_read, + .mask = 0xffffffff, + .shift = 10, +}; + +static int clocksource_init (void) +{ + cs.mult = clocksource_hz2mult(1000 * 1000 * 1000, cs.shift); + + init_clock(&cs); + + return 0; +} + +core_initcall(clocksource_init); diff --git a/arch/sandbox/board/config.h b/arch/sandbox/board/config.h new file mode 100644 index 0000000..c96d762 --- /dev/null +++ b/arch/sandbox/board/config.h @@ -0,0 +1,6 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#define __SANDBOX__ + +#endif /* __CONFIG_H */ diff --git a/arch/sandbox/board/console.c b/arch/sandbox/board/console.c new file mode 100644 index 0000000..2959e85 --- /dev/null +++ b/arch/sandbox/board/console.c @@ -0,0 +1,52 @@ +/* + * console.c - register a console device + * + * Copyright (c) 2007 Sascha Hauer , 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 +#include +#include +#include + +int barebox_register_console(char *name, int stdinfd, int stdoutfd) +{ + struct device_d *dev; + struct linux_console_data *data; + + dev = xzalloc(sizeof(struct device_d) + sizeof(struct linux_console_data)); + + data = (struct linux_console_data *)(dev + 1); + + dev->platform_data = data; + strcpy(dev->name, name); + + strcpy(dev->name, "console"); + + if (stdinfd >= 0) + data->flags = CONSOLE_STDIN; + if (stdoutfd >= 0) + data->flags |= CONSOLE_STDOUT | CONSOLE_STDERR; + + data->stdoutfd = stdoutfd; + data->stdinfd = stdinfd; + + return register_device(dev); +} + diff --git a/arch/sandbox/board/env/bin/init b/arch/sandbox/board/env/bin/init new file mode 100644 index 0000000..a7cb7d5 --- /dev/null +++ b/arch/sandbox/board/env/bin/init @@ -0,0 +1,7 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + diff --git a/arch/sandbox/board/env/config b/arch/sandbox/board/env/config new file mode 100644 index 0000000..2b148b6 --- /dev/null +++ b/arch/sandbox/board/env/config @@ -0,0 +1,8 @@ +#!/bin/sh + +eth0.ipaddr=172.0.0.2 +eth0.netmask=255.255.255.0 +eth0.gateway=172.0.0.1 +eth0.serverip=172.0.0.1 +eth0.ethaddr=80:81:82:83:84:85 + diff --git a/arch/sandbox/board/hostfile.c b/arch/sandbox/board/hostfile.c new file mode 100644 index 0000000..ad625d7 --- /dev/null +++ b/arch/sandbox/board/hostfile.c @@ -0,0 +1,114 @@ +/* + * hostfile.c - use files from the host to simalute barebox devices + * + * Copyright (c) 2007 Sascha Hauer , 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 +#include +#include +#include +#include +#include +#include +#include + +struct hf_priv { + struct cdev cdev; + struct hf_platform_data *pdata; +}; + +static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags) +{ + struct hf_platform_data *hf = cdev->priv; + int fd = hf->fd; + + if (linux_lseek(fd, offset) != offset) + return -EINVAL; + + return linux_read(fd, buf, count); +} + +static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags) +{ + struct hf_platform_data *hf = cdev->priv; + int fd = hf->fd; + + if (linux_lseek(fd, offset) != offset) + return -EINVAL; + + return linux_write(fd, buf, count); +} + +static void hf_info(struct device_d *dev) +{ + struct hf_platform_data *hf = dev->platform_data; + + printf("file: %s\n", hf->filename); +} + +static struct file_operations hf_fops = { + .read = hf_read, + .write = hf_write, +}; + +static int hf_probe(struct device_d *dev) +{ + struct hf_platform_data *hf = dev->platform_data; + struct hf_priv *priv = xzalloc(sizeof(*priv)); + + priv->pdata = hf; + + priv->cdev.name = hf->name; + priv->cdev.size = hf->size; + priv->cdev.ops = &hf_fops; + priv->cdev.priv = hf; + devfs_create(&priv->cdev); + + return 0; +} + +static struct driver_d hf_drv = { + .name = "hostfile", + .probe = hf_probe, + .info = hf_info, +}; + +static int hf_init(void) +{ + return register_driver(&hf_drv); +} + +device_initcall(hf_init); + +int barebox_register_filedev(struct hf_platform_data *hf) +{ + struct device_d *dev; + + dev = xzalloc(sizeof(struct device_d)); + + dev->platform_data = hf; + + strcpy(dev->name, "hostfile"); + dev->size = hf->size; + dev->map_base = hf->map_base; + + return register_device(dev); +} + diff --git a/arch/sandbox/configs/sandbox_defconfig b/arch/sandbox/configs/sandbox_defconfig index adcb07e..9037c8b 100644 --- a/arch/sandbox/configs/sandbox_defconfig +++ b/arch/sandbox/configs/sandbox_defconfig @@ -41,7 +41,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/sandbox/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/sandbox/board/env" # # Debugging diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 2e2cb81..57c5dbc 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -26,7 +26,7 @@ ifneq ($(board-y),) -BOARD := board/$(board-y)/ +BOARD := arch/x86/boards/$(board-y)/ else BOARD := endif diff --git a/arch/x86/boards/x86_generic/Makefile b/arch/x86/boards/x86_generic/Makefile new file mode 100644 index 0000000..248240d --- /dev/null +++ b/arch/x86/boards/x86_generic/Makefile @@ -0,0 +1 @@ +obj-y += generic_pc.o diff --git a/arch/x86/boards/x86_generic/config.h b/arch/x86/boards/x86_generic/config.h new file mode 100644 index 0000000..39bea18 --- /dev/null +++ b/arch/x86/boards/x86_generic/config.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2009 Juergen Beisert, 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 + * + */ + +/* nothing special yet */ diff --git a/arch/x86/boards/x86_generic/env/bin/boot b/arch/x86/boards/x86_generic/env/bin/boot new file mode 100644 index 0000000..fcfffe3 --- /dev/null +++ b/arch/x86/boards/x86_generic/env/bin/boot @@ -0,0 +1,37 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xdisk ]; then + root=disk + kernel=disk +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xdisk ]; then + bootargs="$bootargs root=$rootpart_disk rootfstype=$rootpart_fs rw" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp rw" +fi + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootargs="BOOT_IMAGE=$kernel_device auto $bootargs" + linux16 $kernel_device +fi + diff --git a/arch/x86/boards/x86_generic/env/bin/init b/arch/x86/boards/x86_generic/env/bin/init new file mode 100644 index 0000000..2924a44 --- /dev/null +++ b/arch/x86/boards/x86_generic/env/bin/init @@ -0,0 +1,15 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + exit +fi + +boot diff --git a/arch/x86/boards/x86_generic/env/config b/arch/x86/boards/x86_generic/env/config new file mode 100644 index 0000000..dd57aad --- /dev/null +++ b/arch/x86/boards/x86_generic/env/config @@ -0,0 +1,31 @@ +# +# basic config +# +# boot source: 'disk' or 'net' +kernel=disk +root=disk + +# data for the NFS case +nfsroot="/path/to/nfs_root" + +# data for the disk case +kernel_device=/dev/biosdisk0.1 +rootpart_disk=/dev/sda1 +rootpart_fs=ext2 + +baudrate=115200 +serial=ttyS0 + +# use UART for console +bootargs="console=$serial,$baudrate" + +autoboot_timeout=3 + +# use 'dhcp' to do dhcp in uboot and in kernel +# ip=dhcp +# or set your networking parameters here +# eth0.ipaddr=192.168.3.11 +# eth0.netmask=255.255.255.0 +# eth0.gateway=a.b.c.d +# eth0.serverip=192.168.3.10 +# eth0.ethaddr=aa.bb.cc.dd.ee.ff diff --git a/arch/x86/boards/x86_generic/generic_pc.c b/arch/x86/boards/x86_generic/generic_pc.c new file mode 100644 index 0000000..bd93bc1 --- /dev/null +++ b/arch/x86/boards/x86_generic/generic_pc.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2009 Juergen Beisert, 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 + * + */ + +/** + * @file + * @brief Generic PC support to let barebox acting as a boot loader + */ + +#include +#include +#include +#include +#include +#include + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .size = 16 * 1024 * 1024, + .map_base = 0, + .platform_data = &ram_pdata, +}; + +static struct device_d bios_disk_dev = { + .name = "biosdrive", + .size = 1, +}; + +/* + * These datas are from the MBR, created by the linker and filled by the + * setup tool while installing barebox on the disk drive + */ +extern uint64_t pers_env_storage; +extern uint16_t pers_env_size; +extern uint8_t pers_env_drive; + +/** + * Persistant environment "not used" marker. + * Note: Must be in accordance to the value the tool "setup_mbr" writes. + */ +#define PATCH_AREA_PERS_SIZE_UNUSED 0x000 + +static int devices_init(void) +{ + int rc; + + sdram_dev.size = bios_get_memsize(); /* extended memory only */ + sdram_dev.size <<= 10; + + register_device(&sdram_dev); + register_device(&bios_disk_dev); + + if (pers_env_size != PATCH_AREA_PERS_SIZE_UNUSED) { + rc = devfs_add_partition("disk0", /* FIXME */ + pers_env_storage * 512, + (unsigned)pers_env_size * 512, + DEVFS_PARTITION_FIXED, "env0"); + printf("Partition: %d\n", rc); + } else + printf("No persistant storage defined\n"); + + return 0; +} +device_initcall(devices_init); + +#ifdef CONFIG_DRIVER_SERIAL_NS16550 + +static struct NS16550_plat serial_plat = { + .clock = 1843200, + .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR, + .reg_read = x86_uart_read, + .reg_write = x86_uart_write, +}; + +/* we are expecting always one serial interface */ +static struct device_d generic_pc_serial_device = { + .name = "serial_ns16550", + .map_base = 0x3f8, + .size = 8, + .platform_data = (void *)&serial_plat, +}; + +static int pc_console_init(void) +{ + /* Register the serial port */ + return register_device(&generic_pc_serial_device); +} +console_initcall(pc_console_init); + +#endif + +/** @page generic_pc Generic PC based bootloader + +This platform acts as a generic PC based bootloader. It depends on at least +one boot media that is connected locally (no network boot) and can be +handled by the regular BIOS (any kind of hard disks for example). + +The created @a barebox image can be used to boot a standard x86 bzImage +Linux kernel. + +Refer section @ref x86_bootloader_preparations how to do so. + +How to get the binary image: + +Using the default configuration: + +@code +make ARCH=x86 generic_defconfig +@endcode + +Build the binary image: + +@code +make ARCH=x86 CROSS_COMPILE=x86compiler +@endcode + +@note replace the 'x86compiler' with your x86 (cross) compiler. + +*/ diff --git a/arch/x86/configs/generic_defconfig b/arch/x86/configs/generic_defconfig index 091f696..3c72242 100644 --- a/arch/x86/configs/generic_defconfig +++ b/arch/x86/configs/generic_defconfig @@ -63,7 +63,7 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/x86_generic/env" +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/x86/boards/x86_generic/env" # # Debugging diff --git a/board/a9m2410/Makefile b/board/a9m2410/Makefile deleted file mode 100644 index 63026f0..0000000 --- a/board/a9m2410/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += lowlevel_init.o -obj-y += a9m2410.o diff --git a/board/a9m2410/a9m2410.c b/board/a9m2410/a9m2410.c deleted file mode 100644 index f327f82..0000000 --- a/board/a9m2410/a9m2410.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert, 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 - * - */ - -/** - * @file - * @brief a9m2410 Specific Board Initialization routines - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "ram", - .map_base = CS6_BASE, - .platform_data = &ram_pdata, -}; - -// {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0}, -static struct s3c24x0_nand_platform_data nand_info = { - .nand_timing = CALC_NFCONF_TIMING(A9M2410_TACLS, A9M2410_TWRPH0, A9M2410_TWRPH1) -}; - -static struct device_d nand_dev = { - .name = "s3c24x0_nand", - .map_base = S3C24X0_NAND_BASE, - .platform_data = &nand_info, -}; - -/* - * SMSC 91C111 network controller on the baseboard - * connected to CS line 1 and interrupt line - * GPIO3, data width is 32 bit - */ -static struct device_d network_dev = { - .name = "smc91c111", - .map_base = CS1_BASE + 0x300, - .size = 16, -}; - -static int a9m2410_devices_init(void) -{ - uint32_t reg; - - /* - * detect the current memory size - * Note: On this card the second SDRAM page is not used - */ - reg = readl(BANKSIZE); - - switch (reg &= 0x7) { - case 0: - sdram_dev.size = 32 * 1024 * 1024; - break; - case 1: - sdram_dev.size = 64 * 1024 * 1024; - break; - case 2: - sdram_dev.size = 128 * 1024 * 1024; - break; - case 4: - sdram_dev.size = 2 * 1024 * 1024; - break; - case 5: - sdram_dev.size = 4 * 1024 * 1024; - break; - case 6: - sdram_dev.size = 8 * 1024 * 1024; - break; - case 7: - sdram_dev.size = 16 * 1024 * 1024; - break; - } - - /* ---------- configure the GPIOs ------------- */ - writel(0x007FFFFF, GPACON); - writel(0x00000000, GPCCON); - writel(0x00000000, GPCUP); - writel(0x00000000, GPDCON); - writel(0x00000000, GPDUP); - writel(0xAAAAAAAA, GPECON); - writel(0x0000E03F, GPEUP); - writel(0x00000000, GPBCON); /* all inputs */ - writel(0x00000007, GPBUP); /* pullup disabled for GPB0..3 */ - writel(0x00009000, GPFCON); /* GPF7 CLK_INT#, GPF6 Debug-LED */ - writel(0x000000FF, GPFUP); - writel(readl(GPGDAT) | 0x0010, GPGDAT); /* switch off LCD backlight */ - writel(0xFF00A938, GPGCON); /* switch off USB device */ - writel(0x0000F000, GPGUP); - writel(readl(GPHDAT) | 0x100, GPHDAT); /* switch BOOTINT/GPIO_ON# to high */ - writel(0x000007FF, GPHUP); - writel(0x0029FAAA, GPHCON); - /* - * USB port1 normal, USB port0 normal, USB1 pads for device - * PCLK output on CLKOUT0, UPLL CLK output on CLKOUT1, - * 2nd SDRAM bank off (only bank 1 is used) - */ - writel(0x40140, MISCCR); - - /* ----------- configure the access to the outer space ---------- */ - reg = readl(BWSCON); - - /* CS#1 to access the network controller */ - reg &= ~0xf0; - reg |= 0xe0; - writel(0x1350, BANKCON1); - - /* CS#2 to the dual 16550 UART */ - reg &= ~0xf00; - reg |= 0x400; - writel(0x0d50, BANKCON2); - - writel(reg, BWSCON); - - /* release the reset signal to the network and UART device */ - reg = readl(MISCCR); - reg |= 0x10000; - writel(reg, MISCCR); - - /* ----------- the devices the boot loader should work with -------- */ - register_device(&nand_dev); - register_device(&sdram_dev); - register_device(&network_dev); - -#ifdef CONFIG_NAND - /* ----------- add some vital partitions -------- */ - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); -#endif - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)sdram_dev.map_base + 0x100); - armlinux_set_architecture(MACH_TYPE_A9M2410); - - return 0; -} - -device_initcall(a9m2410_devices_init); - -#ifdef CONFIG_S3C24XX_NAND_BOOT -void __bare_init nand_boot(void) -{ - s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0, 512); -} -#endif - -static struct device_d a9m2410_serial_device = { - .name = "s3c24x0_serial", - .map_base = UART1_BASE, - .size = UART1_SIZE, -}; - -static int a9m2410_console_init(void) -{ - register_device(&a9m2410_serial_device); - return 0; -} - -console_initcall(a9m2410_console_init); - -/** @page a9m2410 DIGI's a9m2410 - -This CPU card is based on a Samsung S3C2410 CPU. The card is shipped with: - -- S3C2410\@200 MHz (ARM920T/ARMv4T) -- 12MHz crystal reference -- SDRAM 32 MiB - - Samsung K4M563233E-EE1H - - 2M x 32Bit x 4 Banks Mobile SDRAM - - 90 pin FBGA - - CL3\@133MHz, CL2\@100MHz (CAS/RAS delay 19ns) - - four banks - - 32 bit data bits - - row address size is 11 - - Row cycle time: 69ns - - collumn address size is 9 bits - - Extended temperature range (-25�C...85�C) - - 64ms refresh period (4k) -- NAND Flash 32 MiB - - Samsung KM29U256T - - 32MiB 3,3V 8-bit - - ID: 0xEC, 0x75, 0x??, 0xBD - - 30ns/40ns/20ns -- I2C interface, 100KHz and 400KHz - - Real Time Clock - - Dallas DS1337 - - address 0x68 - - EEPROM - - ST M24LC64 - - address 0x50 - - 16bit addressing -- LCD interface -- Touch Screen interface -- Camera interface -- I2S interface -- AC97 Audio-CODEC interface -- SD card interface -- 3 serial RS232 interfaces -- Host and device USB interface, USB1.1 compliant -- Ethernet interface - - 10Mbps, Cirrus Logic, CS8900A (on the CPU card) or - - 10/100Mbps, SMSC 91C111 (on the baseboard) -- SPI interface -- JTAG interface - -How to get the binary image: - -Using the default configuration: - -@code -make ARCH=arm a9m2410_defconfig -@endcode - -Build the binary image: - -@code -make ARCH=arm CROSS_COMPILE=armv4compiler -@endcode - -@note replace the armv4compiler with your ARM v4 cross compiler. -*/ diff --git a/board/a9m2410/config.h b/board/a9m2410/config.h deleted file mode 100644 index 87b05fc..0000000 --- a/board/a9m2410/config.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @file - * @brief Global defintions for the ARM S3C2410 based a9m2410 CPU card - */ -/* This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -/** - * The external clock reference is a 12.0MHz crystal - */ -#define S3C24XX_CLOCK_REFERENCE 12000000 - -/** - * Define the main clock configuration to be used in register CLKDIVN - * - * We must limit the frequency of the connected SDRAMs with the clock ratio - * setup to 1:2:4. This will result into FCLK:HCLK:PCLK = 200Mhz:100MHz:50MHz - */ -#define BOARD_SPECIFIC_CLKDIVN 0x003 - -/** - * Define the MPLL configuration to be used in register MPLLCON - * - * We want the MPLL to run at 202.80MHz - */ -#define BOARD_SPECIFIC_MPLL ((0xA1 << 12) + (3 << 4) + 1) - -/** - * Define the UPLL configuration to be used in register UPLLCON - * - * We want the UPLL to run at 48.0MHz - */ -#define BOARD_SPECIFIC_UPLL ((0x78 << 12) + (2 << 4) + 3) - -/* - * SDRAM configuration for Samsung K4M563233E - * - 2M x 32Bit x 4 Banks Mobile SDRAM - * - 90 pin FBGA - * - CL2@100MHz - */ -/* - * SDRAM uses 32bit width - */ -#define BOARD_SPECIFIC_BWSCON ((0x02 << 24) + (0x02 << 28)) -/* - * 32MiB SDRAM in bank6 - * - MT = 11 (= sync dram type) - * - Trcd = 00 (= CL2) - * - SCAN = 01 (= 9 bit collumns) - */ -#define BOARD_SPECIFIC_BANKCON6 ((0x3 << 15) + (0x0 << 2) + 0x1) -/* - * No memory in bank7 - */ -#define BOARD_SPECIFIC_BANKCON7 ((0x3 << 15) + (0x0 << 2) + 0x1) -/* - * SDRAM refresh settings - * - REFEN = 1 (= refresh enabled) - * - TREFMD = 0 (= auto refresh) - * - Trp = 00 (= 2 RAS precharge clocks) - * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) - * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = 489 - */ -#define BOARD_SPECIFIC_REFRESH ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x1 << 18) + 489) -/* - * SDRAM banksize - * - BURST_EN = 1 (= burst mode enabled) - * - SCKE_EN = 1 (= SDRAM SCKE enabled) - * - SCLK_EN = 1 (= clock active only during accesses) - * - BK67MAP = 000 (= 32MiB) - */ -#define BOARD_SPECIFIC_BANKSIZE ((1 << 7) + (1 << 5) + (0 << 4) + 0) -/* - * SDRAM mode register bank6 - * CL = 010 (= 2 clocks) - */ -#define BOARD_SPECIFIC_MRSRB6 (0x2 << 4) -/* - * SDRAM mode register bank7 - * CL = 010 (= 2 clocks) - */ -#define BOARD_SPECIFIC_MRSRB7 (0x2 << 4) - -/* - * Flash access timings - * Tacls = 0ns (but 20ns data setup time) - * Twrph0 = 25ns (write) 35ns (read) - * Twrph1 = 10ns (10ns data hold time) - * Read cycle time = 50ns - * - * Assumed HCLK is 100MHz - * Tacls = 1 (-> 20ns) - * Twrph0 = 3 (-> 40ns) - * Twrph1 = 1 (-> 20ns) - * Cycle time = 80ns - */ -#define A9M2410_TACLS 1 -#define A9M2410_TWRPH0 3 -#define A9M2410_TWRPH1 1 - -/* needed in the generic NAND boot code only */ -#ifdef CONFIG_S3C24XX_NAND_BOOT -# define BOARD_DEFAULT_NAND_TIMING CALC_NFCONF_TIMING(A9M2410_TACLS, A9M2410_TWRPH0, A9M2410_TWRPH1) -#endif - -#endif /* __CONFIG_H */ diff --git a/board/a9m2410/env/bin/_update b/board/a9m2410/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/a9m2410/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/a9m2410/env/bin/boot b/board/a9m2410/env/bin/boot deleted file mode 100644 index 59fa60e..0000000 --- a/board/a9m2410/env/bin/boot +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - root=nand - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=\"NAND 32MiB 3,3V 8-bit:$nand_parts\"" - -if [ x$kernel = xnet ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/a9m2410/env/bin/hush_hack b/board/a9m2410/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/a9m2410/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/a9m2410/env/bin/init b/board/a9m2410/env/bin/init deleted file mode 100644 index 5ae44dd..0000000 --- a/board/a9m2410/env/bin/init +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type update_root [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/a9m2410/env/bin/update_kernel b/board/a9m2410/env/bin/update_kernel deleted file mode 100644 index c43a557..0000000 --- a/board/a9m2410/env/bin/update_kernel +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -. /env/config - -part=/dev/nand0.kernel.bb - -if [ x$1 = x ]; then - image=$uimage -else - image=$1 -fi - -. /env/bin/_update $image diff --git a/board/a9m2410/env/bin/update_root b/board/a9m2410/env/bin/update_root deleted file mode 100644 index 34139e5..0000000 --- a/board/a9m2410/env/bin/update_root +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = x ]; then - image=$jffs2 -else - image=$1 -fi - -. /env/bin/_update $image diff --git a/board/a9m2410/env/config b/board/a9m2410/env/config deleted file mode 100644 index 79150ce..0000000 --- a/board/a9m2410/env/config +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'nand'' -kernel=net -root=net - -uimage=uImage-a9m2410 -jffs2=root-a9m2410.jffs2 - -autoboot_timeout=3 - -nfsroot="/nfsexport/OSELAS.BSP-Hesch-TMU-1/platform-FS_A9M2410/root" -bootargs="console=ttySAC0,38400" - -nand_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" -rootpart_nand="/dev/mtdblock3" - -# use 'dhcp' to do dhcp in barebox and in kernel -#ip=dhcp - -# or set your networking parameters here -eth0.ipaddr=192.168.42.31 -eth0.netmask=255.255.0.0 -eth0.gateway=192.168.23.1 -eth0.serverip=192.168.23.2 -eth0.ethaddr=00:04:f3:00:06:35 diff --git a/board/a9m2410/lowlevel_init.S b/board/a9m2410/lowlevel_init.S deleted file mode 100644 index 461b93c..0000000 --- a/board/a9m2410/lowlevel_init.S +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - */ - -#include -#include - - .section ".text_bare_init.board_init_lowlevel","ax" - -.globl board_init_lowlevel -board_init_lowlevel: - - mov r10, lr /* save the link register */ - - bl s3c24x0_disable_wd - - /* skip everything here if we are already running from SDRAM */ - cmp pc, #S3C24X0_SDRAM_BASE - blo 1f - cmp pc, #S3C24X0_SDRAM_END - bhs 1f - - mov pc, r10 - -/* we are running from NOR or NAND/SRAM memory. Do further initialisation */ -1: - bl s3c24x0_pll_init - - bl s3c24x0_sdram_init - -#ifdef CONFIG_S3C24XX_NAND_BOOT - mov lr, r10 /* restore the link register */ -/* up to here we are running from the internal SRAM area */ - b s3c24x0_nand_boot /* does return directly to our caller into SDRAM */ -#else - mov pc, r10 -#endif diff --git a/board/a9m2440/Makefile b/board/a9m2440/Makefile deleted file mode 100644 index 779e83d..0000000 --- a/board/a9m2440/Makefile +++ /dev/null @@ -1,4 +0,0 @@ - -obj-y += lowlevel_init.o -obj-y += a9m2440.o -obj-$(CONFIG_MACH_A9M2410DEV) += a9m2410dev.o diff --git a/board/a9m2440/a9m2410dev.c b/board/a9m2440/a9m2410dev.c deleted file mode 100644 index 1220bd9..0000000 --- a/board/a9m2440/a9m2410dev.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert - * - * 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 - * - */ - -/** - * @file - * @brief a9m2410dev Baseboad specific initialization routines - * - */ - -#include -#include -#include -#include -#include - -/** - * Initialize the CPU to be able to work with the a9m2410dev evaluation board - */ -int a9m2410dev_devices_init(void) -{ - unsigned int reg; - - /* ---------- configure the GPIOs ------------- */ - writel(0x007FFFFF, GPACON); - writel(0x00000000, GPCCON); - writel(0x00000000, GPCUP); - writel(0x00000000, GPDCON); - writel(0x00000000, GPDUP); - writel(0xAAAAAAAA, GPECON); - writel(0x0000E03F, GPEUP); - writel(0x00000000, GPBCON); /* all inputs */ - writel(0x00000007, GPBUP); /* pullup disabled for GPB0..3 */ - writel(0x00009000, GPFCON); /* GPF7 CLK_INT#, GPF6 Debug-LED */ - writel(0x000000FF, GPFUP); - writel(readl(GPGDAT) | 0x1010, GPGDAT); /* switch off IDLE_SW#, switch off LCD backlight */ - writel(0x0100A93A, GPGCON); /* switch on USB device */ - writel(0x0000F000, GPGUP); - writel(0x0029FAAA, GPHCON); - - writel((1 << 12) | (0 << 11), GPJDAT); - writel(0x0016aaaa, GPJCON); - writel(~((0<<12)| (1<<11)), GPJUP); - - writel((0 << 12) | (0 << 11), GPJDAT); - writel(0x0016aaaa, GPJCON); - writel(0x00001fff, GPJUP); - - writel(0x00000000, DSC0); - writel(0x00000000, DSC1); - - /* - * USB port1 normal, USB port0 normal, USB1 pads for device - * PCLK output on CLKOUT0, UPLL CLK output on CLKOUT1, - */ - writel((readl(MISCCR) & ~0xFFFF) | 0x0140, MISCCR); - - /* ----------- configure the access to the outer space ---------- */ - reg = readl(BWSCON); - - /* CS#1 to access the network controller */ - reg &= ~0xf0; - reg |= 0xe0; - writel(0x1350, BANKCON1); - - /* CS#2 to the dual 16550 UART */ - reg &= ~0xf00; - reg |= 0x400; - writel(0x0d50, BANKCON2); - - writel(reg, BWSCON); - - /* release the reset signal to the network and UART device */ - reg = readl(MISCCR); - reg |= 0x10000; - writel(reg, MISCCR); - - return 0; -} diff --git a/board/a9m2440/a9m2440.c b/board/a9m2440/a9m2440.c deleted file mode 100644 index 2567f5e..0000000 --- a/board/a9m2440/a9m2440.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert, 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 - * - */ - -/** - * @file - * @brief a9m2440 Specific Board Initialization routines - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "baseboards.h" - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = CS6_BASE, - .platform_data = &ram_pdata, -}; - -static struct s3c24x0_nand_platform_data nand_info = { - .nand_timing = CALC_NFCONF_TIMING(A9M2440_TACLS, A9M2440_TWRPH0, A9M2440_TWRPH1) -}; - -static struct device_d nand_dev = { - .name = "s3c24x0_nand", - .map_base = S3C24X0_NAND_BASE, - .platform_data = &nand_info, -}; - -/* - * cs8900 network controller onboard - * Connected to CS line 5 + A24 and interrupt line EINT9, - * data width is 16 bit - */ -static struct device_d network_dev = { - .name = "cs8900", - .map_base = CS5_BASE + (1 << 24) + 0x300, - .size = 16, -}; - -static int a9m2440_check_for_ram(uint32_t addr) -{ - uint32_t tmp1, tmp2; - int rc = 0; - - tmp1 = readl(addr); - tmp2 = readl(addr + sizeof(uint32_t)); - - writel(0xaaaaaaaa, addr); - writel(0x55555555, addr + sizeof(uint32_t)); - if ((readl(addr) != 0xaaaaaaaa) || (readl(addr + sizeof(uint32_t)) != 0x55555555)) - rc = 1; /* seems no RAM */ - - writel(0x55555555, addr); - writel(0xaaaaaaaa, addr + sizeof(uint32_t)); - if ((readl(addr) != 0x55555555) || (readl(addr + sizeof(uint32_t)) != 0xaaaaaaaa)) - rc = 1; /* seems no RAM */ - - writel(tmp1, addr); - writel(tmp2, addr + sizeof(uint32_t)); - - return rc; -} - -static void a9m2440_disable_second_sdram_bank(void) -{ - writel(readl(BANKCON7) & ~(0x3 << 15),BANKCON7); - writel(readl(MISCCR) | (1 << 18), MISCCR); /* disable clock */ -} - -static int a9m2440_devices_init(void) -{ - uint32_t reg; - - /* - * The special SDRAM setup code for this machine will always enable - * both SDRAM banks. But the second SDRAM device may not exists! - * So we must check here, if the second bank is populated to get the - * correct RAM size. - */ - switch (readl(BANKSIZE) & 0x7) { - case 0: - if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 32 * 1024 * 1024)) - a9m2440_disable_second_sdram_bank(); - break; - case 1: - if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 64 * 1024 * 1024)) - a9m2440_disable_second_sdram_bank(); - break; - case 2: - if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 128 * 1024 * 1024)) - a9m2440_disable_second_sdram_bank(); - break; - case 4: - case 5: - case 6: /* not supported on this machine */ - break; - default: - if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 16 * 1024 * 1024)) - a9m2440_disable_second_sdram_bank(); - break; - } - - sdram_dev.size = s3c24x0_get_memory_size(); - - /* ----------- configure the access to the outer space ---------- */ - reg = readl(BWSCON); - - /* CS#5 to access the network controller */ - reg &= ~0x00f00000; - reg |= 0x00d00000; /* 16 bit */ - writel(0x1f4c, BANKCON5); - - writel(reg, BWSCON); - -#ifdef CONFIG_MACH_A9M2410DEV - a9m2410dev_devices_init(); -#endif - - /* release the reset signal to external devices */ - reg = readl(MISCCR); - reg |= 0x10000; - writel(reg, MISCCR); - - /* ----------- the devices the boot loader should work with -------- */ - register_device(&nand_dev); - register_device(&sdram_dev); - register_device(&network_dev); - -#ifdef CONFIG_NAND - /* ----------- add some vital partitions -------- */ - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); -#endif - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)sdram_dev.map_base + 0x100); - armlinux_set_architecture(MACH_TYPE_A9M2440); - - return 0; -} - -device_initcall(a9m2440_devices_init); - -#ifdef CONFIG_S3C24XX_NAND_BOOT -void __bare_init nand_boot(void) -{ - s3c24x0_nand_load_image((void *)TEXT_BASE, 256 * 1024, 0, 512); -} -#endif - -static struct device_d a9m2440_serial_device = { - .name = "s3c24x0_serial", - .map_base = UART1_BASE, - .size = UART1_SIZE, -}; - -static int a9m2440_console_init(void) -{ - register_device(&a9m2440_serial_device); - return 0; -} - -console_initcall(a9m2440_console_init); - -/** @page a9m2440 DIGI's a9m2440 - -This CPU card is based on a Samsung S3C2440 CPU. The card is shipped with: - -- S3C2440\@400 MHz or 533 MHz (ARM920T/ARMv4T) -- 16.9344 MHz crystal reference -- SDRAM 32/64/128 MiB - - Samsung K4M563233E-EE1H (one or two devices for 32 MiB or 64 MiB) - - 2M x 32bit x 4 Banks Mobile SDRAM - - CL2\@100 MHz (CAS/RAS delay 19ns) - - 105 MHz max - - collumn address size is 9 bits - - Row cycle time: 69ns - - Samsung K4M513233C-DG75 (one or two devices for 64 MiB or 128 MiB) - - 4M x 32bit x 4 Banks Mobile SDRAM - - CL2\@100MHz (CAS/RAS delay 18ns) - - 111 MHz max - - collumn address size is 9 bits - - Row cycle time: 63ns - - 64ms refresh period (4k) - - 90 pin FBGA - - 32 bit data bits - - Extended temperature range (-25�C...85�C) -- NAND Flash 32/64/128 MiB - - Samsung KM29U512T (NAND01GW3A0AN6) - - 64 MiB 3,3V 8-bit - - ID: 0xEC, 0x76, 0x??, 0xBD - - Samsung KM29U256T - - 32 MiB 3,3V 8-bit - - ID: 0xEC, 0x75, 0x??, 0xBD - - ST Micro - - 128 MiB 3,3V 8-bit - - ID: 0x20, 0x79 - - 30ns/40ns/20ns -- I2C interface, 100 KHz and 400 KHz - - Real Time Clock - - Dallas DS1337 - - address 0x68 - - EEPROM - - ST M24LC64 - - address 0x50 - - 16bit addressing -- LCD interface -- Touch Screen interface -- Camera interface -- I2S interface -- AC97 Audio-CODEC interface -- SD card interface -- 3 serial RS232 interfaces -- Host and device USB interface, USB1.1 compliant -- Ethernet interface - - 10Mbps, Cirrus Logic, CS8900A (on the CPU card) -- SPI interface -- JTAG interface - -How to get the binary image: - -Using the default configuration: - -@code -make ARCH=arm a9m2440_defconfig -@endcode - -Build the binary image: - -@code -make ARCH=arm CROSS_COMPILE=armv4compiler -@endcode - -@note replace the armv4compiler with your ARM v4 cross compiler. - -*/ diff --git a/board/a9m2440/baseboards.h b/board/a9m2440/baseboards.h deleted file mode 100644 index ec80312..0000000 --- a/board/a9m2440/baseboards.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert - * - * 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 - * - */ - -#ifdef CONFIG_MACH_A9M2410DEV -extern int a9m2410dev_devices_init(void); -#endif diff --git a/board/a9m2440/config.h b/board/a9m2440/config.h deleted file mode 100644 index 43cb6ab..0000000 --- a/board/a9m2440/config.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file - * @brief Global defintions for the ARM S3C2440 based a9m2440 CPU card - */ -/* This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -/** - * The external clock reference is a 16.9344 MHz crystal - */ -#define S3C24XX_CLOCK_REFERENCE 16934400 - -/** - * Define the main clock configuration to be used in register CLKDIVN - * - * We must limit the frequency of the connected SDRAMs with the clock ratio - * setup to 1:4:8. This will result into FCLK:HCLK:PCLK = 400Mhz:100MHz:50MHz - */ -#define BOARD_SPECIFIC_CLKDIVN 0x05 - -/** - * Define the MPLL configuration to be used in register MPLLCON - * - * We want the MPLL to run at 399.65 MHz - */ -#define BOARD_SPECIFIC_MPLL ((0x6e << 12) + (3 << 4) + 1) - -/** - * Define the UPLL configuration to be used in register UPLLCON - * - * We want the UPLL to run at 47.98 MHz - */ -#define BOARD_SPECIFIC_UPLL ((0x3c << 12) + (4 << 4) + 2) - -/* - * Flash access timings - * Tacls = 0ns (but 20ns data setup time) - * Twrph0 = 25ns (write) 35ns (read) - * Twrph1 = 10ns (10ns data hold time) - * Read cycle time = 50ns - * - * Assumed HCLK is 100MHz - * Tacls = 1 (-> 20ns) - * Twrph0 = 3 (-> 40ns) - * Twrph1 = 1 (-> 20ns) - * Cycle time = 80ns - */ -#define A9M2440_TACLS 1 -#define A9M2440_TWRPH0 3 -#define A9M2440_TWRPH1 1 - -/* needed in the generic NAND boot code only */ -#ifdef CONFIG_S3C24XX_NAND_BOOT -# define BOARD_DEFAULT_NAND_TIMING CALC_NFCONF_TIMING(A9M2440_TACLS, A9M2440_TWRPH0, A9M2440_TWRPH1) -#endif - -#endif /* __CONFIG_H */ diff --git a/board/a9m2440/env/bin/_update b/board/a9m2440/env/bin/_update deleted file mode 100644 index b10682e..0000000 --- a/board/a9m2440/env/bin/_update +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/a9m2440/env/bin/boot b/board/a9m2440/env/bin/boot deleted file mode 100644 index 86e22cf..0000000 --- a/board/a9m2440/env/bin/boot +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - root=nand - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -fi -if [ x$root = xnet ]; then - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" - if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" - else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" - fi -fi - -bootargs="$bootargs mtdparts=\"NAND 32MiB 3,3V 8-bit:$nand_parts\"" - -bootargs="$bootargs cs89x0_media=rj45 cs89x0_mac=$eth0.ethaddr" - -if [ x$kernel = xnet ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/a9m2440/env/bin/hush_hack b/board/a9m2440/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/a9m2440/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/a9m2440/env/bin/init b/board/a9m2440/env/bin/init deleted file mode 100644 index 5ae44dd..0000000 --- a/board/a9m2440/env/bin/init +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type update_root [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/a9m2440/env/bin/update_kernel b/board/a9m2440/env/bin/update_kernel deleted file mode 100644 index c43a557..0000000 --- a/board/a9m2440/env/bin/update_kernel +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -. /env/config - -part=/dev/nand0.kernel.bb - -if [ x$1 = x ]; then - image=$uimage -else - image=$1 -fi - -. /env/bin/_update $image diff --git a/board/a9m2440/env/bin/update_root b/board/a9m2440/env/bin/update_root deleted file mode 100644 index 46cbca5..0000000 --- a/board/a9m2440/env/bin/update_root +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh - -. /env/config - -part=/dev/nand0.root.bb - -if [ x$1 = x ]; then - image=$jffs2 -else - image=$1 -fi - -. /env/bin/_update $image diff --git a/board/a9m2440/env/config b/board/a9m2440/env/config deleted file mode 100644 index 936c35f..0000000 --- a/board/a9m2440/env/config +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'nand'' -kernel=net -root=net - -uimage=uImage-a9m2440 -jffs2=root-a9m2440.jffs2 - -autoboot_timeout=3 - -nfsroot="/nfsexport/OSELAS.BSP-Hesch-TMU-1/platform-FS_A9M2440/root" -bootargs="console=ttySAC0,38400" - -nand_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" -rootpart_nand="/dev/mtdblock3" - -# use 'dhcp' to do dhcp in barebox and in kernel -#ip=dhcp - -# or set your networking parameters here -eth0.ipaddr=192.168.42.32 -eth0.netmask=255.255.0.0 -eth0.gateway=192.168.23.1 -eth0.serverip=192.168.23.2 -eth0.ethaddr=00:04:f3:00:06:35 diff --git a/board/a9m2440/lowlevel_init.S b/board/a9m2440/lowlevel_init.S deleted file mode 100644 index 4b5c596..0000000 --- a/board/a9m2440/lowlevel_init.S +++ /dev/null @@ -1,240 +0,0 @@ -/* - * - */ - -#include -#include - - .section ".text_bare_init.board_init_lowlevel","ax" - -/* - * To be able to setup the SDRAM interface correctly, we need some - * external information about the connected SDRAM devices. - * - * When we set GPH8, we can read at GPB: - * Bit 0..1: Memory device size -> 00=16M, 01=64M, 10=32M, 11=128M - * Bit 2: CL setting - * - * Some remarks: The CL setting seems useless. It always signals a CL3 - * requirement, but the SDRAM types I found on the cards are supporting - * CL2 @ 100 MHz. But also these SDRAM types are only support 105 MHz max. - * So, we never need CL3 because we can't run the CPU at 533 MHz (which - * implies an 133 MHz SDRAM clock). - * All devices are connected via 32 bit databus - * - * Note: I was able to check the 32 MiB and 64 MiB configuration only. I didn't - * had access to a 16 MiB nor 128 MiB config. - * - */ - -sdram_init: - /* - * Read the configuration. After reset until any GPIO port is - * configured yet, these pins show external settings, to detect - * the SDRAM size. - */ - ldr r1, =GPBDAT - ldr r4, [r1] - and r4, r4, #0x3 - - ldr r1, =S3C24X0_MEMCTL_BASE - /* configure both SDRAM areas with 32 bit data bus width */ - ldr r0, =((0x2 << 24) + (0x2 << 28)) - str r0, [r1], #0x1c /* post add register offset for bank6 */ - - /* - * With the configuration we simply need to calculate an offset into - * our table with the predefined SDRAM settings - */ - adr r0, SDRAMDATA - mov r2, #6*4 /* # of bytes per table entry */ - mul r3, r4, r2 - add r0, r0, r3 /* start address of the entry */ - - /* - * store the table entry data into the registers - */ -1: - ldr r3, [r0], #4 - str r3, [r1], #4 - subs r2, r2, #4 - bne 1b - -/* TODO: Check if the second bank is populated, and switch it off if not */ - - mov pc, lr - -/* - * we need 4 sets of memory settings per main CPU clock speed - * - * 400MHz main speed: - * - 16 MiB in the first bank, maybe 16 MiB in the second bank (untested!) - * - 32 MiB in the first bank, maybe 32 MiB in the second bank (CL=2) - * - 64 MiB in the first bank, maybe 64 MiB in the second bank (CL=2) - * - 128 MiB in the first bank, maybe 128 MiB in the second bank (untested!) - * - * Note: SDRAM clock runs at 100MHz - */ - -SDRAMDATA: -/* --------------------------- 16 MiB @ 100MHz --------------------------- */ - /* - * - MT = 11 (= sync dram type) - * - Trcd = 01 (= CL3) - * - SCAN = 00 (= 8 bit collumns) - */ - .word ((0x3 << 15) + (0x1 << 2) + (0x0)) - .word ((0x3 << 15) + (0x1 << 2) + (0x0)) - /* - * SDRAM refresh settings - * - REFEN = 1 (= refresh enabled) - * - TREFMD = 0 (= auto refresh) - * - Trp = 00 (= 2 RAS precharge clocks) - * - Tsrc = 11 (= 7 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) - * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = FIXME - */ - .word ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x3 << 18) + 468) - /* - * SDRAM banksize - * - BURST_EN = 0 (= burst mode disabled) - * - SCKE_EN = 1 (= SDRAM SCKE enabled) - * - SCLK_EN = 1 (= clock active only during accesses) - * - BK67MAP = 010 (= 128MiB) FIXME????? - */ - .word ((0 << 7) + (1 << 5) + (1 << 4) + 2) - /* - * SDRAM mode register - * CL = 010 (= 2 clocks) - */ - .word (0x2 << 4) - .word (0x2 << 4) - -/* ------------- one or two banks with 64 MiB @ 100MHz -------------------- */ - - /* - * - MT = 11 (= sync dram type) - * - Trcd = 00 (= CL2) - * - SCAN = 01 (= 9 bit collumns) - */ - .word ((0x3 << 15) + (0x0 << 2) + (0x1)) - .word ((0x3 << 15) + (0x0 << 2) + (0x1)) - /* - * SDRAM refresh settings - * - REFEN = 1 (= refresh enabled) - * - TREFMD = 0 (= auto refresh) - * - Trp = 00 (= 2 RAS precharge clocks) - * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) - * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = 489 - */ - .word ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x1 << 18) + 489) - /* - * SDRAM banksize - * - BURST_EN = 1 (= burst mode enabled) - * - SCKE_EN = 1 (= SDRAM SCKE enabled) - * - SCLK_EN = 1 (= clock active only during accesses) - * - BK67MAP = 001 (= 64 MiB) - */ - .word ((1 << 7) + (1 << 5) + (1 << 4) + 1) - /* - * SDRAM mode register - * CL = 010 (= 2 clocks) - */ - .word (0x2 << 4) - .word (0x2 << 4) - -/* ------------- one or two banks with 32 MiB @ 100MHz -------------------- */ - - /* - * - MT = 11 (= sync dram type) - * - Trcd = 00 (= CL2) - * - SCAN = 01 (= 9 bit collumns) - */ - .word ((0x3 << 15) + (0x0 << 2) + (0x1)) - .word ((0x3 << 15) + (0x0 << 2) + (0x1)) - /* - * SDRAM refresh settings - * - REFEN = 1 (= refresh enabled) - * - TREFMD = 0 (= auto refresh) - * - Trp = 00 (= 2 RAS precharge clocks) - * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) - * - Refrsh = 2^11 + 1 - 100 * 15.6 = 2049 - 1560 = 489 - */ - .word ((0x1 << 23) + (0x0 << 22) + (0x0 << 20) + (0x1 << 18) + 489) - /* - * SDRAM banksize - * - BURST_EN = 1 (= burst mode enabled) - * - SCKE_EN = 1 (= SDRAM SCKE enabled) - * - SCLK_EN = 1 (= clock active only during accesses) - * - BK67MAP = 000 (= 32 MiB) - */ - .word ((1 << 7) + (1 << 5) + (1 << 4) + 0) - /* - * SDRAM mode register - * CL = 010 (= 2 clocks) - */ - .word (0x2 << 4) - .word (0x2 << 4) - -/* ------------ one or two banks with 128 MiB @ 100MHz -------------------- */ - - /* - * - MT = 11 (= sync dram type) - * - Trcd = 00 (= CL2) - * - SCAN = 01 (= 9 bit collumns) - */ - .word ((0x3 << 15) + (0x0 << 2) + (0x1)) - .word ((0x3 << 15) + (0x0 << 2) + (0x1)) - /* - * SDRAM refresh settings - * - REFEN = 1 (= refresh enabled) - * - TREFMD = 0 (= auto refresh) - * - Trp = 00 (= 2 RAS precharge clocks) - * - Tsrc = 01 (= 5 clocks -> row cycle time @100MHz 2+5=7 -> 70ns) - * - Refrsh = 2^11 + 1 - 100 * 7.5 = 2049 - FIXME = 1259 - */ - .word ((0x1 << 23) + (0x0 << 22) + (0x1 << 20) + (0x3 << 18) + 1259) - /* - * SDRAM banksize - * - BURST_EN = 0 (= burst mode disabled) - * - SCKE_EN = 1 (= SDRAM SCKE enabled) - * - SCLK_EN = 1 (= clock active only during accesses) - * - BK67MAP = 010 (= 128MiB) - */ - .word (0x32) - /* - * SDRAM mode register - * CL = 010 (= 2 clocks) - */ - .word (0x2 << 4) - .word (0x2 << 4) - -/* ------------------------------------------------------------------------ */ - -.globl board_init_lowlevel -board_init_lowlevel: - - mov r10, lr /* save the link register */ - - bl s3c24x0_disable_wd - - /* skip everything here if we are already running from SDRAM */ - cmp pc, #S3C24X0_SDRAM_BASE - blo 1f - cmp pc, #S3C24X0_SDRAM_END - bhs 1f - - mov pc, r10 - -/* we are running from NOR or NAND/SRAM memory. Do further initialisation */ -1: - bl s3c24x0_pll_init - - bl sdram_init - -#ifdef CONFIG_S3C24XX_NAND_BOOT - mov lr, r10 /* restore the link register */ -/* up to here we are running from the internal SRAM area */ - b s3c24x0_nand_boot /* does return directly to our caller into SDRAM */ -#else - mov pc, r10 -#endif diff --git a/board/at91sam9260ek/Makefile b/board/at91sam9260ek/Makefile deleted file mode 100644 index 73ef72e..0000000 --- a/board/at91sam9260ek/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-y += lowlevel_init.o -obj-y += init.o diff --git a/board/at91sam9260ek/config.h b/board/at91sam9260ek/config.h deleted file mode 100644 index afd8563..0000000 --- a/board/at91sam9260ek/config.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ - -#endif /* __CONFIG_H */ diff --git a/board/at91sam9260ek/env/bin/_update b/board/at91sam9260ek/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/at91sam9260ek/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/at91sam9260ek/env/bin/boot b/board/at91sam9260ek/env/bin/boot deleted file mode 100644 index ed6f11a..0000000 --- a/board/at91sam9260ek/env/bin/boot +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xflash ]; then - root=flash - kernel=flash -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xflash ]; then - bootargs="$bootargs root=$rootpart rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=192.168.23.111:$nfsroot" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage - bootm uImage -else - bootm /dev/nor0.kernel -fi - diff --git a/board/at91sam9260ek/env/bin/init b/board/at91sam9260ek/env/bin/init deleted file mode 100644 index b8d8399..0000000 --- a/board/at91sam9260ek/env/bin/init +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type udate_root [] to update rootfs into flash" - echo - exit -fi - -boot \ No newline at end of file diff --git a/board/at91sam9260ek/env/bin/pcidmaloop b/board/at91sam9260ek/env/bin/pcidmaloop deleted file mode 100644 index 24e76cb..0000000 --- a/board/at91sam9260ek/env/bin/pcidmaloop +++ /dev/null @@ -1,14 +0,0 @@ -pci stat -pci stat -c -while true; do - pci readm 32 0xA1000000 32 -s - pci readm 32 0xA2000000 256 -s - pci dmatx 2000 a2000100 128 -s - pci writem 32 0xa2000100 0x12345678 4 -s - pci readm 32 0xA3000000 256 -s - pci dmatx 2000 a3000040 128 -s - pci writem 32 0xa3000100 0x12345678 4 -s - pci readm 32 0xA4000000 16 -s - pci dmatx 2000 a4000080 4 -s - pci writem 32 0xa4000080 0x12345678 4 -s -done diff --git a/board/at91sam9260ek/env/bin/pciloop b/board/at91sam9260ek/env/bin/pciloop deleted file mode 100644 index 4a804f9..0000000 --- a/board/at91sam9260ek/env/bin/pciloop +++ /dev/null @@ -1,13 +0,0 @@ -pci stat -pci stat -c -while true; do - pci readm 32 0xA1000000 32 -s - pci readm 32 0xA2000000 256 -s - pci writem 32 0xa2000100 0x12345678 4 -s - pci readm 32 0xA3000000 256 -s - pci writem 32 0xa3000100 0x12345678 4 -s - pci readm 32 0xA4000000 16 -s - pci writem 32 0xa4000080 0x12345678 4 -s - -# pci dmatx 2000 a3000040 128 -s -done diff --git a/board/at91sam9260ek/env/bin/update_kernel b/board/at91sam9260ek/env/bin/update_kernel deleted file mode 100644 index 1ad95fc..0000000 --- a/board/at91sam9260ek/env/bin/update_kernel +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -part=/dev/nor0.kernel - -. /env/bin/_update $1 diff --git a/board/at91sam9260ek/env/bin/update_root b/board/at91sam9260ek/env/bin/update_root deleted file mode 100644 index b757a5b..0000000 --- a/board/at91sam9260ek/env/bin/update_root +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 -part=/dev/nor0.root - -. /env/bin/_update $1 diff --git a/board/at91sam9260ek/env/config b/board/at91sam9260ek/env/config deleted file mode 100644 index 71d6f88..0000000 --- a/board/at91sam9260ek/env/config +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'flash' -kernel=net -root=net - -# use 'dhcp' todo dhcp in barebox and in kernel -ip=dhcp - -# -# setup default ethernet address -# -eth0.serverip=192.168.23.108 - -uimage=uImage-at91sam9260ek - -autoboot_timeout=3 - -nfsroot="/home/jbe/pengutronix/bsp/OSELAS.BSP-Phytec-phyCORE-i.MX27-trunk/root,v3" -bootargs="console=ttyS0,115200 rw init=/bin/sh" diff --git a/board/at91sam9260ek/init.c b/board/at91sam9260ek/init.c deleted file mode 100644 index 9fd7525..0000000 --- a/board/at91sam9260ek/init.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct atmel_nand_data nand_pdata = { - .ale = 21, - .cle = 22, -/* .det_pin = ... not connected */ - .ecc_base = (void __iomem *)(AT91_BASE_SYS + AT91_ECC), - .ecc_mode = NAND_ECC_HW, - .rdy_pin = AT91_PIN_PC13, - .enable_pin = AT91_PIN_PC14, -#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16) - .bus_width_16 = 1, -#else - .bus_width_16 = 0, -#endif -}; - -static struct sam9_smc_config ek_nand_smc_config = { - .ncs_read_setup = 0, - .nrd_setup = 1, - .ncs_write_setup = 0, - .nwe_setup = 1, - - .ncs_read_pulse = 3, - .nrd_pulse = 3, - .ncs_write_pulse = 3, - .nwe_pulse = 3, - - .read_cycle = 5, - .write_cycle = 5, - - .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, - .tdf_cycles = 2, -}; - -static void ek_add_device_nand(void) -{ - /* setup bus-width (8 or 16) */ - if (nand_pdata.bus_width_16) - ek_nand_smc_config.mode |= AT91_SMC_DBW_16; - else - ek_nand_smc_config.mode |= AT91_SMC_DBW_8; - - /* configure chip-select 3 (NAND) */ - sam9_smc_configure(3, &ek_nand_smc_config); - - at91_add_device_nand(&nand_pdata); -} - -static struct at91_ether_platform_data macb_pdata = { - .flags = AT91SAM_ETHER_RMII, - .phy_addr = 0, -}; - -static void at91sam9260ek_phy_reset(void) -{ - unsigned long rstc; - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_EMAC); - - at91_set_gpio_input(AT91_PIN_PA14, 0); - at91_set_gpio_input(AT91_PIN_PA15, 0); - at91_set_gpio_input(AT91_PIN_PA17, 0); - at91_set_gpio_input(AT91_PIN_PA25, 0); - at91_set_gpio_input(AT91_PIN_PA26, 0); - at91_set_gpio_input(AT91_PIN_PA28, 0); - - rstc = at91_sys_read(AT91_RSTC_MR) & AT91_RSTC_ERSTL; - - /* Need to reset PHY -> 500ms reset */ - at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | - (AT91_RSTC_ERSTL & (0x0d << 8)) | - AT91_RSTC_URSTEN); - - at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_EXTRST); - - /* Wait for end hardware reset */ - while (!(at91_sys_read(AT91_RSTC_SR) & AT91_RSTC_NRSTL)); - - /* Restore NRST value */ - at91_sys_write(AT91_RSTC_MR, AT91_RSTC_KEY | - (rstc) | - AT91_RSTC_URSTEN); -} - -static int at91sam9260ek_devices_init(void) -{ - ek_add_device_nand(); - at91sam9260ek_phy_reset(); - at91_add_device_eth(&macb_pdata); - - at91_add_device_sdram(64 * 1024 * 1024); - armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); - armlinux_set_architecture(MACH_TYPE_AT91SAM9260EK); - - devfs_add_partition("nand0", 0x00000, 0x80000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x40000, 0x40000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - - return 0; -} - -device_initcall(at91sam9260ek_devices_init); - -static int at91sam9260ek_console_init(void) -{ - at91_register_uart(0, 0); - return 0; -} - -console_initcall(at91sam9260ek_console_init); diff --git a/board/at91sam9260ek/lowlevel_init.S b/board/at91sam9260ek/lowlevel_init.S deleted file mode 100644 index 4961682..0000000 --- a/board/at91sam9260ek/lowlevel_init.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Board specific setup info - * - * - * 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 - */ - -.globl board_init_lowlevel -board_init_lowlevel: - mov pc, lr diff --git a/board/at91sam9263ek/Makefile b/board/at91sam9263ek/Makefile deleted file mode 100644 index eb072c0..0000000 --- a/board/at91sam9263ek/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += init.o diff --git a/board/at91sam9263ek/config.h b/board/at91sam9263ek/config.h deleted file mode 100644 index 9cc8af2..0000000 --- a/board/at91sam9263ek/config.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -#define AT91_MASTER_CLOCK 100000000 /* peripheral = main / 2 */ - -#define MASTER_PLL_MUL 171 -#define MASTER_PLL_DIV 14 - -/* clocks */ -#define CONFIG_SYS_MOR_VAL \ - (AT91_PMC_MOSCEN | \ - (255 << 8)) /* Main Oscillator Start-up Time */ -#define CONFIG_SYS_PLLAR_VAL \ - (AT91_PMC_PLLA_WR_ERRATA | /* Bit 29 must be 1 when prog */ \ - AT91_PMC_OUT | \ - AT91_PMC_PLLCOUNT | /* PLL Counter */ \ - (2 << 28) | /* PLL Clock Frequency Range */ \ - ((MASTER_PLL_MUL - 1) << 16) | (MASTER_PLL_DIV)) - -/* PCK/2 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR1_VAL \ - (AT91_PMC_CSS_SLOW | \ - AT91_PMC_PRES_1 | \ - AT91SAM9_PMC_MDIV_2 | \ - AT91_PMC_PDIV_1) -/* PCK/2 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR2_VAL \ - (AT91_PMC_CSS_PLLA | \ - AT91_PMC_PRES_1 | \ - AT91SAM9_PMC_MDIV_2 | \ - AT91_PMC_PDIV_1) - -/* define PDC[31:16] as DATA[31:16] */ -#define CONFIG_SYS_PIOD_PDR_VAL1 0xFFFF0000 -/* no pull-up for D[31:16] */ -#define CONFIG_SYS_PIOD_PPUDR_VAL 0xFFFF0000 -/* EBI0_CSA, CS1 SDRAM, CS3 NAND Flash, 3.3V memories */ -#define CONFIG_SYS_MATRIX_EBI0CSA_VAL \ - (AT91_MATRIX_EBI0_DBPUC | AT91_MATRIX_EBI0_VDDIOMSEL_3_3V | \ - AT91_MATRIX_EBI0_CS1A_SDRAMC) - -/* SDRAM */ -/* SDRAMC_MR Mode register */ -#define CONFIG_SYS_SDRC_MR_VAL1 0 -/* SDRAMC_TR - Refresh Timer register */ -#define CONFIG_SYS_SDRC_TR_VAL1 0x13C -/* SDRAMC_CR - Configuration register*/ -#define CONFIG_SYS_SDRC_CR_VAL \ - (AT91_SDRAMC_NC_9 | \ - AT91_SDRAMC_NR_13 | \ - AT91_SDRAMC_NB_4 | \ - AT91_SDRAMC_CAS_3 | \ - AT91_SDRAMC_DBW_32 | \ - (1 << 8) | /* Write Recovery Delay */ \ - (7 << 12) | /* Row Cycle Delay */ \ - (2 << 16) | /* Row Precharge Delay */ \ - (2 << 20) | /* Row to Column Delay */ \ - (5 << 24) | /* Active to Precharge Delay */ \ - (1 << 28)) /* Exit Self Refresh to Active Delay */ - -/* Memory Device Register -> SDRAM */ -#define CONFIG_SYS_SDRC_MDR_VAL AT91_SDRAMC_MD_SDRAM -#define CONFIG_SYS_SDRC_MR_VAL2 AT91_SDRAMC_MODE_PRECHARGE -#define CONFIG_SYS_SDRAM_VAL1 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL3 AT91_SDRAMC_MODE_REFRESH -#define CONFIG_SYS_SDRAM_VAL2 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL3 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL4 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL5 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL6 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL7 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL8 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL9 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL4 AT91_SDRAMC_MODE_LMR -#define CONFIG_SYS_SDRAM_VAL10 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL5 AT91_SDRAMC_MODE_NORMAL -#define CONFIG_SYS_SDRAM_VAL11 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_TR_VAL2 1200 /* SDRAM_TR */ -#define CONFIG_SYS_SDRAM_VAL12 0 /* SDRAM_BASE */ - -/* setup SMC0, CS0 (NOR Flash) - 16-bit, 15 WS */ -#define CONFIG_SYS_SMC0_SETUP0_VAL \ - (AT91_SMC_NWESETUP_(10) | AT91_SMC_NCS_WRSETUP_(10) | \ - AT91_SMC_NRDSETUP_(10) | AT91_SMC_NCS_RDSETUP_(10)) -#define CONFIG_SYS_SMC0_PULSE0_VAL \ - (AT91_SMC_NWEPULSE_(11) | AT91_SMC_NCS_WRPULSE_(11) | \ - AT91_SMC_NRDPULSE_(11) | AT91_SMC_NCS_RDPULSE_(11)) -#define CONFIG_SYS_SMC0_CYCLE0_VAL \ - (AT91_SMC_NWECYCLE_(22) | AT91_SMC_NRDCYCLE_(22)) -#define CONFIG_SYS_SMC0_MODE0_VAL \ - (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ - AT91_SMC_DBW_16 | \ - AT91_SMC_TDFMODE | \ - AT91_SMC_TDF_(6)) - -/* user reset enable */ -#define CONFIG_SYS_RSTC_RMR_VAL \ - (AT91_RSTC_KEY | \ - AT91_RSTC_PROCRST | \ - AT91_RSTC_RSTTYP_WAKEUP | \ - AT91_RSTC_RSTTYP_WATCHDOG) - -/* Disable Watchdog */ -#define CONFIG_SYS_WDTC_WDMR_VAL \ - (AT91_WDT_WDIDLEHLT | AT91_WDT_WDDBGHLT | \ - AT91_WDT_WDV | \ - AT91_WDT_WDDIS | \ - AT91_WDT_WDD) - -#endif /* __CONFIG_H */ diff --git a/board/at91sam9263ek/env/bin/_update b/board/at91sam9263ek/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/at91sam9263ek/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/at91sam9263ek/env/bin/boot b/board/at91sam9263ek/env/bin/boot deleted file mode 100644 index 533dea7..0000000 --- a/board/at91sam9263ek/env/bin/boot +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - root=nand - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$1 = xnor ]; then - root=nor - kernel=nor -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -elif [ x$root = xnor ]; then - bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -elif [ $kernel = nor ]; then - bootm /dev/nor0.kernel -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/at91sam9263ek/env/bin/hush_hack b/board/at91sam9263ek/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/at91sam9263ek/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/at91sam9263ek/env/bin/init b/board/at91sam9263ek/env/bin/init deleted file mode 100644 index eaa298d..0000000 --- a/board/at91sam9263ek/env/bin/init +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nor0 ]; then - addpart /dev/nor0 $nor_parts -fi - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel nor [] to update kernel into flash" - echo "type update_root nor [] to update rootfs into flash" - echo "type update_barebox_xmodem nor to update barebox into flash" - echo - exit -fi - -boot diff --git a/board/at91sam9263ek/env/bin/update_barebox_xmodem b/board/at91sam9263ek/env/bin/update_barebox_xmodem deleted file mode 100644 index 39818b5..0000000 --- a/board/at91sam9263ek/env/bin/update_barebox_xmodem +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - part=/dev/nand0.barebox -elif [ x$1 = xnor ]; then - part=/dev/nor0.barebox -else - echo "usage: $0 nor|nand" - exit 1 -fi - -loadb -f barebox.bin -c - -unprotect $part -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing barebox.bin to $part" -echo -cp barebox.bin $part -crc32 -f barebox.bin -crc32 -f $part diff --git a/board/at91sam9263ek/env/bin/update_kernel b/board/at91sam9263ek/env/bin/update_kernel deleted file mode 100644 index 05c822d..0000000 --- a/board/at91sam9263ek/env/bin/update_kernel +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.kernel.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.kernel -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 diff --git a/board/at91sam9263ek/env/bin/update_root b/board/at91sam9263ek/env/bin/update_root deleted file mode 100644 index a751372..0000000 --- a/board/at91sam9263ek/env/bin/update_root +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 -if [ x$1 = xnand ]; then - part=/dev/nand0.root.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.root -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 - diff --git a/board/at91sam9263ek/env/config b/board/at91sam9263ek/env/config deleted file mode 100644 index 4b322ad..0000000 --- a/board/at91sam9263ek/env/config +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# can be either 'net', 'nor' or 'nand'' -kernel=net -root=net - -uimage=uImage -jffs2=root.jffs2 - -autoboot_timeout=3 - -nfsroot="" -bootargs="console=ttyS0,115200" - -nor_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" -rootpart_nor="/dev/mtdblock3" - -#nand_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" -#rootpart_nand="/dev/mtdblock7" - -# use 'dhcp' to do dhcp in barebox and in kernel -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=192.168.23.1 diff --git a/board/at91sam9263ek/init.c b/board/at91sam9263ek/init.c deleted file mode 100644 index 21803ca..0000000 --- a/board/at91sam9263ek/init.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD - * - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct atmel_nand_data nand_pdata = { - .ale = 21, - .cle = 22, -/* .det_pin = ... not connected */ - .ecc_base = (void __iomem *)(AT91_BASE_SYS + AT91_ECC0), - .ecc_mode = NAND_ECC_HW, - .rdy_pin = AT91_PIN_PA22, - .enable_pin = AT91_PIN_PD15, -#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16) - .bus_width_16 = 1, -#else - .bus_width_16 = 0, -#endif -}; - -static struct sam9_smc_config ek_nand_smc_config = { - .ncs_read_setup = 0, - .nrd_setup = 1, - .ncs_write_setup = 0, - .nwe_setup = 1, - - .ncs_read_pulse = 3, - .nrd_pulse = 3, - .ncs_write_pulse = 3, - .nwe_pulse = 3, - - .read_cycle = 5, - .write_cycle = 5, - - .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, - .tdf_cycles = 2, -}; - -static void ek_add_device_nand(void) -{ - /* setup bus-width (8 or 16) */ - if (nand_pdata.bus_width_16) - ek_nand_smc_config.mode |= AT91_SMC_DBW_16; - else - ek_nand_smc_config.mode |= AT91_SMC_DBW_8; - - /* configure chip-select 3 (NAND) */ - sam9_smc_configure(3, &ek_nand_smc_config); - - at91_add_device_nand(&nand_pdata); -} - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = AT91_CHIPSELECT_0, - .size = 8 * 1024 * 1024, -}; - -static struct at91_ether_platform_data macb_pdata = { - .flags = AT91SAM_ETHER_RMII, - .phy_addr = 0, -}; - -static int at91sam9263ek_devices_init(void) -{ - /* - * PB27 enables the 50MHz oscillator for Ethernet PHY - * 1 - enable - * 0 - disable - */ - at91_set_gpio_output(AT91_PIN_PB27, 1); - at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - - at91_add_device_sdram(64 * 1024 * 1024); - ek_add_device_nand(); - at91_add_device_eth(&macb_pdata); - register_device(&cfi_dev); - -#if defined(CONFIG_DRIVER_CFI) || defined(CONFIG_DRIVER_CFI_OLD) - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self"); - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); -#elif defined(CONFIG_NAND_ATMEL) - devfs_add_partition("nand0", 0x00000, 0x80000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x40000, 0x40000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); -#endif - - armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); - armlinux_set_architecture(MACH_TYPE_AT91SAM9263EK); - - return 0; -} - -device_initcall(at91sam9263ek_devices_init); - -static int at91sam9263ek_console_init(void) -{ - at91_register_uart(0, 0); - return 0; -} - -console_initcall(at91sam9263ek_console_init); diff --git a/board/board.dox b/board/board.dox index 76bff45..6bda416 100644 --- a/board/board.dox +++ b/board/board.dox @@ -5,24 +5,24 @@ @section board_add_files Files/Directories to be added - - board/\ - - board/\/Makefile - - board/\/\.c - - board/\/\.dox + - arch/\/boards/\ + - arch/\/boards/\/Makefile + - arch/\/boards/\/\.c + - arch/\/boards/\/\.dox - include/configs/\.h - arch/\/configs/\_defconfig -@subsection board_makefile board/\Makefile +@subsection board_makefile arch/\/boards/\Makefile @verbatim obj-y += all files that builds the BSP (Assembler and/or C files) @endverbatim -@subsection board_basefile board/\\.c +@subsection board_basefile arch/\/boards/\\.c TBD -@subsection board_doxygen board/\/\.dox +@subsection board_doxygen arch/\/boards/\/\.dox This file should describe in short words your new board, what CPU it uses, what resources are provided and features it supports. @@ -58,7 +58,7 @@ @note Consider to use an unique page lable. -@subsection board_lscript board/\/barebox.lds.S +@subsection board_lscript arch/\/boards/\/barebox.lds.S If your board needs a special binary @a barebox layout, you can provide a local board linker script file. This will replace the generic one provided by your diff --git a/board/edb93xx/Makefile b/board/edb93xx/Makefile deleted file mode 100644 index e19cd7b..0000000 --- a/board/edb93xx/Makefile +++ /dev/null @@ -1,2 +0,0 @@ - -obj-y += edb93xx.o flash_cfg.o pll_cfg.o sdram_cfg.o diff --git a/board/edb93xx/config.h b/board/edb93xx/config.h deleted file mode 100644 index 6ae9a40e..0000000 --- a/board/edb93xx/config.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -#endif /* __CONFIG_H */ diff --git a/board/edb93xx/early_udelay.h b/board/edb93xx/early_udelay.h deleted file mode 100644 index 185283d..0000000 --- a/board/edb93xx/early_udelay.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2009 Matthias Kaehlcke - * - * 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 - -/* delay execution before timers are initialized */ -static inline void early_udelay(uint32_t usecs) -{ - /* loop takes 4 cycles at 5.0ns (fastest case, running at 200MHz) */ - register uint32_t loops = usecs * (1000 / 20); - - __asm__ volatile ("1:\n" - "subs %0, %1, #1\n" - "bne 1b":"=r" (loops):"0" (loops)); -} diff --git a/board/edb93xx/edb93xx.c b/board/edb93xx/edb93xx.c deleted file mode 100644 index b0078a5..0000000 --- a/board/edb93xx/edb93xx.c +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2009 Matthias Kaehlcke - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "edb93xx.h" - -#define DEVCFG_U1EN (1 << 18) - -/* - * Up to 32MiB NOR type flash, connected to - * CS line 6, data width is 16 bit - */ -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0x60000000, - .size = EDB93XX_CFI_FLASH_SIZE, -}; - -static struct memory_platform_data ram_dev_pdata0 = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram0_dev = { - .name = "mem", - .map_base = CONFIG_EP93XX_SDRAM_BANK0_BASE, - .size = CONFIG_EP93XX_SDRAM_BANK0_SIZE, - .platform_data = &ram_dev_pdata0, -}; - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) -static struct memory_platform_data ram_dev_pdata1 = { - .name = "ram1", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram1_dev = { - .name = "mem", - .map_base = CONFIG_EP93XX_SDRAM_BANK1_BASE, - .size = CONFIG_EP93XX_SDRAM_BANK1_SIZE, - .platform_data = &ram_dev_pdata1, -}; -#endif - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) -static struct memory_platform_data ram_dev_pdata2 = { - .name = "ram2", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram2_dev = { - .name = "mem", - .map_base = CONFIG_EP93XX_SDRAM_BANK2_BASE, - .size = CONFIG_EP93XX_SDRAM_BANK2_SIZE, - .platform_data = &ram_dev_pdata2, -}; -#endif - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) -static struct memory_platform_data ram_dev_pdata3 = { - .name = "ram3", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram3_dev = { - .name = "mem", - .map_base = CONFIG_EP93XX_SDRAM_BANK3_BASE, - .size = CONFIG_EP93XX_SDRAM_BANK3_SIZE, - .platform_data = &ram_dev_pdata3, -}; -#endif - -static struct device_d eth_dev = { - .name = "ep93xx_eth", -}; - -static int ep93xx_devices_init(void) -{ - register_device(&cfi_dev); - - /* - * Create partitions that should be - * not touched by any regular user - */ - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); - - protect_file("/dev/env0", 1); - - register_device(&sdram0_dev); -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) - register_device(&sdram1_dev); -#endif -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) - register_device(&sdram2_dev); -#endif -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) - register_device(&sdram3_dev); -#endif - - armlinux_add_dram(&sdram0_dev); -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) - armlinux_add_dram(&sdram1_dev); -#endif -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) - armlinux_add_dram(&sdram2_dev); -#endif -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) - armlinux_add_dram(&sdram3_dev); -#endif - - register_device(ð_dev); - - armlinux_set_bootparams((void *)CONFIG_EP93XX_SDRAM_BANK0_BASE + 0x100); - - armlinux_set_architecture(MACH_TYPE); - - return 0; -} - -device_initcall(ep93xx_devices_init); - -static struct device_d edb93xx_serial_device = { - .name = "pl010_serial", - .map_base = UART1_BASE, - .size = 4096, -}; - -static int edb93xx_console_init(void) -{ - struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; - - /* - * set UARTBAUD bit to drive UARTs with 14.7456MHz instead of - * 14.7456/2 MHz - */ - uint32_t value = readl(&syscon->pwrcnt); - value |= SYSCON_PWRCNT_UART_BAUD; - writel(value, &syscon->pwrcnt); - - /* Enable UART1 */ - value = readl(&syscon->devicecfg); - value |= DEVCFG_U1EN; - writel(0xAA, &syscon->sysswlock); - writel(value, &syscon->devicecfg); - - register_device(&edb93xx_serial_device); - - return 0; -} - -console_initcall(edb93xx_console_init); diff --git a/board/edb93xx/edb93xx.dox b/board/edb93xx/edb93xx.dox deleted file mode 100644 index 3964d55..0000000 --- a/board/edb93xx/edb93xx.dox +++ /dev/null @@ -1,108 +0,0 @@ -/** @page edb9301 Cirrus Logic EDB9301 - -This boards is based on a Cirrus Logic EP9301 CPU. The board is shipped with: - -- 16MiB NOR type Flash Memory -- 32MiB synchronous dynamic RAM on CS3 -- 128kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec - -*/ - -/** @page edb9302 Cirrus Logic EDB9302 - -This board is based on a Cirrus Logic EP9302 CPU. The board is shipped with: - -- 16MiB NOR type Flash Memory -- 32MiB synchronous dynamic RAM on CS3 -- 128kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec - -*/ - -/** @page edb9302a Cirrus Logic EDB9302A - -This board is based on a Cirrus Logic EP9302 CPU. The board is shipped with: - -- 16MiB NOR type Flash Memory -- 32MiB synchronous dynamic RAM on CS0 -- 512kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec - -*/ - -/** @page edb9307 Cirrus Logic EDB9307 - -This board is based on a Cirrus Logic EP9307 CPU. The board is shipped with: - -- 32MiB NOR type Flash Memory -- 64MiB synchronous dynamic RAM on CS3 -- 512kiB asynchronous SRAM -- 128kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec -- Real-Time Clock -- IR receiver - -*/ - -/** @page edb9307a Cirrus Logic EDB9307A - -This board is based on a Cirrus Logic EP9307 CPU. The board is shipped with: - -- 32MiB NOR type Flash Memory -- 64MiB synchronous dynamic RAM on CS0 -- 512kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec -- Real-Time Clock -- IR receiver - -*/ - -/** @page edb9312 Cirrus Logic EDB9312 - -This board is based on a Cirrus Logic EP9312 CPU. The board is shipped with: - -- 32MiB NOR type Flash Memory -- 64MiB synchronous dynamic RAM on CS3 -- 512kiB asynchronous SRAM -- 128kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec -- Real-Time Clock -- IR receiver - -*/ - -/** @page edb9315 Cirrus Logic EDB9315 - -This board is based on a Cirrus Logic EP9315 CPU. The board is shipped with: - -- 32MiB NOR type Flash Memory -- 64MiB synchronous dynamic RAM on CS3 -- 512kiB asynchronous SRAM -- 128kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec -- Real-Time Clock -- IR receiver - -*/ - -/** @page edb9315a Cirrus Logic EDB9315A - -This board is based on a Cirrus Logic EP9315 CPU. The board is shipped with: - -- 32MiB NOR type Flash Memory -- 64MiB synchronous dynamic RAM on CS0 -- 128kiB serial EEPROM -- MII 10/100 Ethernet PHY -- Stereo audio codec -- Real-Time Clock -- IR receiver - -*/ \ No newline at end of file diff --git a/board/edb93xx/edb93xx.h b/board/edb93xx/edb93xx.h deleted file mode 100644 index 5e5c6f5..0000000 --- a/board/edb93xx/edb93xx.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2009 Matthias Kaehlcke - * - * 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 - */ - -#if defined(CONFIG_MACH_EDB9301) -#define MACH_TYPE MACH_TYPE_EDB9301 -#elif defined(CONFIG_MACH_EDB9302) -#define MACH_TYPE MACH_TYPE_EDB9302 -#elif defined(CONFIG_MACH_EDB9302A) -#define MACH_TYPE MACH_TYPE_EDB9302A -#elif defined(CONFIG_MACH_EDB9307) -#define MACH_TYPE MACH_TYPE_EDB9307 -#elif defined(CONFIG_MACH_EDB9307A) -#define MACH_TYPE MACH_TYPE_EDB9307A -#elif defined(CONFIG_MACH_EDB9312) -#define MACH_TYPE MACH_TYPE_EDB9312 -#elif defined(CONFIG_MACH_EDB9315) -#define MACH_TYPE MACH_TYPE_EDB9315 -#elif defined(CONFIG_MACH_EDB9315A) -#define MACH_TYPE MACH_TYPE_EDB9315A -#endif - -#if defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) || \ - defined(CONFIG_MACH_EDB9302A) -#define EDB93XX_CFI_FLASH_SIZE (16 * 1024 * 1024) -#elif defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) || \ - defined(CONFIG_MACH_EDB9312) || defined(CONFIG_MACH_EDB9315) || \ - defined(CONFIG_MACH_EDB9315A) -#define EDB93XX_CFI_FLASH_SIZE (32 * 1024 * 1024) -#endif diff --git a/board/edb93xx/env/bin/boot b/board/edb93xx/env/bin/boot deleted file mode 100644 index 143f3d0..0000000 --- a/board/edb93xx/env/bin/boot +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x${rootfs_boot_media} = xflash ]; -then - rootfs_img=/dev/nor0.rootfs_${active_cfg} - - if [ x${active_cfg} = x1 ]; - then - rootfs_blkdev=/dev/mtdblock4 - cfg_1_ro="ro" - cfg_2_ro="" - else - rootfs_blkdev=/dev/mtdblock6 - cfg_1_ro="" - cfg_2_ro="ro" - fi - - bootargs_rootfs="root=${rootfs_blkdev} rootfstype=squashfs ro" -elif [ x${rootfs_boot_media} = xnet ]; -then - bootargs_rootfs="root=/dev/nfs nfsroot=${eth0.serverip}:/srv/nfs/${board},v3,nolock,tcp ip=${eth0.ipaddr}" -else - echo "ERROR: \$rootfs_boot_media invalid: ${rootfs_boot_media}" - exit 1 -fi - -if [ x${kernel_boot_media} = xflash ]; -then - kernel_img=/dev/nor0.kernel_${active_cfg} -elif [ x${kernel_boot_media} = xnet ]; -then - cd / - tftp ${board}/kernel.img || exit 1 - kernel_img=/kernel.img -else - echo "ERROR: \$kernel_boot_media invalid: ${kernel_boot_media}" - exit 1 -fi - -source /env/bin/set_nor_parts - -bootargs_mtd="mtdparts=physmap-flash.0:${nor_parts}" - -bootargs="${bootargs_common} ${bootargs_mtd} ${bootargs_rootfs}" - -bootm ${kernel_img} \ No newline at end of file diff --git a/board/edb93xx/env/bin/flash_partition b/board/edb93xx/env/bin/flash_partition deleted file mode 100644 index ded40aa..0000000 --- a/board/edb93xx/env/bin/flash_partition +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -if [ $# != 2 ]; -then - echo "Usage: $0 " - exit 1 -fi - -image=$1 -partition=$2 - -echo "Unlocking ${partition}" -unprotect ${partition} - -echo "Erasing ${partition}" -erase ${partition} - -echo "Flashing ${image} to ${partition}" -cp ${image} ${partition} - -echo "Locking ${partition}" -protect ${partition} diff --git a/board/edb93xx/env/bin/init b/board/edb93xx/env/bin/init deleted file mode 100644 index c6b5aed..0000000 --- a/board/edb93xx/env/bin/init +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config - -# add partitions to barebox -. /env/bin/set_nor_parts -addpart /dev/nor0 ${nor_parts} - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - exit -fi - -boot \ No newline at end of file diff --git a/board/edb93xx/env/bin/set_nor_parts b/board/edb93xx/env/bin/set_nor_parts deleted file mode 100644 index 38321fa..0000000 --- a/board/edb93xx/env/bin/set_nor_parts +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -nor_parts="256k(barebox)ro,128k(env_boot),128k(env_boot.bak),1664k(kernel_1)${cfg_1_ro},6144k(rootfs_1)${cfg_1_ro},1664k(kernel_2)${cfg_2_ro},6144k(rootfs_2)${cfg_2_ro},128k(cfg_app),128k(cfg_app.bak)" \ No newline at end of file diff --git a/board/edb93xx/env/bin/update_kernel b/board/edb93xx/env/bin/update_kernel deleted file mode 100644 index 3e4b9b0..0000000 --- a/board/edb93xx/env/bin/update_kernel +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ $# != 1 ]; -then - echo "Usage: $0 <1/2>" - exit 1 -fi - -partition=/dev/nor0.kernel_$1 - -cd / -tftp ${board}/kernel.img || exit 1 - -flash_partition kernel.img ${partition} diff --git a/board/edb93xx/env/bin/update_rootfs b/board/edb93xx/env/bin/update_rootfs deleted file mode 100644 index 52a3699..0000000 --- a/board/edb93xx/env/bin/update_rootfs +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ $# != 1 ]; -then - echo "Usage: $0 <1/2>" - exit 1 -fi - -partition=/dev/nor0.rootfs_$1 - -cd / -tftp ${board}/rootfs.img || exit 1 - -flash_partition rootfs.img ${partition} diff --git a/board/edb93xx/env/config b/board/edb93xx/env/config deleted file mode 100644 index 47ab209..0000000 --- a/board/edb93xx/env/config +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -eth0.ipaddr=192.168.0.50 -eth0.netmask=255.255.0.0 -eth0.serverip=192.168.0.8 -eth0.ethaddr=80:81:82:83:84:85 - -board=edb9301 -autoboot_timeout=3 -active_cfg=1 -bootargs_common="console=ttyAM0,115200" - -# valid media: flash/net -kernel_boot_media=flash -rootfs_boot_media=flash - diff --git a/board/edb93xx/flash_cfg.c b/board/edb93xx/flash_cfg.c deleted file mode 100644 index 91a6a4e..0000000 --- a/board/edb93xx/flash_cfg.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Flash setup for Cirrus edb93xx boards - * - * Copyright (C) 2009 Matthias Kaehlcke - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include - -#define SMC_BCR6_VALUE (2 << SMC_BCR_IDCY_SHIFT | 5 << SMC_BCR_WST1_SHIFT | \ - SMC_BCR_BLE | 2 << SMC_BCR_WST2_SHIFT | \ - 1 << SMC_BCR_MW_SHIFT) - -void flash_cfg(void) -{ - struct smc_regs *smc = (struct smc_regs *)SMC_BASE; - - writel(SMC_BCR6_VALUE, &smc->bcr6); -} diff --git a/board/edb93xx/pll_cfg.c b/board/edb93xx/pll_cfg.c deleted file mode 100644 index a687af0..0000000 --- a/board/edb93xx/pll_cfg.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * PLL setup for Cirrus edb93xx boards - * - * Copyright (C) 2009 Matthias Kaehlcke - * - * Copyright (C) 2006 Dominic Rath - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include "pll_cfg.h" -#include "early_udelay.h" - -void pll_cfg(void) -{ - struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; - - /* setup PLL1 */ - writel(CLKSET1_VAL, &syscon->clkset1); - - /* - * flush the pipeline - * writing to CLKSET1 causes the EP93xx to enter standby for between - * 8 ms to 16 ms, until PLL1 stabilizes - */ - asm("nop"); - asm("nop"); - asm("nop"); - asm("nop"); - asm("nop"); - - /* setup PLL2 */ - writel(CLKSET2_VAL, &syscon->clkset2); - - /* - * the user's guide recommends to wait at least 1 ms for PLL2 to - * stabilize - */ - early_udelay(1000); -} diff --git a/board/edb93xx/pll_cfg.h b/board/edb93xx/pll_cfg.h deleted file mode 100644 index 503507a..0000000 --- a/board/edb93xx/pll_cfg.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * PLL register values for Cirrus edb93xx boards - * - * Copyright (C) 2009 Matthias Kaehlcke - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include - -#if defined(CONFIG_MACH_EDB9301) -/* - * fclk_div: 2, nbyp1: 1, hclk_div: 5, pclk_div: 2 - * pll1_x1: 294912000.000000, pll1_x2ip: 36864000.000000, - * pll1_x2: 331776000.000000, pll1_out: 331776000.000000 - */ -#define CLKSET1_VAL (7 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ - 8 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ - 19 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ - 1 << SYSCON_CLKSET1_PCLK_DIV_SHIFT | \ - 3 << SYSCON_CLKSET1_HCLK_DIV_SHIFT | \ - SYSCON_CLKSET1_NBYP1 | \ - 1 << SYSCON_CLKSET1_FCLK_DIV_SHIFT) -#elif defined(CONFIG_MACH_EDB9302) || defined(CONFIG_MACH_EDB9302A) || \ - defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) || \ - defined CONFIG_MACH_EDB9312 || defined(CONFIG_MACH_EDB9315) ||\ - defined(CONFIG_MACH_EDB9315A) -/* - * fclk_div: 2, nbyp1: 1, hclk_div: 4, pclk_div: 2 - * pll1_x1: 3096576000.000000, pll1_x2ip: 129024000.000000, - * pll1_x2: 3999744000.000000, pll1_out: 1999872000.000000 - */ -#define CLKSET1_VAL (23 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ - 30 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ - 20 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ - 1 << SYSCON_CLKSET1_PCLK_DIV_SHIFT | \ - 2 << SYSCON_CLKSET1_HCLK_DIV_SHIFT | \ - SYSCON_CLKSET1_NBYP1 | \ - 1 << SYSCON_CLKSET1_FCLK_DIV_SHIFT) -#else -#error "Undefined board" -#endif - -/* - * usb_div: 4, nbyp2: 1, pll2_en: 1 - * pll2_x1: 368640000.000000, pll2_x2ip: 15360000.000000, - * pll2_x2: 384000000.000000, pll2_out: 192000000.000000 - */ -#define CLKSET2_VAL (23 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ - 24 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ - 24 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ - 1 << SYSCON_CLKSET_PLL_PS_SHIFT | \ - SYSCON_CLKSET2_PLL2_EN | \ - SYSCON_CLKSET2_NBYP2 | \ - 3 << SYSCON_CLKSET2_USB_DIV_SHIFT) diff --git a/board/edb93xx/sdram_cfg.c b/board/edb93xx/sdram_cfg.c deleted file mode 100644 index 3d4fe08..0000000 --- a/board/edb93xx/sdram_cfg.c +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2009 Matthias Kaehlcke - * - * Copyright (C) 2006 Dominic Rath - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include "sdram_cfg.h" -#include "early_udelay.h" - -#define PROGRAM_MODE_REG(bank) (*(volatile uint32_t *) \ - (SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank | SDRAM_MODE_REG_VAL)) - -#define PRECHARGE_BANK(bank) (*(volatile uint32_t *) \ - (SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank)) = 0 - -static void precharge_all_banks(void); -static void setup_refresh_timer(void); -static void program_mode_registers(void); - -void sdram_cfg(void) -{ - struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; - - writel(SDRAM_DEVCFG_VAL, &sdram->SDRAM_DEVCFG_REG); - - /* Issue continous NOP commands */ - writel(GLCONFIG_INIT | GLCONFIG_MRS | GLCONFIG_CKE, &sdram->glconfig); - - early_udelay(200); - - precharge_all_banks(); - - setup_refresh_timer(); - - program_mode_registers(); - - /* Select normal operation mode */ - writel(GLCONFIG_CKE, &sdram->glconfig); -} - -static void precharge_all_banks(void) -{ - struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; - - /* Issue PRECHARGE ALL commands */ - writel(GLCONFIG_INIT | GLCONFIG_CKE, &sdram->glconfig); - - /* - * Errata of most EP93xx revisions say that PRECHARGE ALL isn't always - * issued. - * - * Cirrus proposes a workaround which consists in performing a read from - * each bank to force the precharge. This causes some boards to hang. - * Writing to the SDRAM banks instead of reading has the same - * side-effect (the SDRAM controller issues the necessary precharges), - * but is known to work on all supported boards - */ - - PRECHARGE_BANK(0); - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) - PRECHARGE_BANK(1); -#endif - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) - PRECHARGE_BANK(2); -#endif - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) - PRECHARGE_BANK(3); -#endif -} - -static void setup_refresh_timer(void) -{ - struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; - - /* Load refresh timer with 10 to issue refresh every 10 cycles */ - writel(0x0a, &sdram->refrshtimr); - - /* - * Wait at least 80 clock cycles to provide 8 refresh cycles - * to all SDRAMs - */ - early_udelay(1); - - /* - * Program refresh timer with normal value - * We need 8192 refresh cycles every 64ms - * at 15ns (HCLK >= 66MHz) per cycle: - * 64ms / 8192 = 7.8125us - * 7.8125us / 15ns = 520 (0x208) - */ - /* - * TODO: redboot uses 0x1e0 for the slowest possible device - * but i don't understand how this value is calculated - */ - writel(0x208, &sdram->refrshtimr); -} - -static void program_mode_registers(void) -{ - struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; - - /* Select mode register update mode */ - writel(GLCONFIG_MRS | GLCONFIG_CKE, &sdram->glconfig); - - PROGRAM_MODE_REG(0); - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) - PROGRAM_MODE_REG(1); -#endif - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) - PROGRAM_MODE_REG(2); -#endif - -#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) - PROGRAM_MODE_REG(3); -#endif -} diff --git a/board/edb93xx/sdram_cfg.h b/board/edb93xx/sdram_cfg.h deleted file mode 100644 index c57b76e..0000000 --- a/board/edb93xx/sdram_cfg.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2009 Matthias Kaehlcke - * - * Copyright (C) 2006 Dominic Rath - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include - -#define SDRAM_BASE_ADDR CONFIG_EP93XX_SDRAM_BANK0_BASE - -#ifdef CONFIG_EP93XX_SDCE0_PHYS_OFFSET -#define SDRAM_DEVCFG_REG devcfg0 -#elif defined(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) -#define SDRAM_DEVCFG_REG devcfg3 -#else -#error "SDRAM bank configuration" -#endif - -#if defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) ||\ - defined(CONFIG_MACH_EDB9302A) -/* - * 1x Samsung K4S561632C-TC/L75 4M x 16bit x 4 banks SDRAM - * - * CLK cycle time min: - * @ CAS latency = 3: 7.5ns - * @ CAS latency = 2: 10ns - * We're running at 66MHz (EDB9301) / 100Mhz (EDB9302(a)) external - * bus speed (HCLK), with a cycle time of 15ns / 10ns, so it's safe - * to use CAS latency = 2 - * - * RAS-to-CAS delay min: - * 20ns - * At 15ns/10ns cycle time, we use RAS-to-CAS delay = 2 - * - * SROMLL = 1: Swap BA[1:0] with A[13:12], making the SDRAM appear - * as four blocks of 8MB size, instead of eight blocks of 4MB size: - * - * EDB9301/EDB9302: - * - * 0x00000000 - 0x007fffff - * 0x01000000 - 0x017fffff - * 0x04000000 - 0x047fffff - * 0x05000000 - 0x057fffff - * - * - * EDB9302a: - * - * 0xc0000000 - 0xc07fffff - * 0xc1000000 - 0xc17fffff - * 0xc4000000 - 0xc47fffff - * 0xc5000000 - 0xc57fffff - * - * BANKCOUNT = 1: This is a device with four banks - */ - -#define SDRAM_DEVCFG_VAL (SDRAM_DEVCFG_BANKCOUNT | \ - SDRAM_DEVCFG_SROMLL | \ - SDRAM_DEVCFG_CASLAT_2 | \ - SDRAM_DEVCFG_RASTOCAS_2 | \ - SDRAM_DEVCFG_EXTBUSWIDTH) - -/* - * 16 bit ext. bus - * - * A[22:09] is output as SYA[13:0] - * CAS latency: 2 - * Burst type: sequential - * Burst length: 8 (required for 16 bit ext. bus) - * SYA[13:0] = 0x0023 - */ -#define SDRAM_MODE_REG_VAL 0x4600 - -#define SDRAM_BANK_SEL_0 0x00000000 /* A[22:21] = b00 */ -#define SDRAM_BANK_SEL_1 0x00200000 /* A[22:21] = b01 */ -#define SDRAM_BANK_SEL_2 0x00400000 /* A[22:21] = b10 */ -#define SDRAM_BANK_SEL_3 0x00600000 /* A[22:21] = b11 */ - -#elif defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) ||\ - defined CONFIG_MACH_EDB9312 || defined(CONFIG_MACH_EDB9315) ||\ - defined(CONFIG_MACH_EDB9315A) -/* - * 2x Samsung K4S561632C-TC/L75 4M x 16bit x 4 banks SDRAM - * - * CLK cycle time min: - * @ CAS latency = 3: 7.5ns - * @ CAS latency = 2: 10ns - * We're running at 100MHz (10ns cycle time) external bus speed (HCLK), - * so it's safe to use CAS latency = 2 - * - * RAS-to-CAS delay min: - * 20ns - * At 10ns cycle time, we use RAS-to-CAS delay = 2 - * - * EDB9307, EDB9312, EDB9315: - * - * 0x00000000 - 0x01ffffff - * 0x04000000 - 0x05ffffff - * - * - * EDB9307a, EDB9315a: - * - * 0xc0000000 - 0xc1ffffff - * 0xc4000000 - 0xc5ffffff - */ - -#define SDRAM_DEVCFG_VAL (SDRAM_DEVCFG_BANKCOUNT | \ - SDRAM_DEVCFG_SROMLL | \ - SDRAM_DEVCFG_CASLAT_2 | \ - SDRAM_DEVCFG_RASTOCAS_2) - -/* - * 32 bit ext. bus - * - * A[23:10] is output as SYA[13:0] - * CAS latency: 2 - * Burst type: sequential - * Burst length: 4 - * SYA[13:0] = 0x0022 - */ -#define SDRAM_MODE_REG_VAL 0x8800 - -#define SDRAM_BANK_SEL_0 0x00000000 /* A[23:22] = b00 */ -#define SDRAM_BANK_SEL_1 0x00400000 /* A[23:22] = b01 */ -#define SDRAM_BANK_SEL_2 0x00800000 /* A[23:22] = b10 */ -#define SDRAM_BANK_SEL_3 0x00c00000 /* A[23:22] = b11 */ -#endif diff --git a/board/eukrea_cpuimx25/Makefile b/board/eukrea_cpuimx25/Makefile deleted file mode 100644 index 406c6f3..0000000 --- a/board/eukrea_cpuimx25/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# (C) 2010 Eukrea Electromatique, Eric Bénard -# -# 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 -# - -obj-y += lowlevel.o -obj-y += eukrea_cpuimx25.o diff --git a/board/eukrea_cpuimx25/config.h b/board/eukrea_cpuimx25/config.h deleted file mode 100644 index efff909..0000000 --- a/board/eukrea_cpuimx25/config.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (c) 2010 Eukrea Electromatique, Eric Bénard - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#define CONFIG_MX25_HCLK_FREQ 24000000 - -#endif - -/* nothing to do here yet */ diff --git a/board/eukrea_cpuimx25/env/bin/_update b/board/eukrea_cpuimx25/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/eukrea_cpuimx25/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/eukrea_cpuimx25/env/bin/boot b/board/eukrea_cpuimx25/env/bin/boot deleted file mode 100644 index 2d9b3af..0000000 --- a/board/eukrea_cpuimx25/env/bin/boot +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xjffS2 ]; then - root=jffs2 - kernel=nand -fi - -if [ x$1 = xubifs ]; then - root=ubifs - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - if [ x$ip = xoff ]; then - bootargs="$bootargs ip=off" - else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" - fi -fi - -if [ x$root = xjffs2 ]; then - bootargs="$bootargs root=/dev/mtdblock$rootpartnum_nand rootfstype=jffs2" -fi - -if [ x$root = xubifs ]; then - bootargs="$bootargs root=ubi0:$ubiroot ubi.mtd=$rootpartnum_nand rootfstype=ubifs" -fi - -if [ x$root = xnet ]; then - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=mxc_nand:$nand_parts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/eukrea_cpuimx25/env/bin/hush_hack b/board/eukrea_cpuimx25/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/eukrea_cpuimx25/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/eukrea_cpuimx25/env/bin/init b/board/eukrea_cpuimx25/env/bin/init deleted file mode 100644 index 335d7ae..0000000 --- a/board/eukrea_cpuimx25/env/bin/init +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -f /env/logo.bmp ]; then - bmp /env/logo.bmp -elif [ -f /env/logo.bmp.lzo ]; then - unlzo /env/logo.bmp.lzo /logo.bmp - bmp /logo.bmp -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" - saveenv -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type update_root [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/eukrea_cpuimx25/env/bin/update_kernel b/board/eukrea_cpuimx25/env/bin/update_kernel deleted file mode 100644 index c2d2cc3..0000000 --- a/board/eukrea_cpuimx25/env/bin/update_kernel +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -part=/dev/nand0.kernel.bb - -. /env/bin/_update $1 diff --git a/board/eukrea_cpuimx25/env/bin/update_root b/board/eukrea_cpuimx25/env/bin/update_root deleted file mode 100644 index dd89a5a..0000000 --- a/board/eukrea_cpuimx25/env/bin/update_root +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$rootfs -part=/dev/nand0.root.bb - -. /env/bin/_update $1 diff --git a/board/eukrea_cpuimx25/env/config b/board/eukrea_cpuimx25/env/config deleted file mode 100644 index 9217ca1..0000000 --- a/board/eukrea_cpuimx25/env/config +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'jffs2' or 'ubifs' -kernel=nand -root=ubifs - -basedir=cpuimx25 -uimage=$basedir/uImage -rootfs=$basedir/rootfs - -autoboot_timeout=1 - -nfsroot="" -bootargs="console=ttymxc0,115200" - -nand_parts="256k(barebox)ro,128k(bareboxenv),2176k(kernel),-(root)" -rootpartnum_nand=3 -ubiroot="eukrea-cpuimx25-rootfs" - -# use 'dhcp' to do dhcp in barebox and in kernel -ip=off - -# 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 diff --git a/board/eukrea_cpuimx25/eukrea_cpuimx25.c b/board/eukrea_cpuimx25/eukrea_cpuimx25.c deleted file mode 100644 index caeb46e..0000000 --- a/board/eukrea_cpuimx25/eukrea_cpuimx25.c +++ /dev/null @@ -1,273 +0,0 @@ -/* - * (C) 2009 Pengutronix, Sascha Hauer - * (c) 2010 Eukrea Electromatique, Eric Bénard - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -extern unsigned long _stext; - -void __naked __flash_header_start go(void) -{ - __asm__ __volatile__("b exception_vectors\n"); -} - -struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { - { .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000004, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92100000, }, - { .ptr_type = 1, .addr = 0x80000400, .val = 0x12344321, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0xa2100000, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2100000, }, - { .ptr_type = 1, .addr = 0x80000033, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x81000000, .val = 0xff, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216080, }, - { .ptr_type = 4, .addr = 0xb8001004, .val = 0x00295729, }, - { .ptr_type = 4, .addr = 0x53f80008, .val = 0x20034000, }, -}; - -struct imx_flash_header __flash_header_0x400 eukrea_cpuimx25_header = { - .app_code_jump_vector = TEXT_BASE + 0x2000, - .app_code_barker = APP_CODE_BARKER, - .app_code_csf = 0, - .dcd_ptr_ptr = TEXT_BASE + 0x400 + offsetof(struct imx_flash_header, dcd), - .super_root_key = 0, - .dcd = TEXT_BASE + 0x400 + offsetof(struct imx_flash_header, dcd_barker), - .app_dest = TEXT_BASE, - .dcd_barker = DCD_BARKER, - .dcd_block_len = sizeof(dcd_entry), -}; - -extern unsigned long __bss_start; - -unsigned long __image_len_0x400 barebox_len = 0x40000; - -static struct fec_platform_data fec_info = { - .xcv_type = RMII, - .phy_addr = 1, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = IMX_FEC_BASE, - .platform_data = &fec_info, -}; - -static struct memory_platform_data sdram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram0_dev = { - .name = "mem", - .map_base = IMX_SDRAM_CS0, - .size = 64 * 1024 * 1024, - .platform_data = &sdram_pdata, -}; - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = IMX_NFC_BASE, - .platform_data = &nand_info, -}; - -static struct imx_fb_videomode imxfb_mode = { - .mode = { - .name = "CMO-QVGA", - .refresh = 60, - .xres = 320, - .yres = 240, - .pixclock = KHZ2PICOS(6500), - .hsync_len = 30, - .left_margin = 38, - .right_margin = 20, - .vsync_len = 3, - .upper_margin = 15, - .lower_margin = 4, - }, - .pcr = 0xCAD08B80, - .bpp = 16, -}; - -static struct imx_fb_platform_data eukrea_cpuimx25_fb_data = { - .mode = &imxfb_mode, - .pwmr = 0x00A903FF, - .lscr1 = 0x00120300, - .dmacr = 0x80040060, -}; - - -static struct device_d imxfb_dev = { - .name = "imxfb", - .map_base = 0x53fbc000, - .size = 0x1000, - .platform_data = &eukrea_cpuimx25_fb_data, -}; - -#ifdef CONFIG_MMU -static void eukrea_cpuimx25_mmu_init(void) -{ - mmu_init(); - - arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); - arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); - - setup_dma_coherent(0x10000000); - - mmu_enable(); -} -#else -static void eukrea_cpuimx25_mmu_init(void) -{ -} -#endif - -static struct pad_desc eukrea_cpuimx25_pads[] = { - MX25_PAD_FEC_MDC__MDC, - MX25_PAD_FEC_MDIO__MDIO, - MX25_PAD_FEC_RDATA0__RDATA0, - MX25_PAD_FEC_RDATA1__RDATA1, - MX25_PAD_FEC_RX_DV__RX_DV, - MX25_PAD_FEC_TDATA0__TDATA0, - MX25_PAD_FEC_TDATA1__TDATA1, - MX25_PAD_FEC_TX_CLK__TX_CLK, - MX25_PAD_FEC_TX_EN__TX_EN, - /* UART1 */ - MX25_PAD_UART1_RXD__RXD_MUX, - MX25_PAD_UART1_TXD__TXD_MUX, - MX25_PAD_UART1_RTS__RTS, - MX25_PAD_UART1_CTS__CTS, - /* LCDC */ - MX25_PAD_LD0__LCDC_LD0, - MX25_PAD_LD1__LCDC_LD1, - MX25_PAD_LD2__LCDC_LD2, - MX25_PAD_LD3__LCDC_LD3, - MX25_PAD_LD4__LCDC_LD4, - MX25_PAD_LD5__LCDC_LD5, - MX25_PAD_LD6__LCDC_LD6, - MX25_PAD_LD7__LCDC_LD7, - MX25_PAD_LD8__LCDC_LD8, - MX25_PAD_LD9__LCDC_LD9, - MX25_PAD_LD10__LCDC_LD10, - MX25_PAD_LD11__LCDC_LD11, - MX25_PAD_LD12__LCDC_LD12, - MX25_PAD_LD13__LCDC_LD13, - MX25_PAD_LD14__LCDC_LD14, - MX25_PAD_LD15__LCDC_LD15, - MX25_PAD_GPIO_E__LCDC_LD16, - MX25_PAD_GPIO_F__LCDC_LD17, - MX25_PAD_LSCLK__LCDC_LSCLK, - MX25_PAD_OE_ACD__LCDC_OE_ACD, - MX25_PAD_VSYNC__LCDC_VSYN, - MX25_PAD_HSYNC__LCDC_HSYN, - /* BACKLIGHT CONTROL */ - MX25_PAD_PWM__GPIO26, -}; - -static int eukrea_cpuimx25_devices_init(void) -{ - eukrea_cpuimx25_mmu_init(); - - mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx25_pads, - ARRAY_SIZE(eukrea_cpuimx25_pads)); - register_device(&fec_dev); - - nand_info.width = 1; - register_device(&nand_dev); - - devfs_add_partition("nand0", 0x00000, 0x40000, - PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - - devfs_add_partition("nand0", 0x40000, 0x20000, - PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - - register_device(&sdram0_dev); - - /* enable LCD */ - gpio_direction_output(26, 1); - gpio_set_value(26, 1); - - register_device(&imxfb_dev); - - armlinux_add_dram(&sdram0_dev); - armlinux_set_bootparams((void *)0x80000100); - armlinux_set_architecture(MACH_TYPE_EUKREA_CPUIMX25); - - return 0; -} - -device_initcall(eukrea_cpuimx25_devices_init); - -static struct device_d eukrea_cpuimx25_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 16 * 1024, -}; - -static int eukrea_cpuimx25_console_init(void) -{ - writel(0x03010101, IMX_CCM_BASE + CCM_PCDR3); - register_device(&eukrea_cpuimx25_serial_device); - return 0; -} - -console_initcall(eukrea_cpuimx25_console_init); - -#ifdef CONFIG_NAND_IMX_BOOT -void __bare_init nand_boot(void) -{ - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); -} -#endif - -static int eukrea_cpuimx25_core_setup(void) -{ - writel(0x01010103, IMX_CCM_BASE + CCM_PCDR2); - return 0; - -} -core_initcall(eukrea_cpuimx25_core_setup); diff --git a/board/eukrea_cpuimx25/lowlevel.c b/board/eukrea_cpuimx25/lowlevel.c deleted file mode 100644 index b9d3ce5..0000000 --- a/board/eukrea_cpuimx25/lowlevel.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * (c) 2010 Eukrea Electromatique, Eric Bénard - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void __bare_init __naked insdram(void) -{ - uint32_t r; - - /* setup a stack to be able to call imx_nand_load_image() */ - r = STACK_BASE + STACK_SIZE - 12; - __asm__ __volatile__("mov sp, %0" : : "r"(r)); - - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); - - board_init_lowlevel_return(); -} - -#define MX25_CCM_MCR 0x64 -#define MX25_CCM_CGR0 0x0c -#define MX25_CCM_CGR1 0x10 -#define MX25_CCM_CGR2 0x14 - -void __bare_init __naked board_init_lowlevel(void) -{ - uint32_t r; - unsigned int *trg, *src; - int i; - - /* AIPS setup - Only setup MPROTx registers. The PACR default values are good. - * Set all MPROTx to be non-bufferable, trusted for R/W, - * not forced to user-mode. - */ - writel(0x77777777, 0x43f00000); - writel(0x77777777, 0x43f00004); - writel(0x77777777, 0x53f00000); - writel(0x77777777, 0x53f00004); - - /* MAX (Multi-Layer AHB Crossbar Switch) setup - * MPR - priority for MX25 is (SDHC2/SDMA)>USBOTG>RTIC>IAHB>DAHB - */ - writel(0x00002143, 0x43f04000); - writel(0x00002143, 0x43f04100); - writel(0x00002143, 0x43f04200); - writel(0x00002143, 0x43f04300); - writel(0x00002143, 0x43f04400); - /* SGPCR - always park on last master */ - writel(0x10, 0x43f04010); - writel(0x10, 0x43f04110); - writel(0x10, 0x43f04210); - writel(0x10, 0x43f04310); - writel(0x10, 0x43f04410); - /* MGPCR - restore default values */ - writel(0x0, 0x43f04800); - writel(0x0, 0x43f04900); - writel(0x0, 0x43f04a00); - writel(0x0, 0x43f04b00); - writel(0x0, 0x43f04c00); - - /* Configure M3IF registers - * M3IF Control Register (M3IFCTL) for MX25 - * MRRP[0] = LCDC on priority list (1 << 0) = 0x00000001 - * MRRP[1] = MAX1 not on priority list (0 << 1) = 0x00000000 - * MRRP[2] = MAX0 not on priority list (0 << 2) = 0x00000000 - * MRRP[3] = USB HOST not on priority list (0 << 3) = 0x00000000 - * MRRP[4] = SDMA not on priority list (0 << 4) = 0x00000000 - * MRRP[5] = SD/ATA/FEC not on priority list (0 << 5) = 0x00000000 - * MRRP[6] = SCMFBC not on priority list (0 << 6) = 0x00000000 - * MRRP[7] = CSI not on priority list (0 << 7) = 0x00000000 - * ---------- - * 0x00000001 - */ - writel(0x1, 0xb8003000); - - /* enable all the clocks */ - writel(0x038A81A2, IMX_CCM_BASE + MX25_CCM_CGR0); - writel(0x24788F00, IMX_CCM_BASE + MX25_CCM_CGR1); - writel(0x00004438, IMX_CCM_BASE + MX25_CCM_CGR2); - writel(0x00, IMX_CCM_BASE + MX25_CCM_MCR); - -#ifdef CONFIG_NAND_IMX_BOOT - /* skip NAND boot if not running from NFC space */ - r = get_pc(); - if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x1000) - board_init_lowlevel_return(); - - src = (unsigned int *)IMX_NFC_BASE; - trg = (unsigned int *)TEXT_BASE; - - /* Move ourselves out of NFC SRAM */ - for (i = 0; i < 0x1000 / sizeof(int); i++) - *trg++ = *src++; - - /* Jump to SDRAM */ - r = (unsigned int)&insdram; - __asm__ __volatile__("mov pc, %0" : : "r"(r)); -#else - board_init_lowlevel_return(); -#endif -} diff --git a/board/eukrea_cpuimx27/Makefile b/board/eukrea_cpuimx27/Makefile deleted file mode 100644 index 5d958fa..0000000 --- a/board/eukrea_cpuimx27/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += lowlevel_init.o -obj-y += eukrea_cpuimx27.o diff --git a/board/eukrea_cpuimx27/config.h b/board/eukrea_cpuimx27/config.h deleted file mode 100644 index ec6f212..0000000 --- a/board/eukrea_cpuimx27/config.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 - */ - -/** - * @file - * @brief Global defintions for the ARM Eukrea cpuimx27 board - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#endif /* __CONFIG_H */ diff --git a/board/eukrea_cpuimx27/env/bin/_update b/board/eukrea_cpuimx27/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/eukrea_cpuimx27/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/eukrea_cpuimx27/env/bin/boot b/board/eukrea_cpuimx27/env/bin/boot deleted file mode 100644 index 7272e56..0000000 --- a/board/eukrea_cpuimx27/env/bin/boot +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - root=nand - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$1 = xnor ]; then - root=nor - kernel=nor -fi - -if [ x$root = xnet ]; then - if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" - else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" - fi -else - bootargs="$bootargs ip=off" -fi - -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -elif [ x$root = xnor ]; then - bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts;mxc_nand:$nand_parts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -elif [ $kernel = nor ]; then - bootm /dev/nor0.kernel -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/eukrea_cpuimx27/env/bin/hush_hack b/board/eukrea_cpuimx27/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/eukrea_cpuimx27/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/eukrea_cpuimx27/env/bin/init b/board/eukrea_cpuimx27/env/bin/init deleted file mode 100644 index 3bfd194..0000000 --- a/board/eukrea_cpuimx27/env/bin/init +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nor0 ]; then - addpart /dev/nor0 $nor_parts -fi - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel nand|nor [] to update kernel into flash" - echo "type update_root nand|nor [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/eukrea_cpuimx27/env/bin/update_kernel b/board/eukrea_cpuimx27/env/bin/update_kernel deleted file mode 100644 index 05c822d..0000000 --- a/board/eukrea_cpuimx27/env/bin/update_kernel +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.kernel.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.kernel -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 diff --git a/board/eukrea_cpuimx27/env/bin/update_root b/board/eukrea_cpuimx27/env/bin/update_root deleted file mode 100644 index eaf36eb..0000000 --- a/board/eukrea_cpuimx27/env/bin/update_root +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.root.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.root -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 - diff --git a/board/eukrea_cpuimx27/env/config b/board/eukrea_cpuimx27/env/config deleted file mode 100644 index 505ada3..0000000 --- a/board/eukrea_cpuimx27/env/config +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh - -# can be either 'net', 'nor' or 'nand'' -kernel=nor -root=nor - -uimage=mx27/uImage -jffs2=mx27/rootfs.jffs2 - -autoboot_timeout=1 - -# DVI-SVGA DVI-VGA CMO-QVGA -video="CMO-QVGA" -bootargs="console=ttymxc0,115200 fec_mac=$eth0.ethaddr video=mxcfb:$video" - -nor_parts="256k(barebox)ro,128k(bareboxenv),2176k(kernel),-(root)" -rootpart_nor="/dev/mtdblock3" - -nand_parts="-(nand)" -rootpart_nand="" - -nfsroot="" - -# use 'dhcp' to do dhcp in barebox and in kernel -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 diff --git a/board/eukrea_cpuimx27/eukrea_cpuimx27.c b/board/eukrea_cpuimx27/eukrea_cpuimx27.c deleted file mode 100644 index 1937d21..0000000 --- a/board/eukrea_cpuimx27/eukrea_cpuimx27.c +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2009 Eric Benard, Eukrea Electromatique - * Based on pcm038.c which is : - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0xC0000000, - .size = 32 * 1024 * 1024, -}; -#ifdef CONFIG_EUKREA_CPUIMX27_NOR_64MB -static struct device_d cfi_dev1 = { - .name = "cfi_flash", - .map_base = 0xC2000000, - .size = 32 * 1024 * 1024, -}; -#endif - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -#if defined CONFIG_EUKREA_CPUIMX27_SDRAM_256MB -#define SDRAM0 256 -#elif defined CONFIG_EUKREA_CPUIMX27_SDRAM_128MB -#define SDRAM0 128 -#endif - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0xa0000000, - .size = SDRAM0 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -static struct fec_platform_data fec_info = { - .xcv_type = MII100, - .phy_addr = 1, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = 0x1002b000, - .platform_data = &fec_info, -}; - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, - .flash_bbt = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = 0xd8000000, - .platform_data = &nand_info, -}; - -#ifdef CONFIG_DRIVER_SERIAL_NS16550 -unsigned int quad_uart_read(unsigned long base, unsigned char reg_idx) -{ - unsigned int reg_addr = (unsigned int)base; - reg_addr += reg_idx << 1; - return 0xff & readw(reg_addr); -} -EXPORT_SYMBOL(quad_uart_read); - -void quad_uart_write(unsigned int val, unsigned long base, - unsigned char reg_idx) -{ - unsigned int reg_addr = (unsigned int)base; - reg_addr += reg_idx << 1; - writew(0xff & val, reg_addr); -} -EXPORT_SYMBOL(quad_uart_write); - -static struct NS16550_plat quad_uart_serial_plat = { - .clock = 14745600, - .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR, - .reg_read = quad_uart_read, - .reg_write = quad_uart_write, -}; - -#ifdef CONFIG_EUKREA_CPUIMX27_QUART1 -#define QUART_OFFSET 0x200000 -#elif defined CONFIG_EUKREA_CPUIMX27_QUART2 -#define QUART_OFFSET 0x400000 -#elif defined CONFIG_EUKREA_CPUIMX27_QUART3 -#define QUART_OFFSET 0x800000 -#elif defined CONFIG_EUKREA_CPUIMX27_QUART4 -#define QUART_OFFSET 0x1000000 -#endif - -static struct device_d quad_uart_serial_device = { - .name = "serial_ns16550", - .map_base = IMX_CS3_BASE + QUART_OFFSET, - .size = 0xF, - .platform_data = (void *)&quad_uart_serial_plat, -}; -#endif - -static struct i2c_board_info i2c_devices[] = { - { - I2C_BOARD_INFO("lp3972", 0x34), - }, -}; - -static struct device_d i2c_dev = { - .name = "i2c-imx", - .map_base = IMX_I2C1_BASE, -}; - -#ifdef CONFIG_MMU -static void eukrea_cpuimx27_mmu_init(void) -{ - mmu_init(); - - arm_create_section(0xa0000000, 0xa0000000, 128, PMD_SECT_DEF_CACHED); - arm_create_section(0xb0000000, 0xa0000000, 128, PMD_SECT_DEF_UNCACHED); - - setup_dma_coherent(0x10000000); - -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); -} -#else -static void eukrea_cpuimx27_mmu_init(void) -{ -} -#endif - -#ifdef CONFIG_DRIVER_VIDEO_IMX -static struct imx_fb_videomode imxfb_mode = { - .mode = { - .name = "CMO-QVGA", - .refresh = 60, - .xres = 320, - .yres = 240, - .pixclock = 156000, - .hsync_len = 30, - .left_margin = 38, - .right_margin = 20, - .vsync_len = 3, - .upper_margin = 15, - .lower_margin = 4, - }, - .pcr = 0xFAD08B80, - .bpp = 16,}; - -static struct imx_fb_platform_data eukrea_cpuimx27_fb_data = { - .mode = &imxfb_mode, - .pwmr = 0x00A903FF, - .lscr1 = 0x00120300, - .dmacr = 0x00020010, -}; - -static struct device_d imxfb_dev = { - .name = "imxfb", - .map_base = 0x10021000, - .size = 0x1000, - .platform_data = &eukrea_cpuimx27_fb_data, -}; -#endif - -static int eukrea_cpuimx27_devices_init(void) -{ - char *envdev = "no"; - int i; - - unsigned int mode[] = { - PD0_AIN_FEC_TXD0, - PD1_AIN_FEC_TXD1, - PD2_AIN_FEC_TXD2, - PD3_AIN_FEC_TXD3, - PD4_AOUT_FEC_RX_ER, - PD5_AOUT_FEC_RXD1, - PD6_AOUT_FEC_RXD2, - PD7_AOUT_FEC_RXD3, - PD8_AF_FEC_MDIO, - PD9_AIN_FEC_MDC | GPIO_PUEN, - PD10_AOUT_FEC_CRS, - PD11_AOUT_FEC_TX_CLK, - PD12_AOUT_FEC_RXD0, - PD13_AOUT_FEC_RX_DV, - PD14_AOUT_FEC_RX_CLK, - PD15_AOUT_FEC_COL, - PD16_AIN_FEC_TX_ER, - PF23_AIN_FEC_TX_EN, - PD17_PF_I2C_DATA, - PD18_PF_I2C_CLK, -#ifdef CONFIG_DRIVER_SERIAL_IMX - PE12_PF_UART1_TXD, - PE13_PF_UART1_RXD, - PE14_PF_UART1_CTS, - PE15_PF_UART1_RTS, -#endif -#ifdef CONFIG_DRIVER_VIDEO_IMX - PA5_PF_LSCLK, - PA6_PF_LD0, - PA7_PF_LD1, - PA8_PF_LD2, - PA9_PF_LD3, - PA10_PF_LD4, - PA11_PF_LD5, - PA12_PF_LD6, - PA13_PF_LD7, - PA14_PF_LD8, - PA15_PF_LD9, - PA16_PF_LD10, - PA17_PF_LD11, - PA18_PF_LD12, - PA19_PF_LD13, - PA20_PF_LD14, - PA21_PF_LD15, - PA22_PF_LD16, - PA23_PF_LD17, - PA28_PF_HSYNC, - PA29_PF_VSYNC, - PA31_PF_OE_ACD, - GPIO_PORTE | 5 | GPIO_GPIO | GPIO_OUT, -#endif - }; - - eukrea_cpuimx27_mmu_init(); - - /* configure 16 bit nor flash on cs0 */ - CS0U = 0x00008F03; - CS0L = 0xA0330D01; - CS0A = 0x002208C0; - - /* initialize gpios */ - for (i = 0; i < ARRAY_SIZE(mode); i++) - imx_gpio_mode(mode[i]); - - register_device(&cfi_dev); -#ifdef CONFIG_EUKREA_CPUIMX27_NOR_64MB - register_device(&cfi_dev1); -#endif - register_device(&nand_dev); - register_device(&sdram_dev); - - PCCR0 |= PCCR0_I2C1_EN; - i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); - register_device(&i2c_dev); - - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); - protect_file("/dev/env0", 1); - envdev = "NOR"; - - printf("Using environment in %s Flash\n", envdev); - -#ifdef CONFIG_DRIVER_VIDEO_IMX - register_device(&imxfb_dev); - gpio_direction_output(GPIO_PORTE | 5, 0); - gpio_set_value(GPIO_PORTE | 5, 1); -#endif - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0xa0000100); - armlinux_set_architecture(MACH_TYPE_CPUIMX27); - - return 0; -} - -device_initcall(eukrea_cpuimx27_devices_init); - -#ifdef CONFIG_DRIVER_SERIAL_IMX -static struct device_d eukrea_cpuimx27_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; -#endif - -static int eukrea_cpuimx27_console_init(void) -{ -#ifdef CONFIG_DRIVER_SERIAL_IMX - register_device(&eukrea_cpuimx27_serial_device); -#endif - /* configure 8 bit UART on cs3 */ - FMCR &= ~0x2; - CS3U = 0x0000D603; - CS3L = 0x0D1D0D01; - CS3A = 0x00D20000; -#ifdef CONFIG_DRIVER_SERIAL_NS16550 - register_device(&quad_uart_serial_device); -#endif - return 0; -} - -console_initcall(eukrea_cpuimx27_console_init); - -static int eukrea_cpuimx27_late_init(void) -{ -#ifdef CONFIG_DRIVER_I2C_LP3972 - struct i2c_client *client; - u8 reg[1]; -#endif - console_flush(); - register_device(&fec_dev); - -#ifdef CONFIG_DRIVER_I2C_LP3972 - client = lp3972_get_client(); - if (!client) - return -ENODEV; - reg[0] = 0xa0; - i2c_write_reg(client, 0x39, reg, sizeof(reg)); -#endif - return 0; -} - -late_initcall(eukrea_cpuimx27_late_init); - -#ifdef CONFIG_NAND_IMX_BOOT -void __bare_init nand_boot(void) -{ - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); -} -#endif - diff --git a/board/eukrea_cpuimx27/eukrea_cpuimx27.dox b/board/eukrea_cpuimx27/eukrea_cpuimx27.dox deleted file mode 100644 index 6c2bfed..0000000 --- a/board/eukrea_cpuimx27/eukrea_cpuimx27.dox +++ /dev/null @@ -1,11 +0,0 @@ -/** @page eukrea_cpuimx27 Eukrea's CPUIMX27 - -This CPU card is based on a Freescale i.MX27 CPU. The card is shipped with: - -- up to 64MiB NOR type Flash Memory -- up to 256MiB synchronous dynamic RAM -- up to 512MiB NAND type Flash Memory -- MII 10/100 ethernet PHY -- optional 16554 Quad UART on CS3 - -*/ diff --git a/board/eukrea_cpuimx27/lowlevel_init.S b/board/eukrea_cpuimx27/lowlevel_init.S deleted file mode 100644 index 5295a8a..0000000 --- a/board/eukrea_cpuimx27/lowlevel_init.S +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#if defined CONFIG_EUKREA_CPUIMX27_SDRAM_256MB -#define ROWS0 ESDCTL_ROW14 -#define CFG0 0x0029572D -#elif defined CONFIG_EUKREA_CPUIMX27_SDRAM_128MB -#define ROWS0 ESDCTL_ROW13 -#define CFG0 0x00095728 -#endif - -#define ESDCTL0_VAL (ESDCTL0_SDE | ROWS0 | ESDCTL0_COL10) - -.macro sdram_init - /* - * DDR on CSD0 - */ - writel(0x0000000C, ESDMISC) /* Enable DDR SDRAM operation */ - - writel(0x55555555, DSCR(3)) /* Set the driving strength */ - writel(0x55555555, DSCR(5)) - writel(0x55555555, DSCR(6)) - writel(0x00005005, DSCR(7)) - writel(0x15555555, DSCR(8)) - - writel(0x00000004, ESDMISC) /* Initial reset */ - writel(CFG0, ESDCFG0) - - writel(ESDCTL0_VAL | ESDCTL0_SMODE_PRECHARGE, ESDCTL0) /* precharge CSD0 all banks */ - writel(0x00000000, 0xA0000F00) /* CSD0 precharge address (A10 = 1) */ - writel(ESDCTL0_VAL | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0) - - ldr r0, =0xa0000f00 - mov r1, #0 - mov r2, #8 -1: - str r1, [r0] - subs r2, #1 - bne 1b - - writel(ESDCTL0_VAL | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0) - ldr r0, =0xA0000033 - mov r1, #0xda - strb r1, [r0] -#if defined CONFIG_EUKREA_CPUIMX27_SDRAM_256MB - ldr r0, =0xA2000000 -#elif defined CONFIG_EUKREA_CPUIMX27_SDRAM_128MB - ldr r0, =0xA1000000 -#endif - mov r1, #0xff - strb r1, [r0] - writel(ESDCTL0_VAL | ESDCTL0_DSIZ_31_0 | ESDCTL0_REF4 | ESDCTL0_BL | ESDCTL0_SMODE_NORMAL, ESDCTL0) -.endm - - .section ".text_bare_init","ax" - -.globl board_init_lowlevel -board_init_lowlevel: - - mov r10, lr - - /* ahb lite ip interface */ - writel(0x20040304, AIPI1_PSR0) - writel(0xDFFBFCFB, AIPI1_PSR1) - writel(0x00000000, AIPI2_PSR0) - writel(0xFFFFFFFF, AIPI2_PSR1) - - /* disable mpll/spll */ - ldr r0, =CSCR - ldr r1, [r0] - bic r1, r1, #0x03 - str r1, [r0] - - /* - * pll clock initialization - see section 3.4.3 of the i.MX27 manual - */ - writel(0x00331C23, MPCTL0) /* MPLL = 399 MHz */ - writel(0x040C2403, SPCTL0) /* SPLL = 240 MHz */ - writel(0x33F38107 | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR) - - /* add some delay here */ - mov r1, #0x1000 -1: subs r1, r1, #0x1 - bne 1b - - /* clock gating enable */ - writel(0x00050f08, GPCR) - - /* peripheral clock divider */ - writel(0x130400c3, PCDR0) /* FIXME */ - writel(0x09030208, PCDR1) /* PERDIV1=08 @133 MHz */ - /* PERDIV1=04 @266 MHz */ - - /* skip sdram initialization if we run from ram */ - cmp pc, #0xa0000000 - bls 1f - cmp pc, #0xc0000000 - bhi 1f - - mov pc,r10 -1: - sdram_init - -#ifdef CONFIG_NAND_IMX_BOOT - ldr sp, =0xa0f00000 /* Setup a temporary stack in SDRAM */ - - ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ - ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ - - /* skip NAND boot if not running from NFC space */ - cmp pc, r0 - bls ret - cmp pc, r2 - bhi ret - - /* Move ourselves out of NFC SRAM */ - ldr r1, =TEXT_BASE - -copy_loop: - ldmia r0!, {r3-r9} /* copy from source address [r0] */ - stmia r1!, {r3-r9} /* copy to target address [r1] */ - cmp r0, r2 /* until source end addreee [r2] */ - ble copy_loop - - ldr pc, =1f /* Jump to SDRAM */ -1: - bl nand_boot /* Load barebox from NAND Flash */ - - ldr r1, =IMX_NFC_BASE - TEXT_BASE - sub r10, r10, r1 /* adjust return address from NFC SRAM */ - /* to SDRAM */ - -#endif /* CONFIG_NAND_IMX_BOOT */ - -ret: - mov pc,r10 diff --git a/board/eukrea_cpuimx35/Makefile b/board/eukrea_cpuimx35/Makefile deleted file mode 100644 index 32ffe42..0000000 --- a/board/eukrea_cpuimx35/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# -# (C) Copyright 2007 Juergen Beisert -# -# 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 -# - -obj-y += lowlevel.o -obj-y += eukrea_cpuimx35.o -obj-$(CONFIG_ARCH_IMX_INTERNAL_BOOT) += flash_header.o diff --git a/board/eukrea_cpuimx35/config.h b/board/eukrea_cpuimx35/config.h deleted file mode 100644 index bfd3b39..0000000 --- a/board/eukrea_cpuimx35/config.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#define CONFIG_MX35_HCLK_FREQ 24000000 - -#endif /* __CONFIG_H */ diff --git a/board/eukrea_cpuimx35/env/bin/_update b/board/eukrea_cpuimx35/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/eukrea_cpuimx35/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/eukrea_cpuimx35/env/bin/boot b/board/eukrea_cpuimx35/env/bin/boot deleted file mode 100644 index fca5b8c..0000000 --- a/board/eukrea_cpuimx35/env/bin/boot +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xjffS2 ]; then - root=jffs2 - kernel=nand -fi - -if [ x$1 = xubifs ]; then - root=ubifs - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - if [ x$ip = xoff ]; then - bootargs="$bootargs ip=off" - else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" - fi -fi - -if [ x$root = xjffs2 ]; then - bootargs="$bootargs root=/dev/mtdblock$rootpartnum_nand rootfstype=jffs2" -fi - -if [ x$root = xubifs ]; then - bootargs="$bootargs root=ubi0:$ubiroot ubi.mtd=$rootpartnum_nand rootfstype=ubifs" -fi - -if [ x$root = xnet ]; then - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=mxc_nand:$nand_parts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm /dev/nand0.kernel.bb -fi diff --git a/board/eukrea_cpuimx35/env/bin/hush_hack b/board/eukrea_cpuimx35/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/eukrea_cpuimx35/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/eukrea_cpuimx35/env/bin/init b/board/eukrea_cpuimx35/env/bin/init deleted file mode 100644 index 49e54c5..0000000 --- a/board/eukrea_cpuimx35/env/bin/init +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -f /env/logo.bmp ]; then - bmp /env/logo.bmp -elif [ -f /env/logo.bmp.lzo ]; then - unlzo /env/logo.bmp.lzo /logo.bmp - bmp /logo.bmp -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" - saveenv -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type update_root [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/eukrea_cpuimx35/env/bin/update_kernel b/board/eukrea_cpuimx35/env/bin/update_kernel deleted file mode 100644 index c2d2cc3..0000000 --- a/board/eukrea_cpuimx35/env/bin/update_kernel +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -part=/dev/nand0.kernel.bb - -. /env/bin/_update $1 diff --git a/board/eukrea_cpuimx35/env/bin/update_root b/board/eukrea_cpuimx35/env/bin/update_root deleted file mode 100644 index dd89a5a..0000000 --- a/board/eukrea_cpuimx35/env/bin/update_root +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$rootfs -part=/dev/nand0.root.bb - -. /env/bin/_update $1 diff --git a/board/eukrea_cpuimx35/env/config b/board/eukrea_cpuimx35/env/config deleted file mode 100644 index df2079f..0000000 --- a/board/eukrea_cpuimx35/env/config +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'nand'' -kernel=nand -root=ubifs - -basedir=cpuimx35 -uimage=$basedir/uImage -rootfs=$basedir/rootfs - -autoboot_timeout=1 - -nfsroot="" -bootargs="console=ttymxc0,115200" - -nand_parts="256k(barebox)ro,128k(bareboxenv),2176k(kernel),-(root)" -rootpartnum_nand=3 -ubiroot="eukrea-cpuimx35-rootfs" - -# use 'dhcp' to do dhcp in barebox and in kernel -ip=off - -# 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 diff --git a/board/eukrea_cpuimx35/eukrea_cpuimx35.c b/board/eukrea_cpuimx35/eukrea_cpuimx35.c deleted file mode 100644 index 7f1c782..0000000 --- a/board/eukrea_cpuimx35/eukrea_cpuimx35.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2007 Sascha Hauer, Pengutronix - * 2009 Marc Kleine-Budde, Pengutronix - * (c) 2010 Eukrea Electromatique, Eric Bénard - * - * 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 - * - * Derived from: - * - * * mx35_3stack.c - board file for uboot-v1 - * Copyright (C) 2007, Guennadi Liakhovetski - * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct fec_platform_data fec_info = { - .xcv_type = MII100, - .phy_addr = 0x1F, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = IMX_FEC_BASE, - .platform_data = &fec_info, -}; - -static struct memory_platform_data sdram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = IMX_SDRAM_CS0, - .size = 128 * 1024 * 1024, - .platform_data = &sdram_pdata, -}; - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, - .flash_bbt = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = IMX_NFC_BASE, - .platform_data = &nand_info, -}; - -static struct fb_videomode imxfb_mode = { - .name = "CMO_QVGA", - .refresh = 60, - .xres = 320, - .yres = 240, - .pixclock = KHZ2PICOS(7000), - .left_margin = 68, - .right_margin = 20, - .upper_margin = 15, - .lower_margin = 4, - .hsync_len = 30, - .vsync_len = 3, - .sync = FB_SYNC_OE_ACT_HIGH, - .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, -}; - -static struct imx_ipu_fb_platform_data ipu_fb_data = { - .mode = &imxfb_mode, - .bpp = 16, -}; - -static struct device_d imxfb_dev = { - .name = "imx-ipu-fb", - .map_base = 0x53fc0000, - .size = 0x1000, - .platform_data = &ipu_fb_data, -}; - -#ifdef CONFIG_MMU -static int eukrea_cpuimx35_mmu_init(void) -{ - mmu_init(); - - arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); - arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); - - setup_dma_coherent(0x10000000); - -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); - -#ifdef CONFIG_CACHE_L2X0 - l2x0_init((void __iomem *)0x30000000, 0x00030024, 0x00000000); -#endif - return 0; -} -postcore_initcall(eukrea_cpuimx35_mmu_init); -#endif - -static int eukrea_cpuimx35_devices_init(void) -{ - register_device(&nand_dev); - - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - - register_device(&fec_dev); - - register_device(&sdram_dev); - register_device(&imxfb_dev); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0x80000100); - armlinux_set_architecture(MACH_TYPE_EUKREA_CPUIMX35); - - return 0; -} - -device_initcall(eukrea_cpuimx35_devices_init); - -static int eukrea_cpuimx35_enable_display(void) -{ - gpio_direction_output(1, 1); - gpio_direction_output(0, 0); - return 0; -} - -late_initcall(eukrea_cpuimx35_enable_display); - -static struct device_d eukrea_cpuimx35_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; - -static struct pad_desc eukrea_cpuimx35_pads[] = { - MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, - MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, - MX35_PAD_FEC_RX_DV__FEC_RX_DV, - MX35_PAD_FEC_COL__FEC_COL, - MX35_PAD_FEC_RDATA0__FEC_RDATA_0, - MX35_PAD_FEC_TDATA0__FEC_TDATA_0, - MX35_PAD_FEC_TX_EN__FEC_TX_EN, - MX35_PAD_FEC_MDC__FEC_MDC, - MX35_PAD_FEC_MDIO__FEC_MDIO, - MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, - MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, - MX35_PAD_FEC_CRS__FEC_CRS, - MX35_PAD_FEC_RDATA0__FEC_RDATA_0, - MX35_PAD_FEC_TDATA0__FEC_TDATA_0, - MX35_PAD_FEC_RDATA1__FEC_RDATA_1, - MX35_PAD_FEC_TDATA1__FEC_TDATA_1, - MX35_PAD_FEC_RDATA2__FEC_RDATA_2, - MX35_PAD_FEC_TDATA2__FEC_TDATA_2, - MX35_PAD_FEC_RDATA3__FEC_RDATA_3, - MX35_PAD_FEC_TDATA3__FEC_TDATA_3, - - MX35_PAD_RXD1__UART1_RXD_MUX, - MX35_PAD_TXD1__UART1_TXD_MUX, - MX35_PAD_RTS1__UART1_RTS, - MX35_PAD_CTS1__UART1_CTS, -}; - -static int eukrea_cpuimx35_console_init(void) -{ - mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx35_pads, - ARRAY_SIZE(eukrea_cpuimx35_pads)); - - register_device(&eukrea_cpuimx35_serial_device); - return 0; -} - -console_initcall(eukrea_cpuimx35_console_init); - -static int eukrea_cpuimx35_core_init(void) -{ - u32 reg; - - /* enable clock for I2C1 and FEC */ - reg = readl(IMX_CCM_BASE + CCM_CGR1); - reg |= 0x3 << CCM_CGR1_FEC_SHIFT; - reg = writel(reg, IMX_CCM_BASE + CCM_CGR1); - - /* AIPS setup - Only setup MPROTx registers. The PACR default values are good.*/ - /* - * Set all MPROTx to be non-bufferable, trusted for R/W, - * not forced to user-mode. - */ - writel(0x77777777, IMX_AIPS1_BASE); - writel(0x77777777, IMX_AIPS1_BASE + 0x4); - writel(0x77777777, IMX_AIPS2_BASE); - writel(0x77777777, IMX_AIPS2_BASE + 0x4); - - /* - * Clear the on and off peripheral modules Supervisor Protect bit - * for SDMA to access them. Did not change the AIPS control registers - * (offset 0x20) access type - */ - writel(0x0, IMX_AIPS1_BASE + 0x40); - writel(0x0, IMX_AIPS1_BASE + 0x44); - writel(0x0, IMX_AIPS1_BASE + 0x48); - writel(0x0, IMX_AIPS1_BASE + 0x4C); - reg = readl(IMX_AIPS1_BASE + 0x50); - reg &= 0x00FFFFFF; - writel(reg, IMX_AIPS1_BASE + 0x50); - - writel(0x0, IMX_AIPS2_BASE + 0x40); - writel(0x0, IMX_AIPS2_BASE + 0x44); - writel(0x0, IMX_AIPS2_BASE + 0x48); - writel(0x0, IMX_AIPS2_BASE + 0x4C); - reg = readl(IMX_AIPS2_BASE + 0x50); - reg &= 0x00FFFFFF; - writel(reg, IMX_AIPS2_BASE + 0x50); - - /* MAX (Multi-Layer AHB Crossbar Switch) setup */ - - /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ -#define MAX_PARAM1 0x00302154 - writel(MAX_PARAM1, IMX_MAX_BASE + 0x000); /* for S0 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x100); /* for S1 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x200); /* for S2 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x300); /* for S3 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x400); /* for S4 */ - - /* SGPCR - always park on last master */ - writel(0x10, IMX_MAX_BASE + 0x10); /* for S0 */ - writel(0x10, IMX_MAX_BASE + 0x110); /* for S1 */ - writel(0x10, IMX_MAX_BASE + 0x210); /* for S2 */ - writel(0x10, IMX_MAX_BASE + 0x310); /* for S3 */ - writel(0x10, IMX_MAX_BASE + 0x410); /* for S4 */ - - /* MGPCR - restore default values */ - writel(0x0, IMX_MAX_BASE + 0x800); /* for M0 */ - writel(0x0, IMX_MAX_BASE + 0x900); /* for M1 */ - writel(0x0, IMX_MAX_BASE + 0xa00); /* for M2 */ - writel(0x0, IMX_MAX_BASE + 0xb00); /* for M3 */ - writel(0x0, IMX_MAX_BASE + 0xc00); /* for M4 */ - writel(0x0, IMX_MAX_BASE + 0xd00); /* for M5 */ - - /* - * M3IF Control Register (M3IFCTL) - * MRRP[0] = L2CC0 not on priority list (0 << 0) = 0x00000000 - * MRRP[1] = MAX1 not on priority list (0 << 0) = 0x00000000 - * MRRP[2] = L2CC1 not on priority list (0 << 0) = 0x00000000 - * MRRP[3] = USB not on priority list (0 << 0) = 0x00000000 - * MRRP[4] = SDMA not on priority list (0 << 0) = 0x00000000 - * MRRP[5] = GPU not on priority list (0 << 0) = 0x00000000 - * MRRP[6] = IPU1 on priority list (1 << 6) = 0x00000040 - * MRRP[7] = IPU2 not on priority list (0 << 0) = 0x00000000 - * ------------ - * 0x00000040 - */ - writel(0x40, IMX_M3IF_BASE); - - return 0; -} - -core_initcall(eukrea_cpuimx35_core_init); - -#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) -#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) - -static int do_cpufreq(struct command *cmdtp, int argc, char *argv[]) -{ - unsigned long freq; - - if (argc != 2) - return COMMAND_ERROR_USAGE; - - freq = simple_strtoul(argv[1], NULL, 0); - - switch (freq) { - case 399: - writel(MPCTL_PARAM_399, IMX_CCM_BASE + CCM_MPCTL); - break; - case 532: - writel(MPCTL_PARAM_532, IMX_CCM_BASE + CCM_MPCTL); - break; - default: - return COMMAND_ERROR_USAGE; - } - - printf("Switched CPU frequency to %dMHz\n", freq); - - return 0; -} - -static const __maybe_unused char cmd_cpufreq_help[] = -"Usage: cpufreq 399|532\n" -"\n" -"Set CPU frequency to MHz\n"; - -BAREBOX_CMD_START(cpufreq) - .cmd = do_cpufreq, - .usage = "adjust CPU frequency", - BAREBOX_CMD_HELP(cmd_cpufreq_help) -BAREBOX_CMD_END diff --git a/board/eukrea_cpuimx35/eukrea_cpuimx35.dox b/board/eukrea_cpuimx35/eukrea_cpuimx35.dox deleted file mode 100644 index cbdf69d..0000000 --- a/board/eukrea_cpuimx35/eukrea_cpuimx35.dox +++ /dev/null @@ -1,4 +0,0 @@ -/** @page eukrea_cpuimx35 Eukrea's CPUIMX35 - - -*/ diff --git a/board/eukrea_cpuimx35/flash_header.c b/board/eukrea_cpuimx35/flash_header.c deleted file mode 100644 index a0ccf5c..0000000 --- a/board/eukrea_cpuimx35/flash_header.c +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include - -extern unsigned long _stext; - -void __naked __flash_header_start go(void) -{ - __asm__ __volatile__("b exception_vectors\n"); -} - -struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { - { .ptr_type = 4, .addr = 0xB8001010, .val = 0x00000004, }, - { .ptr_type = 4, .addr = 0xB8001010, .val = 0x0000000C, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc3f, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0x92220000, }, - { .ptr_type = 1, .addr = 0x80000400, .val = 0x12345678, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0xA2220000, }, - { .ptr_type = 1, .addr = 0x80000000, .val = 0x87654321, }, - { .ptr_type = 1, .addr = 0x80000000, .val = 0x87654321, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0xB2220000, }, - { .ptr_type = 1, .addr = 0x80000033, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x82000000, .val = 0xda, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc2f, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0x82220080, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0x82228080, }, - { .ptr_type = 4, .addr = 0xB8001020, .val = 0x80000028, }, - { .ptr_type = 4, .addr = 0xB8001024, .val = 0x80000028, }, - { .ptr_type = 4, .addr = 0xB8001028, .val = 0x80000028, }, - { .ptr_type = 4, .addr = 0xB800102c, .val = 0x80000028, }, - { .ptr_type = 4, .addr = 0xB8001030, .val = 0x80000028, }, -}; - -#define APP_DEST 0x80000000 - -struct imx_flash_header __flash_header_0x400 flash_header = { - .app_code_jump_vector = APP_DEST + 0x1000, - .app_code_barker = APP_CODE_BARKER, - .app_code_csf = 0, - .dcd_ptr_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd), - .super_root_key = 0, - .dcd = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd_barker), - .app_dest = APP_DEST, - .dcd_barker = DCD_BARKER, - .dcd_block_len = sizeof (dcd_entry), -}; - -unsigned long __image_len_0x400 barebox_len = 0x40000; - diff --git a/board/eukrea_cpuimx35/lowlevel.c b/board/eukrea_cpuimx35/lowlevel.c deleted file mode 100644 index 44f3cf0..0000000 --- a/board/eukrea_cpuimx35/lowlevel.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Assuming 24MHz input clock */ -#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) -#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) -#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) - -#ifdef CONFIG_NAND_IMX_BOOT -static void __bare_init __naked insdram(void) -{ - uint32_t r; - - /* Speed up NAND controller by adjusting the NFC divider */ - r = readl(IMX_CCM_BASE + CCM_PDR4); - r &= ~(0xf << 28); - r |= 0x1 << 28; - writel(r, IMX_CCM_BASE + CCM_PDR4); - - /* setup a stack to be able to call imx_nand_load_image() */ - r = STACK_BASE + STACK_SIZE - 12; - __asm__ __volatile__("mov sp, %0" : : "r"(r)); - - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); - - board_init_lowlevel_return(); -} -#endif - -void __bare_init __naked board_init_lowlevel(void) -{ - uint32_t r, s; - unsigned long ccm_base = IMX_CCM_BASE; - unsigned long iomuxc_base = IMX_IOMUXC_BASE; -#ifdef CONFIG_NAND_IMX_BOOT - unsigned int *trg, *src; - int i; -#endif - - r = get_cr(); - r |= CR_Z; /* Flow prediction (Z) */ - r |= CR_U; /* unaligned accesses */ - r |= CR_FI; /* Low Int Latency */ - - __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1":"=r"(s)); - s |= 0x7; - __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1" : : "r"(s)); - - set_cr(r); - - r = 0; - __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); - - /* - * Branch predicition is now enabled. Flush the BTAC to ensure a valid - * starting point. Don't flush BTAC while it is disabled to avoid - * ARM1136 erratum 408023. - */ - __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 6" : : "r"(r)); - - /* invalidate I cache and D cache */ - __asm__ __volatile__("mcr p15, 0, %0, c7, c7, 0" : : "r"(r)); - - /* invalidate TLBs */ - __asm__ __volatile__("mcr p15, 0, %0, c8, c7, 0" : : "r"(r)); - - /* Drain the write buffer */ - __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4" : : "r"(r)); - - /* Also setup the Peripheral Port Remap register inside the core */ - r = 0x40000015; /* start from AIPS 2GB region */ - __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); - - /* - * End of ARM1136 init - */ - - writel(0x003F4208, ccm_base + CCM_CCMR); - - /* Set MPLL , arm clock and ahb clock*/ - writel(MPCTL_PARAM_532, ccm_base + CCM_MPCTL); - - writel(PPCTL_PARAM_300, ccm_base + CCM_PPCTL); - writel(0x00001000, ccm_base + CCM_PDR0); - - r = readl(ccm_base + CCM_CGR0); - r |= 0x00300000; - writel(r, ccm_base + CCM_CGR0); - - r = readl(ccm_base + CCM_CGR1); - r |= 0x00000C00; - r |= 0x00000003; - writel(r, ccm_base + CCM_CGR1); - - r = readl(IMX_L2CC_BASE + L2X0_AUX_CTRL); - r |= 0x1000; - writel(r, IMX_L2CC_BASE + L2X0_AUX_CTRL); - - /* Skip SDRAM initialization if we run from RAM */ - r = get_pc(); - if (r > 0x80000000 && r < 0x90000000) - board_init_lowlevel_return(); - - /* Set DDR Type to SDRAM, drive strength workaround * - * 0x00000000 MDDR * - * 0x00000800 3,3V SDRAM */ - - r = 0x00000800; - writel(r, iomuxc_base + 0x794); - writel(r, iomuxc_base + 0x798); - writel(r, iomuxc_base + 0x79c); - writel(r, iomuxc_base + 0x7a0); - writel(r, iomuxc_base + 0x7a4); - - /* MDDR init, enable mDDR*/ - writel(0x00000304, ESDMISC); /* was 0x00000004 */ - - /* set timing paramters */ - writel(0x00255417, ESDCFG0); - /* select Precharge-All mode */ - writel(0x92220000, ESDCTL0); - /* Precharge-All */ - writel(0x12345678, IMX_SDRAM_CS0 + 0x400); - - /* select Load-Mode-Register mode */ - writel(0xB8001000, ESDCTL0); - /* Load reg EMR2 */ - writeb(0xda, 0x84000000); - /* Load reg EMR3 */ - writeb(0xda, 0x86000000); - /* Load reg EMR1 -- enable DLL */ - writeb(0xda, 0x82000400); - /* Load reg MR -- reset DLL */ - writeb(0xda, 0x80000333); - - /* select Precharge-All mode */ - writel(0x92220000, ESDCTL0); - /* Precharge-All */ - writel(0x12345678, IMX_SDRAM_CS0 + 0x400); - - /* select Manual-Refresh mode */ - writel(0xA2220000, ESDCTL0); - /* Manual-Refresh 2 times */ - writel(0x87654321, IMX_SDRAM_CS0); - writel(0x87654321, IMX_SDRAM_CS0); - - /* select Load-Mode-Register mode */ - writel(0xB2220000, ESDCTL0); - /* Load reg MR -- CL3, BL8, end DLL reset */ - writeb(0xda, 0x80000233); - /* Load reg EMR1 -- OCD default */ - writeb(0xda, 0x82000780); - /* Load reg EMR1 -- OCD exit */ - writeb(0xda, 0x82000400); - - /* select normal-operation mode - * DSIZ32-bit, BL8, COL10-bit, ROW13-bit - * disable PWT & PRCT - * disable Auto-Refresh */ - writel(0x82220080, ESDCTL0); - - /* enable Auto-Refresh */ - writel(0x82228080, ESDCTL0); - /* enable Auto-Refresh */ - writel(0x00002000, ESDCTL1); - -#ifdef CONFIG_NAND_IMX_BOOT - /* skip NAND boot if not running from NFC space */ - r = get_pc(); - if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x800) - board_init_lowlevel_return(); - - src = (unsigned int *)IMX_NFC_BASE; - trg = (unsigned int *)TEXT_BASE; - - /* Move ourselves out of NFC SRAM */ - for (i = 0; i < 0x800 / sizeof(int); i++) - *trg++ = *src++; - - /* Jump to SDRAM */ - r = (unsigned int)&insdram; - __asm__ __volatile__("mov pc, %0" : : "r"(r)); -#else - board_init_lowlevel_return(); -#endif -} - diff --git a/board/freescale-mx25-3-stack/3stack.c b/board/freescale-mx25-3-stack/3stack.c deleted file mode 100644 index a77a02d..0000000 --- a/board/freescale-mx25-3-stack/3stack.c +++ /dev/null @@ -1,354 +0,0 @@ -/* - * (C) 2009 Pengutronix, Sascha Hauer - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -extern unsigned long _stext; - -void __naked __flash_header_start go(void) -{ - __asm__ __volatile__("b exception_vectors\n"); -} - -struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { - { .ptr_type = 4, .addr = 0xb8002050, .val = 0x0000d843, }, - { .ptr_type = 4, .addr = 0xb8002054, .val = 0x22252521, }, - { .ptr_type = 4, .addr = 0xb8002058, .val = 0x22220a00, }, -#if defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_64MB_DDR2 - { .ptr_type = 4, .addr = 0xb8001004, .val = 0x0076e83a, }, - { .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000304, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92210000, }, - { .ptr_type = 4, .addr = 0x80000f00, .val = 0x12344321, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2210000, }, - { .ptr_type = 1, .addr = 0x82000000, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x83000000, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x81000400, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x80000333, .val = 0xda, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92210000, }, - { .ptr_type = 4, .addr = 0x80000400, .val = 0x12344321, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0xa2210000, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2210000, }, - { .ptr_type = 1, .addr = 0x80000233, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x81000780, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x81000400, .val = 0xda, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216080, }, -#elif defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_128MB_MDDR - { .ptr_type = 4, .addr = 0xb8001010, .val = 0x00000004, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0x92100000, }, - { .ptr_type = 1, .addr = 0x80000400, .val = 0x21, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0xa2100000, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x12344321, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0xb2100000, }, - { .ptr_type = 1, .addr = 0x80000033, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x81000000, .val = 0xff, }, - { .ptr_type = 4, .addr = 0xb8001000, .val = 0x82216880, }, - { .ptr_type = 4, .addr = 0xb8001004, .val = 0x00295729, }, -#else -#error "Unsupported SDRAM type" -#endif - { .ptr_type = 4, .addr = 0x53f80008, .val = 0x20034000, }, -}; - -#define APP_DEST 0x80000000 - -struct imx_flash_header __flash_header_0x400 mx25_3ds_header = { - .app_code_jump_vector = APP_DEST + 0x1000, - .app_code_barker = APP_CODE_BARKER, - .app_code_csf = 0, - .dcd_ptr_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd), - .super_root_key = 0, - .dcd = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd_barker), - .app_dest = APP_DEST, - .dcd_barker = DCD_BARKER, - .dcd_block_len = sizeof (dcd_entry), -}; - -extern unsigned long __bss_start; - -unsigned long __image_len_0x400 barebox_len = 0x40000; - -static struct fec_platform_data fec_info = { - .xcv_type = RMII, - .phy_addr = 1, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = IMX_FEC_BASE, - .platform_data = &fec_info, -}; - -static struct memory_platform_data sdram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram0_dev = { - .name = "mem", - .map_base = IMX_SDRAM_CS0, -#if defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_64MB_DDR2 - .size = 64 * 1024 * 1024, -#elif defined CONFIG_FREESCALE_MX25_3STACK_SDRAM_128MB_MDDR - .size = 128 * 1024 * 1024, -#else -#error "Unsupported SDRAM type" -#endif - .platform_data = &sdram_pdata, -}; - -static struct memory_platform_data sram_pdata = { - .name = "sram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sram0_dev = { - .name = "mem", - .map_base = 0x78000000, - .size = 128 * 1024, - .platform_data = &sram_pdata, -}; - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = IMX_NFC_BASE, - .platform_data = &nand_info, -}; - -#ifdef CONFIG_USB -static void imx25_usb_init(void) -{ - unsigned int tmp; - - /* Host 2 */ - tmp = readl(IMX_OTG_BASE + 0x600); - tmp &= ~(3 << 21); - tmp |= (2 << 21) | (1 << 4) | (1 << 5); - writel(tmp, IMX_OTG_BASE + 0x600); - - tmp = readl(IMX_OTG_BASE + 0x584); - tmp |= 3 << 30; - writel(tmp, IMX_OTG_BASE + 0x584); - - /* Set to Host mode */ - tmp = readl(IMX_OTG_BASE + 0x5a8); - writel(tmp | 0x3, IMX_OTG_BASE + 0x5a8); -} - -static struct device_d usbh2_dev = { - .name = "ehci", - .map_base = IMX_OTG_BASE + 0x400, - .size = 0x200, -}; -#endif - -static struct i2c_board_info i2c_devices[] = { - { - I2C_BOARD_INFO("mc34704", 0x54), - }, -}; - -static struct device_d i2c_dev = { - .name = "i2c-imx", - .map_base = IMX_I2C1_BASE, -}; - -static int imx25_3ds_pmic_init(void) -{ - struct mc34704 *pmic; - - pmic = mc34704_get(); - if (pmic == NULL) - return -EIO; - - return mc34704_reg_write(pmic, 0x2, 0x9); -} - -static int imx25_3ds_fec_init(void) -{ - int ret; - - ret = imx25_3ds_pmic_init(); - if (ret < 0) - return ret; - - /* - * Set up the FEC_RESET_B and FEC_ENABLE GPIO pins. - * Assert FEC_RESET_B, then power up the PHY by asserting - * FEC_ENABLE, at the same time lifting FEC_RESET_B. - * - * FEC_RESET_B: gpio2[3] is ALT 5 mode of pin A17 - * FEC_ENABLE_B: gpio4[8] is ALT 5 mode of pin D12 - */ - writel(0x8, IMX_IOMUXC_BASE + 0x0238); /* open drain */ - writel(0x0, IMX_IOMUXC_BASE + 0x028C); /* cmos, no pu/pd */ - -#define FEC_ENABLE_GPIO 35 -#define FEC_RESET_B_GPIO 104 - - /* make the pins output */ - gpio_direction_output(FEC_ENABLE_GPIO, 0); /* drop PHY power */ - gpio_direction_output(FEC_RESET_B_GPIO, 0); /* assert reset */ - udelay(2); - - /* turn on power & lift reset */ - gpio_set_value(FEC_ENABLE_GPIO, 1); - gpio_set_value(FEC_RESET_B_GPIO, 1); - - return 0; -} -late_initcall(imx25_3ds_fec_init); - -static int imx25_devices_init(void) -{ -#ifdef CONFIG_USB - /* USB does not work yet. Don't know why. Maybe - * the CPLD has to be initialized. - */ - imx25_usb_init(); - register_device(&usbh2_dev); -#endif - - register_device(&fec_dev); - - if (readl(IMX_CCM_BASE + CCM_RCSR) & (1 << 14)) - nand_info.width = 2; - - register_device(&nand_dev); - - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - - register_device(&sdram0_dev); - register_device(&sram0_dev); - - i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); - register_device(&i2c_dev); - - armlinux_add_dram(&sdram0_dev); - armlinux_set_bootparams((void *)0x80000100); - armlinux_set_architecture(MACH_TYPE_MX25_3DS); - - return 0; -} - -device_initcall(imx25_devices_init); - -static struct device_d imx25_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 16 * 1024, -}; - -static struct pad_desc imx25_pads[] = { - MX25_PAD_FEC_MDC__MDC, - MX25_PAD_FEC_MDIO__MDIO, - MX25_PAD_FEC_RDATA0__RDATA0, - MX25_PAD_FEC_RDATA1__RDATA1, - MX25_PAD_FEC_RX_DV__RX_DV, - MX25_PAD_FEC_TDATA0__TDATA0, - MX25_PAD_FEC_TDATA1__TDATA1, - MX25_PAD_FEC_TX_CLK__TX_CLK, - MX25_PAD_FEC_TX_EN__TX_EN, - MX25_PAD_POWER_FAIL__POWER_FAIL_INT, - MX25_PAD_A17__GPIO3, - MX25_PAD_D12__GPIO8, - /* UART1 */ - MX25_PAD_UART1_RXD__RXD_MUX, - MX25_PAD_UART1_TXD__TXD_MUX, - MX25_PAD_UART1_RTS__RTS, - MX25_PAD_UART1_CTS__CTS, - /* USBH2 */ - MX25_PAD_D9__USBH2_PWR, - MX25_PAD_D8__USBH2_OC, - MX25_PAD_LD0__USBH2_CLK, - MX25_PAD_LD1__USBH2_DIR, - MX25_PAD_LD2__USBH2_STP, - MX25_PAD_LD3__USBH2_NXT, - MX25_PAD_LD4__USBH2_DATA0, - MX25_PAD_LD5__USBH2_DATA1, - MX25_PAD_LD6__USBH2_DATA2, - MX25_PAD_LD7__USBH2_DATA3, - MX25_PAD_HSYNC__USBH2_DATA4, - MX25_PAD_VSYNC__USBH2_DATA5, - MX25_PAD_LSCLK__USBH2_DATA6, - MX25_PAD_OE_ACD__USBH2_DATA7, - /* i2c */ - MX25_PAD_I2C1_CLK__SCL, - MX25_PAD_I2C1_DAT__SDA, -}; - -static int imx25_console_init(void) -{ - mxc_iomux_v3_setup_multiple_pads(imx25_pads, ARRAY_SIZE(imx25_pads)); - - writel(0x03010101, 0x53f80024); - - register_device(&imx25_serial_device); - return 0; -} - -console_initcall(imx25_console_init); - -#ifdef CONFIG_NAND_IMX_BOOT -void __bare_init nand_boot(void) -{ - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); -} -#endif - -static int imx25_core_setup(void) -{ - writel(0x01010103, IMX_CCM_BASE + CCM_PCDR2); - return 0; - -} -core_initcall(imx25_core_setup); - diff --git a/board/freescale-mx25-3-stack/Makefile b/board/freescale-mx25-3-stack/Makefile deleted file mode 100644 index ab853e0..0000000 --- a/board/freescale-mx25-3-stack/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# (C) Copyright 2007 Juergen Beisert -# -# 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 -# - -obj-y += lowlevel_init.o -obj-y += 3stack.o diff --git a/board/freescale-mx25-3-stack/config.h b/board/freescale-mx25-3-stack/config.h deleted file mode 100644 index f35e8a0..0000000 --- a/board/freescale-mx25-3-stack/config.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * (C) Copyright 2007 Juergen Beisert - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -/* - * Definitions related to passing arguments to kernel. - */ - -#define CONFIG_MX25_HCLK_FREQ 24000000 - -#endif - -/* nothing to do here yet */ diff --git a/board/freescale-mx25-3-stack/env/bin/_update b/board/freescale-mx25-3-stack/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/freescale-mx25-3-stack/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/freescale-mx25-3-stack/env/bin/boot b/board/freescale-mx25-3-stack/env/bin/boot deleted file mode 100644 index 7bbff2d..0000000 --- a/board/freescale-mx25-3-stack/env/bin/boot +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - root=nand - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$1 = xnor ]; then - root=nor - kernel=nor -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -elif [ x$root = xnor ]; then - bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts;mxc_nand:$nand_parts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -elif [ $kernel = nor ]; then - bootm /dev/nor0.kernel -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/freescale-mx25-3-stack/env/bin/hush_hack b/board/freescale-mx25-3-stack/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/freescale-mx25-3-stack/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/freescale-mx25-3-stack/env/bin/init b/board/freescale-mx25-3-stack/env/bin/init deleted file mode 100644 index 0600b9e..0000000 --- a/board/freescale-mx25-3-stack/env/bin/init +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nor0 ]; then - addpart /dev/nor0 $nor_parts -fi - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel nand|nor [] to update kernel into flash" - echo "type update_root nand|nor [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/freescale-mx25-3-stack/env/bin/update_kernel b/board/freescale-mx25-3-stack/env/bin/update_kernel deleted file mode 100644 index 05c822d..0000000 --- a/board/freescale-mx25-3-stack/env/bin/update_kernel +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.kernel.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.kernel -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 diff --git a/board/freescale-mx25-3-stack/env/bin/update_root b/board/freescale-mx25-3-stack/env/bin/update_root deleted file mode 100644 index eaf36eb..0000000 --- a/board/freescale-mx25-3-stack/env/bin/update_root +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.root.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.root -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 - diff --git a/board/freescale-mx25-3-stack/env/config b/board/freescale-mx25-3-stack/env/config deleted file mode 100644 index a5e492e..0000000 --- a/board/freescale-mx25-3-stack/env/config +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh - -# can be either 'net', 'nor' or 'nand'' -kernel=net -root=net - -uimage=uImage-pcm043 -jffs2=root-pcm043.jffs2 - -autoboot_timeout=3 - -nfsroot="/ptx/work/octopus/rsc/svn/oselas/bsp/phytec/phyCORE-i.MX27/OSELAS.BSP-Phytec-phyCORE-i.MX27-trunk/root" -bootargs="console=ttymxc0,115200" - -nor_parts="256k(barebox)ro,128k(bareboxenv),2048k(kernel),-(root)" -rootpart_nor="/dev/mtdblock3" - -nand_parts="256k(barebox)ro,128k(bareboxenv),2048k(kernel),108416k(root),-(kernel1)" -rootpart_nand="/dev/mtdblock7" - -# use 'dhcp' to do dhcp in barebox and in kernel -#ip=dhcp - -# or set your networking parameters here -eth0.ipaddr=192.168.3.11 -eth0.netmask=255.255.255.0 -#eth0.gateway=a.b.c.d -eth0.serverip=192.168.3.10 -eth0.ethaddr=00:50:c2:8c:e6:0e diff --git a/board/freescale-mx25-3-stack/lowlevel_init.S b/board/freescale-mx25-3-stack/lowlevel_init.S deleted file mode 100644 index 73bb147..0000000 --- a/board/freescale-mx25-3-stack/lowlevel_init.S +++ /dev/null @@ -1,253 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#define writeb(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - strb r1, [r0]; - -/* Assuming 24MHz input clock */ -#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) -#define MPCTL_PARAM_532 (IMX_PLL_PD(1) | IMX_PLL_MFD(0) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) -#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) - -.section ".text_bare_init","ax" - -ARM_PPMRR: .word 0x40000015 -L2CACHE_PARAM: .word 0x00030024 -CCM_CCMR_W: .word 0x003F4208 -CCM_PDR0_W: .word 0x00801000 -MPCTL_PARAM_399_W: .word MPCTL_PARAM_399 -MPCTL_PARAM_532_W: .word MPCTL_PARAM_532 -PPCTL_PARAM_W: .word PPCTL_PARAM_300 -CCM_BASE_ADDR_W: .word IMX_CCM_BASE - -.globl board_init_lowlevel -board_init_lowlevel: - mov r10, lr - -#define MX25_CCM_MCR 0x64 - - ldr r0, CCM_BASE_ADDR_W - /* default CLKO to 1/32 of the ARM core */ - ldr r1, [r0, #MX25_CCM_MCR] - bic r1, r1, #0x00F00000 - bic r1, r1, #0x7F000000 - mov r2, #0x5F000000 - add r2, r2, #0x00200000 - orr r1, r1, r2 - str r1, [r0, #MX25_CCM_MCR] - - /* enable all the clocks */ - writel(0x1FFFFFFF, IMX_CCM_BASE + CCM_CGCR0) - writel(0xFFFFFFFF, IMX_CCM_BASE + CCM_CGCR1) - writel(0x000FDFFF, IMX_CCM_BASE + CCM_CGCR2) - writel(0x0000FEFF, IMX_CCM_BASE + MX25_CCM_MCR) - - /* Skip SDRAM initialization if we run from RAM */ - cmp pc, #0x80000000 - bls 1f - cmp pc, #0x90000000 - bhi 1f - - mov pc, lr - -1: - ldr r0, ESDCTL_BASE_W - mov r3, #0x2000 - str r3, [r0, #0x0] - str r3, [r0, #0x8] - - mov r12, #0x00 - mov r2, #0x1 /* mDDR */ - mov r1, #IMX_SDRAM_CS0 - bl setup_sdram_bank -// cmp r3, #0x0 -// orreq r12, r12, #1 -// eorne r2, r2, #0x1 -// blne setup_sdram_bank - - ldr r3, ESDCTL_DELAY5 - str r3, [r0, #0x30] - -#ifdef CONFIG_NAND_IMX_BOOT - ldr sp, =0xa0f00000 /* Setup a temporary stack in SDRAM */ - - ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ - ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ - - /* skip NAND boot if not running from NFC space */ - cmp pc, r0 - bls ret - cmp pc, r2 - bhi ret - - /* Move ourselves out of NFC SRAM */ - ldr r1, =TEXT_BASE - -copy_loop: - ldmia r0!, {r3-r9} /* copy from source address [r0] */ - stmia r1!, {r3-r9} /* copy to target address [r1] */ - cmp r0, r2 /* until source end addreee [r2] */ - ble copy_loop - - ldr pc, =1f /* Jump to SDRAM */ -1: - bl nand_boot /* Load barebox from NAND Flash */ - - ldr r1, =IMX_NFC_BASE - TEXT_BASE - sub r10, r10, r1 /* adjust return address from NFC SRAM */ - /* to SDRAM */ - -#endif /* CONFIG_NAND_IMX_BOOT */ - -ret: - mov pc, r10 - -/* - * r0: control base, r1: ram bank base - * r2: ddr type(0:DDR2, 1:MDDR) r3, r4: working - */ -setup_sdram_bank: - mov r3, #0xE /* 0xA + 0x4 */ - tst r2, #0x1 - orreq r3, r3, #0x300 /* DDR2 */ - str r3, [r0, #0x10] - bic r3, r3, #0x00A - str r3, [r0, #0x10] - beq 2f - - mov r3, #0x20000 -1: subs r3, r3, #1 - bne 1b - -2: adr r4, ESDCTL_CONFIG - tst r2, #0x1 - ldreq r3, [r4, #0x0] - ldrne r3, [r4, #0x4] - cmp r1, #IMX_SDRAM_CS1 - strlo r3, [r0, #0x4] - strhs r3, [r0, #0xC] - - ldr r3, ESDCTL_0x92220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, RAM_PARAM1_MDDR - strb r3, [r1, r4] - - tst r2, #0x1 - bne skip_set_mode - - cmp r1, #IMX_SDRAM_CS1 - ldr r3, ESDCTL_0xB2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, RAM_PARAM4_MDDR - strb r3, [r1, r4] - ldr r4, RAM_PARAM5_MDDR - strb r3, [r1, r4] - ldr r4, RAM_PARAM3_MDDR - strb r3, [r1, r4] - ldr r4, RAM_PARAM2_MDDR - strb r3, [r1, r4] - - ldr r3, ESDCTL_0x92220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, RAM_PARAM1_MDDR - strb r3, [r1, r4] - -skip_set_mode: - cmp r1, #IMX_SDRAM_CS1 - ldr r3, ESDCTL_0xA2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - strb r3, [r1] - strb r3, [r1] - - ldr r3, ESDCTL_0xB2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - adr r4, RAM_PARAM6_MDDR - tst r2, #0x1 - ldreq r4, [r4, #0x0] - ldrne r4, [r4, #0x4] - mov r3, #0xDA - strb r3, [r1, r4] - ldreq r4, RAM_PARAM7_MDDR - streqb r3, [r1, r4] - adr r4, RAM_PARAM3_MDDR - ldreq r4, [r4, #0x0] - ldrne r4, [r4, #0x4] - strb r3, [r1, r4] - - cmp r1, #IMX_SDRAM_CS1 - ldr r3, ESDCTL_0x82226080 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - - tst r2, #0x1 - moveq r4, #0x20000 - movne r4, #0x200 -1: subs r4, r4, #1 - bne 1b - - str r3, [r1, #0x100] - ldr r4, [r1, #0x100] - cmp r3, r4 - movne r3, #1 - moveq r3, #0 - - mov pc, lr - -RAM_PARAM1_MDDR: .word 0x00000400 -RAM_PARAM2_MDDR: .word 0x00000333 -RAM_PARAM3_MDDR: .word 0x02000400 - .word 0x02000000 -RAM_PARAM4_MDDR: .word 0x04000000 -RAM_PARAM5_MDDR: .word 0x06000000 -RAM_PARAM6_MDDR: .word 0x00000233 - .word 0x00000033 -RAM_PARAM7_MDDR: .word 0x02000780 -ESDCTL_0x92220000: .word 0x92210000 -ESDCTL_0xA2220000: .word 0xA2210000 -ESDCTL_0xB2220000: .word 0xB2210000 -ESDCTL_0x82226080: .word 0x82216080 -ESDCTL_CONFIG: .word 0x007FFC3F - .word 0x007FFC3F -ESDCTL_DELAY5: .word 0x00F49F00 -ESDCTL_BASE_W: .word IMX_ESD_BASE - diff --git a/board/freescale-mx35-3-stack/3stack.c b/board/freescale-mx35-3-stack/3stack.c deleted file mode 100644 index 9a66976..0000000 --- a/board/freescale-mx35-3-stack/3stack.c +++ /dev/null @@ -1,498 +0,0 @@ -/* - * Copyright (C) 2007 Sascha Hauer, Pengutronix - * 2009 Marc Kleine-Budde, 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 - * - * Derived from: - * - * * mx35_3stack.c - board file for uboot-v1 - * Copyright (C) 2007, Guennadi Liakhovetski - * (C) Copyright 2008-2009 Freescale Semiconductor, Inc. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - -/* Board rev for the PDK 3stack */ -#define MX35PDK_BOARD_REV_1 0 -#define MX35PDK_BOARD_REV_2 1 - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = IMX_CS0_BASE, - .size = 64 * 1024 * 1024, -}; - -static struct fec_platform_data fec_info = { - .xcv_type = MII100, - .phy_addr = 0x1F, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = IMX_FEC_BASE, - .platform_data = &fec_info, -}; - -static struct memory_platform_data sdram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = IMX_SDRAM_CS0, - .size = 128 * 1024 * 1024, - .platform_data = &sdram_pdata, -}; - -struct imx_nand_platform_data nand_info = { - .hw_ecc = 1, - .flash_bbt = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = IMX_NFC_BASE, - .platform_data = &nand_info, -}; - -static struct device_d smc911x_dev = { - .name = "smc911x", - .map_base = IMX_CS5_BASE, - .size = IMX_CS5_RANGE, -}; - -static struct i2c_board_info i2c_devices[] = { - { - I2C_BOARD_INFO("mc13892", 0x08), - }, { - I2C_BOARD_INFO("mc9sdz60", 0x69), - }, -}; - -static struct device_d i2c_dev = { - .name = "i2c-imx", - .map_base = IMX_I2C1_BASE, -}; - -/* - * Generic display, shipped with the PDK - */ -static struct fb_videomode CTP_CLAA070LC0ACW = { - /* 800x480 @ 60 Hz */ - .name = "CTP-CLAA070LC0ACW", - .refresh = 60, - .xres = 800, - .yres = 480, - .pixclock = KHZ2PICOS(27000), - .left_margin = 50, - .right_margin = 50, /* whole line should have 900 clocks */ - .upper_margin = 10, - .lower_margin = 10, /* whole frame should have 500 lines */ - .hsync_len = 1, /* note: DE only display */ - .vsync_len = 1, /* note: DE only display */ - .sync = FB_SYNC_CLK_IDLE_EN | FB_SYNC_OE_ACT_HIGH, - .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, -}; - -static struct imx_ipu_fb_platform_data ipu_fb_data = { - .mode = &CTP_CLAA070LC0ACW, - .bpp = 16, -}; - -static struct device_d imxfb_dev = { - .name = "imx-ipu-fb", - .map_base = 0x53fc0000, - .size = 0x1000, - .platform_data = &ipu_fb_data, -}; - -/* - * Revision to be passed to kernel. The kernel provided - * by freescale relies on this. - * - * C --> CPU type - * S --> Silicon revision - * B --> Board rev - * - * 31 20 16 12 8 4 0 - * | Cmaj | Cmin | B | Smaj | Smin| - * - * e.g 0x00035120 --> i.MX35, Cpu silicon rev 2.0, Board rev 2 -*/ -static unsigned int imx35_3ds_system_rev = 0x00035000; - -static void set_silicon_rev( int rev) -{ - imx35_3ds_system_rev = imx35_3ds_system_rev | (rev & 0xFF); -} - -static void set_board_rev(int rev) -{ - imx35_3ds_system_rev = (imx35_3ds_system_rev & ~(0xF << 8)) | (rev & 0xF) << 8; -} - - -static int f3s_devices_init(void) -{ - uint32_t reg; - - /* CS0: Nor Flash */ - writel(0x0000cf03, CSCR_U(0)); - writel(0x10000d03, CSCR_L(0)); - writel(0x00720900, CSCR_A(0)); - - reg = readl(IMX_CCM_BASE + CCM_RCSR); - /* some fuses provide us vital information about connected hardware */ - if (reg & 0x20000000) - nand_info.width = 2; /* 16 bit */ - else - nand_info.width = 1; /* 8 bit */ - - /* - * This platform supports NOR and NAND - */ - register_device(&nand_dev); - register_device(&cfi_dev); - - switch ((reg >> 25) & 0x3) { - case 0x01: /* NAND is the source */ - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x40000, 0x80000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - break; - - case 0x00: /* NOR is the source */ - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x80000, PARTITION_FIXED, "env0"); - protect_file("/dev/env0", 1); - break; - } - - set_silicon_rev(imx_silicon_revision()); - - i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); - register_device(&i2c_dev); - - register_device(&fec_dev); - register_device(&smc911x_dev); - - register_device(&sdram_dev); - register_device(&imxfb_dev); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0x80000100); - armlinux_set_architecture(MACH_TYPE_MX35_3DS); - - return 0; -} - -device_initcall(f3s_devices_init); - -static int f3s_enable_display(void) -{ - /* Enable power to the LCD. (bit 6 hi.) */ - mc9sdz60_set_bits(mc9sdz60_get(), MC9SDZ60_REG_GPIO_1, 0x40, 0x40); - - return 0; -} - -late_initcall(f3s_enable_display); - -static struct device_d f3s_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; - -static struct pad_desc f3s_pads[] = { - MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, - MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, - MX35_PAD_FEC_RX_DV__FEC_RX_DV, - MX35_PAD_FEC_COL__FEC_COL, - MX35_PAD_FEC_RDATA0__FEC_RDATA_0, - MX35_PAD_FEC_TDATA0__FEC_TDATA_0, - MX35_PAD_FEC_TX_EN__FEC_TX_EN, - MX35_PAD_FEC_MDC__FEC_MDC, - MX35_PAD_FEC_MDIO__FEC_MDIO, - MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, - MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, - MX35_PAD_FEC_CRS__FEC_CRS, - MX35_PAD_FEC_RDATA0__FEC_RDATA_0, - MX35_PAD_FEC_TDATA0__FEC_TDATA_0, - MX35_PAD_FEC_RDATA1__FEC_RDATA_1, - MX35_PAD_FEC_TDATA1__FEC_TDATA_1, - MX35_PAD_FEC_RDATA2__FEC_RDATA_2, - MX35_PAD_FEC_TDATA2__FEC_TDATA_2, - MX35_PAD_FEC_RDATA3__FEC_RDATA_3, - MX35_PAD_FEC_TDATA3__FEC_TDATA_3, - - MX35_PAD_RXD1__UART1_RXD_MUX, - MX35_PAD_TXD1__UART1_TXD_MUX, - MX35_PAD_RTS1__UART1_RTS, - MX35_PAD_CTS1__UART1_CTS, - - MX35_PAD_I2C1_CLK__I2C1_SCL, - MX35_PAD_I2C1_DAT__I2C1_SDA, - - MX35_PAD_WDOG_RST__GPIO1_6, - MX35_PAD_COMPARE__GPIO1_5, - - /* Display */ - MX35_PAD_LD0__IPU_DISPB_DAT_0, - MX35_PAD_LD1__IPU_DISPB_DAT_1, - MX35_PAD_LD2__IPU_DISPB_DAT_2, - MX35_PAD_LD3__IPU_DISPB_DAT_3, - MX35_PAD_LD4__IPU_DISPB_DAT_4, - MX35_PAD_LD5__IPU_DISPB_DAT_5, - MX35_PAD_LD6__IPU_DISPB_DAT_6, - MX35_PAD_LD7__IPU_DISPB_DAT_7, - MX35_PAD_LD8__IPU_DISPB_DAT_8, - MX35_PAD_LD9__IPU_DISPB_DAT_9, - MX35_PAD_LD10__IPU_DISPB_DAT_10, - MX35_PAD_LD11__IPU_DISPB_DAT_11, - MX35_PAD_LD12__IPU_DISPB_DAT_12, - MX35_PAD_LD13__IPU_DISPB_DAT_13, - MX35_PAD_LD14__IPU_DISPB_DAT_14, - MX35_PAD_LD15__IPU_DISPB_DAT_15, - MX35_PAD_LD16__IPU_DISPB_DAT_16, - MX35_PAD_LD17__IPU_DISPB_DAT_17, - MX35_PAD_D3_HSYNC__IPU_DISPB_D3_HSYNC, - MX35_PAD_D3_FPSHIFT__IPU_DISPB_D3_CLK, - MX35_PAD_D3_DRDY__IPU_DISPB_D3_DRDY, - MX35_PAD_CONTRAST__IPU_DISPB_CONTR, - MX35_PAD_D3_VSYNC__IPU_DISPB_D3_VSYNC, - MX35_PAD_D3_REV__IPU_DISPB_D3_REV, - MX35_PAD_D3_CLS__IPU_DISPB_D3_CLS, -}; - -static int f3s_console_init(void) -{ - mxc_iomux_v3_setup_multiple_pads(f3s_pads, ARRAY_SIZE(f3s_pads)); - - register_device(&f3s_serial_device); - return 0; -} - -console_initcall(f3s_console_init); - -static int f3s_core_init(void) -{ - u32 reg; - - writel(0x0000D843, CSCR_U(5)); /* CS5: smc9117 */ - writel(0x22252521, CSCR_L(5)); - writel(0x22220A00, CSCR_A(5)); - - /* enable clock for I2C1 and FEC */ - reg = readl(IMX_CCM_BASE + CCM_CGR1); - reg |= 0x3 << CCM_CGR1_FEC_SHIFT; - reg |= 0x3 << CCM_CGR1_I2C1_SHIFT; - reg = writel(reg, IMX_CCM_BASE + CCM_CGR1); - - /* AIPS setup - Only setup MPROTx registers. The PACR default values are good.*/ - /* - * Set all MPROTx to be non-bufferable, trusted for R/W, - * not forced to user-mode. - */ - writel(0x77777777, IMX_AIPS1_BASE); - writel(0x77777777, IMX_AIPS1_BASE + 0x4); - writel(0x77777777, IMX_AIPS2_BASE); - writel(0x77777777, IMX_AIPS2_BASE + 0x4); - - /* - * Clear the on and off peripheral modules Supervisor Protect bit - * for SDMA to access them. Did not change the AIPS control registers - * (offset 0x20) access type - */ - writel(0x0, IMX_AIPS1_BASE + 0x40); - writel(0x0, IMX_AIPS1_BASE + 0x44); - writel(0x0, IMX_AIPS1_BASE + 0x48); - writel(0x0, IMX_AIPS1_BASE + 0x4C); - reg = readl(IMX_AIPS1_BASE + 0x50); - reg &= 0x00FFFFFF; - writel(reg, IMX_AIPS1_BASE + 0x50); - - writel(0x0, IMX_AIPS2_BASE + 0x40); - writel(0x0, IMX_AIPS2_BASE + 0x44); - writel(0x0, IMX_AIPS2_BASE + 0x48); - writel(0x0, IMX_AIPS2_BASE + 0x4C); - reg = readl(IMX_AIPS2_BASE + 0x50); - reg &= 0x00FFFFFF; - writel(reg, IMX_AIPS2_BASE + 0x50); - - /* MAX (Multi-Layer AHB Crossbar Switch) setup */ - - /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ -#define MAX_PARAM1 0x00302154 - writel(MAX_PARAM1, IMX_MAX_BASE + 0x000); /* for S0 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x100); /* for S1 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x200); /* for S2 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x300); /* for S3 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x400); /* for S4 */ - - /* SGPCR - always park on last master */ - writel(0x10, IMX_MAX_BASE + 0x10); /* for S0 */ - writel(0x10, IMX_MAX_BASE + 0x110); /* for S1 */ - writel(0x10, IMX_MAX_BASE + 0x210); /* for S2 */ - writel(0x10, IMX_MAX_BASE + 0x310); /* for S3 */ - writel(0x10, IMX_MAX_BASE + 0x410); /* for S4 */ - - /* MGPCR - restore default values */ - writel(0x0, IMX_MAX_BASE + 0x800); /* for M0 */ - writel(0x0, IMX_MAX_BASE + 0x900); /* for M1 */ - writel(0x0, IMX_MAX_BASE + 0xa00); /* for M2 */ - writel(0x0, IMX_MAX_BASE + 0xb00); /* for M3 */ - writel(0x0, IMX_MAX_BASE + 0xc00); /* for M4 */ - writel(0x0, IMX_MAX_BASE + 0xd00); /* for M5 */ - - return 0; -} - -core_initcall(f3s_core_init); - -static int f3s_get_rev(struct mc13892 *mc13892) -{ - u32 rev; - int err; - - err = mc13892_reg_read(mc13892, MC13892_REG_IDENTIFICATION, &rev); - if (err) - return err; - - dev_info(&mc13892->client->dev, "revision: 0x%x\n", rev); - if (rev == 0x00ffffff) - return -ENODEV; - - return ((rev >> 6) & 0x7) ? MX35PDK_BOARD_REV_2 : MX35PDK_BOARD_REV_1; -} - -static int f3s_pmic_init_v2(struct mc13892 *mc13892) -{ - int err = 0; - - /* COMPARE pin (GPIO1_5) as output and set high */ - gpio_direction_output( 32*0 + 5 , 1); - - err |= mc13892_set_bits(mc13892, MC13892_REG_SETTING_0, 0x03, 0x03); - err |= mc13892_set_bits(mc13892, MC13892_REG_MODE_0, 0x01, 0x01); - if (err) - dev_err(&mc13892->client->dev, - "Init sequence failed, the system might not be working!\n"); - - return err; -} - -static int f3s_pmic_init_all(struct mc9sdz60 *mc9sdz60) -{ - int err = 0; - - err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_GPIO_1, 0x04, 0x04); - - err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_RESET_1, 0x80, 0x00); - mdelay(200); - err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_RESET_1, 0x80, 0x80); - - if (err) - dev_err(&mc9sdz60->client->dev, - "Init sequence failed, the system might not be working!\n"); - - return err; -} - -static int f3s_pmic_init(void) -{ - struct mc13892 *mc13892; - struct mc9sdz60 *mc9sdz60; - int rev; - - mc13892 = mc13892_get(); - if (!mc13892) { - printf("FAILED to get mc13892 handle!\n"); - return 0; - } - - rev = f3s_get_rev(mc13892); - switch (rev) { - case MX35PDK_BOARD_REV_1: - break; - case MX35PDK_BOARD_REV_2: - f3s_pmic_init_v2(mc13892); - break; - default: - printf("FAILED to identify board revision!\n"); - return 0; - } - - set_board_rev(rev); - printf("i.MX35 PDK CPU board version %d.\n", rev ); - - mc9sdz60 = mc9sdz60_get(); - if (!mc9sdz60) { - printf("FAILED to get mc9sdz60 handle!\n"); - return 0; - } - - f3s_pmic_init_all(mc9sdz60); - - armlinux_set_revision(imx35_3ds_system_rev); - - return 0; -} - -late_initcall(f3s_pmic_init); - -#ifdef CONFIG_NAND_IMX_BOOT -void __bare_init nand_boot(void) -{ - /* - * The driver is able to detect NAND's pagesize by CPU internal - * fuses or external pull ups. But not the blocksize... - */ - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); -} -#endif diff --git a/board/freescale-mx35-3-stack/3stack.dox b/board/freescale-mx35-3-stack/3stack.dox deleted file mode 100644 index 15c5b6e..0000000 --- a/board/freescale-mx35-3-stack/3stack.dox +++ /dev/null @@ -1,4 +0,0 @@ -/** @page the3stack Freescale MX35 3-Stack Board - - -*/ diff --git a/board/freescale-mx35-3-stack/Makefile b/board/freescale-mx35-3-stack/Makefile deleted file mode 100644 index a8ea4a3..0000000 --- a/board/freescale-mx35-3-stack/Makefile +++ /dev/null @@ -1,4 +0,0 @@ - -obj-y += lowlevel_init.o -obj-y += 3stack.o -obj-$(CONFIG_ARCH_IMX_INTERNAL_BOOT) += flash_header.o diff --git a/board/freescale-mx35-3-stack/board-mx35_3stack.h b/board/freescale-mx35-3-stack/board-mx35_3stack.h deleted file mode 100644 index c18066a..0000000 --- a/board/freescale-mx35-3-stack/board-mx35_3stack.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * - * (C) Copyright 2008 Freescale Semiconductor, Inc. - * - * 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 __BOARD_MX35_3STACK_H -#define __BOARD_MX35_3STACK_H - -#define UNALIGNED_ACCESS_ENABLE -#define LOW_INT_LATENCY_ENABLE -#define BRANCH_PREDICTION_ENABLE - -#define L2CC_AUX_CTL_CONFIG 0x00030024 - -#define AIPS_MPR_CONFIG 0x77777777 -#define AIPS_OPACR_CONFIG 0x00000000 - -/* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ -#define MAX_MPR_CONFIG 0x00302154 -/* SGPCR - always park on last master */ -#define MAX_SGPCR_CONFIG 0x00000010 -/* MGPCR - restore default values */ -#define MAX_MGPCR_CONFIG 0x00000000 - -/* - * M3IF Control Register (M3IFCTL) - * MRRP[0] = L2CC0 not on priority list (0 << 0) = 0x00000000 - * MRRP[1] = L2CC1 not on priority list (0 << 0) = 0x00000000 - * MRRP[2] = MBX not on priority list (0 << 0) = 0x00000000 - * MRRP[3] = MAX1 not on priority list (0 << 0) = 0x00000000 - * MRRP[4] = SDMA not on priority list (0 << 0) = 0x00000000 - * MRRP[5] = MPEG4 not on priority list (0 << 0) = 0x00000000 - * MRRP[6] = IPU1 on priority list (1 << 6) = 0x00000040 - * MRRP[7] = IPU2 not on priority list (0 << 0) = 0x00000000 - * ------------ - * 0x00000040 - */ -#define M3IF_CONFIG 0x00000040 - -#define DBG_BASE_ADDR WEIM_CTRL_CS5 -#define DBG_CSCR_U_CONFIG 0x0000D843 -#define DBG_CSCR_L_CONFIG 0x22252521 -#define DBG_CSCR_A_CONFIG 0x22220A00 - -#define CCM_CCMR_CONFIG 0x003F4208 -#define CCM_PDR0_CONFIG 0x00821000 - -#define PLL_BRM_OFFSET 31 -#define PLL_PD_OFFSET 26 -#define PLL_MFD_OFFSET 16 -#define PLL_MFI_OFFSET 10 - -#define _PLL_BRM(x) ((x) << PLL_BRM_OFFSET) -#define _PLL_PD(x) (((x) - 1) << PLL_PD_OFFSET) -#define _PLL_MFD(x) (((x) - 1) << PLL_MFD_OFFSET) -#define _PLL_MFI(x) ((x) << PLL_MFI_OFFSET) -#define _PLL_MFN(x) (x) -#define _PLL_SETTING(brm, pd, mfd, mfi, mfn) \ - (_PLL_BRM(brm) | _PLL_PD(pd) | _PLL_MFD(mfd) | _PLL_MFI(mfi) |\ - _PLL_MFN(mfn)) - -#define CCM_MPLL_532_HZ _PLL_SETTING(1, 1, 12, 11, 1) -#define CCM_MPLL_399_HZ _PLL_SETTING(0, 1, 16, 8, 5) -#define CCM_PPLL_300_HZ _PLL_SETTING(0, 1, 4, 6, 1) - -/*MEMORY SETING*/ -#define ESDCTL_0x92220000 0x92220000 -#define ESDCTL_0xA2220000 0xA2220000 -#define ESDCTL_0xB2220000 0xB2220000 -#define ESDCTL_0x82228080 0x82228080 - -#define ESDCTL_PRECHARGE 0x00000400 - -#define ESDCTL_MDDR_CONFIG 0x007FFC3F -#define ESDCTL_MDDR_MR 0x00000033 -#define ESDCTL_MDDR_EMR 0x02000000 - -#define ESDCTL_DDR2_CONFIG 0x007FFC3F -#define ESDCTL_DDR2_EMR2 0x04000000 -#define ESDCTL_DDR2_EMR3 0x06000000 -#define ESDCTL_DDR2_EN_DLL 0x02000400 -#define ESDCTL_DDR2_RESET_DLL 0x00000333 -#define ESDCTL_DDR2_MR 0x00000233 -#define ESDCTL_DDR2_OCD_DEFAULT 0x02000780 - -#define ESDCTL_DELAY_LINE5 0x00F49F00 -#endif /* __BOARD_MX35_3STACK_H */ diff --git a/board/freescale-mx35-3-stack/config.h b/board/freescale-mx35-3-stack/config.h deleted file mode 100644 index c724a57..0000000 --- a/board/freescale-mx35-3-stack/config.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 - */ - -/** - * @file - * @brief Global defintions for the Freescale i.MX35 3-stack board - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#define CONFIG_MX35_HCLK_FREQ 24000000 - -#endif /* __CONFIG_H */ diff --git a/board/freescale-mx35-3-stack/env/bin/_update b/board/freescale-mx35-3-stack/env/bin/_update deleted file mode 100644 index ddd6b84..0000000 --- a/board/freescale-mx35-3-stack/env/bin/_update +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "Server did not reply! Update aborted." - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -echo -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part - -protect $part diff --git a/board/freescale-mx35-3-stack/env/bin/boot b/board/freescale-mx35-3-stack/env/bin/boot deleted file mode 100644 index fb2fe61..0000000 --- a/board/freescale-mx35-3-stack/env/bin/boot +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - rootfs_loc=nand - kernel_loc=nand -elif [ x$1 = xnor ]; then - rootfs_loc=nor - kernel_loc=nor -elif [ x$1 = xnet ]; then - rootfs_loc=net - kernel_loc=net -fi - - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -elif [ x$ip != xno ]; then - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - - -if [ $rootfs_loc != net ]; then - if [ x$rootfs_loc = xnand ]; then - rootfs_mtdblock=$rootfs_mtdblock_nand - else - rootfs_mtdblock=$rootfs_mtdblock_nor - fi - - - if [ $rootfs_type = ubifs ]; then - bootargs="$bootargs root=ubi0:root ubi.mtd=$rootfs_mtdblock" - else - bootargs="$bootargs root=/dev/mtdblock$rootfs_mtdblock" - fi - - bootargs="$bootargs rootfstype=$rootfs_type" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - - -bootargs="$bootargs mtdparts=\"physmap-flash.0:$nor_parts;mxc_nand:$nand_parts\"" - -if [ $kernel_loc = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $kernel uImage || exit 1 - bootm uImage -elif [ $kernel_loc = nor ]; then - bootm /dev/nor0.kernel -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/freescale-mx35-3-stack/env/bin/hush_hack b/board/freescale-mx35-3-stack/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/freescale-mx35-3-stack/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/freescale-mx35-3-stack/env/bin/init b/board/freescale-mx35-3-stack/env/bin/init deleted file mode 100644 index c982f22..0000000 --- a/board/freescale-mx35-3-stack/env/bin/init +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nor0 ]; then - addpart /dev/nor0 $nor_parts -fi - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" - saveenv -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel nand|nor [] to update kernel into flash" - echo "type update_rootfs nand|nor [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/freescale-mx35-3-stack/env/bin/update_kernel b/board/freescale-mx35-3-stack/env/bin/update_kernel deleted file mode 100644 index 63ad11a..0000000 --- a/board/freescale-mx35-3-stack/env/bin/update_kernel +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -. /env/config -image=$kernel - -if [ x$1 = xnand ]; then - part=/dev/nand0.kernel.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.kernel -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 diff --git a/board/freescale-mx35-3-stack/env/bin/update_rootfs b/board/freescale-mx35-3-stack/env/bin/update_rootfs deleted file mode 100644 index 53dd2ca..0000000 --- a/board/freescale-mx35-3-stack/env/bin/update_rootfs +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ $rootfs_type = ubifs ]; then - image=${rootfs}.ubi -else - image=${rootfs}.$rootfs_type -fi - -if [ x$1 = xnand ]; then - part=/dev/nand0.root.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.root -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 diff --git a/board/freescale-mx35-3-stack/env/config b/board/freescale-mx35-3-stack/env/config deleted file mode 100644 index 51195f7..0000000 --- a/board/freescale-mx35-3-stack/env/config +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -# use 'dhcp' to do dhcp in barebox and in kernel -# use 'no' if you don't want to pass the ip from barebox to the kernel -#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 'net', 'nor' or 'nand'' -kernel_loc=nand -rootfs_loc=nand - -# can be either 'jffs2', or 'ubifs' -rootfs_type=ubifs - -kernel=uImage-mx35-3-stack -rootfs=root-mx35-3-stack -envimage=u-boot-v2-environment-mx35-3-stack - -autoboot_timeout=3 - -nfsroot="/path/to/nfs/root" -bootargs="console=ttymxc0,115200" - -bootargs="$bootargs video=mx3fb:CTP-CLAA070LC0ACW" - -nor_parts="256k(barebox)ro,512k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nor=3 - -nand_parts="256k(barebox)ro,512k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nand=7 diff --git a/board/freescale-mx35-3-stack/flash_header.c b/board/freescale-mx35-3-stack/flash_header.c deleted file mode 100644 index 171c499..0000000 --- a/board/freescale-mx35-3-stack/flash_header.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include - -extern unsigned long _stext; - -void __naked __flash_header_start go(void) -{ - __asm__ __volatile__("b exception_vectors\n"); -} - -struct imx_dcd_entry __dcd_entry_0x400 dcd_entry[] = { - { .ptr_type = 4, .addr = 0xb8002050, .val = 0x0000d843, }, - { .ptr_type = 4, .addr = 0xB8002054, .val = 0x22252521, }, - { .ptr_type = 4, .addr = 0xB8002058, .val = 0x22220a00, }, - { .ptr_type = 4, .addr = 0xB8001010, .val = 0x00000304, }, - { .ptr_type = 4, .addr = 0xB8001010, .val = 0x0000030C, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc3f, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0x92220000, }, - { .ptr_type = 4, .addr = 0x80000400, .val = 0x12345678, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0xA2220000, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, - { .ptr_type = 4, .addr = 0x80000000, .val = 0x87654321, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0xB2220000, }, - { .ptr_type = 1, .addr = 0x80000233, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x82000780, .val = 0xda, }, - { .ptr_type = 1, .addr = 0x82000400, .val = 0xda, }, - { .ptr_type = 4, .addr = 0xB8001000, .val = 0x82226080, }, - { .ptr_type = 4, .addr = 0xB8001004, .val = 0x007ffc3f, }, - { .ptr_type = 4, .addr = 0xB800100C, .val = 0x007ffc3f, }, - { .ptr_type = 4, .addr = 0xB8001010, .val = 0x00000304, }, - { .ptr_type = 4, .addr = 0xB8001008, .val = 0x00002000, }, -}; - -#define APP_DEST 0x80000000 - -struct imx_flash_header __flash_header_0x400 flash_header = { - .app_code_jump_vector = APP_DEST + 0x1000, - .app_code_barker = APP_CODE_BARKER, - .app_code_csf = 0, - .dcd_ptr_ptr = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd), - .super_root_key = 0, - .dcd = APP_DEST + 0x400 + offsetof(struct imx_flash_header, dcd_barker), - .app_dest = APP_DEST, - .dcd_barker = DCD_BARKER, - .dcd_block_len = sizeof (dcd_entry), -}; - -unsigned long __image_len_0x400 barebox_len = 0x40000; - diff --git a/board/freescale-mx35-3-stack/lowlevel_init.S b/board/freescale-mx35-3-stack/lowlevel_init.S deleted file mode 100644 index 1680579..0000000 --- a/board/freescale-mx35-3-stack/lowlevel_init.S +++ /dev/null @@ -1,283 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include "board-mx35_3stack.h" - -#define CSD0_BASE_ADDR 0x80000000 -#define ESDCTL_BASE_ADDR 0xB8001000 -#define CSD1_BASE_ADDR 0x90000000 - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#define writeb(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - strb r1, [r0]; - -/* Assuming 24MHz input clock */ -#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) -#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) -#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) - - .section ".text_bare_init","ax" - -ARM_PPMRR: .word 0x40000015 -L2CACHE_PARAM: .word 0x00030024 -CCM_CCMR_W: .word 0x003F4208 -CCM_PDR0_W: .word 0x00001000 -MPCTL_PARAM_399_W: .word MPCTL_PARAM_399 -MPCTL_PARAM_532_W: .word MPCTL_PARAM_532 -PPCTL_PARAM_W: .word PPCTL_PARAM_300 -CCM_BASE_ADDR_W: .word IMX_CCM_BASE - -.globl board_init_lowlevel -board_init_lowlevel: - mov r10, lr - - mrc 15, 0, r1, c1, c0, 0 - - mrc 15, 0, r0, c1, c0, 1 - orr r0, r0, #7 - mcr 15, 0, r0, c1, c0, 1 - - orr r1, r1, #(1 << 11) /* Flow prediction (Z) */ - orr r1, r1, #(1 << 22) /* unaligned accesses */ - orr r1, r1, #(1 << 21) /* Low Int Latency */ - - mcr 15, 0, r1, c1, c0, 0 - - mov r0, #0 - mcr 15, 0, r0, c15, c2, 4 - - /* - * Branch predicition is now enabled. Flush the BTAC to ensure a valid - * starting point. Don't flush BTAC while it is disabled to avoid - * ARM1136 erratum 408023. - */ - mov r0, #0 - mcr p15, 0, r0, c7, c5, 6 /* flush entire BTAC */ - - mov r0, #0 - mcr 15, 0, r0, c7, c7, 0 /* invalidate I cache and D cache */ - mcr 15, 0, r0, c8, c7, 0 /* invalidate TLBs */ - mcr 15, 0, r0, c7, c10, 4 /* Drain the write buffer */ - - /* Also setup the Peripheral Port Remap register inside the core */ - ldr r0, ARM_PPMRR /* start from AIPS 2GB region */ - mcr p15, 0, r0, c15, c2, 4 - -/* - * End of ARM1136 init - */ - ldr r0, CCM_BASE_ADDR_W - - ldr r2, CCM_CCMR_W - str r2, [r0, #CCM_CCMR] - - ldr r3, MPCTL_PARAM_532_W /* consumer path*/ - - /* Set MPLL, arm clock and ahb clock */ - str r3, [r0, #CCM_MPCTL] - - ldr r1, PPCTL_PARAM_W - str r1, [r0, #CCM_PPCTL] - - ldr r1, CCM_PDR0_W - str r1, [r0, #CCM_PDR0] - - ldr r1, [r0, #CCM_CGR0] - orr r1, r1, #0x00300000 - str r1, [r0, #CCM_CGR0] - - ldr r1, [r0, #CCM_CGR1] - orr r1, r1, #0x00000C00 - orr r1, r1, #0x00000003 - str r1, [r0, #CCM_CGR1] - - /* Skip SDRAM initialization if we run from RAM */ - cmp pc, #0x80000000 - bls 1f - cmp pc, #0x90000000 - bhi 1f - - mov pc, r10 - -1: - ldr r0, =ESDCTL_BASE_ADDR - mov r3, #0x2000 - str r3, [r0, #0x0] - str r3, [r0, #0x8] - - /* ip(r12) has used to save lr register in upper calling */ - mov fp, lr - - mov r5, #0x00 - mov r2, #0x00 - mov r1, #CSD0_BASE_ADDR - bl setup_sdram_bank - cmp r3, #0x0 - orreq r5, r5, #1 - eorne r2, r2, #0x1 - blne setup_sdram_bank - - mov lr, fp - - ldr r3, =ESDCTL_DELAY_LINE5 - str r3, [r0, #0x30] - -#ifdef CONFIG_NAND_IMX_BOOT - ldr sp, =TEXT_BASE - 4 /* Setup a temporary stack in SDRAM */ - - ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ - ldr r2, =IMX_NFC_BASE + 0x800 /* end of NFC SRAM */ - - /* skip NAND boot if not running from NFC space */ - cmp pc, r0 - blo ret - cmp pc, r2 - bhs ret - - /* Move ourselves out of NFC SRAM */ - ldr r1, =TEXT_BASE - -copy_loop: - ldmia r0!, {r3-r9} /* copy from source address [r0] */ - stmia r1!, {r3-r9} /* copy to target address [r1] */ - cmp r0, r2 /* until source end addreee [r2] */ - ble copy_loop - - ldr pc, =1f /* Jump to SDRAM */ -1: - bl nand_boot /* Load barebox from NAND Flash */ - - /* rebase the return address */ - ldr r1, =IMX_NFC_BASE - TEXT_BASE - sub r10, r10, r1 /* adjust return address from NFC SRAM */ -ret: -#endif /* CONFIG_NAND_IMX_BOOT */ - - mov pc, r10 - -/* - * r0: ESDCTL control base, r1: sdram slot base - * r2: DDR type (0: DDR2, 1: MDDR) r3, r4: working base - */ -setup_sdram_bank: - mov r3, #0xE /* 0xA + 0x4 */ - tst r2, #0x1 - orreq r3, r3, #0x300 /* DDR2 */ - str r3, [r0, #0x10] - bic r3, r3, #0x00A - str r3, [r0, #0x10] - beq 2f - - mov r3, #0x20000 -1: subs r3, r3, #1 - bne 1b - -2: tst r2, #0x1 - ldreq r3, =ESDCTL_DDR2_CONFIG - ldrne r3, =ESDCTL_MDDR_CONFIG - cmp r1, #CSD1_BASE_ADDR - strlo r3, [r0, #0x4] - strhs r3, [r0, #0xC] - - ldr r3, =ESDCTL_0x92220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, =ESDCTL_PRECHARGE - strb r3, [r1, r4] - - tst r2, #0x1 - bne skip_set_mode - - cmp r1, #CSD1_BASE_ADDR - ldr r3, =ESDCTL_0xB2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, =ESDCTL_DDR2_EMR2 - strb r3, [r1, r4] - ldr r4, =ESDCTL_DDR2_EMR3 - strb r3, [r1, r4] - ldr r4, =ESDCTL_DDR2_EN_DLL - strb r3, [r1, r4] - ldr r4, =ESDCTL_DDR2_RESET_DLL - strb r3, [r1, r4] - - ldr r3, =ESDCTL_0x92220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, =ESDCTL_PRECHARGE - strb r3, [r1, r4] - -skip_set_mode: - cmp r1, #CSD1_BASE_ADDR - ldr r3, =ESDCTL_0xA2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - strb r3, [r1] - strb r3, [r1] - - ldr r3, =ESDCTL_0xB2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - tst r2, #0x1 - ldreq r4, =ESDCTL_DDR2_MR - ldrne r4, =ESDCTL_MDDR_MR - mov r3, #0xDA - strb r3, [r1, r4] - ldreq r4, =ESDCTL_DDR2_OCD_DEFAULT - streqb r3, [r1, r4] - ldreq r4, =ESDCTL_DDR2_EN_DLL - ldrne r4, =ESDCTL_MDDR_EMR - strb r3, [r1, r4] - - cmp r1, #CSD1_BASE_ADDR - ldr r3, =ESDCTL_0x82228080 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - - tst r2, #0x1 - moveq r4, #0x20000 - movne r4, #0x200 -1: subs r4, r4, #1 - bne 1b - - str r3, [r1, #0x100] - ldr r4, [r1, #0x100] - cmp r3, r4 - movne r3, #1 - moveq r3, #0 - - mov pc, lr diff --git a/board/imx21ads/Makefile b/board/imx21ads/Makefile deleted file mode 100644 index 7993fde..0000000 --- a/board/imx21ads/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-y += lowlevel_init.o -obj-y += imx21ads.o diff --git a/board/imx21ads/config.h b/board/imx21ads/config.h deleted file mode 100644 index edfb29f..0000000 --- a/board/imx21ads/config.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 - */ - -/** - * @file - * @brief Global defintions for the ARM i.MX21 based imx21ads - **/ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#endif /* __CONFIG_H */ diff --git a/board/imx21ads/env/bin/init b/board/imx21ads/env/bin/init deleted file mode 100644 index 224a6b4..0000000 --- a/board/imx21ads/env/bin/init +++ /dev/null @@ -1 +0,0 @@ -# Dummy Init environment script diff --git a/board/imx21ads/imx21ads.c b/board/imx21ads/imx21ads.c deleted file mode 100644 index 5e88af4..0000000 --- a/board/imx21ads/imx21ads.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (C) 2009 Ivo Clarysse - * - * Based on imx27ads.c, - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MX21ADS_IO_REG 0xCC800000 -#define MX21ADS_IO_LCDON (1 << 9) - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0xC8000000, - .size = 32 * 1024 * 1024, -}; - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0xc0000000, - .size = 64 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = 0xDF003000, - .platform_data = &nand_info, -}; - -static struct device_d cs8900_dev = { - .name = "cs8900", - .map_base = IMX_CS1_BASE, - // IRQ is connected to UART3_RTS -}; - -/* Sharp LQ035Q7DB02 QVGA display */ -static struct imx_fb_videomode imx_fb_modedata = { - .mode = { - .name = "Sharp-LQ035Q7", - .refresh = 60, - .xres = 240, - .yres = 320, - .pixclock = 188679, - .left_margin = 6, - .right_margin = 16, - .upper_margin = 8, - .lower_margin = 10, - .hsync_len = 2, - .vsync_len = 1, - .sync = 0, - .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, - }, - .pcr = 0xfb108bc7, - .bpp = 16, -}; - -static struct imx_fb_platform_data imx_fb_data = { - .mode = &imx_fb_modedata, - .cmap_greyscale = 0, - .cmap_inverse = 0, - .cmap_static = 0, - .pwmr = 0x00a903ff, - .lscr1 = 0x00120300, - .dmacr = 0x00020008, -}; - -static struct device_d imxfb_dev = { - .name = "imxfb", - .map_base = 0x10021000, - .size = 0x1000, - .platform_data = &imx_fb_data, -}; - -static int imx21ads_timing_init(void) -{ - u32 temp; - - /* Configure External Interface Module */ - /* CS0: burst flash */ - CS0U = 0x00003E00; - CS0L = 0x00000E01; - - /* CS1: Ethernet controller, external UART, memory-mapped I/O (16-bit) */ - CS1U = 0x00002000; - CS1L = 0x11118501; - - /* CS2: disable (not available, since CSD0 in use) */ - CS2U = 0x0; - CS2L = 0x0; - - /* CS3: disable */ - CS3U = 0x0; - CS3L = 0x0; - /* CS4: disable */ - CS4U = 0x0; - CS4L = 0x0; - /* CS5: disable */ - CS5U = 0x0; - CS5L = 0x0; - - temp = PCDR0; - temp &= ~0xF000; - temp |= 0xA000; /* Set NFC divider; 0xA yields 24.18MHz */ - PCDR0 = temp; - - return 0; -} - -core_initcall(imx21ads_timing_init); - -static int mx21ads_devices_init(void) -{ - int i; - unsigned int mode[] = { - PA5_PF_LSCLK, - PA6_PF_LD0, - PA7_PF_LD1, - PA8_PF_LD2, - PA9_PF_LD3, - PA10_PF_LD4, - PA11_PF_LD5, - PA12_PF_LD6, - PA13_PF_LD7, - PA14_PF_LD8, - PA15_PF_LD9, - PA16_PF_LD10, - PA17_PF_LD11, - PA18_PF_LD12, - PA19_PF_LD13, - PA20_PF_LD14, - PA21_PF_LD15, - PA22_PF_LD16, - PA23_PF_LD17, - PA24_PF_REV, - PA25_PF_CLS, - PA26_PF_PS, - PA27_PF_SPL_SPR, - PA28_PF_HSYNC, - PA29_PF_VSYNC, - PA30_PF_CONTRAST, - PA31_PF_OE_ACD, - PE12_PF_UART1_TXD, - PE13_PF_UART1_RXD, - PE14_PF_UART1_CTS, - PE15_PF_UART1_RTS, - }; - - /* initizalize gpios */ - for (i = 0; i < ARRAY_SIZE(mode); i++) - imx_gpio_mode(mode[i]); - - register_device(&cfi_dev); - register_device(&sdram_dev); - register_device(&nand_dev); - register_device(&cs8900_dev); - register_device(&imxfb_dev); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0xc0000100); - armlinux_set_architecture(MACH_TYPE_MX21ADS); - - return 0; -} - -device_initcall(mx21ads_devices_init); - -static int mx21ads_enable_display(void) -{ - u16 tmp; - - tmp = readw(MX21ADS_IO_REG); - tmp |= MX21ADS_IO_LCDON; - writew(tmp, MX21ADS_IO_REG); - return 0; -} - -late_initcall(mx21ads_enable_display); - -static struct device_d mx21ads_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; - -static int mx21ads_console_init(void) -{ - register_device(&mx21ads_serial_device); - return 0; -} - -console_initcall(mx21ads_console_init); - -#ifdef CONFIG_NAND_IMX_BOOT -void __bare_init nand_boot(void) -{ - PCCR0 |= PCCR0_NFC_EN; - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); -} -#endif - diff --git a/board/imx21ads/imx21ads.dox b/board/imx21ads/imx21ads.dox deleted file mode 100644 index 9f11ffa..0000000 --- a/board/imx21ads/imx21ads.dox +++ /dev/null @@ -1,5 +0,0 @@ -/** @page imx21ads Freescale i.MX21ads - -This is the Freescale evaluation board for the i.MX21 Processor - -*/ diff --git a/board/imx21ads/lowlevel_init.S b/board/imx21ads/lowlevel_init.S deleted file mode 100644 index 607da27..0000000 --- a/board/imx21ads/lowlevel_init.S +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (C) 2010 Jaccon Bastiaansen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include - - .section ".text_bare_init","ax" - -.globl board_init_lowlevel -board_init_lowlevel: - -/* Save lr, because it is overwritten by the calls to mem_delay. */ - mov r10, lr - -/* - * Initialize the AHB-Lite IP Interface (AIPI) module (to enable access to - * on chip peripherals) as described in section 7.2 of rev3 of the i.MX21 - * reference manual. - */ - ldr r0, =AIPI1_PSR0 - ldr r1, =0x00040304 - str r1, [r0] - ldr r0, =AIPI1_PSR1 - ldr r1, =0xfffbfcfb - str r1, [r0] - - ldr r0, =AIPI2_PSR0 - ldr r1, =0x3ffc0000 - str r1, [r0] - ldr r0, =AIPI2_PSR1 - ldr r1, =0xffffffff - str r1, [r0] - -/* - * Configure CPU core clock (266MHz), peripheral clock (133MHz) and enable - * the clock to peripherals. - */ - ldr r0, =CSCR - ldr r1, =0x17180607 - str r1, [r0] - - ldr r0, =PCCR1 - ldr r1, =0x0e000000 - str r1, [r0] - - -/* - * SDRAM and SDRAM controller configuration - */ - - /* - * CSD1 not required, because the MX21ADS board only contains 64Mbyte. - * CS3 can therefore be made available. - */ - ldr r0, =FMCR - ldr r1, =0xffffffc9 - str r1, [r0] - - /* Skip SDRAM initialization if we run from RAM */ - cmp pc, #0xc0000000 - bls 1f - cmp pc, #0xc8000000 - bhi 1f - - mov pc, r10 -1: - - /* Precharge */ - ldr r0, =SDCTL0 - ldr r1, =0x92120300 - str r1, [r0] - ldr r2, =0xc0200000 - ldr r1, [r2] - - bl mem_delay - - /* Auto refresh */ - ldr r1, =0xa2120300 - str r1, [r0] - ldr r2, =0xc0000000 - ldr r1, [r2] - ldr r1, [r2] - ldr r1, [r2] - ldr r1, [r2] - ldr r1, [r2] - ldr r1, [r2] - ldr r1, [r2] - ldr r1, [r2] - - /* Set mode register */ - ldr r1, =0xB2120300 - str r1, [r0] - ldr r1, =0xC0119800 - ldr r2, [r1] - - bl mem_delay - - /* Back to Normal Mode */ - ldr r1, =0x8212F339 - str r1, [r0] - - /* Set NFC_CLK to 24MHz */ - ldr r0, =PCDR0 - ldr r1, =0x6419a007 - str r1, [r0] - -#ifdef CONFIG_NAND_IMX_BOOT - ldr sp, =TEXT_BASE - 4 /* Setup a temporary stack in SDRAM */ - - ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ - ldr r2, =IMX_NFC_BASE + 0x800 /* end of NFC SRAM */ - - /* skip NAND boot if not running from NFC space */ - cmp pc, r0 - bls ret - cmp pc, r2 - bhi ret - - /* Move ourselves out of NFC SRAM */ - ldr r1, =TEXT_BASE - -copy_loop: - ldmia r0!, {r3-r9} /* copy from source address [r0] */ - stmia r1!, {r3-r9} /* copy to target address [r1] */ - cmp r0, r2 /* until source end addreee [r2] */ - ble copy_loop - - ldr pc, =1f /* Jump to SDRAM */ -1: - bl nand_boot /* Load barebox from NAND Flash */ - - ldr r1, =IMX_NFC_BASE - TEXT_BASE - sub r10, r10, r1 /* adjust return address from NFC */ - /* SRAM to SDRAM */ -#endif /* CONFIG_NAND_IMX_BOOT */ - -ret: - mov pc, r10 - -/* - * spin for a while. we need to wait at least 200 usecs. - */ -mem_delay: - mov r4, #0x4000 -spin: subs r4, r4, #1 - bne spin - mov pc, lr - diff --git a/board/imx27ads/Makefile b/board/imx27ads/Makefile deleted file mode 100644 index bdc905f..0000000 --- a/board/imx27ads/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += lowlevel_init.o -obj-y += imx27ads.o diff --git a/board/imx27ads/config.h b/board/imx27ads/config.h deleted file mode 100644 index b54a3c5..0000000 --- a/board/imx27ads/config.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 - */ - -/** - * @file - * @brief Global defintions for the Freescale imx27ads ARM board - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#endif /* __CONFIG_H */ diff --git a/board/imx27ads/env/bin/_update b/board/imx27ads/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/imx27ads/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/imx27ads/env/bin/boot b/board/imx27ads/env/bin/boot deleted file mode 100644 index 3859dc1..0000000 --- a/board/imx27ads/env/bin/boot +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xflash ]; then - root=flash - kernel=flash -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xflash ]; then - bootargs="$bootargs root=$rootpart rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm /dev/nor0.kernel -fi - diff --git a/board/imx27ads/env/bin/init b/board/imx27ads/env/bin/init deleted file mode 100644 index 48e2139..0000000 --- a/board/imx27ads/env/bin/init +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -addpart /dev/nor0 $mtdparts - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type udate_root [] to update rootfs into flash" - echo - exit -fi - -boot \ No newline at end of file diff --git a/board/imx27ads/env/bin/update_kernel b/board/imx27ads/env/bin/update_kernel deleted file mode 100644 index 1ad95fc..0000000 --- a/board/imx27ads/env/bin/update_kernel +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -part=/dev/nor0.kernel - -. /env/bin/_update $1 diff --git a/board/imx27ads/env/bin/update_root b/board/imx27ads/env/bin/update_root deleted file mode 100644 index b757a5b..0000000 --- a/board/imx27ads/env/bin/update_root +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 -part=/dev/nor0.root - -. /env/bin/_update $1 diff --git a/board/imx27ads/env/config b/board/imx27ads/env/config deleted file mode 100644 index f18a86b..0000000 --- a/board/imx27ads/env/config +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'flash' -kernel=net -root=net - -# use 'dhcp' todo dhcp in barebox and in kernel -ip=dhcp - -eth0.ipaddr=192.168.23.164 -eth0.netmask=255.255.255.0 -eth0.gateway=192.168.23.2 -eth0.serverip=192.168.23.2 - -uimage=uImage-mx27ads -jffs2=root-mx27ads.jffs2 - -autoboot_timeout=3 - -nfsroot="/tmp/imx27ads" -bootargs="console=ttymxc0,115200" - -mtdparts="128k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" -rootpart="/dev/mtdblock3" - diff --git a/board/imx27ads/imx27ads.c b/board/imx27ads/imx27ads.c deleted file mode 100644 index 6f31520..0000000 --- a/board/imx27ads/imx27ads.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0xC0000000, - .size = 32 * 1024 * 1024, -}; - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0xa0000000, - .size = 128 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -static struct fec_platform_data fec_info = { - .xcv_type = MII100, - .phy_addr = 1, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = 0x1002b000, - .platform_data = &fec_info, -}; - -static int imx27ads_timing_init(void) -{ - /* configure cpld on cs4 */ - CS4U = 0x0000DCF6; - CS4L = 0x444A4541; - CS4A = 0x44443302; - - /* configure synchronous mode for - * 16 bit nor flash on cs0 */ - CS0U = 0x0000CC03; - CS0L = 0xa0330D01; - CS0A = 0x00220800; - - writew(0x00f0, 0xc0000000); - writew(0x00aa, 0xc0000aaa); - writew(0x0055, 0xc0000554); - writew(0x00d0, 0xc0000aaa); - writew(0x66ca, 0xc0000aaa); - writew(0x00f0, 0xc0000000); - - CS0U = 0x23524E80; - CS0L = 0x10000D03; - CS0A = 0x00720900; - - /* Select FEC data through data path */ - writew(0x0020, IMX_CS4_BASE + 0x10); - - /* Enable CPLD FEC data path */ - writew(0x0010, IMX_CS4_BASE + 0x14); - - return 0; -} - -core_initcall(imx27ads_timing_init); - -static int mx27ads_devices_init(void) -{ - int i; - unsigned int mode[] = { - PD0_AIN_FEC_TXD0, - PD1_AIN_FEC_TXD1, - PD2_AIN_FEC_TXD2, - PD3_AIN_FEC_TXD3, - PD4_AOUT_FEC_RX_ER, - PD5_AOUT_FEC_RXD1, - PD6_AOUT_FEC_RXD2, - PD7_AOUT_FEC_RXD3, - PD8_AF_FEC_MDIO, - PD9_AIN_FEC_MDC | GPIO_PUEN, - PD10_AOUT_FEC_CRS, - PD11_AOUT_FEC_TX_CLK, - PD12_AOUT_FEC_RXD0, - PD13_AOUT_FEC_RX_DV, - PD14_AOUT_FEC_RX_CLK, - PD15_AOUT_FEC_COL, - PD16_AIN_FEC_TX_ER, - PF23_AIN_FEC_TX_EN, - PE12_PF_UART1_TXD, - PE13_PF_UART1_RXD, - PE14_PF_UART1_CTS, - PE15_PF_UART1_RTS, - }; - - /* initizalize gpios */ - for (i = 0; i < ARRAY_SIZE(mode); i++) - imx_gpio_mode(mode[i]); - - register_device(&cfi_dev); - register_device(&sdram_dev); - register_device(&fec_dev); - - devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x20000, 0x20000, PARTITION_FIXED, "env0"); - protect_file("/dev/env0", 1); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0xa0000100); - armlinux_set_architecture(MACH_TYPE_MX27ADS); - - return 0; -} - -device_initcall(mx27ads_devices_init); - -static struct device_d mx27ads_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; - -static int mx27ads_console_init(void) -{ - register_device(&mx27ads_serial_device); - return 0; -} - -console_initcall(mx27ads_console_init); - diff --git a/board/imx27ads/imx27ads.dox b/board/imx27ads/imx27ads.dox deleted file mode 100644 index e14d8e3..0000000 --- a/board/imx27ads/imx27ads.dox +++ /dev/null @@ -1,5 +0,0 @@ -/** @page imx27ads Freescale i.MX27ads - -This is the Freescale evaluation board for the i.MX27 Processor - -*/ diff --git a/board/imx27ads/lowlevel_init.S b/board/imx27ads/lowlevel_init.S deleted file mode 100644 index df12aea..0000000 --- a/board/imx27ads/lowlevel_init.S +++ /dev/null @@ -1,172 +0,0 @@ -/* - * For clock initialization, see chapter 3 of the "MCIMX27 Multimedia - * Applications Processor Reference Manual, Rev. 0.2". - * - */ - -#include -#include - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#define CRM_PLL_PCTL_PARAM(pd, fd, fi, fn) (((pd-1)<<26) + ((fd-1)<<16) + (fi<<10) + (fn<<0)) - -.macro sdram_init_sha - /* - * DDR on CSD0 - */ - writel(0x00000008, 0xD8001010) - writel(0x55555555, 0x10027828) - writel(0x55555555, 0x10027830) - writel(0x55555555, 0x10027834) - writel(0x00005005, 0x10027838) - writel(0x15555555, 0x1002783C) - writel(0x00000004, 0xD8001010) - writel(0x006ac73a, 0xD8001004) - writel(0x92100000, 0xD8001000) - writel(0x00000000, 0xA0000F00) - writel(0xA2100000, 0xD8001000) - writel(0x00000000, 0xA0000F00) - writel(0x00000000, 0xA0000F00) - writel(0x00000000, 0xA0000F00) - writel(0x00000000, 0xA0000F00) - writel(0xA2200000, 0xD8001000) - writel(0x00000000, 0xA0000F00) - writel(0x00000000, 0xA0000F00) - writel(0x00000000, 0xA0000F00) - writel(0x00000000, 0xA0000F00) - writel(0xb2100000, 0xD8001000) - ldr r0, =0xA0000033 - mov r1, #0xda - strb r1, [r0] - ldr r0, =0xA1000000 - mov r1, #0xff - strb r1, [r0] - writel(0x82226080, 0xD8001000) -.endm - -.macro sdram_init_mx27_manual - /* - * sdram init sequence, as defined in 18.5.4 of the i.MX27 reference manual - */ -1: - ldr r2, =ESD_ESDCTL0 /* base address of registers */ - ldr r3, =PRE_ALL_CMD /* SMODE=001 */ - str r3,(r2,#0x0) /* put CSD0 in precharge command mode */ - ldr r4, =SDRAM_CSD0 /* CSD0 precharge address (A10=1) */ - str r1,(r4,#0x0) /* precharge CSD0 all banks */ - ldr r3, =AUTO_REF_CMD /* SMODE=010 */ - str r3,(r2,#0x0) /* put array 0 in auto-refresh mode */ - ldr r4, =SDRAM_CSD0_BASE /* CSD0 base address */ - ldr r6,=0x7 /* load loop counter */ -1: ldr r5,(r4,#0x0) /* run auto-refresh cycle to array 0 */ - subs r6,r6,#1 /* decrease counter value */ - bne 1b - ldr r3, =SET_MODE_REG_CMD /* SMODE=011 */ - str r3,(r2,#0x0) /* setup CSD0 for mode register write */ - ldr r3, =MODE_REG_VAL0 /* array 0 mode register value */ - ldrb r5,(r3,#0x0) /* New mode register value on address bus */ - ldr r3, =NORMAL_MODE /* SMODE=000 */ - str r3,(r2,#0x0) /* setup CSD0 for normal operation */ - -ESD_ESDCTL0 .long 0xD8001000 // system/external device dependent data -SDRAM_CSD0 .long 0x00000000 // system/external device dependent data -SDRAM_CSD0_BASE .long 0x00000000 // system/external device dependent data -PRE_ALL_CMD .long 0x00000000 // system/external device dependent data (SMODE=001) -AUTO_REF_CMD .long 0x00000000 // system/external device dependent data (SMODE=010) -SET_MODE_REG_CMD .long 0x00000000 // system/external device dependent data (SMODE=011) -MODE_REG_VAL0 .long 0x00000000 // system/external device dependent data -NORMAL_MODE .long 0x00000000 // system/external device dependent data (SMODE=000) -.endm - -.macro sdram_init_barebox - /* configure 16 bit nor flash on cs0 */ - writel(0x0000CC03, 0xd8002000) - writel(0xa0330D01, 0xd8002004) - writel(0x00220800, 0xd8002008) - - /* ddr on csd0 - initial reset */ - writel(0x00000008, 0xD8001010) - - /* configure ddr on csd0 - wait 5000 cycles */ - writel(0x00000004, 0xD8001010) - writel(0x006ac73a, 0xD8001004) - writel(0x92100000, 0xD8001000) - writel(0x12344321, 0xA0000f00) - writel(0xa2100000, 0xD8001000) - writel(0x12344321, 0xA0000000) - writel(0x12344321, 0xA0000000) - writel(0xb2100000, 0xD8001000) - ldr r0, =0xA0000033 - mov r1, #0xda - strb r1, [r0] - ldr r0, =0xA1000000 - mov r1, #0xff - strb r1, [r0] - writel(0x82226080, 0xD8001000) - writel(0xDEADBEEF, 0xA0000000) - writel(0x0000000c, 0xD8001010) -.endm - -.globl board_init_lowlevel -board_init_lowlevel: - - mov r10, lr - - /* ahb lite ip interface */ - writel(0x20040304, AIPI1_PSR0) - writel(0xDFFBFCFB, AIPI1_PSR1) - writel(0x00000000, AIPI2_PSR0) - writel(0xFFFFFFFF, AIPI2_PSR1) - - /* disable mpll/spll */ - ldr r0, =CSCR - ldr r1, [r0] - bic r1, r1, #0x03 - str r1, [r0] - - /* - * pll clock initialization - see section 3.4.3 of the i.MX27 manual - * - * FIXME: Using the 399*2 MHz values from table 3-8 doens't work - * with 1.2 V core voltage! Find out if this is - * documented somewhere. - */ - writel(0x00191403, MPCTL0) /* MPLL = 199.5*2 MHz */ - writel(0x040C2403, SPCTL0) /* SPLL = FIXME (needs review) */ - - /* - * ARM clock = (399 MHz / 2) / (ARM divider = 1) = 200 MHz - * AHB clock = (399 MHz / 3) / (AHB divider = 2) = 66.5 MHz - * System clock (HCLK) = 133 MHz - */ - writel(0x33F30307 | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR) - - /* add some delay here */ - mov r1, #0x1000 -1: subs r1, r1, #0x1 - bne 1b - - /* clock gating enable */ - writel(0x00050f08, GPCR) - - /* peripheral clock divider */ - writel(0x23C8F403, PCDR0) /* FIXME */ - writel(0x09030913, PCDR1) /* PERDIV1=08 @133 MHz */ - /* PERDIV1=04 @266 MHz * - * / - /* skip sdram initialization if we run from ram */ - cmp pc, #0xa0000000 - bls 1f - cmp pc, #0xc0000000 - bhi 1f - - mov pc,r10 -1: - sdram_init_sha - - mov pc,r10 - diff --git a/board/ipe337/Makefile b/board/ipe337/Makefile deleted file mode 100644 index 172dfb6..0000000 --- a/board/ipe337/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-y += ipe337.o -obj-y += cmd_alternate.o - -extra-y += barebox.lds diff --git a/board/ipe337/barebox.lds.S b/board/ipe337/barebox.lds.S deleted file mode 100644 index 4299b82..0000000 --- a/board/ipe337/barebox.lds.S +++ /dev/null @@ -1,87 +0,0 @@ -/* - * barebox - barebox.lds.S - * - * Copyright (c) 2005-2007 Analog Device Inc. - * - * (C) Copyright 2000-2004 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include - -OUTPUT_ARCH("bfin") -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -/* -MEMORY -{ - ram : ORIGIN = (0x2000000), LENGTH = (256 * 1024) - l1_code : ORIGIN = 0xFFA00000, LENGTH = 0xC000 - l1_data : ORIGIN = 0xFF900000, LENGTH = 0x4000 -} -*/ - -SECTIONS -{ - . = TEXT_BASE; - - . = ALIGN(4); - .text : - { - __stext = .; - __text = .; - _text = .; - *(.text_entry) - *(.text) - } - - . = ALIGN(4); - .rodata : { *(.rodata) } - - __etext = .; /* End of text and rodata section */ - - . = ALIGN(4); - .data : { *(.data) } - - . = ALIGN(4); - .got : { *(.got) } - - . = .; - ___barebox_cmd_start = .; - .barebox_cmd : { BAREBOX_CMDS } - ___barebox_cmd_end = .; - - ___barebox_initcalls_start = .; - .barebox_initcalls : { INITCALLS } - ___barebox_initcalls_end = .; - - ___usymtab_start = .; - __usymtab : { BAREBOX_SYMS } - ___usymtab_end = .; - - . = ALIGN(4); - __bss_start = .; - .bss : { *(.bss) } - _end = .; -} - diff --git a/board/ipe337/cmd_alternate.c b/board/ipe337/cmd_alternate.c deleted file mode 100644 index 2883c77..0000000 --- a/board/ipe337/cmd_alternate.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include -#include - -#define MAGIC 0x19691228 - -static int do_alternate(struct command *cmdtp, int argc, char *argv[]) -{ - void *buf; - size_t size; - ulong *ptr, val = 0, bitcount = 0; - - if (argc != 2) - return COMMAND_ERROR_USAGE; - - buf = read_file(argv[1], &size); - if (!buf) - return 1; - - ptr = buf; - if ((*ptr) != MAGIC) { - printf("Wrong magic! Expected 0x%08x, got 0x%08x.\n", MAGIC, *ptr); - return 1; - } - - ptr++; - - while ((ulong)ptr <= (ulong)buf + size && !(val = *ptr++)) - bitcount += 32; - - if (val) { - do { - if (val & 1) - break; - bitcount++; - } while (val >>= 1); - } - - printf("Bitcount : %d\n", bitcount); - - free(buf); - return (bitcount & 1) ? 3 : 2; -} - -static const __maybe_unused char cmd_alternate_help[] = -"Usage: alternate " -"\n"; - -BAREBOX_CMD_START(alternate) - .cmd = do_alternate, - .usage = "count zero bits in a file", - BAREBOX_CMD_HELP(cmd_alternate_help) -BAREBOX_CMD_END - diff --git a/board/ipe337/config.h b/board/ipe337/config.h deleted file mode 100644 index aa25d07..0000000 --- a/board/ipe337/config.h +++ /dev/null @@ -1,46 +0,0 @@ - -#ifndef __CONFIG_H -#define __CONFIG_H - -/* - * Clock settings - */ - -/* CONFIG_CLKIN_HZ is any value in Hz */ -#if defined(CONFIG_MACH_IPE337_V1) -#define CONFIG_CLKIN_HZ 25000000 -#elif defined(CONFIG_MACH_IPE337_V2) -#define CONFIG_CLKIN_HZ 40000000 -#else -#error "Unknown IPE337 revision" -#endif - -/* CONFIG_CLKIN_HALF controls what is passed to PLL 0=CLKIN */ -/* 1=CLKIN/2 */ -#define CONFIG_CLKIN_HALF 0 -/* CONFIG_PLL_BYPASS controls if the PLL is used 0=don't bypass */ -/* 1=bypass PLL */ -#define CONFIG_PLL_BYPASS 0 -/* CONFIG_VCO_MULT controls what the multiplier of the PLL is. */ -/* Values can range from 1-64 */ -#define CONFIG_VCO_MULT 10 /* POR default */ -/* CONFIG_CCLK_DIV controls what the core clock divider is */ -/* Values can be 1, 2, 4, or 8 ONLY */ -#define CONFIG_CCLK_DIV 1 /* POR default */ -/* CONFIG_SCLK_DIV controls what the peripheral clock divider is */ -/* Values can range from 1-15 */ -#define CONFIG_SCLK_DIV 5 /* POR default */ - -/* Frequencies selected: 400MHz CCLK / 80MHz SCLK ^= 12.5ns cycle time*/ - -#define AMGCTLVAL 0x1F - -/* no need for speed, currently, leave at defaults */ -#define AMBCTL0VAL 0xFFC2FFC2 -#define AMBCTL1VAL 0xFFC2FFC2 - -#define CONFIG_MEM_MT48LC16M16A2TG_75 1 -#define CONFIG_MEM_ADD_WDTH 9 /* 8, 9, 10, 11 */ -#define CONFIG_MEM_SIZE 64 /* 128, 64, 32, 16 */ - -#endif /* __CONFIG_H */ diff --git a/board/ipe337/env/bin/_alternate b/board/ipe337/env/bin/_alternate deleted file mode 100644 index 10ae213..0000000 --- a/board/ipe337/env/bin/_alternate +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -. /env/config - -alternate $ageing -if [ $? -lt 2 ]; then - echo "Error when accesing ageing-partition!" - exit 1 -fi diff --git a/board/ipe337/env/bin/_update b/board/ipe337/env/bin/_update deleted file mode 100644 index 5419ece..0000000 --- a/board/ipe337/env/bin/_update +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -if [ $# = 1 ]; then - image=$1 -fi - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "Erasing partition $part" -erase $part - -echo -echo "Flashing $image to $part" -tftp $image $part - -protect $part diff --git a/board/ipe337/env/bin/boot b/board/ipe337/env/bin/boot deleted file mode 100644 index 62807d2..0000000 --- a/board/ipe337/env/bin/boot +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh - -. /env/config - -alternate $ageing -ret=$? - -if [ $ret = 0 ]; then - echo "Error when accesing ageing-partition!" - exit 1 -elif [ $ret = 2 ]; then - act_kernel=/dev/nor0.kernel0 - act_rootfs=/dev/mtdblock5 -else - act_kernel=/dev/nor0.kernel1 - act_rootfs=/dev/mtdblock6 -fi -echo "-> Active kernel: $act_kernel" -echo "-> Active system: $act_rootfs" -echo - -if [ x$1 = xflash ]; then - root=flash - kernel=flash -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xflash ]; then - bootargs="$bootargs root=$act_rootfs rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm $act_kernel -fi diff --git a/board/ipe337/env/bin/init b/board/ipe337/env/bin/init deleted file mode 100644 index e864dc5..0000000 --- a/board/ipe337/env/bin/init +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -addpart /dev/nor0 $mtdparts - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "Type update_kernel [] to update kernel into flash." - echo "Type update_system [] to update rootfs into flash." - echo "Type update_application [] to update applications into flash." - echo "Type update_persistent [] to update persistent into flash." - echo "Type update_bareboxenv [] to update bareboxenv into flash (use with care!)." - echo "Type reset_ageing to initialize the ageing partittion (use with care!)." - echo - exit -fi - -boot diff --git a/board/ipe337/env/bin/magic.bin b/board/ipe337/env/bin/magic.bin deleted file mode 100644 index f8bff39..0000000 --- a/board/ipe337/env/bin/magic.bin +++ /dev/null @@ -1 +0,0 @@ -(i \ No newline at end of file diff --git a/board/ipe337/env/bin/reset_ageing b/board/ipe337/env/bin/reset_ageing deleted file mode 100644 index 2c95ae7..0000000 --- a/board/ipe337/env/bin/reset_ageing +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -. /env/config - -image=/env/bin/magic.bin -part=$ageing - -if [ \! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -unprotect $part - -echo -echo "Erasing partition $part" -erase $part - -echo -echo "Creating magic" -cp $image $part - -echo -echo "Testing partition" -. /env/bin/_alternate - -protect $part diff --git a/board/ipe337/env/bin/update_application b/board/ipe337/env/bin/update_application deleted file mode 100644 index 46ad210..0000000 --- a/board/ipe337/env/bin/update_application +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$appimage -part=/dev/nor0.application - -. /env/bin/_update $1 diff --git a/board/ipe337/env/bin/update_bareboxenv b/board/ipe337/env/bin/update_bareboxenv deleted file mode 100644 index b0a32c6..0000000 --- a/board/ipe337/env/bin/update_bareboxenv +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$envimage -part=/dev/nor0.bareboxenv - -. /env/bin/_update $1 diff --git a/board/ipe337/env/bin/update_kernel b/board/ipe337/env/bin/update_kernel deleted file mode 100644 index d5c210e..0000000 --- a/board/ipe337/env/bin/update_kernel +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage - -alternate $ageing -ret=$? - -if [ $ret = 0 ]; then - echo "Error when accesing ageing-partition!" - exit 1 -elif [ $ret = 2 ]; then - part=/dev/nor0.kernel0 -else - part=/dev/nor0.kernel1 -fi - -. /env/bin/_update $1 diff --git a/board/ipe337/env/bin/update_persistent b/board/ipe337/env/bin/update_persistent deleted file mode 100644 index a869b22..0000000 --- a/board/ipe337/env/bin/update_persistent +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$perimage -part=/dev/nor0.persistent - -. /env/bin/_update $1 diff --git a/board/ipe337/env/bin/update_system b/board/ipe337/env/bin/update_system deleted file mode 100644 index 598fc10..0000000 --- a/board/ipe337/env/bin/update_system +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 - -alternate $ageing -ret=$? - -if [ $ret = 0 ]; then - echo "Error when accesing ageing-partition!" - exit 1 -elif [ $ret = 2 ]; then - part=/dev/nor0.system0 -else - part=/dev/nor0.system1 -fi - -. /env/bin/_update $1 diff --git a/board/ipe337/env/config b/board/ipe337/env/config deleted file mode 100644 index 7c5ee76..0000000 --- a/board/ipe337/env/config +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'flash' -kernel=net -root=net - -# use 'dhcp' todo dhcp in barebox and in kernel -#ip=dhcp - -eth0.ipaddr=192.168.23.164 -eth0.netmask=255.255.255.0 -eth0.gateway=192.168.23.2 -eth0.serverip=192.168.23.2 - -uimage=uImage-bfin -jffs2=root-bfin.jffs2 -appimage=apps-bfin -perimage=pers-bfin -envimage=uEnv-bfin - -autoboot_timeout=1 - -nfsroot="/ptx/work/octopus/wsa/svn/OSELAS.BSP-Pipetronix-ipe337-trunk/root" -bootargs="console=ttyBF0,115200" - -mtdparts="128k(barebox)ro,128k(bareboxenv),128k(ageing),1280k(kernel0),1280k(kernel1),8704k(system0),8704k(system1),8320k(application),4096k(persistent)" -ageing=/dev/nor0.ageing diff --git a/board/ipe337/ipe337.c b/board/ipe337/ipe337.c deleted file mode 100644 index 269e774..0000000 --- a/board/ipe337/ipe337.c +++ /dev/null @@ -1,68 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0x20000000, - .size = 32 * 1024 * 1024, -}; - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0x0, - .size = 128 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -static struct device_d smc911x_dev = { - .name = "smc911x", - .map_base = 0x24000000, - .size = 4096, -}; - -static int ipe337_devices_init(void) { - register_device(&cfi_dev); - register_device(&sdram_dev); - - /* Reset smc911x */ - *pFIO0_DIR = (1<<12); - *pFIO0_FLAG_C = (1<<12); - mdelay(100); - *pFIO0_FLAG_S = (1<<12); - - register_device(&smc911x_dev); - - devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x20000, 0x20000, PARTITION_FIXED, "env0"); - - protect_file("/dev/env0", 1); - - return 0; -} - -device_initcall(ipe337_devices_init); - -static struct device_d blackfin_serial_device = { - .name = "blackfin_serial", - .map_base = 0, - .size = 4096, -}; - -static int blackfin_console_init(void) -{ - register_device(&blackfin_serial_device); - - return 0; -} - -console_initcall(blackfin_console_init); - diff --git a/board/ipe337/ipe337.dox b/board/ipe337/ipe337.dox deleted file mode 100644 index 4d7925a..0000000 --- a/board/ipe337/ipe337.dox +++ /dev/null @@ -1,10 +0,0 @@ -/** @page ipe337 ipe337 - -This CPU card is based on an Analog Device Blackfin CPU. The card is shipped -with: - -- 32MiB NOR type Flash Memory -- 128MiB synchronous dynamic RAM -- SMSC9xxx network controller - -*/ \ No newline at end of file diff --git a/board/kp_ukd_r1_num/Makefile b/board/kp_ukd_r1_num/Makefile deleted file mode 100644 index 65f2a02..0000000 --- a/board/kp_ukd_r1_num/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# (C) Copyright 2007 Carsten Schlote -# See file CREDITS for list of people who contributed to this project. -# -# This file is part of barebox. -# -# barebox is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# barebox 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 barebox. If not, see . -# - -# The build system allows to split everything into distinct files covering an -# separate issue. Use that! - -# Board specific callbacks and initialisations - -obj-y += lowlevel_init.o -obj-y += highlevel_init.o -obj-y += kp_ukd_r1_num.o - -obj-y += pci-stubs.o - diff --git a/board/kp_ukd_r1_num/env/bin/_update b/board/kp_ukd_r1_num/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/kp_ukd_r1_num/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/kp_ukd_r1_num/env/bin/boot b/board/kp_ukd_r1_num/env/bin/boot deleted file mode 100644 index c9fcbac..0000000 --- a/board/kp_ukd_r1_num/env/bin/boot +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xflash ]; then - root=flash - kernel=flash -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xflash ]; then - bootargs="$bootargs root=$rootpart rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm /dev/nor0.kernel -fi - diff --git a/board/kp_ukd_r1_num/env/bin/init b/board/kp_ukd_r1_num/env/bin/init deleted file mode 100644 index 48e2139..0000000 --- a/board/kp_ukd_r1_num/env/bin/init +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -addpart /dev/nor0 $mtdparts - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type udate_root [] to update rootfs into flash" - echo - exit -fi - -boot \ No newline at end of file diff --git a/board/kp_ukd_r1_num/env/bin/pcidmaloop b/board/kp_ukd_r1_num/env/bin/pcidmaloop deleted file mode 100644 index 24e76cb..0000000 --- a/board/kp_ukd_r1_num/env/bin/pcidmaloop +++ /dev/null @@ -1,14 +0,0 @@ -pci stat -pci stat -c -while true; do - pci readm 32 0xA1000000 32 -s - pci readm 32 0xA2000000 256 -s - pci dmatx 2000 a2000100 128 -s - pci writem 32 0xa2000100 0x12345678 4 -s - pci readm 32 0xA3000000 256 -s - pci dmatx 2000 a3000040 128 -s - pci writem 32 0xa3000100 0x12345678 4 -s - pci readm 32 0xA4000000 16 -s - pci dmatx 2000 a4000080 4 -s - pci writem 32 0xa4000080 0x12345678 4 -s -done diff --git a/board/kp_ukd_r1_num/env/bin/pciloop b/board/kp_ukd_r1_num/env/bin/pciloop deleted file mode 100644 index 4a804f9..0000000 --- a/board/kp_ukd_r1_num/env/bin/pciloop +++ /dev/null @@ -1,13 +0,0 @@ -pci stat -pci stat -c -while true; do - pci readm 32 0xA1000000 32 -s - pci readm 32 0xA2000000 256 -s - pci writem 32 0xa2000100 0x12345678 4 -s - pci readm 32 0xA3000000 256 -s - pci writem 32 0xa3000100 0x12345678 4 -s - pci readm 32 0xA4000000 16 -s - pci writem 32 0xa4000080 0x12345678 4 -s - -# pci dmatx 2000 a3000040 128 -s -done diff --git a/board/kp_ukd_r1_num/env/bin/update_kernel b/board/kp_ukd_r1_num/env/bin/update_kernel deleted file mode 100644 index 1ad95fc..0000000 --- a/board/kp_ukd_r1_num/env/bin/update_kernel +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -part=/dev/nor0.kernel - -. /env/bin/_update $1 diff --git a/board/kp_ukd_r1_num/env/bin/update_root b/board/kp_ukd_r1_num/env/bin/update_root deleted file mode 100644 index b757a5b..0000000 --- a/board/kp_ukd_r1_num/env/bin/update_root +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 -part=/dev/nor0.root - -. /env/bin/_update $1 diff --git a/board/kp_ukd_r1_num/env/config b/board/kp_ukd_r1_num/env/config deleted file mode 100644 index 14958ba..0000000 --- a/board/kp_ukd_r1_num/env/config +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'flash' -kernel=net -root=net - -# use 'dhcp' todo dhcp in barebox and in kernel -ip=dhcp - -# -# setup default ethernet address -# -eth0.ipaddr=192.168.0.99 -eth0.netmask=255.255.255.0 -eth0.gateway=192.168.0.110 -eth0.serverip=192.168.0.110 - -uimage=uImage-mcf5475 -jffs2=root-mcf5475-ptx.jffs2 - -autoboot_timeout=3 - -#nfsroot="/home/cschlote/src/bitshrine/ltib/rootfs" -nfsroot="/home/cschlote/src/pengutronics/ptxdist-project-KP-UKD/root-debug,v3" -bootargs="console=ttyS0 rw initcall_debug debug" - -# -# setup the partitions in the main flash -# -mtdparts=512k(self),256k(env),3M(kernel),-(root) -rootpart="/dev/mtdblock3" - diff --git a/board/kp_ukd_r1_num/highlevel_init.c b/board/kp_ukd_r1_num/highlevel_init.c deleted file mode 100644 index 3a88cd6..0000000 --- a/board/kp_ukd_r1_num/highlevel_init.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) 2007,2008 konzeptpark, Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - -/** @file - * @brief This file contains high-level init functions. - * - */ -#include -#include -#include -#include - -static void board_gpio_init(void) -{ - /* - * Enable Ethernet signals so that, if a cable is plugged into - * the ports, the lines won't be floating and potentially cause - * erroneous transmissions - */ - MCF_GPIO_PAR_FECI2CIRQ = 0 - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDC_EMDC - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDIO_EMDIO - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MII - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E17 - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDC - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDIO - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MII - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E07; -} - - -static void board_psc_init(void) -{ -#if (CFG_EARLY_UART_PORT == 0) - MCF_GPIO_PAR_PSC0 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC0_PAR_CTS0_CTS - | MCF_GPIO_PAR_PSC0_PAR_RTS0_RTS -#endif - | MCF_GPIO_PAR_PSC0_PAR_TXD0 - | MCF_GPIO_PAR_PSC0_PAR_RXD0); -#elif (CFG_EARLY_UART_PORT == 1) - MCF_GPIO_PAR_PSC1 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC1_PAR_CTS1_CTS - | MCF_GPIO_PAR_PSC1_PAR_RTS1_RTS -#endif - | MCF_GPIO_PAR_PSC1_PAR_TXD1 - | MCF_GPIO_PAR_PSC1_PAR_RXD1); -#elif (CFG_EARLY_UART_PORT == 2) - MCF_GPIO_PAR_PSC2 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC2_PAR_CTS2_CTS - | MCF_GPIO_PAR_PSC2_PAR_RTS2_RTS -#endif - | MCF_GPIO_PAR_PSC2_PAR_TXD2 - | MCF_GPIO_PAR_PSC2_PAR_RXD2); -#elif (CFG_EARLY_UART_PORT == 3) - MCF_GPIO_PAR_PSC3 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC3_PAR_CTS3_CTS - | MCF_GPIO_PAR_PSC3_PAR_RTS3_RTS -#endif - | MCF_GPIO_PAR_PSC3_PAR_TXD3 - | MCF_GPIO_PAR_PSC3_PAR_RXD3); -#else -#error "Invalid CFG_EARLY_UART_PORT setting" -#endif - - /* Put PSC in UART mode */ - MCF_PSC_SICR(CFG_EARLY_UART_PORT) = MCF_PSC_SICR_SIM_UART; - - /* Call generic UART initialization */ -// mcf5xxx_uart_init(DBUG_UART_PORT, board_get_baud()); -} - - -/** Do board specific early init - * - * @note We run at link address now, you can now call other code - */ -void board_init_highlevel(void) -{ - /* Initialize platform specific GPIOs */ - board_gpio_init(); - - /* Init UART GPIOs and Modes */ - board_psc_init(); - - /* Setup the early init data */ -#ifdef CONFIG_HAS_EARLY_INIT - early_init(); -#endif - /* Configure the early debug output facility */ -#ifdef CONFIG_DEBUG_LL - early_debug_init(); -#endif -} - -/** Provide address of early debug low-level output - * - * @todo Should return real address for UART register map. - */ -void *get_early_console_base(const char *name) -{ - return (void*)1 + CFG_EARLY_UART_PORT; -} diff --git a/board/kp_ukd_r1_num/kp_ukd_r1_num.c b/board/kp_ukd_r1_num/kp_ukd_r1_num.c deleted file mode 100644 index 9bf1713..0000000 --- a/board/kp_ukd_r1_num/kp_ukd_r1_num.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * (C) 2007 konzeptpark, Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - - -#include -#include -#include -#include -#include -#include -//#include -#include -#include -#include - -/* - * Return board clock in MHz FIXME move to clocks file - */ -ulong mcfv4e_get_bus_clk(void) -{ - return CFG_SYSTEM_CORE_CLOCK; -} -/* - * Up to 64MiB NOR type flash, connected to - * CS line 0, data width is 32 bit - */ -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = CFG_FLASH_ADDRESS, - .size = CFG_FLASH_SIZE, -}; - -/* - * up to 2MiB static RAM type memory, connected - * to CS4, data width is 16 bit - */ -//static struct device_d sram_dev = { -// .name = "sram", -//FIXME .map_base = IMX_CS4_BASE, -//FIXME .size = IMX_CS4_RANGE, /* area size */ -//}; - -/* - * ?MiB NAND type flash, data width 8 bit - */ -//static struct device_d nand_dev = { -// .name = "cfi_flash_nand", -// .map_base = 0xfc000000, /* FIXME */ -// .size = 32 * 1024 * 1024, /* FIXME */ -//}; - - -/* - * Build in FastEthernetControllers (FECs) - */ -static struct fec_platform_data fec_info = { - .xcv_type = MII100, -}; - -static struct device_d network_dev0 = { - .name = "fec_mcf54xx", - .map_base = MCF_FEC_ADDR(0), - .size = MCF_FEC_SIZE(0), /* area size */ - .platform_data = &fec_info, -}; -static struct device_d network_dev1 = { - .name = "fec_mcf54xx", - .map_base = MCF_FEC_ADDR(1), - .size = MCF_FEC_SIZE(1), /* area size */ - .platform_data = &fec_info, -}; - -/* - * 128MiB of SDRAM, data width is 32 bit - */ -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = CFG_SDRAM_ADDRESS, - .size = CFG_SDRAM_SIZE, - .platform_data = &ram_pdata, -}; - -static int mcfv4e_devices_init(void) -{ - printf("Setting up board devices...\n"); - - /* setup pins for I2C2 (for EEPROM, RTC) */ -//FIXME imx_gpio_mode(MUX_CSPI2_MOSI_I2C2_SCL); -//FIXME imx_gpio_mode(MUX_CSPI2_MISO_I2C2_SCL); - - register_device(&cfi_dev); - - /* - * Create partitions that should be - * not touched by any regular user - */ - devfs_add_partition("nor0", 0x00000, 0x80000, PARTITION_FIXED, "self0"); /* ourself */ - devfs_add_partition("nor0", 0x80000, 0x40000, PARTITION_FIXED, "env0"); /* environment */ - protect_file("/dev/env0", 1); - - //register_device(&sram_dev); - //register_device(&nand_dev); - - register_device(&network_dev0); - //register_device(&network_dev1); - - register_device(&sdram_dev); - - return 0; -} - -device_initcall(mcfv4e_devices_init); - -static struct device_d mcfv4e_serial_device = { - .name = "mcfv4e_serial", - .map_base = 1+CFG_EARLY_UART_PORT, - .size = 16 * 1024, -}; - -static int mcfv4e_console_init(void) -{ - /* init gpios for serial port */ - - /* Already set in lowlevel_init.c */ - - register_device(&mcfv4e_serial_device); - return 0; -} - -console_initcall(mcfv4e_console_init); - diff --git a/board/kp_ukd_r1_num/kp_ukd_r1_num.dox b/board/kp_ukd_r1_num/kp_ukd_r1_num.dox deleted file mode 100644 index ca0fcbc..0000000 --- a/board/kp_ukd_r1_num/kp_ukd_r1_num.dox +++ /dev/null @@ -1,13 +0,0 @@ -/** @page kp_ukd_r1 konzeptpark MCB2 Prototype Board - -This target is based on a PhyTec PhyCore MCF54x5 NUM CPU. The card is shipped with: - -- up to 64MiB NOR type Flash Memory -- 128MiB synchronous dynamic RAM -- PCI USB 2.0 Host -- PCCard Controller -- MiniPCI Parallel -- MiniPCIe (USB lane only) -- ... - -*/ diff --git a/board/kp_ukd_r1_num/lowlevel_init.c b/board/kp_ukd_r1_num/lowlevel_init.c deleted file mode 100644 index b3de505..0000000 --- a/board/kp_ukd_r1_num/lowlevel_init.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * (C) 2007 konzeptpark, Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - -/** @file - * @brief This file contains ... - * - */ -#include -#include -#include - -/** Initialize board specific very early inits - * - * @note This code is not allowed to call other code - just init - * your Chipselects and SDRAM stuff here! - */ -void board_init_lowlevel(void) -{ - /* - * The phyCORE-MCF548x has a 32MB or 64MB boot flash. - * The is a CF Card and ControlRegs on CS1 and CS2 - */ - - /* Setup SysGlue Chip-Select */ - MCF_FBCS_CSAR5 = MCF_FBCS_CSAR_BA(CFG_SYSGLUE_ADDRESS); - - MCF_FBCS_CSCR5 = (MCF_FBCS_CSCR_PS_32 - | MCF_FBCS_CSCR_AA - | MCF_FBCS_CSCR_ASET(1) - | MCF_FBCS_CSCR_WS(CFG_SYSGLUE_WAIT_STATES)); - - MCF_FBCS_CSMR5 = (MCF_FBCS_CSMR_BAM_16M - | MCF_FBCS_CSMR_V); - - /* Setup boot flash chip-select */ - MCF_FBCS_CSAR0 = MCF_FBCS_CSAR_BA(CFG_FLASH_ADDRESS); - - MCF_FBCS_CSCR0 = (MCF_FBCS_CSCR_PS_32 - | MCF_FBCS_CSCR_AA - | MCF_FBCS_CSCR_ASET(1) - | MCF_FBCS_CSCR_WS(CFG_FLASH_WAIT_STATES)); - - MCF_FBCS_CSMR0 = (MCF_FBCS_CSMR_BAM_32M - | MCF_FBCS_CSMR_V); - - /* - * Check to see if the SDRAM has already been initialized - * by a run control tool - */ - if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) - { - /* - * Basic configuration and initialization - */ - // 0x000002AA - MCF_SDRAMC_SDRAMDS = (0 - | MCF_SDRAMC_SDRAMDS_SB_E(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_C(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_A(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_S(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_D(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - ); - - // 0x0000001A - MCF_SDRAMC_CS0CFG = (0 - | MCF_SDRAMC_CSnCFG_CSBA(CFG_SDRAM_ADDRESS) - | MCF_SDRAMC_CSnCFG_CSSZ(MCF_SDRAMC_CSnCFG_CSSZ_128MBYTE) - ); - - MCF_SDRAMC_CS1CFG = 0; - MCF_SDRAMC_CS2CFG = 0; - MCF_SDRAMC_CS3CFG = 0; - - // 0x73611730 - MCF_SDRAMC_SDCFG1 = (0 - | MCF_SDRAMC_SDCFG1_SRD2RW((unsigned int)((CFG_SDRAM_CASL + CFG_SDRAM_BL / 2 + 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_SWT2RD((unsigned int) (CFG_SDRAM_TWR + 1)) - | MCF_SDRAMC_SDCFG1_RDLAT((unsigned int)((CFG_SDRAM_CASL * 2) + 2)) - | MCF_SDRAMC_SDCFG1_ACT2RW((unsigned int)(((CFG_SDRAM_TRCD / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_PRE2ACT((unsigned int)(((CFG_SDRAM_TRP / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_REF2ACT((unsigned int)(((CFG_SDRAM_TRFC / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_WTLAT(3) - ); - - // 0x46770000 - MCF_SDRAMC_SDCFG2 = (0 - | MCF_SDRAMC_SDCFG2_BRD2PRE(CFG_SDRAM_BL / 2) - | MCF_SDRAMC_SDCFG2_BWT2RW(CFG_SDRAM_BL / 2 + CFG_SDRAM_TWR) - | MCF_SDRAMC_SDCFG2_BRD2WT(7) - | MCF_SDRAMC_SDCFG2_BL(CFG_SDRAM_BL - 1) - ); - - /* - * Precharge and enable write to SDMR - */ - // 0xE10B0002 - MCF_SDRAMC_SDCR = (0 - | MCF_SDRAMC_SDCR_MODE_EN - | MCF_SDRAMC_SDCR_CKE - | MCF_SDRAMC_SDCR_DDR - | MCF_SDRAMC_SDCR_MUX(1) // 13 x 10 x 2 ==> MUX=1 - | MCF_SDRAMC_SDCR_RCNT((int)(((CFG_SDRAM_TREFI / (CFG_SYSTEM_CORE_PERIOD * 64)) - 1) + 0.5)) - | MCF_SDRAMC_SDCR_IPALL - ); - - /* - * Write extended mode register - */ - // 0x40010000 - MCF_SDRAMC_SDMR = (0 - | MCF_SDRAMC_SDMR_BNKAD_LEMR - | MCF_SDRAMC_SDMR_AD(0x0) - | MCF_SDRAMC_SDMR_CMD - ); - - /* - * Write mode register and reset DLL - */ - // 0x048d0000 - MCF_SDRAMC_SDMR = (0 - | MCF_SDRAMC_SDMR_BNKAD_LMR - | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_RESET_DLL | CFG_SDRAM_MOD) - | MCF_SDRAMC_SDMR_CMD - ); - - /* - * Execute a PALL command - */ - // 0xE10B0002 - MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL; - - /* - * Perform two REF cycles - */ - // 0xE10B0004 - MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; - MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; - - /* - * Write mode register and clear reset DLL - */ - // 0x008D0000 - MCF_SDRAMC_SDMR = (0 - | MCF_SDRAMC_SDMR_BNKAD_LMR - | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_MOD) - | MCF_SDRAMC_SDMR_CMD - ); - - /* - * Enable auto refresh and lock SDMR - */ - // 0x610B0000 - MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN; - - // 0x710B0F00 - MCF_SDRAMC_SDCR |= (0 - | MCF_SDRAMC_SDCR_REF - | MCF_SDRAMC_SDCR_DQS_OE(0xF) - ); - } -} - -/** @file - * - * Target specific early chipselect and SDRAM init. - */ diff --git a/board/kp_ukd_r1_num/pci-stubs.c b/board/kp_ukd_r1_num/pci-stubs.c deleted file mode 100644 index b7ab7c7..0000000 --- a/board/kp_ukd_r1_num/pci-stubs.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * (C) 2007,2008 Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - -/** @file - * @brief This file contains callbacks for the PCI subsystem - * - */ -#include -#include - - -/** Returns mapping from PCI slot to CPU irq for the target board - * @return Coldfire IRQ vector number, or -1 for no irq - */ -int mcfv4e_pci_gethostirq(uint8_t slot, uint8_t irqpin) -{ - int rc = -1; - switch (slot) - { - case 16 : break; - case 17 ... 21 : rc = 64 + 7; break; // Eport IRQ7 - } - return rc; -} diff --git a/board/mmccpu/Makefile b/board/mmccpu/Makefile deleted file mode 100644 index eb072c0..0000000 --- a/board/mmccpu/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += init.o diff --git a/board/mmccpu/config.h b/board/mmccpu/config.h deleted file mode 100644 index 1133b8f..0000000 --- a/board/mmccpu/config.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -#define AT91_MASTER_CLOCK 99532800 /* peripheral = main / 2 */ - -/* values */ -#define MASTER_PLL_MUL 54 -#define MASTER_PLL_DIV 4 - -/* clocks */ -#define CONFIG_SYS_MOR_VAL \ - (AT91_PMC_MOSCEN | \ - (255 << 8)) /* Main Oscillator Start-up Time */ -#define CONFIG_SYS_PLLAR_VAL \ - (AT91_PMC_PLLA_WR_ERRATA | /* Bit 29 must be 1 when prog */ \ - AT91_PMC_OUT | \ - AT91_PMC_PLLCOUNT | /* PLL Counter */ \ - (2 << 28) | /* PLL Clock Frequency Range */ \ - ((MASTER_PLL_MUL - 1) << 16) | (MASTER_PLL_DIV)) - -/* PCK/2 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR1_VAL \ - (AT91_PMC_CSS_SLOW | \ - AT91_PMC_PRES_1 | \ - AT91SAM9_PMC_MDIV_2 | \ - AT91_PMC_PDIV_1) -/* PCK/2 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR2_VAL \ - (AT91_PMC_CSS_PLLA | \ - AT91_PMC_PRES_1 | \ - AT91SAM9_PMC_MDIV_2 | \ - AT91_PMC_PDIV_1) - -/* define PDC[31:16] as DATA[31:16] */ -#define CONFIG_SYS_PIOD_PDR_VAL1 0xFFFF0000 -/* no pull-up for D[31:16] */ -#define CONFIG_SYS_PIOD_PPUDR_VAL 0xFFFF0000 -/* EBI0_CSA, CS1 SDRAM, CS3 NAND Flash, 1.8V memories */ -#define CONFIG_SYS_MATRIX_EBI0CSA_VAL \ - (AT91_MATRIX_EBI0_DBPUC | AT91_MATRIX_EBI0_VDDIOMSEL_1_8V | \ - AT91_MATRIX_EBI0_CS1A_SDRAMC | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA) - -/* SDRAM */ -/* SDRAMC_MR Mode register */ -#define CONFIG_SYS_SDRC_MR_VAL1 0 -/* SDRAMC_TR - Refresh Timer register */ -#define CONFIG_SYS_SDRC_TR_VAL1 0x13c -/* SDRAMC_CR - Configuration register*/ -#define CONFIG_SYS_SDRC_CR_VAL \ - (AT91_SDRAMC_NC_9 | \ - AT91_SDRAMC_NR_13 | \ - AT91_SDRAMC_NB_4 | \ - AT91_SDRAMC_CAS_3 | \ - AT91_SDRAMC_DBW_32 | \ - (2 << 8) | /* tWR - Write Recovery Delay */ \ - (8 << 12) | /* tRC - Row Cycle Delay */ \ - (2 << 16) | /* tRP - Row Precharge Delay */ \ - (2 << 20) | /* tRCD - Row to Column Delay */ \ - (5 << 24) | /* tRAS - Active to Precharge Delay */ \ - (12 << 28)) /* tXSR - Exit Self Refresh to Active Delay */ - -/* Memory Device Register -> SDRAM */ -#define CONFIG_SYS_SDRC_MDR_VAL AT91_SDRAMC_MD_SDRAM -#define CONFIG_SYS_SDRC_MR_VAL2 AT91_SDRAMC_MODE_PRECHARGE -#define CONFIG_SYS_SDRAM_VAL1 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL3 AT91_SDRAMC_MODE_REFRESH -#define CONFIG_SYS_SDRAM_VAL2 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL3 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL4 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL5 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL6 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL7 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL8 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL9 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL4 AT91_SDRAMC_MODE_LMR -#define CONFIG_SYS_SDRAM_VAL10 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL5 AT91_SDRAMC_MODE_NORMAL -#define CONFIG_SYS_SDRAM_VAL11 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_TR_VAL2 780 /* SDRAM_TR */ -#define CONFIG_SYS_SDRAM_VAL12 0 /* SDRAM_BASE */ - -/* setup CS0 (NOR Flash) - 16-bit */ -#if 1 -#define CONFIG_SYS_SMC0_SETUP0_VAL \ - (AT91_SMC_NWESETUP_(3) | AT91_SMC_NCS_WRSETUP_(2) | \ - AT91_SMC_NRDSETUP_(8) | AT91_SMC_NCS_RDSETUP_(0)) -#define CONFIG_SYS_SMC0_PULSE0_VAL \ - (AT91_SMC_NWEPULSE_(5) | AT91_SMC_NCS_WRPULSE_(7) | \ - AT91_SMC_NRDPULSE_(5) | AT91_SMC_NCS_RDPULSE_(13)) -#define CONFIG_SYS_SMC0_CYCLE0_VAL \ - (AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16)) -#define CONFIG_SYS_SMC0_MODE0_VAL \ - (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ - AT91_SMC_DBW_16 | \ - AT91_SMC_TDFMODE | \ - AT91_SMC_TDF_(6)) -#elif 0 /* slow setup */ -#define CONFIG_SYS_SMC0_SETUP0_VAL \ - (AT91_SMC_NWESETUP_(3) | AT91_SMC_NCS_WRSETUP_(2) | \ - AT91_SMC_NRDSETUP_(8) | AT91_SMC_NCS_RDSETUP_(0)) -#define CONFIG_SYS_SMC0_PULSE0_VAL \ - (AT91_SMC_NWEPULSE_(5) | AT91_SMC_NCS_WRPULSE_(7) | \ - AT91_SMC_NRDPULSE_(5) | AT91_SMC_NCS_RDPULSE_(13)) -#define CONFIG_SYS_SMC0_CYCLE0_VAL \ - (AT91_SMC_NWECYCLE_(0xd00) | AT91_SMC_NRDCYCLE_(0xd00)) -#define CONFIG_SYS_SMC0_MODE0_VAL \ - (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ - AT91_SMC_DBW_16 | \ - AT91_SMC_TDFMODE | \ - AT91_SMC_TDF_(1)) -#else /* RONETIX' original values */ -#define CONFIG_SYS_SMC0_SETUP0_VAL \ - (AT91_SMC_NWESETUP_(10) | AT91_SMC_NCS_WRSETUP_(10) | \ - AT91_SMC_NRDSETUP_(10) | AT91_SMC_NCS_RDSETUP_(10)) -#define CONFIG_SYS_SMC0_PULSE0_VAL \ - (AT91_SMC_NWEPULSE_(11) | AT91_SMC_NCS_WRPULSE_(11) | \ - AT91_SMC_NRDPULSE_(11) | AT91_SMC_NCS_RDPULSE_(11)) -#define CONFIG_SYS_SMC0_CYCLE0_VAL \ - (AT91_SMC_NWECYCLE_(22) | AT91_SMC_NRDCYCLE_(22)) -#define CONFIG_SYS_SMC0_MODE0_VAL \ - (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ - AT91_SMC_DBW_16 | \ - AT91_SMC_TDFMODE | \ - AT91_SMC_TDF_(6)) -#endif - -/* user reset enable */ -#define CONFIG_SYS_RSTC_RMR_VAL \ - (AT91_RSTC_KEY | \ - AT91_RSTC_PROCRST | \ - AT91_RSTC_RSTTYP_WAKEUP | \ - AT91_RSTC_RSTTYP_WATCHDOG) - -/* Disable Watchdog */ -#define CONFIG_SYS_WDTC_WDMR_VAL \ - (AT91_WDT_WDIDLEHLT | AT91_WDT_WDDBGHLT | \ - AT91_WDT_WDV | \ - AT91_WDT_WDDIS | \ - AT91_WDT_WDD) - -#endif /* __CONFIG_H */ diff --git a/board/mmccpu/env/bin/_update b/board/mmccpu/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/mmccpu/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/mmccpu/env/bin/boot b/board/mmccpu/env/bin/boot deleted file mode 100644 index 533dea7..0000000 --- a/board/mmccpu/env/bin/boot +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - root=nand - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$1 = xnor ]; then - root=nor - kernel=nor -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -elif [ x$root = xnor ]; then - bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -elif [ $kernel = nor ]; then - bootm /dev/nor0.kernel -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/mmccpu/env/bin/hush_hack b/board/mmccpu/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/mmccpu/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/mmccpu/env/bin/init b/board/mmccpu/env/bin/init deleted file mode 100644 index ac84bd5..0000000 --- a/board/mmccpu/env/bin/init +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nor0 ]; then - addpart /dev/nor0 $nor_parts -fi - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel nor [] to update kernel into flash" - echo "type update_root nor [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/mmccpu/env/bin/update_kernel b/board/mmccpu/env/bin/update_kernel deleted file mode 100644 index 05c822d..0000000 --- a/board/mmccpu/env/bin/update_kernel +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.kernel.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.kernel -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 diff --git a/board/mmccpu/env/bin/update_root b/board/mmccpu/env/bin/update_root deleted file mode 100644 index a751372..0000000 --- a/board/mmccpu/env/bin/update_root +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 -if [ x$1 = xnand ]; then - part=/dev/nand0.root.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.root -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 - diff --git a/board/mmccpu/env/config b/board/mmccpu/env/config deleted file mode 100644 index 5367cd9..0000000 --- a/board/mmccpu/env/config +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -# can be either 'net', 'nor' or 'nand'' -kernel=nor -root=nor - -uimage=uImage-mmccpu -jffs2=root-mmccpu.jffs2 - -autoboot_timeout=3 - -nfsroot="/home/kschwinne/src/pengutronix/OSELAS.BSP-Bucyrus-Grabowski-trunk/platform-Bucyrus-mmccpu/root" - -bootargs="console=ttyS0,115200 mmccpu=p299" - -#nor_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" -nor_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),10240k(root),10240k(rootbu),-(data)" -rootpart_nor="/dev/mtdblock3" - -#nand_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" -#rootpart_nand="/dev/mtdblock7" - -# use 'dhcp' to do dhcp in barebox and in kernel -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 diff --git a/board/mmccpu/init.c b/board/mmccpu/init.c deleted file mode 100644 index e010a83..0000000 --- a/board/mmccpu/init.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = AT91_CHIPSELECT_0, - .size = 0, /* zero means autodetect size */ -}; - -static struct at91_ether_platform_data macb_pdata = { - .flags = AT91SAM_ETHER_MII | AT91SAM_ETHER_FORCE_LINK, - .phy_addr = 4, -}; - -static int mmccpu_devices_init(void) -{ - /* - * PB27 enables the 50MHz oscillator for Ethernet PHY - * 1 - enable - * 0 - disable - */ - at91_set_gpio_output(AT91_PIN_PB27, 1); - at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - - at91_add_device_sdram(128 * 1024 * 1024); - at91_add_device_eth(&macb_pdata); - register_device(&cfi_dev); - - devfs_add_partition("nor0", 0x00000, 256 * 1024, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 128 * 1024, PARTITION_FIXED, "env0"); - - armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); - armlinux_set_architecture(MACH_TYPE_MMCCPU); - - return 0; -} - -device_initcall(mmccpu_devices_init); - -static int mmccpu_console_init(void) -{ - at91_register_uart(0, 0); - return 0; -} - -console_initcall(mmccpu_console_init); diff --git a/board/netx/Makefile b/board/netx/Makefile deleted file mode 100644 index 8b33fec..0000000 --- a/board/netx/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-y += netx.o platform.o - diff --git a/board/netx/config.h b/board/netx/config.h deleted file mode 100644 index ca15136..0000000 --- a/board/netx/config.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -#endif /* __CONFIG_H */ diff --git a/board/netx/netx.c b/board/netx/netx.c deleted file mode 100644 index d6bfcca..0000000 --- a/board/netx/netx.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2004 Sascha Hauer, Synertronixx GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0xC0000000, - .size = 32 * 1024 * 1024, -}; - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0x80000000, - .size = 64 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -struct netx_eth_platform_data eth0_data = { - .xcno = 0, -}; - -static struct device_d netx_eth_dev0 = { - .name = "netx-eth", - .platform_data = ð0_data, -}; - -struct netx_eth_platform_data eth1_data = { - .xcno = 1, -}; - -static struct device_d netx_eth_dev1 = { - .name = "netx-eth", - .platform_data = ð1_data, -}; - -static int netx_devices_init(void) { - register_device(&cfi_dev); - register_device(&sdram_dev); - register_device(&netx_eth_dev0); - register_device(&netx_eth_dev1); - - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); - - /* Do not overwrite primary env for now */ - devfs_add_partition("nor0", 0xc0000, 0x80000, PARTITION_FIXED, "env0"); - - protect_file("/dev/env0", 1); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0x80000100); - armlinux_set_architecture(MACH_TYPE_NXDB500); - - return 0; -} - -device_initcall(netx_devices_init); - -static struct device_d netx_serial_device = { - .name = "netx_serial", - .map_base = NETX_PA_UART0, - .size = 0x40, -}; - -static int netx_console_init(void) -{ - /* configure gpio for serial */ - *(volatile unsigned long *)(0x00100800) = 2; - *(volatile unsigned long *)(0x00100804) = 2; - *(volatile unsigned long *)(0x00100808) = 2; - *(volatile unsigned long *)(0x0010080c) = 2; - - register_device(&netx_serial_device); - return 0; -} - -console_initcall(netx_console_init); - diff --git a/board/netx/netx.dox b/board/netx/netx.dox deleted file mode 100644 index e22c5e8..0000000 --- a/board/netx/netx.dox +++ /dev/null @@ -1,9 +0,0 @@ -/** @page netx Hilscher's NetX card family - -This CPU card is based on a Hilscher's NetX ARM CPU. The card is shipped -in various incarnations: - -Specific to this CPU is, it does not require any setup code to bring the -SDRAM up and working. This is done in a pre bootloader. - -*/ \ No newline at end of file diff --git a/board/netx/platform.S b/board/netx/platform.S deleted file mode 100644 index 4961682..0000000 --- a/board/netx/platform.S +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Board specific setup info - * - * - * 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 - */ - -.globl board_init_lowlevel -board_init_lowlevel: - mov pc, lr diff --git a/board/omap/Kconfig b/board/omap/Kconfig deleted file mode 100644 index 361bed4..0000000 --- a/board/omap/Kconfig +++ /dev/null @@ -1,162 +0,0 @@ -# OMAP based Board Specific Configuration file -# -# (C) Copyright 2008 -# OMAP Architecture specific features -# Texas Instruments, -# Nishanth Menon -# -# 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 - - -menuconfig MACH_OMAP_GPMC_NAND - tristate "Enable NAND device support for GPMC" - depends on HAS_OMAP_NAND - default n - help - Say Y here if you would like to have NAND device support - -if MACH_OMAP_GPMC_NAND -# Single definition used to club all generic definitions together -config MACH_OMAP_GPMC_GENERICNAND - bool - -choice - prompt "Select NAND Device" - -config MACH_OMAP_GPMC_GENERICNAND_LP_X8 - tristate "Enable 8 bit Large page nand" - depends on MACH_OMAP_GPMC_NAND - select MACH_OMAP_GPMC_GENERICNAND - help - Say Y here if you would support for 8 bit NAND - with large page - NOTE: The timing parameter are the most relaxed - If you need optimized timing, selec appropriate - supported NAND flash - -config MACH_OMAP_GPMC_GENERICNAND_LP_X16 - tristate "Enable 16 bit Large page nand" - depends on MACH_OMAP_GPMC_NAND - select MACH_OMAP_GPMC_GENERICNAND - help - Say Y here if you would support for 16 bit NAND - with large page - NOTE: The timing parameter are the most relaxed - If you need optimized timing, selec appropriate - supported NAND flash - -config MACH_OMAP_GPMC_GENERICNAND_SP_X8 - tristate "Enable 8 bit Small page nand" - depends on MACH_OMAP_GPMC_NAND - select MACH_OMAP_GPMC_GENERICNAND - help - Say Y here if you would support for 8 bit NAND - with small page - NOTE: The timing parameter are the most relaxed - If you need optimized timing, selec appropriate - supported NAND flash - -config MACH_OMAP_GPMC_GENERICNAND_SP_X16 - tristate "Enable 16 bit Small page nand" - depends on MACH_OMAP_GPMC_NAND - select MACH_OMAP_GPMC_GENERICNAND - help - Say Y here if you would support for 16 bit NAND - with small page - NOTE: The timing parameter are the most relaxed - If you need optimized timing, selec appropriate - supported NAND flash -endchoice - -config MACH_OMAP_CS - hex "NAND CS" - depends on MACH_OMAP_GPMC_NAND - default 0x0 - help - Provide the Chip select of the NAND flash -endif - -endmenu diff --git a/board/omap/Makefile b/board/omap/Makefile deleted file mode 100644 index b4bb3e1..0000000 --- a/board/omap/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# OMAP Board Specific Makefile -# -# (C) Copyright 2008 -# OMAP Architecture specific features -# Texas Instruments, -# Nishanth Menon -# -# 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 - -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-$(CONFIG_MACH_OMAP_GPMC_GENERICNAND) += devices-gpmc-nand.o - diff --git a/board/omap/board-beagle.c b/board/omap/board-beagle.c deleted file mode 100644 index 866d832..0000000 --- a/board/omap/board-beagle.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * (C) Copyright 2008 - * Texas Instruments, - * Raghavendra KH - * - * 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 - */ - -/** - * @file - * @brief Beagle Specific Board Initialization routines - */ - -/** - * @page ti_beagle Texas Instruments Beagle Board - * - * FileName: board/omap/board-beagle.c - * - * Beagle Board from Texas Instruments as described here: - * http://www.beagleboard.org - * - * This board is based on OMAP3530. - * More on OMAP3530 (including documentation can be found here): - * http://focus.ti.com/docs/prod/folders/print/omap3530.html - * - * This file provides initialization in two stages: - * @li boot time initialization - do basics required to get SDRAM working. - * This is run from SRAM - so no case constructs and global vars can be used. - * @li run time initialization - this is for the rest of the initializations - * such as flash, uart etc. - * - * Boot time initialization includes: - * @li SDRAM initialization. - * @li Pin Muxing relevant for Beagle. - * - * Run time initialization includes - * @li serial @ref serial_ns16550.c driver device definition - * - * Originally from board/omap/board-sdp343x.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "board.h" - -/******************** Board Boot Time *******************/ - -/** - * @brief Do the SDRC initialization for 128Meg Micron DDR for CS0 - * - * @return void - */ -static void sdrc_init(void) -{ - /* SDRAM software reset */ - /* No idle ack and RESET enable */ - writel(0x1A, SDRC_REG(SYSCONFIG)); - sdelay(100); - /* No idle ack and RESET disable */ - writel(0x18, SDRC_REG(SYSCONFIG)); - - /* SDRC Sharing register */ - /* 32-bit SDRAM on data lane [31:0] - CS0 */ - /* pin tri-stated = 1 */ - writel(0x00000100, SDRC_REG(SHARING)); - - /* ----- SDRC Registers Configuration --------- */ - /* SDRC_MCFG0 register */ - writel(0x02584099, SDRC_REG(MCFG_0)); - - /* SDRC_RFR_CTRL0 register */ - writel(0x54601, SDRC_REG(RFR_CTRL_0)); - - /* SDRC_ACTIM_CTRLA0 register */ - writel(0xA29DB4C6, SDRC_REG(ACTIM_CTRLA_0)); - - /* SDRC_ACTIM_CTRLB0 register */ - writel(0x12214, SDRC_REG(ACTIM_CTRLB_0)); - - /* Disble Power Down of CKE due to 1 CKE on combo part */ - writel(0x00000081, SDRC_REG(POWER)); - - /* SDRC_MANUAL command register */ - /* NOP command */ - writel(0x00000000, SDRC_REG(MANUAL_0)); - /* Precharge command */ - writel(0x00000001, SDRC_REG(MANUAL_0)); - /* Auto-refresh command */ - writel(0x00000002, SDRC_REG(MANUAL_0)); - /* Auto-refresh command */ - writel(0x00000002, SDRC_REG(MANUAL_0)); - - /* SDRC MR0 register Burst length=4 */ - writel(0x00000032, SDRC_REG(MR_0)); - - /* SDRC DLLA control register */ - writel(0x0000000A, SDRC_REG(DLLA_CTRL)); - - return; -} - -/** - * @brief Do the pin muxing required for Board operation. - * We enable ONLY the pins we require to set. OMAP provides pins which do not - * have alternate modes. Such pins done need to be set. - * - * See @ref MUX_VAL for description of the muxing mode. - * - * @return void - */ -static void mux_config(void) -{ - - /* SDRC_D0 - SDRC_D31 default mux mode is mode0 */ - - /* GPMC */ - MUX_VAL(CP(GPMC_A1), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A2), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A3), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A4), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A5), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A6), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A7), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A8), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A9), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A10), (IDIS | PTD | DIS | M0)); - - /* D0-D7 default mux mode is mode0 */ - MUX_VAL(CP(GPMC_D8), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D9), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D10), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D11), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D12), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D13), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D14), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D15), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_CLK), (IDIS | PTD | DIS | M0)); - /* GPMC_NADV_ALE default mux mode is mode0 */ - /* GPMC_NOE default mux mode is mode0 */ - /* GPMC_NWE default mux mode is mode0 */ - /* GPMC_NBE0_CLE default mux mode is mode0 */ - MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_NBE1), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); - /* GPMC_WAIT0 default mux mode is mode0 */ - MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)); - - /* SERIAL INTERFACE */ - MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); - MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN | M0)); - MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | DIS | M0)); - /* I2C1_SCL default mux mode is mode0 */ - /* I2C1_SDA default mux mode is mode0 */ -} - -/** - * @brief The basic entry point for board initialization. - * - * This is called as part of machine init (after arch init). - * This is again called with stack in SRAM, so not too many - * constructs possible here. - * - * @return void - */ -void board_init(void) -{ - int in_sdram = running_in_sdram(); - mux_config(); - /* Dont reconfigure SDRAM while running in SDRAM! */ - if (!in_sdram) - sdrc_init(); -} - -/******************** Board Run Time *******************/ - -#ifdef CONFIG_DRIVER_SERIAL_NS16550 - -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 beagle_serial_device = { - .name = "serial_ns16550", - .map_base = OMAP_UART3_BASE, - .size = 1024, - .platform_data = (void *)&serial_plat, -}; - -/** - * @brief UART serial port initialization - remember to enable COM clocks in - * arch - * - * @return result of device registration - */ -static int beagle_console_init(void) -{ - /* Register the serial port */ - return register_device(&beagle_serial_device); -} -console_initcall(beagle_console_init); -#endif /* CONFIG_DRIVER_SERIAL_NS16550 */ - -static struct memory_platform_data sram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0x80000000, - .size = 128 * 1024 * 1024, - .platform_data = &sram_pdata, -}; - -static int beagle_devices_init(void) -{ - int ret; - ret = register_device(&sdram_dev); - if (ret) - goto failed; -#ifdef CONFIG_GPMC - /* WP is made high and WAIT1 active Low */ - gpmc_generic_init(0x10); -#endif - armlinux_add_dram(&sdram_dev); -failed: - return ret; -} -device_initcall(beagle_devices_init); diff --git a/board/omap/board-omap3evm.c b/board/omap/board-omap3evm.c deleted file mode 100644 index fdea0ff..0000000 --- a/board/omap/board-omap3evm.c +++ /dev/null @@ -1,275 +0,0 @@ -/** - * @file - * @brief Board Initialization routines for OMAP3EVM. - * - * FileName: board/omap/board-omap3evm.c - * - * This board is based on OMAP3530. - * More on OMAP3530 (including documentation can be found here): - * http://focus.ti.com/docs/prod/folders/print/omap3530.html - * - * This file provides initialization in two stages: - * @li Boot time initialization - just get SDRAM working. - * This is run from SRAM - so no case constructs and global vars can be used. - * @li Run time initialization - this is for the rest of the initializations - * such as flash, uart etc. - * - * Boot time initialization includes: - * @li SDRAM initialization. - * @li Pin Muxing relevant for the EVM. - * - * Run time initialization includes - * @li serial @ref serial_ns16550.c driver device definition - * - * Originally from board/omap/board-beagle.c - */ - -/* - * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ - * Sanjeev Premi - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "board.h" - - -/* - * Boot-time initialization(s) - */ - -/** - * @brief Initialize the SDRC module - * - * @return void - */ -static void sdrc_init(void) -{ - /* SDRAM software reset */ - /* No idle ack and RESET enable */ - writel(0x1A, SDRC_REG(SYSCONFIG)); - sdelay(100); - /* No idle ack and RESET disable */ - writel(0x18, SDRC_REG(SYSCONFIG)); - - /* SDRC Sharing register */ - /* 32-bit SDRAM on data lane [31:0] - CS0 */ - /* pin tri-stated = 1 */ - writel(0x00000100, SDRC_REG(SHARING)); - - /* ----- SDRC Registers Configuration --------- */ - /* SDRC_MCFG0 register */ - writel(0x02584099, SDRC_REG(MCFG_0)); - - /* SDRC_RFR_CTRL0 register */ - writel(0x54601, SDRC_REG(RFR_CTRL_0)); - - /* SDRC_ACTIM_CTRLA0 register */ - writel(0xA29DB4C6, SDRC_REG(ACTIM_CTRLA_0)); - - /* SDRC_ACTIM_CTRLB0 register */ - writel(0x12214, SDRC_REG(ACTIM_CTRLB_0)); - - /* Disble Power Down of CKE due to 1 CKE on combo part */ - writel(0x00000081, SDRC_REG(POWER)); - - /* SDRC_MANUAL command register */ - /* NOP command */ - writel(0x00000000, SDRC_REG(MANUAL_0)); - /* Precharge command */ - writel(0x00000001, SDRC_REG(MANUAL_0)); - /* Auto-refresh command */ - writel(0x00000002, SDRC_REG(MANUAL_0)); - /* Auto-refresh command */ - writel(0x00000002, SDRC_REG(MANUAL_0)); - - /* SDRC MR0 register Burst length=4 */ - writel(0x00000032, SDRC_REG(MR_0)); - - /* SDRC DLLA control register */ - writel(0x0000000A, SDRC_REG(DLLA_CTRL)); - - return; -} - -/** - * @brief Do the necessary pin muxing required for OMAP3EVM. Some pins in OMAP3 - * do not have alternate modes. We don't program these pins. - * - * See @ref MUX_VAL for description of the muxing mode. - * - * @return void - */ -static void mux_config(void) -{ - /* - * SDRC - * - SDRC_D0-SDRC_D31: Default MUX mode is mode0. - */ - - /* - * GPMC - * - GPMC_D0-GPMC_D7: Default MUX mode is mode0. - * - GPMC_NADV_ALE: Default MUX mode is mode0. - * - GPMC_NOE: Default MUX mode is mode0. - * - GPMC_NWE: Default MUX mode is mode0. - * - GPMC_WAIT0: Default MUX mode is mode0. - */ - MUX_VAL(CP(GPMC_A1), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A2), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A3), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A4), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A5), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A6), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A7), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A8), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A9), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_A10), (IDIS | PTD | DIS | M0)); - - MUX_VAL(CP(GPMC_D8), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D9), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D10), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D11), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D12), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D13), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D14), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_D15), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_CLK), (IDIS | PTD | DIS | M0)); - - MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_NBE1), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); - - MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)); - - /* - * Serial Interface - */ -#if defined(CONFIG_OMAP3EVM_UART1) - MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(UART1_CTS), (IEN | PTU | DIS | M0)); - MUX_VAL(CP(UART1_RX), (IEN | PTD | DIS | M0)); -#elif defined(CONFIG_OMAP3EVM_UART3) - MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); - MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); -#endif -} - -/** - * @brief The basic entry point for board initialization. - * - * This is called as part of machine init (after arch init). - * This is again called with stack in SRAM, so not too many - * constructs possible here. - * - * @return void - */ -void board_init(void) -{ - int in_sdram = running_in_sdram(); - - mux_config(); - /* Dont reconfigure SDRAM while running in SDRAM! */ - if (!in_sdram) - sdrc_init(); -} - -/* - * Run-time initialization(s) - */ - -#ifdef CONFIG_DRIVER_SERIAL_NS16550 - -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 omap3evm_serial_device = { - .name = "serial_ns16550", -#if defined(CONFIG_OMAP3EVM_UART1) - .map_base = OMAP_UART1_BASE, -#elif defined(CONFIG_OMAP3EVM_UART3) - .map_base = OMAP_UART3_BASE, -#endif - .size = 1024, - .platform_data = (void *)&serial_plat, -}; - -/** - * @brief Initialize the serial port to be used as console. - * - * @return result of device registration - */ -static int omap3evm_init_console(void) -{ - return register_device(&omap3evm_serial_device); -} -console_initcall(omap3evm_init_console); -#endif /* CONFIG_DRIVER_SERIAL_NS16550 */ - -static struct memory_platform_data sram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0x80000000, - .size = 128 * 1024 * 1024, - .platform_data = &sram_pdata, -}; - -static int omap3evm_init_devices(void) -{ - int ret; - - ret = register_device(&sdram_dev); - if (ret) - goto failed; - -#ifdef CONFIG_GPMC - /* - * WP is made high and WAIT1 active Low - */ - gpmc_generic_init(0x10); -#endif - - armlinux_add_dram(&sdram_dev); - -failed: - return ret; -} -device_initcall(omap3evm_init_devices); diff --git a/board/omap/board-sdp343x.c b/board/omap/board-sdp343x.c deleted file mode 100644 index fe95fc0..0000000 --- a/board/omap/board-sdp343x.c +++ /dev/null @@ -1,672 +0,0 @@ -/* - * (C) Copyright 2006-2008 - * Texas Instruments, - * Nishanth Menon - * - * 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 - */ - -/** - * @file - * @brief SDP3430 Specific Board Initialization routines - */ - -/** - * @page ti_SDP3430 Texas Instruments SDP3430 - * - * FileName: board/omap/board-sdp343x.c - * - * SDP3430 from Texas Instruments as described here: - * http://www.ti.com/omap3430_devplatform - * This file provides initialization in two stages: - * @li boot time initialization - do basics required to get SDRAM working. - * This is run from SRAM - so no case constructs and global vars can be used. - * @li run time initialization - this is for the rest of the initializations - * such as flash, uart etc. - * - * Boot time initialization includes: - * @li SDRAM initialization. - * @li Pin Muxing relevant for SDP3430. - * - * Run time initialization includes - * @li serial @ref serial_ns16550.c driver device definition - * - * Originally from http://linux.omap.com/pub/bootloader/3430sdp/u-boot-v1.tar.gz - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "board.h" - -/******************** Board Boot Time *******************/ -static void sdrc_init(void); -static void mux_config(void); - -/** - * @brief The basic entry point for board initialization. - * - * This is called as part of machine init (after arch init). - * This is again called with stack in SRAM, so not too many - * constructs possible here. - * - * @return void - */ -void board_init(void) -{ - int in_sdram = running_in_sdram(); - mux_config(); - if (!in_sdram) - sdrc_init(); -} - -/** - * @brief Do the SDRC initialization for 128Meg Infenion DDR for CS0 - * - * @return void - */ -static void sdrc_init(void) -{ - /* Issue SDRC Soft reset */ - writel(0x12, SDRC_REG(SYSCONFIG)); - /* Wait until Reset complete */ - while ((readl(SDRC_REG(STATUS)) & 0x1) == 0); - /* SDRC to normal mode */ - writel(0x10, SDRC_REG(SYSCONFIG)); - /* SDRC Sharing register */ - /* 32-bit SDRAM on data lane [31:0] - CS0 */ - /* pin tri-stated = 1 */ - writel(0x00000100, SDRC_REG(SHARING)); - - /* ----- SDRC_REG(CS0 Configuration --------- */ - /* SDRC_REG(MCFG0 register */ - writel(0x02584019, SDRC_REG(MCFG_0)); - - /* SDRC_REG(RFR_CTRL0 register */ - writel(0x0003DE01, SDRC_REG(RFR_CTRL_0)); - - /* SDRC_REG(ACTIM_CTRLA0 register */ - writel(0X5A9A4486, SDRC_REG(ACTIM_CTRLA_0)); - - /* SDRC_REG(ACTIM_CTRLB0 register */ - writel(0x00000010, SDRC_REG(ACTIM_CTRLB_0)); - - /* Disble Power Down of CKE cuz of 1 CKE on combo part */ - writel(0x00000081, SDRC_REG(POWER)); - - /* SDRC_REG(Manual command register */ - /* NOP command */ - writel(0x00000000, SDRC_REG(MANUAL_0)); - /* Precharge command */ - writel(0x00000001, SDRC_REG(MANUAL_0)); - /* Auto-refresh command */ - writel(0x00000002, SDRC_REG(MANUAL_0)); - /* Auto-refresh command */ - writel(0x00000002, SDRC_REG(MANUAL_0)); - - /* SDRC MR0 register */ - /* CAS latency = 3 */ - /* Write Burst = Read Burst */ - /* Serial Mode */ - writel(0x00000032, SDRC_REG(MR_0)); /* Burst length =4 */ - - /* SDRC DLLA control register */ - /* Enable DLL A */ - writel(0x0000000A, SDRC_REG(DLLA_CTRL)); - - /* wait until DLL is locked */ - while ((readl(SDRC_REG(DLLA_STATUS)) & 0x4) == 0); - return; -} - -/** - * @brief Do the pin muxing required for Board operation. - * - * See @ref MUX_VAL for description of the muxing mode. Since some versions - * of Linux depend on all pin muxing being done at barebox level, we may need to - * enable CONFIG_MACH_OMAP_ADVANCED_MUX to enable the full fledged pin muxing. - * - * @return void - */ -static void mux_config(void) -{ - /* Essential MUX Settings */ - MUX_VAL(CP(SDRC_D0), (IEN | PTD | DIS | M0)); /* SDRC_D0 */ - MUX_VAL(CP(SDRC_D1), (IEN | PTD | DIS | M0)); /* SDRC_D1 */ - MUX_VAL(CP(SDRC_D2), (IEN | PTD | DIS | M0)); /* SDRC_D2 */ - MUX_VAL(CP(SDRC_D3), (IEN | PTD | DIS | M0)); /* SDRC_D3 */ - MUX_VAL(CP(SDRC_D4), (IEN | PTD | DIS | M0)); /* SDRC_D4 */ - MUX_VAL(CP(SDRC_D5), (IEN | PTD | DIS | M0)); /* SDRC_D5 */ - MUX_VAL(CP(SDRC_D6), (IEN | PTD | DIS | M0)); /* SDRC_D6 */ - MUX_VAL(CP(SDRC_D7), (IEN | PTD | DIS | M0)); /* SDRC_D7 */ - MUX_VAL(CP(SDRC_D8), (IEN | PTD | DIS | M0)); /* SDRC_D8 */ - MUX_VAL(CP(SDRC_D9), (IEN | PTD | DIS | M0)); /* SDRC_D9 */ - MUX_VAL(CP(SDRC_D10), (IEN | PTD | DIS | M0)); /* SDRC_D10 */ - MUX_VAL(CP(SDRC_D11), (IEN | PTD | DIS | M0)); /* SDRC_D11 */ - MUX_VAL(CP(SDRC_D12), (IEN | PTD | DIS | M0)); /* SDRC_D12 */ - MUX_VAL(CP(SDRC_D13), (IEN | PTD | DIS | M0)); /* SDRC_D13 */ - MUX_VAL(CP(SDRC_D14), (IEN | PTD | DIS | M0)); /* SDRC_D14 */ - MUX_VAL(CP(SDRC_D15), (IEN | PTD | DIS | M0)); /* SDRC_D15 */ - MUX_VAL(CP(SDRC_D16), (IEN | PTD | DIS | M0)); /* SDRC_D16 */ - MUX_VAL(CP(SDRC_D17), (IEN | PTD | DIS | M0)); /* SDRC_D17 */ - MUX_VAL(CP(SDRC_D18), (IEN | PTD | DIS | M0)); /* SDRC_D18 */ - MUX_VAL(CP(SDRC_D19), (IEN | PTD | DIS | M0)); /* SDRC_D19 */ - MUX_VAL(CP(SDRC_D20), (IEN | PTD | DIS | M0)); /* SDRC_D20 */ - MUX_VAL(CP(SDRC_D21), (IEN | PTD | DIS | M0)); /* SDRC_D21 */ - MUX_VAL(CP(SDRC_D22), (IEN | PTD | DIS | M0)); /* SDRC_D22 */ - MUX_VAL(CP(SDRC_D23), (IEN | PTD | DIS | M0)); /* SDRC_D23 */ - MUX_VAL(CP(SDRC_D24), (IEN | PTD | DIS | M0)); /* SDRC_D24 */ - MUX_VAL(CP(SDRC_D25), (IEN | PTD | DIS | M0)); /* SDRC_D25 */ - MUX_VAL(CP(SDRC_D26), (IEN | PTD | DIS | M0)); /* SDRC_D26 */ - MUX_VAL(CP(SDRC_D27), (IEN | PTD | DIS | M0)); /* SDRC_D27 */ - MUX_VAL(CP(SDRC_D28), (IEN | PTD | DIS | M0)); /* SDRC_D28 */ - MUX_VAL(CP(SDRC_D29), (IEN | PTD | DIS | M0)); /* SDRC_D29 */ - MUX_VAL(CP(SDRC_D30), (IEN | PTD | DIS | M0)); /* SDRC_D30 */ - MUX_VAL(CP(SDRC_D31), (IEN | PTD | DIS | M0)); /* SDRC_D31 */ - MUX_VAL(CP(SDRC_CLK), (IEN | PTD | DIS | M0)); /* SDRC_CLK */ - MUX_VAL(CP(SDRC_DQS0), (IEN | PTD | DIS | M0)); /* SDRC_DQS0 */ - MUX_VAL(CP(SDRC_DQS1), (IEN | PTD | DIS | M0)); /* SDRC_DQS1 */ - MUX_VAL(CP(SDRC_DQS2), (IEN | PTD | DIS | M0)); /* SDRC_DQS2 */ - MUX_VAL(CP(SDRC_DQS3), (IEN | PTD | DIS | M0)); /* SDRC_DQS3 */ - /* GPMC */ - MUX_VAL(CP(GPMC_A1), (IDIS | PTD | DIS | M0)); /* GPMC_A1 */ - MUX_VAL(CP(GPMC_A2), (IDIS | PTD | DIS | M0)); /* GPMC_A2 */ - MUX_VAL(CP(GPMC_A3), (IDIS | PTD | DIS | M0)); /* GPMC_A3 */ - MUX_VAL(CP(GPMC_A4), (IDIS | PTD | DIS | M0)); /* GPMC_A4 */ - MUX_VAL(CP(GPMC_A5), (IDIS | PTD | DIS | M0)); /* GPMC_A5 */ - MUX_VAL(CP(GPMC_A6), (IDIS | PTD | DIS | M0)); /* GPMC_A6 */ - MUX_VAL(CP(GPMC_A7), (IDIS | PTD | DIS | M0)); /* GPMC_A7 */ - MUX_VAL(CP(GPMC_A8), (IDIS | PTD | DIS | M0)); /* GPMC_A8 */ - MUX_VAL(CP(GPMC_A9), (IDIS | PTD | DIS | M0)); /* GPMC_A9 */ - MUX_VAL(CP(GPMC_A10), (IDIS | PTD | DIS | M0)); /* GPMC_A10 */ - MUX_VAL(CP(GPMC_D0), (IEN | PTD | DIS | M0)); /* GPMC_D0 */ - MUX_VAL(CP(GPMC_D1), (IEN | PTD | DIS | M0)); /* GPMC_D1 */ - MUX_VAL(CP(GPMC_D2), (IEN | PTD | DIS | M0)); /* GPMC_D2 */ - MUX_VAL(CP(GPMC_D3), (IEN | PTD | DIS | M0)); /* GPMC_D3 */ - MUX_VAL(CP(GPMC_D4), (IEN | PTD | DIS | M0)); /* GPMC_D4 */ - MUX_VAL(CP(GPMC_D5), (IEN | PTD | DIS | M0)); /* GPMC_D5 */ - MUX_VAL(CP(GPMC_D6), (IEN | PTD | DIS | M0)); /* GPMC_D6 */ - MUX_VAL(CP(GPMC_D7), (IEN | PTD | DIS | M0)); /* GPMC_D7 */ - MUX_VAL(CP(GPMC_D8), (IEN | PTD | DIS | M0)); /* GPMC_D8 */ - MUX_VAL(CP(GPMC_D9), (IEN | PTD | DIS | M0)); /* GPMC_D9 */ - MUX_VAL(CP(GPMC_D10), (IEN | PTD | DIS | M0)); /* GPMC_D10 */ - MUX_VAL(CP(GPMC_D11), (IEN | PTD | DIS | M0)); /* GPMC_D11 */ - MUX_VAL(CP(GPMC_D12), (IEN | PTD | DIS | M0)); /* GPMC_D12 */ - MUX_VAL(CP(GPMC_D13), (IEN | PTD | DIS | M0)); /* GPMC_D13 */ - MUX_VAL(CP(GPMC_D14), (IEN | PTD | DIS | M0)); /* GPMC_D14 */ - MUX_VAL(CP(GPMC_D15), (IEN | PTD | DIS | M0)); /* GPMC_D15 */ - MUX_VAL(CP(GPMC_NCS0), (IDIS | PTU | EN | M0)); /* GPMC_NCS0 */ - MUX_VAL(CP(GPMC_NCS1), (IDIS | PTU | EN | M0)); /* GPMC_NCS1 */ - MUX_VAL(CP(GPMC_NCS2), (IDIS | PTU | EN | M0)); /* GPMC_NCS2 */ - MUX_VAL(CP(GPMC_NCS3), (IDIS | PTU | EN | M0)); /* GPMC_NCS3 */ - /* GPIO_55 - FLASH_DIS */ - MUX_VAL(CP(GPMC_NCS4), (IEN | PTU | EN | M4)); - /* GPIO_56 - TORCH_EN */ - MUX_VAL(CP(GPMC_NCS5), (IDIS | PTD | DIS | M4)); - /* GPIO_57 - AGPS SLP */ - MUX_VAL(CP(GPMC_NCS6), (IEN | PTD | DIS | M4)); - /* GPMC_58 - WLAN_IRQ */ - MUX_VAL(CP(GPMC_NCS7), (IEN | PTU | EN | M4)); - MUX_VAL(CP(GPMC_CLK), (IDIS | PTD | DIS | M0)); /* GPMC_CLK */ - /* GPMC_NADV_ALE */ - MUX_VAL(CP(GPMC_NADV_ALE), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_NOE), (IDIS | PTD | DIS | M0)); /* GPMC_NOE */ - MUX_VAL(CP(GPMC_NWE), (IDIS | PTD | DIS | M0)); /* GPMC_NWE */ - /* GPMC_NBE0_CLE */ - MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(GPMC_NBE1), (IEN | PTD | DIS | M4)); /* GPIO_61 -BT_SHUTDN */ - MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); /* GPMC_NWP */ - MUX_VAL(CP(GPMC_WAIT0), (IEN | PTU | EN | M0)); /* GPMC_WAIT0 */ - MUX_VAL(CP(GPMC_WAIT1), (IEN | PTU | EN | M0)); /* GPMC_WAIT1 */ - MUX_VAL(CP(GPMC_WAIT2), (IEN | PTU | EN | M4)); /* GPIO_64 */ - MUX_VAL(CP(GPMC_WAIT3), (IEN | PTU | EN | M4)); /* GPIO_65 */ - - /* SERIAL INTERFACE */ - /* UART3_CTS_RCTX */ - MUX_VAL(CP(UART3_CTS_RCTX), (IEN | PTD | EN | M0)); - /* UART3_RTS_SD */ - MUX_VAL(CP(UART3_RTS_SD), (IDIS | PTD | DIS | M0)); - /* UART3_RX_IRRX */ - MUX_VAL(CP(UART3_RX_IRRX), (IEN | PTD | DIS | M0)); - /* UART3_TX_IRTX */ - MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); - /* HSUSB0_CLK */ - MUX_VAL(CP(HSUSB0_CLK), (IEN | PTD | DIS | M0)); - /* HSUSB0_STP */ - MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN | M0)); - /* HSUSB0_DIR */ - MUX_VAL(CP(HSUSB0_DIR), (IEN | PTD | DIS | M0)); - /* HSUSB0_NXT */ - MUX_VAL(CP(HSUSB0_NXT), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA0 */ - MUX_VAL(CP(HSUSB0_DATA0), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA1 */ - MUX_VAL(CP(HSUSB0_DATA1), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA2 */ - MUX_VAL(CP(HSUSB0_DATA2), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA3 */ - MUX_VAL(CP(HSUSB0_DATA3), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA4 */ - MUX_VAL(CP(HSUSB0_DATA4), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA5 */ - MUX_VAL(CP(HSUSB0_DATA5), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA6 */ - MUX_VAL(CP(HSUSB0_DATA6), (IEN | PTD | DIS | M0)); - /* HSUSB0_DATA7 */ - MUX_VAL(CP(HSUSB0_DATA7), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(I2C1_SCL), (IEN | PTU | EN | M0)); /* I2C1_SCL */ - MUX_VAL(CP(I2C1_SDA), (IEN | PTU | EN | M0)); /* I2C1_SDA */ -#ifdef CONFIG_MACH_OMAP_ADVANCED_MUX - /* DSS */ - MUX_VAL(CP(DSS_PCLK), (IDIS | PTD | DIS | M0)); /* DSS_PCLK */ - MUX_VAL(CP(DSS_HSYNC), (IDIS | PTD | DIS | M0)); /* DSS_HSYNC */ - MUX_VAL(CP(DSS_VSYNC), (IDIS | PTD | DIS | M0)); /* DSS_VSYNC */ - MUX_VAL(CP(DSS_ACBIAS), (IDIS | PTD | DIS | M0)); /* DSS_ACBIAS */ - MUX_VAL(CP(DSS_DATA0), (IDIS | PTD | DIS | M0)); /* DSS_DATA0 */ - MUX_VAL(CP(DSS_DATA1), (IDIS | PTD | DIS | M0)); /* DSS_DATA1 */ - MUX_VAL(CP(DSS_DATA2), (IDIS | PTD | DIS | M0)); /* DSS_DATA2 */ - MUX_VAL(CP(DSS_DATA3), (IDIS | PTD | DIS | M0)); /* DSS_DATA3 */ - MUX_VAL(CP(DSS_DATA4), (IDIS | PTD | DIS | M0)); /* DSS_DATA4 */ - MUX_VAL(CP(DSS_DATA5), (IDIS | PTD | DIS | M0)); /* DSS_DATA5 */ - MUX_VAL(CP(DSS_DATA6), (IDIS | PTD | DIS | M0)); /* DSS_DATA6 */ - MUX_VAL(CP(DSS_DATA7), (IDIS | PTD | DIS | M0)); /* DSS_DATA7 */ - MUX_VAL(CP(DSS_DATA8), (IDIS | PTD | DIS | M0)); /* DSS_DATA8 */ - MUX_VAL(CP(DSS_DATA9), (IDIS | PTD | DIS | M0)); /* DSS_DATA9 */ - MUX_VAL(CP(DSS_DATA10), (IDIS | PTD | DIS | M0)); /* DSS_DATA10 */ - MUX_VAL(CP(DSS_DATA11), (IDIS | PTD | DIS | M0)); /* DSS_DATA11 */ - MUX_VAL(CP(DSS_DATA12), (IDIS | PTD | DIS | M0)); /* DSS_DATA12 */ - MUX_VAL(CP(DSS_DATA13), (IDIS | PTD | DIS | M0)); /* DSS_DATA13 */ - MUX_VAL(CP(DSS_DATA14), (IDIS | PTD | DIS | M0)); /* DSS_DATA14 */ - MUX_VAL(CP(DSS_DATA15), (IDIS | PTD | DIS | M0)); /* DSS_DATA15 */ - MUX_VAL(CP(DSS_DATA16), (IDIS | PTD | DIS | M0)); /* DSS_DATA16 */ - MUX_VAL(CP(DSS_DATA17), (IDIS | PTD | DIS | M0)); /* DSS_DATA17 */ - MUX_VAL(CP(DSS_DATA18), (IDIS | PTD | DIS | M0)); /* DSS_DATA18 */ - MUX_VAL(CP(DSS_DATA19), (IDIS | PTD | DIS | M0)); /* DSS_DATA19 */ - MUX_VAL(CP(DSS_DATA20), (IDIS | PTD | DIS | M0)); /* DSS_DATA20 */ - MUX_VAL(CP(DSS_DATA21), (IDIS | PTD | DIS | M0)); /* DSS_DATA21 */ - MUX_VAL(CP(DSS_DATA22), (IDIS | PTD | DIS | M0)); /* DSS_DATA22 */ - MUX_VAL(CP(DSS_DATA23), (IDIS | PTD | DIS | M0)); /* DSS_DATA23 */ - /* CAMERA */ - MUX_VAL(CP(CAM_HS), (IEN | PTU | EN | M0)); /* CAM_HS */ - MUX_VAL(CP(CAM_VS), (IEN | PTU | EN | M0)); /* CAM_VS */ - MUX_VAL(CP(CAM_XCLKA), (IDIS | PTD | DIS | M0)); /* CAM_XCLKA */ - MUX_VAL(CP(CAM_PCLK), (IEN | PTU | EN | M0)); /* CAM_PCLK */ - /* GPIO_98 - CAM_RESET */ - MUX_VAL(CP(CAM_FLD), (IDIS | PTD | DIS | M4)); - MUX_VAL(CP(CAM_D0), (IEN | PTD | DIS | M0)); /* CAM_D0 */ - MUX_VAL(CP(CAM_D1), (IEN | PTD | DIS | M0)); /* CAM_D1 */ - MUX_VAL(CP(CAM_D2), (IEN | PTD | DIS | M0)); /* CAM_D2 */ - MUX_VAL(CP(CAM_D3), (IEN | PTD | DIS | M0)); /* CAM_D3 */ - MUX_VAL(CP(CAM_D4), (IEN | PTD | DIS | M0)); /* CAM_D4 */ - MUX_VAL(CP(CAM_D5), (IEN | PTD | DIS | M0)); /* CAM_D5 */ - MUX_VAL(CP(CAM_D6), (IEN | PTD | DIS | M0)); /* CAM_D6 */ - MUX_VAL(CP(CAM_D7), (IEN | PTD | DIS | M0)); /* CAM_D7 */ - MUX_VAL(CP(CAM_D8), (IEN | PTD | DIS | M0)); /* CAM_D8 */ - MUX_VAL(CP(CAM_D9), (IEN | PTD | DIS | M0)); /* CAM_D9 */ - MUX_VAL(CP(CAM_D10), (IEN | PTD | DIS | M0)); /* CAM_D10 */ - MUX_VAL(CP(CAM_D11), (IEN | PTD | DIS | M0)); /* CAM_D11 */ - MUX_VAL(CP(CAM_XCLKB), (IDIS | PTD | DIS | M0)); /* CAM_XCLKB */ - MUX_VAL(CP(CAM_WEN), (IEN | PTD | DIS | M4)); /* GPIO_167 */ - MUX_VAL(CP(CAM_STROBE), (IDIS | PTD | DIS | M0)); /* CAM_STROBE */ - MUX_VAL(CP(CSI2_DX0), (IEN | PTD | DIS | M0)); /* CSI2_DX0 */ - MUX_VAL(CP(CSI2_DY0), (IEN | PTD | DIS | M0)); /* CSI2_DY0 */ - MUX_VAL(CP(CSI2_DX1), (IEN | PTD | DIS | M0)); /* CSI2_DX1 */ - MUX_VAL(CP(CSI2_DY1), (IEN | PTD | DIS | M0)); /* CSI2_DY1 */ - /* AUDIO INTERFACE */ - MUX_VAL(CP(MCBSP2_FSX), (IEN | PTD | DIS | M0)); /* MCBSP2_FSX */ - /* MCBSP2_CLKX */ - MUX_VAL(CP(MCBSP2_CLKX), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(MCBSP2_DR), (IEN | PTD | DIS | M0)); /* MCBSP2_DR */ - MUX_VAL(CP(MCBSP2_DX), (IDIS | PTD | DIS | M0)); /* MCBSP2_DX */ - /* EXPANSION CARD */ - MUX_VAL(CP(MMC1_CLK), (IDIS | PTU | EN | M0)); /* MMC1_CLK */ - MUX_VAL(CP(MMC1_CMD), (IEN | PTU | EN | M0)); /* MMC1_CMD */ - MUX_VAL(CP(MMC1_DAT0), (IEN | PTU | EN | M0)); /* MMC1_DAT0 */ - MUX_VAL(CP(MMC1_DAT1), (IEN | PTU | EN | M0)); /* MMC1_DAT1 */ - MUX_VAL(CP(MMC1_DAT2), (IEN | PTU | EN | M0)); /* MMC1_DAT2 */ - MUX_VAL(CP(MMC1_DAT3), (IEN | PTU | EN | M0)); /* MMC1_DAT3 */ - MUX_VAL(CP(MMC1_DAT4), (IEN | PTU | EN | M0)); /* MMC1_DAT4 */ - MUX_VAL(CP(MMC1_DAT5), (IEN | PTU | EN | M0)); /* MMC1_DAT5 */ - MUX_VAL(CP(MMC1_DAT6), (IEN | PTU | EN | M0)); /* MMC1_DAT6 */ - MUX_VAL(CP(MMC1_DAT7), (IEN | PTU | EN | M0)); /* MMC1_DAT7 */ - /* WIRELESS LAN */ - MUX_VAL(CP(MMC2_CLK), (IEN | PTD | DIS | M0)); /* MMC2_CLK */ - MUX_VAL(CP(MMC2_CMD), (IEN | PTU | EN | M0)); /* MMC2_CMD */ - MUX_VAL(CP(MMC2_DAT0), (IEN | PTU | EN | M0)); /* MMC2_DAT0 */ - MUX_VAL(CP(MMC2_DAT1), (IEN | PTU | EN | M0)); /* MMC2_DAT1 */ - MUX_VAL(CP(MMC2_DAT2), (IEN | PTU | EN | M0)); /* MMC2_DAT2 */ - MUX_VAL(CP(MMC2_DAT3), (IEN | PTU | EN | M0)); /* MMC2_DAT3 */ - /* MMC2_DIR_DAT0 */ - MUX_VAL(CP(MMC2_DAT4), (IDIS | PTD | DIS | M1)); - /* MMC2_DIR_DAT1 */ - MUX_VAL(CP(MMC2_DAT5), (IDIS | PTD | DIS | M1)); - /* MMC2_DIR_CMD */ - MUX_VAL(CP(MMC2_DAT6), (IDIS | PTD | DIS | M1)); - /* MMC2_CLKIN */ - MUX_VAL(CP(MMC2_DAT7), (IEN | PTU | EN | M1)); - /* BLUETOOTH */ - /* MCBSP3_DX */ - MUX_VAL(CP(MCBSP3_DX), (IDIS | PTD | DIS | M0)); - /* MCBSP3_DR */ - MUX_VAL(CP(MCBSP3_DR), (IEN | PTD | DIS | M0)); - /* MCBSP3_CLKX */ - MUX_VAL(CP(MCBSP3_CLKX), (IEN | PTD | DIS | M0)); - /* MCBSP3_FSX */ - MUX_VAL(CP(MCBSP3_FSX), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(UART2_CTS), (IEN | PTU | EN | M0)); /* UART2_CTS */ - MUX_VAL(CP(UART2_RTS), (IDIS | PTD | DIS | M0)); /* UART2_RTS */ - MUX_VAL(CP(UART2_TX), (IDIS | PTD | DIS | M0)); /* UART2_TX */ - MUX_VAL(CP(UART2_RX), (IEN | PTD | DIS | M0)); /* UART2_RX */ - /* MODEM INTERFACE */ - MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)); /* UART1_TX */ - MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)); /* UART1_RTS */ - MUX_VAL(CP(UART1_CTS), (IEN | PTU | DIS | M0)); /* UART1_CTS */ - MUX_VAL(CP(UART1_RX), (IEN | PTD | DIS | M0)); /* UART1_RX */ - /* SSI1_DAT_RX */ - MUX_VAL(CP(MCBSP4_CLKX), (IEN | PTD | DIS | M1)); - MUX_VAL(CP(MCBSP4_DR), (IEN | PTD | DIS | M1)); /* SSI1_FLAG_RX */ - MUX_VAL(CP(MCBSP4_DX), (IEN | PTD | DIS | M1)); /* SSI1_RDY_RX */ - MUX_VAL(CP(MCBSP4_FSX), (IEN | PTD | DIS | M1)); /* SSI1_WAKE */ - /* MCBSP1_CLKR */ - MUX_VAL(CP(MCBSP1_CLKR), (IEN | PTD | DIS | M0)); - /* GPIO_157 - BT_WKUP */ - MUX_VAL(CP(MCBSP1_FSR), (IDIS | PTU | EN | M4)); - /* MCBSP1_DX */ - MUX_VAL(CP(MCBSP1_DX), (IDIS | PTD | DIS | M0)); - MUX_VAL(CP(MCBSP1_DR), (IEN | PTD | DIS | M0)); /* MCBSP1_DR */ - /* MCBSP_CLKS */ - MUX_VAL(CP(MCBSP_CLKS), (IEN | PTU | DIS | M0)); - /* MCBSP1_FSX */ - MUX_VAL(CP(MCBSP1_FSX), (IEN | PTD | DIS | M0)); - /* MCBSP1_CLKX */ - MUX_VAL(CP(MCBSP1_CLKX), (IEN | PTD | DIS | M0)); - /* SERIAL INTERFACE */ - MUX_VAL(CP(I2C2_SCL), (IEN | PTU | EN | M0)); /* I2C2_SCL */ - MUX_VAL(CP(I2C2_SDA), (IEN | PTU | EN | M0)); /* I2C2_SDA */ - MUX_VAL(CP(I2C3_SCL), (IEN | PTU | EN | M0)); /* I2C3_SCL */ - MUX_VAL(CP(I2C3_SDA), (IEN | PTU | EN | M0)); /* I2C3_SDA */ - MUX_VAL(CP(I2C4_SCL), (IEN | PTU | EN | M0)); /* I2C4_SCL */ - MUX_VAL(CP(I2C4_SDA), (IEN | PTU | EN | M0)); /* I2C4_SDA */ - MUX_VAL(CP(HDQ_SIO), (IEN | PTU | EN | M0)); /* HDQ_SIO */ - /* MCSPI1_CLK */ - MUX_VAL(CP(MCSPI1_CLK), (IEN | PTD | DIS | M0)); - /* MCSPI1_SIMO */ - MUX_VAL(CP(MCSPI1_SIMO), (IEN | PTD | DIS | M0)); - /* MCSPI1_SOMI */ - MUX_VAL(CP(MCSPI1_SOMI), (IEN | PTD | DIS | M0)); - /* MCSPI1_CS0 */ - MUX_VAL(CP(MCSPI1_CS0), (IEN | PTD | EN | M0)); - /* MCSPI1_CS1 */ - MUX_VAL(CP(MCSPI1_CS1), (IDIS | PTD | EN | M0)); - /* GPIO_176-NOR_DPD */ - MUX_VAL(CP(MCSPI1_CS2), (IDIS | PTD | DIS | M4)); - /* MCSPI1_CS3 */ - MUX_VAL(CP(MCSPI1_CS3), (IEN | PTD | EN | M0)); - /* MCSPI2_CLK */ - MUX_VAL(CP(MCSPI2_CLK), (IEN | PTD | DIS | M0)); - /* MCSPI2_SIMO */ - MUX_VAL(CP(MCSPI2_SIMO), (IEN | PTD | DIS | M0)); - /* MCSPI2_SOMI */ - MUX_VAL(CP(MCSPI2_SOMI), (IEN | PTD | DIS | M0)); - /* MCSPI2_CS0 */ - MUX_VAL(CP(MCSPI2_CS0), (IEN | PTD | EN | M0)); - /* MCSPI2_CS1 */ - MUX_VAL(CP(MCSPI2_CS1), (IEN | PTD | EN | M0)); - - /* CONTROL AND DEBUG */ - MUX_VAL(CP(SYS_32K), (IEN | PTD | DIS | M0)); /* SYS_32K */ - MUX_VAL(CP(SYS_CLKREQ), (IEN | PTD | DIS | M0)); /* SYS_CLKREQ */ - MUX_VAL(CP(SYS_NIRQ), (IEN | PTU | EN | M0)); /* SYS_NIRQ */ - MUX_VAL(CP(SYS_BOOT0), (IEN | PTD | DIS | M4)); /* GPIO_2 - PEN_IRQ */ - MUX_VAL(CP(SYS_BOOT1), (IEN | PTD | DIS | M4)); /* GPIO_3 */ - MUX_VAL(CP(SYS_BOOT2), (IEN | PTD | DIS | M4)); /* GPIO_4 - MMC1_WP */ - MUX_VAL(CP(SYS_BOOT3), (IEN | PTD | DIS | M4)); /* GPIO_5 - LCD_ENVDD */ - MUX_VAL(CP(SYS_BOOT4), (IEN | PTD | DIS | M4)); /* GPIO_6 - LAN_INTR0 */ - MUX_VAL(CP(SYS_BOOT5), (IEN | PTD | DIS | M4)); /* GPIO_7 - MMC2_WP */ - /* GPIO_8-LCD_ENBKL */ - MUX_VAL(CP(SYS_BOOT6), (IDIS | PTD | DIS | M4)); - /* SYS_OFF_MODE */ - MUX_VAL(CP(SYS_OFF_MODE), (IEN | PTD | DIS | M0)); - /* SYS_CLKOUT1 */ - MUX_VAL(CP(SYS_CLKOUT1), (IEN | PTD | DIS | M0)); - MUX_VAL(CP(SYS_CLKOUT2), (IEN | PTU | EN | M4)); /* GPIO_186 */ - MUX_VAL(CP(JTAG_NTRST), (IEN | PTD | DIS | M0)); /* JTAG_NTRST */ - MUX_VAL(CP(JTAG_TCK), (IEN | PTD | DIS | M0)); /* JTAG_TCK */ - MUX_VAL(CP(JTAG_TMS), (IEN | PTD | DIS | M0)); /* JTAG_TMS */ - MUX_VAL(CP(JTAG_TDI), (IEN | PTD | DIS | M0)); /* JTAG_TDI */ - MUX_VAL(CP(JTAG_EMU0), (IEN | PTD | DIS | M0)); /* JTAG_EMU0 */ - MUX_VAL(CP(JTAG_EMU1), (IEN | PTD | DIS | M0)); /* JTAG_EMU1 */ - /* HSUSB1_TLL_STP */ - MUX_VAL(CP(ETK_CLK_ES2), (IDIS | PTU | EN | M0)); - /* HSUSB1_TLL_CLK */ - MUX_VAL(CP(ETK_CTL_ES2), (IDIS | PTD | DIS | M0)); - /* HSUSB1_TLL_DATA0 */ - MUX_VAL(CP(ETK_D0_ES2), (IEN | PTD | DIS | M1)); - /* MCSPI3_CS0 */ - MUX_VAL(CP(ETK_D1_ES2), (IEN | PTD | DIS | M1)); - /* HSUSB1_TLL_DATA2 */ - MUX_VAL(CP(ETK_D2_ES2), (IEN | PTD | EN | M1)); - /* HSUSB1_TLL_DATA7 */ - MUX_VAL(CP(ETK_D3_ES2), (IEN | PTD | DIS | M1)); - /* HSUSB1_TLL_DATA4 */ - MUX_VAL(CP(ETK_D4_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB1_TLL_DATA5 */ - MUX_VAL(CP(ETK_D5_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB1_TLL_DATA6 */ - MUX_VAL(CP(ETK_D6_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB1_TLL_DATA3 */ - MUX_VAL(CP(ETK_D7_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB1_TLL_DIR */ - MUX_VAL(CP(ETK_D8_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB1_TLL_NXT */ - MUX_VAL(CP(ETK_D9_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB2_TLL_CLK */ - MUX_VAL(CP(ETK_D10_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB2_TLL_STP */ - MUX_VAL(CP(ETK_D11_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB2_TLL_DIR */ - MUX_VAL(CP(ETK_D12_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB2_TLL_NXT */ - MUX_VAL(CP(ETK_D13_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB2_TLL_DATA0 */ - MUX_VAL(CP(ETK_D14_ES2), (IEN | PTD | DIS | M0)); - /* HSUSB2_TLL_DATA1 */ - MUX_VAL(CP(ETK_D15_ES2), (IEN | PTD | DIS | M0)); - - /* DIE TO DIE */ - MUX_VAL(CP(D2D_MCAD0), (IEN | PTD | EN | M0)); /* D2D_MCAD0 */ - MUX_VAL(CP(D2D_MCAD1), (IEN | PTD | EN | M0)); /* D2D_MCAD1 */ - MUX_VAL(CP(D2D_MCAD2), (IEN | PTD | EN | M0)); /* D2D_MCAD2 */ - MUX_VAL(CP(D2D_MCAD3), (IEN | PTD | EN | M0)); /* D2D_MCAD3 */ - MUX_VAL(CP(D2D_MCAD4), (IEN | PTD | EN | M0)); /* D2D_MCAD4 */ - MUX_VAL(CP(D2D_MCAD5), (IEN | PTD | EN | M0)); /* D2D_MCAD5 */ - MUX_VAL(CP(D2D_MCAD6), (IEN | PTD | EN | M0)); /* D2D_MCAD6 */ - MUX_VAL(CP(D2D_MCAD7), (IEN | PTD | EN | M0)); /* D2D_MCAD7 */ - MUX_VAL(CP(D2D_MCAD8), (IEN | PTD | EN | M0)); /* D2D_MCAD8 */ - MUX_VAL(CP(D2D_MCAD9), (IEN | PTD | EN | M0)); /* D2D_MCAD9 */ - MUX_VAL(CP(D2D_MCAD10), (IEN | PTD | EN | M0)); /* D2D_MCAD10 */ - MUX_VAL(CP(D2D_MCAD11), (IEN | PTD | EN | M0)); /* D2D_MCAD11 */ - MUX_VAL(CP(D2D_MCAD12), (IEN | PTD | EN | M0)); /* D2D_MCAD12 */ - MUX_VAL(CP(D2D_MCAD13), (IEN | PTD | EN | M0)); /* D2D_MCAD13 */ - MUX_VAL(CP(D2D_MCAD14), (IEN | PTD | EN | M0)); /* D2D_MCAD14 */ - MUX_VAL(CP(D2D_MCAD15), (IEN | PTD | EN | M0)); /* D2D_MCAD15 */ - MUX_VAL(CP(D2D_MCAD16), (IEN | PTD | EN | M0)); /* D2D_MCAD16 */ - MUX_VAL(CP(D2D_MCAD17), (IEN | PTD | EN | M0)); /* D2D_MCAD17 */ - MUX_VAL(CP(D2D_MCAD18), (IEN | PTD | EN | M0)); /* D2D_MCAD18 */ - MUX_VAL(CP(D2D_MCAD19), (IEN | PTD | EN | M0)); /* D2D_MCAD19 */ - MUX_VAL(CP(D2D_MCAD20), (IEN | PTD | EN | M0)); /* D2D_MCAD20 */ - MUX_VAL(CP(D2D_MCAD21), (IEN | PTD | EN | M0)); /* D2D_MCAD21 */ - MUX_VAL(CP(D2D_MCAD22), (IEN | PTD | EN | M0)); /* D2D_MCAD22 */ - MUX_VAL(CP(D2D_MCAD23), (IEN | PTD | EN | M0)); /* D2D_MCAD23 */ - MUX_VAL(CP(D2D_MCAD24), (IEN | PTD | EN | M0)); /* D2D_MCAD24 */ - MUX_VAL(CP(D2D_MCAD25), (IEN | PTD | EN | M0)); /* D2D_MCAD25 */ - MUX_VAL(CP(D2D_MCAD26), (IEN | PTD | EN | M0)); /* D2D_MCAD26 */ - MUX_VAL(CP(D2D_MCAD27), (IEN | PTD | EN | M0)); /* D2D_MCAD27 */ - MUX_VAL(CP(D2D_MCAD28), (IEN | PTD | EN | M0)); /* D2D_MCAD28 */ - MUX_VAL(CP(D2D_MCAD29), (IEN | PTD | EN | M0)); /* D2D_MCAD29 */ - MUX_VAL(CP(D2D_MCAD30), (IEN | PTD | EN | M0)); /* D2D_MCAD30 */ - MUX_VAL(CP(D2D_MCAD31), (IEN | PTD | EN | M0)); /* D2D_MCAD31 */ - MUX_VAL(CP(D2D_MCAD32), (IEN | PTD | EN | M0)); /* D2D_MCAD32 */ - MUX_VAL(CP(D2D_MCAD33), (IEN | PTD | EN | M0)); /* D2D_MCAD33 */ - MUX_VAL(CP(D2D_MCAD34), (IEN | PTD | EN | M0)); /* D2D_MCAD34 */ - MUX_VAL(CP(D2D_MCAD35), (IEN | PTD | EN | M0)); /* D2D_MCAD35 */ - MUX_VAL(CP(D2D_MCAD36), (IEN | PTD | EN | M0)); /* D2D_MCAD36 */ - /* D2D_CLK26MI */ - MUX_VAL(CP(D2D_CLK26MI), (IEN | PTD | DIS | M0)); - /* D2D_NRESPWRON */ - MUX_VAL(CP(D2D_NRESPWRON), (IEN | PTD | EN | M0)); - /* D2D_NRESWARM */ - MUX_VAL(CP(D2D_NRESWARM), (IEN | PTU | EN | M0)); - /* D2D_ARM9NIRQ */ - MUX_VAL(CP(D2D_ARM9NIRQ), (IEN | PTD | DIS | M0)); - /* D2D_UMA2P6FIQ */ - MUX_VAL(CP(D2D_UMA2P6FIQ), (IEN | PTD | DIS | M0)); - /* D2D_SPINT */ - MUX_VAL(CP(D2D_SPINT), (IEN | PTD | EN | M0)); - /* D2D_FRINT */ - MUX_VAL(CP(D2D_FRINT), (IEN | PTD | EN | M0)); - /* D2D_DMAREQ0 */ - MUX_VAL(CP(D2D_DMAREQ0), (IEN | PTD | DIS | M0)); - /* D2D_DMAREQ1 */ - MUX_VAL(CP(D2D_DMAREQ1), (IEN | PTD | DIS | M0)); - /* D2D_DMAREQ2 */ - MUX_VAL(CP(D2D_DMAREQ2), (IEN | PTD | DIS | M0)); - /* D2D_DMAREQ3 */ - MUX_VAL(CP(D2D_DMAREQ3), (IEN | PTD | DIS | M0)); - /* D2D_N3GTRST */ - MUX_VAL(CP(D2D_N3GTRST), (IEN | PTD | DIS | M0)); - /* D2D_N3GTDI */ - MUX_VAL(CP(D2D_N3GTDI), (IEN | PTD | DIS | M0)); - /* D2D_N3GTDO */ - MUX_VAL(CP(D2D_N3GTDO), (IEN | PTD | DIS | M0)); - /* D2D_N3GTMS */ - MUX_VAL(CP(D2D_N3GTMS), (IEN | PTD | DIS | M0)); - /* D2D_N3GTCK */ - MUX_VAL(CP(D2D_N3GTCK), (IEN | PTD | DIS | M0)); - /* D2D_N3GRTCK */ - MUX_VAL(CP(D2D_N3GRTCK), (IEN | PTD | DIS | M0)); - /* D2D_MSTDBY */ - MUX_VAL(CP(D2D_MSTDBY), (IEN | PTU | EN | M0)); - /* D2D_SWAKEUP */ - MUX_VAL(CP(D2D_SWAKEUP), (IEN | PTD | EN | M0)); - /* D2D_IDLEREQ */ - MUX_VAL(CP(D2D_IDLEREQ), (IEN | PTD | DIS | M0)); - /* D2D_IDLEACK */ - MUX_VAL(CP(D2D_IDLEACK), (IEN | PTU | EN | M0)); - /* D2D_MWRITE */ - MUX_VAL(CP(D2D_MWRITE), (IEN | PTD | DIS | M0)); - /* D2D_SWRITE */ - MUX_VAL(CP(D2D_SWRITE), (IEN | PTD | DIS | M0)); - /* D2D_MREAD */ - MUX_VAL(CP(D2D_MREAD), (IEN | PTD | DIS | M0)); - /* D2D_SREAD */ - MUX_VAL(CP(D2D_SREAD), (IEN | PTD | DIS | M0)); - /* D2D_MBUSFLAG */ - MUX_VAL(CP(D2D_MBUSFLAG), (IEN | PTD | DIS | M0)); - /* D2D_SBUSFLAG */ - MUX_VAL(CP(D2D_SBUSFLAG), (IEN | PTD | DIS | M0)); - /* SDRC_CKE0 */ - MUX_VAL(CP(SDRC_CKE0), (IDIS | PTU | EN | M0)); - /* SDRC_CKE1 NOT USED */ - MUX_VAL(CP(SDRC_CKE1), (IDIS | PTD | DIS | M7)); -#endif /* CONFIG_MACH_OMAP_ADVANCED_MUX */ -} - -/******************** Board Run Time *******************/ - -/*-----------------------CONSOLE Devices -----------------------------------*/ - -#ifdef CONFIG_DRIVER_SERIAL_NS16550 - -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 sdp3430_serial_device = { - .name = "serial_ns16550", - .map_base = OMAP_UART3_BASE, - .size = 1024, - .platform_data = (void *)&serial_plat, -}; - -/** - * @brief UART serial port initialization - remember to enable COM clocks in arch - * - * @return result of device registration - */ -static int sdp3430_console_init(void) -{ - /* Register the serial port */ - return register_device(&sdp3430_serial_device); -} - -console_initcall(sdp3430_console_init); -#endif /* CONFIG_DRIVER_SERIAL_NS16550 */ - -/*------------------------- FLASH Devices -----------------------------------*/ -static int sdp3430_flash_init(void) -{ -#ifdef CONFIG_GPMC - /* WP is made high and WAIT1 active Low */ - gpmc_generic_init(0x10); -#endif - return 0; -} - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -struct device_d sdram_dev = { - .name = "mem", - .map_base = 0x80000000, - .size = 128 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -/*-----------------------Generic Devices Initialization ---------------------*/ - -static int sdp3430_devices_init(void) -{ - int ret; - ret = register_device(&sdram_dev); - if (ret) - goto failed; - ret = sdp3430_flash_init(); - if (ret) - goto failed; - - armlinux_add_dram(&sdram_dev); -failed: - return ret; -} - -device_initcall(sdp3430_devices_init); diff --git a/board/omap/board.h b/board/omap/board.h deleted file mode 100644 index ee3e25e..0000000 --- a/board/omap/board.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @file - * @brief exported generic APIs which various board files implement - * - * FileName: board/omap/board.h - * - * This file will not contain any board specific implementations. - */ -/* - * (C) Copyright 2008 - * Texas Instruments, - * Raghavendra KH - * - * 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 __BOARD_OMAP_H_ -#define __BOARD_OMAP_H_ - -/** Generic Board initialization called from platform.S */ -void board_init(void); - -#endif /* __BOARD_OMAP_H_ */ diff --git a/board/omap/config.h b/board/omap/config.h deleted file mode 100644 index 28b6273..0000000 --- a/board/omap/config.h +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @file - * @brief provide a wrapper for standard malloc and stack size defines - * - * FileName: board/omap/config.h - * - * Standard defines should be configurable for us to move Stack and malloc - * areas around this defines some basics for that - */ -/* - * (C) Copyright 2006-2008 - * Texas Instruments, - * Nishanth Menon - * - * 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 __MACH_OMAP_CONFIG_H -#define __MACH_OMAP_CONFIG_H - -/** define CFG_MALLOC_LEN from Kconfig define */ -#define CFG_MALLOC_LEN CONFIG_OMAP_MALLOC_LEN -/** define CONFIG_STACKSIZE from Kconfig define */ -#define CONFIG_STACKSIZE CONFIG_OMAP_CONFIG_STACKSIZE - -#endif /* __MACH_OMAP_CONFIG_H */ diff --git a/board/omap/devices-gpmc-nand.c b/board/omap/devices-gpmc-nand.c deleted file mode 100644 index bbcceaf..0000000 --- a/board/omap/devices-gpmc-nand.c +++ /dev/null @@ -1,138 +0,0 @@ -/** - * @file - * @brief GPMC specific NAND devices - * - * FileName: board/omap/devices-gpmc-nand.c - * - * GPMC NAND Devices such as those from Micron, Samsung are listed here - */ -/* - * (C) Copyright 2006-2008 - * Texas Instruments, - * Nishanth Menon - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef CONFIG_MACH_OMAP_GPMC_GENERICNAND - -#define GPMC_CONF1_VALx8 0x00000800 -#define GPMC_CONF1_VALx16 0x00001800 -/* Set up the generic params */ -#ifdef CONFIG_MACH_OMAP_GPMC_GENERICNAND_LP_X8 -#define GPMC_NAND_ECC_LAYOUT GPMC_NAND_ECC_LP_x8_LAYOUT -#define GPMC_CONF1_VAL GPMC_CONF1_VALx8 -#define GPMC_NAND_DEV_WIDTH 8 -#endif - -#ifdef CONFIG_MACH_OMAP_GPMC_GENERICNAND_LP_X16 -#define GPMC_NAND_ECC_LAYOUT GPMC_NAND_ECC_LP_x16_LAYOUT -#define GPMC_CONF1_VAL GPMC_CONF1_VALx16 -#define GPMC_NAND_DEV_WIDTH 16 -#endif - -#ifdef CONFIG_MACH_OMAP_GPMC_GENERICNAND_SP_X8 -#define GPMC_NAND_ECC_LAYOUT GPMC_NAND_ECC_SP_x8_LAYOUT -#define GPMC_CONF1_VAL GPMC_CONF1_VALx8 -#define GPMC_NAND_DEV_WIDTH 8 -#endif - -#ifdef CONFIG_MACH_OMAP_GPMC_GENERICNAND_SP_X16 -#define GPMC_NAND_ECC_LAYOUT GPMC_NAND_ECC_SP_x16_LAYOUT -#define GPMC_CONF1_VAL GPMC_CONF1_VALx16 -#define GPMC_NAND_DEV_WIDTH 16 -#endif - -#ifdef CONFIG_NAND_OMAP_GPMC_HWECC -/** - * The following is the organization of ECC as expected by BootROM. - * Based on the type of device, this can vary. select the config accordingly - */ -static struct nand_ecclayout boot_rom_ecc = GPMC_NAND_ECC_LAYOUT; -#endif - -/** GPMC timing for our nand device */ -static struct gpmc_config nand_cfg = { - .cfg = { - GPMC_CONF1_VAL, /*CONF1 */ - 0x00141400, /*CONF2 */ - 0x00141400, /*CONF3 */ - 0x0F010F01, /*CONF4 */ - 0x010C1414, /*CONF5 */ -#ifdef CONFIG_ARCH_OMAP3 - /* Additional bits in OMAP3 */ - 0x1F040000 | -#endif - 0x00000A80, /*CONF6 */ - }, - - /* Nand: dont care about base address */ - .base = 0x28000000, - /* GPMC address map as small as possible */ - .size = GPMC_SIZE_16M, -}; - -/** NAND platform specific settings settings */ -static struct gpmc_nand_platform_data nand_plat = { - .cs = CONFIG_MACH_OMAP_CS, - .device_width = GPMC_NAND_DEV_WIDTH, - .max_timeout = MSECOND, - .wait_mon_pin = 0, -#ifdef CONFIG_NAND_OMAP_GPMC_HWECC - .plat_options = NAND_HWECC_ENABLE, - .oob = &boot_rom_ecc, -#else - .plat_options = NAND_HWECC_DISABLE, -#endif - .priv = (void *)&nand_cfg, -}; - -/** NAND device definition */ -static struct device_d gpmc_generic_nand_nand_device = { - .name = "gpmc_nand", - .map_base = OMAP_GPMC_BASE, - .size = 1024 * 4, /* GPMC size */ - .platform_data = (void *)&nand_plat, -}; - -/** - * @brief gpmc_generic_nand_devices_init - init generic nand device - * - * @return success/fail based on device funtion - */ -static int gpmc_generic_nand_devices_init(void) -{ - /* Configure GPMC CS before register */ - gpmc_cs_config(nand_plat.cs, &nand_cfg); - return register_device(&gpmc_generic_nand_nand_device); -} - -device_initcall(gpmc_generic_nand_devices_init); - -#endif /* CONFIG_MACH_OMAP_GPMC_GENERICNAND */ - -/* All specific optimized nand configurations for GPMC NAND comes here */ - diff --git a/board/omap/env/bin/init b/board/omap/env/bin/init deleted file mode 100644 index 224a6b4..0000000 --- a/board/omap/env/bin/init +++ /dev/null @@ -1 +0,0 @@ -# Dummy Init environment script diff --git a/board/omap/platform.S b/board/omap/platform.S deleted file mode 100644 index 9014a8f..0000000 --- a/board/omap/platform.S +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file - * @brief Wrapper to call board level initialization routine - * - * FileName: board/omap/platform.S - * - * board_init_lowlevel is defined here. This calls board_init which - * is linked to the binary - the board_init only has a SRAM stack. - * so it needs to be careful about the usage of global variables - * and the likes. Enabled only if CONFIG_MACH_DO_LOWLEVEL_INIT is - * defined - */ -/* - * (C) Copyright 2006-2008 - * Texas Instruments, - * Nishanth Menon - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include - -#ifdef CONFIG_MACH_DO_LOWLEVEL_INIT -/** - * @fn void board_init_lowlevel(void) - * - * @brief This provides a assembly wrapper setting up SRAM before calling - * board_init - * - * @return void - */ -.globl board_init_lowlevel -board_init_lowlevel: - /* Setup a temporary stack so that we can call C functions - * Yes. this might have been already done by arch code. - * No harm in being a bit redundant to avoid future complications - */ - ldr sp, SRAM_STACK - str ip, [sp] /* stash old link register */ - str lr, [sp] /* stash current link register */ - mov ip, lr /* save link reg across call */ - /* Do the pin muxes, sdram init etc..board-xxx.c */ - bl board_init - ldr lr, [sp] /* restore current link register */ - ldr ip, [sp] /* restore save ip */ - /* back to arch calling code */ - mov pc, lr -SRAM_STACK: - .word OMAP_SRAM_STACK - -#endif /* CONFIG_MACH_DO_LOWLEVEL_INIT */ diff --git a/board/pcm030/Makefile b/board/pcm030/Makefile deleted file mode 100644 index e7d744b..0000000 --- a/board/pcm030/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-y += pcm030.o -extra-y += barebox.lds diff --git a/board/pcm030/barebox.lds.S b/board/pcm030/barebox.lds.S deleted file mode 100644 index ab99335..0000000 --- a/board/pcm030/barebox.lds.S +++ /dev/null @@ -1,139 +0,0 @@ -/* - * (C) Copyright 2003 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include - -OUTPUT_ARCH("powerpc") -/* Do we need any of these for elf? - __DYNAMIC = 0; */ -SECTIONS -{ - . = TEXT_BASE; - - /* Read-only sections, merged into text segment: */ - .interp : { *(.interp) } - .hash : { *(.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .rel.text : { *(.rel.text) } - .rela.text : { *(.rela.text) } - .rel.data : { *(.rel.data) } - .rela.data : { *(.rela.data) } - .rel.rodata : { *(.rel.rodata) } - .rela.rodata : { *(.rela.rodata) } - .rel.got : { *(.rel.got) } - .rela.got : { *(.rela.got) } - .rel.ctors : { *(.rel.ctors) } - .rela.ctors : { *(.rela.ctors) } - .rel.dtors : { *(.rel.dtors) } - .rela.dtors : { *(.rela.dtors) } - .rel.bss : { *(.rel.bss) } - .rela.bss : { *(.rela.bss) } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : { *(.init) } - .plt : { *(.plt) } - .text : - { - arch/ppc/mach-mpc5xxx/start.o (.text) - *(.text*) - *(.got1*) - . = ALIGN(16); - *(.rodata*) - *(.rodata1*) - *(.rodata.str1.4) - } - .fini : { *(.fini) } =0 - .ctors : { *(.ctors) } - .dtors : { *(.dtors) } - - /* Read-write section, merged into data segment: */ - . = (. + 0x0FFF) & 0xFFFFF000; - _etext = .; - PROVIDE (erotext = .); - .reloc : - { - *(.got) - _GOT2_TABLE_ = .; - *(.got2) - _FIXUP_TABLE_ = .; - *(.fixup) - } - __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; - __fixup_entries = (. - _FIXUP_TABLE_) >> 2; - - - .data : - { - *(.data*) - *(.data1*) - *(.sdata*) - *(.sdata2*) - *(.dynamic*) - CONSTRUCTORS - } - _edata = .; - PROVIDE (edata = .); - - . = .; - __barebox_cmd_start = .; - .barebox_cmd : { BAREBOX_CMDS } - __barebox_cmd_end = .; - - __barebox_initcalls_start = .; - .barebox_initcalls : { INITCALLS } - __barebox_initcalls_end = .; - __initcall_entries = (__barebox_initcalls_end - __barebox_initcalls_start) >> 2; - - __usymtab_start = .; - __usymtab : { BAREBOX_SYMS } - __usymtab_end = .; - - __early_init_data_begin = .; - .early_init_data : { *(.early_init_data) } - __early_init_data_end = .; - - __start___ex_table = .; - __ex_table : { *(__ex_table) } - __stop___ex_table = .; - - . = ALIGN(4096); - __init_begin = .; - .text.init : { *(.text.init) } - .data.init : { *(.data.init) } - . = ALIGN(4096); - __init_end = .; - - __init_size = __init_end - _start; - - __bss_start = .; - .bss : - { - *(.sbss*) *(.scommon*) - *(.dynbss*) - *(.bss*) - *(COMMON) - } - _end = . ; - PROVIDE (end = .); -} diff --git a/board/pcm030/config.h b/board/pcm030/config.h deleted file mode 100644 index a772ee6..0000000 --- a/board/pcm030/config.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * (C) Copyright 2003-2005 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * (C) Copyright 2006 - * Eric Schumann, Phytec Messatechnik GmbH - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#include - -/* #define DEBUG */ - -/*------------------------------------------------------------------------------------------------------------------------------------------------------ -High Level Configuration Options -(easy to change) - ------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define CONFIG_MPC5200_DDR 1 /* (with DDR-SDRAM) */ -#define CFG_MPC5XXX_CLKIN 33333333 /* ... running at 33.333333MHz */ -#define BOOTFLAG_COLD 0x01 /* Normal Power-On: Boot from FLASH */ -#define BOOTFLAG_WARM 0x02 /* Software reboot */ - -/*------------------------------------------------------------------------------------------------------------------------------------------------------ -Serial console configuration - ------------------------------------------------------------------------------------------------------------------------------------------------------*/ - -#if (TEXT_BASE == 0xFF000000) /* Boot low */ -#define CFG_LOWBOOT 1 -#endif -/* RAMBOOT will be defined automatically in memory section */ - -/*------------------------------------------------------------------------------------------------------------------------------------------------------ -IPB Bus clocking configuration. - ------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define CFG_IPBSPEED_133 /* define for 133MHz speed */ -#if defined(CFG_IPBSPEED_133) -/* - * PCI Bus clocking configuration - * - * Actually a PCI Clock of 66 MHz is only set (in cpu_init.c) if - * CFG_IPBSPEED_133 is defined. This is because a PCI Clock of 66 MHz yet hasn't - * been tested with a IPB Bus Clock of 66 MHz. - */ -#define CFG_PCISPEED_66 /* define for 66MHz speed */ -#else -#undef CFG_PCISPEED_66 /* for 33MHz speed */ -#endif - -/* we only use CS-Boot */ -#define CFG_BOOTCS_START 0xFF000000 -#define CFG_BOOTCS_SIZE 0x01000000 - -#if CONFIG_MACH_PHYCORE_MPC5200B_TINY_REV == 1 -#define CFG_BOOTCS_CFG 0x0008FD00 -#else -#define CFG_BOOTCS_CFG 0x00083800 -#endif - -/*------------------------------------------------------------------------------------------------------------------------------------------------------ - Memory map - ------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define CFG_MBAR 0xF0000000 /* MBAR hast to be switched by other bootloader or debugger config */ -#define CFG_SDRAM_BASE 0x00000000 - -/* Use SRAM until RAM will be available */ -#define CFG_INIT_RAM_ADDR MPC5XXX_SRAM -#define CFG_INIT_RAM_SIZE MPC5XXX_SRAM_SIZE /* End of used area in DPRAM */ -#define CONFIG_EARLY_INITDATA_SIZE 0x100 - -#define CFG_BOOTMAPSZ (8 << 20) /* Initial Memory map for Linux */ - -/*------------------------------------------------------------------------------------------------------------------------------------------------------ - GPIO configuration - ------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define CFG_GPS_PORT_CONFIG 0x00558c10 /* PSC6=UART, PSC3=UART ; Ether=100MBit with MD */ - -/*------------------------------------------------------------------------------------------------------------------------------------------------------ - Various low-level settings - ------------------------------------------------------------------------------------------------------------------------------------------------------*/ -#define CFG_HID0_INIT HID0_ICE | HID0_ICFI -#define CFG_HID0_FINAL HID0_ICE - -#define CFG_CS_BURST 0x00000000 -#define CFG_CS_DEADCYCLE 0x33333333 - -#define OF_CPU "PowerPC,5200@0" -#define OF_TBCLK CFG_MPC5XXX_CLKIN -#define OF_SOC "soc5200@f0000000" - -#endif /* __CONFIG_H */ diff --git a/board/pcm030/mt46v32m16-75.h b/board/pcm030/mt46v32m16-75.h deleted file mode 100644 index 4d191f1..0000000 --- a/board/pcm030/mt46v32m16-75.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * (C) Copyright 2004 - * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. - * - * Eric Schumann, Phytec Messtechnik - * adapted for mt46v32m16-75 DDR-RAM - * - * 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 - */ - -#define SDRAM_DDR 1 /* is DDR */ - -/* Settings for XLB = 132 MHz */ -#define SDRAM_MODE 0x018D0000 -#define SDRAM_EMODE 0x40090000 -#define SDRAM_CONTROL 0x715f0f00 -#define SDRAM_CONFIG1 0x73722930 -#define SDRAM_CONFIG2 0x47770000 - - -/* Settings for XLB = 99 MHz */ -/* -#define SDRAM_MODE 0x008D0000 -#define SDRAM_EMODE 0x40090000 -#define SDRAM_CONTROL 0x714b0f00 -#define SDRAM_CONFIG1 0x63611730 -#define SDRAM_CONFIG2 0x47670000 -*/ - -#define SDRAM_TAPDELAY 0x10000000 /* reserved Bit in MPC5200 B3-Step */ diff --git a/board/pcm030/pcm030.c b/board/pcm030/pcm030.c deleted file mode 100644 index f3845ad..0000000 --- a/board/pcm030/pcm030.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * (C) Copyright 2003 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * (C) Copyright 2004 - * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. - * - * (C) Copyright 2006 - * Eric Schumann, Phytec Messtechnik GmbH - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0xff000000, - .size = 16 * 1024 * 1024, -}; - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -struct device_d sdram_dev = { - .name = "mem", - .map_base = 0x0, - .size = 64 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -static struct mpc5xxx_fec_platform_data fec_info = { - .xcv_type = MII100, -}; - -struct device_d eth_dev = { - .name = "fec_mpc5xxx", - .map_base = MPC5XXX_FEC, - .platform_data = &fec_info, -}; - -static int devices_init (void) -{ - register_device(&cfi_dev); - register_device(&sdram_dev); - register_device(ð_dev); - - devfs_add_partition("nor0", 0x00f00000, 0x40000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x00f60000, 0x20000, PARTITION_FIXED, "env0"); - - return 0; -} - -device_initcall(devices_init); - -static struct device_d psc3 = { - .name = "mpc5xxx_serial", - .map_base = MPC5XXX_PSC3, - .size = 4096, -}; - -static struct device_d psc6 = { - .name = "mpc5xxx_serial", - .map_base = MPC5XXX_PSC6, - .size = 4096, -}; - -static int console_init(void) -{ - register_device(&psc3); - register_device(&psc6); - return 0; -} - -console_initcall(console_init); - -void *get_early_console_base(const char *name) -{ - if (!strcmp(name, RELOC("psc3"))) - return (void *)MPC5XXX_PSC3; - if (!strcmp(name, RELOC("psc6"))) - return (void *)MPC5XXX_PSC6; - return NULL; -} - -#include "mt46v32m16-75.h" - -static void sdram_start (int hi_addr) -{ - long hi_addr_bit = hi_addr ? 0x01000000 : 0; - - /* unlock mode register */ - *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000000 | hi_addr_bit; - __asm__ volatile ("sync"); - - /* precharge all banks */ - *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; - __asm__ volatile ("sync"); - -#if SDRAM_DDR - /* set mode register: extended mode */ - *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_EMODE; - __asm__ volatile ("sync"); - - /* set mode register: reset DLL */ - *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE | 0x04000000; - __asm__ volatile ("sync"); -#endif - - /* precharge all banks */ - *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; - __asm__ volatile ("sync"); - - /* auto refresh */ - *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000004 | hi_addr_bit; - __asm__ volatile ("sync"); - - /* set mode register */ - *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE; - __asm__ volatile ("sync"); - - /* normal operation */ - *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | hi_addr_bit; - __asm__ volatile ("sync"); -} - -/* - * ATTENTION: Although partially referenced initdram does NOT make real use - * use of CFG_SDRAM_BASE. The code does not work if CFG_SDRAM_BASE - * is something else than 0x00000000. - */ - -long int initdram (int board_type) -{ - ulong dramsize = 0; - ulong dramsize2 = 0; - - ulong test1, test2; - - if ((ulong)RELOC(initdram) > (2 << 30)) { - /* setup SDRAM chip selects */ - *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x0000001b;/* 256MB at 0x0 */ - *(vu_long *)MPC5XXX_SDRAM_CS1CFG = 0x10000000;/* disabled */ - __asm__ volatile ("sync"); - - /* setup config registers */ - *(vu_long *)MPC5XXX_SDRAM_CONFIG1 = SDRAM_CONFIG1; - *(vu_long *)MPC5XXX_SDRAM_CONFIG2 = SDRAM_CONFIG2; - __asm__ volatile ("sync"); - -#if SDRAM_DDR && SDRAM_TAPDELAY - /* set tap delay */ - *(vu_long *)MPC5XXX_CDM_PORCFG = SDRAM_TAPDELAY; - __asm__ volatile ("sync"); -#endif - - /* find RAM size using SDRAM CS0 only */ - sdram_start(0); - test1 = get_ram_size((ulong *)CFG_SDRAM_BASE, 0x10000000); - sdram_start(1); - test2 = get_ram_size((ulong *)CFG_SDRAM_BASE, 0x10000000); - if (test1 > test2) { - sdram_start(0); - dramsize = test1; - } else { - dramsize = test2; - } - - /* memory smaller than 1MB is impossible */ - if (dramsize < (1 << 20)) { - dramsize = 0; - } - - /* set SDRAM CS0 size according to the amount of RAM found */ - if (dramsize > 0) { - *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x13 + __builtin_ffs(dramsize >> 20) - 1; - } else { - *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ - } - } else - puts(RELOC("skipping sdram initialization\n")); - - /* retrieve size of memory connected to SDRAM CS0 */ - dramsize = *(vu_long *)MPC5XXX_SDRAM_CS0CFG & 0xFF; - if (dramsize >= 0x13) { - dramsize = (1 << (dramsize - 0x13)) << 20; - } else { - dramsize = 0; - } - - /* retrieve size of memory connected to SDRAM CS1 */ - dramsize2 = *(vu_long *)MPC5XXX_SDRAM_CS1CFG & 0xFF; - if (dramsize2 >= 0x13) { - dramsize2 = (1 << (dramsize2 - 0x13)) << 20; - } else { - dramsize2 = 0; - } - - return dramsize + dramsize2; -} - -#if defined(CONFIG_OF_FLAT_TREE) && defined(CONFIG_OF_BOARD_SETUP) -void -ft_board_setup(void *blob, bd_t *bd) -{ - ft_cpu_setup(blob, bd); -} -#endif - diff --git a/board/pcm030/pcm030.dox b/board/pcm030/pcm030.dox deleted file mode 100644 index b9ada83..0000000 --- a/board/pcm030/pcm030.dox +++ /dev/null @@ -1,8 +0,0 @@ -/** @page pcm030 Phytec's phyCORE-MPC5200B-tiny - -This CPU card is based on a Freescale MPC5200B CPU. The card is shipped with: - -- up to 16MiB NOR type Flash Memory -- 64MiB synchronous dynamic RAM - -*/ diff --git a/board/pcm037/Makefile b/board/pcm037/Makefile deleted file mode 100644 index 7d36b77..0000000 --- a/board/pcm037/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# (C) Copyright 2007 Juergen Beisert -# -# 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 -# - -obj-y += lowlevel_init.o -obj-y += pcm037.o diff --git a/board/pcm037/config.h b/board/pcm037/config.h deleted file mode 100644 index 5495d03..0000000 --- a/board/pcm037/config.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * (C) Copyright 2007 Juergen Beisert - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -/* - * Definitions related to passing arguments to kernel. - */ - -/* #define CONFIG_SYSPLL_CLK_FREQ 26000000 */ - -/* FIXME */ -#define CONFIG_MX31_HCLK_FREQ 26000000 -#define CONFIG_MX31_CLK32 32000 - -#endif - -/* nothing to do here yet */ diff --git a/board/pcm037/env/config b/board/pcm037/env/config deleted file mode 100644 index bf15620..0000000 --- a/board/pcm037/env/config +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -machine=pcm037 -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 'net', 'nor' or 'nand' -kernel_loc=net -# 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=ttymxc0,115200" - -nor_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nor=3 - -nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nand=7 - -# set a fancy prompt (if support is compiled in) -PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m " - diff --git a/board/pcm037/lowlevel_init.S b/board/pcm037/lowlevel_init.S deleted file mode 100644 index 8988db2..0000000 --- a/board/pcm037/lowlevel_init.S +++ /dev/null @@ -1,167 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include -#include - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#define writeb(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - strb r1, [r0]; - -.macro DELAY loops - ldr r2, =\loops -1: - subs r2, r2, #1 - nop - bcs 1b -.endm - - .section ".text_bare_init","ax" - -.globl board_init_lowlevel -board_init_lowlevel: - - mov r10, lr - writel(IPU_CONF_DI_EN, IPU_CONF) - writel(0x074B0BF5, IMX_CCM_BASE + CCM_CCMR) - - DELAY 0x40000 - - writel(0x074B0BF5 | CCMR_MPE, IMX_CCM_BASE + CCM_CCMR) - writel((0x074B0BF5 | CCMR_MPE) & ~CCMR_MDS, IMX_CCM_BASE + CCM_CCMR) - - writel(PDR0_CSI_PODF(0xff1) | \ - PDR0_PER_PODF(7) | \ - PDR0_HSP_PODF(3) | \ - PDR0_NFC_PODF(5) | \ - PDR0_IPG_PODF(1) | \ - PDR0_MAX_PODF(3) | \ - PDR0_MCU_PODF(0), \ - IMX_CCM_BASE + CCM_PDR0) - - writel(IMX_PLL_PD(0) | IMX_PLL_MFD(0xe) | IMX_PLL_MFI(9) | IMX_PLL_MFN(0xd), IMX_CCM_BASE + CCM_MPCTL) - writel(IMX_PLL_PD(1) | IMX_PLL_MFD(0x43) | IMX_PLL_MFI(12) | IMX_PLL_MFN(1), IMX_CCM_BASE + CCM_SPCTL) - - /* Configure IOMUXC - * Clears 0x43fa_c26c - 0x43fa_c2dc with 0, except 0x43fa_c278 (untouched), 0x43fa_c27c (set to 0x1000) and 0x43fa_c280 (untouched) - * (behaviour copied by sha, source unknown) - */ - mov r1, #0; - ldr r0, =0x43FAC26C - str r1, [r0], #4 - str r1, [r0], #4 - str r1, [r0], #0x10 - - ldr r2, =0x43FAC2DC -clear_iomux: - str r1, [r0], #4 - cmp r0, r2 - bls clear_iomux - writel(0x1000, 0x43FAC27C )/* CS2 CSD0) */ - - /* Skip SDRAM initialization if we run from RAM */ - cmp pc, #0x80000000 - blo 1f - cmp pc, #0x90000000 - bhs 1f - - mov pc, r10 -1: - -#if defined CONFIG_PCM037_SDRAM_BANK0_128MB -#define ROWS0 ESDCTL0_ROW13 -#elif defined CONFIG_PCM037_SDRAM_BANK0_256MB -#define ROWS0 ESDCTL0_ROW14 -#endif - writel(0x00000004, ESDMISC) - writel(0x006ac73a, ESDCFG0) - writel(0x90100000 | ROWS0, ESDCTL0) - writel(0x12344321, IMX_SDRAM_CS0 + 0xf00) - writel(0xa0100000 | ROWS0, ESDCTL0) - writel(0x12344321, IMX_SDRAM_CS0) - writel(0x12344321, IMX_SDRAM_CS0) - writel(0xb0100000 | ROWS0, ESDCTL0) - writeb(0xda, IMX_SDRAM_CS0 + 0x33) - writeb(0xff, IMX_SDRAM_CS0 + 0x01000000) - writel(0x80226080 | ROWS0, ESDCTL0) - writel(0xDEADBEEF, IMX_SDRAM_CS0) - writel(0x0000000c, ESDMISC) - -#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE -#if defined CONFIG_PCM037_SDRAM_BANK1_128MB -#define ROWS1 ESDCTL0_ROW13 -#elif defined CONFIG_PCM037_SDRAM_BANK1_256MB -#define ROWS1 ESDCTL0_ROW14 -#endif - writel(0x006ac73a, ESDCFG1) - writel(0x90100000 | ROWS1, ESDCTL1) - writel(0x12344321, IMX_SDRAM_CS1 + 0xf00) - writel(0xa0100000 | ROWS1, ESDCTL1) - writel(0x12344321, IMX_SDRAM_CS1) - writel(0x12344321, IMX_SDRAM_CS1) - writel(0xb0100000 | ROWS1, ESDCTL1) - writeb(0xda, IMX_SDRAM_CS1 + 0x33) - writeb(0xff, IMX_SDRAM_CS1 + 0x01000000) - writel(0x80226080 | ROWS1, ESDCTL1) - writel(0xDEADBEEF, IMX_SDRAM_CS1) - writel(0x0000000c, ESDMISC) -#endif - -#ifdef CONFIG_NAND_IMX_BOOT - ldr sp, =0x80f00000 /* Setup a temporary stack in SDRAM */ - - ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ - ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ - - /* skip NAND boot if not running from NFC space */ - cmp pc, r0 - blo ret - cmp pc, r2 - bhs ret - - /* Move ourselves out of NFC SRAM */ - ldr r1, =TEXT_BASE - -copy_loop: - ldmia r0!, {r3-r9} /* copy from source address [r0] */ - stmia r1!, {r3-r9} /* copy to target address [r1] */ - cmp r0, r2 /* until source end addreee [r2] */ - ble copy_loop - - ldr pc, =1f /* Jump to SDRAM */ -1: - bl nand_boot /* Load barebox from NAND Flash */ - - ldr r1, =IMX_NFC_BASE - TEXT_BASE - sub r10, r10, r1 /* adjust return address from NFC SRAM */ -ret: -#endif /* CONFIG_NAND_IMX_BOOT */ - - mov pc, r10 - diff --git a/board/pcm037/pcm037.c b/board/pcm037/pcm037.c deleted file mode 100644 index 2e6968b..0000000 --- a/board/pcm037/pcm037.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * (C) 2007 Pengutronix, Sascha Hauer - * - * 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 - * - * Board support for Phytec's, i.MX31 based CPU card, called: PCM037 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Up to 32MiB NOR type flash, connected to - * CS line 0, data width is 16 bit - */ -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = IMX_CS0_BASE, - .size = 32 * 1024 * 1024, /* area size */ -}; - -/* - * up to 2MiB static RAM type memory, connected - * to CS4, data width is 16 bit - */ -static struct memory_platform_data sram_dev_pdata0 = { - .name = "sram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sram_dev = { - .name = "mem", - .map_base = IMX_CS4_BASE, - .size = IMX_CS4_RANGE, /* area size */ - .platform_data = &sram_dev_pdata0, -}; - -/* - * SMSC 9217 network controller - * connected to CS line 1 and interrupt line - * GPIO3, data width is 16 bit - */ -static struct device_d network_dev = { - .name = "smc911x", - .map_base = IMX_CS1_BASE, - .size = IMX_CS1_RANGE, /* area size */ -}; - -#if defined CONFIG_PCM037_SDRAM_BANK0_128MB -#define SDRAM0 128 -#elif defined CONFIG_PCM037_SDRAM_BANK0_256MB -#define SDRAM0 256 -#endif - -static struct memory_platform_data ram_dev_pdata0 = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram0_dev = { - .name = "mem", - .map_base = IMX_SDRAM_CS0, - .size = SDRAM0 * 1024 * 1024, /* fix size */ - .platform_data = &ram_dev_pdata0, -}; - -#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE - -#if defined CONFIG_PCM037_SDRAM_BANK1_128MB -#define SDRAM1 128 -#elif defined CONFIG_PCM037_SDRAM_BANK1_256MB -#define SDRAM1 256 -#endif - -static struct memory_platform_data ram_dev_pdata1 = { - .name = "ram1", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram1_dev = { - .name = "mem", - .map_base = IMX_SDRAM_CS1, - .size = SDRAM1 * 1024 * 1024, /* fix size */ - .platform_data = &ram_dev_pdata1, -}; -#endif - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, - .flash_bbt = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = 0xB8000000, - .platform_data = &nand_info, -}; - -#ifdef CONFIG_USB -static struct device_d usbotg_dev = { - .name = "ehci", - .map_base = IMX_OTG_BASE, - .size = 0x200, -}; - -static struct device_d usbh2_dev = { - .name = "ehci", - .map_base = IMX_OTG_BASE + 0x400, - .size = 0x200, -}; - -static void pcm037_usb_init(void) -{ - u32 tmp; - - /* enable clock */ - tmp = readl(0x53f80000); - tmp |= (1 << 9); - writel(tmp, 0x53f80000); - - /* Host 1 */ - tmp = readl(IMX_OTG_BASE + 0x600); - tmp &= ~((3 << 21) | 1); - tmp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 11) | (1 << 20); - writel(tmp, IMX_OTG_BASE + 0x600); - - tmp = readl(IMX_OTG_BASE + 0x184); - tmp &= ~(3 << 30); - tmp |= 2 << 30; - writel(tmp, IMX_OTG_BASE + 0x184); - - imx_iomux_mode(MX31_PIN_USBOTG_DATA0__USBOTG_DATA0); - imx_iomux_mode(MX31_PIN_USBOTG_DATA1__USBOTG_DATA1); - imx_iomux_mode(MX31_PIN_USBOTG_DATA2__USBOTG_DATA2); - imx_iomux_mode(MX31_PIN_USBOTG_DATA3__USBOTG_DATA3); - imx_iomux_mode(MX31_PIN_USBOTG_DATA4__USBOTG_DATA4); - imx_iomux_mode(MX31_PIN_USBOTG_DATA5__USBOTG_DATA5); - imx_iomux_mode(MX31_PIN_USBOTG_DATA6__USBOTG_DATA6); - imx_iomux_mode(MX31_PIN_USBOTG_DATA7__USBOTG_DATA7); - imx_iomux_mode(MX31_PIN_USBOTG_CLK__USBOTG_CLK); - imx_iomux_mode(MX31_PIN_USBOTG_DIR__USBOTG_DIR); - imx_iomux_mode(MX31_PIN_USBOTG_NXT__USBOTG_NXT); - imx_iomux_mode(MX31_PIN_USBOTG_STP__USBOTG_STP); - - mdelay(50); - isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x170), 1); - - /* Host 2 */ - tmp = readl(IOMUXC_BASE + 0x8); - tmp |= 1 << 11; - writel(tmp, IOMUXC_BASE + 0x8); - - imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_CLK, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DIR, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_NXT, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_STP, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DATA0, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_USBH2_DATA1, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_STXD3, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_SRXD3, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_SCK3, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_SFS3, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_STXD6, IOMUX_CONFIG_FUNC)); - imx_iomux_mode(IOMUX_MODE(MX31_PIN_SRXD6, IOMUX_CONFIG_FUNC)); - -#define H2_PAD_CFG (PAD_CTL_DRV_MAX | PAD_CTL_SRE_FAST | PAD_CTL_HYS_CMOS | PAD_CTL_ODE_CMOS | PAD_CTL_100K_PU) - imx_iomux_set_pad(MX31_PIN_USBH2_CLK, H2_PAD_CFG); - imx_iomux_set_pad(MX31_PIN_USBH2_DIR, H2_PAD_CFG); - imx_iomux_set_pad(MX31_PIN_USBH2_NXT, H2_PAD_CFG); - imx_iomux_set_pad(MX31_PIN_USBH2_STP, H2_PAD_CFG); - imx_iomux_set_pad(MX31_PIN_USBH2_DATA0, H2_PAD_CFG); /* USBH2_DATA0 */ - imx_iomux_set_pad(MX31_PIN_USBH2_DATA1, H2_PAD_CFG); /* USBH2_DATA1 */ - imx_iomux_set_pad(MX31_PIN_SRXD6, H2_PAD_CFG); /* USBH2_DATA2 */ - imx_iomux_set_pad(MX31_PIN_STXD6, H2_PAD_CFG); /* USBH2_DATA3 */ - imx_iomux_set_pad(MX31_PIN_SFS3, H2_PAD_CFG); /* USBH2_DATA4 */ - imx_iomux_set_pad(MX31_PIN_SCK3, H2_PAD_CFG); /* USBH2_DATA5 */ - imx_iomux_set_pad(MX31_PIN_SRXD3, H2_PAD_CFG); /* USBH2_DATA6 */ - imx_iomux_set_pad(MX31_PIN_STXD3, H2_PAD_CFG); /* USBH2_DATA7 */ - - tmp = readl(IMX_OTG_BASE + 0x600); - tmp &= ~((3 << 21) | 1); - tmp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20); - writel(tmp, IMX_OTG_BASE + 0x600); - - tmp = readl(IMX_OTG_BASE + 0x584); - tmp &= ~(3 << 30); - tmp |= 2 << 30; - writel(tmp, IMX_OTG_BASE + 0x584); - - mdelay(50); - isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x570), 1); - - /* Set to Host mode */ - tmp = readl(IMX_OTG_BASE + 0x1a8); - writel(tmp | 0x3, IMX_OTG_BASE + 0x1a8); - -} -#endif - -#ifdef CONFIG_MMU -static void pcm037_mmu_init(void) -{ - mmu_init(); - - arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); - arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); - - setup_dma_coherent(0x10000000); - -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); - -#ifdef CONFIG_CACHE_L2X0 - l2x0_init((void __iomem *)0x30000000, 0x00030024, 0x00000000); -#endif -} -#else -static void pcm037_mmu_init(void) -{ -} -#endif - -static int imx31_devices_init(void) -{ - pcm037_mmu_init(); - - __REG(CSCR_U(0)) = 0x0000cf03; /* CS0: Nor Flash */ - __REG(CSCR_L(0)) = 0x10000d03; - __REG(CSCR_A(0)) = 0x00720900; - - __REG(CSCR_U(1)) = 0x0000df06; /* CS1: Network Controller */ - __REG(CSCR_L(1)) = 0x444a4541; - __REG(CSCR_A(1)) = 0x44443302; - - __REG(CSCR_U(4)) = 0x0000d843; /* CS4: SRAM */ - __REG(CSCR_L(4)) = 0x22252521; - __REG(CSCR_A(4)) = 0x22220a00; - - __REG(CSCR_U(5)) = 0x0000DCF6; /* CS5: SJA1000 */ - __REG(CSCR_L(5)) = 0x444A0301; - __REG(CSCR_A(5)) = 0x44443302; - - register_device(&cfi_dev); - - /* - * Create partitions that should be - * not touched by any regular user - */ - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); /* ourself */ - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); /* environment */ - - protect_file("/dev/env0", 1); - - register_device(&sram_dev); - register_device(&nand_dev); - register_device(&network_dev); - - register_device(&sdram0_dev); -#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE - register_device(&sdram1_dev); -#endif -#ifdef CONFIG_USB - pcm037_usb_init(); - register_device(&usbotg_dev); - register_device(&usbh2_dev); -#endif - - armlinux_add_dram(&sdram0_dev); -#ifndef CONFIG_PCM037_SDRAM_BANK1_NONE - armlinux_add_dram(&sdram1_dev); -#endif - armlinux_set_bootparams((void *)0x80000100); - armlinux_set_architecture(MACH_TYPE_PCM037); - - return 0; -} - -device_initcall(imx31_devices_init); - -static struct device_d imx31_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 16 * 1024, -}; - -static int imx31_console_init(void) -{ - /* init gpios for serial port */ - imx_iomux_mode(MX31_PIN_RXD1__RXD1); - imx_iomux_mode(MX31_PIN_TXD1__TXD1); - imx_iomux_mode(MX31_PIN_CTS1__CTS1); - imx_iomux_mode(MX31_PIN_RTS1__RTS1); - - register_device(&imx31_serial_device); - return 0; -} - -console_initcall(imx31_console_init); - -#ifdef CONFIG_NAND_IMX_BOOT -void __bare_init nand_boot(void) -{ - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); -} -#endif diff --git a/board/pcm037/pcm037.dox b/board/pcm037/pcm037.dox deleted file mode 100644 index b2afdd6..0000000 --- a/board/pcm037/pcm037.dox +++ /dev/null @@ -1,11 +0,0 @@ -/** @page pcm037 Phytec's phyCORE-i.MX31 - -This CPU card is based on a Freescale i.MX31 CPU. The card is shipped with: - -- up to 64MiB NOR type Flash Memory -- up to 2MiB static RAM -- 64MiB NAND type Flash Memory -- SMSC 9217 network controller -- 128MiB synchronous dynamic RAM - -*/ diff --git a/board/pcm038/Makefile b/board/pcm038/Makefile deleted file mode 100644 index a681dda..0000000 --- a/board/pcm038/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += lowlevel.o pll_init.o -obj-y += pcm038.o diff --git a/board/pcm038/config.h b/board/pcm038/config.h deleted file mode 100644 index c2f5e7c..0000000 --- a/board/pcm038/config.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 - */ - -/** - * @file - * @brief Global defintions for the ARM i.MX27 based pcm038 - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#endif /* __CONFIG_H */ diff --git a/board/pcm038/env/config b/board/pcm038/env/config deleted file mode 100644 index a8be5c9..0000000 --- a/board/pcm038/env/config +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -machine=pcm038 -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 'net', 'nor' or 'nand' -kernel_loc=net -# 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=ttymxc0,115200" - -nor_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nor=3 - -nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nand=7 - -# set a fancy prompt (if support is compiled in) -PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m " - diff --git a/board/pcm038/lowlevel.c b/board/pcm038/lowlevel.c deleted file mode 100644 index 0c376f2..0000000 --- a/board/pcm038/lowlevel.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void __bare_init __naked insdram(void) -{ - uint32_t r; - - PCCR1 |= PCCR1_NFC_BAUDEN; - - /* setup a stack to be able to call imx_nand_load_image() */ - r = STACK_BASE + STACK_SIZE - 12; - __asm__ __volatile__("mov sp, %0" : : "r"(r)); - - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); - - board_init_lowlevel_return(); -} - -#define ESDCTL0_VAL (ESDCTL0_SDE | ESDCTL0_ROW13 | ESDCTL0_COL10) - -void __bare_init __naked board_init_lowlevel(void) -{ - uint32_t r; - int i; - unsigned int *trg, *src; - - /* ahb lite ip interface */ - AIPI1_PSR0 = 0x20040304; - AIPI1_PSR1 = 0xDFFBFCFB; - AIPI2_PSR0 = 0x00000000; - AIPI2_PSR1 = 0xFFFFFFFF; - - /* Skip SDRAM initialization if we run from RAM */ - r = get_pc(); - if (r > 0xa0000000 && r < 0xb0000000) - board_init_lowlevel_return(); - - /* - * DDR on CSD0 - */ - writel(0x00000008, ESDMISC); /* Enable DDR SDRAM operation */ - - DSCR(3) = 0x55555555; /* Set the driving strength */ - DSCR(5) = 0x55555555; - DSCR(6) = 0x55555555; - DSCR(7) = 0x00005005; - DSCR(8) = 0x15555555; - - writel(0x00000004, ESDMISC); /* Initial reset */ - writel(0x006ac73a, ESDCFG0); - - writel(ESDCTL0_VAL | ESDCTL0_SMODE_PRECHARGE, ESDCTL0); /* precharge CSD0 all banks */ - writel(0x00000000, 0xA0000F00); /* CSD0 precharge address (A10 = 1) */ - writel(ESDCTL0_VAL | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0); - - for (i = 0; i < 8; i++) - writel(0, 0xa0000f00); - - writel(ESDCTL0_VAL | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0); - - writeb(0xda, 0xa0000033); - writeb(0xff, 0xa1000000); - writel(ESDCTL0_VAL | ESDCTL0_DSIZ_31_0 | ESDCTL0_REF4 | - ESDCTL0_BL | ESDCTL0_SMODE_NORMAL, ESDCTL0); - -#ifdef CONFIG_NAND_IMX_BOOT - /* skip NAND boot if not running from NFC space */ - r = get_pc(); - if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x800) - board_init_lowlevel_return(); - - src = (unsigned int *)IMX_NFC_BASE; - trg = (unsigned int *)TEXT_BASE; - - /* Move ourselves out of NFC SRAM */ - for (i = 0; i < 0x800 / sizeof(int); i++) - *trg++ = *src++; - - /* Jump to SDRAM */ - r = (unsigned int)&insdram; - __asm__ __volatile__("mov pc, %0" : : "r"(r)); -#else - board_init_lowlevel_return(); -#endif -} - diff --git a/board/pcm038/pcm038.c b/board/pcm038/pcm038.c deleted file mode 100644 index 03794fc..0000000 --- a/board/pcm038/pcm038.c +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = 0xC0000000, - .size = 32 * 1024 * 1024, -}; - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0xa0000000, - .size = 128 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -static struct memory_platform_data sram_pdata = { - .name = "sram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sram_dev = { - .name = "mem", - .map_base = 0xc8000000, - .size = 512 * 1024, /* Can be up to 2MiB */ - .platform_data = &sram_pdata, -}; - -static struct fec_platform_data fec_info = { - .xcv_type = MII100, - .phy_addr = 1, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = 0x1002b000, - .platform_data = &fec_info, -}; - -static int pcm038_spi_cs[] = {GPIO_PORTD + 28}; - -static struct spi_imx_master pcm038_spi_0_data = { - .chipselect = pcm038_spi_cs, - .num_chipselect = ARRAY_SIZE(pcm038_spi_cs), -}; - -static struct device_d spi_dev = { - .name = "imx_spi", - .map_base = 0x1000e000, - .platform_data = &pcm038_spi_0_data, -}; - -static struct spi_board_info pcm038_spi_board_info[] = { - { - .name = "mc13783", - .max_speed_hz = 3000000, - .bus_num = 0, - .chip_select = 0, - } -}; - -static struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, - .flash_bbt = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = 0xd8000000, - .platform_data = &nand_info, -}; - -static struct imx_fb_videomode imxfb_mode = { - .mode = { - .name = "Sharp-LQ035Q7", - .refresh = 60, - .xres = 240, - .yres = 320, - .pixclock = 188679, /* in ps (5.3MHz) */ - .hsync_len = 7, - .left_margin = 5, - .right_margin = 16, - .vsync_len = 1, - .upper_margin = 7, - .lower_margin = 9, - }, - /* - * - HSYNC active high - * - VSYNC active high - * - clk notenabled while idle - * - clock not inverted - * - data not inverted - * - data enable low active - * - enable sharp mode - */ - .pcr = 0xF00080C0, - .bpp = 16, -}; - -static struct imx_fb_platform_data pcm038_fb_data = { - .mode = &imxfb_mode, - .pwmr = 0x00A903FF, - .lscr1 = 0x00120300, - .dmacr = 0x00020010, -}; - -static struct device_d imxfb_dev = { - .name = "imxfb", - .map_base = 0x10021000, - .size = 0x1000, - .platform_data = &pcm038_fb_data, -}; - -#ifdef CONFIG_USB -static struct device_d usbh2_dev = { - .name = "ehci", - .map_base = IMX_OTG_BASE + 0x400, - .size = 0x200, -}; - -static void pcm038_usbh_init(void) -{ - uint32_t temp; - - temp = readl(IMX_OTG_BASE + 0x600); - temp &= ~((3 << 21) | 1); - temp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20); - writel(temp, IMX_OTG_BASE + 0x600); - - temp = readl(IMX_OTG_BASE + 0x584); - temp &= ~(3 << 30); - temp |= 2 << 30; - writel(temp, IMX_OTG_BASE + 0x584); - - mdelay(10); - - isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x570), 1); -} -#endif - -#ifdef CONFIG_MMU -static void pcm038_mmu_init(void) -{ - mmu_init(); - - arm_create_section(0xa0000000, 0xa0000000, 128, PMD_SECT_DEF_CACHED); - arm_create_section(0xb0000000, 0xa0000000, 128, PMD_SECT_DEF_UNCACHED); - - setup_dma_coherent(0x10000000); - -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); -} -#else -static void pcm038_mmu_init(void) -{ -} -#endif - -static int pcm038_devices_init(void) -{ - int i; - char *envdev; - - unsigned int mode[] = { - PD0_AIN_FEC_TXD0, - PD1_AIN_FEC_TXD1, - PD2_AIN_FEC_TXD2, - PD3_AIN_FEC_TXD3, - PD4_AOUT_FEC_RX_ER, - PD5_AOUT_FEC_RXD1, - PD6_AOUT_FEC_RXD2, - PD7_AOUT_FEC_RXD3, - PD8_AF_FEC_MDIO, - PD9_AIN_FEC_MDC | GPIO_PUEN, - PD10_AOUT_FEC_CRS, - PD11_AOUT_FEC_TX_CLK, - PD12_AOUT_FEC_RXD0, - PD13_AOUT_FEC_RX_DV, - PD14_AOUT_FEC_RX_CLK, - PD15_AOUT_FEC_COL, - PD16_AIN_FEC_TX_ER, - PF23_AIN_FEC_TX_EN, - PE12_PF_UART1_TXD, - PE13_PF_UART1_RXD, - PE14_PF_UART1_CTS, - PE15_PF_UART1_RTS, - PD25_PF_CSPI1_RDY, - GPIO_PORTD | 28 | GPIO_GPIO | GPIO_OUT, - PD29_PF_CSPI1_SCLK, - PD30_PF_CSPI1_MISO, - PD31_PF_CSPI1_MOSI, - /* display */ - PA5_PF_LSCLK, - PA6_PF_LD0, - PA7_PF_LD1, - PA8_PF_LD2, - PA9_PF_LD3, - PA10_PF_LD4, - PA11_PF_LD5, - PA12_PF_LD6, - PA13_PF_LD7, - PA14_PF_LD8, - PA15_PF_LD9, - PA16_PF_LD10, - PA17_PF_LD11, - PA18_PF_LD12, - PA19_PF_LD13, - PA20_PF_LD14, - PA21_PF_LD15, - PA22_PF_LD16, - PA23_PF_LD17, - PA24_PF_REV, - PA25_PF_CLS, - PA26_PF_PS, - PA27_PF_SPL_SPR, - PA28_PF_HSYNC, - PA29_PF_VSYNC, - PA30_PF_CONTRAST, - PA31_PF_OE_ACD, - /* USB host 2 */ - PA0_PF_USBH2_CLK, - PA1_PF_USBH2_DIR, - PA2_PF_USBH2_DATA7, - PA3_PF_USBH2_NXT, - PA4_PF_USBH2_STP, - PD19_AF_USBH2_DATA4, - PD20_AF_USBH2_DATA3, - PD21_AF_USBH2_DATA6, - PD22_AF_USBH2_DATA0, - PD23_AF_USBH2_DATA2, - PD24_AF_USBH2_DATA1, - PD26_AF_USBH2_DATA5, - }; - - pcm038_mmu_init(); - - /* configure 16 bit nor flash on cs0 */ - CS0U = 0x0000CC03; - CS0L = 0xa0330D01; - CS0A = 0x00220800; - - /* configure SRAM on cs1 */ - CS1U = 0x0000d843; - CS1L = 0x22252521; - CS1A = 0x22220a00; - - /* configure SJA1000 on cs4 */ - CS4U = 0x0000DCF6; - CS4L = 0x444A0301; - CS4A = 0x44443302; - - /* initizalize gpios */ - for (i = 0; i < ARRAY_SIZE(mode); i++) - imx_gpio_mode(mode[i]); - - PCCR0 |= PCCR0_CSPI1_EN; - PCCR1 |= PCCR1_PERCLK2_EN; - - gpio_direction_output(GPIO_PORTD | 28, 0); - gpio_set_value(GPIO_PORTD | 28, 0); - spi_register_board_info(pcm038_spi_board_info, ARRAY_SIZE(pcm038_spi_board_info)); - register_device(&spi_dev); - - register_device(&cfi_dev); - register_device(&nand_dev); - register_device(&sdram_dev); - register_device(&sram_dev); - register_device(&imxfb_dev); - -#ifdef CONFIG_USB - pcm038_usbh_init(); - register_device(&usbh2_dev); -#endif - - /* Register the fec device after the PLL re-initialisation - * as the fec depends on the (now higher) ipg clock - */ - register_device(&fec_dev); - - switch ((GPCR & GPCR_BOOT_MASK) >> GPCR_BOOT_SHIFT) { - case GPCR_BOOT_8BIT_NAND_2k: - case GPCR_BOOT_16BIT_NAND_2k: - case GPCR_BOOT_16BIT_NAND_512: - case GPCR_BOOT_8BIT_NAND_512: - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - envdev = "NAND"; - break; - default: - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); - protect_file("/dev/env0", 1); - - envdev = "NOR"; - } - - printf("Using environment in %s Flash\n", envdev); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0xa0000100); - armlinux_set_architecture(MACH_TYPE_PCM038); - - return 0; -} - -device_initcall(pcm038_devices_init); - -static struct device_d pcm038_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; - -static int pcm038_console_init(void) -{ - /* bring PLLs to reset default */ - MPCTL0 = 0x00211803; - SPCTL0 = 0x1002700c; - CSCR = 0x33fc1307; - - register_device(&pcm038_serial_device); - - return 0; -} - -console_initcall(pcm038_console_init); - -extern void *pcm038_pll_init, *pcm038_pll_init_end; - -static int pcm038_power_init(void) -{ - int ret; - void *vram = 0xffff4c00; - void (*pllfunc)(void) = vram; - - printf("initialising PLLs: 0x%p 0x%p\n", &pcm038_pll_init); - - memcpy(vram, &pcm038_pll_init, 0x100); - - console_flush(); - - ret = pmic_power(); - if (ret) { - printf("Failed to initialize PMIC. Will continue with low CPU speed\n"); - return 0; - } - - /* wait for good power level */ - udelay(100000); - - pllfunc(); - - /* clock gating enable */ - GPCR = 0x00050f08; - - PCDR0 = 0x130410c3; - PCDR1 = 0x09030911; - - /* Clocks have changed. Notify clients */ - clock_notifier_call_chain(); - - return 0; -} - -late_initcall(pcm038_power_init); - diff --git a/board/pcm038/pcm038.dox b/board/pcm038/pcm038.dox deleted file mode 100644 index 9b17674..0000000 --- a/board/pcm038/pcm038.dox +++ /dev/null @@ -1,8 +0,0 @@ -/** @page pcm038 Phytec's phyCORE-i.MX27 - -This CPU card is based on a Freescale i.MX27 CPU. The card is shipped with: - -- up to 32MiB NOR type Flash Memory -- 32MiB synchronous dynamic RAM - -*/ diff --git a/board/pcm038/pll_init.S b/board/pcm038/pll_init.S deleted file mode 100644 index 0c1ff13..0000000 --- a/board/pcm038/pll_init.S +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#define CSCR_VAL CSCR_USB_DIV(3) | \ - CSCR_SD_CNT(3) | \ - CSCR_MSHC_SEL | \ - CSCR_H264_SEL | \ - CSCR_SSI1_SEL | \ - CSCR_SSI2_SEL | \ - CSCR_MCU_SEL | \ - CSCR_ARM_SRC_MPLL | \ - CSCR_SP_SEL | \ - CSCR_ARM_DIV(0) | \ - CSCR_FPM_EN | \ - CSCR_SPEN | \ - CSCR_MPEN | \ - CSCR_AHB_DIV(1) - -ENTRY(pcm038_pll_init) - - writel(IMX_PLL_PD(0) | - IMX_PLL_MFD(51) | - IMX_PLL_MFI(7) | - IMX_PLL_MFN(35), MPCTL0) /* 399 MHz */ - - writel(IMX_PLL_PD(1) | - IMX_PLL_MFD(12) | - IMX_PLL_MFI(9) | - IMX_PLL_MFN(3), SPCTL0) /* SPLL = 2 * 26 * 4.61538 MHz = 240 MHz */ - - writel(CSCR_VAL | CSCR_MPLL_RESTART | CSCR_SPLL_RESTART, CSCR) - - ldr r2, =16000 -1: - subs r2, r2, #1 - nop - bcs 1b - - mov pc, lr -ENDPROC(pcm038_pll_init) - diff --git a/board/pcm043/Makefile b/board/pcm043/Makefile deleted file mode 100644 index 6753bbe..0000000 --- a/board/pcm043/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# -# (C) Copyright 2007 Juergen Beisert -# -# 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 -# - -obj-y += lowlevel.o -obj-y += pcm043.o diff --git a/board/pcm043/config.h b/board/pcm043/config.h deleted file mode 100644 index 0e3b175..0000000 --- a/board/pcm043/config.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * (C) Copyright 2007 Juergen Beisert - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -/* - * Definitions related to passing arguments to kernel. - */ - -#define CONFIG_MX35_HCLK_FREQ 24000000 - -#endif - -/* nothing to do here yet */ diff --git a/board/pcm043/env/config b/board/pcm043/env/config deleted file mode 100644 index 212b6a9..0000000 --- a/board/pcm043/env/config +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh - -machine=pcm043 -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 'net', 'nor' or 'nand' -kernel_loc=net -# 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=ttymxc0,115200" - -bootargs="$bootargs video=mx3fb:CTP-CLAA070LC0ACW" - -nor_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nor=3 - -nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nand=7 - -# set a fancy prompt (if support is compiled in) -PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m " - diff --git a/board/pcm043/lowlevel.c b/board/pcm043/lowlevel.c deleted file mode 100644 index 9eff5a6..0000000 --- a/board/pcm043/lowlevel.c +++ /dev/null @@ -1,214 +0,0 @@ -/* - * - * (c) 2007 Pengutronix, Sascha Hauer - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Assuming 24MHz input clock */ -#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) -#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) -#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) - -static void __bare_init __naked insdram(void) -{ - uint32_t r; - - /* Speed up NAND controller by adjusting the NFC divider */ - r = readl(IMX_CCM_BASE + CCM_PDR4); - r &= ~(0xf << 28); - r |= 0x1 << 28; - writel(r, IMX_CCM_BASE + CCM_PDR4); - - /* setup a stack to be able to call imx_nand_load_image() */ - r = STACK_BASE + STACK_SIZE - 12; - __asm__ __volatile__("mov sp, %0" : : "r"(r)); - - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); - - board_init_lowlevel_return(); -} - -void __bare_init __naked board_init_lowlevel(void) -{ - uint32_t r, s; - unsigned long ccm_base = IMX_CCM_BASE; - unsigned long iomuxc_base = IMX_IOMUXC_BASE; - unsigned int *trg, *src; - int i; - - r = get_cr(); - r |= CR_Z; /* Flow prediction (Z) */ - r |= CR_U; /* unaligned accesses */ - r |= CR_FI; /* Low Int Latency */ - - __asm__ __volatile__("mrc p15, 0, %0, c1, c0, 1":"=r"(s)); - s |= 0x7; - __asm__ __volatile__("mcr p15, 0, %0, c1, c0, 1" : : "r"(s)); - - set_cr(r); - - r = 0; - __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); - - /* - * Branch predicition is now enabled. Flush the BTAC to ensure a valid - * starting point. Don't flush BTAC while it is disabled to avoid - * ARM1136 erratum 408023. - */ - __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 6" : : "r"(r)); - - /* invalidate I cache and D cache */ - __asm__ __volatile__("mcr p15, 0, %0, c7, c7, 0" : : "r"(r)); - - /* invalidate TLBs */ - __asm__ __volatile__("mcr p15, 0, %0, c8, c7, 0" : : "r"(r)); - - /* Drain the write buffer */ - __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4" : : "r"(r)); - - /* Also setup the Peripheral Port Remap register inside the core */ - r = 0x40000015; /* start from AIPS 2GB region */ - __asm__ __volatile__("mcr p15, 0, %0, c15, c2, 4" : : "r"(r)); - - /* - * End of ARM1136 init - */ - - writel(0x003F4208, ccm_base + CCM_CCMR); - - /* Set MPLL , arm clock and ahb clock*/ - writel(MPCTL_PARAM_532, ccm_base + CCM_MPCTL); - - writel(PPCTL_PARAM_300, ccm_base + CCM_PPCTL); - writel(0x00001000, ccm_base + CCM_PDR0); - - r = readl(ccm_base + CCM_CGR0); - r |= 0x00300000; - writel(r, ccm_base + CCM_CGR0); - - r = readl(ccm_base + CCM_CGR1); - r |= 0x00000C00; - r |= 0x00000003; - writel(r, ccm_base + CCM_CGR1); - - r = readl(IMX_L2CC_BASE + L2X0_AUX_CTRL); - r |= 0x1000; - writel(r, IMX_L2CC_BASE + L2X0_AUX_CTRL); - - /* Skip SDRAM initialization if we run from RAM */ - r = get_pc(); - if (r > 0x80000000 && r < 0x90000000) - board_init_lowlevel_return(); - - /* Set DDR Type to SDRAM, drive strength workaround * - * 0x00000000 MDDR * - * 0x00000800 3,3V SDRAM */ - - r = 0x00000800; - writel(r, iomuxc_base + 0x794); - writel(r, iomuxc_base + 0x798); - writel(r, iomuxc_base + 0x79c); - writel(r, iomuxc_base + 0x7a0); - writel(r, iomuxc_base + 0x7a4); - - /* MDDR init, enable mDDR*/ - writel(0x00000304, ESDMISC); /* was 0x00000004 */ - - /* set timing paramters */ - writel(0x00255417, ESDCFG0); - /* select Precharge-All mode */ - writel(0x92220000, ESDCTL0); - /* Precharge-All */ - writel(0x12345678, IMX_SDRAM_CS0 + 0x400); - - /* select Load-Mode-Register mode */ - writel(0xB8001000, ESDCTL0); - /* Load reg EMR2 */ - writeb(0xda, 0x84000000); - /* Load reg EMR3 */ - writeb(0xda, 0x86000000); - /* Load reg EMR1 -- enable DLL */ - writeb(0xda, 0x82000400); - /* Load reg MR -- reset DLL */ - writeb(0xda, 0x80000333); - - /* select Precharge-All mode */ - writel(0x92220000, ESDCTL0); - /* Precharge-All */ - writel(0x12345678, IMX_SDRAM_CS0 + 0x400); - - /* select Manual-Refresh mode */ - writel(0xA2220000, ESDCTL0); - /* Manual-Refresh 2 times */ - writel(0x87654321, IMX_SDRAM_CS0); - writel(0x87654321, IMX_SDRAM_CS0); - - /* select Load-Mode-Register mode */ - writel(0xB2220000, ESDCTL0); - /* Load reg MR -- CL3, BL8, end DLL reset */ - writeb(0xda, 0x80000233); - /* Load reg EMR1 -- OCD default */ - writeb(0xda, 0x82000780); - /* Load reg EMR1 -- OCD exit */ - writeb(0xda, 0x82000400); - - /* select normal-operation mode - * DSIZ32-bit, BL8, COL10-bit, ROW13-bit - * disable PWT & PRCT - * disable Auto-Refresh */ - writel(0x82220080, ESDCTL0); - - /* enable Auto-Refresh */ - writel(0x82228080, ESDCTL0); - /* enable Auto-Refresh */ - writel(0x00002000, ESDCTL1); - -#ifdef CONFIG_NAND_IMX_BOOT - /* skip NAND boot if not running from NFC space */ - r = get_pc(); - if (r < IMX_NFC_BASE || r > IMX_NFC_BASE + 0x800) - board_init_lowlevel_return(); - - src = (unsigned int *)IMX_NFC_BASE; - trg = (unsigned int *)TEXT_BASE; - - /* Move ourselves out of NFC SRAM */ - for (i = 0; i < 0x800 / sizeof(int); i++) - *trg++ = *src++; - - /* Jump to SDRAM */ - r = (unsigned int)&insdram; - __asm__ __volatile__("mov pc, %0" : : "r"(r)); -#else - board_init_lowlevel_return(); -#endif -} - diff --git a/board/pcm043/pcm043.c b/board/pcm043/pcm043.c deleted file mode 100644 index dd178ed..0000000 --- a/board/pcm043/pcm043.c +++ /dev/null @@ -1,392 +0,0 @@ -/* - * (C) 2007 Pengutronix, Sascha Hauer - * (C) 2009 Pengutronix, Juergen Beisert - * - * 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 - * - * Board support for Phytec's, i.MX35 based CPU card, called: PCM043 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CYG_MACRO_START -#define CYG_MACRO_END -#define ARM_MMU_FIRST_LEVEL_SECTION_ID 0x2 -#define ARM_MMU_FIRST_LEVEL_DESCRIPTOR_ADDRESS(ttb_base, table_index) \ - (unsigned long *)((unsigned long)(ttb_base) + ((table_index) << 2)) - -/* - * Up to 32MiB NOR type flash, connected to - * CS line 0, data width is 16 bit - */ -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = IMX_CS0_BASE, - .size = 32 * 1024 * 1024, /* area size */ -}; - -static struct fec_platform_data fec_info = { - .xcv_type = MII100, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = IMX_FEC_BASE, - .platform_data = &fec_info, -}; - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram0_dev = { - .name = "mem", - .map_base = IMX_SDRAM_CS0, - .size = 128 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, - .flash_bbt = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = IMX_NFC_BASE, - .platform_data = &nand_info, -}; - -#ifdef CONFIG_PCM043_DISPLAY_SHARP -static const struct fb_videomode pcm043_fb_mode = { - /* 240x320 @ 60 Hz */ - .name = "Sharp-LQ035Q7", - .refresh = 60, - .xres = 240, - .yres = 320, - .pixclock = 185925, - .left_margin = 9, - .right_margin = 16, - .upper_margin = 7, - .lower_margin = 9, - .hsync_len = 1, - .vsync_len = 1, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_SHARP_MODE | FB_SYNC_CLK_INVERT | FB_SYNC_CLK_IDLE_EN, - .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, -}; -#else -static const struct fb_videomode pcm043_fb_mode = { - /* 240x320 @ 60 Hz */ - .name = "TX090", - .refresh = 60, - .xres = 240, - .yres = 320, - .pixclock = 38255, - .left_margin = 144, - .right_margin = 0, - .upper_margin = 7, - .lower_margin = 40, - .hsync_len = 96, - .vsync_len = 1, - .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_OE_ACT_HIGH, - .vmode = FB_VMODE_NONINTERLACED, - .flag = 0, -}; -#endif - -static struct imx_ipu_fb_platform_data ipu_fb_data = { - .mode = &pcm043_fb_mode, - .bpp = 16, -}; - -static struct device_d imx_ipu_fb_dev = { - .name = "imx-ipu-fb", - .map_base = 0x53fc0000, - .size = 0x1000, - .platform_data = &ipu_fb_data, -}; - -#ifdef CONFIG_MMU -static int pcm043_mmu_init(void) -{ - mmu_init(); - - arm_create_section(0x80000000, 0x80000000, 128, PMD_SECT_DEF_CACHED); - arm_create_section(0x90000000, 0x80000000, 128, PMD_SECT_DEF_UNCACHED); - - setup_dma_coherent(0x10000000); - -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - - mmu_enable(); - -#ifdef CONFIG_CACHE_L2X0 - l2x0_init((void __iomem *)0x30000000, 0x00030024, 0x00000000); -#endif - return 0; -} -postcore_initcall(pcm043_mmu_init); -#endif - -static int imx35_devices_init(void) -{ - uint32_t reg; - - /* CS0: Nor Flash */ - writel(0x0000cf03, CSCR_U(0)); - writel(0x10000d03, CSCR_L(0)); - writel(0x00720900, CSCR_A(0)); - - reg = readl(IMX_CCM_BASE + CCM_RCSR); - /* some fuses provide us vital information about connected hardware */ - if (reg & 0x20000000) - nand_info.width = 2; /* 16 bit */ - else - nand_info.width = 1; /* 8 bit */ - - register_device(&fec_dev); - /* - * This platform supports NOR and NAND - */ - register_device(&nand_dev); - register_device(&cfi_dev); - - if ((reg & 0xc00) == 0x800) { /* reset mode: external boot */ - switch ( (reg >> 25) & 0x3) { - case 0x01: /* NAND is the source */ - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - break; - - case 0x00: /* NOR is the source */ - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); /* ourself */ - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); /* environment */ - protect_file("/dev/env0", 1); - break; - } - } - - register_device(&sdram0_dev); - register_device(&imx_ipu_fb_dev); - - armlinux_add_dram(&sdram0_dev); - armlinux_set_bootparams((void *)0x80000100); - armlinux_set_architecture(MACH_TYPE_PCM043); - - return 0; -} - -device_initcall(imx35_devices_init); - -static struct device_d imx35_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 16 * 1024, -}; - -static struct pad_desc pcm043_pads[] = { - MX35_PAD_FEC_TX_CLK__FEC_TX_CLK, - MX35_PAD_FEC_RX_CLK__FEC_RX_CLK, - MX35_PAD_FEC_RX_DV__FEC_RX_DV, - MX35_PAD_FEC_COL__FEC_COL, - MX35_PAD_FEC_RDATA0__FEC_RDATA_0, - MX35_PAD_FEC_TDATA0__FEC_TDATA_0, - MX35_PAD_FEC_TX_EN__FEC_TX_EN, - MX35_PAD_FEC_MDC__FEC_MDC, - MX35_PAD_FEC_MDIO__FEC_MDIO, - MX35_PAD_FEC_TX_ERR__FEC_TX_ERR, - MX35_PAD_FEC_RX_ERR__FEC_RX_ERR, - MX35_PAD_FEC_CRS__FEC_CRS, - MX35_PAD_FEC_RDATA0__FEC_RDATA_0, - MX35_PAD_FEC_TDATA0__FEC_TDATA_0, - MX35_PAD_FEC_RDATA1__FEC_RDATA_1, - MX35_PAD_FEC_TDATA1__FEC_TDATA_1, - MX35_PAD_FEC_RDATA2__FEC_RDATA_2, - MX35_PAD_FEC_TDATA2__FEC_TDATA_2, - MX35_PAD_FEC_RDATA3__FEC_RDATA_3, - MX35_PAD_FEC_TDATA3__FEC_TDATA_3, - MX35_PAD_RXD1__UART1_RXD_MUX, - MX35_PAD_TXD1__UART1_TXD_MUX, - MX35_PAD_RTS1__UART1_RTS, - MX35_PAD_CTS1__UART1_CTS, - MX35_PAD_I2C1_CLK__I2C1_SCL, - MX35_PAD_I2C1_DAT__I2C1_SDA -}; - -static int imx35_console_init(void) -{ - mxc_iomux_v3_setup_multiple_pads(pcm043_pads, ARRAY_SIZE(pcm043_pads)); - - register_device(&imx35_serial_device); - return 0; -} - -console_initcall(imx35_console_init); - -static int pcm043_core_setup(void) -{ - u32 tmp; - - /* AIPS setup - Only setup MPROTx registers. The PACR default values are good.*/ - /* - * Set all MPROTx to be non-bufferable, trusted for R/W, - * not forced to user-mode. - */ - writel(0x77777777, IMX_AIPS1_BASE); - writel(0x77777777, IMX_AIPS1_BASE + 0x4); - writel(0x77777777, IMX_AIPS2_BASE); - writel(0x77777777, IMX_AIPS2_BASE + 0x4); - - /* - * Clear the on and off peripheral modules Supervisor Protect bit - * for SDMA to access them. Did not change the AIPS control registers - * (offset 0x20) access type - */ - writel(0x0, IMX_AIPS1_BASE + 0x40); - writel(0x0, IMX_AIPS1_BASE + 0x44); - writel(0x0, IMX_AIPS1_BASE + 0x48); - writel(0x0, IMX_AIPS1_BASE + 0x4C); - tmp = readl(IMX_AIPS1_BASE + 0x50); - tmp &= 0x00FFFFFF; - writel(tmp, IMX_AIPS1_BASE + 0x50); - - writel(0x0, IMX_AIPS2_BASE + 0x40); - writel(0x0, IMX_AIPS2_BASE + 0x44); - writel(0x0, IMX_AIPS2_BASE + 0x48); - writel(0x0, IMX_AIPS2_BASE + 0x4C); - tmp = readl(IMX_AIPS2_BASE + 0x50); - tmp &= 0x00FFFFFF; - writel(tmp, IMX_AIPS2_BASE + 0x50); - - /* MAX (Multi-Layer AHB Crossbar Switch) setup */ - - /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ -#define MAX_PARAM1 0x00302154 - writel(MAX_PARAM1, IMX_MAX_BASE + 0x0); /* for S0 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x100); /* for S1 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x200); /* for S2 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x300); /* for S3 */ - writel(MAX_PARAM1, IMX_MAX_BASE + 0x400); /* for S4 */ - - /* SGPCR - always park on last master */ - writel(0x10, IMX_MAX_BASE + 0x10); /* for S0 */ - writel(0x10, IMX_MAX_BASE + 0x110); /* for S1 */ - writel(0x10, IMX_MAX_BASE + 0x210); /* for S2 */ - writel(0x10, IMX_MAX_BASE + 0x310); /* for S3 */ - writel(0x10, IMX_MAX_BASE + 0x410); /* for S4 */ - - /* MGPCR - restore default values */ - writel(0x0, IMX_MAX_BASE + 0x800); /* for M0 */ - writel(0x0, IMX_MAX_BASE + 0x900); /* for M1 */ - writel(0x0, IMX_MAX_BASE + 0xa00); /* for M2 */ - writel(0x0, IMX_MAX_BASE + 0xb00); /* for M3 */ - writel(0x0, IMX_MAX_BASE + 0xc00); /* for M4 */ - writel(0x0, IMX_MAX_BASE + 0xd00); /* for M5 */ - - writel(0x0000DCF6, CSCR_U(0)); /* CS0: NOR Flash */ - writel(0x444A4541, CSCR_L(0)); - writel(0x44443302, CSCR_A(0)); - - /* - * M3IF Control Register (M3IFCTL) - * MRRP[0] = L2CC0 not on priority list (0 << 0) = 0x00000000 - * MRRP[1] = MAX1 not on priority list (0 << 0) = 0x00000000 - * MRRP[2] = L2CC1 not on priority list (0 << 0) = 0x00000000 - * MRRP[3] = USB not on priority list (0 << 0) = 0x00000000 - * MRRP[4] = SDMA not on priority list (0 << 0) = 0x00000000 - * MRRP[5] = GPU not on priority list (0 << 0) = 0x00000000 - * MRRP[6] = IPU1 on priority list (1 << 6) = 0x00000040 - * MRRP[7] = IPU2 not on priority list (0 << 0) = 0x00000000 - * ------------ - * 0x00000040 - */ - writel(0x40, IMX_M3IF_BASE); - - return 0; -} - -core_initcall(pcm043_core_setup); - -#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) -#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) - -static int do_cpufreq(struct command *cmdtp, int argc, char *argv[]) -{ - unsigned long freq; - - if (argc != 2) - return COMMAND_ERROR_USAGE; - - freq = simple_strtoul(argv[1], NULL, 0); - - switch (freq) { - case 399: - writel(MPCTL_PARAM_399, IMX_CCM_BASE + CCM_MPCTL); - break; - case 532: - writel(MPCTL_PARAM_532, IMX_CCM_BASE + CCM_MPCTL); - break; - default: - return COMMAND_ERROR_USAGE; - } - - printf("Switched CPU frequency to %dMHz\n", freq); - - return 0; -} - -static const __maybe_unused char cmd_cpufreq_help[] = -"Usage: cpufreq 399|532\n" -"\n" -"Set CPU frequency to MHz\n"; - -BAREBOX_CMD_START(cpufreq) - .cmd = do_cpufreq, - .usage = "adjust CPU frequency", - BAREBOX_CMD_HELP(cmd_cpufreq_help) -BAREBOX_CMD_END - diff --git a/board/pcm043/pcm043.dox b/board/pcm043/pcm043.dox deleted file mode 100644 index c6715ff..0000000 --- a/board/pcm043/pcm043.dox +++ /dev/null @@ -1,28 +0,0 @@ -/** @page pcm043 Phytec's phyCORE-i.MX35 - -This CPU card is based on a Freescale i.MX35 CPU. The card is shipped with: - - -FIXME: -- up to 64 MiB NOR type Flash Memory -- up to 2 MiB static RAM -- 1 GiB or 2 GiB NAND type Flash Memory - - Micron NAND 1 GiB 3,3V 8-bit - - 256 kiB block size - - ? kiB page size - - Manufacturer ID: 0x2c - - Device ID: 0xd3 - - Samsung K9K8G08, 1 GiB - - 128 kiB block size - - 2 kiB page size - - Manufacturer ID: ? - - Device ID: ? - - ST NAND08G, 1 GiB - - 128 kiB block size - - 2 kiB page size - - Manufacturer ID: ? - - Device ID: ? -- 128MiB synchronous dynamic RAM - - -*/ diff --git a/board/phycard-i.MX27/Makefile b/board/phycard-i.MX27/Makefile deleted file mode 100644 index fd52350..0000000 --- a/board/phycard-i.MX27/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += lowlevel_init.o -obj-y += pca100.o diff --git a/board/phycard-i.MX27/config.h b/board/phycard-i.MX27/config.h deleted file mode 100644 index c2f5e7c..0000000 --- a/board/phycard-i.MX27/config.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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 - */ - -/** - * @file - * @brief Global defintions for the ARM i.MX27 based pcm038 - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#endif /* __CONFIG_H */ diff --git a/board/phycard-i.MX27/env/config b/board/phycard-i.MX27/env/config deleted file mode 100644 index d0670de..0000000 --- a/board/phycard-i.MX27/env/config +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/sh - -machine=pca100 -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 'net', 'nor' or 'nand' -kernel_loc=net -# 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=ttymxc0,115200" - -nand_parts="256k(barebox)ro,128k(bareboxenv),2M(kernel),-(root)" -rootfs_mtdblock_nand=7 - -# set a fancy prompt (if support is compiled in) -PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m " - - diff --git a/board/phycard-i.MX27/lowlevel_init.S b/board/phycard-i.MX27/lowlevel_init.S deleted file mode 100644 index 9349581..0000000 --- a/board/phycard-i.MX27/lowlevel_init.S +++ /dev/null @@ -1,129 +0,0 @@ -/* - * For clock initialization, see chapter 3 of the "MCIMX27 Multimedia - * Applications Processor Reference Manual, Rev. 0.2". - * - */ - -#include -#include -#include - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - - -#define ESDCTL0_VAL (ESDCTL0_SDE | ESDCTL0_ROW13 | ESDCTL0_COL10) - -.macro sdram_init - /* - * DDR on CSD0 - */ - writel(0x00000008, ESDMISC) /* Enable DDR SDRAM operation */ - - writel(0x55555555, DSCR(3)) /* Set the driving strength */ - writel(0x55555555, DSCR(5)) - writel(0x55555555, DSCR(6)) - writel(0x00005005, DSCR(7)) - writel(0x15555555, DSCR(8)) - - writel(0x00000004, ESDMISC) /* Initial reset */ - writel(0x006ac73a, ESDCFG0) - - writel(ESDCTL0_VAL | ESDCTL0_SMODE_PRECHARGE, ESDCTL0) /* precharge CSD0 all banks */ - writel(0x00000000, 0xA0000F00) /* CSD0 precharge address (A10 = 1) */ - writel(ESDCTL0_VAL | ESDCTL0_SMODE_AUTO_REFRESH, ESDCTL0) - - ldr r0, =0xa0000f00 - mov r1, #0 - mov r2, #8 -1: - str r1, [r0] - subs r2, #1 - bne 1b - - writel(ESDCTL0_VAL | ESDCTL0_SMODE_LOAD_MODE, ESDCTL0) - ldr r0, =0xA0000033 - mov r1, #0xda - strb r1, [r0] - ldr r0, =0xA1000000 - mov r1, #0xff - strb r1, [r0] - writel(ESDCTL0_VAL | ESDCTL0_DSIZ_31_0 | ESDCTL0_REF4 | ESDCTL0_BL | ESDCTL0_SMODE_NORMAL, ESDCTL0) -.endm - - .section ".text_bare_init","ax" - -.globl board_init_lowlevel -board_init_lowlevel: - - mov r10, lr - - /* ahb lite ip interface */ - writel(0x20040304, AIPI1_PSR0) - writel(0xDFFBFCFB, AIPI1_PSR1) - writel(0x00000000, AIPI2_PSR0) - writel(0xFFFFFFFF, AIPI2_PSR1) - - /* skip sdram initialization if we run from ram */ - cmp pc, #0xa0000000 - bls 1f - cmp pc, #0xc0000000 - bhi 1f - - mov pc,r10 - -1: - writel(IMX_PLL_PD(0) | - IMX_PLL_MFD(51) | - IMX_PLL_MFI(7) | - IMX_PLL_MFN(35), MPCTL0) /* 399 MHz */ - - writel(IMX_PLL_PD(1) | - IMX_PLL_MFD(12) | - IMX_PLL_MFI(9) | - IMX_PLL_MFN(3), SPCTL0) /* SPLL = 2 * 26 * 4.61538 MHz = 240 MHz */ - - writel(CSCR_MPLL_RESTART | CSCR_SPLL_RESTART | CSCR_ARM_SRC_MPLL | - CSCR_MCU_SEL | CSCR_SP_SEL | CSCR_FPM_EN | CSCR_MPEN | - CSCR_SPEN | CSCR_ARM_DIV(0) | CSCR_AHB_DIV(1) | CSCR_USB_DIV(3) | - CSCR_SD_CNT(3) | CSCR_SSI2_SEL | CSCR_SSI1_SEL | CSCR_H264_SEL | - CSCR_MSHC_SEL, CSCR) - - sdram_init - -#ifdef CONFIG_NAND_IMX_BOOT - ldr sp, =0xa0f00000 /* Setup a temporary stack in SDRAM */ - - ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ - ldr r2, =IMX_NFC_BASE + 0x1000 /* end of NFC SRAM */ - - /* skip NAND boot if not running from NFC space */ - cmp pc, r0 - bls ret - cmp pc, r2 - bhi ret - - /* Move ourselves out of NFC SRAM */ - ldr r1, =TEXT_BASE - -copy_loop: - ldmia r0!, {r3-r9} /* copy from source address [r0] */ - stmia r1!, {r3-r9} /* copy to target address [r1] */ - cmp r0, r2 /* until source end addreee [r2] */ - ble copy_loop - - ldr pc, =1f /* Jump to SDRAM */ -1: - bl nand_boot /* Load barebox from NAND Flash */ - - ldr r1, =IMX_NFC_BASE - TEXT_BASE - sub r10, r10, r1 /* adjust return address from NFC SRAM */ - /* to SDRAM */ - -#endif /* CONFIG_NAND_IMX_BOOT */ - -ret: - mov pc,r10 - diff --git a/board/phycard-i.MX27/pca100.c b/board/phycard-i.MX27/pca100.c deleted file mode 100644 index ce59960..0000000 --- a/board/phycard-i.MX27/pca100.c +++ /dev/null @@ -1,239 +0,0 @@ - /* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0xa0000000, - .size = 128 * 1024 * 1024, - .platform_data = &ram_pdata, -}; - -static struct fec_platform_data fec_info = { - .xcv_type = MII100, - .phy_addr = 1, -}; - -static struct device_d fec_dev = { - .name = "fec_imx", - .map_base = 0x1002b000, - .platform_data = &fec_info, -}; - -struct imx_nand_platform_data nand_info = { - .width = 1, - .hw_ecc = 1, -}; - -static struct device_d nand_dev = { - .name = "imx_nand", - .map_base = 0xd8000000, - .platform_data = &nand_info, -}; - -#ifdef CONFIG_USB -static struct device_d usbh2_dev = { - .name = "ehci", - .map_base = IMX_OTG_BASE + 0x400, - .size = 0x200, -}; - -static void pca100_usbh_init(void) -{ - uint32_t temp; - - temp = readl(IMX_OTG_BASE + 0x600); - temp &= ~((3 << 21) | 1); - temp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 11) | (1 << 20); - writel(temp, IMX_OTG_BASE + 0x600); - - temp = readl(IMX_OTG_BASE + 0x584); - temp &= ~(3 << 30); - temp |= 2 << 30; - writel(temp, IMX_OTG_BASE + 0x584); - - mdelay(10); - - gpio_direction_output(GPIO_PORTB + 24, 0); - - mdelay(10); - - isp1504_set_vbus_power((void *)(IMX_OTG_BASE + 0x570), 1); -} -#endif - -#ifdef CONFIG_MMU -static void pca100_mmu_init(void) -{ - mmu_init(); - - arm_create_section(0xa0000000, 0xa0000000, 128, PMD_SECT_DEF_CACHED); - arm_create_section(0xb0000000, 0xa0000000, 128, PMD_SECT_DEF_UNCACHED); - - setup_dma_coherent(0x10000000); - -#if TEXT_BASE & (0x100000 - 1) -#warning cannot create vector section. Adjust TEXT_BASE to a 1M boundary -#else - arm_create_section(0x0, TEXT_BASE, 1, PMD_SECT_DEF_UNCACHED); -#endif - mmu_enable(); -} -#else -static void pca100_mmu_init(void) -{ -} -#endif - -static int pca100_devices_init(void) -{ - int i; - struct device_d *nand; - - unsigned int mode[] = { - PD0_AIN_FEC_TXD0, - PD1_AIN_FEC_TXD1, - PD2_AIN_FEC_TXD2, - PD3_AIN_FEC_TXD3, - PD4_AOUT_FEC_RX_ER, - PD5_AOUT_FEC_RXD1, - PD6_AOUT_FEC_RXD2, - PD7_AOUT_FEC_RXD3, - PD8_AF_FEC_MDIO, - PD9_AIN_FEC_MDC | GPIO_PUEN, - PD10_AOUT_FEC_CRS, - PD11_AOUT_FEC_TX_CLK, - PD12_AOUT_FEC_RXD0, - PD13_AOUT_FEC_RX_DV, - PD14_AOUT_FEC_RX_CLK, - PD15_AOUT_FEC_COL, - PD16_AIN_FEC_TX_ER, - PF23_AIN_FEC_TX_EN, - PE12_PF_UART1_TXD, - PE13_PF_UART1_RXD, - PE14_PF_UART1_CTS, - PE15_PF_UART1_RTS, - PD25_PF_CSPI1_RDY, - PD26_PF_CSPI1_SS2, - PD27_PF_CSPI1_SS1, - PD28_PF_CSPI1_SS0, - PD29_PF_CSPI1_SCLK, - PD30_PF_CSPI1_MISO, - PD31_PF_CSPI1_MOSI, - /* USB host 2 */ - PA0_PF_USBH2_CLK, - PA1_PF_USBH2_DIR, - PA2_PF_USBH2_DATA7, - PA3_PF_USBH2_NXT, - PA4_PF_USBH2_STP, - PD19_AF_USBH2_DATA4, - PD20_AF_USBH2_DATA3, - PD21_AF_USBH2_DATA6, - PD22_AF_USBH2_DATA0, - PD23_AF_USBH2_DATA2, - PD24_AF_USBH2_DATA1, - PD26_AF_USBH2_DATA5, - }; - - /* disable the usb phys */ - imx_gpio_mode((GPIO_PORTB | 23) | GPIO_GPIO | GPIO_IN); - gpio_direction_output(GPIO_PORTB + 23, 1); - imx_gpio_mode((GPIO_PORTB | 24) | GPIO_GPIO | GPIO_IN); - gpio_direction_output(GPIO_PORTB + 24, 1); - - /* initizalize gpios */ - for (i = 0; i < ARRAY_SIZE(mode); i++) - imx_gpio_mode(mode[i]); - - register_device(&nand_dev); - register_device(&sdram_dev); - register_device(&fec_dev); - - PCCR1 |= PCCR1_PERCLK2_EN; - -#ifdef CONFIG_USB - pca100_usbh_init(); - register_device(&usbh2_dev); -#endif - - nand = get_device_by_name("nand0"); - devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); - dev_add_bb_dev("self_raw", "self0"); - - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); - dev_add_bb_dev("env_raw", "env0"); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0xa0000100); - armlinux_set_architecture(2149); - - return 0; -} - -device_initcall(pca100_devices_init); - -static struct device_d pca100_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; - -static int pca100_console_init(void) -{ - pca100_mmu_init(); - register_device(&pca100_serial_device); - return 0; -} - -console_initcall(pca100_console_init); - -#ifdef CONFIG_NAND_IMX_BOOT -void __bare_init nand_boot(void) -{ - imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); -} -#endif - diff --git a/board/phycard-i.MX27/pca100.dox b/board/phycard-i.MX27/pca100.dox deleted file mode 100644 index 9b17674..0000000 --- a/board/phycard-i.MX27/pca100.dox +++ /dev/null @@ -1,8 +0,0 @@ -/** @page pcm038 Phytec's phyCORE-i.MX27 - -This CPU card is based on a Freescale i.MX27 CPU. The card is shipped with: - -- up to 32MiB NOR type Flash Memory -- 32MiB synchronous dynamic RAM - -*/ diff --git a/board/phycore_mcf54xx/Makefile b/board/phycore_mcf54xx/Makefile deleted file mode 100644 index 054123f..0000000 --- a/board/phycore_mcf54xx/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# (C) Copyright 2007 Carsten Schlote -# See file CREDITS for list of people who contributed to this project. -# -# This file is part of barebox. -# -# barebox is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# barebox 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 barebox. If not, see . -# - -# The build system allows to split everything into distinct files covering an -# separate issue. Use that! - -# Board specific callbacks and initialisations - -obj-y += lowlevel_init.o -obj-y += highlevel_init.o -obj-y += phyCore_MCF54xx.o - -obj-y += pci-stubs.o - diff --git a/board/phycore_mcf54xx/env/bin/_update b/board/phycore_mcf54xx/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/phycore_mcf54xx/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/phycore_mcf54xx/env/bin/boot b/board/phycore_mcf54xx/env/bin/boot deleted file mode 100644 index c9fcbac..0000000 --- a/board/phycore_mcf54xx/env/bin/boot +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xflash ]; then - root=flash - kernel=flash -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xflash ]; then - bootargs="$bootargs root=$rootpart rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$mtdparts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootm /dev/nor0.kernel -fi - diff --git a/board/phycore_mcf54xx/env/bin/init b/board/phycore_mcf54xx/env/bin/init deleted file mode 100644 index 48e2139..0000000 --- a/board/phycore_mcf54xx/env/bin/init +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -addpart /dev/nor0 $mtdparts - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel [] to update kernel into flash" - echo "type udate_root [] to update rootfs into flash" - echo - exit -fi - -boot \ No newline at end of file diff --git a/board/phycore_mcf54xx/env/bin/pcidmaloop b/board/phycore_mcf54xx/env/bin/pcidmaloop deleted file mode 100644 index 24e76cb..0000000 --- a/board/phycore_mcf54xx/env/bin/pcidmaloop +++ /dev/null @@ -1,14 +0,0 @@ -pci stat -pci stat -c -while true; do - pci readm 32 0xA1000000 32 -s - pci readm 32 0xA2000000 256 -s - pci dmatx 2000 a2000100 128 -s - pci writem 32 0xa2000100 0x12345678 4 -s - pci readm 32 0xA3000000 256 -s - pci dmatx 2000 a3000040 128 -s - pci writem 32 0xa3000100 0x12345678 4 -s - pci readm 32 0xA4000000 16 -s - pci dmatx 2000 a4000080 4 -s - pci writem 32 0xa4000080 0x12345678 4 -s -done diff --git a/board/phycore_mcf54xx/env/bin/pciloop b/board/phycore_mcf54xx/env/bin/pciloop deleted file mode 100644 index 4a804f9..0000000 --- a/board/phycore_mcf54xx/env/bin/pciloop +++ /dev/null @@ -1,13 +0,0 @@ -pci stat -pci stat -c -while true; do - pci readm 32 0xA1000000 32 -s - pci readm 32 0xA2000000 256 -s - pci writem 32 0xa2000100 0x12345678 4 -s - pci readm 32 0xA3000000 256 -s - pci writem 32 0xa3000100 0x12345678 4 -s - pci readm 32 0xA4000000 16 -s - pci writem 32 0xa4000080 0x12345678 4 -s - -# pci dmatx 2000 a3000040 128 -s -done diff --git a/board/phycore_mcf54xx/env/bin/update_kernel b/board/phycore_mcf54xx/env/bin/update_kernel deleted file mode 100644 index 1ad95fc..0000000 --- a/board/phycore_mcf54xx/env/bin/update_kernel +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -part=/dev/nor0.kernel - -. /env/bin/_update $1 diff --git a/board/phycore_mcf54xx/env/bin/update_root b/board/phycore_mcf54xx/env/bin/update_root deleted file mode 100644 index b757a5b..0000000 --- a/board/phycore_mcf54xx/env/bin/update_root +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 -part=/dev/nor0.root - -. /env/bin/_update $1 diff --git a/board/phycore_mcf54xx/env/config b/board/phycore_mcf54xx/env/config deleted file mode 100644 index 5855062..0000000 --- a/board/phycore_mcf54xx/env/config +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -# can be either 'net' or 'flash' -kernel=net -root=net - -# use 'dhcp' todo dhcp in barebox and in kernel -ip=dhcp - -# -# setup default ethernet address -# -eth0.ipaddr=192.168.0.99 -eth0.netmask=255.255.255.0 -eth0.gateway=192.168.0.110 -eth0.serverip=192.168.0.110 - -uimage=uImage-mcf5485 -jffs2=root-mcf5485-ptx.jffs2 - -autoboot_timeout=3 - -#nfsroot="/home/cschlote/src/bitshrine/ltib/rootfs" -nfsroot="/home/cschlote/src/pengutronics/ptxdist-project-KP-UKD/root-debug,v3" -bootargs="console=ttyS0 rw initcall_debug debug" - -# -# setup the partitions in the main flash -# -mtdparts=512k(self),256k(env),3M(kernel),-(root) -rootpart="/dev/mtdblock3" - diff --git a/board/phycore_mcf54xx/highlevel_init.c b/board/phycore_mcf54xx/highlevel_init.c deleted file mode 100644 index 3a88cd6..0000000 --- a/board/phycore_mcf54xx/highlevel_init.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * (C) 2007,2008 konzeptpark, Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - -/** @file - * @brief This file contains high-level init functions. - * - */ -#include -#include -#include -#include - -static void board_gpio_init(void) -{ - /* - * Enable Ethernet signals so that, if a cable is plugged into - * the ports, the lines won't be floating and potentially cause - * erroneous transmissions - */ - MCF_GPIO_PAR_FECI2CIRQ = 0 - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDC_EMDC - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MDIO_EMDIO - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E1MII - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E17 - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDC - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MDIO - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E0MII - | MCF_GPIO_PAR_FECI2CIRQ_PAR_E07; -} - - -static void board_psc_init(void) -{ -#if (CFG_EARLY_UART_PORT == 0) - MCF_GPIO_PAR_PSC0 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC0_PAR_CTS0_CTS - | MCF_GPIO_PAR_PSC0_PAR_RTS0_RTS -#endif - | MCF_GPIO_PAR_PSC0_PAR_TXD0 - | MCF_GPIO_PAR_PSC0_PAR_RXD0); -#elif (CFG_EARLY_UART_PORT == 1) - MCF_GPIO_PAR_PSC1 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC1_PAR_CTS1_CTS - | MCF_GPIO_PAR_PSC1_PAR_RTS1_RTS -#endif - | MCF_GPIO_PAR_PSC1_PAR_TXD1 - | MCF_GPIO_PAR_PSC1_PAR_RXD1); -#elif (CFG_EARLY_UART_PORT == 2) - MCF_GPIO_PAR_PSC2 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC2_PAR_CTS2_CTS - | MCF_GPIO_PAR_PSC2_PAR_RTS2_RTS -#endif - | MCF_GPIO_PAR_PSC2_PAR_TXD2 - | MCF_GPIO_PAR_PSC2_PAR_RXD2); -#elif (CFG_EARLY_UART_PORT == 3) - MCF_GPIO_PAR_PSC3 = (0 -#ifdef HARDWARE_FLOW_CONTROL - | MCF_GPIO_PAR_PSC3_PAR_CTS3_CTS - | MCF_GPIO_PAR_PSC3_PAR_RTS3_RTS -#endif - | MCF_GPIO_PAR_PSC3_PAR_TXD3 - | MCF_GPIO_PAR_PSC3_PAR_RXD3); -#else -#error "Invalid CFG_EARLY_UART_PORT setting" -#endif - - /* Put PSC in UART mode */ - MCF_PSC_SICR(CFG_EARLY_UART_PORT) = MCF_PSC_SICR_SIM_UART; - - /* Call generic UART initialization */ -// mcf5xxx_uart_init(DBUG_UART_PORT, board_get_baud()); -} - - -/** Do board specific early init - * - * @note We run at link address now, you can now call other code - */ -void board_init_highlevel(void) -{ - /* Initialize platform specific GPIOs */ - board_gpio_init(); - - /* Init UART GPIOs and Modes */ - board_psc_init(); - - /* Setup the early init data */ -#ifdef CONFIG_HAS_EARLY_INIT - early_init(); -#endif - /* Configure the early debug output facility */ -#ifdef CONFIG_DEBUG_LL - early_debug_init(); -#endif -} - -/** Provide address of early debug low-level output - * - * @todo Should return real address for UART register map. - */ -void *get_early_console_base(const char *name) -{ - return (void*)1 + CFG_EARLY_UART_PORT; -} diff --git a/board/phycore_mcf54xx/lowlevel_init.c b/board/phycore_mcf54xx/lowlevel_init.c deleted file mode 100644 index 2837e3e..0000000 --- a/board/phycore_mcf54xx/lowlevel_init.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * (C) 2007 konzeptpark, Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - -/** @file - * @brief This file contains ... - * - */ -#include -#include -#include - -/** Initialize board specific very early inits - * - * @note This code is not allowed to call other code - just init - * your Chipselects and SDRAM stuff here! - */ -void board_init_lowlevel(void) -{ - /* - * The phyCORE-MCF548x has a 32MB or 64MB boot flash. - * The is a CF Card and ControlRegs on CS1 and CS2 - */ - - /* Setup SysGlue Chip-Select for user IOs */ - MCF_FBCS_CSAR2 = MCF_FBCS_CSAR_BA(CFG_XPLD_ADDRESS); - - MCF_FBCS_CSCR2 = (MCF_FBCS_CSCR_PS_16 - | MCF_FBCS_CSCR_AA - | MCF_FBCS_CSCR_ASET(1) - | MCF_FBCS_CSCR_WS(CFG_XPLD_WAIT_STATES)); - - MCF_FBCS_CSMR2 = (MCF_FBCS_CSMR_BAM_16M - | MCF_FBCS_CSMR_V); - - /* Setup SysGlue Chip-Select for CFCARD */ - MCF_FBCS_CSAR1 = MCF_FBCS_CSAR_BA(CFG_CFCARD_ADDRESS); - - MCF_FBCS_CSCR1 = (MCF_FBCS_CSCR_PS_16 - | MCF_FBCS_CSCR_AA - | MCF_FBCS_CSCR_ASET(1) - | MCF_FBCS_CSCR_WS(CFG_CFCARD_WAIT_STATES)); - - MCF_FBCS_CSMR1 = (MCF_FBCS_CSMR_BAM_16M - | MCF_FBCS_CSMR_V); - - /* Setup boot flash chip-select */ - MCF_FBCS_CSAR0 = MCF_FBCS_CSAR_BA(CFG_FLASH_ADDRESS); - - MCF_FBCS_CSCR0 = (MCF_FBCS_CSCR_PS_32 - | MCF_FBCS_CSCR_AA - | MCF_FBCS_CSCR_ASET(1) - | MCF_FBCS_CSCR_WS(CFG_FLASH_WAIT_STATES)); - - MCF_FBCS_CSMR0 = (MCF_FBCS_CSMR_BAM_32M - | MCF_FBCS_CSMR_V); - - /* - * Check to see if the SDRAM has already been initialized - * by a run control tool - */ - if (!(MCF_SDRAMC_SDCR & MCF_SDRAMC_SDCR_REF)) - { - /* - * Basic configuration and initialization - */ - // 0x000002AA - MCF_SDRAMC_SDRAMDS = (0 - | MCF_SDRAMC_SDRAMDS_SB_E(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_C(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_A(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_S(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - | MCF_SDRAMC_SDRAMDS_SB_D(MCF_SDRAMC_SDRAMDS_DRIVE_8MA) - ); - - // 0x0000001A - MCF_SDRAMC_CS0CFG = (0 - | MCF_SDRAMC_CSnCFG_CSBA(CFG_SDRAM_ADDRESS) - | MCF_SDRAMC_CSnCFG_CSSZ(MCF_SDRAMC_CSnCFG_CSSZ_128MBYTE) - ); - - MCF_SDRAMC_CS1CFG = 0; - MCF_SDRAMC_CS2CFG = 0; - MCF_SDRAMC_CS3CFG = 0; - - // 0x73611730 - MCF_SDRAMC_SDCFG1 = (0 - | MCF_SDRAMC_SDCFG1_SRD2RW((unsigned int)((CFG_SDRAM_CASL + CFG_SDRAM_BL / 2 + 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_SWT2RD((unsigned int) (CFG_SDRAM_TWR + 1)) - | MCF_SDRAMC_SDCFG1_RDLAT((unsigned int)((CFG_SDRAM_CASL * 2) + 2)) - | MCF_SDRAMC_SDCFG1_ACT2RW((unsigned int)(((CFG_SDRAM_TRCD / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_PRE2ACT((unsigned int)(((CFG_SDRAM_TRP / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_REF2ACT((unsigned int)(((CFG_SDRAM_TRFC / CFG_SYSTEM_CORE_PERIOD) - 1) + 0.5)) - | MCF_SDRAMC_SDCFG1_WTLAT(3) - ); - - // 0x46770000 - MCF_SDRAMC_SDCFG2 = (0 - | MCF_SDRAMC_SDCFG2_BRD2PRE(CFG_SDRAM_BL / 2) - | MCF_SDRAMC_SDCFG2_BWT2RW(CFG_SDRAM_BL / 2 + CFG_SDRAM_TWR) - | MCF_SDRAMC_SDCFG2_BRD2WT(7) - | MCF_SDRAMC_SDCFG2_BL(CFG_SDRAM_BL - 1) - ); - - /* - * Precharge and enable write to SDMR - */ - // 0xE10B0002 - MCF_SDRAMC_SDCR = (0 - | MCF_SDRAMC_SDCR_MODE_EN - | MCF_SDRAMC_SDCR_CKE - | MCF_SDRAMC_SDCR_DDR - | MCF_SDRAMC_SDCR_MUX(1) // 13 x 10 x 2 ==> MUX=1 - | MCF_SDRAMC_SDCR_RCNT((int)(((CFG_SDRAM_TREFI / (CFG_SYSTEM_CORE_PERIOD * 64)) - 1) + 0.5)) - | MCF_SDRAMC_SDCR_IPALL - ); - - /* - * Write extended mode register - */ - // 0x40010000 - MCF_SDRAMC_SDMR = (0 - | MCF_SDRAMC_SDMR_BNKAD_LEMR - | MCF_SDRAMC_SDMR_AD(0x0) - | MCF_SDRAMC_SDMR_CMD - ); - - /* - * Write mode register and reset DLL - */ - // 0x048d0000 - MCF_SDRAMC_SDMR = (0 - | MCF_SDRAMC_SDMR_BNKAD_LMR - | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_RESET_DLL | CFG_SDRAM_MOD) - | MCF_SDRAMC_SDMR_CMD - ); - - /* - * Execute a PALL command - */ - // 0xE10B0002 - MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IPALL; - - /* - * Perform two REF cycles - */ - // 0xE10B0004 - MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; - MCF_SDRAMC_SDCR |= MCF_SDRAMC_SDCR_IREF; - - /* - * Write mode register and clear reset DLL - */ - // 0x008D0000 - MCF_SDRAMC_SDMR = (0 - | MCF_SDRAMC_SDMR_BNKAD_LMR - | MCF_SDRAMC_SDMR_AD(CFG_SDRAM_MOD) - | MCF_SDRAMC_SDMR_CMD - ); - - /* - * Enable auto refresh and lock SDMR - */ - // 0x610B0000 - MCF_SDRAMC_SDCR &= ~MCF_SDRAMC_SDCR_MODE_EN; - - // 0x710B0F00 - MCF_SDRAMC_SDCR |= (0 - | MCF_SDRAMC_SDCR_REF - | MCF_SDRAMC_SDCR_DQS_OE(0xF) - ); - } -} - -/** @file - * - * Target specific early chipselect and SDRAM init. - */ \ No newline at end of file diff --git a/board/phycore_mcf54xx/pci-stubs.c b/board/phycore_mcf54xx/pci-stubs.c deleted file mode 100644 index b7ab7c7..0000000 --- a/board/phycore_mcf54xx/pci-stubs.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * (C) 2007,2008 Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - -/** @file - * @brief This file contains callbacks for the PCI subsystem - * - */ -#include -#include - - -/** Returns mapping from PCI slot to CPU irq for the target board - * @return Coldfire IRQ vector number, or -1 for no irq - */ -int mcfv4e_pci_gethostirq(uint8_t slot, uint8_t irqpin) -{ - int rc = -1; - switch (slot) - { - case 16 : break; - case 17 ... 21 : rc = 64 + 7; break; // Eport IRQ7 - } - return rc; -} diff --git a/board/phycore_mcf54xx/phyCore_MCF54xx.c b/board/phycore_mcf54xx/phyCore_MCF54xx.c deleted file mode 100644 index 3bc2d12..0000000 --- a/board/phycore_mcf54xx/phyCore_MCF54xx.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * (C) 2007 konzeptpark, Carsten Schlote - * See file CREDITS for list of people who contributed to this project. - * - * This file is part of barebox. - * - * barebox is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * barebox 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 barebox. If not, see . - */ - -/** @file - * @brief This file contains ... - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Return board clock in MHz FIXME move to clocks file - */ -ulong mcfv4e_get_bus_clk(void) -{ - return CFG_SYSTEM_CORE_CLOCK; -} - -/* - * Up to 64MiB NOR type flash, connected to - * CS line 0, data width is 32 bit - */ -static struct device_d cfi_dev = -{ - .name = "cfi_flash", - .map_base = CFG_FLASH_ADDRESS, - .size = CFG_FLASH_SIZE, -}; - -/* - * Build in FastEthernetControllers (FECs) - */ -static struct fec_platform_data fec_info = -{ - .xcv_type = MII100, -}; - -static struct device_d network_dev0 = -{ - .name = "fec_mcf54xx", - .map_base = MCF_FEC_ADDR(0), - .size = MCF_FEC_SIZE(0), /* area size */ - .platform_data = &fec_info, -}; -static struct device_d network_dev1 = -{ - .name = "fec_mcf54xx", - .map_base = MCF_FEC_ADDR(1), - .size = MCF_FEC_SIZE(1), /* area size */ - .platform_data = &fec_info, -}; - -/* - * 128MiB of SDRAM, data width is 32 bit - */ -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = -{ - .name = "mem", - .map_base = CFG_SDRAM_ADDRESS, - .size = CFG_SDRAM_SIZE, - .platform_data = &ram_pdata, -}; - -static int mcfv4e_devices_init(void) -{ - printf("FIXME - setup board devices...\n"); - - register_device(&cfi_dev); - - /* - * Create partitions that should be - * not touched by any regular user - */ - devfs_add_partition("nor0", 0x00000, 0x80000, PARTITION_FIXED, "self0"); /* ourself */ - devfs_add_partition("nor0", 0x80000, 0x40000, PARTITION_FIXED, "env0"); /* environment */ - protect_file("/dev/env0", 1); - - register_device(&network_dev0); - //register_device(&network_dev1); - - register_device(&sdram_dev); - - return 0; -} - -device_initcall(mcfv4e_devices_init); - -static struct device_d mcfv4e_serial_device = -{ - .name = "mcfv4e_serial", - .map_base = 1 + CFG_EARLY_UART_PORT, - .size = 16 * 1024, -}; - -static int mcfv4e_console_init(void) -{ - /* init gpios for serial port */ - - /* Already set in lowlevel_init.c */ - - register_device(&mcfv4e_serial_device); - return 0; -} - -console_initcall(mcfv4e_console_init); diff --git a/board/phycore_mcf54xx/phyCore_MCF54xx.dox b/board/phycore_mcf54xx/phyCore_MCF54xx.dox deleted file mode 100644 index 36dd0ad..0000000 --- a/board/phycore_mcf54xx/phyCore_MCF54xx.dox +++ /dev/null @@ -1,14 +0,0 @@ - -/** @page phycore_mcf54xx Phytec's phyCORE-MCF54x5 - -This target is based on a PhyTec PhyCore MCF54x5 CPU module. The card is shipped with: - -- up to 64MiB NOR type Flash Memory -- 128MiB synchronous dynamic RAM -- PCI USB 2.0 Host -- PCCard Controller -- MiniPCI Parallel -- MiniPCIe (USB lane only) -- ... - -*/ diff --git a/board/pm9263/Makefile b/board/pm9263/Makefile deleted file mode 100644 index eb072c0..0000000 --- a/board/pm9263/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += init.o diff --git a/board/pm9263/config.h b/board/pm9263/config.h deleted file mode 100644 index 9a9c5cd..0000000 --- a/board/pm9263/config.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -#define AT91_MASTER_CLOCK 99328000 /* peripheral = main / 2 */ - -#define MASTER_PLL_DIV 6 -#define MASTER_PLL_MUL 65 -#define MAIN_PLL_DIV 2 /* 2 or 4 */ - -/* clocks */ -#define CONFIG_SYS_MOR_VAL \ - (AT91_PMC_MOSCEN | \ - (255 << 8)) /* Main Oscillator Start-up Time */ -#define CONFIG_SYS_PLLAR_VAL \ - (AT91_PMC_PLLA_WR_ERRATA | /* Bit 29 must be 1 when prog */ \ - AT91_PMC_OUT | \ - AT91_PMC_PLLCOUNT | /* PLL Counter */ \ - (2 << 28) | /* PLL Clock Frequency Range */ \ - ((MASTER_PLL_MUL - 1) << 16) | (MASTER_PLL_DIV)) - -#if (MAIN_PLL_DIV == 2) -/* PCK/2 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR1_VAL \ - (AT91_PMC_CSS_SLOW | \ - AT91_PMC_PRES_1 | \ - AT91SAM9_PMC_MDIV_2 | \ - AT91_PMC_PDIV_1) -/* PCK/2 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR2_VAL \ - (AT91_PMC_CSS_PLLA | \ - AT91_PMC_PRES_1 | \ - AT91SAM9_PMC_MDIV_2 | \ - AT91_PMC_PDIV_1) -#else -/* PCK/4 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR1_VAL \ - (AT91_PMC_CSS_SLOW | \ - AT91_PMC_PRES_1 | \ - AT91RM9200_PMC_MDIV_3 | \ - AT91_PMC_PDIV_1) -/* PCK/4 = MCK Master Clock from PLLA */ -#define CONFIG_SYS_MCKR2_VAL \ - (AT91_PMC_CSS_PLLA | \ - AT91_PMC_PRES_1 | \ - AT91RM9200_PMC_MDIV_3 | \ - AT91_PMC_PDIV_1) -#endif -/* define PDC[31:16] as DATA[31:16] */ -#define CONFIG_SYS_PIOD_PDR_VAL1 0xFFFF0000 -/* no pull-up for D[31:16] */ -#define CONFIG_SYS_PIOD_PPUDR_VAL 0xFFFF0000 -/* EBI0_CSA, CS1 SDRAM, CS3 NAND Flash, 3.3V memories */ -#define CONFIG_SYS_MATRIX_EBI0CSA_VAL \ - (AT91_MATRIX_EBI0_DBPUC | AT91_MATRIX_EBI0_VDDIOMSEL_3_3V | \ - AT91_MATRIX_EBI0_CS1A_SDRAMC) - -/* SDRAM */ -/* SDRAMC_MR Mode register */ -#define CONFIG_SYS_SDRC_MR_VAL1 0 -/* SDRAMC_TR - Refresh Timer register */ -#define CONFIG_SYS_SDRC_TR_VAL1 0x3AA -/* SDRAMC_CR - Configuration register*/ -#define CONFIG_SYS_SDRC_CR_VAL \ - (AT91_SDRAMC_NC_9 | \ - AT91_SDRAMC_NR_13 | \ - AT91_SDRAMC_NB_4 | \ - AT91_SDRAMC_CAS_2 | \ - AT91_SDRAMC_DBW_32 | \ - (2 << 8) | /* tWR - Write Recovery Delay */ \ - (7 << 12) | /* tRC - Row Cycle Delay */ \ - (2 << 16) | /* tRP - Row Precharge Delay */ \ - (2 << 20) | /* tRCD - Row to Column Delay */ \ - (5 << 24) | /* tRAS - Active to Precharge Delay */ \ - (8 << 28)) /* tXSR - Exit Self Refresh to Active Delay */ - -/* Memory Device Register -> SDRAM */ -#define CONFIG_SYS_SDRC_MDR_VAL AT91_SDRAMC_MD_SDRAM -#define CONFIG_SYS_SDRC_MR_VAL2 AT91_SDRAMC_MODE_PRECHARGE -#define CONFIG_SYS_SDRAM_VAL1 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL3 AT91_SDRAMC_MODE_REFRESH -#define CONFIG_SYS_SDRAM_VAL2 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL3 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL4 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL5 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL6 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL7 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL8 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRAM_VAL9 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL4 AT91_SDRAMC_MODE_LMR -#define CONFIG_SYS_SDRAM_VAL10 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_MR_VAL5 AT91_SDRAMC_MODE_NORMAL -#define CONFIG_SYS_SDRAM_VAL11 0 /* SDRAM_BASE */ -#define CONFIG_SYS_SDRC_TR_VAL2 1200 /* SDRAM_TR */ -#define CONFIG_SYS_SDRAM_VAL12 0 /* SDRAM_BASE */ - -/* setup SMC0, CS0 (NOR Flash) - 16-bit, 15 WS */ -#define CONFIG_SYS_SMC0_SETUP0_VAL \ - (AT91_SMC_NWESETUP_(10) | AT91_SMC_NCS_WRSETUP_(10) | \ - AT91_SMC_NRDSETUP_(10) | AT91_SMC_NCS_RDSETUP_(10)) -#define CONFIG_SYS_SMC0_PULSE0_VAL \ - (AT91_SMC_NWEPULSE_(11) | AT91_SMC_NCS_WRPULSE_(11) | \ - AT91_SMC_NRDPULSE_(11) | AT91_SMC_NCS_RDPULSE_(11)) -#define CONFIG_SYS_SMC0_CYCLE0_VAL \ - (AT91_SMC_NWECYCLE_(22) | AT91_SMC_NRDCYCLE_(22)) -#define CONFIG_SYS_SMC0_MODE0_VAL \ - (AT91_SMC_READMODE | AT91_SMC_WRITEMODE | \ - AT91_SMC_DBW_16 | \ - AT91_SMC_TDFMODE | \ - AT91_SMC_TDF_(6)) - -/* user reset enable */ -#define CONFIG_SYS_RSTC_RMR_VAL \ - (AT91_RSTC_KEY | \ - AT91_RSTC_PROCRST | \ - AT91_RSTC_RSTTYP_WAKEUP | \ - AT91_RSTC_RSTTYP_WATCHDOG) - -/* Disable Watchdog */ -#define CONFIG_SYS_WDTC_WDMR_VAL \ - (AT91_WDT_WDIDLEHLT | AT91_WDT_WDDBGHLT | \ - AT91_WDT_WDV | \ - AT91_WDT_WDDIS | \ - AT91_WDT_WDD) - - -#endif /* __CONFIG_H */ diff --git a/board/pm9263/env/bin/_update b/board/pm9263/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/board/pm9263/env/bin/_update +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/sh - -if [ -z "$part" -o -z "$image" ]; then - echo "define \$part and \$image" - exit 1 -fi - -if [ ! -e "$part" ]; then - echo "Partition $part does not exist" - exit 1 -fi - -if [ $# = 1 ]; then - image=$1 -fi - -if [ x$ip = xdhcp ]; then - dhcp -fi - -ping $eth0.serverip -if [ $? -ne 0 ] ; then - echo "update aborted" - exit 1 -fi - -unprotect $part - -echo -echo "erasing partition $part" -erase $part - -echo -echo "flashing $image to $part" -echo -tftp $image $part diff --git a/board/pm9263/env/bin/boot b/board/pm9263/env/bin/boot deleted file mode 100644 index 533dea7..0000000 --- a/board/pm9263/env/bin/boot +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xnand ]; then - root=nand - kernel=nand -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$1 = xnor ]; then - root=nor - kernel=nor -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -elif [ x$root = xnor ]; then - bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" -fi - -bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts" - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -elif [ $kernel = nor ]; then - bootm /dev/nor0.kernel -else - bootm /dev/nand0.kernel.bb -fi - diff --git a/board/pm9263/env/bin/hush_hack b/board/pm9263/env/bin/hush_hack deleted file mode 100644 index 5fffa92..0000000 --- a/board/pm9263/env/bin/hush_hack +++ /dev/null @@ -1 +0,0 @@ -nand -a /dev/nand0.* diff --git a/board/pm9263/env/bin/init b/board/pm9263/env/bin/init deleted file mode 100644 index 02f5cd4..0000000 --- a/board/pm9263/env/bin/init +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config -if [ -e /dev/nor0 ]; then - addpart /dev/nor0 $nor_parts -fi - -if [ -e /dev/nand0 ]; then - addpart /dev/nand0 $nand_parts - - # Uh, oh, hush first expands wildcards and then starts executing - # commands. What a bug! - source /env/bin/hush_hack -fi - -if [ -z $eth0.ethaddr ]; then - while [ -z $eth0.ethaddr ]; do - readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr - done - echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" -fi - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - echo - echo "type update_kernel nor [] to update kernel into flash" - echo "type update_root nor [] to update rootfs into flash" - echo - exit -fi - -boot diff --git a/board/pm9263/env/bin/update_kernel b/board/pm9263/env/bin/update_kernel deleted file mode 100644 index 05c822d..0000000 --- a/board/pm9263/env/bin/update_kernel +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.kernel.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.kernel -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 diff --git a/board/pm9263/env/bin/update_root b/board/pm9263/env/bin/update_root deleted file mode 100644 index a751372..0000000 --- a/board/pm9263/env/bin/update_root +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$jffs2 -if [ x$1 = xnand ]; then - part=/dev/nand0.root.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.root -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 - diff --git a/board/pm9263/env/config b/board/pm9263/env/config deleted file mode 100644 index 7513291..0000000 --- a/board/pm9263/env/config +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/sh - -# can be either 'net', 'nor' or 'nand'' -kernel=net -root=net - -uimage=uImage-PM9263 -jffs2=root-PM9263.jffs2 - -autoboot_timeout=3 - -nfsroot="/ptx/work/octopus/mkl/bucyrus/OSELAS.BSP-Bucyrus-Grabowski-trunk/platform-Ronetix-PM9263/root" -bootargs="console=ttyS0,115200" - -nor_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" -rootpart_nor="/dev/mtdblock3" - -#nand_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" -#rootpart_nand="/dev/mtdblock7" - -# use 'dhcp' to do dhcp in barebox and in kernel -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=192.168.23.1 diff --git a/board/pm9263/init.c b/board/pm9263/init.c deleted file mode 100644 index 88b91ea..0000000 --- a/board/pm9263/init.c +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2007 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct atmel_nand_data nand_pdata = { - .ale = 21, - .cle = 22, -/* .det_pin = ... not connected */ - .ecc_base = (void __iomem *)(AT91_BASE_SYS + AT91_ECC0), - .ecc_mode = NAND_ECC_HW, - .rdy_pin = AT91_PIN_PB30, - .enable_pin = AT91_PIN_PD15, -#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16) - .bus_width_16 = 1, -#else - .bus_width_16 = 0, -#endif -}; - -static struct sam9_smc_config pm_nand_smc_config = { - .ncs_read_setup = 1, - .nrd_setup = 1, - .ncs_write_setup = 1, - .nwe_setup = 1, - - .ncs_read_pulse = 3, - .nrd_pulse = 3, - .ncs_write_pulse = 3, - .nwe_pulse = 3, - - .read_cycle = 5, - .write_cycle = 5, - - .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, - .tdf_cycles = 2, -}; - -static void pm_add_device_nand(void) -{ - /* setup bus-width (8 or 16) */ - if (nand_pdata.bus_width_16) - pm_nand_smc_config.mode |= AT91_SMC_DBW_16; - else - pm_nand_smc_config.mode |= AT91_SMC_DBW_8; - - /* configure chip-select 3 (NAND) */ - sam9_smc_configure(3, &pm_nand_smc_config); - - at91_add_device_nand(&nand_pdata); -} - -static struct device_d cfi_dev = { - .name = "cfi_flash", - .map_base = AT91_CHIPSELECT_0, - .size = 4 * 1024 * 1024, -}; - -static struct at91_ether_platform_data macb_pdata = { - .flags = AT91SAM_ETHER_RMII, - .phy_addr = 0, -}; - -static int pm9263_devices_init(void) -{ - /* - * PB27 enables the 50MHz oscillator for Ethernet PHY - * 1 - enable - * 0 - disable - */ - at91_set_gpio_output(AT91_PIN_PB27, 1); - at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */ - - /* Enable clock */ - at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC); - - at91_add_device_sdram(64 * 1024 * 1024); - pm_add_device_nand(); - at91_add_device_eth(&macb_pdata); - register_device(&cfi_dev); - - devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x10000, PARTITION_FIXED, "env0"); - - armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); - armlinux_set_architecture(MACH_TYPE_PM9263); - - return 0; -} - -device_initcall(pm9263_devices_init); - -static int pm9263_console_init(void) -{ - at91_register_uart(0, 0); - return 0; -} - -console_initcall(pm9263_console_init); diff --git a/board/sandbox/.gitignore b/board/sandbox/.gitignore deleted file mode 100644 index d116578..0000000 --- a/board/sandbox/.gitignore +++ /dev/null @@ -1 +0,0 @@ -barebox.lds diff --git a/board/sandbox/Makefile b/board/sandbox/Makefile deleted file mode 100644 index 8abe5dd..0000000 --- a/board/sandbox/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -obj-y += board.o -obj-y += clock.o -obj-y += hostfile.o -obj-y += console.o - -CPPFLAGS_barebox.lds = -U$(SUBARCH) -DELF_ARCH=$(ELF_ARCH) \ - -DELF_FORMAT="$(ELF_FORMAT)" -extra-y += barebox.lds - diff --git a/board/sandbox/barebox.lds.S b/board/sandbox/barebox.lds.S deleted file mode 100644 index 53e9f60..0000000 --- a/board/sandbox/barebox.lds.S +++ /dev/null @@ -1,229 +0,0 @@ -#include - -OUTPUT_FORMAT(ELF_FORMAT) -OUTPUT_ARCH(ELF_ARCH) -ENTRY(_start) - -SECTIONS -{ - /* Read-only sections, merged into text segment: */ - PROVIDE (__executable_start = 0x400000); . = 0x400000 + SIZEOF_HEADERS; - .interp : { *(.interp) } - .hash : { *(.hash) } - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - .rel.dyn : - { - *(.rel.init) - *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) - *(.rel.fini) - *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) - *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*) - *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) - *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) - *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) - *(.rel.ctors) - *(.rel.dtors) - *(.rel.got) - *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) - *(.rel.ldata .rel.ldata.* .rel.gnu.linkonce.l.*) - *(.rel.lbss .rel.lbss.* .rel.gnu.linkonce.lb.*) - *(.rel.lrodata .rel.lrodata.* .rel.gnu.linkonce.lr.*) - } - .rela.dyn : - { - *(.rela.init) - *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) - *(.rela.fini) - *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) - *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) - *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) - *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) - *(.rela.ctors) - *(.rela.dtors) - *(.rela.got) - *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) - *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) - *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) - *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) - } - .rel.plt : { *(.rel.plt) } - .rela.plt : { *(.rela.plt) } - .init : - { - KEEP (*(.init)) - } =0x90909090 - .plt : { *(.plt) } - .text : - { - *(.text .stub .text.* .gnu.linkonce.t.*) - KEEP (*(.text.*personality*)) - /* .gnu.warning sections are handled specially by elf32.em. */ - *(.gnu.warning) - } =0x90909090 - .fini : - { - KEEP (*(.fini)) - } =0x90909090 - - . = ALIGN(64); - __barebox_initcalls_start = .; - __barebox_initcalls : { INITCALLS } - __barebox_initcalls_end = .; - . = ALIGN(64); - __barebox_cmd_start = .; - __barebox_cmd : { BAREBOX_CMDS } - __barebox_cmd_end = .; - - PROVIDE (__etext = .); - PROVIDE (_etext = .); - PROVIDE (etext = .); - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - .rodata1 : { *(.rodata1) } - .eh_frame_hdr : { *(.eh_frame_hdr) } - .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } - /* Adjust the address for the data segment. We want to adjust up to - the same address within the page on the next page up. */ - . = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); - /* Exception handling */ - .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) } - .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } - /* Thread Local Storage sections */ - .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array)) - PROVIDE_HIDDEN (__init_array_end = .); - } - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(.fini_array)) - KEEP (*(SORT(.fini_array.*))) - PROVIDE_HIDDEN (__fini_array_end = .); - } - .ctors : - { - /* gcc uses crtbegin.o to find the start of - the constructors, so we make sure it is - first. Because this is a wildcard, it - doesn't matter if the user does not - actually link against crtbegin.o; the - linker won't look for a file to match a - wildcard. The wildcard also means that it - doesn't matter which directory crtbegin.o - is in. */ - KEEP (*crtbegin.o(.ctors)) - KEEP (*crtbegin?.o(.ctors)) - /* We don't want to include the .ctor section from - the crtend.o file until after the sorted ctors. - The .ctor section from the crtend file contains the - end of ctors marker and it must be last */ - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) - } - .dtors : - { - KEEP (*crtbegin.o(.dtors)) - KEEP (*crtbegin?.o(.dtors)) - KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) - } - .jcr : { KEEP (*(.jcr)) } - .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) } - .dynamic : { *(.dynamic) } - .got : { *(.got) } - . = DATA_SEGMENT_RELRO_END (24, .); - .got.plt : { *(.got.plt) } - .data : - { - *(.data .data.* .gnu.linkonce.d.*) - KEEP (*(.gnu.linkonce.d.*personality*)) - SORT(CONSTRUCTORS) - } - .data1 : { *(.data1) } - _edata = .; PROVIDE (edata = .); - __bss_start = .; - .bss : - { - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - *(COMMON) - /* Align here to ensure that the .bss section occupies space up to - _end. Align after .bss to ensure correct alignment even if the - .bss section disappears because there are no input sections. - FIXME: Why do we need it? When there is no .bss section, we don't - pad the .data section. */ - . = ALIGN(. != 0 ? 64 / 8 : 1); - } - .lbss : - { - *(.dynlbss) - *(.lbss .lbss.* .gnu.linkonce.lb.*) - *(LARGE_COMMON) - } - . = ALIGN(64 / 8); - .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : - { - *(.lrodata .lrodata.* .gnu.linkonce.lr.*) - } - .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : - { - *(.ldata .ldata.* .gnu.linkonce.l.*) - . = ALIGN(. != 0 ? 64 / 8 : 1); - } - . = ALIGN(64 / 8); - _end = .; PROVIDE (end = .); - . = DATA_SEGMENT_END (.); - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - /* SGI/MIPS DWARF 2 extensions */ - .debug_weaknames 0 : { *(.debug_weaknames) } - .debug_funcnames 0 : { *(.debug_funcnames) } - .debug_typenames 0 : { *(.debug_typenames) } - .debug_varnames 0 : { *(.debug_varnames) } - /DISCARD/ : { *(.note.GNU-stack) } -} - diff --git a/board/sandbox/board.c b/board/sandbox/board.c deleted file mode 100644 index 84017eb..0000000 --- a/board/sandbox/board.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * board.c - * - * Copyright (c) 2007 Sascha Hauer , 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 -#include -#include -#include -#include -#include - -static struct device_d tap_device = { - .name = "tap", -}; - -static int devices_init(void) -{ - register_device(&tap_device); - - return 0; -} - -device_initcall(devices_init); - diff --git a/board/sandbox/clock.c b/board/sandbox/clock.c deleted file mode 100644 index b150864..0000000 --- a/board/sandbox/clock.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * clock.c - wrapper between a barebox clocksource and linux - * - * Copyright (c) 2007 Sascha Hauer , 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 -#include -#include -#include - -static uint64_t linux_clocksource_read(void) -{ - return linux_get_time(); -} - -static struct clocksource cs = { - .read = linux_clocksource_read, - .mask = 0xffffffff, - .shift = 10, -}; - -static int clocksource_init (void) -{ - cs.mult = clocksource_hz2mult(1000 * 1000 * 1000, cs.shift); - - init_clock(&cs); - - return 0; -} - -core_initcall(clocksource_init); diff --git a/board/sandbox/config.h b/board/sandbox/config.h deleted file mode 100644 index c96d762..0000000 --- a/board/sandbox/config.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __CONFIG_H -#define __CONFIG_H - -#define __SANDBOX__ - -#endif /* __CONFIG_H */ diff --git a/board/sandbox/console.c b/board/sandbox/console.c deleted file mode 100644 index 2959e85..0000000 --- a/board/sandbox/console.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * console.c - register a console device - * - * Copyright (c) 2007 Sascha Hauer , 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 -#include -#include -#include - -int barebox_register_console(char *name, int stdinfd, int stdoutfd) -{ - struct device_d *dev; - struct linux_console_data *data; - - dev = xzalloc(sizeof(struct device_d) + sizeof(struct linux_console_data)); - - data = (struct linux_console_data *)(dev + 1); - - dev->platform_data = data; - strcpy(dev->name, name); - - strcpy(dev->name, "console"); - - if (stdinfd >= 0) - data->flags = CONSOLE_STDIN; - if (stdoutfd >= 0) - data->flags |= CONSOLE_STDOUT | CONSOLE_STDERR; - - data->stdoutfd = stdoutfd; - data->stdinfd = stdinfd; - - return register_device(dev); -} - diff --git a/board/sandbox/env/bin/init b/board/sandbox/env/bin/init deleted file mode 100644 index a7cb7d5..0000000 --- a/board/sandbox/env/bin/init +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config - diff --git a/board/sandbox/env/config b/board/sandbox/env/config deleted file mode 100644 index 2b148b6..0000000 --- a/board/sandbox/env/config +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -eth0.ipaddr=172.0.0.2 -eth0.netmask=255.255.255.0 -eth0.gateway=172.0.0.1 -eth0.serverip=172.0.0.1 -eth0.ethaddr=80:81:82:83:84:85 - diff --git a/board/sandbox/hostfile.c b/board/sandbox/hostfile.c deleted file mode 100644 index ad625d7..0000000 --- a/board/sandbox/hostfile.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * hostfile.c - use files from the host to simalute barebox devices - * - * Copyright (c) 2007 Sascha Hauer , 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 -#include -#include -#include -#include -#include -#include -#include - -struct hf_priv { - struct cdev cdev; - struct hf_platform_data *pdata; -}; - -static ssize_t hf_read(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags) -{ - struct hf_platform_data *hf = cdev->priv; - int fd = hf->fd; - - if (linux_lseek(fd, offset) != offset) - return -EINVAL; - - return linux_read(fd, buf, count); -} - -static ssize_t hf_write(struct cdev *cdev, const void *buf, size_t count, ulong offset, ulong flags) -{ - struct hf_platform_data *hf = cdev->priv; - int fd = hf->fd; - - if (linux_lseek(fd, offset) != offset) - return -EINVAL; - - return linux_write(fd, buf, count); -} - -static void hf_info(struct device_d *dev) -{ - struct hf_platform_data *hf = dev->platform_data; - - printf("file: %s\n", hf->filename); -} - -static struct file_operations hf_fops = { - .read = hf_read, - .write = hf_write, -}; - -static int hf_probe(struct device_d *dev) -{ - struct hf_platform_data *hf = dev->platform_data; - struct hf_priv *priv = xzalloc(sizeof(*priv)); - - priv->pdata = hf; - - priv->cdev.name = hf->name; - priv->cdev.size = hf->size; - priv->cdev.ops = &hf_fops; - priv->cdev.priv = hf; - devfs_create(&priv->cdev); - - return 0; -} - -static struct driver_d hf_drv = { - .name = "hostfile", - .probe = hf_probe, - .info = hf_info, -}; - -static int hf_init(void) -{ - return register_driver(&hf_drv); -} - -device_initcall(hf_init); - -int barebox_register_filedev(struct hf_platform_data *hf) -{ - struct device_d *dev; - - dev = xzalloc(sizeof(struct device_d)); - - dev->platform_data = hf; - - strcpy(dev->name, "hostfile"); - dev->size = hf->size; - dev->map_base = hf->map_base; - - return register_device(dev); -} - diff --git a/board/scb9328/Makefile b/board/scb9328/Makefile deleted file mode 100644 index db6fd7e..0000000 --- a/board/scb9328/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += lowlevel_init.o -obj-y += scb9328.o diff --git a/board/scb9328/config.h b/board/scb9328/config.h deleted file mode 100644 index cc22b7a..0000000 --- a/board/scb9328/config.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2003 ETC s.r.o. - * - * 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 - * - * Written by Peter Figuli , 2003. - * - * 2003/13/06 Initial MP10 Support copied from wepep250 - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#define CONFIG_SYSPLL_CLK_FREQ 16000000 - -#endif /* __CONFIG_H */ - diff --git a/board/scb9328/env/bin/init b/board/scb9328/env/bin/init deleted file mode 100644 index 416669f..0000000 --- a/board/scb9328/env/bin/init +++ /dev/null @@ -1,3 +0,0 @@ - -echo running init - diff --git a/board/scb9328/lowlevel_init.S b/board/scb9328/lowlevel_init.S deleted file mode 100644 index 5b02428..0000000 --- a/board/scb9328/lowlevel_init.S +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2004 Sascha Hauer, Synertronixx GmbH - * - * 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 - -#define CPU200 - -#ifdef CPU200 -#define CFG_MPCTL0_VAL 0x00321431 -#else -#define CFG_MPCTL0_VAL 0x040e200e -#endif - -#define BUS72 - -#ifdef BUS72 -#define CFG_SPCTL0_VAL 0x04002400 -#endif - -#ifdef BUS96 -#define CFG_SPCTL0_VAL 0x04001800 -#endif - -#ifdef BUS64 -#define CFG_SPCTL0_VAL 0x08001800 -#endif - -/* Das ist der BCLK Divider, der aus der System PLL - BCLK und HCLK erzeugt: - 31 | xxxx xxxx xxxx xxxx xx10 11xx xxxx xxxx | 0 - 0x2f008403 : 192MHz/2=96MHz, 144MHz/2=72MHz PRESC=1->BCLKDIV=2 - 0x2f008803 : 192MHz/3=64MHz, 240MHz/3=80MHz PRESC=1->BCLKDIV=2 - 0x2f001003 : 192MHz/5=38,4MHz - 0x2f000003 : 64MHz/1 - Bit 22: SPLL Restart - Bit 21: MPLL Restart */ - -#ifdef BUS64 -#define CFG_CSCR_VAL 0x2f030003 -#endif - -#ifdef BUS72 -#define CFG_CSCR_VAL 0x2f030403 -#endif -/* Bit[0:3] contain PERCLK1DIV for UART 1 - 0x000b00b ->b<- -> 192MHz/12=16MHz - 0x000b00b ->8<- -> 144MHz/09=16MHz - 0x000b00b ->3<- -> 64MHz/4=16MHz */ - -#ifdef BUS96 -#define CFG_PCDR_VAL 0x000b00b5 -#endif - -#ifdef BUS64 -#define CFG_PCDR_VAL 0x000b00b3 -#endif - -#ifdef BUS72 -#define CFG_PCDR_VAL 0x000b00b8 -#endif - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -.globl board_init_lowlevel -board_init_lowlevel: - - mov r10, lr - - /* Change PERCLK1DIV to 14 ie 14+1 */ - writel(CFG_PCDR_VAL, PCDR) - - /* set MCU PLL Control Register 0 */ - writel(CFG_MPCTL0_VAL, MPCTL0) - - /* set mpll restart bit */ - ldr r0, =CSCR - ldr r1, [r0] - orr r1,r1,#(1<<21) - str r1, [r0] - - mov r2,#0x10 -1: - mov r3,#0x2000 -2: - subs r3,r3,#1 - bne 2b - - subs r2,r2,#1 - bne 1b - - /* set System PLL Control Register 0 */ - writel(CFG_SPCTL0_VAL, SPCTL0) - - /* set spll restart bit */ - ldr r0, =CSCR - ldr r1, [r0] - orr r1,r1,#(1<<22) - str r1, [r0] - - mov r2,#0x10 -1: - mov r3,#0x2000 -2: - subs r3,r3,#1 - bne 2b - - subs r2,r2,#1 - bne 1b - - writel(CFG_CSCR_VAL, CSCR) - -/* I have now read the ARM920 DataSheet back-to-Back, and have stumbled upon - *this..... - * - * It would appear that from a Cold-Boot the ARM920T enters "FastBus" mode CP15 - * register 1, this stops it using the output of the PLL and thus runs at the - * slow rate. Unless you place the Core into "Asynch" mode, the CPU will never - * use the value set in the CM_OSC registers...regardless of what you set it - * too! Thus, although i thought i was running at 140MHz, i'm actually running - * at 40!.. - - * Slapping this into my bootloader does the trick... - - * MRC p15,0,r0,c1,c0,0 ; read core configuration register - * ORR r0,r0,#0xC0000000 ; set asynchronous clocks and not fastbus mode - * MCR p15,0,r0,c1,c0,0 ; write modified value to core configuration - * register - */ - MRC p15,0,r0,c1,c0,0 - ORR r0,r0,#0xC0000000 - MCR p15,0,r0,c1,c0,0 - - /* Skip SDRAM initialization if we run from RAM */ - cmp pc, #0x08000000 - bls 1f - cmp pc, #0x09000000 - bhi 1f - - mov pc,r10 - -1: - -/* SDRAM Setup */ - - writel(0x910a8200, SDCTL0) /* Precharge cmd, CAS = 2 */ - writel(0x0, 0x08200000) /* Issue Precharge all Command */ - writel(0xa10a8200, SDCTL0) /* Autorefresh cmd, CAS = 2 */ - - ldr r0, =0x08000000 - ldr r1, =0x0 /* Issue AutoRefresh Command */ - str r1, [r0] - str r1, [r0] - str r1, [r0] - str r1, [r0] - str r1, [r0] - str r1, [r0] - str r1, [r0] - str r1, [r0] - - writel(0xb10a8300, SDCTL0) - writel(0x0, 0x08223000) /* CAS Latency 2, issue Mode Register Command, Burst Length = 8 */ - writel(0x810a8200, SDCTL0) /* Set to Normal Mode CAS 2 */ - - mov pc,r10 diff --git a/board/scb9328/scb9328.c b/board/scb9328/scb9328.c deleted file mode 100644 index e781393..0000000 --- a/board/scb9328/scb9328.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2004 Sascha Hauer, Synertronixx GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct device_d cfi_dev = { - .name = "cfi_flash", - - .map_base = 0x10000000, - .size = 16 * 1024 * 1024, -}; - -static struct memory_platform_data sdram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .map_base = 0x08000000, - .size = 16 * 1024 * 1024, - .platform_data = &sdram_pdata, -}; - -static struct dm9000_platform_data dm9000_data = { - .iobase = 0x16000000, - .iodata = 0x16000004, - .buswidth = DM9000_WIDTH_16, -}; - -static struct device_d dm9000_dev = { - .name = "dm9000", - .map_base = 0x16000000, - .size = 8, - .platform_data = &dm9000_data, -}; - -static int scb9328_devices_init(void) { - - imx_gpio_mode(PA23_PF_CS5); - -/* CS3 becomes CS3 by clearing reset default bit 1 in FMCR */ - FMCR = 0x1; - - CS0U = 0x000F2000; - CS0L = 0x11110d01; - - CS1U = 0x000F0a00; - CS1L = 0x11110601; - CS2U = 0x0; - CS2L = 0x0; - CS3U = 0x000FFFFF; - CS3L = 0x00000303; - CS4U = 0x000F0a00; - CS4L = 0x11110301; - CS5U = 0x00008400; - CS5L = 0x00000D03; - - register_device(&cfi_dev); - register_device(&sdram_dev); - register_device(&dm9000_dev); - - devfs_add_partition("nor0", 0x00000, 0x20000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); - protect_file("/dev/env0", 1); - - armlinux_add_dram(&sdram_dev); - armlinux_set_bootparams((void *)0x08000100); - armlinux_set_architecture(MACH_TYPE_SCB9328); - - return 0; -} - -device_initcall(scb9328_devices_init); - -static struct device_d scb9328_serial_device = { - .name = "imx_serial", - .map_base = IMX_UART1_BASE, - .size = 4096, -}; - -static int scb9328_console_init(void) -{ - /* init gpios for serial port */ - imx_gpio_mode(PC11_PF_UART1_TXD); - imx_gpio_mode(PC12_PF_UART1_RXD); - - register_device(&scb9328_serial_device); - return 0; -} - -console_initcall(scb9328_console_init); - diff --git a/board/scb9328/scb9328.dox b/board/scb9328/scb9328.dox deleted file mode 100644 index 75bc7c8..0000000 --- a/board/scb9328/scb9328.dox +++ /dev/null @@ -1,9 +0,0 @@ -/** @page scb9328 Synertronixx's scb9328 - -This CPU card is based on a Freescale i.MX1 CPU. The card is shipped with: - -- up to 16MiB NOR type Flash Memory -- 16MiB synchronous dynamic RAM -- DM9000 network controller - -*/ diff --git a/board/x86_generic/Makefile b/board/x86_generic/Makefile deleted file mode 100644 index 248240d..0000000 --- a/board/x86_generic/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += generic_pc.o diff --git a/board/x86_generic/config.h b/board/x86_generic/config.h deleted file mode 100644 index 39bea18..0000000 --- a/board/x86_generic/config.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert, 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 - * - */ - -/* nothing special yet */ diff --git a/board/x86_generic/env/bin/boot b/board/x86_generic/env/bin/boot deleted file mode 100644 index fcfffe3..0000000 --- a/board/x86_generic/env/bin/boot +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -. /env/config - -if [ x$1 = xdisk ]; then - root=disk - kernel=disk -fi - -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$ip = xdhcp ]; then - bootargs="$bootargs ip=dhcp" -else - bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" -fi - -if [ x$root = xdisk ]; then - bootargs="$bootargs root=$rootpart_disk rootfstype=$rootpart_fs rw" -else - bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp rw" -fi - -if [ $kernel = net ]; then - if [ x$ip = xdhcp ]; then - dhcp - fi - tftp $uimage uImage || exit 1 - bootm uImage -else - bootargs="BOOT_IMAGE=$kernel_device auto $bootargs" - linux16 $kernel_device -fi - diff --git a/board/x86_generic/env/bin/init b/board/x86_generic/env/bin/init deleted file mode 100644 index 2924a44..0000000 --- a/board/x86_generic/env/bin/init +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -PATH=/env/bin -export PATH - -. /env/config - -echo -echo -n "Hit any key to stop autoboot: " -timeout -a $autoboot_timeout -if [ $? != 0 ]; then - exit -fi - -boot diff --git a/board/x86_generic/env/config b/board/x86_generic/env/config deleted file mode 100644 index dd57aad..0000000 --- a/board/x86_generic/env/config +++ /dev/null @@ -1,31 +0,0 @@ -# -# basic config -# -# boot source: 'disk' or 'net' -kernel=disk -root=disk - -# data for the NFS case -nfsroot="/path/to/nfs_root" - -# data for the disk case -kernel_device=/dev/biosdisk0.1 -rootpart_disk=/dev/sda1 -rootpart_fs=ext2 - -baudrate=115200 -serial=ttyS0 - -# use UART for console -bootargs="console=$serial,$baudrate" - -autoboot_timeout=3 - -# use 'dhcp' to do dhcp in uboot and in kernel -# ip=dhcp -# or set your networking parameters here -# eth0.ipaddr=192.168.3.11 -# eth0.netmask=255.255.255.0 -# eth0.gateway=a.b.c.d -# eth0.serverip=192.168.3.10 -# eth0.ethaddr=aa.bb.cc.dd.ee.ff diff --git a/board/x86_generic/generic_pc.c b/board/x86_generic/generic_pc.c deleted file mode 100644 index bd93bc1..0000000 --- a/board/x86_generic/generic_pc.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert, 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 - * - */ - -/** - * @file - * @brief Generic PC support to let barebox acting as a boot loader - */ - -#include -#include -#include -#include -#include -#include - -static struct memory_platform_data ram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, -}; - -static struct device_d sdram_dev = { - .name = "mem", - .size = 16 * 1024 * 1024, - .map_base = 0, - .platform_data = &ram_pdata, -}; - -static struct device_d bios_disk_dev = { - .name = "biosdrive", - .size = 1, -}; - -/* - * These datas are from the MBR, created by the linker and filled by the - * setup tool while installing barebox on the disk drive - */ -extern uint64_t pers_env_storage; -extern uint16_t pers_env_size; -extern uint8_t pers_env_drive; - -/** - * Persistant environment "not used" marker. - * Note: Must be in accordance to the value the tool "setup_mbr" writes. - */ -#define PATCH_AREA_PERS_SIZE_UNUSED 0x000 - -static int devices_init(void) -{ - int rc; - - sdram_dev.size = bios_get_memsize(); /* extended memory only */ - sdram_dev.size <<= 10; - - register_device(&sdram_dev); - register_device(&bios_disk_dev); - - if (pers_env_size != PATCH_AREA_PERS_SIZE_UNUSED) { - rc = devfs_add_partition("disk0", /* FIXME */ - pers_env_storage * 512, - (unsigned)pers_env_size * 512, - DEVFS_PARTITION_FIXED, "env0"); - printf("Partition: %d\n", rc); - } else - printf("No persistant storage defined\n"); - - return 0; -} -device_initcall(devices_init); - -#ifdef CONFIG_DRIVER_SERIAL_NS16550 - -static struct NS16550_plat serial_plat = { - .clock = 1843200, - .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR, - .reg_read = x86_uart_read, - .reg_write = x86_uart_write, -}; - -/* we are expecting always one serial interface */ -static struct device_d generic_pc_serial_device = { - .name = "serial_ns16550", - .map_base = 0x3f8, - .size = 8, - .platform_data = (void *)&serial_plat, -}; - -static int pc_console_init(void) -{ - /* Register the serial port */ - return register_device(&generic_pc_serial_device); -} -console_initcall(pc_console_init); - -#endif - -/** @page generic_pc Generic PC based bootloader - -This platform acts as a generic PC based bootloader. It depends on at least -one boot media that is connected locally (no network boot) and can be -handled by the regular BIOS (any kind of hard disks for example). - -The created @a barebox image can be used to boot a standard x86 bzImage -Linux kernel. - -Refer section @ref x86_bootloader_preparations how to do so. - -How to get the binary image: - -Using the default configuration: - -@code -make ARCH=x86 generic_defconfig -@endcode - -Build the binary image: - -@code -make ARCH=x86 CROSS_COMPILE=x86compiler -@endcode - -@note replace the 'x86compiler' with your x86 (cross) compiler. - -*/ diff --git a/commands/Kconfig b/commands/Kconfig index 0ea32d9..1ffc826 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -180,6 +180,12 @@ config CMD_FLASH tristate prompt "protect/erase" + +config CMD_UBI + tristate + default y if UBI + prompt "ubimkvol, ubirmvol, ubiattach" + endmenu diff --git a/commands/Makefile b/commands/Makefile index 3eef5de..b99f042 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_CMD_GPIO) += gpio.o obj-$(CONFIG_CMD_UNLZO) += unlzo.o obj-$(CONFIG_CMD_I2C) += i2c.o +obj-$(CONFIG_CMD_UBI) += ubi.o diff --git a/commands/ubi.c b/commands/ubi.c new file mode 100644 index 0000000..3da0835 --- /dev/null +++ b/commands/ubi.c @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int do_ubimkvol(struct command *cmdtp, int argc, char *argv[]) +{ + struct ubi_mkvol_req req; + int fd, ret; + size_t size; + + if (argc != 4) + return COMMAND_ERROR_USAGE; + + size = strtoul_suffix(argv[3], NULL, 0); + req.name_len = min_t(int, strlen(argv[2]), UBI_VOL_NAME_MAX); + strncpy(req.name, argv[2], req.name_len); + req.name[req.name_len] = 0; + + req.vol_type = UBI_DYNAMIC_VOLUME; + req.bytes = size; + req.vol_id = UBI_VOL_NUM_AUTO; + req.alignment = 1; + + fd = open(argv[1], O_WRONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + ret = ioctl(fd, UBI_IOCMKVOL, &req); + if (ret) + printf("failed to create: %s\n", strerror(-ret)); + close(fd); + + return ret ? 1 : 0; +} + +static const __maybe_unused char cmd_ubimkvol_help[] = +"Usage: ubimkvol \n" +"Create an ubi volume on with name and size \n" +"If size os zero all available space is used for the volume\n"; + +BAREBOX_CMD_START(ubimkvol) + .cmd = do_ubimkvol, + .usage = "create an ubi volume", + BAREBOX_CMD_HELP(cmd_ubimkvol_help) +BAREBOX_CMD_END + + +static int do_ubiattach(struct command *cmdtp, int argc, char *argv[]) +{ + struct mtd_info_user user; + int fd, ret; + + if (argc != 2) + return COMMAND_ERROR_USAGE; + + fd = open(argv[1], O_RDWR); + if (fd < 0) { + perror("open"); + return 1; + } + + ret = ioctl(fd, MEMGETINFO, &user); + if (!ret) + ret = ubi_attach_mtd_dev(user.mtd, UBI_DEV_NUM_AUTO, 0); + + if (ret) + printf("failed to attach: %s\n", strerror(-ret)); + + close(fd); + + return ret ? 1 : 0; +} + +static const __maybe_unused char cmd_ubiattach_help[] = +"Usage: ubiattach \n" +"Attach to ubi\n"; + +BAREBOX_CMD_START(ubiattach) + .cmd = do_ubiattach, + .usage = "attach a mtd dev to ubi", + BAREBOX_CMD_HELP(cmd_ubiattach_help) +BAREBOX_CMD_END + +static int do_ubirmvol(struct command *cmdtp, int argc, char *argv[]) +{ + struct ubi_mkvol_req req; + int fd, ret; + + if (argc != 3) + return COMMAND_ERROR_USAGE; + + strncpy(req.name, argv[2], UBI_VOL_NAME_MAX); + req.name[UBI_VOL_NAME_MAX] = 0; + + fd = open(argv[1], O_WRONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + ret = ioctl(fd, UBI_IOCRMVOL, &req); + if (ret) + printf("failed to delete: %s\n", strerror(-ret)); + close(fd); + + return ret ? 1 : 0; +} + +static const __maybe_unused char cmd_ubirmvol_help[] = +"Usage: ubirmvol \n" +"Delete ubi volume from \n"; + +BAREBOX_CMD_START(ubirmvol) + .cmd = do_ubirmvol, + .usage = "delete an ubi volume", + BAREBOX_CMD_HELP(cmd_ubirmvol_help) +BAREBOX_CMD_END + diff --git a/common/Makefile b/common/Makefile index 8b8686d..14f8643 100644 --- a/common/Makefile +++ b/common/Makefile @@ -26,6 +26,8 @@ endif # ifdef CONFIG_DEFAULT_ENVIRONMENT -include/barebox_default_env.h: $(ENV_FILES) - $(Q)scripts/genenv $(srctree) $(CONFIG_DEFAULT_ENVIRONMENT_PATH) - $(Q)cat barebox_default_env | scripts/bin2c default_environment > $@ +barebox_default_env: $(ENV_FILES) + $(Q)$(srctree)/scripts/genenv $(srctree) $(objtree) $(CONFIG_DEFAULT_ENVIRONMENT_PATH) + +include/barebox_default_env.h: barebox_default_env + $(Q)cat $< | $(objtree)/scripts/bin2c default_environment > $@ diff --git a/drivers/Kconfig b/drivers/Kconfig index bf559c4..ae9efce 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -5,7 +5,7 @@ source "drivers/spi/Kconfig" source "drivers/i2c/Kconfig" source "drivers/nor/Kconfig" -source "drivers/nand/Kconfig" +source "drivers/mtd/Kconfig" source "drivers/ata/Kconfig" source "drivers/usb/Kconfig" source "drivers/video/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 7bae6ff..bce68bc 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,6 +1,6 @@ obj-y += net/ obj-y += serial/ -obj-y += nand/ +obj-y += mtd/ obj-y += nor/ obj-y += usb/ obj-$(CONFIG_ATA) += ata/ diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig new file mode 100644 index 0000000..562f0cd --- /dev/null +++ b/drivers/mtd/Kconfig @@ -0,0 +1,9 @@ +menuconfig MTD + bool "Memory Technology Device (MTD) support" + +if MTD + +source "drivers/mtd/nand/Kconfig" +source "drivers/mtd/ubi/Kconfig" + +endif diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile new file mode 100644 index 0000000..85bed11 --- /dev/null +++ b/drivers/mtd/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_NAND) += nand/ +obj-$(CONFIG_UBI) += ubi/ +obj-$(CONFIG_PARTITION_NEED_MTD) += partition.o diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig new file mode 100644 index 0000000..ddc0c34 --- /dev/null +++ b/drivers/mtd/nand/Kconfig @@ -0,0 +1,101 @@ +menuconfig NAND + bool "NAND support " + select MTD_NAND_IDS + help + This enables support for accessing all type of NAND flash + devices. For further information see + . + +if NAND + +config NAND_IMX + bool + prompt "i.MX NAND driver" + depends on ARCH_IMX21 || ARCH_IMX27 || ARCH_IMX31 || ARCH_IMX35 || ARCH_IMX25 + +config NAND_IMX_BOOT + bool + prompt "Support Starting barebox from NAND" + depends on NAND_IMX || NAND_IMX_V2 + +config NAND_OMAP_GPMC + tristate "NAND Flash Support for GPMC based OMAP platforms" + depends on ((ARCH_OMAP2 || ARCH_OMAP3) && GPMC) + help + Support for NAND flash using GPMC. GPMC is a common memory + interface found on Texas Instrument's OMAP platforms + +config NAND_ATMEL + bool + prompt "Atmel (AT91SAM9xxx) NAND driver" + depends on ARCH_AT91 + +config NAND_S3C24X0 + bool + prompt "Samsung S3C24X0 NAND driver" + depends on ARCH_S3C24xx + help + Add support for processor's NAND device controller. + +config MTD_NAND_VERIFY_WRITE + bool "Verify NAND page writes" + help + This adds an extra check when data is written to the flash. The + NAND flash device internally checks only bits transitioning + from 1 to 0. There is a rare possibility that even though the + device thinks the write was successful, a bit could have been + flipped accidentally due to device wear or something else. + +config MTD_NAND_ECC_SMC + bool "NAND ECC Smart Media byte order" + default n + help + Software ECC according to the Smart Media Specification. + The original Linux implementation had byte 0 and 1 swapped. + +config MTD_NAND_MUSEUM_IDS + bool "Enable chip ids for obsolete ancient NAND devices" + depends on MTD_NAND + default n + help + Enable this option only when your board has first generation + NAND chips (page size 256 byte, erase size 4-8KiB). The IDs + of these chips were reused by later, larger chips. + +config MTD_NAND_IDS + tristate + +config MTD_NAND_DISKONCHIP + tristate "DiskOnChip 2000, Millennium and Millennium Plus" + depends on EXPERIMENTAL && BROKEN + help + This is a reimplementation of M-Systems DiskOnChip 2000, + Millennium and Millennium Plus as a standard NAND device driver, + as opposed to the earlier self-contained MTD device drivers. + This should enable, among other things, proper JFFS2 operation on + these devices. + +config MTD_NAND_DISKONCHIP_BBTWRITE + bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP" + depends on MTD_NAND_DISKONCHIP + help + On DiskOnChip devices shipped with the INFTL filesystem (Millennium + and 2000 TSOP/Alon), Linux reserves some space at the end of the + device for the Bad Block Table (BBT). If you have existing INFTL + data on your device (created by non-Linux tools such as M-Systems' + DOS drivers), your data might overlap the area Linux wants to use for + the BBT. If this is a concern for you, leave this option disabled and + Linux will not write BBT data into this area. + The downside of leaving this option disabled is that if bad blocks + are detected by Linux, they will not be recorded in the BBT, which + could cause future problems. + Once you enable this option, new filesystems (INFTL or others, created + in Linux or other operating systems) will not use the reserved area. + The only reason not to enable this option is to prevent damage to + preexisting filesystems. + Even if you leave this disabled, you can enable BBT writes at module + load time (assuming you build diskonchip as a module) with the module + parameter "inftl_bbt_write=1". + + +endif diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile new file mode 100644 index 0000000..73f7346 --- /dev/null +++ b/drivers/mtd/nand/Makefile @@ -0,0 +1,12 @@ + +# Generic NAND options +obj-$(CONFIG_NAND) += nand.o nand_ecc.o +obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o +obj-$(CONFIG_NAND) += nand_base.o nand_bbt.o + +obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o +obj-$(CONFIG_NAND_IMX) += nand_imx.o +obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.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/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c new file mode 100644 index 0000000..e8f85fc --- /dev/null +++ b/drivers/mtd/nand/atmel_nand.c @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2003 Rick Bronson + * + * Derived from drivers/mtd/nand/autcpu12.c + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * Derived from drivers/mtd/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * + * + * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 + * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 + * + * Derived from Das U-Boot source code + * (u-boot-1.1.5/board/atmel/at91sam9263ek/nand.c) + * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas + * + * + * 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 +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW +#define hard_ecc 1 +#else +#define hard_ecc 0 +#endif + +#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE +#define no_ecc 1 +#else +#define no_ecc 0 +#endif + +/* Register access macros */ +#define ecc_readl(add, reg) \ + readl(add + ATMEL_ECC_##reg) +#define ecc_writel(add, reg, value) \ + writel((value), add + ATMEL_ECC_##reg) + +#include "atmel_nand_ecc.h" /* Hardware ECC registers */ + +/* oob layout for large page size + * bad block info is on bytes 0 and 1 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout atmel_oobinfo_large = { + .eccbytes = 4, + .eccpos = {60, 61, 62, 63}, + .oobfree = { + {2, 58} + }, +}; + +/* oob layout for small page size + * bad block info is on bytes 4 and 5 + * the bytes have to be consecutives to avoid + * several NAND_CMD_RNDOUT during read + */ +static struct nand_ecclayout atmel_oobinfo_small = { + .eccbytes = 4, + .eccpos = {0, 1, 2, 3}, + .oobfree = { + {6, 10} + }, +}; + +struct atmel_nand_host { + struct nand_chip nand_chip; + struct mtd_info mtd; + void __iomem *io_base; + struct atmel_nand_data *board; + struct device_d *dev; + void __iomem *ecc; +}; + +/* + * Enable NAND. + */ +static void atmel_nand_enable(struct atmel_nand_host *host) +{ + if (host->board->enable_pin) + gpio_set_value(host->board->enable_pin, 0); +} + +/* + * Disable NAND. + */ +static void atmel_nand_disable(struct atmel_nand_host *host) +{ + if (host->board->enable_pin) + gpio_set_value(host->board->enable_pin, 1); +} + +/* + * Hardware specific access to control-lines + */ +static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + + if (ctrl & NAND_CTRL_CHANGE) { + if (ctrl & NAND_NCE) + atmel_nand_enable(host); + else + atmel_nand_disable(host); + } + if (cmd == NAND_CMD_NONE) + return; + + if (ctrl & NAND_CLE) + writeb(cmd, host->io_base + (1 << host->board->cle)); + else + writeb(cmd, host->io_base + (1 << host->board->ale)); +} + +/* + * Read the Device Ready pin. + */ +static int atmel_nand_device_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + + return gpio_get_value(host->board->rdy_pin); +} + +/* + * Minimal-overhead PIO for data access. + */ +static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + readsb(nand_chip->IO_ADDR_R, buf, len); +} + +static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + readsw(nand_chip->IO_ADDR_R, buf, len / 2); +} + +static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + writesb(nand_chip->IO_ADDR_W, buf, len); +} + +static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + + writesw(nand_chip->IO_ADDR_W, buf, len / 2); +} + +/* + * Calculate HW ECC + * + * function called after a write + * + * mtd: MTD block structure + * dat: raw data (unused) + * ecc_code: buffer for ECC + */ +static int atmel_nand_calculate(struct mtd_info *mtd, + const u_char *dat, unsigned char *ecc_code) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; +/* uint32_t *eccpos = nand_chip->ecc.layout->eccpos; */ + unsigned int ecc_value; + + /* get the first 2 ECC bytes */ + ecc_value = ecc_readl(host->ecc, PR); + + ecc_code[0] = ecc_value & 0xFF; + ecc_code[1] = (ecc_value >> 8) & 0xFF; + + /* get the last 2 ECC bytes */ + ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; + + ecc_code[2] = ecc_value & 0xFF; + ecc_code[3] = (ecc_value >> 8) & 0xFF; + + return 0; +} + +/* + * HW ECC read page function + * + * mtd: mtd info structure + * chip: nand chip info structure + * buf: buffer to store read data + */ +static int atmel_nand_read_page(struct mtd_info *mtd, + struct nand_chip *chip, uint8_t *buf) +{ + int eccsize = chip->ecc.size; + int eccbytes = chip->ecc.bytes; + uint32_t *eccpos = chip->ecc.layout->eccpos; + uint8_t *p = buf; + uint8_t *oob = chip->oob_poi; + uint8_t *ecc_pos; + int stat; + + /* + * Errata: ALE is incorrectly wired up to the ECC controller + * on the AP7000, so it will include the address cycles in the + * ECC calculation. + * + * Workaround: Reset the parity registers before reading the + * actual data. + */ +#if 0 + if (cpu_is_at32ap7000()) { + struct atmel_nand_host *host = chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } +#endif + + /* read the page */ + chip->read_buf(mtd, p, eccsize); + + /* move to ECC position if needed */ + if (eccpos[0] != 0) { + /* This only works on large pages + * because the ECC controller waits for + * NAND_CMD_RNDOUTSTART after the + * NAND_CMD_RNDOUT. + * anyway, for small pages, the eccpos[0] == 0 + */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, + mtd->writesize + eccpos[0], -1); + } + + /* the ECC controller needs to read the ECC just after the data */ + ecc_pos = oob + eccpos[0]; + chip->read_buf(mtd, ecc_pos, eccbytes); + + /* check if there's an error */ + stat = chip->ecc.correct(mtd, p, oob, NULL); + + if (stat < 0) + mtd->ecc_stats.failed++; + else + mtd->ecc_stats.corrected += stat; + + /* get back to oob start (end of page) */ + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); + + /* read the oob */ + chip->read_buf(mtd, oob, mtd->oobsize); + + return 0; +} + +/* + * HW ECC Correction + * + * function called after a read + * + * mtd: MTD block structure + * dat: raw data read from the chip + * read_ecc: ECC from the chip (unused) + * isnull: unused + * + * Detect and correct a 1 bit error for a page + */ +static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *isnull) +{ + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + unsigned int ecc_status; + unsigned int ecc_word, ecc_bit; + + /* get the status from the Status Register */ + ecc_status = ecc_readl(host->ecc, SR); + + /* if there's no error */ + if (likely(!(ecc_status & ATMEL_ECC_RECERR))) + return 0; + + /* get error bit offset (4 bits) */ + ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; + /* get word address (12 bits) */ + ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; + ecc_word >>= 4; + + /* if there are multiple errors */ + if (ecc_status & ATMEL_ECC_MULERR) { + /* check if it is a freshly erased block + * (filled with 0xff) */ + if ((ecc_bit == ATMEL_ECC_BITADDR) + && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { + /* the block has just been erased, return OK */ + return 0; + } + /* it doesn't seems to be a freshly + * erased block. + * We can't correct so many errors */ + dev_dbg(host->dev, "atmel_nand : multiple errors detected." + " Unable to correct.\n"); + return -EIO; + } + + /* if there's a single bit error : we can correct it */ + if (ecc_status & ATMEL_ECC_ECCERR) { + /* there's nothing much to do here. + * the bit error is on the ECC itself. + */ + dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." + " Nothing to correct\n"); + return 0; + } + + dev_dbg(host->dev, "atmel_nand : one bit error on data." + " (word offset in the page :" + " 0x%x bit offset : 0x%x)\n", + ecc_word, ecc_bit); + /* correct the error */ + if (nand_chip->options & NAND_BUSWIDTH_16) { + /* 16 bits words */ + ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); + } else { + /* 8 bits words */ + dat[ecc_word] ^= (1 << ecc_bit); + } + dev_dbg(host->dev, "atmel_nand : error corrected\n"); + return 1; +} + +/* + * Enable HW ECC : unused on most chips + */ +static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) +{ +#if 0 + if (cpu_is_at32ap7000()) { + struct nand_chip *nand_chip = mtd->priv; + struct atmel_nand_host *host = nand_chip->priv; + ecc_writel(host->ecc, CR, ATMEL_ECC_RST); + } +#endif +} + +/* + * Probe for the NAND device. + */ +static int __init atmel_nand_probe(struct device_d *dev) +{ + struct atmel_nand_data *pdata = dev->platform_data; + struct atmel_nand_host *host; + struct mtd_info *mtd; + struct nand_chip *nand_chip; + int res = 0; + + /* Allocate memory for the device structure (and zero it) */ + host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->io_base = (void __iomem *)dev->map_base; + + mtd = &host->mtd; + nand_chip = &host->nand_chip; + host->board = pdata; + host->dev = dev; + + nand_chip->priv = host; /* link the private data structures */ + mtd->priv = nand_chip; + + /* Set address of NAND IO lines */ + nand_chip->IO_ADDR_R = host->io_base; + nand_chip->IO_ADDR_W = host->io_base; + nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; + + if (host->board->rdy_pin) + nand_chip->dev_ready = atmel_nand_device_ready; + + nand_chip->ecc.mode = pdata->ecc_mode; + + if (pdata->ecc_mode == NAND_ECC_HW) { + if (!pdata->ecc_base) + return -ENODEV; + + host->ecc = pdata->ecc_base; + + nand_chip->ecc.mode = NAND_ECC_HW; + nand_chip->ecc.calculate = atmel_nand_calculate; + nand_chip->ecc.correct = atmel_nand_correct; + nand_chip->ecc.hwctl = atmel_nand_hwctl; + nand_chip->ecc.read_page = atmel_nand_read_page; + nand_chip->ecc.bytes = 4; + } + + nand_chip->chip_delay = 20; /* 20us command delay time */ + + if (host->board->bus_width_16) { /* 16-bit bus width */ + nand_chip->options |= NAND_BUSWIDTH_16; + nand_chip->read_buf = atmel_read_buf16; + nand_chip->write_buf = atmel_write_buf16; + } else { + nand_chip->read_buf = atmel_read_buf; + nand_chip->write_buf = atmel_write_buf; + } + + atmel_nand_enable(host); + + if (host->board->det_pin) { + if (gpio_get_value(host->board->det_pin)) { + printk("No SmartMedia card inserted.\n"); + res = ENXIO; + goto err_no_card; + } + } + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1)) { + res = -ENXIO; + goto err_scan_ident; + } + + if (nand_chip->ecc.mode == NAND_ECC_HW) { + /* ECC is calculated for the whole page (1 step) */ + nand_chip->ecc.size = mtd->writesize; + + /* set ECC page size and oob layout */ + switch (mtd->writesize) { + case 512: + nand_chip->ecc.layout = &atmel_oobinfo_small; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); + break; + case 1024: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); + break; + case 2048: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); + break; + case 4096: + nand_chip->ecc.layout = &atmel_oobinfo_large; + ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); + break; + default: + /* page size not handled by HW ECC */ + /* switching back to soft ECC */ + nand_chip->ecc.mode = NAND_ECC_SOFT; + nand_chip->ecc.calculate = NULL; + nand_chip->ecc.correct = NULL; + nand_chip->ecc.hwctl = NULL; + nand_chip->ecc.read_page = NULL; + nand_chip->ecc.postpad = 0; + nand_chip->ecc.prepad = 0; + nand_chip->ecc.bytes = 0; + break; + } + } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + res = -ENXIO; + goto err_scan_tail; + } + + add_mtd_device(mtd); + + if (!res) + return res; + + nand_release(mtd); +err_scan_tail: +err_scan_ident: +err_no_card: + atmel_nand_disable(host); + kfree(host); + return res; +} + +static struct driver_d atmel_nand_driver = { + .name = "atmel_nand", + .probe = atmel_nand_probe, +}; + +static int __init atmel_nand_init(void) +{ + return register_driver(&atmel_nand_driver); +} + +device_initcall(atmel_nand_init); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Rick Bronson"); +MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h new file mode 100644 index 0000000..578c776 --- /dev/null +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -0,0 +1,39 @@ +/* + * Error Corrected Code Controller (ECC) - System peripherals regsters. + * Based on AT91SAM9260 datasheet revision B. + * + * Copyright (C) 2007 Andrew Victor + * Copyright (C) 2007 Atmel Corporation. + * + * 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. + */ + +#ifndef ATMEL_NAND_ECC_H +#define ATMEL_NAND_ECC_H + +#define ATMEL_ECC_CR 0x00 /* Control register */ +#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ + +#define ATMEL_ECC_MR 0x04 /* Mode register */ +#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ +#define ATMEL_ECC_PAGESIZE_528 (0) +#define ATMEL_ECC_PAGESIZE_1056 (1) +#define ATMEL_ECC_PAGESIZE_2112 (2) +#define ATMEL_ECC_PAGESIZE_4224 (3) + +#define ATMEL_ECC_SR 0x08 /* Status register */ +#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ +#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ +#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ + +#define ATMEL_ECC_PR 0x0c /* Parity register */ +#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ +#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ + +#define ATMEL_ECC_NPR 0x10 /* NParity register */ +#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ + +#endif diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c new file mode 100644 index 0000000..e762524 --- /dev/null +++ b/drivers/mtd/nand/diskonchip.c @@ -0,0 +1,1787 @@ +/* + * drivers/mtd/nand/diskonchip.c + * + * (C) 2003 Red Hat, Inc. + * (C) 2004 Dan Brown + * (C) 2004 Kalev Lember + * + * Author: David Woodhouse + * Additional Diskonchip 2000 and Millennium support by Dan Brown + * Diskonchip Millennium Plus support by Kalev Lember + * + * Error correction code lifted from the old docecc code + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Copyright (C) 2000 Netgem S.A. + * converted to the generic Reed-Solomon library by Thomas Gleixner + * + * Interface to generic NAND code for M-Systems DiskOnChip devices + * + * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $ + */ + +#include + +#if !defined(CFG_NAND_LEGACY) + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* Where to look for the devices? */ +#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS +#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0 +#endif + +static unsigned long __initdata doc_locations[] = { +#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) +#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH + 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, + 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, + 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, + 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, + 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, +#else /* CONFIG_MTD_DOCPROBE_HIGH */ + 0xc8000, 0xca000, 0xcc000, 0xce000, + 0xd0000, 0xd2000, 0xd4000, 0xd6000, + 0xd8000, 0xda000, 0xdc000, 0xde000, + 0xe0000, 0xe2000, 0xe4000, 0xe6000, + 0xe8000, 0xea000, 0xec000, 0xee000, +#endif /* CONFIG_MTD_DOCPROBE_HIGH */ +#elif defined(__PPC__) + 0xe4000000, +#elif defined(CONFIG_MOMENCO_OCELOT) + 0x2f000000, + 0xff000000, +#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) + 0xff000000, +##else +#warning Unknown architecture for DiskOnChip. No default probe locations defined +#endif + 0xffffffff }; + +static struct mtd_info *doclist = NULL; + +struct doc_priv { + void __iomem *virtadr; + unsigned long physadr; + u_char ChipID; + u_char CDSNControl; + int chips_per_floor; /* The number of chips detected on each floor */ + int curfloor; + int curchip; + int mh0_page; + int mh1_page; + struct mtd_info *nextdoc; +}; + +/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL + MediaHeader. The spec says to just keep going, I think, but that's just + silly. */ +#define MAX_MEDIAHEADER_SCAN 8 + +/* This is the syndrome computed by the HW ecc generator upon reading an empty + page, one with all 0xff for data and stored ecc code. */ +static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a }; +/* This is the ecc value computed by the HW ecc generator upon writing an empty + page, one with all 0xff for data. */ +static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; + +#define INFTL_BBT_RESERVED_BLOCKS 4 + +#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32) +#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) +#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) + +static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); +static void doc200x_select_chip(struct mtd_info *mtd, int chip); + +static int debug=0; +module_param(debug, int, 0); + +static int try_dword=1; +module_param(try_dword, int, 0); + +static int no_ecc_failures=0; +module_param(no_ecc_failures, int, 0); + +#ifdef CONFIG_MTD_PARTITIONS +static int no_autopart=0; +module_param(no_autopart, int, 0); +#endif + +#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE +static int inftl_bbt_write=1; +#else +static int inftl_bbt_write=0; +#endif +module_param(inftl_bbt_write, int, 0); + +static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS; +module_param(doc_config_location, ulong, 0); +MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); + + +/* Sector size for HW ECC */ +#define SECTOR_SIZE 512 +/* The sector bytes are packed into NB_DATA 10 bit words */ +#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10) +/* Number of roots */ +#define NROOTS 4 +/* First consective root */ +#define FCR 510 +/* Number of symbols */ +#define NN 1023 + +/* the Reed Solomon control structure */ +static struct rs_control *rs_decoder; + +/* + * The HW decoder in the DoC ASIC's provides us a error syndrome, + * which we must convert to a standard syndrom usable by the generic + * Reed-Solomon library code. + * + * Fabrice Bellard figured this out in the old docecc code. I added + * some comments, improved a minor bit and converted it to make use + * of the generic Reed-Solomon libary. tglx + */ +static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) +{ + int i, j, nerr, errpos[8]; + uint8_t parity; + uint16_t ds[4], s[5], tmp, errval[8], syn[4]; + + /* Convert the ecc bytes into words */ + ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8); + ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6); + ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4); + ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2); + parity = ecc[1]; + + /* Initialize the syndrom buffer */ + for (i = 0; i < NROOTS; i++) + s[i] = ds[0]; + /* + * Evaluate + * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] + * where x = alpha^(FCR + i) + */ + for(j = 1; j < NROOTS; j++) { + if(ds[j] == 0) + continue; + tmp = rs->index_of[ds[j]]; + for(i = 0; i < NROOTS; i++) + s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)]; + } + + /* Calc s[i] = s[i] / alpha^(v + i) */ + for (i = 0; i < NROOTS; i++) { + if (syn[i]) + syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i)); + } + /* Call the decoder library */ + nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval); + + /* Incorrectable errors ? */ + if (nerr < 0) + return nerr; + + /* + * Correct the errors. The bitpositions are a bit of magic, + * but they are given by the design of the de/encoder circuit + * in the DoC ASIC's. + */ + for(i = 0;i < nerr; i++) { + int index, bitpos, pos = 1015 - errpos[i]; + uint8_t val; + if (pos >= NB_DATA && pos < 1019) + continue; + if (pos < NB_DATA) { + /* extract bit position (MSB first) */ + pos = 10 * (NB_DATA - 1 - pos) - 6; + /* now correct the following 10 bits. At most two bytes + can be modified since pos is even */ + index = (pos >> 3) ^ 1; + bitpos = pos & 7; + if ((index >= 0 && index < SECTOR_SIZE) || + index == (SECTOR_SIZE + 1)) { + val = (uint8_t) (errval[i] >> (2 + bitpos)); + parity ^= val; + if (index < SECTOR_SIZE) + data[index] ^= val; + } + index = ((pos >> 3) + 1) ^ 1; + bitpos = (bitpos + 10) & 7; + if (bitpos == 0) + bitpos = 8; + if ((index >= 0 && index < SECTOR_SIZE) || + index == (SECTOR_SIZE + 1)) { + val = (uint8_t)(errval[i] << (8 - bitpos)); + parity ^= val; + if (index < SECTOR_SIZE) + data[index] ^= val; + } + } + } + /* If the parity is wrong, no rescue possible */ + return parity ? -1 : nerr; +} + +static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) +{ + volatile char dummy; + int i; + + for (i = 0; i < cycles; i++) { + if (DoC_is_Millennium(doc)) + dummy = ReadDOC(doc->virtadr, NOP); + else if (DoC_is_MillenniumPlus(doc)) + dummy = ReadDOC(doc->virtadr, Mplus_NOP); + else + dummy = ReadDOC(doc->virtadr, DOCStatus); + } + +} + +#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) + +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ +static int _DoC_WaitReady(struct doc_priv *doc) +{ + void __iomem *docptr = doc->virtadr; + unsigned long timeo = jiffies + (HZ * 10); + + if(debug) printk("_DoC_WaitReady...\n"); + /* Out-of-line routine to wait for chip response */ + if (DoC_is_MillenniumPlus(doc)) { + while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { + if (time_after(jiffies, timeo)) { + printk("_DoC_WaitReady timed out.\n"); + return -EIO; + } + udelay(1); + cond_resched(); + } + } else { + while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { + if (time_after(jiffies, timeo)) { + printk("_DoC_WaitReady timed out.\n"); + return -EIO; + } + udelay(1); + cond_resched(); + } + } + + return 0; +} + +static inline int DoC_WaitReady(struct doc_priv *doc) +{ + void __iomem *docptr = doc->virtadr; + int ret = 0; + + if (DoC_is_MillenniumPlus(doc)) { + DoC_Delay(doc, 4); + + if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(doc); + } else { + DoC_Delay(doc, 4); + + if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(doc); + DoC_Delay(doc, 2); + } + + if(debug) printk("DoC_WaitReady OK\n"); + return ret; +} + +static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + if(debug)printk("write_byte %02x\n", datum); + WriteDOC(datum, docptr, CDSNSlowIO); + WriteDOC(datum, docptr, 2k_CDSN_IO); +} + +static u_char doc2000_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + u_char ret; + + ReadDOC(docptr, CDSNSlowIO); + DoC_Delay(doc, 2); + ret = ReadDOC(docptr, 2k_CDSN_IO); + if (debug) printk("read_byte returns %02x\n", ret); + return ret; +} + +static void doc2000_writebuf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + if (debug)printk("writebuf of %d bytes: ", len); + for (i=0; i < len; i++) { + WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i); + if (debug && i < 16) + printk("%02x ", buf[i]); + } + if (debug) printk("\n"); +} + +static void doc2000_readbuf(struct mtd_info *mtd, + u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + if (debug)printk("readbuf of %d bytes: ", len); + + for (i=0; i < len; i++) { + buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i); + } +} + +static void doc2000_readbuf_dword(struct mtd_info *mtd, + u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + if (debug) printk("readbuf_dword of %d bytes: ", len); + + if (unlikely((((unsigned long)buf)|len) & 3)) { + for (i=0; i < len; i++) { + *(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i); + } + } else { + for (i=0; i < len; i+=4) { + *(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i); + } + } +} + +static int doc2000_verifybuf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + for (i=0; i < len; i++) + if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO)) + return -EFAULT; + return 0; +} + +static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + uint16_t ret; + + doc200x_select_chip(mtd, nr); + doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); + this->write_byte(mtd, NAND_CMD_READID); + doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); + doc200x_hwcontrol(mtd, NAND_CTL_SETALE); + this->write_byte(mtd, 0); + doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); + + ret = this->read_byte(mtd) << 8; + ret |= this->read_byte(mtd); + + if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) { + /* First chip probe. See if we get same results by 32-bit access */ + union { + uint32_t dword; + uint8_t byte[4]; + } ident; + void __iomem *docptr = doc->virtadr; + + doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); + doc2000_write_byte(mtd, NAND_CMD_READID); + doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); + doc200x_hwcontrol(mtd, NAND_CTL_SETALE); + doc2000_write_byte(mtd, 0); + doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); + + ident.dword = readl(docptr + DoC_2k_CDSN_IO); + if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { + printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); + this->read_buf = &doc2000_readbuf_dword; + } + } + + return ret; +} + +static void __init doc2000_count_chips(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + uint16_t mfrid; + int i; + + /* Max 4 chips per floor on DiskOnChip 2000 */ + doc->chips_per_floor = 4; + + /* Find out what the first chip is */ + mfrid = doc200x_ident_chip(mtd, 0); + + /* Find how many chips in each floor. */ + for (i = 1; i < 4; i++) { + if (doc200x_ident_chip(mtd, i) != mfrid) + break; + } + doc->chips_per_floor = i; + printk(KERN_DEBUG "Detected %d chips per floor.\n", i); +} + +static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) +{ + struct doc_priv *doc = this->priv; + + int status; + + DoC_WaitReady(doc); + this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + DoC_WaitReady(doc); + status = (int)this->read_byte(mtd); + + return status; +} + +static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + WriteDOC(datum, docptr, CDSNSlowIO); + WriteDOC(datum, docptr, Mil_CDSN_IO); + WriteDOC(datum, docptr, WritePipeTerm); +} + +static u_char doc2001_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + /*ReadDOC(docptr, CDSNSlowIO); */ + /* 11.4.5 -- delay twice to allow extended length cycle */ + DoC_Delay(doc, 2); + ReadDOC(docptr, ReadPipeInit); + /*return ReadDOC(docptr, Mil_CDSN_IO); */ + return ReadDOC(docptr, LastDataRead); +} + +static void doc2001_writebuf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + for (i=0; i < len; i++) + WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); + /* Terminate write pipeline */ + WriteDOC(0x00, docptr, WritePipeTerm); +} + +static void doc2001_readbuf(struct mtd_info *mtd, + u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + /* Start read pipeline */ + ReadDOC(docptr, ReadPipeInit); + + for (i=0; i < len-1; i++) + buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff)); + + /* Terminate read pipeline */ + buf[i] = ReadDOC(docptr, LastDataRead); +} + +static int doc2001_verifybuf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + /* Start read pipeline */ + ReadDOC(docptr, ReadPipeInit); + + for (i=0; i < len-1; i++) + if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) { + ReadDOC(docptr, LastDataRead); + return i; + } + if (buf[i] != ReadDOC(docptr, LastDataRead)) + return i; + return 0; +} + +static u_char doc2001plus_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + u_char ret; + + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + ret = ReadDOC(docptr, Mplus_LastDataRead); + if (debug) printk("read_byte returns %02x\n", ret); + return ret; +} + +static void doc2001plus_writebuf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + if (debug)printk("writebuf of %d bytes: ", len); + for (i=0; i < len; i++) { + WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); + if (debug && i < 16) + printk("%02x ", buf[i]); + } + if (debug) printk("\n"); +} + +static void doc2001plus_readbuf(struct mtd_info *mtd, + u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + if (debug)printk("readbuf of %d bytes: ", len); + + /* Start read pipeline */ + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + + for (i=0; i < len-2; i++) { + buf[i] = ReadDOC(docptr, Mil_CDSN_IO); + if (debug && i < 16) + printk("%02x ", buf[i]); + } + + /* Terminate read pipeline */ + buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); + if (debug && i < 16) + printk("%02x ", buf[len-2]); + buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); + if (debug && i < 16) + printk("%02x ", buf[len-1]); + if (debug) printk("\n"); +} + +static int doc2001plus_verifybuf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + + if (debug)printk("verifybuf of %d bytes: ", len); + + /* Start read pipeline */ + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + + for (i=0; i < len-2; i++) + if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) { + ReadDOC(docptr, Mplus_LastDataRead); + ReadDOC(docptr, Mplus_LastDataRead); + return i; + } + if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead)) + return len-2; + if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead)) + return len-1; + return 0; +} + +static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int floor = 0; + + if(debug)printk("select chip (%d)\n", chip); + + if (chip == -1) { + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + return; + } + + floor = chip / doc->chips_per_floor; + chip -= (floor * doc->chips_per_floor); + + /* Assert ChipEnable and deassert WriteProtect */ + WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect); + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + doc->curchip = chip; + doc->curfloor = floor; +} + +static void doc200x_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int floor = 0; + + if(debug)printk("select chip (%d)\n", chip); + + if (chip == -1) + return; + + floor = chip / doc->chips_per_floor; + chip -= (floor * doc->chips_per_floor); + + /* 11.4.4 -- deassert CE before changing chip */ + doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); + + WriteDOC(floor, docptr, FloorSelect); + WriteDOC(chip, docptr, CDSNDeviceSelect); + + doc200x_hwcontrol(mtd, NAND_CTL_SETNCE); + + doc->curchip = chip; + doc->curfloor = floor; +} + +static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + switch(cmd) { + case NAND_CTL_SETNCE: + doc->CDSNControl |= CDSN_CTRL_CE; + break; + case NAND_CTL_CLRNCE: + doc->CDSNControl &= ~CDSN_CTRL_CE; + break; + case NAND_CTL_SETCLE: + doc->CDSNControl |= CDSN_CTRL_CLE; + break; + case NAND_CTL_CLRCLE: + doc->CDSNControl &= ~CDSN_CTRL_CLE; + break; + case NAND_CTL_SETALE: + doc->CDSNControl |= CDSN_CTRL_ALE; + break; + case NAND_CTL_CLRALE: + doc->CDSNControl &= ~CDSN_CTRL_ALE; + break; + case NAND_CTL_SETWP: + doc->CDSNControl |= CDSN_CTRL_WP; + break; + case NAND_CTL_CLRWP: + doc->CDSNControl &= ~CDSN_CTRL_WP; + break; + } + if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); + WriteDOC(doc->CDSNControl, docptr, CDSNControl); + /* 11.4.3 -- 4 NOPs after CSDNControl write */ + DoC_Delay(doc, 4); +} + +static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + /* + * Must terminate write pipeline before sending any commands + * to the device. + */ + if (command == NAND_CMD_PAGEPROG) { + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + } + + /* + * Write out the command to the device. + */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->oobblock) { + /* OOB area */ + column -= mtd->oobblock; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + WriteDOC(readcmd, docptr, Mplus_FlashCmd); + } + WriteDOC(command, docptr, Mplus_FlashCmd); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + + if (column != -1 || page_addr != -1) { + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (this->options & NAND_BUSWIDTH_16) + column >>= 1; + WriteDOC(column, docptr, Mplus_FlashAddress); + } + if (page_addr != -1) { + WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress); + WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); + /* One more address cycle for higher density devices */ + if (this->chipsize & 0x0c000000) { + WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); + printk("high density\n"); + } + } + WriteDOC(0, docptr, Mplus_WritePipeTerm); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + /* deassert ALE */ + if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID) + WriteDOC(0, docptr, Mplus_FlashControl); + } + + /* + * program and erase have their own busy handlers + * status and sequential in needs no delay + */ + switch (command) { + + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + return; + + case NAND_CMD_RESET: + if (this->dev_ready) + break; + udelay(this->chip_delay); + WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + WriteDOC(0, docptr, Mplus_WritePipeTerm); + while ( !(this->read_byte(mtd) & 0x40)); + return; + + /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!this->dev_ready) { + udelay (this->chip_delay); + return; + } + } + + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay (100); + /* wait until command is processed */ + while (!this->dev_ready(mtd)); +} + +static int doc200x_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + if (DoC_is_MillenniumPlus(doc)) { + /* 11.4.2 -- must NOP four times before checking FR/B# */ + DoC_Delay(doc, 4); + if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { + if(debug) + printk("not ready\n"); + return 0; + } + if (debug)printk("was ready\n"); + return 1; + } else { + /* 11.4.2 -- must NOP four times before checking FR/B# */ + DoC_Delay(doc, 4); + if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { + if(debug) + printk("not ready\n"); + return 0; + } + /* 11.4.2 -- Must NOP twice if it's ready */ + DoC_Delay(doc, 2); + if (debug)printk("was ready\n"); + return 1; + } +} + +static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) +{ + /* This is our last resort if we couldn't find or create a BBT. Just + pretend all blocks are good. */ + return 0; +} + +static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + /* Prime the ECC engine */ + switch(mode) { + case NAND_ECC_READ: + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_EN, docptr, ECCConf); + break; + case NAND_ECC_WRITE: + WriteDOC(DOC_ECC_RESET, docptr, ECCConf); + WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); + break; + } +} + +static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + + /* Prime the ECC engine */ + switch(mode) { + case NAND_ECC_READ: + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); + break; + case NAND_ECC_WRITE: + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); + break; + } +} + +/* This code is only called on write */ +static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + unsigned char *ecc_code) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + int i; + int emptymatch = 1; + + /* flush the pipeline */ + if (DoC_is_2000(doc)) { + WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl); + WriteDOC(0, docptr, 2k_CDSN_IO); + WriteDOC(0, docptr, 2k_CDSN_IO); + WriteDOC(0, docptr, 2k_CDSN_IO); + WriteDOC(doc->CDSNControl, docptr, CDSNControl); + } else if (DoC_is_MillenniumPlus(doc)) { + WriteDOC(0, docptr, Mplus_NOP); + WriteDOC(0, docptr, Mplus_NOP); + WriteDOC(0, docptr, Mplus_NOP); + } else { + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + WriteDOC(0, docptr, NOP); + } + + for (i = 0; i < 6; i++) { + if (DoC_is_MillenniumPlus(doc)) + ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); + else + ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); + if (ecc_code[i] != empty_write_ecc[i]) + emptymatch = 0; + } + if (DoC_is_MillenniumPlus(doc)) + WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); + else + WriteDOC(DOC_ECC_DIS, docptr, ECCConf); +#if 0 + /* If emptymatch=1, we might have an all-0xff data buffer. Check. */ + if (emptymatch) { + /* Note: this somewhat expensive test should not be triggered + often. It could be optimized away by examining the data in + the writebuf routine, and remembering the result. */ + for (i = 0; i < 512; i++) { + if (dat[i] == 0xff) continue; + emptymatch = 0; + break; + } + } + /* If emptymatch still =1, we do have an all-0xff data buffer. + Return all-0xff ecc value instead of the computed one, so + it'll look just like a freshly-erased page. */ + if (emptymatch) memset(ecc_code, 0xff, 6); +#endif + return 0; +} + +static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) +{ + int i, ret = 0; + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + void __iomem *docptr = doc->virtadr; + volatile u_char dummy; + int emptymatch = 1; + + /* flush the pipeline */ + if (DoC_is_2000(doc)) { + dummy = ReadDOC(docptr, 2k_ECCStatus); + dummy = ReadDOC(docptr, 2k_ECCStatus); + dummy = ReadDOC(docptr, 2k_ECCStatus); + } else if (DoC_is_MillenniumPlus(doc)) { + dummy = ReadDOC(docptr, Mplus_ECCConf); + dummy = ReadDOC(docptr, Mplus_ECCConf); + dummy = ReadDOC(docptr, Mplus_ECCConf); + } else { + dummy = ReadDOC(docptr, ECCConf); + dummy = ReadDOC(docptr, ECCConf); + dummy = ReadDOC(docptr, ECCConf); + } + + /* Error occured ? */ + if (dummy & 0x80) { + for (i = 0; i < 6; i++) { + if (DoC_is_MillenniumPlus(doc)) + calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); + else + calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); + if (calc_ecc[i] != empty_read_syndrome[i]) + emptymatch = 0; + } + /* If emptymatch=1, the read syndrome is consistent with an + all-0xff data and stored ecc block. Check the stored ecc. */ + if (emptymatch) { + for (i = 0; i < 6; i++) { + if (read_ecc[i] == 0xff) continue; + emptymatch = 0; + break; + } + } + /* If emptymatch still =1, check the data block. */ + if (emptymatch) { + /* Note: this somewhat expensive test should not be triggered + often. It could be optimized away by examining the data in + the readbuf routine, and remembering the result. */ + for (i = 0; i < 512; i++) { + if (dat[i] == 0xff) continue; + emptymatch = 0; + break; + } + } + /* If emptymatch still =1, this is almost certainly a freshly- + erased block, in which case the ECC will not come out right. + We'll suppress the error and tell the caller everything's + OK. Because it is. */ + if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); + if (ret > 0) + printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); + } + if (DoC_is_MillenniumPlus(doc)) + WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); + else + WriteDOC(DOC_ECC_DIS, docptr, ECCConf); + if (no_ecc_failures && (ret == -1)) { + printk(KERN_ERR "suppressing ECC failure\n"); + ret = 0; + } + return ret; +} + +/*u_char mydatabuf[528]; */ + +static struct nand_oobinfo doc200x_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 6, + .eccpos = {0, 1, 2, 3, 4, 5}, + .oobfree = { {8, 8} } +}; + +/* Find the (I)NFTL Media Header, and optionally also the mirror media header. + On sucessful return, buf will contain a copy of the media header for + further processing. id is the string to scan for, and will presumably be + either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media + header. The page #s of the found media headers are placed in mh0_page and + mh1_page in the DOC private structure. */ +static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, + const char *id, int findmirror) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift); + int ret; + size_t retlen; + + end = min(end, mtd->size); /* paranoia */ + for (offs = 0; offs < end; offs += mtd->erasesize) { + ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); + if (retlen != mtd->oobblock) continue; + if (ret) { + printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", + offs); + } + if (memcmp(buf, id, 6)) continue; + printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs); + if (doc->mh0_page == -1) { + doc->mh0_page = offs >> this->page_shift; + if (!findmirror) return 1; + continue; + } + doc->mh1_page = offs >> this->page_shift; + return 2; + } + if (doc->mh0_page == -1) { + printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id); + return 0; + } + /* Only one mediaheader was found. We want buf to contain a + mediaheader on return, so we'll have to re-read the one we found. */ + offs = doc->mh0_page << this->page_shift; + ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); + if (retlen != mtd->oobblock) { + /* Insanity. Give up. */ + printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n"); + return 0; + } + return 1; +} + +static inline int __init nftl_partscan(struct mtd_info *mtd, + struct mtd_partition *parts) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + int ret = 0; + u_char *buf; + struct NFTLMediaHeader *mh; + const unsigned psize = 1 << this->page_shift; + unsigned blocks, maxblocks; + int offs, numheaders; + + buf = kmalloc(mtd->oobblock, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); + return 0; + } + if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; + mh = (struct NFTLMediaHeader *) buf; + +/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ +/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ + printk(KERN_INFO " DataOrgID = %s\n" + " NumEraseUnits = %d\n" + " FirstPhysicalEUN = %d\n" + " FormattedSize = %d\n" + " UnitSizeFactor = %d\n", + mh->DataOrgID, mh->NumEraseUnits, + mh->FirstPhysicalEUN, mh->FormattedSize, + mh->UnitSizeFactor); +/*#endif */ + + blocks = mtd->size >> this->phys_erase_shift; + maxblocks = min(32768U, mtd->erasesize - psize); + + if (mh->UnitSizeFactor == 0x00) { + /* Auto-determine UnitSizeFactor. The constraints are: + - There can be at most 32768 virtual blocks. + - There can be at most (virtual block size - page size) + virtual blocks (because MediaHeader+BBT must fit in 1). + */ + mh->UnitSizeFactor = 0xff; + while (blocks > maxblocks) { + blocks >>= 1; + maxblocks = min(32768U, (maxblocks << 1) + psize); + mh->UnitSizeFactor--; + } + printk(KERN_WARNING "UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor); + } + + /* NOTE: The lines below modify internal variables of the NAND and MTD + layers; variables with have already been configured by nand_scan. + Unfortunately, we didn't know before this point what these values + should be. Thus, this code is somewhat dependant on the exact + implementation of the NAND layer. */ + if (mh->UnitSizeFactor != 0xff) { + this->bbt_erase_shift += (0xff - mh->UnitSizeFactor); + mtd->erasesize <<= (0xff - mh->UnitSizeFactor); + printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize); + blocks = mtd->size >> this->bbt_erase_shift; + maxblocks = min(32768U, mtd->erasesize - psize); + } + + if (blocks > maxblocks) { + printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor); + goto out; + } + + /* Skip past the media headers. */ + offs = max(doc->mh0_page, doc->mh1_page); + offs <<= this->page_shift; + offs += mtd->erasesize; + + /*parts[0].name = " DiskOnChip Boot / Media Header partition"; */ + /*parts[0].offset = 0; */ + /*parts[0].size = offs; */ + + parts[0].name = " DiskOnChip BDTL partition"; + parts[0].offset = offs; + parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; + + offs += parts[0].size; + if (offs < mtd->size) { + parts[1].name = " DiskOnChip Remainder partition"; + parts[1].offset = offs; + parts[1].size = mtd->size - offs; + ret = 2; + goto out; + } + ret = 1; +out: + kfree(buf); + return ret; +} + +/* This is a stripped-down copy of the code in inftlmount.c */ +static inline int __init inftl_partscan(struct mtd_info *mtd, + struct mtd_partition *parts) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + int ret = 0; + u_char *buf; + struct INFTLMediaHeader *mh; + struct INFTLPartition *ip; + int numparts = 0; + int blocks; + int vshift, lastvunit = 0; + int i; + int end = mtd->size; + + if (inftl_bbt_write) + end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift); + + buf = kmalloc(mtd->oobblock, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); + return 0; + } + + if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out; + doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift); + mh = (struct INFTLMediaHeader *) buf; + + mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); + mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); + mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); + mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); + mh->FormatFlags = le32_to_cpu(mh->FormatFlags); + mh->PercentUsed = le32_to_cpu(mh->PercentUsed); + +/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ +/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ + printk(KERN_INFO " bootRecordID = %s\n" + " NoOfBootImageBlocks = %d\n" + " NoOfBinaryPartitions = %d\n" + " NoOfBDTLPartitions = %d\n" + " BlockMultiplerBits = %d\n" + " FormatFlgs = %d\n" + " OsakVersion = %d.%d.%d.%d\n" + " PercentUsed = %d\n", + mh->bootRecordID, mh->NoOfBootImageBlocks, + mh->NoOfBinaryPartitions, + mh->NoOfBDTLPartitions, + mh->BlockMultiplierBits, mh->FormatFlags, + ((unsigned char *) &mh->OsakVersion)[0] & 0xf, + ((unsigned char *) &mh->OsakVersion)[1] & 0xf, + ((unsigned char *) &mh->OsakVersion)[2] & 0xf, + ((unsigned char *) &mh->OsakVersion)[3] & 0xf, + mh->PercentUsed); +/*#endif */ + + vshift = this->phys_erase_shift + mh->BlockMultiplierBits; + + blocks = mtd->size >> vshift; + if (blocks > 32768) { + printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits); + goto out; + } + + blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift); + if (inftl_bbt_write && (blocks > mtd->erasesize)) { + printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n"); + goto out; + } + + /* Scan the partitions */ + for (i = 0; (i < 4); i++) { + ip = &(mh->Partitions[i]); + ip->virtualUnits = le32_to_cpu(ip->virtualUnits); + ip->firstUnit = le32_to_cpu(ip->firstUnit); + ip->lastUnit = le32_to_cpu(ip->lastUnit); + ip->flags = le32_to_cpu(ip->flags); + ip->spareUnits = le32_to_cpu(ip->spareUnits); + ip->Reserved0 = le32_to_cpu(ip->Reserved0); + +/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ +/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ + printk(KERN_INFO " PARTITION[%d] ->\n" + " virtualUnits = %d\n" + " firstUnit = %d\n" + " lastUnit = %d\n" + " flags = 0x%x\n" + " spareUnits = %d\n", + i, ip->virtualUnits, ip->firstUnit, + ip->lastUnit, ip->flags, + ip->spareUnits); +/*#endif */ + +/* + if ((i == 0) && (ip->firstUnit > 0)) { + parts[0].name = " DiskOnChip IPL / Media Header partition"; + parts[0].offset = 0; + parts[0].size = mtd->erasesize * ip->firstUnit; + numparts = 1; + } +*/ + + if (ip->flags & INFTL_BINARY) + parts[numparts].name = " DiskOnChip BDK partition"; + else + parts[numparts].name = " DiskOnChip BDTL partition"; + parts[numparts].offset = ip->firstUnit << vshift; + parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift; + numparts++; + if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit; + if (ip->flags & INFTL_LAST) break; + } + lastvunit++; + if ((lastvunit << vshift) < end) { + parts[numparts].name = " DiskOnChip Remainder partition"; + parts[numparts].offset = lastvunit << vshift; + parts[numparts].size = end - parts[numparts].offset; + numparts++; + } + ret = numparts; +out: + kfree(buf); + return ret; +} + +static int __init nftl_scan_bbt(struct mtd_info *mtd) +{ + int ret, numparts; + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + struct mtd_partition parts[2]; + + memset((char *) parts, 0, sizeof(parts)); + /* On NFTL, we have to find the media headers before we can read the + BBTs, since they're stored in the media header eraseblocks. */ + numparts = nftl_partscan(mtd, parts); + if (!numparts) return -EIO; + this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | + NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | + NAND_BBT_VERSION; + this->bbt_td->veroffs = 7; + this->bbt_td->pages[0] = doc->mh0_page + 1; + if (doc->mh1_page != -1) { + this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | + NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | + NAND_BBT_VERSION; + this->bbt_md->veroffs = 7; + this->bbt_md->pages[0] = doc->mh1_page + 1; + } else { + this->bbt_md = NULL; + } + + /* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set. + At least as nand_bbt.c is currently written. */ + if ((ret = nand_scan_bbt(mtd, NULL))) + return ret; + add_mtd_device(mtd); +#ifdef CONFIG_MTD_PARTITIONS + if (!no_autopart) + add_mtd_partitions(mtd, parts, numparts); +#endif + return 0; +} + +static int __init inftl_scan_bbt(struct mtd_info *mtd) +{ + int ret, numparts; + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + struct mtd_partition parts[5]; + + if (this->numchips > doc->chips_per_floor) { + printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n"); + return -EIO; + } + + if (DoC_is_MillenniumPlus(doc)) { + this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE; + if (inftl_bbt_write) + this->bbt_td->options |= NAND_BBT_WRITE; + this->bbt_td->pages[0] = 2; + this->bbt_md = NULL; + } else { + this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | + NAND_BBT_VERSION; + if (inftl_bbt_write) + this->bbt_td->options |= NAND_BBT_WRITE; + this->bbt_td->offs = 8; + this->bbt_td->len = 8; + this->bbt_td->veroffs = 7; + this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS; + this->bbt_td->reserved_block_code = 0x01; + this->bbt_td->pattern = "MSYS_BBT"; + + this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | + NAND_BBT_VERSION; + if (inftl_bbt_write) + this->bbt_md->options |= NAND_BBT_WRITE; + this->bbt_md->offs = 8; + this->bbt_md->len = 8; + this->bbt_md->veroffs = 7; + this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS; + this->bbt_md->reserved_block_code = 0x01; + this->bbt_md->pattern = "TBB_SYSM"; + } + + /* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set. + At least as nand_bbt.c is currently written. */ + if ((ret = nand_scan_bbt(mtd, NULL))) + return ret; + memset((char *) parts, 0, sizeof(parts)); + numparts = inftl_partscan(mtd, parts); + /* At least for now, require the INFTL Media Header. We could probably + do without it for non-INFTL use, since all it gives us is + autopartitioning, but I want to give it more thought. */ + if (!numparts) return -EIO; + add_mtd_device(mtd); +#ifdef CONFIG_MTD_PARTITIONS + if (!no_autopart) + add_mtd_partitions(mtd, parts, numparts); +#endif + return 0; +} + +static inline int __init doc2000_init(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + + this->write_byte = doc2000_write_byte; + this->read_byte = doc2000_read_byte; + this->write_buf = doc2000_writebuf; + this->read_buf = doc2000_readbuf; + this->verify_buf = doc2000_verifybuf; + this->scan_bbt = nftl_scan_bbt; + + doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO; + doc2000_count_chips(mtd); + mtd->name = "DiskOnChip 2000 (NFTL Model)"; + return (4 * doc->chips_per_floor); +} + +static inline int __init doc2001_init(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + + this->write_byte = doc2001_write_byte; + this->read_byte = doc2001_read_byte; + this->write_buf = doc2001_writebuf; + this->read_buf = doc2001_readbuf; + this->verify_buf = doc2001_verifybuf; + + ReadDOC(doc->virtadr, ChipID); + ReadDOC(doc->virtadr, ChipID); + ReadDOC(doc->virtadr, ChipID); + if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { + /* It's not a Millennium; it's one of the newer + DiskOnChip 2000 units with a similar ASIC. + Treat it like a Millennium, except that it + can have multiple chips. */ + doc2000_count_chips(mtd); + mtd->name = "DiskOnChip 2000 (INFTL Model)"; + this->scan_bbt = inftl_scan_bbt; + return (4 * doc->chips_per_floor); + } else { + /* Bog-standard Millennium */ + doc->chips_per_floor = 1; + mtd->name = "DiskOnChip Millennium"; + this->scan_bbt = nftl_scan_bbt; + return 1; + } +} + +static inline int __init doc2001plus_init(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + struct doc_priv *doc = this->priv; + + this->write_byte = NULL; + this->read_byte = doc2001plus_read_byte; + this->write_buf = doc2001plus_writebuf; + this->read_buf = doc2001plus_readbuf; + this->verify_buf = doc2001plus_verifybuf; + this->scan_bbt = inftl_scan_bbt; + this->hwcontrol = NULL; + this->select_chip = doc2001plus_select_chip; + this->cmdfunc = doc2001plus_command; + this->enable_hwecc = doc2001plus_enable_hwecc; + + doc->chips_per_floor = 1; + mtd->name = "DiskOnChip Millennium Plus"; + + return 1; +} + +static inline int __init doc_probe(unsigned long physadr) +{ + unsigned char ChipID; + struct mtd_info *mtd; + struct nand_chip *nand; + struct doc_priv *doc; + void __iomem *virtadr; + unsigned char save_control; + unsigned char tmp, tmpb, tmpc; + int reg, len, numchips; + int ret = 0; + + virtadr = ioremap(physadr, DOC_IOREMAP_LEN); + if (!virtadr) { + printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr); + return -EIO; + } + + /* It's not possible to cleanly detect the DiskOnChip - the + * bootup procedure will put the device into reset mode, and + * it's not possible to talk to it without actually writing + * to the DOCControl register. So we store the current contents + * of the DOCControl register's location, in case we later decide + * that it's not a DiskOnChip, and want to put it back how we + * found it. + */ + save_control = ReadDOC(virtadr, DOCControl); + + /* Reset the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + virtadr, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, + virtadr, DOCControl); + + /* Enable the DiskOnChip ASIC */ + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + virtadr, DOCControl); + WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, + virtadr, DOCControl); + + ChipID = ReadDOC(virtadr, ChipID); + + switch(ChipID) { + case DOC_ChipID_Doc2k: + reg = DoC_2k_ECCStatus; + break; + case DOC_ChipID_DocMil: + reg = DoC_ECCConf; + break; + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + case 0: + /* Possible Millennium Plus, need to do more checks */ + /* Possibly release from power down mode */ + for (tmp = 0; (tmp < 4); tmp++) + ReadDOC(virtadr, Mplus_Power); + + /* Reset the Millennium Plus ASIC */ + tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, virtadr, Mplus_DOCControl); + WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm); + + mdelay(1); + /* Enable the Millennium Plus ASIC */ + tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, virtadr, Mplus_DOCControl); + WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm); + mdelay(1); + + ChipID = ReadDOC(virtadr, ChipID); + + switch (ChipID) { + case DOC_ChipID_DocMilPlus16: + reg = DoC_Mplus_Toggle; + break; + case DOC_ChipID_DocMilPlus32: + printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); + default: + ret = -ENODEV; + goto notfound; + } + break; + + default: + ret = -ENODEV; + goto notfound; + } + /* Check the TOGGLE bit in the ECC register */ + tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; + tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; + tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; + if ((tmp == tmpb) || (tmp != tmpc)) { + printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr); + ret = -ENODEV; + goto notfound; + } + + for (mtd = doclist; mtd; mtd = doc->nextdoc) { + unsigned char oldval; + unsigned char newval; + nand = mtd->priv; + doc = nand->priv; + /* Use the alias resolution register to determine if this is + in fact the same DOC aliased to a new address. If writes + to one chip's alias resolution register change the value on + the other chip, they're the same chip. */ + if (ChipID == DOC_ChipID_DocMilPlus16) { + oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); + newval = ReadDOC(virtadr, Mplus_AliasResolution); + } else { + oldval = ReadDOC(doc->virtadr, AliasResolution); + newval = ReadDOC(virtadr, AliasResolution); + } + if (oldval != newval) + continue; + if (ChipID == DOC_ChipID_DocMilPlus16) { + WriteDOC(~newval, virtadr, Mplus_AliasResolution); + oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); + WriteDOC(newval, virtadr, Mplus_AliasResolution); /* restore it */ + } else { + WriteDOC(~newval, virtadr, AliasResolution); + oldval = ReadDOC(doc->virtadr, AliasResolution); + WriteDOC(newval, virtadr, AliasResolution); /* restore it */ + } + newval = ~newval; + if (oldval == newval) { + printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr); + goto notfound; + } + } + + printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr); + + len = sizeof(struct mtd_info) + + sizeof(struct nand_chip) + + sizeof(struct doc_priv) + + (2 * sizeof(struct nand_bbt_descr)); + mtd = kmalloc(len, GFP_KERNEL); + if (!mtd) { + printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len); + ret = -ENOMEM; + goto fail; + } + memset(mtd, 0, len); + + nand = (struct nand_chip *) (mtd + 1); + doc = (struct doc_priv *) (nand + 1); + nand->bbt_td = (struct nand_bbt_descr *) (doc + 1); + nand->bbt_md = nand->bbt_td + 1; + + mtd->priv = nand; + mtd->owner = THIS_MODULE; + + nand->priv = doc; + nand->select_chip = doc200x_select_chip; + nand->hwcontrol = doc200x_hwcontrol; + nand->dev_ready = doc200x_dev_ready; + nand->waitfunc = doc200x_wait; + nand->block_bad = doc200x_block_bad; + nand->enable_hwecc = doc200x_enable_hwecc; + nand->calculate_ecc = doc200x_calculate_ecc; + nand->correct_data = doc200x_correct_data; + + nand->autooob = &doc200x_oobinfo; + nand->eccmode = NAND_ECC_HW6_512; + nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME; + + doc->physadr = physadr; + doc->virtadr = virtadr; + doc->ChipID = ChipID; + doc->curfloor = -1; + doc->curchip = -1; + doc->mh0_page = -1; + doc->mh1_page = -1; + doc->nextdoc = doclist; + + if (ChipID == DOC_ChipID_Doc2k) + numchips = doc2000_init(mtd); + else if (ChipID == DOC_ChipID_DocMilPlus16) + numchips = doc2001plus_init(mtd); + else + numchips = doc2001_init(mtd); + + if ((ret = nand_scan(mtd, numchips))) { + /* DBB note: i believe nand_release is necessary here, as + buffers may have been allocated in nand_base. Check with + Thomas. FIX ME! */ + /* nand_release will call del_mtd_device, but we haven't yet + added it. This is handled without incident by + del_mtd_device, as far as I can tell. */ + nand_release(mtd); + kfree(mtd); + goto fail; + } + + /* Success! */ + doclist = mtd; + return 0; + +notfound: + /* Put back the contents of the DOCControl register, in case it's not + actually a DiskOnChip. */ + WriteDOC(save_control, virtadr, DOCControl); +fail: + iounmap(virtadr); + return ret; +} + +static void release_nanddoc(void) +{ + struct mtd_info *mtd, *nextmtd; + struct nand_chip *nand; + struct doc_priv *doc; + + for (mtd = doclist; mtd; mtd = nextmtd) { + nand = mtd->priv; + doc = nand->priv; + + nextmtd = doc->nextdoc; + nand_release(mtd); + iounmap(doc->virtadr); + kfree(mtd); + } +} + +static int __init init_nanddoc(void) +{ + int i, ret = 0; + + /* We could create the decoder on demand, if memory is a concern. + * This way we have it handy, if an error happens + * + * Symbolsize is 10 (bits) + * Primitve polynomial is x^10+x^3+1 + * first consecutive root is 510 + * primitve element to generate roots = 1 + * generator polinomial degree = 4 + */ + rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); + if (!rs_decoder) { + printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n"); + return -ENOMEM; + } + + if (doc_config_location) { + printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); + ret = doc_probe(doc_config_location); + if (ret < 0) + goto outerr; + } else { + for (i=0; (doc_locations[i] != 0xffffffff); i++) { + doc_probe(doc_locations[i]); + } + } + /* No banner message any more. Print a message if no DiskOnChip + found, so the user knows we at least tried. */ + if (!doclist) { + printk(KERN_INFO "No valid DiskOnChip devices found\n"); + ret = -ENODEV; + goto outerr; + } + return 0; +outerr: + free_rs(rs_decoder); + return ret; +} + +static void __exit cleanup_nanddoc(void) +{ + /* Cleanup the nand/DoC resources */ + release_nanddoc(); + + /* Free the reed solomon resources */ + if (rs_decoder) { + free_rs(rs_decoder); + } +} + +module_init(init_nanddoc); +module_exit(cleanup_nanddoc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Woodhouse "); +MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n"); +#endif diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c new file mode 100644 index 0000000..6a150fe --- /dev/null +++ b/drivers/mtd/nand/nand.c @@ -0,0 +1,249 @@ +/* + * (C) Copyright 2005 + * 2N Telekomunikace, a.s. + * Ladislav Michl + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static ssize_t nand_read(struct cdev *cdev, void* buf, size_t count, ulong offset, ulong flags) +{ + struct mtd_info *info = cdev->priv; + size_t retlen; + int ret; + + debug("nand_read: 0x%08x 0x%08x\n", offset, count); + + ret = info->read(info, offset, count, &retlen, buf); + + if(ret) { + printf("err %d\n", ret); + return ret; + } + return retlen; +} + +#define NOTALIGNED(x) (x & (info->writesize - 1)) != 0 + +static int all_ff(const void *buf, int len) +{ + int i; + const uint8_t *p = buf; + + for (i = 0; i < len; i++) + if (p[i] != 0xFF) + return 0; + return 1; +} + +static ssize_t nand_write(struct cdev* cdev, const void *buf, size_t _count, ulong offset, ulong flags) +{ + struct mtd_info *info = cdev->priv; + size_t retlen, now; + int ret = 0; + void *wrbuf = NULL; + size_t count = _count; + + if (NOTALIGNED(offset)) { + printf("offset 0x%08x not page aligned\n", offset); + return -EINVAL; + } + + debug("write: 0x%08x 0x%08x\n", offset, count); + + while (count) { + now = count > info->writesize ? info->writesize : count; + + if (NOTALIGNED(now)) { + debug("not aligned: %d %d\n", info->writesize, (offset % info->writesize)); + wrbuf = xmalloc(info->writesize); + memset(wrbuf, 0xff, info->writesize); + memcpy(wrbuf + (offset % info->writesize), buf, now); + if (!all_ff(wrbuf, info->writesize)) + ret = info->write(info, offset & ~(info->writesize - 1), + info->writesize, &retlen, wrbuf); + free(wrbuf); + } else { + if (!all_ff(buf, info->writesize)) + ret = info->write(info, offset, now, &retlen, buf); + debug("offset: 0x%08x now: 0x%08x retlen: 0x%08x\n", offset, now, retlen); + } + if (ret) + goto out; + + offset += now; + count -= now; + buf += now; + } + +out: + return ret ? ret : _count; +} + +static int nand_ioctl(struct cdev *cdev, int request, void *buf) +{ + struct mtd_info *info = cdev->priv; + struct mtd_info_user *user = buf; + + switch (request) { + case MEMGETBADBLOCK: + debug("MEMGETBADBLOCK: 0x%08x\n", (off_t)buf); + return info->block_isbad(info, (off_t)buf); + case MEMSETBADBLOCK: + debug("MEMSETBADBLOCK: 0x%08x\n", (off_t)buf); + return info->block_markbad(info, (off_t)buf); + case MEMGETINFO: + user->type = info->type; + user->flags = info->flags; + user->size = info->size; + user->erasesize = info->erasesize; + user->oobsize = info->oobsize; + user->mtd = info; + /* The below fields are obsolete */ + user->ecctype = -1; + user->eccsize = 0; + return 0; + } + + return 0; +} + +static ssize_t nand_erase(struct cdev *cdev, size_t count, unsigned long offset) +{ + struct mtd_info *info = cdev->priv; + struct erase_info erase; + int ret; + + memset(&erase, 0, sizeof(erase)); + erase.mtd = info; + erase.addr = offset; + erase.len = info->erasesize; + + while (count > 0) { + debug("erase %d %d\n", erase.addr, erase.len); + + ret = info->block_isbad(info, erase.addr); + if (ret > 0) { + printf("Skipping bad block at 0x%08x\n", erase.addr); + } else { + ret = info->erase(info, &erase); + if (ret) + return ret; + } + + erase.addr += info->erasesize; + count -= count > info->erasesize ? info->erasesize : count; + } + + return 0; +} +#if 0 +static char* mtd_get_size(struct device_d *, struct param_d *param) +{ + static char +} +#endif + +static struct file_operations nand_ops = { + .read = nand_read, + .write = nand_write, + .ioctl = nand_ioctl, + .lseek = dev_lseek_default, + .erase = nand_erase, +}; + +static ssize_t nand_read_oob(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags) +{ + struct mtd_info *info = cdev->priv; + struct nand_chip *chip = info->priv; + struct mtd_oob_ops ops; + int ret; + + if (count < info->oobsize) + return -EINVAL; + + ops.mode = MTD_OOB_RAW; + ops.ooboffs = 0; + ops.ooblen = info->oobsize; + ops.oobbuf = buf; + ops.datbuf = NULL; + ops.len = info->oobsize; + + offset /= info->oobsize; + ret = info->read_oob(info, offset << chip->page_shift, &ops); + if (ret) + return ret; + + return info->oobsize; +} + +static struct file_operations nand_ops_oob = { + .read = nand_read_oob, + .ioctl = nand_ioctl, + .lseek = dev_lseek_default, +}; + +int add_mtd_device(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + char str[16]; + + strcpy(mtd->class_dev.name, "nand"); + register_device(&mtd->class_dev); + + mtd->cdev.ops = &nand_ops; + mtd->cdev.size = mtd->size; + mtd->cdev.name = asprintf("nand%d", mtd->class_dev.id); + mtd->cdev.priv = mtd; + mtd->cdev.dev = &mtd->class_dev; + mtd->cdev.mtd = mtd; + + sprintf(str, "%u", mtd->size); + dev_add_param_fixed(&mtd->class_dev, "size", str); + + 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); + + return 0; +} + +int del_mtd_device (struct mtd_info *mtd) +{ + unregister_device(&mtd->class_dev); + free(mtd->cdev_oob.name); + free(mtd->param_size.value); + free(mtd->cdev.name); + return 0; +} + diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c new file mode 100644 index 0000000..b75a450 --- /dev/null +++ b/drivers/mtd/nand/nand_base.c @@ -0,0 +1,2648 @@ +/* + * drivers/mtd/nand.c + * + * Overview: + * This is the generic MTD driver for NAND flash devices. It should be + * capable of working with almost all NAND chips currently available. + * Basic support for AG-AND chips is provided. + * + * Additional technical information is available on + * http://www.linux-mtd.infradead.org/doc/nand.html + * + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002-2006 Thomas Gleixner (tglx@linutronix.de) + * + * Credits: + * David Woodhouse for adding multichip support + * + * Aleph One Ltd. and Toby Churchill Ltd. for supporting the + * rework for 2K page size chips + * + * TODO: + * Enable cached programming for 2k page size chips + * Check, if mtd->ecctype should be set to MTD_ECC_HW + * if we have HW ecc support. + * The AG-AND chips have nice features for speed improvement, + * which are not supported yet. Read / program 4 pages in one go. + * BBT table is not serialized, has to be fixed + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +/* Define default oob placement schemes for large and small page devices */ +static struct nand_ecclayout nand_oob_8 = { + .eccbytes = 3, + .eccpos = {0, 1, 2}, + .oobfree = { + {.offset = 3, + .length = 2}, + {.offset = 6, + .length = 2}} +}; + +static struct nand_ecclayout nand_oob_16 = { + .eccbytes = 6, + .eccpos = {0, 1, 2, 3, 6, 7}, + .oobfree = { + {.offset = 8, + . length = 8}} +}; + +static struct nand_ecclayout nand_oob_64 = { + .eccbytes = 24, + .eccpos = { + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63}, + .oobfree = { + {.offset = 2, + .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) +#define led_trigger_unregister_simple(x) do {} while(0) +#define led_trigger_event(x, y) do {} while(0) + +/* + * For devices which display every fart in the system on a separate LED. Is + * compiled away when LED support is disabled. + */ +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 + * + * Default read function for 8bit buswith + */ +static uint8_t nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + return readb(chip->IO_ADDR_R); +} + +/** + * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip + * @mtd: MTD device structure + * + * Default read function for 16bit buswith with + * endianess conversion + */ +static uint8_t nand_read_byte16(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); +} + +/** + * nand_read_word - [DEFAULT] read one word from the chip + * @mtd: MTD device structure + * + * Default read function for 16bit buswith without + * endianess conversion + */ +static u16 nand_read_word(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + return readw(chip->IO_ADDR_R); +} + +/** + * nand_select_chip - [DEFAULT] control CE line + * @mtd: MTD device structure + * @chipnr: chipnumber to select, -1 for deselect + * + * Default select function for 1 chip devices. + */ +static void nand_select_chip(struct mtd_info *mtd, int chipnr) +{ + struct nand_chip *chip = mtd->priv; + + switch (chipnr) { + case -1: + chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); + break; + case 0: + break; + default: + printf("%s: illegal chip number %d\n", 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 + * @len: number of bytes to read + * + * Default read function for 8bit buswith + */ +static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + int i; + struct nand_chip *chip = mtd->priv; + + for (i = 0; i < len; i++) + buf[i] = readb(chip->IO_ADDR_R); +} + +/** + * nand_verify_buf - [DEFAULT] Verify chip data against buffer + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare + * + * Default verify function for 8bit buswith + */ +static int nand_verify_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++) + if (buf[i] != readb(chip->IO_ADDR_R)) + return -EFAULT; + return 0; +} + +/** + * 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 + * @len: number of bytes to read + * + * Default read function for 16bit buswith + */ +static void nand_read_buf16(struct mtd_info *mtd, 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++) + p[i] = readw(chip->IO_ADDR_R); +} + +/** + * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare + * + * Default verify function for 16bit buswith + */ +static int nand_verify_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++) + if (p[i] != readw(chip->IO_ADDR_R)) + return -EFAULT; + + return 0; +} + +/** + * nand_block_bad - [DEFAULT] Read bad block marker from the chip + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected + * + * Check, if the block is bad. + */ +static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) +{ + int page, chipnr, res = 0; + struct nand_chip *chip = mtd->priv; + u16 bad; + + page = (int)(ofs >> chip->page_shift) & chip->pagemask; + + if (getchip) { + chipnr = (int)(ofs >> chip->chip_shift); + + nand_get_device(chip, mtd, FL_READING); + + /* Select the NAND device */ + chip->select_chip(mtd, chipnr); + } + + if (chip->options & NAND_BUSWIDTH_16) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, + page); + bad = cpu_to_le16(chip->read_word(mtd)); + if (chip->badblockpos & 0x1) + bad >>= 8; + if ((bad & 0xFF) != 0xff) + res = 1; + } else { + chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); + if (chip->read_byte(mtd) != 0xff) + 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 + * @getchip: 0, if the chip is already selected + * @allowbbt: 1, if its allowed to access the bbt area + * + * 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 allowbbt) +{ + struct nand_chip *chip = mtd->priv; + + if (!chip->bbt) + return chip->block_bad(mtd, ofs, getchip); + + /* Return info from the table */ + return nand_isbad_bbt(mtd, ofs, allowbbt); +} + +/* + * Wait for the ready pin, after a command + * The timeout is catched later. + */ +void nand_wait_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + uint64_t start = get_time_ns(); + + led_trigger_event(nand_led_trigger, LED_FULL); + /* wait until command is processed or timeout occures */ + do { + if (chip->dev_ready(mtd)) + break; + } while (!is_timeout(start, SECOND * 2)); + led_trigger_event(nand_led_trigger, LED_OFF); +} +EXPORT_SYMBOL(nand_wait_ready); + +/** + * nand_command - [DEFAULT] Send command to NAND device + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This function is used for small page + * devices (256/512 Bytes per page) + */ +static void nand_command(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + register struct nand_chip *chip = mtd->priv; + int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; + + /* + * Write out the command to the device. + */ + if (command == NAND_CMD_SEQIN) { + int readcmd; + + if (column >= mtd->writesize) { + /* OOB area */ + column -= mtd->writesize; + readcmd = NAND_CMD_READOOB; + } else if (column < 256) { + /* First 256 bytes --> READ0 */ + readcmd = NAND_CMD_READ0; + } else { + column -= 256; + readcmd = NAND_CMD_READ1; + } + chip->cmd_ctrl(mtd, readcmd, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + chip->cmd_ctrl(mtd, command, ctrl); + + /* + * Address cycle, when necessary + */ + ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16) + column >>= 1; + chip->cmd_ctrl(mtd, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + } + if (page_addr != -1) { + chip->cmd_ctrl(mtd, page_addr, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); + /* One more address cycle for devices > 32MiB */ + if (chip->chipsize > (32 << 20)) + chip->cmd_ctrl(mtd, page_addr >> 16, ctrl); + } + chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * program and erase have their own busy handlers + * status and sequential in needs no delay + */ + switch (command) { + + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + return; + + case NAND_CMD_RESET: + if (chip->dev_ready) + break; + udelay(chip->chip_delay); + chip->cmd_ctrl(mtd, NAND_CMD_STATUS, + NAND_CTRL_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, + NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; + return; + + /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!chip->dev_ready) { + udelay(chip->chip_delay); + return; + } + } + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay(100); + + nand_wait_ready(mtd); +} + +/** + * nand_command_lp - [DEFAULT] Send command to NAND large page device + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none + * + * Send command to NAND device. This is the version for the new large page + * devices We dont have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + */ +static void nand_command_lp(struct mtd_info *mtd, unsigned int command, + int column, int page_addr) +{ + register struct nand_chip *chip = mtd->priv; + + /* Emulate NAND_CMD_READOOB */ + if (command == NAND_CMD_READOOB) { + column += mtd->writesize; + command = NAND_CMD_READ0; + } + + /* Command latch cycle */ + chip->cmd_ctrl(mtd, command & 0xff, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + + if (column != -1 || page_addr != -1) { + int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; + + /* Serially input address */ + if (column != -1) { + /* Adjust columns for 16 bit buswidth */ + if (chip->options & NAND_BUSWIDTH_16) + column >>= 1; + chip->cmd_ctrl(mtd, column, ctrl); + ctrl &= ~NAND_CTRL_CHANGE; + chip->cmd_ctrl(mtd, column >> 8, ctrl); + } + if (page_addr != -1) { + chip->cmd_ctrl(mtd, page_addr, ctrl); + chip->cmd_ctrl(mtd, page_addr >> 8, + NAND_NCE | NAND_ALE); + /* One more address cycle for devices > 128MiB */ + if (chip->chipsize > (128 << 20)) + chip->cmd_ctrl(mtd, page_addr >> 16, + NAND_NCE | NAND_ALE); + } + } + chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + /* + * program and erase have their own busy handlers + * status, sequential in, and deplete1 need no delay + */ + switch (command) { + + case NAND_CMD_CACHEDPROG: + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_RNDIN: + case NAND_CMD_STATUS: + case NAND_CMD_DEPLETE1: + return; + + /* + * read error status commands require only a short delay + */ + case NAND_CMD_STATUS_ERROR: + case NAND_CMD_STATUS_ERROR0: + case NAND_CMD_STATUS_ERROR1: + case NAND_CMD_STATUS_ERROR2: + case NAND_CMD_STATUS_ERROR3: + udelay(chip->chip_delay); + return; + + case NAND_CMD_RESET: + if (chip->dev_ready) + break; + udelay(chip->chip_delay); + chip->cmd_ctrl(mtd, NAND_CMD_STATUS, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; + return; + + case NAND_CMD_RNDOUT: + /* No ready / busy check necessary */ + chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + return; + + case NAND_CMD_READ0: + chip->cmd_ctrl(mtd, NAND_CMD_READSTART, + NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); + chip->cmd_ctrl(mtd, NAND_CMD_NONE, + NAND_NCE | NAND_CTRL_CHANGE); + + /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!chip->dev_ready) { + udelay(chip->chip_delay); + return; + } + } + + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay(100); + + nand_wait_ready(mtd); +} + +/** + * 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 + * + * Wait for command done. This applies to erase and program only + * Erase can take up to 400ms and program up to 20ms according to + * general NAND and SmartMedia specs + */ +static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) +{ + + uint64_t start = get_time_ns(); + uint64_t timeo; + int status, state = chip->state; + + if (state == FL_ERASING) + timeo = 400 * MSECOND; + else + timeo = 20 * MSECOND; + + led_trigger_event(nand_led_trigger, LED_FULL); + + /* Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. */ + ndelay(100); + + if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) + chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); + else + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); + + while (!is_timeout(start, timeo)) { + if (chip->dev_ready) { + if (chip->dev_ready(mtd)) + break; + } else { + if (chip->read_byte(mtd) & NAND_STATUS_READY) + break; + } + } + led_trigger_event(nand_led_trigger, LED_OFF); + + status = (int)chip->read_byte(mtd); + return status; +} + +/** + * nand_read_page_raw - [Intern] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + */ +static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf) +{ + chip->read_buf(mtd, buf, mtd->writesize); + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return 0; +} + +/** + * 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 + */ +static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, + struct mtd_oob_ops *ops, size_t len) +{ + switch(ops->mode) { + + case MTD_OOB_PLACE: + case MTD_OOB_RAW: + memcpy(oob, chip->oob_poi + ops->ooboffs, len); + return oob + len; + + case MTD_OOB_AUTO: { + struct nand_oobfree *free = chip->ecc.layout->oobfree; + uint32_t boffs = 0, roffs = ops->ooboffs; + size_t bytes = 0; + + for(; free->length && len; free++, len -= bytes) { + /* Read request not from offset 0 ? */ + if (unlikely(roffs)) { + if (roffs >= free->length) { + roffs -= free->length; + continue; + } + boffs = free->offset + roffs; + bytes = min_t(size_t, len, + (free->length - roffs)); + roffs = 0; + } else { + bytes = min_t(size_t, len, free->length); + boffs = free->offset; + } + memcpy(oob, chip->oob_poi + boffs, bytes); + oob += bytes; + } + return oob; + } + default: + BUG(); + } + return NULL; +} + +/** + * nand_do_read_ops - [Internal] Read data with ECC + * + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure + * + * Internal function. Called with chip held. + */ +static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + int chipnr, page, realpage, col, bytes, aligned; + struct nand_chip *chip = mtd->priv; + struct mtd_ecc_stats stats; + int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + int sndcmd = 1; + int ret = 0; + uint32_t readlen = ops->len; + uint32_t oobreadlen = ops->ooblen; + uint8_t *bufpoi, *oob, *buf; + + stats = mtd->ecc_stats; + + chipnr = (int)(from >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + realpage = (int)(from >> chip->page_shift); + page = realpage & chip->pagemask; + + col = (int)(from & (mtd->writesize - 1)); + + buf = ops->datbuf; + oob = ops->oobbuf; + + while(1) { + bytes = min(mtd->writesize - col, readlen); + aligned = (bytes == mtd->writesize); + + /* Is the current page in the buffer ? */ + if (realpage != chip->pagebuf || oob) { + bufpoi = aligned ? buf : chip->buffers->databuf; + + if (likely(sndcmd)) { + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + sndcmd = 0; + } + + /* Now read the page into the buffer */ + if (unlikely(ops->mode == MTD_OOB_RAW)) + ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); + else + ret = chip->ecc.read_page(mtd, chip, bufpoi); + if (ret < 0) + break; + + /* Transfer not aligned data */ + if (!aligned) { + chip->pagebuf = realpage; + memcpy(buf, chip->buffers->databuf + col, bytes); + } + + buf += bytes; + + if (unlikely(oob)) { + /* Raw mode does data:oob:data:oob */ + if (ops->mode != MTD_OOB_RAW) { + int toread = min(oobreadlen, + chip->ecc.layout->oobavail); + if (toread) { + oob = nand_transfer_oob(chip, + oob, ops, toread); + oobreadlen -= toread; + } + } else + buf = nand_transfer_oob(chip, + buf, ops, mtd->oobsize); + } + + if (!(chip->options & NAND_NO_READRDY)) { + /* + * Apply delay or wait for ready/busy pin. Do + * this before the AUTOINCR check, so no + * problems arise if a chip which does auto + * increment is marked as NOAUTOINCR by the + * board driver. + */ + if (!chip->dev_ready) + udelay(chip->chip_delay); + else + nand_wait_ready(mtd); + } + } else { + memcpy(buf, chip->buffers->databuf + col, bytes); + buf += bytes; + } + + readlen -= bytes; + + if (!readlen) + break; + + /* For subsequent reads align to page boundary. */ + col = 0; + /* Increment page address */ + 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); + } + + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ + if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) + sndcmd = 1; + } + + ops->retlen = ops->len - (size_t) readlen; + if (oob) + ops->oobretlen = ops->ooblen - oobreadlen; + + if (ret) + return ret; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return 0; +} + +/** + * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data + * + * Get hold of the chip and call nand_do_read + */ +static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, uint8_t *buf) +{ + struct nand_chip *chip = mtd->priv; + int ret; + + /* Do not allow reads past end of device */ + if ((from + len) > mtd->size) + return -EINVAL; + if (!len) + return 0; + + nand_get_device(chip, mtd, FL_READING); + + chip->ops.len = len; + chip->ops.datbuf = buf; + chip->ops.oobbuf = NULL; + + ret = nand_do_read_ops(mtd, from, &chip->ops); + + *retlen = chip->ops.retlen; + + nand_release_device(mtd); + + return ret; +} + +/** + * nand_read_oob_std - [REPLACABLE] the most common OOB data read function + * @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_std(struct mtd_info *mtd, struct nand_chip *chip, + int page, int sndcmd) +{ + if (sndcmd) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); + sndcmd = 0; + } + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + return sndcmd; +} + +/** + * 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 + * @ops: oob operations description structure + * + * NAND read out-of-band data from the spare area + */ +static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + int page, realpage, chipnr, sndcmd = 1; + struct nand_chip *chip = mtd->priv; + int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + int readlen = ops->ooblen; + int len; + uint8_t *buf = ops->oobbuf; + + MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", + (unsigned long long)from, readlen); + + if (ops->mode == MTD_OOB_AUTO) + len = chip->ecc.layout->oobavail; + else + len = mtd->oobsize; + + if (unlikely(ops->ooboffs >= len)) { + MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " + "Attempt to start read outside oob\n"); + return -EINVAL; + } + + /* Do not allow reads past end of device */ + if (unlikely(from >= mtd->size || + ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - + (from >> chip->page_shift)) * len)) { + MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " + "Attempt read beyond end of device\n"); + return -EINVAL; + } + + chipnr = (int)(from >> chip->chip_shift); + chip->select_chip(mtd, chipnr); + + /* Shift to get page */ + realpage = (int)(from >> chip->page_shift); + page = realpage & chip->pagemask; + + while(1) { + sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); + + len = min(len, readlen); + buf = nand_transfer_oob(chip, buf, ops, len); + + if (!(chip->options & NAND_NO_READRDY)) { + /* + * Apply delay or wait for ready/busy pin. Do this + * before the AUTOINCR check, so no problems arise if a + * chip which does auto increment is marked as + * NOAUTOINCR by the board driver. + */ + if (!chip->dev_ready) + udelay(chip->chip_delay); + else + nand_wait_ready(mtd); + } + + readlen -= len; + if (!readlen) + break; + + /* Increment page address */ + 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); + } + + /* Check, if the chip supports auto page increment + * or if we have hit a block boundary. + */ + if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) + sndcmd = 1; + } + + ops->oobretlen = ops->ooblen; + return 0; +} + +/** + * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure + * + * NAND read data and/or out-of-band data + */ +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; + + /* Do not allow reads past end of device */ + if (ops->datbuf && (from + 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_READING); + + 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_read_oob(mtd, from, ops); + else + 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) +{ + /* Check for invalid offset */ + if (offs > mtd->size) + return -EINVAL; + + 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 + */ +static void nand_set_defaults(struct nand_chip *chip, int busw) +{ + /* check for proper chip_delay setup, set 20us if not */ + if (!chip->chip_delay) + chip->chip_delay = 20; + + /* check, if a user supplied command function given */ + if (chip->cmdfunc == NULL) + chip->cmdfunc = nand_command; + + /* check, if a user supplied wait function given */ + if (chip->waitfunc == NULL) + chip->waitfunc = nand_wait; + + if (!chip->select_chip) + chip->select_chip = nand_select_chip; + if (!chip->read_byte) + chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; + if (!chip->read_word) + chip->read_word = nand_read_word; + if (!chip->block_bad) + chip->block_bad = nand_block_bad; + 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; + 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; + if (!chip->scan_bbt) + chip->scan_bbt = nand_default_bbt; + + if (!chip->controller) { + chip->controller = &chip->hwcontrol; + } + +} + +/* + * Get the flash and manufacturer id and lookup if the type is supported + */ +static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, + struct nand_chip *chip, + int busw, int *maf_id) +{ + struct nand_flash_dev *type = NULL; + int i, dev_id, maf_idx; + int tmp_id, tmp_manf; + + /* Select the device */ + chip->select_chip(mtd, 0); + + /* Send the command for reading device ID */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + *maf_id = chip->read_byte(mtd); + dev_id = chip->read_byte(mtd); + + /* Try again to make sure, as some systems the bus-hold or other + * interface concerns can cause random data which looks like a + * possibly credible NAND flash to appear. If the two results do + * not match, ignore the device completely. + */ + + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + + /* Read manufacturer and device IDs */ + + tmp_manf = chip->read_byte(mtd); + tmp_id = chip->read_byte(mtd); + + if (tmp_manf != *maf_id || tmp_id != dev_id) { + printk(KERN_INFO "%s: second ID read did not match " + "%02x,%02x against %02x,%02x\n", __func__, + *maf_id, dev_id, tmp_manf, tmp_id); + return ERR_PTR(-ENODEV); + } + + /* Lookup the flash id */ + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (dev_id == nand_flash_ids[i].id) { + type = &nand_flash_ids[i]; + break; + } + } + + if (!type) + return ERR_PTR(-ENODEV); + + if (!mtd->name) + mtd->name = type->name; + + chip->chipsize = type->chipsize << 20; + + /* Newer devices have all the information in additional id bytes */ + if (!type->pagesize) { + int extid; + /* The 3rd id byte holds MLC / multichip data */ + chip->cellinfo = chip->read_byte(mtd); + /* The 4th id byte is the important one */ + extid = chip->read_byte(mtd); + /* Calc pagesize */ + mtd->writesize = 1024 << (extid & 0x3); + extid >>= 2; + /* Calc oobsize */ + mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); + extid >>= 2; + /* Calc blocksize. Blocksize is multiples of 64KiB */ + mtd->erasesize = (64 * 1024) << (extid & 0x03); + extid >>= 2; + /* Get buswidth information */ + busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; + + } else { + /* + * Old devices have chip data hardcoded in the device id table + */ + mtd->erasesize = type->erasesize; + mtd->writesize = type->pagesize; + mtd->oobsize = mtd->writesize / 32; + busw = type->options & NAND_BUSWIDTH_16; + } + + /* Try to identify manufacturer */ + for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { + if (nand_manuf_ids[maf_idx].id == *maf_id) + break; + } + + /* + * Check, if buswidth is correct. Hardware drivers should set + * chip correct ! + */ + if (busw != (chip->options & NAND_BUSWIDTH_16)) { + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, + dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + printk(KERN_WARNING "NAND bus width %d instead %d bit\n", + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, + busw ? 16 : 8); + return ERR_PTR(-EINVAL); + } + + /* Calculate the address shift from the page size */ + chip->page_shift = ffs(mtd->writesize) - 1; + /* Convert chipsize to number of pages per chip -1. */ + chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; + + chip->bbt_erase_shift = chip->phys_erase_shift = + ffs(mtd->erasesize) - 1; + chip->chip_shift = ffs(chip->chipsize) - 1; + + /* Set the bad block position */ + chip->badblockpos = mtd->writesize > 512 ? + NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; + + /* Get chip options, preserve non chip based options */ + chip->options &= ~NAND_CHIPOPTIONS_MSK; + chip->options |= type->options & NAND_CHIPOPTIONS_MSK; + + /* + * Set chip as a default. Board drivers can override it, if necessary + */ + chip->options |= NAND_NO_AUTOINCR; + + /* Check if chip is a not a samsung device. Do not clear the + * options for chips which are not having an extended id. + */ + if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) + chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; + + /* 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; + + /* Do not replace user supplied command function ! */ + if (mtd->writesize > 512 && chip->cmdfunc == nand_command) + chip->cmdfunc = nand_command_lp; + + printk(KERN_INFO "NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, + nand_manuf_ids[maf_idx].name, type->name); + + return type; +} + +/** + * nand_scan_ident - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This is the first phase of the normal nand_scan() function. It + * reads the flash ID and sets up MTD fields accordingly. + * + * The mtd->owner field must be set to the module of the caller. + */ +int nand_scan_ident(struct mtd_info *mtd, int maxchips) +{ + int i, busw, nand_maf_id; + struct nand_chip *chip = mtd->priv; + struct nand_flash_dev *type; + + /* Get buswidth to select the correct functions */ + busw = chip->options & NAND_BUSWIDTH_16; + /* Set the default functions */ + nand_set_defaults(chip, busw); + + /* Read the flash type */ + type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); + + if (IS_ERR(type)) { + printk(KERN_WARNING "No NAND device found!!!\n"); + chip->select_chip(mtd, -1); + return PTR_ERR(type); + } + + /* Check for a chip array */ + for (i = 1; i < maxchips; i++) { + chip->select_chip(mtd, i); + /* Send the command for reading device ID */ + chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); + /* Read manufacturer and device IDs */ + if (nand_maf_id != chip->read_byte(mtd) || + type->id != chip->read_byte(mtd)) + break; + } + if (i > 1) + printk(KERN_INFO "%d NAND chips detected\n", i); + + /* Store the number of chips and calc total size for mtd */ + chip->numchips = i; + mtd->size = i * chip->chipsize; + + return 0; +} + + +/** + * nand_scan_tail - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This is the second phase of the normal nand_scan() function. It + * fills out all the uninitialized function pointers with the defaults + * and scans for a bad block table if appropriate. + */ +int nand_scan_tail(struct mtd_info *mtd) +{ + int i; + struct nand_chip *chip = mtd->priv; + + if (!(chip->options & NAND_OWN_BUFFERS)) + chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); + if (!chip->buffers) + return -ENOMEM; + + /* Set the internal oob buffer location, just after the page data */ + chip->oob_poi = chip->buffers->databuf + mtd->writesize; + + /* + * If no default placement scheme is given, select an appropriate one + */ + if (!chip->ecc.layout) { + switch (mtd->oobsize) { + case 8: + chip->ecc.layout = &nand_oob_8; + break; + case 16: + chip->ecc.layout = &nand_oob_16; + break; + case 64: + chip->ecc.layout = &nand_oob_64; + break; + default: + printk(KERN_WARNING "No oob scheme defined for " + "oobsize %d\n", mtd->oobsize); + BUG(); + } + } + + if (!chip->write_page) + chip->write_page = nand_write_page; + + /* + * check ECC mode, default to software if 3byte/512byte hardware ECC is + * selected and we have 256 byte pagesize fallback to software ECC + */ + if (!chip->ecc.read_page_raw) + chip->ecc.read_page_raw = nand_read_page_raw; + if (!chip->ecc.write_page_raw) + chip->ecc.write_page_raw = nand_write_page_raw; + + switch (chip->ecc.mode) { + 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; + + 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; + + 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; + break; + + 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; + chip->ecc.write_page = nand_write_page_raw; + chip->ecc.read_oob = nand_read_oob_std; + chip->ecc.write_oob = nand_write_oob_std; + chip->ecc.size = mtd->writesize; + chip->ecc.bytes = 0; + break; + + default: + printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", + chip->ecc.mode); + BUG(); + } + + /* + * The number of bytes available for a client to place data into + * the out of band area + */ + chip->ecc.layout->oobavail = 0; + for (i = 0; chip->ecc.layout->oobfree[i].length; i++) + chip->ecc.layout->oobavail += + chip->ecc.layout->oobfree[i].length; + mtd->oobavail = chip->ecc.layout->oobavail; + + /* + * Set the number of read / write steps for one page depending on ECC + * mode + */ + chip->ecc.steps = mtd->writesize / chip->ecc.size; + if(chip->ecc.steps * chip->ecc.size != mtd->writesize) { + printk(KERN_WARNING "Invalid ecc parameters\n"); + BUG(); + } + chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; + + /* + * Allow subpage writes up to ecc.steps. Not possible for MLC + * FLASH. + */ + if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && + !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { + switch(chip->ecc.steps) { + case 2: + mtd->subpage_sft = 1; + break; + case 4: + case 8: + mtd->subpage_sft = 2; + break; + } + } + chip->subpagesize = mtd->writesize >> mtd->subpage_sft; + + /* Initialize state */ + chip->state = FL_READY; + + /* De-select the device */ + chip->select_chip(mtd, -1); + + /* Invalidate the pagebuffer reference */ + chip->pagebuf = -1; + + /* Fill in remaining MTD driver data */ + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + 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; + mtd->lock = NULL; + mtd->unlock = NULL; + mtd->suspend = nand_suspend; + mtd->resume = nand_resume; + mtd->block_isbad = nand_block_isbad; + mtd->block_markbad = nand_block_markbad; + + /* 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; + + /* Build bad block table */ + return chip->scan_bbt(mtd); +} + +/** + * nand_scan - [NAND Interface] Scan for the NAND device + * @mtd: MTD device structure + * @maxchips: Number of chips to scan for + * + * This fills out all the uninitialized function pointers + * with the defaults. + * The flash ID is read and the mtd/chip structures are + * filled with the appropriate values. + * The mtd->owner field must be set to the module of the caller + * + */ +int nand_scan(struct mtd_info *mtd, int maxchips) +{ + int ret; + + ret = nand_scan_ident(mtd, maxchips); + if (!ret) + ret = nand_scan_tail(mtd); + return ret; +} + +/** + * nand_release - [NAND Interface] Free resources held by the NAND device + * @mtd: MTD device structure +*/ +void nand_release(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd->priv; + + /* Deregister the device */ + del_mtd_device(mtd); + + /* Free bad block table memory */ + kfree(chip->bbt); + if (!(chip->options & NAND_OWN_BUFFERS)) + kfree(chip->buffers); +} + +EXPORT_SYMBOL(nand_scan); +EXPORT_SYMBOL(nand_scan_ident); +EXPORT_SYMBOL(nand_scan_tail); +EXPORT_SYMBOL(nand_release); + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c new file mode 100644 index 0000000..4a6bf39 --- /dev/null +++ b/drivers/mtd/nand/nand_bbt.c @@ -0,0 +1,1224 @@ +/* + * drivers/mtd/nand_bbt.c + * + * Overview: + * Bad block table support for the NAND driver + * + * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) + * + * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Description: + * + * When nand_scan_bbt is called, then it tries to find the bad block table + * depending on the options in the bbt descriptor(s). If a bbt is found + * then the contents are read and the memory based bbt is created. If a + * mirrored bbt is selected then the mirror is searched too and the + * versions are compared. If the mirror has a greater version number + * than the mirror bbt is used to build the memory based bbt. + * If the tables are not versioned, then we "or" the bad block information. + * If one of the bbt's is out of date or does not exist it is (re)created. + * If no bbt exists at all then the device is scanned for factory marked + * good / bad blocks and the bad block tables are created. + * + * For manufacturer created bbts like the one found on M-SYS DOC devices + * the bbt is searched and read but never created + * + * The autogenerated bad block table is located in the last good blocks + * of the device. The table is mirrored, so it can be updated eventually. + * The table is marked in the oob area with an ident pattern and a version + * number which indicates which of both tables is more up to date. + * + * The table uses 2 bits per block + * 11b: block is good + * 00b: block is factory marked bad + * 01b, 10b: block is marked bad due to wear + * + * The memory bad block table uses the following scheme: + * 00b: block is good + * 01b: block is marked bad due to wear + * 10b: block is reserved (to protect the bbt area) + * 11b: block is factory marked bad + * + * Multichip devices like DOC store the bad block info per floor. + * + * Following assumptions are made: + * - bbts start at a page boundary, if autolocated on a block boundary + * - the space necessary for a bbt in FLASH does not exceed a block boundary + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +/** + * check_pattern - [GENERIC] check if a pattern is in the buffer + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block + * tables and good / bad block identifiers. + * If the SCAN_EMPTY option is set then check, if all bytes except the + * pattern area contain 0xff + * +*/ +static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) +{ + int i, end = 0; + uint8_t *p = buf; + + end = paglen + td->offs; + if (td->options & NAND_BBT_SCANEMPTY) { + for (i = 0; i < end; i++) { + if (p[i] != 0xff) + return -1; + } + } + p += end; + + /* Compare the pattern */ + for (i = 0; i < td->len; i++) { + if (p[i] != td->pattern[i]) + return -1; + } + + if (td->options & NAND_BBT_SCANEMPTY) { + p += td->len; + end += td->len; + for (i = end; i < len; i++) { + if (*p++ != 0xff) + return -1; + } + } + return 0; +} + +/** + * check_short_pattern - [GENERIC] check if a pattern is in the buffer + * @buf: the buffer to search + * @td: search pattern descriptor + * + * Check for a pattern at the given place. Used to search bad block + * tables and good / bad block identifiers. Same as check_pattern, but + * no optional empty check + * +*/ +static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) +{ + int i; + uint8_t *p = buf; + + /* Compare the pattern */ + for (i = 0; i < td->len; i++) { + if (p[td->offs + i] != td->pattern[i]) + return -1; + } + return 0; +} + +/** + * read_bbt - [GENERIC] Read the bad block table starting from page + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @bits: number of bits per block + * @offs: offset in the memory table + * @reserved_block_code: Pattern to identify reserved blocks + * + * Read the bad block table starting from page. + * + */ +static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, + int bits, int offs, int reserved_block_code) +{ + int res, i, j, act = 0; + struct nand_chip *this = mtd->priv; + size_t retlen, len, totlen; + loff_t from; + uint8_t msk = (uint8_t) ((1 << bits) - 1); + + totlen = (num * bits) >> 3; + from = ((loff_t) page) << this->page_shift; + + while (totlen) { + len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + res = mtd->read(mtd, from, len, &retlen, buf); + if (res < 0) { + if (retlen != len) { + printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); + return res; + } + printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); + } + + /* Analyse data */ + for (i = 0; i < len; i++) { + uint8_t dat = buf[i]; + for (j = 0; j < 8; j += bits, act += 2) { + uint8_t tmp = (dat >> j) & msk; + if (tmp == msk) + continue; + if (reserved_block_code && (tmp == reserved_block_code)) { + printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", + ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); + mtd->ecc_stats.bbtblocks++; + continue; + } + /* Leave it for now, if its matured we can move this + * message to MTD_DEBUG_LEVEL0 */ + printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", + ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + /* Factory marked bad or worn out ? */ + if (tmp == 0) + this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); + else + this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); + mtd->ecc_stats.badblocks++; + } + } + totlen -= len; + from += len; + } + return 0; +} + +/** + * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips. + * Applies only if NAND_BBT_PERCHIP option is set + * + * Read the bad block table for all chips starting at a given page + * We assume that the bbt bits are in consecutive order. +*/ +static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) +{ + struct nand_chip *this = mtd->priv; + int res = 0, i; + int bits; + + bits = td->options & NAND_BBT_NRBITS_MSK; + if (td->options & NAND_BBT_PERCHIP) { + int offs = 0; + for (i = 0; i < this->numchips; i++) { + if (chip == -1 || chip == i) + res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); + if (res) + return res; + offs += this->chipsize >> (this->bbt_erase_shift + 2); + } + } else { + res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); + if (res) + return res; + } + return 0; +} + +/* + * Scan read raw data from flash + */ +static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, + size_t len) +{ + struct mtd_oob_ops ops; + + ops.mode = MTD_OOB_RAW; + ops.ooboffs = 0; + ops.ooblen = mtd->oobsize; + ops.oobbuf = buf; + ops.datbuf = buf; + ops.len = len; + + return mtd->read_oob(mtd, offs, &ops); +} + +/* + * Scan write data with oob to flash + */ +static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, + uint8_t *buf, uint8_t *oob) +{ + struct mtd_oob_ops ops; + + ops.mode = MTD_OOB_PLACE; + ops.ooboffs = 0; + ops.ooblen = mtd->oobsize; + ops.datbuf = buf; + ops.oobbuf = oob; + ops.len = len; + + return mtd->write_oob(mtd, offs, &ops); +} + +/** + * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * + * Read the bad block table(s) for all chips starting at a given page + * We assume that the bbt bits are in consecutive order. + * +*/ +static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, struct nand_bbt_descr *md) +{ + struct nand_chip *this = mtd->priv; + + /* Read the primary version, if available */ + if (td->options & NAND_BBT_VERSION) { + scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, + mtd->writesize); + td->version[0] = buf[mtd->writesize + td->veroffs]; + printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", + td->pages[0], td->version[0]); + } + + /* Read the mirror version, if available */ + if (md && (md->options & NAND_BBT_VERSION)) { + scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, + mtd->writesize); + md->version[0] = buf[mtd->writesize + md->veroffs]; + printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", + md->pages[0], md->version[0]); + } + return 1; +} + +/* + * Scan a given block full + */ +static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, + loff_t offs, uint8_t *buf, size_t readlen, + int scanlen, int len) +{ + int ret, j; + + ret = scan_read_raw(mtd, buf, offs, readlen); + if (ret) + return ret; + + for (j = 0; j < len; j++, buf += scanlen) { + if (check_pattern(buf, scanlen, mtd->writesize, bd)) + return 1; + } + return 0; +} + +/* + * Scan a given block partially + */ +static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, + loff_t offs, uint8_t *buf, int len) +{ + struct mtd_oob_ops ops; + int j, ret; + + ops.ooblen = mtd->oobsize; + ops.oobbuf = buf; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OOB_PLACE; + + for (j = 0; j < len; j++) { + /* + * Read the full oob until read_oob is fixed to + * handle single byte reads for 16 bit + * buswidth + */ + ret = mtd->read_oob(mtd, offs, &ops); + if (ret) + return ret; + + if (check_short_pattern(buf, bd)) + return 1; + + offs += mtd->writesize; + } + return 0; +} + +/** + * create_bbt - [GENERIC] Create a bad block table by scanning the device + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips. + * Applies only if NAND_BBT_PERCHIP option is set + * + * Create a bad block table by scanning the device + * for the given good/bad block identify pattern + */ +static int create_bbt(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *bd, int chip) +{ + struct nand_chip *this = mtd->priv; + int i, numblocks, len, scanlen; + int startblock; + loff_t from; + size_t readlen; + + printk(KERN_INFO "Scanning device for bad blocks\n"); + + if (bd->options & NAND_BBT_SCANALLPAGES) + len = 1 << (this->bbt_erase_shift - this->page_shift); + else { + if (bd->options & NAND_BBT_SCAN2NDPAGE) + len = 2; + else + len = 1; + } + + if (!(bd->options & NAND_BBT_SCANEMPTY)) { + /* We need only read few bytes from the OOB area */ + scanlen = 0; + readlen = bd->len; + } else { + /* Full page content should be read */ + scanlen = mtd->writesize + mtd->oobsize; + readlen = len * mtd->writesize; + } + + if (chip == -1) { + /* Note that numblocks is 2 * (real numblocks) here, see i+=2 + * below as it makes shifting and masking less painful */ + numblocks = mtd->size >> (this->bbt_erase_shift - 1); + startblock = 0; + from = 0; + } else { + if (chip >= this->numchips) { + printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", + chip + 1, this->numchips); + return -EINVAL; + } + numblocks = this->chipsize >> (this->bbt_erase_shift - 1); + startblock = chip * numblocks; + numblocks += startblock; + from = startblock << (this->bbt_erase_shift - 1); + } + + for (i = startblock; i < numblocks;) { + int ret; + + if (bd->options & NAND_BBT_SCANALLPAGES) + ret = scan_block_full(mtd, bd, from, buf, readlen, + scanlen, len); + else + ret = scan_block_fast(mtd, bd, from, buf, len); + + if (ret < 0) + return ret; + + if (ret) { + this->bbt[i >> 3] |= 0x03 << (i & 0x6); + printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", + i >> 1, (unsigned int)from); + mtd->ecc_stats.badblocks++; + } + + i += 2; + from += (1 << this->bbt_erase_shift); + } + return 0; +} + +/** + * search_bbt - [GENERIC] scan the device for a specific bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * + * Read the bad block table by searching for a given ident pattern. + * Search is preformed either from the beginning up or from the end of + * the device downwards. The search starts always at the start of a + * block. + * If the option NAND_BBT_PERCHIP is given, each chip is searched + * for a bbt, which contains the bad block information of this chip. + * This is necessary to provide support for certain DOC devices. + * + * The bbt ident pattern resides in the oob area of the first page + * in a block. + */ +static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) +{ + struct nand_chip *this = mtd->priv; + int i, chips; + int bits, startblock, block, dir; + int scanlen = mtd->writesize + mtd->oobsize; + int bbtblocks; + int blocktopage = this->bbt_erase_shift - this->page_shift; + + /* Search direction top -> down ? */ + if (td->options & NAND_BBT_LASTBLOCK) { + startblock = (mtd->size >> this->bbt_erase_shift) - 1; + dir = -1; + } else { + startblock = 0; + dir = 1; + } + + /* Do we have a bbt per chip ? */ + if (td->options & NAND_BBT_PERCHIP) { + chips = this->numchips; + bbtblocks = this->chipsize >> this->bbt_erase_shift; + startblock &= bbtblocks - 1; + } else { + chips = 1; + bbtblocks = mtd->size >> this->bbt_erase_shift; + } + + /* Number of bits for each erase block in the bbt */ + bits = td->options & NAND_BBT_NRBITS_MSK; + + for (i = 0; i < chips; i++) { + /* Reset version information */ + td->version[i] = 0; + td->pages[i] = -1; + /* Scan the maximum number of blocks */ + for (block = 0; block < td->maxblocks; block++) { + + int actblock = startblock + dir * block; + loff_t offs = actblock << this->bbt_erase_shift; + + /* Read first page */ + scan_read_raw(mtd, buf, offs, mtd->writesize); + if (!check_pattern(buf, scanlen, mtd->writesize, td)) { + td->pages[i] = actblock << blocktopage; + if (td->options & NAND_BBT_VERSION) { + td->version[i] = buf[mtd->writesize + td->veroffs]; + } + break; + } + } + startblock += this->chipsize >> this->bbt_erase_shift; + } + /* Check, if we found a bbt for each requested chip */ + for (i = 0; i < chips; i++) { + if (td->pages[i] == -1) + printk(KERN_WARNING "Bad block table not found for chip %d\n", i); + else + printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], + td->version[i]); + } + return 0; +} + +/** + * search_read_bbts - [GENERIC] scan the device for bad block table(s) + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * + * Search and read the bad block table(s) +*/ +static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) +{ + /* Search the primary table */ + search_bbt(mtd, buf, td); + + /* Search the mirror table */ + if (md) + search_bbt(mtd, buf, md); + + /* Force result check */ + return 1; +} + +/** + * write_bbt - [GENERIC] (Re)write the bad block table + * + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all + * + * (Re)write the bad block table + * +*/ +static int write_bbt(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, struct nand_bbt_descr *md, + int chipsel) +{ + struct nand_chip *this = mtd->priv; + struct erase_info einfo; + int i, j, res, chip = 0; + int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; + int nrchips, bbtoffs, pageoffs, ooboffs; + uint8_t msk[4]; + uint8_t rcode = td->reserved_block_code; + size_t retlen, len = 0; + loff_t to; + struct mtd_oob_ops ops; + + ops.ooblen = mtd->oobsize; + ops.ooboffs = 0; + ops.datbuf = NULL; + ops.mode = MTD_OOB_PLACE; + + if (!rcode) + rcode = 0xff; + /* Write bad block table per chip rather than per device ? */ + if (td->options & NAND_BBT_PERCHIP) { + numblocks = (int)(this->chipsize >> this->bbt_erase_shift); + /* Full device write or specific chip ? */ + if (chipsel == -1) { + nrchips = this->numchips; + } else { + nrchips = chipsel + 1; + chip = chipsel; + } + } else { + numblocks = (int)(mtd->size >> this->bbt_erase_shift); + nrchips = 1; + } + + /* Loop through the chips */ + for (; chip < nrchips; chip++) { + + /* There was already a version of the table, reuse the page + * This applies for absolute placement too, as we have the + * page nr. in td->pages. + */ + if (td->pages[chip] != -1) { + page = td->pages[chip]; + goto write; + } + + /* Automatic placement of the bad block table */ + /* Search direction top -> down ? */ + if (td->options & NAND_BBT_LASTBLOCK) { + startblock = numblocks * (chip + 1) - 1; + dir = -1; + } else { + startblock = chip * numblocks; + dir = 1; + } + + for (i = 0; i < td->maxblocks; i++) { + int block = startblock + dir * i; + /* Check, if the block is bad */ + switch ((this->bbt[block >> 2] >> + (2 * (block & 0x03))) & 0x03) { + case 0x01: + case 0x03: + continue; + } + page = block << + (this->bbt_erase_shift - this->page_shift); + /* Check, if the block is used by the mirror table */ + if (!md || md->pages[chip] != page) + goto write; + } + printk(KERN_ERR "No space left to write bad block table\n"); + return -ENOSPC; + write: + + /* Set up shift count and masks for the flash table */ + bits = td->options & NAND_BBT_NRBITS_MSK; + msk[2] = ~rcode; + switch (bits) { + case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x01; + break; + case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; + msk[3] = 0x03; + break; + case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; + msk[3] = 0x0f; + break; + case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; + msk[3] = 0xff; + break; + default: return -EINVAL; + } + + bbtoffs = chip * (numblocks >> 2); + + to = ((loff_t) page) << this->page_shift; + + /* Must we save the block contents ? */ + if (td->options & NAND_BBT_SAVECONTENT) { + /* Make it block aligned */ + to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); + len = 1 << this->bbt_erase_shift; + res = mtd->read(mtd, to, len, &retlen, buf); + if (res < 0) { + if (retlen != len) { + printk(KERN_INFO "nand_bbt: Error " + "reading block for writing " + "the bad block table\n"); + return res; + } + printk(KERN_WARNING "nand_bbt: ECC error " + "while reading block for writing " + "bad block table\n"); + } + /* Read oob data */ + ops.ooblen = (len >> this->page_shift) * mtd->oobsize; + ops.oobbuf = &buf[len]; + res = mtd->read_oob(mtd, to + mtd->writesize, &ops); + if (res < 0 || ops.oobretlen != ops.ooblen) + goto outerr; + + /* Calc the byte offset in the buffer */ + pageoffs = page - (int)(to >> this->page_shift); + offs = pageoffs << this->page_shift; + /* Preset the bbt area with 0xff */ + memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); + ooboffs = len + (pageoffs * mtd->oobsize); + + } else { + /* Calc length */ + len = (size_t) (numblocks >> sft); + /* Make it page aligned ! */ + len = (len + (mtd->writesize - 1)) & + ~(mtd->writesize - 1); + /* Preset the buffer with 0xff */ + memset(buf, 0xff, len + + (len >> this->page_shift)* mtd->oobsize); + offs = 0; + ooboffs = len; + /* Pattern is located in oob area of first page */ + memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); + } + + if (td->options & NAND_BBT_VERSION) + buf[ooboffs + td->veroffs] = td->version[chip]; + + /* walk through the memory table */ + for (i = 0; i < numblocks;) { + uint8_t dat; + dat = this->bbt[bbtoffs + (i >> 2)]; + for (j = 0; j < 4; j++, i++) { + int sftcnt = (i << (3 - sft)) & sftmsk; + /* Do not store the reserved bbt blocks ! */ + buf[offs + (i >> sft)] &= + ~(msk[dat & 0x03] << sftcnt); + dat >>= 2; + } + } + + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = (unsigned long)to; + einfo.len = 1 << this->bbt_erase_shift; + res = nand_erase_nand(mtd, &einfo, 1); + if (res < 0) + goto outerr; + + res = scan_write_bbt(mtd, to, len, buf, &buf[len]); + if (res < 0) + goto outerr; + + printk(KERN_DEBUG "Bad block table written to 0x%08x, version " + "0x%02X\n", (unsigned int)to, td->version[chip]); + + /* Mark it as used */ + td->pages[chip] = page; + } + return 0; + + outerr: + printk(KERN_WARNING + "nand_bbt: Error while writing bad block table %d\n", res); + return res; +} + +/** + * nand_memory_bbt - [GENERIC] create a memory based bad block table + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern + * + * The function creates a memory based bbt by scanning the device + * for manufacturer / software marked good / bad blocks +*/ +static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct nand_chip *this = mtd->priv; + + bd->options &= ~NAND_BBT_SCANEMPTY; + return create_bbt(mtd, this->buffers->databuf, bd, -1); +} + +/** + * check_create - [GENERIC] create and write bbt(s) if necessary + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * + * The function checks the results of the previous call to read_bbt + * and creates / updates the bbt(s) if necessary + * Creation is necessary if no bbt was found for the chip/device + * Update is necessary if one of the tables is missing or the + * version nr. of one table is less than the other +*/ +static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) +{ + int i, chips, writeops, chipsel, res; + struct nand_chip *this = mtd->priv; + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + struct nand_bbt_descr *rd, *rd2; + + /* Do we have a bbt per chip ? */ + if (td->options & NAND_BBT_PERCHIP) + chips = this->numchips; + else + chips = 1; + + for (i = 0; i < chips; i++) { + writeops = 0; + rd = NULL; + rd2 = NULL; + /* Per chip or per device ? */ + chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; + /* Mirrored table avilable ? */ + if (md) { + if (td->pages[i] == -1 && md->pages[i] == -1) { + writeops = 0x03; + goto create; + } + + if (td->pages[i] == -1) { + rd = md; + td->version[i] = md->version[i]; + writeops = 1; + goto writecheck; + } + + if (md->pages[i] == -1) { + rd = td; + md->version[i] = td->version[i]; + writeops = 2; + goto writecheck; + } + + if (td->version[i] == md->version[i]) { + rd = td; + if (!(td->options & NAND_BBT_VERSION)) + rd2 = md; + goto writecheck; + } + + if (((int8_t) (td->version[i] - md->version[i])) > 0) { + rd = td; + md->version[i] = td->version[i]; + writeops = 2; + } else { + rd = md; + td->version[i] = md->version[i]; + writeops = 1; + } + + goto writecheck; + + } else { + if (td->pages[i] == -1) { + writeops = 0x01; + goto create; + } + rd = td; + goto writecheck; + } + create: + /* Create the bad block table by scanning the device ? */ + if (!(td->options & NAND_BBT_CREATE)) + continue; + + /* Create the table in memory by scanning the chip(s) */ + create_bbt(mtd, buf, bd, chipsel); + + td->version[i] = 1; + if (md) + md->version[i] = 1; + writecheck: + /* read back first ? */ + if (rd) + read_abs_bbt(mtd, buf, rd, chipsel); + /* If they weren't versioned, read both. */ + if (rd2) + read_abs_bbt(mtd, buf, rd2, chipsel); + + /* Write the bad block table to the device ? */ + if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { + res = write_bbt(mtd, buf, td, md, chipsel); + if (res < 0) + return res; + } + + /* Write the mirror bad block table to the device ? */ + if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { + res = write_bbt(mtd, buf, md, td, chipsel); + if (res < 0) + return res; + } + } + return 0; +} + +/** + * mark_bbt_regions - [GENERIC] mark the bad block table regions + * @mtd: MTD device structure + * @td: bad block table descriptor + * + * The bad block table regions are marked as "bad" to prevent + * accidental erasures / writes. The regions are identified by + * the mark 0x02. +*/ +static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ + struct nand_chip *this = mtd->priv; + int i, j, chips, block, nrblocks, update; + uint8_t oldval, newval; + + /* Do we have a bbt per chip ? */ + if (td->options & NAND_BBT_PERCHIP) { + chips = this->numchips; + nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); + } else { + chips = 1; + nrblocks = (int)(mtd->size >> this->bbt_erase_shift); + } + + for (i = 0; i < chips; i++) { + if ((td->options & NAND_BBT_ABSPAGE) || + !(td->options & NAND_BBT_WRITE)) { + if (td->pages[i] == -1) + continue; + block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); + block <<= 1; + oldval = this->bbt[(block >> 3)]; + newval = oldval | (0x2 << (block & 0x06)); + this->bbt[(block >> 3)] = newval; + if ((oldval != newval) && td->reserved_block_code) + nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); + continue; + } + update = 0; + if (td->options & NAND_BBT_LASTBLOCK) + block = ((i + 1) * nrblocks) - td->maxblocks; + else + block = i * nrblocks; + block <<= 1; + for (j = 0; j < td->maxblocks; j++) { + oldval = this->bbt[(block >> 3)]; + newval = oldval | (0x2 << (block & 0x06)); + this->bbt[(block >> 3)] = newval; + if (oldval != newval) + update = 1; + block += 2; + } + /* If we want reserved blocks to be recorded to flash, and some + new ones have been marked, then we need to update the stored + bbts. This should only happen once. */ + if (update && td->reserved_block_code) + nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1)); + } +} + +/** + * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern + * + * The function checks, if a bad block table(s) is/are already + * available. If not it scans the device for manufacturer + * marked good / bad blocks and writes the bad block table(s) to + * the selected place. + * + * The bad block table memory is allocated here. It must be freed + * by calling the nand_free_bbt function. + * +*/ +int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ + struct nand_chip *this = mtd->priv; + int len, res = 0; + uint8_t *buf; + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + + len = mtd->size >> (this->bbt_erase_shift + 2); + /* Allocate memory (2bit per block) and clear the memory bad block table */ + this->bbt = kzalloc(len, GFP_KERNEL); + if (!this->bbt) { + printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); + return -ENOMEM; + } + + /* If no primary table decriptor is given, scan the device + * to build a memory based bad block table + */ + if (!td) { + if ((res = nand_memory_bbt(mtd, bd))) { + printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + kfree(this->bbt); + this->bbt = NULL; + } + return res; + } + + /* Allocate a temporary buffer for one eraseblock incl. oob */ + len = (1 << this->bbt_erase_shift); + len += (len >> this->page_shift) * mtd->oobsize; + buf = vmalloc(len); + if (!buf) { + printk(KERN_ERR "nand_bbt: Out of memory\n"); + kfree(this->bbt); + this->bbt = NULL; + return -ENOMEM; + } + + /* Is the bbt at a given page ? */ + if (td->options & NAND_BBT_ABSPAGE) { + res = read_abs_bbts(mtd, buf, td, md); + } else { + /* Search the bad block table using a pattern in oob */ + res = search_read_bbts(mtd, buf, td, md); + } + + if (res) + res = check_create(mtd, buf, bd); + + /* Prevent the bbt regions from erasing / writing */ + mark_bbt_region(mtd, td); + if (md) + mark_bbt_region(mtd, md); + + vfree(buf); + return res; +} + +/** + * nand_update_bbt - [NAND Interface] update bad block table(s) + * @mtd: MTD device structure + * @offs: the offset of the newly marked block + * + * The function updates the bad block table(s) +*/ +int nand_update_bbt(struct mtd_info *mtd, loff_t offs) +{ + struct nand_chip *this = mtd->priv; + int len, res = 0, writeops = 0; + int chip, chipsel; + uint8_t *buf; + struct nand_bbt_descr *td = this->bbt_td; + struct nand_bbt_descr *md = this->bbt_md; + + if (!this->bbt || !td) + return -EINVAL; + + len = mtd->size >> (this->bbt_erase_shift + 2); + /* Allocate a temporary buffer for one eraseblock incl. oob */ + len = (1 << this->bbt_erase_shift); + len += (len >> this->page_shift) * mtd->oobsize; + buf = kmalloc(len, GFP_KERNEL); + if (!buf) { + printk(KERN_ERR "nand_update_bbt: Out of memory\n"); + return -ENOMEM; + } + + writeops = md != NULL ? 0x03 : 0x01; + + /* Do we have a bbt per chip ? */ + if (td->options & NAND_BBT_PERCHIP) { + chip = (int)(offs >> this->chip_shift); + chipsel = chip; + } else { + chip = 0; + chipsel = -1; + } + + td->version[chip]++; + if (md) + md->version[chip]++; + + /* Write the bad block table to the device ? */ + if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { + res = write_bbt(mtd, buf, td, md, chipsel); + if (res < 0) + goto out; + } + /* Write the mirror bad block table to the device ? */ + if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { + res = write_bbt(mtd, buf, md, td, chipsel); + } + + out: + kfree(buf); + return res; +} + +/* 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, 0xff }; + +static struct nand_bbt_descr smallpage_memorybased = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = 5, + .len = 1, + .pattern = scan_ff_pattern +}; + +static struct nand_bbt_descr largepage_memorybased = { + .options = 0, + .offs = 0, + .len = 2, + .pattern = scan_ff_pattern +}; + +static struct nand_bbt_descr smallpage_flashbased = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = 5, + .len = 1, + .pattern = scan_ff_pattern +}; + +static struct nand_bbt_descr largepage_flashbased = { + .options = NAND_BBT_SCAN2NDPAGE, + .offs = 0, + .len = 2, + .pattern = scan_ff_pattern +}; + +static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; + +static struct nand_bbt_descr agand_flashbased = { + .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, + .offs = 0x20, + .len = 6, + .pattern = scan_agand_pattern +}; + +/* Generic flash bbt decriptors +*/ +static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 8, + .len = 4, + .veroffs = 12, + .maxblocks = 4, + .pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 8, + .len = 4, + .veroffs = 12, + .maxblocks = 4, + .pattern = mirror_pattern +}; + +/** + * nand_default_bbt - [NAND Interface] Select a default bad block table for the device + * @mtd: MTD device structure + * + * This function selects the default bad block table + * support for the device and calls the nand_scan_bbt function + * +*/ +int nand_default_bbt(struct mtd_info *mtd) +{ + struct nand_chip *this = mtd->priv; + + /* Default for AG-AND. We must use a flash based + * bad block table as the devices have factory marked + * _good_ blocks. Erasing those blocks leads to loss + * of the good / bad information, so we _must_ store + * this information in a good / bad table during + * startup + */ + if (this->options & NAND_IS_AND) { + /* Use the default pattern descriptors */ + if (!this->bbt_td) { + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + } + this->options |= NAND_USE_FLASH_BBT; + return nand_scan_bbt(mtd, &agand_flashbased); + } + + /* Is a flash based bad block table requested ? */ + if (this->options & NAND_USE_FLASH_BBT) { + /* Use the default pattern descriptors */ + if (!this->bbt_td) { + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + } + if (!this->badblock_pattern) { + this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; + } + } else { + this->bbt_td = NULL; + this->bbt_md = NULL; + if (!this->badblock_pattern) { + this->badblock_pattern = (mtd->writesize > 512) ? + &largepage_memorybased : &smallpage_memorybased; + } + } + return nand_scan_bbt(mtd, this->badblock_pattern); +} + +/** + * nand_isbad_bbt - [NAND Interface] Check if a block is bad + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + * +*/ +int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) +{ + struct nand_chip *this = mtd->priv; + int block; + uint8_t res; + + /* Get block number * 2 */ + block = (int)(offs >> (this->bbt_erase_shift - 1)); + res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; + + MTD_DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", + (unsigned int)offs, block >> 1, res); + + switch ((int)res) { + case 0x00: + return 0; + case 0x01: + return 1; + case 0x02: + return allowbbt ? 0 : 1; + } + return 1; +} + +EXPORT_SYMBOL(nand_scan_bbt); +EXPORT_SYMBOL(nand_default_bbt); + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c new file mode 100644 index 0000000..266d573 --- /dev/null +++ b/drivers/mtd/nand/nand_ecc.c @@ -0,0 +1,198 @@ +/* + * This file contains an ECC algorithm from Toshiba that detects and + * corrects 1 bit errors in a 256 byte block of data. + * + * drivers/mtd/nand/nand_ecc.c + * + * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) + * Toshiba America Electronics Components, Inc. + * + * Copyright (C) 2006 Thomas Gleixner + * + * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ + * + * This file 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 or (at your option) any + * later version. + * + * This file 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 file; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + * + * As a special exception, if other files instantiate templates or use + * macros or inline functions from these files, or you compile these + * files and link them with other works to produce a work based on these + * files, these files do not by themselves cause the resulting work to be + * covered by the GNU General Public License. However the source code for + * these files must still be made available in accordance with section (3) + * of the GNU General Public License. + * + * This exception does not invalidate any other reasons why a work based on + * this file might be covered by the GNU General Public License. + */ + +#include +#include +#include +#include + +/* + * Pre-calculated 256-way 1 byte column parity + */ +static const u_char nand_ecc_precalc_table[] = { + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, + 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, + 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, + 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, + 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, + 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, + 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, + 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 +}; + +/** + * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block + * @mtd: MTD block structure + * @dat: raw data + * @ecc_code: buffer for ECC + */ +int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, + u_char *ecc_code) +{ + uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; + int i; + + /* Initialize variables */ + reg1 = reg2 = reg3 = 0; + + /* Build up column parity */ + for(i = 0; i < 256; i++) { + /* Get CP0 - CP5 from table */ + idx = nand_ecc_precalc_table[*dat++]; + reg1 ^= (idx & 0x3f); + + /* All bit XOR = 1 ? */ + if (idx & 0x40) { + reg3 ^= (uint8_t) i; + reg2 ^= ~((uint8_t) i); + } + } + + /* Create non-inverted ECC code from line parity */ + tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ + tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ + tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ + tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ + tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ + tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ + tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ + tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ + + tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ + tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ + tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ + tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ + tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ + tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ + tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ + tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ + + /* Calculate final ECC code */ +#ifdef CONFIG_MTD_NAND_ECC_SMC + ecc_code[0] = ~tmp2; + ecc_code[1] = ~tmp1; +#else + ecc_code[0] = ~tmp1; + ecc_code[1] = ~tmp2; +#endif + ecc_code[2] = ((~reg1) << 2) | 0x03; + + return 0; +} +EXPORT_SYMBOL(nand_calculate_ecc); + +static inline int countbits(uint32_t byte) +{ + int res = 0; + + for (;byte; byte >>= 1) + res += byte & 0x01; + return res; +} + +/** + * nand_correct_data - [NAND Interface] Detect and correct bit error(s) + * @mtd: MTD block structure + * @dat: raw data read from the chip + * @read_ecc: ECC from the chip + * @calc_ecc: the ECC calculated from raw data + * + * Detect and correct a 1 bit error for 256 byte block + */ +int nand_correct_data(struct mtd_info *mtd, u_char *dat, + u_char *read_ecc, u_char *calc_ecc) +{ + uint8_t s0, s1, s2; + +#ifdef CONFIG_MTD_NAND_ECC_SMC + s0 = calc_ecc[0] ^ read_ecc[0]; + s1 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; +#else + s1 = calc_ecc[0] ^ read_ecc[0]; + s0 = calc_ecc[1] ^ read_ecc[1]; + s2 = calc_ecc[2] ^ read_ecc[2]; +#endif + if ((s0 | s1 | s2) == 0) + return 0; + + /* Check for a single bit error */ + if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && + ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && + ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { + + uint32_t byteoffs, bitnum; + + byteoffs = (s1 << 0) & 0x80; + byteoffs |= (s1 << 1) & 0x40; + byteoffs |= (s1 << 2) & 0x20; + byteoffs |= (s1 << 3) & 0x10; + + byteoffs |= (s0 >> 4) & 0x08; + byteoffs |= (s0 >> 3) & 0x04; + byteoffs |= (s0 >> 2) & 0x02; + byteoffs |= (s0 >> 1) & 0x01; + + bitnum = (s2 >> 5) & 0x04; + bitnum |= (s2 >> 4) & 0x02; + bitnum |= (s2 >> 3) & 0x01; + + dat[byteoffs] ^= (1 << bitnum); + + return 1; + } + + if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) + return 1; + + return -EBADMSG; +} +EXPORT_SYMBOL(nand_correct_data); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Steven J. Hill "); +MODULE_DESCRIPTION("Generic NAND ECC support"); diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c new file mode 100644 index 0000000..f95975c --- /dev/null +++ b/drivers/mtd/nand/nand_ids.c @@ -0,0 +1,153 @@ +/* + * drivers/mtd/nandids.c + * + * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) + * + * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include +#include +/* +* Chip ID list +* +* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, +* options +* +* Pagesize; 0, 256, 512 +* 0 get this information from the extended chip ID ++ 256 256 Byte page size +* 512 512 Byte page size +*/ +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}, +#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}, + + {"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}, + + {"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}, + + {"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}, + + {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, + + /* + * These are the new chips with large page size. The pagesize and the + * erasesize is determined from the extended id bytes + */ +#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR) +#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}, + + /* 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}, + + /* 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}, + + /* 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}, + + /* 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}, + + /* 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}, + + /* + * Renesas AND 1 Gigabit. Those chips do not support extended id and + * have a strange page/block layout ! The chosen minimum erasesize is + * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page + * planes 1 block = 2 pages, but due to plane arrangement the blocks + * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would + * increase the eraseblock size so we chose a combined one which can be + * 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, + NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | + BBT_AUTO_REFRESH + }, + + {NULL,} +}; + +/* +* 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"}, + {0x0, "Unknown"} +}; + +EXPORT_SYMBOL(nand_manuf_ids); +EXPORT_SYMBOL(nand_flash_ids); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Gleixner "); +MODULE_DESCRIPTION("Nand device & manufacturer IDs"); diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c new file mode 100644 index 0000000..5454e32 --- /dev/null +++ b/drivers/mtd/nand/nand_imx.c @@ -0,0 +1,1210 @@ +/* + * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2008 Sascha Hauer, Pengutronix + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* + * MX21 Hardware contains a bug which causes HW ECC to fail for two + * consecutive read pages containing 1bit Errors (See MX21 Chip Erata, + * Erratum 16). Use software ECC for this chip. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DVR_VER "2.0" + +#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) +#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) + +/* + * Addresses for NFC registers + */ +#define NFC_BUF_SIZE 0xE00 +#define NFC_BUF_ADDR 0xE04 +#define NFC_FLASH_ADDR 0xE06 +#define NFC_FLASH_CMD 0xE08 +#define NFC_CONFIG 0xE0A +#define NFC_ECC_STATUS_RESULT 0xE0C +#define NFC_RSLTMAIN_AREA 0xE0E +#define NFC_RSLTSPARE_AREA 0xE10 +#define NFC_SPAS 0xe10 +#define NFC_WRPROT 0xE12 +#define NFC_V1_UNLOCKSTART_BLKADDR 0xe14 +#define NFC_V1_UNLOCKEND_BLKADDR 0xe16 +#define NFC_V21_UNLOCKSTART_BLKADDR 0xe20 +#define NFC_V21_UNLOCKEND_BLKADDR 0xe22 +#define NFC_NF_WRPRST 0xE18 +#define NFC_CONFIG1 0xE1A +#define NFC_CONFIG2 0xE1C + +/* + * Addresses for NFC RAM BUFFER Main area 0 + */ +#define MAIN_AREA0 0x000 +#define MAIN_AREA1 0x200 +#define MAIN_AREA2 0x400 +#define MAIN_AREA3 0x600 + +/* + * Addresses for NFC SPARE BUFFER Spare area 0 + */ +#define SPARE_AREA0 0x800 +#define SPARE_AREA1 0x810 +#define SPARE_AREA2 0x820 +#define SPARE_AREA3 0x830 + +/* + * Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register for Command + * operation + */ +#define NFC_CMD 0x1 + +/* + * Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register for Address + * operation + */ +#define NFC_ADDR 0x2 + +/* + * Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register for Input + * operation + */ +#define NFC_INPUT 0x4 + +/* + * Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register for Data Output + * operation + */ +#define NFC_OUTPUT 0x8 + +/* + * Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register for Read ID + * operation + */ +#define NFC_ID 0x10 + +/* + * Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register for Read Status + * operation + */ +#define NFC_STATUS 0x20 + +/* + * Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read Status + * operation + */ +#define NFC_INT 0x8000 + +#define NFC_ECC_MODE (1 << 0) +#define NFC_SP_EN (1 << 2) +#define NFC_ECC_EN (1 << 3) +#define NFC_INT_MSK (1 << 4) +#define NFC_BIG (1 << 5) +#define NFC_RST (1 << 6) +#define NFC_CE (1 << 7) +#define NFC_ONE_CYCLE (1 << 8) + +#define NFC_SPAS_16 8 +#define NFC_SPAS_64 32 +#define NFC_SPAS_128 64 +#define NFC_SPAS_218 109 + +#ifdef CONFIG_NAND_IMX_BOOT +#define __nand_boot_init __bare_init +#else +#define __nand_boot_init +#endif + +struct imx_nand_host { + struct mtd_info mtd; + struct nand_chip nand; + struct mtd_partition *parts; + struct device_d *dev; + + void *spare0; + void *main_area0; + void *main_area1; + + void __iomem *base; + void __iomem *regs; + int status_request; + struct clk *clk; + + int pagesize_2k; + uint8_t *data_buf; + unsigned int buf_start; + int spare_len; + +}; + +/* + * OOB placement block for use with hardware ecc generation + */ +static struct nand_ecclayout nandv1_hw_eccoob_smallpage = { + .eccbytes = 5, + .eccpos = {6, 7, 8, 9, 10}, + .oobfree = {{0, 5}, {12, 4}} +}; + +static struct nand_ecclayout nandv1_hw_eccoob_largepage = { + .eccbytes = 20, + .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, + 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, + .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } +}; + +/* OOB description for 512 byte pages with 16 byte OOB */ +static struct nand_ecclayout nandv2_hw_eccoob_smallpage = { + .eccbytes = 1 * 9, + .eccpos = { + 7, 8, 9, 10, 11, 12, 13, 14, 15 + }, + .oobfree = { + {.offset = 0, .length = 5} + } +}; + +/* OOB description for 2048 byte pages with 64 byte OOB */ +static struct nand_ecclayout nandv2_hw_eccoob_largepage = { + .eccbytes = 4 * 9, + .eccpos = { + 7, 8, 9, 10, 11, 12, 13, 14, 15, + 23, 24, 25, 26, 27, 28, 29, 30, 31, + 39, 40, 41, 42, 43, 44, 45, 46, 47, + 55, 56, 57, 58, 59, 60, 61, 62, 63 + }, + .oobfree = { + {.offset = 2, .length = 4}, + {.offset = 16, .length = 7}, + {.offset = 32, .length = 7}, + {.offset = 48, .length = 7} + } +}; + +static void memcpy32(void *trg, const void *src, int size) +{ + int i; + unsigned int *t = trg; + unsigned const int *s = src; + +#ifdef CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS + if (!((unsigned long)trg & 0x3) && !((unsigned long)src & 0x3)) + memcpy(trg, src, size); + else +#endif + for (i = 0; i < (size >> 2); i++) + *t++ = *s++; +} + +/* + * This function polls the NANDFC to wait for the basic operation to complete by + * checking the INT bit of config2 register. + * + * @param max_retries number of retry attempts (separated by 1 us) + * @param param parameter for debug + */ +static void __nand_boot_init wait_op_done(struct imx_nand_host *host) +{ + u32 tmp; + int i; + + /* This is a timeout of roughly 15ms on my system. We + * need about 2us, but be generous. Don't use udelay + * here as we might be here from nand booting. + */ + for (i = 0; i < 100000; i++) { + if (readw(host->regs + NFC_CONFIG2) & NFC_INT) { + tmp = readw(host->regs + NFC_CONFIG2); + tmp &= ~NFC_INT; + writew(tmp, host->regs + NFC_CONFIG2); + return; + } + } +} + +/* + * This function issues the specified command to the NAND device and + * waits for completion. + * + * @param cmd command for NAND Flash + */ +static void __nand_boot_init send_cmd(struct imx_nand_host *host, u16 cmd) +{ + MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd); + + writew(cmd, host->regs + NFC_FLASH_CMD); + writew(NFC_CMD, host->regs + NFC_CONFIG2); + + if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { + /* Reset completion is indicated by NFC_CONFIG2 */ + /* being set to 0 */ + int i; + for (i = 0; i < 100000; i++) { + if (readw(host->regs + NFC_CONFIG2) == 0) { + break; + } + } + } else + /* Wait for operation to complete */ + wait_op_done(host); +} + +/* + * This function sends an address (or partial address) to the + * NAND device. The address is used to select the source/destination for + * a NAND command. + * + * @param addr address to be written to NFC. + * @param islast True if this is the last address cycle for command + */ +static void __nand_boot_init noinline send_addr(struct imx_nand_host *host, u16 addr) +{ + MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); + + writew(addr, host->regs + NFC_FLASH_ADDR); + writew(NFC_ADDR, host->regs + NFC_CONFIG2); + + /* Wait for operation to complete */ + wait_op_done(host); +} + +/* + * This function requests the NANDFC to initate the transfer + * of data currently in the NANDFC RAM buffer to the NAND device. + * + * @param buf_id Specify Internal RAM Buffer number (0-3) + * @param spare_only set true if only the spare area is transferred + */ +static void __nand_boot_init send_page(struct imx_nand_host *host, + unsigned int ops) +{ + int bufs, i; + + if (nfc_is_v1() && host->pagesize_2k) + bufs = 4; + else + bufs = 1; + + for (i = 0; i < bufs; i++) { + /* NANDFC buffer 0 is used for page read/write */ + writew(i, host->regs + NFC_BUF_ADDR); + + writew(ops, host->regs + NFC_CONFIG2); + + /* Wait for operation to complete */ + wait_op_done(host); + } +} + +/* + * This function requests the NANDFC to perform a read of the + * NAND device ID. + */ +static void send_read_id(struct imx_nand_host *host) +{ + struct nand_chip *this = &host->nand; + u16 tmp; + + /* NANDFC buffer 0 is used for device ID output */ + writew(0x0, host->regs + NFC_BUF_ADDR); + + /* Read ID into main buffer */ + tmp = readw(host->regs + NFC_CONFIG1); + tmp &= ~NFC_SP_EN; + writew(tmp, host->regs + NFC_CONFIG1); + + writew(NFC_ID, host->regs + NFC_CONFIG2); + + /* Wait for operation to complete */ + wait_op_done(host); + + if (this->options & NAND_BUSWIDTH_16) { + volatile u16 *mainbuf = host->main_area0; + + /* + * Pack the every-other-byte result for 16-bit ID reads + * into every-byte as the generic code expects and various + * chips implement. + */ + + mainbuf[0] = (mainbuf[0] & 0xff) | ((mainbuf[1] & 0xff) << 8); + mainbuf[1] = (mainbuf[2] & 0xff) | ((mainbuf[3] & 0xff) << 8); + mainbuf[2] = (mainbuf[4] & 0xff) | ((mainbuf[5] & 0xff) << 8); + } + memcpy32(host->data_buf, host->main_area0, 16); +} + +/* + * This function requests the NANDFC to perform a read of the + * NAND device status and returns the current status. + * + * @return device status + */ +static u16 get_dev_status(struct imx_nand_host *host) +{ + volatile u16 *mainbuf = host->main_area1; + u32 store; + u16 ret, tmp; + /* Issue status request to NAND device */ + + /* store the main area1 first word, later do recovery */ + store = *((u32 *) mainbuf); + /* + * NANDFC buffer 1 is used for device status to prevent + * corruption of read/write buffer on status requests. + */ + writew(1, host->regs + NFC_BUF_ADDR); + + /* Read status into main buffer */ + tmp = readw(host->regs + NFC_CONFIG1); + tmp &= ~NFC_SP_EN; + writew(tmp, host->regs + NFC_CONFIG1); + + writew(NFC_STATUS, host->regs + NFC_CONFIG2); + + /* Wait for operation to complete */ + wait_op_done(host); + + /* Status is placed in first word of main buffer */ + /* get status, then recovery area 1 data */ + ret = mainbuf[0]; + *((u32 *) mainbuf) = store; + + return ret; +} + +/* + * This function is used by upper layer to checks if device is ready + * + * @param mtd MTD structure for the NAND Flash + * + * @return 0 if device is busy else 1 + */ +static int imx_nand_dev_ready(struct mtd_info *mtd) +{ + /* + * NFC handles R/B internally.Therefore,this function + * always returns status as ready. + */ + return 1; +} + +static void imx_nand_enable_hwecc(struct mtd_info *mtd, int mode) +{ + /* + * If HW ECC is enabled, we turn it on during init. There is + * no need to enable again here. + */ +} + +static int imx_nand_correct_data(struct mtd_info *mtd, u_char * dat, + u_char * read_ecc, u_char * calc_ecc) +{ + struct nand_chip *nand_chip = mtd->priv; + struct imx_nand_host *host = nand_chip->priv; + + /* + * 1-Bit errors are automatically corrected in HW. No need for + * additional correction. 2-Bit errors cannot be corrected by + * HW ECC, so we need to return failure + */ + u16 ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT); + + if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { + MTD_DEBUG(MTD_DEBUG_LEVEL0, + "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); + return -1; + } + + return 0; +} + +static int imx_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, + u_char * ecc_code) +{ + return 0; +} + +/* + * This function reads byte from the NAND Flash + * + * @param mtd MTD structure for the NAND Flash + * + * @return data read from the NAND Flash + */ +static u_char imx_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct imx_nand_host *host = nand_chip->priv; + u_char ret; + + /* Check for status request */ + if (host->status_request) + return get_dev_status(host) & 0xFF; + + ret = *(uint8_t *)(host->data_buf + host->buf_start); + host->buf_start++; + + return ret; +} + +/* + * This function reads word from the NAND Flash + * + * @param mtd MTD structure for the NAND Flash + * + * @return data read from the NAND Flash + */ +static u16 imx_nand_read_word(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct imx_nand_host *host = nand_chip->priv; + uint16_t ret; + + ret = *(uint16_t *)(host->data_buf + host->buf_start); + host->buf_start += 2; + + return ret; +} + +/* + * This function writes data of length \b len to buffer \b buf. The data to be + * written on NAND Flash is first copied to RAMbuffer. After the Data Input + * Operation by the NFC, the data is written to NAND Flash + * + * @param mtd MTD structure for the NAND Flash + * @param buf data to be written to NAND Flash + * @param len number of bytes to be written + */ +static void imx_nand_write_buf(struct mtd_info *mtd, + const u_char *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct imx_nand_host *host = nand_chip->priv; + u16 col = host->buf_start; + int n = mtd->oobsize + mtd->writesize - col; + + n = min(n, len); + memcpy(host->data_buf + col, buf, n); + + host->buf_start += n; +} + +/* + * This function is used to read the data buffer from the NAND Flash. To + * read the data from NAND Flash first the data output cycle is initiated by + * the NFC, which copies the data to RAMbuffer. This data of length \b len is + * then copied to buffer \b buf. + * + * @param mtd MTD structure for the NAND Flash + * @param buf data to be read from NAND Flash + * @param len number of bytes to be read + */ +static void imx_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct imx_nand_host *host = nand_chip->priv; + u16 col = host->buf_start; + int n = mtd->oobsize + mtd->writesize - col; + + n = min(n, len); + + memcpy(buf, host->data_buf + col, len); + + host->buf_start += len; +} + +/* + * Function to transfer data to/from spare area. + */ +static void copy_spare(struct mtd_info *mtd, int bfrom) +{ + struct nand_chip *this = mtd->priv; + struct imx_nand_host *host = this->priv; + u16 i, j; + u16 n = mtd->writesize >> 9; + u8 *d = host->data_buf + mtd->writesize; + u8 *s = host->spare0; + u16 t = host->spare_len; + + j = (mtd->oobsize / n >> 1) << 1; + + if (bfrom) { + for (i = 0; i < n - 1; i++) + memcpy32(d + i * j, s + i * t, j); + + /* the last section */ + memcpy32(d + i * j, s + i * t, mtd->oobsize - i * j); + } else { + for (i = 0; i < n - 1; i++) + memcpy32(&s[i * t], &d[i * j], j); + + /* the last section */ + memcpy32(&s[i * t], &d[i * j], mtd->oobsize - i * j); + } +} + +/* + * This function is used by the upper layer to verify the data in NAND Flash + * with the data in the \b buf. + * + * @param mtd MTD structure for the NAND Flash + * @param buf data to be verified + * @param len length of the data to be verified + * + * @return -EFAULT if error else 0 + * + */ +static int +imx_nand_verify_buf(struct mtd_info *mtd, const u_char * buf, int len) +{ + return -EFAULT; +} + +/* + * This function is used by upper layer for select and deselect of the NAND + * chip + * + * @param mtd MTD structure for the NAND Flash + * @param chip val indicating select or deselect + */ +static void imx_nand_select_chip(struct mtd_info *mtd, int chip) +{ +#ifdef CONFIG_MTD_NAND_MXC_FORCE_CE + u16 tmp; + + if (chip > 0) { + MTD_DEBUG(MTD_DEBUG_LEVEL0, + "ERROR: Illegal chip select (chip = %d)\n", chip); + return; + } + + if (chip == -1) { + tmp = readw(host->regs + NFC_CONFIG1); + tmp &= ~NFC_CE; + writew(tmp, host->regs + NFC_CONFIG1); + return; + } + + tmp = readw(host->regs + NFC_CONFIG1); + tmp |= NFC_CE; + writew(tmp, host->regs + NFC_CONFIG1); +#endif +} + +static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) +{ + struct nand_chip *nand_chip = mtd->priv; + struct imx_nand_host *host = nand_chip->priv; + + /* + * Write out column address, if necessary + */ + if (column != -1) { + /* + * MXC NANDFC can only perform full page+spare or + * spare-only read/write. When the upper layers + * layers perform a read/write buf operation, + * we will used the saved column adress to index into + * the full page. + */ + send_addr(host, 0); + if (host->pagesize_2k) + /* another col addr cycle for 2k page */ + send_addr(host, 0); + } + + /* + * Write out page address, if necessary + */ + if (page_addr != -1) { + send_addr(host, (page_addr & 0xff)); /* paddr_0 - p_addr_7 */ + + if (host->pagesize_2k) { + send_addr(host, (page_addr >> 8) & 0xFF); + if (mtd->size >= 0x10000000) { + send_addr(host, (page_addr >> 16) & 0xff); + } + } else { + /* One more address cycle for higher density devices */ + if (mtd->size >= 0x4000000) { + /* paddr_8 - paddr_15 */ + send_addr(host, (page_addr >> 8) & 0xff); + send_addr(host, (page_addr >> 16) & 0xff); + } else + /* paddr_8 - paddr_15 */ + send_addr(host, (page_addr >> 8) & 0xff); + } + } +} + +/* + * This function is used by the upper layer to write command to NAND Flash for + * different operations to be carried out on NAND Flash + * + * @param mtd MTD structure for the NAND Flash + * @param command command for NAND Flash + * @param column column offset for the page read + * @param page_addr page to be read from NAND Flash + */ +static void imx_nand_command(struct mtd_info *mtd, unsigned command, + int column, int page_addr) +{ + struct nand_chip *nand_chip = mtd->priv; + struct imx_nand_host *host = nand_chip->priv; + + MTD_DEBUG(MTD_DEBUG_LEVEL3, + "imx_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", + command, column, page_addr); + + /* + * Reset command state information + */ + host->status_request = 0; + + /* + * Command pre-processing step + */ + switch (command) { + + case NAND_CMD_STATUS: + host->buf_start = 0; + host->status_request = 1; + send_cmd(host, command); + mxc_do_addr_cycle(mtd, column, page_addr); + break; + + case NAND_CMD_READ0: + case NAND_CMD_READOOB: + if (command == NAND_CMD_READ0) + host->buf_start = column; + else + host->buf_start = column + mtd->writesize; + + command = NAND_CMD_READ0; + + send_cmd(host, command); + mxc_do_addr_cycle(mtd, column, page_addr); + + if (host->pagesize_2k) + /* send read confirm command */ + send_cmd(host, NAND_CMD_READSTART); + + send_page(host, NFC_OUTPUT); + + memcpy32(host->data_buf, host->main_area0, mtd->writesize); + copy_spare(mtd, 1); + break; + + case NAND_CMD_SEQIN: + if (column >= mtd->writesize) { + if (host->pagesize_2k) { + /** + * FIXME: before send SEQIN command for write + * OOB, we must read one page out. For K9F1GXX + * has no READ1 command to set current HW + * pointer to spare area, we must write the + * whole page including OOB together. + */ + /* call ourself to read a page */ + imx_nand_command(mtd, NAND_CMD_READ0, 0, + page_addr); + } + host->buf_start = column; + + /* Set program pointer to spare region */ + if (!host->pagesize_2k) + send_cmd(host, NAND_CMD_READOOB); + } else { + host->buf_start = column; + + /* Set program pointer to page start */ + if (!host->pagesize_2k) + send_cmd(host, NAND_CMD_READ0); + } + send_cmd(host, command); + mxc_do_addr_cycle(mtd, column, page_addr); + + break; + + case NAND_CMD_PAGEPROG: + memcpy32(host->main_area0, host->data_buf, mtd->writesize); + copy_spare(mtd, 0); + send_page(host, NFC_INPUT); + send_cmd(host, command); + mxc_do_addr_cycle(mtd, column, page_addr); + break; + + case NAND_CMD_READID: + send_cmd(host, command); + mxc_do_addr_cycle(mtd, column, page_addr); + host->buf_start = 0; + send_read_id(host); + break; + + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_RESET: + send_cmd(host, command); + mxc_do_addr_cycle(mtd, column, page_addr); + break; + } +} + +#ifdef CONFIG_MXC_NAND_LOW_LEVEL_ERASE +static void imx_low_erase(struct mtd_info *mtd) +{ + + struct nand_chip *this = mtd->priv; + unsigned int page_addr, addr; + u_char status; + + MTD_DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : imx_low_erase:Erasing NAND\n"); + for (addr = 0; addr < this->chipsize; addr += mtd->erasesize) { + page_addr = addr / mtd->writesize; + imx_nand_command(mtd, NAND_CMD_ERASE1, -1, page_addr); + imx_nand_command(mtd, NAND_CMD_ERASE2, -1, -1); + imx_nand_command(mtd, NAND_CMD_STATUS, -1, -1); + status = imx_nand_read_byte(mtd); + if (status & NAND_STATUS_FAIL) { + printk(KERN_ERR + "ERASE FAILED(block = %d,status = 0x%x)\n", + addr / mtd->erasesize, status); + } + } + +} +#endif + +/* + * The generic flash bbt decriptors overlap with our ecc + * hardware, so define some i.MX specific ones. + */ +static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; +static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; + +static struct nand_bbt_descr bbt_main_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = bbt_pattern, +}; + +static struct nand_bbt_descr bbt_mirror_descr = { + .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE + | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, + .offs = 0, + .len = 4, + .veroffs = 4, + .maxblocks = 4, + .pattern = mirror_pattern, +}; + +/* + * This function is called during the driver binding process. + * + * @param pdev the device structure used to store device specific + * information that is used by the suspend, resume and + * remove functions + * + * @return The function always returns 0. + */ + +static int __init imxnd_probe(struct device_d *dev) +{ + struct nand_chip *this; + struct mtd_info *mtd; + struct imx_nand_platform_data *pdata = dev->platform_data; + struct imx_nand_host *host; + struct nand_ecclayout *oob_smallpage, *oob_largepage; + u16 tmp; + int err = 0; + +#ifdef CONFIG_ARCH_IMX27 + PCCR1 |= PCCR1_NFC_BAUDEN; +#endif +#ifdef CONFIG_ARCH_IMX21 + PCCR0 |= PCCR0_NFC_EN; +#endif + /* Allocate memory for MTD device structure and private data */ + host = kzalloc(sizeof(struct imx_nand_host) + NAND_MAX_PAGESIZE + + NAND_MAX_OOBSIZE, GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->data_buf = (uint8_t *)(host + 1); + host->base = (void __iomem *)dev->map_base; + + host->main_area0 = host->base; + host->main_area1 = host->base + 0x200; + + if (nfc_is_v21()) { + host->regs = host->base + 0x1000; + host->spare0 = host->base + 0x1000; + host->spare_len = 64; + oob_smallpage = &nandv2_hw_eccoob_smallpage; + oob_largepage = &nandv2_hw_eccoob_largepage; + } else if (nfc_is_v1()) { + host->regs = host->base; + host->spare0 = host->base + 0x800; + host->spare_len = 16; + oob_smallpage = &nandv1_hw_eccoob_smallpage; + oob_largepage = &nandv1_hw_eccoob_largepage; + } + + host->dev = dev; + /* structures must be linked */ + this = &host->nand; + mtd = &host->mtd; + mtd->priv = this; + + /* 50 us command delay time */ + this->chip_delay = 5; + + this->priv = host; + this->dev_ready = imx_nand_dev_ready; + this->cmdfunc = imx_nand_command; + this->select_chip = imx_nand_select_chip; + this->read_byte = imx_nand_read_byte; + this->read_word = imx_nand_read_word; + this->write_buf = imx_nand_write_buf; + this->read_buf = imx_nand_read_buf; + this->verify_buf = imx_nand_verify_buf; +#if 0 + host->clk = clk_get(&pdev->dev, "nfc_clk"); + if (IS_ERR(host->clk)) + goto eclk; + + clk_enable(host->clk); +#endif + + tmp = readw(host->regs + NFC_CONFIG1); + tmp |= NFC_INT_MSK; + tmp &= ~NFC_SP_EN; + if (nfc_is_v21()) + /* currently no support for 218 byte OOB with stronger ECC */ + tmp |= NFC_ECC_MODE; + writew(tmp, host->regs + NFC_CONFIG1); + + if (pdata->hw_ecc) { + this->ecc.calculate = imx_nand_calculate_ecc; + this->ecc.hwctl = imx_nand_enable_hwecc; + this->ecc.correct = imx_nand_correct_data; + this->ecc.mode = NAND_ECC_HW; + this->ecc.size = 512; + tmp = readw(host->regs + NFC_CONFIG1); + tmp |= NFC_ECC_EN; + writew(tmp, host->regs + NFC_CONFIG1); + } else { + this->ecc.size = 512; + this->ecc.mode = NAND_ECC_SOFT; + tmp = readw(host->regs + NFC_CONFIG1); + tmp &= ~NFC_ECC_EN; + writew(tmp, host->regs + NFC_CONFIG1); + } + + /* Reset NAND */ + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + + /* preset operation */ + /* Unlock the internal RAM Buffer */ + writew(0x2, host->regs + NFC_CONFIG); + + /* Blocks to be unlocked */ + if (nfc_is_v21()) { + writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR); + writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR); + this->ecc.bytes = 9; + } else if (nfc_is_v1()) { + writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR); + writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR); + this->ecc.bytes = 3; + } + + /* Unlock Block Command for given address range */ + writew(0x4, host->regs + NFC_WRPROT); + + this->ecc.layout = oob_smallpage; + + /* NAND bus width determines access funtions used by upper layer */ + if (pdata->width == 2) { + this->options |= NAND_BUSWIDTH_16; + this->ecc.layout = &nandv1_hw_eccoob_smallpage; + imx_nand_set_layout(0, 16); + } + + if (pdata->flash_bbt) { + this->bbt_td = &bbt_main_descr; + this->bbt_md = &bbt_mirror_descr; + /* update flash based bbt */ + this->options |= NAND_USE_FLASH_BBT; + } + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(mtd, 1)) { + err = -ENXIO; + goto escan; + } + + imx_nand_set_layout(mtd->writesize, pdata->width == 2 ? 16 : 8); + + if (mtd->writesize == 2048) { + this->ecc.layout = oob_largepage; + host->pagesize_2k = 1; + if (nfc_is_v21()) { + tmp = readw(host->regs + NFC_SPAS); + tmp &= 0xff00; + tmp |= NFC_SPAS_64; + writew(tmp, host->regs + NFC_SPAS); + } + } else { + if (nfc_is_v21()) { + tmp = readw(host->regs + NFC_SPAS); + tmp &= 0xff00; + tmp |= NFC_SPAS_16; + writew(tmp, host->regs + NFC_SPAS); + } + } + + /* second phase scan */ + if (nand_scan_tail(mtd)) { + err = -ENXIO; + goto escan; + } + + add_mtd_device(mtd); + + dev->priv = host; + + return 0; + +escan: + kfree(host); + + return err; + +} + +static struct driver_d imx_nand_driver = { + .name = "imx_nand", + .probe = imxnd_probe, +}; + +#ifdef CONFIG_NAND_IMX_BOOT + +static void __nand_boot_init nfc_addr(struct imx_nand_host *host, u32 offs) +{ + if (host->pagesize_2k) { + send_addr(host, offs & 0xff); + send_addr(host, offs & 0xff); + send_addr(host, (offs >> 11) & 0xff); + send_addr(host, (offs >> 19) & 0xff); + send_addr(host, (offs >> 27) & 0xff); + } else { + send_addr(host, offs & 0xff); + send_addr(host, (offs >> 9) & 0xff); + send_addr(host, (offs >> 17) & 0xff); + send_addr(host, (offs >> 25) & 0xff); + } +} + +static void __nand_boot_init __memcpy32(void *trg, const void *src, int size) +{ + int i; + unsigned int *t = trg; + unsigned const int *s = src; + + for (i = 0; i < (size >> 2); i++) + *t++ = *s++; +} + +void __nand_boot_init imx_nand_load_image(void *dest, int size) +{ + struct imx_nand_host host; + u32 tmp, page, block, blocksize, pagesize; +#ifdef CONFIG_ARCH_IMX21 + tmp = readl(IMX_SYSTEM_CTL_BASE + 0x14); + if (tmp & (1 << 5)) + host.pagesize_2k = 1; + else + host.pagesize_2k = 0; +#endif +#ifdef CONFIG_ARCH_IMX27 + tmp = readl(IMX_SYSTEM_CTL_BASE + 0x14); + if (tmp & (1 << 5)) + host.pagesize_2k = 1; + else + host.pagesize_2k = 0; +#endif +#ifdef CONFIG_ARCH_IMX31 + tmp = readl(IMX_CCM_BASE + CCM_RCSR); + if (tmp & RCSR_NFMS) + host.pagesize_2k = 1; + else + host.pagesize_2k = 0; +#endif +#if defined(CONFIG_ARCH_IMX35) || defined(CONFIG_ARCH_IMX25) + if (readl(IMX_CCM_BASE + CCM_RCSR) & (1 << 8)) + host.pagesize_2k = 1; + else + host.pagesize_2k = 0; +#endif + if (host.pagesize_2k) { + pagesize = 2048; + blocksize = 128 * 1024; + } else { + pagesize = 512; + blocksize = 16 * 1024; + } + + host.base = (void __iomem *)IMX_NFC_BASE; + if (nfc_is_v21()) { + host.regs = host.base + 0x1000; + host.spare0 = host.base + 0x1000; + host.spare_len = 64; + } else if (nfc_is_v1()) { + host.regs = host.base; + host.spare0 = host.base + 0x800; + host.spare_len = 16; + } + + send_cmd(&host, NAND_CMD_RESET); + + /* preset operation */ + /* Unlock the internal RAM Buffer */ + writew(0x2, host.regs + NFC_CONFIG); + + /* Unlock Block Command for given address range */ + writew(0x4, host.regs + NFC_WRPROT); + + tmp = readw(host.regs + NFC_CONFIG1); + tmp |= NFC_ECC_EN; + if (nfc_is_v21()) + /* currently no support for 218 byte OOB with stronger ECC */ + tmp |= NFC_ECC_MODE; + tmp &= ~(NFC_SP_EN | NFC_INT_MSK); + writew(tmp, host.regs + NFC_CONFIG1); + + if (nfc_is_v21()) { + if (host.pagesize_2k) { + tmp = readw(host.regs + NFC_SPAS); + tmp &= 0xff00; + tmp |= NFC_SPAS_64; + writew(tmp, host.regs + NFC_SPAS); + } else { + tmp = readw(host.regs + NFC_SPAS); + tmp &= 0xff00; + tmp |= NFC_SPAS_16; + writew(tmp, host.regs + NFC_SPAS); + } + } + + block = page = 0; + + while (1) { + page = 0; + while (page * pagesize < blocksize) { + debug("page: %d block: %d dest: %p src " + "0x%08x\n", + page, block, dest, + block * blocksize + + page * pagesize); + + send_cmd(&host, NAND_CMD_READ0); + nfc_addr(&host, block * blocksize + + page * pagesize); + if (host.pagesize_2k) + send_cmd(&host, NAND_CMD_READSTART); + send_page(&host, NFC_OUTPUT); + page++; + + if (host.pagesize_2k) { + if ((readw(host.spare0) & 0xff) + != 0xff) + continue; + } else { + if ((readw(host.spare0 + 4) & 0xff00) + != 0xff00) + continue; + } + + __memcpy32(dest, host.base, pagesize); + dest += pagesize; + size -= pagesize; + + if (size <= 0) + return; + } + block++; + } +} +#define CONFIG_NAND_IMX_BOOT_DEBUG +#ifdef CONFIG_NAND_IMX_BOOT_DEBUG +#include + +static int do_nand_boot_test(struct command *cmdtp, int argc, char *argv[]) +{ + void *dest; + int size; + + if (argc < 3) + return COMMAND_ERROR_USAGE; + + dest = (void *)strtoul_suffix(argv[1], NULL, 0); + size = strtoul_suffix(argv[2], NULL, 0); + + imx_nand_load_image(dest, size); + + return 0; +} + +static const __maybe_unused char cmd_nand_boot_test_help[] = +"Usage: nand_boot_test \n" +"This command loads the booloader from the NAND memory like the reset\n" +"routine does. Its intended for development tests only"; + +BAREBOX_CMD_START(nand_boot_test) + .cmd = do_nand_boot_test, + .usage = "load bootloader from NAND", + BAREBOX_CMD_HELP(cmd_nand_boot_test_help) +BAREBOX_CMD_END +#endif + +#endif /* CONFIG_NAND_IMX_BOOT */ + +/* + * Main initialization routine + * @return 0 if successful; non-zero otherwise + */ +static int __init imx_nand_init(void) +{ + return register_driver(&imx_nand_driver); +} + +device_initcall(imx_nand_init); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC NAND MTD driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c new file mode 100644 index 0000000..1363808 --- /dev/null +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -0,0 +1,605 @@ +/** + * @file + * @brief Provide Generic GPMC NAND implementation for OMAP platforms + * + * FileName: arch/arm/mach-omap/gpmc_nand.c + * + * GPMC has a NAND controller inbuilt. This provides a generic implementation + * for board files to register a nand device. drivers/nand/nand_base.c takes + * care of identifing the type of device, size etc. + * + * A typical device registration is as follows: + * + * @code + * static struct device_d my_nand_device = { + * .name = "gpmc_nand", + * .id = some identifier you need to show.. e.g. "gpmc_nand0" + * .map_base = GPMC base address + * .size = GPMC address map size. + * .platform_data = platform data - required - explained below + * }; + * platform data required: + * static struct gpmc_nand_platform_data nand_plat = { + * .cs = give the chip select of the device + * .device_width = what is the width of the device 8 or 16? + * .max_timeout = delay desired for operation + * .wait_mon_pin = do you use wait monitoring? if so wait pin + * .plat_options = platform options. + * NAND_HWECC_ENABLE/DISABLE - hw ecc enable/disable + * NAND_WAITPOL_LOW/HIGH - wait pin polarity + * .oob = if you would like to replace oob with a custom OOB. + * .nand_setup = if you would like a special setup function to be called + * .priv = any params you'd like to save(e.g. like nand_setup to use) + *}; + * then in your code, you'd device_register(&my_nand_device); + * @endcode + * + * Note: + * @li Enable CONFIG_NAND_OMAP_GPMC_HWECC in menuconfig to get H/w ECC support + * @li You may choose to register two "devices" for the same CS to get BOTH + * hwecc and swecc devices. + * @li You can choose to have your own OOB definition for compliance with ROM + * code organization - only if you dont want to use NAND's default oob layout. + * see GPMC_NAND_ECC_LP_x8_LAYOUT etc.. + * + * @see gpmc_nand_platform_data + * @warning Remember to initialize GPMC before initializing the nand dev. + */ +/* + * (C) Copyright 2008 + * Texas Instruments, + * Nishanth Menon + * + * Based on: + * drivers/mtd/nand/omap2.c from linux kernel + * + * Copyright (c) 2004 Texas Instruments, Jian Zhang + * Copyright (c) 2004 Micron Technology Inc. + * Copyright (c) 2004 David Brownell + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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); + +/** internal structure maintained for nand information */ +struct gpmc_nand_info { + struct nand_hw_control controller; + struct device_d *pdev; + struct gpmc_nand_platform_data *pdata; + struct nand_chip nand; + struct mtd_info minfo; + int gpmc_cs; + void *gpmc_command; + void *gpmc_address; + void *gpmc_data; + unsigned long gpmc_base; + unsigned char wait_mon_mask; + uint64_t timeout; + unsigned inuse:1; + unsigned wait_pol:1; + unsigned char ecc_parity_pairs; + unsigned int ecc_config; +}; + +/* Typical BOOTROM oob layouts-requires hwecc **/ + +/** Large Page x8 NAND device Layout */ +static struct nand_ecclayout ecc_lp_x8 = { + .eccbytes = 12, + .eccpos = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, + .oobfree = { + { + .offset = 60, + .length = 2, + } + } +}; + +/** Large Page x16 NAND device Layout */ +static struct nand_ecclayout ecc_lp_x16 = { + .eccbytes = 12, + .eccpos = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, + .oobfree = { + { + .offset = 60, + .length = 2, + } + } +}; + +/** Small Page x8 NAND device Layout */ +static struct nand_ecclayout ecc_sp_x8 = { + .eccbytes = 3, + .eccpos = {1, 2, 3}, + .oobfree = { + { + .offset = 14, + .length = 2, + } + } +}; + +/** Small Page x16 NAND device Layout */ +static struct nand_ecclayout ecc_sp_x16 = { + .eccbytes = 3, + .eccpos = {2, 3, 4}, + .oobfree = { + { + .offset = 14, + .length = 2 } + } +}; + +/** + * @brief calls the platform specific dev_ready functionds + * + * @param mtd - mtd info structure + * + * @return + */ +static int omap_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); + uint64_t start = get_time_ns(); + unsigned long comp; + + gpmcnand_dbg("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"); + return -ETIMEDOUT; + } + /* if the wait is released, we are good to go */ + if (comp == + (readl(oinfo->gpmc_base + GPMC_STATUS) && + oinfo->wait_mon_mask)) + break; + } + return 0; +} + +/** + * @brief This function will enable or disable the Write Protect feature on + * NAND device. GPMC has a single WP bit for all CS devices.. + * + * @param oinfo omap nand info + * @param mode 0-disable else enable + * + * @return none + */ +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); + if (mode) + config &= ~(NAND_WP_BIT); /* WP is ON */ + else + config |= (NAND_WP_BIT); /* WP is OFF */ + + writel(config, oinfo->gpmc_base + GPMC_CFG); +} + +/** + * @brief respond to hw event change request + * + * MTD layer uses NAND_CTRL_CLE etc to control selection of the latch + * we hoodwink by changing the R and W registers according to the state + * we are requested. + * + * @param mtd - mtd info structure + * @param cmd command mtd layer is requesting + * + * @return none + */ +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, + cmd, ctrl); + switch (ctrl) { + case NAND_CTRL_CHANGE | NAND_CTRL_CLE: + nand->IO_ADDR_W = oinfo->gpmc_command; + nand->IO_ADDR_R = oinfo->gpmc_data; + break; + + case NAND_CTRL_CHANGE | NAND_CTRL_ALE: + nand->IO_ADDR_W = oinfo->gpmc_address; + nand->IO_ADDR_R = oinfo->gpmc_data; + break; + + case NAND_CTRL_CHANGE | NAND_NCE: + nand->IO_ADDR_W = oinfo->gpmc_data; + nand->IO_ADDR_R = oinfo->gpmc_data; + break; + } + + if (cmd != NAND_CMD_NONE) + writeb(cmd, nand->IO_ADDR_W); + return; +} + +/** + * @brief This function will generate true ECC value, which can be used + * when correcting data read from NAND flash memory core + * + * @param ecc_buf buffer to store ecc code + * + * @return re-formatted ECC value + */ +static unsigned int gen_true_ecc(u8 *ecc_buf) +{ + gpmcnand_dbg("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); +} + +/** + * @brief Compares the ecc read from nand spare area with ECC + * registers values and corrects one bit error if it has occured + * Further details can be had from OMAP TRM and the following selected links: + * http://en.wikipedia.org/wiki/Hamming_code + * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf + * + * @param mtd - mtd info structure + * @param dat page data + * @param read_ecc ecc readback + * @param calc_ecc calculated ecc (from reg) + * + * @return 0 if data is OK or corrected, else returns -1 + */ +static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + unsigned int orig_ecc, new_ecc, res, hm; + unsigned short parity_bits, byte; + unsigned char bit; + struct nand_chip *nand = (struct nand_chip *)(mtd->priv); + struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); + + gpmcnand_dbg("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; + } + } + 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); + /* 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); + break; + default: + gpmcnand_err("Error: Unrecognized Mode[%d]!\n", mode); + break; + } +} + +/** + * @brief nand device probe. + * + * @param pdev -matching device + * + * @return -failure reason or give 0 + */ +static int gpmc_nand_probe(struct device_d *pdev) +{ + struct gpmc_nand_info *oinfo; + struct gpmc_nand_platform_data *pdata; + struct nand_chip *nand; + struct mtd_info *minfo; + unsigned long cs_base; + 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"); + return -ENODEV; + } + + oinfo = calloc(1, sizeof(struct gpmc_nand_info)); + if (!oinfo) { + gpmcnand_err("oinfo alloc failed!\n"); + return -ENOMEM; + } + + /* fill up my data structures */ + oinfo->pdev = pdev; + oinfo->pdata = pdata; + pdev->platform_data = (void *)oinfo; + + nand = &oinfo->nand; + nand->priv = (void *)oinfo; + + minfo = &oinfo->minfo; + minfo->priv = (void *)nand; + + if (pdata->cs >= GPMC_NUM_CS) { + gpmcnand_err("Invalid CS!\n"); + err = -EINVAL; + goto out_release_mem; + } + /* Setup register specific data */ + oinfo->gpmc_cs = pdata->cs; + oinfo->gpmc_base = pdev->map_base; + cs_base = oinfo->gpmc_base + GPMC_CONFIG1_0 + + (pdata->cs * GPMC_CONFIG_CS_SIZE); + oinfo->gpmc_command = (void *)(cs_base + GPMC_CS_NAND_COMMAND); + oinfo->gpmc_address = (void *)(cs_base + GPMC_CS_NAND_ADDRESS); + oinfo->gpmc_data = (void *)(cs_base + GPMC_CS_NAND_DATA); + oinfo->timeout = pdata->max_timeout; + debug("GPMC Details:\n" + "GPMC BASE=%x\n" + "CMD=%x\n" + "ADDRESS=%x\n" + "DATA=%x\n" + "CS_BASE=%x\n", + oinfo->gpmc_base, oinfo->gpmc_command, + oinfo->gpmc_address, oinfo->gpmc_data, cs_base); + + /* If we are 16 bit dev, our gpmc config tells us that */ + if ((readl(cs_base) & 0x3000) == 0x1000) { + debug("16 bit dev\n"); + nand->options |= NAND_BUSWIDTH_16; + } + + /* Same data register for in and out */ + nand->IO_ADDR_W = nand->IO_ADDR_R = (void *)oinfo->gpmc_data; + /* + * If RDY/BSY line is connected to OMAP then use the omap ready + * function and the generic nand_wait function which reads the + * status register after monitoring the RDY/BSY line. Otherwise + * use a standard chip delay which is slightly more than tR + * (AC Timing) of the NAND device and read the status register + * until you get a failure or success + */ + if (pdata->wait_mon_pin > 4) { + gpmcnand_err("Invalid wait monitoring pin\n"); + err = -EINVAL; + goto out_release_mem; + } + if (pdata->wait_mon_pin) { + /* Set up the wait monitoring mask + * This is GPMC_STATUS reg relevant */ + oinfo->wait_mon_mask = (0x1 << (pdata->wait_mon_pin - 1)) << 8; + oinfo->wait_pol = (pdata->plat_options & NAND_WAITPOL_MASK); + nand->dev_ready = omap_dev_ready; + nand->chip_delay = 0; + } else { + /* use the default nand_wait function */ + nand->chip_delay = 50; + } + + /* Use default cmdfunc */ + /* nand cmd control */ + nand->cmd_ctrl = omap_hwcontrol; + + /* Dont do a bbt scan at the start */ + nand->options |= NAND_SKIP_BBTSCAN; + + /* State my controller */ + nand->controller = &oinfo->controller; + + if (pdata->plat_options & NAND_HWECC_ENABLE) { + /* 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; + + /* All information is ready.. now lets call setup, if present */ + if (pdata->nand_setup) { + err = pdata->nand_setup(pdata); + if (err) { + gpmcnand_err("pdataform setup failed\n"); + goto out_release_mem; + } + } + /* Remove write protection */ + gpmc_nand_wp(oinfo, 0); + + /* we do not know what state of device we have is, so + * Send a reset to the device + * 8 bit write will work on 16 and 8 bit devices + */ + writeb(NAND_CMD_RESET, oinfo->gpmc_command); + mdelay(1); + + /* first scan to find the device and get the page size */ + if (nand_scan_ident(minfo, 1)) { + err = -ENXIO; + goto out_release_mem; + } + + switch (pdata->device_width) { + case 8: + lsp = &ecc_sp_x8; + llp = &ecc_lp_x8; + break; + case 16: + lsp = &ecc_sp_x16; + llp = &ecc_lp_x16; + break; + default: + err = -EINVAL; + goto out_release_mem; + } + + switch (minfo->writesize) { + case 512: + layout = lsp; + break; + case 2048: + layout = llp; + break; + default: + err = -EINVAL; + goto out_release_mem; + } + + /* second phase scan */ + if (nand_scan_tail(minfo)) { + err = -ENXIO; + goto out_release_mem; + } + + if (pdata->plat_options & NAND_HWECC_ENABLE) + nand->ecc.layout = layout; + + /* We are all set to register with the system now! */ + err = add_mtd_device(minfo); + if (err) { + gpmcnand_err("device registration failed\n"); + goto out_release_mem; + } + return 0; + +out_release_mem: + if (oinfo) + free(oinfo); + + gpmcnand_err("Failed!!\n"); + return err; +} + +/** GMPC nand driver -> device registered by platforms */ +static struct driver_d gpmc_nand_driver = { + .name = "gpmc_nand", + .probe = gpmc_nand_probe, +}; + +static int gpmc_nand_init(void) +{ + return register_driver(&gpmc_nand_driver); +} + +device_initcall(gpmc_nand_init); diff --git a/drivers/mtd/nand/nand_s3c2410.c b/drivers/mtd/nand/nand_s3c2410.c new file mode 100644 index 0000000..b989583 --- /dev/null +++ b/drivers/mtd/nand/nand_s3c2410.c @@ -0,0 +1,525 @@ +/* linux/drivers/mtd/nand/s3c2410.c + * + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * Copyright © 2004-2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks + * + * Samsung S3C2410 NAND driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_S3C24XX_NAND_BOOT +# define __nand_boot_init __bare_init +# ifndef BOARD_DEFAULT_NAND_TIMING +# define BOARD_DEFAULT_NAND_TIMING 0x0737 +# endif +#else +# define __nand_boot_init +#endif + +/** + * Define this symbol for testing purpose. It will add a command to read an + * image from the NAND like it the boot strap code will do. + */ +#define CONFIG_NAND_S3C24XX_BOOT_DEBUG + +/* NAND controller's register */ + +#define NFCONF 0x00 + +#ifdef CONFIG_CPU_S3C2410 + +#define NFCMD 0x04 +#define NFADDR 0x08 +#define NFDATA 0x0c +#define NFSTAT 0x10 +#define NFECC 0x14 + +/* S3C2410 specific bits */ +#define NFSTAT_BUSY (1) +#define NFCONF_nFCE (1 << 11) +#define NFCONF_INITECC (1 << 12) +#define NFCONF_EN (1 << 15) + +#endif /* CONFIG_CPU_S3C2410 */ + +#ifdef CONFIG_CPU_S3C2440 + +#define NFCONT 0x04 +#define NFCMD 0x08 +#define NFADDR 0x0C +#define NFDATA 0x10 + +#define NFECC 0x1C +#define NFSTAT 0x20 + +/* S3C2440 specific bits */ +#define NFSTAT_BUSY (1) +#define NFCONT_nFCE (1 << 1) +#define NFCONF_INITECC (1 << 12) +#define NFCONT_EN (1) + +#endif /* CONFIG_CPU_S3C2440 */ + + +struct s3c24x0_nand_host { + struct mtd_info mtd; + struct nand_chip nand; + struct mtd_partition *parts; + struct device_d *dev; + + unsigned long base; +}; + +/** + * oob placement block for use with hardware ecc generation + */ +static struct nand_ecclayout nand_hw_eccoob = { + .eccbytes = 3, + .eccpos = { 0, 1, 2}, + .oobfree = { + { + .offset = 8, + .length = 8 + } + } +}; + +/* - Functions shared between the boot strap code and the regular driver - */ + +/** + * Issue the specified command to the NAND device + * @param[in] host Base address of the NAND controller + * @param[in] cmd Command for NAND flash + */ +static void __nand_boot_init send_cmd(unsigned long host, uint8_t cmd) +{ + writeb(cmd, host + NFCMD); +} + +/** + * Issue the specified address to the NAND device + * @param[in] host Base address of the NAND controller + * @param[in] addr Address for the NAND flash + */ +static void __nand_boot_init send_addr(unsigned long host, uint8_t addr) +{ + writeb(addr, host + NFADDR); +} + +/** + * Enable the NAND flash access + * @param[in] host Base address of the NAND controller + */ +static void __nand_boot_init enable_cs(unsigned long host) +{ +#ifdef CONFIG_CPU_S3C2410 + writew(readw(host + NFCONF) & ~NFCONF_nFCE, host + NFCONF); +#endif +#ifdef CONFIG_CPU_S3C2440 + writew(readw(host + NFCONT) & ~NFCONT_nFCE, host + NFCONT); +#endif +} + +/** + * Disable the NAND flash access + * @param[in] host Base address of the NAND controller + */ +static void __nand_boot_init disable_cs(unsigned long host) +{ +#ifdef CONFIG_CPU_S3C2410 + writew(readw(host + NFCONF) | NFCONF_nFCE, host + NFCONF); +#endif +#ifdef CONFIG_CPU_S3C2440 + writew(readw(host + NFCONT) | NFCONT_nFCE, host + NFCONT); +#endif +} + +/** + * Enable the NAND flash controller + * @param[in] host Base address of the NAND controller + * @param[in] timing Timing to access the NAND memory + */ +static void __nand_boot_init enable_nand_controller(unsigned long host, uint32_t timing) +{ +#ifdef CONFIG_CPU_S3C2410 + writew(timing + NFCONF_EN + NFCONF_nFCE, host + NFCONF); +#endif +#ifdef CONFIG_CPU_S3C2440 + writew(NFCONT_EN + NFCONT_nFCE, host + NFCONT); + writew(timing, host + NFCONF); +#endif +} + +/** + * Diable the NAND flash controller + * @param[in] host Base address of the NAND controller + */ +static void __nand_boot_init disable_nand_controller(unsigned long host) +{ +#ifdef CONFIG_CPU_S3C2410 + writew(NFCONF_nFCE, host + NFCONF); +#endif +#ifdef CONFIG_CPU_S3C2440 + writew(NFCONT_nFCE, host + NFCONT); +#endif +} + +/* ----------------------------------------------------------------------- */ + +/** + * Check the ECC and try to repair the data if possible + * @param[in] mtd_info FIXME + * @param[inout] dat Pointer to the data buffer that might contain a bit error + * @param[in] read_ecc ECC data from the OOB space + * @param[in] calc_ecc ECC data calculated from the data + * @return 0 no error, 1 repaired error, -1 no way... + * + * @note: Alsways 512 byte of data + */ +static int s3c2410_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, + uint8_t *read_ecc, uint8_t *calc_ecc) +{ + unsigned int diff0, diff1, diff2; + unsigned int bit, byte; + + diff0 = read_ecc[0] ^ calc_ecc[0]; + diff1 = read_ecc[1] ^ calc_ecc[1]; + diff2 = read_ecc[2] ^ calc_ecc[2]; + + if (diff0 == 0 && diff1 == 0 && diff2 == 0) + return 0; /* ECC is ok */ + + /* sometimes people do not think about using the ECC, so check + * to see if we have an 0xff,0xff,0xff read ECC and then ignore + * the error, on the assumption that this is an un-eccd page. + */ + if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff + /* && info->platform->ignore_unset_ecc */) + return 0; + + /* Can we correct this ECC (ie, one row and column change). + * Note, this is similar to the 256 error code on smartmedia */ + + if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 && + ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 && + ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) { + /* calculate the bit position of the error */ + + bit = ((diff2 >> 3) & 1) | + ((diff2 >> 4) & 2) | + ((diff2 >> 5) & 4); + + /* calculate the byte position of the error */ + + byte = ((diff2 << 7) & 0x100) | + ((diff1 << 0) & 0x80) | + ((diff1 << 1) & 0x40) | + ((diff1 << 2) & 0x20) | + ((diff1 << 3) & 0x10) | + ((diff0 >> 4) & 0x08) | + ((diff0 >> 3) & 0x04) | + ((diff0 >> 2) & 0x02) | + ((diff0 >> 1) & 0x01); + + dat[byte] ^= (1 << bit); + return 1; + } + + /* if there is only one bit difference in the ECC, then + * one of only a row or column parity has changed, which + * means the error is most probably in the ECC itself */ + + diff0 |= (diff1 << 8); + diff0 |= (diff2 << 16); + + if ((diff0 & ~(1<priv; + struct s3c24x0_nand_host *host = nand_chip->priv; + + writel(readl(host->base + NFCONF) | NFCONF_INITECC , host->base + NFCONF); +} + +static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) +{ + struct nand_chip *nand_chip = mtd->priv; + struct s3c24x0_nand_host *host = nand_chip->priv; + + ecc_code[0] = readb(host->base + NFECC); + ecc_code[1] = readb(host->base + NFECC + 1); + ecc_code[2] = readb(host->base + NFECC + 2); + + return 0; +} + +static void s3c24x0_nand_select_chip(struct mtd_info *mtd, int chip) +{ + struct nand_chip *nand_chip = mtd->priv; + struct s3c24x0_nand_host *host = nand_chip->priv; + + if (chip == -1) + disable_cs(host->base); + else + enable_cs(host->base); +} + +static int s3c24x0_nand_devready(struct mtd_info *mtd) +{ + struct nand_chip *nand_chip = mtd->priv; + struct s3c24x0_nand_host *host = nand_chip->priv; + + return readw(host->base + NFSTAT) & NFSTAT_BUSY; +} + +static void s3c24x0_nand_hwcontrol(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *nand_chip = mtd->priv; + struct s3c24x0_nand_host *host = nand_chip->priv; + + if (cmd == NAND_CMD_NONE) + return; + /* + * If the CLE should be active, this call is a NAND command + */ + if (ctrl & NAND_CLE) + send_cmd(host->base, cmd); + /* + * If the ALE should be active, this call is a NAND address + */ + if (ctrl & NAND_ALE) + send_addr(host->base, cmd); +} + +static int s3c24x0_nand_inithw(struct s3c24x0_nand_host *host) +{ + struct s3c24x0_nand_platform_data *pdata = host->dev->platform_data; + uint32_t tmp; + + /* reset the NAND controller */ + disable_nand_controller(host->base); + + if (pdata != NULL) + tmp = pdata->nand_timing; + else + /* else slowest possible timing */ + tmp = CALC_NFCONF_TIMING(4, 8, 8); + + /* reenable the NAND controller */ + enable_nand_controller(host->base, tmp); + + return 0; +} + +static int s3c24x0_nand_probe(struct device_d *dev) +{ + struct nand_chip *chip; + struct mtd_info *mtd; + struct s3c24x0_nand_host *host; + int ret; + + /* Allocate memory for MTD device structure and private data */ + host = kzalloc(sizeof(struct s3c24x0_nand_host), GFP_KERNEL); + if (!host) + return -ENOMEM; + + host->dev = dev; + host->base = dev->map_base; + + /* structures must be linked */ + chip = &host->nand; + mtd = &host->mtd; + mtd->priv = chip; + + /* init the default settings */ +#if 0 + /* TODO: Will follow later */ + init_nand_chip_bw8(chip); +#endif + /* 50 us command delay time */ + chip->chip_delay = 50; + chip->priv = host; + + chip->IO_ADDR_R = chip->IO_ADDR_W = (void*)(dev->map_base + NFDATA); + + chip->cmd_ctrl = s3c24x0_nand_hwcontrol; + chip->dev_ready = s3c24x0_nand_devready; + chip->select_chip = s3c24x0_nand_select_chip; + + /* we are using the hardware ECC feature of this device */ + chip->ecc.calculate = s3c2410_nand_calculate_ecc; + chip->ecc.correct = s3c2410_nand_correct_data; + chip->ecc.hwctl = s3c2410_nand_enable_hwecc; + chip->ecc.calculate = s3c2410_nand_calculate_ecc; + + /* our hardware capabilities */ + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.size = 512; + chip->ecc.bytes = 3; + chip->ecc.layout = &nand_hw_eccoob; + + ret = s3c24x0_nand_inithw(host); + if (ret != 0) + goto on_error; + + /* Scan to find existence of the device */ + ret = nand_scan(mtd, 1); + if (ret != 0) { + ret = -ENXIO; + goto on_error; + } + + return add_mtd_device(mtd); + +on_error: + free(host); + return ret; +} + +static struct driver_d s3c24x0_nand_driver = { + .name = "s3c24x0_nand", + .probe = s3c24x0_nand_probe, +}; + +#ifdef CONFIG_S3C24XX_NAND_BOOT + +static void __nand_boot_init wait_for_completion(unsigned long host) +{ + while (!(readw(host + NFSTAT) & NFSTAT_BUSY)) + ; +} + +static void __nand_boot_init nfc_addr(unsigned long host, uint32_t offs) +{ + send_addr(host, offs & 0xff); + send_addr(host, (offs >> 9) & 0xff); + send_addr(host, (offs >> 17) & 0xff); + send_addr(host, (offs >> 25) & 0xff); +} + +/** + * Load a sequential count of blocks from the NAND into memory + * @param[out] dest Pointer to target area (in SDRAM) + * @param[in] size Bytes to read from NAND device + * @param[in] page Start page to read from + * @param[in] pagesize Size of each page in the NAND + * + * This function must be located in the first 4kiB of the barebox image + * (guess why). When this routine is running the SDRAM is up and running + * and it runs from the correct address (physical=linked address). + * TODO Could we access the platform data from the boardfile? + * Due to it makes no sense this function does not return in case of failure. + */ +void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page, int pagesize) +{ + unsigned long host = S3C24X0_NAND_BASE; + int i; + + /* + * Reenable the NFC and use the default (but slow) access + * timing or the board specific setting if provided. + */ + enable_nand_controller(host, BOARD_DEFAULT_NAND_TIMING); + enable_cs(host); + + /* Reset the NAND device */ + send_cmd(host, NAND_CMD_RESET); + wait_for_completion(host); + disable_cs(host); + + do { + enable_cs(host); + send_cmd(host, NAND_CMD_READ0); + nfc_addr(host, page * pagesize); + wait_for_completion(host); + /* copy one page (do *not* use readsb() here!)*/ + for (i = 0; i < pagesize; i++) + writeb(readb(host + NFDATA), (unsigned long)(dest + i)); + disable_cs(host); + + page++; + dest += pagesize; + size -= pagesize; + } while (size >= 0); + + /* disable the controller again */ + disable_nand_controller(host); +} + +#ifdef CONFIG_NAND_S3C24XX_BOOT_DEBUG +#include + +static int do_nand_boot_test(struct command *cmdtp, int argc, char *argv[]) +{ + void *dest; + int size, pagesize; + + if (argc < 3) + return COMMAND_ERROR_USAGE; + + dest = (void *)strtoul_suffix(argv[1], NULL, 0); + size = strtoul_suffix(argv[2], NULL, 0); + pagesize = strtoul_suffix(argv[3], NULL, 0); + + s3c24x0_nand_load_image(dest, size, 0, pagesize); + + return 0; +} + +static const __maybe_unused char cmd_nand_boot_test_help[] = +"Usage: nand_boot_test \n"; + +BAREBOX_CMD_START(nand_boot_test) + .cmd = do_nand_boot_test, + .usage = "load an image from NAND", + BAREBOX_CMD_HELP(cmd_nand_boot_test_help) +BAREBOX_CMD_END +#endif + +#endif /* CONFIG_S3C24XX_NAND_BOOT */ + +/* + * Main initialization routine + * @return 0 if successful; non-zero otherwise + */ +static int __init s3c24x0_nand_init(void) +{ + return register_driver(&s3c24x0_nand_driver); +} + +device_initcall(s3c24x0_nand_init); diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c new file mode 100644 index 0000000..d57294e --- /dev/null +++ b/drivers/mtd/nand/nand_util.c @@ -0,0 +1,858 @@ +/* + * drivers/nand/nand_util.c + * + * Copyright (C) 2006 by Weiss-Electronic GmbH. + * All rights reserved. + * + * @author: Guido Classen + * @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 +#include +#include +#include + +#include +//#include + +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/partition.c b/drivers/mtd/partition.c new file mode 100644 index 0000000..df2eb40 --- /dev/null +++ b/drivers/mtd/partition.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include + +struct mtd_part { + struct mtd_info mtd; + struct mtd_info *master; + uint64_t offset; + struct list_head list; +}; + +#define PART(x) ((struct mtd_part *)(x)) + +static int mtd_part_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + struct mtd_ecc_stats stats; + int res; + + stats = part->master->ecc_stats; + + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + res = part->master->read(part->master, from + part->offset, + len, retlen, buf); + return res; +} + +static int mtd_part_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_part *part = PART(mtd); + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->write(part->master, to + part->offset, + len, retlen, buf); +} + +static int mtd_part_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct mtd_part *part = PART(mtd); + int ret; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (instr->addr >= mtd->size) + return -EINVAL; + instr->addr += part->offset; + ret = part->master->erase(part->master, instr); + if (ret) { + if (instr->fail_addr != 0xffffffff) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; + } + return ret; +} + +static int mtd_part_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_part *part = PART(mtd); + if (ofs >= mtd->size) + return -EINVAL; + ofs += part->offset; + return part->master->block_isbad(part->master, ofs); +} + +static int mtd_part_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + struct mtd_part *part = PART(mtd); + int res; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (ofs >= mtd->size) + return -EINVAL; + ofs += part->offset; + res = part->master->block_markbad(part->master, ofs); + if (!res) + mtd->ecc_stats.badblocks++; + return res; +} + +struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t size, + unsigned long flags, const char *name) +{ + struct mtd_part *slave; + struct mtd_info *slave_mtd; + int start = 0, end = 0, i; + + slave = xzalloc(sizeof(*slave)); + slave_mtd = &slave->mtd; + + memcpy(slave_mtd, mtd, sizeof(*slave)); + + /* + * find the number of eraseregions the partition includes. + * Do not bother to create the mtd_erase_region_infos as + * ubi is only interested in its number. UBI does not + * yet support multiple erase regions. + */ + for (i = mtd->numeraseregions - 1; i >= 0; i--) { + struct mtd_erase_region_info *region = &mtd->eraseregions[i]; + if (offset >= region->offset && + offset < region->offset + region->erasesize * region->numblocks) + start = i; + if (offset + size >= region->offset && + offset + size <= region->offset + region->erasesize * region->numblocks) + end = i; + } + + slave_mtd->numeraseregions = end - start; + + slave_mtd->read = mtd_part_read; + slave_mtd->write = mtd_part_write; + slave_mtd->erase = mtd_part_erase; + slave_mtd->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; + slave_mtd->block_markbad = mtd->block_markbad ? mtd_part_block_markbad : NULL; + slave_mtd->size = size; + slave_mtd->name = strdup(name); + + slave->offset = offset; + slave->master = mtd; + + return slave_mtd; +} + +void mtd_del_partition(struct mtd_info *mtd) +{ + struct mtd_part *part = PART(mtd); + + free(mtd->name); + free(part); +} diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig new file mode 100644 index 0000000..35d321b --- /dev/null +++ b/drivers/mtd/ubi/Kconfig @@ -0,0 +1,6 @@ +config UBI + bool "UBI support " + select PARTITION_NEED_MTD + help + This enables support for UBI (unsorted block images) + diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile new file mode 100644 index 0000000..cef1141 --- /dev/null +++ b/drivers/mtd/ubi/Makefile @@ -0,0 +1,3 @@ +obj-y += build.o vtbl.o vmt.o upd.o kapi.o eba.o io.o wl.o scan.o misc.o debug.o cdev.o + + diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c new file mode 100644 index 0000000..a59972f --- /dev/null +++ b/drivers/mtd/ubi/build.c @@ -0,0 +1,1059 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Nokia Corporation, 2007 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём), + * Frank Haverkamp + */ + +/* + * This file includes UBI initialization and building of UBI devices. + * + * When UBI is initialized, it attaches all the MTD devices specified as the + * module load parameters or the kernel boot parameters. If MTD devices were + * specified, UBI does not attach any MTD device, but it is possible to do + * later using the "UBI control device". + * + * At the moment we only attach UBI devices by scanning, which will become a + * bottleneck when flashes reach certain large size. Then one may improve UBI + * and add other methods, although it does not seem to be easy to do. + */ + +#ifdef UBI_LINUX +#include +#include +#include +#include +#include +#include +#include +#include +#endif +#include "ubi-barebox.h" +#include "ubi.h" + +/* Maximum length of the 'mtd=' parameter */ +#define MTD_PARAM_LEN_MAX 64 + +/** + * struct mtd_dev_param - MTD device parameter description data structure. + * @name: MTD device name or number string + * @vid_hdr_offs: VID header offset + */ +struct mtd_dev_param +{ + char name[MTD_PARAM_LEN_MAX]; + int vid_hdr_offs; +}; + +/* Numbers of elements set in the @mtd_dev_param array */ +static int mtd_devs = 0; + +/* MTD devices specification parameters */ +static struct mtd_dev_param mtd_dev_param[UBI_MAX_DEVICES]; + +/* Root UBI "class" object (corresponds to '//class/ubi/') */ +struct class *ubi_class; + +#ifdef UBI_LINUX +/* Slab cache for wear-leveling entries */ +struct kmem_cache *ubi_wl_entry_slab; + +/* UBI control character device */ +static struct miscdevice ubi_ctrl_cdev = { + .minor = MISC_DYNAMIC_MINOR, + .name = "ubi_ctrl", + .fops = &ubi_ctrl_cdev_operations, +}; +#endif + +/* All UBI devices in system */ +struct ubi_device *ubi_devices[UBI_MAX_DEVICES]; + +#ifdef UBI_LINUX +/* Serializes UBI devices creations and removals */ +DEFINE_MUTEX(ubi_devices_mutex); + +/* Protects @ubi_devices and @ubi->ref_count */ +static DEFINE_SPINLOCK(ubi_devices_lock); + +/* "Show" method for files in '//class/ubi/' */ +static ssize_t ubi_version_show(struct class *class, char *buf) +{ + return sprintf(buf, "%d\n", UBI_VERSION); +} + +/* UBI version attribute ('//class/ubi/version') */ +static struct class_attribute ubi_version = + __ATTR(version, S_IRUGO, ubi_version_show, NULL); + +static ssize_t dev_attribute_show(struct device *dev, + struct device_attribute *attr, char *buf); + +/* UBI device attributes (correspond to files in '//class/ubi/ubiX') */ +static struct device_attribute dev_eraseblock_size = + __ATTR(eraseblock_size, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_avail_eraseblocks = + __ATTR(avail_eraseblocks, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_total_eraseblocks = + __ATTR(total_eraseblocks, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_volumes_count = + __ATTR(volumes_count, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_max_ec = + __ATTR(max_ec, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_reserved_for_bad = + __ATTR(reserved_for_bad, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_bad_peb_count = + __ATTR(bad_peb_count, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_max_vol_count = + __ATTR(max_vol_count, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_min_io_size = + __ATTR(min_io_size, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_bgt_enabled = + __ATTR(bgt_enabled, S_IRUGO, dev_attribute_show, NULL); +static struct device_attribute dev_mtd_num = + __ATTR(mtd_num, S_IRUGO, dev_attribute_show, NULL); +#endif + +/** + * ubi_get_device - get UBI device. + * @ubi_num: UBI device number + * + * This function returns UBI device description object for UBI device number + * @ubi_num, or %NULL if the device does not exist. This function increases the + * device reference count to prevent removal of the device. In other words, the + * device cannot be removed if its reference count is not zero. + */ +struct ubi_device *ubi_get_device(int ubi_num) +{ + struct ubi_device *ubi; + + spin_lock(&ubi_devices_lock); + ubi = ubi_devices[ubi_num]; + if (ubi) { + ubi_assert(ubi->ref_count >= 0); + ubi->ref_count += 1; + get_device(&ubi->dev); + } + spin_unlock(&ubi_devices_lock); + + return ubi; +} + +/** + * ubi_put_device - drop an UBI device reference. + * @ubi: UBI device description object + */ +void ubi_put_device(struct ubi_device *ubi) +{ + spin_lock(&ubi_devices_lock); + ubi->ref_count -= 1; + put_device(&ubi->dev); + spin_unlock(&ubi_devices_lock); +} + +/** + * ubi_get_by_major - get UBI device description object by character device + * major number. + * @major: major number + * + * This function is similar to 'ubi_get_device()', but it searches the device + * by its major number. + */ +struct ubi_device *ubi_get_by_major(int major) +{ + int i; + struct ubi_device *ubi; + + spin_lock(&ubi_devices_lock); + for (i = 0; i < UBI_MAX_DEVICES; i++) { + ubi = ubi_devices[i]; + if (ubi && MAJOR(ubi->cdev.dev) == major) { + ubi_assert(ubi->ref_count >= 0); + ubi->ref_count += 1; + get_device(&ubi->dev); + spin_unlock(&ubi_devices_lock); + return ubi; + } + } + spin_unlock(&ubi_devices_lock); + + return NULL; +} + +/** + * ubi_major2num - get UBI device number by character device major number. + * @major: major number + * + * This function searches UBI device number object by its major number. If UBI + * device was not found, this function returns -ENODEV, otherwise the UBI device + * number is returned. + */ +int ubi_major2num(int major) +{ + int i, ubi_num = -ENODEV; + + spin_lock(&ubi_devices_lock); + for (i = 0; i < UBI_MAX_DEVICES; i++) { + struct ubi_device *ubi = ubi_devices[i]; + + if (ubi && MAJOR(ubi->cdev.dev) == major) { + ubi_num = ubi->ubi_num; + break; + } + } + spin_unlock(&ubi_devices_lock); + + return ubi_num; +} + +#ifdef UBI_LINUX +/* "Show" method for files in '//class/ubi/ubiX/' */ +static ssize_t dev_attribute_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + ssize_t ret; + struct ubi_device *ubi; + + /* + * The below code looks weird, but it actually makes sense. We get the + * UBI device reference from the contained 'struct ubi_device'. But it + * is unclear if the device was removed or not yet. Indeed, if the + * device was removed before we increased its reference count, + * 'ubi_get_device()' will return -ENODEV and we fail. + * + * Remember, 'struct ubi_device' is freed in the release function, so + * we still can use 'ubi->ubi_num'. + */ + ubi = container_of(dev, struct ubi_device, dev); + ubi = ubi_get_device(ubi->ubi_num); + if (!ubi) + return -ENODEV; + + if (attr == &dev_eraseblock_size) + ret = sprintf(buf, "%d\n", ubi->leb_size); + else if (attr == &dev_avail_eraseblocks) + ret = sprintf(buf, "%d\n", ubi->avail_pebs); + else if (attr == &dev_total_eraseblocks) + ret = sprintf(buf, "%d\n", ubi->good_peb_count); + else if (attr == &dev_volumes_count) + ret = sprintf(buf, "%d\n", ubi->vol_count - UBI_INT_VOL_COUNT); + else if (attr == &dev_max_ec) + ret = sprintf(buf, "%d\n", ubi->max_ec); + else if (attr == &dev_reserved_for_bad) + ret = sprintf(buf, "%d\n", ubi->beb_rsvd_pebs); + else if (attr == &dev_bad_peb_count) + ret = sprintf(buf, "%d\n", ubi->bad_peb_count); + else if (attr == &dev_max_vol_count) + ret = sprintf(buf, "%d\n", ubi->vtbl_slots); + else if (attr == &dev_min_io_size) + ret = sprintf(buf, "%d\n", ubi->min_io_size); + else if (attr == &dev_bgt_enabled) + ret = sprintf(buf, "%d\n", ubi->thread_enabled); + else if (attr == &dev_mtd_num) + ret = sprintf(buf, "%d\n", ubi->mtd->index); + else + ret = -EINVAL; + + ubi_put_device(ubi); + return ret; +} + +/* Fake "release" method for UBI devices */ +static void dev_release(struct device *dev) { } + +/** + * ubi_sysfs_init - initialize sysfs for an UBI device. + * @ubi: UBI device description object + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +static int ubi_sysfs_init(struct ubi_device *ubi) +{ + int err; + + ubi->dev.release = dev_release; + ubi->dev.devt = ubi->cdev.dev; + ubi->dev.class = ubi_class; + sprintf(&ubi->dev.bus_id[0], UBI_NAME_STR"%d", ubi->ubi_num); + err = device_register(&ubi->dev); + if (err) + return err; + + err = device_create_file(&ubi->dev, &dev_eraseblock_size); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_avail_eraseblocks); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_total_eraseblocks); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_volumes_count); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_max_ec); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_reserved_for_bad); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_bad_peb_count); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_max_vol_count); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_min_io_size); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_bgt_enabled); + if (err) + return err; + err = device_create_file(&ubi->dev, &dev_mtd_num); + return err; +} + +/** + * ubi_sysfs_close - close sysfs for an UBI device. + * @ubi: UBI device description object + */ +static void ubi_sysfs_close(struct ubi_device *ubi) +{ + device_remove_file(&ubi->dev, &dev_mtd_num); + device_remove_file(&ubi->dev, &dev_bgt_enabled); + device_remove_file(&ubi->dev, &dev_min_io_size); + device_remove_file(&ubi->dev, &dev_max_vol_count); + device_remove_file(&ubi->dev, &dev_bad_peb_count); + device_remove_file(&ubi->dev, &dev_reserved_for_bad); + device_remove_file(&ubi->dev, &dev_max_ec); + device_remove_file(&ubi->dev, &dev_volumes_count); + device_remove_file(&ubi->dev, &dev_total_eraseblocks); + device_remove_file(&ubi->dev, &dev_avail_eraseblocks); + device_remove_file(&ubi->dev, &dev_eraseblock_size); + device_unregister(&ubi->dev); +} +#endif + +/** + * kill_volumes - destroy all volumes. + * @ubi: UBI device description object + */ +static void kill_volumes(struct ubi_device *ubi) +{ + int i; + + for (i = 0; i < ubi->vtbl_slots; i++) + if (ubi->volumes[i]) + ubi_free_volume(ubi, ubi->volumes[i]); +} + +/** + * uif_init - initialize user interfaces for an UBI device. + * @ubi: UBI device description object + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +static int uif_init(struct ubi_device *ubi) +{ + int i, err; +#ifdef UBI_LINUX + dev_t dev; +#endif + + sprintf(ubi->ubi_name, UBI_NAME_STR "%d", ubi->ubi_num); + + /* + * Major numbers for the UBI character devices are allocated + * dynamically. Major numbers of volume character devices are + * equivalent to ones of the corresponding UBI character device. Minor + * numbers of UBI character devices are 0, while minor numbers of + * volume character devices start from 1. Thus, we allocate one major + * number and ubi->vtbl_slots + 1 minor numbers. + */ + err = alloc_chrdev_region(&dev, 0, ubi->vtbl_slots + 1, ubi->ubi_name); + if (err) { + ubi_err("cannot register UBI character devices"); + return err; + } + + ubi_assert(MINOR(dev) == 0); + cdev_init(&ubi->cdev, &ubi_cdev_operations); + dbg_msg("%s major is %u", ubi->ubi_name, MAJOR(dev)); +#ifdef UBI_LINUX + ubi->cdev.owner = THIS_MODULE; +#endif + err = ubi_cdev_add(ubi); + if (err) { + ubi_err("cannot add character device"); + goto out_unreg; + } + + err = ubi_sysfs_init(ubi); + if (err) + goto out_sysfs; + + for (i = 0; i < ubi->vtbl_slots; i++) + if (ubi->volumes[i]) { + err = ubi_add_volume(ubi, ubi->volumes[i]); + if (err) { + ubi_err("cannot add volume %d", i); + goto out_volumes; + } + } + + return 0; + +out_volumes: + kill_volumes(ubi); +out_sysfs: + ubi_sysfs_close(ubi); + ubi_cdev_remove(ubi); +out_unreg: + unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); + ubi_err("cannot initialize UBI %s, error %d", ubi->ubi_name, err); + return err; +} + +/** + * uif_close - close user interfaces for an UBI device. + * @ubi: UBI device description object + */ +static void uif_close(struct ubi_device *ubi) +{ + kill_volumes(ubi); + ubi_sysfs_close(ubi); + ubi_cdev_remove(ubi); + unregister_chrdev_region(ubi->cdev.dev, ubi->vtbl_slots + 1); +} + +/** + * attach_by_scanning - attach an MTD device using scanning method. + * @ubi: UBI device descriptor + * + * This function returns zero in case of success and a negative error code in + * case of failure. + * + * Note, currently this is the only method to attach UBI devices. Hopefully in + * the future we'll have more scalable attaching methods and avoid full media + * scanning. But even in this case scanning will be needed as a fall-back + * attaching method if there are some on-flash table corruptions. + */ +static int attach_by_scanning(struct ubi_device *ubi) +{ + int err; + struct ubi_scan_info *si; + + si = ubi_scan(ubi); + if (IS_ERR(si)) + return PTR_ERR(si); + + ubi->bad_peb_count = si->bad_peb_count; + ubi->good_peb_count = ubi->peb_count - ubi->bad_peb_count; + ubi->max_ec = si->max_ec; + ubi->mean_ec = si->mean_ec; + + err = ubi_read_volume_table(ubi, si); + if (err) + goto out_si; + + err = ubi_wl_init_scan(ubi, si); + if (err) + goto out_vtbl; + + err = ubi_eba_init_scan(ubi, si); + if (err) + goto out_wl; + + ubi_scan_destroy_si(si); + return 0; + +out_wl: + ubi_wl_close(ubi); +out_vtbl: + vfree(ubi->vtbl); +out_si: + ubi_scan_destroy_si(si); + return err; +} + +/** + * io_init - initialize I/O unit for a given UBI device. + * @ubi: UBI device description object + * + * If @ubi->vid_hdr_offset or @ubi->leb_start is zero, default offsets are + * assumed: + * o EC header is always at offset zero - this cannot be changed; + * o VID header starts just after the EC header at the closest address + * aligned to @io->hdrs_min_io_size; + * o data starts just after the VID header at the closest address aligned to + * @io->min_io_size + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +static int io_init(struct ubi_device *ubi) +{ + if (ubi->mtd->numeraseregions != 0) { + /* + * Some flashes have several erase regions. Different regions + * may have different eraseblock size and other + * characteristics. It looks like mostly multi-region flashes + * have one "main" region and one or more small regions to + * store boot loader code or boot parameters or whatever. I + * guess we should just pick the largest region. But this is + * not implemented. + */ + ubi_err("multiple regions, not implemented"); + return -EINVAL; + } + + if (ubi->vid_hdr_offset < 0) + return -EINVAL; + + /* + * Note, in this implementation we support MTD devices with 0x7FFFFFFF + * physical eraseblocks maximum. + */ + + ubi->peb_size = ubi->mtd->erasesize; + ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd); + ubi->flash_size = ubi->mtd->size; + + if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) + ubi->bad_allowed = 1; + + ubi->min_io_size = ubi->mtd->writesize; + ubi->hdrs_min_io_size = ubi->mtd->writesize >> ubi->mtd->subpage_sft; + + /* + * Make sure minimal I/O unit is power of 2. Note, there is no + * fundamental reason for this assumption. It is just an optimization + * which allows us to avoid costly division operations. + */ + if (!is_power_of_2(ubi->min_io_size)) { + ubi_err("min. I/O unit (%d) is not power of 2", + ubi->min_io_size); + return -EINVAL; + } + + ubi_assert(ubi->hdrs_min_io_size > 0); + ubi_assert(ubi->hdrs_min_io_size <= ubi->min_io_size); + ubi_assert(ubi->min_io_size % ubi->hdrs_min_io_size == 0); + + /* Calculate default aligned sizes of EC and VID headers */ + ubi->ec_hdr_alsize = ALIGN(UBI_EC_HDR_SIZE, ubi->hdrs_min_io_size); + ubi->vid_hdr_alsize = ALIGN(UBI_VID_HDR_SIZE, ubi->hdrs_min_io_size); + + dbg_msg("min_io_size %d", ubi->min_io_size); + dbg_msg("hdrs_min_io_size %d", ubi->hdrs_min_io_size); + dbg_msg("ec_hdr_alsize %d", ubi->ec_hdr_alsize); + dbg_msg("vid_hdr_alsize %d", ubi->vid_hdr_alsize); + + if (ubi->vid_hdr_offset == 0) + /* Default offset */ + ubi->vid_hdr_offset = ubi->vid_hdr_aloffset = + ubi->ec_hdr_alsize; + else { + ubi->vid_hdr_aloffset = ubi->vid_hdr_offset & + ~(ubi->hdrs_min_io_size - 1); + ubi->vid_hdr_shift = ubi->vid_hdr_offset - + ubi->vid_hdr_aloffset; + } + + /* Similar for the data offset */ + ubi->leb_start = ubi->vid_hdr_offset + UBI_EC_HDR_SIZE; + ubi->leb_start = ALIGN(ubi->leb_start, ubi->min_io_size); + + dbg_msg("vid_hdr_offset %d", ubi->vid_hdr_offset); + dbg_msg("vid_hdr_aloffset %d", ubi->vid_hdr_aloffset); + dbg_msg("vid_hdr_shift %d", ubi->vid_hdr_shift); + dbg_msg("leb_start %d", ubi->leb_start); + + /* The shift must be aligned to 32-bit boundary */ + if (ubi->vid_hdr_shift % 4) { + ubi_err("unaligned VID header shift %d", + ubi->vid_hdr_shift); + return -EINVAL; + } + + /* Check sanity */ + if (ubi->vid_hdr_offset < UBI_EC_HDR_SIZE || + ubi->leb_start < ubi->vid_hdr_offset + UBI_VID_HDR_SIZE || + ubi->leb_start > ubi->peb_size - UBI_VID_HDR_SIZE || + ubi->leb_start & (ubi->min_io_size - 1)) { + ubi_err("bad VID header (%d) or data offsets (%d)", + ubi->vid_hdr_offset, ubi->leb_start); + return -EINVAL; + } + + /* + * It may happen that EC and VID headers are situated in one minimal + * I/O unit. In this case we can only accept this UBI image in + * read-only mode. + */ + if (ubi->vid_hdr_offset + UBI_VID_HDR_SIZE <= ubi->hdrs_min_io_size) { + ubi_warn("EC and VID headers are in the same minimal I/O unit, " + "switch to read-only mode"); + ubi->ro_mode = 1; + } + + ubi->leb_size = ubi->peb_size - ubi->leb_start; + + if (!(ubi->mtd->flags & MTD_WRITEABLE)) { + ubi_msg("MTD device %d is write-protected, attach in " + "read-only mode", ubi->mtd->index); + ubi->ro_mode = 1; + } + + ubi_msg("physical eraseblock size: %d bytes (%d KiB)", + ubi->peb_size, ubi->peb_size >> 10); + ubi_msg("logical eraseblock size: %d bytes", ubi->leb_size); + ubi_msg("smallest flash I/O unit: %d", ubi->min_io_size); + if (ubi->hdrs_min_io_size != ubi->min_io_size) + ubi_msg("sub-page size: %d", + ubi->hdrs_min_io_size); + ubi_msg("VID header offset: %d (aligned %d)", + ubi->vid_hdr_offset, ubi->vid_hdr_aloffset); + ubi_msg("data offset: %d", ubi->leb_start); + + /* + * Note, ideally, we have to initialize ubi->bad_peb_count here. But + * unfortunately, MTD does not provide this information. We should loop + * over all physical eraseblocks and invoke mtd->block_is_bad() for + * each physical eraseblock. So, we skip ubi->bad_peb_count + * uninitialized and initialize it after scanning. + */ + + return 0; +} + +/** + * autoresize - re-size the volume which has the "auto-resize" flag set. + * @ubi: UBI device description object + * @vol_id: ID of the volume to re-size + * + * This function re-sizes the volume marked by the @UBI_VTBL_AUTORESIZE_FLG in + * the volume table to the largest possible size. See comments in ubi-header.h + * for more description of the flag. Returns zero in case of success and a + * negative error code in case of failure. + */ +static int autoresize(struct ubi_device *ubi, int vol_id) +{ + struct ubi_volume_desc desc; + struct ubi_volume *vol = ubi->volumes[vol_id]; + int err, old_reserved_pebs = vol->reserved_pebs; + + /* + * Clear the auto-resize flag in the volume in-memory copy of the + * volume table, and 'ubi_resize_volume()' will propogate this change + * to the flash. + */ + ubi->vtbl[vol_id].flags &= ~UBI_VTBL_AUTORESIZE_FLG; + + if (ubi->avail_pebs == 0) { + struct ubi_vtbl_record vtbl_rec; + + /* + * No avalilable PEBs to re-size the volume, clear the flag on + * flash and exit. + */ + memcpy(&vtbl_rec, &ubi->vtbl[vol_id], + sizeof(struct ubi_vtbl_record)); + err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + if (err) + ubi_err("cannot clean auto-resize flag for volume %d", + vol_id); + } else { + desc.vol = vol; + err = ubi_resize_volume(&desc, + old_reserved_pebs + ubi->avail_pebs); + if (err) + ubi_err("cannot auto-resize volume %d", vol_id); + } + + if (err) + return err; + + ubi_msg("volume %d (\"%s\") re-sized from %d to %d LEBs", vol_id, + vol->name, old_reserved_pebs, vol->reserved_pebs); + return 0; +} + +/** + * ubi_attach_mtd_dev - attach an MTD device. + * @mtd_dev: MTD device description object + * @ubi_num: number to assign to the new UBI device + * @vid_hdr_offset: VID header offset + * + * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number + * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in + * which case this function finds a vacant device nubert and assings it + * automatically. Returns the new UBI device number in case of success and a + * negative error code in case of failure. + * + * Note, the invocations of this function has to be serialized by the + * @ubi_devices_mutex. + */ +int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset) +{ + struct ubi_device *ubi; + int i, err; + + /* + * Check if we already have the same MTD device attached. + * + * Note, this function assumes that UBI devices creations and deletions + * are serialized, so it does not take the &ubi_devices_lock. + */ + for (i = 0; i < UBI_MAX_DEVICES; i++) { + ubi = ubi_devices[i]; + if (ubi && mtd == ubi->mtd) { + dbg_err("mtd%d is already attached to ubi%d", + mtd->index, i); + return -EEXIST; + } + } + + /* + * Make sure this MTD device is not emulated on top of an UBI volume + * already. Well, generally this recursion works fine, but there are + * different problems like the UBI module takes a reference to itself + * by attaching (and thus, opening) the emulated MTD device. This + * results in inability to unload the module. And in general it makes + * no sense to attach emulated MTD devices, so we prohibit this. + */ + if (mtd->type == MTD_UBIVOLUME) { + ubi_err("refuse attaching mtd%d - it is already emulated on " + "top of UBI", mtd->index); + return -EINVAL; + } + + if (ubi_num == UBI_DEV_NUM_AUTO) { + /* Search for an empty slot in the @ubi_devices array */ + for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) + if (!ubi_devices[ubi_num]) + break; + if (ubi_num == UBI_MAX_DEVICES) { + dbg_err("only %d UBI devices may be created", UBI_MAX_DEVICES); + return -ENFILE; + } + } else { + if (ubi_num >= UBI_MAX_DEVICES) + return -EINVAL; + + /* Make sure ubi_num is not busy */ + if (ubi_devices[ubi_num]) { + dbg_err("ubi%d already exists", ubi_num); + return -EEXIST; + } + } + + ubi = kzalloc(sizeof(struct ubi_device), GFP_KERNEL); + if (!ubi) + return -ENOMEM; + + ubi->mtd = mtd; + ubi->ubi_num = ubi_num; + ubi->vid_hdr_offset = vid_hdr_offset; + ubi->autoresize_vol_id = -1; + + mutex_init(&ubi->buf_mutex); + mutex_init(&ubi->ckvol_mutex); + mutex_init(&ubi->volumes_mutex); + spin_lock_init(&ubi->volumes_lock); + + ubi_msg("attaching mtd%d to ubi%d", mtd->index, ubi_num); + + err = io_init(ubi); + if (err) + goto out_free; + + err = -ENOMEM; + ubi->peb_buf1 = vmalloc(ubi->peb_size); + if (!ubi->peb_buf1) + goto out_free; + + ubi->peb_buf2 = vmalloc(ubi->peb_size); + if (!ubi->peb_buf2) + goto out_free; + +#ifdef CONFIG_MTD_UBI_DEBUG + mutex_init(&ubi->dbg_buf_mutex); + ubi->dbg_peb_buf = vmalloc(ubi->peb_size); + if (!ubi->dbg_peb_buf) + goto out_free; +#endif + + err = attach_by_scanning(ubi); + if (err) { + dbg_err("failed to attach by scanning, error %d", err); + goto out_free; + } + + if (ubi->autoresize_vol_id != -1) { + err = autoresize(ubi, ubi->autoresize_vol_id); + if (err) + goto out_detach; + } + + err = uif_init(ubi); + if (err) + goto out_detach; + + ubi->bgt_thread = kthread_create(ubi_thread, ubi, ubi->bgt_name); + if (IS_ERR(ubi->bgt_thread)) { + err = PTR_ERR(ubi->bgt_thread); + ubi_err("cannot spawn \"%s\", error %d", ubi->bgt_name, + err); + goto out_uif; + } + + ubi_msg("attached mtd%d to ubi%d", mtd->index, ubi_num); + ubi_msg("MTD device name: \"%s\"", mtd->name); + ubi_msg("MTD device size: %llu MiB", ubi->flash_size >> 20); + ubi_msg("number of good PEBs: %d", ubi->good_peb_count); + ubi_msg("number of bad PEBs: %d", ubi->bad_peb_count); + ubi_msg("max. allowed volumes: %d", ubi->vtbl_slots); + ubi_msg("wear-leveling threshold: %d", CONFIG_MTD_UBI_WL_THRESHOLD); + ubi_msg("number of internal volumes: %d", UBI_INT_VOL_COUNT); + ubi_msg("number of user volumes: %d", + ubi->vol_count - UBI_INT_VOL_COUNT); + ubi_msg("available PEBs: %d", ubi->avail_pebs); + ubi_msg("total number of reserved PEBs: %d", ubi->rsvd_pebs); + ubi_msg("number of PEBs reserved for bad PEB handling: %d", + ubi->beb_rsvd_pebs); + ubi_msg("max/mean erase counter: %d/%d", ubi->max_ec, ubi->mean_ec); + + /* Enable the background thread */ + if (!DBG_DISABLE_BGT) { + ubi->thread_enabled = 1; + wake_up_process(ubi->bgt_thread); + } + + ubi_devices[ubi_num] = ubi; + return ubi_num; + +out_uif: + uif_close(ubi); +out_detach: + ubi_eba_close(ubi); + ubi_wl_close(ubi); + vfree(ubi->vtbl); +out_free: + vfree(ubi->peb_buf1); + vfree(ubi->peb_buf2); +#ifdef CONFIG_MTD_UBI_DEBUG + vfree(ubi->dbg_peb_buf); +#endif + kfree(ubi); + return err; +} + +/** + * ubi_detach_mtd_dev - detach an MTD device. + * @ubi_num: UBI device number to detach from + * @anyway: detach MTD even if device reference count is not zero + * + * This function destroys an UBI device number @ubi_num and detaches the + * underlying MTD device. Returns zero in case of success and %-EBUSY if the + * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not + * exist. + * + * Note, the invocations of this function has to be serialized by the + * @ubi_devices_mutex. + */ +int ubi_detach_mtd_dev(struct mtd_info *mtd, int anyway) +{ + struct ubi_device *ubi; + int ubi_num = 0, i; + + spin_lock(&ubi_devices_lock); + + for (i = 0; i < UBI_MAX_DEVICES; i++) { + ubi = ubi_devices[i]; + if (ubi && mtd == ubi->mtd) { + ubi_num = i; + break; + } + } + + if (!ubi) { + spin_unlock(&ubi_devices_lock); + return -EINVAL; + } + + if (ubi->ref_count) { + if (!anyway) { + spin_unlock(&ubi_devices_lock); + return -EBUSY; + } + /* This may only happen if there is a bug */ + ubi_err("%s reference count %d, destroy anyway", + ubi->ubi_name, ubi->ref_count); + } + ubi_devices[ubi_num] = NULL; + spin_unlock(&ubi_devices_lock); + + ubi_assert(ubi_num == ubi->ubi_num); + dbg_msg("detaching mtd%d from ubi%d", ubi->mtd->index, ubi_num); + + /* + * Before freeing anything, we have to stop the background thread to + * prevent it from doing anything on this device while we are freeing. + */ + if (ubi->bgt_thread) + kthread_stop(ubi->bgt_thread); + + uif_close(ubi); + ubi_eba_close(ubi); + ubi_wl_close(ubi); + vfree(ubi->vtbl); + vfree(ubi->peb_buf1); + vfree(ubi->peb_buf2); +#ifdef CONFIG_MTD_UBI_DEBUG + vfree(ubi->dbg_peb_buf); +#endif + ubi_msg("mtd%d is detached from ubi%d", ubi->mtd->index, ubi->ubi_num); + kfree(ubi); + return 0; +} + +/** + * bytes_str_to_int - convert a string representing number of bytes to an + * integer. + * @str: the string to convert + * + * This function returns positive resulting integer in case of success and a + * negative error code in case of failure. + */ +static int __init bytes_str_to_int(const char *str) +{ + char *endp; + unsigned long result; + + result = simple_strtoul(str, &endp, 0); + if (str == endp || result < 0) { + printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", + str); + return -EINVAL; + } + + switch (*endp) { + case 'G': + result *= 1024; + case 'M': + result *= 1024; + case 'K': + result *= 1024; + if (endp[1] == 'i' && endp[2] == 'B') + endp += 2; + case '\0': + break; + default: + printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", + str); + return -EINVAL; + } + + return result; +} + +/** + * ubi_mtd_param_parse - parse the 'mtd=' UBI parameter. + * @val: the parameter value to parse + * @kp: not used + * + * This function returns zero in case of success and a negative error code in + * case of error. + */ +int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp) +{ + int i, len; + struct mtd_dev_param *p; + char buf[MTD_PARAM_LEN_MAX]; + char *pbuf = &buf[0]; + char *tokens[2] = {NULL, NULL}; + + if (!val) + return -EINVAL; + + if (mtd_devs == UBI_MAX_DEVICES) { + printk(KERN_ERR "UBI error: too many parameters, max. is %d\n", + UBI_MAX_DEVICES); + return -EINVAL; + } + + len = strnlen(val, MTD_PARAM_LEN_MAX); + if (len == MTD_PARAM_LEN_MAX) { + printk(KERN_ERR "UBI error: parameter \"%s\" is too long, " + "max. is %d\n", val, MTD_PARAM_LEN_MAX); + return -EINVAL; + } + + if (len == 0) { + printk(KERN_WARNING "UBI warning: empty 'mtd=' parameter - " + "ignored\n"); + return 0; + } + + strcpy(buf, val); + + /* Get rid of the final newline */ + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + + for (i = 0; i < 2; i++) + tokens[i] = strsep(&pbuf, ","); + + if (pbuf) { + printk(KERN_ERR "UBI error: too many arguments at \"%s\"\n", + val); + return -EINVAL; + } + + p = &mtd_dev_param[mtd_devs]; + strcpy(&p->name[0], tokens[0]); + + if (tokens[1]) + p->vid_hdr_offs = bytes_str_to_int(tokens[1]); + + if (p->vid_hdr_offs < 0) + return p->vid_hdr_offs; + + mtd_devs += 1; + return 0; +} + +module_param_call(mtd, ubi_mtd_param_parse, NULL, NULL, 000); +MODULE_PARM_DESC(mtd, "MTD devices to attach. Parameter format: " + "mtd=[,].\n" + "Multiple \"mtd\" parameters may be specified.\n" + "MTD devices may be specified by their number or name.\n" + "Optional \"vid_hdr_offs\" parameter specifies UBI VID " + "header position and data starting position to be used " + "by UBI.\n" + "Example: mtd=content,1984 mtd=4 - attach MTD device" + "with name \"content\" using VID header offset 1984, and " + "MTD device number 4 with default VID header offset."); + +MODULE_VERSION(__stringify(UBI_VERSION)); +MODULE_DESCRIPTION("UBI - Unsorted Block Images"); +MODULE_AUTHOR("Artem Bityutskiy"); +MODULE_LICENSE("GPL"); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c new file mode 100644 index 0000000..30b8308 --- /dev/null +++ b/drivers/mtd/ubi/cdev.c @@ -0,0 +1,238 @@ +#include +#include +#include +#include +#include "ubi-barebox.h" +#include "ubi.h" + +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, + unsigned long offset, unsigned long flags) +{ + struct ubi_volume_cdev_priv *priv = cdev->priv; + struct ubi_volume *vol = priv->vol; + struct ubi_device *ubi = priv->ubi; + int err, lnum, off, len; + size_t count_save = size; + unsigned long long tmp; + loff_t offp = offset; + int usable_leb_size = vol->usable_leb_size; + + printf("%s: %d @ 0x%08x\n", __func__, size, offset); + + len = size > usable_leb_size ? usable_leb_size : size; + + tmp = offp; + off = do_div(tmp, usable_leb_size); + lnum = tmp; + do { + if (off + len >= usable_leb_size) + len = usable_leb_size - off; + + err = ubi_eba_read_leb(ubi, vol, lnum, buf, off, len, 0); + if (err) { + printf("read err %x\n", err); + break; + } + off += len; + if (off == usable_leb_size) { + lnum += 1; + off -= usable_leb_size; + } + + size -= len; + offp += len; + + buf += len; + len = size > usable_leb_size ? usable_leb_size : size; + } while (size); + + return count_save; +} + +static ssize_t ubi_volume_cdev_write(struct cdev* cdev, const void *buf, + size_t size, unsigned long offset, unsigned long flags) +{ + struct ubi_volume_cdev_priv *priv = cdev->priv; + struct ubi_volume *vol = priv->vol; + struct ubi_device *ubi = priv->ubi; + int err; + + if (!priv->updating) { + err = ubi_start_update(ubi, vol, 16*1024*1024); + if (err < 0) { + printf("Cannot start volume update\n"); + return err; + } + priv->updating = 1; + } + + err = ubi_more_update_data(ubi, vol, buf, size); + if (err < 0) { + printf("Couldnt or partially wrote data \n"); + return err; + } + + return err; +} + +static int ubi_volume_cdev_open(struct cdev *cdev, struct filep *f) +{ + 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) +{ + struct ubi_volume_cdev_priv *priv = cdev->priv; + struct ubi_volume *vol = priv->vol; + struct ubi_device *ubi = priv->ubi; + int err; + + if (priv->updating) { + err = ubi_finish_update(ubi, vol); + if (err) + return err; + + err = ubi_check_volume(ubi, vol->vol_id); + if (err < 0) { + printf("check failed: %s\n", strerror(err)); + return err; + } + + if (err) { + ubi_warn("volume %d on UBI device %d is corrupted", + vol->vol_id, ubi->ubi_num); + vol->corrupted = 1; + } + + vol->checked = 1; + ubi_gluebi_updated(vol); + } + + return 0; +} + +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) + return -EINVAL; + + return ofs; +} + +static struct file_operations ubi_volume_fops = { + .open = ubi_volume_cdev_open, + .close = ubi_volume_cdev_close, + .read = ubi_volume_cdev_read, + .write = ubi_volume_cdev_write, + .lseek = ubi_volume_cdev_lseek, +}; + +int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol) +{ + struct cdev *cdev = &vol->cdev; + struct ubi_volume_cdev_priv *priv; + int ret; + + priv = xzalloc(sizeof(*priv)); + + priv->vol = vol; + priv->ubi = ubi; + + cdev->ops = &ubi_volume_fops; + cdev->name = asprintf("ubi%d.%s", ubi->ubi_num, vol->name); + cdev->priv = priv; + cdev->size = vol->used_bytes; + printf("registering %s as /dev/%s\n", vol->name, cdev->name); + ret = devfs_create(cdev); + if (ret) { + free(priv); + free(cdev->name); + } + + return 0; +} + +void ubi_volume_cdev_remove(struct ubi_volume *vol) +{ + struct cdev *cdev = &vol->cdev; + struct ubi_volume_cdev_priv *priv = cdev->priv; + + devfs_remove(cdev); + free(cdev->name); + free(priv); +} + +static int ubi_cdev_ioctl(struct cdev *cdev, int cmd, void *buf) +{ + struct ubi_volume_desc *desc; + struct ubi_device *ubi = cdev->priv; + struct ubi_mkvol_req *req = buf; + + switch (cmd) { + case UBI_IOCRMVOL: + desc = ubi_open_volume_nm(ubi->ubi_num, req->name, + UBI_EXCLUSIVE); + if (IS_ERR(desc)) + return PTR_ERR(desc); + ubi_remove_volume(desc); + break; + case UBI_IOCMKVOL: + if (!req->bytes) + req->bytes = ubi->avail_pebs * ubi->leb_size; + return ubi_create_volume(ubi, req); + }; + + return 0; +} + + +static struct file_operations ubi_fops = { + .ioctl = ubi_cdev_ioctl, +}; + +int ubi_cdev_add(struct ubi_device *ubi) +{ + struct cdev *cdev = &ubi->cdev; + int ret; + + cdev->ops = &ubi_fops; + cdev->name = asprintf("ubi%d", ubi->ubi_num); + cdev->priv = ubi; + cdev->size = 0; + + printf("registering /dev/%s\n", cdev->name); + ret = devfs_create(cdev); + if (ret) + free(cdev->name); + + return ret; +} + +void ubi_cdev_remove(struct ubi_device *ubi) +{ + struct cdev *cdev = &ubi->cdev; + + printf("removing %s\n", cdev->name); + + devfs_remove(cdev); + free(cdev->name); +} diff --git a/drivers/mtd/ubi/crc32defs.h b/drivers/mtd/ubi/crc32defs.h new file mode 100644 index 0000000..f5a5401 --- /dev/null +++ b/drivers/mtd/ubi/crc32defs.h @@ -0,0 +1,32 @@ +/* + * There are multiple 16-bit CRC polynomials in common use, but this is + * *the* standard CRC-32 polynomial, first popularized by Ethernet. + * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 + */ +#define CRCPOLY_LE 0xedb88320 +#define CRCPOLY_BE 0x04c11db7 + +/* How many bits at a time to use. Requires a table of 4< 8 || CRC_LE_BITS < 1 || CRC_LE_BITS & CRC_LE_BITS-1 +# error CRC_LE_BITS must be a power of 2 between 1 and 8 +#endif + +/* + * Big-endian CRC computation. Used with serial bit streams sent + * msbit-first. Be sure to use cpu_to_be32() to append the computed CRC. + */ +#if CRC_BE_BITS > 8 || CRC_BE_BITS < 1 || CRC_BE_BITS & CRC_BE_BITS-1 +# error CRC_BE_BITS must be a power of 2 between 1 and 8 +#endif diff --git a/drivers/mtd/ubi/debug.c b/drivers/mtd/ubi/debug.c new file mode 100644 index 0000000..6e4b0ff --- /dev/null +++ b/drivers/mtd/ubi/debug.c @@ -0,0 +1,192 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* + * Here we keep all the UBI debugging stuff which should normally be disabled + * and compiled-out, but it is extremely helpful when hunting bugs or doing big + * changes. + */ +#include "ubi-barebox.h" + +#ifdef CONFIG_MTD_UBI_DEBUG_MSG + +#include "ubi.h" + +/** + * ubi_dbg_dump_ec_hdr - dump an erase counter header. + * @ec_hdr: the erase counter header to dump + */ +void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr) +{ + dbg_msg("erase counter header dump:"); + dbg_msg("magic %#08x", be32_to_cpu(ec_hdr->magic)); + dbg_msg("version %d", (int)ec_hdr->version); + dbg_msg("ec %llu", (long long)be64_to_cpu(ec_hdr->ec)); + dbg_msg("vid_hdr_offset %d", be32_to_cpu(ec_hdr->vid_hdr_offset)); + dbg_msg("data_offset %d", be32_to_cpu(ec_hdr->data_offset)); + dbg_msg("hdr_crc %#08x", be32_to_cpu(ec_hdr->hdr_crc)); + dbg_msg("erase counter header hexdump:"); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ec_hdr, UBI_EC_HDR_SIZE, 1); +} + +/** + * ubi_dbg_dump_vid_hdr - dump a volume identifier header. + * @vid_hdr: the volume identifier header to dump + */ +void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr) +{ + dbg_msg("volume identifier header dump:"); + dbg_msg("magic %08x", be32_to_cpu(vid_hdr->magic)); + dbg_msg("version %d", (int)vid_hdr->version); + dbg_msg("vol_type %d", (int)vid_hdr->vol_type); + dbg_msg("copy_flag %d", (int)vid_hdr->copy_flag); + dbg_msg("compat %d", (int)vid_hdr->compat); + dbg_msg("vol_id %d", be32_to_cpu(vid_hdr->vol_id)); + dbg_msg("lnum %d", be32_to_cpu(vid_hdr->lnum)); + dbg_msg("leb_ver %u", be32_to_cpu(vid_hdr->leb_ver)); + dbg_msg("data_size %d", be32_to_cpu(vid_hdr->data_size)); + dbg_msg("used_ebs %d", be32_to_cpu(vid_hdr->used_ebs)); + dbg_msg("data_pad %d", be32_to_cpu(vid_hdr->data_pad)); + dbg_msg("sqnum %llu", + (unsigned long long)be64_to_cpu(vid_hdr->sqnum)); + dbg_msg("hdr_crc %08x", be32_to_cpu(vid_hdr->hdr_crc)); + dbg_msg("volume identifier header hexdump:"); +} + +/** + * ubi_dbg_dump_vol_info- dump volume information. + * @vol: UBI volume description object + */ +void ubi_dbg_dump_vol_info(const struct ubi_volume *vol) +{ + dbg_msg("volume information dump:"); + dbg_msg("vol_id %d", vol->vol_id); + dbg_msg("reserved_pebs %d", vol->reserved_pebs); + dbg_msg("alignment %d", vol->alignment); + dbg_msg("data_pad %d", vol->data_pad); + dbg_msg("vol_type %d", vol->vol_type); + dbg_msg("name_len %d", vol->name_len); + dbg_msg("usable_leb_size %d", vol->usable_leb_size); + dbg_msg("used_ebs %d", vol->used_ebs); + dbg_msg("used_bytes %lld", vol->used_bytes); + dbg_msg("last_eb_bytes %d", vol->last_eb_bytes); + dbg_msg("corrupted %d", vol->corrupted); + dbg_msg("upd_marker %d", vol->upd_marker); + + if (vol->name_len <= UBI_VOL_NAME_MAX && + strnlen(vol->name, vol->name_len + 1) == vol->name_len) { + dbg_msg("name %s", vol->name); + } else { + dbg_msg("the 1st 5 characters of the name: %c%c%c%c%c", + vol->name[0], vol->name[1], vol->name[2], + vol->name[3], vol->name[4]); + } +} + +/** + * ubi_dbg_dump_vtbl_record - dump a &struct ubi_vtbl_record object. + * @r: the object to dump + * @idx: volume table index + */ +void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx) +{ + int name_len = be16_to_cpu(r->name_len); + + dbg_msg("volume table record %d dump:", idx); + dbg_msg("reserved_pebs %d", be32_to_cpu(r->reserved_pebs)); + dbg_msg("alignment %d", be32_to_cpu(r->alignment)); + dbg_msg("data_pad %d", be32_to_cpu(r->data_pad)); + dbg_msg("vol_type %d", (int)r->vol_type); + dbg_msg("upd_marker %d", (int)r->upd_marker); + dbg_msg("name_len %d", name_len); + + if (r->name[0] == '\0') { + dbg_msg("name NULL"); + return; + } + + if (name_len <= UBI_VOL_NAME_MAX && + strnlen(&r->name[0], name_len + 1) == name_len) { + dbg_msg("name %s", &r->name[0]); + } else { + dbg_msg("1st 5 characters of the name: %c%c%c%c%c", + r->name[0], r->name[1], r->name[2], r->name[3], + r->name[4]); + } + dbg_msg("crc %#08x", be32_to_cpu(r->crc)); +} + +/** + * ubi_dbg_dump_sv - dump a &struct ubi_scan_volume object. + * @sv: the object to dump + */ +void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv) +{ + dbg_msg("volume scanning information dump:"); + dbg_msg("vol_id %d", sv->vol_id); + dbg_msg("highest_lnum %d", sv->highest_lnum); + dbg_msg("leb_count %d", sv->leb_count); + dbg_msg("compat %d", sv->compat); + dbg_msg("vol_type %d", sv->vol_type); + dbg_msg("used_ebs %d", sv->used_ebs); + dbg_msg("last_data_size %d", sv->last_data_size); + dbg_msg("data_pad %d", sv->data_pad); +} + +/** + * ubi_dbg_dump_seb - dump a &struct ubi_scan_leb object. + * @seb: the object to dump + * @type: object type: 0 - not corrupted, 1 - corrupted + */ +void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type) +{ + dbg_msg("eraseblock scanning information dump:"); + dbg_msg("ec %d", seb->ec); + dbg_msg("pnum %d", seb->pnum); + if (type == 0) { + dbg_msg("lnum %d", seb->lnum); + dbg_msg("scrub %d", seb->scrub); + dbg_msg("sqnum %llu", seb->sqnum); + dbg_msg("leb_ver %u", seb->leb_ver); + } +} + +/** + * ubi_dbg_dump_mkvol_req - dump a &struct ubi_mkvol_req object. + * @req: the object to dump + */ +void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req) +{ + char nm[17]; + + dbg_msg("volume creation request dump:"); + dbg_msg("vol_id %d", req->vol_id); + dbg_msg("alignment %d", req->alignment); + dbg_msg("bytes %lld", (long long)req->bytes); + dbg_msg("vol_type %d", req->vol_type); + dbg_msg("name_len %d", req->name_len); + + memcpy(nm, req->name, 16); + nm[16] = 0; + dbg_msg("the 1st 16 characters of the name: %s", nm); +} + +#endif /* CONFIG_MTD_UBI_DEBUG_MSG */ diff --git a/drivers/mtd/ubi/debug.h b/drivers/mtd/ubi/debug.h new file mode 100644 index 0000000..b44380b --- /dev/null +++ b/drivers/mtd/ubi/debug.h @@ -0,0 +1,152 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +#ifndef __UBI_DEBUG_H__ +#define __UBI_DEBUG_H__ + +#ifdef CONFIG_MTD_UBI_DEBUG +#ifdef UBI_LINUX +#include +#endif + +#define ubi_assert(expr) BUG_ON(!(expr)) +#define dbg_err(fmt, ...) ubi_err(fmt, ##__VA_ARGS__) +#else +#define ubi_assert(expr) ({}) +#define dbg_err(fmt, ...) ({}) +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_DISABLE_BGT +#define DBG_DISABLE_BGT 1 +#else +#define DBG_DISABLE_BGT 0 +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_MSG +/* Generic debugging message */ +#define dbg_msg(fmt, ...) \ + printk(KERN_DEBUG "UBI DBG: %s: " fmt "\n", \ + __FUNCTION__, ##__VA_ARGS__) + +#define ubi_dbg_dump_stack() dump_stack() + +struct ubi_ec_hdr; +struct ubi_vid_hdr; +struct ubi_volume; +struct ubi_vtbl_record; +struct ubi_scan_volume; +struct ubi_scan_leb; +struct ubi_mkvol_req; + +void ubi_dbg_dump_ec_hdr(const struct ubi_ec_hdr *ec_hdr); +void ubi_dbg_dump_vid_hdr(const struct ubi_vid_hdr *vid_hdr); +void ubi_dbg_dump_vol_info(const struct ubi_volume *vol); +void ubi_dbg_dump_vtbl_record(const struct ubi_vtbl_record *r, int idx); +void ubi_dbg_dump_sv(const struct ubi_scan_volume *sv); +void ubi_dbg_dump_seb(const struct ubi_scan_leb *seb, int type); +void ubi_dbg_dump_mkvol_req(const struct ubi_mkvol_req *req); + +#else + +#define dbg_msg(fmt, ...) ({}) +#define ubi_dbg_dump_stack() ({}) +#define ubi_dbg_dump_ec_hdr(ec_hdr) ({}) +#define ubi_dbg_dump_vid_hdr(vid_hdr) ({}) +#define ubi_dbg_dump_vol_info(vol) ({}) +#define ubi_dbg_dump_vtbl_record(r, idx) ({}) +#define ubi_dbg_dump_sv(sv) ({}) +#define ubi_dbg_dump_seb(seb, type) ({}) +#define ubi_dbg_dump_mkvol_req(req) ({}) + +#endif /* CONFIG_MTD_UBI_DEBUG_MSG */ + +#ifdef CONFIG_MTD_UBI_DEBUG_MSG_EBA +/* Messages from the eraseblock association unit */ +#define dbg_eba(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) +#else +#define dbg_eba(fmt, ...) ({}) +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_MSG_WL +/* Messages from the wear-leveling unit */ +#define dbg_wl(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) +#else +#define dbg_wl(fmt, ...) ({}) +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_MSG_IO +/* Messages from the input/output unit */ +#define dbg_io(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) +#else +#define dbg_io(fmt, ...) ({}) +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_MSG_BLD +/* Initialization and build messages */ +#define dbg_bld(fmt, ...) dbg_msg(fmt, ##__VA_ARGS__) +#else +#define dbg_bld(fmt, ...) ({}) +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_BITFLIPS +/** + * ubi_dbg_is_bitflip - if it is time to emulate a bit-flip. + * + * Returns non-zero if a bit-flip should be emulated, otherwise returns zero. + */ +static inline int ubi_dbg_is_bitflip(void) +{ + return !(random32() % 200); +} +#else +#define ubi_dbg_is_bitflip() 0 +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_WRITE_FAILURES +/** + * ubi_dbg_is_write_failure - if it is time to emulate a write failure. + * + * Returns non-zero if a write failure should be emulated, otherwise returns + * zero. + */ +static inline int ubi_dbg_is_write_failure(void) +{ + return !(random32() % 500); +} +#else +#define ubi_dbg_is_write_failure() 0 +#endif + +#ifdef CONFIG_MTD_UBI_DEBUG_EMULATE_ERASE_FAILURES +/** + * ubi_dbg_is_erase_failure - if its time to emulate an erase failure. + * + * Returns non-zero if an erase failure should be emulated, otherwise returns + * zero. + */ +static inline int ubi_dbg_is_erase_failure(void) +{ + return !(random32() % 400); +} +#else +#define ubi_dbg_is_erase_failure() 0 +#endif + +#endif /* !__UBI_DEBUG_H__ */ diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c new file mode 100644 index 0000000..8f2b3b1 --- /dev/null +++ b/drivers/mtd/ubi/eba.c @@ -0,0 +1,1256 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* + * The UBI Eraseblock Association (EBA) unit. + * + * This unit is responsible for I/O to/from logical eraseblock. + * + * Although in this implementation the EBA table is fully kept and managed in + * RAM, which assumes poor scalability, it might be (partially) maintained on + * flash in future implementations. + * + * The EBA unit implements per-logical eraseblock locking. Before accessing a + * logical eraseblock it is locked for reading or writing. The per-logical + * eraseblock locking is implemented by means of the lock tree. The lock tree + * is an RB-tree which refers all the currently locked logical eraseblocks. The + * lock tree elements are &struct ubi_ltree_entry objects. They are indexed by + * (@vol_id, @lnum) pairs. + * + * EBA also maintains the global sequence counter which is incremented each + * time a logical eraseblock is mapped to a physical eraseblock and it is + * stored in the volume identifier header. This means that each VID header has + * a unique sequence number. The sequence number is only increased an we assume + * 64 bits is enough to never overflow. + */ + +#ifdef UBI_LINUX +#include +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +/* Number of physical eraseblocks reserved for atomic LEB change operation */ +#define EBA_RESERVED_PEBS 1 + +/** + * next_sqnum - get next sequence number. + * @ubi: UBI device description object + * + * This function returns next sequence number to use, which is just the current + * global sequence counter value. It also increases the global sequence + * counter. + */ +static unsigned long long next_sqnum(struct ubi_device *ubi) +{ + unsigned long long sqnum; + + spin_lock(&ubi->ltree_lock); + sqnum = ubi->global_sqnum++; + spin_unlock(&ubi->ltree_lock); + + return sqnum; +} + +/** + * ubi_get_compat - get compatibility flags of a volume. + * @ubi: UBI device description object + * @vol_id: volume ID + * + * This function returns compatibility flags for an internal volume. User + * volumes have no compatibility flags, so %0 is returned. + */ +static int ubi_get_compat(const struct ubi_device *ubi, int vol_id) +{ + if (vol_id == UBI_LAYOUT_VOLUME_ID) + return UBI_LAYOUT_VOLUME_COMPAT; + return 0; +} + +/** + * ltree_lookup - look up the lock tree. + * @ubi: UBI device description object + * @vol_id: volume ID + * @lnum: logical eraseblock number + * + * This function returns a pointer to the corresponding &struct ubi_ltree_entry + * object if the logical eraseblock is locked and %NULL if it is not. + * @ubi->ltree_lock has to be locked. + */ +static struct ubi_ltree_entry *ltree_lookup(struct ubi_device *ubi, int vol_id, + int lnum) +{ + struct rb_node *p; + + p = ubi->ltree.rb_node; + while (p) { + struct ubi_ltree_entry *le; + + le = rb_entry(p, struct ubi_ltree_entry, rb); + + if (vol_id < le->vol_id) + p = p->rb_left; + else if (vol_id > le->vol_id) + p = p->rb_right; + else { + if (lnum < le->lnum) + p = p->rb_left; + else if (lnum > le->lnum) + p = p->rb_right; + else + return le; + } + } + + return NULL; +} + +/** + * ltree_add_entry - add new entry to the lock tree. + * @ubi: UBI device description object + * @vol_id: volume ID + * @lnum: logical eraseblock number + * + * This function adds new entry for logical eraseblock (@vol_id, @lnum) to the + * lock tree. If such entry is already there, its usage counter is increased. + * Returns pointer to the lock tree entry or %-ENOMEM if memory allocation + * failed. + */ +static struct ubi_ltree_entry *ltree_add_entry(struct ubi_device *ubi, + int vol_id, int lnum) +{ + struct ubi_ltree_entry *le, *le1, *le_free; + + le = kmalloc(sizeof(struct ubi_ltree_entry), GFP_NOFS); + if (!le) + return ERR_PTR(-ENOMEM); + + le->users = 0; + init_rwsem(&le->mutex); + le->vol_id = vol_id; + le->lnum = lnum; + + spin_lock(&ubi->ltree_lock); + le1 = ltree_lookup(ubi, vol_id, lnum); + + if (le1) { + /* + * This logical eraseblock is already locked. The newly + * allocated lock entry is not needed. + */ + le_free = le; + le = le1; + } else { + struct rb_node **p, *parent = NULL; + + /* + * No lock entry, add the newly allocated one to the + * @ubi->ltree RB-tree. + */ + le_free = NULL; + + p = &ubi->ltree.rb_node; + while (*p) { + parent = *p; + le1 = rb_entry(parent, struct ubi_ltree_entry, rb); + + if (vol_id < le1->vol_id) + p = &(*p)->rb_left; + else if (vol_id > le1->vol_id) + p = &(*p)->rb_right; + else { + ubi_assert(lnum != le1->lnum); + if (lnum < le1->lnum) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + } + + rb_link_node(&le->rb, parent, p); + rb_insert_color(&le->rb, &ubi->ltree); + } + le->users += 1; + spin_unlock(&ubi->ltree_lock); + + if (le_free) + kfree(le_free); + + return le; +} + +/** + * leb_read_lock - lock logical eraseblock for reading. + * @ubi: UBI device description object + * @vol_id: volume ID + * @lnum: logical eraseblock number + * + * This function locks a logical eraseblock for reading. Returns zero in case + * of success and a negative error code in case of failure. + */ +static int leb_read_lock(struct ubi_device *ubi, int vol_id, int lnum) +{ + struct ubi_ltree_entry *le; + + le = ltree_add_entry(ubi, vol_id, lnum); + if (IS_ERR(le)) + return PTR_ERR(le); + down_read(&le->mutex); + return 0; +} + +/** + * leb_read_unlock - unlock logical eraseblock. + * @ubi: UBI device description object + * @vol_id: volume ID + * @lnum: logical eraseblock number + */ +static void leb_read_unlock(struct ubi_device *ubi, int vol_id, int lnum) +{ + int _free = 0; + struct ubi_ltree_entry *le; + + spin_lock(&ubi->ltree_lock); + le = ltree_lookup(ubi, vol_id, lnum); + le->users -= 1; + ubi_assert(le->users >= 0); + if (le->users == 0) { + rb_erase(&le->rb, &ubi->ltree); + _free = 1; + } + spin_unlock(&ubi->ltree_lock); + + up_read(&le->mutex); + if (_free) + kfree(le); +} + +/** + * leb_write_lock - lock logical eraseblock for writing. + * @ubi: UBI device description object + * @vol_id: volume ID + * @lnum: logical eraseblock number + * + * This function locks a logical eraseblock for writing. Returns zero in case + * of success and a negative error code in case of failure. + */ +static int leb_write_lock(struct ubi_device *ubi, int vol_id, int lnum) +{ + struct ubi_ltree_entry *le; + + le = ltree_add_entry(ubi, vol_id, lnum); + if (IS_ERR(le)) + return PTR_ERR(le); + down_write(&le->mutex); + return 0; +} + +/** + * leb_write_lock - lock logical eraseblock for writing. + * @ubi: UBI device description object + * @vol_id: volume ID + * @lnum: logical eraseblock number + * + * This function locks a logical eraseblock for writing if there is no + * contention and does nothing if there is contention. Returns %0 in case of + * success, %1 in case of contention, and and a negative error code in case of + * failure. + */ +static int leb_write_trylock(struct ubi_device *ubi, int vol_id, int lnum) +{ + int _free; + struct ubi_ltree_entry *le; + + le = ltree_add_entry(ubi, vol_id, lnum); + if (IS_ERR(le)) + return PTR_ERR(le); + if (down_write_trylock(&le->mutex)) + return 0; + + /* Contention, cancel */ + spin_lock(&ubi->ltree_lock); + le->users -= 1; + ubi_assert(le->users >= 0); + if (le->users == 0) { + rb_erase(&le->rb, &ubi->ltree); + _free = 1; + } else + _free = 0; + spin_unlock(&ubi->ltree_lock); + if (_free) + kfree(le); + + return 1; +} + +/** + * leb_write_unlock - unlock logical eraseblock. + * @ubi: UBI device description object + * @vol_id: volume ID + * @lnum: logical eraseblock number + */ +static void leb_write_unlock(struct ubi_device *ubi, int vol_id, int lnum) +{ + int _free; + struct ubi_ltree_entry *le; + + spin_lock(&ubi->ltree_lock); + le = ltree_lookup(ubi, vol_id, lnum); + le->users -= 1; + ubi_assert(le->users >= 0); + if (le->users == 0) { + rb_erase(&le->rb, &ubi->ltree); + _free = 1; + } else + _free = 0; + spin_unlock(&ubi->ltree_lock); + + up_write(&le->mutex); + if (_free) + kfree(le); +} + +/** + * ubi_eba_unmap_leb - un-map logical eraseblock. + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * + * This function un-maps logical eraseblock @lnum and schedules corresponding + * physical eraseblock for erasure. Returns zero in case of success and a + * negative error code in case of failure. + */ +int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, + int lnum) +{ + int err, pnum, vol_id = vol->vol_id; + + if (ubi->ro_mode) + return -EROFS; + + err = leb_write_lock(ubi, vol_id, lnum); + if (err) + return err; + + pnum = vol->eba_tbl[lnum]; + if (pnum < 0) + /* This logical eraseblock is already unmapped */ + goto out_unlock; + + dbg_eba("erase LEB %d:%d, PEB %d", vol_id, lnum, pnum); + + vol->eba_tbl[lnum] = UBI_LEB_UNMAPPED; + err = ubi_wl_put_peb(ubi, pnum, 0); + +out_unlock: + leb_write_unlock(ubi, vol_id, lnum); + return err; +} + +/** + * ubi_eba_read_leb - read data. + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @buf: buffer to store the read data + * @offset: offset from where to read + * @len: how many bytes to read + * @check: data CRC check flag + * + * If the logical eraseblock @lnum is unmapped, @buf is filled with 0xFF + * bytes. The @check flag only makes sense for static volumes and forces + * eraseblock data CRC checking. + * + * In case of success this function returns zero. In case of a static volume, + * if data CRC mismatches - %-EBADMSG is returned. %-EBADMSG may also be + * returned for any volume type if an ECC error was detected by the MTD device + * driver. Other negative error cored may be returned in case of other errors. + */ +int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + void *buf, int offset, int len, int check) +{ + int err, pnum, scrub = 0, vol_id = vol->vol_id; + struct ubi_vid_hdr *vid_hdr; + uint32_t uninitialized_var(crc); + + err = leb_read_lock(ubi, vol_id, lnum); + if (err) + return err; + + pnum = vol->eba_tbl[lnum]; + if (pnum < 0) { + /* + * The logical eraseblock is not mapped, fill the whole buffer + * with 0xFF bytes. The exception is static volumes for which + * it is an error to read unmapped logical eraseblocks. + */ + dbg_eba("read %d bytes from offset %d of LEB %d:%d (unmapped)", + len, offset, vol_id, lnum); + leb_read_unlock(ubi, vol_id, lnum); + ubi_assert(vol->vol_type != UBI_STATIC_VOLUME); + memset(buf, 0xFF, len); + return 0; + } + + dbg_eba("read %d bytes from offset %d of LEB %d:%d, PEB %d", + len, offset, vol_id, lnum, pnum); + + if (vol->vol_type == UBI_DYNAMIC_VOLUME) + check = 0; + +retry: + if (check) { + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) { + err = -ENOMEM; + goto out_unlock; + } + + err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); + if (err && err != UBI_IO_BITFLIPS) { + if (err > 0) { + /* + * The header is either absent or corrupted. + * The former case means there is a bug - + * switch to read-only mode just in case. + * The latter case means a real corruption - we + * may try to recover data. FIXME: but this is + * not implemented. + */ + if (err == UBI_IO_BAD_VID_HDR) { + ubi_warn("bad VID header at PEB %d, LEB" + "%d:%d", pnum, vol_id, lnum); + err = -EBADMSG; + } else + ubi_ro_mode(ubi); + } + goto out_free; + } else if (err == UBI_IO_BITFLIPS) + scrub = 1; + + ubi_assert(lnum < be32_to_cpu(vid_hdr->used_ebs)); + ubi_assert(len == be32_to_cpu(vid_hdr->data_size)); + + crc = be32_to_cpu(vid_hdr->data_crc); + ubi_free_vid_hdr(ubi, vid_hdr); + } + + err = ubi_io_read_data(ubi, buf, pnum, offset, len); + if (err) { + if (err == UBI_IO_BITFLIPS) { + scrub = 1; + err = 0; + } else if (err == -EBADMSG) { + if (vol->vol_type == UBI_DYNAMIC_VOLUME) + goto out_unlock; + scrub = 1; + if (!check) { + ubi_msg("force data checking"); + check = 1; + goto retry; + } + } else + goto out_unlock; + } + + if (check) { + uint32_t crc1 = crc32(UBI_CRC32_INIT, buf, len); + if (crc1 != crc) { + ubi_warn("CRC error: calculated %#08x, must be %#08x", + crc1, crc); + err = -EBADMSG; + goto out_unlock; + } + } + + if (scrub) + err = ubi_wl_scrub_peb(ubi, pnum); + + leb_read_unlock(ubi, vol_id, lnum); + return err; + +out_free: + ubi_free_vid_hdr(ubi, vid_hdr); +out_unlock: + leb_read_unlock(ubi, vol_id, lnum); + return err; +} + +/** + * recover_peb - recover from write failure. + * @ubi: UBI device description object + * @pnum: the physical eraseblock to recover + * @vol_id: volume ID + * @lnum: logical eraseblock number + * @buf: data which was not written because of the write failure + * @offset: offset of the failed write + * @len: how many bytes should have been written + * + * This function is called in case of a write failure and moves all good data + * from the potentially bad physical eraseblock to a good physical eraseblock. + * This function also writes the data which was not written due to the failure. + * Returns new physical eraseblock number in case of success, and a negative + * error code in case of failure. + */ +static int recover_peb(struct ubi_device *ubi, int pnum, int vol_id, int lnum, + const void *buf, int offset, int len) +{ + int err, idx = vol_id2idx(ubi, vol_id), new_pnum, data_size, tries = 0; + struct ubi_volume *vol = ubi->volumes[idx]; + struct ubi_vid_hdr *vid_hdr; + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) { + return -ENOMEM; + } + + mutex_lock(&ubi->buf_mutex); + +retry: + new_pnum = ubi_wl_get_peb(ubi, UBI_UNKNOWN); + if (new_pnum < 0) { + mutex_unlock(&ubi->buf_mutex); + ubi_free_vid_hdr(ubi, vid_hdr); + return new_pnum; + } + + ubi_msg("recover PEB %d, move data to PEB %d", pnum, new_pnum); + + err = ubi_io_read_vid_hdr(ubi, pnum, vid_hdr, 1); + if (err && err != UBI_IO_BITFLIPS) { + if (err > 0) + err = -EIO; + goto out_put; + } + + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + err = ubi_io_write_vid_hdr(ubi, new_pnum, vid_hdr); + if (err) + goto write_error; + + data_size = offset + len; + memset(ubi->peb_buf1 + offset, 0xFF, len); + + /* Read everything before the area where the write failure happened */ + if (offset > 0) { + err = ubi_io_read_data(ubi, ubi->peb_buf1, pnum, 0, offset); + if (err && err != UBI_IO_BITFLIPS) + goto out_put; + } + + memcpy(ubi->peb_buf1 + offset, buf, len); + + err = ubi_io_write_data(ubi, ubi->peb_buf1, new_pnum, 0, data_size); + if (err) + goto write_error; + + mutex_unlock(&ubi->buf_mutex); + ubi_free_vid_hdr(ubi, vid_hdr); + + vol->eba_tbl[lnum] = new_pnum; + ubi_wl_put_peb(ubi, pnum, 1); + + ubi_msg("data was successfully recovered"); + return 0; + +out_put: + mutex_unlock(&ubi->buf_mutex); + ubi_wl_put_peb(ubi, new_pnum, 1); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + +write_error: + /* + * Bad luck? This physical eraseblock is bad too? Crud. Let's try to + * get another one. + */ + ubi_warn("failed to write to PEB %d", new_pnum); + ubi_wl_put_peb(ubi, new_pnum, 1); + if (++tries > UBI_IO_RETRIES) { + mutex_unlock(&ubi->buf_mutex); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + } + ubi_msg("try again"); + goto retry; +} + +/** + * ubi_eba_write_leb - write data to dynamic volume. + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @buf: the data to write + * @offset: offset within the logical eraseblock where to write + * @len: how many bytes to write + * @dtype: data type + * + * This function writes data to logical eraseblock @lnum of a dynamic volume + * @vol. Returns zero in case of success and a negative error code in case + * of failure. In case of error, it is possible that something was still + * written to the flash media, but may be some garbage. + */ +int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + const void *buf, int offset, int len, int dtype) +{ + int err, pnum, tries = 0, vol_id = vol->vol_id; + struct ubi_vid_hdr *vid_hdr; + + if (ubi->ro_mode) + return -EROFS; + + err = leb_write_lock(ubi, vol_id, lnum); + if (err) + return err; + + pnum = vol->eba_tbl[lnum]; + if (pnum >= 0) { + dbg_eba("write %d bytes at offset %d of LEB %d:%d, PEB %d", + len, offset, vol_id, lnum, pnum); + + err = ubi_io_write_data(ubi, buf, pnum, offset, len); + if (err) { + ubi_warn("failed to write data to PEB %d", pnum); + if (err == -EIO && ubi->bad_allowed) + err = recover_peb(ubi, pnum, vol_id, lnum, buf, + offset, len); + if (err) + ubi_ro_mode(ubi); + } + leb_write_unlock(ubi, vol_id, lnum); + return err; + } + + /* + * The logical eraseblock is not mapped. We have to get a free physical + * eraseblock and write the volume identifier header there first. + */ + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) { + leb_write_unlock(ubi, vol_id, lnum); + return -ENOMEM; + } + + vid_hdr->vol_type = UBI_VID_DYNAMIC; + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + vid_hdr->vol_id = cpu_to_be32(vol_id); + vid_hdr->lnum = cpu_to_be32(lnum); + vid_hdr->compat = ubi_get_compat(ubi, vol_id); + vid_hdr->data_pad = cpu_to_be32(vol->data_pad); + +retry: + pnum = ubi_wl_get_peb(ubi, dtype); + if (pnum < 0) { + ubi_free_vid_hdr(ubi, vid_hdr); + leb_write_unlock(ubi, vol_id, lnum); + return pnum; + } + + dbg_eba("write VID hdr and %d bytes at offset %d of LEB %d:%d, PEB %d", + len, offset, vol_id, lnum, pnum); + + err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); + if (err) { + ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + vol_id, lnum, pnum); + goto write_error; + } + + if (len) { + err = ubi_io_write_data(ubi, buf, pnum, offset, len); + if (err) { + ubi_warn("failed to write %d bytes at offset %d of " + "LEB %d:%d, PEB %d", len, offset, vol_id, + lnum, pnum); + goto write_error; + } + } + + vol->eba_tbl[lnum] = pnum; + + leb_write_unlock(ubi, vol_id, lnum); + ubi_free_vid_hdr(ubi, vid_hdr); + return 0; + +write_error: + if (err != -EIO || !ubi->bad_allowed) { + ubi_ro_mode(ubi); + leb_write_unlock(ubi, vol_id, lnum); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + } + + /* + * Fortunately, this is the first write operation to this physical + * eraseblock, so just put it and request a new one. We assume that if + * this physical eraseblock went bad, the erase code will handle that. + */ + err = ubi_wl_put_peb(ubi, pnum, 1); + if (err || ++tries > UBI_IO_RETRIES) { + ubi_ro_mode(ubi); + leb_write_unlock(ubi, vol_id, lnum); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + } + + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + ubi_msg("try another PEB"); + goto retry; +} + +/** + * ubi_eba_write_leb_st - write data to static volume. + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @buf: data to write + * @len: how many bytes to write + * @dtype: data type + * @used_ebs: how many logical eraseblocks will this volume contain + * + * This function writes data to logical eraseblock @lnum of static volume + * @vol. The @used_ebs argument should contain total number of logical + * eraseblock in this static volume. + * + * When writing to the last logical eraseblock, the @len argument doesn't have + * to be aligned to the minimal I/O unit size. Instead, it has to be equivalent + * to the real data size, although the @buf buffer has to contain the + * alignment. In all other cases, @len has to be aligned. + * + * It is prohibited to write more then once to logical eraseblocks of static + * volumes. This function returns zero in case of success and a negative error + * code in case of failure. + */ +int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, + int lnum, const void *buf, int len, int dtype, + int used_ebs) +{ + int err, pnum, tries = 0, data_size = len, vol_id = vol->vol_id; + struct ubi_vid_hdr *vid_hdr; + uint32_t crc; + + if (ubi->ro_mode) + return -EROFS; + + if (lnum == used_ebs - 1) + /* If this is the last LEB @len may be unaligned */ + len = ALIGN(data_size, ubi->min_io_size); + else + ubi_assert(!(len & (ubi->min_io_size - 1))); + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) + return -ENOMEM; + + err = leb_write_lock(ubi, vol_id, lnum); + if (err) { + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + } + + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + vid_hdr->vol_id = cpu_to_be32(vol_id); + vid_hdr->lnum = cpu_to_be32(lnum); + vid_hdr->compat = ubi_get_compat(ubi, vol_id); + vid_hdr->data_pad = cpu_to_be32(vol->data_pad); + + crc = crc32(UBI_CRC32_INIT, buf, data_size); + vid_hdr->vol_type = UBI_VID_STATIC; + vid_hdr->data_size = cpu_to_be32(data_size); + vid_hdr->used_ebs = cpu_to_be32(used_ebs); + vid_hdr->data_crc = cpu_to_be32(crc); + +retry: + pnum = ubi_wl_get_peb(ubi, dtype); + if (pnum < 0) { + ubi_free_vid_hdr(ubi, vid_hdr); + leb_write_unlock(ubi, vol_id, lnum); + return pnum; + } + + dbg_eba("write VID hdr and %d bytes at LEB %d:%d, PEB %d, used_ebs %d", + len, vol_id, lnum, pnum, used_ebs); + + err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); + if (err) { + ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + vol_id, lnum, pnum); + goto write_error; + } + + err = ubi_io_write_data(ubi, buf, pnum, 0, len); + if (err) { + ubi_warn("failed to write %d bytes of data to PEB %d", + len, pnum); + goto write_error; + } + + ubi_assert(vol->eba_tbl[lnum] < 0); + vol->eba_tbl[lnum] = pnum; + + leb_write_unlock(ubi, vol_id, lnum); + ubi_free_vid_hdr(ubi, vid_hdr); + return 0; + +write_error: + if (err != -EIO || !ubi->bad_allowed) { + /* + * This flash device does not admit of bad eraseblocks or + * something nasty and unexpected happened. Switch to read-only + * mode just in case. + */ + ubi_ro_mode(ubi); + leb_write_unlock(ubi, vol_id, lnum); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + } + + err = ubi_wl_put_peb(ubi, pnum, 1); + if (err || ++tries > UBI_IO_RETRIES) { + ubi_ro_mode(ubi); + leb_write_unlock(ubi, vol_id, lnum); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + } + + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + ubi_msg("try another PEB"); + goto retry; +} + +/* + * ubi_eba_atomic_leb_change - change logical eraseblock atomically. + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @buf: data to write + * @len: how many bytes to write + * @dtype: data type + * + * This function changes the contents of a logical eraseblock atomically. @buf + * has to contain new logical eraseblock data, and @len - the length of the + * data, which has to be aligned. This function guarantees that in case of an + * unclean reboot the old contents is preserved. Returns zero in case of + * success and a negative error code in case of failure. + * + * UBI reserves one LEB for the "atomic LEB change" operation, so only one + * LEB change may be done at a time. This is ensured by @ubi->alc_mutex. + */ +int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, + int lnum, const void *buf, int len, int dtype) +{ + int err, pnum, tries = 0, vol_id = vol->vol_id; + struct ubi_vid_hdr *vid_hdr; + uint32_t crc; + + if (ubi->ro_mode) + return -EROFS; + + if (len == 0) { + /* + * Special case when data length is zero. In this case the LEB + * has to be unmapped and mapped somewhere else. + */ + err = ubi_eba_unmap_leb(ubi, vol, lnum); + if (err) + return err; + return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); + } + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) + return -ENOMEM; + + mutex_lock(&ubi->alc_mutex); + err = leb_write_lock(ubi, vol_id, lnum); + if (err) + goto out_mutex; + + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + vid_hdr->vol_id = cpu_to_be32(vol_id); + vid_hdr->lnum = cpu_to_be32(lnum); + vid_hdr->compat = ubi_get_compat(ubi, vol_id); + vid_hdr->data_pad = cpu_to_be32(vol->data_pad); + + crc = crc32(UBI_CRC32_INIT, buf, len); + vid_hdr->vol_type = UBI_VID_DYNAMIC; + vid_hdr->data_size = cpu_to_be32(len); + vid_hdr->copy_flag = 1; + vid_hdr->data_crc = cpu_to_be32(crc); + +retry: + pnum = ubi_wl_get_peb(ubi, dtype); + if (pnum < 0) { + err = pnum; + goto out_leb_unlock; + } + + dbg_eba("change LEB %d:%d, PEB %d, write VID hdr to PEB %d", + vol_id, lnum, vol->eba_tbl[lnum], pnum); + + err = ubi_io_write_vid_hdr(ubi, pnum, vid_hdr); + if (err) { + ubi_warn("failed to write VID header to LEB %d:%d, PEB %d", + vol_id, lnum, pnum); + goto write_error; + } + + err = ubi_io_write_data(ubi, buf, pnum, 0, len); + if (err) { + ubi_warn("failed to write %d bytes of data to PEB %d", + len, pnum); + goto write_error; + } + + if (vol->eba_tbl[lnum] >= 0) { + err = ubi_wl_put_peb(ubi, vol->eba_tbl[lnum], 1); + if (err) + goto out_leb_unlock; + } + + vol->eba_tbl[lnum] = pnum; + +out_leb_unlock: + leb_write_unlock(ubi, vol_id, lnum); +out_mutex: + mutex_unlock(&ubi->alc_mutex); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + +write_error: + if (err != -EIO || !ubi->bad_allowed) { + /* + * This flash device does not admit of bad eraseblocks or + * something nasty and unexpected happened. Switch to read-only + * mode just in case. + */ + ubi_ro_mode(ubi); + goto out_leb_unlock; + } + + err = ubi_wl_put_peb(ubi, pnum, 1); + if (err || ++tries > UBI_IO_RETRIES) { + ubi_ro_mode(ubi); + goto out_leb_unlock; + } + + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + ubi_msg("try another PEB"); + goto retry; +} + +/** + * ubi_eba_copy_leb - copy logical eraseblock. + * @ubi: UBI device description object + * @from: physical eraseblock number from where to copy + * @to: physical eraseblock number where to copy + * @vid_hdr: VID header of the @from physical eraseblock + * + * This function copies logical eraseblock from physical eraseblock @from to + * physical eraseblock @to. The @vid_hdr buffer may be changed by this + * function. Returns: + * o %0 in case of success; + * o %1 if the operation was canceled and should be tried later (e.g., + * because a bit-flip was detected at the target PEB); + * o %2 if the volume is being deleted and this LEB should not be moved. + */ +int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, + struct ubi_vid_hdr *vid_hdr) +{ + int err, vol_id, lnum, data_size, aldata_size, idx; + struct ubi_volume *vol; + uint32_t crc; + + vol_id = be32_to_cpu(vid_hdr->vol_id); + lnum = be32_to_cpu(vid_hdr->lnum); + + dbg_eba("copy LEB %d:%d, PEB %d to PEB %d", vol_id, lnum, from, to); + + if (vid_hdr->vol_type == UBI_VID_STATIC) { + data_size = be32_to_cpu(vid_hdr->data_size); + aldata_size = ALIGN(data_size, ubi->min_io_size); + } else + data_size = aldata_size = + ubi->leb_size - be32_to_cpu(vid_hdr->data_pad); + + idx = vol_id2idx(ubi, vol_id); + spin_lock(&ubi->volumes_lock); + /* + * Note, we may race with volume deletion, which means that the volume + * this logical eraseblock belongs to might be being deleted. Since the + * volume deletion unmaps all the volume's logical eraseblocks, it will + * be locked in 'ubi_wl_put_peb()' and wait for the WL worker to finish. + */ + vol = ubi->volumes[idx]; + if (!vol) { + /* No need to do further work, cancel */ + dbg_eba("volume %d is being removed, cancel", vol_id); + spin_unlock(&ubi->volumes_lock); + return 2; + } + spin_unlock(&ubi->volumes_lock); + + /* + * We do not want anybody to write to this logical eraseblock while we + * are moving it, so lock it. + * + * Note, we are using non-waiting locking here, because we cannot sleep + * on the LEB, since it may cause deadlocks. Indeed, imagine a task is + * unmapping the LEB which is mapped to the PEB we are going to move + * (@from). This task locks the LEB and goes sleep in the + * 'ubi_wl_put_peb()' function on the @ubi->move_mutex. In turn, we are + * holding @ubi->move_mutex and go sleep on the LEB lock. So, if the + * LEB is already locked, we just do not move it and return %1. + */ + err = leb_write_trylock(ubi, vol_id, lnum); + if (err) { + dbg_eba("contention on LEB %d:%d, cancel", vol_id, lnum); + return err; + } + + /* + * The LEB might have been put meanwhile, and the task which put it is + * probably waiting on @ubi->move_mutex. No need to continue the work, + * cancel it. + */ + if (vol->eba_tbl[lnum] != from) { + dbg_eba("LEB %d:%d is no longer mapped to PEB %d, mapped to " + "PEB %d, cancel", vol_id, lnum, from, + vol->eba_tbl[lnum]); + err = 1; + goto out_unlock_leb; + } + + /* + * OK, now the LEB is locked and we can safely start moving iy. Since + * this function utilizes thie @ubi->peb1_buf buffer which is shared + * with some other functions, so lock the buffer by taking the + * @ubi->buf_mutex. + */ + mutex_lock(&ubi->buf_mutex); + dbg_eba("read %d bytes of data", aldata_size); + err = ubi_io_read_data(ubi, ubi->peb_buf1, from, 0, aldata_size); + if (err && err != UBI_IO_BITFLIPS) { + ubi_warn("error %d while reading data from PEB %d", + err, from); + goto out_unlock_buf; + } + + /* + * Now we have got to calculate how much data we have to to copy. In + * case of a static volume it is fairly easy - the VID header contains + * the data size. In case of a dynamic volume it is more difficult - we + * have to read the contents, cut 0xFF bytes from the end and copy only + * the first part. We must do this to avoid writing 0xFF bytes as it + * may have some side-effects. And not only this. It is important not + * to include those 0xFFs to CRC because later the they may be filled + * by data. + */ + if (vid_hdr->vol_type == UBI_VID_DYNAMIC) + aldata_size = data_size = + ubi_calc_data_len(ubi, ubi->peb_buf1, data_size); + + cond_resched(); + crc = crc32(UBI_CRC32_INIT, ubi->peb_buf1, data_size); + cond_resched(); + + /* + * It may turn out to me that the whole @from physical eraseblock + * contains only 0xFF bytes. Then we have to only write the VID header + * and do not write any data. This also means we should not set + * @vid_hdr->copy_flag, @vid_hdr->data_size, and @vid_hdr->data_crc. + */ + if (data_size > 0) { + vid_hdr->copy_flag = 1; + vid_hdr->data_size = cpu_to_be32(data_size); + vid_hdr->data_crc = cpu_to_be32(crc); + } + vid_hdr->sqnum = cpu_to_be64(next_sqnum(ubi)); + + err = ubi_io_write_vid_hdr(ubi, to, vid_hdr); + if (err) + goto out_unlock_buf; + + cond_resched(); + + /* Read the VID header back and check if it was written correctly */ + err = ubi_io_read_vid_hdr(ubi, to, vid_hdr, 1); + if (err) { + if (err != UBI_IO_BITFLIPS) + ubi_warn("cannot read VID header back from PEB %d", to); + else + err = 1; + goto out_unlock_buf; + } + + if (data_size > 0) { + err = ubi_io_write_data(ubi, ubi->peb_buf1, to, 0, aldata_size); + if (err) + goto out_unlock_buf; + + cond_resched(); + + /* + * We've written the data and are going to read it back to make + * sure it was written correctly. + */ + + err = ubi_io_read_data(ubi, ubi->peb_buf2, to, 0, aldata_size); + if (err) { + if (err != UBI_IO_BITFLIPS) + ubi_warn("cannot read data back from PEB %d", + to); + else + err = 1; + goto out_unlock_buf; + } + + cond_resched(); + + if (memcmp(ubi->peb_buf1, ubi->peb_buf2, aldata_size)) { + ubi_warn("read data back from PEB %d - it is different", + to); + goto out_unlock_buf; + } + } + + ubi_assert(vol->eba_tbl[lnum] == from); + vol->eba_tbl[lnum] = to; + +out_unlock_buf: + mutex_unlock(&ubi->buf_mutex); +out_unlock_leb: + leb_write_unlock(ubi, vol_id, lnum); + return err; +} + +/** + * ubi_eba_init_scan - initialize the EBA unit using scanning information. + * @ubi: UBI device description object + * @si: scanning information + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) +{ + int i, j, err, num_volumes; + struct ubi_scan_volume *sv; + struct ubi_volume *vol; + struct ubi_scan_leb *seb; + struct rb_node *rb; + + dbg_eba("initialize EBA unit"); + + spin_lock_init(&ubi->ltree_lock); + mutex_init(&ubi->alc_mutex); + ubi->ltree = RB_ROOT; + + ubi->global_sqnum = si->max_sqnum + 1; + num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; + + for (i = 0; i < num_volumes; i++) { + vol = ubi->volumes[i]; + if (!vol) + continue; + + cond_resched(); + + vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), + GFP_KERNEL); + if (!vol->eba_tbl) { + err = -ENOMEM; + goto out_free; + } + + for (j = 0; j < vol->reserved_pebs; j++) + vol->eba_tbl[j] = UBI_LEB_UNMAPPED; + + sv = ubi_scan_find_sv(si, idx2vol_id(ubi, i)); + if (!sv) + continue; + + ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { + if (seb->lnum >= vol->reserved_pebs) + /* + * This may happen in case of an unclean reboot + * during re-size. + */ + ubi_scan_move_to_list(sv, seb, &si->erase); + vol->eba_tbl[seb->lnum] = seb->pnum; + } + } + + if (ubi->avail_pebs < EBA_RESERVED_PEBS) { + ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi->avail_pebs, EBA_RESERVED_PEBS); + err = -ENOSPC; + goto out_free; + } + ubi->avail_pebs -= EBA_RESERVED_PEBS; + ubi->rsvd_pebs += EBA_RESERVED_PEBS; + + if (ubi->bad_allowed) { + ubi_calculate_reserved(ubi); + + if (ubi->avail_pebs < ubi->beb_rsvd_level) { + /* No enough free physical eraseblocks */ + ubi->beb_rsvd_pebs = ubi->avail_pebs; + ubi_warn("cannot reserve enough PEBs for bad PEB " + "handling, reserved %d, need %d", + ubi->beb_rsvd_pebs, ubi->beb_rsvd_level); + } else + ubi->beb_rsvd_pebs = ubi->beb_rsvd_level; + + ubi->avail_pebs -= ubi->beb_rsvd_pebs; + ubi->rsvd_pebs += ubi->beb_rsvd_pebs; + } + + dbg_eba("EBA unit is initialized"); + return 0; + +out_free: + for (i = 0; i < num_volumes; i++) { + if (!ubi->volumes[i]) + continue; + kfree(ubi->volumes[i]->eba_tbl); + } + return err; +} + +/** + * ubi_eba_close - close EBA unit. + * @ubi: UBI device description object + */ +void ubi_eba_close(const struct ubi_device *ubi) +{ + int i, num_volumes = ubi->vtbl_slots + UBI_INT_VOL_COUNT; + + dbg_eba("close EBA unit"); + + for (i = 0; i < num_volumes; i++) { + if (!ubi->volumes[i]) + continue; + kfree(ubi->volumes[i]->eba_tbl); + } +} diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c new file mode 100644 index 0000000..96d2772 --- /dev/null +++ b/drivers/mtd/ubi/io.c @@ -0,0 +1,1274 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Nokia Corporation, 2006, 2007 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* + * UBI input/output unit. + * + * This unit provides a uniform way to work with all kinds of the underlying + * MTD devices. It also implements handy functions for reading and writing UBI + * headers. + * + * We are trying to have a paranoid mindset and not to trust to what we read + * from the flash media in order to be more secure and robust. So this unit + * validates every single header it reads from the flash media. + * + * Some words about how the eraseblock headers are stored. + * + * The erase counter header is always stored at offset zero. By default, the + * VID header is stored after the EC header at the closest aligned offset + * (i.e. aligned to the minimum I/O unit size). Data starts next to the VID + * header at the closest aligned offset. But this default layout may be + * changed. For example, for different reasons (e.g., optimization) UBI may be + * asked to put the VID header at further offset, and even at an unaligned + * offset. Of course, if the offset of the VID header is unaligned, UBI adds + * proper padding in front of it. Data offset may also be changed but it has to + * be aligned. + * + * About minimal I/O units. In general, UBI assumes flash device model where + * there is only one minimal I/O unit size. E.g., in case of NOR flash it is 1, + * in case of NAND flash it is a NAND page, etc. This is reported by MTD in the + * @ubi->mtd->writesize field. But as an exception, UBI admits of using another + * (smaller) minimal I/O unit size for EC and VID headers to make it possible + * to do different optimizations. + * + * This is extremely useful in case of NAND flashes which admit of several + * write operations to one NAND page. In this case UBI can fit EC and VID + * headers at one NAND page. Thus, UBI may use "sub-page" size as the minimal + * I/O unit for the headers (the @ubi->hdrs_min_io_size field). But it still + * reports NAND page size (@ubi->min_io_size) as a minimal I/O unit for the UBI + * users. + * + * Example: some Samsung NANDs with 2KiB pages allow 4x 512-byte writes, so + * although the minimal I/O unit is 2K, UBI uses 512 bytes for EC and VID + * headers. + * + * Q: why not just to treat sub-page as a minimal I/O unit of this flash + * device, e.g., make @ubi->min_io_size = 512 in the example above? + * + * A: because when writing a sub-page, MTD still writes a full 2K page but the + * bytes which are no relevant to the sub-page are 0xFF. So, basically, writing + * 4x512 sub-pages is 4 times slower then writing one 2KiB NAND page. Thus, we + * prefer to use sub-pages only for EV and VID headers. + * + * As it was noted above, the VID header may start at a non-aligned offset. + * For example, in case of a 2KiB page NAND flash with a 512 bytes sub-page, + * the VID header may reside at offset 1984 which is the last 64 bytes of the + * last sub-page (EC header is always at offset zero). This causes some + * difficulties when reading and writing VID headers. + * + * Suppose we have a 64-byte buffer and we read a VID header at it. We change + * the data and want to write this VID header out. As we can only write in + * 512-byte chunks, we have to allocate one more buffer and copy our VID header + * to offset 448 of this buffer. + * + * The I/O unit does the following trick in order to avoid this extra copy. + * It always allocates a @ubi->vid_hdr_alsize bytes buffer for the VID header + * and returns a pointer to offset @ubi->vid_hdr_shift of this buffer. When the + * VID header is being written out, it shifts the VID header pointer back and + * writes the whole sub-page. + */ + +#ifdef UBI_LINUX +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID +static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum); +static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum); +static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, + const struct ubi_ec_hdr *ec_hdr); +static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum); +static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, + const struct ubi_vid_hdr *vid_hdr); +static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, + int len); +#else +#define paranoid_check_not_bad(ubi, pnum) 0 +#define paranoid_check_peb_ec_hdr(ubi, pnum) 0 +#define paranoid_check_ec_hdr(ubi, pnum, ec_hdr) 0 +#define paranoid_check_peb_vid_hdr(ubi, pnum) 0 +#define paranoid_check_vid_hdr(ubi, pnum, vid_hdr) 0 +#define paranoid_check_all_ff(ubi, pnum, offset, len) 0 +#endif + +/** + * ubi_io_read - read data from a physical eraseblock. + * @ubi: UBI device description object + * @buf: buffer where to store the read data + * @pnum: physical eraseblock number to read from + * @offset: offset within the physical eraseblock from where to read + * @len: how many bytes to read + * + * This function reads data from offset @offset of physical eraseblock @pnum + * and stores the read data in the @buf buffer. The following return codes are + * possible: + * + * o %0 if all the requested data were successfully read; + * o %UBI_IO_BITFLIPS if all the requested data were successfully read, but + * correctable bit-flips were detected; this is harmless but may indicate + * that this eraseblock may become bad soon (but do not have to); + * o %-EBADMSG if the MTD subsystem reported about data integrity problems, for + * example it can be an ECC error in case of NAND; this most probably means + * that the data is corrupted; + * o %-EIO if some I/O error occurred; + * o other negative error codes in case of other errors. + */ +int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, + int len) +{ + int err, retries = 0; + size_t read; + loff_t addr; + + dbg_io("read %d bytes from PEB %d:%d", len, pnum, offset); + + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + ubi_assert(offset >= 0 && offset + len <= ubi->peb_size); + ubi_assert(len > 0); + + err = paranoid_check_not_bad(ubi, pnum); + if (err) + return err > 0 ? -EINVAL : err; + + addr = (loff_t)pnum * ubi->peb_size + offset; +retry: + err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); + if (err) { + if (err == -EUCLEAN) { + /* + * -EUCLEAN is reported if there was a bit-flip which + * was corrected, so this is harmless. + */ + ubi_msg("fixable bit-flip detected at PEB %d", pnum); + ubi_assert(len == read); + return UBI_IO_BITFLIPS; + } + + if (read != len && retries++ < UBI_IO_RETRIES) { + dbg_io("error %d while reading %d bytes from PEB %d:%d, " + "read only %zd bytes, retry", + err, len, pnum, offset, read); + yield(); + goto retry; + } + + ubi_err("error %d while reading %d bytes from PEB %d:%d, " + "read %zd bytes", err, len, pnum, offset, read); + ubi_dbg_dump_stack(); + + /* + * The driver should never return -EBADMSG if it failed to read + * all the requested data. But some buggy drivers might do + * this, so we change it to -EIO. + */ + if (read != len && err == -EBADMSG) { + ubi_assert(0); + printk("%s[%d] not here\n", __func__, __LINE__); +/* err = -EIO; */ + } + } else { + ubi_assert(len == read); + + if (ubi_dbg_is_bitflip()) { + dbg_msg("bit-flip (emulated)"); + err = UBI_IO_BITFLIPS; + } + } + + return err; +} + +/** + * ubi_io_write - write data to a physical eraseblock. + * @ubi: UBI device description object + * @buf: buffer with the data to write + * @pnum: physical eraseblock number to write to + * @offset: offset within the physical eraseblock where to write + * @len: how many bytes to write + * + * This function writes @len bytes of data from buffer @buf to offset @offset + * of physical eraseblock @pnum. If all the data were successfully written, + * zero is returned. If an error occurred, this function returns a negative + * error code. If %-EIO is returned, the physical eraseblock most probably went + * bad. + * + * Note, in case of an error, it is possible that something was still written + * to the flash media, but may be some garbage. + */ +int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, + int len) +{ + int err; + size_t written; + loff_t addr; + + dbg_io("write %d bytes to PEB %d:%d", len, pnum, offset); + + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + ubi_assert(offset >= 0 && offset + len <= ubi->peb_size); + ubi_assert(offset % ubi->hdrs_min_io_size == 0); + ubi_assert(len > 0 && len % ubi->hdrs_min_io_size == 0); + + if (ubi->ro_mode) { + ubi_err("read-only mode"); + return -EROFS; + } + + /* The below has to be compiled out if paranoid checks are disabled */ + + err = paranoid_check_not_bad(ubi, pnum); + if (err) + return err > 0 ? -EINVAL : err; + + /* The area we are writing to has to contain all 0xFF bytes */ + err = paranoid_check_all_ff(ubi, pnum, offset, len); + if (err) + return err > 0 ? -EINVAL : err; + + if (offset >= ubi->leb_start) { + /* + * We write to the data area of the physical eraseblock. Make + * sure it has valid EC and VID headers. + */ + err = paranoid_check_peb_ec_hdr(ubi, pnum); + if (err) + return err > 0 ? -EINVAL : err; + err = paranoid_check_peb_vid_hdr(ubi, pnum); + if (err) + return err > 0 ? -EINVAL : err; + } + + if (ubi_dbg_is_write_failure()) { + dbg_err("cannot write %d bytes to PEB %d:%d " + "(emulated)", len, pnum, offset); + ubi_dbg_dump_stack(); + return -EIO; + } + + addr = (loff_t)pnum * ubi->peb_size + offset; + err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); + if (err) { + ubi_err("error %d while writing %d bytes to PEB %d:%d, written" + " %zd bytes", err, len, pnum, offset, written); + ubi_dbg_dump_stack(); + } else + ubi_assert(written == len); + + return err; +} + +/** + * erase_callback - MTD erasure call-back. + * @ei: MTD erase information object. + * + * Note, even though MTD erase interface is asynchronous, all the current + * implementations are synchronous anyway. + */ +static void erase_callback(struct erase_info *ei) +{ + wake_up_interruptible((wait_queue_head_t *)ei->priv); +} + +/** + * do_sync_erase - synchronously erase a physical eraseblock. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to erase + * + * This function synchronously erases physical eraseblock @pnum and returns + * zero in case of success and a negative error code in case of failure. If + * %-EIO is returned, the physical eraseblock most probably went bad. + */ +static int do_sync_erase(struct ubi_device *ubi, int pnum) +{ + int err, retries = 0; + struct erase_info ei; + wait_queue_head_t wq; + + dbg_io("erase PEB %d", pnum); + +retry: + init_waitqueue_head(&wq); + memset(&ei, 0, sizeof(struct erase_info)); + + ei.mtd = ubi->mtd; + ei.addr = (loff_t)pnum * ubi->peb_size; + ei.len = ubi->peb_size; + ei.callback = erase_callback; + ei.priv = (unsigned long)&wq; + + err = ubi->mtd->erase(ubi->mtd, &ei); + if (err) { + if (retries++ < UBI_IO_RETRIES) { + dbg_io("error %d while erasing PEB %d, retry", + err, pnum); + yield(); + goto retry; + } + ubi_err("cannot erase PEB %d, error %d", pnum, err); + ubi_dbg_dump_stack(); + return err; + } + + err = wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE || + ei.state == MTD_ERASE_FAILED); + if (err) { + ubi_err("interrupted PEB %d erasure", pnum); + return -EINTR; + } + + if (ei.state == MTD_ERASE_FAILED) { + if (retries++ < UBI_IO_RETRIES) { + dbg_io("error while erasing PEB %d, retry", pnum); + yield(); + goto retry; + } + ubi_err("cannot erase PEB %d", pnum); + ubi_dbg_dump_stack(); + return -EIO; + } + + err = paranoid_check_all_ff(ubi, pnum, 0, ubi->peb_size); + if (err) + return err > 0 ? -EINVAL : err; + + if (ubi_dbg_is_erase_failure() && !err) { + dbg_err("cannot erase PEB %d (emulated)", pnum); + return -EIO; + } + + return 0; +} + +/** + * check_pattern - check if buffer contains only a certain byte pattern. + * @buf: buffer to check + * @patt: the pattern to check + * @size: buffer size in bytes + * + * This function returns %1 in there are only @patt bytes in @buf, and %0 if + * something else was also found. + */ +static int check_pattern(const void *buf, uint8_t patt, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (((const uint8_t *)buf)[i] != patt) + return 0; + return 1; +} + +/* Patterns to write to a physical eraseblock when torturing it */ +static uint8_t patterns[] = {0xa5, 0x5a, 0x0}; + +/** + * torture_peb - test a supposedly bad physical eraseblock. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to test + * + * This function returns %-EIO if the physical eraseblock did not pass the + * test, a positive number of erase operations done if the test was + * successfully passed, and other negative error codes in case of other errors. + */ +static int torture_peb(struct ubi_device *ubi, int pnum) +{ + int err, i, patt_count; + + patt_count = ARRAY_SIZE(patterns); + ubi_assert(patt_count > 0); + + mutex_lock(&ubi->buf_mutex); + for (i = 0; i < patt_count; i++) { + err = do_sync_erase(ubi, pnum); + if (err) + goto out; + + /* Make sure the PEB contains only 0xFF bytes */ + err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); + if (err) + goto out; + + err = check_pattern(ubi->peb_buf1, 0xFF, ubi->peb_size); + if (err == 0) { + ubi_err("erased PEB %d, but a non-0xFF byte found", + pnum); + err = -EIO; + goto out; + } + + /* Write a pattern and check it */ + memset(ubi->peb_buf1, patterns[i], ubi->peb_size); + err = ubi_io_write(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); + if (err) + goto out; + + memset(ubi->peb_buf1, ~patterns[i], ubi->peb_size); + err = ubi_io_read(ubi, ubi->peb_buf1, pnum, 0, ubi->peb_size); + if (err) + goto out; + + err = check_pattern(ubi->peb_buf1, patterns[i], ubi->peb_size); + if (err == 0) { + ubi_err("pattern %x checking failed for PEB %d", + patterns[i], pnum); + err = -EIO; + goto out; + } + } + + err = patt_count; + +out: + mutex_unlock(&ubi->buf_mutex); + if (err == UBI_IO_BITFLIPS || err == -EBADMSG) { + /* + * If a bit-flip or data integrity error was detected, the test + * has not passed because it happened on a freshly erased + * physical eraseblock which means something is wrong with it. + */ + ubi_err("read problems on freshly erased PEB %d, must be bad", + pnum); + err = -EIO; + } + return err; +} + +/** + * ubi_io_sync_erase - synchronously erase a physical eraseblock. + * @ubi: UBI device description object + * @pnum: physical eraseblock number to erase + * @torture: if this physical eraseblock has to be tortured + * + * This function synchronously erases physical eraseblock @pnum. If @torture + * flag is not zero, the physical eraseblock is checked by means of writing + * different patterns to it and reading them back. If the torturing is enabled, + * the physical eraseblock is erased more then once. + * + * This function returns the number of erasures made in case of success, %-EIO + * if the erasure failed or the torturing test failed, and other negative error + * codes in case of other errors. Note, %-EIO means that the physical + * eraseblock is bad. + */ +int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture) +{ + int err, ret = 0; + + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + + err = paranoid_check_not_bad(ubi, pnum); + if (err != 0) + return err > 0 ? -EINVAL : err; + + if (ubi->ro_mode) { + ubi_err("read-only mode"); + return -EROFS; + } + + if (torture) { + ret = torture_peb(ubi, pnum); + if (ret < 0) + return ret; + } + + err = do_sync_erase(ubi, pnum); + if (err) + return err; + + return ret + 1; +} + +/** + * ubi_io_is_bad - check if a physical eraseblock is bad. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to check + * + * This function returns a positive number if the physical eraseblock is bad, + * zero if not, and a negative error code if an error occurred. + */ +int ubi_io_is_bad(const struct ubi_device *ubi, int pnum) +{ + struct mtd_info *mtd = ubi->mtd; + + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + + if (ubi->bad_allowed) { + int ret; + + ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size); + if (ret < 0) + ubi_err("error %d while checking if PEB %d is bad", + ret, pnum); + else if (ret) + dbg_io("PEB %d is bad", pnum); + return ret; + } + + return 0; +} + +/** + * ubi_io_mark_bad - mark a physical eraseblock as bad. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to mark + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) +{ + int err; + struct mtd_info *mtd = ubi->mtd; + + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + + if (ubi->ro_mode) { + ubi_err("read-only mode"); + return -EROFS; + } + + if (!ubi->bad_allowed) + return 0; + + err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size); + if (err) + ubi_err("cannot mark PEB %d bad, error %d", pnum, err); + return err; +} + +/** + * validate_ec_hdr - validate an erase counter header. + * @ubi: UBI device description object + * @ec_hdr: the erase counter header to check + * + * This function returns zero if the erase counter header is OK, and %1 if + * not. + */ +static int validate_ec_hdr(const struct ubi_device *ubi, + const struct ubi_ec_hdr *ec_hdr) +{ + long long ec; + int vid_hdr_offset, leb_start; + + ec = be64_to_cpu(ec_hdr->ec); + vid_hdr_offset = be32_to_cpu(ec_hdr->vid_hdr_offset); + leb_start = be32_to_cpu(ec_hdr->data_offset); + + if (ec_hdr->version != UBI_VERSION) { + ubi_err("node with incompatible UBI version found: " + "this UBI version is %d, image version is %d", + UBI_VERSION, (int)ec_hdr->version); + goto bad; + } + + if (vid_hdr_offset != ubi->vid_hdr_offset) { + ubi_err("bad VID header offset %d, expected %d", + vid_hdr_offset, ubi->vid_hdr_offset); + goto bad; + } + + if (leb_start != ubi->leb_start) { + ubi_err("bad data offset %d, expected %d", + leb_start, ubi->leb_start); + goto bad; + } + + if (ec < 0 || ec > UBI_MAX_ERASECOUNTER) { + ubi_err("bad erase counter %lld", ec); + goto bad; + } + + return 0; + +bad: + ubi_err("bad EC header"); + ubi_dbg_dump_ec_hdr(ec_hdr); + ubi_dbg_dump_stack(); + return 1; +} + +/** + * ubi_io_read_ec_hdr - read and check an erase counter header. + * @ubi: UBI device description object + * @pnum: physical eraseblock to read from + * @ec_hdr: a &struct ubi_ec_hdr object where to store the read erase counter + * header + * @verbose: be verbose if the header is corrupted or was not found + * + * This function reads erase counter header from physical eraseblock @pnum and + * stores it in @ec_hdr. This function also checks CRC checksum of the read + * erase counter header. The following codes may be returned: + * + * o %0 if the CRC checksum is correct and the header was successfully read; + * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected + * and corrected by the flash driver; this is harmless but may indicate that + * this eraseblock may become bad soon (but may be not); + * o %UBI_IO_BAD_EC_HDR if the erase counter header is corrupted (a CRC error); + * o %UBI_IO_PEB_EMPTY if the physical eraseblock is empty; + * o a negative error code in case of failure. + */ +int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, + struct ubi_ec_hdr *ec_hdr, int verbose) +{ + int err, read_err = 0; + uint32_t crc, magic, hdr_crc; + + dbg_io("read EC header from PEB %d", pnum); + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + if (UBI_IO_DEBUG) + verbose = 1; + + err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); + if (err) { + if (err != UBI_IO_BITFLIPS && err != -EBADMSG) + return err; + + /* + * We read all the data, but either a correctable bit-flip + * occurred, or MTD reported about some data integrity error, + * like an ECC error in case of NAND. The former is harmless, + * the later may mean that the read data is corrupted. But we + * have a CRC check-sum and we will detect this. If the EC + * header is still OK, we just report this as there was a + * bit-flip. + */ + read_err = err; + } + + magic = be32_to_cpu(ec_hdr->magic); + if (magic != UBI_EC_HDR_MAGIC) { + /* + * The magic field is wrong. Let's check if we have read all + * 0xFF. If yes, this physical eraseblock is assumed to be + * empty. + * + * But if there was a read error, we do not test it for all + * 0xFFs. Even if it does contain all 0xFFs, this error + * indicates that something is still wrong with this physical + * eraseblock and we anyway cannot treat it as empty. + */ + if (read_err != -EBADMSG && + check_pattern(ec_hdr, 0xFF, UBI_EC_HDR_SIZE)) { + /* The physical eraseblock is supposedly empty */ + + /* + * The below is just a paranoid check, it has to be + * compiled out if paranoid checks are disabled. + */ + err = paranoid_check_all_ff(ubi, pnum, 0, + ubi->peb_size); + if (err) + return err > 0 ? UBI_IO_BAD_EC_HDR : err; + + if (verbose) + ubi_warn("no EC header found at PEB %d, " + "only 0xFF bytes", pnum); + return UBI_IO_PEB_EMPTY; + } + + /* + * This is not a valid erase counter header, and these are not + * 0xFF bytes. Report that the header is corrupted. + */ + if (verbose) { + ubi_warn("bad magic number at PEB %d: %08x instead of " + "%08x", pnum, magic, UBI_EC_HDR_MAGIC); + ubi_dbg_dump_ec_hdr(ec_hdr); + } + return UBI_IO_BAD_EC_HDR; + } + + crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); + hdr_crc = be32_to_cpu(ec_hdr->hdr_crc); + + if (hdr_crc != crc) { + if (verbose) { + ubi_warn("bad EC header CRC at PEB %d, calculated %#08x," + " read %#08x", pnum, crc, hdr_crc); + ubi_dbg_dump_ec_hdr(ec_hdr); + } + return UBI_IO_BAD_EC_HDR; + } + + /* And of course validate what has just been read from the media */ + err = validate_ec_hdr(ubi, ec_hdr); + if (err) { + ubi_err("validation failed for PEB %d", pnum); + return -EINVAL; + } + + return read_err ? UBI_IO_BITFLIPS : 0; +} + +/** + * ubi_io_write_ec_hdr - write an erase counter header. + * @ubi: UBI device description object + * @pnum: physical eraseblock to write to + * @ec_hdr: the erase counter header to write + * + * This function writes erase counter header described by @ec_hdr to physical + * eraseblock @pnum. It also fills most fields of @ec_hdr before writing, so + * the caller do not have to fill them. Callers must only fill the @ec_hdr->ec + * field. + * + * This function returns zero in case of success and a negative error code in + * case of failure. If %-EIO is returned, the physical eraseblock most probably + * went bad. + */ +int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, + struct ubi_ec_hdr *ec_hdr) +{ + int err; + uint32_t crc; + + dbg_io("write EC header to PEB %d", pnum); + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + + ec_hdr->magic = cpu_to_be32(UBI_EC_HDR_MAGIC); + ec_hdr->version = UBI_VERSION; + ec_hdr->vid_hdr_offset = cpu_to_be32(ubi->vid_hdr_offset); + ec_hdr->data_offset = cpu_to_be32(ubi->leb_start); + crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); + ec_hdr->hdr_crc = cpu_to_be32(crc); + + err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr); + if (err) + return -EINVAL; + + err = ubi_io_write(ubi, ec_hdr, pnum, 0, ubi->ec_hdr_alsize); + return err; +} + +/** + * validate_vid_hdr - validate a volume identifier header. + * @ubi: UBI device description object + * @vid_hdr: the volume identifier header to check + * + * This function checks that data stored in the volume identifier header + * @vid_hdr. Returns zero if the VID header is OK and %1 if not. + */ +static int validate_vid_hdr(const struct ubi_device *ubi, + const struct ubi_vid_hdr *vid_hdr) +{ + int vol_type = vid_hdr->vol_type; + int copy_flag = vid_hdr->copy_flag; + int vol_id = be32_to_cpu(vid_hdr->vol_id); + int lnum = be32_to_cpu(vid_hdr->lnum); + int compat = vid_hdr->compat; + int data_size = be32_to_cpu(vid_hdr->data_size); + int used_ebs = be32_to_cpu(vid_hdr->used_ebs); + int data_pad = be32_to_cpu(vid_hdr->data_pad); + int data_crc = be32_to_cpu(vid_hdr->data_crc); + int usable_leb_size = ubi->leb_size - data_pad; + + if (copy_flag != 0 && copy_flag != 1) { + dbg_err("bad copy_flag"); + goto bad; + } + + if (vol_id < 0 || lnum < 0 || data_size < 0 || used_ebs < 0 || + data_pad < 0) { + dbg_err("negative values"); + goto bad; + } + + if (vol_id >= UBI_MAX_VOLUMES && vol_id < UBI_INTERNAL_VOL_START) { + dbg_err("bad vol_id"); + goto bad; + } + + if (vol_id < UBI_INTERNAL_VOL_START && compat != 0) { + dbg_err("bad compat"); + goto bad; + } + + if (vol_id >= UBI_INTERNAL_VOL_START && compat != UBI_COMPAT_DELETE && + compat != UBI_COMPAT_RO && compat != UBI_COMPAT_PRESERVE && + compat != UBI_COMPAT_REJECT) { + dbg_err("bad compat"); + goto bad; + } + + if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { + dbg_err("bad vol_type"); + goto bad; + } + + if (data_pad >= ubi->leb_size / 2) { + dbg_err("bad data_pad"); + goto bad; + } + + if (vol_type == UBI_VID_STATIC) { + /* + * Although from high-level point of view static volumes may + * contain zero bytes of data, but no VID headers can contain + * zero at these fields, because they empty volumes do not have + * mapped logical eraseblocks. + */ + if (used_ebs == 0) { + dbg_err("zero used_ebs"); + goto bad; + } + if (data_size == 0) { + dbg_err("zero data_size"); + goto bad; + } + if (lnum < used_ebs - 1) { + if (data_size != usable_leb_size) { + dbg_err("bad data_size"); + goto bad; + } + } else if (lnum == used_ebs - 1) { + if (data_size == 0) { + dbg_err("bad data_size at last LEB"); + goto bad; + } + } else { + dbg_err("too high lnum"); + goto bad; + } + } else { + if (copy_flag == 0) { + if (data_crc != 0) { + dbg_err("non-zero data CRC"); + goto bad; + } + if (data_size != 0) { + dbg_err("non-zero data_size"); + goto bad; + } + } else { + if (data_size == 0) { + dbg_err("zero data_size of copy"); + goto bad; + } + } + if (used_ebs != 0) { + dbg_err("bad used_ebs"); + goto bad; + } + } + + return 0; + +bad: + ubi_err("bad VID header"); + ubi_dbg_dump_vid_hdr(vid_hdr); + ubi_dbg_dump_stack(); + return 1; +} + +/** + * ubi_io_read_vid_hdr - read and check a volume identifier header. + * @ubi: UBI device description object + * @pnum: physical eraseblock number to read from + * @vid_hdr: &struct ubi_vid_hdr object where to store the read volume + * identifier header + * @verbose: be verbose if the header is corrupted or wasn't found + * + * This function reads the volume identifier header from physical eraseblock + * @pnum and stores it in @vid_hdr. It also checks CRC checksum of the read + * volume identifier header. The following codes may be returned: + * + * o %0 if the CRC checksum is correct and the header was successfully read; + * o %UBI_IO_BITFLIPS if the CRC is correct, but bit-flips were detected + * and corrected by the flash driver; this is harmless but may indicate that + * this eraseblock may become bad soon; + * o %UBI_IO_BAD_VID_HRD if the volume identifier header is corrupted (a CRC + * error detected); + * o %UBI_IO_PEB_FREE if the physical eraseblock is free (i.e., there is no VID + * header there); + * o a negative error code in case of failure. + */ +int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, + struct ubi_vid_hdr *vid_hdr, int verbose) +{ + int err, read_err = 0; + uint32_t crc, magic, hdr_crc; + void *p; + + dbg_io("read VID header from PEB %d", pnum); + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + if (UBI_IO_DEBUG) + verbose = 1; + + p = (char *)vid_hdr - ubi->vid_hdr_shift; + err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, + ubi->vid_hdr_alsize); + if (err) { + if (err != UBI_IO_BITFLIPS && err != -EBADMSG) + return err; + + /* + * We read all the data, but either a correctable bit-flip + * occurred, or MTD reported about some data integrity error, + * like an ECC error in case of NAND. The former is harmless, + * the later may mean the read data is corrupted. But we have a + * CRC check-sum and we will identify this. If the VID header is + * still OK, we just report this as there was a bit-flip. + */ + read_err = err; + } + + magic = be32_to_cpu(vid_hdr->magic); + if (magic != UBI_VID_HDR_MAGIC) { + /* + * If we have read all 0xFF bytes, the VID header probably does + * not exist and the physical eraseblock is assumed to be free. + * + * But if there was a read error, we do not test the data for + * 0xFFs. Even if it does contain all 0xFFs, this error + * indicates that something is still wrong with this physical + * eraseblock and it cannot be regarded as free. + */ + if (read_err != -EBADMSG && + check_pattern(vid_hdr, 0xFF, UBI_VID_HDR_SIZE)) { + /* The physical eraseblock is supposedly free */ + + /* + * The below is just a paranoid check, it has to be + * compiled out if paranoid checks are disabled. + */ + err = paranoid_check_all_ff(ubi, pnum, ubi->leb_start, + ubi->leb_size); + if (err) + return err > 0 ? UBI_IO_BAD_VID_HDR : err; + + if (verbose) + ubi_warn("no VID header found at PEB %d, " + "only 0xFF bytes", pnum); + return UBI_IO_PEB_FREE; + } + + /* + * This is not a valid VID header, and these are not 0xFF + * bytes. Report that the header is corrupted. + */ + if (verbose) { + ubi_warn("bad magic number at PEB %d: %08x instead of " + "%08x", pnum, magic, UBI_VID_HDR_MAGIC); + ubi_dbg_dump_vid_hdr(vid_hdr); + } + return UBI_IO_BAD_VID_HDR; + } + + crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); + hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); + + if (hdr_crc != crc) { + if (verbose) { + ubi_warn("bad CRC at PEB %d, calculated %#08x, " + "read %#08x", pnum, crc, hdr_crc); + ubi_dbg_dump_vid_hdr(vid_hdr); + } + return UBI_IO_BAD_VID_HDR; + } + + /* Validate the VID header that we have just read */ + err = validate_vid_hdr(ubi, vid_hdr); + if (err) { + ubi_err("validation failed for PEB %d", pnum); + return -EINVAL; + } + + return read_err ? UBI_IO_BITFLIPS : 0; +} + +/** + * ubi_io_write_vid_hdr - write a volume identifier header. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to write to + * @vid_hdr: the volume identifier header to write + * + * This function writes the volume identifier header described by @vid_hdr to + * physical eraseblock @pnum. This function automatically fills the + * @vid_hdr->magic and the @vid_hdr->version fields, as well as calculates + * header CRC checksum and stores it at vid_hdr->hdr_crc. + * + * This function returns zero in case of success and a negative error code in + * case of failure. If %-EIO is returned, the physical eraseblock probably went + * bad. + */ +int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, + struct ubi_vid_hdr *vid_hdr) +{ + int err; + uint32_t crc; + void *p; + + dbg_io("write VID header to PEB %d", pnum); + ubi_assert(pnum >= 0 && pnum < ubi->peb_count); + + err = paranoid_check_peb_ec_hdr(ubi, pnum); + if (err) + return err > 0 ? -EINVAL: err; + + vid_hdr->magic = cpu_to_be32(UBI_VID_HDR_MAGIC); + vid_hdr->version = UBI_VERSION; + crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_VID_HDR_SIZE_CRC); + vid_hdr->hdr_crc = cpu_to_be32(crc); + + err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr); + if (err) + return -EINVAL; + + p = (char *)vid_hdr - ubi->vid_hdr_shift; + err = ubi_io_write(ubi, p, pnum, ubi->vid_hdr_aloffset, + ubi->vid_hdr_alsize); + return err; +} + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID + +/** + * paranoid_check_not_bad - ensure that a physical eraseblock is not bad. + * @ubi: UBI device description object + * @pnum: physical eraseblock number to check + * + * This function returns zero if the physical eraseblock is good, a positive + * number if it is bad and a negative error code if an error occurred. + */ +static int paranoid_check_not_bad(const struct ubi_device *ubi, int pnum) +{ + int err; + + err = ubi_io_is_bad(ubi, pnum); + if (!err) + return err; + + ubi_err("paranoid check failed for PEB %d", pnum); + ubi_dbg_dump_stack(); + return err; +} + +/** + * paranoid_check_ec_hdr - check if an erase counter header is all right. + * @ubi: UBI device description object + * @pnum: physical eraseblock number the erase counter header belongs to + * @ec_hdr: the erase counter header to check + * + * This function returns zero if the erase counter header contains valid + * values, and %1 if not. + */ +static int paranoid_check_ec_hdr(const struct ubi_device *ubi, int pnum, + const struct ubi_ec_hdr *ec_hdr) +{ + int err; + uint32_t magic; + + magic = be32_to_cpu(ec_hdr->magic); + if (magic != UBI_EC_HDR_MAGIC) { + ubi_err("bad magic %#08x, must be %#08x", + magic, UBI_EC_HDR_MAGIC); + goto fail; + } + + err = validate_ec_hdr(ubi, ec_hdr); + if (err) { + ubi_err("paranoid check failed for PEB %d", pnum); + goto fail; + } + + return 0; + +fail: + ubi_dbg_dump_ec_hdr(ec_hdr); + ubi_dbg_dump_stack(); + return 1; +} + +/** + * paranoid_check_peb_ec_hdr - check that the erase counter header of a + * physical eraseblock is in-place and is all right. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to check + * + * This function returns zero if the erase counter header is all right, %1 if + * not, and a negative error code if an error occurred. + */ +static int paranoid_check_peb_ec_hdr(const struct ubi_device *ubi, int pnum) +{ + int err; + uint32_t crc, hdr_crc; + struct ubi_ec_hdr *ec_hdr; + + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); + if (!ec_hdr) + return -ENOMEM; + + err = ubi_io_read(ubi, ec_hdr, pnum, 0, UBI_EC_HDR_SIZE); + if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + goto exit; + + crc = crc32(UBI_CRC32_INIT, ec_hdr, UBI_EC_HDR_SIZE_CRC); + hdr_crc = be32_to_cpu(ec_hdr->hdr_crc); + if (hdr_crc != crc) { + ubi_err("bad CRC, calculated %#08x, read %#08x", crc, hdr_crc); + ubi_err("paranoid check failed for PEB %d", pnum); + ubi_dbg_dump_ec_hdr(ec_hdr); + ubi_dbg_dump_stack(); + err = 1; + goto exit; + } + + err = paranoid_check_ec_hdr(ubi, pnum, ec_hdr); + +exit: + kfree(ec_hdr); + return err; +} + +/** + * paranoid_check_vid_hdr - check that a volume identifier header is all right. + * @ubi: UBI device description object + * @pnum: physical eraseblock number the volume identifier header belongs to + * @vid_hdr: the volume identifier header to check + * + * This function returns zero if the volume identifier header is all right, and + * %1 if not. + */ +static int paranoid_check_vid_hdr(const struct ubi_device *ubi, int pnum, + const struct ubi_vid_hdr *vid_hdr) +{ + int err; + uint32_t magic; + + magic = be32_to_cpu(vid_hdr->magic); + if (magic != UBI_VID_HDR_MAGIC) { + ubi_err("bad VID header magic %#08x at PEB %d, must be %#08x", + magic, pnum, UBI_VID_HDR_MAGIC); + goto fail; + } + + err = validate_vid_hdr(ubi, vid_hdr); + if (err) { + ubi_err("paranoid check failed for PEB %d", pnum); + goto fail; + } + + return err; + +fail: + ubi_err("paranoid check failed for PEB %d", pnum); + ubi_dbg_dump_vid_hdr(vid_hdr); + ubi_dbg_dump_stack(); + return 1; + +} + +/** + * paranoid_check_peb_vid_hdr - check that the volume identifier header of a + * physical eraseblock is in-place and is all right. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to check + * + * This function returns zero if the volume identifier header is all right, + * %1 if not, and a negative error code if an error occurred. + */ +static int paranoid_check_peb_vid_hdr(const struct ubi_device *ubi, int pnum) +{ + int err; + uint32_t crc, hdr_crc; + struct ubi_vid_hdr *vid_hdr; + void *p; + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) + return -ENOMEM; + + p = (char *)vid_hdr - ubi->vid_hdr_shift; + err = ubi_io_read(ubi, p, pnum, ubi->vid_hdr_aloffset, + ubi->vid_hdr_alsize); + if (err && err != UBI_IO_BITFLIPS && err != -EBADMSG) + goto exit; + + crc = crc32(UBI_CRC32_INIT, vid_hdr, UBI_EC_HDR_SIZE_CRC); + hdr_crc = be32_to_cpu(vid_hdr->hdr_crc); + if (hdr_crc != crc) { + ubi_err("bad VID header CRC at PEB %d, calculated %#08x, " + "read %#08x", pnum, crc, hdr_crc); + ubi_err("paranoid check failed for PEB %d", pnum); + ubi_dbg_dump_vid_hdr(vid_hdr); + ubi_dbg_dump_stack(); + err = 1; + goto exit; + } + + err = paranoid_check_vid_hdr(ubi, pnum, vid_hdr); + +exit: + ubi_free_vid_hdr(ubi, vid_hdr); + return err; +} + +/** + * paranoid_check_all_ff - check that a region of flash is empty. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to check + * @offset: the starting offset within the physical eraseblock to check + * @len: the length of the region to check + * + * This function returns zero if only 0xFF bytes are present at offset + * @offset of the physical eraseblock @pnum, %1 if not, and a negative error + * code if an error occurred. + */ +static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, + int len) +{ + size_t read; + int err; + loff_t addr = (loff_t)pnum * ubi->peb_size + offset; + + mutex_lock(&ubi->dbg_buf_mutex); + err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); + if (err && err != -EUCLEAN) { + ubi_err("error %d while reading %d bytes from PEB %d:%d, " + "read %zd bytes", err, len, pnum, offset, read); + goto error; + } + + err = check_pattern(ubi->dbg_peb_buf, 0xFF, len); + if (err == 0) { + ubi_err("flash region at PEB %d:%d, length %d does not " + "contain all 0xFF bytes", pnum, offset, len); + goto fail; + } + mutex_unlock(&ubi->dbg_buf_mutex); + + return 0; + +fail: + ubi_err("paranoid check failed for PEB %d", pnum); + dbg_msg("hex dump of the %d-%d region", offset, offset + len); + print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, + ubi->dbg_peb_buf, len, 1); + err = 1; +error: + ubi_dbg_dump_stack(); + mutex_unlock(&ubi->dbg_buf_mutex); + return err; +} + +#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c new file mode 100644 index 0000000..d423f87 --- /dev/null +++ b/drivers/mtd/ubi/kapi.c @@ -0,0 +1,638 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* This file mostly implements UBI kernel API functions */ + +#ifdef UBI_LINUX +#include +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +/** + * ubi_get_device_info - get information about UBI device. + * @ubi_num: UBI device number + * @di: the information is stored here + * + * This function returns %0 in case of success, %-EINVAL if the UBI device + * number is invalid, and %-ENODEV if there is no such UBI device. + */ +int ubi_get_device_info(int ubi_num, struct ubi_device_info *di) +{ + struct ubi_device *ubi; + + if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) + return -EINVAL; + + ubi = ubi_get_device(ubi_num); + if (!ubi) + return -ENODEV; + + di->ubi_num = ubi->ubi_num; + di->leb_size = ubi->leb_size; + di->min_io_size = ubi->min_io_size; + di->ro_mode = ubi->ro_mode; + di->cdev = &ubi->cdev; + + ubi_put_device(ubi); + return 0; +} +EXPORT_SYMBOL_GPL(ubi_get_device_info); + +/** + * ubi_get_volume_info - get information about UBI volume. + * @desc: volume descriptor + * @vi: the information is stored here + */ +void ubi_get_volume_info(struct ubi_volume_desc *desc, + struct ubi_volume_info *vi) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + + vi->vol_id = vol->vol_id; + vi->ubi_num = ubi->ubi_num; + vi->size = vol->reserved_pebs; + vi->used_bytes = vol->used_bytes; + vi->vol_type = vol->vol_type; + vi->corrupted = vol->corrupted; + vi->upd_marker = vol->upd_marker; + vi->alignment = vol->alignment; + vi->usable_leb_size = vol->usable_leb_size; + vi->name_len = vol->name_len; + vi->name = vol->name; + vi->cdev = &vol->cdev; +} +EXPORT_SYMBOL_GPL(ubi_get_volume_info); + +/** + * ubi_open_volume - open UBI volume. + * @ubi_num: UBI device number + * @vol_id: volume ID + * @mode: open mode + * + * The @mode parameter specifies if the volume should be opened in read-only + * mode, read-write mode, or exclusive mode. The exclusive mode guarantees that + * nobody else will be able to open this volume. UBI allows to have many volume + * readers and one writer at a time. + * + * If a static volume is being opened for the first time since boot, it will be + * checked by this function, which means it will be fully read and the CRC + * checksum of each logical eraseblock will be checked. + * + * This function returns volume descriptor in case of success and a negative + * error code in case of failure. + */ +struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) +{ + int err; + struct ubi_volume_desc *desc; + struct ubi_device *ubi; + struct ubi_volume *vol; + + dbg_msg("open device %d volume %d, mode %d", ubi_num, vol_id, mode); + + if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) + return ERR_PTR(-EINVAL); + + if (mode != UBI_READONLY && mode != UBI_READWRITE && + mode != UBI_EXCLUSIVE) + return ERR_PTR(-EINVAL); + + /* + * First of all, we have to get the UBI device to prevent its removal. + */ + ubi = ubi_get_device(ubi_num); + if (!ubi) + return ERR_PTR(-ENODEV); + + if (vol_id < 0 || vol_id >= ubi->vtbl_slots) { + err = -EINVAL; + goto out_put_ubi; + } + + desc = kmalloc(sizeof(struct ubi_volume_desc), GFP_KERNEL); + if (!desc) { + err = -ENOMEM; + goto out_put_ubi; + } + + err = -ENODEV; + if (!try_module_get(THIS_MODULE)) + goto out_free; + + spin_lock(&ubi->volumes_lock); + vol = ubi->volumes[vol_id]; + if (!vol) + goto out_unlock; + + err = -EBUSY; + switch (mode) { + case UBI_READONLY: + if (vol->exclusive) + goto out_unlock; + vol->readers += 1; + break; + + case UBI_READWRITE: + if (vol->exclusive || vol->writers > 0) + goto out_unlock; + vol->writers += 1; + break; + + case UBI_EXCLUSIVE: + if (vol->exclusive || vol->writers || vol->readers) + goto out_unlock; + vol->exclusive = 1; + break; + } + get_device(&vol->dev); + vol->ref_count += 1; + spin_unlock(&ubi->volumes_lock); + + desc->vol = vol; + desc->mode = mode; + + mutex_lock(&ubi->ckvol_mutex); + if (!vol->checked) { + /* This is the first open - check the volume */ + err = ubi_check_volume(ubi, vol_id); + if (err < 0) { + mutex_unlock(&ubi->ckvol_mutex); + ubi_close_volume(desc); + return ERR_PTR(err); + } + if (err == 1) { + ubi_warn("volume %d on UBI device %d is corrupted", + vol_id, ubi->ubi_num); + vol->corrupted = 1; + } + vol->checked = 1; + } + mutex_unlock(&ubi->ckvol_mutex); + + return desc; + +out_unlock: + spin_unlock(&ubi->volumes_lock); + module_put(THIS_MODULE); +out_free: + kfree(desc); +out_put_ubi: + ubi_put_device(ubi); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(ubi_open_volume); + +/** + * ubi_open_volume_nm - open UBI volume by name. + * @ubi_num: UBI device number + * @name: volume name + * @mode: open mode + * + * This function is similar to 'ubi_open_volume()', but opens a volume by name. + */ +struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, + int mode) +{ + int i, vol_id = -1, len; + struct ubi_device *ubi; + struct ubi_volume_desc *ret; + + dbg_msg("open volume %s, mode %d", name, mode); + + if (!name) + return ERR_PTR(-EINVAL); + + len = strnlen(name, UBI_VOL_NAME_MAX + 1); + if (len > UBI_VOL_NAME_MAX) + return ERR_PTR(-EINVAL); + + if (ubi_num < 0 || ubi_num >= UBI_MAX_DEVICES) + return ERR_PTR(-EINVAL); + + ubi = ubi_get_device(ubi_num); + if (!ubi) + return ERR_PTR(-ENODEV); + + spin_lock(&ubi->volumes_lock); + /* Walk all volumes of this UBI device */ + for (i = 0; i < ubi->vtbl_slots; i++) { + struct ubi_volume *vol = ubi->volumes[i]; + + if (vol && len == vol->name_len && !strcmp(name, vol->name)) { + vol_id = i; + break; + } + } + spin_unlock(&ubi->volumes_lock); + + if (vol_id >= 0) + ret = ubi_open_volume(ubi_num, vol_id, mode); + else + ret = ERR_PTR(-ENODEV); + + /* + * We should put the UBI device even in case of success, because + * 'ubi_open_volume()' took a reference as well. + */ + ubi_put_device(ubi); + return ret; +} +EXPORT_SYMBOL_GPL(ubi_open_volume_nm); + +/** + * ubi_close_volume - close UBI volume. + * @desc: volume descriptor + */ +void ubi_close_volume(struct ubi_volume_desc *desc) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + + dbg_msg("close volume %d, mode %d", vol->vol_id, desc->mode); + + spin_lock(&ubi->volumes_lock); + switch (desc->mode) { + case UBI_READONLY: + vol->readers -= 1; + break; + case UBI_READWRITE: + vol->writers -= 1; + break; + case UBI_EXCLUSIVE: + vol->exclusive = 0; + } + vol->ref_count -= 1; + spin_unlock(&ubi->volumes_lock); + + kfree(desc); + put_device(&vol->dev); + ubi_put_device(ubi); + module_put(THIS_MODULE); +} +EXPORT_SYMBOL_GPL(ubi_close_volume); + +/** + * ubi_leb_read - read data. + * @desc: volume descriptor + * @lnum: logical eraseblock number to read from + * @buf: buffer where to store the read data + * @offset: offset within the logical eraseblock to read from + * @len: how many bytes to read + * @check: whether UBI has to check the read data's CRC or not. + * + * This function reads data from offset @offset of logical eraseblock @lnum and + * stores the data at @buf. When reading from static volumes, @check specifies + * whether the data has to be checked or not. If yes, the whole logical + * eraseblock will be read and its CRC checksum will be checked (i.e., the CRC + * checksum is per-eraseblock). So checking may substantially slow down the + * read speed. The @check argument is ignored for dynamic volumes. + * + * In case of success, this function returns zero. In case of failure, this + * function returns a negative error code. + * + * %-EBADMSG error code is returned: + * o for both static and dynamic volumes if MTD driver has detected a data + * integrity problem (unrecoverable ECC checksum mismatch in case of NAND); + * o for static volumes in case of data CRC mismatch. + * + * If the volume is damaged because of an interrupted update this function just + * returns immediately with %-EBADF error code. + */ +int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, + int len, int check) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + int err, vol_id = vol->vol_id; + + dbg_msg("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset); + + if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 || + lnum >= vol->used_ebs || offset < 0 || len < 0 || + offset + len > vol->usable_leb_size) + return -EINVAL; + + if (vol->vol_type == UBI_STATIC_VOLUME) { + if (vol->used_ebs == 0) + /* Empty static UBI volume */ + return 0; + if (lnum == vol->used_ebs - 1 && + offset + len > vol->last_eb_bytes) + return -EINVAL; + } + + if (vol->upd_marker) + return -EBADF; + if (len == 0) + return 0; + + err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); + if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { + ubi_warn("mark volume %d as corrupted", vol_id); + vol->corrupted = 1; + } + + return err; +} +EXPORT_SYMBOL_GPL(ubi_leb_read); + +/** + * ubi_leb_write - write data. + * @desc: volume descriptor + * @lnum: logical eraseblock number to write to + * @buf: data to write + * @offset: offset within the logical eraseblock where to write + * @len: how many bytes to write + * @dtype: expected data type + * + * This function writes @len bytes of data from @buf to offset @offset of + * logical eraseblock @lnum. The @dtype argument describes expected lifetime of + * the data. + * + * This function takes care of physical eraseblock write failures. If write to + * the physical eraseblock write operation fails, the logical eraseblock is + * re-mapped to another physical eraseblock, the data is recovered, and the + * write finishes. UBI has a pool of reserved physical eraseblocks for this. + * + * If all the data were successfully written, zero is returned. If an error + * occurred and UBI has not been able to recover from it, this function returns + * a negative error code. Note, in case of an error, it is possible that + * something was still written to the flash media, but that may be some + * garbage. + * + * If the volume is damaged because of an interrupted update this function just + * returns immediately with %-EBADF code. + */ +int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, + int offset, int len, int dtype) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + int vol_id = vol->vol_id; + + dbg_msg("write %d bytes to LEB %d:%d:%d", len, vol_id, lnum, offset); + + if (vol_id < 0 || vol_id >= ubi->vtbl_slots) + return -EINVAL; + + if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) + return -EROFS; + + if (lnum < 0 || lnum >= vol->reserved_pebs || offset < 0 || len < 0 || + offset + len > vol->usable_leb_size || + offset & (ubi->min_io_size - 1) || len & (ubi->min_io_size - 1)) + return -EINVAL; + + if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && + dtype != UBI_UNKNOWN) + return -EINVAL; + + if (vol->upd_marker) + return -EBADF; + + if (len == 0) + return 0; + + return ubi_eba_write_leb(ubi, vol, lnum, buf, offset, len, dtype); +} +EXPORT_SYMBOL_GPL(ubi_leb_write); + +/* + * ubi_leb_change - change logical eraseblock atomically. + * @desc: volume descriptor + * @lnum: logical eraseblock number to change + * @buf: data to write + * @len: how many bytes to write + * @dtype: expected data type + * + * This function changes the contents of a logical eraseblock atomically. @buf + * has to contain new logical eraseblock data, and @len - the length of the + * data, which has to be aligned. The length may be shorter then the logical + * eraseblock size, ant the logical eraseblock may be appended to more times + * later on. This function guarantees that in case of an unclean reboot the old + * contents is preserved. Returns zero in case of success and a negative error + * code in case of failure. + */ +int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, + int len, int dtype) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + int vol_id = vol->vol_id; + + dbg_msg("atomically write %d bytes to LEB %d:%d", len, vol_id, lnum); + + if (vol_id < 0 || vol_id >= ubi->vtbl_slots) + return -EINVAL; + + if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) + return -EROFS; + + if (lnum < 0 || lnum >= vol->reserved_pebs || len < 0 || + len > vol->usable_leb_size || len & (ubi->min_io_size - 1)) + return -EINVAL; + + if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && + dtype != UBI_UNKNOWN) + return -EINVAL; + + if (vol->upd_marker) + return -EBADF; + + if (len == 0) + return 0; + + return ubi_eba_atomic_leb_change(ubi, vol, lnum, buf, len, dtype); +} +EXPORT_SYMBOL_GPL(ubi_leb_change); + +/** + * ubi_leb_erase - erase logical eraseblock. + * @desc: volume descriptor + * @lnum: logical eraseblock number + * + * This function un-maps logical eraseblock @lnum and synchronously erases the + * correspondent physical eraseblock. Returns zero in case of success and a + * negative error code in case of failure. + * + * If the volume is damaged because of an interrupted update this function just + * returns immediately with %-EBADF code. + */ +int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + int err; + + dbg_msg("erase LEB %d:%d", vol->vol_id, lnum); + + if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) + return -EROFS; + + if (lnum < 0 || lnum >= vol->reserved_pebs) + return -EINVAL; + + if (vol->upd_marker) + return -EBADF; + + err = ubi_eba_unmap_leb(ubi, vol, lnum); + if (err) + return err; + + return ubi_wl_flush(ubi); +} +EXPORT_SYMBOL_GPL(ubi_leb_erase); + +/** + * ubi_leb_unmap - un-map logical eraseblock. + * @desc: volume descriptor + * @lnum: logical eraseblock number + * + * This function un-maps logical eraseblock @lnum and schedules the + * corresponding physical eraseblock for erasure, so that it will eventually be + * physically erased in background. This operation is much faster then the + * erase operation. + * + * Unlike erase, the un-map operation does not guarantee that the logical + * eraseblock will contain all 0xFF bytes when UBI is initialized again. For + * example, if several logical eraseblocks are un-mapped, and an unclean reboot + * happens after this, the logical eraseblocks will not necessarily be + * un-mapped again when this MTD device is attached. They may actually be + * mapped to the same physical eraseblocks again. So, this function has to be + * used with care. + * + * In other words, when un-mapping a logical eraseblock, UBI does not store + * any information about this on the flash media, it just marks the logical + * eraseblock as "un-mapped" in RAM. If UBI is detached before the physical + * eraseblock is physically erased, it will be mapped again to the same logical + * eraseblock when the MTD device is attached again. + * + * The main and obvious use-case of this function is when the contents of a + * logical eraseblock has to be re-written. Then it is much more efficient to + * first un-map it, then write new data, rather then first erase it, then write + * new data. Note, once new data has been written to the logical eraseblock, + * UBI guarantees that the old contents has gone forever. In other words, if an + * unclean reboot happens after the logical eraseblock has been un-mapped and + * then written to, it will contain the last written data. + * + * This function returns zero in case of success and a negative error code in + * case of failure. If the volume is damaged because of an interrupted update + * this function just returns immediately with %-EBADF code. + */ +int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + + dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); + + if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) + return -EROFS; + + if (lnum < 0 || lnum >= vol->reserved_pebs) + return -EINVAL; + + if (vol->upd_marker) + return -EBADF; + + return ubi_eba_unmap_leb(ubi, vol, lnum); +} +EXPORT_SYMBOL_GPL(ubi_leb_unmap); + +/** + * ubi_leb_map - map logical erasblock to a physical eraseblock. + * @desc: volume descriptor + * @lnum: logical eraseblock number + * @dtype: expected data type + * + * This function maps an un-mapped logical eraseblock @lnum to a physical + * eraseblock. This means, that after a successfull invocation of this + * function the logical eraseblock @lnum will be empty (contain only %0xFF + * bytes) and be mapped to a physical eraseblock, even if an unclean reboot + * happens. + * + * This function returns zero in case of success, %-EBADF if the volume is + * damaged because of an interrupted update, %-EBADMSG if the logical + * eraseblock is already mapped, and other negative error codes in case of + * other failures. + */ +int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + + dbg_msg("unmap LEB %d:%d", vol->vol_id, lnum); + + if (desc->mode == UBI_READONLY || vol->vol_type == UBI_STATIC_VOLUME) + return -EROFS; + + if (lnum < 0 || lnum >= vol->reserved_pebs) + return -EINVAL; + + if (dtype != UBI_LONGTERM && dtype != UBI_SHORTTERM && + dtype != UBI_UNKNOWN) + return -EINVAL; + + if (vol->upd_marker) + return -EBADF; + + if (vol->eba_tbl[lnum] >= 0) + return -EBADMSG; + + return ubi_eba_write_leb(ubi, vol, lnum, NULL, 0, 0, dtype); +} +EXPORT_SYMBOL_GPL(ubi_leb_map); + +/** + * ubi_is_mapped - check if logical eraseblock is mapped. + * @desc: volume descriptor + * @lnum: logical eraseblock number + * + * This function checks if logical eraseblock @lnum is mapped to a physical + * eraseblock. If a logical eraseblock is un-mapped, this does not necessarily + * mean it will still be un-mapped after the UBI device is re-attached. The + * logical eraseblock may become mapped to the physical eraseblock it was last + * mapped to. + * + * This function returns %1 if the LEB is mapped, %0 if not, and a negative + * error code in case of failure. If the volume is damaged because of an + * interrupted update this function just returns immediately with %-EBADF error + * code. + */ +int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum) +{ + struct ubi_volume *vol = desc->vol; + + dbg_msg("test LEB %d:%d", vol->vol_id, lnum); + + if (lnum < 0 || lnum >= vol->reserved_pebs) + return -EINVAL; + + if (vol->upd_marker) + return -EBADF; + + return vol->eba_tbl[lnum] >= 0; +} +EXPORT_SYMBOL_GPL(ubi_is_mapped); diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c new file mode 100644 index 0000000..298925d --- /dev/null +++ b/drivers/mtd/ubi/misc.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* Here we keep miscellaneous functions which are used all over the UBI code */ + +#include "ubi-barebox.h" +#include "ubi.h" + +/** + * calc_data_len - calculate how much real data is stored in a buffer. + * @ubi: UBI device description object + * @buf: a buffer with the contents of the physical eraseblock + * @length: the buffer length + * + * This function calculates how much "real data" is stored in @buf and returnes + * the length. Continuous 0xFF bytes at the end of the buffer are not + * considered as "real data". + */ +int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, + int length) +{ + int i; + + ubi_assert(!(length & (ubi->min_io_size - 1))); + + for (i = length - 1; i >= 0; i--) + if (((const uint8_t *)buf)[i] != 0xFF) + break; + + /* The resulting length must be aligned to the minimum flash I/O size */ + length = ALIGN(i + 1, ubi->min_io_size); + return length; +} + +/** + * ubi_check_volume - check the contents of a static volume. + * @ubi: UBI device description object + * @vol_id: ID of the volume to check + * + * This function checks if static volume @vol_id is corrupted by fully reading + * it and checking data CRC. This function returns %0 if the volume is not + * corrupted, %1 if it is corrupted and a negative error code in case of + * failure. Dynamic volumes are not checked and zero is returned immediately. + */ +int ubi_check_volume(struct ubi_device *ubi, int vol_id) +{ + void *buf; + int err = 0, i; + struct ubi_volume *vol = ubi->volumes[vol_id]; + + if (vol->vol_type != UBI_STATIC_VOLUME) + return 0; + + buf = vmalloc(vol->usable_leb_size); + if (!buf) + return -ENOMEM; + + for (i = 0; i < vol->used_ebs; i++) { + int size; + + if (i == vol->used_ebs - 1) + size = vol->last_eb_bytes; + else + size = vol->usable_leb_size; + + err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); + if (err) { + if (err == -EBADMSG) + err = 1; + break; + } + } + + vfree(buf); + return err; +} + +/** + * ubi_calculate_rsvd_pool - calculate how many PEBs must be reserved for bad + * eraseblock handling. + * @ubi: UBI device description object + */ +void ubi_calculate_reserved(struct ubi_device *ubi) +{ + ubi->beb_rsvd_level = ubi->good_peb_count/100; + ubi->beb_rsvd_level *= CONFIG_MTD_UBI_BEB_RESERVE; + if (ubi->beb_rsvd_level < MIN_RESEVED_PEBS) + ubi->beb_rsvd_level = MIN_RESEVED_PEBS; +} diff --git a/drivers/mtd/ubi/scan.c b/drivers/mtd/ubi/scan.c new file mode 100644 index 0000000..3e7fc35 --- /dev/null +++ b/drivers/mtd/ubi/scan.c @@ -0,0 +1,1362 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* + * UBI scanning unit. + * + * This unit is responsible for scanning the flash media, checking UBI + * headers and providing complete information about the UBI flash image. + * + * The scanning information is represented by a &struct ubi_scan_info' object. + * Information about found volumes is represented by &struct ubi_scan_volume + * objects which are kept in volume RB-tree with root at the @volumes field. + * The RB-tree is indexed by the volume ID. + * + * Found logical eraseblocks are represented by &struct ubi_scan_leb objects. + * These objects are kept in per-volume RB-trees with the root at the + * corresponding &struct ubi_scan_volume object. To put it differently, we keep + * an RB-tree of per-volume objects and each of these objects is the root of + * RB-tree of per-eraseblock objects. + * + * Corrupted physical eraseblocks are put to the @corr list, free physical + * eraseblocks are put to the @free list and the physical eraseblock to be + * erased are put to the @erase list. + */ + +#ifdef UBI_LINUX +#include +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID +static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si); +#else +#define paranoid_check_si(ubi, si) 0 +#endif + +/* Temporary variables used during scanning */ +static struct ubi_ec_hdr *ech; +static struct ubi_vid_hdr *vidh; + +/** + * add_to_list - add physical eraseblock to a list. + * @si: scanning information + * @pnum: physical eraseblock number to add + * @ec: erase counter of the physical eraseblock + * @list: the list to add to + * + * This function adds physical eraseblock @pnum to free, erase, corrupted or + * alien lists. Returns zero in case of success and a negative error code in + * case of failure. + */ +static int add_to_list(struct ubi_scan_info *si, int pnum, int ec, + struct list_head *list) +{ + struct ubi_scan_leb *seb; + + if (list == &si->free) + dbg_bld("add to free: PEB %d, EC %d", pnum, ec); + else if (list == &si->erase) + dbg_bld("add to erase: PEB %d, EC %d", pnum, ec); + else if (list == &si->corr) + dbg_bld("add to corrupted: PEB %d, EC %d", pnum, ec); + else if (list == &si->alien) + dbg_bld("add to alien: PEB %d, EC %d", pnum, ec); + else + BUG(); + + seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); + if (!seb) + return -ENOMEM; + + seb->pnum = pnum; + seb->ec = ec; + list_add_tail(&seb->u.list, list); + return 0; +} + +/** + * validate_vid_hdr - check that volume identifier header is correct and + * consistent. + * @vid_hdr: the volume identifier header to check + * @sv: information about the volume this logical eraseblock belongs to + * @pnum: physical eraseblock number the VID header came from + * + * This function checks that data stored in @vid_hdr is consistent. Returns + * non-zero if an inconsistency was found and zero if not. + * + * Note, UBI does sanity check of everything it reads from the flash media. + * Most of the checks are done in the I/O unit. Here we check that the + * information in the VID header is consistent to the information in other VID + * headers of the same volume. + */ +static int validate_vid_hdr(const struct ubi_vid_hdr *vid_hdr, + const struct ubi_scan_volume *sv, int pnum) +{ + int vol_type = vid_hdr->vol_type; + int vol_id = be32_to_cpu(vid_hdr->vol_id); + int used_ebs = be32_to_cpu(vid_hdr->used_ebs); + int data_pad = be32_to_cpu(vid_hdr->data_pad); + + if (sv->leb_count != 0) { + int sv_vol_type; + + /* + * This is not the first logical eraseblock belonging to this + * volume. Ensure that the data in its VID header is consistent + * to the data in previous logical eraseblock headers. + */ + + if (vol_id != sv->vol_id) { + dbg_err("inconsistent vol_id"); + goto bad; + } + + if (sv->vol_type == UBI_STATIC_VOLUME) + sv_vol_type = UBI_VID_STATIC; + else + sv_vol_type = UBI_VID_DYNAMIC; + + if (vol_type != sv_vol_type) { + dbg_err("inconsistent vol_type"); + goto bad; + } + + if (used_ebs != sv->used_ebs) { + dbg_err("inconsistent used_ebs"); + goto bad; + } + + if (data_pad != sv->data_pad) { + dbg_err("inconsistent data_pad"); + goto bad; + } + } + + return 0; + +bad: + ubi_err("inconsistent VID header at PEB %d", pnum); + ubi_dbg_dump_vid_hdr(vid_hdr); + ubi_dbg_dump_sv(sv); + return -EINVAL; +} + +/** + * add_volume - add volume to the scanning information. + * @si: scanning information + * @vol_id: ID of the volume to add + * @pnum: physical eraseblock number + * @vid_hdr: volume identifier header + * + * If the volume corresponding to the @vid_hdr logical eraseblock is already + * present in the scanning information, this function does nothing. Otherwise + * it adds corresponding volume to the scanning information. Returns a pointer + * to the scanning volume object in case of success and a negative error code + * in case of failure. + */ +static struct ubi_scan_volume *add_volume(struct ubi_scan_info *si, int vol_id, + int pnum, + const struct ubi_vid_hdr *vid_hdr) +{ + struct ubi_scan_volume *sv; + struct rb_node **p = &si->volumes.rb_node, *parent = NULL; + + ubi_assert(vol_id == be32_to_cpu(vid_hdr->vol_id)); + + /* Walk the volume RB-tree to look if this volume is already present */ + while (*p) { + parent = *p; + sv = rb_entry(parent, struct ubi_scan_volume, rb); + + if (vol_id == sv->vol_id) + return sv; + + if (vol_id > sv->vol_id) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + + /* The volume is absent - add it */ + sv = kmalloc(sizeof(struct ubi_scan_volume), GFP_KERNEL); + if (!sv) + return ERR_PTR(-ENOMEM); + + sv->highest_lnum = sv->leb_count = 0; + sv->vol_id = vol_id; + sv->root = RB_ROOT; + sv->used_ebs = be32_to_cpu(vid_hdr->used_ebs); + sv->data_pad = be32_to_cpu(vid_hdr->data_pad); + sv->compat = vid_hdr->compat; + sv->vol_type = vid_hdr->vol_type == UBI_VID_DYNAMIC ? UBI_DYNAMIC_VOLUME + : UBI_STATIC_VOLUME; + if (vol_id > si->highest_vol_id) + si->highest_vol_id = vol_id; + + rb_link_node(&sv->rb, parent, p); + rb_insert_color(&sv->rb, &si->volumes); + si->vols_found += 1; + dbg_bld("added volume %d", vol_id); + return sv; +} + +/** + * compare_lebs - find out which logical eraseblock is newer. + * @ubi: UBI device description object + * @seb: first logical eraseblock to compare + * @pnum: physical eraseblock number of the second logical eraseblock to + * compare + * @vid_hdr: volume identifier header of the second logical eraseblock + * + * This function compares 2 copies of a LEB and informs which one is newer. In + * case of success this function returns a positive value, in case of failure, a + * negative error code is returned. The success return codes use the following + * bits: + * o bit 0 is cleared: the first PEB (described by @seb) is newer then the + * second PEB (described by @pnum and @vid_hdr); + * o bit 0 is set: the second PEB is newer; + * o bit 1 is cleared: no bit-flips were detected in the newer LEB; + * o bit 1 is set: bit-flips were detected in the newer LEB; + * o bit 2 is cleared: the older LEB is not corrupted; + * o bit 2 is set: the older LEB is corrupted. + */ +static int compare_lebs(struct ubi_device *ubi, const struct ubi_scan_leb *seb, + int pnum, const struct ubi_vid_hdr *vid_hdr) +{ + void *buf; + int len, err, second_is_newer, bitflips = 0, corrupted = 0; + uint32_t data_crc, crc; + struct ubi_vid_hdr *vh = NULL; + unsigned long long sqnum2 = be64_to_cpu(vid_hdr->sqnum); + + if (seb->sqnum == 0 && sqnum2 == 0) { + long long abs, v1 = seb->leb_ver, v2 = be32_to_cpu(vid_hdr->leb_ver); + + /* + * UBI constantly increases the logical eraseblock version + * number and it can overflow. Thus, we have to bear in mind + * that versions that are close to %0xFFFFFFFF are less then + * versions that are close to %0. + * + * The UBI WL unit guarantees that the number of pending tasks + * is not greater then %0x7FFFFFFF. So, if the difference + * between any two versions is greater or equivalent to + * %0x7FFFFFFF, there was an overflow and the logical + * eraseblock with lower version is actually newer then the one + * with higher version. + * + * FIXME: but this is anyway obsolete and will be removed at + * some point. + */ + dbg_bld("using old crappy leb_ver stuff"); + + if (v1 == v2) { + ubi_err("PEB %d and PEB %d have the same version %lld", + seb->pnum, pnum, v1); + return -EINVAL; + } + + abs = v1 - v2; + if (abs < 0) + abs = -abs; + + if (abs < 0x7FFFFFFF) + /* Non-overflow situation */ + second_is_newer = (v2 > v1); + else + second_is_newer = (v2 < v1); + } else + /* Obviously the LEB with lower sequence counter is older */ + second_is_newer = sqnum2 > seb->sqnum; + + /* + * Now we know which copy is newer. If the copy flag of the PEB with + * newer version is not set, then we just return, otherwise we have to + * check data CRC. For the second PEB we already have the VID header, + * for the first one - we'll need to re-read it from flash. + * + * FIXME: this may be optimized so that we wouldn't read twice. + */ + + if (second_is_newer) { + if (!vid_hdr->copy_flag) { + /* It is not a copy, so it is newer */ + dbg_bld("second PEB %d is newer, copy_flag is unset", + pnum); + return 1; + } + } else { + pnum = seb->pnum; + + vh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); + if (!vh) + return -ENOMEM; + + err = ubi_io_read_vid_hdr(ubi, pnum, vh, 0); + if (err) { + if (err == UBI_IO_BITFLIPS) + bitflips = 1; + else { + dbg_err("VID of PEB %d header is bad, but it " + "was OK earlier", pnum); + if (err > 0) + err = -EIO; + + goto out_free_vidh; + } + } + + if (!vh->copy_flag) { + /* It is not a copy, so it is newer */ + dbg_bld("first PEB %d is newer, copy_flag is unset", + pnum); + err = bitflips << 1; + goto out_free_vidh; + } + + vid_hdr = vh; + } + + /* Read the data of the copy and check the CRC */ + + len = be32_to_cpu(vid_hdr->data_size); + buf = vmalloc(len); + if (!buf) { + err = -ENOMEM; + goto out_free_vidh; + } + + err = ubi_io_read_data(ubi, buf, pnum, 0, len); + if (err && err != UBI_IO_BITFLIPS) + goto out_free_buf; + + data_crc = be32_to_cpu(vid_hdr->data_crc); + crc = crc32(UBI_CRC32_INIT, buf, len); + if (crc != data_crc) { + dbg_bld("PEB %d CRC error: calculated %#08x, must be %#08x", + pnum, crc, data_crc); + corrupted = 1; + bitflips = 0; + second_is_newer = !second_is_newer; + } else { + dbg_bld("PEB %d CRC is OK", pnum); + bitflips = !!err; + } + + vfree(buf); + ubi_free_vid_hdr(ubi, vh); + + if (second_is_newer) + dbg_bld("second PEB %d is newer, copy_flag is set", pnum); + else + dbg_bld("first PEB %d is newer, copy_flag is set", pnum); + + return second_is_newer | (bitflips << 1) | (corrupted << 2); + +out_free_buf: + vfree(buf); +out_free_vidh: + ubi_free_vid_hdr(ubi, vh); + return err; +} + +/** + * ubi_scan_add_used - add information about a physical eraseblock to the + * scanning information. + * @ubi: UBI device description object + * @si: scanning information + * @pnum: the physical eraseblock number + * @ec: erase counter + * @vid_hdr: the volume identifier header + * @bitflips: if bit-flips were detected when this physical eraseblock was read + * + * This function adds information about a used physical eraseblock to the + * 'used' tree of the corresponding volume. The function is rather complex + * because it has to handle cases when this is not the first physical + * eraseblock belonging to the same logical eraseblock, and the newer one has + * to be picked, while the older one has to be dropped. This function returns + * zero in case of success and a negative error code in case of failure. + */ +int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, + int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, + int bitflips) +{ + int err, vol_id, lnum; + uint32_t leb_ver; + unsigned long long sqnum; + struct ubi_scan_volume *sv; + struct ubi_scan_leb *seb; + struct rb_node **p, *parent = NULL; + + vol_id = be32_to_cpu(vid_hdr->vol_id); + lnum = be32_to_cpu(vid_hdr->lnum); + sqnum = be64_to_cpu(vid_hdr->sqnum); + leb_ver = be32_to_cpu(vid_hdr->leb_ver); + + dbg_bld("PEB %d, LEB %d:%d, EC %d, sqnum %llu, ver %u, bitflips %d", + pnum, vol_id, lnum, ec, sqnum, leb_ver, bitflips); + + sv = add_volume(si, vol_id, pnum, vid_hdr); + if (IS_ERR(sv) < 0) + return PTR_ERR(sv); + + if (si->max_sqnum < sqnum) + si->max_sqnum = sqnum; + + /* + * Walk the RB-tree of logical eraseblocks of volume @vol_id to look + * if this is the first instance of this logical eraseblock or not. + */ + p = &sv->root.rb_node; + while (*p) { + int cmp_res; + + parent = *p; + seb = rb_entry(parent, struct ubi_scan_leb, u.rb); + if (lnum != seb->lnum) { + if (lnum < seb->lnum) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + continue; + } + + /* + * There is already a physical eraseblock describing the same + * logical eraseblock present. + */ + + dbg_bld("this LEB already exists: PEB %d, sqnum %llu, " + "LEB ver %u, EC %d", seb->pnum, seb->sqnum, + seb->leb_ver, seb->ec); + + /* + * Make sure that the logical eraseblocks have different + * versions. Otherwise the image is bad. + */ + if (seb->leb_ver == leb_ver && leb_ver != 0) { + ubi_err("two LEBs with same version %u", leb_ver); + ubi_dbg_dump_seb(seb, 0); + ubi_dbg_dump_vid_hdr(vid_hdr); + return -EINVAL; + } + + /* + * Make sure that the logical eraseblocks have different + * sequence numbers. Otherwise the image is bad. + * + * FIXME: remove 'sqnum != 0' check when leb_ver is removed. + */ + if (seb->sqnum == sqnum && sqnum != 0) { + ubi_err("two LEBs with same sequence number %llu", + sqnum); + ubi_dbg_dump_seb(seb, 0); + ubi_dbg_dump_vid_hdr(vid_hdr); + return -EINVAL; + } + + /* + * Now we have to drop the older one and preserve the newer + * one. + */ + cmp_res = compare_lebs(ubi, seb, pnum, vid_hdr); + if (cmp_res < 0) + return cmp_res; + + if (cmp_res & 1) { + /* + * This logical eraseblock is newer then the one + * found earlier. + */ + err = validate_vid_hdr(vid_hdr, sv, pnum); + if (err) + return err; + + if (cmp_res & 4) + err = add_to_list(si, seb->pnum, seb->ec, + &si->corr); + else + err = add_to_list(si, seb->pnum, seb->ec, + &si->erase); + if (err) + return err; + + seb->ec = ec; + seb->pnum = pnum; + seb->scrub = ((cmp_res & 2) || bitflips); + seb->sqnum = sqnum; + seb->leb_ver = leb_ver; + + if (sv->highest_lnum == lnum) + sv->last_data_size = + be32_to_cpu(vid_hdr->data_size); + + return 0; + } else { + /* + * This logical eraseblock is older then the one found + * previously. + */ + if (cmp_res & 4) + return add_to_list(si, pnum, ec, &si->corr); + else + return add_to_list(si, pnum, ec, &si->erase); + } + } + + /* + * We've met this logical eraseblock for the first time, add it to the + * scanning information. + */ + + err = validate_vid_hdr(vid_hdr, sv, pnum); + if (err) + return err; + + seb = kmalloc(sizeof(struct ubi_scan_leb), GFP_KERNEL); + if (!seb) + return -ENOMEM; + + seb->ec = ec; + seb->pnum = pnum; + seb->lnum = lnum; + seb->sqnum = sqnum; + seb->scrub = bitflips; + seb->leb_ver = leb_ver; + + if (sv->highest_lnum <= lnum) { + sv->highest_lnum = lnum; + sv->last_data_size = be32_to_cpu(vid_hdr->data_size); + } + + sv->leb_count += 1; + rb_link_node(&seb->u.rb, parent, p); + rb_insert_color(&seb->u.rb, &sv->root); + return 0; +} + +/** + * ubi_scan_find_sv - find information about a particular volume in the + * scanning information. + * @si: scanning information + * @vol_id: the requested volume ID + * + * This function returns a pointer to the volume description or %NULL if there + * are no data about this volume in the scanning information. + */ +struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, + int vol_id) +{ + struct ubi_scan_volume *sv; + struct rb_node *p = si->volumes.rb_node; + + while (p) { + sv = rb_entry(p, struct ubi_scan_volume, rb); + + if (vol_id == sv->vol_id) + return sv; + + if (vol_id > sv->vol_id) + p = p->rb_left; + else + p = p->rb_right; + } + + return NULL; +} + +/** + * ubi_scan_find_seb - find information about a particular logical + * eraseblock in the volume scanning information. + * @sv: a pointer to the volume scanning information + * @lnum: the requested logical eraseblock + * + * This function returns a pointer to the scanning logical eraseblock or %NULL + * if there are no data about it in the scanning volume information. + */ +struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv, + int lnum) +{ + struct ubi_scan_leb *seb; + struct rb_node *p = sv->root.rb_node; + + while (p) { + seb = rb_entry(p, struct ubi_scan_leb, u.rb); + + if (lnum == seb->lnum) + return seb; + + if (lnum > seb->lnum) + p = p->rb_left; + else + p = p->rb_right; + } + + return NULL; +} + +/** + * ubi_scan_rm_volume - delete scanning information about a volume. + * @si: scanning information + * @sv: the volume scanning information to delete + */ +void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv) +{ + struct rb_node *rb; + struct ubi_scan_leb *seb; + + dbg_bld("remove scanning information about volume %d", sv->vol_id); + + while ((rb = rb_first(&sv->root))) { + seb = rb_entry(rb, struct ubi_scan_leb, u.rb); + rb_erase(&seb->u.rb, &sv->root); + list_add_tail(&seb->u.list, &si->erase); + } + + rb_erase(&sv->rb, &si->volumes); + kfree(sv); + si->vols_found -= 1; +} + +/** + * ubi_scan_erase_peb - erase a physical eraseblock. + * @ubi: UBI device description object + * @si: scanning information + * @pnum: physical eraseblock number to erase; + * @ec: erase counter value to write (%UBI_SCAN_UNKNOWN_EC if it is unknown) + * + * This function erases physical eraseblock 'pnum', and writes the erase + * counter header to it. This function should only be used on UBI device + * initialization stages, when the EBA unit had not been yet initialized. This + * function returns zero in case of success and a negative error code in case + * of failure. + */ +int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, + int pnum, int ec) +{ + int err; + struct ubi_ec_hdr *ec_hdr; + + if ((long long)ec >= UBI_MAX_ERASECOUNTER) { + /* + * Erase counter overflow. Upgrade UBI and use 64-bit + * erase counters internally. + */ + ubi_err("erase counter overflow at PEB %d, EC %d", pnum, ec); + return -EINVAL; + } + + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + if (!ec_hdr) + return -ENOMEM; + + ec_hdr->ec = cpu_to_be64(ec); + + err = ubi_io_sync_erase(ubi, pnum, 0); + if (err < 0) + goto out_free; + + err = ubi_io_write_ec_hdr(ubi, pnum, ec_hdr); + +out_free: + kfree(ec_hdr); + return err; +} + +/** + * ubi_scan_get_free_peb - get a free physical eraseblock. + * @ubi: UBI device description object + * @si: scanning information + * + * This function returns a free physical eraseblock. It is supposed to be + * called on the UBI initialization stages when the wear-leveling unit is not + * initialized yet. This function picks a physical eraseblocks from one of the + * lists, writes the EC header if it is needed, and removes it from the list. + * + * This function returns scanning physical eraseblock information in case of + * success and an error code in case of failure. + */ +struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, + struct ubi_scan_info *si) +{ + int err = 0, i; + struct ubi_scan_leb *seb; + + if (!list_empty(&si->free)) { + seb = list_entry(si->free.next, struct ubi_scan_leb, u.list); + list_del(&seb->u.list); + dbg_bld("return free PEB %d, EC %d", seb->pnum, seb->ec); + return seb; + } + + for (i = 0; i < 2; i++) { + struct list_head *head; + struct ubi_scan_leb *tmp_seb; + + if (i == 0) + head = &si->erase; + else + head = &si->corr; + + /* + * We try to erase the first physical eraseblock from the @head + * list and pick it if we succeed, or try to erase the + * next one if not. And so forth. We don't want to take care + * about bad eraseblocks here - they'll be handled later. + */ + list_for_each_entry_safe(seb, tmp_seb, head, u.list) { + if (seb->ec == UBI_SCAN_UNKNOWN_EC) + seb->ec = si->mean_ec; + + err = ubi_scan_erase_peb(ubi, si, seb->pnum, seb->ec+1); + if (err) + continue; + + seb->ec += 1; + list_del(&seb->u.list); + dbg_bld("return PEB %d, EC %d", seb->pnum, seb->ec); + return seb; + } + } + + ubi_err("no eraseblocks found"); + return ERR_PTR(-ENOSPC); +} + +/** + * process_eb - read UBI headers, check them and add corresponding data + * to the scanning information. + * @ubi: UBI device description object + * @si: scanning information + * @pnum: the physical eraseblock number + * + * This function returns a zero if the physical eraseblock was successfully + * handled and a negative error code in case of failure. + */ +static int process_eb(struct ubi_device *ubi, struct ubi_scan_info *si, int pnum) +{ + long long uninitialized_var(ec); + int err, bitflips = 0, vol_id, ec_corr = 0; + + dbg_bld("scan PEB %d", pnum); + + /* Skip bad physical eraseblocks */ + err = ubi_io_is_bad(ubi, pnum); + if (err < 0) + return err; + else if (err) { + /* + * FIXME: this is actually duty of the I/O unit to initialize + * this, but MTD does not provide enough information. + */ + si->bad_peb_count += 1; + return 0; + } + + err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0); + if (err < 0) + return err; + else if (err == UBI_IO_BITFLIPS) + bitflips = 1; + else if (err == UBI_IO_PEB_EMPTY) + return add_to_list(si, pnum, UBI_SCAN_UNKNOWN_EC, &si->erase); + else if (err == UBI_IO_BAD_EC_HDR) { + /* + * We have to also look at the VID header, possibly it is not + * corrupted. Set %bitflips flag in order to make this PEB be + * moved and EC be re-created. + */ + ec_corr = 1; + ec = UBI_SCAN_UNKNOWN_EC; + bitflips = 1; + } + + si->is_empty = 0; + + if (!ec_corr) { + /* Make sure UBI version is OK */ + if (ech->version != UBI_VERSION) { + ubi_err("this UBI version is %d, image version is %d", + UBI_VERSION, (int)ech->version); + return -EINVAL; + } + + ec = be64_to_cpu(ech->ec); + if (ec > UBI_MAX_ERASECOUNTER) { + /* + * Erase counter overflow. The EC headers have 64 bits + * reserved, but we anyway make use of only 31 bit + * values, as this seems to be enough for any existing + * flash. Upgrade UBI and use 64-bit erase counters + * internally. + */ + ubi_err("erase counter overflow, max is %d", + UBI_MAX_ERASECOUNTER); + ubi_dbg_dump_ec_hdr(ech); + return -EINVAL; + } + } + + /* OK, we've done with the EC header, let's look at the VID header */ + + err = ubi_io_read_vid_hdr(ubi, pnum, vidh, 0); + if (err < 0) + return err; + else if (err == UBI_IO_BITFLIPS) + bitflips = 1; + else if (err == UBI_IO_BAD_VID_HDR || + (err == UBI_IO_PEB_FREE && ec_corr)) { + /* VID header is corrupted */ + err = add_to_list(si, pnum, ec, &si->corr); + if (err) + return err; + goto adjust_mean_ec; + } else if (err == UBI_IO_PEB_FREE) { + /* No VID header - the physical eraseblock is free */ + err = add_to_list(si, pnum, ec, &si->free); + if (err) + return err; + goto adjust_mean_ec; + } + + vol_id = be32_to_cpu(vidh->vol_id); + if (vol_id > UBI_MAX_VOLUMES && vol_id != UBI_LAYOUT_VOLUME_ID) { + int lnum = be32_to_cpu(vidh->lnum); + + /* Unsupported internal volume */ + switch (vidh->compat) { + case UBI_COMPAT_DELETE: + ubi_msg("\"delete\" compatible internal volume %d:%d" + " found, remove it", vol_id, lnum); + err = add_to_list(si, pnum, ec, &si->corr); + if (err) + return err; + break; + + case UBI_COMPAT_RO: + ubi_msg("read-only compatible internal volume %d:%d" + " found, switch to read-only mode", + vol_id, lnum); + ubi->ro_mode = 1; + break; + + case UBI_COMPAT_PRESERVE: + ubi_msg("\"preserve\" compatible internal volume %d:%d" + " found", vol_id, lnum); + err = add_to_list(si, pnum, ec, &si->alien); + if (err) + return err; + si->alien_peb_count += 1; + return 0; + + case UBI_COMPAT_REJECT: + ubi_err("incompatible internal volume %d:%d found", + vol_id, lnum); + return -EINVAL; + } + } + + /* Both UBI headers seem to be fine */ + err = ubi_scan_add_used(ubi, si, pnum, ec, vidh, bitflips); + if (err) + return err; + +adjust_mean_ec: + if (!ec_corr) { + si->ec_sum += ec; + si->ec_count += 1; + if (ec > si->max_ec) + si->max_ec = ec; + if (ec < si->min_ec) + si->min_ec = ec; + } + + return 0; +} + +/** + * ubi_scan - scan an MTD device. + * @ubi: UBI device description object + * + * This function does full scanning of an MTD device and returns complete + * information about it. In case of failure, an error code is returned. + */ +struct ubi_scan_info *ubi_scan(struct ubi_device *ubi) +{ + int err, pnum; + struct rb_node *rb1, *rb2; + struct ubi_scan_volume *sv; + struct ubi_scan_leb *seb; + struct ubi_scan_info *si; + + si = kzalloc(sizeof(struct ubi_scan_info), GFP_KERNEL); + if (!si) + return ERR_PTR(-ENOMEM); + + INIT_LIST_HEAD(&si->corr); + INIT_LIST_HEAD(&si->free); + INIT_LIST_HEAD(&si->erase); + INIT_LIST_HEAD(&si->alien); + si->volumes = RB_ROOT; + si->is_empty = 1; + + err = -ENOMEM; + ech = kzalloc(ubi->ec_hdr_alsize, GFP_KERNEL); + if (!ech) + goto out_si; + + vidh = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); + if (!vidh) + goto out_ech; + + for (pnum = 0; pnum < ubi->peb_count; pnum++) { + cond_resched(); + +// dbg_msg("process PEB %d", pnum); + err = process_eb(ubi, si, pnum); + if(err < 0) + printf("err: %d\n", err); + if (err < 0) + goto out_vidh; + } + + dbg_msg("scanning is finished"); + + /* Calculate mean erase counter */ + if (si->ec_count) { + do_div(si->ec_sum, si->ec_count); + si->mean_ec = si->ec_sum; + } + + if (si->is_empty) + ubi_msg("empty MTD device detected"); + + /* + * In case of unknown erase counter we use the mean erase counter + * value. + */ + ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { + ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) + if (seb->ec == UBI_SCAN_UNKNOWN_EC) + seb->ec = si->mean_ec; + } + + list_for_each_entry(seb, &si->free, u.list) { + if (seb->ec == UBI_SCAN_UNKNOWN_EC) + seb->ec = si->mean_ec; + } + + list_for_each_entry(seb, &si->corr, u.list) + if (seb->ec == UBI_SCAN_UNKNOWN_EC) + seb->ec = si->mean_ec; + + list_for_each_entry(seb, &si->erase, u.list) + if (seb->ec == UBI_SCAN_UNKNOWN_EC) + seb->ec = si->mean_ec; + + err = paranoid_check_si(ubi, si); + if (err) { + if (err > 0) + err = -EINVAL; + goto out_vidh; + } + + ubi_free_vid_hdr(ubi, vidh); + kfree(ech); + + return si; + +out_vidh: + ubi_free_vid_hdr(ubi, vidh); +out_ech: + kfree(ech); +out_si: + ubi_scan_destroy_si(si); + return ERR_PTR(err); +} + +/** + * destroy_sv - free the scanning volume information + * @sv: scanning volume information + * + * This function destroys the volume RB-tree (@sv->root) and the scanning + * volume information. + */ +static void destroy_sv(struct ubi_scan_volume *sv) +{ + struct ubi_scan_leb *seb; + struct rb_node *this = sv->root.rb_node; + + while (this) { + if (this->rb_left) + this = this->rb_left; + else if (this->rb_right) + this = this->rb_right; + else { + seb = rb_entry(this, struct ubi_scan_leb, u.rb); + this = rb_parent(this); + if (this) { + if (this->rb_left == &seb->u.rb) + this->rb_left = NULL; + else + this->rb_right = NULL; + } + + kfree(seb); + } + } + kfree(sv); +} + +/** + * ubi_scan_destroy_si - destroy scanning information. + * @si: scanning information + */ +void ubi_scan_destroy_si(struct ubi_scan_info *si) +{ + struct ubi_scan_leb *seb, *seb_tmp; + struct ubi_scan_volume *sv; + struct rb_node *rb; + + list_for_each_entry_safe(seb, seb_tmp, &si->alien, u.list) { + list_del(&seb->u.list); + kfree(seb); + } + list_for_each_entry_safe(seb, seb_tmp, &si->erase, u.list) { + list_del(&seb->u.list); + kfree(seb); + } + list_for_each_entry_safe(seb, seb_tmp, &si->corr, u.list) { + list_del(&seb->u.list); + kfree(seb); + } + list_for_each_entry_safe(seb, seb_tmp, &si->free, u.list) { + list_del(&seb->u.list); + kfree(seb); + } + + /* Destroy the volume RB-tree */ + rb = si->volumes.rb_node; + while (rb) { + if (rb->rb_left) + rb = rb->rb_left; + else if (rb->rb_right) + rb = rb->rb_right; + else { + sv = rb_entry(rb, struct ubi_scan_volume, rb); + + rb = rb_parent(rb); + if (rb) { + if (rb->rb_left == &sv->rb) + rb->rb_left = NULL; + else + rb->rb_right = NULL; + } + + destroy_sv(sv); + } + } + + kfree(si); +} + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID + +/** + * paranoid_check_si - check if the scanning information is correct and + * consistent. + * @ubi: UBI device description object + * @si: scanning information + * + * This function returns zero if the scanning information is all right, %1 if + * not and a negative error code if an error occurred. + */ +static int paranoid_check_si(struct ubi_device *ubi, struct ubi_scan_info *si) +{ + int pnum, err, vols_found = 0; + struct rb_node *rb1, *rb2; + struct ubi_scan_volume *sv; + struct ubi_scan_leb *seb, *last_seb; + uint8_t *buf; + + /* + * At first, check that scanning information is OK. + */ + ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { + int leb_count = 0; + + cond_resched(); + + vols_found += 1; + + if (si->is_empty) { + ubi_err("bad is_empty flag"); + goto bad_sv; + } + + if (sv->vol_id < 0 || sv->highest_lnum < 0 || + sv->leb_count < 0 || sv->vol_type < 0 || sv->used_ebs < 0 || + sv->data_pad < 0 || sv->last_data_size < 0) { + ubi_err("negative values"); + goto bad_sv; + } + + if (sv->vol_id >= UBI_MAX_VOLUMES && + sv->vol_id < UBI_INTERNAL_VOL_START) { + ubi_err("bad vol_id"); + goto bad_sv; + } + + if (sv->vol_id > si->highest_vol_id) { + ubi_err("highest_vol_id is %d, but vol_id %d is there", + si->highest_vol_id, sv->vol_id); + goto out; + } + + if (sv->vol_type != UBI_DYNAMIC_VOLUME && + sv->vol_type != UBI_STATIC_VOLUME) { + ubi_err("bad vol_type"); + goto bad_sv; + } + + if (sv->data_pad > ubi->leb_size / 2) { + ubi_err("bad data_pad"); + goto bad_sv; + } + + last_seb = NULL; + ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { + cond_resched(); + + last_seb = seb; + leb_count += 1; + + if (seb->pnum < 0 || seb->ec < 0) { + ubi_err("negative values"); + goto bad_seb; + } + + if (seb->ec < si->min_ec) { + ubi_err("bad si->min_ec (%d), %d found", + si->min_ec, seb->ec); + goto bad_seb; + } + + if (seb->ec > si->max_ec) { + ubi_err("bad si->max_ec (%d), %d found", + si->max_ec, seb->ec); + goto bad_seb; + } + + if (seb->pnum >= ubi->peb_count) { + ubi_err("too high PEB number %d, total PEBs %d", + seb->pnum, ubi->peb_count); + goto bad_seb; + } + + if (sv->vol_type == UBI_STATIC_VOLUME) { + if (seb->lnum >= sv->used_ebs) { + ubi_err("bad lnum or used_ebs"); + goto bad_seb; + } + } else { + if (sv->used_ebs != 0) { + ubi_err("non-zero used_ebs"); + goto bad_seb; + } + } + + if (seb->lnum > sv->highest_lnum) { + ubi_err("incorrect highest_lnum or lnum"); + goto bad_seb; + } + } + + if (sv->leb_count != leb_count) { + ubi_err("bad leb_count, %d objects in the tree", + leb_count); + goto bad_sv; + } + + if (!last_seb) + continue; + + seb = last_seb; + + if (seb->lnum != sv->highest_lnum) { + ubi_err("bad highest_lnum"); + goto bad_seb; + } + } + + if (vols_found != si->vols_found) { + ubi_err("bad si->vols_found %d, should be %d", + si->vols_found, vols_found); + goto out; + } + + /* Check that scanning information is correct */ + ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { + last_seb = NULL; + ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { + int vol_type; + + cond_resched(); + + last_seb = seb; + + err = ubi_io_read_vid_hdr(ubi, seb->pnum, vidh, 1); + if (err && err != UBI_IO_BITFLIPS) { + ubi_err("VID header is not OK (%d)", err); + if (err > 0) + err = -EIO; + return err; + } + + vol_type = vidh->vol_type == UBI_VID_DYNAMIC ? + UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; + if (sv->vol_type != vol_type) { + ubi_err("bad vol_type"); + goto bad_vid_hdr; + } + + if (seb->sqnum != be64_to_cpu(vidh->sqnum)) { + ubi_err("bad sqnum %llu", seb->sqnum); + goto bad_vid_hdr; + } + + if (sv->vol_id != be32_to_cpu(vidh->vol_id)) { + ubi_err("bad vol_id %d", sv->vol_id); + goto bad_vid_hdr; + } + + if (sv->compat != vidh->compat) { + ubi_err("bad compat %d", vidh->compat); + goto bad_vid_hdr; + } + + if (seb->lnum != be32_to_cpu(vidh->lnum)) { + ubi_err("bad lnum %d", seb->lnum); + goto bad_vid_hdr; + } + + if (sv->used_ebs != be32_to_cpu(vidh->used_ebs)) { + ubi_err("bad used_ebs %d", sv->used_ebs); + goto bad_vid_hdr; + } + + if (sv->data_pad != be32_to_cpu(vidh->data_pad)) { + ubi_err("bad data_pad %d", sv->data_pad); + goto bad_vid_hdr; + } + + if (seb->leb_ver != be32_to_cpu(vidh->leb_ver)) { + ubi_err("bad leb_ver %u", seb->leb_ver); + goto bad_vid_hdr; + } + } + + if (!last_seb) + continue; + + if (sv->highest_lnum != be32_to_cpu(vidh->lnum)) { + ubi_err("bad highest_lnum %d", sv->highest_lnum); + goto bad_vid_hdr; + } + + if (sv->last_data_size != be32_to_cpu(vidh->data_size)) { + ubi_err("bad last_data_size %d", sv->last_data_size); + goto bad_vid_hdr; + } + } + + /* + * Make sure that all the physical eraseblocks are in one of the lists + * or trees. + */ + buf = kzalloc(ubi->peb_count, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + for (pnum = 0; pnum < ubi->peb_count; pnum++) { + err = ubi_io_is_bad(ubi, pnum); + if (err < 0) { + kfree(buf); + return err; + } + else if (err) + buf[pnum] = 1; + } + + ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) + ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) + buf[seb->pnum] = 1; + + list_for_each_entry(seb, &si->free, u.list) + buf[seb->pnum] = 1; + + list_for_each_entry(seb, &si->corr, u.list) + buf[seb->pnum] = 1; + + list_for_each_entry(seb, &si->erase, u.list) + buf[seb->pnum] = 1; + + list_for_each_entry(seb, &si->alien, u.list) + buf[seb->pnum] = 1; + + err = 0; + for (pnum = 0; pnum < ubi->peb_count; pnum++) + if (!buf[pnum]) { + ubi_err("PEB %d is not referred", pnum); + err = 1; + } + + kfree(buf); + if (err) + goto out; + return 0; + +bad_seb: + ubi_err("bad scanning information about LEB %d", seb->lnum); + ubi_dbg_dump_seb(seb, 0); + ubi_dbg_dump_sv(sv); + goto out; + +bad_sv: + ubi_err("bad scanning information about volume %d", sv->vol_id); + ubi_dbg_dump_sv(sv); + goto out; + +bad_vid_hdr: + ubi_err("bad scanning information about volume %d", sv->vol_id); + ubi_dbg_dump_sv(sv); + ubi_dbg_dump_vid_hdr(vidh); + +out: + ubi_dbg_dump_stack(); + return 1; +} + +#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/drivers/mtd/ubi/scan.h b/drivers/mtd/ubi/scan.h new file mode 100644 index 0000000..966b9b6 --- /dev/null +++ b/drivers/mtd/ubi/scan.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +#ifndef __UBI_SCAN_H__ +#define __UBI_SCAN_H__ + +/* The erase counter value for this physical eraseblock is unknown */ +#define UBI_SCAN_UNKNOWN_EC (-1) + +/** + * struct ubi_scan_leb - scanning information about a physical eraseblock. + * @ec: erase counter (%UBI_SCAN_UNKNOWN_EC if it is unknown) + * @pnum: physical eraseblock number + * @lnum: logical eraseblock number + * @scrub: if this physical eraseblock needs scrubbing + * @sqnum: sequence number + * @u: unions RB-tree or @list links + * @u.rb: link in the per-volume RB-tree of &struct ubi_scan_leb objects + * @u.list: link in one of the eraseblock lists + * @leb_ver: logical eraseblock version (obsolete) + * + * One object of this type is allocated for each physical eraseblock during + * scanning. + */ +struct ubi_scan_leb { + int ec; + int pnum; + int lnum; + int scrub; + unsigned long long sqnum; + union { + struct rb_node rb; + struct list_head list; + } u; + uint32_t leb_ver; +}; + +/** + * struct ubi_scan_volume - scanning information about a volume. + * @vol_id: volume ID + * @highest_lnum: highest logical eraseblock number in this volume + * @leb_count: number of logical eraseblocks in this volume + * @vol_type: volume type + * @used_ebs: number of used logical eraseblocks in this volume (only for + * static volumes) + * @last_data_size: amount of data in the last logical eraseblock of this + * volume (always equivalent to the usable logical eraseblock size in case of + * dynamic volumes) + * @data_pad: how many bytes at the end of logical eraseblocks of this volume + * are not used (due to volume alignment) + * @compat: compatibility flags of this volume + * @rb: link in the volume RB-tree + * @root: root of the RB-tree containing all the eraseblock belonging to this + * volume (&struct ubi_scan_leb objects) + * + * One object of this type is allocated for each volume during scanning. + */ +struct ubi_scan_volume { + int vol_id; + int highest_lnum; + int leb_count; + int vol_type; + int used_ebs; + int last_data_size; + int data_pad; + int compat; + struct rb_node rb; + struct rb_root root; +}; + +/** + * struct ubi_scan_info - UBI scanning information. + * @volumes: root of the volume RB-tree + * @corr: list of corrupted physical eraseblocks + * @free: list of free physical eraseblocks + * @erase: list of physical eraseblocks which have to be erased + * @alien: list of physical eraseblocks which should not be used by UBI (e.g., + * @bad_peb_count: count of bad physical eraseblocks + * those belonging to "preserve"-compatible internal volumes) + * @vols_found: number of volumes found during scanning + * @highest_vol_id: highest volume ID + * @alien_peb_count: count of physical eraseblocks in the @alien list + * @is_empty: flag indicating whether the MTD device is empty or not + * @min_ec: lowest erase counter value + * @max_ec: highest erase counter value + * @max_sqnum: highest sequence number value + * @mean_ec: mean erase counter value + * @ec_sum: a temporary variable used when calculating @mean_ec + * @ec_count: a temporary variable used when calculating @mean_ec + * + * This data structure contains the result of scanning and may be used by other + * UBI units to build final UBI data structures, further error-recovery and so + * on. + */ +struct ubi_scan_info { + struct rb_root volumes; + struct list_head corr; + struct list_head free; + struct list_head erase; + struct list_head alien; + int bad_peb_count; + int vols_found; + int highest_vol_id; + int alien_peb_count; + int is_empty; + int min_ec; + int max_ec; + unsigned long long max_sqnum; + int mean_ec; + uint64_t ec_sum; + int ec_count; +}; + +struct ubi_device; +struct ubi_vid_hdr; + +/* + * ubi_scan_move_to_list - move a physical eraseblock from the volume tree to a + * list. + * + * @sv: volume scanning information + * @seb: scanning eraseblock infprmation + * @list: the list to move to + */ +static inline void ubi_scan_move_to_list(struct ubi_scan_volume *sv, + struct ubi_scan_leb *seb, + struct list_head *list) +{ + rb_erase(&seb->u.rb, &sv->root); + list_add_tail(&seb->u.list, list); +} + +int ubi_scan_add_used(struct ubi_device *ubi, struct ubi_scan_info *si, + int pnum, int ec, const struct ubi_vid_hdr *vid_hdr, + int bitflips); +struct ubi_scan_volume *ubi_scan_find_sv(const struct ubi_scan_info *si, + int vol_id); +struct ubi_scan_leb *ubi_scan_find_seb(const struct ubi_scan_volume *sv, + int lnum); +void ubi_scan_rm_volume(struct ubi_scan_info *si, struct ubi_scan_volume *sv); +struct ubi_scan_leb *ubi_scan_get_free_peb(struct ubi_device *ubi, + struct ubi_scan_info *si); +int ubi_scan_erase_peb(struct ubi_device *ubi, const struct ubi_scan_info *si, + int pnum, int ec); +struct ubi_scan_info *ubi_scan(struct ubi_device *ubi); +void ubi_scan_destroy_si(struct ubi_scan_info *si); + +#endif /* !__UBI_SCAN_H__ */ diff --git a/drivers/mtd/ubi/ubi-barebox.h b/drivers/mtd/ubi/ubi-barebox.h new file mode 100644 index 0000000..84c589f --- /dev/null +++ b/drivers/mtd/ubi/ubi-barebox.h @@ -0,0 +1,191 @@ +/* + * Header file for UBI support for U-Boot + * + * Adaptation from kernel to U-Boot + * + * Copyright (C) 2005-2007 Samsung Electronics + * Kyungmin Park + * + * 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 __UBOOT_UBI_H +#define __UBOOT_UBI_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define crc32(seed, data, length) crc32_no_comp(seed, (unsigned char const *)data, length) + +#define DPRINTK(format, args...) \ +do { \ + printf("%s[%d]: " format "\n", __func__, __LINE__, ##args); \ +} while (0) + +/* configurable */ +#define CONFIG_MTD_UBI_WL_THRESHOLD 4096 +#define CONFIG_MTD_UBI_BEB_RESERVE 1 +#define UBI_IO_DEBUG 0 + +/* debug options (Linux: drivers/mtd/ubi/Kconfig.debug) */ +#undef CONFIG_MTD_UBI_DEBUG +#undef CONFIG_MTD_UBI_DEBUG_PARANOID +#undef CONFIG_MTD_UBI_DEBUG_MSG +#undef CONFIG_MTD_UBI_DEBUG_MSG_EBA +#undef CONFIG_MTD_UBI_DEBUG_MSG_WL +#undef CONFIG_MTD_UBI_DEBUG_MSG_IO +#undef CONFIG_MTD_UBI_DEBUG_MSG_BLD +#define CONFIG_MTD_UBI_DEBUG_DISABLE_BGT + +/* build.c */ +#define get_device(...) +#define put_device(...) +#define ubi_sysfs_init(...) 0 +#define ubi_sysfs_close(...) do { } while (0) +static inline int is_power_of_2(unsigned long n) +{ + return (n != 0 && ((n & (n - 1)) == 0)); +} + +/* FIXME */ +#define MKDEV(...) 0 +#define MAJOR(dev) 0 +#define MINOR(dev) 0 + +#define alloc_chrdev_region(...) 0 +#define unregister_chrdev_region(...) + +#define class_create(...) __builtin_return_address(0) +#define class_create_file(...) 0 +#define class_remove_file(...) +#define class_destroy(...) +#define misc_register(...) 0 +#define misc_deregister(...) + +/* vmt.c */ +#define device_register(...) 0 +#define volume_sysfs_init(...) 0 +#define volume_sysfs_close(...) do { } while (0) + +/* kapi.c */ + +/* eba.c */ + +/* io.c */ +#define init_waitqueue_head(...) do { } while (0) +#define wait_event_interruptible(...) 0 +#define wake_up_interruptible(...) do { } while (0) +#define print_hex_dump(...) do { } while (0) +#define dump_stack(...) do { } while (0) + +/* wl.c */ +#define task_pid_nr(x) 0 +#define set_freezable(...) do { } while (0) +#define try_to_freeze(...) 0 +#define set_current_state(...) do { } while (0) +#define kthread_should_stop(...) 0 +#define schedule() do { } while (0) + +/* upd.c */ +static inline unsigned long copy_from_user(void *dest, const void *src, + unsigned long count) +{ + memcpy((void *)dest, (void *)src, count); + return 0; +} + +/* common */ +typedef int spinlock_t; +typedef int wait_queue_head_t; +#define spin_lock_init(...) +#define spin_lock(...) +#define spin_unlock(...) + +#define mutex_init(...) +#define mutex_lock(...) +#define mutex_unlock(...) + +#define init_rwsem(...) do { } while (0) +#define down_read(...) do { } while (0) +#define down_write(...) do { } while (0) +#define down_write_trylock(...) 1 +#define up_read(...) do { } while (0) +#define up_write(...) do { } while (0) + +struct kmem_cache { int i; }; +#define kmem_cache_create(...) 1 +#define kmem_cache_alloc(obj, gfp) malloc(sizeof(struct ubi_wl_entry)) +#define kmem_cache_free(obj, size) free(size) +#define kmem_cache_destroy(...) + +#define cond_resched() do { } while (0) +#define yield() do { } while (0) + +#define GFP_KERNEL 0 +#define GFP_NOFS 1 + +#define __user +#define __init +#define __exit + +#define kthread_create(...) __builtin_return_address(0) +#define kthread_stop(...) do { } while (0) +#define wake_up_process(...) do { } while (0) + +#define BUS_ID_SIZE 20 + +struct rw_semaphore { int i; }; +struct device { + struct device *parent; + struct class *class; + char bus_id[BUS_ID_SIZE]; /* position on parent bus */ + dev_t devt; /* dev_t, creates the sysfs "dev" */ + void (*release)(struct device *dev); +}; +struct mutex { int i; }; +struct kernel_param { int i; }; + +struct cdev_ { + int owner; + dev_t dev; +}; +#define cdev_init(...) do { } while (0) +#define cdev_add(...) 0 +#define cdev_del(...) do { } while (0) + +#define MAX_ERRNO 4095 + +/* module */ +#define THIS_MODULE 0 +#define try_module_get(...) 1 +#define module_put(...) do { } while (0) +#define module_init(...) +#define module_exit(...) +#define EXPORT_SYMBOL_GPL(...) +#define module_param_call(...) +#define MODULE_PARM_DESC(...) +#define MODULE_VERSION(...) + +#ifndef __UBIFS_H__ +#include "ubi.h" +#endif + +/* functions */ +extern int ubi_mtd_param_parse(const char *val, struct kernel_param *kp); +extern int ubi_init(void); +extern void ubi_exit(void); + +extern struct ubi_device *ubi_devices[]; + +#endif diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h new file mode 100644 index 0000000..c3185d9 --- /dev/null +++ b/drivers/mtd/ubi/ubi-media.h @@ -0,0 +1,372 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Authors: Artem Bityutskiy (Битюцкий Артём) + * Thomas Gleixner + * Frank Haverkamp + * Oliver Lohmann + * Andreas Arnez + */ + +/* + * This file defines the layout of UBI headers and all the other UBI on-flash + * data structures. + */ + +#ifndef __UBI_MEDIA_H__ +#define __UBI_MEDIA_H__ + +#include + +/* The version of UBI images supported by this implementation */ +#define UBI_VERSION 1 + +/* The highest erase counter value supported by this implementation */ +#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF + +/* The initial CRC32 value used when calculating CRC checksums */ +#define UBI_CRC32_INIT 0xFFFFFFFFU + +/* Erase counter header magic number (ASCII "UBI#") */ +#define UBI_EC_HDR_MAGIC 0x55424923 +/* Volume identifier header magic number (ASCII "UBI!") */ +#define UBI_VID_HDR_MAGIC 0x55424921 + +/* + * Volume type constants used in the volume identifier header. + * + * @UBI_VID_DYNAMIC: dynamic volume + * @UBI_VID_STATIC: static volume + */ +enum { + UBI_VID_DYNAMIC = 1, + UBI_VID_STATIC = 2 +}; + +/* + * Volume flags used in the volume table record. + * + * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume + * + * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume + * table. UBI automatically re-sizes the volume which has this flag and makes + * the volume to be of largest possible size. This means that if after the + * initialization UBI finds out that there are available physical eraseblocks + * present on the device, it automatically appends all of them to the volume + * (the physical eraseblocks reserved for bad eraseblocks handling and other + * reserved physical eraseblocks are not taken). So, if there is a volume with + * the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical + * eraseblocks will be zero after UBI is loaded, because all of them will be + * reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared + * after the volume had been initialized. + * + * The auto-resize feature is useful for device production purposes. For + * example, different NAND flash chips may have different amount of initial bad + * eraseblocks, depending of particular chip instance. Manufacturers of NAND + * chips usually guarantee that the amount of initial bad eraseblocks does not + * exceed certain percent, e.g. 2%. When one creates an UBI image which will be + * flashed to the end devices in production, he does not know the exact amount + * of good physical eraseblocks the NAND chip on the device will have, but this + * number is required to calculate the volume sized and put them to the volume + * table of the UBI image. In this case, one of the volumes (e.g., the one + * which will store the root file system) is marked as "auto-resizable", and + * UBI will adjust its size on the first boot if needed. + * + * Note, first UBI reserves some amount of physical eraseblocks for bad + * eraseblock handling, and then re-sizes the volume, not vice-versa. This + * means that the pool of reserved physical eraseblocks will always be present. + */ +enum { + UBI_VTBL_AUTORESIZE_FLG = 0x01, +}; + +/* + * Compatibility constants used by internal volumes. + * + * @UBI_COMPAT_DELETE: delete this internal volume before anything is written + * to the flash + * @UBI_COMPAT_RO: attach this device in read-only mode + * @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its + * physical eraseblocks, don't allow the wear-leveling unit to move them + * @UBI_COMPAT_REJECT: reject this UBI image + */ +enum { + UBI_COMPAT_DELETE = 1, + UBI_COMPAT_RO = 2, + UBI_COMPAT_PRESERVE = 4, + UBI_COMPAT_REJECT = 5 +}; + +/* Sizes of UBI headers */ +#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr) +#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr) + +/* Sizes of UBI headers without the ending CRC */ +#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32)) +#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32)) + +/** + * struct ubi_ec_hdr - UBI erase counter header. + * @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC) + * @version: version of UBI implementation which is supposed to accept this + * UBI image + * @padding1: reserved for future, zeroes + * @ec: the erase counter + * @vid_hdr_offset: where the VID header starts + * @data_offset: where the user data start + * @padding2: reserved for future, zeroes + * @hdr_crc: erase counter header CRC checksum + * + * The erase counter header takes 64 bytes and has a plenty of unused space for + * future usage. The unused fields are zeroed. The @version field is used to + * indicate the version of UBI implementation which is supposed to be able to + * work with this UBI image. If @version is greater then the current UBI + * version, the image is rejected. This may be useful in future if something + * is changed radically. This field is duplicated in the volume identifier + * header. + * + * The @vid_hdr_offset and @data_offset fields contain the offset of the the + * volume identifier header and user data, relative to the beginning of the + * physical eraseblock. These values have to be the same for all physical + * eraseblocks. + */ +struct ubi_ec_hdr { + __be32 magic; + __u8 version; + __u8 padding1[3]; + __be64 ec; /* Warning: the current limit is 31-bit anyway! */ + __be32 vid_hdr_offset; + __be32 data_offset; + __u8 padding2[36]; + __be32 hdr_crc; +} __attribute__ ((packed)); + +/** + * struct ubi_vid_hdr - on-flash UBI volume identifier header. + * @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC) + * @version: UBI implementation version which is supposed to accept this UBI + * image (%UBI_VERSION) + * @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC) + * @copy_flag: if this logical eraseblock was copied from another physical + * eraseblock (for wear-leveling reasons) + * @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE, + * %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT) + * @vol_id: ID of this volume + * @lnum: logical eraseblock number + * @leb_ver: version of this logical eraseblock (IMPORTANT: obsolete, to be + * removed, kept only for not breaking older UBI users) + * @data_size: how many bytes of data this logical eraseblock contains + * @used_ebs: total number of used logical eraseblocks in this volume + * @data_pad: how many bytes at the end of this physical eraseblock are not + * used + * @data_crc: CRC checksum of the data stored in this logical eraseblock + * @padding1: reserved for future, zeroes + * @sqnum: sequence number + * @padding2: reserved for future, zeroes + * @hdr_crc: volume identifier header CRC checksum + * + * The @sqnum is the value of the global sequence counter at the time when this + * VID header was created. The global sequence counter is incremented each time + * UBI writes a new VID header to the flash, i.e. when it maps a logical + * eraseblock to a new physical eraseblock. The global sequence counter is an + * unsigned 64-bit integer and we assume it never overflows. The @sqnum + * (sequence number) is used to distinguish between older and newer versions of + * logical eraseblocks. + * + * There are 2 situations when there may be more then one physical eraseblock + * corresponding to the same logical eraseblock, i.e., having the same @vol_id + * and @lnum values in the volume identifier header. Suppose we have a logical + * eraseblock L and it is mapped to the physical eraseblock P. + * + * 1. Because UBI may erase physical eraseblocks asynchronously, the following + * situation is possible: L is asynchronously erased, so P is scheduled for + * erasure, then L is written to,i.e. mapped to another physical eraseblock P1, + * so P1 is written to, then an unclean reboot happens. Result - there are 2 + * physical eraseblocks P and P1 corresponding to the same logical eraseblock + * L. But P1 has greater sequence number, so UBI picks P1 when it attaches the + * flash. + * + * 2. From time to time UBI moves logical eraseblocks to other physical + * eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P + * to P1, and an unclean reboot happens before P is physically erased, there + * are two physical eraseblocks P and P1 corresponding to L and UBI has to + * select one of them when the flash is attached. The @sqnum field says which + * PEB is the original (obviously P will have lower @sqnum) and the copy. But + * it is not enough to select the physical eraseblock with the higher sequence + * number, because the unclean reboot could have happen in the middle of the + * copying process, so the data in P is corrupted. It is also not enough to + * just select the physical eraseblock with lower sequence number, because the + * data there may be old (consider a case if more data was added to P1 after + * the copying). Moreover, the unclean reboot may happen when the erasure of P + * was just started, so it result in unstable P, which is "mostly" OK, but + * still has unstable bits. + * + * UBI uses the @copy_flag field to indicate that this logical eraseblock is a + * copy. UBI also calculates data CRC when the data is moved and stores it at + * the @data_crc field of the copy (P1). So when UBI needs to pick one physical + * eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is + * examined. If it is cleared, the situation* is simple and the newer one is + * picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC + * checksum is correct, this physical eraseblock is selected (P1). Otherwise + * the older one (P) is selected. + * + * Note, there is an obsolete @leb_ver field which was used instead of @sqnum + * in the past. But it is not used anymore and we keep it in order to be able + * to deal with old UBI images. It will be removed at some point. + * + * There are 2 sorts of volumes in UBI: user volumes and internal volumes. + * Internal volumes are not seen from outside and are used for various internal + * UBI purposes. In this implementation there is only one internal volume - the + * layout volume. Internal volumes are the main mechanism of UBI extensions. + * For example, in future one may introduce a journal internal volume. Internal + * volumes have their own reserved range of IDs. + * + * The @compat field is only used for internal volumes and contains the "degree + * of their compatibility". It is always zero for user volumes. This field + * provides a mechanism to introduce UBI extensions and to be still compatible + * with older UBI binaries. For example, if someone introduced a journal in + * future, he would probably use %UBI_COMPAT_DELETE compatibility for the + * journal volume. And in this case, older UBI binaries, which know nothing + * about the journal volume, would just delete this volume and work perfectly + * fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image + * - it just ignores the Ext3fs journal. + * + * The @data_crc field contains the CRC checksum of the contents of the logical + * eraseblock if this is a static volume. In case of dynamic volumes, it does + * not contain the CRC checksum as a rule. The only exception is when the + * data of the physical eraseblock was moved by the wear-leveling unit, then + * the wear-leveling unit calculates the data CRC and stores it in the + * @data_crc field. And of course, the @copy_flag is %in this case. + * + * The @data_size field is used only for static volumes because UBI has to know + * how many bytes of data are stored in this eraseblock. For dynamic volumes, + * this field usually contains zero. The only exception is when the data of the + * physical eraseblock was moved to another physical eraseblock for + * wear-leveling reasons. In this case, UBI calculates CRC checksum of the + * contents and uses both @data_crc and @data_size fields. In this case, the + * @data_size field contains data size. + * + * The @used_ebs field is used only for static volumes and indicates how many + * eraseblocks the data of the volume takes. For dynamic volumes this field is + * not used and always contains zero. + * + * The @data_pad is calculated when volumes are created using the alignment + * parameter. So, effectively, the @data_pad field reduces the size of logical + * eraseblocks of this volume. This is very handy when one uses block-oriented + * software (say, cramfs) on top of the UBI volume. + */ +struct ubi_vid_hdr { + __be32 magic; + __u8 version; + __u8 vol_type; + __u8 copy_flag; + __u8 compat; + __be32 vol_id; + __be32 lnum; + __be32 leb_ver; /* obsolete, to be removed, don't use */ + __be32 data_size; + __be32 used_ebs; + __be32 data_pad; + __be32 data_crc; + __u8 padding1[4]; + __be64 sqnum; + __u8 padding2[12]; + __be32 hdr_crc; +} __attribute__ ((packed)); + +/* Internal UBI volumes count */ +#define UBI_INT_VOL_COUNT 1 + +/* + * Starting ID of internal volumes. There is reserved room for 4096 internal + * volumes. + */ +#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096) + +/* The layout volume contains the volume table */ + +#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START +#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC +#define UBI_LAYOUT_VOLUME_ALIGN 1 +#define UBI_LAYOUT_VOLUME_EBS 2 +#define UBI_LAYOUT_VOLUME_NAME "layout volume" +#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT + +/* The maximum number of volumes per one UBI device */ +#define UBI_MAX_VOLUMES 128 + +/* The maximum volume name length */ +#define UBI_VOL_NAME_MAX 127 + +/* Size of the volume table record */ +#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record) + +/* Size of the volume table record without the ending CRC */ +#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32)) + +/** + * struct ubi_vtbl_record - a record in the volume table. + * @reserved_pebs: how many physical eraseblocks are reserved for this volume + * @alignment: volume alignment + * @data_pad: how many bytes are unused at the end of the each physical + * eraseblock to satisfy the requested alignment + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @upd_marker: if volume update was started but not finished + * @name_len: volume name length + * @name: the volume name + * @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG) + * @padding: reserved, zeroes + * @crc: a CRC32 checksum of the record + * + * The volume table records are stored in the volume table, which is stored in + * the layout volume. The layout volume consists of 2 logical eraseblock, each + * of which contains a copy of the volume table (i.e., the volume table is + * duplicated). The volume table is an array of &struct ubi_vtbl_record + * objects indexed by the volume ID. + * + * If the size of the logical eraseblock is large enough to fit + * %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES + * records. Otherwise, it contains as many records as it can fit (i.e., size of + * logical eraseblock divided by sizeof(struct ubi_vtbl_record)). + * + * The @upd_marker flag is used to implement volume update. It is set to %1 + * before update and set to %0 after the update. So if the update operation was + * interrupted, UBI knows that the volume is corrupted. + * + * The @alignment field is specified when the volume is created and cannot be + * later changed. It may be useful, for example, when a block-oriented file + * system works on top of UBI. The @data_pad field is calculated using the + * logical eraseblock size and @alignment. The alignment must be multiple to the + * minimal flash I/O unit. If @alignment is 1, all the available space of + * the physical eraseblocks is used. + * + * Empty records contain all zeroes and the CRC checksum of those zeroes. + */ +struct ubi_vtbl_record { + __be32 reserved_pebs; + __be32 alignment; + __be32 data_pad; + __u8 vol_type; + __u8 upd_marker; + __be16 name_len; + __u8 name[UBI_VOL_NAME_MAX+1]; + __u8 flags; + __u8 padding[23]; + __be32 crc; +} __attribute__ ((packed)); + +#endif /* !__UBI_MEDIA_H__ */ diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h new file mode 100644 index 0000000..5552237 --- /dev/null +++ b/drivers/mtd/ubi/ubi.h @@ -0,0 +1,648 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Nokia Corporation, 2006, 2007 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +#ifndef __UBI_UBI_H__ +#define __UBI_UBI_H__ + +#ifdef UBI_LINUX +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include "ubi-media.h" +#include "scan.h" +#include "debug.h" + +/* Maximum number of supported UBI devices */ +#define UBI_MAX_DEVICES 32 + +/* UBI name used for character devices, sysfs, etc */ +#define UBI_NAME_STR "ubi" + +/* Normal UBI messages */ +#define ubi_msg(fmt, ...) printk(KERN_NOTICE "UBI: " fmt "\n", ##__VA_ARGS__) +/* UBI warning messages */ +#define ubi_warn(fmt, ...) printk(KERN_WARNING "UBI warning: %s: " fmt "\n", \ + __func__, ##__VA_ARGS__) +/* UBI error messages */ +#define ubi_err(fmt, ...) printk(KERN_ERR "UBI error: %s: " fmt "\n", \ + __func__, ##__VA_ARGS__) + +/* Lowest number PEBs reserved for bad PEB handling */ +#define MIN_RESEVED_PEBS 2 + +/* Background thread name pattern */ +#define UBI_BGT_NAME_PATTERN "ubi_bgt%dd" + +/* This marker in the EBA table means that the LEB is um-mapped */ +#define UBI_LEB_UNMAPPED -1 + +/* + * In case of errors, UBI tries to repeat the operation several times before + * returning error. The below constant defines how many times UBI re-tries. + */ +#define UBI_IO_RETRIES 3 + +/* + * Error codes returned by the I/O unit. + * + * UBI_IO_PEB_EMPTY: the physical eraseblock is empty, i.e. it contains only + * 0xFF bytes + * UBI_IO_PEB_FREE: the physical eraseblock is free, i.e. it contains only a + * valid erase counter header, and the rest are %0xFF bytes + * UBI_IO_BAD_EC_HDR: the erase counter header is corrupted (bad magic or CRC) + * UBI_IO_BAD_VID_HDR: the volume identifier header is corrupted (bad magic or + * CRC) + * UBI_IO_BITFLIPS: bit-flips were detected and corrected + */ +enum { + UBI_IO_PEB_EMPTY = 1, + UBI_IO_PEB_FREE, + UBI_IO_BAD_EC_HDR, + UBI_IO_BAD_VID_HDR, + UBI_IO_BITFLIPS +}; + +/** + * struct ubi_wl_entry - wear-leveling entry. + * @rb: link in the corresponding RB-tree + * @ec: erase counter + * @pnum: physical eraseblock number + * + * This data structure is used in the WL unit. Each physical eraseblock has a + * corresponding &struct wl_entry object which may be kept in different + * RB-trees. See WL unit for details. + */ +struct ubi_wl_entry { + struct rb_node rb; + int ec; + int pnum; +}; + +/** + * struct ubi_ltree_entry - an entry in the lock tree. + * @rb: links RB-tree nodes + * @vol_id: volume ID of the locked logical eraseblock + * @lnum: locked logical eraseblock number + * @users: how many tasks are using this logical eraseblock or wait for it + * @mutex: read/write mutex to implement read/write access serialization to + * the (@vol_id, @lnum) logical eraseblock + * + * This data structure is used in the EBA unit to implement per-LEB locking. + * When a logical eraseblock is being locked - corresponding + * &struct ubi_ltree_entry object is inserted to the lock tree (@ubi->ltree). + * See EBA unit for details. + */ +struct ubi_ltree_entry { + struct rb_node rb; + int vol_id; + int lnum; + int users; + struct rw_semaphore mutex; +}; + +struct ubi_volume_desc; + +/** + * struct ubi_volume - UBI volume description data structure. + * @dev: device object to make use of the the Linux device model + * @cdev: character device object to create character device + * @ubi: reference to the UBI device description object + * @vol_id: volume ID + * @ref_count: volume reference count + * @readers: number of users holding this volume in read-only mode + * @writers: number of users holding this volume in read-write mode + * @exclusive: whether somebody holds this volume in exclusive mode + * + * @reserved_pebs: how many physical eraseblocks are reserved for this volume + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @usable_leb_size: logical eraseblock size without padding + * @used_ebs: how many logical eraseblocks in this volume contain data + * @last_eb_bytes: how many bytes are stored in the last logical eraseblock + * @used_bytes: how many bytes of data this volume contains + * @alignment: volume alignment + * @data_pad: how many bytes are not used at the end of physical eraseblocks to + * satisfy the requested alignment + * @name_len: volume name length + * @name: volume name + * + * @upd_ebs: how many eraseblocks are expected to be updated + * @ch_lnum: LEB number which is being changing by the atomic LEB change + * operation + * @ch_dtype: data persistency type which is being changing by the atomic LEB + * change operation + * @upd_bytes: how many bytes are expected to be received for volume update or + * atomic LEB change + * @upd_received: how many bytes were already received for volume update or + * atomic LEB change + * @upd_buf: update buffer which is used to collect update data or data for + * atomic LEB change + * + * @eba_tbl: EBA table of this volume (LEB->PEB mapping) + * @checked: %1 if this static volume was checked + * @corrupted: %1 if the volume is corrupted (static volumes only) + * @upd_marker: %1 if the update marker is set for this volume + * @updating: %1 if the volume is being updated + * @changing_leb: %1 if the atomic LEB change ioctl command is in progress + * + * @gluebi_desc: gluebi UBI volume descriptor + * @gluebi_refcount: reference count of the gluebi MTD device + * @gluebi_mtd: MTD device description object of the gluebi MTD device + * + * The @corrupted field indicates that the volume's contents is corrupted. + * Since UBI protects only static volumes, this field is not relevant to + * dynamic volumes - it is user's responsibility to assure their data + * integrity. + * + * The @upd_marker flag indicates that this volume is either being updated at + * the moment or is damaged because of an unclean reboot. + */ +struct ubi_volume { + struct device dev; + struct cdev cdev; + struct ubi_device *ubi; + int vol_id; + int ref_count; + int readers; + int writers; + int exclusive; + + int reserved_pebs; + int vol_type; + int usable_leb_size; + int used_ebs; + int last_eb_bytes; + long long used_bytes; + int alignment; + int data_pad; + int name_len; + char name[UBI_VOL_NAME_MAX+1]; + + int upd_ebs; + int ch_lnum; + int ch_dtype; + long long upd_bytes; + long long upd_received; + void *upd_buf; + + int *eba_tbl; + unsigned int checked:1; + unsigned int corrupted:1; + unsigned int upd_marker:1; + unsigned int updating:1; + unsigned int changing_leb:1; + +#ifdef CONFIG_MTD_UBI_GLUEBI + /* + * Gluebi-related stuff may be compiled out. + * TODO: this should not be built into UBI but should be a separate + * ubimtd driver which works on top of UBI and emulates MTD devices. + */ + struct ubi_volume_desc *gluebi_desc; + int gluebi_refcount; + struct mtd_info gluebi_mtd; +#endif +}; + +/** + * struct ubi_volume_desc - descriptor of the UBI volume returned when it is + * opened. + * @vol: reference to the corresponding volume description object + * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE) + */ +struct ubi_volume_desc { + struct ubi_volume *vol; + int mode; +}; + +struct ubi_wl_entry; + +/** + * struct ubi_device - UBI device description structure + * @dev: UBI device object to use the the Linux device model + * @cdev: character device object to create character device + * @ubi_num: UBI device number + * @ubi_name: UBI device name + * @vol_count: number of volumes in this UBI device + * @volumes: volumes of this UBI device + * @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs, + * @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count, + * @vol->readers, @vol->writers, @vol->exclusive, + * @vol->ref_count, @vol->mapping and @vol->eba_tbl. + * @ref_count: count of references on the UBI device + * + * @rsvd_pebs: count of reserved physical eraseblocks + * @avail_pebs: count of available physical eraseblocks + * @beb_rsvd_pebs: how many physical eraseblocks are reserved for bad PEB + * handling + * @beb_rsvd_level: normal level of PEBs reserved for bad PEB handling + * + * @autoresize_vol_id: ID of the volume which has to be auto-resized at the end + * of UBI ititializetion + * @vtbl_slots: how many slots are available in the volume table + * @vtbl_size: size of the volume table in bytes + * @vtbl: in-RAM volume table copy + * @volumes_mutex: protects on-flash volume table and serializes volume + * changes, like creation, deletion, update, resize + * + * @max_ec: current highest erase counter value + * @mean_ec: current mean erase counter value + * + * @global_sqnum: global sequence number + * @ltree_lock: protects the lock tree and @global_sqnum + * @ltree: the lock tree + * @alc_mutex: serializes "atomic LEB change" operations + * + * @used: RB-tree of used physical eraseblocks + * @free: RB-tree of free physical eraseblocks + * @scrub: RB-tree of physical eraseblocks which need scrubbing + * @prot: protection trees + * @prot.pnum: protection tree indexed by physical eraseblock numbers + * @prot.aec: protection tree indexed by absolute erase counter value + * @wl_lock: protects the @used, @free, @prot, @lookuptbl, @abs_ec, @move_from, + * @move_to, @move_to_put @erase_pending, @wl_scheduled, and @works + * fields + * @move_mutex: serializes eraseblock moves + * @wl_scheduled: non-zero if the wear-leveling was scheduled + * @lookuptbl: a table to quickly find a &struct ubi_wl_entry object for any + * physical eraseblock + * @abs_ec: absolute erase counter + * @move_from: physical eraseblock from where the data is being moved + * @move_to: physical eraseblock where the data is being moved to + * @move_to_put: if the "to" PEB was put + * @works: list of pending works + * @works_count: count of pending works + * @bgt_thread: background thread description object + * @thread_enabled: if the background thread is enabled + * @bgt_name: background thread name + * + * @flash_size: underlying MTD device size (in bytes) + * @peb_count: count of physical eraseblocks on the MTD device + * @peb_size: physical eraseblock size + * @bad_peb_count: count of bad physical eraseblocks + * @good_peb_count: count of good physical eraseblocks + * @min_io_size: minimal input/output unit size of the underlying MTD device + * @hdrs_min_io_size: minimal I/O unit size used for VID and EC headers + * @ro_mode: if the UBI device is in read-only mode + * @leb_size: logical eraseblock size + * @leb_start: starting offset of logical eraseblocks within physical + * eraseblocks + * @ec_hdr_alsize: size of the EC header aligned to @hdrs_min_io_size + * @vid_hdr_alsize: size of the VID header aligned to @hdrs_min_io_size + * @vid_hdr_offset: starting offset of the volume identifier header (might be + * unaligned) + * @vid_hdr_aloffset: starting offset of the VID header aligned to + * @hdrs_min_io_size + * @vid_hdr_shift: contains @vid_hdr_offset - @vid_hdr_aloffset + * @bad_allowed: whether the MTD device admits of bad physical eraseblocks or + * not + * @mtd: MTD device descriptor + * + * @peb_buf1: a buffer of PEB size used for different purposes + * @peb_buf2: another buffer of PEB size used for different purposes + * @buf_mutex: proptects @peb_buf1 and @peb_buf2 + * @dbg_peb_buf: buffer of PEB size used for debugging + * @dbg_buf_mutex: proptects @dbg_peb_buf + */ +struct ubi_device { + struct cdev cdev; + struct device dev; + int ubi_num; + char ubi_name[sizeof(UBI_NAME_STR)+5]; + int vol_count; + struct ubi_volume *volumes[UBI_MAX_VOLUMES+UBI_INT_VOL_COUNT]; + spinlock_t volumes_lock; + int ref_count; + + int rsvd_pebs; + int avail_pebs; + int beb_rsvd_pebs; + int beb_rsvd_level; + + int autoresize_vol_id; + int vtbl_slots; + int vtbl_size; + struct ubi_vtbl_record *vtbl; + struct mutex volumes_mutex; + + int max_ec; + /* TODO: mean_ec is not updated run-time, fix */ + int mean_ec; + + /* EBA unit's stuff */ + unsigned long long global_sqnum; + spinlock_t ltree_lock; + struct rb_root ltree; + struct mutex alc_mutex; + + /* Wear-leveling unit's stuff */ + struct rb_root used; + struct rb_root free; + struct rb_root scrub; + struct { + struct rb_root pnum; + struct rb_root aec; + } prot; + spinlock_t wl_lock; + struct mutex move_mutex; + struct rw_semaphore work_sem; + int wl_scheduled; + struct ubi_wl_entry **lookuptbl; + unsigned long long abs_ec; + struct ubi_wl_entry *move_from; + struct ubi_wl_entry *move_to; + int move_to_put; + struct list_head works; + int works_count; + struct task_struct *bgt_thread; + int thread_enabled; + char bgt_name[sizeof(UBI_BGT_NAME_PATTERN)+2]; + + /* I/O unit's stuff */ + long long flash_size; + int peb_count; + int peb_size; + int bad_peb_count; + int good_peb_count; + int min_io_size; + int hdrs_min_io_size; + int ro_mode; + int leb_size; + int leb_start; + int ec_hdr_alsize; + int vid_hdr_alsize; + int vid_hdr_offset; + int vid_hdr_aloffset; + int vid_hdr_shift; + int bad_allowed; + struct mtd_info *mtd; + + void *peb_buf1; + void *peb_buf2; + struct mutex buf_mutex; + struct mutex ckvol_mutex; +#ifdef CONFIG_MTD_UBI_DEBUG + void *dbg_peb_buf; + struct mutex dbg_buf_mutex; +#endif +}; + +extern struct kmem_cache *ubi_wl_entry_slab; +extern struct file_operations ubi_ctrl_cdev_operations; +extern struct file_operations ubi_cdev_operations; +extern struct file_operations ubi_vol_cdev_operations; +extern struct class *ubi_class; +extern struct mutex ubi_devices_mutex; + +/* vtbl.c */ +int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, + struct ubi_vtbl_record *vtbl_rec); +int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si); + +/* vmt.c */ +int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req); +int ubi_remove_volume(struct ubi_volume_desc *desc); +int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs); +int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol); +void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol); + +/* upd.c */ +int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, + long long bytes); +int ubi_finish_update(struct ubi_device *ubi, struct ubi_volume *vol); +int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, + const void __user *buf, int count); +int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, + const struct ubi_leb_change_req *req); +int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, + const void __user *buf, int count); + +/* misc.c */ +int ubi_calc_data_len(const struct ubi_device *ubi, const void *buf, int length); +int ubi_check_volume(struct ubi_device *ubi, int vol_id); +void ubi_calculate_reserved(struct ubi_device *ubi); + +/* gluebi.c */ +#ifdef CONFIG_MTD_UBI_GLUEBI +int ubi_create_gluebi(struct ubi_device *ubi, struct ubi_volume *vol); +int ubi_destroy_gluebi(struct ubi_volume *vol); +void ubi_gluebi_updated(struct ubi_volume *vol); +#else +#define ubi_create_gluebi(ubi, vol) 0 +#define ubi_destroy_gluebi(vol) 0 +#define ubi_gluebi_updated(vol) +#endif + +/* eba.c */ +int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol, + int lnum); +int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + void *buf, int offset, int len, int check); +int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + const void *buf, int offset, int len, int dtype); +int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol, + int lnum, const void *buf, int len, int dtype, + int used_ebs); +int ubi_eba_atomic_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, + int lnum, const void *buf, int len, int dtype); +int ubi_eba_copy_leb(struct ubi_device *ubi, int from, int to, + struct ubi_vid_hdr *vid_hdr); +int ubi_eba_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); +void ubi_eba_close(const struct ubi_device *ubi); + +/* wl.c */ +int ubi_wl_get_peb(struct ubi_device *ubi, int dtype); +int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture); +int ubi_wl_flush(struct ubi_device *ubi); +int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum); +int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si); +void ubi_wl_close(struct ubi_device *ubi); +int ubi_thread(void *u); + +/* io.c */ +int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, + int len); +int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, + int len); +int ubi_io_sync_erase(struct ubi_device *ubi, int pnum, int torture); +int ubi_io_is_bad(const struct ubi_device *ubi, int pnum); +int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum); +int ubi_io_read_ec_hdr(struct ubi_device *ubi, int pnum, + struct ubi_ec_hdr *ec_hdr, int verbose); +int ubi_io_write_ec_hdr(struct ubi_device *ubi, int pnum, + struct ubi_ec_hdr *ec_hdr); +int ubi_io_read_vid_hdr(struct ubi_device *ubi, int pnum, + struct ubi_vid_hdr *vid_hdr, int verbose); +int ubi_io_write_vid_hdr(struct ubi_device *ubi, int pnum, + struct ubi_vid_hdr *vid_hdr); + +/* build.c */ +int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset); +int ubi_detach_mtd_dev(struct mtd_info *mtd, int anyway); +struct ubi_device *ubi_get_device(int ubi_num); +void ubi_put_device(struct ubi_device *ubi); +struct ubi_device *ubi_get_by_major(int major); +int ubi_major2num(int major); + +/* cdev.c */ +int ubi_cdev_add(struct ubi_device *ubi); +void ubi_cdev_remove(struct ubi_device *ubi); +int ubi_volume_cdev_add(struct ubi_device *ubi, struct ubi_volume *vol); +void ubi_volume_cdev_remove(struct ubi_volume *vol); + +/* + * ubi_rb_for_each_entry - walk an RB-tree. + * @rb: a pointer to type 'struct rb_node' to to use as a loop counter + * @pos: a pointer to RB-tree entry type to use as a loop counter + * @root: RB-tree's root + * @member: the name of the 'struct rb_node' within the RB-tree entry + */ +#define ubi_rb_for_each_entry(rb, pos, root, member) \ + for (rb = rb_first(root), \ + pos = (rb ? container_of(rb, typeof(*pos), member) : NULL); \ + rb; \ + rb = rb_next(rb), pos = container_of(rb, typeof(*pos), member)) + +/** + * ubi_zalloc_vid_hdr - allocate a volume identifier header object. + * @ubi: UBI device description object + * @gfp_flags: GFP flags to allocate with + * + * This function returns a pointer to the newly allocated and zero-filled + * volume identifier header object in case of success and %NULL in case of + * failure. + */ +static inline struct ubi_vid_hdr * +ubi_zalloc_vid_hdr(const struct ubi_device *ubi, unsigned int gfp_flags) +{ + void *vid_hdr; + + vid_hdr = kzalloc(ubi->vid_hdr_alsize, gfp_flags); + if (!vid_hdr) + return NULL; + + /* + * VID headers may be stored at un-aligned flash offsets, so we shift + * the pointer. + */ + return vid_hdr + ubi->vid_hdr_shift; +} + +/** + * ubi_free_vid_hdr - free a volume identifier header object. + * @ubi: UBI device description object + * @vid_hdr: the object to free + */ +static inline void ubi_free_vid_hdr(const struct ubi_device *ubi, + struct ubi_vid_hdr *vid_hdr) +{ + void *p = vid_hdr; + + if (!p) + return; + + kfree(p - ubi->vid_hdr_shift); +} + +/* + * This function is equivalent to 'ubi_io_read()', but @offset is relative to + * the beginning of the logical eraseblock, not to the beginning of the + * physical eraseblock. + */ +static inline int ubi_io_read_data(const struct ubi_device *ubi, void *buf, + int pnum, int offset, int len) +{ + ubi_assert(offset >= 0); + return ubi_io_read(ubi, buf, pnum, offset + ubi->leb_start, len); +} + +/* + * This function is equivalent to 'ubi_io_write()', but @offset is relative to + * the beginning of the logical eraseblock, not to the beginning of the + * physical eraseblock. + */ +static inline int ubi_io_write_data(struct ubi_device *ubi, const void *buf, + int pnum, int offset, int len) +{ + ubi_assert(offset >= 0); + return ubi_io_write(ubi, buf, pnum, offset + ubi->leb_start, len); +} + +/** + * ubi_ro_mode - switch to read-only mode. + * @ubi: UBI device description object + */ +static inline void ubi_ro_mode(struct ubi_device *ubi) +{ + if (!ubi->ro_mode) { + ubi->ro_mode = 1; + ubi_warn("switch to read-only mode"); + } +} + +/** + * vol_id2idx - get table index by volume ID. + * @ubi: UBI device description object + * @vol_id: volume ID + */ +static inline int vol_id2idx(const struct ubi_device *ubi, int vol_id) +{ + if (vol_id >= UBI_INTERNAL_VOL_START) + return vol_id - UBI_INTERNAL_VOL_START + ubi->vtbl_slots; + else + return vol_id; +} + +/** + * idx2vol_id - get volume ID by table index. + * @ubi: UBI device description object + * @idx: table index + */ +static inline int idx2vol_id(const struct ubi_device *ubi, int idx) +{ + if (idx >= ubi->vtbl_slots) + return idx - ubi->vtbl_slots + UBI_INTERNAL_VOL_START; + else + return idx; +} + +#endif /* !__UBI_UBI_H__ */ diff --git a/drivers/mtd/ubi/upd.c b/drivers/mtd/ubi/upd.c new file mode 100644 index 0000000..fda2043 --- /dev/null +++ b/drivers/mtd/ubi/upd.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Nokia Corporation, 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + * + * Jan 2007: Alexander Schmidt, hacked per-volume update. + */ + +/* + * This file contains implementation of the volume update and atomic LEB change + * functionality. + * + * The update operation is based on the per-volume update marker which is + * stored in the volume table. The update marker is set before the update + * starts, and removed after the update has been finished. So if the update was + * interrupted by an unclean re-boot or due to some other reasons, the update + * marker stays on the flash media and UBI finds it when it attaches the MTD + * device next time. If the update marker is set for a volume, the volume is + * treated as damaged and most I/O operations are prohibited. Only a new update + * operation is allowed. + * + * Note, in general it is possible to implement the update operation as a + * transaction with a roll-back capability. + */ + +#ifdef UBI_LINUX +#include +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +/** + * set_update_marker - set update marker. + * @ubi: UBI device description object + * @vol: volume description object + * + * This function sets the update marker flag for volume @vol. Returns zero + * in case of success and a negative error code in case of failure. + */ +static int set_update_marker(struct ubi_device *ubi, struct ubi_volume *vol) +{ + int err; + struct ubi_vtbl_record vtbl_rec; + + dbg_msg("set update marker for volume %d", vol->vol_id); + + if (vol->upd_marker) { + ubi_assert(ubi->vtbl[vol->vol_id].upd_marker); + dbg_msg("already set"); + return 0; + } + + memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], + sizeof(struct ubi_vtbl_record)); + vtbl_rec.upd_marker = 1; + + mutex_lock(&ubi->volumes_mutex); + err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); + mutex_unlock(&ubi->volumes_mutex); + vol->upd_marker = 1; + return err; +} + +/** + * clear_update_marker - clear update marker. + * @ubi: UBI device description object + * @vol: volume description object + * @bytes: new data size in bytes + * + * This function clears the update marker for volume @vol, sets new volume + * data size and clears the "corrupted" flag (static volumes only). Returns + * zero in case of success and a negative error code in case of failure. + */ +static int clear_update_marker(struct ubi_device *ubi, struct ubi_volume *vol, + long long bytes) +{ + int err; + uint64_t tmp; + struct ubi_vtbl_record vtbl_rec; + + dbg_msg("clear update marker for volume %d", vol->vol_id); + + memcpy(&vtbl_rec, &ubi->vtbl[vol->vol_id], + sizeof(struct ubi_vtbl_record)); + ubi_assert(vol->upd_marker && vtbl_rec.upd_marker); + vtbl_rec.upd_marker = 0; + + if (vol->vol_type == UBI_STATIC_VOLUME) { + vol->corrupted = 0; + vol->used_bytes = tmp = bytes; + vol->last_eb_bytes = do_div(tmp, vol->usable_leb_size); + vol->used_ebs = tmp; + if (vol->last_eb_bytes) + vol->used_ebs += 1; + else + vol->last_eb_bytes = vol->usable_leb_size; + } + + mutex_lock(&ubi->volumes_mutex); + err = ubi_change_vtbl_record(ubi, vol->vol_id, &vtbl_rec); + mutex_unlock(&ubi->volumes_mutex); + vol->upd_marker = 0; + return err; +} + +/** + * ubi_start_update - start volume update. + * @ubi: UBI device description object + * @vol: volume description object + * @bytes: update bytes + * + * This function starts volume update operation. If @bytes is zero, the volume + * is just wiped out. Returns zero in case of success and a negative error code + * in case of failure. + */ +int ubi_start_update(struct ubi_device *ubi, struct ubi_volume *vol, + long long bytes) +{ + int i, err; + uint64_t tmp; + + dbg_msg("start update of volume %d, %llu bytes", vol->vol_id, bytes); + ubi_assert(!vol->updating && !vol->changing_leb); + vol->updating = 1; + + err = set_update_marker(ubi, vol); + if (err) + return err; + + /* Before updating - wipe out the volume */ + for (i = 0; i < vol->reserved_pebs; i++) { + err = ubi_eba_unmap_leb(ubi, vol, i); + if (err) + return err; + } + + if (bytes == 0) { + err = clear_update_marker(ubi, vol, 0); + if (err) + return err; + err = ubi_wl_flush(ubi); + if (!err) + vol->updating = 0; + } + + vol->upd_buf = vmalloc(ubi->leb_size); + if (!vol->upd_buf) + return -ENOMEM; + + tmp = bytes; + vol->upd_ebs = !!do_div(tmp, vol->usable_leb_size); + vol->upd_ebs += tmp; + vol->upd_bytes = bytes; + vol->upd_received = 0; + return 0; +} + +int ubi_finish_update(struct ubi_device *ubi, struct ubi_volume *vol) +{ + int err; + + /* The update is finished, clear the update marker */ + err = clear_update_marker(ubi, vol, vol->upd_bytes); + if (err) + return err; + err = ubi_wl_flush(ubi); + if (err == 0) { + vol->updating = 0; + vfree(vol->upd_buf); + } + + return err; +} + +/** + * ubi_start_leb_change - start atomic LEB change. + * @ubi: UBI device description object + * @vol: volume description object + * @req: operation request + * + * This function starts atomic LEB change operation. Returns zero in case of + * success and a negative error code in case of failure. + */ +int ubi_start_leb_change(struct ubi_device *ubi, struct ubi_volume *vol, + const struct ubi_leb_change_req *req) +{ + ubi_assert(!vol->updating && !vol->changing_leb); + + dbg_msg("start changing LEB %d:%d, %u bytes", + vol->vol_id, req->lnum, req->bytes); + if (req->bytes == 0) + return ubi_eba_atomic_leb_change(ubi, vol, req->lnum, NULL, 0, + req->dtype); + + vol->upd_bytes = req->bytes; + vol->upd_received = 0; + vol->changing_leb = 1; + vol->ch_lnum = req->lnum; + vol->ch_dtype = req->dtype; + + vol->upd_buf = vmalloc(req->bytes); + if (!vol->upd_buf) + return -ENOMEM; + + return 0; +} + +/** + * write_leb - write update data. + * @ubi: UBI device description object + * @vol: volume description object + * @lnum: logical eraseblock number + * @buf: data to write + * @len: data size + * @used_ebs: how many logical eraseblocks will this volume contain (static + * volumes only) + * + * This function writes update data to corresponding logical eraseblock. In + * case of dynamic volume, this function checks if the data contains 0xFF bytes + * at the end. If yes, the 0xFF bytes are cut and not written. So if the whole + * buffer contains only 0xFF bytes, the LEB is left unmapped. + * + * The reason why we skip the trailing 0xFF bytes in case of dynamic volume is + * that we want to make sure that more data may be appended to the logical + * eraseblock in future. Indeed, writing 0xFF bytes may have side effects and + * this PEB won't be writable anymore. So if one writes the file-system image + * to the UBI volume where 0xFFs mean free space - UBI makes sure this free + * space is writable after the update. + * + * We do not do this for static volumes because they are read-only. But this + * also cannot be done because we have to store per-LEB CRC and the correct + * data length. + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +static int write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum, + void *buf, int len, int used_ebs) +{ + int err; + + if (vol->vol_type == UBI_DYNAMIC_VOLUME) { + int l = ALIGN(len, ubi->min_io_size); + + memset(buf + len, 0xFF, l - len); + len = ubi_calc_data_len(ubi, buf, l); + if (len == 0) { + dbg_msg("all %d bytes contain 0xFF - skip", len); + return 0; + } + + err = ubi_eba_write_leb(ubi, vol, lnum, buf, 0, len, UBI_UNKNOWN); + } else { + /* + * When writing static volume, and this is the last logical + * eraseblock, the length (@len) does not have to be aligned to + * the minimal flash I/O unit. The 'ubi_eba_write_leb_st()' + * function accepts exact (unaligned) length and stores it in + * the VID header. And it takes care of proper alignment by + * padding the buffer. Here we just make sure the padding will + * contain zeros, not random trash. + */ + memset(buf + len, 0, vol->usable_leb_size - len); + err = ubi_eba_write_leb_st(ubi, vol, lnum, buf, len, + UBI_UNKNOWN, used_ebs); + } + + return err; +} + +/** + * ubi_more_update_data - write more update data. + * @vol: volume description object + * @buf: write data (user-space memory buffer) + * @count: how much bytes to write + * + * This function writes more data to the volume which is being updated. It may + * be called arbitrary number of times until all the update data arriveis. This + * function returns %0 in case of success, number of bytes written during the + * last call if the whole volume update has been successfully finished, and a + * negative error code in case of failure. + */ +int ubi_more_update_data(struct ubi_device *ubi, struct ubi_volume *vol, + const void __user *buf, int count) +{ + uint64_t tmp; + int lnum, offs, err = 0, len, to_write = count; + + dbg_msg("write %d of %lld bytes, %lld already passed", + count, vol->upd_bytes, vol->upd_received); + + if (ubi->ro_mode) + return -EROFS; + + tmp = vol->upd_received; + offs = do_div(tmp, vol->usable_leb_size); + lnum = tmp; + + if (vol->upd_received + count > vol->upd_bytes) + to_write = count = vol->upd_bytes - vol->upd_received; + + /* + * When updating volumes, we accumulate whole logical eraseblock of + * data and write it at once. + */ + if (offs != 0) { + /* + * This is a write to the middle of the logical eraseblock. We + * copy the data to our update buffer and wait for more data or + * flush it if the whole eraseblock is written or the update + * is finished. + */ + + len = vol->usable_leb_size - offs; + if (len > count) + len = count; + + err = copy_from_user(vol->upd_buf + offs, buf, len); + if (err) + return -EFAULT; + + if (offs + len == vol->usable_leb_size) { + int flush_len = offs + len; + + /* + * OK, we gathered the whole eraseblock, it's time to flush + * the buffer. + */ + ubi_assert(flush_len <= vol->usable_leb_size); + err = write_leb(ubi, vol, lnum, vol->upd_buf, flush_len, + vol->upd_ebs); + if (err) + return err; + } + + vol->upd_received += len; + count -= len; + buf += len; + lnum += 1; + } + + /* + * If we've got more to write, let's continue. At this point we know we + * are starting from the beginning of an eraseblock. + */ + while (count) { + if (count > vol->usable_leb_size) + len = vol->usable_leb_size; + else + len = count; + + err = copy_from_user(vol->upd_buf, buf, len); + if (err) + return -EFAULT; + + if (len == vol->usable_leb_size || + vol->upd_received + len == vol->upd_bytes) { + err = write_leb(ubi, vol, lnum, vol->upd_buf, + len, vol->upd_ebs); + if (err) + break; + } + + vol->upd_received += len; + count -= len; + lnum += 1; + buf += len; + } + + ubi_assert(vol->upd_received <= vol->upd_bytes); + + return err; +} + +/** + * ubi_more_leb_change_data - accept more data for atomic LEB change. + * @vol: volume description object + * @buf: write data (user-space memory buffer) + * @count: how much bytes to write + * + * This function accepts more data to the volume which is being under the + * "atomic LEB change" operation. It may be called arbitrary number of times + * until all data arrives. This function returns %0 in case of success, number + * of bytes written during the last call if the whole "atomic LEB change" + * operation has been successfully finished, and a negative error code in case + * of failure. + */ +int ubi_more_leb_change_data(struct ubi_device *ubi, struct ubi_volume *vol, + const void __user *buf, int count) +{ + int err; + + dbg_msg("write %d of %lld bytes, %lld already passed", + count, vol->upd_bytes, vol->upd_received); + + if (ubi->ro_mode) + return -EROFS; + + if (vol->upd_received + count > vol->upd_bytes) + count = vol->upd_bytes - vol->upd_received; + + err = copy_from_user(vol->upd_buf + vol->upd_received, buf, count); + if (err) + return -EFAULT; + + vol->upd_received += count; + + if (vol->upd_received == vol->upd_bytes) { + int len = ALIGN((int)vol->upd_bytes, ubi->min_io_size); + + memset(vol->upd_buf + vol->upd_bytes, 0xFF, len - vol->upd_bytes); + len = ubi_calc_data_len(ubi, vol->upd_buf, len); + err = ubi_eba_atomic_leb_change(ubi, vol, vol->ch_lnum, + vol->upd_buf, len, UBI_UNKNOWN); + if (err) + return err; + } + + ubi_assert(vol->upd_received <= vol->upd_bytes); + if (vol->upd_received == vol->upd_bytes) { + vol->changing_leb = 0; + err = count; + vfree(vol->upd_buf); + } + + return err; +} diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c new file mode 100644 index 0000000..4f1d0f4 --- /dev/null +++ b/drivers/mtd/ubi/vmt.c @@ -0,0 +1,866 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* + * This file contains implementation of volume creation, deletion, updating and + * resizing. + */ + +#ifdef UBI_LINUX +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID +static void paranoid_check_volumes(struct ubi_device *ubi); +#else +#define paranoid_check_volumes(ubi) +#endif + +#ifdef UBI_LINUX +static ssize_t vol_attribute_show(struct device *dev, + struct device_attribute *attr, char *buf); + +/* Device attributes corresponding to files in '//class/ubi/ubiX_Y' */ +static struct device_attribute attr_vol_reserved_ebs = + __ATTR(reserved_ebs, S_IRUGO, vol_attribute_show, NULL); +static struct device_attribute attr_vol_type = + __ATTR(type, S_IRUGO, vol_attribute_show, NULL); +static struct device_attribute attr_vol_name = + __ATTR(name, S_IRUGO, vol_attribute_show, NULL); +static struct device_attribute attr_vol_corrupted = + __ATTR(corrupted, S_IRUGO, vol_attribute_show, NULL); +static struct device_attribute attr_vol_alignment = + __ATTR(alignment, S_IRUGO, vol_attribute_show, NULL); +static struct device_attribute attr_vol_usable_eb_size = + __ATTR(usable_eb_size, S_IRUGO, vol_attribute_show, NULL); +static struct device_attribute attr_vol_data_bytes = + __ATTR(data_bytes, S_IRUGO, vol_attribute_show, NULL); +static struct device_attribute attr_vol_upd_marker = + __ATTR(upd_marker, S_IRUGO, vol_attribute_show, NULL); + +/* + * "Show" method for files in '//class/ubi/ubiX_Y/'. + * + * Consider a situation: + * A. process 1 opens a sysfs file related to volume Y, say + * //class/ubi/ubiX_Y/reserved_ebs; + * B. process 2 removes volume Y; + * C. process 1 starts reading the //class/ubi/ubiX_Y/reserved_ebs file; + * + * In this situation, this function will return %-ENODEV because it will find + * out that the volume was removed from the @ubi->volumes array. + */ +static ssize_t vol_attribute_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); + struct ubi_device *ubi; + + ubi = ubi_get_device(vol->ubi->ubi_num); + if (!ubi) + return -ENODEV; + + spin_lock(&ubi->volumes_lock); + if (!ubi->volumes[vol->vol_id]) { + spin_unlock(&ubi->volumes_lock); + ubi_put_device(ubi); + return -ENODEV; + } + /* Take a reference to prevent volume removal */ + vol->ref_count += 1; + spin_unlock(&ubi->volumes_lock); + + if (attr == &attr_vol_reserved_ebs) + ret = sprintf(buf, "%d\n", vol->reserved_pebs); + else if (attr == &attr_vol_type) { + const char *tp; + + if (vol->vol_type == UBI_DYNAMIC_VOLUME) + tp = "dynamic"; + else + tp = "static"; + ret = sprintf(buf, "%s\n", tp); + } else if (attr == &attr_vol_name) + ret = sprintf(buf, "%s\n", vol->name); + else if (attr == &attr_vol_corrupted) + ret = sprintf(buf, "%d\n", vol->corrupted); + else if (attr == &attr_vol_alignment) + ret = sprintf(buf, "%d\n", vol->alignment); + else if (attr == &attr_vol_usable_eb_size) + ret = sprintf(buf, "%d\n", vol->usable_leb_size); + else if (attr == &attr_vol_data_bytes) + ret = sprintf(buf, "%lld\n", vol->used_bytes); + else if (attr == &attr_vol_upd_marker) + ret = sprintf(buf, "%d\n", vol->upd_marker); + else + /* This must be a bug */ + ret = -EINVAL; + + /* We've done the operation, drop volume and UBI device references */ + spin_lock(&ubi->volumes_lock); + vol->ref_count -= 1; + ubi_assert(vol->ref_count >= 0); + spin_unlock(&ubi->volumes_lock); + ubi_put_device(ubi); + return ret; +} +#endif + +/* Release method for volume devices */ +static void vol_release(struct device *dev) +{ + struct ubi_volume *vol = container_of(dev, struct ubi_volume, dev); + + kfree(vol); +} + +#ifdef UBI_LINUX +/** + * volume_sysfs_init - initialize sysfs for new volume. + * @ubi: UBI device description object + * @vol: volume description object + * + * This function returns zero in case of success and a negative error code in + * case of failure. + * + * Note, this function does not free allocated resources in case of failure - + * the caller does it. This is because this would cause release() here and the + * caller would oops. + */ +static int volume_sysfs_init(struct ubi_device *ubi, struct ubi_volume *vol) +{ + int err; + + err = device_create_file(&vol->dev, &attr_vol_reserved_ebs); + if (err) + return err; + err = device_create_file(&vol->dev, &attr_vol_type); + if (err) + return err; + err = device_create_file(&vol->dev, &attr_vol_name); + if (err) + return err; + err = device_create_file(&vol->dev, &attr_vol_corrupted); + if (err) + return err; + err = device_create_file(&vol->dev, &attr_vol_alignment); + if (err) + return err; + err = device_create_file(&vol->dev, &attr_vol_usable_eb_size); + if (err) + return err; + err = device_create_file(&vol->dev, &attr_vol_data_bytes); + if (err) + return err; + err = device_create_file(&vol->dev, &attr_vol_upd_marker); + return err; +} + +/** + * volume_sysfs_close - close sysfs for a volume. + * @vol: volume description object + */ +static void volume_sysfs_close(struct ubi_volume *vol) +{ + device_remove_file(&vol->dev, &attr_vol_upd_marker); + device_remove_file(&vol->dev, &attr_vol_data_bytes); + device_remove_file(&vol->dev, &attr_vol_usable_eb_size); + device_remove_file(&vol->dev, &attr_vol_alignment); + device_remove_file(&vol->dev, &attr_vol_corrupted); + device_remove_file(&vol->dev, &attr_vol_name); + device_remove_file(&vol->dev, &attr_vol_type); + device_remove_file(&vol->dev, &attr_vol_reserved_ebs); + device_unregister(&vol->dev); +} +#endif + +/** + * ubi_create_volume - create volume. + * @ubi: UBI device description object + * @req: volume creation request + * + * This function creates volume described by @req. If @req->vol_id id + * %UBI_VOL_NUM_AUTO, this function automatically assign ID to the new volume + * and saves it in @req->vol_id. Returns zero in case of success and a negative + * error code in case of failure. Note, the caller has to have the + * @ubi->volumes_mutex locked. + */ +int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) +{ + int i, err, vol_id = req->vol_id, dont_free = 0; + struct ubi_volume *vol; + struct ubi_vtbl_record vtbl_rec; + uint64_t bytes; + dev_t dev; + + if (ubi->ro_mode) + return -EROFS; + + vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); + if (!vol) + return -ENOMEM; + + spin_lock(&ubi->volumes_lock); + if (vol_id == UBI_VOL_NUM_AUTO) { + /* Find unused volume ID */ + dbg_msg("search for vacant volume ID"); + for (i = 0; i < ubi->vtbl_slots; i++) + if (!ubi->volumes[i]) { + vol_id = i; + break; + } + + if (vol_id == UBI_VOL_NUM_AUTO) { + dbg_err("out of volume IDs"); + err = -ENFILE; + goto out_unlock; + } + req->vol_id = vol_id; + } + + dbg_msg("volume ID %d, %llu bytes, type %d, name %s", + vol_id, (unsigned long long)req->bytes, + (int)req->vol_type, req->name); + + /* Ensure that this volume does not exist */ + err = -EEXIST; + if (ubi->volumes[vol_id]) { + dbg_err("volume %d already exists", vol_id); + goto out_unlock; + } + + /* Ensure that the name is unique */ + for (i = 0; i < ubi->vtbl_slots; i++) + if (ubi->volumes[i] && + ubi->volumes[i]->name_len == req->name_len && + !strcmp(ubi->volumes[i]->name, req->name)) { + dbg_err("volume \"%s\" exists (ID %d)", req->name, i); + goto out_unlock; + } + + /* Calculate how many eraseblocks are requested */ + vol->usable_leb_size = ubi->leb_size - ubi->leb_size % req->alignment; + bytes = req->bytes; + if (do_div(bytes, vol->usable_leb_size)) + vol->reserved_pebs = 1; + vol->reserved_pebs += bytes; + + /* Reserve physical eraseblocks */ + if (vol->reserved_pebs > ubi->avail_pebs) { + dbg_err("not enough PEBs, only %d available", ubi->avail_pebs); + err = -ENOSPC; + goto out_unlock; + } + ubi->avail_pebs -= vol->reserved_pebs; + ubi->rsvd_pebs += vol->reserved_pebs; + spin_unlock(&ubi->volumes_lock); + + vol->vol_id = vol_id; + vol->alignment = req->alignment; + vol->data_pad = ubi->leb_size % vol->alignment; + vol->vol_type = req->vol_type; + vol->name_len = req->name_len; + memcpy(vol->name, req->name, vol->name_len + 1); + vol->ubi = ubi; + + /* + * Finish all pending erases because there may be some LEBs belonging + * to the same volume ID. + */ + err = ubi_wl_flush(ubi); + if (err) + goto out_acc; + + vol->eba_tbl = kmalloc(vol->reserved_pebs * sizeof(int), GFP_KERNEL); + if (!vol->eba_tbl) { + err = -ENOMEM; + goto out_acc; + } + + for (i = 0; i < vol->reserved_pebs; i++) + vol->eba_tbl[i] = UBI_LEB_UNMAPPED; + + if (vol->vol_type == UBI_DYNAMIC_VOLUME) { + vol->used_ebs = vol->reserved_pebs; + vol->last_eb_bytes = vol->usable_leb_size; + vol->used_bytes = + (long long)vol->used_ebs * vol->usable_leb_size; + } else { + bytes = vol->used_bytes; + vol->last_eb_bytes = do_div(bytes, vol->usable_leb_size); + vol->used_ebs = bytes; + if (vol->last_eb_bytes) + vol->used_ebs += 1; + else + vol->last_eb_bytes = vol->usable_leb_size; + } + + /* Register character device for the volume */ + cdev_init(&vol->cdev, &ubi_vol_cdev_operations); +#ifdef UBI_LINUX + vol->cdev.owner = THIS_MODULE; +#endif + dev = MKDEV(MAJOR(ubi->cdev.dev), vol_id + 1); + err = ubi_volume_cdev_add(ubi, vol); + if (err) { + ubi_err("cannot add character device"); + goto out_mapping; + } + + err = ubi_create_gluebi(ubi, vol); + if (err) + goto out_cdev; + + vol->dev.release = vol_release; + vol->dev.parent = &ubi->dev; + vol->dev.devt = dev; + vol->dev.class = ubi_class; + + sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); + err = device_register(&vol->dev); + if (err) { + ubi_err("cannot register device"); + goto out_gluebi; + } + + err = volume_sysfs_init(ubi, vol); + if (err) + goto out_sysfs; + + /* Fill volume table record */ + memset(&vtbl_rec, 0, sizeof(struct ubi_vtbl_record)); + vtbl_rec.reserved_pebs = cpu_to_be32(vol->reserved_pebs); + vtbl_rec.alignment = cpu_to_be32(vol->alignment); + vtbl_rec.data_pad = cpu_to_be32(vol->data_pad); + vtbl_rec.name_len = cpu_to_be16(vol->name_len); + if (vol->vol_type == UBI_DYNAMIC_VOLUME) + vtbl_rec.vol_type = UBI_VID_DYNAMIC; + else + vtbl_rec.vol_type = UBI_VID_STATIC; + memcpy(vtbl_rec.name, vol->name, vol->name_len + 1); + + err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + if (err) + goto out_sysfs; + + spin_lock(&ubi->volumes_lock); + ubi->volumes[vol_id] = vol; + ubi->vol_count += 1; + spin_unlock(&ubi->volumes_lock); + + paranoid_check_volumes(ubi); + return 0; + +out_sysfs: + /* + * We have registered our device, we should not free the volume* + * description object in this function in case of an error - it is + * freed by the release function. + * + * Get device reference to prevent the release function from being + * called just after sysfs has been closed. + */ + dont_free = 1; + get_device(&vol->dev); + volume_sysfs_close(vol); +out_gluebi: + if (ubi_destroy_gluebi(vol)) + dbg_err("cannot destroy gluebi for volume %d:%d", + ubi->ubi_num, vol_id); +out_cdev: + ubi_volume_cdev_remove(vol); +out_mapping: + kfree(vol->eba_tbl); +out_acc: + spin_lock(&ubi->volumes_lock); + ubi->rsvd_pebs -= vol->reserved_pebs; + ubi->avail_pebs += vol->reserved_pebs; +out_unlock: + spin_unlock(&ubi->volumes_lock); + if (dont_free) + put_device(&vol->dev); + else + kfree(vol); + ubi_err("cannot create volume %d, error %d", vol_id, err); + return err; +} + +/** + * ubi_remove_volume - remove volume. + * @desc: volume descriptor + * + * This function removes volume described by @desc. The volume has to be opened + * in "exclusive" mode. Returns zero in case of success and a negative error + * code in case of failure. The caller has to have the @ubi->volumes_mutex + * locked. + */ +int ubi_remove_volume(struct ubi_volume_desc *desc) +{ + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + int i, err, vol_id = vol->vol_id, reserved_pebs = vol->reserved_pebs; + + dbg_msg("remove UBI volume %d", vol_id); + ubi_assert(desc->mode == UBI_EXCLUSIVE); + ubi_assert(vol == ubi->volumes[vol_id]); + + if (ubi->ro_mode) + return -EROFS; + + spin_lock(&ubi->volumes_lock); + if (vol->ref_count > 1) { + /* + * The volume is busy, probably someone is reading one of its + * sysfs files. + */ + err = -EBUSY; + goto out_unlock; + } + ubi->volumes[vol_id] = NULL; + spin_unlock(&ubi->volumes_lock); + + err = ubi_destroy_gluebi(vol); + if (err) + goto out_err; + + err = ubi_change_vtbl_record(ubi, vol_id, NULL); + if (err) + goto out_err; + + for (i = 0; i < vol->reserved_pebs; i++) { + err = ubi_eba_unmap_leb(ubi, vol, i); + if (err) + goto out_err; + } + + kfree(vol->eba_tbl); + vol->eba_tbl = NULL; + ubi_volume_cdev_remove(vol); + volume_sysfs_close(vol); + + spin_lock(&ubi->volumes_lock); + ubi->rsvd_pebs -= reserved_pebs; + ubi->avail_pebs += reserved_pebs; + i = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; + if (i > 0) { + i = ubi->avail_pebs >= i ? i : ubi->avail_pebs; + ubi->avail_pebs -= i; + ubi->rsvd_pebs += i; + ubi->beb_rsvd_pebs += i; + if (i > 0) + ubi_msg("reserve more %d PEBs", i); + } + ubi->vol_count -= 1; + spin_unlock(&ubi->volumes_lock); + + paranoid_check_volumes(ubi); + return 0; + +out_err: + ubi_err("cannot remove volume %d, error %d", vol_id, err); + spin_lock(&ubi->volumes_lock); + ubi->volumes[vol_id] = vol; +out_unlock: + spin_unlock(&ubi->volumes_lock); + return err; +} + +/** + * ubi_resize_volume - re-size volume. + * @desc: volume descriptor + * @reserved_pebs: new size in physical eraseblocks + * + * This function re-sizes the volume and returns zero in case of success, and a + * negative error code in case of failure. The caller has to have the + * @ubi->volumes_mutex locked. + */ +int ubi_resize_volume(struct ubi_volume_desc *desc, int reserved_pebs) +{ + int i, err, pebs, *new_mapping; + struct ubi_volume *vol = desc->vol; + struct ubi_device *ubi = vol->ubi; + struct ubi_vtbl_record vtbl_rec; + int vol_id = vol->vol_id; + + if (ubi->ro_mode) + return -EROFS; + + dbg_msg("re-size volume %d to from %d to %d PEBs", + vol_id, vol->reserved_pebs, reserved_pebs); + + if (vol->vol_type == UBI_STATIC_VOLUME && + reserved_pebs < vol->used_ebs) { + dbg_err("too small size %d, %d LEBs contain data", + reserved_pebs, vol->used_ebs); + return -EINVAL; + } + + /* If the size is the same, we have nothing to do */ + if (reserved_pebs == vol->reserved_pebs) + return 0; + + new_mapping = kmalloc(reserved_pebs * sizeof(int), GFP_KERNEL); + if (!new_mapping) + return -ENOMEM; + + for (i = 0; i < reserved_pebs; i++) + new_mapping[i] = UBI_LEB_UNMAPPED; + + spin_lock(&ubi->volumes_lock); + if (vol->ref_count > 1) { + spin_unlock(&ubi->volumes_lock); + err = -EBUSY; + goto out_free; + } + spin_unlock(&ubi->volumes_lock); + + /* Reserve physical eraseblocks */ + pebs = reserved_pebs - vol->reserved_pebs; + if (pebs > 0) { + spin_lock(&ubi->volumes_lock); + if (pebs > ubi->avail_pebs) { + dbg_err("not enough PEBs: requested %d, available %d", + pebs, ubi->avail_pebs); + spin_unlock(&ubi->volumes_lock); + err = -ENOSPC; + goto out_free; + } + ubi->avail_pebs -= pebs; + ubi->rsvd_pebs += pebs; + for (i = 0; i < vol->reserved_pebs; i++) + new_mapping[i] = vol->eba_tbl[i]; + kfree(vol->eba_tbl); + vol->eba_tbl = new_mapping; + spin_unlock(&ubi->volumes_lock); + } + + /* Change volume table record */ + memcpy(&vtbl_rec, &ubi->vtbl[vol_id], sizeof(struct ubi_vtbl_record)); + vtbl_rec.reserved_pebs = cpu_to_be32(reserved_pebs); + err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); + if (err) + goto out_acc; + + if (pebs < 0) { + for (i = 0; i < -pebs; i++) { + err = ubi_eba_unmap_leb(ubi, vol, reserved_pebs + i); + if (err) + goto out_acc; + } + spin_lock(&ubi->volumes_lock); + ubi->rsvd_pebs += pebs; + ubi->avail_pebs -= pebs; + pebs = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs; + if (pebs > 0) { + pebs = ubi->avail_pebs >= pebs ? pebs : ubi->avail_pebs; + ubi->avail_pebs -= pebs; + ubi->rsvd_pebs += pebs; + ubi->beb_rsvd_pebs += pebs; + if (pebs > 0) + ubi_msg("reserve more %d PEBs", pebs); + } + for (i = 0; i < reserved_pebs; i++) + new_mapping[i] = vol->eba_tbl[i]; + kfree(vol->eba_tbl); + vol->eba_tbl = new_mapping; + spin_unlock(&ubi->volumes_lock); + } + + vol->reserved_pebs = reserved_pebs; + if (vol->vol_type == UBI_DYNAMIC_VOLUME) { + vol->used_ebs = reserved_pebs; + vol->last_eb_bytes = vol->usable_leb_size; + vol->used_bytes = + (long long)vol->used_ebs * vol->usable_leb_size; + } + + paranoid_check_volumes(ubi); + return 0; + +out_acc: + if (pebs > 0) { + spin_lock(&ubi->volumes_lock); + ubi->rsvd_pebs -= pebs; + ubi->avail_pebs += pebs; + spin_unlock(&ubi->volumes_lock); + } +out_free: + kfree(new_mapping); + return err; +} + +/** + * ubi_add_volume - add volume. + * @ubi: UBI device description object + * @vol: volume description object + * + * This function adds an existing volume and initializes all its data + * structures. Returns zero in case of success and a negative error code in + * case of failure. + */ +int ubi_add_volume(struct ubi_device *ubi, struct ubi_volume *vol) +{ + int err, vol_id = vol->vol_id; + dev_t dev; + + dbg_msg("add volume %d", vol_id); + ubi_dbg_dump_vol_info(vol); + + /* Register character device for the volume */ + cdev_init(&vol->cdev, &ubi_vol_cdev_operations); +#ifdef UBI_LINUX + vol->cdev.owner = THIS_MODULE; +#endif + dev = MKDEV(MAJOR(ubi->cdev.dev), vol->vol_id + 1); + err = ubi_volume_cdev_add(ubi, vol); + if (err) { + ubi_err("cannot add character device for volume %d, error %d", + vol_id, err); + return err; + } + + err = ubi_create_gluebi(ubi, vol); + if (err) + goto out_cdev; + + vol->dev.release = vol_release; + vol->dev.parent = &ubi->dev; + vol->dev.devt = dev; + vol->dev.class = ubi_class; + sprintf(&vol->dev.bus_id[0], "%s_%d", ubi->ubi_name, vol->vol_id); + err = device_register(&vol->dev); + if (err) + goto out_gluebi; + + err = volume_sysfs_init(ubi, vol); + if (err) { + ubi_volume_cdev_remove(vol); + err = ubi_destroy_gluebi(vol); + volume_sysfs_close(vol); + return err; + } + + paranoid_check_volumes(ubi); + return 0; + +out_gluebi: + err = ubi_destroy_gluebi(vol); +out_cdev: + ubi_volume_cdev_remove(vol); + return err; +} + +/** + * ubi_free_volume - free volume. + * @ubi: UBI device description object + * @vol: volume description object + * + * This function frees all resources for volume @vol but does not remove it. + * Used only when the UBI device is detached. + */ +void ubi_free_volume(struct ubi_device *ubi, struct ubi_volume *vol) +{ + int err; + + dbg_msg("free volume %d", vol->vol_id); + + ubi->volumes[vol->vol_id] = NULL; + err = ubi_destroy_gluebi(vol); + ubi_volume_cdev_remove(vol); + volume_sysfs_close(vol); +} + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID + +/** + * paranoid_check_volume - check volume information. + * @ubi: UBI device description object + * @vol_id: volume ID + */ +static void paranoid_check_volume(struct ubi_device *ubi, int vol_id) +{ + int idx = vol_id2idx(ubi, vol_id); + int reserved_pebs, alignment, data_pad, vol_type, name_len, upd_marker; + const struct ubi_volume *vol; + long long n; + const char *name; + + spin_lock(&ubi->volumes_lock); + reserved_pebs = be32_to_cpu(ubi->vtbl[vol_id].reserved_pebs); + vol = ubi->volumes[idx]; + + if (!vol) { + if (reserved_pebs) { + ubi_err("no volume info, but volume exists"); + goto fail; + } + spin_unlock(&ubi->volumes_lock); + return; + } + + if (vol->exclusive) { + /* + * The volume may be being created at the moment, do not check + * it (e.g., it may be in the middle of ubi_create_volume(). + */ + spin_unlock(&ubi->volumes_lock); + return; + } + + if (vol->reserved_pebs < 0 || vol->alignment < 0 || vol->data_pad < 0 || + vol->name_len < 0) { + ubi_err("negative values"); + goto fail; + } + if (vol->alignment > ubi->leb_size || vol->alignment == 0) { + ubi_err("bad alignment"); + goto fail; + } + + n = vol->alignment & (ubi->min_io_size - 1); + if (vol->alignment != 1 && n) { + ubi_err("alignment is not multiple of min I/O unit"); + goto fail; + } + + n = ubi->leb_size % vol->alignment; + if (vol->data_pad != n) { + ubi_err("bad data_pad, has to be %lld", n); + goto fail; + } + + if (vol->vol_type != UBI_DYNAMIC_VOLUME && + vol->vol_type != UBI_STATIC_VOLUME) { + ubi_err("bad vol_type"); + goto fail; + } + + if (vol->upd_marker && vol->corrupted) { + dbg_err("update marker and corrupted simultaneously"); + goto fail; + } + + if (vol->reserved_pebs > ubi->good_peb_count) { + ubi_err("too large reserved_pebs"); + goto fail; + } + + n = ubi->leb_size - vol->data_pad; + if (vol->usable_leb_size != ubi->leb_size - vol->data_pad) { + ubi_err("bad usable_leb_size, has to be %lld", n); + goto fail; + } + + if (vol->name_len > UBI_VOL_NAME_MAX) { + ubi_err("too long volume name, max is %d", UBI_VOL_NAME_MAX); + goto fail; + } + + if (!vol->name) { + ubi_err("NULL volume name"); + goto fail; + } + + n = strnlen(vol->name, vol->name_len + 1); + if (n != vol->name_len) { + ubi_err("bad name_len %lld", n); + goto fail; + } + + n = (long long)vol->used_ebs * vol->usable_leb_size; + if (vol->vol_type == UBI_DYNAMIC_VOLUME) { + if (vol->corrupted) { + ubi_err("corrupted dynamic volume"); + goto fail; + } + if (vol->used_ebs != vol->reserved_pebs) { + ubi_err("bad used_ebs"); + goto fail; + } + if (vol->last_eb_bytes != vol->usable_leb_size) { + ubi_err("bad last_eb_bytes"); + goto fail; + } + if (vol->used_bytes != n) { + ubi_err("bad used_bytes"); + goto fail; + } + } else { + if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { + ubi_err("bad used_ebs"); + goto fail; + } + if (vol->last_eb_bytes < 0 || + vol->last_eb_bytes > vol->usable_leb_size) { + ubi_err("bad last_eb_bytes"); + goto fail; + } + if (vol->used_bytes < 0 || vol->used_bytes > n || + vol->used_bytes < n - vol->usable_leb_size) { + ubi_err("bad used_bytes"); + goto fail; + } + } + + alignment = be32_to_cpu(ubi->vtbl[vol_id].alignment); + data_pad = be32_to_cpu(ubi->vtbl[vol_id].data_pad); + name_len = be16_to_cpu(ubi->vtbl[vol_id].name_len); + upd_marker = ubi->vtbl[vol_id].upd_marker; + name = &ubi->vtbl[vol_id].name[0]; + if (ubi->vtbl[vol_id].vol_type == UBI_VID_DYNAMIC) + vol_type = UBI_DYNAMIC_VOLUME; + else + vol_type = UBI_STATIC_VOLUME; + + if (alignment != vol->alignment || data_pad != vol->data_pad || + upd_marker != vol->upd_marker || vol_type != vol->vol_type || + name_len!= vol->name_len || strncmp(name, vol->name, name_len)) { + ubi_err("volume info is different"); + goto fail; + } + + spin_unlock(&ubi->volumes_lock); + return; + +fail: + ubi_err("paranoid check failed for volume %d", vol_id); + ubi_dbg_dump_vol_info(vol); + ubi_dbg_dump_vtbl_record(&ubi->vtbl[vol_id], vol_id); + spin_unlock(&ubi->volumes_lock); + BUG(); +} + +/** + * paranoid_check_volumes - check information about all volumes. + * @ubi: UBI device description object + */ +static void paranoid_check_volumes(struct ubi_device *ubi) +{ + int i; + + for (i = 0; i < ubi->vtbl_slots; i++) + paranoid_check_volume(ubi, i); +} +#endif diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c new file mode 100644 index 0000000..765c811 --- /dev/null +++ b/drivers/mtd/ubi/vtbl.c @@ -0,0 +1,837 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Nokia Corporation, 2006, 2007 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +/* + * This file includes volume table manipulation code. The volume table is an + * on-flash table containing volume meta-data like name, number of reserved + * physical eraseblocks, type, etc. The volume table is stored in the so-called + * "layout volume". + * + * The layout volume is an internal volume which is organized as follows. It + * consists of two logical eraseblocks - LEB 0 and LEB 1. Each logical + * eraseblock stores one volume table copy, i.e. LEB 0 and LEB 1 duplicate each + * other. This redundancy guarantees robustness to unclean reboots. The volume + * table is basically an array of volume table records. Each record contains + * full information about the volume and protected by a CRC checksum. + * + * The volume table is changed, it is first changed in RAM. Then LEB 0 is + * erased, and the updated volume table is written back to LEB 0. Then same for + * LEB 1. This scheme guarantees recoverability from unclean reboots. + * + * In this UBI implementation the on-flash volume table does not contain any + * information about how many data static volumes contain. This information may + * be found from the scanning data. + * + * But it would still be beneficial to store this information in the volume + * table. For example, suppose we have a static volume X, and all its physical + * eraseblocks became bad for some reasons. Suppose we are attaching the + * corresponding MTD device, the scanning has found no logical eraseblocks + * corresponding to the volume X. According to the volume table volume X does + * exist. So we don't know whether it is just empty or all its physical + * eraseblocks went bad. So we cannot alarm the user about this corruption. + * + * The volume table also stores so-called "update marker", which is used for + * volume updates. Before updating the volume, the update marker is set, and + * after the update operation is finished, the update marker is cleared. So if + * the update operation was interrupted (e.g. by an unclean reboot) - the + * update marker is still there and we know that the volume's contents is + * damaged. + */ + +#ifdef UBI_LINUX +#include +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID +static void paranoid_vtbl_check(const struct ubi_device *ubi); +#else +#define paranoid_vtbl_check(ubi) +#endif + +/* Empty volume table record */ +static struct ubi_vtbl_record empty_vtbl_record; + +/** + * ubi_change_vtbl_record - change volume table record. + * @ubi: UBI device description object + * @idx: table index to change + * @vtbl_rec: new volume table record + * + * This function changes volume table record @idx. If @vtbl_rec is %NULL, empty + * volume table record is written. The caller does not have to calculate CRC of + * the record as it is done by this function. Returns zero in case of success + * and a negative error code in case of failure. + */ +int ubi_change_vtbl_record(struct ubi_device *ubi, int idx, + struct ubi_vtbl_record *vtbl_rec) +{ + int i, err; + uint32_t crc; + struct ubi_volume *layout_vol; + + ubi_assert(idx >= 0 && idx < ubi->vtbl_slots); + layout_vol = ubi->volumes[vol_id2idx(ubi, UBI_LAYOUT_VOLUME_ID)]; + + if (!vtbl_rec) + vtbl_rec = &empty_vtbl_record; + else { + crc = crc32(UBI_CRC32_INIT, vtbl_rec, UBI_VTBL_RECORD_SIZE_CRC); + vtbl_rec->crc = cpu_to_be32(crc); + } + + memcpy(&ubi->vtbl[idx], vtbl_rec, sizeof(struct ubi_vtbl_record)); + for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { + err = ubi_eba_unmap_leb(ubi, layout_vol, i); + if (err) + return err; + + err = ubi_eba_write_leb(ubi, layout_vol, i, ubi->vtbl, 0, + ubi->vtbl_size, UBI_LONGTERM); + if (err) + return err; + } + + paranoid_vtbl_check(ubi); + return 0; +} + +/** + * vtbl_check - check if volume table is not corrupted and contains sensible + * data. + * @ubi: UBI device description object + * @vtbl: volume table + * + * This function returns zero if @vtbl is all right, %1 if CRC is incorrect, + * and %-EINVAL if it contains inconsistent data. + */ +static int vtbl_check(const struct ubi_device *ubi, + const struct ubi_vtbl_record *vtbl) +{ + int i, n, reserved_pebs, alignment, data_pad, vol_type, name_len; + int upd_marker, err; + uint32_t crc; + const char *name; + + for (i = 0; i < ubi->vtbl_slots; i++) { + cond_resched(); + + reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs); + alignment = be32_to_cpu(vtbl[i].alignment); + data_pad = be32_to_cpu(vtbl[i].data_pad); + upd_marker = vtbl[i].upd_marker; + vol_type = vtbl[i].vol_type; + name_len = be16_to_cpu(vtbl[i].name_len); + name = (const char *) &vtbl[i].name[0]; + + crc = crc32(UBI_CRC32_INIT, &vtbl[i], UBI_VTBL_RECORD_SIZE_CRC); + if (be32_to_cpu(vtbl[i].crc) != crc) { + ubi_err("bad CRC at record %u: %#08x, not %#08x", + i, crc, be32_to_cpu(vtbl[i].crc)); + ubi_dbg_dump_vtbl_record(&vtbl[i], i); + return 1; + } + + if (reserved_pebs == 0) { + if (memcmp(&vtbl[i], &empty_vtbl_record, + UBI_VTBL_RECORD_SIZE)) { + err = 2; + goto bad; + } + continue; + } + + if (reserved_pebs < 0 || alignment < 0 || data_pad < 0 || + name_len < 0) { + err = 3; + goto bad; + } + + if (alignment > ubi->leb_size || alignment == 0) { + err = 4; + goto bad; + } + + n = alignment & (ubi->min_io_size - 1); + if (alignment != 1 && n) { + err = 5; + goto bad; + } + + n = ubi->leb_size % alignment; + if (data_pad != n) { + dbg_err("bad data_pad, has to be %d", n); + err = 6; + goto bad; + } + + if (vol_type != UBI_VID_DYNAMIC && vol_type != UBI_VID_STATIC) { + err = 7; + goto bad; + } + + if (upd_marker != 0 && upd_marker != 1) { + err = 8; + goto bad; + } + + if (reserved_pebs > ubi->good_peb_count) { + dbg_err("too large reserved_pebs, good PEBs %d", + ubi->good_peb_count); + err = 9; + goto bad; + } + + if (name_len > UBI_VOL_NAME_MAX) { + err = 10; + goto bad; + } + + if (name[0] == '\0') { + err = 11; + goto bad; + } + + if (name_len != strnlen(name, name_len + 1)) { + err = 12; + goto bad; + } + } + + /* Checks that all names are unique */ + for (i = 0; i < ubi->vtbl_slots - 1; i++) { + for (n = i + 1; n < ubi->vtbl_slots; n++) { + int len1 = be16_to_cpu(vtbl[i].name_len); + int len2 = be16_to_cpu(vtbl[n].name_len); + + if (len1 > 0 && len1 == len2 && + !strncmp((char *)vtbl[i].name, (char *)vtbl[n].name, len1)) { + ubi_err("volumes %d and %d have the same name" + " \"%s\"", i, n, vtbl[i].name); + ubi_dbg_dump_vtbl_record(&vtbl[i], i); + ubi_dbg_dump_vtbl_record(&vtbl[n], n); + return -EINVAL; + } + } + } + + return 0; + +bad: + ubi_err("volume table check failed: record %d, error %d", i, err); + ubi_dbg_dump_vtbl_record(&vtbl[i], i); + return -EINVAL; +} + +/** + * create_vtbl - create a copy of volume table. + * @ubi: UBI device description object + * @si: scanning information + * @copy: number of the volume table copy + * @vtbl: contents of the volume table + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +static int create_vtbl(struct ubi_device *ubi, struct ubi_scan_info *si, + int copy, void *vtbl) +{ + int err, tries = 0; + static struct ubi_vid_hdr *vid_hdr; + struct ubi_scan_volume *sv; + struct ubi_scan_leb *new_seb, *old_seb = NULL; + + ubi_msg("create volume table (copy #%d)", copy + 1); + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_KERNEL); + if (!vid_hdr) + return -ENOMEM; + + /* + * Check if there is a logical eraseblock which would have to contain + * this volume table copy was found during scanning. It has to be wiped + * out. + */ + sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); + if (sv) + old_seb = ubi_scan_find_seb(sv, copy); + +retry: + new_seb = ubi_scan_get_free_peb(ubi, si); + if (IS_ERR(new_seb)) { + err = PTR_ERR(new_seb); + goto out_free; + } + + vid_hdr->vol_type = UBI_VID_DYNAMIC; + vid_hdr->vol_id = cpu_to_be32(UBI_LAYOUT_VOLUME_ID); + vid_hdr->compat = UBI_LAYOUT_VOLUME_COMPAT; + vid_hdr->data_size = vid_hdr->used_ebs = + vid_hdr->data_pad = cpu_to_be32(0); + vid_hdr->lnum = cpu_to_be32(copy); + vid_hdr->sqnum = cpu_to_be64(++si->max_sqnum); + vid_hdr->leb_ver = cpu_to_be32(old_seb ? old_seb->leb_ver + 1: 0); + + /* The EC header is already there, write the VID header */ + err = ubi_io_write_vid_hdr(ubi, new_seb->pnum, vid_hdr); + if (err) + goto write_error; + + /* Write the layout volume contents */ + err = ubi_io_write_data(ubi, vtbl, new_seb->pnum, 0, ubi->vtbl_size); + if (err) + goto write_error; + + /* + * And add it to the scanning information. Don't delete the old + * @old_seb as it will be deleted and freed in 'ubi_scan_add_used()'. + */ + err = ubi_scan_add_used(ubi, si, new_seb->pnum, new_seb->ec, + vid_hdr, 0); + kfree(new_seb); + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + +write_error: + if (err == -EIO && ++tries <= 5) { + /* + * Probably this physical eraseblock went bad, try to pick + * another one. + */ + list_add_tail(&new_seb->u.list, &si->corr); + goto retry; + } + kfree(new_seb); +out_free: + ubi_free_vid_hdr(ubi, vid_hdr); + return err; + +} + +/** + * process_lvol - process the layout volume. + * @ubi: UBI device description object + * @si: scanning information + * @sv: layout volume scanning information + * + * This function is responsible for reading the layout volume, ensuring it is + * not corrupted, and recovering from corruptions if needed. Returns volume + * table in case of success and a negative error code in case of failure. + */ +static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, + struct ubi_scan_info *si, + struct ubi_scan_volume *sv) +{ + int err; + struct rb_node *rb; + struct ubi_scan_leb *seb; + struct ubi_vtbl_record *leb[UBI_LAYOUT_VOLUME_EBS] = { NULL, NULL }; + int leb_corrupted[UBI_LAYOUT_VOLUME_EBS] = {1, 1}; + + /* + * UBI goes through the following steps when it changes the layout + * volume: + * a. erase LEB 0; + * b. write new data to LEB 0; + * c. erase LEB 1; + * d. write new data to LEB 1. + * + * Before the change, both LEBs contain the same data. + * + * Due to unclean reboots, the contents of LEB 0 may be lost, but there + * should LEB 1. So it is OK if LEB 0 is corrupted while LEB 1 is not. + * Similarly, LEB 1 may be lost, but there should be LEB 0. And + * finally, unclean reboots may result in a situation when neither LEB + * 0 nor LEB 1 are corrupted, but they are different. In this case, LEB + * 0 contains more recent information. + * + * So the plan is to first check LEB 0. Then + * a. if LEB 0 is OK, it must be containing the most resent data; then + * we compare it with LEB 1, and if they are different, we copy LEB + * 0 to LEB 1; + * b. if LEB 0 is corrupted, but LEB 1 has to be OK, and we copy LEB 1 + * to LEB 0. + */ + + dbg_msg("check layout volume"); + + /* Read both LEB 0 and LEB 1 into memory */ + ubi_rb_for_each_entry(rb, seb, &sv->root, u.rb) { + leb[seb->lnum] = vmalloc(ubi->vtbl_size); + if (!leb[seb->lnum]) { + err = -ENOMEM; + goto out_free; + } + memset(leb[seb->lnum], 0, ubi->vtbl_size); + + err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, + ubi->vtbl_size); + if (err == UBI_IO_BITFLIPS || err == -EBADMSG) + /* + * Scrub the PEB later. Note, -EBADMSG indicates an + * uncorrectable ECC error, but we have our own CRC and + * the data will be checked later. If the data is OK, + * the PEB will be scrubbed (because we set + * seb->scrub). If the data is not OK, the contents of + * the PEB will be recovered from the second copy, and + * seb->scrub will be cleared in + * 'ubi_scan_add_used()'. + */ + seb->scrub = 1; + else if (err) + goto out_free; + } + + err = -EINVAL; + if (leb[0]) { + leb_corrupted[0] = vtbl_check(ubi, leb[0]); + if (leb_corrupted[0] < 0) + goto out_free; + } + + if (!leb_corrupted[0]) { + /* LEB 0 is OK */ + if (leb[1]) + leb_corrupted[1] = memcmp(leb[0], leb[1], ubi->vtbl_size); + if (leb_corrupted[1]) { + ubi_warn("volume table copy #2 is corrupted"); + err = create_vtbl(ubi, si, 1, leb[0]); + if (err) + goto out_free; + ubi_msg("volume table was restored"); + } + + /* Both LEB 1 and LEB 2 are OK and consistent */ + vfree(leb[1]); + return leb[0]; + } else { + /* LEB 0 is corrupted or does not exist */ + if (leb[1]) { + leb_corrupted[1] = vtbl_check(ubi, leb[1]); + if (leb_corrupted[1] < 0) + goto out_free; + } + if (leb_corrupted[1]) { + /* Both LEB 0 and LEB 1 are corrupted */ + ubi_err("both volume tables are corrupted"); + goto out_free; + } + + ubi_warn("volume table copy #1 is corrupted"); + err = create_vtbl(ubi, si, 0, leb[1]); + if (err) + goto out_free; + ubi_msg("volume table was restored"); + + vfree(leb[0]); + return leb[1]; + } + +out_free: + vfree(leb[0]); + vfree(leb[1]); + return ERR_PTR(err); +} + +/** + * create_empty_lvol - create empty layout volume. + * @ubi: UBI device description object + * @si: scanning information + * + * This function returns volume table contents in case of success and a + * negative error code in case of failure. + */ +static struct ubi_vtbl_record *create_empty_lvol(struct ubi_device *ubi, + struct ubi_scan_info *si) +{ + int i; + struct ubi_vtbl_record *vtbl; + + vtbl = vmalloc(ubi->vtbl_size); + if (!vtbl) + return ERR_PTR(-ENOMEM); + memset(vtbl, 0, ubi->vtbl_size); + + for (i = 0; i < ubi->vtbl_slots; i++) + memcpy(&vtbl[i], &empty_vtbl_record, UBI_VTBL_RECORD_SIZE); + + for (i = 0; i < UBI_LAYOUT_VOLUME_EBS; i++) { + int err; + + err = create_vtbl(ubi, si, i, vtbl); + if (err) { + vfree(vtbl); + return ERR_PTR(err); + } + } + + return vtbl; +} + +/** + * init_volumes - initialize volume information for existing volumes. + * @ubi: UBI device description object + * @si: scanning information + * @vtbl: volume table + * + * This function allocates volume description objects for existing volumes. + * Returns zero in case of success and a negative error code in case of + * failure. + */ +static int init_volumes(struct ubi_device *ubi, const struct ubi_scan_info *si, + const struct ubi_vtbl_record *vtbl) +{ + int i, reserved_pebs = 0; + struct ubi_scan_volume *sv; + struct ubi_volume *vol; + + for (i = 0; i < ubi->vtbl_slots; i++) { + cond_resched(); + + if (be32_to_cpu(vtbl[i].reserved_pebs) == 0) + continue; /* Empty record */ + + vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); + if (!vol) + return -ENOMEM; + + vol->reserved_pebs = be32_to_cpu(vtbl[i].reserved_pebs); + vol->alignment = be32_to_cpu(vtbl[i].alignment); + vol->data_pad = be32_to_cpu(vtbl[i].data_pad); + vol->vol_type = vtbl[i].vol_type == UBI_VID_DYNAMIC ? + UBI_DYNAMIC_VOLUME : UBI_STATIC_VOLUME; + vol->name_len = be16_to_cpu(vtbl[i].name_len); + vol->usable_leb_size = ubi->leb_size - vol->data_pad; + memcpy(vol->name, vtbl[i].name, vol->name_len); + vol->name[vol->name_len] = '\0'; + vol->vol_id = i; + + if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { + /* Auto re-size flag may be set only for one volume */ + if (ubi->autoresize_vol_id != -1) { + ubi_err("more then one auto-resize volume (%d " + "and %d)", ubi->autoresize_vol_id, i); + kfree(vol); + return -EINVAL; + } + + ubi->autoresize_vol_id = i; + } + + ubi_assert(!ubi->volumes[i]); + ubi->volumes[i] = vol; + ubi->vol_count += 1; + vol->ubi = ubi; + reserved_pebs += vol->reserved_pebs; + + /* + * In case of dynamic volume UBI knows nothing about how many + * data is stored there. So assume the whole volume is used. + */ + if (vol->vol_type == UBI_DYNAMIC_VOLUME) { + vol->used_ebs = vol->reserved_pebs; + vol->last_eb_bytes = vol->usable_leb_size; + vol->used_bytes = + (long long)vol->used_ebs * vol->usable_leb_size; + continue; + } + + /* Static volumes only */ + sv = ubi_scan_find_sv(si, i); + if (!sv) { + /* + * No eraseblocks belonging to this volume found. We + * don't actually know whether this static volume is + * completely corrupted or just contains no data. And + * we cannot know this as long as data size is not + * stored on flash. So we just assume the volume is + * empty. FIXME: this should be handled. + */ + continue; + } + + if (sv->leb_count != sv->used_ebs) { + /* + * We found a static volume which misses several + * eraseblocks. Treat it as corrupted. + */ + ubi_warn("static volume %d misses %d LEBs - corrupted", + sv->vol_id, sv->used_ebs - sv->leb_count); + vol->corrupted = 1; + continue; + } + + vol->used_ebs = sv->used_ebs; + vol->used_bytes = + (long long)(vol->used_ebs - 1) * vol->usable_leb_size; + vol->used_bytes += sv->last_data_size; + vol->last_eb_bytes = sv->last_data_size; + } + + /* And add the layout volume */ + vol = kzalloc(sizeof(struct ubi_volume), GFP_KERNEL); + if (!vol) + return -ENOMEM; + + vol->reserved_pebs = UBI_LAYOUT_VOLUME_EBS; + vol->alignment = 1; + vol->vol_type = UBI_DYNAMIC_VOLUME; + vol->name_len = sizeof(UBI_LAYOUT_VOLUME_NAME) - 1; + memcpy(vol->name, UBI_LAYOUT_VOLUME_NAME, vol->name_len + 1); + vol->usable_leb_size = ubi->leb_size; + vol->used_ebs = vol->reserved_pebs; + vol->last_eb_bytes = vol->reserved_pebs; + vol->used_bytes = + (long long)vol->used_ebs * (ubi->leb_size - vol->data_pad); + vol->vol_id = UBI_LAYOUT_VOLUME_ID; + vol->ref_count = 1; + + ubi_assert(!ubi->volumes[i]); + ubi->volumes[vol_id2idx(ubi, vol->vol_id)] = vol; + reserved_pebs += vol->reserved_pebs; + ubi->vol_count += 1; + vol->ubi = ubi; + + if (reserved_pebs > ubi->avail_pebs) + ubi_err("not enough PEBs, required %d, available %d", + reserved_pebs, ubi->avail_pebs); + ubi->rsvd_pebs += reserved_pebs; + ubi->avail_pebs -= reserved_pebs; + + return 0; +} + +/** + * check_sv - check volume scanning information. + * @vol: UBI volume description object + * @sv: volume scanning information + * + * This function returns zero if the volume scanning information is consistent + * to the data read from the volume tabla, and %-EINVAL if not. + */ +static int check_sv(const struct ubi_volume *vol, + const struct ubi_scan_volume *sv) +{ + int err; + + if (sv->highest_lnum >= vol->reserved_pebs) { + err = 1; + goto bad; + } + if (sv->leb_count > vol->reserved_pebs) { + err = 2; + goto bad; + } + if (sv->vol_type != vol->vol_type) { + err = 3; + goto bad; + } + if (sv->used_ebs > vol->reserved_pebs) { + err = 4; + goto bad; + } + if (sv->data_pad != vol->data_pad) { + err = 5; + goto bad; + } + return 0; + +bad: + ubi_err("bad scanning information, error %d", err); + ubi_dbg_dump_sv(sv); + ubi_dbg_dump_vol_info(vol); + return -EINVAL; +} + +/** + * check_scanning_info - check that scanning information. + * @ubi: UBI device description object + * @si: scanning information + * + * Even though we protect on-flash data by CRC checksums, we still don't trust + * the media. This function ensures that scanning information is consistent to + * the information read from the volume table. Returns zero if the scanning + * information is OK and %-EINVAL if it is not. + */ +static int check_scanning_info(const struct ubi_device *ubi, + struct ubi_scan_info *si) +{ + int err, i; + struct ubi_scan_volume *sv; + struct ubi_volume *vol; + + if (si->vols_found > UBI_INT_VOL_COUNT + ubi->vtbl_slots) { + ubi_err("scanning found %d volumes, maximum is %d + %d", + si->vols_found, UBI_INT_VOL_COUNT, ubi->vtbl_slots); + return -EINVAL; + } + + if (si->highest_vol_id >= ubi->vtbl_slots + UBI_INT_VOL_COUNT && + si->highest_vol_id < UBI_INTERNAL_VOL_START) { + ubi_err("too large volume ID %d found by scanning", + si->highest_vol_id); + return -EINVAL; + } + + for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) { + cond_resched(); + + sv = ubi_scan_find_sv(si, i); + vol = ubi->volumes[i]; + if (!vol) { + if (sv) + ubi_scan_rm_volume(si, sv); + continue; + } + + if (vol->reserved_pebs == 0) { + ubi_assert(i < ubi->vtbl_slots); + + if (!sv) + continue; + + /* + * During scanning we found a volume which does not + * exist according to the information in the volume + * table. This must have happened due to an unclean + * reboot while the volume was being removed. Discard + * these eraseblocks. + */ + ubi_msg("finish volume %d removal", sv->vol_id); + ubi_scan_rm_volume(si, sv); + } else if (sv) { + err = check_sv(vol, sv); + if (err) + return err; + } + } + + return 0; +} + +/** + * ubi_read_volume_table - read volume table. + * information. + * @ubi: UBI device description object + * @si: scanning information + * + * This function reads volume table, checks it, recover from errors if needed, + * or creates it if needed. Returns zero in case of success and a negative + * error code in case of failure. + */ +int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_scan_info *si) +{ + int i, err; + struct ubi_scan_volume *sv; + + empty_vtbl_record.crc = cpu_to_be32(0xf116c36b); + + /* + * The number of supported volumes is limited by the eraseblock size + * and by the UBI_MAX_VOLUMES constant. + */ + ubi->vtbl_slots = ubi->leb_size / UBI_VTBL_RECORD_SIZE; + if (ubi->vtbl_slots > UBI_MAX_VOLUMES) + ubi->vtbl_slots = UBI_MAX_VOLUMES; + + ubi->vtbl_size = ubi->vtbl_slots * UBI_VTBL_RECORD_SIZE; + ubi->vtbl_size = ALIGN(ubi->vtbl_size, ubi->min_io_size); + + sv = ubi_scan_find_sv(si, UBI_LAYOUT_VOLUME_ID); + if (!sv) { + /* + * No logical eraseblocks belonging to the layout volume were + * found. This could mean that the flash is just empty. In + * this case we create empty layout volume. + * + * But if flash is not empty this must be a corruption or the + * MTD device just contains garbage. + */ + if (si->is_empty) { + ubi->vtbl = create_empty_lvol(ubi, si); + if (IS_ERR(ubi->vtbl)) + return PTR_ERR(ubi->vtbl); + } else { + ubi_err("the layout volume was not found"); + return -EINVAL; + } + } else { + if (sv->leb_count > UBI_LAYOUT_VOLUME_EBS) { + /* This must not happen with proper UBI images */ + dbg_err("too many LEBs (%d) in layout volume", + sv->leb_count); + return -EINVAL; + } + + ubi->vtbl = process_lvol(ubi, si, sv); + if (IS_ERR(ubi->vtbl)) + return PTR_ERR(ubi->vtbl); + } + + ubi->avail_pebs = ubi->good_peb_count; + + /* + * The layout volume is OK, initialize the corresponding in-RAM data + * structures. + */ + err = init_volumes(ubi, si, ubi->vtbl); + if (err) + goto out_free; + + /* + * Get sure that the scanning information is consistent to the + * information stored in the volume table. + */ + err = check_scanning_info(ubi, si); + if (err) + goto out_free; + + return 0; + +out_free: + vfree(ubi->vtbl); + for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) + if (ubi->volumes[i]) { + kfree(ubi->volumes[i]); + ubi->volumes[i] = NULL; + } + return err; +} + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID + +/** + * paranoid_vtbl_check - check volume table. + * @ubi: UBI device description object + */ +static void paranoid_vtbl_check(const struct ubi_device *ubi) +{ + if (vtbl_check(ubi, ubi->vtbl)) { + ubi_err("paranoid check failed"); + BUG(); + } +} + +#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c new file mode 100644 index 0000000..137e600 --- /dev/null +++ b/drivers/mtd/ubi/wl.c @@ -0,0 +1,1675 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Authors: Artem Bityutskiy (Битюцкий Артём), Thomas Gleixner + */ + +/* + * UBI wear-leveling unit. + * + * This unit is responsible for wear-leveling. It works in terms of physical + * eraseblocks and erase counters and knows nothing about logical eraseblocks, + * volumes, etc. From this unit's perspective all physical eraseblocks are of + * two types - used and free. Used physical eraseblocks are those that were + * "get" by the 'ubi_wl_get_peb()' function, and free physical eraseblocks are + * those that were put by the 'ubi_wl_put_peb()' function. + * + * Physical eraseblocks returned by 'ubi_wl_get_peb()' have only erase counter + * header. The rest of the physical eraseblock contains only 0xFF bytes. + * + * When physical eraseblocks are returned to the WL unit by means of the + * 'ubi_wl_put_peb()' function, they are scheduled for erasure. The erasure is + * done asynchronously in context of the per-UBI device background thread, + * which is also managed by the WL unit. + * + * The wear-leveling is ensured by means of moving the contents of used + * physical eraseblocks with low erase counter to free physical eraseblocks + * with high erase counter. + * + * The 'ubi_wl_get_peb()' function accepts data type hints which help to pick + * an "optimal" physical eraseblock. For example, when it is known that the + * physical eraseblock will be "put" soon because it contains short-term data, + * the WL unit may pick a free physical eraseblock with low erase counter, and + * so forth. + * + * If the WL unit fails to erase a physical eraseblock, it marks it as bad. + * + * This unit is also responsible for scrubbing. If a bit-flip is detected in a + * physical eraseblock, it has to be moved. Technically this is the same as + * moving it for wear-leveling reasons. + * + * As it was said, for the UBI unit all physical eraseblocks are either "free" + * or "used". Free eraseblock are kept in the @wl->free RB-tree, while used + * eraseblocks are kept in a set of different RB-trees: @wl->used, + * @wl->prot.pnum, @wl->prot.aec, and @wl->scrub. + * + * Note, in this implementation, we keep a small in-RAM object for each physical + * eraseblock. This is surely not a scalable solution. But it appears to be good + * enough for moderately large flashes and it is simple. In future, one may + * re-work this unit and make it more scalable. + * + * At the moment this unit does not utilize the sequence number, which was + * introduced relatively recently. But it would be wise to do this because the + * sequence number of a logical eraseblock characterizes how old is it. For + * example, when we move a PEB with low erase counter, and we need to pick the + * target PEB, we pick a PEB with the highest EC if our PEB is "old" and we + * pick target PEB with an average EC if our PEB is not very "old". This is a + * room for future re-works of the WL unit. + * + * FIXME: looks too complex, should be simplified (later). + */ + +#ifdef UBI_LINUX +#include +#include +#include +#include +#endif + +#include "ubi-barebox.h" +#include "ubi.h" + +/* Number of physical eraseblocks reserved for wear-leveling purposes */ +#define WL_RESERVED_PEBS 1 + +/* + * How many erase cycles are short term, unknown, and long term physical + * eraseblocks protected. + */ +#define ST_PROTECTION 16 +#define U_PROTECTION 10 +#define LT_PROTECTION 4 + +/* + * Maximum difference between two erase counters. If this threshold is + * exceeded, the WL unit starts moving data from used physical eraseblocks with + * low erase counter to free physical eraseblocks with high erase counter. + */ +#define UBI_WL_THRESHOLD CONFIG_MTD_UBI_WL_THRESHOLD + +/* + * When a physical eraseblock is moved, the WL unit has to pick the target + * physical eraseblock to move to. The simplest way would be just to pick the + * one with the highest erase counter. But in certain workloads this could lead + * to an unlimited wear of one or few physical eraseblock. Indeed, imagine a + * situation when the picked physical eraseblock is constantly erased after the + * data is written to it. So, we have a constant which limits the highest erase + * counter of the free physical eraseblock to pick. Namely, the WL unit does + * not pick eraseblocks with erase counter greater then the lowest erase + * counter plus %WL_FREE_MAX_DIFF. + */ +#define WL_FREE_MAX_DIFF (2*UBI_WL_THRESHOLD) + +/* + * Maximum number of consecutive background thread failures which is enough to + * switch to read-only mode. + */ +#define WL_MAX_FAILURES 32 + +/** + * struct ubi_wl_prot_entry - PEB protection entry. + * @rb_pnum: link in the @wl->prot.pnum RB-tree + * @rb_aec: link in the @wl->prot.aec RB-tree + * @abs_ec: the absolute erase counter value when the protection ends + * @e: the wear-leveling entry of the physical eraseblock under protection + * + * When the WL unit returns a physical eraseblock, the physical eraseblock is + * protected from being moved for some "time". For this reason, the physical + * eraseblock is not directly moved from the @wl->free tree to the @wl->used + * tree. There is one more tree in between where this physical eraseblock is + * temporarily stored (@wl->prot). + * + * All this protection stuff is needed because: + * o we don't want to move physical eraseblocks just after we have given them + * to the user; instead, we first want to let users fill them up with data; + * + * o there is a chance that the user will put the physical eraseblock very + * soon, so it makes sense not to move it for some time, but wait; this is + * especially important in case of "short term" physical eraseblocks. + * + * Physical eraseblocks stay protected only for limited time. But the "time" is + * measured in erase cycles in this case. This is implemented with help of the + * absolute erase counter (@wl->abs_ec). When it reaches certain value, the + * physical eraseblocks are moved from the protection trees (@wl->prot.*) to + * the @wl->used tree. + * + * Protected physical eraseblocks are searched by physical eraseblock number + * (when they are put) and by the absolute erase counter (to check if it is + * time to move them to the @wl->used tree). So there are actually 2 RB-trees + * storing the protected physical eraseblocks: @wl->prot.pnum and + * @wl->prot.aec. They are referred to as the "protection" trees. The + * first one is indexed by the physical eraseblock number. The second one is + * indexed by the absolute erase counter. Both trees store + * &struct ubi_wl_prot_entry objects. + * + * Each physical eraseblock has 2 main states: free and used. The former state + * corresponds to the @wl->free tree. The latter state is split up on several + * sub-states: + * o the WL movement is allowed (@wl->used tree); + * o the WL movement is temporarily prohibited (@wl->prot.pnum and + * @wl->prot.aec trees); + * o scrubbing is needed (@wl->scrub tree). + * + * Depending on the sub-state, wear-leveling entries of the used physical + * eraseblocks may be kept in one of those trees. + */ +struct ubi_wl_prot_entry { + struct rb_node rb_pnum; + struct rb_node rb_aec; + unsigned long long abs_ec; + struct ubi_wl_entry *e; +}; + +/** + * struct ubi_work - UBI work description data structure. + * @list: a link in the list of pending works + * @func: worker function + * @priv: private data of the worker function + * + * @e: physical eraseblock to erase + * @torture: if the physical eraseblock has to be tortured + * + * The @func pointer points to the worker function. If the @cancel argument is + * not zero, the worker has to free the resources and exit immediately. The + * worker has to return zero in case of success and a negative error code in + * case of failure. + */ +struct ubi_work { + struct list_head list; + int (*func)(struct ubi_device *ubi, struct ubi_work *wrk, int cancel); + /* The below fields are only relevant to erasure works */ + struct ubi_wl_entry *e; + int torture; +}; + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID +static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec); +static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, + struct rb_root *root); +#else +#define paranoid_check_ec(ubi, pnum, ec) 0 +#define paranoid_check_in_wl_tree(e, root) +#endif + +/** + * wl_tree_add - add a wear-leveling entry to a WL RB-tree. + * @e: the wear-leveling entry to add + * @root: the root of the tree + * + * Note, we use (erase counter, physical eraseblock number) pairs as keys in + * the @ubi->used and @ubi->free RB-trees. + */ +static void wl_tree_add(struct ubi_wl_entry *e, struct rb_root *root) +{ + struct rb_node **p, *parent = NULL; + + p = &root->rb_node; + while (*p) { + struct ubi_wl_entry *e1; + + parent = *p; + e1 = rb_entry(parent, struct ubi_wl_entry, rb); + + if (e->ec < e1->ec) + p = &(*p)->rb_left; + else if (e->ec > e1->ec) + p = &(*p)->rb_right; + else { + ubi_assert(e->pnum != e1->pnum); + if (e->pnum < e1->pnum) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + } + + rb_link_node(&e->rb, parent, p); + rb_insert_color(&e->rb, root); +} + +/** + * do_work - do one pending work. + * @ubi: UBI device description object + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +static int do_work(struct ubi_device *ubi) +{ + int err; + struct ubi_work *wrk; + + cond_resched(); + + /* + * @ubi->work_sem is used to synchronize with the workers. Workers take + * it in read mode, so many of them may be doing works at a time. But + * the queue flush code has to be sure the whole queue of works is + * done, and it takes the mutex in write mode. + */ + down_read(&ubi->work_sem); + spin_lock(&ubi->wl_lock); + if (list_empty(&ubi->works)) { + spin_unlock(&ubi->wl_lock); + up_read(&ubi->work_sem); + return 0; + } + + wrk = list_entry(ubi->works.next, struct ubi_work, list); + list_del(&wrk->list); + ubi->works_count -= 1; + ubi_assert(ubi->works_count >= 0); + spin_unlock(&ubi->wl_lock); + + /* + * Call the worker function. Do not touch the work structure + * after this call as it will have been freed or reused by that + * time by the worker function. + */ + err = wrk->func(ubi, wrk, 0); + if (err) + ubi_err("work failed with error code %d", err); + up_read(&ubi->work_sem); + + return err; +} + +/** + * produce_free_peb - produce a free physical eraseblock. + * @ubi: UBI device description object + * + * This function tries to make a free PEB by means of synchronous execution of + * pending works. This may be needed if, for example the background thread is + * disabled. Returns zero in case of success and a negative error code in case + * of failure. + */ +static int produce_free_peb(struct ubi_device *ubi) +{ + int err; + + spin_lock(&ubi->wl_lock); + while (!ubi->free.rb_node) { + spin_unlock(&ubi->wl_lock); + + dbg_wl("do one work synchronously"); + err = do_work(ubi); + if (err) + return err; + + spin_lock(&ubi->wl_lock); + } + spin_unlock(&ubi->wl_lock); + + return 0; +} + +/** + * in_wl_tree - check if wear-leveling entry is present in a WL RB-tree. + * @e: the wear-leveling entry to check + * @root: the root of the tree + * + * This function returns non-zero if @e is in the @root RB-tree and zero if it + * is not. + */ +static int in_wl_tree(struct ubi_wl_entry *e, struct rb_root *root) +{ + struct rb_node *p; + + p = root->rb_node; + while (p) { + struct ubi_wl_entry *e1; + + e1 = rb_entry(p, struct ubi_wl_entry, rb); + + if (e->pnum == e1->pnum) { + ubi_assert(e == e1); + return 1; + } + + if (e->ec < e1->ec) + p = p->rb_left; + else if (e->ec > e1->ec) + p = p->rb_right; + else { + ubi_assert(e->pnum != e1->pnum); + if (e->pnum < e1->pnum) + p = p->rb_left; + else + p = p->rb_right; + } + } + + return 0; +} + +/** + * prot_tree_add - add physical eraseblock to protection trees. + * @ubi: UBI device description object + * @e: the physical eraseblock to add + * @pe: protection entry object to use + * @abs_ec: absolute erase counter value when this physical eraseblock has + * to be removed from the protection trees. + * + * @wl->lock has to be locked. + */ +static void prot_tree_add(struct ubi_device *ubi, struct ubi_wl_entry *e, + struct ubi_wl_prot_entry *pe, int abs_ec) +{ + struct rb_node **p, *parent = NULL; + struct ubi_wl_prot_entry *pe1; + + pe->e = e; + pe->abs_ec = ubi->abs_ec + abs_ec; + + p = &ubi->prot.pnum.rb_node; + while (*p) { + parent = *p; + pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_pnum); + + if (e->pnum < pe1->e->pnum) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + rb_link_node(&pe->rb_pnum, parent, p); + rb_insert_color(&pe->rb_pnum, &ubi->prot.pnum); + + p = &ubi->prot.aec.rb_node; + parent = NULL; + while (*p) { + parent = *p; + pe1 = rb_entry(parent, struct ubi_wl_prot_entry, rb_aec); + + if (pe->abs_ec < pe1->abs_ec) + p = &(*p)->rb_left; + else + p = &(*p)->rb_right; + } + rb_link_node(&pe->rb_aec, parent, p); + rb_insert_color(&pe->rb_aec, &ubi->prot.aec); +} + +/** + * find_wl_entry - find wear-leveling entry closest to certain erase counter. + * @root: the RB-tree where to look for + * @max: highest possible erase counter + * + * This function looks for a wear leveling entry with erase counter closest to + * @max and less then @max. + */ +static struct ubi_wl_entry *find_wl_entry(struct rb_root *root, int max) +{ + struct rb_node *p; + struct ubi_wl_entry *e; + + e = rb_entry(rb_first(root), struct ubi_wl_entry, rb); + max += e->ec; + + p = root->rb_node; + while (p) { + struct ubi_wl_entry *e1; + + e1 = rb_entry(p, struct ubi_wl_entry, rb); + if (e1->ec >= max) + p = p->rb_left; + else { + p = p->rb_right; + e = e1; + } + } + + return e; +} + +/** + * ubi_wl_get_peb - get a physical eraseblock. + * @ubi: UBI device description object + * @dtype: type of data which will be stored in this physical eraseblock + * + * This function returns a physical eraseblock in case of success and a + * negative error code in case of failure. Might sleep. + */ +int ubi_wl_get_peb(struct ubi_device *ubi, int dtype) +{ + int err, protect, medium_ec; + struct ubi_wl_entry *e, *first, *last; + struct ubi_wl_prot_entry *pe; + + ubi_assert(dtype == UBI_LONGTERM || dtype == UBI_SHORTTERM || + dtype == UBI_UNKNOWN); + + pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS); + if (!pe) + return -ENOMEM; + +retry: + spin_lock(&ubi->wl_lock); + if (!ubi->free.rb_node) { + if (ubi->works_count == 0) { + ubi_assert(list_empty(&ubi->works)); + ubi_err("no free eraseblocks"); + spin_unlock(&ubi->wl_lock); + kfree(pe); + return -ENOSPC; + } + spin_unlock(&ubi->wl_lock); + + err = produce_free_peb(ubi); + if (err < 0) { + kfree(pe); + return err; + } + goto retry; + } + + switch (dtype) { + case UBI_LONGTERM: + /* + * For long term data we pick a physical eraseblock + * with high erase counter. But the highest erase + * counter we can pick is bounded by the the lowest + * erase counter plus %WL_FREE_MAX_DIFF. + */ + e = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); + protect = LT_PROTECTION; + break; + case UBI_UNKNOWN: + /* + * For unknown data we pick a physical eraseblock with + * medium erase counter. But we by no means can pick a + * physical eraseblock with erase counter greater or + * equivalent than the lowest erase counter plus + * %WL_FREE_MAX_DIFF. + */ + first = rb_entry(rb_first(&ubi->free), + struct ubi_wl_entry, rb); + last = rb_entry(rb_last(&ubi->free), + struct ubi_wl_entry, rb); + + if (last->ec - first->ec < WL_FREE_MAX_DIFF) + e = rb_entry(ubi->free.rb_node, + struct ubi_wl_entry, rb); + else { + medium_ec = (first->ec + WL_FREE_MAX_DIFF)/2; + e = find_wl_entry(&ubi->free, medium_ec); + } + protect = U_PROTECTION; + break; + case UBI_SHORTTERM: + /* + * For short term data we pick a physical eraseblock + * with the lowest erase counter as we expect it will + * be erased soon. + */ + e = rb_entry(rb_first(&ubi->free), + struct ubi_wl_entry, rb); + protect = ST_PROTECTION; + break; + default: + protect = 0; + e = NULL; + BUG(); + } + + /* + * Move the physical eraseblock to the protection trees where it will + * be protected from being moved for some time. + */ + paranoid_check_in_wl_tree(e, &ubi->free); + rb_erase(&e->rb, &ubi->free); + prot_tree_add(ubi, e, pe, protect); + + dbg_wl("PEB %d EC %d, protection %d", e->pnum, e->ec, protect); + spin_unlock(&ubi->wl_lock); + + return e->pnum; +} + +/** + * prot_tree_del - remove a physical eraseblock from the protection trees + * @ubi: UBI device description object + * @pnum: the physical eraseblock to remove + * + * This function returns PEB @pnum from the protection trees and returns zero + * in case of success and %-ENODEV if the PEB was not found in the protection + * trees. + */ +static int prot_tree_del(struct ubi_device *ubi, int pnum) +{ + struct rb_node *p; + struct ubi_wl_prot_entry *pe = NULL; + + p = ubi->prot.pnum.rb_node; + while (p) { + + pe = rb_entry(p, struct ubi_wl_prot_entry, rb_pnum); + + if (pnum == pe->e->pnum) + goto found; + + if (pnum < pe->e->pnum) + p = p->rb_left; + else + p = p->rb_right; + } + + return -ENODEV; + +found: + ubi_assert(pe->e->pnum == pnum); + rb_erase(&pe->rb_aec, &ubi->prot.aec); + rb_erase(&pe->rb_pnum, &ubi->prot.pnum); + kfree(pe); + return 0; +} + +/** + * sync_erase - synchronously erase a physical eraseblock. + * @ubi: UBI device description object + * @e: the the physical eraseblock to erase + * @torture: if the physical eraseblock has to be tortured + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +static int sync_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, int torture) +{ + int err; + struct ubi_ec_hdr *ec_hdr; + unsigned long long ec = e->ec; + + dbg_wl("erase PEB %d, old EC %llu", e->pnum, ec); + + err = paranoid_check_ec(ubi, e->pnum, e->ec); + if (err > 0) + return -EINVAL; + + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); + if (!ec_hdr) + return -ENOMEM; + + err = ubi_io_sync_erase(ubi, e->pnum, torture); + if (err < 0) + goto out_free; + + ec += err; + if (ec > UBI_MAX_ERASECOUNTER) { + /* + * Erase counter overflow. Upgrade UBI and use 64-bit + * erase counters internally. + */ + ubi_err("erase counter overflow at PEB %d, EC %llu", + e->pnum, ec); + err = -EINVAL; + goto out_free; + } + + dbg_wl("erased PEB %d, new EC %llu", e->pnum, ec); + + ec_hdr->ec = cpu_to_be64(ec); + + err = ubi_io_write_ec_hdr(ubi, e->pnum, ec_hdr); + if (err) + goto out_free; + + e->ec = ec; + spin_lock(&ubi->wl_lock); + if (e->ec > ubi->max_ec) + ubi->max_ec = e->ec; + spin_unlock(&ubi->wl_lock); + +out_free: + kfree(ec_hdr); + return err; +} + +/** + * check_protection_over - check if it is time to stop protecting some + * physical eraseblocks. + * @ubi: UBI device description object + * + * This function is called after each erase operation, when the absolute erase + * counter is incremented, to check if some physical eraseblock have not to be + * protected any longer. These physical eraseblocks are moved from the + * protection trees to the used tree. + */ +static void check_protection_over(struct ubi_device *ubi) +{ + struct ubi_wl_prot_entry *pe; + + /* + * There may be several protected physical eraseblock to remove, + * process them all. + */ + while (1) { + spin_lock(&ubi->wl_lock); + if (!ubi->prot.aec.rb_node) { + spin_unlock(&ubi->wl_lock); + break; + } + + pe = rb_entry(rb_first(&ubi->prot.aec), + struct ubi_wl_prot_entry, rb_aec); + + if (pe->abs_ec > ubi->abs_ec) { + spin_unlock(&ubi->wl_lock); + break; + } + + dbg_wl("PEB %d protection over, abs_ec %llu, PEB abs_ec %llu", + pe->e->pnum, ubi->abs_ec, pe->abs_ec); + rb_erase(&pe->rb_aec, &ubi->prot.aec); + rb_erase(&pe->rb_pnum, &ubi->prot.pnum); + wl_tree_add(pe->e, &ubi->used); + spin_unlock(&ubi->wl_lock); + + kfree(pe); + cond_resched(); + } +} + +/** + * schedule_ubi_work - schedule a work. + * @ubi: UBI device description object + * @wrk: the work to schedule + * + * This function enqueues a work defined by @wrk to the tail of the pending + * works list. + */ +static void schedule_ubi_work(struct ubi_device *ubi, struct ubi_work *wrk) +{ + spin_lock(&ubi->wl_lock); + list_add_tail(&wrk->list, &ubi->works); + ubi_assert(ubi->works_count >= 0); + ubi->works_count += 1; + + /* + * U-Boot special: We have no bgt_thread in U-Boot! + * So just call do_work() here directly. + */ + do_work(ubi); + + spin_unlock(&ubi->wl_lock); +} + +static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, + int cancel); + +/** + * schedule_erase - schedule an erase work. + * @ubi: UBI device description object + * @e: the WL entry of the physical eraseblock to erase + * @torture: if the physical eraseblock has to be tortured + * + * This function returns zero in case of success and a %-ENOMEM in case of + * failure. + */ +static int schedule_erase(struct ubi_device *ubi, struct ubi_wl_entry *e, + int torture) +{ + struct ubi_work *wl_wrk; + + dbg_wl("schedule erasure of PEB %d, EC %d, torture %d", + e->pnum, e->ec, torture); + + wl_wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); + if (!wl_wrk) + return -ENOMEM; + + wl_wrk->func = &erase_worker; + wl_wrk->e = e; + wl_wrk->torture = torture; + + schedule_ubi_work(ubi, wl_wrk); + return 0; +} + +/** + * wear_leveling_worker - wear-leveling worker function. + * @ubi: UBI device description object + * @wrk: the work object + * @cancel: non-zero if the worker has to free memory and exit + * + * This function copies a more worn out physical eraseblock to a less worn out + * one. Returns zero in case of success and a negative error code in case of + * failure. + */ +static int wear_leveling_worker(struct ubi_device *ubi, struct ubi_work *wrk, + int cancel) +{ + int err, put = 0, scrubbing = 0, protect = 0; + struct ubi_wl_prot_entry *uninitialized_var(pe); + struct ubi_wl_entry *e1, *e2; + struct ubi_vid_hdr *vid_hdr; + + kfree(wrk); + + if (cancel) + return 0; + + vid_hdr = ubi_zalloc_vid_hdr(ubi, GFP_NOFS); + if (!vid_hdr) + return -ENOMEM; + + mutex_lock(&ubi->move_mutex); + spin_lock(&ubi->wl_lock); + ubi_assert(!ubi->move_from && !ubi->move_to); + ubi_assert(!ubi->move_to_put); + + if (!ubi->free.rb_node || + (!ubi->used.rb_node && !ubi->scrub.rb_node)) { + /* + * No free physical eraseblocks? Well, they must be waiting in + * the queue to be erased. Cancel movement - it will be + * triggered again when a free physical eraseblock appears. + * + * No used physical eraseblocks? They must be temporarily + * protected from being moved. They will be moved to the + * @ubi->used tree later and the wear-leveling will be + * triggered again. + */ + dbg_wl("cancel WL, a list is empty: free %d, used %d", + !ubi->free.rb_node, !ubi->used.rb_node); + goto out_cancel; + } + + if (!ubi->scrub.rb_node) { + /* + * Now pick the least worn-out used physical eraseblock and a + * highly worn-out free physical eraseblock. If the erase + * counters differ much enough, start wear-leveling. + */ + e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb); + e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); + + if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) { + dbg_wl("no WL needed: min used EC %d, max free EC %d", + e1->ec, e2->ec); + goto out_cancel; + } + paranoid_check_in_wl_tree(e1, &ubi->used); + rb_erase(&e1->rb, &ubi->used); + dbg_wl("move PEB %d EC %d to PEB %d EC %d", + e1->pnum, e1->ec, e2->pnum, e2->ec); + } else { + /* Perform scrubbing */ + scrubbing = 1; + e1 = rb_entry(rb_first(&ubi->scrub), struct ubi_wl_entry, rb); + e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); + paranoid_check_in_wl_tree(e1, &ubi->scrub); + rb_erase(&e1->rb, &ubi->scrub); + dbg_wl("scrub PEB %d to PEB %d", e1->pnum, e2->pnum); + } + + paranoid_check_in_wl_tree(e2, &ubi->free); + rb_erase(&e2->rb, &ubi->free); + ubi->move_from = e1; + ubi->move_to = e2; + spin_unlock(&ubi->wl_lock); + + /* + * Now we are going to copy physical eraseblock @e1->pnum to @e2->pnum. + * We so far do not know which logical eraseblock our physical + * eraseblock (@e1) belongs to. We have to read the volume identifier + * header first. + * + * Note, we are protected from this PEB being unmapped and erased. The + * 'ubi_wl_put_peb()' would wait for moving to be finished if the PEB + * which is being moved was unmapped. + */ + + err = ubi_io_read_vid_hdr(ubi, e1->pnum, vid_hdr, 0); + if (err && err != UBI_IO_BITFLIPS) { + if (err == UBI_IO_PEB_FREE) { + /* + * We are trying to move PEB without a VID header. UBI + * always write VID headers shortly after the PEB was + * given, so we have a situation when it did not have + * chance to write it down because it was preempted. + * Just re-schedule the work, so that next time it will + * likely have the VID header in place. + */ + dbg_wl("PEB %d has no VID header", e1->pnum); + goto out_not_moved; + } + + ubi_err("error %d while reading VID header from PEB %d", + err, e1->pnum); + if (err > 0) + err = -EIO; + goto out_error; + } + + err = ubi_eba_copy_leb(ubi, e1->pnum, e2->pnum, vid_hdr); + if (err) { + + if (err < 0) + goto out_error; + if (err == 1) + goto out_not_moved; + + /* + * For some reason the LEB was not moved - it might be because + * the volume is being deleted. We should prevent this PEB from + * being selected for wear-levelling movement for some "time", + * so put it to the protection tree. + */ + + dbg_wl("cancelled moving PEB %d", e1->pnum); + pe = kmalloc(sizeof(struct ubi_wl_prot_entry), GFP_NOFS); + if (!pe) { + err = -ENOMEM; + goto out_error; + } + + protect = 1; + } + + ubi_free_vid_hdr(ubi, vid_hdr); + spin_lock(&ubi->wl_lock); + if (protect) + prot_tree_add(ubi, e1, pe, protect); + if (!ubi->move_to_put) + wl_tree_add(e2, &ubi->used); + else + put = 1; + ubi->move_from = ubi->move_to = NULL; + ubi->move_to_put = ubi->wl_scheduled = 0; + spin_unlock(&ubi->wl_lock); + + if (put) { + /* + * Well, the target PEB was put meanwhile, schedule it for + * erasure. + */ + dbg_wl("PEB %d was put meanwhile, erase", e2->pnum); + err = schedule_erase(ubi, e2, 0); + if (err) + goto out_error; + } + + if (!protect) { + err = schedule_erase(ubi, e1, 0); + if (err) + goto out_error; + } + + + dbg_wl("done"); + mutex_unlock(&ubi->move_mutex); + return 0; + + /* + * For some reasons the LEB was not moved, might be an error, might be + * something else. @e1 was not changed, so return it back. @e2 might + * be changed, schedule it for erasure. + */ +out_not_moved: + ubi_free_vid_hdr(ubi, vid_hdr); + spin_lock(&ubi->wl_lock); + if (scrubbing) + wl_tree_add(e1, &ubi->scrub); + else + wl_tree_add(e1, &ubi->used); + ubi->move_from = ubi->move_to = NULL; + ubi->move_to_put = ubi->wl_scheduled = 0; + spin_unlock(&ubi->wl_lock); + + err = schedule_erase(ubi, e2, 0); + if (err) + goto out_error; + + mutex_unlock(&ubi->move_mutex); + return 0; + +out_error: + ubi_err("error %d while moving PEB %d to PEB %d", + err, e1->pnum, e2->pnum); + + ubi_free_vid_hdr(ubi, vid_hdr); + spin_lock(&ubi->wl_lock); + ubi->move_from = ubi->move_to = NULL; + ubi->move_to_put = ubi->wl_scheduled = 0; + spin_unlock(&ubi->wl_lock); + + kmem_cache_free(ubi_wl_entry_slab, e1); + kmem_cache_free(ubi_wl_entry_slab, e2); + ubi_ro_mode(ubi); + + mutex_unlock(&ubi->move_mutex); + return err; + +out_cancel: + ubi->wl_scheduled = 0; + spin_unlock(&ubi->wl_lock); + mutex_unlock(&ubi->move_mutex); + ubi_free_vid_hdr(ubi, vid_hdr); + return 0; +} + +/** + * ensure_wear_leveling - schedule wear-leveling if it is needed. + * @ubi: UBI device description object + * + * This function checks if it is time to start wear-leveling and schedules it + * if yes. This function returns zero in case of success and a negative error + * code in case of failure. + */ +static int ensure_wear_leveling(struct ubi_device *ubi) +{ + int err = 0; + struct ubi_wl_entry *e1; + struct ubi_wl_entry *e2; + struct ubi_work *wrk; + + spin_lock(&ubi->wl_lock); + if (ubi->wl_scheduled) + /* Wear-leveling is already in the work queue */ + goto out_unlock; + + /* + * If the ubi->scrub tree is not empty, scrubbing is needed, and the + * the WL worker has to be scheduled anyway. + */ + if (!ubi->scrub.rb_node) { + if (!ubi->used.rb_node || !ubi->free.rb_node) + /* No physical eraseblocks - no deal */ + goto out_unlock; + + /* + * We schedule wear-leveling only if the difference between the + * lowest erase counter of used physical eraseblocks and a high + * erase counter of free physical eraseblocks is greater then + * %UBI_WL_THRESHOLD. + */ + e1 = rb_entry(rb_first(&ubi->used), struct ubi_wl_entry, rb); + e2 = find_wl_entry(&ubi->free, WL_FREE_MAX_DIFF); + + if (!(e2->ec - e1->ec >= UBI_WL_THRESHOLD)) + goto out_unlock; + dbg_wl("schedule wear-leveling"); + } else + dbg_wl("schedule scrubbing"); + + ubi->wl_scheduled = 1; + spin_unlock(&ubi->wl_lock); + + wrk = kmalloc(sizeof(struct ubi_work), GFP_NOFS); + if (!wrk) { + err = -ENOMEM; + goto out_cancel; + } + + wrk->func = &wear_leveling_worker; + schedule_ubi_work(ubi, wrk); + return err; + +out_cancel: + spin_lock(&ubi->wl_lock); + ubi->wl_scheduled = 0; +out_unlock: + spin_unlock(&ubi->wl_lock); + return err; +} + +/** + * erase_worker - physical eraseblock erase worker function. + * @ubi: UBI device description object + * @wl_wrk: the work object + * @cancel: non-zero if the worker has to free memory and exit + * + * This function erases a physical eraseblock and perform torture testing if + * needed. It also takes care about marking the physical eraseblock bad if + * needed. Returns zero in case of success and a negative error code in case of + * failure. + */ +static int erase_worker(struct ubi_device *ubi, struct ubi_work *wl_wrk, + int cancel) +{ + struct ubi_wl_entry *e = wl_wrk->e; + int pnum = e->pnum, err, need; + + if (cancel) { + dbg_wl("cancel erasure of PEB %d EC %d", pnum, e->ec); + kfree(wl_wrk); + kmem_cache_free(ubi_wl_entry_slab, e); + return 0; + } + + dbg_wl("erase PEB %d EC %d", pnum, e->ec); + + err = sync_erase(ubi, e, wl_wrk->torture); + if (!err) { + /* Fine, we've erased it successfully */ + kfree(wl_wrk); + + spin_lock(&ubi->wl_lock); + ubi->abs_ec += 1; + wl_tree_add(e, &ubi->free); + spin_unlock(&ubi->wl_lock); + + /* + * One more erase operation has happened, take care about protected + * physical eraseblocks. + */ + check_protection_over(ubi); + + /* And take care about wear-leveling */ + err = ensure_wear_leveling(ubi); + return err; + } + + ubi_err("failed to erase PEB %d, error %d", pnum, err); + kfree(wl_wrk); + kmem_cache_free(ubi_wl_entry_slab, e); + + if (err == -EINTR || err == -ENOMEM || err == -EAGAIN || + err == -EBUSY) { + int err1; + + /* Re-schedule the LEB for erasure */ + err1 = schedule_erase(ubi, e, 0); + if (err1) { + err = err1; + goto out_ro; + } + return err; + } else if (err != -EIO) { + /* + * If this is not %-EIO, we have no idea what to do. Scheduling + * this physical eraseblock for erasure again would cause + * errors again and again. Well, lets switch to RO mode. + */ + goto out_ro; + } + + /* It is %-EIO, the PEB went bad */ + + if (!ubi->bad_allowed) { + ubi_err("bad physical eraseblock %d detected", pnum); + goto out_ro; + } + + spin_lock(&ubi->volumes_lock); + need = ubi->beb_rsvd_level - ubi->beb_rsvd_pebs + 1; + if (need > 0) { + need = ubi->avail_pebs >= need ? need : ubi->avail_pebs; + ubi->avail_pebs -= need; + ubi->rsvd_pebs += need; + ubi->beb_rsvd_pebs += need; + if (need > 0) + ubi_msg("reserve more %d PEBs", need); + } + + if (ubi->beb_rsvd_pebs == 0) { + spin_unlock(&ubi->volumes_lock); + ubi_err("no reserved physical eraseblocks"); + goto out_ro; + } + + spin_unlock(&ubi->volumes_lock); + ubi_msg("mark PEB %d as bad", pnum); + + err = ubi_io_mark_bad(ubi, pnum); + if (err) + goto out_ro; + + spin_lock(&ubi->volumes_lock); + ubi->beb_rsvd_pebs -= 1; + ubi->bad_peb_count += 1; + ubi->good_peb_count -= 1; + ubi_calculate_reserved(ubi); + if (ubi->beb_rsvd_pebs == 0) + ubi_warn("last PEB from the reserved pool was used"); + spin_unlock(&ubi->volumes_lock); + + return err; + +out_ro: + ubi_ro_mode(ubi); + return err; +} + +/** + * ubi_wl_put_peb - return a physical eraseblock to the wear-leveling unit. + * @ubi: UBI device description object + * @pnum: physical eraseblock to return + * @torture: if this physical eraseblock has to be tortured + * + * This function is called to return physical eraseblock @pnum to the pool of + * free physical eraseblocks. The @torture flag has to be set if an I/O error + * occurred to this @pnum and it has to be tested. This function returns zero + * in case of success, and a negative error code in case of failure. + */ +int ubi_wl_put_peb(struct ubi_device *ubi, int pnum, int torture) +{ + int err; + struct ubi_wl_entry *e; + + dbg_wl("PEB %d", pnum); + ubi_assert(pnum >= 0); + ubi_assert(pnum < ubi->peb_count); + +retry: + spin_lock(&ubi->wl_lock); + e = ubi->lookuptbl[pnum]; + if (e == ubi->move_from) { + /* + * User is putting the physical eraseblock which was selected to + * be moved. It will be scheduled for erasure in the + * wear-leveling worker. + */ + dbg_wl("PEB %d is being moved, wait", pnum); + spin_unlock(&ubi->wl_lock); + + /* Wait for the WL worker by taking the @ubi->move_mutex */ + mutex_lock(&ubi->move_mutex); + mutex_unlock(&ubi->move_mutex); + goto retry; + } else if (e == ubi->move_to) { + /* + * User is putting the physical eraseblock which was selected + * as the target the data is moved to. It may happen if the EBA + * unit already re-mapped the LEB in 'ubi_eba_copy_leb()' but + * the WL unit has not put the PEB to the "used" tree yet, but + * it is about to do this. So we just set a flag which will + * tell the WL worker that the PEB is not needed anymore and + * should be scheduled for erasure. + */ + dbg_wl("PEB %d is the target of data moving", pnum); + ubi_assert(!ubi->move_to_put); + ubi->move_to_put = 1; + spin_unlock(&ubi->wl_lock); + return 0; + } else { + if (in_wl_tree(e, &ubi->used)) { + paranoid_check_in_wl_tree(e, &ubi->used); + rb_erase(&e->rb, &ubi->used); + } else if (in_wl_tree(e, &ubi->scrub)) { + paranoid_check_in_wl_tree(e, &ubi->scrub); + rb_erase(&e->rb, &ubi->scrub); + } else { + err = prot_tree_del(ubi, e->pnum); + if (err) { + ubi_err("PEB %d not found", pnum); + ubi_ro_mode(ubi); + spin_unlock(&ubi->wl_lock); + return err; + } + } + } + spin_unlock(&ubi->wl_lock); + + err = schedule_erase(ubi, e, torture); + if (err) { + spin_lock(&ubi->wl_lock); + wl_tree_add(e, &ubi->used); + spin_unlock(&ubi->wl_lock); + } + + return err; +} + +/** + * ubi_wl_scrub_peb - schedule a physical eraseblock for scrubbing. + * @ubi: UBI device description object + * @pnum: the physical eraseblock to schedule + * + * If a bit-flip in a physical eraseblock is detected, this physical eraseblock + * needs scrubbing. This function schedules a physical eraseblock for + * scrubbing which is done in background. This function returns zero in case of + * success and a negative error code in case of failure. + */ +int ubi_wl_scrub_peb(struct ubi_device *ubi, int pnum) +{ + struct ubi_wl_entry *e; + + ubi_msg("schedule PEB %d for scrubbing", pnum); + +retry: + spin_lock(&ubi->wl_lock); + e = ubi->lookuptbl[pnum]; + if (e == ubi->move_from || in_wl_tree(e, &ubi->scrub)) { + spin_unlock(&ubi->wl_lock); + return 0; + } + + if (e == ubi->move_to) { + /* + * This physical eraseblock was used to move data to. The data + * was moved but the PEB was not yet inserted to the proper + * tree. We should just wait a little and let the WL worker + * proceed. + */ + spin_unlock(&ubi->wl_lock); + dbg_wl("the PEB %d is not in proper tree, retry", pnum); + yield(); + goto retry; + } + + if (in_wl_tree(e, &ubi->used)) { + paranoid_check_in_wl_tree(e, &ubi->used); + rb_erase(&e->rb, &ubi->used); + } else { + int err; + + err = prot_tree_del(ubi, e->pnum); + if (err) { + ubi_err("PEB %d not found", pnum); + ubi_ro_mode(ubi); + spin_unlock(&ubi->wl_lock); + return err; + } + } + + wl_tree_add(e, &ubi->scrub); + spin_unlock(&ubi->wl_lock); + + /* + * Technically scrubbing is the same as wear-leveling, so it is done + * by the WL worker. + */ + return ensure_wear_leveling(ubi); +} + +/** + * ubi_wl_flush - flush all pending works. + * @ubi: UBI device description object + * + * This function returns zero in case of success and a negative error code in + * case of failure. + */ +int ubi_wl_flush(struct ubi_device *ubi) +{ + int err; + + /* + * Erase while the pending works queue is not empty, but not more then + * the number of currently pending works. + */ + dbg_wl("flush (%d pending works)", ubi->works_count); + while (ubi->works_count) { + err = do_work(ubi); + if (err) + return err; + } + + /* + * Make sure all the works which have been done in parallel are + * finished. + */ + down_write(&ubi->work_sem); + up_write(&ubi->work_sem); + + /* + * And in case last was the WL worker and it cancelled the LEB + * movement, flush again. + */ + while (ubi->works_count) { + dbg_wl("flush more (%d pending works)", ubi->works_count); + err = do_work(ubi); + if (err) + return err; + } + + return 0; +} + +/** + * tree_destroy - destroy an RB-tree. + * @root: the root of the tree to destroy + */ +static void tree_destroy(struct rb_root *root) +{ + struct rb_node *rb; + struct ubi_wl_entry *e; + + rb = root->rb_node; + while (rb) { + if (rb->rb_left) + rb = rb->rb_left; + else if (rb->rb_right) + rb = rb->rb_right; + else { + e = rb_entry(rb, struct ubi_wl_entry, rb); + + rb = rb_parent(rb); + if (rb) { + if (rb->rb_left == &e->rb) + rb->rb_left = NULL; + else + rb->rb_right = NULL; + } + + kmem_cache_free(ubi_wl_entry_slab, e); + } + } +} + +/** + * ubi_thread - UBI background thread. + * @u: the UBI device description object pointer + */ +int ubi_thread(void *u) +{ + int failures = 0; + struct ubi_device *ubi = u; + + ubi_msg("background thread \"%s\" started, PID %d", + ubi->bgt_name, task_pid_nr(current)); + + set_freezable(); + for (;;) { + int err; + + if (kthread_should_stop()) + break; + + if (try_to_freeze()) + continue; + + spin_lock(&ubi->wl_lock); + if (list_empty(&ubi->works) || ubi->ro_mode || + !ubi->thread_enabled) { + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock(&ubi->wl_lock); + schedule(); + continue; + } + spin_unlock(&ubi->wl_lock); + + err = do_work(ubi); + if (err) { + ubi_err("%s: work failed with error code %d", + ubi->bgt_name, err); + if (failures++ > WL_MAX_FAILURES) { + /* + * Too many failures, disable the thread and + * switch to read-only mode. + */ + ubi_msg("%s: %d consecutive failures", + ubi->bgt_name, WL_MAX_FAILURES); + ubi_ro_mode(ubi); + break; + } + } else + failures = 0; + + cond_resched(); + } + + dbg_wl("background thread \"%s\" is killed", ubi->bgt_name); + return 0; +} + +/** + * cancel_pending - cancel all pending works. + * @ubi: UBI device description object + */ +static void cancel_pending(struct ubi_device *ubi) +{ + while (!list_empty(&ubi->works)) { + struct ubi_work *wrk; + + wrk = list_entry(ubi->works.next, struct ubi_work, list); + list_del(&wrk->list); + wrk->func(ubi, wrk, 1); + ubi->works_count -= 1; + ubi_assert(ubi->works_count >= 0); + } +} + +/** + * ubi_wl_init_scan - initialize the wear-leveling unit using scanning + * information. + * @ubi: UBI device description object + * @si: scanning information + * + * This function returns zero in case of success, and a negative error code in + * case of failure. + */ +int ubi_wl_init_scan(struct ubi_device *ubi, struct ubi_scan_info *si) +{ + int err; + struct rb_node *rb1, *rb2; + struct ubi_scan_volume *sv; + struct ubi_scan_leb *seb, *tmp; + struct ubi_wl_entry *e; + + + ubi->used = ubi->free = ubi->scrub = RB_ROOT; + ubi->prot.pnum = ubi->prot.aec = RB_ROOT; + spin_lock_init(&ubi->wl_lock); + mutex_init(&ubi->move_mutex); + init_rwsem(&ubi->work_sem); + ubi->max_ec = si->max_ec; + INIT_LIST_HEAD(&ubi->works); + + sprintf(ubi->bgt_name, UBI_BGT_NAME_PATTERN, ubi->ubi_num); + + err = -ENOMEM; + ubi->lookuptbl = kzalloc(ubi->peb_count * sizeof(void *), GFP_KERNEL); + if (!ubi->lookuptbl) + return err; + + list_for_each_entry_safe(seb, tmp, &si->erase, u.list) { + cond_resched(); + + e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); + if (!e) + goto out_free; + + e->pnum = seb->pnum; + e->ec = seb->ec; + ubi->lookuptbl[e->pnum] = e; + if (schedule_erase(ubi, e, 0)) { + kmem_cache_free(ubi_wl_entry_slab, e); + goto out_free; + } + } + + list_for_each_entry(seb, &si->free, u.list) { + cond_resched(); + + e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); + if (!e) + goto out_free; + + e->pnum = seb->pnum; + e->ec = seb->ec; + ubi_assert(e->ec >= 0); + wl_tree_add(e, &ubi->free); + ubi->lookuptbl[e->pnum] = e; + } + + list_for_each_entry(seb, &si->corr, u.list) { + cond_resched(); + + e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); + if (!e) + goto out_free; + + e->pnum = seb->pnum; + e->ec = seb->ec; + ubi->lookuptbl[e->pnum] = e; + if (schedule_erase(ubi, e, 0)) { + kmem_cache_free(ubi_wl_entry_slab, e); + goto out_free; + } + } + + ubi_rb_for_each_entry(rb1, sv, &si->volumes, rb) { + ubi_rb_for_each_entry(rb2, seb, &sv->root, u.rb) { + cond_resched(); + + e = kmem_cache_alloc(ubi_wl_entry_slab, GFP_KERNEL); + if (!e) + goto out_free; + + e->pnum = seb->pnum; + e->ec = seb->ec; + ubi->lookuptbl[e->pnum] = e; + if (!seb->scrub) { + dbg_wl("add PEB %d EC %d to the used tree", + e->pnum, e->ec); + wl_tree_add(e, &ubi->used); + } else { + dbg_wl("add PEB %d EC %d to the scrub tree", + e->pnum, e->ec); + wl_tree_add(e, &ubi->scrub); + } + } + } + + if (ubi->avail_pebs < WL_RESERVED_PEBS) { + ubi_err("no enough physical eraseblocks (%d, need %d)", + ubi->avail_pebs, WL_RESERVED_PEBS); + goto out_free; + } + ubi->avail_pebs -= WL_RESERVED_PEBS; + ubi->rsvd_pebs += WL_RESERVED_PEBS; + + /* Schedule wear-leveling if needed */ + err = ensure_wear_leveling(ubi); + if (err) + goto out_free; + + return 0; + +out_free: + cancel_pending(ubi); + tree_destroy(&ubi->used); + tree_destroy(&ubi->free); + tree_destroy(&ubi->scrub); + kfree(ubi->lookuptbl); + return err; +} + +/** + * protection_trees_destroy - destroy the protection RB-trees. + * @ubi: UBI device description object + */ +static void protection_trees_destroy(struct ubi_device *ubi) +{ + struct rb_node *rb; + struct ubi_wl_prot_entry *pe; + + rb = ubi->prot.aec.rb_node; + while (rb) { + if (rb->rb_left) + rb = rb->rb_left; + else if (rb->rb_right) + rb = rb->rb_right; + else { + pe = rb_entry(rb, struct ubi_wl_prot_entry, rb_aec); + + rb = rb_parent(rb); + if (rb) { + if (rb->rb_left == &pe->rb_aec) + rb->rb_left = NULL; + else + rb->rb_right = NULL; + } + + kmem_cache_free(ubi_wl_entry_slab, pe->e); + kfree(pe); + } + } +} + +/** + * ubi_wl_close - close the wear-leveling unit. + * @ubi: UBI device description object + */ +void ubi_wl_close(struct ubi_device *ubi) +{ + dbg_wl("close the UBI wear-leveling unit"); + + cancel_pending(ubi); + protection_trees_destroy(ubi); + tree_destroy(&ubi->used); + tree_destroy(&ubi->free); + tree_destroy(&ubi->scrub); + kfree(ubi->lookuptbl); +} + +#ifdef CONFIG_MTD_UBI_DEBUG_PARANOID + +/** + * paranoid_check_ec - make sure that the erase counter of a physical eraseblock + * is correct. + * @ubi: UBI device description object + * @pnum: the physical eraseblock number to check + * @ec: the erase counter to check + * + * This function returns zero if the erase counter of physical eraseblock @pnum + * is equivalent to @ec, %1 if not, and a negative error code if an error + * occurred. + */ +static int paranoid_check_ec(struct ubi_device *ubi, int pnum, int ec) +{ + int err; + long long read_ec; + struct ubi_ec_hdr *ec_hdr; + + ec_hdr = kzalloc(ubi->ec_hdr_alsize, GFP_NOFS); + if (!ec_hdr) + return -ENOMEM; + + err = ubi_io_read_ec_hdr(ubi, pnum, ec_hdr, 0); + if (err && err != UBI_IO_BITFLIPS) { + /* The header does not have to exist */ + err = 0; + goto out_free; + } + + read_ec = be64_to_cpu(ec_hdr->ec); + if (ec != read_ec) { + ubi_err("paranoid check failed for PEB %d", pnum); + ubi_err("read EC is %lld, should be %d", read_ec, ec); + ubi_dbg_dump_stack(); + err = 1; + } else + err = 0; + +out_free: + kfree(ec_hdr); + return err; +} + +/** + * paranoid_check_in_wl_tree - make sure that a wear-leveling entry is present + * in a WL RB-tree. + * @e: the wear-leveling entry to check + * @root: the root of the tree + * + * This function returns zero if @e is in the @root RB-tree and %1 if it + * is not. + */ +static int paranoid_check_in_wl_tree(struct ubi_wl_entry *e, + struct rb_root *root) +{ + if (in_wl_tree(e, root)) + return 0; + + ubi_err("paranoid check failed for PEB %d, EC %d, RB-tree %p ", + e->pnum, e->ec, root); + ubi_dbg_dump_stack(); + return 1; +} + +#endif /* CONFIG_MTD_UBI_DEBUG_PARANOID */ diff --git a/drivers/nand/Kconfig b/drivers/nand/Kconfig deleted file mode 100644 index 031b94d..0000000 --- a/drivers/nand/Kconfig +++ /dev/null @@ -1,109 +0,0 @@ -menuconfig NAND - bool "NAND support " - select MTD_NAND_IDS - help - This enables support for accessing all type of NAND flash - devices. For further information see - . - -if NAND - -config NAND_IMX - bool - prompt "i.MX NAND driver" - depends on ARCH_IMX21 || ARCH_IMX27 || ARCH_IMX31 || ARCH_IMX35 || ARCH_IMX25 - -config NAND_IMX_BOOT - bool - prompt "Support Starting barebox from NAND" - depends on NAND_IMX || NAND_IMX_V2 - -config NAND_OMAP_GPMC - tristate "NAND Flash Support for GPMC based OMAP platforms" - depends on ((ARCH_OMAP2 || ARCH_OMAP3) && GPMC) - help - Support for NAND flash using GPMC. GPMC is a common memory - interface found on Texas Instrument's OMAP platforms - -config NAND_OMAP_GPMC_HWECC - bool "The Hardware ECC support" - depends on NAND && NAND_OMAP_GPMC - default n - help - The ECC compuatation for the data to be written/read can be either by - software or omap has Hw ecc engine which calculates it. - -config NAND_ATMEL - bool - prompt "Atmel (AT91SAM9xxx) NAND driver" - depends on ARCH_AT91 - -config NAND_S3C24X0 - bool - prompt "Samsung S3C24X0 NAND driver" - depends on ARCH_S3C24xx - help - Add support for processor's NAND device controller. - -config MTD_NAND_VERIFY_WRITE - bool "Verify NAND page writes" - help - This adds an extra check when data is written to the flash. The - NAND flash device internally checks only bits transitioning - from 1 to 0. There is a rare possibility that even though the - device thinks the write was successful, a bit could have been - flipped accidentally due to device wear or something else. - -config MTD_NAND_ECC_SMC - bool "NAND ECC Smart Media byte order" - default n - help - Software ECC according to the Smart Media Specification. - The original Linux implementation had byte 0 and 1 swapped. - -config MTD_NAND_MUSEUM_IDS - bool "Enable chip ids for obsolete ancient NAND devices" - depends on MTD_NAND - default n - help - Enable this option only when your board has first generation - NAND chips (page size 256 byte, erase size 4-8KiB). The IDs - of these chips were reused by later, larger chips. - -config MTD_NAND_IDS - tristate - -config MTD_NAND_DISKONCHIP - tristate "DiskOnChip 2000, Millennium and Millennium Plus" - depends on EXPERIMENTAL && BROKEN - help - This is a reimplementation of M-Systems DiskOnChip 2000, - Millennium and Millennium Plus as a standard NAND device driver, - as opposed to the earlier self-contained MTD device drivers. - This should enable, among other things, proper JFFS2 operation on - these devices. - -config MTD_NAND_DISKONCHIP_BBTWRITE - bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP" - depends on MTD_NAND_DISKONCHIP - help - On DiskOnChip devices shipped with the INFTL filesystem (Millennium - and 2000 TSOP/Alon), Linux reserves some space at the end of the - device for the Bad Block Table (BBT). If you have existing INFTL - data on your device (created by non-Linux tools such as M-Systems' - DOS drivers), your data might overlap the area Linux wants to use for - the BBT. If this is a concern for you, leave this option disabled and - Linux will not write BBT data into this area. - The downside of leaving this option disabled is that if bad blocks - are detected by Linux, they will not be recorded in the BBT, which - could cause future problems. - Once you enable this option, new filesystems (INFTL or others, created - in Linux or other operating systems) will not use the reserved area. - The only reason not to enable this option is to prevent damage to - preexisting filesystems. - Even if you leave this disabled, you can enable BBT writes at module - load time (assuming you build diskonchip as a module) with the module - parameter "inftl_bbt_write=1". - - -endif diff --git a/drivers/nand/Makefile b/drivers/nand/Makefile deleted file mode 100644 index 73f7346..0000000 --- a/drivers/nand/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -# Generic NAND options -obj-$(CONFIG_NAND) += nand.o nand_ecc.o -obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o -obj-$(CONFIG_NAND) += nand_base.o nand_bbt.o - -obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o -obj-$(CONFIG_NAND_IMX) += nand_imx.o -obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.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/nand/atmel_nand.c b/drivers/nand/atmel_nand.c deleted file mode 100644 index c3669e5..0000000 --- a/drivers/nand/atmel_nand.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright (C) 2003 Rick Bronson - * - * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * - * Derived from drivers/mtd/spia.c - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) - * - * - * Add Hardware ECC support for AT91SAM9260 / AT91SAM9263 - * Richard Genoud (richard.genoud@gmail.com), Adeneo Copyright (C) 2007 - * - * Derived from Das barebox source code - * (barebox-1.1.5/board/atmel/at91sam9263ek/nand.c) - * (C) Copyright 2006 ATMEL Rousset, Lacressonniere Nicolas - * - * - * 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 -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include - -#ifdef CONFIG_MTD_NAND_ATMEL_ECC_HW -#define hard_ecc 1 -#else -#define hard_ecc 0 -#endif - -#ifdef CONFIG_MTD_NAND_ATMEL_ECC_NONE -#define no_ecc 1 -#else -#define no_ecc 0 -#endif - -/* Register access macros */ -#define ecc_readl(add, reg) \ - readl(add + ATMEL_ECC_##reg) -#define ecc_writel(add, reg, value) \ - writel((value), add + ATMEL_ECC_##reg) - -#include "atmel_nand_ecc.h" /* Hardware ECC registers */ - -/* oob layout for large page size - * bad block info is on bytes 0 and 1 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout atmel_oobinfo_large = { - .eccbytes = 4, - .eccpos = {60, 61, 62, 63}, - .oobfree = { - {2, 58} - }, -}; - -/* oob layout for small page size - * bad block info is on bytes 4 and 5 - * the bytes have to be consecutives to avoid - * several NAND_CMD_RNDOUT during read - */ -static struct nand_ecclayout atmel_oobinfo_small = { - .eccbytes = 4, - .eccpos = {0, 1, 2, 3}, - .oobfree = { - {6, 10} - }, -}; - -struct atmel_nand_host { - struct nand_chip nand_chip; - struct mtd_info mtd; - void __iomem *io_base; - struct atmel_nand_data *board; - struct device_d *dev; - void __iomem *ecc; -}; - -/* - * Enable NAND. - */ -static void atmel_nand_enable(struct atmel_nand_host *host) -{ - if (host->board->enable_pin) - gpio_set_value(host->board->enable_pin, 0); -} - -/* - * Disable NAND. - */ -static void atmel_nand_disable(struct atmel_nand_host *host) -{ - if (host->board->enable_pin) - gpio_set_value(host->board->enable_pin, 1); -} - -/* - * Hardware specific access to control-lines - */ -static void atmel_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - - if (ctrl & NAND_CTRL_CHANGE) { - if (ctrl & NAND_NCE) - atmel_nand_enable(host); - else - atmel_nand_disable(host); - } - if (cmd == NAND_CMD_NONE) - return; - - if (ctrl & NAND_CLE) - writeb(cmd, host->io_base + (1 << host->board->cle)); - else - writeb(cmd, host->io_base + (1 << host->board->ale)); -} - -/* - * Read the Device Ready pin. - */ -static int atmel_nand_device_ready(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - - return gpio_get_value(host->board->rdy_pin); -} - -/* - * Minimal-overhead PIO for data access. - */ -static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - readsb(nand_chip->IO_ADDR_R, buf, len); -} - -static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - readsw(nand_chip->IO_ADDR_R, buf, len / 2); -} - -static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - writesb(nand_chip->IO_ADDR_W, buf, len); -} - -static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - - writesw(nand_chip->IO_ADDR_W, buf, len / 2); -} - -/* - * Calculate HW ECC - * - * function called after a write - * - * mtd: MTD block structure - * dat: raw data (unused) - * ecc_code: buffer for ECC - */ -static int atmel_nand_calculate(struct mtd_info *mtd, - const u_char *dat, unsigned char *ecc_code) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; -/* uint32_t *eccpos = nand_chip->ecc.layout->eccpos; */ - unsigned int ecc_value; - - /* get the first 2 ECC bytes */ - ecc_value = ecc_readl(host->ecc, PR); - - ecc_code[0] = ecc_value & 0xFF; - ecc_code[1] = (ecc_value >> 8) & 0xFF; - - /* get the last 2 ECC bytes */ - ecc_value = ecc_readl(host->ecc, NPR) & ATMEL_ECC_NPARITY; - - ecc_code[2] = ecc_value & 0xFF; - ecc_code[3] = (ecc_value >> 8) & 0xFF; - - return 0; -} - -/* - * HW ECC read page function - * - * mtd: mtd info structure - * chip: nand chip info structure - * buf: buffer to store read data - */ -static int atmel_nand_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf) -{ - int eccsize = chip->ecc.size; - int eccbytes = chip->ecc.bytes; - uint32_t *eccpos = chip->ecc.layout->eccpos; - uint8_t *p = buf; - uint8_t *oob = chip->oob_poi; - uint8_t *ecc_pos; - int stat; - - /* - * Errata: ALE is incorrectly wired up to the ECC controller - * on the AP7000, so it will include the address cycles in the - * ECC calculation. - * - * Workaround: Reset the parity registers before reading the - * actual data. - */ -#if 0 - if (cpu_is_at32ap7000()) { - struct atmel_nand_host *host = chip->priv; - ecc_writel(host->ecc, CR, ATMEL_ECC_RST); - } -#endif - - /* read the page */ - chip->read_buf(mtd, p, eccsize); - - /* move to ECC position if needed */ - if (eccpos[0] != 0) { - /* This only works on large pages - * because the ECC controller waits for - * NAND_CMD_RNDOUTSTART after the - * NAND_CMD_RNDOUT. - * anyway, for small pages, the eccpos[0] == 0 - */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, - mtd->writesize + eccpos[0], -1); - } - - /* the ECC controller needs to read the ECC just after the data */ - ecc_pos = oob + eccpos[0]; - chip->read_buf(mtd, ecc_pos, eccbytes); - - /* check if there's an error */ - stat = chip->ecc.correct(mtd, p, oob, NULL); - - if (stat < 0) - mtd->ecc_stats.failed++; - else - mtd->ecc_stats.corrected += stat; - - /* get back to oob start (end of page) */ - chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); - - /* read the oob */ - chip->read_buf(mtd, oob, mtd->oobsize); - - return 0; -} - -/* - * HW ECC Correction - * - * function called after a read - * - * mtd: MTD block structure - * dat: raw data read from the chip - * read_ecc: ECC from the chip (unused) - * isnull: unused - * - * Detect and correct a 1 bit error for a page - */ -static int atmel_nand_correct(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *isnull) -{ - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - unsigned int ecc_status; - unsigned int ecc_word, ecc_bit; - - /* get the status from the Status Register */ - ecc_status = ecc_readl(host->ecc, SR); - - /* if there's no error */ - if (likely(!(ecc_status & ATMEL_ECC_RECERR))) - return 0; - - /* get error bit offset (4 bits) */ - ecc_bit = ecc_readl(host->ecc, PR) & ATMEL_ECC_BITADDR; - /* get word address (12 bits) */ - ecc_word = ecc_readl(host->ecc, PR) & ATMEL_ECC_WORDADDR; - ecc_word >>= 4; - - /* if there are multiple errors */ - if (ecc_status & ATMEL_ECC_MULERR) { - /* check if it is a freshly erased block - * (filled with 0xff) */ - if ((ecc_bit == ATMEL_ECC_BITADDR) - && (ecc_word == (ATMEL_ECC_WORDADDR >> 4))) { - /* the block has just been erased, return OK */ - return 0; - } - /* it doesn't seems to be a freshly - * erased block. - * We can't correct so many errors */ - dev_dbg(host->dev, "atmel_nand : multiple errors detected." - " Unable to correct.\n"); - return -EIO; - } - - /* if there's a single bit error : we can correct it */ - if (ecc_status & ATMEL_ECC_ECCERR) { - /* there's nothing much to do here. - * the bit error is on the ECC itself. - */ - dev_dbg(host->dev, "atmel_nand : one bit error on ECC code." - " Nothing to correct\n"); - return 0; - } - - dev_dbg(host->dev, "atmel_nand : one bit error on data." - " (word offset in the page :" - " 0x%x bit offset : 0x%x)\n", - ecc_word, ecc_bit); - /* correct the error */ - if (nand_chip->options & NAND_BUSWIDTH_16) { - /* 16 bits words */ - ((unsigned short *) dat)[ecc_word] ^= (1 << ecc_bit); - } else { - /* 8 bits words */ - dat[ecc_word] ^= (1 << ecc_bit); - } - dev_dbg(host->dev, "atmel_nand : error corrected\n"); - return 1; -} - -/* - * Enable HW ECC : unused on most chips - */ -static void atmel_nand_hwctl(struct mtd_info *mtd, int mode) -{ -#if 0 - if (cpu_is_at32ap7000()) { - struct nand_chip *nand_chip = mtd->priv; - struct atmel_nand_host *host = nand_chip->priv; - ecc_writel(host->ecc, CR, ATMEL_ECC_RST); - } -#endif -} - -/* - * Probe for the NAND device. - */ -static int __init atmel_nand_probe(struct device_d *dev) -{ - struct atmel_nand_data *pdata = dev->platform_data; - struct atmel_nand_host *host; - struct mtd_info *mtd; - struct nand_chip *nand_chip; - int res = 0; - - /* Allocate memory for the device structure (and zero it) */ - host = kzalloc(sizeof(struct atmel_nand_host), GFP_KERNEL); - if (!host) - return -ENOMEM; - - host->io_base = (void __iomem *)dev->map_base; - - mtd = &host->mtd; - nand_chip = &host->nand_chip; - host->board = pdata; - host->dev = dev; - - nand_chip->priv = host; /* link the private data structures */ - mtd->priv = nand_chip; - - /* Set address of NAND IO lines */ - nand_chip->IO_ADDR_R = host->io_base; - nand_chip->IO_ADDR_W = host->io_base; - nand_chip->cmd_ctrl = atmel_nand_cmd_ctrl; - - if (host->board->rdy_pin) - nand_chip->dev_ready = atmel_nand_device_ready; - - nand_chip->ecc.mode = pdata->ecc_mode; - - if (pdata->ecc_mode == NAND_ECC_HW) { - if (!pdata->ecc_base) - return -ENODEV; - - host->ecc = pdata->ecc_base; - - nand_chip->ecc.mode = NAND_ECC_HW; - nand_chip->ecc.calculate = atmel_nand_calculate; - nand_chip->ecc.correct = atmel_nand_correct; - nand_chip->ecc.hwctl = atmel_nand_hwctl; - nand_chip->ecc.read_page = atmel_nand_read_page; - nand_chip->ecc.bytes = 4; - } - - nand_chip->chip_delay = 20; /* 20us command delay time */ - - if (host->board->bus_width_16) { /* 16-bit bus width */ - nand_chip->options |= NAND_BUSWIDTH_16; - nand_chip->read_buf = atmel_read_buf16; - nand_chip->write_buf = atmel_write_buf16; - } else { - nand_chip->read_buf = atmel_read_buf; - nand_chip->write_buf = atmel_write_buf; - } - - atmel_nand_enable(host); - - if (host->board->det_pin) { - if (gpio_get_value(host->board->det_pin)) { - printk("No SmartMedia card inserted.\n"); - res = ENXIO; - goto err_no_card; - } - } - - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1)) { - res = -ENXIO; - goto err_scan_ident; - } - - if (nand_chip->ecc.mode == NAND_ECC_HW) { - /* ECC is calculated for the whole page (1 step) */ - nand_chip->ecc.size = mtd->writesize; - - /* set ECC page size and oob layout */ - switch (mtd->writesize) { - case 512: - nand_chip->ecc.layout = &atmel_oobinfo_small; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_528); - break; - case 1024: - nand_chip->ecc.layout = &atmel_oobinfo_large; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_1056); - break; - case 2048: - nand_chip->ecc.layout = &atmel_oobinfo_large; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_2112); - break; - case 4096: - nand_chip->ecc.layout = &atmel_oobinfo_large; - ecc_writel(host->ecc, MR, ATMEL_ECC_PAGESIZE_4224); - break; - default: - /* page size not handled by HW ECC */ - /* switching back to soft ECC */ - nand_chip->ecc.mode = NAND_ECC_SOFT; - nand_chip->ecc.calculate = NULL; - nand_chip->ecc.correct = NULL; - nand_chip->ecc.hwctl = NULL; - nand_chip->ecc.read_page = NULL; - nand_chip->ecc.postpad = 0; - nand_chip->ecc.prepad = 0; - nand_chip->ecc.bytes = 0; - break; - } - } - - /* second phase scan */ - if (nand_scan_tail(mtd)) { - res = -ENXIO; - goto err_scan_tail; - } - - add_mtd_device(mtd); - - if (!res) - return res; - - nand_release(mtd); -err_scan_tail: -err_scan_ident: -err_no_card: - atmel_nand_disable(host); - kfree(host); - return res; -} - -static struct driver_d atmel_nand_driver = { - .name = "atmel_nand", - .probe = atmel_nand_probe, -}; - -static int __init atmel_nand_init(void) -{ - return register_driver(&atmel_nand_driver); -} - -device_initcall(atmel_nand_init); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Rick Bronson"); -MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91 / AVR32"); diff --git a/drivers/nand/atmel_nand_ecc.h b/drivers/nand/atmel_nand_ecc.h deleted file mode 100644 index 578c776..0000000 --- a/drivers/nand/atmel_nand_ecc.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Error Corrected Code Controller (ECC) - System peripherals regsters. - * Based on AT91SAM9260 datasheet revision B. - * - * Copyright (C) 2007 Andrew Victor - * Copyright (C) 2007 Atmel Corporation. - * - * 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. - */ - -#ifndef ATMEL_NAND_ECC_H -#define ATMEL_NAND_ECC_H - -#define ATMEL_ECC_CR 0x00 /* Control register */ -#define ATMEL_ECC_RST (1 << 0) /* Reset parity */ - -#define ATMEL_ECC_MR 0x04 /* Mode register */ -#define ATMEL_ECC_PAGESIZE (3 << 0) /* Page Size */ -#define ATMEL_ECC_PAGESIZE_528 (0) -#define ATMEL_ECC_PAGESIZE_1056 (1) -#define ATMEL_ECC_PAGESIZE_2112 (2) -#define ATMEL_ECC_PAGESIZE_4224 (3) - -#define ATMEL_ECC_SR 0x08 /* Status register */ -#define ATMEL_ECC_RECERR (1 << 0) /* Recoverable Error */ -#define ATMEL_ECC_ECCERR (1 << 1) /* ECC Single Bit Error */ -#define ATMEL_ECC_MULERR (1 << 2) /* Multiple Errors */ - -#define ATMEL_ECC_PR 0x0c /* Parity register */ -#define ATMEL_ECC_BITADDR (0xf << 0) /* Bit Error Address */ -#define ATMEL_ECC_WORDADDR (0xfff << 4) /* Word Error Address */ - -#define ATMEL_ECC_NPR 0x10 /* NParity register */ -#define ATMEL_ECC_NPARITY (0xffff << 0) /* NParity */ - -#endif diff --git a/drivers/nand/diskonchip.c b/drivers/nand/diskonchip.c deleted file mode 100644 index e762524..0000000 --- a/drivers/nand/diskonchip.c +++ /dev/null @@ -1,1787 +0,0 @@ -/* - * drivers/mtd/nand/diskonchip.c - * - * (C) 2003 Red Hat, Inc. - * (C) 2004 Dan Brown - * (C) 2004 Kalev Lember - * - * Author: David Woodhouse - * Additional Diskonchip 2000 and Millennium support by Dan Brown - * Diskonchip Millennium Plus support by Kalev Lember - * - * Error correction code lifted from the old docecc code - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) - * Copyright (C) 2000 Netgem S.A. - * converted to the generic Reed-Solomon library by Thomas Gleixner - * - * Interface to generic NAND code for M-Systems DiskOnChip devices - * - * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $ - */ - -#include - -#if !defined(CFG_NAND_LEGACY) - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* Where to look for the devices? */ -#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS -#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0 -#endif - -static unsigned long __initdata doc_locations[] = { -#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) -#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH - 0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000, - 0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000, - 0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000, - 0xfffe0000, 0xfffe2000, 0xfffe4000, 0xfffe6000, - 0xfffe8000, 0xfffea000, 0xfffec000, 0xfffee000, -#else /* CONFIG_MTD_DOCPROBE_HIGH */ - 0xc8000, 0xca000, 0xcc000, 0xce000, - 0xd0000, 0xd2000, 0xd4000, 0xd6000, - 0xd8000, 0xda000, 0xdc000, 0xde000, - 0xe0000, 0xe2000, 0xe4000, 0xe6000, - 0xe8000, 0xea000, 0xec000, 0xee000, -#endif /* CONFIG_MTD_DOCPROBE_HIGH */ -#elif defined(__PPC__) - 0xe4000000, -#elif defined(CONFIG_MOMENCO_OCELOT) - 0x2f000000, - 0xff000000, -#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) - 0xff000000, -##else -#warning Unknown architecture for DiskOnChip. No default probe locations defined -#endif - 0xffffffff }; - -static struct mtd_info *doclist = NULL; - -struct doc_priv { - void __iomem *virtadr; - unsigned long physadr; - u_char ChipID; - u_char CDSNControl; - int chips_per_floor; /* The number of chips detected on each floor */ - int curfloor; - int curchip; - int mh0_page; - int mh1_page; - struct mtd_info *nextdoc; -}; - -/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL - MediaHeader. The spec says to just keep going, I think, but that's just - silly. */ -#define MAX_MEDIAHEADER_SCAN 8 - -/* This is the syndrome computed by the HW ecc generator upon reading an empty - page, one with all 0xff for data and stored ecc code. */ -static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a }; -/* This is the ecc value computed by the HW ecc generator upon writing an empty - page, one with all 0xff for data. */ -static u_char empty_write_ecc[6] = { 0x4b, 0x00, 0xe2, 0x0e, 0x93, 0xf7 }; - -#define INFTL_BBT_RESERVED_BLOCKS 4 - -#define DoC_is_MillenniumPlus(doc) ((doc)->ChipID == DOC_ChipID_DocMilPlus16 || (doc)->ChipID == DOC_ChipID_DocMilPlus32) -#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) -#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) - -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); -static void doc200x_select_chip(struct mtd_info *mtd, int chip); - -static int debug=0; -module_param(debug, int, 0); - -static int try_dword=1; -module_param(try_dword, int, 0); - -static int no_ecc_failures=0; -module_param(no_ecc_failures, int, 0); - -#ifdef CONFIG_MTD_PARTITIONS -static int no_autopart=0; -module_param(no_autopart, int, 0); -#endif - -#ifdef CONFIG_MTD_NAND_DISKONCHIP_BBTWRITE -static int inftl_bbt_write=1; -#else -static int inftl_bbt_write=0; -#endif -module_param(inftl_bbt_write, int, 0); - -static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS; -module_param(doc_config_location, ulong, 0); -MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); - - -/* Sector size for HW ECC */ -#define SECTOR_SIZE 512 -/* The sector bytes are packed into NB_DATA 10 bit words */ -#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10) -/* Number of roots */ -#define NROOTS 4 -/* First consective root */ -#define FCR 510 -/* Number of symbols */ -#define NN 1023 - -/* the Reed Solomon control structure */ -static struct rs_control *rs_decoder; - -/* - * The HW decoder in the DoC ASIC's provides us a error syndrome, - * which we must convert to a standard syndrom usable by the generic - * Reed-Solomon library code. - * - * Fabrice Bellard figured this out in the old docecc code. I added - * some comments, improved a minor bit and converted it to make use - * of the generic Reed-Solomon libary. tglx - */ -static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc) -{ - int i, j, nerr, errpos[8]; - uint8_t parity; - uint16_t ds[4], s[5], tmp, errval[8], syn[4]; - - /* Convert the ecc bytes into words */ - ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8); - ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6); - ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4); - ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2); - parity = ecc[1]; - - /* Initialize the syndrom buffer */ - for (i = 0; i < NROOTS; i++) - s[i] = ds[0]; - /* - * Evaluate - * s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0] - * where x = alpha^(FCR + i) - */ - for(j = 1; j < NROOTS; j++) { - if(ds[j] == 0) - continue; - tmp = rs->index_of[ds[j]]; - for(i = 0; i < NROOTS; i++) - s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)]; - } - - /* Calc s[i] = s[i] / alpha^(v + i) */ - for (i = 0; i < NROOTS; i++) { - if (syn[i]) - syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i)); - } - /* Call the decoder library */ - nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval); - - /* Incorrectable errors ? */ - if (nerr < 0) - return nerr; - - /* - * Correct the errors. The bitpositions are a bit of magic, - * but they are given by the design of the de/encoder circuit - * in the DoC ASIC's. - */ - for(i = 0;i < nerr; i++) { - int index, bitpos, pos = 1015 - errpos[i]; - uint8_t val; - if (pos >= NB_DATA && pos < 1019) - continue; - if (pos < NB_DATA) { - /* extract bit position (MSB first) */ - pos = 10 * (NB_DATA - 1 - pos) - 6; - /* now correct the following 10 bits. At most two bytes - can be modified since pos is even */ - index = (pos >> 3) ^ 1; - bitpos = pos & 7; - if ((index >= 0 && index < SECTOR_SIZE) || - index == (SECTOR_SIZE + 1)) { - val = (uint8_t) (errval[i] >> (2 + bitpos)); - parity ^= val; - if (index < SECTOR_SIZE) - data[index] ^= val; - } - index = ((pos >> 3) + 1) ^ 1; - bitpos = (bitpos + 10) & 7; - if (bitpos == 0) - bitpos = 8; - if ((index >= 0 && index < SECTOR_SIZE) || - index == (SECTOR_SIZE + 1)) { - val = (uint8_t)(errval[i] << (8 - bitpos)); - parity ^= val; - if (index < SECTOR_SIZE) - data[index] ^= val; - } - } - } - /* If the parity is wrong, no rescue possible */ - return parity ? -1 : nerr; -} - -static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) -{ - volatile char dummy; - int i; - - for (i = 0; i < cycles; i++) { - if (DoC_is_Millennium(doc)) - dummy = ReadDOC(doc->virtadr, NOP); - else if (DoC_is_MillenniumPlus(doc)) - dummy = ReadDOC(doc->virtadr, Mplus_NOP); - else - dummy = ReadDOC(doc->virtadr, DOCStatus); - } - -} - -#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) - -/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ -static int _DoC_WaitReady(struct doc_priv *doc) -{ - void __iomem *docptr = doc->virtadr; - unsigned long timeo = jiffies + (HZ * 10); - - if(debug) printk("_DoC_WaitReady...\n"); - /* Out-of-line routine to wait for chip response */ - if (DoC_is_MillenniumPlus(doc)) { - while ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { - if (time_after(jiffies, timeo)) { - printk("_DoC_WaitReady timed out.\n"); - return -EIO; - } - udelay(1); - cond_resched(); - } - } else { - while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { - if (time_after(jiffies, timeo)) { - printk("_DoC_WaitReady timed out.\n"); - return -EIO; - } - udelay(1); - cond_resched(); - } - } - - return 0; -} - -static inline int DoC_WaitReady(struct doc_priv *doc) -{ - void __iomem *docptr = doc->virtadr; - int ret = 0; - - if (DoC_is_MillenniumPlus(doc)) { - DoC_Delay(doc, 4); - - if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) - /* Call the out-of-line routine to wait */ - ret = _DoC_WaitReady(doc); - } else { - DoC_Delay(doc, 4); - - if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) - /* Call the out-of-line routine to wait */ - ret = _DoC_WaitReady(doc); - DoC_Delay(doc, 2); - } - - if(debug) printk("DoC_WaitReady OK\n"); - return ret; -} - -static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - if(debug)printk("write_byte %02x\n", datum); - WriteDOC(datum, docptr, CDSNSlowIO); - WriteDOC(datum, docptr, 2k_CDSN_IO); -} - -static u_char doc2000_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - u_char ret; - - ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(doc, 2); - ret = ReadDOC(docptr, 2k_CDSN_IO); - if (debug) printk("read_byte returns %02x\n", ret); - return ret; -} - -static void doc2000_writebuf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - if (debug)printk("writebuf of %d bytes: ", len); - for (i=0; i < len; i++) { - WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i); - if (debug && i < 16) - printk("%02x ", buf[i]); - } - if (debug) printk("\n"); -} - -static void doc2000_readbuf(struct mtd_info *mtd, - u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - if (debug)printk("readbuf of %d bytes: ", len); - - for (i=0; i < len; i++) { - buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i); - } -} - -static void doc2000_readbuf_dword(struct mtd_info *mtd, - u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - if (debug) printk("readbuf_dword of %d bytes: ", len); - - if (unlikely((((unsigned long)buf)|len) & 3)) { - for (i=0; i < len; i++) { - *(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i); - } - } else { - for (i=0; i < len; i+=4) { - *(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i); - } - } -} - -static int doc2000_verifybuf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - for (i=0; i < len; i++) - if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO)) - return -EFAULT; - return 0; -} - -static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - uint16_t ret; - - doc200x_select_chip(mtd, nr); - doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); - this->write_byte(mtd, NAND_CMD_READID); - doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); - doc200x_hwcontrol(mtd, NAND_CTL_SETALE); - this->write_byte(mtd, 0); - doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); - - ret = this->read_byte(mtd) << 8; - ret |= this->read_byte(mtd); - - if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) { - /* First chip probe. See if we get same results by 32-bit access */ - union { - uint32_t dword; - uint8_t byte[4]; - } ident; - void __iomem *docptr = doc->virtadr; - - doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); - doc2000_write_byte(mtd, NAND_CMD_READID); - doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); - doc200x_hwcontrol(mtd, NAND_CTL_SETALE); - doc2000_write_byte(mtd, 0); - doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); - - ident.dword = readl(docptr + DoC_2k_CDSN_IO); - if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { - printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); - this->read_buf = &doc2000_readbuf_dword; - } - } - - return ret; -} - -static void __init doc2000_count_chips(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - uint16_t mfrid; - int i; - - /* Max 4 chips per floor on DiskOnChip 2000 */ - doc->chips_per_floor = 4; - - /* Find out what the first chip is */ - mfrid = doc200x_ident_chip(mtd, 0); - - /* Find how many chips in each floor. */ - for (i = 1; i < 4; i++) { - if (doc200x_ident_chip(mtd, i) != mfrid) - break; - } - doc->chips_per_floor = i; - printk(KERN_DEBUG "Detected %d chips per floor.\n", i); -} - -static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) -{ - struct doc_priv *doc = this->priv; - - int status; - - DoC_WaitReady(doc); - this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - DoC_WaitReady(doc); - status = (int)this->read_byte(mtd); - - return status; -} - -static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - WriteDOC(datum, docptr, CDSNSlowIO); - WriteDOC(datum, docptr, Mil_CDSN_IO); - WriteDOC(datum, docptr, WritePipeTerm); -} - -static u_char doc2001_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - /*ReadDOC(docptr, CDSNSlowIO); */ - /* 11.4.5 -- delay twice to allow extended length cycle */ - DoC_Delay(doc, 2); - ReadDOC(docptr, ReadPipeInit); - /*return ReadDOC(docptr, Mil_CDSN_IO); */ - return ReadDOC(docptr, LastDataRead); -} - -static void doc2001_writebuf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - for (i=0; i < len; i++) - WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); - /* Terminate write pipeline */ - WriteDOC(0x00, docptr, WritePipeTerm); -} - -static void doc2001_readbuf(struct mtd_info *mtd, - u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - /* Start read pipeline */ - ReadDOC(docptr, ReadPipeInit); - - for (i=0; i < len-1; i++) - buf[i] = ReadDOC(docptr, Mil_CDSN_IO + (i & 0xff)); - - /* Terminate read pipeline */ - buf[i] = ReadDOC(docptr, LastDataRead); -} - -static int doc2001_verifybuf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - /* Start read pipeline */ - ReadDOC(docptr, ReadPipeInit); - - for (i=0; i < len-1; i++) - if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) { - ReadDOC(docptr, LastDataRead); - return i; - } - if (buf[i] != ReadDOC(docptr, LastDataRead)) - return i; - return 0; -} - -static u_char doc2001plus_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - u_char ret; - - ReadDOC(docptr, Mplus_ReadPipeInit); - ReadDOC(docptr, Mplus_ReadPipeInit); - ret = ReadDOC(docptr, Mplus_LastDataRead); - if (debug) printk("read_byte returns %02x\n", ret); - return ret; -} - -static void doc2001plus_writebuf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - if (debug)printk("writebuf of %d bytes: ", len); - for (i=0; i < len; i++) { - WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); - if (debug && i < 16) - printk("%02x ", buf[i]); - } - if (debug) printk("\n"); -} - -static void doc2001plus_readbuf(struct mtd_info *mtd, - u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - if (debug)printk("readbuf of %d bytes: ", len); - - /* Start read pipeline */ - ReadDOC(docptr, Mplus_ReadPipeInit); - ReadDOC(docptr, Mplus_ReadPipeInit); - - for (i=0; i < len-2; i++) { - buf[i] = ReadDOC(docptr, Mil_CDSN_IO); - if (debug && i < 16) - printk("%02x ", buf[i]); - } - - /* Terminate read pipeline */ - buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); - if (debug && i < 16) - printk("%02x ", buf[len-2]); - buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); - if (debug && i < 16) - printk("%02x ", buf[len-1]); - if (debug) printk("\n"); -} - -static int doc2001plus_verifybuf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - - if (debug)printk("verifybuf of %d bytes: ", len); - - /* Start read pipeline */ - ReadDOC(docptr, Mplus_ReadPipeInit); - ReadDOC(docptr, Mplus_ReadPipeInit); - - for (i=0; i < len-2; i++) - if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) { - ReadDOC(docptr, Mplus_LastDataRead); - ReadDOC(docptr, Mplus_LastDataRead); - return i; - } - if (buf[len-2] != ReadDOC(docptr, Mplus_LastDataRead)) - return len-2; - if (buf[len-1] != ReadDOC(docptr, Mplus_LastDataRead)) - return len-1; - return 0; -} - -static void doc2001plus_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int floor = 0; - - if(debug)printk("select chip (%d)\n", chip); - - if (chip == -1) { - /* Disable flash internally */ - WriteDOC(0, docptr, Mplus_FlashSelect); - return; - } - - floor = chip / doc->chips_per_floor; - chip -= (floor * doc->chips_per_floor); - - /* Assert ChipEnable and deassert WriteProtect */ - WriteDOC((DOC_FLASH_CE), docptr, Mplus_FlashSelect); - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - doc->curchip = chip; - doc->curfloor = floor; -} - -static void doc200x_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int floor = 0; - - if(debug)printk("select chip (%d)\n", chip); - - if (chip == -1) - return; - - floor = chip / doc->chips_per_floor; - chip -= (floor * doc->chips_per_floor); - - /* 11.4.4 -- deassert CE before changing chip */ - doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); - - WriteDOC(floor, docptr, FloorSelect); - WriteDOC(chip, docptr, CDSNDeviceSelect); - - doc200x_hwcontrol(mtd, NAND_CTL_SETNCE); - - doc->curchip = chip; - doc->curfloor = floor; -} - -static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - switch(cmd) { - case NAND_CTL_SETNCE: - doc->CDSNControl |= CDSN_CTRL_CE; - break; - case NAND_CTL_CLRNCE: - doc->CDSNControl &= ~CDSN_CTRL_CE; - break; - case NAND_CTL_SETCLE: - doc->CDSNControl |= CDSN_CTRL_CLE; - break; - case NAND_CTL_CLRCLE: - doc->CDSNControl &= ~CDSN_CTRL_CLE; - break; - case NAND_CTL_SETALE: - doc->CDSNControl |= CDSN_CTRL_ALE; - break; - case NAND_CTL_CLRALE: - doc->CDSNControl &= ~CDSN_CTRL_ALE; - break; - case NAND_CTL_SETWP: - doc->CDSNControl |= CDSN_CTRL_WP; - break; - case NAND_CTL_CLRWP: - doc->CDSNControl &= ~CDSN_CTRL_WP; - break; - } - if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); - WriteDOC(doc->CDSNControl, docptr, CDSNControl); - /* 11.4.3 -- 4 NOPs after CSDNControl write */ - DoC_Delay(doc, 4); -} - -static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - /* - * Must terminate write pipeline before sending any commands - * to the device. - */ - if (command == NAND_CMD_PAGEPROG) { - WriteDOC(0x00, docptr, Mplus_WritePipeTerm); - WriteDOC(0x00, docptr, Mplus_WritePipeTerm); - } - - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->oobblock) { - /* OOB area */ - column -= mtd->oobblock; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - WriteDOC(readcmd, docptr, Mplus_FlashCmd); - } - WriteDOC(command, docptr, Mplus_FlashCmd); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - - if (column != -1 || page_addr != -1) { - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (this->options & NAND_BUSWIDTH_16) - column >>= 1; - WriteDOC(column, docptr, Mplus_FlashAddress); - } - if (page_addr != -1) { - WriteDOC((unsigned char) (page_addr & 0xff), docptr, Mplus_FlashAddress); - WriteDOC((unsigned char) ((page_addr >> 8) & 0xff), docptr, Mplus_FlashAddress); - /* One more address cycle for higher density devices */ - if (this->chipsize & 0x0c000000) { - WriteDOC((unsigned char) ((page_addr >> 16) & 0x0f), docptr, Mplus_FlashAddress); - printk("high density\n"); - } - } - WriteDOC(0, docptr, Mplus_WritePipeTerm); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - /* deassert ALE */ - if (command == NAND_CMD_READ0 || command == NAND_CMD_READ1 || command == NAND_CMD_READOOB || command == NAND_CMD_READID) - WriteDOC(0, docptr, Mplus_FlashControl); - } - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (this->dev_ready) - break; - udelay(this->chip_delay); - WriteDOC(NAND_CMD_STATUS, docptr, Mplus_FlashCmd); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - WriteDOC(0, docptr, Mplus_WritePipeTerm); - while ( !(this->read_byte(mtd) & 0x40)); - return; - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!this->dev_ready) { - udelay (this->chip_delay); - return; - } - } - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay (100); - /* wait until command is processed */ - while (!this->dev_ready(mtd)); -} - -static int doc200x_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - if (DoC_is_MillenniumPlus(doc)) { - /* 11.4.2 -- must NOP four times before checking FR/B# */ - DoC_Delay(doc, 4); - if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) { - if(debug) - printk("not ready\n"); - return 0; - } - if (debug)printk("was ready\n"); - return 1; - } else { - /* 11.4.2 -- must NOP four times before checking FR/B# */ - DoC_Delay(doc, 4); - if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { - if(debug) - printk("not ready\n"); - return 0; - } - /* 11.4.2 -- Must NOP twice if it's ready */ - DoC_Delay(doc, 2); - if (debug)printk("was ready\n"); - return 1; - } -} - -static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) -{ - /* This is our last resort if we couldn't find or create a BBT. Just - pretend all blocks are good. */ - return 0; -} - -static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - /* Prime the ECC engine */ - switch(mode) { - case NAND_ECC_READ: - WriteDOC(DOC_ECC_RESET, docptr, ECCConf); - WriteDOC(DOC_ECC_EN, docptr, ECCConf); - break; - case NAND_ECC_WRITE: - WriteDOC(DOC_ECC_RESET, docptr, ECCConf); - WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, ECCConf); - break; - } -} - -static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - - /* Prime the ECC engine */ - switch(mode) { - case NAND_ECC_READ: - WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); - WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); - break; - case NAND_ECC_WRITE: - WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); - WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); - break; - } -} - -/* This code is only called on write */ -static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - unsigned char *ecc_code) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - int i; - int emptymatch = 1; - - /* flush the pipeline */ - if (DoC_is_2000(doc)) { - WriteDOC(doc->CDSNControl & ~CDSN_CTRL_FLASH_IO, docptr, CDSNControl); - WriteDOC(0, docptr, 2k_CDSN_IO); - WriteDOC(0, docptr, 2k_CDSN_IO); - WriteDOC(0, docptr, 2k_CDSN_IO); - WriteDOC(doc->CDSNControl, docptr, CDSNControl); - } else if (DoC_is_MillenniumPlus(doc)) { - WriteDOC(0, docptr, Mplus_NOP); - WriteDOC(0, docptr, Mplus_NOP); - WriteDOC(0, docptr, Mplus_NOP); - } else { - WriteDOC(0, docptr, NOP); - WriteDOC(0, docptr, NOP); - WriteDOC(0, docptr, NOP); - } - - for (i = 0; i < 6; i++) { - if (DoC_is_MillenniumPlus(doc)) - ecc_code[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); - else - ecc_code[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); - if (ecc_code[i] != empty_write_ecc[i]) - emptymatch = 0; - } - if (DoC_is_MillenniumPlus(doc)) - WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); - else - WriteDOC(DOC_ECC_DIS, docptr, ECCConf); -#if 0 - /* If emptymatch=1, we might have an all-0xff data buffer. Check. */ - if (emptymatch) { - /* Note: this somewhat expensive test should not be triggered - often. It could be optimized away by examining the data in - the writebuf routine, and remembering the result. */ - for (i = 0; i < 512; i++) { - if (dat[i] == 0xff) continue; - emptymatch = 0; - break; - } - } - /* If emptymatch still =1, we do have an all-0xff data buffer. - Return all-0xff ecc value instead of the computed one, so - it'll look just like a freshly-erased page. */ - if (emptymatch) memset(ecc_code, 0xff, 6); -#endif - return 0; -} - -static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) -{ - int i, ret = 0; - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - void __iomem *docptr = doc->virtadr; - volatile u_char dummy; - int emptymatch = 1; - - /* flush the pipeline */ - if (DoC_is_2000(doc)) { - dummy = ReadDOC(docptr, 2k_ECCStatus); - dummy = ReadDOC(docptr, 2k_ECCStatus); - dummy = ReadDOC(docptr, 2k_ECCStatus); - } else if (DoC_is_MillenniumPlus(doc)) { - dummy = ReadDOC(docptr, Mplus_ECCConf); - dummy = ReadDOC(docptr, Mplus_ECCConf); - dummy = ReadDOC(docptr, Mplus_ECCConf); - } else { - dummy = ReadDOC(docptr, ECCConf); - dummy = ReadDOC(docptr, ECCConf); - dummy = ReadDOC(docptr, ECCConf); - } - - /* Error occured ? */ - if (dummy & 0x80) { - for (i = 0; i < 6; i++) { - if (DoC_is_MillenniumPlus(doc)) - calc_ecc[i] = ReadDOC_(docptr, DoC_Mplus_ECCSyndrome0 + i); - else - calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i); - if (calc_ecc[i] != empty_read_syndrome[i]) - emptymatch = 0; - } - /* If emptymatch=1, the read syndrome is consistent with an - all-0xff data and stored ecc block. Check the stored ecc. */ - if (emptymatch) { - for (i = 0; i < 6; i++) { - if (read_ecc[i] == 0xff) continue; - emptymatch = 0; - break; - } - } - /* If emptymatch still =1, check the data block. */ - if (emptymatch) { - /* Note: this somewhat expensive test should not be triggered - often. It could be optimized away by examining the data in - the readbuf routine, and remembering the result. */ - for (i = 0; i < 512; i++) { - if (dat[i] == 0xff) continue; - emptymatch = 0; - break; - } - } - /* If emptymatch still =1, this is almost certainly a freshly- - erased block, in which case the ECC will not come out right. - We'll suppress the error and tell the caller everything's - OK. Because it is. */ - if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc); - if (ret > 0) - printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret); - } - if (DoC_is_MillenniumPlus(doc)) - WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); - else - WriteDOC(DOC_ECC_DIS, docptr, ECCConf); - if (no_ecc_failures && (ret == -1)) { - printk(KERN_ERR "suppressing ECC failure\n"); - ret = 0; - } - return ret; -} - -/*u_char mydatabuf[528]; */ - -static struct nand_oobinfo doc200x_oobinfo = { - .useecc = MTD_NANDECC_AUTOPLACE, - .eccbytes = 6, - .eccpos = {0, 1, 2, 3, 4, 5}, - .oobfree = { {8, 8} } -}; - -/* Find the (I)NFTL Media Header, and optionally also the mirror media header. - On sucessful return, buf will contain a copy of the media header for - further processing. id is the string to scan for, and will presumably be - either "ANAND" or "BNAND". If findmirror=1, also look for the mirror media - header. The page #s of the found media headers are placed in mh0_page and - mh1_page in the DOC private structure. */ -static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, - const char *id, int findmirror) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift); - int ret; - size_t retlen; - - end = min(end, mtd->size); /* paranoia */ - for (offs = 0; offs < end; offs += mtd->erasesize) { - ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); - if (retlen != mtd->oobblock) continue; - if (ret) { - printk(KERN_WARNING "ECC error scanning DOC at 0x%x\n", - offs); - } - if (memcmp(buf, id, 6)) continue; - printk(KERN_INFO "Found DiskOnChip %s Media Header at 0x%x\n", id, offs); - if (doc->mh0_page == -1) { - doc->mh0_page = offs >> this->page_shift; - if (!findmirror) return 1; - continue; - } - doc->mh1_page = offs >> this->page_shift; - return 2; - } - if (doc->mh0_page == -1) { - printk(KERN_WARNING "DiskOnChip %s Media Header not found.\n", id); - return 0; - } - /* Only one mediaheader was found. We want buf to contain a - mediaheader on return, so we'll have to re-read the one we found. */ - offs = doc->mh0_page << this->page_shift; - ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf); - if (retlen != mtd->oobblock) { - /* Insanity. Give up. */ - printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n"); - return 0; - } - return 1; -} - -static inline int __init nftl_partscan(struct mtd_info *mtd, - struct mtd_partition *parts) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - int ret = 0; - u_char *buf; - struct NFTLMediaHeader *mh; - const unsigned psize = 1 << this->page_shift; - unsigned blocks, maxblocks; - int offs, numheaders; - - buf = kmalloc(mtd->oobblock, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); - return 0; - } - if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out; - mh = (struct NFTLMediaHeader *) buf; - -/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ -/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ - printk(KERN_INFO " DataOrgID = %s\n" - " NumEraseUnits = %d\n" - " FirstPhysicalEUN = %d\n" - " FormattedSize = %d\n" - " UnitSizeFactor = %d\n", - mh->DataOrgID, mh->NumEraseUnits, - mh->FirstPhysicalEUN, mh->FormattedSize, - mh->UnitSizeFactor); -/*#endif */ - - blocks = mtd->size >> this->phys_erase_shift; - maxblocks = min(32768U, mtd->erasesize - psize); - - if (mh->UnitSizeFactor == 0x00) { - /* Auto-determine UnitSizeFactor. The constraints are: - - There can be at most 32768 virtual blocks. - - There can be at most (virtual block size - page size) - virtual blocks (because MediaHeader+BBT must fit in 1). - */ - mh->UnitSizeFactor = 0xff; - while (blocks > maxblocks) { - blocks >>= 1; - maxblocks = min(32768U, (maxblocks << 1) + psize); - mh->UnitSizeFactor--; - } - printk(KERN_WARNING "UnitSizeFactor=0x00 detected. Correct value is assumed to be 0x%02x.\n", mh->UnitSizeFactor); - } - - /* NOTE: The lines below modify internal variables of the NAND and MTD - layers; variables with have already been configured by nand_scan. - Unfortunately, we didn't know before this point what these values - should be. Thus, this code is somewhat dependant on the exact - implementation of the NAND layer. */ - if (mh->UnitSizeFactor != 0xff) { - this->bbt_erase_shift += (0xff - mh->UnitSizeFactor); - mtd->erasesize <<= (0xff - mh->UnitSizeFactor); - printk(KERN_INFO "Setting virtual erase size to %d\n", mtd->erasesize); - blocks = mtd->size >> this->bbt_erase_shift; - maxblocks = min(32768U, mtd->erasesize - psize); - } - - if (blocks > maxblocks) { - printk(KERN_ERR "UnitSizeFactor of 0x%02x is inconsistent with device size. Aborting.\n", mh->UnitSizeFactor); - goto out; - } - - /* Skip past the media headers. */ - offs = max(doc->mh0_page, doc->mh1_page); - offs <<= this->page_shift; - offs += mtd->erasesize; - - /*parts[0].name = " DiskOnChip Boot / Media Header partition"; */ - /*parts[0].offset = 0; */ - /*parts[0].size = offs; */ - - parts[0].name = " DiskOnChip BDTL partition"; - parts[0].offset = offs; - parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift; - - offs += parts[0].size; - if (offs < mtd->size) { - parts[1].name = " DiskOnChip Remainder partition"; - parts[1].offset = offs; - parts[1].size = mtd->size - offs; - ret = 2; - goto out; - } - ret = 1; -out: - kfree(buf); - return ret; -} - -/* This is a stripped-down copy of the code in inftlmount.c */ -static inline int __init inftl_partscan(struct mtd_info *mtd, - struct mtd_partition *parts) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - int ret = 0; - u_char *buf; - struct INFTLMediaHeader *mh; - struct INFTLPartition *ip; - int numparts = 0; - int blocks; - int vshift, lastvunit = 0; - int i; - int end = mtd->size; - - if (inftl_bbt_write) - end -= (INFTL_BBT_RESERVED_BLOCKS << this->phys_erase_shift); - - buf = kmalloc(mtd->oobblock, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n"); - return 0; - } - - if (!find_media_headers(mtd, buf, "BNAND", 0)) goto out; - doc->mh1_page = doc->mh0_page + (4096 >> this->page_shift); - mh = (struct INFTLMediaHeader *) buf; - - mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); - mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); - mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); - mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); - mh->FormatFlags = le32_to_cpu(mh->FormatFlags); - mh->PercentUsed = le32_to_cpu(mh->PercentUsed); - -/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ -/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ - printk(KERN_INFO " bootRecordID = %s\n" - " NoOfBootImageBlocks = %d\n" - " NoOfBinaryPartitions = %d\n" - " NoOfBDTLPartitions = %d\n" - " BlockMultiplerBits = %d\n" - " FormatFlgs = %d\n" - " OsakVersion = %d.%d.%d.%d\n" - " PercentUsed = %d\n", - mh->bootRecordID, mh->NoOfBootImageBlocks, - mh->NoOfBinaryPartitions, - mh->NoOfBDTLPartitions, - mh->BlockMultiplierBits, mh->FormatFlags, - ((unsigned char *) &mh->OsakVersion)[0] & 0xf, - ((unsigned char *) &mh->OsakVersion)[1] & 0xf, - ((unsigned char *) &mh->OsakVersion)[2] & 0xf, - ((unsigned char *) &mh->OsakVersion)[3] & 0xf, - mh->PercentUsed); -/*#endif */ - - vshift = this->phys_erase_shift + mh->BlockMultiplierBits; - - blocks = mtd->size >> vshift; - if (blocks > 32768) { - printk(KERN_ERR "BlockMultiplierBits=%d is inconsistent with device size. Aborting.\n", mh->BlockMultiplierBits); - goto out; - } - - blocks = doc->chips_per_floor << (this->chip_shift - this->phys_erase_shift); - if (inftl_bbt_write && (blocks > mtd->erasesize)) { - printk(KERN_ERR "Writeable BBTs spanning more than one erase block are not yet supported. FIX ME!\n"); - goto out; - } - - /* Scan the partitions */ - for (i = 0; (i < 4); i++) { - ip = &(mh->Partitions[i]); - ip->virtualUnits = le32_to_cpu(ip->virtualUnits); - ip->firstUnit = le32_to_cpu(ip->firstUnit); - ip->lastUnit = le32_to_cpu(ip->lastUnit); - ip->flags = le32_to_cpu(ip->flags); - ip->spareUnits = le32_to_cpu(ip->spareUnits); - ip->Reserved0 = le32_to_cpu(ip->Reserved0); - -/*#ifdef CONFIG_MTD_DEBUG_VERBOSE */ -/* if (CONFIG_MTD_DEBUG_VERBOSE >= 2) */ - printk(KERN_INFO " PARTITION[%d] ->\n" - " virtualUnits = %d\n" - " firstUnit = %d\n" - " lastUnit = %d\n" - " flags = 0x%x\n" - " spareUnits = %d\n", - i, ip->virtualUnits, ip->firstUnit, - ip->lastUnit, ip->flags, - ip->spareUnits); -/*#endif */ - -/* - if ((i == 0) && (ip->firstUnit > 0)) { - parts[0].name = " DiskOnChip IPL / Media Header partition"; - parts[0].offset = 0; - parts[0].size = mtd->erasesize * ip->firstUnit; - numparts = 1; - } -*/ - - if (ip->flags & INFTL_BINARY) - parts[numparts].name = " DiskOnChip BDK partition"; - else - parts[numparts].name = " DiskOnChip BDTL partition"; - parts[numparts].offset = ip->firstUnit << vshift; - parts[numparts].size = (1 + ip->lastUnit - ip->firstUnit) << vshift; - numparts++; - if (ip->lastUnit > lastvunit) lastvunit = ip->lastUnit; - if (ip->flags & INFTL_LAST) break; - } - lastvunit++; - if ((lastvunit << vshift) < end) { - parts[numparts].name = " DiskOnChip Remainder partition"; - parts[numparts].offset = lastvunit << vshift; - parts[numparts].size = end - parts[numparts].offset; - numparts++; - } - ret = numparts; -out: - kfree(buf); - return ret; -} - -static int __init nftl_scan_bbt(struct mtd_info *mtd) -{ - int ret, numparts; - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - struct mtd_partition parts[2]; - - memset((char *) parts, 0, sizeof(parts)); - /* On NFTL, we have to find the media headers before we can read the - BBTs, since they're stored in the media header eraseblocks. */ - numparts = nftl_partscan(mtd, parts); - if (!numparts) return -EIO; - this->bbt_td->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | - NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | - NAND_BBT_VERSION; - this->bbt_td->veroffs = 7; - this->bbt_td->pages[0] = doc->mh0_page + 1; - if (doc->mh1_page != -1) { - this->bbt_md->options = NAND_BBT_ABSPAGE | NAND_BBT_8BIT | - NAND_BBT_SAVECONTENT | NAND_BBT_WRITE | - NAND_BBT_VERSION; - this->bbt_md->veroffs = 7; - this->bbt_md->pages[0] = doc->mh1_page + 1; - } else { - this->bbt_md = NULL; - } - - /* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set. - At least as nand_bbt.c is currently written. */ - if ((ret = nand_scan_bbt(mtd, NULL))) - return ret; - add_mtd_device(mtd); -#ifdef CONFIG_MTD_PARTITIONS - if (!no_autopart) - add_mtd_partitions(mtd, parts, numparts); -#endif - return 0; -} - -static int __init inftl_scan_bbt(struct mtd_info *mtd) -{ - int ret, numparts; - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - struct mtd_partition parts[5]; - - if (this->numchips > doc->chips_per_floor) { - printk(KERN_ERR "Multi-floor INFTL devices not yet supported.\n"); - return -EIO; - } - - if (DoC_is_MillenniumPlus(doc)) { - this->bbt_td->options = NAND_BBT_2BIT | NAND_BBT_ABSPAGE; - if (inftl_bbt_write) - this->bbt_td->options |= NAND_BBT_WRITE; - this->bbt_td->pages[0] = 2; - this->bbt_md = NULL; - } else { - this->bbt_td->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | - NAND_BBT_VERSION; - if (inftl_bbt_write) - this->bbt_td->options |= NAND_BBT_WRITE; - this->bbt_td->offs = 8; - this->bbt_td->len = 8; - this->bbt_td->veroffs = 7; - this->bbt_td->maxblocks = INFTL_BBT_RESERVED_BLOCKS; - this->bbt_td->reserved_block_code = 0x01; - this->bbt_td->pattern = "MSYS_BBT"; - - this->bbt_md->options = NAND_BBT_LASTBLOCK | NAND_BBT_8BIT | - NAND_BBT_VERSION; - if (inftl_bbt_write) - this->bbt_md->options |= NAND_BBT_WRITE; - this->bbt_md->offs = 8; - this->bbt_md->len = 8; - this->bbt_md->veroffs = 7; - this->bbt_md->maxblocks = INFTL_BBT_RESERVED_BLOCKS; - this->bbt_md->reserved_block_code = 0x01; - this->bbt_md->pattern = "TBB_SYSM"; - } - - /* It's safe to set bd=NULL below because NAND_BBT_CREATE is not set. - At least as nand_bbt.c is currently written. */ - if ((ret = nand_scan_bbt(mtd, NULL))) - return ret; - memset((char *) parts, 0, sizeof(parts)); - numparts = inftl_partscan(mtd, parts); - /* At least for now, require the INFTL Media Header. We could probably - do without it for non-INFTL use, since all it gives us is - autopartitioning, but I want to give it more thought. */ - if (!numparts) return -EIO; - add_mtd_device(mtd); -#ifdef CONFIG_MTD_PARTITIONS - if (!no_autopart) - add_mtd_partitions(mtd, parts, numparts); -#endif - return 0; -} - -static inline int __init doc2000_init(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - - this->write_byte = doc2000_write_byte; - this->read_byte = doc2000_read_byte; - this->write_buf = doc2000_writebuf; - this->read_buf = doc2000_readbuf; - this->verify_buf = doc2000_verifybuf; - this->scan_bbt = nftl_scan_bbt; - - doc->CDSNControl = CDSN_CTRL_FLASH_IO | CDSN_CTRL_ECC_IO; - doc2000_count_chips(mtd); - mtd->name = "DiskOnChip 2000 (NFTL Model)"; - return (4 * doc->chips_per_floor); -} - -static inline int __init doc2001_init(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - - this->write_byte = doc2001_write_byte; - this->read_byte = doc2001_read_byte; - this->write_buf = doc2001_writebuf; - this->read_buf = doc2001_readbuf; - this->verify_buf = doc2001_verifybuf; - - ReadDOC(doc->virtadr, ChipID); - ReadDOC(doc->virtadr, ChipID); - ReadDOC(doc->virtadr, ChipID); - if (ReadDOC(doc->virtadr, ChipID) != DOC_ChipID_DocMil) { - /* It's not a Millennium; it's one of the newer - DiskOnChip 2000 units with a similar ASIC. - Treat it like a Millennium, except that it - can have multiple chips. */ - doc2000_count_chips(mtd); - mtd->name = "DiskOnChip 2000 (INFTL Model)"; - this->scan_bbt = inftl_scan_bbt; - return (4 * doc->chips_per_floor); - } else { - /* Bog-standard Millennium */ - doc->chips_per_floor = 1; - mtd->name = "DiskOnChip Millennium"; - this->scan_bbt = nftl_scan_bbt; - return 1; - } -} - -static inline int __init doc2001plus_init(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - struct doc_priv *doc = this->priv; - - this->write_byte = NULL; - this->read_byte = doc2001plus_read_byte; - this->write_buf = doc2001plus_writebuf; - this->read_buf = doc2001plus_readbuf; - this->verify_buf = doc2001plus_verifybuf; - this->scan_bbt = inftl_scan_bbt; - this->hwcontrol = NULL; - this->select_chip = doc2001plus_select_chip; - this->cmdfunc = doc2001plus_command; - this->enable_hwecc = doc2001plus_enable_hwecc; - - doc->chips_per_floor = 1; - mtd->name = "DiskOnChip Millennium Plus"; - - return 1; -} - -static inline int __init doc_probe(unsigned long physadr) -{ - unsigned char ChipID; - struct mtd_info *mtd; - struct nand_chip *nand; - struct doc_priv *doc; - void __iomem *virtadr; - unsigned char save_control; - unsigned char tmp, tmpb, tmpc; - int reg, len, numchips; - int ret = 0; - - virtadr = ioremap(physadr, DOC_IOREMAP_LEN); - if (!virtadr) { - printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr); - return -EIO; - } - - /* It's not possible to cleanly detect the DiskOnChip - the - * bootup procedure will put the device into reset mode, and - * it's not possible to talk to it without actually writing - * to the DOCControl register. So we store the current contents - * of the DOCControl register's location, in case we later decide - * that it's not a DiskOnChip, and want to put it back how we - * found it. - */ - save_control = ReadDOC(virtadr, DOCControl); - - /* Reset the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, - virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, - virtadr, DOCControl); - - /* Enable the DiskOnChip ASIC */ - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, - virtadr, DOCControl); - WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, - virtadr, DOCControl); - - ChipID = ReadDOC(virtadr, ChipID); - - switch(ChipID) { - case DOC_ChipID_Doc2k: - reg = DoC_2k_ECCStatus; - break; - case DOC_ChipID_DocMil: - reg = DoC_ECCConf; - break; - case DOC_ChipID_DocMilPlus16: - case DOC_ChipID_DocMilPlus32: - case 0: - /* Possible Millennium Plus, need to do more checks */ - /* Possibly release from power down mode */ - for (tmp = 0; (tmp < 4); tmp++) - ReadDOC(virtadr, Mplus_Power); - - /* Reset the Millennium Plus ASIC */ - tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | - DOC_MODE_BDECT; - WriteDOC(tmp, virtadr, Mplus_DOCControl); - WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm); - - mdelay(1); - /* Enable the Millennium Plus ASIC */ - tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | - DOC_MODE_BDECT; - WriteDOC(tmp, virtadr, Mplus_DOCControl); - WriteDOC(~tmp, virtadr, Mplus_CtrlConfirm); - mdelay(1); - - ChipID = ReadDOC(virtadr, ChipID); - - switch (ChipID) { - case DOC_ChipID_DocMilPlus16: - reg = DoC_Mplus_Toggle; - break; - case DOC_ChipID_DocMilPlus32: - printk(KERN_ERR "DiskOnChip Millennium Plus 32MB is not supported, ignoring.\n"); - default: - ret = -ENODEV; - goto notfound; - } - break; - - default: - ret = -ENODEV; - goto notfound; - } - /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; - tmpb = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; - tmpc = ReadDOC_(virtadr, reg) & DOC_TOGGLE_BIT; - if ((tmp == tmpb) || (tmp != tmpc)) { - printk(KERN_WARNING "Possible DiskOnChip at 0x%lx failed TOGGLE test, dropping.\n", physadr); - ret = -ENODEV; - goto notfound; - } - - for (mtd = doclist; mtd; mtd = doc->nextdoc) { - unsigned char oldval; - unsigned char newval; - nand = mtd->priv; - doc = nand->priv; - /* Use the alias resolution register to determine if this is - in fact the same DOC aliased to a new address. If writes - to one chip's alias resolution register change the value on - the other chip, they're the same chip. */ - if (ChipID == DOC_ChipID_DocMilPlus16) { - oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); - newval = ReadDOC(virtadr, Mplus_AliasResolution); - } else { - oldval = ReadDOC(doc->virtadr, AliasResolution); - newval = ReadDOC(virtadr, AliasResolution); - } - if (oldval != newval) - continue; - if (ChipID == DOC_ChipID_DocMilPlus16) { - WriteDOC(~newval, virtadr, Mplus_AliasResolution); - oldval = ReadDOC(doc->virtadr, Mplus_AliasResolution); - WriteDOC(newval, virtadr, Mplus_AliasResolution); /* restore it */ - } else { - WriteDOC(~newval, virtadr, AliasResolution); - oldval = ReadDOC(doc->virtadr, AliasResolution); - WriteDOC(newval, virtadr, AliasResolution); /* restore it */ - } - newval = ~newval; - if (oldval == newval) { - printk(KERN_DEBUG "Found alias of DOC at 0x%lx to 0x%lx\n", doc->physadr, physadr); - goto notfound; - } - } - - printk(KERN_NOTICE "DiskOnChip found at 0x%lx\n", physadr); - - len = sizeof(struct mtd_info) + - sizeof(struct nand_chip) + - sizeof(struct doc_priv) + - (2 * sizeof(struct nand_bbt_descr)); - mtd = kmalloc(len, GFP_KERNEL); - if (!mtd) { - printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len); - ret = -ENOMEM; - goto fail; - } - memset(mtd, 0, len); - - nand = (struct nand_chip *) (mtd + 1); - doc = (struct doc_priv *) (nand + 1); - nand->bbt_td = (struct nand_bbt_descr *) (doc + 1); - nand->bbt_md = nand->bbt_td + 1; - - mtd->priv = nand; - mtd->owner = THIS_MODULE; - - nand->priv = doc; - nand->select_chip = doc200x_select_chip; - nand->hwcontrol = doc200x_hwcontrol; - nand->dev_ready = doc200x_dev_ready; - nand->waitfunc = doc200x_wait; - nand->block_bad = doc200x_block_bad; - nand->enable_hwecc = doc200x_enable_hwecc; - nand->calculate_ecc = doc200x_calculate_ecc; - nand->correct_data = doc200x_correct_data; - - nand->autooob = &doc200x_oobinfo; - nand->eccmode = NAND_ECC_HW6_512; - nand->options = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME; - - doc->physadr = physadr; - doc->virtadr = virtadr; - doc->ChipID = ChipID; - doc->curfloor = -1; - doc->curchip = -1; - doc->mh0_page = -1; - doc->mh1_page = -1; - doc->nextdoc = doclist; - - if (ChipID == DOC_ChipID_Doc2k) - numchips = doc2000_init(mtd); - else if (ChipID == DOC_ChipID_DocMilPlus16) - numchips = doc2001plus_init(mtd); - else - numchips = doc2001_init(mtd); - - if ((ret = nand_scan(mtd, numchips))) { - /* DBB note: i believe nand_release is necessary here, as - buffers may have been allocated in nand_base. Check with - Thomas. FIX ME! */ - /* nand_release will call del_mtd_device, but we haven't yet - added it. This is handled without incident by - del_mtd_device, as far as I can tell. */ - nand_release(mtd); - kfree(mtd); - goto fail; - } - - /* Success! */ - doclist = mtd; - return 0; - -notfound: - /* Put back the contents of the DOCControl register, in case it's not - actually a DiskOnChip. */ - WriteDOC(save_control, virtadr, DOCControl); -fail: - iounmap(virtadr); - return ret; -} - -static void release_nanddoc(void) -{ - struct mtd_info *mtd, *nextmtd; - struct nand_chip *nand; - struct doc_priv *doc; - - for (mtd = doclist; mtd; mtd = nextmtd) { - nand = mtd->priv; - doc = nand->priv; - - nextmtd = doc->nextdoc; - nand_release(mtd); - iounmap(doc->virtadr); - kfree(mtd); - } -} - -static int __init init_nanddoc(void) -{ - int i, ret = 0; - - /* We could create the decoder on demand, if memory is a concern. - * This way we have it handy, if an error happens - * - * Symbolsize is 10 (bits) - * Primitve polynomial is x^10+x^3+1 - * first consecutive root is 510 - * primitve element to generate roots = 1 - * generator polinomial degree = 4 - */ - rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS); - if (!rs_decoder) { - printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n"); - return -ENOMEM; - } - - if (doc_config_location) { - printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); - ret = doc_probe(doc_config_location); - if (ret < 0) - goto outerr; - } else { - for (i=0; (doc_locations[i] != 0xffffffff); i++) { - doc_probe(doc_locations[i]); - } - } - /* No banner message any more. Print a message if no DiskOnChip - found, so the user knows we at least tried. */ - if (!doclist) { - printk(KERN_INFO "No valid DiskOnChip devices found\n"); - ret = -ENODEV; - goto outerr; - } - return 0; -outerr: - free_rs(rs_decoder); - return ret; -} - -static void __exit cleanup_nanddoc(void) -{ - /* Cleanup the nand/DoC resources */ - release_nanddoc(); - - /* Free the reed solomon resources */ - if (rs_decoder) { - free_rs(rs_decoder); - } -} - -module_init(init_nanddoc); -module_exit(cleanup_nanddoc); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("David Woodhouse "); -MODULE_DESCRIPTION("M-Systems DiskOnChip 2000, Millennium and Millennium Plus device driver\n"); -#endif diff --git a/drivers/nand/nand.c b/drivers/nand/nand.c deleted file mode 100644 index 4927231..0000000 --- a/drivers/nand/nand.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * (C) Copyright 2005 - * 2N Telekomunikace, a.s. - * Ladislav Michl - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static ssize_t nand_read(struct cdev *cdev, void* buf, size_t count, ulong offset, ulong flags) -{ - struct mtd_info *info = cdev->priv; - size_t retlen; - int ret; - - debug("nand_read: 0x%08x 0x%08x\n", offset, count); - - ret = info->read(info, offset, count, &retlen, buf); - - if(ret) { - printf("err %d\n", ret); - return ret; - } - return retlen; -} - -#define NOTALIGNED(x) (x & (info->writesize - 1)) != 0 - -static int all_ff(const void *buf, int len) -{ - int i; - const uint8_t *p = buf; - - for (i = 0; i < len; i++) - if (p[i] != 0xFF) - return 0; - return 1; -} - -static ssize_t nand_write(struct cdev* cdev, const void *buf, size_t _count, ulong offset, ulong flags) -{ - struct mtd_info *info = cdev->priv; - size_t retlen, now; - int ret = 0; - void *wrbuf = NULL; - size_t count = _count; - - if (NOTALIGNED(offset)) { - printf("offset 0x%08x not page aligned\n", offset); - return -EINVAL; - } - - debug("write: 0x%08x 0x%08x\n", offset, count); - - while (count) { - now = count > info->writesize ? info->writesize : count; - - if (NOTALIGNED(now)) { - debug("not aligned: %d %d\n", info->writesize, (offset % info->writesize)); - wrbuf = xmalloc(info->writesize); - memset(wrbuf, 0xff, info->writesize); - memcpy(wrbuf + (offset % info->writesize), buf, now); - if (!all_ff(wrbuf, info->writesize)) - ret = info->write(info, offset & ~(info->writesize - 1), - info->writesize, &retlen, wrbuf); - free(wrbuf); - } else { - if (!all_ff(buf, info->writesize)) - ret = info->write(info, offset, now, &retlen, buf); - debug("offset: 0x%08x now: 0x%08x retlen: 0x%08x\n", offset, now, retlen); - } - if (ret) - goto out; - - offset += now; - count -= now; - buf += now; - } - -out: - return ret ? ret : _count; -} - -static int nand_ioctl(struct cdev *cdev, int request, void *buf) -{ - struct mtd_info *info = cdev->priv; - struct mtd_info_user *user = buf; - - switch (request) { - case MEMGETBADBLOCK: - debug("MEMGETBADBLOCK: 0x%08x\n", (off_t)buf); - return info->block_isbad(info, (off_t)buf); - case MEMSETBADBLOCK: - debug("MEMSETBADBLOCK: 0x%08x\n", (off_t)buf); - return info->block_markbad(info, (off_t)buf); - case MEMGETINFO: - user->type = info->type; - user->flags = info->flags; - user->size = info->size; - user->erasesize = info->erasesize; - user->oobsize = info->oobsize; - /* The below fields are obsolete */ - user->ecctype = -1; - user->eccsize = 0; - return 0; - } - - return 0; -} - -static ssize_t nand_erase(struct cdev *cdev, size_t count, unsigned long offset) -{ - struct mtd_info *info = cdev->priv; - struct erase_info erase; - int ret; - - memset(&erase, 0, sizeof(erase)); - erase.mtd = info; - erase.addr = offset; - erase.len = info->erasesize; - - while (count > 0) { - debug("erase %d %d\n", erase.addr, erase.len); - - ret = info->block_isbad(info, erase.addr); - if (ret > 0) { - printf("Skipping bad block at 0x%08x\n", erase.addr); - } else { - ret = info->erase(info, &erase); - if (ret) - return ret; - } - - erase.addr += info->erasesize; - count -= count > info->erasesize ? info->erasesize : count; - } - - return 0; -} -#if 0 -static char* mtd_get_size(struct device_d *, struct param_d *param) -{ - static char -} -#endif - -static struct file_operations nand_ops = { - .read = nand_read, - .write = nand_write, - .ioctl = nand_ioctl, - .lseek = dev_lseek_default, - .erase = nand_erase, -}; - -static ssize_t nand_read_oob(struct cdev *cdev, void *buf, size_t count, ulong offset, ulong flags) -{ - struct mtd_info *info = cdev->priv; - struct nand_chip *chip = info->priv; - struct mtd_oob_ops ops; - int ret; - - if (count < info->oobsize) - return -EINVAL; - - ops.mode = MTD_OOB_RAW; - ops.ooboffs = 0; - ops.ooblen = info->oobsize; - ops.oobbuf = buf; - ops.datbuf = NULL; - ops.len = info->oobsize; - - offset /= info->oobsize; - ret = info->read_oob(info, offset << chip->page_shift, &ops); - if (ret) - return ret; - - return info->oobsize; -} - -static struct file_operations nand_ops_oob = { - .read = nand_read_oob, - .ioctl = nand_ioctl, - .lseek = dev_lseek_default, -}; - -int add_mtd_device(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - char str[16]; - - strcpy(mtd->class_dev.name, "nand"); - register_device(&mtd->class_dev); - - mtd->cdev.ops = &nand_ops; - mtd->cdev.size = mtd->size; - mtd->cdev.name = asprintf("nand%d", mtd->class_dev.id); - mtd->cdev.priv = mtd; - mtd->cdev.dev = &mtd->class_dev; - - sprintf(str, "%u", mtd->size); - dev_add_param_fixed(&mtd->class_dev, "size", str); - - 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); - - return 0; -} - -int del_mtd_device (struct mtd_info *mtd) -{ - unregister_device(&mtd->class_dev); - free(mtd->cdev_oob.name); - free(mtd->param_size.value); - free(mtd->cdev.name); - return 0; -} - diff --git a/drivers/nand/nand_base.c b/drivers/nand/nand_base.c deleted file mode 100644 index b75a450..0000000 --- a/drivers/nand/nand_base.c +++ /dev/null @@ -1,2648 +0,0 @@ -/* - * drivers/mtd/nand.c - * - * Overview: - * This is the generic MTD driver for NAND flash devices. It should be - * capable of working with almost all NAND chips currently available. - * Basic support for AG-AND chips is provided. - * - * Additional technical information is available on - * http://www.linux-mtd.infradead.org/doc/nand.html - * - * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002-2006 Thomas Gleixner (tglx@linutronix.de) - * - * Credits: - * David Woodhouse for adding multichip support - * - * Aleph One Ltd. and Toby Churchill Ltd. for supporting the - * rework for 2K page size chips - * - * TODO: - * Enable cached programming for 2k page size chips - * Check, if mtd->ecctype should be set to MTD_ECC_HW - * if we have HW ecc support. - * The AG-AND chips have nice features for speed improvement, - * which are not supported yet. Read / program 4 pages in one go. - * BBT table is not serialized, has to be fixed - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -/* Define default oob placement schemes for large and small page devices */ -static struct nand_ecclayout nand_oob_8 = { - .eccbytes = 3, - .eccpos = {0, 1, 2}, - .oobfree = { - {.offset = 3, - .length = 2}, - {.offset = 6, - .length = 2}} -}; - -static struct nand_ecclayout nand_oob_16 = { - .eccbytes = 6, - .eccpos = {0, 1, 2, 3, 6, 7}, - .oobfree = { - {.offset = 8, - . length = 8}} -}; - -static struct nand_ecclayout nand_oob_64 = { - .eccbytes = 24, - .eccpos = { - 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 61, 62, 63}, - .oobfree = { - {.offset = 2, - .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) -#define led_trigger_unregister_simple(x) do {} while(0) -#define led_trigger_event(x, y) do {} while(0) - -/* - * For devices which display every fart in the system on a separate LED. Is - * compiled away when LED support is disabled. - */ -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 - * - * Default read function for 8bit buswith - */ -static uint8_t nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - return readb(chip->IO_ADDR_R); -} - -/** - * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * @mtd: MTD device structure - * - * Default read function for 16bit buswith with - * endianess conversion - */ -static uint8_t nand_read_byte16(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - return (uint8_t) cpu_to_le16(readw(chip->IO_ADDR_R)); -} - -/** - * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure - * - * Default read function for 16bit buswith without - * endianess conversion - */ -static u16 nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - return readw(chip->IO_ADDR_R); -} - -/** - * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect - * - * Default select function for 1 chip devices. - */ -static void nand_select_chip(struct mtd_info *mtd, int chipnr) -{ - struct nand_chip *chip = mtd->priv; - - switch (chipnr) { - case -1: - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); - break; - case 0: - break; - default: - printf("%s: illegal chip number %d\n", 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 - * @len: number of bytes to read - * - * Default read function for 8bit buswith - */ -static void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - int i; - struct nand_chip *chip = mtd->priv; - - for (i = 0; i < len; i++) - buf[i] = readb(chip->IO_ADDR_R); -} - -/** - * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare - * - * Default verify function for 8bit buswith - */ -static int nand_verify_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++) - if (buf[i] != readb(chip->IO_ADDR_R)) - return -EFAULT; - return 0; -} - -/** - * 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 - * @len: number of bytes to read - * - * Default read function for 16bit buswith - */ -static void nand_read_buf16(struct mtd_info *mtd, 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++) - p[i] = readw(chip->IO_ADDR_R); -} - -/** - * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare - * - * Default verify function for 16bit buswith - */ -static int nand_verify_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++) - if (p[i] != readw(chip->IO_ADDR_R)) - return -EFAULT; - - return 0; -} - -/** - * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * - * Check, if the block is bad. - */ -static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) -{ - int page, chipnr, res = 0; - struct nand_chip *chip = mtd->priv; - u16 bad; - - page = (int)(ofs >> chip->page_shift) & chip->pagemask; - - if (getchip) { - chipnr = (int)(ofs >> chip->chip_shift); - - nand_get_device(chip, mtd, FL_READING); - - /* Select the NAND device */ - chip->select_chip(mtd, chipnr); - } - - if (chip->options & NAND_BUSWIDTH_16) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, - page); - bad = cpu_to_le16(chip->read_word(mtd)); - if (chip->badblockpos & 0x1) - bad >>= 8; - if ((bad & 0xFF) != 0xff) - res = 1; - } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); - if (chip->read_byte(mtd) != 0xff) - 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 - * @getchip: 0, if the chip is already selected - * @allowbbt: 1, if its allowed to access the bbt area - * - * 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 allowbbt) -{ - struct nand_chip *chip = mtd->priv; - - if (!chip->bbt) - return chip->block_bad(mtd, ofs, getchip); - - /* Return info from the table */ - return nand_isbad_bbt(mtd, ofs, allowbbt); -} - -/* - * Wait for the ready pin, after a command - * The timeout is catched later. - */ -void nand_wait_ready(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - uint64_t start = get_time_ns(); - - led_trigger_event(nand_led_trigger, LED_FULL); - /* wait until command is processed or timeout occures */ - do { - if (chip->dev_ready(mtd)) - break; - } while (!is_timeout(start, SECOND * 2)); - led_trigger_event(nand_led_trigger, LED_OFF); -} -EXPORT_SYMBOL(nand_wait_ready); - -/** - * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none - * - * Send command to NAND device. This function is used for small page - * devices (256/512 Bytes per page) - */ -static void nand_command(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd->priv; - int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; - - /* - * Write out the command to the device. - */ - if (command == NAND_CMD_SEQIN) { - int readcmd; - - if (column >= mtd->writesize) { - /* OOB area */ - column -= mtd->writesize; - readcmd = NAND_CMD_READOOB; - } else if (column < 256) { - /* First 256 bytes --> READ0 */ - readcmd = NAND_CMD_READ0; - } else { - column -= 256; - readcmd = NAND_CMD_READ1; - } - chip->cmd_ctrl(mtd, readcmd, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - chip->cmd_ctrl(mtd, command, ctrl); - - /* - * Address cycle, when necessary - */ - ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - chip->cmd_ctrl(mtd, page_addr >> 8, ctrl); - /* One more address cycle for devices > 32MiB */ - if (chip->chipsize > (32 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, ctrl); - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * program and erase have their own busy handlers - * status and sequential in needs no delay - */ - switch (command) { - - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_STATUS: - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_CTRL_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, - NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; - return; - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } - } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay(100); - - nand_wait_ready(mtd); -} - -/** - * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none - * - * Send command to NAND device. This is the version for the new large page - * devices We dont have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. - */ -static void nand_command_lp(struct mtd_info *mtd, unsigned int command, - int column, int page_addr) -{ - register struct nand_chip *chip = mtd->priv; - - /* Emulate NAND_CMD_READOOB */ - if (command == NAND_CMD_READOOB) { - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - /* Command latch cycle */ - chip->cmd_ctrl(mtd, command & 0xff, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - - if (column != -1 || page_addr != -1) { - int ctrl = NAND_CTRL_CHANGE | NAND_NCE | NAND_ALE; - - /* Serially input address */ - if (column != -1) { - /* Adjust columns for 16 bit buswidth */ - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - chip->cmd_ctrl(mtd, column, ctrl); - ctrl &= ~NAND_CTRL_CHANGE; - chip->cmd_ctrl(mtd, column >> 8, ctrl); - } - if (page_addr != -1) { - chip->cmd_ctrl(mtd, page_addr, ctrl); - chip->cmd_ctrl(mtd, page_addr >> 8, - NAND_NCE | NAND_ALE); - /* One more address cycle for devices > 128MiB */ - if (chip->chipsize > (128 << 20)) - chip->cmd_ctrl(mtd, page_addr >> 16, - NAND_NCE | NAND_ALE); - } - } - chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - - /* - * program and erase have their own busy handlers - * status, sequential in, and deplete1 need no delay - */ - switch (command) { - - case NAND_CMD_CACHEDPROG: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_RNDIN: - case NAND_CMD_STATUS: - case NAND_CMD_DEPLETE1: - return; - - /* - * read error status commands require only a short delay - */ - case NAND_CMD_STATUS_ERROR: - case NAND_CMD_STATUS_ERROR0: - case NAND_CMD_STATUS_ERROR1: - case NAND_CMD_STATUS_ERROR2: - case NAND_CMD_STATUS_ERROR3: - udelay(chip->chip_delay); - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - chip->cmd_ctrl(mtd, NAND_CMD_STATUS, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; - return; - - case NAND_CMD_RNDOUT: - /* No ready / busy check necessary */ - chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - return; - - case NAND_CMD_READ0: - chip->cmd_ctrl(mtd, NAND_CMD_READSTART, - NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); - chip->cmd_ctrl(mtd, NAND_CMD_NONE, - NAND_NCE | NAND_CTRL_CHANGE); - - /* This applies to read commands */ - default: - /* - * If we don't have access to the busy pin, we apply the given - * command delay - */ - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } - } - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay(100); - - nand_wait_ready(mtd); -} - -/** - * 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 - * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs - */ -static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) -{ - - uint64_t start = get_time_ns(); - uint64_t timeo; - int status, state = chip->state; - - if (state == FL_ERASING) - timeo = 400 * MSECOND; - else - timeo = 20 * MSECOND; - - led_trigger_event(nand_led_trigger, LED_FULL); - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay(100); - - if ((state == FL_ERASING) && (chip->options & NAND_IS_AND)) - chip->cmdfunc(mtd, NAND_CMD_STATUS_MULTI, -1, -1); - else - chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); - - while (!is_timeout(start, timeo)) { - if (chip->dev_ready) { - if (chip->dev_ready(mtd)) - break; - } else { - if (chip->read_byte(mtd) & NAND_STATUS_READY) - break; - } - } - led_trigger_event(nand_led_trigger, LED_OFF); - - status = (int)chip->read_byte(mtd); - return status; -} - -/** - * nand_read_page_raw - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - */ -static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf) -{ - chip->read_buf(mtd, buf, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return 0; -} - -/** - * 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 - */ -static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, - struct mtd_oob_ops *ops, size_t len) -{ - switch(ops->mode) { - - case MTD_OOB_PLACE: - case MTD_OOB_RAW: - memcpy(oob, chip->oob_poi + ops->ooboffs, len); - return oob + len; - - case MTD_OOB_AUTO: { - struct nand_oobfree *free = chip->ecc.layout->oobfree; - uint32_t boffs = 0, roffs = ops->ooboffs; - size_t bytes = 0; - - for(; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0 ? */ - if (unlikely(roffs)) { - if (roffs >= free->length) { - roffs -= free->length; - continue; - } - boffs = free->offset + roffs; - bytes = min_t(size_t, len, - (free->length - roffs)); - roffs = 0; - } else { - bytes = min_t(size_t, len, free->length); - boffs = free->offset; - } - memcpy(oob, chip->oob_poi + boffs, bytes); - oob += bytes; - } - return oob; - } - default: - BUG(); - } - return NULL; -} - -/** - * nand_do_read_ops - [Internal] Read data with ECC - * - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob ops structure - * - * Internal function. Called with chip held. - */ -static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - int chipnr, page, realpage, col, bytes, aligned; - struct nand_chip *chip = mtd->priv; - struct mtd_ecc_stats stats; - int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; - int sndcmd = 1; - int ret = 0; - uint32_t readlen = ops->len; - uint32_t oobreadlen = ops->ooblen; - uint8_t *bufpoi, *oob, *buf; - - stats = mtd->ecc_stats; - - chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - realpage = (int)(from >> chip->page_shift); - page = realpage & chip->pagemask; - - col = (int)(from & (mtd->writesize - 1)); - - buf = ops->datbuf; - oob = ops->oobbuf; - - while(1) { - bytes = min(mtd->writesize - col, readlen); - aligned = (bytes == mtd->writesize); - - /* Is the current page in the buffer ? */ - if (realpage != chip->pagebuf || oob) { - bufpoi = aligned ? buf : chip->buffers->databuf; - - if (likely(sndcmd)) { - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - sndcmd = 0; - } - - /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OOB_RAW)) - ret = chip->ecc.read_page_raw(mtd, chip, bufpoi); - else - ret = chip->ecc.read_page(mtd, chip, bufpoi); - if (ret < 0) - break; - - /* Transfer not aligned data */ - if (!aligned) { - chip->pagebuf = realpage; - memcpy(buf, chip->buffers->databuf + col, bytes); - } - - buf += bytes; - - if (unlikely(oob)) { - /* Raw mode does data:oob:data:oob */ - if (ops->mode != MTD_OOB_RAW) { - int toread = min(oobreadlen, - chip->ecc.layout->oobavail); - if (toread) { - oob = nand_transfer_oob(chip, - oob, ops, toread); - oobreadlen -= toread; - } - } else - buf = nand_transfer_oob(chip, - buf, ops, mtd->oobsize); - } - - if (!(chip->options & NAND_NO_READRDY)) { - /* - * Apply delay or wait for ready/busy pin. Do - * this before the AUTOINCR check, so no - * problems arise if a chip which does auto - * increment is marked as NOAUTOINCR by the - * board driver. - */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } - } else { - memcpy(buf, chip->buffers->databuf + col, bytes); - buf += bytes; - } - - readlen -= bytes; - - if (!readlen) - break; - - /* For subsequent reads align to page boundary. */ - col = 0; - /* Increment page address */ - 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); - } - - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ - if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) - sndcmd = 1; - } - - ops->retlen = ops->len - (size_t) readlen; - if (oob) - ops->oobretlen = ops->ooblen - oobreadlen; - - if (ret) - return ret; - - if (mtd->ecc_stats.failed - stats.failed) - return -EBADMSG; - - return 0; -} - -/** - * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data - * - * Get hold of the chip and call nand_do_read - */ -static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, uint8_t *buf) -{ - struct nand_chip *chip = mtd->priv; - int ret; - - /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) - return -EINVAL; - if (!len) - return 0; - - nand_get_device(chip, mtd, FL_READING); - - chip->ops.len = len; - chip->ops.datbuf = buf; - chip->ops.oobbuf = NULL; - - ret = nand_do_read_ops(mtd, from, &chip->ops); - - *retlen = chip->ops.retlen; - - nand_release_device(mtd); - - return ret; -} - -/** - * nand_read_oob_std - [REPLACABLE] the most common OOB data read function - * @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_std(struct mtd_info *mtd, struct nand_chip *chip, - int page, int sndcmd) -{ - if (sndcmd) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - sndcmd = 0; - } - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return sndcmd; -} - -/** - * 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 - * @ops: oob operations description structure - * - * NAND read out-of-band data from the spare area - */ -static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - int page, realpage, chipnr, sndcmd = 1; - struct nand_chip *chip = mtd->priv; - int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; - int readlen = ops->ooblen; - int len; - uint8_t *buf = ops->oobbuf; - - MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", - (unsigned long long)from, readlen); - - if (ops->mode == MTD_OOB_AUTO) - len = chip->ecc.layout->oobavail; - else - len = mtd->oobsize; - - if (unlikely(ops->ooboffs >= len)) { - MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " - "Attempt to start read outside oob\n"); - return -EINVAL; - } - - /* Do not allow reads past end of device */ - if (unlikely(from >= mtd->size || - ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) - - (from >> chip->page_shift)) * len)) { - MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: " - "Attempt read beyond end of device\n"); - return -EINVAL; - } - - chipnr = (int)(from >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Shift to get page */ - realpage = (int)(from >> chip->page_shift); - page = realpage & chip->pagemask; - - while(1) { - sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); - - len = min(len, readlen); - buf = nand_transfer_oob(chip, buf, ops, len); - - if (!(chip->options & NAND_NO_READRDY)) { - /* - * Apply delay or wait for ready/busy pin. Do this - * before the AUTOINCR check, so no problems arise if a - * chip which does auto increment is marked as - * NOAUTOINCR by the board driver. - */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } - - readlen -= len; - if (!readlen) - break; - - /* Increment page address */ - 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); - } - - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ - if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) - sndcmd = 1; - } - - ops->oobretlen = ops->ooblen; - return 0; -} - -/** - * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure - * - * NAND read data and/or out-of-band data - */ -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; - - /* Do not allow reads past end of device */ - if (ops->datbuf && (from + 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_READING); - - 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_read_oob(mtd, from, ops); - else - 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) -{ - /* Check for invalid offset */ - if (offs > mtd->size) - return -EINVAL; - - 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 - */ -static void nand_set_defaults(struct nand_chip *chip, int busw) -{ - /* check for proper chip_delay setup, set 20us if not */ - if (!chip->chip_delay) - chip->chip_delay = 20; - - /* check, if a user supplied command function given */ - if (chip->cmdfunc == NULL) - chip->cmdfunc = nand_command; - - /* check, if a user supplied wait function given */ - if (chip->waitfunc == NULL) - chip->waitfunc = nand_wait; - - if (!chip->select_chip) - chip->select_chip = nand_select_chip; - if (!chip->read_byte) - chip->read_byte = busw ? nand_read_byte16 : nand_read_byte; - if (!chip->read_word) - chip->read_word = nand_read_word; - if (!chip->block_bad) - chip->block_bad = nand_block_bad; - 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; - 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; - if (!chip->scan_bbt) - chip->scan_bbt = nand_default_bbt; - - if (!chip->controller) { - chip->controller = &chip->hwcontrol; - } - -} - -/* - * Get the flash and manufacturer id and lookup if the type is supported - */ -static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, - struct nand_chip *chip, - int busw, int *maf_id) -{ - struct nand_flash_dev *type = NULL; - int i, dev_id, maf_idx; - int tmp_id, tmp_manf; - - /* Select the device */ - chip->select_chip(mtd, 0); - - /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read manufacturer and device IDs */ - *maf_id = chip->read_byte(mtd); - dev_id = chip->read_byte(mtd); - - /* Try again to make sure, as some systems the bus-hold or other - * interface concerns can cause random data which looks like a - * possibly credible NAND flash to appear. If the two results do - * not match, ignore the device completely. - */ - - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read manufacturer and device IDs */ - - tmp_manf = chip->read_byte(mtd); - tmp_id = chip->read_byte(mtd); - - if (tmp_manf != *maf_id || tmp_id != dev_id) { - printk(KERN_INFO "%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, dev_id, tmp_manf, tmp_id); - return ERR_PTR(-ENODEV); - } - - /* Lookup the flash id */ - for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (dev_id == nand_flash_ids[i].id) { - type = &nand_flash_ids[i]; - break; - } - } - - if (!type) - return ERR_PTR(-ENODEV); - - if (!mtd->name) - mtd->name = type->name; - - chip->chipsize = type->chipsize << 20; - - /* Newer devices have all the information in additional id bytes */ - if (!type->pagesize) { - int extid; - /* The 3rd id byte holds MLC / multichip data */ - chip->cellinfo = chip->read_byte(mtd); - /* The 4th id byte is the important one */ - extid = chip->read_byte(mtd); - /* Calc pagesize */ - mtd->writesize = 1024 << (extid & 0x3); - extid >>= 2; - /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * (mtd->writesize >> 9); - extid >>= 2; - /* Calc blocksize. Blocksize is multiples of 64KiB */ - mtd->erasesize = (64 * 1024) << (extid & 0x03); - extid >>= 2; - /* Get buswidth information */ - busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - - } else { - /* - * Old devices have chip data hardcoded in the device id table - */ - mtd->erasesize = type->erasesize; - mtd->writesize = type->pagesize; - mtd->oobsize = mtd->writesize / 32; - busw = type->options & NAND_BUSWIDTH_16; - } - - /* Try to identify manufacturer */ - for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { - if (nand_manuf_ids[maf_idx].id == *maf_id) - break; - } - - /* - * Check, if buswidth is correct. Hardware drivers should set - * chip correct ! - */ - if (busw != (chip->options & NAND_BUSWIDTH_16)) { - printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - printk(KERN_WARNING "NAND bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); - return ERR_PTR(-EINVAL); - } - - /* Calculate the address shift from the page size */ - chip->page_shift = ffs(mtd->writesize) - 1; - /* Convert chipsize to number of pages per chip -1. */ - chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; - - chip->bbt_erase_shift = chip->phys_erase_shift = - ffs(mtd->erasesize) - 1; - chip->chip_shift = ffs(chip->chipsize) - 1; - - /* Set the bad block position */ - chip->badblockpos = mtd->writesize > 512 ? - NAND_LARGE_BADBLOCK_POS : NAND_SMALL_BADBLOCK_POS; - - /* Get chip options, preserve non chip based options */ - chip->options &= ~NAND_CHIPOPTIONS_MSK; - chip->options |= type->options & NAND_CHIPOPTIONS_MSK; - - /* - * Set chip as a default. Board drivers can override it, if necessary - */ - chip->options |= NAND_NO_AUTOINCR; - - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. - */ - if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) - chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; - - /* 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; - - /* Do not replace user supplied command function ! */ - if (mtd->writesize > 512 && chip->cmdfunc == nand_command) - chip->cmdfunc = nand_command_lp; - - printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id, - nand_manuf_ids[maf_idx].name, type->name); - - return type; -} - -/** - * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This is the first phase of the normal nand_scan() function. It - * reads the flash ID and sets up MTD fields accordingly. - * - * The mtd->owner field must be set to the module of the caller. - */ -int nand_scan_ident(struct mtd_info *mtd, int maxchips) -{ - int i, busw, nand_maf_id; - struct nand_chip *chip = mtd->priv; - struct nand_flash_dev *type; - - /* Get buswidth to select the correct functions */ - busw = chip->options & NAND_BUSWIDTH_16; - /* Set the default functions */ - nand_set_defaults(chip, busw); - - /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); - - if (IS_ERR(type)) { - printk(KERN_WARNING "No NAND device found!!!\n"); - chip->select_chip(mtd, -1); - return PTR_ERR(type); - } - - /* Check for a chip array */ - for (i = 1; i < maxchips; i++) { - chip->select_chip(mtd, i); - /* Send the command for reading device ID */ - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - /* Read manufacturer and device IDs */ - if (nand_maf_id != chip->read_byte(mtd) || - type->id != chip->read_byte(mtd)) - break; - } - if (i > 1) - printk(KERN_INFO "%d NAND chips detected\n", i); - - /* Store the number of chips and calc total size for mtd */ - chip->numchips = i; - mtd->size = i * chip->chipsize; - - return 0; -} - - -/** - * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This is the second phase of the normal nand_scan() function. It - * fills out all the uninitialized function pointers with the defaults - * and scans for a bad block table if appropriate. - */ -int nand_scan_tail(struct mtd_info *mtd) -{ - int i; - struct nand_chip *chip = mtd->priv; - - if (!(chip->options & NAND_OWN_BUFFERS)) - chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL); - if (!chip->buffers) - return -ENOMEM; - - /* Set the internal oob buffer location, just after the page data */ - chip->oob_poi = chip->buffers->databuf + mtd->writesize; - - /* - * If no default placement scheme is given, select an appropriate one - */ - if (!chip->ecc.layout) { - switch (mtd->oobsize) { - case 8: - chip->ecc.layout = &nand_oob_8; - break; - case 16: - chip->ecc.layout = &nand_oob_16; - break; - case 64: - chip->ecc.layout = &nand_oob_64; - break; - default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); - BUG(); - } - } - - if (!chip->write_page) - chip->write_page = nand_write_page; - - /* - * check ECC mode, default to software if 3byte/512byte hardware ECC is - * selected and we have 256 byte pagesize fallback to software ECC - */ - if (!chip->ecc.read_page_raw) - chip->ecc.read_page_raw = nand_read_page_raw; - if (!chip->ecc.write_page_raw) - chip->ecc.write_page_raw = nand_write_page_raw; - - switch (chip->ecc.mode) { - 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; - - 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; - - 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; - break; - - 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; - chip->ecc.write_page = nand_write_page_raw; - chip->ecc.read_oob = nand_read_oob_std; - chip->ecc.write_oob = nand_write_oob_std; - chip->ecc.size = mtd->writesize; - chip->ecc.bytes = 0; - break; - - default: - printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", - chip->ecc.mode); - BUG(); - } - - /* - * The number of bytes available for a client to place data into - * the out of band area - */ - chip->ecc.layout->oobavail = 0; - for (i = 0; chip->ecc.layout->oobfree[i].length; i++) - chip->ecc.layout->oobavail += - chip->ecc.layout->oobfree[i].length; - mtd->oobavail = chip->ecc.layout->oobavail; - - /* - * Set the number of read / write steps for one page depending on ECC - * mode - */ - chip->ecc.steps = mtd->writesize / chip->ecc.size; - if(chip->ecc.steps * chip->ecc.size != mtd->writesize) { - printk(KERN_WARNING "Invalid ecc parameters\n"); - BUG(); - } - chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; - - /* - * Allow subpage writes up to ecc.steps. Not possible for MLC - * FLASH. - */ - if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && - !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { - switch(chip->ecc.steps) { - case 2: - mtd->subpage_sft = 1; - break; - case 4: - case 8: - mtd->subpage_sft = 2; - break; - } - } - chip->subpagesize = mtd->writesize >> mtd->subpage_sft; - - /* Initialize state */ - chip->state = FL_READY; - - /* De-select the device */ - chip->select_chip(mtd, -1); - - /* Invalidate the pagebuffer reference */ - chip->pagebuf = -1; - - /* Fill in remaining MTD driver data */ - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH; - 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; - mtd->lock = NULL; - mtd->unlock = NULL; - mtd->suspend = nand_suspend; - mtd->resume = nand_resume; - mtd->block_isbad = nand_block_isbad; - mtd->block_markbad = nand_block_markbad; - - /* 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; - - /* Build bad block table */ - return chip->scan_bbt(mtd); -} - -/** - * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller - * - */ -int nand_scan(struct mtd_info *mtd, int maxchips) -{ - int ret; - - ret = nand_scan_ident(mtd, maxchips); - if (!ret) - ret = nand_scan_tail(mtd); - return ret; -} - -/** - * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd: MTD device structure -*/ -void nand_release(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - /* Deregister the device */ - del_mtd_device(mtd); - - /* Free bad block table memory */ - kfree(chip->bbt); - if (!(chip->options & NAND_OWN_BUFFERS)) - kfree(chip->buffers); -} - -EXPORT_SYMBOL(nand_scan); -EXPORT_SYMBOL(nand_scan_ident); -EXPORT_SYMBOL(nand_scan_tail); -EXPORT_SYMBOL(nand_release); - -#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/drivers/nand/nand_bbt.c b/drivers/nand/nand_bbt.c deleted file mode 100644 index 4a6bf39..0000000 --- a/drivers/nand/nand_bbt.c +++ /dev/null @@ -1,1224 +0,0 @@ -/* - * drivers/mtd/nand_bbt.c - * - * Overview: - * Bad block table support for the NAND driver - * - * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) - * - * $Id: nand_bbt.c,v 1.36 2005/11/07 11:14:30 gleixner Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Description: - * - * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the bbt descriptor(s). If a bbt is found - * then the contents are read and the memory based bbt is created. If a - * mirrored bbt is selected then the mirror is searched too and the - * versions are compared. If the mirror has a greater version number - * than the mirror bbt is used to build the memory based bbt. - * If the tables are not versioned, then we "or" the bad block information. - * If one of the bbt's is out of date or does not exist it is (re)created. - * If no bbt exists at all then the device is scanned for factory marked - * good / bad blocks and the bad block tables are created. - * - * For manufacturer created bbts like the one found on M-SYS DOC devices - * the bbt is searched and read but never created - * - * The autogenerated bad block table is located in the last good blocks - * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the oob area with an ident pattern and a version - * number which indicates which of both tables is more up to date. - * - * The table uses 2 bits per block - * 11b: block is good - * 00b: block is factory marked bad - * 01b, 10b: block is marked bad due to wear - * - * The memory bad block table uses the following scheme: - * 00b: block is good - * 01b: block is marked bad due to wear - * 10b: block is reserved (to protect the bbt area) - * 11b: block is factory marked bad - * - * Multichip devices like DOC store the bad block info per floor. - * - * Following assumptions are made: - * - bbts start at a page boundary, if autolocated on a block boundary - * - the space necessary for a bbt in FLASH does not exceed a block boundary - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef DOXYGEN_SHOULD_SKIP_THIS - -/** - * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @len: the length of buffer to search - * @paglen: the pagelength - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. - * If the SCAN_EMPTY option is set then check, if all bytes except the - * pattern area contain 0xff - * -*/ -static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) -{ - int i, end = 0; - uint8_t *p = buf; - - end = paglen + td->offs; - if (td->options & NAND_BBT_SCANEMPTY) { - for (i = 0; i < end; i++) { - if (p[i] != 0xff) - return -1; - } - } - p += end; - - /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - - if (td->options & NAND_BBT_SCANEMPTY) { - p += td->len; - end += td->len; - for (i = end; i < len; i++) { - if (*p++ != 0xff) - return -1; - } - } - return 0; -} - -/** - * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but - * no optional empty check - * -*/ -static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) -{ - int i; - uint8_t *p = buf; - - /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[td->offs + i] != td->pattern[i]) - return -1; - } - return 0; -} - -/** - * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure - * @buf: temporary buffer - * @page: the starting page - * @num: the number of bbt descriptors to read - * @bits: number of bits per block - * @offs: offset in the memory table - * @reserved_block_code: Pattern to identify reserved blocks - * - * Read the bad block table starting from page. - * - */ -static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, - int bits, int offs, int reserved_block_code) -{ - int res, i, j, act = 0; - struct nand_chip *this = mtd->priv; - size_t retlen, len, totlen; - loff_t from; - uint8_t msk = (uint8_t) ((1 << bits) - 1); - - totlen = (num * bits) >> 3; - from = ((loff_t) page) << this->page_shift; - - while (totlen) { - len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); - res = mtd->read(mtd, from, len, &retlen, buf); - if (res < 0) { - if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); - return res; - } - printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); - } - - /* Analyse data */ - for (i = 0; i < len; i++) { - uint8_t dat = buf[i]; - for (j = 0; j < 8; j += bits, act += 2) { - uint8_t tmp = (dat >> j) & msk; - if (tmp == msk) - continue; - if (reserved_block_code && (tmp == reserved_block_code)) { - printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); - mtd->ecc_stats.bbtblocks++; - continue; - } - /* Leave it for now, if its matured we can move this - * message to MTD_DEBUG_LEVEL0 */ - printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n", - ((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - /* Factory marked bad or worn out ? */ - if (tmp == 0) - this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); - else - this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06); - mtd->ecc_stats.badblocks++; - } - } - totlen -= len; - from += len; - } - return 0; -} - -/** - * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set - * - * Read the bad block table for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. -*/ -static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) -{ - struct nand_chip *this = mtd->priv; - int res = 0, i; - int bits; - - bits = td->options & NAND_BBT_NRBITS_MSK; - if (td->options & NAND_BBT_PERCHIP) { - int offs = 0; - for (i = 0; i < this->numchips; i++) { - if (chip == -1 || chip == i) - res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); - if (res) - return res; - offs += this->chipsize >> (this->bbt_erase_shift + 2); - } - } else { - res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); - if (res) - return res; - } - return 0; -} - -/* - * Scan read raw data from flash - */ -static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, - size_t len) -{ - struct mtd_oob_ops ops; - - ops.mode = MTD_OOB_RAW; - ops.ooboffs = 0; - ops.ooblen = mtd->oobsize; - ops.oobbuf = buf; - ops.datbuf = buf; - ops.len = len; - - return mtd->read_oob(mtd, offs, &ops); -} - -/* - * Scan write data with oob to flash - */ -static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, - uint8_t *buf, uint8_t *oob) -{ - struct mtd_oob_ops ops; - - ops.mode = MTD_OOB_PLACE; - ops.ooboffs = 0; - ops.ooblen = mtd->oobsize; - ops.datbuf = buf; - ops.oobbuf = oob; - ops.len = len; - - return mtd->write_oob(mtd, offs, &ops); -} - -/** - * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Read the bad block table(s) for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. - * -*/ -static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md) -{ - struct nand_chip *this = mtd->priv; - - /* Read the primary version, if available */ - if (td->options & NAND_BBT_VERSION) { - scan_read_raw(mtd, buf, td->pages[0] << this->page_shift, - mtd->writesize); - td->version[0] = buf[mtd->writesize + td->veroffs]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - td->pages[0], td->version[0]); - } - - /* Read the mirror version, if available */ - if (md && (md->options & NAND_BBT_VERSION)) { - scan_read_raw(mtd, buf, md->pages[0] << this->page_shift, - mtd->writesize); - md->version[0] = buf[mtd->writesize + md->veroffs]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - md->pages[0], md->version[0]); - } - return 1; -} - -/* - * Scan a given block full - */ -static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, - loff_t offs, uint8_t *buf, size_t readlen, - int scanlen, int len) -{ - int ret, j; - - ret = scan_read_raw(mtd, buf, offs, readlen); - if (ret) - return ret; - - for (j = 0; j < len; j++, buf += scanlen) { - if (check_pattern(buf, scanlen, mtd->writesize, bd)) - return 1; - } - return 0; -} - -/* - * Scan a given block partially - */ -static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, - loff_t offs, uint8_t *buf, int len) -{ - struct mtd_oob_ops ops; - int j, ret; - - ops.ooblen = mtd->oobsize; - ops.oobbuf = buf; - ops.ooboffs = 0; - ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; - - for (j = 0; j < len; j++) { - /* - * Read the full oob until read_oob is fixed to - * handle single byte reads for 16 bit - * buswidth - */ - ret = mtd->read_oob(mtd, offs, &ops); - if (ret) - return ret; - - if (check_short_pattern(buf, bd)) - return 1; - - offs += mtd->writesize; - } - return 0; -} - -/** - * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * @chip: create the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set - * - * Create a bad block table by scanning the device - * for the given good/bad block identify pattern - */ -static int create_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *bd, int chip) -{ - struct nand_chip *this = mtd->priv; - int i, numblocks, len, scanlen; - int startblock; - loff_t from; - size_t readlen; - - printk(KERN_INFO "Scanning device for bad blocks\n"); - - if (bd->options & NAND_BBT_SCANALLPAGES) - len = 1 << (this->bbt_erase_shift - this->page_shift); - else { - if (bd->options & NAND_BBT_SCAN2NDPAGE) - len = 2; - else - len = 1; - } - - if (!(bd->options & NAND_BBT_SCANEMPTY)) { - /* We need only read few bytes from the OOB area */ - scanlen = 0; - readlen = bd->len; - } else { - /* Full page content should be read */ - scanlen = mtd->writesize + mtd->oobsize; - readlen = len * mtd->writesize; - } - - if (chip == -1) { - /* Note that numblocks is 2 * (real numblocks) here, see i+=2 - * below as it makes shifting and masking less painful */ - numblocks = mtd->size >> (this->bbt_erase_shift - 1); - startblock = 0; - from = 0; - } else { - if (chip >= this->numchips) { - printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", - chip + 1, this->numchips); - return -EINVAL; - } - numblocks = this->chipsize >> (this->bbt_erase_shift - 1); - startblock = chip * numblocks; - numblocks += startblock; - from = startblock << (this->bbt_erase_shift - 1); - } - - for (i = startblock; i < numblocks;) { - int ret; - - if (bd->options & NAND_BBT_SCANALLPAGES) - ret = scan_block_full(mtd, bd, from, buf, readlen, - scanlen, len); - else - ret = scan_block_fast(mtd, bd, from, buf, len); - - if (ret < 0) - return ret; - - if (ret) { - this->bbt[i >> 3] |= 0x03 << (i & 0x6); - printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n", - i >> 1, (unsigned int)from); - mtd->ecc_stats.badblocks++; - } - - i += 2; - from += (1 << this->bbt_erase_shift); - } - return 0; -} - -/** - * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * - * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of - * the device downwards. The search starts always at the start of a - * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched - * for a bbt, which contains the bad block information of this chip. - * This is necessary to provide support for certain DOC devices. - * - * The bbt ident pattern resides in the oob area of the first page - * in a block. - */ -static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) -{ - struct nand_chip *this = mtd->priv; - int i, chips; - int bits, startblock, block, dir; - int scanlen = mtd->writesize + mtd->oobsize; - int bbtblocks; - int blocktopage = this->bbt_erase_shift - this->page_shift; - - /* Search direction top -> down ? */ - if (td->options & NAND_BBT_LASTBLOCK) { - startblock = (mtd->size >> this->bbt_erase_shift) - 1; - dir = -1; - } else { - startblock = 0; - dir = 1; - } - - /* Do we have a bbt per chip ? */ - if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - bbtblocks = this->chipsize >> this->bbt_erase_shift; - startblock &= bbtblocks - 1; - } else { - chips = 1; - bbtblocks = mtd->size >> this->bbt_erase_shift; - } - - /* Number of bits for each erase block in the bbt */ - bits = td->options & NAND_BBT_NRBITS_MSK; - - for (i = 0; i < chips; i++) { - /* Reset version information */ - td->version[i] = 0; - td->pages[i] = -1; - /* Scan the maximum number of blocks */ - for (block = 0; block < td->maxblocks; block++) { - - int actblock = startblock + dir * block; - loff_t offs = actblock << this->bbt_erase_shift; - - /* Read first page */ - scan_read_raw(mtd, buf, offs, mtd->writesize); - if (!check_pattern(buf, scanlen, mtd->writesize, td)) { - td->pages[i] = actblock << blocktopage; - if (td->options & NAND_BBT_VERSION) { - td->version[i] = buf[mtd->writesize + td->veroffs]; - } - break; - } - } - startblock += this->chipsize >> this->bbt_erase_shift; - } - /* Check, if we found a bbt for each requested chip */ - for (i = 0; i < chips; i++) { - if (td->pages[i] == -1) - printk(KERN_WARNING "Bad block table not found for chip %d\n", i); - else - printk(KERN_DEBUG "Bad block table found at page %d, version 0x%02X\n", td->pages[i], - td->version[i]); - } - return 0; -} - -/** - * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Search and read the bad block table(s) -*/ -static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) -{ - /* Search the primary table */ - search_bbt(mtd, buf, td); - - /* Search the mirror table */ - if (md) - search_bbt(mtd, buf, md); - - /* Force result check */ - return 1; -} - -/** - * write_bbt - [GENERIC] (Re)write the bad block table - * - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * @chipsel: selector for a specific chip, -1 for all - * - * (Re)write the bad block table - * -*/ -static int write_bbt(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md, - int chipsel) -{ - struct nand_chip *this = mtd->priv; - struct erase_info einfo; - int i, j, res, chip = 0; - int bits, startblock, dir, page, offs, numblocks, sft, sftmsk; - int nrchips, bbtoffs, pageoffs, ooboffs; - uint8_t msk[4]; - uint8_t rcode = td->reserved_block_code; - size_t retlen, len = 0; - loff_t to; - struct mtd_oob_ops ops; - - ops.ooblen = mtd->oobsize; - ops.ooboffs = 0; - ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; - - if (!rcode) - rcode = 0xff; - /* Write bad block table per chip rather than per device ? */ - if (td->options & NAND_BBT_PERCHIP) { - numblocks = (int)(this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip ? */ - if (chipsel == -1) { - nrchips = this->numchips; - } else { - nrchips = chipsel + 1; - chip = chipsel; - } - } else { - numblocks = (int)(mtd->size >> this->bbt_erase_shift); - nrchips = 1; - } - - /* Loop through the chips */ - for (; chip < nrchips; chip++) { - - /* There was already a version of the table, reuse the page - * This applies for absolute placement too, as we have the - * page nr. in td->pages. - */ - if (td->pages[chip] != -1) { - page = td->pages[chip]; - goto write; - } - - /* Automatic placement of the bad block table */ - /* Search direction top -> down ? */ - if (td->options & NAND_BBT_LASTBLOCK) { - startblock = numblocks * (chip + 1) - 1; - dir = -1; - } else { - startblock = chip * numblocks; - dir = 1; - } - - for (i = 0; i < td->maxblocks; i++) { - int block = startblock + dir * i; - /* Check, if the block is bad */ - switch ((this->bbt[block >> 2] >> - (2 * (block & 0x03))) & 0x03) { - case 0x01: - case 0x03: - continue; - } - page = block << - (this->bbt_erase_shift - this->page_shift); - /* Check, if the block is used by the mirror table */ - if (!md || md->pages[chip] != page) - goto write; - } - printk(KERN_ERR "No space left to write bad block table\n"); - return -ENOSPC; - write: - - /* Set up shift count and masks for the flash table */ - bits = td->options & NAND_BBT_NRBITS_MSK; - msk[2] = ~rcode; - switch (bits) { - case 1: sft = 3; sftmsk = 0x07; msk[0] = 0x00; msk[1] = 0x01; - msk[3] = 0x01; - break; - case 2: sft = 2; sftmsk = 0x06; msk[0] = 0x00; msk[1] = 0x01; - msk[3] = 0x03; - break; - case 4: sft = 1; sftmsk = 0x04; msk[0] = 0x00; msk[1] = 0x0C; - msk[3] = 0x0f; - break; - case 8: sft = 0; sftmsk = 0x00; msk[0] = 0x00; msk[1] = 0x0F; - msk[3] = 0xff; - break; - default: return -EINVAL; - } - - bbtoffs = chip * (numblocks >> 2); - - to = ((loff_t) page) << this->page_shift; - - /* Must we save the block contents ? */ - if (td->options & NAND_BBT_SAVECONTENT) { - /* Make it block aligned */ - to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); - len = 1 << this->bbt_erase_shift; - res = mtd->read(mtd, to, len, &retlen, buf); - if (res < 0) { - if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error " - "reading block for writing " - "the bad block table\n"); - return res; - } - printk(KERN_WARNING "nand_bbt: ECC error " - "while reading block for writing " - "bad block table\n"); - } - /* Read oob data */ - ops.ooblen = (len >> this->page_shift) * mtd->oobsize; - ops.oobbuf = &buf[len]; - res = mtd->read_oob(mtd, to + mtd->writesize, &ops); - if (res < 0 || ops.oobretlen != ops.ooblen) - goto outerr; - - /* Calc the byte offset in the buffer */ - pageoffs = page - (int)(to >> this->page_shift); - offs = pageoffs << this->page_shift; - /* Preset the bbt area with 0xff */ - memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); - ooboffs = len + (pageoffs * mtd->oobsize); - - } else { - /* Calc length */ - len = (size_t) (numblocks >> sft); - /* Make it page aligned ! */ - len = (len + (mtd->writesize - 1)) & - ~(mtd->writesize - 1); - /* Preset the buffer with 0xff */ - memset(buf, 0xff, len + - (len >> this->page_shift)* mtd->oobsize); - offs = 0; - ooboffs = len; - /* Pattern is located in oob area of first page */ - memcpy(&buf[ooboffs + td->offs], td->pattern, td->len); - } - - if (td->options & NAND_BBT_VERSION) - buf[ooboffs + td->veroffs] = td->version[chip]; - - /* walk through the memory table */ - for (i = 0; i < numblocks;) { - uint8_t dat; - dat = this->bbt[bbtoffs + (i >> 2)]; - for (j = 0; j < 4; j++, i++) { - int sftcnt = (i << (3 - sft)) & sftmsk; - /* Do not store the reserved bbt blocks ! */ - buf[offs + (i >> sft)] &= - ~(msk[dat & 0x03] << sftcnt); - dat >>= 2; - } - } - - memset(&einfo, 0, sizeof(einfo)); - einfo.mtd = mtd; - einfo.addr = (unsigned long)to; - einfo.len = 1 << this->bbt_erase_shift; - res = nand_erase_nand(mtd, &einfo, 1); - if (res < 0) - goto outerr; - - res = scan_write_bbt(mtd, to, len, buf, &buf[len]); - if (res < 0) - goto outerr; - - printk(KERN_DEBUG "Bad block table written to 0x%08x, version " - "0x%02X\n", (unsigned int)to, td->version[chip]); - - /* Mark it as used */ - td->pages[chip] = page; - } - return 0; - - outerr: - printk(KERN_WARNING - "nand_bbt: Error while writing bad block table %d\n", res); - return res; -} - -/** - * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function creates a memory based bbt by scanning the device - * for manufacturer / software marked good / bad blocks -*/ -static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd->priv; - - bd->options &= ~NAND_BBT_SCANEMPTY; - return create_bbt(mtd, this->buffers->databuf, bd, -1); -} - -/** - * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * - * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if necessary - * Creation is necessary if no bbt was found for the chip/device - * Update is necessary if one of the tables is missing or the - * version nr. of one table is less than the other -*/ -static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) -{ - int i, chips, writeops, chipsel, res; - struct nand_chip *this = mtd->priv; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - struct nand_bbt_descr *rd, *rd2; - - /* Do we have a bbt per chip ? */ - if (td->options & NAND_BBT_PERCHIP) - chips = this->numchips; - else - chips = 1; - - for (i = 0; i < chips; i++) { - writeops = 0; - rd = NULL; - rd2 = NULL; - /* Per chip or per device ? */ - chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table avilable ? */ - if (md) { - if (td->pages[i] == -1 && md->pages[i] == -1) { - writeops = 0x03; - goto create; - } - - if (td->pages[i] == -1) { - rd = md; - td->version[i] = md->version[i]; - writeops = 1; - goto writecheck; - } - - if (md->pages[i] == -1) { - rd = td; - md->version[i] = td->version[i]; - writeops = 2; - goto writecheck; - } - - if (td->version[i] == md->version[i]) { - rd = td; - if (!(td->options & NAND_BBT_VERSION)) - rd2 = md; - goto writecheck; - } - - if (((int8_t) (td->version[i] - md->version[i])) > 0) { - rd = td; - md->version[i] = td->version[i]; - writeops = 2; - } else { - rd = md; - td->version[i] = md->version[i]; - writeops = 1; - } - - goto writecheck; - - } else { - if (td->pages[i] == -1) { - writeops = 0x01; - goto create; - } - rd = td; - goto writecheck; - } - create: - /* Create the bad block table by scanning the device ? */ - if (!(td->options & NAND_BBT_CREATE)) - continue; - - /* Create the table in memory by scanning the chip(s) */ - create_bbt(mtd, buf, bd, chipsel); - - td->version[i] = 1; - if (md) - md->version[i] = 1; - writecheck: - /* read back first ? */ - if (rd) - read_abs_bbt(mtd, buf, rd, chipsel); - /* If they weren't versioned, read both. */ - if (rd2) - read_abs_bbt(mtd, buf, rd2, chipsel); - - /* Write the bad block table to the device ? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - return res; - } - - /* Write the mirror bad block table to the device ? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - if (res < 0) - return res; - } - } - return 0; -} - -/** - * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure - * @td: bad block table descriptor - * - * The bad block table regions are marked as "bad" to prevent - * accidental erasures / writes. The regions are identified by - * the mark 0x02. -*/ -static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) -{ - struct nand_chip *this = mtd->priv; - int i, j, chips, block, nrblocks, update; - uint8_t oldval, newval; - - /* Do we have a bbt per chip ? */ - if (td->options & NAND_BBT_PERCHIP) { - chips = this->numchips; - nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); - } else { - chips = 1; - nrblocks = (int)(mtd->size >> this->bbt_erase_shift); - } - - for (i = 0; i < chips; i++) { - if ((td->options & NAND_BBT_ABSPAGE) || - !(td->options & NAND_BBT_WRITE)) { - if (td->pages[i] == -1) - continue; - block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift); - block <<= 1; - oldval = this->bbt[(block >> 3)]; - newval = oldval | (0x2 << (block & 0x06)); - this->bbt[(block >> 3)] = newval; - if ((oldval != newval) && td->reserved_block_code) - nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1)); - continue; - } - update = 0; - if (td->options & NAND_BBT_LASTBLOCK) - block = ((i + 1) * nrblocks) - td->maxblocks; - else - block = i * nrblocks; - block <<= 1; - for (j = 0; j < td->maxblocks; j++) { - oldval = this->bbt[(block >> 3)]; - newval = oldval | (0x2 << (block & 0x06)); - this->bbt[(block >> 3)] = newval; - if (oldval != newval) - update = 1; - block += 2; - } - /* If we want reserved blocks to be recorded to flash, and some - new ones have been marked, then we need to update the stored - bbts. This should only happen once. */ - if (update && td->reserved_block_code) - nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1)); - } -} - -/** - * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already - * available. If not it scans the device for manufacturer - * marked good / bad blocks and writes the bad block table(s) to - * the selected place. - * - * The bad block table memory is allocated here. It must be freed - * by calling the nand_free_bbt function. - * -*/ -int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) -{ - struct nand_chip *this = mtd->priv; - int len, res = 0; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - len = mtd->size >> (this->bbt_erase_shift + 2); - /* Allocate memory (2bit per block) and clear the memory bad block table */ - this->bbt = kzalloc(len, GFP_KERNEL); - if (!this->bbt) { - printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); - return -ENOMEM; - } - - /* If no primary table decriptor is given, scan the device - * to build a memory based bad block table - */ - if (!td) { - if ((res = nand_memory_bbt(mtd, bd))) { - printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); - kfree(this->bbt); - this->bbt = NULL; - } - return res; - } - - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = vmalloc(len); - if (!buf) { - printk(KERN_ERR "nand_bbt: Out of memory\n"); - kfree(this->bbt); - this->bbt = NULL; - return -ENOMEM; - } - - /* Is the bbt at a given page ? */ - if (td->options & NAND_BBT_ABSPAGE) { - res = read_abs_bbts(mtd, buf, td, md); - } else { - /* Search the bad block table using a pattern in oob */ - res = search_read_bbts(mtd, buf, td, md); - } - - if (res) - res = check_create(mtd, buf, bd); - - /* Prevent the bbt regions from erasing / writing */ - mark_bbt_region(mtd, td); - if (md) - mark_bbt_region(mtd, md); - - vfree(buf); - return res; -} - -/** - * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block - * - * The function updates the bad block table(s) -*/ -int nand_update_bbt(struct mtd_info *mtd, loff_t offs) -{ - struct nand_chip *this = mtd->priv; - int len, res = 0, writeops = 0; - int chip, chipsel; - uint8_t *buf; - struct nand_bbt_descr *td = this->bbt_td; - struct nand_bbt_descr *md = this->bbt_md; - - if (!this->bbt || !td) - return -EINVAL; - - len = mtd->size >> (this->bbt_erase_shift + 2); - /* Allocate a temporary buffer for one eraseblock incl. oob */ - len = (1 << this->bbt_erase_shift); - len += (len >> this->page_shift) * mtd->oobsize; - buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "nand_update_bbt: Out of memory\n"); - return -ENOMEM; - } - - writeops = md != NULL ? 0x03 : 0x01; - - /* Do we have a bbt per chip ? */ - if (td->options & NAND_BBT_PERCHIP) { - chip = (int)(offs >> this->chip_shift); - chipsel = chip; - } else { - chip = 0; - chipsel = -1; - } - - td->version[chip]++; - if (md) - md->version[chip]++; - - /* Write the bad block table to the device ? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, td, md, chipsel); - if (res < 0) - goto out; - } - /* Write the mirror bad block table to the device ? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { - res = write_bbt(mtd, buf, md, td, chipsel); - } - - out: - kfree(buf); - return res; -} - -/* 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, 0xff }; - -static struct nand_bbt_descr smallpage_memorybased = { - .options = NAND_BBT_SCAN2NDPAGE, - .offs = 5, - .len = 1, - .pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr largepage_memorybased = { - .options = 0, - .offs = 0, - .len = 2, - .pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr smallpage_flashbased = { - .options = NAND_BBT_SCAN2NDPAGE, - .offs = 5, - .len = 1, - .pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr largepage_flashbased = { - .options = NAND_BBT_SCAN2NDPAGE, - .offs = 0, - .len = 2, - .pattern = scan_ff_pattern -}; - -static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; - -static struct nand_bbt_descr agand_flashbased = { - .options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES, - .offs = 0x20, - .len = 6, - .pattern = scan_agand_pattern -}; - -/* Generic flash bbt decriptors -*/ -static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; -static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = 4, - .pattern = bbt_pattern -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 8, - .len = 4, - .veroffs = 12, - .maxblocks = 4, - .pattern = mirror_pattern -}; - -/** - * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure - * - * This function selects the default bad block table - * support for the device and calls the nand_scan_bbt function - * -*/ -int nand_default_bbt(struct mtd_info *mtd) -{ - struct nand_chip *this = mtd->priv; - - /* Default for AG-AND. We must use a flash based - * bad block table as the devices have factory marked - * _good_ blocks. Erasing those blocks leads to loss - * of the good / bad information, so we _must_ store - * this information in a good / bad table during - * startup - */ - if (this->options & NAND_IS_AND) { - /* Use the default pattern descriptors */ - if (!this->bbt_td) { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; - } - this->options |= NAND_USE_FLASH_BBT; - return nand_scan_bbt(mtd, &agand_flashbased); - } - - /* Is a flash based bad block table requested ? */ - if (this->options & NAND_USE_FLASH_BBT) { - /* Use the default pattern descriptors */ - if (!this->bbt_td) { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; - } - if (!this->badblock_pattern) { - this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; - } - } else { - this->bbt_td = NULL; - this->bbt_md = NULL; - if (!this->badblock_pattern) { - this->badblock_pattern = (mtd->writesize > 512) ? - &largepage_memorybased : &smallpage_memorybased; - } - } - return nand_scan_bbt(mtd, this->badblock_pattern); -} - -/** - * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure - * @offs: offset in the device - * @allowbbt: allow access to bad block table region - * -*/ -int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) -{ - struct nand_chip *this = mtd->priv; - int block; - uint8_t res; - - /* Get block number * 2 */ - block = (int)(offs >> (this->bbt_erase_shift - 1)); - res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; - - MTD_DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", - (unsigned int)offs, block >> 1, res); - - switch ((int)res) { - case 0x00: - return 0; - case 0x01: - return 1; - case 0x02: - return allowbbt ? 0 : 1; - } - return 1; -} - -EXPORT_SYMBOL(nand_scan_bbt); -EXPORT_SYMBOL(nand_default_bbt); - -#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/drivers/nand/nand_ecc.c b/drivers/nand/nand_ecc.c deleted file mode 100644 index 266d573..0000000 --- a/drivers/nand/nand_ecc.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * This file contains an ECC algorithm from Toshiba that detects and - * corrects 1 bit errors in a 256 byte block of data. - * - * drivers/mtd/nand/nand_ecc.c - * - * Copyright (C) 2000-2004 Steven J. Hill (sjhill@realitydiluted.com) - * Toshiba America Electronics Components, Inc. - * - * Copyright (C) 2006 Thomas Gleixner - * - * $Id: nand_ecc.c,v 1.15 2005/11/07 11:14:30 gleixner Exp $ - * - * This file 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 or (at your option) any - * later version. - * - * This file 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 file; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * As a special exception, if other files instantiate templates or use - * macros or inline functions from these files, or you compile these - * files and link them with other works to produce a work based on these - * files, these files do not by themselves cause the resulting work to be - * covered by the GNU General Public License. However the source code for - * these files must still be made available in accordance with section (3) - * of the GNU General Public License. - * - * This exception does not invalidate any other reasons why a work based on - * this file might be covered by the GNU General Public License. - */ - -#include -#include -#include -#include - -/* - * Pre-calculated 256-way 1 byte column parity - */ -static const u_char nand_ecc_precalc_table[] = { - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x6a, 0x3f, 0x3c, 0x69, 0x33, 0x66, 0x65, 0x30, 0x30, 0x65, 0x66, 0x33, 0x69, 0x3c, 0x3f, 0x6a, - 0x0f, 0x5a, 0x59, 0x0c, 0x56, 0x03, 0x00, 0x55, 0x55, 0x00, 0x03, 0x56, 0x0c, 0x59, 0x5a, 0x0f, - 0x0c, 0x59, 0x5a, 0x0f, 0x55, 0x00, 0x03, 0x56, 0x56, 0x03, 0x00, 0x55, 0x0f, 0x5a, 0x59, 0x0c, - 0x69, 0x3c, 0x3f, 0x6a, 0x30, 0x65, 0x66, 0x33, 0x33, 0x66, 0x65, 0x30, 0x6a, 0x3f, 0x3c, 0x69, - 0x03, 0x56, 0x55, 0x00, 0x5a, 0x0f, 0x0c, 0x59, 0x59, 0x0c, 0x0f, 0x5a, 0x00, 0x55, 0x56, 0x03, - 0x66, 0x33, 0x30, 0x65, 0x3f, 0x6a, 0x69, 0x3c, 0x3c, 0x69, 0x6a, 0x3f, 0x65, 0x30, 0x33, 0x66, - 0x65, 0x30, 0x33, 0x66, 0x3c, 0x69, 0x6a, 0x3f, 0x3f, 0x6a, 0x69, 0x3c, 0x66, 0x33, 0x30, 0x65, - 0x00, 0x55, 0x56, 0x03, 0x59, 0x0c, 0x0f, 0x5a, 0x5a, 0x0f, 0x0c, 0x59, 0x03, 0x56, 0x55, 0x00 -}; - -/** - * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256-byte block - * @mtd: MTD block structure - * @dat: raw data - * @ecc_code: buffer for ECC - */ -int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, - u_char *ecc_code) -{ - uint8_t idx, reg1, reg2, reg3, tmp1, tmp2; - int i; - - /* Initialize variables */ - reg1 = reg2 = reg3 = 0; - - /* Build up column parity */ - for(i = 0; i < 256; i++) { - /* Get CP0 - CP5 from table */ - idx = nand_ecc_precalc_table[*dat++]; - reg1 ^= (idx & 0x3f); - - /* All bit XOR = 1 ? */ - if (idx & 0x40) { - reg3 ^= (uint8_t) i; - reg2 ^= ~((uint8_t) i); - } - } - - /* Create non-inverted ECC code from line parity */ - tmp1 = (reg3 & 0x80) >> 0; /* B7 -> B7 */ - tmp1 |= (reg2 & 0x80) >> 1; /* B7 -> B6 */ - tmp1 |= (reg3 & 0x40) >> 1; /* B6 -> B5 */ - tmp1 |= (reg2 & 0x40) >> 2; /* B6 -> B4 */ - tmp1 |= (reg3 & 0x20) >> 2; /* B5 -> B3 */ - tmp1 |= (reg2 & 0x20) >> 3; /* B5 -> B2 */ - tmp1 |= (reg3 & 0x10) >> 3; /* B4 -> B1 */ - tmp1 |= (reg2 & 0x10) >> 4; /* B4 -> B0 */ - - tmp2 = (reg3 & 0x08) << 4; /* B3 -> B7 */ - tmp2 |= (reg2 & 0x08) << 3; /* B3 -> B6 */ - tmp2 |= (reg3 & 0x04) << 3; /* B2 -> B5 */ - tmp2 |= (reg2 & 0x04) << 2; /* B2 -> B4 */ - tmp2 |= (reg3 & 0x02) << 2; /* B1 -> B3 */ - tmp2 |= (reg2 & 0x02) << 1; /* B1 -> B2 */ - tmp2 |= (reg3 & 0x01) << 1; /* B0 -> B1 */ - tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */ - - /* Calculate final ECC code */ -#ifdef CONFIG_MTD_NAND_ECC_SMC - ecc_code[0] = ~tmp2; - ecc_code[1] = ~tmp1; -#else - ecc_code[0] = ~tmp1; - ecc_code[1] = ~tmp2; -#endif - ecc_code[2] = ((~reg1) << 2) | 0x03; - - return 0; -} -EXPORT_SYMBOL(nand_calculate_ecc); - -static inline int countbits(uint32_t byte) -{ - int res = 0; - - for (;byte; byte >>= 1) - res += byte & 0x01; - return res; -} - -/** - * nand_correct_data - [NAND Interface] Detect and correct bit error(s) - * @mtd: MTD block structure - * @dat: raw data read from the chip - * @read_ecc: ECC from the chip - * @calc_ecc: the ECC calculated from raw data - * - * Detect and correct a 1 bit error for 256 byte block - */ -int nand_correct_data(struct mtd_info *mtd, u_char *dat, - u_char *read_ecc, u_char *calc_ecc) -{ - uint8_t s0, s1, s2; - -#ifdef CONFIG_MTD_NAND_ECC_SMC - s0 = calc_ecc[0] ^ read_ecc[0]; - s1 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#else - s1 = calc_ecc[0] ^ read_ecc[0]; - s0 = calc_ecc[1] ^ read_ecc[1]; - s2 = calc_ecc[2] ^ read_ecc[2]; -#endif - if ((s0 | s1 | s2) == 0) - return 0; - - /* Check for a single bit error */ - if( ((s0 ^ (s0 >> 1)) & 0x55) == 0x55 && - ((s1 ^ (s1 >> 1)) & 0x55) == 0x55 && - ((s2 ^ (s2 >> 1)) & 0x54) == 0x54) { - - uint32_t byteoffs, bitnum; - - byteoffs = (s1 << 0) & 0x80; - byteoffs |= (s1 << 1) & 0x40; - byteoffs |= (s1 << 2) & 0x20; - byteoffs |= (s1 << 3) & 0x10; - - byteoffs |= (s0 >> 4) & 0x08; - byteoffs |= (s0 >> 3) & 0x04; - byteoffs |= (s0 >> 2) & 0x02; - byteoffs |= (s0 >> 1) & 0x01; - - bitnum = (s2 >> 5) & 0x04; - bitnum |= (s2 >> 4) & 0x02; - bitnum |= (s2 >> 3) & 0x01; - - dat[byteoffs] ^= (1 << bitnum); - - return 1; - } - - if(countbits(s0 | ((uint32_t)s1 << 8) | ((uint32_t)s2 <<16)) == 1) - return 1; - - return -EBADMSG; -} -EXPORT_SYMBOL(nand_correct_data); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill "); -MODULE_DESCRIPTION("Generic NAND ECC support"); diff --git a/drivers/nand/nand_ids.c b/drivers/nand/nand_ids.c deleted file mode 100644 index f95975c..0000000 --- a/drivers/nand/nand_ids.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * drivers/mtd/nandids.c - * - * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * $Id: nand_ids.c,v 1.16 2005/11/07 11:14:31 gleixner Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#include -#include -/* -* Chip ID list -* -* Name. ID code, pagesize, chipsize in MegaByte, eraseblock size, -* options -* -* Pagesize; 0, 256, 512 -* 0 get this information from the extended chip ID -+ 256 256 Byte page size -* 512 512 Byte page size -*/ -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}, -#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}, - - {"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}, - - {"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}, - - {"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}, - - {"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0}, - - /* - * These are the new chips with large page size. The pagesize and the - * erasesize is determined from the extended id bytes - */ -#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR) -#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}, - - /* 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}, - - /* 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}, - - /* 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}, - - /* 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}, - - /* 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}, - - /* - * Renesas AND 1 Gigabit. Those chips do not support extended id and - * have a strange page/block layout ! The chosen minimum erasesize is - * 4 * 2 * 2048 = 16384 Byte, as those chips have an array of 4 page - * planes 1 block = 2 pages, but due to plane arrangement the blocks - * 0-3 consists of page 0 + 4,1 + 5, 2 + 6, 3 + 7 Anyway JFFS2 would - * increase the eraseblock size so we chose a combined one which can be - * 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, - NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | - BBT_AUTO_REFRESH - }, - - {NULL,} -}; - -/* -* 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"}, - {0x0, "Unknown"} -}; - -EXPORT_SYMBOL(nand_manuf_ids); -EXPORT_SYMBOL(nand_flash_ids); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Thomas Gleixner "); -MODULE_DESCRIPTION("Nand device & manufacturer IDs"); diff --git a/drivers/nand/nand_imx.c b/drivers/nand/nand_imx.c deleted file mode 100644 index 5454e32..0000000 --- a/drivers/nand/nand_imx.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* - * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved. - * Copyright 2008 Sascha Hauer, Pengutronix - */ - -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html - */ - -/* - * MX21 Hardware contains a bug which causes HW ECC to fail for two - * consecutive read pages containing 1bit Errors (See MX21 Chip Erata, - * Erratum 16). Use software ECC for this chip. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DVR_VER "2.0" - -#define nfc_is_v21() (cpu_is_mx25() || cpu_is_mx35()) -#define nfc_is_v1() (cpu_is_mx31() || cpu_is_mx27() || cpu_is_mx21()) - -/* - * Addresses for NFC registers - */ -#define NFC_BUF_SIZE 0xE00 -#define NFC_BUF_ADDR 0xE04 -#define NFC_FLASH_ADDR 0xE06 -#define NFC_FLASH_CMD 0xE08 -#define NFC_CONFIG 0xE0A -#define NFC_ECC_STATUS_RESULT 0xE0C -#define NFC_RSLTMAIN_AREA 0xE0E -#define NFC_RSLTSPARE_AREA 0xE10 -#define NFC_SPAS 0xe10 -#define NFC_WRPROT 0xE12 -#define NFC_V1_UNLOCKSTART_BLKADDR 0xe14 -#define NFC_V1_UNLOCKEND_BLKADDR 0xe16 -#define NFC_V21_UNLOCKSTART_BLKADDR 0xe20 -#define NFC_V21_UNLOCKEND_BLKADDR 0xe22 -#define NFC_NF_WRPRST 0xE18 -#define NFC_CONFIG1 0xE1A -#define NFC_CONFIG2 0xE1C - -/* - * Addresses for NFC RAM BUFFER Main area 0 - */ -#define MAIN_AREA0 0x000 -#define MAIN_AREA1 0x200 -#define MAIN_AREA2 0x400 -#define MAIN_AREA3 0x600 - -/* - * Addresses for NFC SPARE BUFFER Spare area 0 - */ -#define SPARE_AREA0 0x800 -#define SPARE_AREA1 0x810 -#define SPARE_AREA2 0x820 -#define SPARE_AREA3 0x830 - -/* - * Set INT to 0, FCMD to 1, rest to 0 in NFC_CONFIG2 Register for Command - * operation - */ -#define NFC_CMD 0x1 - -/* - * Set INT to 0, FADD to 1, rest to 0 in NFC_CONFIG2 Register for Address - * operation - */ -#define NFC_ADDR 0x2 - -/* - * Set INT to 0, FDI to 1, rest to 0 in NFC_CONFIG2 Register for Input - * operation - */ -#define NFC_INPUT 0x4 - -/* - * Set INT to 0, FDO to 001, rest to 0 in NFC_CONFIG2 Register for Data Output - * operation - */ -#define NFC_OUTPUT 0x8 - -/* - * Set INT to 0, FD0 to 010, rest to 0 in NFC_CONFIG2 Register for Read ID - * operation - */ -#define NFC_ID 0x10 - -/* - * Set INT to 0, FDO to 100, rest to 0 in NFC_CONFIG2 Register for Read Status - * operation - */ -#define NFC_STATUS 0x20 - -/* - * Set INT to 1, rest to 0 in NFC_CONFIG2 Register for Read Status - * operation - */ -#define NFC_INT 0x8000 - -#define NFC_ECC_MODE (1 << 0) -#define NFC_SP_EN (1 << 2) -#define NFC_ECC_EN (1 << 3) -#define NFC_INT_MSK (1 << 4) -#define NFC_BIG (1 << 5) -#define NFC_RST (1 << 6) -#define NFC_CE (1 << 7) -#define NFC_ONE_CYCLE (1 << 8) - -#define NFC_SPAS_16 8 -#define NFC_SPAS_64 32 -#define NFC_SPAS_128 64 -#define NFC_SPAS_218 109 - -#ifdef CONFIG_NAND_IMX_BOOT -#define __nand_boot_init __bare_init -#else -#define __nand_boot_init -#endif - -struct imx_nand_host { - struct mtd_info mtd; - struct nand_chip nand; - struct mtd_partition *parts; - struct device_d *dev; - - void *spare0; - void *main_area0; - void *main_area1; - - void __iomem *base; - void __iomem *regs; - int status_request; - struct clk *clk; - - int pagesize_2k; - uint8_t *data_buf; - unsigned int buf_start; - int spare_len; - -}; - -/* - * OOB placement block for use with hardware ecc generation - */ -static struct nand_ecclayout nandv1_hw_eccoob_smallpage = { - .eccbytes = 5, - .eccpos = {6, 7, 8, 9, 10}, - .oobfree = {{0, 5}, {12, 4}} -}; - -static struct nand_ecclayout nandv1_hw_eccoob_largepage = { - .eccbytes = 20, - .eccpos = {6, 7, 8, 9, 10, 22, 23, 24, 25, 26, - 38, 39, 40, 41, 42, 54, 55, 56, 57, 58}, - .oobfree = {{2, 4}, {11, 10}, {27, 10}, {43, 10}, {59, 5}, } -}; - -/* OOB description for 512 byte pages with 16 byte OOB */ -static struct nand_ecclayout nandv2_hw_eccoob_smallpage = { - .eccbytes = 1 * 9, - .eccpos = { - 7, 8, 9, 10, 11, 12, 13, 14, 15 - }, - .oobfree = { - {.offset = 0, .length = 5} - } -}; - -/* OOB description for 2048 byte pages with 64 byte OOB */ -static struct nand_ecclayout nandv2_hw_eccoob_largepage = { - .eccbytes = 4 * 9, - .eccpos = { - 7, 8, 9, 10, 11, 12, 13, 14, 15, - 23, 24, 25, 26, 27, 28, 29, 30, 31, - 39, 40, 41, 42, 43, 44, 45, 46, 47, - 55, 56, 57, 58, 59, 60, 61, 62, 63 - }, - .oobfree = { - {.offset = 2, .length = 4}, - {.offset = 16, .length = 7}, - {.offset = 32, .length = 7}, - {.offset = 48, .length = 7} - } -}; - -static void memcpy32(void *trg, const void *src, int size) -{ - int i; - unsigned int *t = trg; - unsigned const int *s = src; - -#ifdef CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS - if (!((unsigned long)trg & 0x3) && !((unsigned long)src & 0x3)) - memcpy(trg, src, size); - else -#endif - for (i = 0; i < (size >> 2); i++) - *t++ = *s++; -} - -/* - * This function polls the NANDFC to wait for the basic operation to complete by - * checking the INT bit of config2 register. - * - * @param max_retries number of retry attempts (separated by 1 us) - * @param param parameter for debug - */ -static void __nand_boot_init wait_op_done(struct imx_nand_host *host) -{ - u32 tmp; - int i; - - /* This is a timeout of roughly 15ms on my system. We - * need about 2us, but be generous. Don't use udelay - * here as we might be here from nand booting. - */ - for (i = 0; i < 100000; i++) { - if (readw(host->regs + NFC_CONFIG2) & NFC_INT) { - tmp = readw(host->regs + NFC_CONFIG2); - tmp &= ~NFC_INT; - writew(tmp, host->regs + NFC_CONFIG2); - return; - } - } -} - -/* - * This function issues the specified command to the NAND device and - * waits for completion. - * - * @param cmd command for NAND Flash - */ -static void __nand_boot_init send_cmd(struct imx_nand_host *host, u16 cmd) -{ - MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x)\n", cmd); - - writew(cmd, host->regs + NFC_FLASH_CMD); - writew(NFC_CMD, host->regs + NFC_CONFIG2); - - if (cpu_is_mx21() && (cmd == NAND_CMD_RESET)) { - /* Reset completion is indicated by NFC_CONFIG2 */ - /* being set to 0 */ - int i; - for (i = 0; i < 100000; i++) { - if (readw(host->regs + NFC_CONFIG2) == 0) { - break; - } - } - } else - /* Wait for operation to complete */ - wait_op_done(host); -} - -/* - * This function sends an address (or partial address) to the - * NAND device. The address is used to select the source/destination for - * a NAND command. - * - * @param addr address to be written to NFC. - * @param islast True if this is the last address cycle for command - */ -static void __nand_boot_init noinline send_addr(struct imx_nand_host *host, u16 addr) -{ - MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast); - - writew(addr, host->regs + NFC_FLASH_ADDR); - writew(NFC_ADDR, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host); -} - -/* - * This function requests the NANDFC to initate the transfer - * of data currently in the NANDFC RAM buffer to the NAND device. - * - * @param buf_id Specify Internal RAM Buffer number (0-3) - * @param spare_only set true if only the spare area is transferred - */ -static void __nand_boot_init send_page(struct imx_nand_host *host, - unsigned int ops) -{ - int bufs, i; - - if (nfc_is_v1() && host->pagesize_2k) - bufs = 4; - else - bufs = 1; - - for (i = 0; i < bufs; i++) { - /* NANDFC buffer 0 is used for page read/write */ - writew(i, host->regs + NFC_BUF_ADDR); - - writew(ops, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host); - } -} - -/* - * This function requests the NANDFC to perform a read of the - * NAND device ID. - */ -static void send_read_id(struct imx_nand_host *host) -{ - struct nand_chip *this = &host->nand; - u16 tmp; - - /* NANDFC buffer 0 is used for device ID output */ - writew(0x0, host->regs + NFC_BUF_ADDR); - - /* Read ID into main buffer */ - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_SP_EN; - writew(tmp, host->regs + NFC_CONFIG1); - - writew(NFC_ID, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host); - - if (this->options & NAND_BUSWIDTH_16) { - volatile u16 *mainbuf = host->main_area0; - - /* - * Pack the every-other-byte result for 16-bit ID reads - * into every-byte as the generic code expects and various - * chips implement. - */ - - mainbuf[0] = (mainbuf[0] & 0xff) | ((mainbuf[1] & 0xff) << 8); - mainbuf[1] = (mainbuf[2] & 0xff) | ((mainbuf[3] & 0xff) << 8); - mainbuf[2] = (mainbuf[4] & 0xff) | ((mainbuf[5] & 0xff) << 8); - } - memcpy32(host->data_buf, host->main_area0, 16); -} - -/* - * This function requests the NANDFC to perform a read of the - * NAND device status and returns the current status. - * - * @return device status - */ -static u16 get_dev_status(struct imx_nand_host *host) -{ - volatile u16 *mainbuf = host->main_area1; - u32 store; - u16 ret, tmp; - /* Issue status request to NAND device */ - - /* store the main area1 first word, later do recovery */ - store = *((u32 *) mainbuf); - /* - * NANDFC buffer 1 is used for device status to prevent - * corruption of read/write buffer on status requests. - */ - writew(1, host->regs + NFC_BUF_ADDR); - - /* Read status into main buffer */ - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_SP_EN; - writew(tmp, host->regs + NFC_CONFIG1); - - writew(NFC_STATUS, host->regs + NFC_CONFIG2); - - /* Wait for operation to complete */ - wait_op_done(host); - - /* Status is placed in first word of main buffer */ - /* get status, then recovery area 1 data */ - ret = mainbuf[0]; - *((u32 *) mainbuf) = store; - - return ret; -} - -/* - * This function is used by upper layer to checks if device is ready - * - * @param mtd MTD structure for the NAND Flash - * - * @return 0 if device is busy else 1 - */ -static int imx_nand_dev_ready(struct mtd_info *mtd) -{ - /* - * NFC handles R/B internally.Therefore,this function - * always returns status as ready. - */ - return 1; -} - -static void imx_nand_enable_hwecc(struct mtd_info *mtd, int mode) -{ - /* - * If HW ECC is enabled, we turn it on during init. There is - * no need to enable again here. - */ -} - -static int imx_nand_correct_data(struct mtd_info *mtd, u_char * dat, - u_char * read_ecc, u_char * calc_ecc) -{ - struct nand_chip *nand_chip = mtd->priv; - struct imx_nand_host *host = nand_chip->priv; - - /* - * 1-Bit errors are automatically corrected in HW. No need for - * additional correction. 2-Bit errors cannot be corrected by - * HW ECC, so we need to return failure - */ - u16 ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT); - - if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) { - MTD_DEBUG(MTD_DEBUG_LEVEL0, - "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n"); - return -1; - } - - return 0; -} - -static int imx_nand_calculate_ecc(struct mtd_info *mtd, const u_char * dat, - u_char * ecc_code) -{ - return 0; -} - -/* - * This function reads byte from the NAND Flash - * - * @param mtd MTD structure for the NAND Flash - * - * @return data read from the NAND Flash - */ -static u_char imx_nand_read_byte(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct imx_nand_host *host = nand_chip->priv; - u_char ret; - - /* Check for status request */ - if (host->status_request) - return get_dev_status(host) & 0xFF; - - ret = *(uint8_t *)(host->data_buf + host->buf_start); - host->buf_start++; - - return ret; -} - -/* - * This function reads word from the NAND Flash - * - * @param mtd MTD structure for the NAND Flash - * - * @return data read from the NAND Flash - */ -static u16 imx_nand_read_word(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct imx_nand_host *host = nand_chip->priv; - uint16_t ret; - - ret = *(uint16_t *)(host->data_buf + host->buf_start); - host->buf_start += 2; - - return ret; -} - -/* - * This function writes data of length \b len to buffer \b buf. The data to be - * written on NAND Flash is first copied to RAMbuffer. After the Data Input - * Operation by the NFC, the data is written to NAND Flash - * - * @param mtd MTD structure for the NAND Flash - * @param buf data to be written to NAND Flash - * @param len number of bytes to be written - */ -static void imx_nand_write_buf(struct mtd_info *mtd, - const u_char *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct imx_nand_host *host = nand_chip->priv; - u16 col = host->buf_start; - int n = mtd->oobsize + mtd->writesize - col; - - n = min(n, len); - memcpy(host->data_buf + col, buf, n); - - host->buf_start += n; -} - -/* - * This function is used to read the data buffer from the NAND Flash. To - * read the data from NAND Flash first the data output cycle is initiated by - * the NFC, which copies the data to RAMbuffer. This data of length \b len is - * then copied to buffer \b buf. - * - * @param mtd MTD structure for the NAND Flash - * @param buf data to be read from NAND Flash - * @param len number of bytes to be read - */ -static void imx_nand_read_buf(struct mtd_info *mtd, u_char * buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct imx_nand_host *host = nand_chip->priv; - u16 col = host->buf_start; - int n = mtd->oobsize + mtd->writesize - col; - - n = min(n, len); - - memcpy(buf, host->data_buf + col, len); - - host->buf_start += len; -} - -/* - * Function to transfer data to/from spare area. - */ -static void copy_spare(struct mtd_info *mtd, int bfrom) -{ - struct nand_chip *this = mtd->priv; - struct imx_nand_host *host = this->priv; - u16 i, j; - u16 n = mtd->writesize >> 9; - u8 *d = host->data_buf + mtd->writesize; - u8 *s = host->spare0; - u16 t = host->spare_len; - - j = (mtd->oobsize / n >> 1) << 1; - - if (bfrom) { - for (i = 0; i < n - 1; i++) - memcpy32(d + i * j, s + i * t, j); - - /* the last section */ - memcpy32(d + i * j, s + i * t, mtd->oobsize - i * j); - } else { - for (i = 0; i < n - 1; i++) - memcpy32(&s[i * t], &d[i * j], j); - - /* the last section */ - memcpy32(&s[i * t], &d[i * j], mtd->oobsize - i * j); - } -} - -/* - * This function is used by the upper layer to verify the data in NAND Flash - * with the data in the \b buf. - * - * @param mtd MTD structure for the NAND Flash - * @param buf data to be verified - * @param len length of the data to be verified - * - * @return -EFAULT if error else 0 - * - */ -static int -imx_nand_verify_buf(struct mtd_info *mtd, const u_char * buf, int len) -{ - return -EFAULT; -} - -/* - * This function is used by upper layer for select and deselect of the NAND - * chip - * - * @param mtd MTD structure for the NAND Flash - * @param chip val indicating select or deselect - */ -static void imx_nand_select_chip(struct mtd_info *mtd, int chip) -{ -#ifdef CONFIG_MTD_NAND_MXC_FORCE_CE - u16 tmp; - - if (chip > 0) { - MTD_DEBUG(MTD_DEBUG_LEVEL0, - "ERROR: Illegal chip select (chip = %d)\n", chip); - return; - } - - if (chip == -1) { - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_CE; - writew(tmp, host->regs + NFC_CONFIG1); - return; - } - - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_CE; - writew(tmp, host->regs + NFC_CONFIG1); -#endif -} - -static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) -{ - struct nand_chip *nand_chip = mtd->priv; - struct imx_nand_host *host = nand_chip->priv; - - /* - * Write out column address, if necessary - */ - if (column != -1) { - /* - * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers - * layers perform a read/write buf operation, - * we will used the saved column adress to index into - * the full page. - */ - send_addr(host, 0); - if (host->pagesize_2k) - /* another col addr cycle for 2k page */ - send_addr(host, 0); - } - - /* - * Write out page address, if necessary - */ - if (page_addr != -1) { - send_addr(host, (page_addr & 0xff)); /* paddr_0 - p_addr_7 */ - - if (host->pagesize_2k) { - send_addr(host, (page_addr >> 8) & 0xFF); - if (mtd->size >= 0x10000000) { - send_addr(host, (page_addr >> 16) & 0xff); - } - } else { - /* One more address cycle for higher density devices */ - if (mtd->size >= 0x4000000) { - /* paddr_8 - paddr_15 */ - send_addr(host, (page_addr >> 8) & 0xff); - send_addr(host, (page_addr >> 16) & 0xff); - } else - /* paddr_8 - paddr_15 */ - send_addr(host, (page_addr >> 8) & 0xff); - } - } -} - -/* - * This function is used by the upper layer to write command to NAND Flash for - * different operations to be carried out on NAND Flash - * - * @param mtd MTD structure for the NAND Flash - * @param command command for NAND Flash - * @param column column offset for the page read - * @param page_addr page to be read from NAND Flash - */ -static void imx_nand_command(struct mtd_info *mtd, unsigned command, - int column, int page_addr) -{ - struct nand_chip *nand_chip = mtd->priv; - struct imx_nand_host *host = nand_chip->priv; - - MTD_DEBUG(MTD_DEBUG_LEVEL3, - "imx_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n", - command, column, page_addr); - - /* - * Reset command state information - */ - host->status_request = 0; - - /* - * Command pre-processing step - */ - switch (command) { - - case NAND_CMD_STATUS: - host->buf_start = 0; - host->status_request = 1; - send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); - break; - - case NAND_CMD_READ0: - case NAND_CMD_READOOB: - if (command == NAND_CMD_READ0) - host->buf_start = column; - else - host->buf_start = column + mtd->writesize; - - command = NAND_CMD_READ0; - - send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); - - if (host->pagesize_2k) - /* send read confirm command */ - send_cmd(host, NAND_CMD_READSTART); - - send_page(host, NFC_OUTPUT); - - memcpy32(host->data_buf, host->main_area0, mtd->writesize); - copy_spare(mtd, 1); - break; - - case NAND_CMD_SEQIN: - if (column >= mtd->writesize) { - if (host->pagesize_2k) { - /** - * FIXME: before send SEQIN command for write - * OOB, we must read one page out. For K9F1GXX - * has no READ1 command to set current HW - * pointer to spare area, we must write the - * whole page including OOB together. - */ - /* call ourself to read a page */ - imx_nand_command(mtd, NAND_CMD_READ0, 0, - page_addr); - } - host->buf_start = column; - - /* Set program pointer to spare region */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READOOB); - } else { - host->buf_start = column; - - /* Set program pointer to page start */ - if (!host->pagesize_2k) - send_cmd(host, NAND_CMD_READ0); - } - send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); - - break; - - case NAND_CMD_PAGEPROG: - memcpy32(host->main_area0, host->data_buf, mtd->writesize); - copy_spare(mtd, 0); - send_page(host, NFC_INPUT); - send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); - break; - - case NAND_CMD_READID: - send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); - host->buf_start = 0; - send_read_id(host); - break; - - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_RESET: - send_cmd(host, command); - mxc_do_addr_cycle(mtd, column, page_addr); - break; - } -} - -#ifdef CONFIG_MXC_NAND_LOW_LEVEL_ERASE -static void imx_low_erase(struct mtd_info *mtd) -{ - - struct nand_chip *this = mtd->priv; - unsigned int page_addr, addr; - u_char status; - - MTD_DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : imx_low_erase:Erasing NAND\n"); - for (addr = 0; addr < this->chipsize; addr += mtd->erasesize) { - page_addr = addr / mtd->writesize; - imx_nand_command(mtd, NAND_CMD_ERASE1, -1, page_addr); - imx_nand_command(mtd, NAND_CMD_ERASE2, -1, -1); - imx_nand_command(mtd, NAND_CMD_STATUS, -1, -1); - status = imx_nand_read_byte(mtd); - if (status & NAND_STATUS_FAIL) { - printk(KERN_ERR - "ERASE FAILED(block = %d,status = 0x%x)\n", - addr / mtd->erasesize, status); - } - } - -} -#endif - -/* - * The generic flash bbt decriptors overlap with our ecc - * hardware, so define some i.MX specific ones. - */ -static uint8_t bbt_pattern[] = { 'B', 'b', 't', '0' }; -static uint8_t mirror_pattern[] = { '1', 't', 'b', 'B' }; - -static struct nand_bbt_descr bbt_main_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 0, - .len = 4, - .veroffs = 4, - .maxblocks = 4, - .pattern = bbt_pattern, -}; - -static struct nand_bbt_descr bbt_mirror_descr = { - .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE - | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP, - .offs = 0, - .len = 4, - .veroffs = 4, - .maxblocks = 4, - .pattern = mirror_pattern, -}; - -/* - * This function is called during the driver binding process. - * - * @param pdev the device structure used to store device specific - * information that is used by the suspend, resume and - * remove functions - * - * @return The function always returns 0. - */ - -static int __init imxnd_probe(struct device_d *dev) -{ - struct nand_chip *this; - struct mtd_info *mtd; - struct imx_nand_platform_data *pdata = dev->platform_data; - struct imx_nand_host *host; - struct nand_ecclayout *oob_smallpage, *oob_largepage; - u16 tmp; - int err = 0; - -#ifdef CONFIG_ARCH_IMX27 - PCCR1 |= PCCR1_NFC_BAUDEN; -#endif -#ifdef CONFIG_ARCH_IMX21 - PCCR0 |= PCCR0_NFC_EN; -#endif - /* Allocate memory for MTD device structure and private data */ - host = kzalloc(sizeof(struct imx_nand_host) + NAND_MAX_PAGESIZE + - NAND_MAX_OOBSIZE, GFP_KERNEL); - if (!host) - return -ENOMEM; - - host->data_buf = (uint8_t *)(host + 1); - host->base = (void __iomem *)dev->map_base; - - host->main_area0 = host->base; - host->main_area1 = host->base + 0x200; - - if (nfc_is_v21()) { - host->regs = host->base + 0x1000; - host->spare0 = host->base + 0x1000; - host->spare_len = 64; - oob_smallpage = &nandv2_hw_eccoob_smallpage; - oob_largepage = &nandv2_hw_eccoob_largepage; - } else if (nfc_is_v1()) { - host->regs = host->base; - host->spare0 = host->base + 0x800; - host->spare_len = 16; - oob_smallpage = &nandv1_hw_eccoob_smallpage; - oob_largepage = &nandv1_hw_eccoob_largepage; - } - - host->dev = dev; - /* structures must be linked */ - this = &host->nand; - mtd = &host->mtd; - mtd->priv = this; - - /* 50 us command delay time */ - this->chip_delay = 5; - - this->priv = host; - this->dev_ready = imx_nand_dev_ready; - this->cmdfunc = imx_nand_command; - this->select_chip = imx_nand_select_chip; - this->read_byte = imx_nand_read_byte; - this->read_word = imx_nand_read_word; - this->write_buf = imx_nand_write_buf; - this->read_buf = imx_nand_read_buf; - this->verify_buf = imx_nand_verify_buf; -#if 0 - host->clk = clk_get(&pdev->dev, "nfc_clk"); - if (IS_ERR(host->clk)) - goto eclk; - - clk_enable(host->clk); -#endif - - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_INT_MSK; - tmp &= ~NFC_SP_EN; - if (nfc_is_v21()) - /* currently no support for 218 byte OOB with stronger ECC */ - tmp |= NFC_ECC_MODE; - writew(tmp, host->regs + NFC_CONFIG1); - - if (pdata->hw_ecc) { - this->ecc.calculate = imx_nand_calculate_ecc; - this->ecc.hwctl = imx_nand_enable_hwecc; - this->ecc.correct = imx_nand_correct_data; - this->ecc.mode = NAND_ECC_HW; - this->ecc.size = 512; - tmp = readw(host->regs + NFC_CONFIG1); - tmp |= NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); - } else { - this->ecc.size = 512; - this->ecc.mode = NAND_ECC_SOFT; - tmp = readw(host->regs + NFC_CONFIG1); - tmp &= ~NFC_ECC_EN; - writew(tmp, host->regs + NFC_CONFIG1); - } - - /* Reset NAND */ - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* preset operation */ - /* Unlock the internal RAM Buffer */ - writew(0x2, host->regs + NFC_CONFIG); - - /* Blocks to be unlocked */ - if (nfc_is_v21()) { - writew(0x0, host->regs + NFC_V21_UNLOCKSTART_BLKADDR); - writew(0xffff, host->regs + NFC_V21_UNLOCKEND_BLKADDR); - this->ecc.bytes = 9; - } else if (nfc_is_v1()) { - writew(0x0, host->regs + NFC_V1_UNLOCKSTART_BLKADDR); - writew(0x4000, host->regs + NFC_V1_UNLOCKEND_BLKADDR); - this->ecc.bytes = 3; - } - - /* Unlock Block Command for given address range */ - writew(0x4, host->regs + NFC_WRPROT); - - this->ecc.layout = oob_smallpage; - - /* NAND bus width determines access funtions used by upper layer */ - if (pdata->width == 2) { - this->options |= NAND_BUSWIDTH_16; - this->ecc.layout = &nandv1_hw_eccoob_smallpage; - imx_nand_set_layout(0, 16); - } - - if (pdata->flash_bbt) { - this->bbt_td = &bbt_main_descr; - this->bbt_md = &bbt_mirror_descr; - /* update flash based bbt */ - this->options |= NAND_USE_FLASH_BBT; - } - - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1)) { - err = -ENXIO; - goto escan; - } - - imx_nand_set_layout(mtd->writesize, pdata->width == 2 ? 16 : 8); - - if (mtd->writesize == 2048) { - this->ecc.layout = oob_largepage; - host->pagesize_2k = 1; - if (nfc_is_v21()) { - tmp = readw(host->regs + NFC_SPAS); - tmp &= 0xff00; - tmp |= NFC_SPAS_64; - writew(tmp, host->regs + NFC_SPAS); - } - } else { - if (nfc_is_v21()) { - tmp = readw(host->regs + NFC_SPAS); - tmp &= 0xff00; - tmp |= NFC_SPAS_16; - writew(tmp, host->regs + NFC_SPAS); - } - } - - /* second phase scan */ - if (nand_scan_tail(mtd)) { - err = -ENXIO; - goto escan; - } - - add_mtd_device(mtd); - - dev->priv = host; - - return 0; - -escan: - kfree(host); - - return err; - -} - -static struct driver_d imx_nand_driver = { - .name = "imx_nand", - .probe = imxnd_probe, -}; - -#ifdef CONFIG_NAND_IMX_BOOT - -static void __nand_boot_init nfc_addr(struct imx_nand_host *host, u32 offs) -{ - if (host->pagesize_2k) { - send_addr(host, offs & 0xff); - send_addr(host, offs & 0xff); - send_addr(host, (offs >> 11) & 0xff); - send_addr(host, (offs >> 19) & 0xff); - send_addr(host, (offs >> 27) & 0xff); - } else { - send_addr(host, offs & 0xff); - send_addr(host, (offs >> 9) & 0xff); - send_addr(host, (offs >> 17) & 0xff); - send_addr(host, (offs >> 25) & 0xff); - } -} - -static void __nand_boot_init __memcpy32(void *trg, const void *src, int size) -{ - int i; - unsigned int *t = trg; - unsigned const int *s = src; - - for (i = 0; i < (size >> 2); i++) - *t++ = *s++; -} - -void __nand_boot_init imx_nand_load_image(void *dest, int size) -{ - struct imx_nand_host host; - u32 tmp, page, block, blocksize, pagesize; -#ifdef CONFIG_ARCH_IMX21 - tmp = readl(IMX_SYSTEM_CTL_BASE + 0x14); - if (tmp & (1 << 5)) - host.pagesize_2k = 1; - else - host.pagesize_2k = 0; -#endif -#ifdef CONFIG_ARCH_IMX27 - tmp = readl(IMX_SYSTEM_CTL_BASE + 0x14); - if (tmp & (1 << 5)) - host.pagesize_2k = 1; - else - host.pagesize_2k = 0; -#endif -#ifdef CONFIG_ARCH_IMX31 - tmp = readl(IMX_CCM_BASE + CCM_RCSR); - if (tmp & RCSR_NFMS) - host.pagesize_2k = 1; - else - host.pagesize_2k = 0; -#endif -#if defined(CONFIG_ARCH_IMX35) || defined(CONFIG_ARCH_IMX25) - if (readl(IMX_CCM_BASE + CCM_RCSR) & (1 << 8)) - host.pagesize_2k = 1; - else - host.pagesize_2k = 0; -#endif - if (host.pagesize_2k) { - pagesize = 2048; - blocksize = 128 * 1024; - } else { - pagesize = 512; - blocksize = 16 * 1024; - } - - host.base = (void __iomem *)IMX_NFC_BASE; - if (nfc_is_v21()) { - host.regs = host.base + 0x1000; - host.spare0 = host.base + 0x1000; - host.spare_len = 64; - } else if (nfc_is_v1()) { - host.regs = host.base; - host.spare0 = host.base + 0x800; - host.spare_len = 16; - } - - send_cmd(&host, NAND_CMD_RESET); - - /* preset operation */ - /* Unlock the internal RAM Buffer */ - writew(0x2, host.regs + NFC_CONFIG); - - /* Unlock Block Command for given address range */ - writew(0x4, host.regs + NFC_WRPROT); - - tmp = readw(host.regs + NFC_CONFIG1); - tmp |= NFC_ECC_EN; - if (nfc_is_v21()) - /* currently no support for 218 byte OOB with stronger ECC */ - tmp |= NFC_ECC_MODE; - tmp &= ~(NFC_SP_EN | NFC_INT_MSK); - writew(tmp, host.regs + NFC_CONFIG1); - - if (nfc_is_v21()) { - if (host.pagesize_2k) { - tmp = readw(host.regs + NFC_SPAS); - tmp &= 0xff00; - tmp |= NFC_SPAS_64; - writew(tmp, host.regs + NFC_SPAS); - } else { - tmp = readw(host.regs + NFC_SPAS); - tmp &= 0xff00; - tmp |= NFC_SPAS_16; - writew(tmp, host.regs + NFC_SPAS); - } - } - - block = page = 0; - - while (1) { - page = 0; - while (page * pagesize < blocksize) { - debug("page: %d block: %d dest: %p src " - "0x%08x\n", - page, block, dest, - block * blocksize + - page * pagesize); - - send_cmd(&host, NAND_CMD_READ0); - nfc_addr(&host, block * blocksize + - page * pagesize); - if (host.pagesize_2k) - send_cmd(&host, NAND_CMD_READSTART); - send_page(&host, NFC_OUTPUT); - page++; - - if (host.pagesize_2k) { - if ((readw(host.spare0) & 0xff) - != 0xff) - continue; - } else { - if ((readw(host.spare0 + 4) & 0xff00) - != 0xff00) - continue; - } - - __memcpy32(dest, host.base, pagesize); - dest += pagesize; - size -= pagesize; - - if (size <= 0) - return; - } - block++; - } -} -#define CONFIG_NAND_IMX_BOOT_DEBUG -#ifdef CONFIG_NAND_IMX_BOOT_DEBUG -#include - -static int do_nand_boot_test(struct command *cmdtp, int argc, char *argv[]) -{ - void *dest; - int size; - - if (argc < 3) - return COMMAND_ERROR_USAGE; - - dest = (void *)strtoul_suffix(argv[1], NULL, 0); - size = strtoul_suffix(argv[2], NULL, 0); - - imx_nand_load_image(dest, size); - - return 0; -} - -static const __maybe_unused char cmd_nand_boot_test_help[] = -"Usage: nand_boot_test \n" -"This command loads the booloader from the NAND memory like the reset\n" -"routine does. Its intended for development tests only"; - -BAREBOX_CMD_START(nand_boot_test) - .cmd = do_nand_boot_test, - .usage = "load bootloader from NAND", - BAREBOX_CMD_HELP(cmd_nand_boot_test_help) -BAREBOX_CMD_END -#endif - -#endif /* CONFIG_NAND_IMX_BOOT */ - -/* - * Main initialization routine - * @return 0 if successful; non-zero otherwise - */ -static int __init imx_nand_init(void) -{ - return register_driver(&imx_nand_driver); -} - -device_initcall(imx_nand_init); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("MXC NAND MTD driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/nand/nand_omap_gpmc.c b/drivers/nand/nand_omap_gpmc.c deleted file mode 100644 index c6647e5..0000000 --- a/drivers/nand/nand_omap_gpmc.c +++ /dev/null @@ -1,534 +0,0 @@ -/** - * @file - * @brief Provide Generic GPMC NAND implementation for OMAP platforms - * - * FileName: arch/arm/mach-omap/gpmc_nand.c - * - * GPMC has a NAND controller inbuilt. This provides a generic implementation - * for board files to register a nand device. drivers/nand/nand_base.c takes - * care of identifing the type of device, size etc. - * - * A typical device registration is as follows: - * - * @code - * static struct device_d my_nand_device = { - * .name = "gpmc_nand", - * .id = some identifier you need to show.. e.g. "gpmc_nand0" - * .map_base = GPMC base address - * .size = GPMC address map size. - * .platform_data = platform data - required - explained below - * }; - * platform data required: - * static struct gpmc_nand_platform_data nand_plat = { - * .cs = give the chip select of the device - * .device_width = what is the width of the device 8 or 16? - * .max_timeout = delay desired for operation - * .wait_mon_pin = do you use wait monitoring? if so wait pin - * .plat_options = platform options. - * NAND_HWECC_ENABLE/DISABLE - hw ecc enable/disable - * NAND_WAITPOL_LOW/HIGH - wait pin polarity - * .oob = if you would like to replace oob with a custom OOB. - * .nand_setup = if you would like a special setup function to be called - * .priv = any params you'd like to save(e.g. like nand_setup to use) - *}; - * then in your code, you'd device_register(&my_nand_device); - * @endcode - * - * Note: - * @li Enable CONFIG_NAND_OMAP_GPMC_HWECC in menuconfig to get H/w ECC support - * @li You may choose to register two "devices" for the same CS to get BOTH - * hwecc and swecc devices. - * @li You can choose to have your own OOB definition for compliance with ROM - * code organization - only if you dont want to use NAND's default oob layout. - * see GPMC_NAND_ECC_LP_x8_LAYOUT etc.. - * - * @see gpmc_nand_platform_data - * @warning Remember to initialize GPMC before initializing the nand dev. - */ -/* - * (C) Copyright 2008 - * Texas Instruments, - * Nishanth Menon - * - * Based on: - * drivers/mtd/nand/omap2.c from linux kernel - * - * Copyright (c) 2004 Texas Instruments, Jian Zhang - * Copyright (c) 2004 Micron Technology Inc. - * Copyright (c) 2004 David Brownell - * - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* 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); - -/** internal structure maintained for nand information */ -struct gpmc_nand_info { - struct nand_hw_control controller; - struct device_d *pdev; - struct gpmc_nand_platform_data *pdata; - struct nand_chip nand; - struct mtd_info minfo; - int gpmc_cs; - void *gpmc_command; - void *gpmc_address; - void *gpmc_data; - unsigned long gpmc_base; - unsigned char wait_mon_mask; - uint64_t timeout; - unsigned inuse:1; - unsigned wait_pol:1; -#ifdef CONFIG_NAND_OMAP_GPMC_HWECC - unsigned char ecc_parity_pairs; - unsigned int ecc_config; -#endif -}; - -/** - * @brief calls the platform specific dev_ready functionds - * - * @param mtd - mtd info structure - * - * @return - */ -static int omap_dev_ready(struct mtd_info *mtd) -{ - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); - struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); - uint64_t start = get_time_ns(); - unsigned long comp; - - gpmcnand_dbg("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"); - return -ETIMEDOUT; - } - /* if the wait is released, we are good to go */ - if (comp == - (readl(oinfo->gpmc_base + GPMC_STATUS) && - oinfo->wait_mon_mask)) - break; - } - return 0; -} - -/** - * @brief This function will enable or disable the Write Protect feature on - * NAND device. GPMC has a single WP bit for all CS devices.. - * - * @param oinfo omap nand info - * @param mode 0-disable else enable - * - * @return none - */ -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); - if (mode) - config &= ~(NAND_WP_BIT); /* WP is ON */ - else - config |= (NAND_WP_BIT); /* WP is OFF */ - - writel(config, oinfo->gpmc_base + GPMC_CFG); -} - -/** - * @brief respond to hw event change request - * - * MTD layer uses NAND_CTRL_CLE etc to control selection of the latch - * we hoodwink by changing the R and W registers according to the state - * we are requested. - * - * @param mtd - mtd info structure - * @param cmd command mtd layer is requesting - * - * @return none - */ -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, - cmd, ctrl); - switch (ctrl) { - case NAND_CTRL_CHANGE | NAND_CTRL_CLE: - nand->IO_ADDR_W = oinfo->gpmc_command; - nand->IO_ADDR_R = oinfo->gpmc_data; - break; - - case NAND_CTRL_CHANGE | NAND_CTRL_ALE: - nand->IO_ADDR_W = oinfo->gpmc_address; - nand->IO_ADDR_R = oinfo->gpmc_data; - break; - - case NAND_CTRL_CHANGE | NAND_NCE: - nand->IO_ADDR_W = oinfo->gpmc_data; - nand->IO_ADDR_R = oinfo->gpmc_data; - break; - } - - if (cmd != NAND_CMD_NONE) - writeb(cmd, nand->IO_ADDR_W); - return; -} - -#ifdef CONFIG_NAND_OMAP_GPMC_HWECC - -/** - * @brief This function will generate true ECC value, which can be used - * when correcting data read from NAND flash memory core - * - * @param ecc_buf buffer to store ecc code - * - * @return re-formatted ECC value - */ -static unsigned int gen_true_ecc(u8 *ecc_buf) -{ - gpmcnand_dbg("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); -} - -/** - * @brief Compares the ecc read from nand spare area with ECC - * registers values and corrects one bit error if it has occured - * Further details can be had from OMAP TRM and the following selected links: - * http://en.wikipedia.org/wiki/Hamming_code - * http://www.cs.utexas.edu/users/plaxton/c/337/05f/slides/ErrorCorrection-4.pdf - * - * @param mtd - mtd info structure - * @param dat page data - * @param read_ecc ecc readback - * @param calc_ecc calculated ecc (from reg) - * - * @return 0 if data is OK or corrected, else returns -1 - */ -static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - unsigned int orig_ecc, new_ecc, res, hm; - unsigned short parity_bits, byte; - unsigned char bit; - struct nand_chip *nand = (struct nand_chip *)(mtd->priv); - struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv); - - gpmcnand_dbg("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; - } - } - 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); - /* 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); - break; - default: - gpmcnand_err("Error: Unrecognized Mode[%d]!\n", mode); - break; - } -} -#endif /* CONFIG_NAND_OMAP_GPMC_HWECC */ - -/** - * @brief nand device probe. - * - * @param pdev -matching device - * - * @return -failure reason or give 0 - */ -static int gpmc_nand_probe(struct device_d *pdev) -{ - struct gpmc_nand_info *oinfo; - struct gpmc_nand_platform_data *pdata; - struct nand_chip *nand; - struct mtd_info *minfo; - unsigned long cs_base; - int err; - - 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"); - return -ENODEV; - } - - oinfo = calloc(1, sizeof(struct gpmc_nand_info)); - if (!oinfo) { - gpmcnand_err("oinfo alloc failed!\n"); - return -ENOMEM; - } - - /* fill up my data structures */ - oinfo->pdev = pdev; - oinfo->pdata = pdata; - pdev->platform_data = (void *)oinfo; - - nand = &oinfo->nand; - nand->priv = (void *)oinfo; - - minfo = &oinfo->minfo; - minfo->priv = (void *)nand; - - if (pdata->cs >= GPMC_NUM_CS) { - gpmcnand_err("Invalid CS!\n"); - err = -EINVAL; - goto out_release_mem; - } - /* Setup register specific data */ - oinfo->gpmc_cs = pdata->cs; - oinfo->gpmc_base = pdev->map_base; - cs_base = oinfo->gpmc_base + GPMC_CONFIG1_0 + - (pdata->cs * GPMC_CONFIG_CS_SIZE); - oinfo->gpmc_command = (void *)(cs_base + GPMC_CS_NAND_COMMAND); - oinfo->gpmc_address = (void *)(cs_base + GPMC_CS_NAND_ADDRESS); - oinfo->gpmc_data = (void *)(cs_base + GPMC_CS_NAND_DATA); - oinfo->timeout = pdata->max_timeout; - debug("GPMC Details:\n" - "GPMC BASE=%x\n" - "CMD=%x\n" - "ADDRESS=%x\n" - "DATA=%x\n" - "CS_BASE=%x\n", - oinfo->gpmc_base, oinfo->gpmc_command, - oinfo->gpmc_address, oinfo->gpmc_data, cs_base); - - /* If we are 16 bit dev, our gpmc config tells us that */ - if ((readl(cs_base) & 0x3000) == 0x1000) { - debug("16 bit dev\n"); - nand->options |= NAND_BUSWIDTH_16; - } - - /* Same data register for in and out */ - nand->IO_ADDR_W = nand->IO_ADDR_R = (void *)oinfo->gpmc_data; - /* - * If RDY/BSY line is connected to OMAP then use the omap ready - * function and the generic nand_wait function which reads the - * status register after monitoring the RDY/BSY line. Otherwise - * use a standard chip delay which is slightly more than tR - * (AC Timing) of the NAND device and read the status register - * until you get a failure or success - */ - if (pdata->wait_mon_pin > 4) { - gpmcnand_err("Invalid wait monitoring pin\n"); - err = -EINVAL; - goto out_release_mem; - } - if (pdata->wait_mon_pin) { - /* Set up the wait monitoring mask - * This is GPMC_STATUS reg relevant */ - oinfo->wait_mon_mask = (0x1 << (pdata->wait_mon_pin - 1)) << 8; - oinfo->wait_pol = (pdata->plat_options & NAND_WAITPOL_MASK); - nand->dev_ready = omap_dev_ready; - nand->chip_delay = 0; - } else { - /* use the default nand_wait function */ - nand->chip_delay = 50; - } - - /* Use default cmdfunc */ - /* nand cmd control */ - nand->cmd_ctrl = omap_hwcontrol; - - /* Dont do a bbt scan at the start */ - nand->options |= NAND_SKIP_BBTSCAN; - - /* State my controller */ - nand->controller = &oinfo->controller; - - /* if a different placement scheme is requested */ - if (pdata->oob) - nand->ecc.layout = pdata->oob; - -#ifdef CONFIG_NAND_OMAP_GPMC_HWECC - if (pdata->plat_options & NAND_HWECC_ENABLE) { - /* 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 -#endif - nand->ecc.mode = NAND_ECC_SOFT; - - /* All information is ready.. now lets call setup, if present */ - if (pdata->nand_setup) { - err = pdata->nand_setup(pdata); - if (err) { - gpmcnand_err("pdataform setup failed\n"); - goto out_release_mem; - } - } - /* Remove write protection */ - gpmc_nand_wp(oinfo, 0); - - /* we do not know what state of device we have is, so - * Send a reset to the device - * 8 bit write will work on 16 and 8 bit devices - */ - writeb(NAND_CMD_RESET, oinfo->gpmc_command); - mdelay(1); - - /* In normal mode, we scan to get just the device - * presence and then to get the device geometry - */ - if (nand_scan(minfo, 1)) { - gpmcnand_err("device scan failed\n"); - err = -ENXIO; - goto out_release_mem; - } - - /* We are all set to register with the system now! */ - err = add_mtd_device(minfo); - if (err) { - gpmcnand_err("device registration failed\n"); - goto out_release_mem; - } - return 0; - -out_release_mem: - if (oinfo) - free(oinfo); - - gpmcnand_err("Failed!!\n"); - return err; -} - -/** GMPC nand driver -> device registered by platforms */ -static struct driver_d gpmc_nand_driver = { - .name = "gpmc_nand", - .probe = gpmc_nand_probe, -}; - -static int gpmc_nand_init(void) -{ - return register_driver(&gpmc_nand_driver); -} - -device_initcall(gpmc_nand_init); diff --git a/drivers/nand/nand_s3c2410.c b/drivers/nand/nand_s3c2410.c deleted file mode 100644 index b989583..0000000 --- a/drivers/nand/nand_s3c2410.c +++ /dev/null @@ -1,525 +0,0 @@ -/* linux/drivers/mtd/nand/s3c2410.c - * - * Copyright (C) 2009 Juergen Beisert, Pengutronix - * - * Copyright © 2004-2008 Simtec Electronics - * http://armlinux.simtec.co.uk/ - * Ben Dooks - * - * Samsung S3C2410 NAND driver - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_S3C24XX_NAND_BOOT -# define __nand_boot_init __bare_init -# ifndef BOARD_DEFAULT_NAND_TIMING -# define BOARD_DEFAULT_NAND_TIMING 0x0737 -# endif -#else -# define __nand_boot_init -#endif - -/** - * Define this symbol for testing purpose. It will add a command to read an - * image from the NAND like it the boot strap code will do. - */ -#define CONFIG_NAND_S3C24XX_BOOT_DEBUG - -/* NAND controller's register */ - -#define NFCONF 0x00 - -#ifdef CONFIG_CPU_S3C2410 - -#define NFCMD 0x04 -#define NFADDR 0x08 -#define NFDATA 0x0c -#define NFSTAT 0x10 -#define NFECC 0x14 - -/* S3C2410 specific bits */ -#define NFSTAT_BUSY (1) -#define NFCONF_nFCE (1 << 11) -#define NFCONF_INITECC (1 << 12) -#define NFCONF_EN (1 << 15) - -#endif /* CONFIG_CPU_S3C2410 */ - -#ifdef CONFIG_CPU_S3C2440 - -#define NFCONT 0x04 -#define NFCMD 0x08 -#define NFADDR 0x0C -#define NFDATA 0x10 - -#define NFECC 0x1C -#define NFSTAT 0x20 - -/* S3C2440 specific bits */ -#define NFSTAT_BUSY (1) -#define NFCONT_nFCE (1 << 1) -#define NFCONF_INITECC (1 << 12) -#define NFCONT_EN (1) - -#endif /* CONFIG_CPU_S3C2440 */ - - -struct s3c24x0_nand_host { - struct mtd_info mtd; - struct nand_chip nand; - struct mtd_partition *parts; - struct device_d *dev; - - unsigned long base; -}; - -/** - * oob placement block for use with hardware ecc generation - */ -static struct nand_ecclayout nand_hw_eccoob = { - .eccbytes = 3, - .eccpos = { 0, 1, 2}, - .oobfree = { - { - .offset = 8, - .length = 8 - } - } -}; - -/* - Functions shared between the boot strap code and the regular driver - */ - -/** - * Issue the specified command to the NAND device - * @param[in] host Base address of the NAND controller - * @param[in] cmd Command for NAND flash - */ -static void __nand_boot_init send_cmd(unsigned long host, uint8_t cmd) -{ - writeb(cmd, host + NFCMD); -} - -/** - * Issue the specified address to the NAND device - * @param[in] host Base address of the NAND controller - * @param[in] addr Address for the NAND flash - */ -static void __nand_boot_init send_addr(unsigned long host, uint8_t addr) -{ - writeb(addr, host + NFADDR); -} - -/** - * Enable the NAND flash access - * @param[in] host Base address of the NAND controller - */ -static void __nand_boot_init enable_cs(unsigned long host) -{ -#ifdef CONFIG_CPU_S3C2410 - writew(readw(host + NFCONF) & ~NFCONF_nFCE, host + NFCONF); -#endif -#ifdef CONFIG_CPU_S3C2440 - writew(readw(host + NFCONT) & ~NFCONT_nFCE, host + NFCONT); -#endif -} - -/** - * Disable the NAND flash access - * @param[in] host Base address of the NAND controller - */ -static void __nand_boot_init disable_cs(unsigned long host) -{ -#ifdef CONFIG_CPU_S3C2410 - writew(readw(host + NFCONF) | NFCONF_nFCE, host + NFCONF); -#endif -#ifdef CONFIG_CPU_S3C2440 - writew(readw(host + NFCONT) | NFCONT_nFCE, host + NFCONT); -#endif -} - -/** - * Enable the NAND flash controller - * @param[in] host Base address of the NAND controller - * @param[in] timing Timing to access the NAND memory - */ -static void __nand_boot_init enable_nand_controller(unsigned long host, uint32_t timing) -{ -#ifdef CONFIG_CPU_S3C2410 - writew(timing + NFCONF_EN + NFCONF_nFCE, host + NFCONF); -#endif -#ifdef CONFIG_CPU_S3C2440 - writew(NFCONT_EN + NFCONT_nFCE, host + NFCONT); - writew(timing, host + NFCONF); -#endif -} - -/** - * Diable the NAND flash controller - * @param[in] host Base address of the NAND controller - */ -static void __nand_boot_init disable_nand_controller(unsigned long host) -{ -#ifdef CONFIG_CPU_S3C2410 - writew(NFCONF_nFCE, host + NFCONF); -#endif -#ifdef CONFIG_CPU_S3C2440 - writew(NFCONT_nFCE, host + NFCONT); -#endif -} - -/* ----------------------------------------------------------------------- */ - -/** - * Check the ECC and try to repair the data if possible - * @param[in] mtd_info FIXME - * @param[inout] dat Pointer to the data buffer that might contain a bit error - * @param[in] read_ecc ECC data from the OOB space - * @param[in] calc_ecc ECC data calculated from the data - * @return 0 no error, 1 repaired error, -1 no way... - * - * @note: Alsways 512 byte of data - */ -static int s3c2410_nand_correct_data(struct mtd_info *mtd, uint8_t *dat, - uint8_t *read_ecc, uint8_t *calc_ecc) -{ - unsigned int diff0, diff1, diff2; - unsigned int bit, byte; - - diff0 = read_ecc[0] ^ calc_ecc[0]; - diff1 = read_ecc[1] ^ calc_ecc[1]; - diff2 = read_ecc[2] ^ calc_ecc[2]; - - if (diff0 == 0 && diff1 == 0 && diff2 == 0) - return 0; /* ECC is ok */ - - /* sometimes people do not think about using the ECC, so check - * to see if we have an 0xff,0xff,0xff read ECC and then ignore - * the error, on the assumption that this is an un-eccd page. - */ - if (read_ecc[0] == 0xff && read_ecc[1] == 0xff && read_ecc[2] == 0xff - /* && info->platform->ignore_unset_ecc */) - return 0; - - /* Can we correct this ECC (ie, one row and column change). - * Note, this is similar to the 256 error code on smartmedia */ - - if (((diff0 ^ (diff0 >> 1)) & 0x55) == 0x55 && - ((diff1 ^ (diff1 >> 1)) & 0x55) == 0x55 && - ((diff2 ^ (diff2 >> 1)) & 0x55) == 0x55) { - /* calculate the bit position of the error */ - - bit = ((diff2 >> 3) & 1) | - ((diff2 >> 4) & 2) | - ((diff2 >> 5) & 4); - - /* calculate the byte position of the error */ - - byte = ((diff2 << 7) & 0x100) | - ((diff1 << 0) & 0x80) | - ((diff1 << 1) & 0x40) | - ((diff1 << 2) & 0x20) | - ((diff1 << 3) & 0x10) | - ((diff0 >> 4) & 0x08) | - ((diff0 >> 3) & 0x04) | - ((diff0 >> 2) & 0x02) | - ((diff0 >> 1) & 0x01); - - dat[byte] ^= (1 << bit); - return 1; - } - - /* if there is only one bit difference in the ECC, then - * one of only a row or column parity has changed, which - * means the error is most probably in the ECC itself */ - - diff0 |= (diff1 << 8); - diff0 |= (diff2 << 16); - - if ((diff0 & ~(1<priv; - struct s3c24x0_nand_host *host = nand_chip->priv; - - writel(readl(host->base + NFCONF) | NFCONF_INITECC , host->base + NFCONF); -} - -static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat, uint8_t *ecc_code) -{ - struct nand_chip *nand_chip = mtd->priv; - struct s3c24x0_nand_host *host = nand_chip->priv; - - ecc_code[0] = readb(host->base + NFECC); - ecc_code[1] = readb(host->base + NFECC + 1); - ecc_code[2] = readb(host->base + NFECC + 2); - - return 0; -} - -static void s3c24x0_nand_select_chip(struct mtd_info *mtd, int chip) -{ - struct nand_chip *nand_chip = mtd->priv; - struct s3c24x0_nand_host *host = nand_chip->priv; - - if (chip == -1) - disable_cs(host->base); - else - enable_cs(host->base); -} - -static int s3c24x0_nand_devready(struct mtd_info *mtd) -{ - struct nand_chip *nand_chip = mtd->priv; - struct s3c24x0_nand_host *host = nand_chip->priv; - - return readw(host->base + NFSTAT) & NFSTAT_BUSY; -} - -static void s3c24x0_nand_hwcontrol(struct mtd_info *mtd, int cmd, - unsigned int ctrl) -{ - struct nand_chip *nand_chip = mtd->priv; - struct s3c24x0_nand_host *host = nand_chip->priv; - - if (cmd == NAND_CMD_NONE) - return; - /* - * If the CLE should be active, this call is a NAND command - */ - if (ctrl & NAND_CLE) - send_cmd(host->base, cmd); - /* - * If the ALE should be active, this call is a NAND address - */ - if (ctrl & NAND_ALE) - send_addr(host->base, cmd); -} - -static int s3c24x0_nand_inithw(struct s3c24x0_nand_host *host) -{ - struct s3c24x0_nand_platform_data *pdata = host->dev->platform_data; - uint32_t tmp; - - /* reset the NAND controller */ - disable_nand_controller(host->base); - - if (pdata != NULL) - tmp = pdata->nand_timing; - else - /* else slowest possible timing */ - tmp = CALC_NFCONF_TIMING(4, 8, 8); - - /* reenable the NAND controller */ - enable_nand_controller(host->base, tmp); - - return 0; -} - -static int s3c24x0_nand_probe(struct device_d *dev) -{ - struct nand_chip *chip; - struct mtd_info *mtd; - struct s3c24x0_nand_host *host; - int ret; - - /* Allocate memory for MTD device structure and private data */ - host = kzalloc(sizeof(struct s3c24x0_nand_host), GFP_KERNEL); - if (!host) - return -ENOMEM; - - host->dev = dev; - host->base = dev->map_base; - - /* structures must be linked */ - chip = &host->nand; - mtd = &host->mtd; - mtd->priv = chip; - - /* init the default settings */ -#if 0 - /* TODO: Will follow later */ - init_nand_chip_bw8(chip); -#endif - /* 50 us command delay time */ - chip->chip_delay = 50; - chip->priv = host; - - chip->IO_ADDR_R = chip->IO_ADDR_W = (void*)(dev->map_base + NFDATA); - - chip->cmd_ctrl = s3c24x0_nand_hwcontrol; - chip->dev_ready = s3c24x0_nand_devready; - chip->select_chip = s3c24x0_nand_select_chip; - - /* we are using the hardware ECC feature of this device */ - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - chip->ecc.correct = s3c2410_nand_correct_data; - chip->ecc.hwctl = s3c2410_nand_enable_hwecc; - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - - /* our hardware capabilities */ - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.size = 512; - chip->ecc.bytes = 3; - chip->ecc.layout = &nand_hw_eccoob; - - ret = s3c24x0_nand_inithw(host); - if (ret != 0) - goto on_error; - - /* Scan to find existence of the device */ - ret = nand_scan(mtd, 1); - if (ret != 0) { - ret = -ENXIO; - goto on_error; - } - - return add_mtd_device(mtd); - -on_error: - free(host); - return ret; -} - -static struct driver_d s3c24x0_nand_driver = { - .name = "s3c24x0_nand", - .probe = s3c24x0_nand_probe, -}; - -#ifdef CONFIG_S3C24XX_NAND_BOOT - -static void __nand_boot_init wait_for_completion(unsigned long host) -{ - while (!(readw(host + NFSTAT) & NFSTAT_BUSY)) - ; -} - -static void __nand_boot_init nfc_addr(unsigned long host, uint32_t offs) -{ - send_addr(host, offs & 0xff); - send_addr(host, (offs >> 9) & 0xff); - send_addr(host, (offs >> 17) & 0xff); - send_addr(host, (offs >> 25) & 0xff); -} - -/** - * Load a sequential count of blocks from the NAND into memory - * @param[out] dest Pointer to target area (in SDRAM) - * @param[in] size Bytes to read from NAND device - * @param[in] page Start page to read from - * @param[in] pagesize Size of each page in the NAND - * - * This function must be located in the first 4kiB of the barebox image - * (guess why). When this routine is running the SDRAM is up and running - * and it runs from the correct address (physical=linked address). - * TODO Could we access the platform data from the boardfile? - * Due to it makes no sense this function does not return in case of failure. - */ -void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page, int pagesize) -{ - unsigned long host = S3C24X0_NAND_BASE; - int i; - - /* - * Reenable the NFC and use the default (but slow) access - * timing or the board specific setting if provided. - */ - enable_nand_controller(host, BOARD_DEFAULT_NAND_TIMING); - enable_cs(host); - - /* Reset the NAND device */ - send_cmd(host, NAND_CMD_RESET); - wait_for_completion(host); - disable_cs(host); - - do { - enable_cs(host); - send_cmd(host, NAND_CMD_READ0); - nfc_addr(host, page * pagesize); - wait_for_completion(host); - /* copy one page (do *not* use readsb() here!)*/ - for (i = 0; i < pagesize; i++) - writeb(readb(host + NFDATA), (unsigned long)(dest + i)); - disable_cs(host); - - page++; - dest += pagesize; - size -= pagesize; - } while (size >= 0); - - /* disable the controller again */ - disable_nand_controller(host); -} - -#ifdef CONFIG_NAND_S3C24XX_BOOT_DEBUG -#include - -static int do_nand_boot_test(struct command *cmdtp, int argc, char *argv[]) -{ - void *dest; - int size, pagesize; - - if (argc < 3) - return COMMAND_ERROR_USAGE; - - dest = (void *)strtoul_suffix(argv[1], NULL, 0); - size = strtoul_suffix(argv[2], NULL, 0); - pagesize = strtoul_suffix(argv[3], NULL, 0); - - s3c24x0_nand_load_image(dest, size, 0, pagesize); - - return 0; -} - -static const __maybe_unused char cmd_nand_boot_test_help[] = -"Usage: nand_boot_test \n"; - -BAREBOX_CMD_START(nand_boot_test) - .cmd = do_nand_boot_test, - .usage = "load an image from NAND", - BAREBOX_CMD_HELP(cmd_nand_boot_test_help) -BAREBOX_CMD_END -#endif - -#endif /* CONFIG_S3C24XX_NAND_BOOT */ - -/* - * Main initialization routine - * @return 0 if successful; non-zero otherwise - */ -static int __init s3c24x0_nand_init(void) -{ - return register_driver(&s3c24x0_nand_driver); -} - -device_initcall(s3c24x0_nand_init); diff --git a/drivers/nand/nand_util.c b/drivers/nand/nand_util.c deleted file mode 100644 index d57294e..0000000 --- a/drivers/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 - * @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 -#include -#include -#include - -#include -//#include - -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/nor/cfi_flash.c b/drivers/nor/cfi_flash.c index b21739b..fa5e5ee 100644 --- a/drivers/nor/cfi_flash.c +++ b/drivers/nor/cfi_flash.c @@ -77,7 +77,7 @@ * Functions */ -static void flash_add_byte (flash_info_t * info, cfiword_t * cword, uchar c) +static void flash_add_byte (struct flash_info *info, cfiword_t * cword, uchar c) { #if defined(__LITTLE_ENDIAN) unsigned short w; @@ -114,7 +114,7 @@ } } -static int flash_write_cfiword (flash_info_t * info, ulong dest, +static int flash_write_cfiword (struct flash_info *info, ulong dest, cfiword_t cword) { cfiptr_t cptr; @@ -159,7 +159,7 @@ sprintf (&str[i * 2], "%2.2x", *cp++); } -static void flash_printqry (flash_info_t * info, flash_sect_t sect) +static void flash_printqry (struct flash_info *info, flash_sect_t sect) { cfiptr_t cptr; int x, y; @@ -188,7 +188,7 @@ /* * read a short word by swapping for ppc format. */ -static ushort flash_read_ushort (flash_info_t * info, flash_sect_t sect, uint offset) +static ushort flash_read_ushort (struct flash_info *info, flash_sect_t sect, uint offset) { uchar *addr; ushort retval; @@ -220,7 +220,7 @@ * read a long word by picking the least significant byte of each maximum * port size word. Swap for ppc format. */ -static ulong flash_read_long (flash_info_t * info, flash_sect_t sect, uint offset) +static ulong flash_read_long (struct flash_info *info, flash_sect_t sect, uint offset) { uchar *addr; ulong retval; @@ -254,7 +254,7 @@ * http://www.jedec.org/download/search/jesd68.pdf * */ -static int flash_detect_cfi (flash_info_t * info) +static int flash_detect_cfi (struct flash_info *info) { int cfi_offset; debug ("flash detect cfi\n"); @@ -291,7 +291,7 @@ /* * The following code cannot be run from FLASH! */ -static ulong flash_get_size (flash_info_t *info, ulong base) +static ulong flash_get_size (struct flash_info *info, ulong base) { int i, j; flash_sect_t sect_cnt; @@ -302,6 +302,7 @@ int erase_region_size; int erase_region_count; int geometry_reversed = 0; + int cur_offset = 0; info->ext_addr = 0; info->cfi_version = 0; @@ -401,10 +402,14 @@ size_ratio, info->portwidth << CFI_FLASH_SHIFT_WIDTH, info->chipwidth << CFI_FLASH_SHIFT_WIDTH); debug ("found %d erase regions\n", num_erase_regions); + info->eraseregions = xzalloc(sizeof(*(info->eraseregions)) * num_erase_regions); + info->numeraseregions = num_erase_regions; sect_cnt = 0; sector = base; for (i = 0; i < num_erase_regions; i++) { + struct mtd_erase_region_info *region = &info->eraseregions[i]; + if (i > NUM_ERASE_REGIONS) { printf ("%d erase regions found, only %d used\n", num_erase_regions, NUM_ERASE_REGIONS); @@ -425,6 +430,11 @@ debug ("erase_region_count = %d erase_region_size = %d\n", erase_region_count, erase_region_size); + region->offset = cur_offset; + region->erasesize = erase_region_size; + region->numblocks = erase_region_count; + cur_offset += erase_region_size * erase_region_count; + /* increase the space malloced for the sector start addresses */ info->start = realloc(info->start, sizeof(ulong) * (erase_region_count + sect_cnt)); info->protect = realloc(info->protect, sizeof(uchar) * (erase_region_count + sect_cnt)); @@ -478,7 +488,7 @@ * when the passed address is greater or equal to the sector address * we have a match */ -flash_sect_t find_sector (flash_info_t * info, ulong addr) +flash_sect_t find_sector (struct flash_info *info, ulong addr) { flash_sect_t sector; @@ -489,37 +499,47 @@ return sector; } -static int cfi_erase(struct cdev *cdev, size_t count, unsigned long offset) +static int __cfi_erase(struct cdev *cdev, size_t count, unsigned long offset, + int verbose) { - flash_info_t *finfo = (flash_info_t *)cdev->priv; + struct flash_info *finfo = (struct flash_info *)cdev->priv; unsigned long start, end; int i, ret = 0; - printf("%s: erase 0x%08x (size %d)\n", __FUNCTION__, offset, count); + debug("%s: erase 0x%08x (size %d)\n", __func__, offset, count); start = find_sector(finfo, cdev->dev->map_base + offset); end = find_sector(finfo, cdev->dev->map_base + offset + count - 1); - init_progression_bar(end - start); + if (verbose) + init_progression_bar(end - start); for (i = start; i <= end; i++) { ret = finfo->cfi_cmd_set->flash_erase_one(finfo, i); if (ret) goto out; - show_progress(i - start); + + if (verbose) + show_progress(i - start); } out: - putchar('\n'); + if (verbose) + putchar('\n'); return ret; } +static int cfi_erase(struct cdev *cdev, size_t count, unsigned long offset) +{ + return __cfi_erase(cdev, count, offset, 1); +} + /* * Copy memory to flash, returns: * 0 - OK * 1 - write timeout * 2 - Flash not erased */ -static int write_buff (flash_info_t * info, const uchar * src, ulong addr, ulong cnt) +static int write_buff (struct flash_info *info, const uchar * src, ulong addr, ulong cnt) { ulong wp; ulong cp; @@ -614,7 +634,7 @@ return flash_write_cfiword (info, wp, cword); } -static int flash_real_protect (flash_info_t * info, long sector, int prot) +static int flash_real_protect (struct flash_info *info, long sector, int prot) { int retcode = 0; @@ -649,7 +669,7 @@ static int cfi_protect(struct cdev *cdev, size_t count, unsigned long offset, int prot) { - flash_info_t *finfo = (flash_info_t *)cdev->priv; + struct flash_info *finfo = (struct flash_info *)cdev->priv; unsigned long start, end; int i, ret = 0; const char *action = (prot? "protect" : "unprotect"); @@ -672,7 +692,7 @@ static ssize_t cfi_write(struct cdev *cdev, const void *buf, size_t count, unsigned long offset, ulong flags) { - flash_info_t *finfo = (flash_info_t *)cdev->priv; + struct flash_info *finfo = (struct flash_info *)cdev->priv; int ret; debug("cfi_write: buf=0x%08x addr=0x%08x count=0x%08x\n",buf, cdev->dev->map_base + offset, count); @@ -683,7 +703,7 @@ static void cfi_info (struct device_d* dev) { - flash_info_t *info = (flash_info_t *)dev->priv; + struct flash_info *info = (struct flash_info *)dev->priv; int i; if (info->flash_id != FLASH_MAN_CFI) { @@ -775,7 +795,7 @@ /* * flash_read_user_serial - read the OneTimeProgramming cells */ -static void flash_read_user_serial (flash_info_t * info, void *buffer, int offset, +static void flash_read_user_serial (struct flash_info *info, void *buffer, int offset, int len) { uchar *src; @@ -791,7 +811,7 @@ /* * flash_read_factory_serial - read the device Id from the protection area */ -static void flash_read_factory_serial (flash_info_t * info, void *buffer, int offset, +static void flash_read_factory_serial (struct flash_info *info, void *buffer, int offset, int len) { uchar *src; @@ -804,7 +824,7 @@ #endif -int flash_status_check (flash_info_t * info, flash_sect_t sector, +int flash_status_check (struct flash_info *info, flash_sect_t sector, uint64_t tout, char *prompt) { return info->cfi_cmd_set->flash_status_check(info, sector, tout, prompt); @@ -814,7 +834,7 @@ * wait for XSR.7 to be set. Time out with an error if it does not. * This routine does not set the flash to read-array mode. */ -int flash_generic_status_check (flash_info_t * info, flash_sect_t sector, +int flash_generic_status_check (struct flash_info *info, flash_sect_t sector, uint64_t tout, char *prompt) { uint64_t start; @@ -839,7 +859,7 @@ /* * make a proper sized command based on the port and chip widths */ -void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf) +void flash_make_cmd (struct flash_info *info, uchar cmd, void *cmdbuf) { int i; uchar *cp = (uchar *) cmdbuf; @@ -855,7 +875,7 @@ /* * Write a proper sized command to the correct address */ -void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +void flash_write_cmd (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd) { uchar *addr; @@ -866,7 +886,7 @@ flash_write_word(info, cword, addr); } -int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd) { cfiptr_t cptr; cfiword_t cword; @@ -903,7 +923,7 @@ return retval; } -int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +int flash_isset (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd) { cfiptr_t cptr; cfiword_t cword; @@ -934,10 +954,72 @@ .memmap = generic_memmap_ro, }; +#ifdef CONFIG_PARTITION_NEED_MTD +static int cfi_mtd_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct flash_info *info = container_of(mtd, struct flash_info, mtd); + + memcpy(buf, info->base + from, len); + *retlen = len; + + return 0; +} + +static int cfi_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct flash_info *info = container_of(mtd, struct flash_info, mtd); + int ret; + + ret = write_buff(info, buf, (unsigned long)info->base + to, len); + *retlen = len; + + return ret; +} + +static int cfi_mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct flash_info *info = container_of(mtd, struct flash_info, mtd); + struct cdev *cdev = &info->cdev; + int ret; + + ret = __cfi_erase(cdev, instr->len, instr->addr, 0); + + if (ret) { + instr->state = MTD_ERASE_FAILED; + return -EIO; + } + + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + + return 0; +} + +static void cfi_init_mtd(struct flash_info *info) +{ + struct mtd_info *mtd = &info->mtd; + + mtd->read = cfi_mtd_read; + mtd->write = cfi_mtd_write; + mtd->erase = cfi_mtd_erase; + mtd->size = info->size; + mtd->name = info->cdev.name; + mtd->erasesize = info->eraseregions[1].erasesize; /* FIXME */ + mtd->writesize = 1; + mtd->subpage_sft = 0; + mtd->eraseregions = info->eraseregions; + mtd->numeraseregions = info->numeraseregions; + mtd->flags = MTD_CAP_NORFLASH; + info->cdev.mtd = mtd; +} +#endif + static int cfi_probe (struct device_d *dev) { unsigned long size = 0; - flash_info_t *info = xzalloc(sizeof(flash_info_t)); + struct flash_info *info = xzalloc(sizeof(*info)); dev->priv = (void *)info; @@ -946,6 +1028,7 @@ /* Init: no FLASHes known */ info->flash_id = FLASH_UNKNOWN; size += info->size = flash_get_size(info, dev->map_base); + info->base = (void __iomem *)dev->map_base; if (dev->size == 0) { printf("cfi_probe: size : 0x%08x\n", info->size); @@ -963,6 +1046,10 @@ info->cdev.dev = dev; info->cdev.ops = &cfi_ops; info->cdev.priv = info; + +#ifdef CONFIG_PARTITION_NEED_MTD + cfi_init_mtd(info); +#endif devfs_create(&info->cdev); return 0; diff --git a/drivers/nor/cfi_flash.h b/drivers/nor/cfi_flash.h index a8fa879..057e56c 100644 --- a/drivers/nor/cfi_flash.h +++ b/drivers/nor/cfi_flash.h @@ -26,6 +26,7 @@ #include #include +#include typedef unsigned long flash_sect_t; struct cfi_cmd_set; @@ -34,7 +35,7 @@ * FLASH Info: contains chip specific data, per FLASH bank */ -typedef struct { +struct flash_info { struct driver_d driver; ulong size; /* total bank size in bytes */ ushort sector_count; /* number of erase units */ @@ -60,15 +61,21 @@ ushort cfi_offset; /* offset for cfi query */ struct cfi_cmd_set *cfi_cmd_set; struct cdev cdev; -} flash_info_t; +#ifdef CONFIG_PARTITION_NEED_MTD + struct mtd_info mtd; +#endif + int numeraseregions; + struct mtd_erase_region_info *eraseregions; + void *base; +}; struct cfi_cmd_set { - int (*flash_write_cfibuffer) (flash_info_t * info, ulong dest, const uchar * cp, int len); - int (*flash_erase_one) (flash_info_t * info, long sect); - int (*flash_is_busy) (flash_info_t * info, flash_sect_t sect); - void (*flash_read_jedec_ids) (flash_info_t * info); - void (*flash_prepare_write) (flash_info_t * info); - int (*flash_status_check) (flash_info_t * info, flash_sect_t sector, uint64_t tout, char *prompt); + int (*flash_write_cfibuffer) (struct flash_info *info, ulong dest, const uchar * cp, int len); + int (*flash_erase_one) (struct flash_info *info, long sect); + int (*flash_is_busy) (struct flash_info *info, flash_sect_t sect); + void (*flash_read_jedec_ids) (struct flash_info *info); + void (*flash_prepare_write) (struct flash_info *info); + int (*flash_status_check) (struct flash_info *info, flash_sect_t sector, uint64_t tout, char *prompt); }; extern struct cfi_cmd_set cfi_cmd_set_intel; @@ -180,21 +187,21 @@ #define CFI_FLASH_SHIFT_WIDTH 3 /* Prototypes */ -int flash_isset (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); -void flash_write_cmd (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); -flash_sect_t find_sector (flash_info_t * info, ulong addr); -int flash_status_check (flash_info_t * info, flash_sect_t sector, +int flash_isset (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd); +void flash_write_cmd (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd); +flash_sect_t find_sector (struct flash_info *info, ulong addr); +int flash_status_check (struct flash_info *info, flash_sect_t sector, uint64_t tout, char *prompt); -int flash_generic_status_check (flash_info_t * info, flash_sect_t sector, +int flash_generic_status_check (struct flash_info *info, flash_sect_t sector, uint64_t tout, char *prompt); -int flash_isequal (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd); -void flash_make_cmd (flash_info_t * info, uchar cmd, void *cmdbuf); +int flash_isequal (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd); +void flash_make_cmd (struct flash_info *info, uchar cmd, void *cmdbuf); /* * create an address based on the offset and the port width */ -static inline uchar *flash_make_addr (flash_info_t * info, flash_sect_t sect, uint offset) +static inline uchar *flash_make_addr (struct flash_info *info, flash_sect_t sect, uint offset) { return ((uchar *) (info->start[sect] + (offset * info->portwidth))); } @@ -202,7 +209,7 @@ /* * read a character at a port width address */ -static inline uchar flash_read_uchar (flash_info_t * info, uint offset) +static inline uchar flash_read_uchar (struct flash_info *info, uint offset) { uchar *cp; @@ -252,7 +259,7 @@ volatile unsigned long long *llp; } cfiptr_t; -static inline void flash_write_word(flash_info_t *info, cfiword_t datum, void *addr) +static inline void flash_write_word(struct flash_info *info, cfiword_t datum, void *addr) { if (bankwidth_is_1(info)) { debug("fw addr %p val %02x\n", addr, datum.c); @@ -268,21 +275,21 @@ } } -extern void flash_print_info (flash_info_t *); +extern void flash_print_info (struct flash_info *); extern int flash_sect_erase (ulong addr_first, ulong addr_last); extern int flash_sect_protect (int flag, ulong addr_first, ulong addr_last); /* common/flash.c */ -extern void flash_protect (int flag, ulong from, ulong to, flash_info_t *info); +extern void flash_protect (int flag, ulong from, ulong to, struct flash_info *info); extern int flash_write (char *, ulong, ulong); -extern flash_info_t *addr2info (ulong); +extern struct flash_info *addr2info (ulong); //extern int write_buff (flash_info_t *info, const uchar *src, ulong addr, ulong cnt); /* board/?/flash.c */ #if defined(CFG_FLASH_PROTECTION) -extern int flash_real_protect(flash_info_t *info, long sector, int prot); -extern void flash_read_user_serial(flash_info_t * info, void * buffer, int offset, int len); -extern void flash_read_factory_serial(flash_info_t * info, void * buffer, int offset, int len); +extern int flash_real_protect(struct flash_info *info, long sector, int prot); +extern void flash_read_user_serial(struct flash_info *info, void * buffer, int offset, int len); +extern void flash_read_factory_serial(struct flash_info *info, void * buffer, int offset, int len); #endif /* CFG_FLASH_PROTECTION */ /*----------------------------------------------------------------------- diff --git a/drivers/nor/cfi_flash_amd.c b/drivers/nor/cfi_flash_amd.c index ea4c2c9..45b7e5c 100644 --- a/drivers/nor/cfi_flash_amd.c +++ b/drivers/nor/cfi_flash_amd.c @@ -2,7 +2,7 @@ #include #include "cfi_flash.h" -static void flash_unlock_seq (flash_info_t * info) +static void flash_unlock_seq (struct flash_info *info) { flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_UNLOCK_START); flash_write_cmd (info, 0, AMD_ADDR_ACK, AMD_CMD_UNLOCK_ACK); @@ -14,7 +14,7 @@ * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct * */ -static void amd_read_jedec_ids (flash_info_t * info) +static void amd_read_jedec_ids (struct flash_info *info) { info->manufacturer_id = 0; info->device_id = 0; @@ -39,7 +39,7 @@ flash_write_cmd(info, 0, 0, AMD_CMD_RESET); } -static int flash_toggle (flash_info_t * info, flash_sect_t sect, uint offset, uchar cmd) +static int flash_toggle (struct flash_info *info, flash_sect_t sect, uint offset, uchar cmd) { cfiptr_t cptr; cfiword_t cword; @@ -66,12 +66,12 @@ * flash_is_busy - check to see if the flash is busy * This routine checks the status of the chip and returns true if the chip is busy */ -static int amd_flash_is_busy (flash_info_t * info, flash_sect_t sect) +static int amd_flash_is_busy (struct flash_info *info, flash_sect_t sect) { return flash_toggle (info, sect, 0, AMD_STATUS_TOGGLE); } -static int amd_flash_erase_one (flash_info_t * info, long sect) +static int amd_flash_erase_one (struct flash_info *info, long sect) { flash_unlock_seq(info); flash_write_cmd (info, 0, AMD_ADDR_ERASE_START, AMD_CMD_ERASE_START); @@ -81,14 +81,14 @@ return flash_status_check(info, sect, info->erase_blk_tout, "erase"); } -static void amd_flash_prepare_write(flash_info_t * info) +static void amd_flash_prepare_write(struct flash_info *info) { flash_unlock_seq(info); flash_write_cmd (info, 0, AMD_ADDR_START, AMD_CMD_WRITE); } #ifdef CONFIG_CFI_BUFFER_WRITE -static int amd_flash_write_cfibuffer (flash_info_t * info, ulong dest, const uchar * cp, +static int amd_flash_write_cfibuffer (struct flash_info *info, ulong dest, const uchar * cp, int len) { flash_sect_t sector; diff --git a/drivers/nor/cfi_flash_intel.c b/drivers/nor/cfi_flash_intel.c index e4dfdfa..4344760 100644 --- a/drivers/nor/cfi_flash_intel.c +++ b/drivers/nor/cfi_flash_intel.c @@ -7,7 +7,7 @@ * Note: assume cfi->vendor, cfi->portwidth and cfi->chipwidth are correct * */ -static void intel_read_jedec_ids (flash_info_t * info) +static void intel_read_jedec_ids (struct flash_info *info) { info->manufacturer_id = 0; info->device_id = 0; @@ -27,12 +27,12 @@ * flash_is_busy - check to see if the flash is busy * This routine checks the status of the chip and returns true if the chip is busy */ -static int intel_flash_is_busy (flash_info_t * info, flash_sect_t sect) +static int intel_flash_is_busy (struct flash_info *info, flash_sect_t sect) { return !flash_isset (info, sect, 0, FLASH_STATUS_DONE); } -static int intel_flash_erase_one (flash_info_t * info, long sect) +static int intel_flash_erase_one (struct flash_info *info, long sect) { flash_write_cmd (info, sect, 0, FLASH_CMD_CLEAR_STATUS); flash_write_cmd (info, sect, 0, FLASH_CMD_BLOCK_ERASE); @@ -41,14 +41,14 @@ return flash_status_check(info, sect, info->erase_blk_tout, "erase"); } -static void intel_flash_prepare_write(flash_info_t * info) +static void intel_flash_prepare_write(struct flash_info *info) { flash_write_cmd (info, 0, 0, FLASH_CMD_CLEAR_STATUS); flash_write_cmd (info, 0, 0, FLASH_CMD_WRITE); } #ifdef CONFIG_CFI_BUFFER_WRITE -static int intel_flash_write_cfibuffer (flash_info_t * info, ulong dest, const uchar * cp, +static int intel_flash_write_cfibuffer (struct flash_info *info, ulong dest, const uchar * cp, int len) { flash_sect_t sector; @@ -94,7 +94,7 @@ #define intel_flash_write_cfibuffer NULL #endif /* CONFIG_CFI_BUFFER_WRITE */ -static int intel_flash_status_check (flash_info_t * info, flash_sect_t sector, +static int intel_flash_status_check (struct flash_info *info, flash_sect_t sector, uint64_t tout, char *prompt) { int retcode; diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 839efeb..c7b2c52 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -3,15 +3,9 @@ if USB -config USB_EHCI - bool "EHCI driver" +source drivers/usb/host/Kconfig -config USB_ULPI - bool - -config USB_ISP1504 - select USB_ULPI - bool "ISP1504 Tranceiver support" +source drivers/usb/otg/Kconfig endif diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 57d0bed..e6f683b 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -1,6 +1,5 @@ -obj-$(CONFIG_USB) += usb.o -obj-$(CONFIG_USB_EHCI) += usb_ehci_core.o -obj-$(CONFIG_USB_ULPI) += ulpi.o -obj-$(CONFIG_USB_ISP1504) += isp1504.o +obj-$(CONFIG_USB) += core/ obj-$(CONFIG_USB_GADGET) += gadget/ +obj-y += host/ +obj-y += otg/ diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile new file mode 100644 index 0000000..d49c68d --- /dev/null +++ b/drivers/usb/core/Makefile @@ -0,0 +1,2 @@ + +obj-y += usb.o diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c new file mode 100644 index 0000000..76e033e --- /dev/null +++ b/drivers/usb/core/usb.c @@ -0,0 +1,1397 @@ +/* + * + * Most of this source has been derived from the Linux USB + * project: + * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999-2001 + * (C) Copyright Andreas Gal 1999 + * (C) Copyright Gregory P. Smith 1999 + * (C) Copyright Deti Fliegl 1999 (new USB architecture) + * (C) Copyright Randy Dunlap 2000 + * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id) + * (C) Copyright Yggdrasil Computing, Inc. 2000 + * (usb_device_id matching changes by Adam J. Richter) + * + * Adapted for barebox: + * (C) Copyright 2001 Denis Peter, MPL AG Switzerland + * + * 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 + * + */ + +/* + * How it works: + * + * Since this is a bootloader, the devices will not be automatic + * (re)configured on hotplug, but after a restart of the USB the + * device should work. + * + * For each transfer (except "Interrupt") we wait for completion. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* #define USB_DEBUG */ + +#ifdef USB_DEBUG +#define USB_PRINTF(fmt, args...) printf(fmt , ##args) +#else +#define USB_PRINTF(fmt, args...) +#endif + +#define USB_BUFSIZ 512 + +static int dev_index; +static int asynch_allowed; +static struct devrequest setup_packet; + +static int usb_hub_probe(struct usb_device *dev, int ifnum); +static int hub_port_reset(struct usb_device *dev, int port, + unsigned short *portstat); + +static LIST_HEAD(host_list); +static LIST_HEAD(usb_device_list); + +static void print_usb_device(struct usb_device *dev) +{ + printf("%s: %04x:%04x %s\n", dev->dev.name, + dev->descriptor.idVendor, + dev->descriptor.idProduct, + dev->prod); +} + +static int host_busnum; + +int usb_register_host(struct usb_host *host) +{ + list_add_tail(&host->list, &host_list); + host->busnum = host_busnum++; + asynch_allowed = 1; + return 0; +} + +/** + * set configuration number to configuration + */ +static int usb_set_configuration(struct usb_device *dev, int configuration) +{ + int res; + USB_PRINTF("set configuration %d\n", configuration); + /* set setup command */ + res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_CONFIGURATION, 0, + configuration, 0, + NULL, 0, USB_CNTL_TIMEOUT); + if (res == 0) { + dev->toggle[0] = 0; + dev->toggle[1] = 0; + return 0; + } else + return -1; +} + +/* The routine usb_set_maxpacket_ep() is extracted from the loop of routine + * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine + * when it is inlined in 1 single routine. What happens is that the register r3 + * is used as loop-count 'i', but gets overwritten later on. + * This is clearly a compiler bug, but it is easier to workaround it here than + * to update the compiler (Occurs with at least several GCC 4.{1,2},x + * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM) + */ +static void noinline +usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep) +{ + int b; + + b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + + if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == + USB_ENDPOINT_XFER_CONTROL) { + /* Control => bidirectional */ + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + dev->epmaxpacketin[b] = ep->wMaxPacketSize; + USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n", + b, dev->epmaxpacketin[b]); + } else { + if ((ep->bEndpointAddress & 0x80) == 0) { + /* OUT Endpoint */ + if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) { + dev->epmaxpacketout[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketout[%d] = %d\n", + b, dev->epmaxpacketout[b]); + } + } else { + /* IN Endpoint */ + if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) { + dev->epmaxpacketin[b] = ep->wMaxPacketSize; + USB_PRINTF("##EP epmaxpacketin[%d] = %d\n", + b, dev->epmaxpacketin[b]); + } + } /* if out */ + } /* if control */ +} + +/* + * set the max packed value of all endpoints in the given configuration + */ +static int usb_set_maxpacket(struct usb_device *dev) +{ + int i, ii; + + for (i = 0; i < dev->config.bNumInterfaces; i++) + for (ii = 0; ii < dev->config.if_desc[i].bNumEndpoints; ii++) + usb_set_maxpacket_ep(dev, + &dev->config.if_desc[i].ep_desc[ii]); + + return 0; +} + +/** + * Parse the config, located in buffer, and fills the dev->config structure. + * Note that all little/big endian swapping are done automatically. + */ +static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) +{ + struct usb_descriptor_header *head; + int index, ifno, epno, curr_if_num; + int i; + unsigned char *ch; + + ifno = -1; + epno = -1; + curr_if_num = -1; + + dev->configno = cfgno; + head = (struct usb_descriptor_header *) &buffer[0]; + if (head->bDescriptorType != USB_DT_CONFIG) { + printf(" ERROR: NOT USB_CONFIG_DESC %x\n", + head->bDescriptorType); + return -1; + } + memcpy(&dev->config, buffer, buffer[0]); + le16_to_cpus(&(dev->config.wTotalLength)); + dev->config.no_of_if = 0; + + index = dev->config.bLength; + /* Ok the first entry must be a configuration entry, + * now process the others */ + head = (struct usb_descriptor_header *) &buffer[index]; + while (index + 1 < dev->config.wTotalLength) { + switch (head->bDescriptorType) { + case USB_DT_INTERFACE: + if (((struct usb_interface_descriptor *) \ + &buffer[index])->bInterfaceNumber != curr_if_num) { + /* this is a new interface, copy new desc */ + ifno = dev->config.no_of_if; + dev->config.no_of_if++; + memcpy(&dev->config.if_desc[ifno], + &buffer[index], buffer[index]); + dev->config.if_desc[ifno].no_of_ep = 0; + dev->config.if_desc[ifno].num_altsetting = 1; + curr_if_num = + dev->config.if_desc[ifno].bInterfaceNumber; + } else { + /* found alternate setting for the interface */ + dev->config.if_desc[ifno].num_altsetting++; + } + break; + case USB_DT_ENDPOINT: + epno = dev->config.if_desc[ifno].no_of_ep; + /* found an endpoint */ + dev->config.if_desc[ifno].no_of_ep++; + memcpy(&dev->config.if_desc[ifno].ep_desc[epno], + &buffer[index], buffer[index]); + le16_to_cpus(&(dev->config.if_desc[ifno].ep_desc[epno].\ + wMaxPacketSize)); + USB_PRINTF("if %d, ep %d\n", ifno, epno); + break; + default: + if (head->bLength == 0) + return 1; + + USB_PRINTF("unknown Description Type : %x\n", + head->bDescriptorType); + + { + ch = (unsigned char *)head; + for (i = 0; i < head->bLength; i++) + USB_PRINTF("%02X ", *ch++); + USB_PRINTF("\n\n\n"); + } + break; + } + index += head->bLength; + head = (struct usb_descriptor_header *)&buffer[index]; + } + return 1; +} + +/** + * set address of a device to the value in dev->devnum. + * This can only be done by addressing the device via the default address (0) + */ +static int usb_set_address(struct usb_device *dev) +{ + int res; + + USB_PRINTF("set address %d\n", dev->devnum); + res = usb_control_msg(dev, usb_snddefctrl(dev), + USB_REQ_SET_ADDRESS, 0, + (dev->devnum), 0, + NULL, 0, USB_CNTL_TIMEOUT); + return res; +} + +static int usb_get_descriptor(struct usb_device *dev, unsigned char type, + unsigned char index, void *buf, int size) +{ + int res; + res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (type << 8) + index, 0, + buf, size, USB_CNTL_TIMEOUT); + return res; +} + +/* + * By the time we get here, the device has gotten a new device ID + * and is in the default state. We need to identify the thing and + * get the ball rolling.. + * + * Returns 0 for success, != 0 for error. + */ +static int usb_new_device(struct usb_device *dev) +{ + int addr, err; + int tmp; + unsigned char tmpbuf[USB_BUFSIZ]; + struct usb_device_descriptor *desc; + int port = -1; + struct usb_device *parent = dev->parent; + unsigned short portstatus; + + /* We still haven't set the Address yet */ + addr = dev->devnum; + dev->devnum = 0; + + /* This is a Windows scheme of initialization sequence, with double + * reset of the device (Linux uses the same sequence) + * Some equipment is said to work only with such init sequence; this + * patch is based on the work by Alan Stern: + * http://sourceforge.net/mailarchive/forum.php? + * thread_id=5729457&forum_id=5398 + */ + + /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is + * only 18 bytes long, this will terminate with a short packet. But if + * the maxpacket size is 8 or 16 the device may be waiting to transmit + * some more, or keeps on retransmitting the 8 byte header. */ + + desc = (struct usb_device_descriptor *)tmpbuf; + dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */ + /* Default to 64 byte max packet size */ + dev->maxpacketsize = PACKET_SIZE_64; + dev->epmaxpacketin[0] = 64; + dev->epmaxpacketout[0] = 64; + + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64); + if (err < 0) { + USB_PRINTF("%s: usb_get_descriptor() failed with %d\n", __func__, err); + return 1; + } + + dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0; + + /* find the port number we're at */ + if (parent) { + int j; + + for (j = 0; j < parent->maxchild; j++) { + if (parent->children[j] == dev) { + port = j; + break; + } + } + if (port < 0) { + printf("%s: cannot locate device's port.\n", __func__); + return 1; + } + + /* reset the port for the second time */ + err = hub_port_reset(dev->parent, port, &portstatus); + if (err < 0) { + printf("\n Couldn't reset port %i\n", port); + return 1; + } + } + + dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; + dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; + switch (dev->descriptor.bMaxPacketSize0) { + case 8: + dev->maxpacketsize = PACKET_SIZE_8; + break; + case 16: + dev->maxpacketsize = PACKET_SIZE_16; + break; + case 32: + dev->maxpacketsize = PACKET_SIZE_32; + break; + case 64: + dev->maxpacketsize = PACKET_SIZE_64; + break; + } + dev->devnum = addr; + + err = usb_set_address(dev); /* set address */ + + if (err < 0) { + printf("\n USB device not accepting new address " \ + "(error=%lX)\n", dev->status); + return 1; + } + + wait_ms(10); /* Let the SET_ADDRESS settle */ + + tmp = sizeof(dev->descriptor); + + err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, + &dev->descriptor, sizeof(dev->descriptor)); + if (err < tmp) { + if (err < 0) + printf("unable to get device descriptor (error=%d)\n", + err); + else + printf("USB device descriptor short read " \ + "(expected %i, got %i)\n", tmp, err); + return 1; + } + /* correct le values */ + le16_to_cpus(&dev->descriptor.bcdUSB); + le16_to_cpus(&dev->descriptor.idVendor); + le16_to_cpus(&dev->descriptor.idProduct); + le16_to_cpus(&dev->descriptor.bcdDevice); + /* only support for one config for now */ + usb_get_configuration_no(dev, &tmpbuf[0], 0); + usb_parse_config(dev, &tmpbuf[0], 0); + usb_set_maxpacket(dev); + /* we set the default configuration here */ + if (usb_set_configuration(dev, dev->config.bConfigurationValue)) { + printf("failed to set default configuration " \ + "len %d, status %lX\n", dev->act_len, dev->status); + return -1; + } + USB_PRINTF("new device: Mfr=%d, Product=%d, SerialNumber=%d\n", + dev->descriptor.iManufacturer, dev->descriptor.iProduct, + dev->descriptor.iSerialNumber); + memset(dev->mf, 0, sizeof(dev->mf)); + memset(dev->prod, 0, sizeof(dev->prod)); + memset(dev->serial, 0, sizeof(dev->serial)); + if (dev->descriptor.iManufacturer) + usb_string(dev, dev->descriptor.iManufacturer, + dev->mf, sizeof(dev->mf)); + if (dev->descriptor.iProduct) + usb_string(dev, dev->descriptor.iProduct, + dev->prod, sizeof(dev->prod)); + if (dev->descriptor.iSerialNumber) + usb_string(dev, dev->descriptor.iSerialNumber, + dev->serial, sizeof(dev->serial)); + /* now prode if the device is a hub */ + usb_hub_probe(dev, 0); + + sprintf(dev->dev.name, "usb%d-%d", dev->host->busnum, dev->devnum); + + print_usb_device(dev); + + register_device(&dev->dev); + list_add_tail(&dev->list, &usb_device_list); + + return 0; +} + +static struct usb_device *usb_alloc_new_device(void) +{ + struct usb_device *usbdev = xzalloc(sizeof (*usbdev)); + + if (!usbdev) + return NULL; + + usbdev->devnum = dev_index + 1; + usbdev->maxchild = 0; + usbdev->dev.bus = &usb_bus_type; + + dev_index++; + + return usbdev; +} + +static int __usb_init(void) +{ + struct usb_device *dev, *tmp; + struct usb_host *host; + int ret; + + list_for_each_entry_safe(dev, tmp, &usb_device_list, list) { + list_del(&dev->list); + unregister_device(&dev->dev); + if (dev->hub) + free(dev->hub); + free(dev); + } + + printf("USB: scanning bus for devices...\n"); + dev_index = 0; + + list_for_each_entry(host, &host_list, list) { + ret = host->init(host); + if (ret) + continue; + + dev = usb_alloc_new_device(); + dev->host = host; + usb_new_device(dev); + } + + 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. + */ +void usb_disable_asynch(int disable) +{ + asynch_allowed = !disable; +} + + +/*------------------------------------------------------------------- + * Message wrappers. + * + */ + +/* + * submits an Interrupt Message + */ +int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, + void *buffer, int transfer_len, int interval) +{ + struct usb_host *host = dev->host; + + return host->submit_int_msg(dev, pipe, buffer, transfer_len, interval); +} + +/* + * submits a control message and waits for comletion (at least timeout * 1ms) + * If timeout is 0, we don't wait for completion (used as example to set and + * clear keyboards LEDs). For data transfers, (storage transfers) we don't + * allow control messages with 0 timeout, by previousely resetting the flag + * asynch_allowed (usb_disable_asynch(1)). + * returns the transfered length if OK or -1 if error. The transfered length + * and the current status are stored in the dev->act_len and dev->status. + */ +int usb_control_msg(struct usb_device *dev, unsigned int pipe, + unsigned char request, unsigned char requesttype, + unsigned short value, unsigned short index, + void *data, unsigned short size, int timeout) +{ + struct usb_host *host = dev->host; + + if ((timeout == 0) && (!asynch_allowed)) { + /* request for a asynch control pipe is not allowed */ + return -1; + } + + /* set setup command */ + setup_packet.requesttype = requesttype; + setup_packet.request = request; + setup_packet.value = cpu_to_le16(value); + setup_packet.index = cpu_to_le16(index); + setup_packet.length = cpu_to_le16(size); + USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \ + "value 0x%X index 0x%X length 0x%X\n", + request, requesttype, value, index, size); + dev->status = USB_ST_NOT_PROC; /*not yet processed */ + + host->submit_control_msg(dev, pipe, data, size, &setup_packet); + if (timeout == 0) + return (int)size; + + if (dev->status != 0) { + /* + * Let's wait a while for the timeout to elapse. + * It has no real use, but it keeps the interface happy. + */ + wait_ms(timeout); + return -1; + } + + return dev->act_len; +} + +/*------------------------------------------------------------------- + * submits bulk message, and waits for completion. returns 0 if Ok or + * -1 if Error. + * synchronous behavior + */ +int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, + void *data, int len, int *actual_length, int timeout) +{ + struct usb_host *host = dev->host; + int ret; + + if (len < 0) + return -1; + + dev->status = USB_ST_NOT_PROC; /* not yet processed */ + ret = host->submit_bulk_msg(dev, pipe, data, len); + if (ret) + return ret; + + *actual_length = dev->act_len; + + return (dev->status == 0) ? 0 : -1; +} + + +/*------------------------------------------------------------------- + * Max Packet stuff + */ + +/* + * returns the max packet size, depending on the pipe direction and + * the configurations values + */ +int usb_maxpacket(struct usb_device *dev, unsigned long pipe) +{ + /* direction is out -> use emaxpacket out */ + if ((pipe & USB_DIR_IN) == 0) + return dev->epmaxpacketout[((pipe>>15) & 0xf)]; + else + return dev->epmaxpacketin[((pipe>>15) & 0xf)]; +} + +/*********************************************************************** + * Clears an endpoint + * endp: endpoint number in bits 0-3; + * direction flag in bit 7 (1 = IN, 0 = OUT) + */ +int usb_clear_halt(struct usb_device *dev, int pipe) +{ + int result; + int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7); + + result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, + endp, NULL, 0, USB_CNTL_TIMEOUT * 3); + + /* don't clear if failed */ + if (result < 0) + return result; + + /* + * NOTE: we do not get status and verify reset was successful + * as some devices are reported to lock up upon this check.. + */ + + usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + + /* toggle is reset on clear */ + usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); + return 0; +} + +/********************************************************************** + * gets configuration cfgno and store it in the buffer + */ +int usb_get_configuration_no(struct usb_device *dev, + unsigned char *buffer, int cfgno) +{ + int result; + unsigned int tmp; + struct usb_config_descriptor *config; + + + config = (struct usb_config_descriptor *)&buffer[0]; + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9); + if (result < 9) { + if (result < 0) + printf("unable to get descriptor, error %lX\n", + dev->status); + else + printf("config descriptor too short " \ + "(expected %i, got %i)\n", 9, result); + return -1; + } + tmp = le16_to_cpu(config->wTotalLength); + + if (tmp > USB_BUFSIZ) { + USB_PRINTF("usb_get_configuration_no: failed to get " \ + "descriptor - too long: %d\n", tmp); + return -1; + } + + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp); + USB_PRINTF("get_conf_no %d Result %d, wLength %d\n", + cfgno, result, tmp); + return result; +} + +/******************************************************************** + * set interface number to interface + */ +int usb_set_interface(struct usb_device *dev, int interface, int alternate) +{ + struct usb_interface_descriptor *if_face = NULL; + int ret, i; + + for (i = 0; i < dev->config.bNumInterfaces; i++) { + if (dev->config.if_desc[i].bInterfaceNumber == interface) { + if_face = &dev->config.if_desc[i]; + break; + } + } + if (!if_face) { + printf("selecting invalid interface %d", interface); + return -1; + } + /* + * We should return now for devices with only one alternate setting. + * According to 9.4.10 of the Universal Serial Bus Specification + * Revision 2.0 such devices can return with a STALL. This results in + * some USB sticks timeouting during initialization and then being + * unusable in barebox. + */ + if (if_face->num_altsetting == 1) + return 0; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, + alternate, interface, NULL, 0, + USB_CNTL_TIMEOUT * 5); + if (ret < 0) + return ret; + + return 0; +} + +/******************************************************************** + * set protocol to protocol + */ +int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * set idle + */ +int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * get report + */ +int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, + unsigned char id, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_REPORT, + USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, + (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * get class descriptor + */ +int usb_get_class_descriptor(struct usb_device *dev, int ifnum, + unsigned char type, unsigned char id, void *buf, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, + (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT); +} + +/******************************************************************** + * get string index in buffer + */ +int usb_get_string(struct usb_device *dev, unsigned short langid, + unsigned char index, void *buf, int size) +{ + int i; + int result; + + for (i = 0; i < 3; ++i) { + /* some devices are flaky */ + result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, + (USB_DT_STRING << 8) + index, langid, buf, size, + USB_CNTL_TIMEOUT); + + if (result > 0) + break; + } + + return result; +} + + +static void usb_try_string_workarounds(unsigned char *buf, int *length) +{ + int newlength, oldlength = *length; + + for (newlength = 2; newlength + 1 < oldlength; newlength += 2) + if (!isprint(buf[newlength]) || buf[newlength + 1]) + break; + + if (newlength > 2) { + buf[0] = newlength; + *length = newlength; + } +} + + +static int usb_string_sub(struct usb_device *dev, unsigned int langid, + unsigned int index, unsigned char *buf) +{ + int rc; + + /* Try to read the string descriptor by asking for the maximum + * possible number of bytes */ + rc = usb_get_string(dev, langid, index, buf, 255); + + /* If that failed try to read the descriptor length, then + * ask for just that many bytes */ + if (rc < 2) { + rc = usb_get_string(dev, langid, index, buf, 2); + if (rc == 2) + rc = usb_get_string(dev, langid, index, buf, buf[0]); + } + + if (rc >= 2) { + if (!buf[0] && !buf[1]) + usb_try_string_workarounds(buf, &rc); + + /* There might be extra junk at the end of the descriptor */ + if (buf[0] < rc) + rc = buf[0]; + + rc = rc - (rc & 1); /* force a multiple of two */ + } + + if (rc < 2) + rc = -1; + + return rc; +} + + +/******************************************************************** + * usb_string: + * Get string index and translate it to ascii. + * returns string length (> 0) or error (< 0) + */ +int usb_string(struct usb_device *dev, int index, char *buf, size_t size) +{ + unsigned char mybuf[USB_BUFSIZ]; + unsigned char *tbuf; + int err; + unsigned int u, idx; + + if (size <= 0 || !buf || !index) + return -1; + buf[0] = 0; + tbuf = &mybuf[0]; + + /* get langid for strings if it's not yet known */ + if (!dev->have_langid) { + err = usb_string_sub(dev, 0, 0, tbuf); + if (err < 0) { + USB_PRINTF("error getting string descriptor 0 " \ + "(error=%lx)\n", dev->status); + return -1; + } else if (tbuf[0] < 4) { + USB_PRINTF("string descriptor 0 too short\n"); + return -1; + } else { + dev->have_langid = -1; + dev->string_langid = tbuf[2] | (tbuf[3] << 8); + /* always use the first langid listed */ + USB_PRINTF("USB device number %d default " \ + "language ID 0x%x\n", + dev->devnum, dev->string_langid); + } + } + + err = usb_string_sub(dev, dev->string_langid, index, tbuf); + if (err < 0) + return err; + + size--; /* leave room for trailing NULL char in output buffer */ + for (idx = 0, u = 2; u < err; u += 2) { + if (idx >= size) + break; + if (tbuf[u+1]) /* high byte */ + buf[idx++] = '?'; /* non-ASCII character */ + else + buf[idx++] = tbuf[u]; + } + buf[idx] = 0; + err = idx; + return err; +} + +/**************************************************************************** + * HUB "Driver" + * Probes device for being a hub and configurate it + */ + +#undef USB_HUB_DEBUG + +#ifdef USB_HUB_DEBUG +#define USB_HUB_PRINTF(fmt, args...) printf(fmt , ##args) +#else +#define USB_HUB_PRINTF(fmt, args...) +#endif + +int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, + USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT); +} + +int usb_clear_hub_feature(struct usb_device *dev, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, + 0, NULL, 0, USB_CNTL_TIMEOUT); +} + +int usb_clear_port_feature(struct usb_device *dev, int port, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, + port, NULL, 0, USB_CNTL_TIMEOUT); +} + +int usb_set_port_feature(struct usb_device *dev, int port, int feature) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, + port, NULL, 0, USB_CNTL_TIMEOUT); +} + +int usb_get_hub_status(struct usb_device *dev, void *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, + data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); +} + +int usb_get_port_status(struct usb_device *dev, int port, void *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, + data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); +} + + +static void usb_hub_power_on(struct usb_hub_device *hub) +{ + int i; + struct usb_device *dev; + + dev = hub->pusb_dev; + /* Enable power to the ports */ + USB_HUB_PRINTF("enabling power on all ports\n"); + for (i = 0; i < dev->maxchild; i++) { + usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status); + wait_ms(hub->desc.bPwrOn2PwrGood * 2); + } +} + +#define MAX_TRIES 5 + +static inline char *portspeed(int portstatus) +{ + if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) + return "480 Mb/s"; + else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) + return "1.5 Mb/s"; + else + return "12 Mb/s"; +} + +static int hub_port_reset(struct usb_device *dev, int port, + unsigned short *portstat) +{ + int tries; + struct usb_port_status portsts; + unsigned short portstatus, portchange; + + USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port); + for (tries = 0; tries < MAX_TRIES; tries++) { + + usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET); + wait_ms(200); + + if (usb_get_port_status(dev, port + 1, &portsts) < 0) { + USB_HUB_PRINTF("get_port_status failed status %lX\n", + dev->status); + return -1; + } + portstatus = le16_to_cpu(portsts.wPortStatus); + portchange = le16_to_cpu(portsts.wPortChange); + + USB_HUB_PRINTF("portstatus %x, change %x, %s\n", + portstatus, portchange, + portspeed(portstatus)); + + USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \ + " USB_PORT_STAT_ENABLE %d\n", + (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0, + (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0, + (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); + + if ((portchange & USB_PORT_STAT_C_CONNECTION) || + !(portstatus & USB_PORT_STAT_CONNECTION)) + return -1; + + if (portstatus & USB_PORT_STAT_ENABLE) + break; + + wait_ms(200); + } + + if (tries == MAX_TRIES) { + USB_HUB_PRINTF("Cannot enable port %i after %i retries, " \ + "disabling port.\n", port + 1, MAX_TRIES); + USB_HUB_PRINTF("Maybe the USB cable is bad?\n"); + return -1; + } + + usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET); + *portstat = portstatus; + return 0; +} + + +static void usb_hub_port_connect_change(struct usb_device *dev, int port) +{ + struct usb_device *usb; + struct usb_port_status portsts; + unsigned short portstatus, portchange; + + /* Check status */ + if (usb_get_port_status(dev, port + 1, &portsts) < 0) { + USB_HUB_PRINTF("get_port_status failed\n"); + return; + } + + portstatus = le16_to_cpu(portsts.wPortStatus); + portchange = le16_to_cpu(portsts.wPortChange); + USB_HUB_PRINTF("portstatus %x, change %x, %s\n", + portstatus, portchange, portspeed(portstatus)); + + /* Clear the connection change status */ + usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION); + + /* Disconnect any existing devices under this port */ + if (((!(portstatus & USB_PORT_STAT_CONNECTION)) && + (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) { + USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n"); + /* Return now if nothing is connected */ + if (!(portstatus & USB_PORT_STAT_CONNECTION)) + return; + } + wait_ms(200); + + /* Reset the port */ + if (hub_port_reset(dev, port, &portstatus) < 0) { + printf("cannot reset port %i!?\n", port + 1); + return; + } + + wait_ms(200); + + /* Allocate a new device struct for it */ + usb = usb_alloc_new_device(); + usb->host = dev->host; + + if (portstatus & USB_PORT_STAT_HIGH_SPEED) + usb->speed = USB_SPEED_HIGH; + else if (portstatus & USB_PORT_STAT_LOW_SPEED) + usb->speed = USB_SPEED_LOW; + else + usb->speed = USB_SPEED_FULL; + + dev->children[port] = usb; + usb->parent = dev; + /* Run it through the hoops (find a driver, etc) */ + if (usb_new_device(usb)) { + /* Woops, disable the port */ + USB_HUB_PRINTF("hub: disabling port %d\n", port + 1); + usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); + } +} + + +int usb_hub_configure(struct usb_device *dev) +{ + unsigned char buffer[USB_BUFSIZ], *bitmap; + struct usb_hub_descriptor *descriptor; + struct usb_hub_status *hubsts; + int i; + struct usb_hub_device *hub; + + hub = xzalloc(sizeof (*hub)); + dev->hub = hub; + + hub->pusb_dev = dev; + /* Get the the hub descriptor */ + if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { + USB_HUB_PRINTF("%s: failed to get hub " \ + "descriptor, giving up %lX\n", __func__, dev->status); + return -1; + } + descriptor = (struct usb_hub_descriptor *)buffer; + + /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ + i = descriptor->bLength; + if (i > USB_BUFSIZ) { + USB_HUB_PRINTF("%s: failed to get hub " \ + "descriptor - too long: %d\n", __func__, + descriptor->bLength); + return -1; + } + + if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { + USB_HUB_PRINTF("%s: failed to get hub " \ + "descriptor 2nd giving up %lX\n", __func__, dev->status); + return -1; + } + memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); + /* adjust 16bit values */ + hub->desc.wHubCharacteristics = + le16_to_cpu(descriptor->wHubCharacteristics); + /* set the bitmap */ + bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; + /* devices not removable by default */ + memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); + bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; + memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ + + for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) + hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; + + for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) + hub->desc.DeviceRemovable[i] = descriptor->PortPowerCtrlMask[i]; + + dev->maxchild = descriptor->bNbrPorts; + USB_HUB_PRINTF("%d ports detected\n", dev->maxchild); + + switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) { + case 0x00: + USB_HUB_PRINTF("ganged power switching\n"); + break; + case 0x01: + USB_HUB_PRINTF("individual port power switching\n"); + break; + case 0x02: + case 0x03: + USB_HUB_PRINTF("unknown reserved power switching mode\n"); + break; + } + + if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND) + USB_HUB_PRINTF("part of a compound device\n"); + else + USB_HUB_PRINTF("standalone hub\n"); + + switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) { + case 0x00: + USB_HUB_PRINTF("global over-current protection\n"); + break; + case 0x08: + USB_HUB_PRINTF("individual port over-current protection\n"); + break; + case 0x10: + case 0x18: + USB_HUB_PRINTF("no over-current protection\n"); + break; + } + + USB_HUB_PRINTF("power on to power good time: %dms\n", + descriptor->bPwrOn2PwrGood * 2); + USB_HUB_PRINTF("hub controller current requirement: %dmA\n", + descriptor->bHubContrCurrent); + + for (i = 0; i < dev->maxchild; i++) + USB_HUB_PRINTF("port %d is%s removable\n", i + 1, + hub->desc.DeviceRemovable[(i + 1) / 8] & \ + (1 << ((i + 1) % 8)) ? " not" : ""); + + if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { + USB_HUB_PRINTF("%s: failed to get Status - " \ + "too long: %d\n", __func__, descriptor->bLength); + return -1; + } + + if (usb_get_hub_status(dev, buffer) < 0) { + USB_HUB_PRINTF("%s: failed to get Status %lX\n", __func__, + dev->status); + return -1; + } + + hubsts = (struct usb_hub_status *)buffer; + USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n", + le16_to_cpu(hubsts->wHubStatus), + le16_to_cpu(hubsts->wHubChange)); + USB_HUB_PRINTF("local power source is %s\n", + (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ + "lost (inactive)" : "good"); + USB_HUB_PRINTF("%sover-current condition exists\n", + (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ + "" : "no "); + usb_hub_power_on(hub); + + for (i = 0; i < dev->maxchild; i++) { + struct usb_port_status portsts; + unsigned short portstatus, portchange; + + if (usb_get_port_status(dev, i + 1, &portsts) < 0) { + USB_HUB_PRINTF("get_port_status failed\n"); + continue; + } + + portstatus = le16_to_cpu(portsts.wPortStatus); + portchange = le16_to_cpu(portsts.wPortChange); + USB_HUB_PRINTF("Port %d Status %X Change %X\n", + i + 1, portstatus, portchange); + + if (portchange & USB_PORT_STAT_C_CONNECTION) { + USB_HUB_PRINTF("port %d connection change\n", i + 1); + usb_hub_port_connect_change(dev, i); + } + if (portchange & USB_PORT_STAT_C_ENABLE) { + USB_HUB_PRINTF("port %d enable change, status %x\n", + i + 1, portstatus); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_ENABLE); + + /* EM interference sometimes causes bad shielded USB + * devices to be shutdown by the hub, this hack enables + * them again. Works at least with mouse driver */ + if (!(portstatus & USB_PORT_STAT_ENABLE) && + (portstatus & USB_PORT_STAT_CONNECTION) && + ((dev->children[i]))) { + USB_HUB_PRINTF("already running port %i " \ + "disabled by hub (EMI?), " \ + "re-enabling...\n", i + 1); + usb_hub_port_connect_change(dev, i); + } + } + if (portstatus & USB_PORT_STAT_SUSPEND) { + USB_HUB_PRINTF("port %d suspend change\n", i + 1); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_SUSPEND); + } + + if (portchange & USB_PORT_STAT_C_OVERCURRENT) { + USB_HUB_PRINTF("port %d over-current change\n", i + 1); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_OVER_CURRENT); + usb_hub_power_on(hub); + } + + if (portchange & USB_PORT_STAT_C_RESET) { + USB_HUB_PRINTF("port %d reset change\n", i + 1); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_RESET); + } + } /* end for i all ports */ + + return 0; +} + +static int usb_hub_probe(struct usb_device *dev, int ifnum) +{ + struct usb_interface_descriptor *iface; + struct usb_endpoint_descriptor *ep; + int ret; + + iface = &dev->config.if_desc[ifnum]; + /* Is it a hub? */ + if (iface->bInterfaceClass != USB_CLASS_HUB) + return 0; + /* Some hubs have a subclass of 1, which AFAICT according to the */ + /* specs is not defined, but it works */ + if ((iface->bInterfaceSubClass != 0) && + (iface->bInterfaceSubClass != 1)) + return 0; + /* Multiple endpoints? What kind of mutant ninja-hub is this? */ + if (iface->bNumEndpoints != 1) + return 0; + ep = &iface->ep_desc[0]; + /* Output endpoint? Curiousier and curiousier.. */ + if (!(ep->bEndpointAddress & USB_DIR_IN)) + return 0; + /* If it's not an interrupt endpoint, we'd better punt! */ + if ((ep->bmAttributes & 3) != 3) + return 0; + /* We found a hub */ + USB_HUB_PRINTF("USB hub found\n"); + ret = usb_hub_configure(dev); + return ret; +} + +int usb_driver_register(struct usb_driver *drv) +{ + drv->driver.bus = &usb_bus_type; + return register_driver(&drv->driver); +} + +/* returns 0 if no match, 1 if match */ +int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) +{ + if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && + id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) + return 0; + + if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && + id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) + return 0; + + return 1; +} + +/* returns 0 if no match, 1 if match */ +int usb_match_one_id(struct usb_device *usbdev, + const struct usb_device_id *id) +{ + /* proc_connectinfo in devio.c may call us with id == NULL. */ + if (id == NULL) + return 0; + + if (!usb_match_device(usbdev, id)) + return 0; + + return 1; +} +EXPORT_SYMBOL(usb_match_one_id); + +const struct usb_device_id *usb_match_id(struct usb_device *usbdev, + const struct usb_device_id *id) +{ + /* proc_connectinfo in devio.c may call us with id == NULL. */ + if (id == NULL) + return NULL; + + /* It is important to check that id->driver_info is nonzero, + since an entry that is all zeroes except for a nonzero + id->driver_info is the way to create an entry that + indicates that the driver want to examine every + device and interface. */ + for (; id->idVendor || id->idProduct || id->bDeviceClass || + id->bInterfaceClass || id->driver_info; id++) { + if (usb_match_one_id(usbdev, id)) + return id; + } + + return NULL; +} +EXPORT_SYMBOL(usb_match_id); + +static int usb_match(struct device_d *dev, struct driver_d *drv) +{ + struct usb_device *usbdev = container_of(dev, struct usb_device, dev); + struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); + const struct usb_device_id *id; + + debug("matching: 0x%04x 0x%04x\n", usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); + + id = usb_match_id(usbdev, usbdrv->id_table); + if (id) { + debug("match: 0x%04x 0x%04x\n", id->idVendor, id->idProduct); + return 0; + } + return 1; +} + +static int usb_probe(struct device_d *dev) +{ + struct usb_device *usbdev = container_of(dev, struct usb_device, dev); + struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); + const struct usb_device_id *id; + + id = usb_match_id(usbdev, usbdrv->id_table); + + return usbdrv->probe(usbdev, id); +} + +static void usb_remove(struct device_d *dev) +{ + struct usb_device *usbdev = container_of(dev, struct usb_device, dev); + struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); + + usbdrv->disconnect(usbdev); +} + +struct bus_type usb_bus_type = { + .name = "usb", + .match = usb_match, + .probe = usb_probe, + .remove = usb_remove, +}; + diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig new file mode 100644 index 0000000..e1549e8 --- /dev/null +++ b/drivers/usb/host/Kconfig @@ -0,0 +1,2 @@ +config USB_EHCI + bool "EHCI driver" diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile new file mode 100644 index 0000000..6c48e3a --- /dev/null +++ b/drivers/usb/host/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_EHCI) += ehci-hcd.o diff --git a/drivers/usb/host/ehci-core.h b/drivers/usb/host/ehci-core.h new file mode 100644 index 0000000..39e5c5e --- /dev/null +++ b/drivers/usb/host/ehci-core.h @@ -0,0 +1,29 @@ +/*- + * Copyright (c) 2007-2008, Juniper Networks, Inc. + * Copyright (c) 2008, Excito Elektronik i Skåne AB + * All rights reserved. + * + * 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 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 + */ + +#ifndef USB_EHCI_CORE_H +#define USB_EHCI_CORE_H + +extern int rootdev; +extern struct ehci_hccr *hccr; +extern volatile struct ehci_hcor *hcor; + +#endif diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c new file mode 100644 index 0000000..8995fa3 --- /dev/null +++ b/drivers/usb/host/ehci-hcd.c @@ -0,0 +1,938 @@ +/*- + * Copyright (c) 2007-2008, Juniper Networks, Inc. + * Copyright (c) 2008, Excito Elektronik i Skåne AB + * Copyright (c) 2008, Michael Trimarchi + * + * All rights reserved. + * + * 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ehci.h" + +struct ehci_priv { + int rootdev; + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; + struct usb_host host; + struct QH *qh_list; + void *qhp; + int portreset; + unsigned long flags; +}; + +#define to_ehci(ptr) container_of(ptr, struct ehci_priv, host) + +static struct descriptor { + struct usb_hub_descriptor hub; + struct usb_device_descriptor device; + struct usb_linux_config_descriptor config; + struct usb_linux_interface_descriptor interface; + struct usb_endpoint_descriptor endpoint; +} __attribute__ ((packed)) descriptor = { + { + 0x8, /* bDescLength */ + 0x29, /* bDescriptorType: hub descriptor */ + 2, /* bNrPorts -- runtime modified */ + 0, /* wHubCharacteristics */ + 0xff, /* bPwrOn2PwrGood */ + 0, /* bHubCntrCurrent */ + {}, /* Device removable */ + {} /* at most 7 ports! XXX */ + }, + { + 0x12, /* bLength */ + 1, /* bDescriptorType: UDESC_DEVICE */ + 0x0002, /* bcdUSB: v2.0 */ + 9, /* bDeviceClass: UDCLASS_HUB */ + 0, /* bDeviceSubClass: UDSUBCLASS_HUB */ + 1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */ + 64, /* bMaxPacketSize: 64 bytes */ + 0x0000, /* idVendor */ + 0x0000, /* idProduct */ + 0x0001, /* bcdDevice */ + 1, /* iManufacturer */ + 2, /* iProduct */ + 0, /* iSerialNumber */ + 1 /* bNumConfigurations: 1 */ + }, + { + 0x9, + 2, /* bDescriptorType: UDESC_CONFIG */ + cpu_to_le16(0x19), + 1, /* bNumInterface */ + 1, /* bConfigurationValue */ + 0, /* iConfiguration */ + 0x40, /* bmAttributes: UC_SELF_POWER */ + 0 /* bMaxPower */ + }, + { + 0x9, /* bLength */ + 4, /* bDescriptorType: UDESC_INTERFACE */ + 0, /* bInterfaceNumber */ + 0, /* bAlternateSetting */ + 1, /* bNumEndpoints */ + 9, /* bInterfaceClass: UICLASS_HUB */ + 0, /* bInterfaceSubClass: UISUBCLASS_HUB */ + 0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */ + 0 /* iInterface */ + }, + { + 0x7, /* bLength */ + 5, /* bDescriptorType: UDESC_ENDPOINT */ + 0x81, /* bEndpointAddress: + * UE_DIR_IN | EHCI_INTR_ENDPT + */ + 3, /* bmAttributes: UE_INTERRUPT */ + 8, 0, /* wMaxPacketSize */ + 255 /* bInterval */ + }, +}; + +#define ehci_is_TDI() (ehci->flags & EHCI_HAS_TT) + +#ifdef CONFIG_MMU +/* + * Routines to handle (flush/invalidate) the dcache for the QH and qTD + * structures and data buffers. This is needed on platforms using this + * EHCI support with dcache enabled. + */ +static void flush_invalidate(void *addr, int size, int flush) +{ + if (flush) + dma_flush_range((unsigned long)addr, (unsigned long)(addr + size)); + else + dma_inv_range((unsigned long)addr, (unsigned long)(addr + size)); +} + +static void cache_qtd(struct qTD *qtd, int flush) +{ + u32 *ptr = (u32 *)qtd->qt_buffer[0]; + int len = (qtd->qt_token & 0x7fff0000) >> 16; + + flush_invalidate(qtd, sizeof(struct qTD), flush); + if (ptr && len) + flush_invalidate(ptr, len, flush); +} + + +static inline struct QH *qh_addr(struct QH *qh) +{ + return (struct QH *)((u32)qh & 0xffffffe0); +} + +static void cache_qh(struct QH *qh, int flush) +{ + struct qTD *qtd; + struct qTD *next; + static struct qTD *first_qtd; + + /* + * Walk the QH list and flush/invalidate all entries + */ + while (1) { + flush_invalidate(qh_addr(qh), sizeof(struct QH), flush); + if ((u32)qh & QH_LINK_TYPE_QH) + break; + qh = qh_addr(qh); + qh = (struct QH *)qh->qh_link; + } + qh = qh_addr(qh); + + /* + * Save first qTD pointer, needed for invalidating pass on this QH + */ + if (flush) + first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay & + 0xffffffe0); + else + qtd = first_qtd; + + /* + * Walk the qTD list and flush/invalidate all entries + */ + while (1) { + if (qtd == NULL) + break; + cache_qtd(qtd, flush); + next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0); + if (next == qtd) + break; + qtd = next; + } +} + +static inline void ehci_flush_dcache(struct QH *qh) +{ + cache_qh(qh, 1); +} + +static inline void ehci_invalidate_dcache(struct QH *qh) +{ + cache_qh(qh, 0); +} +#else /* CONFIG_MMU */ +/* + * + */ +static inline void ehci_flush_dcache(struct QH *qh) +{ +} + +static inline void ehci_invalidate_dcache(struct QH *qh) +{ +} +#endif /* CONFIG_MMU */ + +static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec) +{ + uint32_t result; + uint64_t start; + + start = get_time_ns(); + + while (1) { + result = ehci_readl(ptr); + if (result == ~(uint32_t)0) + return -1; + result &= mask; + if (result == done) + return 0; + if (is_timeout(start, usec * USECOND)) + return -ETIMEDOUT; + } +} + +static int ehci_reset(struct ehci_priv *ehci) +{ + uint32_t cmd; + uint32_t tmp; + uint32_t *reg_ptr; + int ret = 0; + + cmd = ehci_readl(&ehci->hcor->or_usbcmd); + cmd |= CMD_RESET; + ehci_writel(&ehci->hcor->or_usbcmd, cmd); + ret = handshake(&ehci->hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000); + if (ret < 0) { + printf("EHCI fail to reset\n"); + goto out; + } + + if (ehci_is_TDI()) { + reg_ptr = (uint32_t *)((u8 *)ehci->hcor + USBMODE); + tmp = ehci_readl(reg_ptr); + tmp |= USBMODE_CM_HC; +#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) + tmp |= USBMODE_BE; +#endif + ehci_writel(reg_ptr, tmp); + } +out: + return ret; +} + +static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) +{ + uint32_t addr, delta, next; + int idx; + + addr = (uint32_t) buf; + idx = 0; + while (idx < 5) { + td->qt_buffer[idx] = cpu_to_hc32(addr); + next = (addr + 4096) & ~4095; + delta = next - addr; + if (delta >= sz) + break; + sz -= delta; + addr = next; + idx++; + } + + if (idx == 5) { + debug("out of buffer pointers (%u bytes left)\n", sz); + return -1; + } + + return 0; +} + +static int +ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, struct devrequest *req) +{ + struct usb_host *host = dev->host; + struct ehci_priv *ehci = to_ehci(host); + struct QH *qh; + struct qTD *td; + volatile struct qTD *vtd; + uint32_t *tdp; + uint32_t endpt, token, usbsts; + uint32_t c, toggle; + uint32_t cmd; + int ret = 0; + uint64_t start; + static struct QH __qh __attribute__((aligned(32))); + static struct qTD __td[3] __attribute__((aligned(32))); + + debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, + buffer, length, req); + if (req != NULL) + debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n", + req->request, req->request, + req->requesttype, req->requesttype, + le16_to_cpu(req->value), le16_to_cpu(req->value), + le16_to_cpu(req->index)); + + memset(&__qh, sizeof(struct QH), 0); + memset(&__td, sizeof(struct qTD) * 3, 0); + + qh = &__qh; + qh->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); + c = (usb_pipespeed(pipe) != USB_SPEED_HIGH && + usb_pipeendpoint(pipe) == 0) ? 1 : 0; + endpt = (8 << 28) | + (c << 27) | + (usb_maxpacket(dev, pipe) << 16) | + (0 << 15) | + (1 << 14) | + (usb_pipespeed(pipe) << 12) | + (usb_pipeendpoint(pipe) << 8) | + (0 << 7) | (usb_pipedevice(pipe) << 0); + qh->qh_endpt1 = cpu_to_hc32(endpt); + endpt = (1 << 30) | + (dev->portnr << 23) | + (dev->parent->devnum << 16) | (0 << 8) | (0 << 0); + qh->qh_endpt2 = cpu_to_hc32(endpt); + qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + + td = NULL; + tdp = &qh->qh_overlay.qt_next; + + toggle = + usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); + + if (req != NULL) { + td = &__td[0]; + + td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + token = (0 << 31) | + (sizeof(*req) << 16) | + (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0); + td->qt_token = cpu_to_hc32(token); + if (ehci_td_buffer(td, req, sizeof(*req)) != 0) { + debug("unable construct SETUP td\n"); + goto fail; + } + *tdp = cpu_to_hc32((uint32_t) td); + tdp = &td->qt_next; + + toggle = 1; + } + + if (length > 0 || req == NULL) { + td = &__td[1]; + + td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + token = (toggle << 31) | + (length << 16) | + ((req == NULL ? 1 : 0) << 15) | + (0 << 12) | + (3 << 10) | + ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0); + td->qt_token = cpu_to_hc32(token); + if (ehci_td_buffer(td, buffer, length) != 0) { + printf("unable construct DATA td\n"); + goto fail; + } + *tdp = cpu_to_hc32((uint32_t) td); + tdp = &td->qt_next; + } + + if (req) { + td = &__td[2]; + + td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + token = (toggle << 31) | + (0 << 16) | + (1 << 15) | + (0 << 12) | + (3 << 10) | + ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0); + td->qt_token = cpu_to_hc32(token); + *tdp = cpu_to_hc32((uint32_t)td); + tdp = &td->qt_next; + } + + ehci->qh_list->qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH); + + /* Flush dcache */ + ehci_flush_dcache(ehci->qh_list); + + usbsts = ehci_readl(&ehci->hcor->or_usbsts); + ehci_writel(&ehci->hcor->or_usbsts, (usbsts & 0x3f)); + + /* Enable async. schedule. */ + cmd = ehci_readl(&ehci->hcor->or_usbcmd); + cmd |= CMD_ASE; + ehci_writel(&ehci->hcor->or_usbcmd, cmd); + + ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, STD_ASS, 100 * 1000); + if (ret < 0) { + printf("EHCI fail timeout STD_ASS set\n"); + goto fail; + } + + /* Wait for TDs to be processed. */ + start = get_time_ns(); + vtd = td; + do { + /* Invalidate dcache */ + ehci_invalidate_dcache(ehci->qh_list); + token = hc32_to_cpu(vtd->qt_token); + if (is_timeout(start, SECOND >> 2)) { + /* Disable async schedule. */ + cmd = ehci_readl(&ehci->hcor->or_usbcmd); + cmd &= ~CMD_ASE; + ehci_writel(&ehci->hcor->or_usbcmd, cmd); + + ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, 0, 100 * 1000); + ehci_writel(&qh->qh_overlay.qt_token, 0); + return -ETIMEDOUT; + } + } while (token & 0x80); + + /* Disable async schedule. */ + cmd = ehci_readl(&ehci->hcor->or_usbcmd); + cmd &= ~CMD_ASE; + ehci_writel(&ehci->hcor->or_usbcmd, cmd); + + ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, 0, + 100 * 1000); + if (ret < 0) { + printf("EHCI fail timeout STD_ASS reset\n"); + goto fail; + } + + ehci->qh_list->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); + + token = hc32_to_cpu(qh->qh_overlay.qt_token); + if (!(token & 0x80)) { + debug("TOKEN=0x%08x\n", token); + switch (token & 0xfc) { + case 0: + toggle = token >> 31; + usb_settoggle(dev, usb_pipeendpoint(pipe), + usb_pipeout(pipe), toggle); + dev->status = 0; + break; + case 0x40: + dev->status = USB_ST_STALLED; + break; + case 0xa0: + case 0x20: + dev->status = USB_ST_BUF_ERR; + break; + case 0x50: + case 0x10: + dev->status = USB_ST_BABBLE_DET; + break; + default: + dev->status = USB_ST_CRC_ERR; + break; + } + dev->act_len = length - ((token >> 16) & 0x7fff); + } else { + dev->act_len = 0; + debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n", + dev->devnum, ehci_readl(&ehci->hcor->or_usbsts), + ehci_readl(&ehci->hcor->or_portsc[0]), + ehci_readl(&ehci->hcor->or_portsc[1])); + } + + return (dev->status != USB_ST_NOT_PROC) ? 0 : -1; + +fail: + printf("fail1\n"); + td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); + while (td != (void *)QT_NEXT_TERMINATE) { + qh->qh_overlay.qt_next = td->qt_next; + td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); + } + return -1; +} + +static inline int min3(int a, int b, int c) +{ + + if (b < a) + a = b; + if (c < a) + a = c; + return a; +} + +int +ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, struct devrequest *req) +{ + struct usb_host *host = dev->host; + struct ehci_priv *ehci = to_ehci(host); + uint8_t tmpbuf[4]; + u16 typeReq; + void *srcptr = NULL; + int len, srclen; + uint32_t reg; + uint32_t *status_reg; + + if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { + printf("The request port(%d) is not configured\n", + le16_to_cpu(req->index) - 1); + return -1; + } + status_reg = (uint32_t *)&ehci->hcor->or_portsc[le16_to_cpu(req->index) - 1]; + srclen = 0; + + debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", + req->request, req->request, + req->requesttype, req->requesttype, + le16_to_cpu(req->value), le16_to_cpu(req->index)); + + typeReq = req->request | (req->requesttype << 8); + + switch (typeReq) { + case DeviceRequest | USB_REQ_GET_DESCRIPTOR: + switch (le16_to_cpu(req->value) >> 8) { + case USB_DT_DEVICE: + debug("USB_DT_DEVICE request\n"); + srcptr = &descriptor.device; + srclen = 0x12; + break; + case USB_DT_CONFIG: + debug("USB_DT_CONFIG config\n"); + srcptr = &descriptor.config; + srclen = 0x19; + break; + case USB_DT_STRING: + debug("USB_DT_STRING config\n"); + switch (le16_to_cpu(req->value) & 0xff) { + case 0: /* Language */ + srcptr = "\4\3\1\0"; + srclen = 4; + break; + case 1: /* Vendor */ + srcptr = "\16\3u\0-\0b\0o\0o\0t\0"; + srclen = 14; + break; + case 2: /* Product */ + srcptr = "\52\3E\0H\0C\0I\0 " + "\0H\0o\0s\0t\0 " + "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0"; + srclen = 42; + break; + default: + debug("unknown value DT_STRING %x\n", + le16_to_cpu(req->value)); + goto unknown; + } + break; + default: + debug("unknown value %x\n", le16_to_cpu(req->value)); + goto unknown; + } + break; + case ((USB_DIR_IN | USB_RT_HUB) << 8) | USB_REQ_GET_DESCRIPTOR: + switch (le16_to_cpu(req->value) >> 8) { + case USB_DT_HUB: + debug("USB_DT_HUB config\n"); + srcptr = &descriptor.hub; + srclen = 0x8; + break; + default: + debug("unknown value %x\n", le16_to_cpu(req->value)); + goto unknown; + } + break; + case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8): + debug("USB_REQ_SET_ADDRESS\n"); + ehci->rootdev = le16_to_cpu(req->value); + break; + case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: + debug("USB_REQ_SET_CONFIGURATION\n"); + /* Nothing to do */ + break; + case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8): + tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */ + tmpbuf[1] = 0; + srcptr = tmpbuf; + srclen = 2; + break; + case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): + memset(tmpbuf, 0, 4); + reg = ehci_readl(status_reg); + if (reg & EHCI_PS_CS) + tmpbuf[0] |= USB_PORT_STAT_CONNECTION; + if (reg & EHCI_PS_PE) + tmpbuf[0] |= USB_PORT_STAT_ENABLE; + if (reg & EHCI_PS_SUSP) + tmpbuf[0] |= USB_PORT_STAT_SUSPEND; + if (reg & EHCI_PS_OCA) + tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT; + if (reg & EHCI_PS_PR && + (ehci->portreset & (1 << le16_to_cpu(req->index)))) { + int ret; + /* force reset to complete */ + reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR); + ehci_writel(status_reg, reg); + ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000); + if (!ret) + tmpbuf[0] |= USB_PORT_STAT_RESET; + else + printf("port(%d) reset error\n", + le16_to_cpu(req->index) - 1); + } + if (reg & EHCI_PS_PP) + tmpbuf[1] |= USB_PORT_STAT_POWER >> 8; + + if (ehci_is_TDI()) { + switch ((reg >> 26) & 3) { + case 0: + break; + case 1: + tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8; + break; + case 2: + default: + tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8; + break; + } + } else { + tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8; + } + + if (reg & EHCI_PS_CSC) + tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION; + if (reg & EHCI_PS_PEC) + tmpbuf[2] |= USB_PORT_STAT_C_ENABLE; + if (reg & EHCI_PS_OCC) + tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT; + if (ehci->portreset & (1 << le16_to_cpu(req->index))) + tmpbuf[2] |= USB_PORT_STAT_C_RESET; + + srcptr = tmpbuf; + srclen = 4; + break; + case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): + reg = ehci_readl(status_reg); + reg &= ~EHCI_PS_CLEAR; + switch (le16_to_cpu(req->value)) { + case USB_PORT_FEAT_ENABLE: + reg |= EHCI_PS_PE; + ehci_writel(status_reg, reg); + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(ehci_readl(&ehci->hccr->cr_hcsparams))) { + reg |= EHCI_PS_PP; + ehci_writel(status_reg, reg); + } + break; + case USB_PORT_FEAT_RESET: + if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS && + !ehci_is_TDI() && + EHCI_PS_IS_LOWSPEED(reg)) { + /* Low speed device, give up ownership. */ + debug("port %d low speed --> companion\n", + req->index - 1); + reg |= EHCI_PS_PO; + ehci_writel(status_reg, reg); + break; + } else { + int ret; + + reg |= EHCI_PS_PR; + reg &= ~EHCI_PS_PE; + ehci_writel(status_reg, reg); + /* + * caller must wait, then call GetPortStatus + * usb 2.0 specification say 50 ms resets on + * root + */ + wait_ms(50); + ehci->portreset |= 1 << le16_to_cpu(req->index); + /* terminate the reset */ + ehci_writel(status_reg, reg & ~EHCI_PS_PR); + /* + * A host controller must terminate the reset + * and stabilize the state of the port within + * 2 milliseconds + */ + ret = handshake(status_reg, EHCI_PS_PR, 0, + 2 * 1000); + if (!ret) + ehci->portreset |= + 1 << le16_to_cpu(req->index); + else + printf("port(%d) reset error\n", + le16_to_cpu(req->index) - 1); + + } + break; + default: + debug("unknown feature %x\n", le16_to_cpu(req->value)); + goto unknown; + } + /* unblock posted writes */ + ehci_readl(&ehci->hcor->or_usbcmd); + break; + case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): + reg = ehci_readl(status_reg); + switch (le16_to_cpu(req->value)) { + case USB_PORT_FEAT_ENABLE: + reg &= ~EHCI_PS_PE; + break; + case USB_PORT_FEAT_C_ENABLE: + reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE; + break; + case USB_PORT_FEAT_POWER: + if (HCS_PPC(ehci_readl(&ehci->hccr->cr_hcsparams))) + reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP); + case USB_PORT_FEAT_C_CONNECTION: + reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC; + break; + case USB_PORT_FEAT_OVER_CURRENT: + reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; + break; + case USB_PORT_FEAT_C_RESET: + ehci->portreset &= ~(1 << le16_to_cpu(req->index)); + break; + default: + debug("unknown feature %x\n", le16_to_cpu(req->value)); + goto unknown; + } + ehci_writel(status_reg, reg); + /* unblock posted write */ + ehci_readl(&ehci->hcor->or_usbcmd); + break; + default: + debug("Unknown request\n"); + goto unknown; + } + + wait_ms(1); + len = min3(srclen, le16_to_cpu(req->length), length); + if (srcptr != NULL && len > 0) + memcpy(buffer, srcptr, len); + else + debug("Len is 0\n"); + + dev->act_len = len; + dev->status = 0; + return 0; + +unknown: + debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n", + req->requesttype, req->request, le16_to_cpu(req->value), + le16_to_cpu(req->index), le16_to_cpu(req->length)); + + dev->act_len = 0; + dev->status = USB_ST_STALLED; + return -1; +} + +/* force HC to halt state from unknown (EHCI spec section 2.3) */ +static int ehci_halt(struct ehci_priv *ehci) +{ + u32 temp = ehci_readl(&ehci->hcor->or_usbsts); + + /* disable any irqs left enabled by previous code */ + ehci_writel(&ehci->hcor->or_usbintr, 0); + + if (temp & STS_HALT) + return 0; + + temp = ehci_readl(&ehci->hcor->or_usbcmd); + temp &= ~CMD_RUN; + ehci_writel(&ehci->hcor->or_usbcmd, temp); + + return handshake(&ehci->hcor->or_usbsts, + STS_HALT, STS_HALT, 16 * 125); +} + +static int ehci_init(struct usb_host *host) +{ + struct ehci_priv *ehci = to_ehci(host); + uint32_t reg; + uint32_t cmd; + + ehci_halt(ehci); + + /* EHCI spec section 4.1 */ + if (ehci_reset(ehci) != 0) + return -1; + + /* Set head of reclaim list */ + ehci->qhp = xzalloc(sizeof(struct QH) + 32); + ehci->qh_list = (struct QH *)(((unsigned long)ehci->qhp + 32) & ~31); + + ehci->qh_list->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); + ehci->qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12)); + ehci->qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE); + ehci->qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); + ehci->qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + ehci->qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40); + + /* Set async. queue head pointer. */ + ehci_writel(&ehci->hcor->or_asynclistaddr, (uint32_t)ehci->qh_list); + + reg = ehci_readl(&ehci->hccr->cr_hcsparams); + descriptor.hub.bNbrPorts = HCS_N_PORTS(reg); + + /* Port Indicators */ + if (HCS_INDICATOR(reg)) + descriptor.hub.wHubCharacteristics |= 0x80; + /* Port Power Control */ + if (HCS_PPC(reg)) + descriptor.hub.wHubCharacteristics |= 0x01; + + /* Start the host controller. */ + cmd = ehci_readl(&ehci->hcor->or_usbcmd); + /* + * Philips, Intel, and maybe others need CMD_RUN before the + * root hub will detect new devices (why?); NEC doesn't + */ + cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); + cmd |= CMD_RUN; + ehci_writel(&ehci->hcor->or_usbcmd, cmd); + + /* take control over the ports */ + cmd = ehci_readl(&ehci->hcor->or_configflag); + cmd |= FLAG_CF; + ehci_writel(&ehci->hcor->or_configflag, cmd); + /* unblock posted write */ + cmd = ehci_readl(&ehci->hcor->or_usbcmd); + wait_ms(5); + + ehci->rootdev = 0; + + return 0; +} + +static int +submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length) +{ + + if (usb_pipetype(pipe) != PIPE_BULK) { + debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe)); + return -1; + } + return ehci_submit_async(dev, pipe, buffer, length, NULL); +} + +static int +submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, struct devrequest *setup) +{ + struct usb_host *host = dev->host; + struct ehci_priv *ehci = to_ehci(host); + + if (usb_pipetype(pipe) != PIPE_CONTROL) { + debug("non-control pipe (type=%lu)", usb_pipetype(pipe)); + return -1; + } + + if (usb_pipedevice(pipe) == ehci->rootdev) { + if (ehci->rootdev == 0) + dev->speed = USB_SPEED_HIGH; + return ehci_submit_root(dev, pipe, buffer, length, setup); + } + return ehci_submit_async(dev, pipe, buffer, length, setup); +} + +static int +submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, + int length, int interval) +{ + debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d", + dev, pipe, buffer, length, interval); + return -1; +} + +static int ehci_probe(struct device_d *dev) +{ + struct usb_host *host; + struct ehci_priv *ehci; + uint32_t reg; + struct ehci_platform_data *pdata = dev->platform_data; + + ehci = xmalloc(sizeof(struct ehci_priv)); + host = &ehci->host; + + if (pdata) + ehci->flags = pdata->flags; + else + /* default to EHCI_HAS_TT to not change behaviour of boards + * with platform_data + */ + ehci->flags = EHCI_HAS_TT; + + host->init = ehci_init; + host->submit_int_msg = submit_int_msg; + host->submit_control_msg = submit_control_msg; + host->submit_bulk_msg = submit_bulk_msg; + + ehci->hccr = (void *)(dev->map_base + 0x100); + ehci->hcor = (void *)(dev->map_base + 0x140); + + usb_register_host(host); + + reg = HC_VERSION(ehci_readl(&ehci->hccr->cr_capbase)); + dev_info(dev, "USB EHCI %x.%02x\n", reg >> 8, reg & 0xff); + + return 0; +} + +static struct driver_d ehci_driver = { + .name = "ehci", + .probe = ehci_probe, +}; + +static int ehcil_init(void) +{ + register_driver(&ehci_driver); + return 0; +} + +device_initcall(ehcil_init); + diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h new file mode 100644 index 0000000..af49249 --- /dev/null +++ b/drivers/usb/host/ehci.h @@ -0,0 +1,190 @@ +/*- + * Copyright (c) 2007-2008, Juniper Networks, Inc. + * Copyright (c) 2008, Michael Trimarchi + * All rights reserved. + * + * 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 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 + */ + +#ifndef USB_EHCI_H +#define USB_EHCI_H + +#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) +#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2 +#endif + +/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */ +#define DeviceRequest \ + ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8) + +#define DeviceOutRequest \ + ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8) + +#define InterfaceRequest \ + ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) + +#define EndpointRequest \ + ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) + +#define EndpointOutRequest \ + ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) + +/* + * Register Space. + */ +struct ehci_hccr { + uint32_t cr_capbase; +#define HC_LENGTH(p) (((p) >> 0) & 0x00ff) +#define HC_VERSION(p) (((p) >> 16) & 0xffff) + uint32_t cr_hcsparams; +#define HCS_PPC(p) ((p) & (1 << 4)) +#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* Port indicators */ +#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) + uint32_t cr_hccparams; + uint8_t cr_hcsp_portrt[8]; +} __attribute__ ((packed)); + +struct ehci_hcor { + uint32_t or_usbcmd; +#define CMD_PARK (1 << 11) /* enable "park" */ +#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */ +#define CMD_ASE (1 << 5) /* async schedule enable */ +#define CMD_LRESET (1 << 7) /* partial reset */ +#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */ +#define CMD_PSE (1 << 4) /* periodic schedule enable */ +#define CMD_RESET (1 << 1) /* reset HC not bus */ +#define CMD_RUN (1 << 0) /* start/stop HC */ + uint32_t or_usbsts; +#define STD_ASS (1 << 15) +#define STS_HALT (1 << 12) + uint32_t or_usbintr; + uint32_t or_frindex; + uint32_t or_ctrldssegment; + uint32_t or_periodiclistbase; + uint32_t or_asynclistaddr; + uint32_t _reserved_[9]; + uint32_t or_configflag; +#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */ + uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS]; + uint32_t or_systune; +} __attribute__ ((packed)); + +#define USBMODE 0x68 /* USB Device mode */ +#define USBMODE_SDIS (1 << 3) /* Stream disable */ +#define USBMODE_BE (1 << 2) /* BE/LE endiannes select */ +#define USBMODE_CM_HC (3 << 0) /* host controller mode */ +#define USBMODE_CM_IDLE (0 << 0) /* idle state */ + +/* Interface descriptor */ +struct usb_linux_interface_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned char bInterfaceNumber; + unsigned char bAlternateSetting; + unsigned char bNumEndpoints; + unsigned char bInterfaceClass; + unsigned char bInterfaceSubClass; + unsigned char bInterfaceProtocol; + unsigned char iInterface; +} __attribute__ ((packed)); + +/* Configuration descriptor information.. */ +struct usb_linux_config_descriptor { + unsigned char bLength; + unsigned char bDescriptorType; + unsigned short wTotalLength; + unsigned char bNumInterfaces; + unsigned char bConfigurationValue; + unsigned char iConfiguration; + unsigned char bmAttributes; + unsigned char MaxPower; +} __attribute__ ((packed)); + +#if defined CONFIG_EHCI_DESC_BIG_ENDIAN +#define ehci_readl(x) (*((volatile u32 *)(x))) +#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b)) +#else +#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x)))) +#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \ + cpu_to_le32(((volatile u32)b))) +#endif + +#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN +#define hc32_to_cpu(x) be32_to_cpu((x)) +#define cpu_to_hc32(x) cpu_to_be32((x)) +#else +#define hc32_to_cpu(x) le32_to_cpu((x)) +#define cpu_to_hc32(x) cpu_to_le32((x)) +#endif + +#define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */ +#define EHCI_PS_WKDSCNNT_E (1 << 21) /* RW wake on disconnect */ +#define EHCI_PS_WKCNNT_E (1 << 20) /* RW wake on connect */ +#define EHCI_PS_PO (1 << 13) /* RW port owner */ +#define EHCI_PS_PP (1 << 12) /* RW,RO port power */ +#define EHCI_PS_LS (3 << 10) /* RO line status */ +#define EHCI_PS_PR (1 << 8) /* RW port reset */ +#define EHCI_PS_SUSP (1 << 7) /* RW suspend */ +#define EHCI_PS_FPR (1 << 6) /* RW force port resume */ +#define EHCI_PS_OCC (1 << 5) /* RWC over current change */ +#define EHCI_PS_OCA (1 << 4) /* RO over current active */ +#define EHCI_PS_PEC (1 << 3) /* RWC port enable change */ +#define EHCI_PS_PE (1 << 2) /* RW port enable */ +#define EHCI_PS_CSC (1 << 1) /* RWC connect status change */ +#define EHCI_PS_CS (1 << 0) /* RO connect status */ +#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC) + +#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == (1 << 10)) + +/* + * Schedule Interface Space. + * + * IMPORTANT: Software must ensure that no interface data structure + * reachable by the EHCI host controller spans a 4K page boundary! + * + * Periodic transfers (i.e. isochronous and interrupt transfers) are + * not supported. + */ + +/* Queue Element Transfer Descriptor (qTD). */ +struct qTD { + uint32_t qt_next; +#define QT_NEXT_TERMINATE 1 + uint32_t qt_altnext; + uint32_t qt_token; + uint32_t qt_buffer[5]; +}; + +/* Queue Head (QH). */ +struct QH { + uint32_t qh_link; +#define QH_LINK_TERMINATE 1 +#define QH_LINK_TYPE_ITD 0 +#define QH_LINK_TYPE_QH 2 +#define QH_LINK_TYPE_SITD 4 +#define QH_LINK_TYPE_FSTN 6 + uint32_t qh_endpt1; + uint32_t qh_endpt2; + uint32_t qh_curtd; + struct qTD qh_overlay; + /* + * Add dummy fill value to make the size of this struct + * aligned to 32 bytes + */ + uint8_t fill[16]; +}; + +#endif /* USB_EHCI_H */ diff --git a/drivers/usb/isp1504.c b/drivers/usb/isp1504.c deleted file mode 100644 index 9ba74b1..0000000 --- a/drivers/usb/isp1504.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include - -int isp1504_set_vbus_power(void __iomem *view, int on) -{ - int vid, pid, ret = 0; - - vid = (ulpi_read(ISP1504_VID_HIGH, view) << 8) | - ulpi_read(ISP1504_VID_LOW, view); - pid = (ulpi_read(ISP1504_PID_HIGH, view) << 8) | - ulpi_read(ISP1504_PID_LOW, view); - - pr_info("ULPI Vendor ID 0x%x Product ID 0x%x\n", vid, pid); - if (vid != 0x4cc || pid != 0x1504) { - pr_err("No ISP1504 found\n"); - return -1; - } - - if (on) { - ret = ulpi_set(DRV_VBUS_EXT | /* enable external Vbus */ - DRV_VBUS | /* enable internal Vbus */ - USE_EXT_VBUS_IND | /* use external indicator */ - CHRG_VBUS, /* charge Vbus */ - ISP1504_OTGCTL, view); - } else { - ret = ulpi_clear(DRV_VBUS_EXT | /* disable external Vbus */ - DRV_VBUS, /* disable internal Vbus */ - ISP1504_OTGCTL, view); - - ret |= ulpi_set(USE_EXT_VBUS_IND | /* use external indicator */ - DISCHRG_VBUS, /* discharge Vbus */ - ISP1504_OTGCTL, view); - } - - return ret; -} diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig new file mode 100644 index 0000000..0191c87 --- /dev/null +++ b/drivers/usb/otg/Kconfig @@ -0,0 +1,6 @@ +config USB_ULPI + bool + +config USB_ISP1504 + select USB_ULPI + bool "ISP1504 Tranceiver support" diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile new file mode 100644 index 0000000..785f922 --- /dev/null +++ b/drivers/usb/otg/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_USB_ULPI) += ulpi.o +obj-$(CONFIG_USB_ISP1504) += isp1504.o diff --git a/drivers/usb/otg/isp1504.c b/drivers/usb/otg/isp1504.c new file mode 100644 index 0000000..9ba74b1 --- /dev/null +++ b/drivers/usb/otg/isp1504.c @@ -0,0 +1,37 @@ +#include +#include +#include + +int isp1504_set_vbus_power(void __iomem *view, int on) +{ + int vid, pid, ret = 0; + + vid = (ulpi_read(ISP1504_VID_HIGH, view) << 8) | + ulpi_read(ISP1504_VID_LOW, view); + pid = (ulpi_read(ISP1504_PID_HIGH, view) << 8) | + ulpi_read(ISP1504_PID_LOW, view); + + pr_info("ULPI Vendor ID 0x%x Product ID 0x%x\n", vid, pid); + if (vid != 0x4cc || pid != 0x1504) { + pr_err("No ISP1504 found\n"); + return -1; + } + + if (on) { + ret = ulpi_set(DRV_VBUS_EXT | /* enable external Vbus */ + DRV_VBUS | /* enable internal Vbus */ + USE_EXT_VBUS_IND | /* use external indicator */ + CHRG_VBUS, /* charge Vbus */ + ISP1504_OTGCTL, view); + } else { + ret = ulpi_clear(DRV_VBUS_EXT | /* disable external Vbus */ + DRV_VBUS, /* disable internal Vbus */ + ISP1504_OTGCTL, view); + + ret |= ulpi_set(USE_EXT_VBUS_IND | /* use external indicator */ + DISCHRG_VBUS, /* discharge Vbus */ + ISP1504_OTGCTL, view); + } + + return ret; +} diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c new file mode 100644 index 0000000..4a898fb --- /dev/null +++ b/drivers/usb/otg/ulpi.c @@ -0,0 +1,118 @@ +/* + * Copyright 2008 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., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include +#include +#include +#include + +/* ULPIVIEW register bits */ +#define ULPIVW_WU (1 << 31) /* Wakeup */ +#define ULPIVW_RUN (1 << 30) /* read/write run */ +#define ULPIVW_WRITE (1 << 29) /* 0 = read 1 = write */ +#define ULPIVW_SS (1 << 27) /* SyncState */ +#define ULPIVW_PORT_MASK 0x07 /* Port field */ +#define ULPIVW_PORT_SHIFT 24 +#define ULPIVW_ADDR_MASK 0xFF /* data address field */ +#define ULPIVW_ADDR_SHIFT 16 +#define ULPIVW_RDATA_MASK 0xFF /* read data field */ +#define ULPIVW_RDATA_SHIFT 8 +#define ULPIVW_WDATA_MASK 0xFF /* write data field */ +#define ULPIVW_WDATA_SHIFT 0 + +static int ulpi_poll(void __iomem *view, uint32_t bit) +{ + uint32_t data; + int timeout = 10000; + + data = readl(view); + while (data & bit) { + if (!timeout--) + return -ETIMEDOUT; + + udelay(1); + data = readl(view); + } + return (data >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK; +} + +int ulpi_read(int reg, void __iomem *view) +{ + int ret; + + /* make sure interface is running */ + if (!(readl(view) && ULPIVW_SS)) { + writel(ULPIVW_WU, view); + + /* wait for wakeup */ + ret = ulpi_poll(view, ULPIVW_WU); + if (ret < 0) + return ret; + } + + /* read the register */ + writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view); + + /* wait for completion */ + return ulpi_poll(view, ULPIVW_RUN); +} +EXPORT_SYMBOL(ulpi_read); + +int ulpi_set(u8 bits, int reg, void __iomem *view) +{ + int ret; + + /* make sure the interface is running */ + if (!(readl(view) && ULPIVW_SS)) { + writel(ULPIVW_WU, view); + /* wait for wakeup */ + ret = ulpi_poll(view, ULPIVW_WU); + if (ret < 0) + return ret; + } + + writel((ULPIVW_RUN | ULPIVW_WRITE | + ((reg + ISP1504_REG_SET) << ULPIVW_ADDR_SHIFT) | + ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), + view); + + /* wait for completion */ + ret = ulpi_poll(view, ULPIVW_RUN); + if (ret < 0) + return ret; + return 0; +} +EXPORT_SYMBOL(ulpi_set); + +int ulpi_clear(u8 bits, int reg, void __iomem *view) +{ + int ret; + + writel((ULPIVW_RUN | ULPIVW_WRITE | + ((reg + ISP1504_REG_CLEAR) << ULPIVW_ADDR_SHIFT) | + ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), + view); + + /* wait for completion */ + ret = ulpi_poll(view, ULPIVW_RUN); + if (ret < 0) + return ret; + return 0; +} +EXPORT_SYMBOL(ulpi_clear); + diff --git a/drivers/usb/ulpi.c b/drivers/usb/ulpi.c deleted file mode 100644 index 4a898fb..0000000 --- a/drivers/usb/ulpi.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2008 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., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include -#include -#include -#include - -/* ULPIVIEW register bits */ -#define ULPIVW_WU (1 << 31) /* Wakeup */ -#define ULPIVW_RUN (1 << 30) /* read/write run */ -#define ULPIVW_WRITE (1 << 29) /* 0 = read 1 = write */ -#define ULPIVW_SS (1 << 27) /* SyncState */ -#define ULPIVW_PORT_MASK 0x07 /* Port field */ -#define ULPIVW_PORT_SHIFT 24 -#define ULPIVW_ADDR_MASK 0xFF /* data address field */ -#define ULPIVW_ADDR_SHIFT 16 -#define ULPIVW_RDATA_MASK 0xFF /* read data field */ -#define ULPIVW_RDATA_SHIFT 8 -#define ULPIVW_WDATA_MASK 0xFF /* write data field */ -#define ULPIVW_WDATA_SHIFT 0 - -static int ulpi_poll(void __iomem *view, uint32_t bit) -{ - uint32_t data; - int timeout = 10000; - - data = readl(view); - while (data & bit) { - if (!timeout--) - return -ETIMEDOUT; - - udelay(1); - data = readl(view); - } - return (data >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK; -} - -int ulpi_read(int reg, void __iomem *view) -{ - int ret; - - /* make sure interface is running */ - if (!(readl(view) && ULPIVW_SS)) { - writel(ULPIVW_WU, view); - - /* wait for wakeup */ - ret = ulpi_poll(view, ULPIVW_WU); - if (ret < 0) - return ret; - } - - /* read the register */ - writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view); - - /* wait for completion */ - return ulpi_poll(view, ULPIVW_RUN); -} -EXPORT_SYMBOL(ulpi_read); - -int ulpi_set(u8 bits, int reg, void __iomem *view) -{ - int ret; - - /* make sure the interface is running */ - if (!(readl(view) && ULPIVW_SS)) { - writel(ULPIVW_WU, view); - /* wait for wakeup */ - ret = ulpi_poll(view, ULPIVW_WU); - if (ret < 0) - return ret; - } - - writel((ULPIVW_RUN | ULPIVW_WRITE | - ((reg + ISP1504_REG_SET) << ULPIVW_ADDR_SHIFT) | - ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), - view); - - /* wait for completion */ - ret = ulpi_poll(view, ULPIVW_RUN); - if (ret < 0) - return ret; - return 0; -} -EXPORT_SYMBOL(ulpi_set); - -int ulpi_clear(u8 bits, int reg, void __iomem *view) -{ - int ret; - - writel((ULPIVW_RUN | ULPIVW_WRITE | - ((reg + ISP1504_REG_CLEAR) << ULPIVW_ADDR_SHIFT) | - ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), - view); - - /* wait for completion */ - ret = ulpi_poll(view, ULPIVW_RUN); - if (ret < 0) - return ret; - return 0; -} -EXPORT_SYMBOL(ulpi_clear); - diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c deleted file mode 100644 index 76e033e..0000000 --- a/drivers/usb/usb.c +++ /dev/null @@ -1,1397 +0,0 @@ -/* - * - * Most of this source has been derived from the Linux USB - * project: - * (C) Copyright Linus Torvalds 1999 - * (C) Copyright Johannes Erdfelt 1999-2001 - * (C) Copyright Andreas Gal 1999 - * (C) Copyright Gregory P. Smith 1999 - * (C) Copyright Deti Fliegl 1999 (new USB architecture) - * (C) Copyright Randy Dunlap 2000 - * (C) Copyright David Brownell 2000 (kernel hotplug, usb_device_id) - * (C) Copyright Yggdrasil Computing, Inc. 2000 - * (usb_device_id matching changes by Adam J. Richter) - * - * Adapted for barebox: - * (C) Copyright 2001 Denis Peter, MPL AG Switzerland - * - * 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 - * - */ - -/* - * How it works: - * - * Since this is a bootloader, the devices will not be automatic - * (re)configured on hotplug, but after a restart of the USB the - * device should work. - * - * For each transfer (except "Interrupt") we wait for completion. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* #define USB_DEBUG */ - -#ifdef USB_DEBUG -#define USB_PRINTF(fmt, args...) printf(fmt , ##args) -#else -#define USB_PRINTF(fmt, args...) -#endif - -#define USB_BUFSIZ 512 - -static int dev_index; -static int asynch_allowed; -static struct devrequest setup_packet; - -static int usb_hub_probe(struct usb_device *dev, int ifnum); -static int hub_port_reset(struct usb_device *dev, int port, - unsigned short *portstat); - -static LIST_HEAD(host_list); -static LIST_HEAD(usb_device_list); - -static void print_usb_device(struct usb_device *dev) -{ - printf("%s: %04x:%04x %s\n", dev->dev.name, - dev->descriptor.idVendor, - dev->descriptor.idProduct, - dev->prod); -} - -static int host_busnum; - -int usb_register_host(struct usb_host *host) -{ - list_add_tail(&host->list, &host_list); - host->busnum = host_busnum++; - asynch_allowed = 1; - return 0; -} - -/** - * set configuration number to configuration - */ -static int usb_set_configuration(struct usb_device *dev, int configuration) -{ - int res; - USB_PRINTF("set configuration %d\n", configuration); - /* set setup command */ - res = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_CONFIGURATION, 0, - configuration, 0, - NULL, 0, USB_CNTL_TIMEOUT); - if (res == 0) { - dev->toggle[0] = 0; - dev->toggle[1] = 0; - return 0; - } else - return -1; -} - -/* The routine usb_set_maxpacket_ep() is extracted from the loop of routine - * usb_set_maxpacket(), because the optimizer of GCC 4.x chokes on this routine - * when it is inlined in 1 single routine. What happens is that the register r3 - * is used as loop-count 'i', but gets overwritten later on. - * This is clearly a compiler bug, but it is easier to workaround it here than - * to update the compiler (Occurs with at least several GCC 4.{1,2},x - * CodeSourcery compilers like e.g. 2007q3, 2008q1, 2008q3 lite editions on ARM) - */ -static void noinline -usb_set_maxpacket_ep(struct usb_device *dev, struct usb_endpoint_descriptor *ep) -{ - int b; - - b = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL) { - /* Control => bidirectional */ - dev->epmaxpacketout[b] = ep->wMaxPacketSize; - dev->epmaxpacketin[b] = ep->wMaxPacketSize; - USB_PRINTF("##Control EP epmaxpacketout/in[%d] = %d\n", - b, dev->epmaxpacketin[b]); - } else { - if ((ep->bEndpointAddress & 0x80) == 0) { - /* OUT Endpoint */ - if (ep->wMaxPacketSize > dev->epmaxpacketout[b]) { - dev->epmaxpacketout[b] = ep->wMaxPacketSize; - USB_PRINTF("##EP epmaxpacketout[%d] = %d\n", - b, dev->epmaxpacketout[b]); - } - } else { - /* IN Endpoint */ - if (ep->wMaxPacketSize > dev->epmaxpacketin[b]) { - dev->epmaxpacketin[b] = ep->wMaxPacketSize; - USB_PRINTF("##EP epmaxpacketin[%d] = %d\n", - b, dev->epmaxpacketin[b]); - } - } /* if out */ - } /* if control */ -} - -/* - * set the max packed value of all endpoints in the given configuration - */ -static int usb_set_maxpacket(struct usb_device *dev) -{ - int i, ii; - - for (i = 0; i < dev->config.bNumInterfaces; i++) - for (ii = 0; ii < dev->config.if_desc[i].bNumEndpoints; ii++) - usb_set_maxpacket_ep(dev, - &dev->config.if_desc[i].ep_desc[ii]); - - return 0; -} - -/** - * Parse the config, located in buffer, and fills the dev->config structure. - * Note that all little/big endian swapping are done automatically. - */ -static int usb_parse_config(struct usb_device *dev, unsigned char *buffer, int cfgno) -{ - struct usb_descriptor_header *head; - int index, ifno, epno, curr_if_num; - int i; - unsigned char *ch; - - ifno = -1; - epno = -1; - curr_if_num = -1; - - dev->configno = cfgno; - head = (struct usb_descriptor_header *) &buffer[0]; - if (head->bDescriptorType != USB_DT_CONFIG) { - printf(" ERROR: NOT USB_CONFIG_DESC %x\n", - head->bDescriptorType); - return -1; - } - memcpy(&dev->config, buffer, buffer[0]); - le16_to_cpus(&(dev->config.wTotalLength)); - dev->config.no_of_if = 0; - - index = dev->config.bLength; - /* Ok the first entry must be a configuration entry, - * now process the others */ - head = (struct usb_descriptor_header *) &buffer[index]; - while (index + 1 < dev->config.wTotalLength) { - switch (head->bDescriptorType) { - case USB_DT_INTERFACE: - if (((struct usb_interface_descriptor *) \ - &buffer[index])->bInterfaceNumber != curr_if_num) { - /* this is a new interface, copy new desc */ - ifno = dev->config.no_of_if; - dev->config.no_of_if++; - memcpy(&dev->config.if_desc[ifno], - &buffer[index], buffer[index]); - dev->config.if_desc[ifno].no_of_ep = 0; - dev->config.if_desc[ifno].num_altsetting = 1; - curr_if_num = - dev->config.if_desc[ifno].bInterfaceNumber; - } else { - /* found alternate setting for the interface */ - dev->config.if_desc[ifno].num_altsetting++; - } - break; - case USB_DT_ENDPOINT: - epno = dev->config.if_desc[ifno].no_of_ep; - /* found an endpoint */ - dev->config.if_desc[ifno].no_of_ep++; - memcpy(&dev->config.if_desc[ifno].ep_desc[epno], - &buffer[index], buffer[index]); - le16_to_cpus(&(dev->config.if_desc[ifno].ep_desc[epno].\ - wMaxPacketSize)); - USB_PRINTF("if %d, ep %d\n", ifno, epno); - break; - default: - if (head->bLength == 0) - return 1; - - USB_PRINTF("unknown Description Type : %x\n", - head->bDescriptorType); - - { - ch = (unsigned char *)head; - for (i = 0; i < head->bLength; i++) - USB_PRINTF("%02X ", *ch++); - USB_PRINTF("\n\n\n"); - } - break; - } - index += head->bLength; - head = (struct usb_descriptor_header *)&buffer[index]; - } - return 1; -} - -/** - * set address of a device to the value in dev->devnum. - * This can only be done by addressing the device via the default address (0) - */ -static int usb_set_address(struct usb_device *dev) -{ - int res; - - USB_PRINTF("set address %d\n", dev->devnum); - res = usb_control_msg(dev, usb_snddefctrl(dev), - USB_REQ_SET_ADDRESS, 0, - (dev->devnum), 0, - NULL, 0, USB_CNTL_TIMEOUT); - return res; -} - -static int usb_get_descriptor(struct usb_device *dev, unsigned char type, - unsigned char index, void *buf, int size) -{ - int res; - res = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (type << 8) + index, 0, - buf, size, USB_CNTL_TIMEOUT); - return res; -} - -/* - * By the time we get here, the device has gotten a new device ID - * and is in the default state. We need to identify the thing and - * get the ball rolling.. - * - * Returns 0 for success, != 0 for error. - */ -static int usb_new_device(struct usb_device *dev) -{ - int addr, err; - int tmp; - unsigned char tmpbuf[USB_BUFSIZ]; - struct usb_device_descriptor *desc; - int port = -1; - struct usb_device *parent = dev->parent; - unsigned short portstatus; - - /* We still haven't set the Address yet */ - addr = dev->devnum; - dev->devnum = 0; - - /* This is a Windows scheme of initialization sequence, with double - * reset of the device (Linux uses the same sequence) - * Some equipment is said to work only with such init sequence; this - * patch is based on the work by Alan Stern: - * http://sourceforge.net/mailarchive/forum.php? - * thread_id=5729457&forum_id=5398 - */ - - /* send 64-byte GET-DEVICE-DESCRIPTOR request. Since the descriptor is - * only 18 bytes long, this will terminate with a short packet. But if - * the maxpacket size is 8 or 16 the device may be waiting to transmit - * some more, or keeps on retransmitting the 8 byte header. */ - - desc = (struct usb_device_descriptor *)tmpbuf; - dev->descriptor.bMaxPacketSize0 = 64; /* Start off at 64 bytes */ - /* Default to 64 byte max packet size */ - dev->maxpacketsize = PACKET_SIZE_64; - dev->epmaxpacketin[0] = 64; - dev->epmaxpacketout[0] = 64; - - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, desc, 64); - if (err < 0) { - USB_PRINTF("%s: usb_get_descriptor() failed with %d\n", __func__, err); - return 1; - } - - dev->descriptor.bMaxPacketSize0 = desc->bMaxPacketSize0; - - /* find the port number we're at */ - if (parent) { - int j; - - for (j = 0; j < parent->maxchild; j++) { - if (parent->children[j] == dev) { - port = j; - break; - } - } - if (port < 0) { - printf("%s: cannot locate device's port.\n", __func__); - return 1; - } - - /* reset the port for the second time */ - err = hub_port_reset(dev->parent, port, &portstatus); - if (err < 0) { - printf("\n Couldn't reset port %i\n", port); - return 1; - } - } - - dev->epmaxpacketin[0] = dev->descriptor.bMaxPacketSize0; - dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0; - switch (dev->descriptor.bMaxPacketSize0) { - case 8: - dev->maxpacketsize = PACKET_SIZE_8; - break; - case 16: - dev->maxpacketsize = PACKET_SIZE_16; - break; - case 32: - dev->maxpacketsize = PACKET_SIZE_32; - break; - case 64: - dev->maxpacketsize = PACKET_SIZE_64; - break; - } - dev->devnum = addr; - - err = usb_set_address(dev); /* set address */ - - if (err < 0) { - printf("\n USB device not accepting new address " \ - "(error=%lX)\n", dev->status); - return 1; - } - - wait_ms(10); /* Let the SET_ADDRESS settle */ - - tmp = sizeof(dev->descriptor); - - err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, - &dev->descriptor, sizeof(dev->descriptor)); - if (err < tmp) { - if (err < 0) - printf("unable to get device descriptor (error=%d)\n", - err); - else - printf("USB device descriptor short read " \ - "(expected %i, got %i)\n", tmp, err); - return 1; - } - /* correct le values */ - le16_to_cpus(&dev->descriptor.bcdUSB); - le16_to_cpus(&dev->descriptor.idVendor); - le16_to_cpus(&dev->descriptor.idProduct); - le16_to_cpus(&dev->descriptor.bcdDevice); - /* only support for one config for now */ - usb_get_configuration_no(dev, &tmpbuf[0], 0); - usb_parse_config(dev, &tmpbuf[0], 0); - usb_set_maxpacket(dev); - /* we set the default configuration here */ - if (usb_set_configuration(dev, dev->config.bConfigurationValue)) { - printf("failed to set default configuration " \ - "len %d, status %lX\n", dev->act_len, dev->status); - return -1; - } - USB_PRINTF("new device: Mfr=%d, Product=%d, SerialNumber=%d\n", - dev->descriptor.iManufacturer, dev->descriptor.iProduct, - dev->descriptor.iSerialNumber); - memset(dev->mf, 0, sizeof(dev->mf)); - memset(dev->prod, 0, sizeof(dev->prod)); - memset(dev->serial, 0, sizeof(dev->serial)); - if (dev->descriptor.iManufacturer) - usb_string(dev, dev->descriptor.iManufacturer, - dev->mf, sizeof(dev->mf)); - if (dev->descriptor.iProduct) - usb_string(dev, dev->descriptor.iProduct, - dev->prod, sizeof(dev->prod)); - if (dev->descriptor.iSerialNumber) - usb_string(dev, dev->descriptor.iSerialNumber, - dev->serial, sizeof(dev->serial)); - /* now prode if the device is a hub */ - usb_hub_probe(dev, 0); - - sprintf(dev->dev.name, "usb%d-%d", dev->host->busnum, dev->devnum); - - print_usb_device(dev); - - register_device(&dev->dev); - list_add_tail(&dev->list, &usb_device_list); - - return 0; -} - -static struct usb_device *usb_alloc_new_device(void) -{ - struct usb_device *usbdev = xzalloc(sizeof (*usbdev)); - - if (!usbdev) - return NULL; - - usbdev->devnum = dev_index + 1; - usbdev->maxchild = 0; - usbdev->dev.bus = &usb_bus_type; - - dev_index++; - - return usbdev; -} - -static int __usb_init(void) -{ - struct usb_device *dev, *tmp; - struct usb_host *host; - int ret; - - list_for_each_entry_safe(dev, tmp, &usb_device_list, list) { - list_del(&dev->list); - unregister_device(&dev->dev); - if (dev->hub) - free(dev->hub); - free(dev); - } - - printf("USB: scanning bus for devices...\n"); - dev_index = 0; - - list_for_each_entry(host, &host_list, list) { - ret = host->init(host); - if (ret) - continue; - - dev = usb_alloc_new_device(); - dev->host = host; - usb_new_device(dev); - } - - 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. - */ -void usb_disable_asynch(int disable) -{ - asynch_allowed = !disable; -} - - -/*------------------------------------------------------------------- - * Message wrappers. - * - */ - -/* - * submits an Interrupt Message - */ -int usb_submit_int_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, int interval) -{ - struct usb_host *host = dev->host; - - return host->submit_int_msg(dev, pipe, buffer, transfer_len, interval); -} - -/* - * submits a control message and waits for comletion (at least timeout * 1ms) - * If timeout is 0, we don't wait for completion (used as example to set and - * clear keyboards LEDs). For data transfers, (storage transfers) we don't - * allow control messages with 0 timeout, by previousely resetting the flag - * asynch_allowed (usb_disable_asynch(1)). - * returns the transfered length if OK or -1 if error. The transfered length - * and the current status are stored in the dev->act_len and dev->status. - */ -int usb_control_msg(struct usb_device *dev, unsigned int pipe, - unsigned char request, unsigned char requesttype, - unsigned short value, unsigned short index, - void *data, unsigned short size, int timeout) -{ - struct usb_host *host = dev->host; - - if ((timeout == 0) && (!asynch_allowed)) { - /* request for a asynch control pipe is not allowed */ - return -1; - } - - /* set setup command */ - setup_packet.requesttype = requesttype; - setup_packet.request = request; - setup_packet.value = cpu_to_le16(value); - setup_packet.index = cpu_to_le16(index); - setup_packet.length = cpu_to_le16(size); - USB_PRINTF("usb_control_msg: request: 0x%X, requesttype: 0x%X, " \ - "value 0x%X index 0x%X length 0x%X\n", - request, requesttype, value, index, size); - dev->status = USB_ST_NOT_PROC; /*not yet processed */ - - host->submit_control_msg(dev, pipe, data, size, &setup_packet); - if (timeout == 0) - return (int)size; - - if (dev->status != 0) { - /* - * Let's wait a while for the timeout to elapse. - * It has no real use, but it keeps the interface happy. - */ - wait_ms(timeout); - return -1; - } - - return dev->act_len; -} - -/*------------------------------------------------------------------- - * submits bulk message, and waits for completion. returns 0 if Ok or - * -1 if Error. - * synchronous behavior - */ -int usb_bulk_msg(struct usb_device *dev, unsigned int pipe, - void *data, int len, int *actual_length, int timeout) -{ - struct usb_host *host = dev->host; - int ret; - - if (len < 0) - return -1; - - dev->status = USB_ST_NOT_PROC; /* not yet processed */ - ret = host->submit_bulk_msg(dev, pipe, data, len); - if (ret) - return ret; - - *actual_length = dev->act_len; - - return (dev->status == 0) ? 0 : -1; -} - - -/*------------------------------------------------------------------- - * Max Packet stuff - */ - -/* - * returns the max packet size, depending on the pipe direction and - * the configurations values - */ -int usb_maxpacket(struct usb_device *dev, unsigned long pipe) -{ - /* direction is out -> use emaxpacket out */ - if ((pipe & USB_DIR_IN) == 0) - return dev->epmaxpacketout[((pipe>>15) & 0xf)]; - else - return dev->epmaxpacketin[((pipe>>15) & 0xf)]; -} - -/*********************************************************************** - * Clears an endpoint - * endp: endpoint number in bits 0-3; - * direction flag in bit 7 (1 = IN, 0 = OUT) - */ -int usb_clear_halt(struct usb_device *dev, int pipe) -{ - int result; - int endp = usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7); - - result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0, USB_CNTL_TIMEOUT * 3); - - /* don't clear if failed */ - if (result < 0) - return result; - - /* - * NOTE: we do not get status and verify reset was successful - * as some devices are reported to lock up upon this check.. - */ - - usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - - /* toggle is reset on clear */ - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - return 0; -} - -/********************************************************************** - * gets configuration cfgno and store it in the buffer - */ -int usb_get_configuration_no(struct usb_device *dev, - unsigned char *buffer, int cfgno) -{ - int result; - unsigned int tmp; - struct usb_config_descriptor *config; - - - config = (struct usb_config_descriptor *)&buffer[0]; - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 9); - if (result < 9) { - if (result < 0) - printf("unable to get descriptor, error %lX\n", - dev->status); - else - printf("config descriptor too short " \ - "(expected %i, got %i)\n", 9, result); - return -1; - } - tmp = le16_to_cpu(config->wTotalLength); - - if (tmp > USB_BUFSIZ) { - USB_PRINTF("usb_get_configuration_no: failed to get " \ - "descriptor - too long: %d\n", tmp); - return -1; - } - - result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, tmp); - USB_PRINTF("get_conf_no %d Result %d, wLength %d\n", - cfgno, result, tmp); - return result; -} - -/******************************************************************** - * set interface number to interface - */ -int usb_set_interface(struct usb_device *dev, int interface, int alternate) -{ - struct usb_interface_descriptor *if_face = NULL; - int ret, i; - - for (i = 0; i < dev->config.bNumInterfaces; i++) { - if (dev->config.if_desc[i].bInterfaceNumber == interface) { - if_face = &dev->config.if_desc[i]; - break; - } - } - if (!if_face) { - printf("selecting invalid interface %d", interface); - return -1; - } - /* - * We should return now for devices with only one alternate setting. - * According to 9.4.10 of the Universal Serial Bus Specification - * Revision 2.0 such devices can return with a STALL. This results in - * some USB sticks timeouting during initialization and then being - * unusable in barebox. - */ - if (if_face->num_altsetting == 1) - return 0; - - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, - alternate, interface, NULL, 0, - USB_CNTL_TIMEOUT * 5); - if (ret < 0) - return ret; - - return 0; -} - -/******************************************************************** - * set protocol to protocol - */ -int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - protocol, ifnum, NULL, 0, USB_CNTL_TIMEOUT); -} - -/******************************************************************** - * set idle - */ -int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (duration << 8) | report_id, ifnum, NULL, 0, USB_CNTL_TIMEOUT); -} - -/******************************************************************** - * get report - */ -int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, - unsigned char id, void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_REPORT, - USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, - (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT); -} - -/******************************************************************** - * get class descriptor - */ -int usb_get_class_descriptor(struct usb_device *dev, int ifnum, - unsigned char type, unsigned char id, void *buf, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, - (type << 8) + id, ifnum, buf, size, USB_CNTL_TIMEOUT); -} - -/******************************************************************** - * get string index in buffer - */ -int usb_get_string(struct usb_device *dev, unsigned short langid, - unsigned char index, void *buf, int size) -{ - int i; - int result; - - for (i = 0; i < 3; ++i) { - /* some devices are flaky */ - result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN, - (USB_DT_STRING << 8) + index, langid, buf, size, - USB_CNTL_TIMEOUT); - - if (result > 0) - break; - } - - return result; -} - - -static void usb_try_string_workarounds(unsigned char *buf, int *length) -{ - int newlength, oldlength = *length; - - for (newlength = 2; newlength + 1 < oldlength; newlength += 2) - if (!isprint(buf[newlength]) || buf[newlength + 1]) - break; - - if (newlength > 2) { - buf[0] = newlength; - *length = newlength; - } -} - - -static int usb_string_sub(struct usb_device *dev, unsigned int langid, - unsigned int index, unsigned char *buf) -{ - int rc; - - /* Try to read the string descriptor by asking for the maximum - * possible number of bytes */ - rc = usb_get_string(dev, langid, index, buf, 255); - - /* If that failed try to read the descriptor length, then - * ask for just that many bytes */ - if (rc < 2) { - rc = usb_get_string(dev, langid, index, buf, 2); - if (rc == 2) - rc = usb_get_string(dev, langid, index, buf, buf[0]); - } - - if (rc >= 2) { - if (!buf[0] && !buf[1]) - usb_try_string_workarounds(buf, &rc); - - /* There might be extra junk at the end of the descriptor */ - if (buf[0] < rc) - rc = buf[0]; - - rc = rc - (rc & 1); /* force a multiple of two */ - } - - if (rc < 2) - rc = -1; - - return rc; -} - - -/******************************************************************** - * usb_string: - * Get string index and translate it to ascii. - * returns string length (> 0) or error (< 0) - */ -int usb_string(struct usb_device *dev, int index, char *buf, size_t size) -{ - unsigned char mybuf[USB_BUFSIZ]; - unsigned char *tbuf; - int err; - unsigned int u, idx; - - if (size <= 0 || !buf || !index) - return -1; - buf[0] = 0; - tbuf = &mybuf[0]; - - /* get langid for strings if it's not yet known */ - if (!dev->have_langid) { - err = usb_string_sub(dev, 0, 0, tbuf); - if (err < 0) { - USB_PRINTF("error getting string descriptor 0 " \ - "(error=%lx)\n", dev->status); - return -1; - } else if (tbuf[0] < 4) { - USB_PRINTF("string descriptor 0 too short\n"); - return -1; - } else { - dev->have_langid = -1; - dev->string_langid = tbuf[2] | (tbuf[3] << 8); - /* always use the first langid listed */ - USB_PRINTF("USB device number %d default " \ - "language ID 0x%x\n", - dev->devnum, dev->string_langid); - } - } - - err = usb_string_sub(dev, dev->string_langid, index, tbuf); - if (err < 0) - return err; - - size--; /* leave room for trailing NULL char in output buffer */ - for (idx = 0, u = 2; u < err; u += 2) { - if (idx >= size) - break; - if (tbuf[u+1]) /* high byte */ - buf[idx++] = '?'; /* non-ASCII character */ - else - buf[idx++] = tbuf[u]; - } - buf[idx] = 0; - err = idx; - return err; -} - -/**************************************************************************** - * HUB "Driver" - * Probes device for being a hub and configurate it - */ - -#undef USB_HUB_DEBUG - -#ifdef USB_HUB_DEBUG -#define USB_HUB_PRINTF(fmt, args...) printf(fmt , ##args) -#else -#define USB_HUB_PRINTF(fmt, args...) -#endif - -int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, - USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT); -} - -int usb_clear_hub_feature(struct usb_device *dev, int feature) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, - 0, NULL, 0, USB_CNTL_TIMEOUT); -} - -int usb_clear_port_feature(struct usb_device *dev, int port, int feature) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, - port, NULL, 0, USB_CNTL_TIMEOUT); -} - -int usb_set_port_feature(struct usb_device *dev, int port, int feature) -{ - return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - USB_REQ_SET_FEATURE, USB_RT_PORT, feature, - port, NULL, 0, USB_CNTL_TIMEOUT); -} - -int usb_get_hub_status(struct usb_device *dev, void *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, - data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); -} - -int usb_get_port_status(struct usb_device *dev, int port, void *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, - data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); -} - - -static void usb_hub_power_on(struct usb_hub_device *hub) -{ - int i; - struct usb_device *dev; - - dev = hub->pusb_dev; - /* Enable power to the ports */ - USB_HUB_PRINTF("enabling power on all ports\n"); - for (i = 0; i < dev->maxchild; i++) { - usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); - USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status); - wait_ms(hub->desc.bPwrOn2PwrGood * 2); - } -} - -#define MAX_TRIES 5 - -static inline char *portspeed(int portstatus) -{ - if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) - return "480 Mb/s"; - else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) - return "1.5 Mb/s"; - else - return "12 Mb/s"; -} - -static int hub_port_reset(struct usb_device *dev, int port, - unsigned short *portstat) -{ - int tries; - struct usb_port_status portsts; - unsigned short portstatus, portchange; - - USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port); - for (tries = 0; tries < MAX_TRIES; tries++) { - - usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET); - wait_ms(200); - - if (usb_get_port_status(dev, port + 1, &portsts) < 0) { - USB_HUB_PRINTF("get_port_status failed status %lX\n", - dev->status); - return -1; - } - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); - - USB_HUB_PRINTF("portstatus %x, change %x, %s\n", - portstatus, portchange, - portspeed(portstatus)); - - USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \ - " USB_PORT_STAT_ENABLE %d\n", - (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0, - (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0, - (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); - - if ((portchange & USB_PORT_STAT_C_CONNECTION) || - !(portstatus & USB_PORT_STAT_CONNECTION)) - return -1; - - if (portstatus & USB_PORT_STAT_ENABLE) - break; - - wait_ms(200); - } - - if (tries == MAX_TRIES) { - USB_HUB_PRINTF("Cannot enable port %i after %i retries, " \ - "disabling port.\n", port + 1, MAX_TRIES); - USB_HUB_PRINTF("Maybe the USB cable is bad?\n"); - return -1; - } - - usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_RESET); - *portstat = portstatus; - return 0; -} - - -static void usb_hub_port_connect_change(struct usb_device *dev, int port) -{ - struct usb_device *usb; - struct usb_port_status portsts; - unsigned short portstatus, portchange; - - /* Check status */ - if (usb_get_port_status(dev, port + 1, &portsts) < 0) { - USB_HUB_PRINTF("get_port_status failed\n"); - return; - } - - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); - USB_HUB_PRINTF("portstatus %x, change %x, %s\n", - portstatus, portchange, portspeed(portstatus)); - - /* Clear the connection change status */ - usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION); - - /* Disconnect any existing devices under this port */ - if (((!(portstatus & USB_PORT_STAT_CONNECTION)) && - (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) { - USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n"); - /* Return now if nothing is connected */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return; - } - wait_ms(200); - - /* Reset the port */ - if (hub_port_reset(dev, port, &portstatus) < 0) { - printf("cannot reset port %i!?\n", port + 1); - return; - } - - wait_ms(200); - - /* Allocate a new device struct for it */ - usb = usb_alloc_new_device(); - usb->host = dev->host; - - if (portstatus & USB_PORT_STAT_HIGH_SPEED) - usb->speed = USB_SPEED_HIGH; - else if (portstatus & USB_PORT_STAT_LOW_SPEED) - usb->speed = USB_SPEED_LOW; - else - usb->speed = USB_SPEED_FULL; - - dev->children[port] = usb; - usb->parent = dev; - /* Run it through the hoops (find a driver, etc) */ - if (usb_new_device(usb)) { - /* Woops, disable the port */ - USB_HUB_PRINTF("hub: disabling port %d\n", port + 1); - usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); - } -} - - -int usb_hub_configure(struct usb_device *dev) -{ - unsigned char buffer[USB_BUFSIZ], *bitmap; - struct usb_hub_descriptor *descriptor; - struct usb_hub_status *hubsts; - int i; - struct usb_hub_device *hub; - - hub = xzalloc(sizeof (*hub)); - dev->hub = hub; - - hub->pusb_dev = dev; - /* Get the the hub descriptor */ - if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { - USB_HUB_PRINTF("%s: failed to get hub " \ - "descriptor, giving up %lX\n", __func__, dev->status); - return -1; - } - descriptor = (struct usb_hub_descriptor *)buffer; - - /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ - i = descriptor->bLength; - if (i > USB_BUFSIZ) { - USB_HUB_PRINTF("%s: failed to get hub " \ - "descriptor - too long: %d\n", __func__, - descriptor->bLength); - return -1; - } - - if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { - USB_HUB_PRINTF("%s: failed to get hub " \ - "descriptor 2nd giving up %lX\n", __func__, dev->status); - return -1; - } - memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); - /* adjust 16bit values */ - hub->desc.wHubCharacteristics = - le16_to_cpu(descriptor->wHubCharacteristics); - /* set the bitmap */ - bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; - /* devices not removable by default */ - memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); - bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; - memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ - - for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) - hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; - - for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) - hub->desc.DeviceRemovable[i] = descriptor->PortPowerCtrlMask[i]; - - dev->maxchild = descriptor->bNbrPorts; - USB_HUB_PRINTF("%d ports detected\n", dev->maxchild); - - switch (hub->desc.wHubCharacteristics & HUB_CHAR_LPSM) { - case 0x00: - USB_HUB_PRINTF("ganged power switching\n"); - break; - case 0x01: - USB_HUB_PRINTF("individual port power switching\n"); - break; - case 0x02: - case 0x03: - USB_HUB_PRINTF("unknown reserved power switching mode\n"); - break; - } - - if (hub->desc.wHubCharacteristics & HUB_CHAR_COMPOUND) - USB_HUB_PRINTF("part of a compound device\n"); - else - USB_HUB_PRINTF("standalone hub\n"); - - switch (hub->desc.wHubCharacteristics & HUB_CHAR_OCPM) { - case 0x00: - USB_HUB_PRINTF("global over-current protection\n"); - break; - case 0x08: - USB_HUB_PRINTF("individual port over-current protection\n"); - break; - case 0x10: - case 0x18: - USB_HUB_PRINTF("no over-current protection\n"); - break; - } - - USB_HUB_PRINTF("power on to power good time: %dms\n", - descriptor->bPwrOn2PwrGood * 2); - USB_HUB_PRINTF("hub controller current requirement: %dmA\n", - descriptor->bHubContrCurrent); - - for (i = 0; i < dev->maxchild; i++) - USB_HUB_PRINTF("port %d is%s removable\n", i + 1, - hub->desc.DeviceRemovable[(i + 1) / 8] & \ - (1 << ((i + 1) % 8)) ? " not" : ""); - - if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { - USB_HUB_PRINTF("%s: failed to get Status - " \ - "too long: %d\n", __func__, descriptor->bLength); - return -1; - } - - if (usb_get_hub_status(dev, buffer) < 0) { - USB_HUB_PRINTF("%s: failed to get Status %lX\n", __func__, - dev->status); - return -1; - } - - hubsts = (struct usb_hub_status *)buffer; - USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n", - le16_to_cpu(hubsts->wHubStatus), - le16_to_cpu(hubsts->wHubChange)); - USB_HUB_PRINTF("local power source is %s\n", - (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ - "lost (inactive)" : "good"); - USB_HUB_PRINTF("%sover-current condition exists\n", - (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ - "" : "no "); - usb_hub_power_on(hub); - - for (i = 0; i < dev->maxchild; i++) { - struct usb_port_status portsts; - unsigned short portstatus, portchange; - - if (usb_get_port_status(dev, i + 1, &portsts) < 0) { - USB_HUB_PRINTF("get_port_status failed\n"); - continue; - } - - portstatus = le16_to_cpu(portsts.wPortStatus); - portchange = le16_to_cpu(portsts.wPortChange); - USB_HUB_PRINTF("Port %d Status %X Change %X\n", - i + 1, portstatus, portchange); - - if (portchange & USB_PORT_STAT_C_CONNECTION) { - USB_HUB_PRINTF("port %d connection change\n", i + 1); - usb_hub_port_connect_change(dev, i); - } - if (portchange & USB_PORT_STAT_C_ENABLE) { - USB_HUB_PRINTF("port %d enable change, status %x\n", - i + 1, portstatus); - usb_clear_port_feature(dev, i + 1, - USB_PORT_FEAT_C_ENABLE); - - /* EM interference sometimes causes bad shielded USB - * devices to be shutdown by the hub, this hack enables - * them again. Works at least with mouse driver */ - if (!(portstatus & USB_PORT_STAT_ENABLE) && - (portstatus & USB_PORT_STAT_CONNECTION) && - ((dev->children[i]))) { - USB_HUB_PRINTF("already running port %i " \ - "disabled by hub (EMI?), " \ - "re-enabling...\n", i + 1); - usb_hub_port_connect_change(dev, i); - } - } - if (portstatus & USB_PORT_STAT_SUSPEND) { - USB_HUB_PRINTF("port %d suspend change\n", i + 1); - usb_clear_port_feature(dev, i + 1, - USB_PORT_FEAT_SUSPEND); - } - - if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - USB_HUB_PRINTF("port %d over-current change\n", i + 1); - usb_clear_port_feature(dev, i + 1, - USB_PORT_FEAT_C_OVER_CURRENT); - usb_hub_power_on(hub); - } - - if (portchange & USB_PORT_STAT_C_RESET) { - USB_HUB_PRINTF("port %d reset change\n", i + 1); - usb_clear_port_feature(dev, i + 1, - USB_PORT_FEAT_C_RESET); - } - } /* end for i all ports */ - - return 0; -} - -static int usb_hub_probe(struct usb_device *dev, int ifnum) -{ - struct usb_interface_descriptor *iface; - struct usb_endpoint_descriptor *ep; - int ret; - - iface = &dev->config.if_desc[ifnum]; - /* Is it a hub? */ - if (iface->bInterfaceClass != USB_CLASS_HUB) - return 0; - /* Some hubs have a subclass of 1, which AFAICT according to the */ - /* specs is not defined, but it works */ - if ((iface->bInterfaceSubClass != 0) && - (iface->bInterfaceSubClass != 1)) - return 0; - /* Multiple endpoints? What kind of mutant ninja-hub is this? */ - if (iface->bNumEndpoints != 1) - return 0; - ep = &iface->ep_desc[0]; - /* Output endpoint? Curiousier and curiousier.. */ - if (!(ep->bEndpointAddress & USB_DIR_IN)) - return 0; - /* If it's not an interrupt endpoint, we'd better punt! */ - if ((ep->bmAttributes & 3) != 3) - return 0; - /* We found a hub */ - USB_HUB_PRINTF("USB hub found\n"); - ret = usb_hub_configure(dev); - return ret; -} - -int usb_driver_register(struct usb_driver *drv) -{ - drv->driver.bus = &usb_bus_type; - return register_driver(&drv->driver); -} - -/* returns 0 if no match, 1 if match */ -int usb_match_device(struct usb_device *dev, const struct usb_device_id *id) -{ - if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && - id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) - return 0; - - if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && - id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) - return 0; - - return 1; -} - -/* returns 0 if no match, 1 if match */ -int usb_match_one_id(struct usb_device *usbdev, - const struct usb_device_id *id) -{ - /* proc_connectinfo in devio.c may call us with id == NULL. */ - if (id == NULL) - return 0; - - if (!usb_match_device(usbdev, id)) - return 0; - - return 1; -} -EXPORT_SYMBOL(usb_match_one_id); - -const struct usb_device_id *usb_match_id(struct usb_device *usbdev, - const struct usb_device_id *id) -{ - /* proc_connectinfo in devio.c may call us with id == NULL. */ - if (id == NULL) - return NULL; - - /* It is important to check that id->driver_info is nonzero, - since an entry that is all zeroes except for a nonzero - id->driver_info is the way to create an entry that - indicates that the driver want to examine every - device and interface. */ - for (; id->idVendor || id->idProduct || id->bDeviceClass || - id->bInterfaceClass || id->driver_info; id++) { - if (usb_match_one_id(usbdev, id)) - return id; - } - - return NULL; -} -EXPORT_SYMBOL(usb_match_id); - -static int usb_match(struct device_d *dev, struct driver_d *drv) -{ - struct usb_device *usbdev = container_of(dev, struct usb_device, dev); - struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); - const struct usb_device_id *id; - - debug("matching: 0x%04x 0x%04x\n", usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); - - id = usb_match_id(usbdev, usbdrv->id_table); - if (id) { - debug("match: 0x%04x 0x%04x\n", id->idVendor, id->idProduct); - return 0; - } - return 1; -} - -static int usb_probe(struct device_d *dev) -{ - struct usb_device *usbdev = container_of(dev, struct usb_device, dev); - struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); - const struct usb_device_id *id; - - id = usb_match_id(usbdev, usbdrv->id_table); - - return usbdrv->probe(usbdev, id); -} - -static void usb_remove(struct device_d *dev) -{ - struct usb_device *usbdev = container_of(dev, struct usb_device, dev); - struct usb_driver *usbdrv = container_of(dev->driver, struct usb_driver, driver); - - usbdrv->disconnect(usbdev); -} - -struct bus_type usb_bus_type = { - .name = "usb", - .match = usb_match, - .probe = usb_probe, - .remove = usb_remove, -}; - diff --git a/drivers/usb/usb_ehci.h b/drivers/usb/usb_ehci.h deleted file mode 100644 index af49249..0000000 --- a/drivers/usb/usb_ehci.h +++ /dev/null @@ -1,190 +0,0 @@ -/*- - * Copyright (c) 2007-2008, Juniper Networks, Inc. - * Copyright (c) 2008, Michael Trimarchi - * All rights reserved. - * - * 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 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 - */ - -#ifndef USB_EHCI_H -#define USB_EHCI_H - -#if !defined(CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) -#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 2 -#endif - -/* (shifted) direction/type/recipient from the USB 2.0 spec, table 9.2 */ -#define DeviceRequest \ - ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8) - -#define DeviceOutRequest \ - ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) << 8) - -#define InterfaceRequest \ - ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) - -#define EndpointRequest \ - ((USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) - -#define EndpointOutRequest \ - ((USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE) << 8) - -/* - * Register Space. - */ -struct ehci_hccr { - uint32_t cr_capbase; -#define HC_LENGTH(p) (((p) >> 0) & 0x00ff) -#define HC_VERSION(p) (((p) >> 16) & 0xffff) - uint32_t cr_hcsparams; -#define HCS_PPC(p) ((p) & (1 << 4)) -#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* Port indicators */ -#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) - uint32_t cr_hccparams; - uint8_t cr_hcsp_portrt[8]; -} __attribute__ ((packed)); - -struct ehci_hcor { - uint32_t or_usbcmd; -#define CMD_PARK (1 << 11) /* enable "park" */ -#define CMD_PARK_CNT(c) (((c) >> 8) & 3) /* how many transfers to park */ -#define CMD_ASE (1 << 5) /* async schedule enable */ -#define CMD_LRESET (1 << 7) /* partial reset */ -#define CMD_IAAD (1 << 5) /* "doorbell" interrupt */ -#define CMD_PSE (1 << 4) /* periodic schedule enable */ -#define CMD_RESET (1 << 1) /* reset HC not bus */ -#define CMD_RUN (1 << 0) /* start/stop HC */ - uint32_t or_usbsts; -#define STD_ASS (1 << 15) -#define STS_HALT (1 << 12) - uint32_t or_usbintr; - uint32_t or_frindex; - uint32_t or_ctrldssegment; - uint32_t or_periodiclistbase; - uint32_t or_asynclistaddr; - uint32_t _reserved_[9]; - uint32_t or_configflag; -#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */ - uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS]; - uint32_t or_systune; -} __attribute__ ((packed)); - -#define USBMODE 0x68 /* USB Device mode */ -#define USBMODE_SDIS (1 << 3) /* Stream disable */ -#define USBMODE_BE (1 << 2) /* BE/LE endiannes select */ -#define USBMODE_CM_HC (3 << 0) /* host controller mode */ -#define USBMODE_CM_IDLE (0 << 0) /* idle state */ - -/* Interface descriptor */ -struct usb_linux_interface_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned char bInterfaceNumber; - unsigned char bAlternateSetting; - unsigned char bNumEndpoints; - unsigned char bInterfaceClass; - unsigned char bInterfaceSubClass; - unsigned char bInterfaceProtocol; - unsigned char iInterface; -} __attribute__ ((packed)); - -/* Configuration descriptor information.. */ -struct usb_linux_config_descriptor { - unsigned char bLength; - unsigned char bDescriptorType; - unsigned short wTotalLength; - unsigned char bNumInterfaces; - unsigned char bConfigurationValue; - unsigned char iConfiguration; - unsigned char bmAttributes; - unsigned char MaxPower; -} __attribute__ ((packed)); - -#if defined CONFIG_EHCI_DESC_BIG_ENDIAN -#define ehci_readl(x) (*((volatile u32 *)(x))) -#define ehci_writel(a, b) (*((volatile u32 *)(a)) = ((volatile u32)b)) -#else -#define ehci_readl(x) cpu_to_le32((*((volatile u32 *)(x)))) -#define ehci_writel(a, b) (*((volatile u32 *)(a)) = \ - cpu_to_le32(((volatile u32)b))) -#endif - -#if defined CONFIG_EHCI_MMIO_BIG_ENDIAN -#define hc32_to_cpu(x) be32_to_cpu((x)) -#define cpu_to_hc32(x) cpu_to_be32((x)) -#else -#define hc32_to_cpu(x) le32_to_cpu((x)) -#define cpu_to_hc32(x) cpu_to_le32((x)) -#endif - -#define EHCI_PS_WKOC_E (1 << 22) /* RW wake on over current */ -#define EHCI_PS_WKDSCNNT_E (1 << 21) /* RW wake on disconnect */ -#define EHCI_PS_WKCNNT_E (1 << 20) /* RW wake on connect */ -#define EHCI_PS_PO (1 << 13) /* RW port owner */ -#define EHCI_PS_PP (1 << 12) /* RW,RO port power */ -#define EHCI_PS_LS (3 << 10) /* RO line status */ -#define EHCI_PS_PR (1 << 8) /* RW port reset */ -#define EHCI_PS_SUSP (1 << 7) /* RW suspend */ -#define EHCI_PS_FPR (1 << 6) /* RW force port resume */ -#define EHCI_PS_OCC (1 << 5) /* RWC over current change */ -#define EHCI_PS_OCA (1 << 4) /* RO over current active */ -#define EHCI_PS_PEC (1 << 3) /* RWC port enable change */ -#define EHCI_PS_PE (1 << 2) /* RW port enable */ -#define EHCI_PS_CSC (1 << 1) /* RWC connect status change */ -#define EHCI_PS_CS (1 << 0) /* RO connect status */ -#define EHCI_PS_CLEAR (EHCI_PS_OCC | EHCI_PS_PEC | EHCI_PS_CSC) - -#define EHCI_PS_IS_LOWSPEED(x) (((x) & EHCI_PS_LS) == (1 << 10)) - -/* - * Schedule Interface Space. - * - * IMPORTANT: Software must ensure that no interface data structure - * reachable by the EHCI host controller spans a 4K page boundary! - * - * Periodic transfers (i.e. isochronous and interrupt transfers) are - * not supported. - */ - -/* Queue Element Transfer Descriptor (qTD). */ -struct qTD { - uint32_t qt_next; -#define QT_NEXT_TERMINATE 1 - uint32_t qt_altnext; - uint32_t qt_token; - uint32_t qt_buffer[5]; -}; - -/* Queue Head (QH). */ -struct QH { - uint32_t qh_link; -#define QH_LINK_TERMINATE 1 -#define QH_LINK_TYPE_ITD 0 -#define QH_LINK_TYPE_QH 2 -#define QH_LINK_TYPE_SITD 4 -#define QH_LINK_TYPE_FSTN 6 - uint32_t qh_endpt1; - uint32_t qh_endpt2; - uint32_t qh_curtd; - struct qTD qh_overlay; - /* - * Add dummy fill value to make the size of this struct - * aligned to 32 bytes - */ - uint8_t fill[16]; -}; - -#endif /* USB_EHCI_H */ diff --git a/drivers/usb/usb_ehci_core.c b/drivers/usb/usb_ehci_core.c deleted file mode 100644 index af066de..0000000 --- a/drivers/usb/usb_ehci_core.c +++ /dev/null @@ -1,938 +0,0 @@ -/*- - * Copyright (c) 2007-2008, Juniper Networks, Inc. - * Copyright (c) 2008, Excito Elektronik i Skåne AB - * Copyright (c) 2008, Michael Trimarchi - * - * All rights reserved. - * - * 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 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "usb_ehci.h" - -struct ehci_priv { - int rootdev; - struct ehci_hccr *hccr; - struct ehci_hcor *hcor; - struct usb_host host; - struct QH *qh_list; - void *qhp; - int portreset; - unsigned long flags; -}; - -#define to_ehci(ptr) container_of(ptr, struct ehci_priv, host) - -static struct descriptor { - struct usb_hub_descriptor hub; - struct usb_device_descriptor device; - struct usb_linux_config_descriptor config; - struct usb_linux_interface_descriptor interface; - struct usb_endpoint_descriptor endpoint; -} __attribute__ ((packed)) descriptor = { - { - 0x8, /* bDescLength */ - 0x29, /* bDescriptorType: hub descriptor */ - 2, /* bNrPorts -- runtime modified */ - 0, /* wHubCharacteristics */ - 0xff, /* bPwrOn2PwrGood */ - 0, /* bHubCntrCurrent */ - {}, /* Device removable */ - {} /* at most 7 ports! XXX */ - }, - { - 0x12, /* bLength */ - 1, /* bDescriptorType: UDESC_DEVICE */ - 0x0002, /* bcdUSB: v2.0 */ - 9, /* bDeviceClass: UDCLASS_HUB */ - 0, /* bDeviceSubClass: UDSUBCLASS_HUB */ - 1, /* bDeviceProtocol: UDPROTO_HSHUBSTT */ - 64, /* bMaxPacketSize: 64 bytes */ - 0x0000, /* idVendor */ - 0x0000, /* idProduct */ - 0x0001, /* bcdDevice */ - 1, /* iManufacturer */ - 2, /* iProduct */ - 0, /* iSerialNumber */ - 1 /* bNumConfigurations: 1 */ - }, - { - 0x9, - 2, /* bDescriptorType: UDESC_CONFIG */ - cpu_to_le16(0x19), - 1, /* bNumInterface */ - 1, /* bConfigurationValue */ - 0, /* iConfiguration */ - 0x40, /* bmAttributes: UC_SELF_POWER */ - 0 /* bMaxPower */ - }, - { - 0x9, /* bLength */ - 4, /* bDescriptorType: UDESC_INTERFACE */ - 0, /* bInterfaceNumber */ - 0, /* bAlternateSetting */ - 1, /* bNumEndpoints */ - 9, /* bInterfaceClass: UICLASS_HUB */ - 0, /* bInterfaceSubClass: UISUBCLASS_HUB */ - 0, /* bInterfaceProtocol: UIPROTO_HSHUBSTT */ - 0 /* iInterface */ - }, - { - 0x7, /* bLength */ - 5, /* bDescriptorType: UDESC_ENDPOINT */ - 0x81, /* bEndpointAddress: - * UE_DIR_IN | EHCI_INTR_ENDPT - */ - 3, /* bmAttributes: UE_INTERRUPT */ - 8, 0, /* wMaxPacketSize */ - 255 /* bInterval */ - }, -}; - -#define ehci_is_TDI() (ehci->flags & EHCI_HAS_TT) - -#ifdef CONFIG_MMU -/* - * Routines to handle (flush/invalidate) the dcache for the QH and qTD - * structures and data buffers. This is needed on platforms using this - * EHCI support with dcache enabled. - */ -static void flush_invalidate(void *addr, int size, int flush) -{ - if (flush) - dma_flush_range((unsigned long)addr, (unsigned long)(addr + size)); - else - dma_inv_range((unsigned long)addr, (unsigned long)(addr + size)); -} - -static void cache_qtd(struct qTD *qtd, int flush) -{ - u32 *ptr = (u32 *)qtd->qt_buffer[0]; - int len = (qtd->qt_token & 0x7fff0000) >> 16; - - flush_invalidate(qtd, sizeof(struct qTD), flush); - if (ptr && len) - flush_invalidate(ptr, len, flush); -} - - -static inline struct QH *qh_addr(struct QH *qh) -{ - return (struct QH *)((u32)qh & 0xffffffe0); -} - -static void cache_qh(struct QH *qh, int flush) -{ - struct qTD *qtd; - struct qTD *next; - static struct qTD *first_qtd; - - /* - * Walk the QH list and flush/invalidate all entries - */ - while (1) { - flush_invalidate(qh_addr(qh), sizeof(struct QH), flush); - if ((u32)qh & QH_LINK_TYPE_QH) - break; - qh = qh_addr(qh); - qh = (struct QH *)qh->qh_link; - } - qh = qh_addr(qh); - - /* - * Save first qTD pointer, needed for invalidating pass on this QH - */ - if (flush) - first_qtd = qtd = (struct qTD *)(*(u32 *)&qh->qh_overlay & - 0xffffffe0); - else - qtd = first_qtd; - - /* - * Walk the qTD list and flush/invalidate all entries - */ - while (1) { - if (qtd == NULL) - break; - cache_qtd(qtd, flush); - next = (struct qTD *)((u32)qtd->qt_next & 0xffffffe0); - if (next == qtd) - break; - qtd = next; - } -} - -static inline void ehci_flush_dcache(struct QH *qh) -{ - cache_qh(qh, 1); -} - -static inline void ehci_invalidate_dcache(struct QH *qh) -{ - cache_qh(qh, 0); -} -#else /* CONFIG_MMU */ -/* - * - */ -static inline void ehci_flush_dcache(struct QH *qh) -{ -} - -static inline void ehci_invalidate_dcache(struct QH *qh) -{ -} -#endif /* CONFIG_MMU */ - -static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec) -{ - uint32_t result; - uint64_t start; - - start = get_time_ns(); - - while (1) { - result = ehci_readl(ptr); - if (result == ~(uint32_t)0) - return -1; - result &= mask; - if (result == done) - return 0; - if (is_timeout(start, usec * USECOND)) - return -ETIMEDOUT; - } -} - -static int ehci_reset(struct ehci_priv *ehci) -{ - uint32_t cmd; - uint32_t tmp; - uint32_t *reg_ptr; - int ret = 0; - - cmd = ehci_readl(&ehci->hcor->or_usbcmd); - cmd |= CMD_RESET; - ehci_writel(&ehci->hcor->or_usbcmd, cmd); - ret = handshake(&ehci->hcor->or_usbcmd, CMD_RESET, 0, 250 * 1000); - if (ret < 0) { - printf("EHCI fail to reset\n"); - goto out; - } - - if (ehci_is_TDI()) { - reg_ptr = (uint32_t *)((u8 *)ehci->hcor + USBMODE); - tmp = ehci_readl(reg_ptr); - tmp |= USBMODE_CM_HC; -#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN) - tmp |= USBMODE_BE; -#endif - ehci_writel(reg_ptr, tmp); - } -out: - return ret; -} - -static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) -{ - uint32_t addr, delta, next; - int idx; - - addr = (uint32_t) buf; - idx = 0; - while (idx < 5) { - td->qt_buffer[idx] = cpu_to_hc32(addr); - next = (addr + 4096) & ~4095; - delta = next - addr; - if (delta >= sz) - break; - sz -= delta; - addr = next; - idx++; - } - - if (idx == 5) { - debug("out of buffer pointers (%u bytes left)\n", sz); - return -1; - } - - return 0; -} - -static int -ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, - int length, struct devrequest *req) -{ - struct usb_host *host = dev->host; - struct ehci_priv *ehci = to_ehci(host); - struct QH *qh; - struct qTD *td; - volatile struct qTD *vtd; - uint32_t *tdp; - uint32_t endpt, token, usbsts; - uint32_t c, toggle; - uint32_t cmd; - int ret = 0; - uint64_t start; - static struct QH __qh __attribute__((aligned(32))); - static struct qTD __td[3] __attribute__((aligned(32))); - - debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe, - buffer, length, req); - if (req != NULL) - debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n", - req->request, req->request, - req->requesttype, req->requesttype, - le16_to_cpu(req->value), le16_to_cpu(req->value), - le16_to_cpu(req->index)); - - memset(&__qh, sizeof(struct QH), 0); - memset(&__td, sizeof(struct qTD) * 3, 0); - - qh = &__qh; - qh->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); - c = (usb_pipespeed(pipe) != USB_SPEED_HIGH && - usb_pipeendpoint(pipe) == 0) ? 1 : 0; - endpt = (8 << 28) | - (c << 27) | - (usb_maxpacket(dev, pipe) << 16) | - (0 << 15) | - (1 << 14) | - (usb_pipespeed(pipe) << 12) | - (usb_pipeendpoint(pipe) << 8) | - (0 << 7) | (usb_pipedevice(pipe) << 0); - qh->qh_endpt1 = cpu_to_hc32(endpt); - endpt = (1 << 30) | - (dev->portnr << 23) | - (dev->parent->devnum << 16) | (0 << 8) | (0 << 0); - qh->qh_endpt2 = cpu_to_hc32(endpt); - qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); - - td = NULL; - tdp = &qh->qh_overlay.qt_next; - - toggle = - usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)); - - if (req != NULL) { - td = &__td[0]; - - td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); - token = (0 << 31) | - (sizeof(*req) << 16) | - (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0); - td->qt_token = cpu_to_hc32(token); - if (ehci_td_buffer(td, req, sizeof(*req)) != 0) { - debug("unable construct SETUP td\n"); - goto fail; - } - *tdp = cpu_to_hc32((uint32_t) td); - tdp = &td->qt_next; - - toggle = 1; - } - - if (length > 0 || req == NULL) { - td = &__td[1]; - - td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); - token = (toggle << 31) | - (length << 16) | - ((req == NULL ? 1 : 0) << 15) | - (0 << 12) | - (3 << 10) | - ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0); - td->qt_token = cpu_to_hc32(token); - if (ehci_td_buffer(td, buffer, length) != 0) { - printf("unable construct DATA td\n"); - goto fail; - } - *tdp = cpu_to_hc32((uint32_t) td); - tdp = &td->qt_next; - } - - if (req) { - td = &__td[2]; - - td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); - token = (toggle << 31) | - (0 << 16) | - (1 << 15) | - (0 << 12) | - (3 << 10) | - ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0); - td->qt_token = cpu_to_hc32(token); - *tdp = cpu_to_hc32((uint32_t)td); - tdp = &td->qt_next; - } - - ehci->qh_list->qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH); - - /* Flush dcache */ - ehci_flush_dcache(ehci->qh_list); - - usbsts = ehci_readl(&ehci->hcor->or_usbsts); - ehci_writel(&ehci->hcor->or_usbsts, (usbsts & 0x3f)); - - /* Enable async. schedule. */ - cmd = ehci_readl(&ehci->hcor->or_usbcmd); - cmd |= CMD_ASE; - ehci_writel(&ehci->hcor->or_usbcmd, cmd); - - ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, STD_ASS, 100 * 1000); - if (ret < 0) { - printf("EHCI fail timeout STD_ASS set\n"); - goto fail; - } - - /* Wait for TDs to be processed. */ - start = get_time_ns(); - vtd = td; - do { - /* Invalidate dcache */ - ehci_invalidate_dcache(ehci->qh_list); - token = hc32_to_cpu(vtd->qt_token); - if (is_timeout(start, SECOND >> 2)) { - /* Disable async schedule. */ - cmd = ehci_readl(&ehci->hcor->or_usbcmd); - cmd &= ~CMD_ASE; - ehci_writel(&ehci->hcor->or_usbcmd, cmd); - - ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, 0, 100 * 1000); - ehci_writel(&qh->qh_overlay.qt_token, 0); - return -ETIMEDOUT; - } - } while (token & 0x80); - - /* Disable async schedule. */ - cmd = ehci_readl(&ehci->hcor->or_usbcmd); - cmd &= ~CMD_ASE; - ehci_writel(&ehci->hcor->or_usbcmd, cmd); - - ret = handshake(&ehci->hcor->or_usbsts, STD_ASS, 0, - 100 * 1000); - if (ret < 0) { - printf("EHCI fail timeout STD_ASS reset\n"); - goto fail; - } - - ehci->qh_list->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); - - token = hc32_to_cpu(qh->qh_overlay.qt_token); - if (!(token & 0x80)) { - debug("TOKEN=0x%08x\n", token); - switch (token & 0xfc) { - case 0: - toggle = token >> 31; - usb_settoggle(dev, usb_pipeendpoint(pipe), - usb_pipeout(pipe), toggle); - dev->status = 0; - break; - case 0x40: - dev->status = USB_ST_STALLED; - break; - case 0xa0: - case 0x20: - dev->status = USB_ST_BUF_ERR; - break; - case 0x50: - case 0x10: - dev->status = USB_ST_BABBLE_DET; - break; - default: - dev->status = USB_ST_CRC_ERR; - break; - } - dev->act_len = length - ((token >> 16) & 0x7fff); - } else { - dev->act_len = 0; - debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n", - dev->devnum, ehci_readl(&ehci->hcor->or_usbsts), - ehci_readl(&ehci->hcor->or_portsc[0]), - ehci_readl(&ehci->hcor->or_portsc[1])); - } - - return (dev->status != USB_ST_NOT_PROC) ? 0 : -1; - -fail: - printf("fail1\n"); - td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); - while (td != (void *)QT_NEXT_TERMINATE) { - qh->qh_overlay.qt_next = td->qt_next; - td = (void *)hc32_to_cpu(qh->qh_overlay.qt_next); - } - return -1; -} - -static inline int min3(int a, int b, int c) -{ - - if (b < a) - a = b; - if (c < a) - a = c; - return a; -} - -int -ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, - int length, struct devrequest *req) -{ - struct usb_host *host = dev->host; - struct ehci_priv *ehci = to_ehci(host); - uint8_t tmpbuf[4]; - u16 typeReq; - void *srcptr = NULL; - int len, srclen; - uint32_t reg; - uint32_t *status_reg; - - if (le16_to_cpu(req->index) >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { - printf("The request port(%d) is not configured\n", - le16_to_cpu(req->index) - 1); - return -1; - } - status_reg = (uint32_t *)&ehci->hcor->or_portsc[le16_to_cpu(req->index) - 1]; - srclen = 0; - - debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", - req->request, req->request, - req->requesttype, req->requesttype, - le16_to_cpu(req->value), le16_to_cpu(req->index)); - - typeReq = req->request | (req->requesttype << 8); - - switch (typeReq) { - case DeviceRequest | USB_REQ_GET_DESCRIPTOR: - switch (le16_to_cpu(req->value) >> 8) { - case USB_DT_DEVICE: - debug("USB_DT_DEVICE request\n"); - srcptr = &descriptor.device; - srclen = 0x12; - break; - case USB_DT_CONFIG: - debug("USB_DT_CONFIG config\n"); - srcptr = &descriptor.config; - srclen = 0x19; - break; - case USB_DT_STRING: - debug("USB_DT_STRING config\n"); - switch (le16_to_cpu(req->value) & 0xff) { - case 0: /* Language */ - srcptr = "\4\3\1\0"; - srclen = 4; - break; - case 1: /* Vendor */ - srcptr = "\16\3u\0-\0b\0o\0o\0t\0"; - srclen = 14; - break; - case 2: /* Product */ - srcptr = "\52\3E\0H\0C\0I\0 " - "\0H\0o\0s\0t\0 " - "\0C\0o\0n\0t\0r\0o\0l\0l\0e\0r\0"; - srclen = 42; - break; - default: - debug("unknown value DT_STRING %x\n", - le16_to_cpu(req->value)); - goto unknown; - } - break; - default: - debug("unknown value %x\n", le16_to_cpu(req->value)); - goto unknown; - } - break; - case ((USB_DIR_IN | USB_RT_HUB) << 8) | USB_REQ_GET_DESCRIPTOR: - switch (le16_to_cpu(req->value) >> 8) { - case USB_DT_HUB: - debug("USB_DT_HUB config\n"); - srcptr = &descriptor.hub; - srclen = 0x8; - break; - default: - debug("unknown value %x\n", le16_to_cpu(req->value)); - goto unknown; - } - break; - case USB_REQ_SET_ADDRESS | (USB_RECIP_DEVICE << 8): - debug("USB_REQ_SET_ADDRESS\n"); - ehci->rootdev = le16_to_cpu(req->value); - break; - case DeviceOutRequest | USB_REQ_SET_CONFIGURATION: - debug("USB_REQ_SET_CONFIGURATION\n"); - /* Nothing to do */ - break; - case USB_REQ_GET_STATUS | ((USB_DIR_IN | USB_RT_HUB) << 8): - tmpbuf[0] = 1; /* USB_STATUS_SELFPOWERED */ - tmpbuf[1] = 0; - srcptr = tmpbuf; - srclen = 2; - break; - case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): - memset(tmpbuf, 0, 4); - reg = ehci_readl(status_reg); - if (reg & EHCI_PS_CS) - tmpbuf[0] |= USB_PORT_STAT_CONNECTION; - if (reg & EHCI_PS_PE) - tmpbuf[0] |= USB_PORT_STAT_ENABLE; - if (reg & EHCI_PS_SUSP) - tmpbuf[0] |= USB_PORT_STAT_SUSPEND; - if (reg & EHCI_PS_OCA) - tmpbuf[0] |= USB_PORT_STAT_OVERCURRENT; - if (reg & EHCI_PS_PR && - (ehci->portreset & (1 << le16_to_cpu(req->index)))) { - int ret; - /* force reset to complete */ - reg = reg & ~(EHCI_PS_PR | EHCI_PS_CLEAR); - ehci_writel(status_reg, reg); - ret = handshake(status_reg, EHCI_PS_PR, 0, 2 * 1000); - if (!ret) - tmpbuf[0] |= USB_PORT_STAT_RESET; - else - printf("port(%d) reset error\n", - le16_to_cpu(req->index) - 1); - } - if (reg & EHCI_PS_PP) - tmpbuf[1] |= USB_PORT_STAT_POWER >> 8; - - if (ehci_is_TDI()) { - switch ((reg >> 26) & 3) { - case 0: - break; - case 1: - tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8; - break; - case 2: - default: - tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8; - break; - } - } else { - tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8; - } - - if (reg & EHCI_PS_CSC) - tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION; - if (reg & EHCI_PS_PEC) - tmpbuf[2] |= USB_PORT_STAT_C_ENABLE; - if (reg & EHCI_PS_OCC) - tmpbuf[2] |= USB_PORT_STAT_C_OVERCURRENT; - if (ehci->portreset & (1 << le16_to_cpu(req->index))) - tmpbuf[2] |= USB_PORT_STAT_C_RESET; - - srcptr = tmpbuf; - srclen = 4; - break; - case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): - reg = ehci_readl(status_reg); - reg &= ~EHCI_PS_CLEAR; - switch (le16_to_cpu(req->value)) { - case USB_PORT_FEAT_ENABLE: - reg |= EHCI_PS_PE; - ehci_writel(status_reg, reg); - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC(ehci_readl(&ehci->hccr->cr_hcsparams))) { - reg |= EHCI_PS_PP; - ehci_writel(status_reg, reg); - } - break; - case USB_PORT_FEAT_RESET: - if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS && - !ehci_is_TDI() && - EHCI_PS_IS_LOWSPEED(reg)) { - /* Low speed device, give up ownership. */ - debug("port %d low speed --> companion\n", - req->index - 1); - reg |= EHCI_PS_PO; - ehci_writel(status_reg, reg); - break; - } else { - int ret; - - reg |= EHCI_PS_PR; - reg &= ~EHCI_PS_PE; - ehci_writel(status_reg, reg); - /* - * caller must wait, then call GetPortStatus - * usb 2.0 specification say 50 ms resets on - * root - */ - wait_ms(50); - ehci->portreset |= 1 << le16_to_cpu(req->index); - /* terminate the reset */ - ehci_writel(status_reg, reg & ~EHCI_PS_PR); - /* - * A host controller must terminate the reset - * and stabilize the state of the port within - * 2 milliseconds - */ - ret = handshake(status_reg, EHCI_PS_PR, 0, - 2 * 1000); - if (!ret) - ehci->portreset |= - 1 << le16_to_cpu(req->index); - else - printf("port(%d) reset error\n", - le16_to_cpu(req->index) - 1); - - } - break; - default: - debug("unknown feature %x\n", le16_to_cpu(req->value)); - goto unknown; - } - /* unblock posted writes */ - ehci_readl(&ehci->hcor->or_usbcmd); - break; - case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): - reg = ehci_readl(status_reg); - switch (le16_to_cpu(req->value)) { - case USB_PORT_FEAT_ENABLE: - reg &= ~EHCI_PS_PE; - break; - case USB_PORT_FEAT_C_ENABLE: - reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE; - break; - case USB_PORT_FEAT_POWER: - if (HCS_PPC(ehci_readl(&ehci->hccr->cr_hcsparams))) - reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP); - case USB_PORT_FEAT_C_CONNECTION: - reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC; - break; - case USB_PORT_FEAT_OVER_CURRENT: - reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; - break; - case USB_PORT_FEAT_C_RESET: - ehci->portreset &= ~(1 << le16_to_cpu(req->index)); - break; - default: - debug("unknown feature %x\n", le16_to_cpu(req->value)); - goto unknown; - } - ehci_writel(status_reg, reg); - /* unblock posted write */ - ehci_readl(&ehci->hcor->or_usbcmd); - break; - default: - debug("Unknown request\n"); - goto unknown; - } - - wait_ms(1); - len = min3(srclen, le16_to_cpu(req->length), length); - if (srcptr != NULL && len > 0) - memcpy(buffer, srcptr, len); - else - debug("Len is 0\n"); - - dev->act_len = len; - dev->status = 0; - return 0; - -unknown: - debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n", - req->requesttype, req->request, le16_to_cpu(req->value), - le16_to_cpu(req->index), le16_to_cpu(req->length)); - - dev->act_len = 0; - dev->status = USB_ST_STALLED; - return -1; -} - -/* force HC to halt state from unknown (EHCI spec section 2.3) */ -static int ehci_halt(struct ehci_priv *ehci) -{ - u32 temp = ehci_readl(&ehci->hcor->or_usbsts); - - /* disable any irqs left enabled by previous code */ - ehci_writel(&ehci->hcor->or_usbintr, 0); - - if (temp & STS_HALT) - return 0; - - temp = ehci_readl(&ehci->hcor->or_usbcmd); - temp &= ~CMD_RUN; - ehci_writel(&ehci->hcor->or_usbcmd, temp); - - return handshake(&ehci->hcor->or_usbsts, - STS_HALT, STS_HALT, 16 * 125); -} - -static int ehci_init(struct usb_host *host) -{ - struct ehci_priv *ehci = to_ehci(host); - uint32_t reg; - uint32_t cmd; - - ehci_halt(ehci); - - /* EHCI spec section 4.1 */ - if (ehci_reset(ehci) != 0) - return -1; - - /* Set head of reclaim list */ - ehci->qhp = xzalloc(sizeof(struct QH) + 32); - ehci->qh_list = (struct QH *)(((unsigned long)ehci->qhp + 32) & ~31); - - ehci->qh_list->qh_link = cpu_to_hc32((uint32_t)ehci->qh_list | QH_LINK_TYPE_QH); - ehci->qh_list->qh_endpt1 = cpu_to_hc32((1 << 15) | (USB_SPEED_HIGH << 12)); - ehci->qh_list->qh_curtd = cpu_to_hc32(QT_NEXT_TERMINATE); - ehci->qh_list->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); - ehci->qh_list->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); - ehci->qh_list->qh_overlay.qt_token = cpu_to_hc32(0x40); - - /* Set async. queue head pointer. */ - ehci_writel(&ehci->hcor->or_asynclistaddr, (uint32_t)ehci->qh_list); - - reg = ehci_readl(&ehci->hccr->cr_hcsparams); - descriptor.hub.bNbrPorts = HCS_N_PORTS(reg); - - /* Port Indicators */ - if (HCS_INDICATOR(reg)) - descriptor.hub.wHubCharacteristics |= 0x80; - /* Port Power Control */ - if (HCS_PPC(reg)) - descriptor.hub.wHubCharacteristics |= 0x01; - - /* Start the host controller. */ - cmd = ehci_readl(&ehci->hcor->or_usbcmd); - /* - * Philips, Intel, and maybe others need CMD_RUN before the - * root hub will detect new devices (why?); NEC doesn't - */ - cmd &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET); - cmd |= CMD_RUN; - ehci_writel(&ehci->hcor->or_usbcmd, cmd); - - /* take control over the ports */ - cmd = ehci_readl(&ehci->hcor->or_configflag); - cmd |= FLAG_CF; - ehci_writel(&ehci->hcor->or_configflag, cmd); - /* unblock posted write */ - cmd = ehci_readl(&ehci->hcor->or_usbcmd); - wait_ms(5); - - ehci->rootdev = 0; - - return 0; -} - -static int -submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int length) -{ - - if (usb_pipetype(pipe) != PIPE_BULK) { - debug("non-bulk pipe (type=%lu)", usb_pipetype(pipe)); - return -1; - } - return ehci_submit_async(dev, pipe, buffer, length, NULL); -} - -static int -submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int length, struct devrequest *setup) -{ - struct usb_host *host = dev->host; - struct ehci_priv *ehci = to_ehci(host); - - if (usb_pipetype(pipe) != PIPE_CONTROL) { - debug("non-control pipe (type=%lu)", usb_pipetype(pipe)); - return -1; - } - - if (usb_pipedevice(pipe) == ehci->rootdev) { - if (ehci->rootdev == 0) - dev->speed = USB_SPEED_HIGH; - return ehci_submit_root(dev, pipe, buffer, length, setup); - } - return ehci_submit_async(dev, pipe, buffer, length, setup); -} - -static int -submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int length, int interval) -{ - debug("dev=%p, pipe=%lu, buffer=%p, length=%d, interval=%d", - dev, pipe, buffer, length, interval); - return -1; -} - -static int ehci_probe(struct device_d *dev) -{ - struct usb_host *host; - struct ehci_priv *ehci; - uint32_t reg; - struct ehci_platform_data *pdata = dev->platform_data; - - ehci = xmalloc(sizeof(struct ehci_priv)); - host = &ehci->host; - - if (pdata) - ehci->flags = pdata->flags; - else - /* default to EHCI_HAS_TT to not change behaviour of boards - * with platform_data - */ - ehci->flags = EHCI_HAS_TT; - - host->init = ehci_init; - host->submit_int_msg = submit_int_msg; - host->submit_control_msg = submit_control_msg; - host->submit_bulk_msg = submit_bulk_msg; - - ehci->hccr = (void *)(dev->map_base + 0x100); - ehci->hcor = (void *)(dev->map_base + 0x140); - - usb_register_host(host); - - reg = HC_VERSION(ehci_readl(&ehci->hccr->cr_capbase)); - dev_info(dev, "USB EHCI %x.%02x\n", reg >> 8, reg & 0xff); - - return 0; -} - -static struct driver_d ehci_driver = { - .name = "ehci", - .probe = ehci_probe, -}; - -static int ehcil_init(void) -{ - register_driver(&ehci_driver); - return 0; -} - -device_initcall(ehcil_init); - diff --git a/drivers/usb/usb_ehci_core.h b/drivers/usb/usb_ehci_core.h deleted file mode 100644 index 39e5c5e..0000000 --- a/drivers/usb/usb_ehci_core.h +++ /dev/null @@ -1,29 +0,0 @@ -/*- - * Copyright (c) 2007-2008, Juniper Networks, Inc. - * Copyright (c) 2008, Excito Elektronik i Skåne AB - * All rights reserved. - * - * 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 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 - */ - -#ifndef USB_EHCI_CORE_H -#define USB_EHCI_CORE_H - -extern int rootdev; -extern struct ehci_hccr *hccr; -extern volatile struct ehci_hcor *hcor; - -#endif diff --git a/fs/Kconfig b/fs/Kconfig index 3e9de96..d05797a 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -16,4 +16,7 @@ default y prompt "devfs support" +config PARTITION_NEED_MTD + bool + endmenu diff --git a/fs/devfs.c b/fs/devfs.c index 7478ef9..7019c8d 100644 --- a/fs/devfs.c +++ b/fs/devfs.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -170,6 +172,7 @@ static int partition_ioctl(struct cdev *cdev, int request, void *buf) { size_t offset; + struct mtd_info_user *user = buf; switch (request) { case MEMSETBADBLOCK: @@ -178,6 +181,20 @@ 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; @@ -187,17 +204,14 @@ static int devfs_ioctl(struct device_d *_dev, FILE *f, int request, void *buf) { struct cdev *cdev = f->inode; - int ret = -EINVAL; - - if (!cdev->ops->ioctl) - goto out; if (cdev->flags & DEVFS_IS_PARTITION) - ret = partition_ioctl(cdev, request, buf); - else - ret = cdev->ops->ioctl(cdev, request, buf); -out: - return ret; + return partition_ioctl(cdev, request, buf); + + if (!cdev->ops->ioctl) + return -EINVAL; + + return cdev->ops->ioctl(cdev, request, buf); } static int devfs_truncate(struct device_d *dev, FILE *f, ulong size) @@ -351,6 +365,17 @@ 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; @@ -370,6 +395,11 @@ 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; diff --git a/fs/fs.c b/fs/fs.c index 8417067..3b5f284 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -229,6 +229,16 @@ files[f->no].in_use = 0; } +static int check_fd(int fd) +{ + if (fd < 0 || fd >= MAX_FILES || !files[fd].in_use) { + errno = -EBADF; + return errno; + } + + return 0; +} + static struct device_d *get_fs_device_by_path(char **path) { struct device_d *dev; @@ -457,6 +467,9 @@ 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; @@ -474,6 +487,9 @@ 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; @@ -494,6 +510,9 @@ 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; @@ -524,6 +543,9 @@ FILE *f = &files[fildes]; off_t pos; + if (check_fd(fildes)) + return -1; + errno = 0; dev = f->dev; @@ -567,6 +589,9 @@ 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; @@ -589,6 +614,9 @@ 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; @@ -627,6 +655,9 @@ FILE *f = &files[fd]; void *ret = (void *)-1; + if (check_fd(fd)) + return ret; + dev = f->dev; fsdrv = (struct fs_driver_d *)dev->driver->type_data; @@ -646,6 +677,9 @@ 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; diff --git a/include/common.h b/include/common.h index 319535b..0edc778 100644 --- a/include/common.h +++ b/include/common.h @@ -109,8 +109,8 @@ long simple_strtol(const char *cp,char **endp,unsigned int base); /* lib_generic/crc32.c */ -ulong crc32 (ulong, const unsigned char *, uint); -ulong crc32_no_comp (ulong, const unsigned char *, uint); +uint32_t crc32(uint32_t, const void*, unsigned int); +uint32_t crc32_no_comp(uint32_t, const void*, unsigned int); /* common/console.c */ int ctrlc (void); diff --git a/include/driver.h b/include/driver.h index 6950c02..ae3e777 100644 --- a/include/driver.h +++ b/include/driver.h @@ -307,6 +307,7 @@ size_t size; unsigned int flags; int open; + struct mtd_info *mtd; }; int devfs_create(struct cdev *); diff --git a/include/linux/mtd/mtd-abi.h b/include/linux/mtd/mtd-abi.h index 04b4227..33e1fe2 100644 --- a/include/linux/mtd/mtd-abi.h +++ b/include/linux/mtd/mtd-abi.h @@ -62,6 +62,7 @@ * (TODO: remove at some point) */ uint32_t ecctype; uint32_t eccsize; + struct mtd_info *mtd; }; struct region_info_user { diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index ca98a16..01980f3 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -15,6 +15,7 @@ #include #include #include +#include #define MTD_CHAR_MAJOR 90 #define MTD_BLOCK_MAJOR 31 @@ -211,7 +212,16 @@ char *size_str; }; +static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) +{ + do_div(sz, mtd->erasesize); + return sz; +} +static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd) +{ + return do_div(sz, mtd->erasesize); +} /* Kernel-side ioctl definitions */ extern int add_mtd_device(struct mtd_info *mtd); @@ -229,6 +239,9 @@ struct list_head list; }; +struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, size_t size, + unsigned long flags, const char *name); +void mtd_del_partition(struct mtd_info *mtd); extern void register_mtd_user (struct mtd_notifier *new); extern int unregister_mtd_user (struct mtd_notifier *old); diff --git a/include/linux/mtd/ubi.h b/include/linux/mtd/ubi.h new file mode 100644 index 0000000..2f1db31 --- /dev/null +++ b/include/linux/mtd/ubi.h @@ -0,0 +1,186 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +#ifndef __LINUX_UBI_H__ +#define __LINUX_UBI_H__ + +/* #include */ +#include +#include + +/* + * enum ubi_open_mode - UBI volume open mode constants. + * + * UBI_READONLY: read-only mode + * UBI_READWRITE: read-write mode + * UBI_EXCLUSIVE: exclusive mode + */ +enum { + UBI_READONLY = 1, + UBI_READWRITE, + UBI_EXCLUSIVE +}; + +/** + * struct ubi_volume_info - UBI volume description data structure. + * @vol_id: volume ID + * @ubi_num: UBI device number this volume belongs to + * @size: how many physical eraseblocks are reserved for this volume + * @used_bytes: how many bytes of data this volume contains + * @used_ebs: how many physical eraseblocks of this volume actually contain any + * data + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @corrupted: non-zero if the volume is corrupted (static volumes only) + * @upd_marker: non-zero if the volume has update marker set + * @alignment: volume alignment + * @usable_leb_size: how many bytes are available in logical eraseblocks of + * this volume + * @name_len: volume name length + * @name: volume name + * @cdev: UBI volume character device major and minor numbers + * + * The @corrupted flag is only relevant to static volumes and is always zero + * for dynamic ones. This is because UBI does not care about dynamic volume + * data protection and only cares about protecting static volume data. + * + * The @upd_marker flag is set if the volume update operation was interrupted. + * Before touching the volume data during the update operation, UBI first sets + * the update marker flag for this volume. If the volume update operation was + * further interrupted, the update marker indicates this. If the update marker + * is set, the contents of the volume is certainly damaged and a new volume + * update operation has to be started. + * + * To put it differently, @corrupted and @upd_marker fields have different + * semantics: + * o the @corrupted flag means that this static volume is corrupted for some + * reasons, but not because an interrupted volume update + * o the @upd_marker field means that the volume is damaged because of an + * interrupted update operation. + * + * I.e., the @corrupted flag is never set if the @upd_marker flag is set. + * + * The @used_bytes and @used_ebs fields are only really needed for static + * volumes and contain the number of bytes stored in this static volume and how + * many eraseblock this data occupies. In case of dynamic volumes, the + * @used_bytes field is equivalent to @size*@usable_leb_size, and the @used_ebs + * field is equivalent to @size. + * + * In general, logical eraseblock size is a property of the UBI device, not + * of the UBI volume. Indeed, the logical eraseblock size depends on the + * physical eraseblock size and on how much bytes UBI headers consume. But + * because of the volume alignment (@alignment), the usable size of logical + * eraseblocks if a volume may be less. The following equation is true: + * @usable_leb_size = LEB size - (LEB size mod @alignment), + * where LEB size is the logical eraseblock size defined by the UBI device. + * + * The alignment is multiple to the minimal flash input/output unit size or %1 + * if all the available space is used. + * + * To put this differently, alignment may be considered is a way to change + * volume logical eraseblock sizes. + */ +struct ubi_volume_info { + int ubi_num; + int vol_id; + int size; + long long used_bytes; + int used_ebs; + int vol_type; + int corrupted; + int upd_marker; + int alignment; + int usable_leb_size; + int name_len; + const char *name; + struct cdev *cdev; +}; + +/** + * struct ubi_device_info - UBI device description data structure. + * @ubi_num: ubi device number + * @leb_size: logical eraseblock size on this UBI device + * @min_io_size: minimal I/O unit size + * @ro_mode: if this device is in read-only mode + * @cdev: UBI character device major and minor numbers + * + * Note, @leb_size is the logical eraseblock size offered by the UBI device. + * Volumes of this UBI device may have smaller logical eraseblock size if their + * alignment is not equivalent to %1. + */ +struct ubi_device_info { + int ubi_num; + int leb_size; + int min_io_size; + int ro_mode; + struct cdev *cdev; +}; + +/* UBI descriptor given to users when they open UBI volumes */ +struct ubi_volume_desc; + +int ubi_get_device_info(int ubi_num, struct ubi_device_info *di); +void ubi_get_volume_info(struct ubi_volume_desc *desc, + struct ubi_volume_info *vi); +struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode); +struct ubi_volume_desc *ubi_open_volume_nm(int ubi_num, const char *name, + int mode); +void ubi_close_volume(struct ubi_volume_desc *desc); +int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, + int len, int check); +int ubi_leb_write(struct ubi_volume_desc *desc, int lnum, const void *buf, + int offset, int len, int dtype); +int ubi_leb_change(struct ubi_volume_desc *desc, int lnum, const void *buf, + int len, int dtype); +int ubi_leb_erase(struct ubi_volume_desc *desc, int lnum); +int ubi_leb_unmap(struct ubi_volume_desc *desc, int lnum); +int ubi_leb_map(struct ubi_volume_desc *desc, int lnum, int dtype); +int ubi_is_mapped(struct ubi_volume_desc *desc, int lnum); + +/* + * This function is the same as the 'ubi_leb_read()' function, but it does not + * provide the checking capability. + */ +static inline int ubi_read(struct ubi_volume_desc *desc, int lnum, char *buf, + int offset, int len) +{ + return ubi_leb_read(desc, lnum, buf, offset, len, 0); +} + +/* + * This function is the same as the 'ubi_leb_write()' functions, but it does + * not have the data type argument. + */ +static inline int ubi_write(struct ubi_volume_desc *desc, int lnum, + const void *buf, int offset, int len) +{ + return ubi_leb_write(desc, lnum, buf, offset, len, UBI_UNKNOWN); +} + +/* + * This function is the same as the 'ubi_leb_change()' functions, but it does + * not have the data type argument. + */ +static inline int ubi_change(struct ubi_volume_desc *desc, int lnum, + const void *buf, int len) +{ + return ubi_leb_change(desc, lnum, buf, len, UBI_UNKNOWN); +} + +#endif /* !__LINUX_UBI_H__ */ diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h new file mode 100644 index 0000000..6ff28e0 --- /dev/null +++ b/include/linux/rbtree.h @@ -0,0 +1,160 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + + 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 + + linux/include/linux/rbtree.h + + To use rbtrees you'll have to implement your own insert and search cores. + This will avoid us to use callbacks and to drop drammatically performances. + I know it's not the cleaner way, but in C (not in C++) to get + performances and genericity... + + Some example of insert and search follows here. The search is a plain + normal search over an ordered tree. The insert instead must be implemented + int two steps: as first thing the code must insert the element in + order as a red leaf in the tree, then the support library function + rb_insert_color() must be called. Such function will do the + not trivial work to rebalance the rbtree if necessary. + +----------------------------------------------------------------------- +static inline struct page * rb_search_page_cache(struct inode * inode, + unsigned long offset) +{ + struct rb_node * n = inode->i_rb_page_cache.rb_node; + struct page * page; + + while (n) + { + page = rb_entry(n, struct page, rb_page_cache); + + if (offset < page->offset) + n = n->rb_left; + else if (offset > page->offset) + n = n->rb_right; + else + return page; + } + return NULL; +} + +static inline struct page * __rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct rb_node ** p = &inode->i_rb_page_cache.rb_node; + struct rb_node * parent = NULL; + struct page * page; + + while (*p) + { + parent = *p; + page = rb_entry(parent, struct page, rb_page_cache); + + if (offset < page->offset) + p = &(*p)->rb_left; + else if (offset > page->offset) + p = &(*p)->rb_right; + else + return page; + } + + rb_link_node(node, parent, p); + + return NULL; +} + +static inline struct page * rb_insert_page_cache(struct inode * inode, + unsigned long offset, + struct rb_node * node) +{ + struct page * ret; + if ((ret = __rb_insert_page_cache(inode, offset, node))) + goto out; + rb_insert_color(node, &inode->i_rb_page_cache); + out: + return ret; +} +----------------------------------------------------------------------- +*/ + +#ifndef _LINUX_RBTREE_H +#define _LINUX_RBTREE_H + +#include + +struct rb_node +{ + unsigned long rb_parent_color; +#define RB_RED 0 +#define RB_BLACK 1 + struct rb_node *rb_right; + struct rb_node *rb_left; +} __attribute__((aligned(sizeof(long)))); + /* The alignment might seem pointless, but allegedly CRIS needs it */ + +struct rb_root +{ + struct rb_node *rb_node; +}; + + +#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3)) +#define rb_color(r) ((r)->rb_parent_color & 1) +#define rb_is_red(r) (!rb_color(r)) +#define rb_is_black(r) rb_color(r) +#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0) +#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0) + +static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) +{ + rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p; +} +static inline void rb_set_color(struct rb_node *rb, int color) +{ + rb->rb_parent_color = (rb->rb_parent_color & ~1) | color; +} + +#define RB_ROOT (struct rb_root) { NULL, } +#define rb_entry(ptr, type, member) container_of(ptr, type, member) + +#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL) +#define RB_EMPTY_NODE(node) (rb_parent(node) == node) +#define RB_CLEAR_NODE(node) (rb_set_parent(node, node)) + +extern void rb_insert_color(struct rb_node *, struct rb_root *); +extern void rb_erase(struct rb_node *, struct rb_root *); + +/* Find logical next and previous nodes in a tree */ +extern struct rb_node *rb_next(struct rb_node *); +extern struct rb_node *rb_prev(struct rb_node *); +extern struct rb_node *rb_first(struct rb_root *); +extern struct rb_node *rb_last(struct rb_root *); + +/* Fast replacement of a single node without remove/rebalance/add/rebalance */ +extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root); + +static inline void rb_link_node(struct rb_node * node, struct rb_node * parent, + struct rb_node ** rb_link) +{ + node->rb_parent_color = (unsigned long )parent; + node->rb_left = node->rb_right = NULL; + + *rb_link = node; +} + +#endif /* _LINUX_RBTREE_H */ diff --git a/include/mtd/ubi-user.h b/include/mtd/ubi-user.h new file mode 100644 index 0000000..62d8c93 --- /dev/null +++ b/include/mtd/ubi-user.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) International Business Machines Corp., 2006 + * + * 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 + * + * Author: Artem Bityutskiy (Битюцкий Артём) + */ + +#ifndef __UBI_USER_H__ +#define __UBI_USER_H__ + +/* + * UBI device creation (the same as MTD device attachment) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI + * control device. The caller has to properly fill and pass + * &struct ubi_attach_req object - UBI will attach the MTD device specified in + * the request and return the newly created UBI device number as the ioctl + * return value. + * + * UBI device deletion (the same as MTD device detachment) + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI + * control device. + * + * UBI volume creation + * ~~~~~~~~~~~~~~~~~~~ + * + * UBI volumes are created via the %UBI_IOCMKVOL IOCTL command of UBI character + * device. A &struct ubi_mkvol_req object has to be properly filled and a + * pointer to it has to be passed to the IOCTL. + * + * UBI volume deletion + * ~~~~~~~~~~~~~~~~~~~ + * + * To delete a volume, the %UBI_IOCRMVOL IOCTL command of the UBI character + * device should be used. A pointer to the 32-bit volume ID hast to be passed + * to the IOCTL. + * + * UBI volume re-size + * ~~~~~~~~~~~~~~~~~~ + * + * To re-size a volume, the %UBI_IOCRSVOL IOCTL command of the UBI character + * device should be used. A &struct ubi_rsvol_req object has to be properly + * filled and a pointer to it has to be passed to the IOCTL. + * + * UBI volume update + * ~~~~~~~~~~~~~~~~~ + * + * Volume update should be done via the %UBI_IOCVOLUP IOCTL command of the + * corresponding UBI volume character device. A pointer to a 64-bit update + * size should be passed to the IOCTL. After this, UBI expects user to write + * this number of bytes to the volume character device. The update is finished + * when the claimed number of bytes is passed. So, the volume update sequence + * is something like: + * + * fd = open("/dev/my_volume"); + * ioctl(fd, UBI_IOCVOLUP, &image_size); + * write(fd, buf, image_size); + * close(fd); + * + * Atomic eraseblock change + * ~~~~~~~~~~~~~~~~~~~~~~~~ + * + * Atomic eraseblock change operation is done via the %UBI_IOCEBCH IOCTL + * command of the corresponding UBI volume character device. A pointer to + * &struct ubi_leb_change_req has to be passed to the IOCTL. Then the user is + * expected to write the requested amount of bytes. This is similar to the + * "volume update" IOCTL. + */ + +/* + * When a new UBI volume or UBI device is created, users may either specify the + * volume/device number they want to create or to let UBI automatically assign + * the number using these constants. + */ +#define UBI_VOL_NUM_AUTO (-1) +#define UBI_DEV_NUM_AUTO (-1) + +/* Maximum volume name length */ +#define UBI_MAX_VOLUME_NAME 127 + +/* IOCTL commands of UBI character devices */ + +#define UBI_IOC_MAGIC 'o' + +/* Create an UBI volume */ +#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req) +/* Remove an UBI volume */ +#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t) +/* Re-size an UBI volume */ +#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req) + +/* IOCTL commands of the UBI control character device */ + +#define UBI_CTRL_IOC_MAGIC 'o' + +/* Attach an MTD device */ +#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req) +/* Detach an MTD device */ +#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t) + +/* IOCTL commands of UBI volume character devices */ + +#define UBI_VOL_IOC_MAGIC 'O' + +/* Start UBI volume update */ +#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t) +/* An eraseblock erasure command, used for debugging, disabled by default */ +#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t) +/* An atomic eraseblock change command */ +#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t) + +/* Maximum MTD device name length supported by UBI */ +#define MAX_UBI_MTD_NAME_LEN 127 + +/* + * UBI data type hint constants. + * + * UBI_LONGTERM: long-term data + * UBI_SHORTTERM: short-term data + * UBI_UNKNOWN: data persistence is unknown + * + * These constants are used when data is written to UBI volumes in order to + * help the UBI wear-leveling unit to find more appropriate physical + * eraseblocks. + */ +enum { + UBI_LONGTERM = 1, + UBI_SHORTTERM = 2, + UBI_UNKNOWN = 3, +}; + +/* + * UBI volume type constants. + * + * @UBI_DYNAMIC_VOLUME: dynamic volume + * @UBI_STATIC_VOLUME: static volume + */ +enum { + UBI_DYNAMIC_VOLUME = 3, + UBI_STATIC_VOLUME = 4, +}; + +/** + * struct ubi_attach_req - attach MTD device request. + * @ubi_num: UBI device number to create + * @mtd_num: MTD device number to attach + * @vid_hdr_offset: VID header offset (use defaults if %0) + * @padding: reserved for future, not used, has to be zeroed + * + * This data structure is used to specify MTD device UBI has to attach and the + * parameters it has to use. The number which should be assigned to the new UBI + * device is passed in @ubi_num. UBI may automatically assign the number if + * @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in + * @ubi_num. + * + * Most applications should pass %0 in @vid_hdr_offset to make UBI use default + * offset of the VID header within physical eraseblocks. The default offset is + * the next min. I/O unit after the EC header. For example, it will be offset + * 512 in case of a 512 bytes page NAND flash with no sub-page support. Or + * it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages. + * + * But in rare cases, if this optimizes things, the VID header may be placed to + * a different offset. For example, the boot-loader might do things faster if the + * VID header sits at the end of the first 2KiB NAND page with 4 sub-pages. As + * the boot-loader would not normally need to read EC headers (unless it needs + * UBI in RW mode), it might be faster to calculate ECC. This is weird example, + * but it real-life example. So, in this example, @vid_hdr_offer would be + * 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes + * aligned, which is OK, as UBI is clever enough to realize this is 4th sub-page + * of the first page and add needed padding. + */ +struct ubi_attach_req { + int32_t ubi_num; + int32_t mtd_num; + int32_t vid_hdr_offset; + uint8_t padding[12]; +}; + +/** + * struct ubi_mkvol_req - volume description data structure used in + * volume creation requests. + * @vol_id: volume number + * @alignment: volume alignment + * @bytes: volume size in bytes + * @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME) + * @padding1: reserved for future, not used, has to be zeroed + * @name_len: volume name length + * @padding2: reserved for future, not used, has to be zeroed + * @name: volume name + * + * This structure is used by user-space programs when creating new volumes. The + * @used_bytes field is only necessary when creating static volumes. + * + * The @alignment field specifies the required alignment of the volume logical + * eraseblock. This means, that the size of logical eraseblocks will be aligned + * to this number, i.e., + * (UBI device logical eraseblock size) mod (@alignment) = 0. + * + * To put it differently, the logical eraseblock of this volume may be slightly + * shortened in order to make it properly aligned. The alignment has to be + * multiple of the flash minimal input/output unit, or %1 to utilize the entire + * available space of logical eraseblocks. + * + * The @alignment field may be useful, for example, when one wants to maintain + * a block device on top of an UBI volume. In this case, it is desirable to fit + * an integer number of blocks in logical eraseblocks of this UBI volume. With + * alignment it is possible to update this volume using plane UBI volume image + * BLOBs, without caring about how to properly align them. + */ +struct ubi_mkvol_req { + int32_t vol_id; + int32_t alignment; + int64_t bytes; + int8_t vol_type; + int8_t padding1; + int16_t name_len; + int8_t padding2[4]; + char name[UBI_MAX_VOLUME_NAME + 1]; +} __attribute__ ((packed)); + +/** + * struct ubi_rsvol_req - a data structure used in volume re-size requests. + * @vol_id: ID of the volume to re-size + * @bytes: new size of the volume in bytes + * + * Re-sizing is possible for both dynamic and static volumes. But while dynamic + * volumes may be re-sized arbitrarily, static volumes cannot be made to be + * smaller then the number of bytes they bear. To arbitrarily shrink a static + * volume, it must be wiped out first (by means of volume update operation with + * zero number of bytes). + */ +struct ubi_rsvol_req { + int64_t bytes; + int32_t vol_id; +} __attribute__ ((packed)); + +/** + * struct ubi_leb_change_req - a data structure used in atomic logical + * eraseblock change requests. + * @lnum: logical eraseblock number to change + * @bytes: how many bytes will be written to the logical eraseblock + * @dtype: data type (%UBI_LONGTERM, %UBI_SHORTTERM, %UBI_UNKNOWN) + * @padding: reserved for future, not used, has to be zeroed + */ +struct ubi_leb_change_req { + int32_t lnum; + int32_t bytes; + uint8_t dtype; + uint8_t padding[7]; +} __attribute__ ((packed)); + +/** + * ubi_attach_mtd_dev - attach an MTD device. + * @mtd_dev: MTD device description object + * @ubi_num: number to assign to the new UBI device + * @vid_hdr_offset: VID header offset + * + * This function attaches MTD device @mtd_dev to UBI and assign @ubi_num number + * to the newly created UBI device, unless @ubi_num is %UBI_DEV_NUM_AUTO, in + * which case this function finds a vacant device nubert and assings it + * automatically. Returns the new UBI device number in case of success and a + * negative error code in case of failure. + * + * This of course is originally not exported but is now part of the UBI + * interface to barebox. + */ +int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num, int vid_hdr_offset); + +/** + * ubi_detach_mtd_dev - detach an MTD device. + * @ubi_num: UBI device number to detach from + * @anyway: detach MTD even if device reference count is not zero + * + * This function destroys an UBI device number @ubi_num and detaches the + * underlying MTD device. Returns zero in case of success and %-EBUSY if the + * UBI device is busy and cannot be destroyed, and %-EINVAL if it does not + * exist. + * + * This of course is originally not exported but is now part of the UBI + * interface to barebox. + */ +int ubi_detach_mtd_dev(struct mtd_info *mtd, int anyway); + +#endif /* __UBI_USER_H__ */ diff --git a/lib/Makefile b/lib/Makefile index 5afbf13..8c5df08 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,5 @@ obj-y += ctype.o +obj-y += rbtree.o obj-y += display_options.o obj-y += ldiv.o obj-y += string.o diff --git a/lib/crc32.c b/lib/crc32.c index be35366..3481782 100644 --- a/lib/crc32.c +++ b/lib/crc32.c @@ -132,8 +132,10 @@ #define DO8(buf) DO4(buf); DO4(buf); /* ========================================================================= */ -ulong crc32(ulong crc, const unsigned char *buf, uint len) +uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len) { + const unsigned char *buf = _buf; + #ifdef CONFIG_DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); @@ -153,13 +155,13 @@ EXPORT_SYMBOL(crc32); #endif -#if 0 - /* No ones complement version. JFFS2 (and other things ?) * don't use ones compliment in their CRC calculations. */ -uLong crc32_no_comp(uLong crc, const Bytef *buf, uint len) +uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len) { + const unsigned char *buf = _buf; + #ifdef CONFIG_DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); @@ -176,4 +178,3 @@ return crc; } -#endif diff --git a/lib/rbtree.c b/lib/rbtree.c new file mode 100644 index 0000000..99e69bb --- /dev/null +++ b/lib/rbtree.c @@ -0,0 +1,389 @@ +/* + Red Black Trees + (C) 1999 Andrea Arcangeli + (C) 2002 David Woodhouse + + 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 + + linux/lib/rbtree.c +*/ + +#include + +static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *right = node->rb_right; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_right = right->rb_left)) + rb_set_parent(right->rb_left, node); + right->rb_left = node; + + rb_set_parent(right, parent); + + if (parent) + { + if (node == parent->rb_left) + parent->rb_left = right; + else + parent->rb_right = right; + } + else + root->rb_node = right; + rb_set_parent(node, right); +} + +static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *left = node->rb_left; + struct rb_node *parent = rb_parent(node); + + if ((node->rb_left = left->rb_right)) + rb_set_parent(left->rb_right, node); + left->rb_right = node; + + rb_set_parent(left, parent); + + if (parent) + { + if (node == parent->rb_right) + parent->rb_right = left; + else + parent->rb_left = left; + } + else + root->rb_node = left; + rb_set_parent(node, left); +} + +void rb_insert_color(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *parent, *gparent; + + while ((parent = rb_parent(node)) && rb_is_red(parent)) + { + gparent = rb_parent(parent); + + if (parent == gparent->rb_left) + { + { + register struct rb_node *uncle = gparent->rb_right; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_right == node) + { + register struct rb_node *tmp; + __rb_rotate_left(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_right(gparent, root); + } else { + { + register struct rb_node *uncle = gparent->rb_left; + if (uncle && rb_is_red(uncle)) + { + rb_set_black(uncle); + rb_set_black(parent); + rb_set_red(gparent); + node = gparent; + continue; + } + } + + if (parent->rb_left == node) + { + register struct rb_node *tmp; + __rb_rotate_right(parent, root); + tmp = parent; + parent = node; + node = tmp; + } + + rb_set_black(parent); + rb_set_red(gparent); + __rb_rotate_left(gparent, root); + } + } + + rb_set_black(root->rb_node); +} + +static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, + struct rb_root *root) +{ + struct rb_node *other; + + while ((!node || rb_is_black(node)) && node != root->rb_node) + { + if (parent->rb_left == node) + { + other = parent->rb_right; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_left(parent, root); + other = parent->rb_right; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_right || rb_is_black(other->rb_right)) + { + struct rb_node *o_left; + if ((o_left = other->rb_left)) + rb_set_black(o_left); + rb_set_red(other); + __rb_rotate_right(other, root); + other = parent->rb_right; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_right) + rb_set_black(other->rb_right); + __rb_rotate_left(parent, root); + node = root->rb_node; + break; + } + } + else + { + other = parent->rb_left; + if (rb_is_red(other)) + { + rb_set_black(other); + rb_set_red(parent); + __rb_rotate_right(parent, root); + other = parent->rb_left; + } + if ((!other->rb_left || rb_is_black(other->rb_left)) && + (!other->rb_right || rb_is_black(other->rb_right))) + { + rb_set_red(other); + node = parent; + parent = rb_parent(node); + } + else + { + if (!other->rb_left || rb_is_black(other->rb_left)) + { + register struct rb_node *o_right; + if ((o_right = other->rb_right)) + rb_set_black(o_right); + rb_set_red(other); + __rb_rotate_left(other, root); + other = parent->rb_left; + } + rb_set_color(other, rb_color(parent)); + rb_set_black(parent); + if (other->rb_left) + rb_set_black(other->rb_left); + __rb_rotate_right(parent, root); + node = root->rb_node; + break; + } + } + } + if (node) + rb_set_black(node); +} + +void rb_erase(struct rb_node *node, struct rb_root *root) +{ + struct rb_node *child, *parent; + int color; + + if (!node->rb_left) + child = node->rb_right; + else if (!node->rb_right) + child = node->rb_left; + else + { + struct rb_node *old = node, *left; + + node = node->rb_right; + while ((left = node->rb_left) != NULL) + node = left; + child = node->rb_right; + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent == old) { + parent->rb_right = child; + parent = node; + } else + parent->rb_left = child; + + node->rb_parent_color = old->rb_parent_color; + node->rb_right = old->rb_right; + node->rb_left = old->rb_left; + + if (rb_parent(old)) + { + if (rb_parent(old)->rb_left == old) + rb_parent(old)->rb_left = node; + else + rb_parent(old)->rb_right = node; + } else + root->rb_node = node; + + rb_set_parent(old->rb_left, node); + if (old->rb_right) + rb_set_parent(old->rb_right, node); + goto color; + } + + parent = rb_parent(node); + color = rb_color(node); + + if (child) + rb_set_parent(child, parent); + if (parent) + { + if (parent->rb_left == node) + parent->rb_left = child; + else + parent->rb_right = child; + } + else + root->rb_node = child; + + color: + if (color == RB_BLACK) + __rb_erase_color(child, parent, root); +} + +/* + * This function returns the first node (in sort order) of the tree. + */ +struct rb_node *rb_first(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_left) + n = n->rb_left; + return n; +} + +struct rb_node *rb_last(struct rb_root *root) +{ + struct rb_node *n; + + n = root->rb_node; + if (!n) + return NULL; + while (n->rb_right) + n = n->rb_right; + return n; +} + +struct rb_node *rb_next(struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a right-hand child, go down and then left as far + as we can. */ + if (node->rb_right) { + node = node->rb_right; + while (node->rb_left) + node=node->rb_left; + return node; + } + + /* No right-hand children. Everything down and left is + smaller than us, so any 'next' node must be in the general + direction of our parent. Go up the tree; any time the + ancestor is a right-hand child of its parent, keep going + up. First time it's a left-hand child of its parent, said + parent is our 'next' node. */ + while ((parent = rb_parent(node)) && node == parent->rb_right) + node = parent; + + return parent; +} + +struct rb_node *rb_prev(struct rb_node *node) +{ + struct rb_node *parent; + + if (rb_parent(node) == node) + return NULL; + + /* If we have a left-hand child, go down and then right as far + as we can. */ + if (node->rb_left) { + node = node->rb_left; + while (node->rb_right) + node=node->rb_right; + return node; + } + + /* No left-hand children. Go up till we find an ancestor which + is a right-hand child of its parent */ + while ((parent = rb_parent(node)) && node == parent->rb_left) + node = parent; + + return parent; +} + +void rb_replace_node(struct rb_node *victim, struct rb_node *new, + struct rb_root *root) +{ + struct rb_node *parent = rb_parent(victim); + + /* Set the surrounding nodes to point to the replacement */ + if (parent) { + if (victim == parent->rb_left) + parent->rb_left = new; + else + parent->rb_right = new; + } else { + root->rb_node = new; + } + if (victim->rb_left) + rb_set_parent(victim->rb_left, new); + if (victim->rb_right) + rb_set_parent(victim->rb_right, new); + + /* Copy the pointers/colour from the victim to the replacement */ + *new = *victim; +} diff --git a/scripts/genenv b/scripts/genenv index 6a833b1..de8b4f1 100755 --- a/scripts/genenv +++ b/scripts/genenv @@ -1,17 +1,19 @@ #!/bin/bash # Generate the default environment file from a list of directories -# usage: genenv ... +# usage: genenv ... # where is the base directory for relative pathes in +# where is the base directory for relative pathes for result +objtree=$2 cd $1 || exit 1 -shift +shift 2 tempdir=$(mktemp -d) for i in $*; do cp -r $i/* $tempdir done -scripts/bareboxenv -s $tempdir barebox_default_env +$objtree/scripts/bareboxenv -s $tempdir $objtree/barebox_default_env rm -r $tempdir