diff --git a/Documentation/boards.dox b/Documentation/boards.dox index 1407479..ba332a7 100644 --- a/Documentation/boards.dox +++ b/Documentation/boards.dox @@ -36,6 +36,7 @@ @li @subpage edb9315 @li @subpage edb9315a @li @subpage board_cupid +@li @subpage phycard-a-l1 Blackfin type: diff --git a/MAKEALL b/MAKEALL index 25b9977..1ba4710 100755 --- a/MAKEALL +++ b/MAKEALL @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Print statistics when we exit trap exit 1 2 3 15 diff --git a/Makefile b/Makefile index 2108f67..eb7ba8d 100644 --- a/Makefile +++ b/Makefile @@ -450,6 +450,12 @@ # Force gcc to behave correct even for buggy distributions CFLAGS += $(call cc-option, -fno-stack-protector) +# This warning generated too much noise in a regular build. +# Use make W=1 to enable this warning (see scripts/Makefile.build) +CFLAGS += $(call cc-disable-warning, unused-but-set-variable) + +CFLAGS += $(call cc-disable-warning, trampolines) + # arch Makefile may override CC so keep this after arch Makefile is included NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 40677a3..b600179 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -68,6 +68,7 @@ config ARCH_S3C24xx bool "Samsung S3C2410, S3C2412, S3C2413, S3C2440, S3C2442, S3C2443" + select ARCH_SAMSUNG select CPU_ARM920T select GENERIC_GPIO @@ -86,7 +87,7 @@ source arch/arm/mach-nomadik/Kconfig source arch/arm/mach-omap/Kconfig source arch/arm/mach-pxa/Kconfig -source arch/arm/mach-s3c24xx/Kconfig +source arch/arm/mach-samsung/Kconfig source arch/arm/mach-versatile/Kconfig config ARM_ASM_UNIFIED diff --git a/arch/arm/Makefile b/arch/arm/Makefile index a3e12e6..9885634 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -52,7 +52,7 @@ machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_OMAP) := omap machine-$(CONFIG_ARCH_PXA) := pxa -machine-$(CONFIG_ARCH_S3C24xx) := s3c24xx +machine-$(CONFIG_ARCH_SAMSUNG) := samsung machine-$(CONFIG_ARCH_VERSATILE) := versatile # Board directory name. This list is sorted alphanumerically @@ -93,6 +93,7 @@ board-$(CONFIG_MACH_PANDA) := panda board-$(CONFIG_MACH_PCM049) := pcm049 board-$(CONFIG_MACH_PCA100) := phycard-i.MX27 +board-$(CONFIG_MACH_PCAAL1) := phycard-a-l1 board-$(CONFIG_MACH_PCM037) := pcm037 board-$(CONFIG_MACH_PCM038) := pcm038 board-$(CONFIG_MACH_PCM043) := pcm043 @@ -104,6 +105,7 @@ board-$(CONFIG_MACH_MX23EVK) := freescale-mx23-evk board-$(CONFIG_MACH_CHUMBY) := chumby_falconwing board-$(CONFIG_MACH_TX28) := karo-tx28 +board-$(CONFIG_MACH_MX28EVK) := freescale-mx28-evk board-$(CONFIG_MACH_FREESCALE_MX51_PDK) := freescale-mx51-pdk board-$(CONFIG_MACH_FREESCALE_MX53_LOCO) := freescale-mx53-loco board-$(CONFIG_MACH_FREESCALE_MX53_SMD) := freescale-mx53-smd diff --git a/arch/arm/boards/a9m2410/a9m2410.c b/arch/arm/boards/a9m2410/a9m2410.c index bbe1604..adeaacc 100644 --- a/arch/arm/boards/a9m2410/a9m2410.c +++ b/arch/arm/boards/a9m2410/a9m2410.c @@ -32,8 +32,11 @@ #include #include #include -#include -#include +#include +#include +#include +#include +#include // {"NAND 1MiB 3,3V 8-bit", 0xec, 256, 1, 0x1000, 0}, static struct s3c24x0_nand_platform_data nand_info = { @@ -42,65 +45,40 @@ static int a9m2410_mem_init(void) { - resource_size_t size = 0; - uint32_t reg; + resource_size_t size; /* - * detect the current memory size * Note: On this card the second SDRAM page is not used */ - reg = readl(BANKSIZE); - - switch (reg &= 0x7) { - case 0: - size = 32 * 1024 * 1024; - break; - case 1: - size = 64 * 1024 * 1024; - break; - case 2: - size = 128 * 1024 * 1024; - break; - case 4: - size = 2 * 1024 * 1024; - break; - case 5: - size = 4 * 1024 * 1024; - break; - case 6: - size = 8 * 1024 * 1024; - break; - case 7: - size = 16 * 1024 * 1024; - break; - } + s3c24xx_disable_second_sdram_bank(); + size = s3c24xx_get_memory_size(); /* ---------- 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); + writel(0x007FFFFF, S3C_GPACON); + writel(0x00000000, S3C_GPCCON); + writel(0x00000000, S3C_GPCUP); + writel(0x00000000, S3C_GPDCON); + writel(0x00000000, S3C_GPDUP); + writel(0xAAAAAAAA, S3C_GPECON); + writel(0x0000E03F, S3C_GPEUP); + writel(0x00000000, S3C_GPBCON); /* all inputs */ + writel(0x00000007, S3C_GPBUP); /* pullup disabled for GPB0..3 */ + writel(0x00009000, S3C_GPFCON); /* GPF7 CLK_INT#, GPF6 Debug-LED */ + writel(0x000000FF, S3C_GPFUP); + writel(readl(S3C_GPGDAT) | 0x0010, S3C_GPGDAT); /* switch off LCD backlight */ + writel(0xFF00A938, S3C_GPGCON); /* switch off USB device */ + writel(0x0000F000, S3C_GPGUP); + writel(readl(S3C_GPHDAT) | 0x100, S3C_GPHDAT); /* switch BOOTINT/GPIO_ON# to high */ + writel(0x000007FF, S3C_GPHUP); + writel(0x0029FAAA, S3C_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); + writel(0x40140, S3C_MISCCR); - arm_add_mem_device("ram0", CS6_BASE, size); + arm_add_mem_device("ram0", S3C_SDRAM_BASE, size); return 0; } @@ -111,24 +89,24 @@ uint32_t reg; /* ----------- configure the access to the outer space ---------- */ - reg = readl(BWSCON); + reg = readl(S3C_BWSCON); /* CS#1 to access the network controller */ reg &= ~0xf0; reg |= 0xe0; - writel(0x1350, BANKCON1); + writel(0x1350, S3C_BANKCON1); /* CS#2 to the dual 16550 UART */ reg &= ~0xf00; reg |= 0x400; - writel(0x0d50, BANKCON2); + writel(0x0d50, S3C_BANKCON2); - writel(reg, BWSCON); + writel(reg, S3C_BWSCON); /* release the reset signal to the network and UART device */ - reg = readl(MISCCR); + reg = readl(S3C_MISCCR); reg |= 0x10000; - writel(reg, MISCCR); + writel(reg, S3C_MISCCR); /* ----------- the devices the boot loader should work with -------- */ add_generic_device("s3c24x0_nand", -1, NULL, S3C24X0_NAND_BASE, 0, @@ -138,7 +116,7 @@ * connected to CS line 1 and interrupt line * GPIO3, data width is 32 bit */ - add_generic_device("smc91c111", -1, NULL, CS1_BASE + 0x300, 16, + add_generic_device("smc91c111", -1, NULL, S3C_CS1_BASE + 0x300, 16, IORESOURCE_MEM, NULL); #ifdef CONFIG_NAND @@ -150,7 +128,7 @@ dev_add_bb_dev("env_raw", "env0"); #endif - armlinux_set_bootparams((void*)CS6_BASE + 0x100); + armlinux_set_bootparams((void*)S3C_SDRAM_BASE + 0x100); armlinux_set_architecture(MACH_TYPE_A9M2410); return 0; @@ -167,7 +145,7 @@ static int a9m2410_console_init(void) { - add_generic_device("s3c24x0_serial", -1, NULL, UART1_BASE, UART1_SIZE, + add_generic_device("s3c_serial", -1, NULL, S3C_UART1_BASE, S3C_UART1_SIZE, IORESOURCE_MEM, NULL); return 0; } diff --git a/arch/arm/boards/a9m2410/lowlevel_init.S b/arch/arm/boards/a9m2410/lowlevel_init.S index 461b93c..a106d53 100644 --- a/arch/arm/boards/a9m2410/lowlevel_init.S +++ b/arch/arm/boards/a9m2410/lowlevel_init.S @@ -3,7 +3,7 @@ */ #include -#include +#include .section ".text_bare_init.board_init_lowlevel","ax" @@ -15,9 +15,9 @@ bl s3c24x0_disable_wd /* skip everything here if we are already running from SDRAM */ - cmp pc, #S3C24X0_SDRAM_BASE + cmp pc, #S3C_SDRAM_BASE blo 1f - cmp pc, #S3C24X0_SDRAM_END + cmp pc, #S3C_SDRAM_END bhs 1f mov pc, r10 diff --git a/arch/arm/boards/a9m2440/a9m2410dev.c b/arch/arm/boards/a9m2440/a9m2410dev.c index 5f7c53b..bedb0f7 100644 --- a/arch/arm/boards/a9m2440/a9m2410dev.c +++ b/arch/arm/boards/a9m2440/a9m2410dev.c @@ -28,7 +28,9 @@ #include #include #include -#include +#include +#include +#include /** * Initialize the CPU to be able to work with the a9m2410dev evaluation board @@ -38,58 +40,58 @@ 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(0x007FFFFF, S3C_GPACON); + writel(0x00000000, S3C_GPCCON); + writel(0x00000000, S3C_GPCUP); + writel(0x00000000, S3C_GPDCON); + writel(0x00000000, S3C_GPDUP); + writel(0xAAAAAAAA, S3C_GPECON); + writel(0x0000E03F, S3C_GPEUP); + writel(0x00000000, S3C_GPBCON); /* all inputs */ + writel(0x00000007, S3C_GPBUP); /* pullup disabled for GPB0..3 */ + writel(0x00009000, S3C_GPFCON); /* GPF7 CLK_INT#, GPF6 Debug-LED */ + writel(0x000000FF, S3C_GPFUP); + writel(readl(S3C_GPGDAT) | 0x1010, S3C_GPGDAT); /* switch off IDLE_SW#, switch off LCD backlight */ + writel(0x0100A93A, S3C_GPGCON); /* switch on USB device */ + writel(0x0000F000, S3C_GPGUP); + writel(0x0029FAAA, S3C_GPHCON); - writel((1 << 12) | (0 << 11), GPJDAT); - writel(0x0016aaaa, GPJCON); - writel(~((0<<12)| (1<<11)), GPJUP); + writel((1 << 12) | (0 << 11), S3C_GPJDAT); + writel(0x0016aaaa, S3C_GPJCON); + writel(~((0<<12)| (1<<11)), S3C_GPJUP); - writel((0 << 12) | (0 << 11), GPJDAT); - writel(0x0016aaaa, GPJCON); - writel(0x00001fff, GPJUP); + writel((0 << 12) | (0 << 11), S3C_GPJDAT); + writel(0x0016aaaa, S3C_GPJCON); + writel(0x00001fff, S3C_GPJUP); - writel(0x00000000, DSC0); - writel(0x00000000, DSC1); + writel(0x00000000, S3C_DSC0); + writel(0x00000000, S3C_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); + writel((readl(S3C_MISCCR) & ~0xFFFF) | 0x0140, S3C_MISCCR); /* ----------- configure the access to the outer space ---------- */ - reg = readl(BWSCON); + reg = readl(S3C_BWSCON); /* CS#1 to access the network controller */ reg &= ~0xf0; reg |= 0xe0; - writel(0x1350, BANKCON1); + writel(0x1350, S3C_BANKCON1); /* CS#2 to the dual 16550 UART */ reg &= ~0xf00; reg |= 0x400; - writel(0x0d50, BANKCON2); + writel(0x0d50, S3C_BANKCON2); - writel(reg, BWSCON); + writel(reg, S3C_BWSCON); /* release the reset signal to the network and UART device */ - reg = readl(MISCCR); + reg = readl(S3C_MISCCR); reg |= 0x10000; - writel(reg, MISCCR); + writel(reg, S3C_MISCCR); return 0; } diff --git a/arch/arm/boards/a9m2440/a9m2440.c b/arch/arm/boards/a9m2440/a9m2440.c index 964d376..6c6ccdb 100644 --- a/arch/arm/boards/a9m2440/a9m2440.c +++ b/arch/arm/boards/a9m2440/a9m2440.c @@ -32,9 +32,11 @@ #include #include #include -#include -#include -#include +#include +#include +#include +#include +#include #include "baseboards.h" @@ -66,12 +68,6 @@ 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_mem_init(void) { /* @@ -80,30 +76,30 @@ * So we must check here, if the second bank is populated to get the * correct RAM size. */ - switch (readl(BANKSIZE) & 0x7) { + switch (readl(S3C_BANKSIZE) & 0x7) { case 0: - if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 32 * 1024 * 1024)) - a9m2440_disable_second_sdram_bank(); + if (a9m2440_check_for_ram(S3C_SDRAM_BASE + 32 * 1024 * 1024)) + s3c24xx_disable_second_sdram_bank(); break; case 1: - if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 64 * 1024 * 1024)) - a9m2440_disable_second_sdram_bank(); + if (a9m2440_check_for_ram(S3C_SDRAM_BASE + 64 * 1024 * 1024)) + s3c24xx_disable_second_sdram_bank(); break; case 2: - if (a9m2440_check_for_ram(S3C24X0_SDRAM_BASE + 128 * 1024 * 1024)) - a9m2440_disable_second_sdram_bank(); + if (a9m2440_check_for_ram(S3C_SDRAM_BASE + 128 * 1024 * 1024)) + s3c24xx_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(); + if (a9m2440_check_for_ram(S3C_SDRAM_BASE + 16 * 1024 * 1024)) + s3c24xx_disable_second_sdram_bank(); break; } - arm_add_mem_device("ram0", CS6_BASE, s3c24x0_get_memory_size()); + arm_add_mem_device("ram0", S3C_SDRAM_BASE, s3c24xx_get_memory_size()); return 0; } @@ -114,23 +110,23 @@ uint32_t reg; /* ----------- configure the access to the outer space ---------- */ - reg = readl(BWSCON); + reg = readl(S3C_BWSCON); /* CS#5 to access the network controller */ reg &= ~0x00f00000; reg |= 0x00d00000; /* 16 bit */ - writel(0x1f4c, BANKCON5); + writel(0x1f4c, S3C_BANKCON5); - writel(reg, BWSCON); + writel(reg, S3C_BWSCON); #ifdef CONFIG_MACH_A9M2410DEV a9m2410dev_devices_init(); #endif /* release the reset signal to external devices */ - reg = readl(MISCCR); + reg = readl(S3C_MISCCR); reg |= 0x10000; - writel(reg, MISCCR); + writel(reg, S3C_MISCCR); /* ----------- the devices the boot loader should work with -------- */ add_generic_device("s3c24x0_nand", -1, NULL, S3C24X0_NAND_BASE, 0, @@ -140,7 +136,7 @@ * Connected to CS line 5 + A24 and interrupt line EINT9, * data width is 16 bit */ - add_generic_device("cs8900", -1, NULL, CS5_BASE + (1 << 24) + 0x300, 16, + add_generic_device("cs8900", -1, NULL, S3C_CS5_BASE + (1 << 24) + 0x300, 16, IORESOURCE_MEM, NULL); #ifdef CONFIG_NAND @@ -151,7 +147,7 @@ devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); dev_add_bb_dev("env_raw", "env0"); #endif - armlinux_set_bootparams((void*)CS6_BASE + 0x100); + armlinux_set_bootparams((void*)S3C_SDRAM_BASE + 0x100); armlinux_set_architecture(MACH_TYPE_A9M2440); return 0; @@ -168,7 +164,7 @@ static int a9m2440_console_init(void) { - add_generic_device("s3c24x0_serial", -1, NULL, UART1_BASE, UART1_SIZE, + add_generic_device("s3c_serial", -1, NULL, S3C_UART1_BASE, S3C_UART1_SIZE, IORESOURCE_MEM, NULL); return 0; } diff --git a/arch/arm/boards/a9m2440/lowlevel_init.S b/arch/arm/boards/a9m2440/lowlevel_init.S index 4b5c596..e915a16 100644 --- a/arch/arm/boards/a9m2440/lowlevel_init.S +++ b/arch/arm/boards/a9m2440/lowlevel_init.S @@ -3,7 +3,8 @@ */ #include -#include +#include +#include .section ".text_bare_init.board_init_lowlevel","ax" @@ -33,11 +34,11 @@ * configured yet, these pins show external settings, to detect * the SDRAM size. */ - ldr r1, =GPBDAT + ldr r1, =S3C_GPBDAT ldr r4, [r1] and r4, r4, #0x3 - ldr r1, =S3C24X0_MEMCTL_BASE + ldr r1, =S3C_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 */ @@ -218,9 +219,9 @@ bl s3c24x0_disable_wd /* skip everything here if we are already running from SDRAM */ - cmp pc, #S3C24X0_SDRAM_BASE + cmp pc, #S3C_SDRAM_BASE blo 1f - cmp pc, #S3C24X0_SDRAM_END + cmp pc, #S3C_SDRAM_END bhs 1f mov pc, r10 diff --git a/arch/arm/boards/at91rm9200ek/env/config b/arch/arm/boards/at91rm9200ek/env/config index 1b56b25..12655c2 100644 --- a/arch/arm/boards/at91rm9200ek/env/config +++ b/arch/arm/boards/at91rm9200ek/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nor_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" diff --git a/arch/arm/boards/at91sam9260ek/env/bin/_update b/arch/arm/boards/at91sam9260ek/env/bin/_update deleted file mode 100644 index 014bce3..0000000 --- a/arch/arm/boards/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/arch/arm/boards/at91sam9260ek/env/bin/boot b/arch/arm/boards/at91sam9260ek/env/bin/boot deleted file mode 100644 index ed6f11a..0000000 --- a/arch/arm/boards/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/arch/arm/boards/at91sam9260ek/env/bin/init b/arch/arm/boards/at91sam9260ek/env/bin/init deleted file mode 100644 index b8d8399..0000000 --- a/arch/arm/boards/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/arch/arm/boards/at91sam9260ek/env/bin/init_board b/arch/arm/boards/at91sam9260ek/env/bin/init_board new file mode 100644 index 0000000..0da2781 --- /dev/null +++ b/arch/arm/boards/at91sam9260ek/env/bin/init_board @@ -0,0 +1,23 @@ +#!/bin/sh + +#PIOA_31 +gpio_get_value 63 +if [ $? != 0 ] +then + exit +fi + +echo "BP4 pressed detected wait 5s" +timeout -s -a 5 +gpio_get_value 63 +if [ $? != 0 ] +then + echo "BP4 released, normal boot" + exit +fi + +echo "" +echo "Start DFU Mode" +echo "" + +dfu /dev/self0(barebox)sr,/dev/nand0.kernel.bb(kernel)r,/dev/nand0.root.bb(root)r -P 0x1234 -V 0x4321 diff --git a/arch/arm/boards/at91sam9260ek/env/bin/pcidmaloop b/arch/arm/boards/at91sam9260ek/env/bin/pcidmaloop deleted file mode 100644 index 24e76cb..0000000 --- a/arch/arm/boards/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/arch/arm/boards/at91sam9260ek/env/bin/pciloop b/arch/arm/boards/at91sam9260ek/env/bin/pciloop deleted file mode 100644 index 4a804f9..0000000 --- a/arch/arm/boards/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/arch/arm/boards/at91sam9260ek/env/bin/update_kernel b/arch/arm/boards/at91sam9260ek/env/bin/update_kernel deleted file mode 100644 index 1ad95fc..0000000 --- a/arch/arm/boards/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/arch/arm/boards/at91sam9260ek/env/bin/update_root b/arch/arm/boards/at91sam9260ek/env/bin/update_root deleted file mode 100644 index b757a5b..0000000 --- a/arch/arm/boards/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/arch/arm/boards/at91sam9260ek/env/config b/arch/arm/boards/at91sam9260ek/env/config index 71d6f88..ba14c2b 100644 --- a/arch/arm/boards/at91sam9260ek/env/config +++ b/arch/arm/boards/at91sam9260ek/env/config @@ -1,20 +1,41 @@ #!/bin/sh -# can be either 'net' or 'flash' -kernel=net -root=net - -# use 'dhcp' todo dhcp in barebox and in kernel +# use 'dhcp' to do dhcp in barebox and in kernel +# use 'none' if you want to skip kernel ip autoconfiguration ip=dhcp -# -# setup default ethernet address -# -eth0.serverip=192.168.23.108 +# 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 -uimage=uImage-at91sam9260ek +# can be either 'nfs', 'tftp', 'nor' or 'nand' +kernel_loc=nfs +# can be either 'net', 'nor', 'nand' or 'initrd' +rootfs_loc=net + +# can be either 'jffs2' or 'ubifs' +rootfs_type=ubifs +rootfsimage=root.$rootfs_type + +# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo +#kernelimage_type=zimage +#kernelimage=zImage +kernelimage_type=uimage +kernelimage=uImage +#kernelimage_type=raw +#kernelimage=Image +#kernelimage_type=raw_lzo +#kernelimage=Image.lzo + +nand_device=atmel_nand +nand_parts="128k(at91bootstrap),256k(barebox)ro,128k(bareboxenv),128k(bareboxenv2),4M(kernel),120M(rootfs),-(data)" +rootfs_mtdblock_nand=5 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" +bootargs="console=ttyS0,115200" + +# set a fancy prompt (if support is compiled in) +PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m\n# " diff --git a/arch/arm/boards/at91sam9260ek/init.c b/arch/arm/boards/at91sam9260ek/init.c index 958319e..b10d0dc 100644 --- a/arch/arm/boards/at91sam9260ek/init.c +++ b/arch/arm/boards/at91sam9260ek/init.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -70,9 +71,10 @@ #else .bus_width_16 = 0, #endif + .on_flash_bbt = 1, }; -static struct sam9_smc_config ek_nand_smc_config = { +static struct sam9_smc_config ek_9260_nand_smc_config = { .ncs_read_setup = 0, .nrd_setup = 1, .ncs_write_setup = 0, @@ -90,16 +92,41 @@ .tdf_cycles = 2, }; +static struct sam9_smc_config ek_9g20_nand_smc_config = { + .ncs_read_setup = 0, + .nrd_setup = 2, + .ncs_write_setup = 0, + .nwe_setup = 2, + + .ncs_read_pulse = 4, + .nrd_pulse = 4, + .ncs_write_pulse = 4, + .nwe_pulse = 4, + + .read_cycle = 7, + .write_cycle = 7, + + .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE, + .tdf_cycles = 3, +}; + static void ek_add_device_nand(void) { + struct sam9_smc_config *smc; + + if (machine_is_at91sam9g20ek()) + smc = &ek_9g20_nand_smc_config; + else + smc = &ek_9260_nand_smc_config; + /* setup bus-width (8 or 16) */ if (nand_pdata.bus_width_16) - ek_nand_smc_config.mode |= AT91_SMC_DBW_16; + smc->mode |= AT91_SMC_DBW_16; else - ek_nand_smc_config.mode |= AT91_SMC_DBW_8; + smc->mode |= AT91_SMC_DBW_8; /* configure chip-select 3 (NAND) */ - sam9_smc_configure(3, &ek_nand_smc_config); + sam9_smc_configure(3, smc); at91_add_device_nand(&nand_pdata); } @@ -139,6 +166,40 @@ AT91_RSTC_URSTEN); } +/* + * MCI (SD/MMC) + */ +#if defined(CONFIG_MCI_ATMEL) +static struct atmel_mci_platform_data __initdata ek_mci_data = { + .bus_width = 4, +}; + +static void ek_usb_add_device_mci(void) +{ + if (machine_is_at91sam9g20ek()) + ek_mci_data.detect_pin = AT91_PIN_PC9; + + at91_add_device_mci(1, &ek_mci_data); +} +#else +static void ek_usb_add_device_mci(void) {} +#endif + +/* + * USB Host port + */ +static struct at91_usbh_data __initdata ek_usbh_data = { + .ports = 2, +}; + +/* + * USB Device port + */ +static struct at91_udc_data __initdata ek_udc_data = { + .vbus_pin = AT91_PIN_PC5, + .pullup_pin = -EINVAL, /* pull-up driven by UDC */ +}; + static int at91sam9260ek_mem_init(void) { at91_add_device_sdram(64 * 1024 * 1024); @@ -147,19 +208,35 @@ } mem_initcall(at91sam9260ek_mem_init); +static void __init ek_add_device_buttons(void) +{ + at91_set_gpio_input(AT91_PIN_PA30, 1); /* btn3 */ + at91_set_deglitch(AT91_PIN_PA30, 1); + at91_set_gpio_input(AT91_PIN_PA31, 1); /* btn4 */ + at91_set_deglitch(AT91_PIN_PA31, 1); +} + static int at91sam9260ek_devices_init(void) { ek_add_device_nand(); at91sam9260ek_phy_reset(); at91_add_device_eth(&macb_pdata); + at91_add_device_usbh_ohci(&ek_usbh_data); + at91_add_device_udc(&ek_udc_data); + ek_usb_add_device_mci(); + ek_add_device_buttons(); armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); ek_set_board_type(); - devfs_add_partition("nand0", 0x00000, 0x80000, PARTITION_FIXED, "self_raw"); + devfs_add_partition("nand0", 0x00000, SZ_128K, PARTITION_FIXED, "at91bootstrap_raw"); + dev_add_bb_dev("at91bootstrap_raw", "at91bootstrap"); + devfs_add_partition("nand0", SZ_128K, SZ_256K, PARTITION_FIXED, "self_raw"); dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x80000, 0x20000, PARTITION_FIXED, "env_raw"); + devfs_add_partition("nand0", SZ_256K + SZ_128K, SZ_128K, PARTITION_FIXED, "env_raw"); dev_add_bb_dev("env_raw", "env0"); + devfs_add_partition("nand0", SZ_512K, SZ_128K, PARTITION_FIXED, "env_raw1"); + dev_add_bb_dev("env_raw1", "env1"); return 0; } diff --git a/arch/arm/boards/at91sam9261ek/env/config b/arch/arm/boards/at91sam9261ek/env/config index 733326d..d6eeea4 100644 --- a/arch/arm/boards/at91sam9261ek/env/config +++ b/arch/arm/boards/at91sam9261ek/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nand_device=atmel_nand diff --git a/arch/arm/boards/at91sam9261ek/init.c b/arch/arm/boards/at91sam9261ek/init.c index 0bef84d..8b192b2 100644 --- a/arch/arm/boards/at91sam9261ek/init.c +++ b/arch/arm/boards/at91sam9261ek/init.c @@ -50,6 +50,7 @@ #else .bus_width_16 = 0, #endif + .on_flash_bbt = 1, }; static struct sam9_smc_config ek_nand_smc_config = { @@ -87,7 +88,7 @@ /* * DM9000 ethernet device */ -#if defined(CONFIG_DRIVER_NET_DM9000) +#if defined(CONFIG_DRIVER_NET_DM9K) static struct dm9000_platform_data dm9000_data = { .srom = 0, }; @@ -130,7 +131,7 @@ } #else static void __init ek_add_device_dm9000(void) {} -#endif /* CONFIG_DRIVER_NET_DM9000 */ +#endif /* CONFIG_DRIVER_NET_DM9K */ static int at91sam9261ek_mem_init(void) { diff --git a/arch/arm/boards/at91sam9263ek/config.h b/arch/arm/boards/at91sam9263ek/config.h index bc33227..8f764eb 100644 --- a/arch/arm/boards/at91sam9263ek/config.h +++ b/arch/arm/boards/at91sam9263ek/config.h @@ -40,8 +40,6 @@ 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*/ @@ -60,23 +58,7 @@ /* 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 \ diff --git a/arch/arm/boards/at91sam9263ek/env/config b/arch/arm/boards/at91sam9263ek/env/config index 4e29232..e189b8e 100644 --- a/arch/arm/boards/at91sam9263ek/env/config +++ b/arch/arm/boards/at91sam9263ek/env/config @@ -19,20 +19,17 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nand_device=atmel_nand nand_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" rootfs_mtdblock_nand=3 +nor_parts="256k(barebox),64k(bareboxenv),1536k(kernel),-(root)" + autoboot_timeout=3 bootargs="console=ttyS0,115200" diff --git a/arch/arm/boards/at91sam9263ek/init.c b/arch/arm/boards/at91sam9263ek/init.c index bb564d7..d7b9afe 100644 --- a/arch/arm/boards/at91sam9263ek/init.c +++ b/arch/arm/boards/at91sam9263ek/init.c @@ -51,6 +51,7 @@ #else .bus_width_16 = 0, #endif + .on_flash_bbt = 1, }; static struct sam9_smc_config ek_nand_smc_config = { diff --git a/arch/arm/boards/at91sam9m10g45ek/env/config b/arch/arm/boards/at91sam9m10g45ek/env/config index b8ca18d..3dea724 100644 --- a/arch/arm/boards/at91sam9m10g45ek/env/config +++ b/arch/arm/boards/at91sam9m10g45ek/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nand_device=atmel_nand diff --git a/arch/arm/boards/at91sam9m10g45ek/init.c b/arch/arm/boards/at91sam9m10g45ek/init.c index 5fdc960..eff2769 100644 --- a/arch/arm/boards/at91sam9m10g45ek/init.c +++ b/arch/arm/boards/at91sam9m10g45ek/init.c @@ -72,6 +72,7 @@ #else .bus_width_16 = 0, #endif + .on_flash_bbt = 1, }; static struct sam9_smc_config ek_nand_smc_config = { diff --git a/arch/arm/boards/chumby_falconwing/env/bin/boot b/arch/arm/boards/chumby_falconwing/env/bin/boot index 981a387..999170c 100644 --- a/arch/arm/boards/chumby_falconwing/env/bin/boot +++ b/arch/arm/boards/chumby_falconwing/env/bin/boot @@ -26,13 +26,6 @@ bootargs="$bootargs root=/dev/ram0 rdinit=/sbin/init" fi -if [ x$kernelimage_type = xuimage ]; then - bootm /dev/$kernel_part -elif [ x$kernelimage_type = xzimage ]; then - bootz /dev/$kernel_part -else - echo "Booting failed. Correct setup of 'kernelimage_type'?" - exit -fi +bootm /dev/$kernel_part echo "Booting failed. Correct setup of 'kernel_part'?" diff --git a/arch/arm/boards/chumby_falconwing/env/config b/arch/arm/boards/chumby_falconwing/env/config index 1e61dce..1419161 100644 --- a/arch/arm/boards/chumby_falconwing/env/config +++ b/arch/arm/boards/chumby_falconwing/env/config @@ -25,8 +25,6 @@ # Where is the rootfs in case of 'rootfs_loc=net' nfsroot=FIXME -# The image type of the kernel. Can be uimage, zimage -kernelimage_type=uimage # Where to get the kernel image in case of 'kernel_loc=disk' kernel_part=disk0.2 diff --git a/arch/arm/boards/dss11/env/config b/arch/arm/boards/dss11/env/config index 5c9be7d..adf3af5 100644 --- a/arch/arm/boards/dss11/env/config +++ b/arch/arm/boards/dss11/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nand_device=atmel_nand diff --git a/arch/arm/boards/eukrea_cpuimx25/env/config b/arch/arm/boards/eukrea_cpuimx25/env/config index 5cedbf8..bc1cfd5 100644 --- a/arch/arm/boards/eukrea_cpuimx25/env/config +++ b/arch/arm/boards/eukrea_cpuimx25/env/config @@ -25,7 +25,6 @@ rootfsimage=$machine/rootfs.$rootfs_type # kernel -kernelimage_type=uimage kernelimage=$machine/uImage-${machine}.bin # barebox and it's env diff --git a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c index 162c117..73e54f2 100644 --- a/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c +++ b/arch/arm/boards/eukrea_cpuimx25/eukrea_cpuimx25.c @@ -116,6 +116,7 @@ static struct imx_fb_platform_data eukrea_cpuimx25_fb_data = { .mode = &imxfb_mode, + .num_modes = 1, .pwmr = 0x00A903FF, .lscr1 = 0x00120300, .dmacr = 0x80040060, diff --git a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c index c419c73..e2766fb 100644 --- a/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c +++ b/arch/arm/boards/eukrea_cpuimx27/eukrea_cpuimx27.c @@ -116,6 +116,7 @@ static struct imx_fb_platform_data eukrea_cpuimx27_fb_data = { .mode = &imxfb_mode, + .num_modes = 1, .pwmr = 0x00A903FF, .lscr1 = 0x00120300, .dmacr = 0x00020010, diff --git a/arch/arm/boards/eukrea_cpuimx35/env/config b/arch/arm/boards/eukrea_cpuimx35/env/config index 776d19a..8f64ba0 100644 --- a/arch/arm/boards/eukrea_cpuimx35/env/config +++ b/arch/arm/boards/eukrea_cpuimx35/env/config @@ -25,7 +25,6 @@ rootfsimage=$machine/rootfs.$rootfs_type # kernel -kernelimage_type=uimage kernelimage=$machine/uImage-${machine}.bin # barebox and it's env diff --git a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c index 20cfad4..d167ab9 100644 --- a/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c +++ b/arch/arm/boards/eukrea_cpuimx35/eukrea_cpuimx35.c @@ -144,6 +144,9 @@ static int eukrea_cpuimx35_devices_init(void) { +#ifdef CONFIG_USB_GADGET + unsigned int tmp; +#endif imx35_add_nand(&nand_info); devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); diff --git a/arch/arm/boards/eukrea_cpuimx51/Makefile b/arch/arm/boards/eukrea_cpuimx51/Makefile index 0f506a3..0f781c0 100644 --- a/arch/arm/boards/eukrea_cpuimx51/Makefile +++ b/arch/arm/boards/eukrea_cpuimx51/Makefile @@ -1,3 +1,2 @@ -obj-y += lowlevel_init.o obj-y += eukrea_cpuimx51.o obj-y += flash_header.o diff --git a/arch/arm/boards/eukrea_cpuimx51/env/config b/arch/arm/boards/eukrea_cpuimx51/env/config index 91a2671..1b57b29 100644 --- a/arch/arm/boards/eukrea_cpuimx51/env/config +++ b/arch/arm/boards/eukrea_cpuimx51/env/config @@ -28,7 +28,6 @@ rootfsimage=$machine/rootfs.$rootfs_type # kernel -kernelimage_type=uimage kernelimage=$machine/uImage-${machine}.bin # barebox and it's env diff --git a/arch/arm/boards/eukrea_cpuimx51/eukrea_cpuimx51.c b/arch/arm/boards/eukrea_cpuimx51/eukrea_cpuimx51.c index a2db6d9..153ad2f 100644 --- a/arch/arm/boards/eukrea_cpuimx51/eukrea_cpuimx51.c +++ b/arch/arm/boards/eukrea_cpuimx51/eukrea_cpuimx51.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -139,6 +140,8 @@ { mxc_iomux_v3_setup_multiple_pads(eukrea_cpuimx51_pads, ARRAY_SIZE(eukrea_cpuimx51_pads)); + imx51_init_lowlevel(); + writel(0, 0x73fa8228); writel(0, 0x73fa822c); writel(0, 0x73fa8230); diff --git a/arch/arm/boards/eukrea_cpuimx51/lowlevel_init.S b/arch/arm/boards/eukrea_cpuimx51/lowlevel_init.S deleted file mode 100644 index 0b3726f..0000000 --- a/arch/arm/boards/eukrea_cpuimx51/lowlevel_init.S +++ /dev/null @@ -1,216 +0,0 @@ -/* - * This code is based on the ecos babbage startup code - * - * 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 ROM_SI_REV_OFFSET 0x48 - -.macro setup_pll pll, freq - ldr r2, =\pll - ldr r1, =0x00001232 - str r1, [r2, #MX5_PLL_DP_CTL] /* Set DPLL ON (set UPEN bit): BRMO=1 */ - mov r1, #0x2 - str r1, [r2, #MX5_PLL_DP_CONFIG] /* Enable auto-restart AREN bit */ - - str r3, [r2, #MX5_PLL_DP_OP] - str r3, [r2, #MX5_PLL_DP_HFS_OP] - - str r4, [r2, #MX5_PLL_DP_MFD] - str r4, [r2, #MX5_PLL_DP_HFS_MFD] - - str r5, [r2, #MX5_PLL_DP_MFN] - str r5, [r2, #MX5_PLL_DP_HFS_MFN] - - ldr r1, =0x00001232 - str r1, [r2, #MX5_PLL_DP_CTL] -1: ldr r1, [r2, #MX5_PLL_DP_CTL] - ands r1, r1, #0x1 - beq 1b -.endm - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#define IMX51_TO_2 - -.globl board_init_lowlevel -board_init_lowlevel: - mov r10, lr - - /* explicitly disable L2 cache */ - mrc 15, 0, r0, c1, c0, 1 - bic r0, r0, #0x2 - mcr 15, 0, r0, c1, c0, 1 - - /* reconfigure L2 cache aux control reg */ - mov r0, #0xC0 /* tag RAM */ - add r0, r0, #0x4 /* data RAM */ - orr r0, r0, #(1 << 24) /* disable write allocate delay */ - orr r0, r0, #(1 << 23) /* disable write allocate combine */ - orr r0, r0, #(1 << 22) /* disable write allocate */ - - ldr r1, =MX51_IROM_BASE_ADDR - ldr r3, [r1, #ROM_SI_REV_OFFSET] - cmp r3, #0x10 - orrls r0, r0, #(1 << 25) /* disable write combine for TO 2 and lower revs */ - - mcr 15, 1, r0, c9, c0, 2 - - ldr r0, =MX51_CCM_BASE_ADDR - - /* Gate of clocks to the peripherals first */ - ldr r1, =0x3FFFFFFF - str r1, [r0, #MX5_CCM_CCGR0] - ldr r1, =0x0 - str r1, [r0, #MX5_CCM_CCGR1] - str r1, [r0, #MX5_CCM_CCGR2] - str r1, [r0, #MX5_CCM_CCGR3] - - ldr r1, =0x00030000 - str r1, [r0, #MX5_CCM_CCGR4] - ldr r1, =0x00FFF030 - str r1, [r0, #MX5_CCM_CCGR5] - ldr r1, =0x00000300 - str r1, [r0, #MX5_CCM_CCGR6] - - /* Disable IPU and HSC dividers */ - mov r1, #0x60000 - str r1, [r0, #MX5_CCM_CCDR] - -#ifdef IMX51_TO_2 - /* Make sure to switch the DDR away from PLL 1 */ - ldr r1, =0x19239145 - str r1, [r0, #MX5_CCM_CBCDR] - /* make sure divider effective */ -1: ldr r1, [r0, #MX5_CCM_CDHIPR] - cmp r1, #0x0 - bne 1b -#endif - - /* Switch ARM to step clock */ - mov r1, #0x4 - str r1, [r0, #MX5_CCM_CCSR] - - mov r3, #MX5_PLL_DP_OP_800 - mov r4, #MX5_PLL_DP_MFD_800 - mov r5, #MX5_PLL_DP_MFN_800 - setup_pll MX51_PLL1_BASE_ADDR - - mov r3, #MX5_PLL_DP_OP_665 - mov r4, #MX5_PLL_DP_MFD_665 - mov r5, #MX5_PLL_DP_MFN_665 - setup_pll MX51_PLL3_BASE_ADDR - - /* Switch peripheral to PLL 3 */ - ldr r1, =0x000010C0 - str r1, [r0, #MX5_CCM_CBCMR] - ldr r1, =0x13239145 - str r1, [r0, #MX5_CCM_CBCDR] - - mov r3, #MX5_PLL_DP_OP_665 - mov r4, #MX5_PLL_DP_MFD_665 - mov r5, #MX5_PLL_DP_MFN_665 - setup_pll MX51_PLL2_BASE_ADDR - - /* Switch peripheral to PLL2 */ - ldr r1, =0x19239145 - str r1, [r0, #MX5_CCM_CBCDR] - ldr r1, =0x000020C0 - str r1, [r0, #MX5_CCM_CBCMR] - - mov r3, #MX5_PLL_DP_OP_216 - mov r4, #MX5_PLL_DP_MFD_216 - mov r5, #MX5_PLL_DP_MFN_216 - setup_pll MX51_PLL3_BASE_ADDR - - /* Set the platform clock dividers */ - ldr r2, =MX51_ARM_BASE_ADDR - ldr r1, =0x00000124 - str r1, [r2, #0x14] - - /* Run TO 3.0 at Full speed, for other TO's wait till we increase VDDGP */ - ldr r1, =MX51_IROM_BASE_ADDR - ldr r3, [r1, #ROM_SI_REV_OFFSET] - cmp r3, #0x10 - movls r1, #0x1 - movhi r1, #0 - str r1, [r0, #MX5_CCM_CACRR] - - /* Switch ARM back to PLL 1 */ - mov r1, #0 - str r1, [r0, #MX5_CCM_CCSR] - - /* setup the rest */ - /* Use lp_apm (24MHz) source for perclk */ -#ifdef IMX51_TO_2 - ldr r1, =0x000020C2 - str r1, [r0, #MX5_CCM_CBCMR] - // ddr clock from PLL 1, all perclk dividers are 1 since using 24MHz - ldr r1, =0x59239100 - str r1, [r0, #MX5_CCM_CBCDR] -#else - ldr r1, =0x0000E3C2 - str r1, [r0, #MX5_CCM_CBCMR] - // emi=ahb, all perclk dividers are 1 since using 24MHz - // DDR divider=6 to have 665/6=110MHz - ldr r1, =0x013B9100 - str r1, [r0, #MX5_CCM_CBCDR] -#endif - - /* Restore the default values in the Gate registers */ - ldr r1, =0xFFFFFFFF - str r1, [r0, #MX5_CCM_CCGR0] - str r1, [r0, #MX5_CCM_CCGR1] - str r1, [r0, #MX5_CCM_CCGR2] - str r1, [r0, #MX5_CCM_CCGR3] - str r1, [r0, #MX5_CCM_CCGR4] - str r1, [r0, #MX5_CCM_CCGR5] - str r1, [r0, #MX5_CCM_CCGR6] - - /* Use PLL 2 for UART's, get 66.5MHz from it */ - ldr r1, =0xA5A2A020 - str r1, [r0, #MX5_CCM_CSCMR1] - ldr r1, =0x00C30321 - str r1, [r0, #MX5_CCM_CSCDR1] - - /* make sure divider effective */ - 1: ldr r1, [r0, #MX5_CCM_CDHIPR] - cmp r1, #0x0 - bne 1b - - mov r1, #0x0 - str r1, [r0, #MX5_CCM_CCDR] - - writel(0x1, 0x73fa8074) - ldr r0, =0x73f88000 - ldr r1, [r0] - orr r1, #0x40 - str r1, [r0] - - ldr r0, =0x73f88004 - ldr r1, [r0] - orr r1, #0x40 - str r1, [r0] - - mov pc, r10 - diff --git a/arch/arm/boards/freescale-mx23-evk/mx23-evk.c b/arch/arm/boards/freescale-mx23-evk/mx23-evk.c index 47f6769..20d49fd 100644 --- a/arch/arm/boards/freescale-mx23-evk/mx23-evk.c +++ b/arch/arm/boards/freescale-mx23-evk/mx23-evk.c @@ -1,5 +1,6 @@ /* * (C) Copyright 2010 Juergen Beisert - Pengutronix + * (C) Copyright 2011 Wolfram Sang - Pengutronix * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,9 +22,28 @@ #include #include #include +#include #include #include #include +#include +#include + +static struct mxs_mci_platform_data mci_pdata = { + .caps = MMC_MODE_4BIT, + .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, /* fixed to 3.3 V */ +}; + +static const uint32_t pad_setup[] = { + /* SD card interface */ + SSP1_DATA0 | PULLUP(1), + SSP1_DATA1 | PULLUP(1), + SSP1_DATA2 | PULLUP(1), + SSP1_DATA3 | PULLUP(1), + SSP1_SCK, + SSP1_CMD | PULLUP(1), + SSP1_DETECT | PULLUP(1), +}; static int mx23_evk_mem_init(void) { @@ -35,9 +55,20 @@ static int mx23_evk_devices_init(void) { + int i; + + /* initizalize gpios */ + for (i = 0; i < ARRAY_SIZE(pad_setup); i++) + imx_gpio_mode(pad_setup[i]); + armlinux_set_bootparams((void*)IMX_MEMORY_BASE + 0x100); armlinux_set_architecture(MACH_TYPE_MX23EVK); + imx_set_ioclk(480000000); /* enable IOCLK to run at the PLL frequency */ + imx_set_sspclk(0, 100000000, 1); + add_generic_device("mxs_mci", 0, NULL, IMX_SSP1_BASE, 0, + IORESOURCE_MEM, &mci_pdata); + return 0; } diff --git a/arch/arm/boards/freescale-mx28-evk/Makefile b/arch/arm/boards/freescale-mx28-evk/Makefile new file mode 100644 index 0000000..3e1f53b --- /dev/null +++ b/arch/arm/boards/freescale-mx28-evk/Makefile @@ -0,0 +1 @@ +obj-y += mx28-evk.o diff --git a/arch/arm/boards/freescale-mx28-evk/config.h b/arch/arm/boards/freescale-mx28-evk/config.h new file mode 100644 index 0000000..8f18fda --- /dev/null +++ b/arch/arm/boards/freescale-mx28-evk/config.h @@ -0,0 +1,16 @@ +/* + * 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. + */ + +#ifndef _CONFIG_H_ +# define _CONFIG_H_ + +#endif /* _CONFIG_H_ */ diff --git a/arch/arm/boards/freescale-mx28-evk/env/config b/arch/arm/boards/freescale-mx28-evk/env/config new file mode 100644 index 0000000..5095633 --- /dev/null +++ b/arch/arm/boards/freescale-mx28-evk/env/config @@ -0,0 +1,51 @@ +#!/bin/sh + +machine=mx28-evk +#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.serverip=a.b.c.d +#eth0.gateway=a.b.c.d +#eth0.ethaddr=de:ad:be:ef:00:00 + +# can be either 'tftp', 'nfs', 'nand', 'nor' or 'disk' +kernel_loc=tftp +# can be either 'net', 'nand', 'nor', 'disk' or 'initrd' +rootfs_loc=net + +# for flash based rootfs: 'jffs2' or 'ubifs' +# in case of disk any regular filesystem like 'ext2', 'ext3', 'reiserfs' +rootfs_type=ext2 +# where is the rootfs in case of 'rootfs_loc=disk' (linux name) +rootfs_part_linux_dev=mmcblk0p4 +rootfsimage=rootfs-${machine}.$rootfs_type + +# where is the kernel image in case of 'kernel_loc=disk' +kernel_part=disk0.2 + +kernelimage=zImage-$machine +bareboximage=barebox-${machine}.bin +bareboxenvimage=barebox-${machine}.bin + +if [ -n $user ]; then + bareboximage="$user"-"$bareboximage" + bareboxenvimage="$user"-"$bareboxenvimage" + kernelimage="$user"-"$kernelimage" + rootfsimage="$user"-"$rootfsimage" + nfsroot="/home/$user/nfsroot/$machine" +else + nfsroot="/path/to/nfs/root" +fi + +autoboot_timeout=3 + +bootargs="console=ttyAMA0,115200" + +# set a fancy prompt (if support is compiled in) +PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m " diff --git a/arch/arm/boards/freescale-mx28-evk/mx28-evk.c b/arch/arm/boards/freescale-mx28-evk/mx28-evk.c new file mode 100644 index 0000000..b80b910 --- /dev/null +++ b/arch/arm/boards/freescale-mx28-evk/mx28-evk.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 Juergen Beisert, Pengutronix + * Copyright (C) 2011 Marc Kleine-Budde, Pengutronix + * Copyright (C) 2011 Wolfram Sang, 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#define MX28EVK_FEC_PHY_RESET_GPIO 141 + +/* setup the CPU card internal signals */ +static const uint32_t mx28evk_pads[] = { + /* duart */ + PWM0_DUART_RX | VE_3_3V, + PWM1_DUART_TX | VE_3_3V, + + /* fec0 */ + ENET_CLK | VE_3_3V | BITKEEPER(0), + ENET0_MDC | VE_3_3V | PULLUP(1), + ENET0_MDIO | VE_3_3V | PULLUP(1), + ENET0_TXD0 | VE_3_3V | PULLUP(1), + ENET0_TXD1 | VE_3_3V | PULLUP(1), + ENET0_TX_EN | VE_3_3V | PULLUP(1), + ENET0_TX_CLK | VE_3_3V | BITKEEPER(0), + ENET0_RXD0 | VE_3_3V | PULLUP(1), + ENET0_RXD1 | VE_3_3V | PULLUP(1), + ENET0_RX_EN | VE_3_3V | PULLUP(1), + /* send a "good morning" to the ext. phy 0 = reset */ + ENET0_RX_CLK_GPIO | VE_3_3V | PULLUP(0) | GPIO_OUT | GPIO_VALUE(0), + /* phy power control 1 = on */ + SSP1_D3_GPIO | VE_3_3V | PULLUP(0) | GPIO_OUT | GPIO_VALUE(0), + + /* mmc0 */ + SSP0_D0 | VE_3_3V | PULLUP(1), + SSP0_D1 | VE_3_3V | PULLUP(1), + SSP0_D2 | VE_3_3V | PULLUP(1), + SSP0_D3 | VE_3_3V | PULLUP(1), + SSP0_D4 | VE_3_3V | PULLUP(1), + SSP0_D5 | VE_3_3V | PULLUP(1), + SSP0_D6 | VE_3_3V | PULLUP(1), + SSP0_D7 | VE_3_3V | PULLUP(1), + SSP0_CMD | VE_3_3V | PULLUP(1), + SSP0_CD | VE_3_3V | PULLUP(1), + SSP0_SCK | VE_3_3V | BITKEEPER(0), + /* MCI slot power control 1 = off */ + PWM3_GPIO | VE_3_3V | GPIO_OUT | GPIO_VALUE(0), + /* MCI write protect 1 = not protected */ + SSP1_SCK_GPIO | VE_3_3V | GPIO_IN, +}; + +static struct mxs_mci_platform_data mci_pdata = { + .caps = MMC_MODE_8BIT, + .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, /* fixed to 3.3 V */ + .f_min = 400 * 1000, + .f_max = 25000000, +}; + +/* fec */ +static void __init mx28_evk_fec_reset(void) +{ + mdelay(1); + gpio_set_value(MX28EVK_FEC_PHY_RESET_GPIO, 1); +} + +/* PhyAD[0..2]=0, RMIISEL=1 */ +static struct fec_platform_data fec_info = { + .xcv_type = RMII, + .phy_addr = 0, +}; + +static int mx28_evk_mem_init(void) +{ + arm_add_mem_device("ram0", IMX_MEMORY_BASE, 128 * 1024 * 1024); + + return 0; +} +mem_initcall(mx28_evk_mem_init); + +static int mx28_evk_devices_init(void) +{ + int i; + + /* initizalize muxing */ + for (i = 0; i < ARRAY_SIZE(mx28evk_pads); i++) + imx_gpio_mode(mx28evk_pads[i]); + + /* enable IOCLK0 to run at the PLL frequency */ + imx_set_ioclk(0, 480000000); + /* run the SSP unit clock at 100 MHz */ + imx_set_sspclk(0, 100000000, 1); + + armlinux_set_bootparams((void *)IMX_MEMORY_BASE + 0x100); + armlinux_set_architecture(MACH_TYPE_MX28EVK); + + add_generic_device("mxs_mci", 0, NULL, IMX_SSP0_BASE, 0, + IORESOURCE_MEM, &mci_pdata); + + imx_enable_enetclk(); + mx28_evk_fec_reset(); + add_generic_device("fec_imx", 0, NULL, IMX_FEC0_BASE, 0, + IORESOURCE_MEM, &fec_info); + + return 0; +} +device_initcall(mx28_evk_devices_init); + +static int mx28_evk_console_init(void) +{ + add_generic_device("stm_serial", 0, NULL, IMX_DBGUART_BASE, 8192, + IORESOURCE_MEM, NULL); + + return 0; +} +console_initcall(mx28_evk_console_init); diff --git a/arch/arm/boards/freescale-mx35-3-stack/env/config b/arch/arm/boards/freescale-mx35-3-stack/env/config index ee9bd07..17b1e31 100644 --- a/arch/arm/boards/freescale-mx35-3-stack/env/config +++ b/arch/arm/boards/freescale-mx35-3-stack/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/freescale-mx51-pdk/Makefile b/arch/arm/boards/freescale-mx51-pdk/Makefile index 8e0c87c..b56ce7f 100644 --- a/arch/arm/boards/freescale-mx51-pdk/Makefile +++ b/arch/arm/boards/freescale-mx51-pdk/Makefile @@ -1,3 +1,2 @@ -obj-y += lowlevel_init.o obj-y += board.o obj-y += flash_header.o diff --git a/arch/arm/boards/freescale-mx51-pdk/board.c b/arch/arm/boards/freescale-mx51-pdk/board.c index d56effa..e6781f3 100644 --- a/arch/arm/boards/freescale-mx51-pdk/board.c +++ b/arch/arm/boards/freescale-mx51-pdk/board.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -265,6 +266,8 @@ { mxc_iomux_v3_setup_multiple_pads(f3s_pads, ARRAY_SIZE(f3s_pads)); + imx51_init_lowlevel(); + writel(0, 0x73fa8228); writel(0, 0x73fa822c); writel(0, 0x73fa8230); diff --git a/arch/arm/boards/freescale-mx51-pdk/env/config b/arch/arm/boards/freescale-mx51-pdk/env/config index 8e6b34e..10690c9 100644 --- a/arch/arm/boards/freescale-mx51-pdk/env/config +++ b/arch/arm/boards/freescale-mx51-pdk/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/freescale-mx51-pdk/lowlevel_init.S b/arch/arm/boards/freescale-mx51-pdk/lowlevel_init.S deleted file mode 100644 index 0b3726f..0000000 --- a/arch/arm/boards/freescale-mx51-pdk/lowlevel_init.S +++ /dev/null @@ -1,216 +0,0 @@ -/* - * This code is based on the ecos babbage startup code - * - * 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 ROM_SI_REV_OFFSET 0x48 - -.macro setup_pll pll, freq - ldr r2, =\pll - ldr r1, =0x00001232 - str r1, [r2, #MX5_PLL_DP_CTL] /* Set DPLL ON (set UPEN bit): BRMO=1 */ - mov r1, #0x2 - str r1, [r2, #MX5_PLL_DP_CONFIG] /* Enable auto-restart AREN bit */ - - str r3, [r2, #MX5_PLL_DP_OP] - str r3, [r2, #MX5_PLL_DP_HFS_OP] - - str r4, [r2, #MX5_PLL_DP_MFD] - str r4, [r2, #MX5_PLL_DP_HFS_MFD] - - str r5, [r2, #MX5_PLL_DP_MFN] - str r5, [r2, #MX5_PLL_DP_HFS_MFN] - - ldr r1, =0x00001232 - str r1, [r2, #MX5_PLL_DP_CTL] -1: ldr r1, [r2, #MX5_PLL_DP_CTL] - ands r1, r1, #0x1 - beq 1b -.endm - -#define writel(val, reg) \ - ldr r0, =reg; \ - ldr r1, =val; \ - str r1, [r0]; - -#define IMX51_TO_2 - -.globl board_init_lowlevel -board_init_lowlevel: - mov r10, lr - - /* explicitly disable L2 cache */ - mrc 15, 0, r0, c1, c0, 1 - bic r0, r0, #0x2 - mcr 15, 0, r0, c1, c0, 1 - - /* reconfigure L2 cache aux control reg */ - mov r0, #0xC0 /* tag RAM */ - add r0, r0, #0x4 /* data RAM */ - orr r0, r0, #(1 << 24) /* disable write allocate delay */ - orr r0, r0, #(1 << 23) /* disable write allocate combine */ - orr r0, r0, #(1 << 22) /* disable write allocate */ - - ldr r1, =MX51_IROM_BASE_ADDR - ldr r3, [r1, #ROM_SI_REV_OFFSET] - cmp r3, #0x10 - orrls r0, r0, #(1 << 25) /* disable write combine for TO 2 and lower revs */ - - mcr 15, 1, r0, c9, c0, 2 - - ldr r0, =MX51_CCM_BASE_ADDR - - /* Gate of clocks to the peripherals first */ - ldr r1, =0x3FFFFFFF - str r1, [r0, #MX5_CCM_CCGR0] - ldr r1, =0x0 - str r1, [r0, #MX5_CCM_CCGR1] - str r1, [r0, #MX5_CCM_CCGR2] - str r1, [r0, #MX5_CCM_CCGR3] - - ldr r1, =0x00030000 - str r1, [r0, #MX5_CCM_CCGR4] - ldr r1, =0x00FFF030 - str r1, [r0, #MX5_CCM_CCGR5] - ldr r1, =0x00000300 - str r1, [r0, #MX5_CCM_CCGR6] - - /* Disable IPU and HSC dividers */ - mov r1, #0x60000 - str r1, [r0, #MX5_CCM_CCDR] - -#ifdef IMX51_TO_2 - /* Make sure to switch the DDR away from PLL 1 */ - ldr r1, =0x19239145 - str r1, [r0, #MX5_CCM_CBCDR] - /* make sure divider effective */ -1: ldr r1, [r0, #MX5_CCM_CDHIPR] - cmp r1, #0x0 - bne 1b -#endif - - /* Switch ARM to step clock */ - mov r1, #0x4 - str r1, [r0, #MX5_CCM_CCSR] - - mov r3, #MX5_PLL_DP_OP_800 - mov r4, #MX5_PLL_DP_MFD_800 - mov r5, #MX5_PLL_DP_MFN_800 - setup_pll MX51_PLL1_BASE_ADDR - - mov r3, #MX5_PLL_DP_OP_665 - mov r4, #MX5_PLL_DP_MFD_665 - mov r5, #MX5_PLL_DP_MFN_665 - setup_pll MX51_PLL3_BASE_ADDR - - /* Switch peripheral to PLL 3 */ - ldr r1, =0x000010C0 - str r1, [r0, #MX5_CCM_CBCMR] - ldr r1, =0x13239145 - str r1, [r0, #MX5_CCM_CBCDR] - - mov r3, #MX5_PLL_DP_OP_665 - mov r4, #MX5_PLL_DP_MFD_665 - mov r5, #MX5_PLL_DP_MFN_665 - setup_pll MX51_PLL2_BASE_ADDR - - /* Switch peripheral to PLL2 */ - ldr r1, =0x19239145 - str r1, [r0, #MX5_CCM_CBCDR] - ldr r1, =0x000020C0 - str r1, [r0, #MX5_CCM_CBCMR] - - mov r3, #MX5_PLL_DP_OP_216 - mov r4, #MX5_PLL_DP_MFD_216 - mov r5, #MX5_PLL_DP_MFN_216 - setup_pll MX51_PLL3_BASE_ADDR - - /* Set the platform clock dividers */ - ldr r2, =MX51_ARM_BASE_ADDR - ldr r1, =0x00000124 - str r1, [r2, #0x14] - - /* Run TO 3.0 at Full speed, for other TO's wait till we increase VDDGP */ - ldr r1, =MX51_IROM_BASE_ADDR - ldr r3, [r1, #ROM_SI_REV_OFFSET] - cmp r3, #0x10 - movls r1, #0x1 - movhi r1, #0 - str r1, [r0, #MX5_CCM_CACRR] - - /* Switch ARM back to PLL 1 */ - mov r1, #0 - str r1, [r0, #MX5_CCM_CCSR] - - /* setup the rest */ - /* Use lp_apm (24MHz) source for perclk */ -#ifdef IMX51_TO_2 - ldr r1, =0x000020C2 - str r1, [r0, #MX5_CCM_CBCMR] - // ddr clock from PLL 1, all perclk dividers are 1 since using 24MHz - ldr r1, =0x59239100 - str r1, [r0, #MX5_CCM_CBCDR] -#else - ldr r1, =0x0000E3C2 - str r1, [r0, #MX5_CCM_CBCMR] - // emi=ahb, all perclk dividers are 1 since using 24MHz - // DDR divider=6 to have 665/6=110MHz - ldr r1, =0x013B9100 - str r1, [r0, #MX5_CCM_CBCDR] -#endif - - /* Restore the default values in the Gate registers */ - ldr r1, =0xFFFFFFFF - str r1, [r0, #MX5_CCM_CCGR0] - str r1, [r0, #MX5_CCM_CCGR1] - str r1, [r0, #MX5_CCM_CCGR2] - str r1, [r0, #MX5_CCM_CCGR3] - str r1, [r0, #MX5_CCM_CCGR4] - str r1, [r0, #MX5_CCM_CCGR5] - str r1, [r0, #MX5_CCM_CCGR6] - - /* Use PLL 2 for UART's, get 66.5MHz from it */ - ldr r1, =0xA5A2A020 - str r1, [r0, #MX5_CCM_CSCMR1] - ldr r1, =0x00C30321 - str r1, [r0, #MX5_CCM_CSCDR1] - - /* make sure divider effective */ - 1: ldr r1, [r0, #MX5_CCM_CDHIPR] - cmp r1, #0x0 - bne 1b - - mov r1, #0x0 - str r1, [r0, #MX5_CCM_CCDR] - - writel(0x1, 0x73fa8074) - ldr r0, =0x73f88000 - ldr r1, [r0] - orr r1, #0x40 - str r1, [r0] - - ldr r0, =0x73f88004 - ldr r1, [r0] - orr r1, #0x40 - str r1, [r0] - - mov pc, r10 - diff --git a/arch/arm/boards/freescale-mx53-loco/board.c b/arch/arm/boards/freescale-mx53-loco/board.c index aec2254..fa3a409 100644 --- a/arch/arm/boards/freescale-mx53-loco/board.c +++ b/arch/arm/boards/freescale-mx53-loco/board.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -155,7 +155,7 @@ { mxc_iomux_v3_setup_multiple_pads(loco_pads, ARRAY_SIZE(loco_pads)); - mx53_init_lowlevel(); + imx53_init_lowlevel(); imx53_add_uart0(); return 0; diff --git a/arch/arm/boards/freescale-mx53-loco/env/config b/arch/arm/boards/freescale-mx53-loco/env/config index 3659a62..fd238a6 100644 --- a/arch/arm/boards/freescale-mx53-loco/env/config +++ b/arch/arm/boards/freescale-mx53-loco/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/freescale-mx53-smd/board.c b/arch/arm/boards/freescale-mx53-smd/board.c index 325458e..e7aa419 100644 --- a/arch/arm/boards/freescale-mx53-smd/board.c +++ b/arch/arm/boards/freescale-mx53-smd/board.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include @@ -160,7 +160,7 @@ { mxc_iomux_v3_setup_multiple_pads(smd_pads, ARRAY_SIZE(smd_pads)); - mx53_init_lowlevel(); + imx53_init_lowlevel(); imx53_add_uart0(); imx53_add_uart1(); diff --git a/arch/arm/boards/freescale-mx53-smd/env/config b/arch/arm/boards/freescale-mx53-smd/env/config index 3659a62..fd238a6 100644 --- a/arch/arm/boards/freescale-mx53-smd/env/config +++ b/arch/arm/boards/freescale-mx53-smd/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/guf-cupid/env/config b/arch/arm/boards/guf-cupid/env/config index cd11eb1..930a97d 100644 --- a/arch/arm/boards/guf-cupid/env/config +++ b/arch/arm/boards/guf-cupid/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/guf-neso/board.c b/arch/arm/boards/guf-neso/board.c index e524b70..62d82f2 100644 --- a/arch/arm/boards/guf-neso/board.c +++ b/arch/arm/boards/guf-neso/board.c @@ -105,6 +105,7 @@ static struct imx_fb_platform_data neso_fb_data = { .mode = &imxfb_mode, + .num_modes = 1, .pwmr = 0x00000000, /* doesn't matter */ .lscr1 = 0x00120300, /* doesn't matter */ /* dynamic mode -> using the reset values (as recommended in the datasheet) */ diff --git a/arch/arm/boards/guf-neso/env/config b/arch/arm/boards/guf-neso/env/config index 162488f..9b675b5 100644 --- a/arch/arm/boards/guf-neso/env/config +++ b/arch/arm/boards/guf-neso/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/imx21ads/imx21ads.c b/arch/arm/boards/imx21ads/imx21ads.c index fc34709..fde6774 100644 --- a/arch/arm/boards/imx21ads/imx21ads.c +++ b/arch/arm/boards/imx21ads/imx21ads.c @@ -70,6 +70,7 @@ static struct imx_fb_platform_data imx_fb_data = { .mode = &imx_fb_modedata, + .num_modes = 1, .cmap_greyscale = 0, .cmap_inverse = 0, .cmap_static = 0, diff --git a/arch/arm/boards/karo-tx25/board.c b/arch/arm/boards/karo-tx25/board.c index 1eece1d..bfccd0c 100644 --- a/arch/arm/boards/karo-tx25/board.c +++ b/arch/arm/boards/karo-tx25/board.c @@ -239,6 +239,7 @@ static struct imx_fb_platform_data tx25_fb_data = { .mode = &stk5_fb_mode, + .num_modes = 1, .dmacr = 0x80040060, .enable = tx25_fb_enable, }; diff --git a/arch/arm/boards/karo-tx25/env/config b/arch/arm/boards/karo-tx25/env/config index 9113a87..69f2c26 100644 --- a/arch/arm/boards/karo-tx25/env/config +++ b/arch/arm/boards/karo-tx25/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/karo-tx28/env/config b/arch/arm/boards/karo-tx28/env/config index fdf57ea..ed361eb 100644 --- a/arch/arm/boards/karo-tx28/env/config +++ b/arch/arm/boards/karo-tx28/env/config @@ -24,14 +24,9 @@ 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 diff --git a/arch/arm/boards/mini2440/env/config b/arch/arm/boards/mini2440/env/config index ff6f1ea..ac8c32a 100644 --- a/arch/arm/boards/mini2440/env/config +++ b/arch/arm/boards/mini2440/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/mini2440/lowlevel_init.S b/arch/arm/boards/mini2440/lowlevel_init.S index 41f50cb..1c8860a 100644 --- a/arch/arm/boards/mini2440/lowlevel_init.S +++ b/arch/arm/boards/mini2440/lowlevel_init.S @@ -3,7 +3,7 @@ */ #include -#include +#include .section ".text_bare_init.board_init_lowlevel","ax" @@ -17,9 +17,9 @@ bl s3c24x0_disable_wd /* skip everything here if we are already running from SDRAM */ - cmp pc, #S3C24X0_SDRAM_BASE + cmp pc, #S3C_SDRAM_BASE blo 1f - cmp pc, #S3C24X0_SDRAM_END + cmp pc, #S3C_SDRAM_END bhs 1f mov pc, r10 diff --git a/arch/arm/boards/mini2440/mini2440.c b/arch/arm/boards/mini2440/mini2440.c index b4cc0f8..97e56db 100644 --- a/arch/arm/boards/mini2440/mini2440.c +++ b/arch/arm/boards/mini2440/mini2440.c @@ -38,11 +38,13 @@ #include #include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include static struct s3c24x0_nand_platform_data nand_info = { .nand_timing = CALC_NFCONF_TIMING(MINI2440_TACLS, MINI2440_TWRPH0, @@ -266,7 +268,7 @@ static int mini2440_mem_init(void) { - arm_add_mem_device("ram0", CS6_BASE, s3c24x0_get_memory_size()); + arm_add_mem_device("ram0", S3C_SDRAM_BASE, s3c24xx_get_memory_size()); return 0; } @@ -281,24 +283,24 @@ for (i = 0; i < ARRAY_SIZE(pin_usage); i++) s3c_gpio_mode(pin_usage[i]); - reg = readl(BWSCON); + reg = readl(S3C_BWSCON); /* CS#4 to access the network controller */ reg &= ~0x000f0000; reg |= 0x000d0000; /* 16 bit */ - writel(0x1f4c, BANKCON4); + writel(0x1f4c, S3C_BANKCON4); - writel(reg, BWSCON); + writel(reg, S3C_BWSCON); /* release the reset signal to external devices */ - reg = readl(MISCCR); + reg = readl(S3C_MISCCR); reg |= 0x10000; - writel(reg, MISCCR); + writel(reg, S3C_MISCCR); add_generic_device("s3c24x0_nand", -1, NULL, S3C24X0_NAND_BASE, 0, IORESOURCE_MEM, &nand_info); - add_dm9000_device(0, CS4_BASE + 0x300, CS4_BASE + 0x304, + add_dm9000_device(0, S3C_CS4_BASE + 0x300, S3C_CS4_BASE + 0x304, IORESOURCE_MEM_16BIT, &dm9000_data); #ifdef CONFIG_NAND /* ----------- add some vital partitions -------- */ @@ -316,7 +318,7 @@ IORESOURCE_MEM, &s3c24x0_fb_data); add_generic_device("ohci", 0, NULL, S3C2410_USB_HOST_BASE, 0x100, IORESOURCE_MEM, NULL); - armlinux_set_bootparams((void*)CS6_BASE + 0x100); + armlinux_set_bootparams((void*)S3C_SDRAM_BASE + 0x100); armlinux_set_architecture(MACH_TYPE_MINI2440); return 0; @@ -342,7 +344,7 @@ s3c_gpio_mode(GPH2_TXD0); s3c_gpio_mode(GPH3_RXD0); - add_generic_device("s3c24x0_serial", -1, NULL, UART1_BASE, UART1_SIZE, + add_generic_device("s3c_serial", -1, NULL, S3C_UART1_BASE, S3C_UART1_SIZE, IORESOURCE_MEM, NULL); return 0; } diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h index c37d5eb..765b610 100644 --- a/arch/arm/boards/mmccpu/config.h +++ b/arch/arm/boards/mmccpu/config.h @@ -41,8 +41,6 @@ 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*/ @@ -61,23 +59,7 @@ /* 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 diff --git a/arch/arm/boards/nhk8815/env/config b/arch/arm/boards/nhk8815/env/config index 7428c43..c05ed27 100644 --- a/arch/arm/boards/nhk8815/env/config +++ b/arch/arm/boards/nhk8815/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo # Partition Size Start diff --git a/arch/arm/boards/panda/env/config b/arch/arm/boards/panda/env/config index 363208e..29672be 100644 --- a/arch/arm/boards/panda/env/config +++ b/arch/arm/boards/panda/env/config @@ -18,14 +18,9 @@ # can be either 'net', 'nor', 'nand' or 'initrd' rootfs_loc=net -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -kernelimage_type=zimage kernelimage=zImage-$machine -#kernelimage_type=uimage #kernelimage=uImage-$machine -#kernelimage_type=raw #kernelimage=Image-$machine -#kernelimage_type=raw_lzo #kernelimage=Image-${machine}.lzo if [ -n $user ]; then diff --git a/arch/arm/boards/pcm037/env/config b/arch/arm/boards/pcm037/env/config index 3748cc4..d67d319 100644 --- a/arch/arm/boards/pcm037/env/config +++ b/arch/arm/boards/pcm037/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/pcm038/env/config b/arch/arm/boards/pcm038/env/config index 9e28f5d..eb0f9c1 100644 --- a/arch/arm/boards/pcm038/env/config +++ b/arch/arm/boards/pcm038/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/pcm038/pcm038.c b/arch/arm/boards/pcm038/pcm038.c index 6b8897e..8dd6521 100644 --- a/arch/arm/boards/pcm038/pcm038.c +++ b/arch/arm/boards/pcm038/pcm038.c @@ -104,6 +104,7 @@ static struct imx_fb_platform_data pcm038_fb_data = { .mode = &imxfb_mode, + .num_modes = 1, .pwmr = 0x00A903FF, .lscr1 = 0x00120300, .dmacr = 0x00020010, diff --git a/arch/arm/boards/pcm043/env/config b/arch/arm/boards/pcm043/env/config index e7f94f8..2a355e6 100644 --- a/arch/arm/boards/pcm043/env/config +++ b/arch/arm/boards/pcm043/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/pcm049/board.c b/arch/arm/boards/pcm049/board.c index 30e24bc..826856c 100644 --- a/arch/arm/boards/pcm049/board.c +++ b/arch/arm/boards/pcm049/board.c @@ -40,6 +40,7 @@ #include #include #include +#include static struct NS16550_plat serial_plat = { .clock = 48000000, /* 48MHz (APLL96/2) */ @@ -86,8 +87,18 @@ IORESOURCE_MEM, NULL); } +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO("twl6030", 0x48), + }, +}; + static int pcm049_devices_init(void) { + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + add_generic_device("i2c-omap", -1, NULL, 0x48070000, 0x1000, + IORESOURCE_MEM, NULL); + add_generic_device("omap-hsmmc", -1, NULL, 0x4809C100, SZ_4K, IORESOURCE_MEM, NULL); diff --git a/arch/arm/boards/pcm049/env/config b/arch/arm/boards/pcm049/env/config index 54b2e3d..f348714 100644 --- a/arch/arm/boards/pcm049/env/config +++ b/arch/arm/boards/pcm049/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/phycard-a-l1/Makefile b/arch/arm/boards/phycard-a-l1/Makefile new file mode 100644 index 0000000..cb0106b --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/Makefile @@ -0,0 +1,22 @@ +# (C) Copyright 2011 Juergen Kilb +# +# 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-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += lowlevel.o +obj-y += pca-a-l1.o diff --git a/arch/arm/boards/phycard-a-l1/config.h b/arch/arm/boards/phycard-a-l1/config.h new file mode 100644 index 0000000..811b7ac --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/config.h @@ -0,0 +1,22 @@ +/* + * (C) Copyright 2011 Jurgen Kilb + * + * 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 + +#endif /* __CONFIG_H */ diff --git a/arch/arm/boards/phycard-a-l1/env/config b/arch/arm/boards/phycard-a-l1/env/config new file mode 100644 index 0000000..4a648b9 --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/env/config @@ -0,0 +1,78 @@ +#!/bin/sh + +machine=pcaal1 +#user= + +# Enter MAC address here if not retrieved automatically +#eth0.ethaddr=de:ad:be:ef:00:00 + +# 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.serverip=a.b.c.d +#eth0.gateway=a.b.c.d + +# can be either 'tftp', 'nfs', 'nand' or 'disk' +kernel_loc=nand +# can be either 'net', 'nand', 'disk' or 'initrd' +rootfs_loc=nand + +# for flash based rootfs: 'jffs2' or 'ubifs' +# in case of disk any regular filesystem like 'ext2', 'ext3', 'reiserfs' +rootfs_type=jffs2 +# where is the rootfs in case of 'rootfs_loc=disk' (linux name) +rootfs_part_linux_dev=mmcblk0p4 +rootfsimage=rootfs-${machine}.$rootfs_type + +# where is the kernel image in case of 'kernel_loc=disk' +kernel_part=disk0.2 + +# The image type of the kernel. Can be uimage, zimage, raw or raw_lzo +#kernelimage=zImage-$machine +kernelimage=uImage-$machine +#kernelimage=Image-$machine +#kernelimage=Image-$machine.lzo + +bareboximage=barebox-${machine}.bin +bareboxenvimage=barebox-${machine}.bin + +if [ -n $user ]; then + bareboximage="$user"-"$bareboximage" + bareboxenvimage="$user"-"$bareboxenvimage" + kernelimage="$user"-"$kernelimage" + rootfsimage="$user"-"$rootfsimage" + nfsroot="/home/$user/nfsroot/$machine" +else + nfsroot="/path/to/nfs/root" +fi + +autoboot_timeout=3 + +bootargs="console=ttyO2,115200" + +# the following displays are supported +# pd050vl1 (640 x 480) +# pd035vl1 (640 x 480) +# pd104slf (800 x 600) +# pm070wl4 (800 x 480) +# +# omapfb.mode=:,[,...] +# omapfb.debug= +# - Enable debug printing. You have to have OMAPFB debug support enabled +# in kernel config. +# +bootargs="$bootargs omapdss.def_disp=pd050vl1" +#bootargs="$bootargs omapdss.def_disp=pd035vl1" +#bootargs="$bootargs omapdss.def_disp=pd104slf" +#bootargs="$bootargs omapdss.def_disp=pm070wl4" + +nand_parts="512k(x-loader)ro,1920k(barebox),128k(bareboxenv),4M(kernel),-(root)" +nand_device=omap2-nand.0 +rootfs_mtdblock_nand=4 + +# set a fancy prompt (if support is compiled in) +PS1="\e[1;32mbarebox@\e[1;31m\h:\w\e[0m " diff --git a/arch/arm/boards/phycard-a-l1/lowlevel.c b/arch/arm/boards/phycard-a-l1/lowlevel.c new file mode 100644 index 0000000..bffbb08 --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/lowlevel.c @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2011 + * Phytec Messtechnik GmbH + * Juergen Kilb + * + * 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 + +void __naked board_init_lowlevel(void) +{ + uint32_t r; + + /* setup a stack */ + r = OMAP_SRAM_STACK; + __asm__ __volatile__("mov sp, %0" : : "r"(r)); + + board_init(); + + board_init_lowlevel_return(); +} diff --git a/arch/arm/boards/phycard-a-l1/pca-a-l1.c b/arch/arm/boards/phycard-a-l1/pca-a-l1.c new file mode 100644 index 0000000..6fe27b7 --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/pca-a-l1.c @@ -0,0 +1,350 @@ +/** + * @file + * @brief Board Initialization routines for the phyCARD-A-L1 + * + * FileName: arch/arm/boards/phycard-a-l1/pca-a-l1.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) 2011 Phytec Messtechnik GmbH - http://www.phytec.de/ + * Juergen Kilb + * + * based on code from Texas Instruments / 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pca-a-l1.h" + +#define SMC911X_BASE 0x2c000000 + +/* + * Boot-time initialization(s) + */ + +/** + * @brief Initialize the SDRC module + * Initialisation for 1x256MByte but normally + * done by x-loader. + * @return void + */ +static void pcaal1_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(0x03588099, SDRC_REG(MCFG_0)); + + /* SDRC_RFR_CTRL0 register */ + writel(0x0004e201, SDRC_REG(RFR_CTRL_0)); + + /* SDRC_ACTIM_CTRLA0 register */ + writel(0x629DB4C6, SDRC_REG(ACTIM_CTRLA_0)); + + /* SDRC_ACTIM_CTRLB0 register */ + writel(0x00011113, 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)); +} + +/** + * @brief Do the necessary pin muxing required for phyCARD-A-L1. + * 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 pcaal1_mux_config(void) +{ + /* + * 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 | EN | M0)); + MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); + + /* GPMC */ + MUX_VAL(CP(GPMC_A1), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A2), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A3), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A4), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A5), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A6), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A7), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A8), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A9), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_A10), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D0), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D1), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D2), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D3), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D4), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D5), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D6), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D7), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D8), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D9), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D10), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D11), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D12), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D13), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D14), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_D15), (IEN | PTU | EN | M0)); + MUX_VAL(CP(GPMC_NCS0), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(GPMC_NADV_ALE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NOE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NWE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NBE0_CLE), (IDIS | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_NWP), (IEN | PTD | DIS | M0)); + MUX_VAL(CP(GPMC_WAIT0), (IEN | PTU | EN | M0)); + + /* ETH_PME (GPIO_55) */ + MUX_VAL(CP(GPMC_NCS4), (IDIS | PTU | EN | M4)); + /* #CS5 (Ethernet) */ + MUX_VAL(CP(GPMC_NCS5), (IDIS | PTU | EN | M0)); + /* ETH_FIFO_SEL (GPIO_57) */ + MUX_VAL(CP(GPMC_NCS6), (IDIS | PTD | EN | M4)); + /* ETH_AMDIX_EN (GPIO_58) */ + MUX_VAL(CP(GPMC_NCS7), (IDIS | PTU | EN | M4)); + /* ETH_nRST (GPIO_64) */ + MUX_VAL(CP(GPMC_WAIT2), (IDIS | PTU | EN | M4)); + + /* HSMMC1 */ + MUX_VAL(CP(MMC1_CLK), (IDIS | PTU | EN | M0)); + MUX_VAL(CP(MMC1_CMD), (IEN | PTU | EN | M0)); + MUX_VAL(CP(MMC1_DAT0), (IEN | PTU | EN | M0)); + MUX_VAL(CP(MMC1_DAT1), (IEN | PTU | EN | M0)); + MUX_VAL(CP(MMC1_DAT2), (IEN | PTU | EN | M0)); + MUX_VAL(CP(MMC1_DAT3), (IEN | PTU | EN | M0)); + + /* USBOTG_nRST (GPIO_63) */ + MUX_VAL(CP(GPMC_WAIT1), (IDIS | PTU | EN | M4)); + + /* USBH_nRST (GPIO_65) */ + MUX_VAL(CP(GPMC_WAIT3), (IDIS | PTU | EN | M4)); +} + +/** + * @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(); + + pcaal1_mux_config(); + /* Dont reconfigure SDRAM while running in SDRAM! */ + if (!in_sdram) + pcaal1_sdrc_init(); +} + +/* + * Run-time initialization(s) + */ +static struct NS16550_plat serial_plat = { + .clock = 48000000, /* 48MHz (APLL96/2) */ + .shift = 2, +}; + +/** + * @brief Initialize the serial port to be used as console. + * + * @return result of device registration + */ +static int pcaal1_init_console(void) +{ + add_ns16550_device(-1, OMAP_UART3_BASE, 1024, IORESOURCE_MEM_8BIT, + &serial_plat); + + return 0; +} +console_initcall(pcaal1_init_console); + +#ifdef CONFIG_DRIVER_NET_SMC911X +/** GPMC timing for our SMSC9221 device */ +static struct gpmc_config smsc_cfg = { + .cfg = { + 0x41001000, /*CONF1 */ + 0x00040500, /*CONF2 */ + 0x00000000, /*CONF3 */ + 0x04000500, /*CONF4 */ + 0x05050505, /*CONF5 */ + 0x000002c1, /*CONF6 */ + }, + .base = SMC911X_BASE, + /* GPMC address map as small as possible */ + .size = GPMC_SIZE_16M, +}; + +/* + * Routine: setup_net_chip + * Description: Setting up the configuration GPMC registers specific to the + * Ethernet hardware. + */ +static void pcaal1_setup_net_chip(void) +{ + gpmc_cs_config(5, &smsc_cfg); +} +#endif + +static int pcaal1_mem_init(void) +{ + +#ifdef CONFIG_GPMC + /* + * WP is made high and WAIT1 active Low + */ + gpmc_generic_init(0x10); +#endif + + arm_add_mem_device("ram0", OMAP_SDRC_CS0, get_sdr_cs_size(SDRC_CS0_OSET)); + + if ((get_sdr_cs_size(SDRC_CS1_OSET) != 0) && (get_sdr_cs1_base() != OMAP_SDRC_CS0)) + arm_add_mem_device("ram1", get_sdr_cs1_base(), get_sdr_cs_size(SDRC_CS1_OSET)); + + return 0; +} +mem_initcall(pcaal1_mem_init); + +#ifdef CONFIG_MCI_OMAP_HSMMC +struct omap_hsmmc_platform_data pcaal1_hsmmc_plat = { + .f_max = 26000000, +}; +#endif + +static int pcaal1_init_devices(void) +{ +#ifdef CONFIG_MCI_OMAP_HSMMC + add_generic_device("omap-hsmmc", -1, NULL, OMAP_MMC1_BASE, SZ_4K, + IORESOURCE_MEM, &pcaal1_hsmmc_plat); +#endif + +#ifdef CONFIG_DRIVER_NET_SMC911X + pcaal1_setup_net_chip(); + add_generic_device("smc911x", -1, NULL, SMC911X_BASE, SZ_4K, + IORESOURCE_MEM, NULL); +#endif + + armlinux_set_bootparams((void *)0x80000100); + armlinux_set_architecture(MACH_TYPE_PCAAL1); + + return 0; +} +device_initcall(pcaal1_init_devices); + +static int pcaal1_late_init(void) +{ + struct device_d *nand; + + gpmc_generic_nand_devices_init(0, 16, OMAP_ECC_SOFT); + + nand = get_device_by_name("nand0"); + + devfs_add_partition("nand0", 0x00000, 0x80000, PARTITION_FIXED, "x-loader"); + dev_add_bb_dev("self_raw", "x_loader0"); + + devfs_add_partition("nand0", 0x80000, 0x1e0000, PARTITION_FIXED, "self_raw"); + dev_add_bb_dev("self_raw", "self0"); + + devfs_add_partition("nand0", 0x260000, 0x20000, PARTITION_FIXED, "env_raw"); + dev_add_bb_dev("env_raw", "env0"); + + return 0; +} +late_initcall(pcaal1_late_init); diff --git a/arch/arm/boards/phycard-a-l1/pca-a-l1.dox b/arch/arm/boards/phycard-a-l1/pca-a-l1.dox new file mode 100644 index 0000000..d93c574 --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/pca-a-l1.dox @@ -0,0 +1,16 @@ +/** @page phycard-a-l1 Phytec's phyCARD-A-L1 (OMAP35xx) + +This phyCARD is based on a Texas Instruments OMAP35xx CPU. +The card is shipped with: + +- 256MiB DDR-RAM +- 256MiB NAND Flash Memory +- SMSC9221 ethernet controller +- USB-host interface +- USB-OTG interface +- LVDS camera interface +- LVDS display interface +- TPS65023 Power-Managmanet IC +- 4kB I2C EEPROM + +*/ diff --git a/arch/arm/boards/phycard-a-l1/pca-a-l1.h b/arch/arm/boards/phycard-a-l1/pca-a-l1.h new file mode 100644 index 0000000..b931d8c --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/pca-a-l1.h @@ -0,0 +1,35 @@ +/** + * @file + * @brief exported generic APIs which various board files implement + * + * FileName: arch/arm/boards/phycard-a-l1/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/phycard-a-l1/platform.S b/arch/arm/boards/phycard-a-l1/platform.S new file mode 100644 index 0000000..596d3ab --- /dev/null +++ b/arch/arm/boards/phycard-a-l1/platform.S @@ -0,0 +1,65 @@ +/** + * @file + * @brief Wrapper to call board level initialization routine + * + * FileName: arch/arm/boards/phycard-a-l1/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/phycard-i.MX27/env/config b/arch/arm/boards/phycard-i.MX27/env/config index 0e20b48..5db33d0 100644 --- a/arch/arm/boards/phycard-i.MX27/env/config +++ b/arch/arm/boards/phycard-i.MX27/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/phycard-i.MX27/pca100.c b/arch/arm/boards/phycard-i.MX27/pca100.c index 4156767..1b43951 100644 --- a/arch/arm/boards/phycard-i.MX27/pca100.c +++ b/arch/arm/boards/phycard-i.MX27/pca100.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,82 @@ .flash_bbt = 1, }; +static struct imx_fb_videomode imxfb_mode[] = { + { + .mode = { + .name = "Primeview-PD050VL1", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 40000, /* in ps (25MHz) */ + .hsync_len = 32, + .left_margin = 112, + .right_margin = 36, + .vsync_len = 2, + .upper_margin = 33, + .lower_margin = 33, + }, + .pcr = 0xF0C88080, + .bpp = 16, + }, { + .mode = { + .name = "Primeview-PD035VL1", + .refresh = 60, + .xres = 640, + .yres = 480, + .pixclock = 40000, /* in ps (25 MHz) */ + .hsync_len = 30, + .left_margin = 98, + .right_margin = 36, + .vsync_len = 2, + .upper_margin = 15, + .lower_margin = 33, + }, + .pcr = 0xF0C88080, + .bpp = 16, + }, { + .mode = { + .name = "Primeview-PD104SLF", + .refresh = 60, + .xres = 800, + .yres = 600, + .pixclock = 25000, /* in ps (40,0 MHz) */ + .hsync_len = 40, + .left_margin = 174, + .right_margin = 174, + .vsync_len = 4, + .upper_margin = 24, + .lower_margin = 23, + }, + .pcr = 0xF0C88080, + .bpp = 16, + }, { + .mode = { + .name = "Primeview-PM070WL4", + .refresh = 60, + .xres = 800, + .yres = 480, + .pixclock = 31250, /* in ps (32 MHz) */ + .hsync_len = 40, + .left_margin = 174, + .right_margin = 174, + .vsync_len = 2, + .upper_margin = 33, + .lower_margin = 23, + }, + .pcr = 0xF0C88080, + .bpp = 16, + }, +}; + +static struct imx_fb_platform_data pca100_fb_data = { + .mode = imxfb_mode, + .num_modes = ARRAY_SIZE(imxfb_mode), + .pwmr = 0x00A903FF, + .lscr1 = 0x00120300, + .dmacr = 0x00040060, +}; + #ifdef CONFIG_USB static void pca100_usb_register(void) { @@ -176,6 +253,33 @@ PE2_PF_USBOTG_DIR, PE24_PF_USBOTG_CLK, PE25_PF_USBOTG_DATA7, + /* 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, + PA26_PF_PS, + PA28_PF_HSYNC, + PA29_PF_VSYNC, + PA31_PF_OE_ACD, + /* external I2C */ + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, }; PCCR0 |= PCCR0_SDHC2_EN; @@ -189,6 +293,7 @@ imx27_add_nand(&nand_info); imx27_add_fec(&fec_info); imx27_add_mmc0(NULL); + imx27_add_fb(&pca100_fb_data); PCCR1 |= PCCR1_PERCLK2_EN; diff --git a/arch/arm/boards/pm9261/config.h b/arch/arm/boards/pm9261/config.h index 97f8efc..e8822a5 100644 --- a/arch/arm/boards/pm9261/config.h +++ b/arch/arm/boards/pm9261/config.h @@ -40,8 +40,6 @@ (AT91_MATRIX_DBPUC | AT91_MATRIX_CS1A_SDRAMC) /* SDRAM */ -/* SDRAMC_MR Mode register */ -#define CONFIG_SYS_SDRC_MR_VAL1 AT91_SDRAMC_MODE_NORMAL /* SDRAMC_TR - Refresh Timer register */ #define CONFIG_SYS_SDRC_TR_VAL1 0x13C /* SDRAMC_CR - Configuration register*/ @@ -60,23 +58,7 @@ /* 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 \ diff --git a/arch/arm/boards/pm9261/env/config b/arch/arm/boards/pm9261/env/config index 7933379..bdc2d38 100644 --- a/arch/arm/boards/pm9261/env/config +++ b/arch/arm/boards/pm9261/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nor_parts="256k(barebox)ro,64k(bareboxenv),1536k(kernel),-(root)" diff --git a/arch/arm/boards/pm9261/init.c b/arch/arm/boards/pm9261/init.c index 2766f47..23ed44e 100644 --- a/arch/arm/boards/pm9261/init.c +++ b/arch/arm/boards/pm9261/init.c @@ -87,7 +87,7 @@ /* * DM9000 ethernet device */ -#if defined(CONFIG_DRIVER_NET_DM9000) +#if defined(CONFIG_DRIVER_NET_DM9K) static struct dm9000_platform_data dm9000_data = { .srom = 1, }; @@ -124,7 +124,7 @@ } #else static void __init ek_add_device_dm9000(void) {} -#endif /* CONFIG_DRIVER_NET_DM9000 */ +#endif /* CONFIG_DRIVER_NET_DM9K */ static int pm9261_mem_init(void) { diff --git a/arch/arm/boards/pm9263/config.h b/arch/arm/boards/pm9263/config.h index 5252df2..d5add0f 100644 --- a/arch/arm/boards/pm9263/config.h +++ b/arch/arm/boards/pm9263/config.h @@ -55,8 +55,6 @@ 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*/ @@ -75,23 +73,7 @@ /* 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 \ diff --git a/arch/arm/boards/pm9g45/env/config b/arch/arm/boards/pm9g45/env/config index b8ca18d..3dea724 100644 --- a/arch/arm/boards/pm9g45/env/config +++ b/arch/arm/boards/pm9g45/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nand_device=atmel_nand diff --git a/arch/arm/boards/scb9328/env/config b/arch/arm/boards/scb9328/env/config index d0f3f25..e1c5807 100644 --- a/arch/arm/boards/scb9328/env/config +++ b/arch/arm/boards/scb9328/env/config @@ -23,14 +23,9 @@ 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 diff --git a/arch/arm/boards/usb-a926x/env/bin/init_board b/arch/arm/boards/usb-a926x/env/bin/init_board new file mode 100644 index 0000000..0a6baf7 --- /dev/null +++ b/arch/arm/boards/usb-a926x/env/bin/init_board @@ -0,0 +1,49 @@ +#!/bin/sh + +button_name="dfu_bp" +button_wait=5 + +product_id=0x1234 +vendor_id=0x4321 + +dfu_config="/dev/nand0.barebox.bb(barebox)sr,/dev/nand0.kernel.bb(kernel)r,/dev/nand0.rootfs.bb(rootfs)r" + +if [ $at91_udc0.vbus != 1 ] +then + echo "No USB Device cable plugged, normal boot" + exit +fi + +gpio_get_value ${dfu_button} +if [ $? != 0 ] +then + autoboot_timeout=16 + echo "enable tty over USB Device, increase the boot delay to ${autoboot_timeout}s" + usbserial + exit +fi + +echo "${button_name} pressed detected wait ${button_wait}s" +timeout -s -a ${button_wait} + +if [ $at91_udc0.vbus != 1 ] +then + echo "No USB Device cable plugged, normal boot" + exit +fi + +gpio_get_value ${dfu_button} +if [ $? != 0 ] +then + echo "${button_name} released, normal boot" + autoboot_timeout=16 + echo "enable tty over USB Device, increase the boot delay to ${autoboot_timeout}s" + usbserial + exit +fi + +echo "" +echo "Start DFU Mode" +echo "" + +dfu ${dfu_config} -P ${product_id} -V ${vendor_id} diff --git a/arch/arm/boards/usb-a926x/env/config b/arch/arm/boards/usb-a926x/env/config index d77f678..96a4524 100644 --- a/arch/arm/boards/usb-a926x/env/config +++ b/arch/arm/boards/usb-a926x/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nand_device=atmel_nand diff --git a/arch/arm/boards/usb-a926x/init.c b/arch/arm/boards/usb-a926x/init.c index 58460c1..364c1ba 100644 --- a/arch/arm/boards/usb-a926x/init.c +++ b/arch/arm/boards/usb-a926x/init.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -57,6 +58,7 @@ /* .det_pin = ... not connected */ .rdy_pin = AT91_PIN_PC13, .enable_pin = AT91_PIN_PC14, + .on_flash_bbt = 1, }; static struct sam9_smc_config usb_a9260_nand_smc_config = { @@ -165,6 +167,38 @@ .ports = 2, }; +/* + * USB Device port + */ +static struct at91_udc_data __initdata ek_udc_data = { + .vbus_pin = AT91_PIN_PB11, + .pullup_pin = -EINVAL, /* pull-up driven by UDC */ +}; + +static void __init ek_add_device_udc(void) +{ + if (machine_is_usb_a9260() || machine_is_usb_a9g20()) + ek_udc_data.vbus_pin = AT91_PIN_PC5; + + at91_add_device_udc(&ek_udc_data); +} + +struct gpio_led led = { + .gpio = AT91_PIN_PB21, + .led = { + .name = "user_led", + }, +}; + +static void __init ek_add_led(void) +{ + if (machine_is_usb_a9263()) + led.active_low = 1; + + at91_set_gpio_output(led.gpio, led.active_low); + led_gpio_register(&led); +} + static int usb_a9260_mem_init(void) { #ifdef CONFIG_AT91_HAVE_SRAM_128M @@ -177,6 +211,14 @@ } mem_initcall(usb_a9260_mem_init); +static void __init ek_add_device_button(void) +{ + at91_set_GPIO_periph(AT91_PIN_PB10, 1); /* user push button, pull up enabled */ + at91_set_deglitch(AT91_PIN_PB10, 1); + + export_env_ull("dfu_button", AT91_PIN_PB10); +} + static int usb_a9260_devices_init(void) { usb_a9260_add_device_nand(); @@ -184,6 +226,9 @@ at91_add_device_eth(&macb_pdata); usb_a9260_add_device_mci(); at91_add_device_usbh_ohci(&ek_usbh_data); + ek_add_device_udc(); + ek_add_led(); + ek_add_device_button(); armlinux_set_bootparams((void *)(AT91_CHIPSELECT_1 + 0x100)); usb_a9260_set_board_type(); diff --git a/arch/arm/boards/versatile/env/config b/arch/arm/boards/versatile/env/config index 9c5ce61..667dce3 100644 --- a/arch/arm/boards/versatile/env/config +++ b/arch/arm/boards/versatile/env/config @@ -19,14 +19,9 @@ rootfs_type=ubifs rootfsimage=root.$rootfs_type -# The image type of the kernel. Can be uimage, zimage, raw, or raw_lzo -#kernelimage_type=zimage #kernelimage=zImage -kernelimage_type=uimage kernelimage=uImage -#kernelimage_type=raw #kernelimage=Image -#kernelimage_type=raw_lzo #kernelimage=Image.lzo nfsroot="$eth0.serverip:/opt/work/busybox/arm9/rootfs_arm" diff --git a/arch/arm/configs/at91sam9260ek_defconfig b/arch/arm/configs/at91sam9260ek_defconfig index 2d04206..3367cee 100644 --- a/arch/arm/configs/at91sam9260ek_defconfig +++ b/arch/arm/configs/at91sam9260ek_defconfig @@ -1,10 +1,14 @@ CONFIG_ARCH_AT91SAM9260=y +CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_PROMPT="9260-EK:" CONFIG_LONGHELP=y CONFIG_GLOB=y +CONFIG_PROMPT_HUSH_PS2="y" +CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y -CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/at91sam9260ek/env" CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y @@ -13,18 +17,37 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_LOADB=y CONFIG_CMD_MEMINFO=y -CONFIG_CMD_CRC=y CONFIG_CMD_MTEST=y +CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_GPIO=y CONFIG_NET=y CONFIG_NET_DHCP=y +CONFIG_NET_NFS=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y +CONFIG_NET_NETCONSOLE=y CONFIG_DRIVER_NET_MACB=y # CONFIG_SPI is not set +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_ATMEL=y +CONFIG_UBI=y +CONFIG_USB_GADGET=y +CONFIG_MCI=y +CONFIG_MCI_STARTUP=y +CONFIG_MCI_ATMEL=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_BZLIB=y diff --git a/arch/arm/configs/at91sam9261ek_defconfig b/arch/arm/configs/at91sam9261ek_defconfig index a4adee9..b60407f 100644 --- a/arch/arm/configs/at91sam9261ek_defconfig +++ b/arch/arm/configs/at91sam9261ek_defconfig @@ -41,7 +41,7 @@ CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y diff --git a/arch/arm/configs/at91sam9g10ek_defconfig b/arch/arm/configs/at91sam9g10ek_defconfig index 9271b68..d54e42c 100644 --- a/arch/arm/configs/at91sam9g10ek_defconfig +++ b/arch/arm/configs/at91sam9g10ek_defconfig @@ -33,7 +33,7 @@ CONFIG_NET_NFS=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y diff --git a/arch/arm/configs/at91sam9g20ek_defconfig b/arch/arm/configs/at91sam9g20ek_defconfig index bc7c242..2492b30 100644 --- a/arch/arm/configs/at91sam9g20ek_defconfig +++ b/arch/arm/configs/at91sam9g20ek_defconfig @@ -1,14 +1,15 @@ CONFIG_ARCH_AT91SAM9G20=y -CONFIG_MACH_AT91SAM9G20EK=y CONFIG_AT91_HAVE_2MMC=y +CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_PROMPT="9G20-EK:" CONFIG_LONGHELP=y CONFIG_GLOB=y CONFIG_PROMPT_HUSH_PS2="y" +CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y -CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/at91sam9260ek/env" CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y @@ -17,23 +18,37 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_LOADB=y CONFIG_CMD_MEMINFO=y -CONFIG_CMD_CRC=y CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y CONFIG_CMD_BOOTM_SHOW_TYPE=y CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_GPIO=y CONFIG_NET=y CONFIG_NET_DHCP=y +CONFIG_NET_NFS=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y +CONFIG_NET_NETCONSOLE=y CONFIG_DRIVER_NET_MACB=y # CONFIG_SPI is not set -CONFIG_I2C=y -CONFIG_DRIVER_CFI=y -CONFIG_CFI_BUFFER_WRITE=y +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_ATMEL=y +CONFIG_UBI=y +CONFIG_USB_GADGET=y +CONFIG_MCI=y +CONFIG_MCI_STARTUP=y +CONFIG_MCI_ATMEL=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_BZLIB=y diff --git a/arch/arm/configs/cupid_defconfig b/arch/arm/configs/cupid_defconfig index 3f5038f..a311e27 100644 --- a/arch/arm/configs/cupid_defconfig +++ b/arch/arm/configs/cupid_defconfig @@ -9,6 +9,7 @@ CONFIG_MMU=y CONFIG_TEXT_BASE=0x87F00000 CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -16,7 +17,6 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y -CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv arch/arm/boards/guf-cupid/env" CONFIG_CMD_EDIT=y @@ -26,13 +26,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_BMP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y @@ -56,3 +68,8 @@ CONFIG_DRIVER_VIDEO_IMX_IPU=y CONFIG_MCI=y CONFIG_MCI_IMX_ESDHC=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/freescale_mx25_3stack_defconfig b/arch/arm/configs/freescale_mx25_3stack_defconfig index e833636..eac343f 100644 --- a/arch/arm/configs/freescale_mx25_3stack_defconfig +++ b/arch/arm/configs/freescale_mx25_3stack_defconfig @@ -1,13 +1,22 @@ CONFIG_ARCH_IMX=y CONFIG_ARCH_IMX25=y CONFIG_MACH_FREESCALE_MX25_3STACK=y +CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_ARM_UNWIND=y +CONFIG_MMU=y CONFIG_TEXT_BASE=0x87F00000 +CONFIG_MALLOC_SIZE=0x01000000 +CONFIG_MALLOC_TLSF=y +CONFIG_KALLSYMS=y +CONFIG_LONGHELP=y CONFIG_GLOB=y +CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y # CONFIG_ERRNO_MESSAGES is not set CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/freescale-mx25-3-stack/env/" CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y @@ -16,14 +25,27 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y +CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y -CONFIG_CMD_CRC=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y +CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_PING=y @@ -32,3 +54,5 @@ # CONFIG_SPI is not set CONFIG_USB=y CONFIG_USB_EHCI=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/freescale_mx35_3stack_defconfig b/arch/arm/configs/freescale_mx35_3stack_defconfig index c8d159f..a60658d 100644 --- a/arch/arm/configs/freescale_mx35_3stack_defconfig +++ b/arch/arm/configs/freescale_mx35_3stack_defconfig @@ -3,8 +3,11 @@ CONFIG_MACH_FREESCALE_MX35_3STACK=y CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_ARM_UNWIND=y CONFIG_TEXT_BASE=0x87F00000 CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_MALLOC_TLSF=y +CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y CONFIG_HUSH_FANCY_PROMPT=y @@ -20,13 +23,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_BMP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y @@ -43,7 +58,8 @@ CONFIG_MTD=y CONFIG_NAND=y CONFIG_NAND_IMX=y -CONFIG_NAND_IMX_BOOT=y CONFIG_UBI=y CONFIG_VIDEO=y CONFIG_DRIVER_VIDEO_IMX_IPU=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/freescale_mx51_babbage_defconfig b/arch/arm/configs/freescale_mx51_babbage_defconfig index 472ed62..dbdb76d 100644 --- a/arch/arm/configs/freescale_mx51_babbage_defconfig +++ b/arch/arm/configs/freescale_mx51_babbage_defconfig @@ -8,13 +8,13 @@ CONFIG_MMU=y CONFIG_TEXT_BASE=0x97f00000 CONFIG_MALLOC_SIZE=0x2000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y -CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv arch/arm/boards/freescale-mx51-pdk/env/" CONFIG_CMD_EDIT=y @@ -24,14 +24,27 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y +CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_NFS=y @@ -46,3 +59,8 @@ CONFIG_MCI_STARTUP=y CONFIG_MCI_IMX_ESDHC=y CONFIG_I2C_MC13892=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/freescale_mx53_loco_defconfig b/arch/arm/configs/freescale_mx53_loco_defconfig index cb07f85..b4e872d 100644 --- a/arch/arm/configs/freescale_mx53_loco_defconfig +++ b/arch/arm/configs/freescale_mx53_loco_defconfig @@ -8,13 +8,13 @@ CONFIG_MMU=y CONFIG_TEXT_BASE=0x7ff00000 CONFIG_MALLOC_SIZE=0x2000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y -CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv arch/arm/boards/freescale-mx53-loco/env/" CONFIG_DEBUG_INFO=y @@ -25,13 +25,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y @@ -49,3 +61,5 @@ CONFIG_FS_FAT=y CONFIG_FS_FAT_WRITE=y CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/freescale_mx53_smd_defconfig b/arch/arm/configs/freescale_mx53_smd_defconfig index 1548b05..f37df56 100644 --- a/arch/arm/configs/freescale_mx53_smd_defconfig +++ b/arch/arm/configs/freescale_mx53_smd_defconfig @@ -9,6 +9,7 @@ CONFIG_MMU=y CONFIG_TEXT_BASE=0x7ff00000 CONFIG_MALLOC_SIZE=0x2000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -25,13 +26,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y @@ -49,3 +62,5 @@ CONFIG_FS_FAT=y CONFIG_FS_FAT_WRITE=y CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/imx28evk_defconfig b/arch/arm/configs/imx28evk_defconfig new file mode 100644 index 0000000..1860aef --- /dev/null +++ b/arch/arm/configs/imx28evk_defconfig @@ -0,0 +1,48 @@ +CONFIG_ARCH_MXS=y +CONFIG_ARCH_IMX28=y +CONFIG_MACH_MX28EVK=y +CONFIG_AEABI=y +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_MMU=y +CONFIG_TEXT_BASE=0x43000000 +CONFIG_MALLOC_SIZE=0x800000 +CONFIG_BROKEN=y +CONFIG_LONGHELP=y +CONFIG_GLOB=y +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/freescale-mx28-evk/env" +CONFIG_DEBUG_INFO=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_MTEST=y +CONFIG_CMD_MTEST_ALTERNATIVE=y +CONFIG_CMD_BOOTM_ZLIB=y +CONFIG_CMD_BOOTM_BZLIB=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_RESET=y +CONFIG_CMD_GO=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_GPIO=y +CONFIG_NET=y +CONFIG_NET_DHCP=y +CONFIG_NET_PING=y +CONFIG_NET_TFTP=y +CONFIG_NET_RESOLV=y +CONFIG_DRIVER_NET_FEC_IMX=y +# CONFIG_SPI is not set +CONFIG_MCI=y +CONFIG_MCI_STARTUP=y +CONFIG_MCI_MXS=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_LFN=y diff --git a/arch/arm/configs/mini2440_defconfig b/arch/arm/configs/mini2440_defconfig index e770871..9b35dd5 100644 --- a/arch/arm/configs/mini2440_defconfig +++ b/arch/arm/configs/mini2440_defconfig @@ -1,5 +1,6 @@ CONFIG_ARCH_S3C24xx=y CONFIG_MACH_MINI2440=y +CONFIG_MINI2440_VIDEO_N35=y CONFIG_S3C24XX_NAND_BOOT=y CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y @@ -10,7 +11,6 @@ CONFIG_GLOB=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y -CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/mini2440/env" CONFIG_DEBUG_INFO=y @@ -33,7 +33,10 @@ CONFIG_NET_DHCP=y CONFIG_NET_PING=y CONFIG_NET_TFTP=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set +CONFIG_USB=y +CONFIG_USB_OHCI=y +CONFIG_DRIVER_VIDEO_S3C24XX=y CONFIG_MCI=y CONFIG_MCI_S3C=y diff --git a/arch/arm/configs/neso_defconfig b/arch/arm/configs/neso_defconfig index dcc2f70..45ffe30 100644 --- a/arch/arm/configs/neso_defconfig +++ b/arch/arm/configs/neso_defconfig @@ -8,6 +8,7 @@ CONFIG_ARM_UNWIND=y CONFIG_MMU=y CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -24,14 +25,26 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_MTEST=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_BMP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y diff --git a/arch/arm/configs/pca100_defconfig b/arch/arm/configs/pca100_defconfig index 29e02c5..2df7e34 100644 --- a/arch/arm/configs/pca100_defconfig +++ b/arch/arm/configs/pca100_defconfig @@ -7,7 +7,8 @@ CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y CONFIG_MMU=y -CONFIG_MALLOC_SIZE=0x500000 +CONFIG_MALLOC_SIZE=0x01000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -24,14 +25,26 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_MTEST=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y @@ -53,3 +66,5 @@ CONFIG_USB=y CONFIG_USB_EHCI=y CONFIG_USB_ISP1504=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/pcm037_defconfig b/arch/arm/configs/pcm037_defconfig index ec43317..7705bcf 100644 --- a/arch/arm/configs/pcm037_defconfig +++ b/arch/arm/configs/pcm037_defconfig @@ -7,6 +7,8 @@ CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y CONFIG_ARM_UNWIND=y CONFIG_MMU=y +CONFIG_MALLOC_SIZE=0x01000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -14,6 +16,7 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_PARTITION=y +CONFIG_PARTITION_DISK=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/pcm037/env" CONFIG_CMD_EDIT=y @@ -23,13 +26,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y @@ -50,3 +65,5 @@ CONFIG_UBI=y CONFIG_USB=y CONFIG_USB_EHCI=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/pcm038_defconfig b/arch/arm/configs/pcm038_defconfig index 2f4823a..b63337e 100644 --- a/arch/arm/configs/pcm038_defconfig +++ b/arch/arm/configs/pcm038_defconfig @@ -9,6 +9,7 @@ CONFIG_MMU=y CONFIG_TEXT_BASE=0xa7f00000 CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -16,6 +17,7 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_PARTITION=y +CONFIG_PARTITION_DISK=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/pcm038/env" CONFIG_CMD_EDIT=y @@ -25,16 +27,30 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_MTEST=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_BMP=y CONFIG_CMD_GPIO=y +CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_PING=y @@ -58,3 +74,5 @@ CONFIG_VIDEO=y CONFIG_DRIVER_VIDEO_IMX=y CONFIG_IMXFB_DRIVER_VIDEO_IMX_OVERLAY=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/pcm043_defconfig b/arch/arm/configs/pcm043_defconfig index e47bb35..179d403 100644 --- a/arch/arm/configs/pcm043_defconfig +++ b/arch/arm/configs/pcm043_defconfig @@ -12,6 +12,7 @@ CONFIG_MMU=y CONFIG_TEXT_BASE=0x87F00000 CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -28,13 +29,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y @@ -52,3 +65,5 @@ CONFIG_NAND=y CONFIG_NAND_IMX=y CONFIG_UBI=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/pcm049_defconfig b/arch/arm/configs/pcm049_defconfig index 9b4c341..cf1cf48 100644 --- a/arch/arm/configs/pcm049_defconfig +++ b/arch/arm/configs/pcm049_defconfig @@ -7,16 +7,15 @@ CONFIG_MMU=y CONFIG_TEXT_BASE=0x8f000000 CONFIG_MALLOC_SIZE=0x2000000 +CONFIG_MALLOC_TLSF=y CONFIG_KALLSYMS=y CONFIG_PROMPT="barebox> " CONFIG_LONGHELP=y CONFIG_GLOB=y CONFIG_HUSH_FANCY_PROMPT=y -CONFIG_HUSH_GETOPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y # CONFIG_TIMESTAMP is not set -CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/pcm049/env" CONFIG_CMD_EDIT=y @@ -26,14 +25,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_LOADB=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y -# CONFIG_CMD_BOOTM is not set +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y @@ -55,3 +65,5 @@ CONFIG_FS_FAT=y CONFIG_FS_FAT_WRITE=y CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/pcm049_xload_defconfig b/arch/arm/configs/pcm049_xload_defconfig index 7303c9a..bf30941 100644 --- a/arch/arm/configs/pcm049_xload_defconfig +++ b/arch/arm/configs/pcm049_xload_defconfig @@ -22,14 +22,14 @@ CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y # CONFIG_SPI is not set CONFIG_MTD=y +# CONFIG_MTD_WRITE is not set +# CONFIG_MTD_OOB_DEVICE is not set CONFIG_NAND=y -# CONFIG_NAND_WRITE is not set # CONFIG_NAND_ECC_SOFT is not set # CONFIG_NAND_ECC_HW_SYNDROME is not set # CONFIG_NAND_ECC_HW_NONE is not set # CONFIG_NAND_INFO is not set # CONFIG_NAND_BBT is not set -# CONFIG_NAND_READ_OOB is not set CONFIG_NAND_OMAP_GPMC=y CONFIG_MCI=y CONFIG_MCI_STARTUP=y diff --git a/arch/arm/configs/phycard_a_l1_defconfig b/arch/arm/configs/phycard_a_l1_defconfig new file mode 100644 index 0000000..95dffbb --- /dev/null +++ b/arch/arm/configs/phycard_a_l1_defconfig @@ -0,0 +1,183 @@ +CONFIG_GENERIC_LINKER_SCRIPT=y +CONFIG_ARM=y +CONFIG_ARM_LINUX=y +CONFIG_ARCH_OMAP=y +CONFIG_CPU_32=y +CONFIG_CPU_V7=y +CONFIG_CPU_32v7=y +CONFIG_BOARDINFO="Phytec phyCARD-A-L1" +CONFIG_ARCH_OMAP3=y +CONFIG_OMAP_CLOCK_ALL=y +CONFIG_OMAP_CLOCK_SOURCE_S32K=y +CONFIG_OMAP3_CLOCK_CONFIG=y +CONFIG_OMAP3_COPY_CLOCK_SRAM=n +CONFIG_OMAP_GPMC=y +CONFIG_MACH_PCAAL1=y +CONFIG_HAS_OMAP_NAND=y +CONFIG_AEABI=y +CONFIG_CMD_ARM_CPUINFO=y +CONFIG_ARM_EXCEPTIONS=y +CONFIG_DEFCONFIG_LIST="$ARCH_DEFCONFIG" +CONFIG_GREGORIAN_CALENDER=y +CONFIG_HAS_KALLSYMS=y +CONFIG_HAS_MODULES=y +CONFIG_CMD_MEMORY=y +CONFIG_ENV_HANDLING=y +CONFIG_GENERIC_GPIO=y +CONFIG_BLOCK=y +CONFIG_BLOCK_WRITE=y +CONFIG_LOCALVERSION="" +CONFIG_LOCALVERSION_AUTO=y +CONFIG_ENVIRONMENT_VARIABLES=y +CONFIG_HAVE_CONFIGURABLE_TEXT_BASE=y +CONFIG_TEXT_BASE=0x85000000 +CONFIG_HAVE_CONFIGURABLE_MEMORY_LAYOUT=y +CONFIG_MEMORY_LAYOUT_DEFAULT=y +CONFIG_STACK_SIZE=0x8000 +CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_EXPERIMENTAL=y +CONFIG_MALLOC_DLMALLOC=y +CONFIG_MACH_HAS_LOWLEVEL_INIT=y +CONFIG_MACH_DO_LOWLEVEL_INIT=y +CONFIG_ARCH_HAS_LOWLEVEL_INIT=y +CONFIG_PROMPT="phyCARD-A-L1 >" +CONFIG_BAUDRATE=115200 +CONFIG_LONGHELP=y +CONFIG_CBSIZE=1024 +CONFIG_MAXARGS=16 +CONFIG_SHELL_HUSH=y +CONFIG_GLOB=y +CONFIG_PROMPT_HUSH_PS2="> " +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_HUSH_GETOPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_MENU=y +CONFIG_PASSWORD=y +CONFIG_PASSWD_SUM_MD5=y +CONFIG_DYNAMIC_CRC_TABLE=y +CONFIG_ERRNO_MESSAGES=y +CONFIG_TIMESTAMP=y +CONFIG_CONSOLE_FULL=y +CONFIG_CONSOLE_ACTIVATE_FIRST=y +CONFIG_PARTITION=y +CONFIG_PARTITION_DISK=y +CONFIG_PARTITION_DISK_DOS=y +CONFIG_DEFAULT_ENVIRONMENT=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="defaultenv ./arch/arm/boards/phycard-a-l1/env" +CONFIG_COMMAND_SUPPORT=y +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 +CONFIG_CMD_MENU=y +CONFIG_CMD_MENU_MANAGEMENT=y +CONFIG_CMD_LOGIN=y +CONFIG_CMD_PASSWD=y +CONFIG_PASSWD_MODE_STAR=y +CONFIG_CMD_TIME=y +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 +CONFIG_CMD_NAND=y +CONFIG_CMD_CLEAR=y +CONFIG_CMD_ECHO=y +CONFIG_CMD_ECHO_E=y +CONFIG_CMD_LOADB=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y +CONFIG_CMD_CRC=y +CONFIG_CMD_CRC_CMP=y +CONFIG_CMD_DIGEST=y +CONFIG_CMD_MD5SUM=y +CONFIG_CMD_SHA1SUM=y +CONFIG_CMD_SHA256SUM=y +CONFIG_CMD_SHA224SUM=y +CONFIG_CMD_MTEST=y +CONFIG_CMD_MTEST_ALTERNATIVE=y +CONFIG_CMD_FLASH=y +CONFIG_CMD_UBI=y +CONFIG_CMD_BOOTM=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_IMINFO=y +CONFIG_CMD_BOOTZ=n +CONFIG_CMD_BOOTU=n +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_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y +CONFIG_CMD_DEVINFO=y +CONFIG_CMD_UNCOMPRESS=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 +CONFIG_DRIVER_SERIAL_NS16550=y +CONFIG_DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS=y +CONFIG_MIIDEV=y +CONFIG_DRIVER_NET_SMC911X=y +CONFIG_DRIVER_NET_SMC911X_ADDRESS_SHIFT=0 +CONFIG_SPI=n +CONFIG_MTD=y +CONFIG_NAND=y +CONFIG_NAND_WRITE=y +CONFIG_NAND_ECC_SOFT=y +CONFIG_NAND_ECC_HW=y +CONFIG_NAND_ECC_HW_SYNDROME=y +CONFIG_NAND_ECC_HW_NONE=y +CONFIG_NAND_INFO=y +CONFIG_NAND_READ_OOB=y +CONFIG_NAND_BBT=y +CONFIG_NAND_OOB_DEVICE=y +CONFIG_NAND_OMAP_GPMC=y +CONFIG_MTD_NAND_IDS=y +CONFIG_UBI=y +CONFIG_DISK=y +CONFIG_DISK_WRITE=y +CONFIG_DISK_ATA=y +CONFIG_DISK_INTF_PLATFORM_IDE=y +CONFIG_MCI=y +CONFIG_MCI_INFO=y +CONFIG_MCI_WRITE=y +CONFIG_MCI_OMAP_HSMMC=y +CONFIG_FS_CRAMFS=y +CONFIG_FS_RAMFS=y +CONFIG_FS_DEVFS=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y +CONFIG_PARTITION_NEED_MTD=y +CONFIG_ZLIB=y +CONFIG_BZLIB=y +CONFIG_PROCESS_ESCAPE_SEQUENCE=y +CONFIG_LZO_DECOMPRESS=y +CONFIG_FDT=y +CONFIG_OFTREE=y +CONFIG_CRC32=y +CONFIG_CRC16=y +CONFIG_DIGEST=y +CONFIG_MD5=y +CONFIG_SHA1=y +CONFIG_SHA224=y +CONFIG_SHA256=y diff --git a/arch/arm/configs/pm9261_defconfig b/arch/arm/configs/pm9261_defconfig index 89aa033..39f401f 100644 --- a/arch/arm/configs/pm9261_defconfig +++ b/arch/arm/configs/pm9261_defconfig @@ -42,7 +42,7 @@ CONFIG_NET_TFTP=y CONFIG_NET_TFTP_PUSH=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y # CONFIG_SPI is not set CONFIG_DRIVER_CFI=y CONFIG_CFI_BUFFER_WRITE=y diff --git a/arch/arm/configs/scb9328_defconfig b/arch/arm/configs/scb9328_defconfig index 4955646..1a16999 100644 --- a/arch/arm/configs/scb9328_defconfig +++ b/arch/arm/configs/scb9328_defconfig @@ -20,13 +20,25 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_GPIO=y CONFIG_CMD_UNCOMPRESS=y CONFIG_CMD_LED=y @@ -39,12 +51,12 @@ CONFIG_NET_TFTP_PUSH=y CONFIG_NET_NETCONSOLE=y CONFIG_NET_RESOLV=y -CONFIG_DRIVER_NET_DM9000=y +CONFIG_DRIVER_NET_DM9K=y CONFIG_DRIVER_CFI=y # CONFIG_DRIVER_CFI_BANK_WIDTH_4 is not set CONFIG_CFI_BUFFER_WRITE=y -CONFIG_MTD=y -CONFIG_UBI=y CONFIG_LED=y CONFIG_LED_GPIO=y CONFIG_LED_TRIGGERS=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/tx25stk5_defconfig b/arch/arm/configs/tx25stk5_defconfig index 8127ff3..99057c2 100644 --- a/arch/arm/configs/tx25stk5_defconfig +++ b/arch/arm/configs/tx25stk5_defconfig @@ -4,8 +4,11 @@ CONFIG_IMX_IIM=y CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_ARM_UNWIND=y CONFIG_MMU=y CONFIG_MALLOC_SIZE=0x1000000 +CONFIG_MALLOC_TLSF=y +CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y CONFIG_HUSH_FANCY_PROMPT=y @@ -21,17 +24,30 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y CONFIG_CMD_MEMINFO=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y +CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_BMP=y CONFIG_CMD_GPIO=y +CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_PING=y @@ -43,7 +59,8 @@ CONFIG_MTD=y CONFIG_NAND=y CONFIG_NAND_IMX=y -CONFIG_NAND_IMX_BOOT=y CONFIG_UBI=y CONFIG_VIDEO=y CONFIG_DRIVER_VIDEO_IMX=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/tx28stk5_defconfig b/arch/arm/configs/tx28stk5_defconfig index 384c1c9..b4e3747 100644 --- a/arch/arm/configs/tx28stk5_defconfig +++ b/arch/arm/configs/tx28stk5_defconfig @@ -2,16 +2,18 @@ CONFIG_ARCH_IMX28=y CONFIG_AEABI=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_ARM_UNWIND=y CONFIG_MMU=y -CONFIG_MALLOC_SIZE=0x800000 +CONFIG_MALLOC_SIZE=0x01000000 CONFIG_BROKEN=y +CONFIG_MALLOC_TLSF=y +CONFIG_KALLSYMS=y CONFIG_LONGHELP=y CONFIG_GLOB=y CONFIG_HUSH_FANCY_PROMPT=y CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y -CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/karo-tx28/env" CONFIG_DEBUG_INFO=y @@ -22,18 +24,26 @@ CONFIG_CMD_EXPORT=y CONFIG_CMD_PRINTENV=y CONFIG_CMD_READLINE=y +CONFIG_CMD_TIME=y CONFIG_CMD_ECHO_E=y +CONFIG_CMD_IOMEM=y CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y -CONFIG_CMD_BOOTM_ZLIB=y -CONFIG_CMD_BOOTM_BZLIB=y CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_VERBOSE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_BOOTM_OFTREE=y +CONFIG_CMD_BOOTM_OFTREE_UIMAGE=y +CONFIG_CMD_UIMAGE=y CONFIG_CMD_RESET=y CONFIG_CMD_GO=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y +CONFIG_CMD_MAGICVAR=y +CONFIG_CMD_MAGICVAR_HELP=y CONFIG_CMD_BMP=y CONFIG_CMD_GPIO=y +CONFIG_CMD_UNCOMPRESS=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_TFTP=y @@ -44,4 +54,9 @@ CONFIG_DRIVER_VIDEO_STM=y CONFIG_MCI=y CONFIG_MCI_STARTUP=y -CONFIG_MCI_STM378X=y +CONFIG_MCI_MXS=y +CONFIG_FS_FAT=y +CONFIG_FS_FAT_WRITE=y +CONFIG_FS_FAT_LFN=y +CONFIG_ZLIB=y +CONFIG_LZO_DECOMPRESS=y diff --git a/arch/arm/configs/usb_a9260_defconfig b/arch/arm/configs/usb_a9260_defconfig index adcb603..9073d04 100644 --- a/arch/arm/configs/usb_a9260_defconfig +++ b/arch/arm/configs/usb_a9260_defconfig @@ -1,9 +1,9 @@ CONFIG_ARCH_AT91SAM9260=y CONFIG_MACH_USB_A9260=y CONFIG_AEABI=y +# CONFIG_CMD_ARM_CPUINFO is not set CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y -CONFIG_MMU=y -CONFIG_KALLSYMS=y +CONFIG_EXPERIMENTAL=y CONFIG_PROMPT="USB-9G20:" CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -12,6 +12,8 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +# CONFIG_CONSOLE_ACTIVATE_FIRST is not set +CONFIG_CONSOLE_ACTIVATE_ALL=y CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/usb-a926x/env" @@ -34,14 +36,19 @@ CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y -CONFIG_CMD_BOOTM_ZLIB=y -CONFIG_CMD_BOOTM_BZLIB=y CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_LED_TRIGGER=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_NFS=y @@ -54,5 +61,14 @@ # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y +# CONFIG_NAND_ECC_HW is not set +# CONFIG_NAND_ECC_HW_SYNDROME is not set +# CONFIG_NAND_ECC_HW_NONE is not set CONFIG_NAND_ATMEL=y CONFIG_UBI=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DFU=y +CONFIG_USB_GADGET_SERIAL=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_TRIGGERS=y diff --git a/arch/arm/configs/usb_a9263_128mib_defconfig b/arch/arm/configs/usb_a9263_128mib_defconfig index 8d5342e..457b25c 100644 --- a/arch/arm/configs/usb_a9263_128mib_defconfig +++ b/arch/arm/configs/usb_a9263_128mib_defconfig @@ -1,10 +1,10 @@ CONFIG_ARCH_AT91SAM9263=y CONFIG_MACH_USB_A9263=y CONFIG_AEABI=y +# CONFIG_CMD_ARM_CPUINFO is not set CONFIG_AT91_HAVE_SRAM_128M=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y -CONFIG_MMU=y -CONFIG_KALLSYMS=y +CONFIG_EXPERIMENTAL=y CONFIG_PROMPT="USB-9G20:" CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -13,6 +13,8 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +# CONFIG_CONSOLE_ACTIVATE_FIRST is not set +CONFIG_CONSOLE_ACTIVATE_ALL=y CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/usb-a926x/env" @@ -35,14 +37,19 @@ CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y -CONFIG_CMD_BOOTM_ZLIB=y -CONFIG_CMD_BOOTM_BZLIB=y CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_LED_TRIGGER=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_NFS=y @@ -55,5 +62,14 @@ # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y +# CONFIG_NAND_ECC_HW is not set +# CONFIG_NAND_ECC_HW_SYNDROME is not set +# CONFIG_NAND_ECC_HW_NONE is not set CONFIG_NAND_ATMEL=y CONFIG_UBI=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DFU=y +CONFIG_USB_GADGET_SERIAL=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_TRIGGERS=y diff --git a/arch/arm/configs/usb_a9263_defconfig b/arch/arm/configs/usb_a9263_defconfig index 9f53431..6a7ded7 100644 --- a/arch/arm/configs/usb_a9263_defconfig +++ b/arch/arm/configs/usb_a9263_defconfig @@ -1,9 +1,9 @@ CONFIG_ARCH_AT91SAM9263=y CONFIG_MACH_USB_A9263=y CONFIG_AEABI=y +# CONFIG_CMD_ARM_CPUINFO is not set CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y -CONFIG_MMU=y -CONFIG_KALLSYMS=y +CONFIG_EXPERIMENTAL=y CONFIG_PROMPT="USB-9G20:" CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -12,6 +12,8 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +# CONFIG_CONSOLE_ACTIVATE_FIRST is not set +CONFIG_CONSOLE_ACTIVATE_ALL=y CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/usb-a926x/env" @@ -34,14 +36,19 @@ CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y -CONFIG_CMD_BOOTM_ZLIB=y -CONFIG_CMD_BOOTM_BZLIB=y CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_LED_TRIGGER=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_NFS=y @@ -54,5 +61,14 @@ # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y +# CONFIG_NAND_ECC_HW is not set +# CONFIG_NAND_ECC_HW_SYNDROME is not set +# CONFIG_NAND_ECC_HW_NONE is not set CONFIG_NAND_ATMEL=y CONFIG_UBI=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DFU=y +CONFIG_USB_GADGET_SERIAL=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_TRIGGERS=y diff --git a/arch/arm/configs/usb_a9g20_128mib_defconfig b/arch/arm/configs/usb_a9g20_128mib_defconfig index 3c0e6f7..3d44f39 100644 --- a/arch/arm/configs/usb_a9g20_128mib_defconfig +++ b/arch/arm/configs/usb_a9g20_128mib_defconfig @@ -1,10 +1,10 @@ CONFIG_ARCH_AT91SAM9G20=y CONFIG_MACH_USB_A9G20=y CONFIG_AEABI=y +# CONFIG_CMD_ARM_CPUINFO is not set CONFIG_AT91_HAVE_SRAM_128M=y CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y -CONFIG_MMU=y -CONFIG_KALLSYMS=y +CONFIG_EXPERIMENTAL=y CONFIG_PROMPT="USB-9G20:" CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -13,6 +13,8 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +# CONFIG_CONSOLE_ACTIVATE_FIRST is not set +CONFIG_CONSOLE_ACTIVATE_ALL=y CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/usb-a926x/env" @@ -35,14 +37,19 @@ CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y -CONFIG_CMD_BOOTM_ZLIB=y -CONFIG_CMD_BOOTM_BZLIB=y CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_LED_TRIGGER=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_NFS=y @@ -55,5 +62,14 @@ # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y +# CONFIG_NAND_ECC_HW is not set +# CONFIG_NAND_ECC_HW_SYNDROME is not set +# CONFIG_NAND_ECC_HW_NONE is not set CONFIG_NAND_ATMEL=y CONFIG_UBI=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DFU=y +CONFIG_USB_GADGET_SERIAL=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_TRIGGERS=y diff --git a/arch/arm/configs/usb_a9g20_defconfig b/arch/arm/configs/usb_a9g20_defconfig index 2bcb8eb..7abcd95 100644 --- a/arch/arm/configs/usb_a9g20_defconfig +++ b/arch/arm/configs/usb_a9g20_defconfig @@ -1,9 +1,9 @@ CONFIG_ARCH_AT91SAM9G20=y CONFIG_MACH_USB_A9G20=y CONFIG_AEABI=y +# CONFIG_CMD_ARM_CPUINFO is not set CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y -CONFIG_MMU=y -CONFIG_KALLSYMS=y +CONFIG_EXPERIMENTAL=y CONFIG_PROMPT="USB-9G20:" CONFIG_LONGHELP=y CONFIG_GLOB=y @@ -12,6 +12,8 @@ CONFIG_CMDLINE_EDITING=y CONFIG_AUTO_COMPLETE=y CONFIG_MENU=y +# CONFIG_CONSOLE_ACTIVATE_FIRST is not set +CONFIG_CONSOLE_ACTIVATE_ALL=y CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y CONFIG_DEFAULT_ENVIRONMENT_PATH="arch/arm/boards/usb-a926x/env" @@ -34,14 +36,19 @@ CONFIG_CMD_MTEST=y CONFIG_CMD_MTEST_ALTERNATIVE=y CONFIG_CMD_FLASH=y -CONFIG_CMD_BOOTM_ZLIB=y -CONFIG_CMD_BOOTM_BZLIB=y CONFIG_CMD_BOOTM_SHOW_TYPE=y +CONFIG_CMD_BOOTM_INITRD=y +CONFIG_CMD_UIMAGE=y +# CONFIG_CMD_BOOTZ is not set +# CONFIG_CMD_BOOTU is not set CONFIG_CMD_RESET=y CONFIG_CMD_GO=y +CONFIG_CMD_OFTREE=y CONFIG_CMD_TIMEOUT=y CONFIG_CMD_PARTITION=y CONFIG_CMD_GPIO=y +CONFIG_CMD_LED=y +CONFIG_CMD_LED_TRIGGER=y CONFIG_NET=y CONFIG_NET_DHCP=y CONFIG_NET_NFS=y @@ -54,5 +61,14 @@ # CONFIG_SPI is not set CONFIG_MTD=y CONFIG_NAND=y +# CONFIG_NAND_ECC_HW is not set +# CONFIG_NAND_ECC_HW_SYNDROME is not set +# CONFIG_NAND_ECC_HW_NONE is not set CONFIG_NAND_ATMEL=y CONFIG_UBI=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_DFU=y +CONFIG_USB_GADGET_SERIAL=y +CONFIG_LED=y +CONFIG_LED_GPIO=y +CONFIG_LED_TRIGGERS=y diff --git a/arch/arm/cpu/cache-armv7.S b/arch/arm/cpu/cache-armv7.S index 5b8491e..f25dcfa 100644 --- a/arch/arm/cpu/cache-armv7.S +++ b/arch/arm/cpu/cache-armv7.S @@ -84,8 +84,12 @@ loop2: mov r9, r4 @ create working copy of max way size loop3: - orr r11, r10, r9, lsl r5 @ factor way and cache number into r11 - orr r11, r11, r7, lsl r2 @ factor index number into r11 +ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11 +ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11 +THUMB( lsl r6, r9, r5 ) +THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11 +THUMB( lsl r6, r7, r2 ) +THUMB( orr r11, r11, r6 ) @ factor index number into r11 mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way subs r9, r9, #1 @ decrement the way bge loop3 diff --git a/arch/arm/cpu/cpu.c b/arch/arm/cpu/cpu.c index fc98844..cf31e8b 100644 --- a/arch/arm/cpu/cpu.c +++ b/arch/arm/cpu/cpu.c @@ -89,37 +89,3 @@ ); #endif } - -/** - * @page arm_boot_preparation Linux Preparation on ARM - * - * For ARM we never enable data cache so we do not need to disable it again. - * Linux can be called with instruction cache enabled. As this is the - * default setting we are running in barebox, there's no special preparation - * required. - */ -#ifdef CONFIG_COMMAND -static int do_icache(struct command *cmdtp, int argc, char *argv[]) -{ - if (argc == 1) { - printf("icache is %sabled\n", icache_status() ? "en" : "dis"); - return 0; - } - - if (simple_strtoul(argv[1], NULL, 0) > 0) - icache_enable(); - else - icache_disable(); - - return 0; -} - -static const __maybe_unused char cmd_icache_help[] = -"Usage: icache [0|1]\n"; - -BAREBOX_CMD_START(icache) - .cmd = do_icache, - .usage = "show/change icache status", - BAREBOX_CMD_HELP(cmd_icache_help) -BAREBOX_CMD_END -#endif diff --git a/arch/arm/cpu/cpuinfo.c b/arch/arm/cpu/cpuinfo.c index 05971b3..7be1671 100644 --- a/arch/arm/cpu/cpuinfo.c +++ b/arch/arm/cpu/cpuinfo.c @@ -47,8 +47,8 @@ } static char *crbits[] = {"M", "A", "C", "W", "P", "D", "L", "B", "S", "R", - "F", "Z", "I", "V", "RR", "L4", "", "", "", "", "", "FI", "U", "XP", - "VE", "EE", "L2"}; + "F", "Z", "I", "V", "RR", "L4", "DT", "", "IT", "ST", "", "FI", "U", "XP", + "VE", "EE", "L2", "", "TRE", "AFE", "TE"}; static int do_cpuinfo(struct command *cmdtp, int argc, char *argv[]) { @@ -170,7 +170,7 @@ } printf("Control register: "); - for (i = 0; i < 27; i++) + for (i = 0; i < ARRAY_SIZE(crbits); i++) if (cr & (1 << i)) printf("%s ", crbits[i]); printf("\n"); diff --git a/arch/arm/cpu/mmu.c b/arch/arm/cpu/mmu.c index 29e12b7..6d9b1e0 100644 --- a/arch/arm/cpu/mmu.c +++ b/arch/arm/cpu/mmu.c @@ -111,6 +111,18 @@ tlb_invalidate(); } +void *map_io_sections(unsigned long phys, void *_start, size_t size) +{ + unsigned long start = (unsigned long)_start, sec; + + phys >>= 20; + for (sec = start; sec < start + size; sec += (1 << 20)) + ttb[sec >> 20] = (phys++ << 20) | PMD_SECT_DEF_UNCACHED; + + tlb_invalidate(); + return _start; +} + /* * remap the memory bank described by mem cachable and * bufferable diff --git a/arch/arm/include/asm/armlinux.h b/arch/arm/include/asm/armlinux.h index ba3a424..9ca1e4b 100644 --- a/arch/arm/include/asm/armlinux.h +++ b/arch/arm/include/asm/armlinux.h @@ -29,6 +29,7 @@ struct image_data; -void start_linux(void *adr, int swap, struct image_data *data); +void start_linux(void *adr, int swap, unsigned long initrd_address, + unsigned long initrd_size, void *oftree); #endif /* __ARCH_ARMLINUX_H */ diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h index ab78be3..e0630eb 100644 --- a/arch/arm/include/asm/io.h +++ b/arch/arm/include/asm/io.h @@ -3,4 +3,11 @@ #include +/* + * String version of IO memory access ops: + */ +extern void memcpy_fromio(void *, const volatile void __iomem *, size_t); +extern void memcpy_toio(volatile void __iomem *, const void *, size_t); +extern void memset_io(volatile void __iomem *, int, size_t); + #endif /* __ASM_ARM_IO_H */ diff --git a/arch/arm/include/asm/mmu.h b/arch/arm/include/asm/mmu.h index 9ca5e2a..f5ae7a8 100644 --- a/arch/arm/include/asm/mmu.h +++ b/arch/arm/include/asm/mmu.h @@ -32,6 +32,7 @@ void dma_inv_range(unsigned long, unsigned long); unsigned long virt_to_phys(void *virt); void *phys_to_virt(unsigned long phys); +void *map_io_sections(unsigned long physaddr, void *start, size_t size); #else static inline void *dma_alloc_coherent(size_t size) @@ -66,6 +67,11 @@ { } +static inline void *map_io_sections(unsigned long phys, void *start, size_t size) +{ + return (void *)phys; +} + #endif #ifdef CONFIG_CACHE_L2X0 diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile index 9383ae1..27a4b88 100644 --- a/arch/arm/lib/Makefile +++ b/arch/arm/lib/Makefile @@ -5,6 +5,7 @@ obj-y += div0.o obj-y += findbit.o obj-y += arm.o +obj-y += io.o obj-y += io-readsb.o obj-y += io-readsw-armv4.o obj-y += io-readsl.o diff --git a/arch/arm/lib/armlinux.c b/arch/arm/lib/armlinux.c index bd9b72a..1d210d1 100644 --- a/arch/arm/lib/armlinux.c +++ b/arch/arm/lib/armlinux.c @@ -224,7 +224,8 @@ params->hdr.size = 0; } -static void setup_tags(struct image_data *data, int swap) +static void setup_tags(unsigned long initrd_address, + unsigned long initrd_size, int swap) { const char *commandline = getenv("bootargs"); @@ -232,8 +233,8 @@ setup_memory_tags(); setup_commandline_tag(commandline, swap); - if (data && (data->initrd_size > 0)) - setup_initrd_tag(data->initrd_address, data->initrd_size); + if (initrd_size) + setup_initrd_tag(initrd_address, initrd_size); setup_revision_tag(); setup_serial_tag(); @@ -249,17 +250,16 @@ armlinux_bootparams = params; } -void start_linux(void *adr, int swap, struct image_data *data) +void start_linux(void *adr, int swap, unsigned long initrd_address, + unsigned long initrd_size, void *oftree) { void (*kernel)(int zero, int arch, void *params) = adr; void *params = NULL; -#ifdef CONFIG_OFTREE - params = of_get_fixed_tree(); - if (params) + + if (oftree) { printf("booting Linux kernel with devicetree\n"); -#endif - if (!params) { - setup_tags(data, swap); + } else { + setup_tags(initrd_address, initrd_size, swap); params = armlinux_bootparams; } diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 031a269..defc89b 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include @@ -18,32 +20,224 @@ #include #include -static int do_bootm_linux(struct image_data *data) +static int __do_bootm_linux(struct image_data *data, int swap) { - void (*theKernel)(int zero, int arch, void *params); - image_header_t *os_header = &data->os->header; + unsigned long kernel; + unsigned long initrd_start = 0, initrd_size = 0; + struct memory_bank *bank; + unsigned long load_address; - theKernel = (void *)image_get_ep(os_header); + if (data->os_res) { + load_address = data->os_res->start; + } else if (data->os_address != UIMAGE_INVALID_ADDRESS) { + load_address = data->os_address; + } else { + bank = list_first_entry(&memory_banks, + struct memory_bank, list); + load_address = bank->start + SZ_32K; + if (bootm_verbose(data)) + printf("no os load address, defaulting to 0x%08lx\n", + load_address); + } - debug("## Transferring control to Linux (at address 0x%p) ...\n", - theKernel); + if (!data->os_res && data->os) { + data->os_res = uimage_load_to_sdram(data->os, + data->os_num, load_address); + if (!data->os_res) + return -ENOMEM; + } - /* we assume that the kernel is in place */ - printf("\nStarting kernel %s...\n\n", data->initrd ? "with initrd " : ""); + if (!data->os_res) { + data->os_res = file_to_sdram(data->os_file, load_address); + if (!data->os_res) + return -ENOMEM; + } - start_linux(theKernel, 0, data); + kernel = data->os_res->start + data->os_entry; - return -1; + if (data->initrd_file && data->initrd_address == UIMAGE_INVALID_ADDRESS) { + initrd_start = data->os_res->start + SZ_8M; + + if (bootm_verbose(data)) { + printf("no initrd load address, defaulting to 0x%08lx\n", + initrd_start); + } + } + + if (data->initrd) { + data->initrd_res = uimage_load_to_sdram(data->initrd, + data->initrd_num, initrd_start); + if (!data->initrd_res) + return -ENOMEM; + } else if (data->initrd_file) { + data->initrd_res = file_to_sdram(data->initrd_file, initrd_start); + if (!data->initrd_res) + return -ENOMEM; + } + + if (data->initrd_res) { + initrd_start = data->initrd_res->start; + initrd_size = data->initrd_res->size; + } + + if (bootm_verbose(data)) { + printf("\nStarting kernel at 0x%08lx", kernel); + if (initrd_size) + printf(", initrd at 0x%08lx", initrd_start); + if (data->oftree) + printf(", oftree at 0x%p", data->oftree); + printf("...\n"); + } + + start_linux((void *)kernel, swap, initrd_start, initrd_size, data->oftree); + + reset_cpu(0); + + return -ERESTARTSYS; } -static struct image_handler handler = { +static int do_bootm_linux(struct image_data *data) +{ + return __do_bootm_linux(data, 0); +} + +static struct image_handler uimage_handler = { + .name = "ARM Linux uImage", .bootm = do_bootm_linux, - .image_type = IH_OS_LINUX, + .filetype = filetype_uimage, + .ih_os = IH_OS_LINUX, +}; + +static struct image_handler rawimage_handler = { + .name = "ARM raw image", + .bootm = do_bootm_linux, + .filetype = filetype_unknown, +}; + +struct zimage_header { + u32 unused[9]; + u32 magic; + u32 start; + u32 end; +}; + +#define ZIMAGE_MAGIC 0x016F2818 + +static int do_bootz_linux(struct image_data *data) +{ + int fd, ret, swap = 0; + struct zimage_header __header, *header; + void *zimage; + u32 end; + unsigned long load_address = data->os_address; + + if (load_address == UIMAGE_INVALID_ADDRESS) { + struct memory_bank *bank = list_first_entry(&memory_banks, + struct memory_bank, list); + data->os_address = bank->start + SZ_8M; + load_address = data->os_address; + if (bootm_verbose(data)) + printf("no os load address, defaulting to 0x%08lx\n", + load_address); + } + + fd = open(data->os_file, O_RDONLY); + if (fd < 0) { + perror("open"); + return 1; + } + + header = &__header; + ret = read(fd, header, sizeof(*header)); + if (ret < sizeof(*header)) { + printf("could not read %s\n", data->os_file); + goto err_out; + } + + switch (header->magic) { + case swab32(ZIMAGE_MAGIC): + swap = 1; + /* fall through */ + case ZIMAGE_MAGIC: + break; + default: + printf("invalid magic 0x%08x\n", header->magic); + ret = -EINVAL; + goto err_out; + } + + end = header->end; + + if (swap) + end = swab32(end); + + data->os_res = request_sdram_region("zimage", load_address, end); + if (!data->os_res) { + ret = -ENOMEM; + goto err_out; + } + + zimage = (void *)data->os_res->start; + + memcpy(zimage, header, sizeof(*header)); + + ret = read_full(fd, zimage + sizeof(*header), end - sizeof(*header)); + if (ret < 0) + goto err_out; + if (ret < end - sizeof(*header)) { + printf("premature end of image\n"); + ret = -EIO; + goto err_out; + } + + if (swap) { + void *ptr; + for (ptr = zimage; ptr < zimage + end; ptr += 4) + *(u32 *)ptr = swab32(*(u32 *)ptr); + } + + return __do_bootm_linux(data, swap); + +err_out: + close(fd); + + return ret; +} + +static struct image_handler zimage_handler = { + .name = "ARM zImage", + .bootm = do_bootz_linux, + .filetype = filetype_arm_zimage, +}; + +static int do_bootm_barebox(struct image_data *data) +{ + void (*barebox)(void); + + barebox = read_file(data->os_file, NULL); + if (!barebox) + return -EINVAL; + + shutdown_barebox(); + + barebox(); + + reset_cpu(0); +} + +static struct image_handler barebox_handler = { + .name = "ARM barebox", + .bootm = do_bootm_barebox, + .filetype = filetype_arm_barebox, }; static int armlinux_register_image_handler(void) { - return register_image_handler(&handler); -} + register_image_handler(&barebox_handler); + register_image_handler(&uimage_handler); + register_image_handler(&rawimage_handler); + register_image_handler(&zimage_handler); + return 0; +} late_initcall(armlinux_register_image_handler); diff --git a/arch/arm/lib/bootu.c b/arch/arm/lib/bootu.c index e97ded0..89d793a 100644 --- a/arch/arm/lib/bootu.c +++ b/arch/arm/lib/bootu.c @@ -3,12 +3,14 @@ #include #include #include +#include #include static int do_bootu(struct command *cmdtp, int argc, char *argv[]) { int fd; void *kernel = NULL; + void *oftree = NULL; if (argc != 2) { barebox_cmd_usage(cmdtp); @@ -22,7 +24,11 @@ if (!kernel) kernel = (void *)simple_strtoul(argv[1], NULL, 0); - start_linux(kernel, 0, NULL); +#ifdef CONFIG_OFTREE + oftree = of_get_fixed_tree(); +#endif + + start_linux(kernel, 0, 0, 0, oftree); return 1; } diff --git a/arch/arm/lib/bootz.c b/arch/arm/lib/bootz.c index 956ea82..40facf6 100644 --- a/arch/arm/lib/bootz.c +++ b/arch/arm/lib/bootz.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -25,6 +26,7 @@ int fd, ret, swap = 0; struct zimage_header __header, *header; void *zimage; + void *oftree = NULL; u32 end; int usemap = 0; struct memory_bank *bank = list_first_entry(&memory_banks, struct memory_bank, list); @@ -105,8 +107,11 @@ } printf("loaded zImage from %s with size %d\n", argv[1], end); +#ifdef CONFIG_OFTREE + oftree = of_get_fixed_tree(); +#endif - start_linux(zimage, swap, NULL); + start_linux(zimage, swap, 0, 0, oftree); return 0; diff --git a/arch/arm/lib/copy_template.S b/arch/arm/lib/copy_template.S index 61b6e54..d8eb063 100644 --- a/arch/arm/lib/copy_template.S +++ b/arch/arm/lib/copy_template.S @@ -57,6 +57,13 @@ * * Restore registers with the values previously saved with the * 'preserv' macro. Called upon code termination. + * + * LDR1W_SHIFT + * STR1W_SHIFT + * + * Correction to be applied to the "ip" register when branching into + * the ldr1w or str1w instructions (some of these macros may expand to + * than one 32bit instruction in Thumb-2) */ @@ -99,9 +106,15 @@ 5: ands ip, r2, #28 rsb ip, ip, #32 +#if LDR1W_SHIFT > 0 + lsl ip, ip, #LDR1W_SHIFT +#endif addne pc, pc, ip @ C is always clear here b 7f -6: nop +6: + .rept (1 << LDR1W_SHIFT) + W(nop) + .endr ldr1w r1, r3, abort=20f ldr1w r1, r4, abort=20f ldr1w r1, r5, abort=20f @@ -110,9 +123,16 @@ ldr1w r1, r8, abort=20f ldr1w r1, lr, abort=20f +#if LDR1W_SHIFT < STR1W_SHIFT + lsl ip, ip, #STR1W_SHIFT - LDR1W_SHIFT +#elif LDR1W_SHIFT > STR1W_SHIFT + lsr ip, ip, #LDR1W_SHIFT - STR1W_SHIFT +#endif add pc, pc, ip nop - nop + .rept (1 << STR1W_SHIFT) + W(nop) + .endr str1w r0, r3, abort=20f str1w r0, r4, abort=20f str1w r0, r5, abort=20f diff --git a/arch/arm/lib/findbit.S b/arch/arm/lib/findbit.S index 7fa93a5..ef4caff 100644 --- a/arch/arm/lib/findbit.S +++ b/arch/arm/lib/findbit.S @@ -14,18 +14,22 @@ * also call with zero size. * Reworked by rmk. */ - .section .text.basic_bit_functions +#include +#include + .text /* * Purpose : Find a 'zero' bit * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit); */ - .globl _find_first_zero_bit_le; -_find_first_zero_bit_le: +ENTRY(_find_first_zero_bit_le) teq r1, #0 beq 3f mov r2, #0 -1: ldrb r3, [r0, r2, lsr #3] +1: + ARM( ldrb r3, [r0, r2, lsr #3] ) + THUMB( lsr r3, r2, #3 ) + THUMB( ldrb r3, [r0, r3] ) eors r3, r3, #0xff @ invert bits bne .L_found @ any now set - found zero bit add r2, r2, #8 @ next bit pointer @@ -33,36 +37,40 @@ blo 1b 3: mov r0, r1 @ no free bits mov pc, lr +ENDPROC(_find_first_zero_bit_le) /* * Purpose : Find next 'zero' bit - * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, - * int offset) + * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset) */ - .globl _find_next_zero_bit_le; -_find_next_zero_bit_le: +ENTRY(_find_next_zero_bit_le) teq r1, #0 beq 3b ands ip, r2, #7 beq 1b @ If new byte, goto old routine - ldrb r3, [r0, r2, lsr #3] + ARM( ldrb r3, [r0, r2, lsr #3] ) + THUMB( lsr r3, r2, #3 ) + THUMB( ldrb r3, [r0, r3] ) eor r3, r3, #0xff @ now looking for a 1 bit movs r3, r3, lsr ip @ shift off unused bits bne .L_found orr r2, r2, #7 @ if zero, then no bits here add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit +ENDPROC(_find_next_zero_bit_le) /* * Purpose : Find a 'one' bit - * Prototype: int find_first_bit(const unsigned long *addr, unsigned int maxbit) + * Prototype: int find_first_bit(const unsigned long *addr, unsigned int maxbit); */ - .globl _find_first_bit_le; -_find_first_bit_le: +ENTRY(_find_first_bit_le) teq r1, #0 beq 3f mov r2, #0 -1: ldrb r3, [r0, r2, lsr #3] +1: + ARM( ldrb r3, [r0, r2, lsr #3] ) + THUMB( lsr r3, r2, #3 ) + THUMB( ldrb r3, [r0, r3] ) movs r3, r3 bne .L_found @ any now set - found zero bit add r2, r2, #8 @ next bit pointer @@ -70,34 +78,37 @@ blo 1b 3: mov r0, r1 @ no free bits mov pc, lr +ENDPROC(_find_first_bit_le) /* * Purpose : Find next 'one' bit - * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, - * int offset) + * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset) */ - .globl _find_next_bit_le; -_find_next_bit_le: +ENTRY(_find_next_bit_le) teq r1, #0 beq 3b ands ip, r2, #7 beq 1b @ If new byte, goto old routine - ldrb r3, [r0, r2, lsr #3] + ARM( ldrb r3, [r0, r2, lsr #3] ) + THUMB( lsr r3, r2, #3 ) + THUMB( ldrb r3, [r0, r3] ) movs r3, r3, lsr ip @ shift off unused bits bne .L_found orr r2, r2, #7 @ if zero, then no bits here add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit +ENDPROC(_find_next_bit_le) #ifdef __ARMEB__ - .globl _find_first_zero_bit_be; -_find_first_zero_bit_be: +ENTRY(_find_first_zero_bit_be) teq r1, #0 beq 3f mov r2, #0 1: eor r3, r2, #0x18 @ big endian byte ordering - ldrb r3, [r0, r3, lsr #3] + ARM( ldrb r3, [r0, r3, lsr #3] ) + THUMB( lsr r3, #3 ) + THUMB( ldrb r3, [r0, r3] ) eors r3, r3, #0xff @ invert bits bne .L_found @ any now set - found zero bit add r2, r2, #8 @ next bit pointer @@ -105,29 +116,33 @@ blo 1b 3: mov r0, r1 @ no free bits mov pc, lr +ENDPROC(_find_first_zero_bit_be) - .globl _find_next_zero_bit_be; -_find_next_zero_bit_be: +ENTRY(_find_next_zero_bit_be) teq r1, #0 beq 3b ands ip, r2, #7 beq 1b @ If new byte, goto old routine eor r3, r2, #0x18 @ big endian byte ordering - ldrb r3, [r0, r3, lsr #3] + ARM( ldrb r3, [r0, r3, lsr #3] ) + THUMB( lsr r3, #3 ) + THUMB( ldrb r3, [r0, r3] ) eor r3, r3, #0xff @ now looking for a 1 bit movs r3, r3, lsr ip @ shift off unused bits bne .L_found orr r2, r2, #7 @ if zero, then no bits here add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit +ENDPROC(_find_next_zero_bit_be) - .globl _find_first_bit_be; -_find_first_bit_be: +ENTRY(_find_first_bit_be) teq r1, #0 beq 3f mov r2, #0 1: eor r3, r2, #0x18 @ big endian byte ordering - ldrb r3, [r0, r3, lsr #3] + ARM( ldrb r3, [r0, r3, lsr #3] ) + THUMB( lsr r3, #3 ) + THUMB( ldrb r3, [r0, r3] ) movs r3, r3 bne .L_found @ any now set - found zero bit add r2, r2, #8 @ next bit pointer @@ -135,20 +150,23 @@ blo 1b 3: mov r0, r1 @ no free bits mov pc, lr +ENDPROC(_find_first_bit_be) - .globl _find_next_bit_be; -_find_next_bit_be: +ENTRY(_find_next_bit_be) teq r1, #0 beq 3b ands ip, r2, #7 beq 1b @ If new byte, goto old routine eor r3, r2, #0x18 @ big endian byte ordering - ldrb r3, [r0, r3, lsr #3] + ARM( ldrb r3, [r0, r3, lsr #3] ) + THUMB( lsr r3, #3 ) + THUMB( ldrb r3, [r0, r3] ) movs r3, r3, lsr ip @ shift off unused bits bne .L_found orr r2, r2, #7 @ if zero, then no bits here add r2, r2, #1 @ align bit pointer b 2b @ loop for next bit +ENDPROC(_find_next_bit_be) #endif @@ -157,8 +175,8 @@ */ .L_found: #if __LINUX_ARM_ARCH__ >= 5 - rsb r1, r3, #0 - and r3, r3, r1 + rsb r0, r3, #0 + and r3, r3, r0 clz r3, r3 rsb r3, r3, #31 add r0, r2, r3 @@ -173,5 +191,7 @@ addeq r2, r2, #1 mov r0, r2 #endif + cmp r1, r0 @ Clamp to maxbit + movlo r0, r1 mov pc, lr diff --git a/arch/arm/lib/io-writesw-armv4.S b/arch/arm/lib/io-writesw-armv4.S index cd0aa7f..ff4f71b 100644 --- a/arch/arm/lib/io-writesw-armv4.S +++ b/arch/arm/lib/io-writesw-armv4.S @@ -22,8 +22,6 @@ #endif .endm -.section .text.writesw - .Loutsw_align: movs ip, r1, lsl #31 bne .Loutsw_noalign @@ -31,7 +29,7 @@ sub r2, r2, #1 strh r3, [r0] -ENTRY(writesw) +ENTRY(__raw_writesw) teq r2, #0 moveq pc, lr ands r3, r1, #3 @@ -77,7 +75,10 @@ #endif .Loutsw_noalign: - ldr r3, [r1, -r3]! + ARM( ldr r3, [r1, -r3]! ) + THUMB( rsb r3, r3, #0 ) + THUMB( ldr r3, [r1, r3] ) + THUMB( sub r1, r3 ) subcs r2, r2, #1 bcs 2f subs r2, r2, #2 @@ -96,4 +97,4 @@ 3: movne ip, r3, lsr #8 strneh ip, [r0] mov pc, lr -ENDPROC(writesw) +ENDPROC(__raw_writesw) diff --git a/arch/arm/lib/io.c b/arch/arm/lib/io.c new file mode 100644 index 0000000..abfd887 --- /dev/null +++ b/arch/arm/lib/io.c @@ -0,0 +1,50 @@ +#include +#include +#include + +/* + * Copy data from IO memory space to "real" memory space. + * This needs to be optimized. + */ +void memcpy_fromio(void *to, const volatile void __iomem *from, size_t count) +{ + unsigned char *t = to; + while (count) { + count--; + *t = readb(from); + t++; + from++; + } +} + +/* + * Copy data from "real" memory space to IO memory space. + * This needs to be optimized. + */ +void memcpy_toio(volatile void __iomem *to, const void *from, size_t count) +{ + const unsigned char *f = from; + while (count) { + count--; + writeb(*f, to); + f++; + to++; + } +} + +/* + * "memset" on IO memory space. + * This needs to be optimized. + */ +void memset_io(volatile void __iomem *dst, int c, size_t count) +{ + while (count) { + count--; + writeb(c, dst); + dst++; + } +} + +EXPORT_SYMBOL(memcpy_fromio); +EXPORT_SYMBOL(memcpy_toio); +EXPORT_SYMBOL(memset_io); diff --git a/arch/arm/lib/memcpy.S b/arch/arm/lib/memcpy.S index 513ed64..5123691 100644 --- a/arch/arm/lib/memcpy.S +++ b/arch/arm/lib/memcpy.S @@ -13,8 +13,11 @@ #include #include +#define LDR1W_SHIFT 0 +#define STR1W_SHIFT 0 + .macro ldr1w ptr reg abort - ldr \reg, [\ptr], #4 + W(ldr) \reg, [\ptr], #4 .endm .macro ldr4w ptr reg1 reg2 reg3 reg4 abort @@ -30,7 +33,7 @@ .endm .macro str1w ptr reg abort - str \reg, [\ptr], #4 + W(str) \reg, [\ptr], #4 .endm .macro str8w ptr reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 abort diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index b902eab..5e3fdeb 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -216,20 +216,16 @@ static struct at91_gpio_bank at91rm9200_gpio[] = { { - .id = AT91RM9200_ID_PIOA, - .offset = AT91_PIOA, + .regbase = IOMEM(AT91_BASE_PIOA), .clock = &pioA_clk, }, { - .id = AT91RM9200_ID_PIOB, - .offset = AT91_PIOB, + .regbase = IOMEM(AT91_BASE_PIOB), .clock = &pioB_clk, }, { - .id = AT91RM9200_ID_PIOC, - .offset = AT91_PIOC, + .regbase = IOMEM(AT91_BASE_PIOC), .clock = &pioC_clk, }, { - .id = AT91RM9200_ID_PIOD, - .offset = AT91_PIOD, + .regbase = IOMEM(AT91_BASE_PIOD), .clock = &pioD_clk, } }; diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index bd7d3f0..68bcffc 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -17,12 +17,15 @@ #include #include #include +#include #include "generic.h" void at91_add_device_sdram(u32 size) { arm_add_mem_device("ram0", AT91_CHIPSELECT_1, size); + add_mem_device("sram0", AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE, + IORESOURCE_MEM_WRITEABLE); } /* -------------------------------------------------------------------- @@ -42,6 +45,27 @@ void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {} #endif +/* -------------------------------------------------------------------- + * USB Device (Gadget) + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_USB_GADGET_DRIVER_AT91 +void __init at91_add_device_udc(struct at91_udc_data *data) +{ + if (data->vbus_pin > 0) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + } + + if (data->pullup_pin > 0) + at91_set_gpio_output(data->pullup_pin, 0); + + add_generic_device("at91_udc", -1, NULL, AT91RM9200_BASE_UDP, SZ_16K, + IORESOURCE_MEM, data); +} +#else +void __init at91_add_device_udc(struct at91_udc_data *data) {} +#endif /* -------------------------------------------------------------------- * Ethernet diff --git a/arch/arm/mach-at91/at91rm9200_lowlevel_init.c b/arch/arm/mach-at91/at91rm9200_lowlevel_init.c index 8d9ae08..dc54bcf 100644 --- a/arch/arm/mach-at91/at91rm9200_lowlevel_init.c +++ b/arch/arm/mach-at91/at91rm9200_lowlevel_init.c @@ -101,11 +101,11 @@ */ /* PIOC_ASR: Configure PIOC as peripheral (D16/D31) */ - at91_sys_write(AT91_PIOC + PIO_ASR, CONFIG_SYS_PIOC_ASR_VAL); + __raw_writel(CONFIG_SYS_PIOC_ASR_VAL, AT91_BASE_PIOC + PIO_ASR); /* PIOC_BSR */ - at91_sys_write(AT91_PIOC + PIO_BSR, CONFIG_SYS_PIOC_BSR_VAL); + __raw_writel(CONFIG_SYS_PIOC_BSR_VAL, AT91_BASE_PIOC + PIO_BSR); /* PIOC_PDR */ - at91_sys_write(AT91_PIOC + PIO_PDR, CONFIG_SYS_PIOC_PDR_VAL); + __raw_writel(CONFIG_SYS_PIOC_PDR_VAL, AT91_BASE_PIOC + PIO_PDR); /* EBI_CSA : CS1=SDRAM */ at91_sys_write(AT91_EBI_CSA, CONFIG_SYS_EBI_CSA_VAL); diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 3af5747..cf9e511 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -223,16 +223,13 @@ static struct at91_gpio_bank at91sam9260_gpio[] = { { - .id = AT91SAM9260_ID_PIOA, - .offset = AT91_PIOA, + .regbase = IOMEM(AT91_BASE_PIOA), .clock = &pioA_clk, }, { - .id = AT91SAM9260_ID_PIOB, - .offset = AT91_PIOB, + .regbase = IOMEM(AT91_BASE_PIOB), .clock = &pioB_clk, }, { - .id = AT91SAM9260_ID_PIOC, - .offset = AT91_PIOC, + .regbase = IOMEM(AT91_BASE_PIOC), .clock = &pioC_clk, } }; diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index be1fdd9..25a68ca 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -18,12 +18,24 @@ #include #include #include +#include #include "generic.h" void at91_add_device_sdram(u32 size) { arm_add_mem_device("ram0", AT91_CHIPSELECT_1, size); + if (cpu_is_at91sam9g20()) { + add_mem_device("sram0", AT91SAM9G20_SRAM0_BASE, + AT91SAM9G20_SRAM0_SIZE, IORESOURCE_MEM_WRITEABLE); + add_mem_device("sram1", AT91SAM9G20_SRAM1_BASE, + AT91SAM9G20_SRAM1_SIZE, IORESOURCE_MEM_WRITEABLE); + } else { + add_mem_device("sram0", AT91SAM9260_SRAM0_BASE, + AT91SAM9260_SRAM0_SIZE, IORESOURCE_MEM_WRITEABLE); + add_mem_device("sram1", AT91SAM9260_SRAM1_BASE, + AT91SAM9260_SRAM1_SIZE, IORESOURCE_MEM_WRITEABLE); + } } #if defined(CONFIG_USB_OHCI) @@ -39,6 +51,25 @@ void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {} #endif +/* -------------------------------------------------------------------- + * USB Device (Gadget) + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_USB_GADGET_DRIVER_AT91 +void __init at91_add_device_udc(struct at91_udc_data *data) +{ + if (data->vbus_pin > 0) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + } + + add_generic_device("at91_udc", -1, NULL, AT91SAM9260_BASE_UDP, SZ_16K, + IORESOURCE_MEM, data); +} +#else +void __init at91_add_device_udc(struct at91_udc_data *data) {} +#endif + #if defined(CONFIG_DRIVER_NET_MACB) void at91_add_device_eth(struct at91_ether_platform_data *data) { diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index b1e09ef..d20b250 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -216,16 +216,13 @@ static struct at91_gpio_bank at91sam9261_gpio[] = { { - .id = AT91SAM9261_ID_PIOA, - .offset = AT91_PIOA, + .regbase = IOMEM(AT91_BASE_PIOA), .clock = &pioA_clk, }, { - .id = AT91SAM9261_ID_PIOB, - .offset = AT91_PIOB, + .regbase = IOMEM(AT91_BASE_PIOB), .clock = &pioB_clk, }, { - .id = AT91SAM9261_ID_PIOC, - .offset = AT91_PIOC, + .regbase = IOMEM(AT91_BASE_PIOC), .clock = &pioC_clk, } }; diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 3f69b18..ff7a938 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -18,12 +18,19 @@ #include #include #include +#include #include "generic.h" void at91_add_device_sdram(u32 size) { arm_add_mem_device("ram0", AT91_CHIPSELECT_1, size); + if (cpu_is_at91sam9g10()) + add_mem_device("sram0", AT91SAM9G10_SRAM_BASE, + AT91SAM9G10_SRAM_SIZE, IORESOURCE_MEM_WRITEABLE); + else + add_mem_device("sram0", AT91SAM9261_SRAM_BASE, + AT91SAM9261_SRAM_SIZE, IORESOURCE_MEM_WRITEABLE); } /* -------------------------------------------------------------------- @@ -43,6 +50,25 @@ void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {} #endif +/* -------------------------------------------------------------------- + * USB Device (Gadget) + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_USB_GADGET_DRIVER_AT91 +void __init at91_add_device_udc(struct at91_udc_data *data) +{ + if (data->vbus_pin > 0) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + } + + add_generic_device("at91_udc", -1, NULL, AT91SAM9261_BASE_UDP, SZ_16K, + IORESOURCE_MEM, data); +} +#else +void __init at91_add_device_udc(struct at91_udc_data *data) {} +#endif + #if defined(CONFIG_NAND_ATMEL) void at91_add_device_nand(struct atmel_nand_data *data) { diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index eef7ad0..b3116d3 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -230,24 +230,19 @@ static struct at91_gpio_bank at91sam9263_gpio[] = { { - .id = AT91SAM9263_ID_PIOA, - .offset = AT91_PIOA, + .regbase = IOMEM(AT91_BASE_PIOA), .clock = &pioA_clk, }, { - .id = AT91SAM9263_ID_PIOB, - .offset = AT91_PIOB, + .regbase = IOMEM(AT91_BASE_PIOB), .clock = &pioB_clk, }, { - .id = AT91SAM9263_ID_PIOCDE, - .offset = AT91_PIOC, + .regbase = IOMEM(AT91_BASE_PIOC), .clock = &pioCDE_clk, }, { - .id = AT91SAM9263_ID_PIOCDE, - .offset = AT91_PIOD, + .regbase = IOMEM(AT91_BASE_PIOD), .clock = &pioCDE_clk, }, { - .id = AT91SAM9263_ID_PIOCDE, - .offset = AT91_PIOE, + .regbase = IOMEM(AT91_BASE_PIOE), .clock = &pioCDE_clk, } }; diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 994a975..d447e24 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -24,6 +24,10 @@ void at91_add_device_sdram(u32 size) { arm_add_mem_device("ram0", AT91_CHIPSELECT_1, size); + add_mem_device("sram0", AT91SAM9263_SRAM0_BASE, + AT91SAM9263_SRAM0_SIZE, IORESOURCE_MEM_WRITEABLE); + add_mem_device("sram1", AT91SAM9263_SRAM1_BASE, + AT91SAM9263_SRAM1_SIZE, IORESOURCE_MEM_WRITEABLE); } /* -------------------------------------------------------------------- @@ -51,6 +55,25 @@ void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {} #endif +/* -------------------------------------------------------------------- + * USB Device (Gadget) + * -------------------------------------------------------------------- */ + +#ifdef CONFIG_USB_GADGET_DRIVER_AT91 +void __init at91_add_device_udc(struct at91_udc_data *data) +{ + if (data->vbus_pin > 0) { + at91_set_gpio_input(data->vbus_pin, 0); + at91_set_deglitch(data->vbus_pin, 1); + } + + add_generic_device("at91_udc", -1, NULL, AT91SAM9263_BASE_UDP, SZ_16K, + IORESOURCE_MEM, data); +} +#else +void __init at91_add_device_udc(struct at91_udc_data *data) {} +#endif + #if defined(CONFIG_DRIVER_NET_MACB) void at91_add_device_eth(struct at91_ether_platform_data *data) { diff --git a/arch/arm/mach-at91/at91sam926x_lowlevel_init.S b/arch/arm/mach-at91/at91sam926x_lowlevel_init.S deleted file mode 100644 index 805b201..0000000 --- a/arch/arm/mach-at91/at91sam926x_lowlevel_init.S +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Memory Setup stuff - taken from blob memsetup.S - * - * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and - * Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) - * - * Copyright (C) 2008 Ronetix Ilko Iliev (www.ronetix.at) - * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD - * - * 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 - -_TEXT_BASE: - .word TEXT_BASE - -.globl board_init_lowlevel -.type board_init_lowlevel,function -board_init_lowlevel: - - mov r5, pc /* r5 = POS1 + 4 current */ -POS1: - ldr r0, =POS1 /* r0 = POS1 compile */ - ldr r2, _TEXT_BASE - sub r0, r0, r2 /* r0 = POS1-_TEXT_BASE (POS1 relative) */ - sub r5, r5, r0 /* r0 = TEXT_BASE-1 */ - sub r5, r5, #4 /* r1 = text base - current */ - - /* memory control configuration 1 */ - ldr r0, =SMRDATA - ldr r2, =SMRDATA1 - ldr r1, _TEXT_BASE - sub r0, r0, r1 - sub r2, r2, r1 - add r0, r0, r5 - add r2, r2, r5 -0: - /* the address */ - ldr r1, [r0], #4 - /* the value */ - ldr r3, [r0], #4 - str r3, [r1] - cmp r2, r0 - bne 0b - -/* ---------------------------------------------------------------------------- - * PMC Init Step 1. - * ---------------------------------------------------------------------------- - * - Check if the PLL is already initialized - * ---------------------------------------------------------------------------- - */ - ldr r1, =(AT91_BASE_SYS + AT91_PMC_MCKR) - ldr r0, [r1] - and r0, r0, #3 - cmp r0, #0 - bne PLL_setup_end - -/* --------------------------------------------------------------------------- - * - Enable the Main Oscillator - * --------------------------------------------------------------------------- - */ - ldr r1, =(AT91_BASE_SYS + AT91_CKGR_MOR) - ldr r2, =(AT91_BASE_SYS + AT91_PMC_SR) - /* Main oscillator Enable register PMC_MOR: */ - ldr r0, =CONFIG_SYS_MOR_VAL - str r0, [r1] - - /* Reading the PMC Status to detect when the Main Oscillator is enabled */ - mov r4, #AT91_PMC_MOSCS -MOSCS_Loop: - ldr r3, [r2] - and r3, r4, r3 - cmp r3, #AT91_PMC_MOSCS - bne MOSCS_Loop - -/* ---------------------------------------------------------------------------- - * PMC Init Step 2. - * ---------------------------------------------------------------------------- - * Setup PLLA - * ---------------------------------------------------------------------------- - */ - ldr r1, =(AT91_BASE_SYS + AT91_CKGR_PLLAR) - ldr r0, =CONFIG_SYS_PLLAR_VAL - str r0, [r1] - - /* Reading the PMC Status register to detect when the PLLA is locked */ - mov r4, #AT91_PMC_LOCKA -MOSCS_Loop1: - ldr r3, [r2] - and r3, r4, r3 - cmp r3, #AT91_PMC_LOCKA - bne MOSCS_Loop1 - -/* ---------------------------------------------------------------------------- - * PMC Init Step 3. - * ---------------------------------------------------------------------------- - * - Switch on the Main Oscillator - * ---------------------------------------------------------------------------- - */ - ldr r1, =(AT91_BASE_SYS + AT91_PMC_MCKR) - - /* -Master Clock Controller register PMC_MCKR */ - ldr r0, =CONFIG_SYS_MCKR1_VAL - str r0, [r1] - - /* Reading the PMC Status to detect when the Master clock is ready */ - mov r4, #AT91_PMC_MCKRDY -MCKRDY_Loop: - ldr r3, [r2] - and r3, r4, r3 - cmp r3, #AT91_PMC_MCKRDY - bne MCKRDY_Loop - - ldr r0, =CONFIG_SYS_MCKR2_VAL - str r0, [r1] - - /* Reading the PMC Status to detect when the Master clock is ready */ - mov r4, #AT91_PMC_MCKRDY -MCKRDY_Loop1: - ldr r3, [r2] - and r3, r4, r3 - cmp r3, #AT91_PMC_MCKRDY - bne MCKRDY_Loop1 - -PLL_setup_end: - -/* ---------------------------------------------------------------------------- - * - memory control configuration 2 - * ---------------------------------------------------------------------------- - */ - ldr r0, =(AT91_BASE_SYS + AT91_SDRAMC_TR) - ldr r1, [r0] - cmp r1, #0 - bne SDRAM_setup_end - - ldr r0, =SMRDATA1 - ldr r2, =SMRDATA2 - ldr r1, _TEXT_BASE - sub r0, r0, r1 - sub r2, r2, r1 - add r0, r0, r5 - add r2, r2, r5 - -2: - /* the address */ - ldr r1, [r0], #4 - /* the value */ - ldr r3, [r0], #4 - str r3, [r1] - cmp r2, r0 - bne 2b - -SDRAM_setup_end: - /* everything is fine now */ - mov pc, lr - - .ltorg - -SMRDATA: - .word (AT91_BASE_SYS + AT91_WDT_MR) - .word CONFIG_SYS_WDTC_WDMR_VAL - - /* configure PIOx as EBI0 D[16-31] */ -#if defined(CONFIG_ARCH_AT91SAM9263) - .word (AT91_BASE_SYS + AT91_PIOD + PIO_PDR) - .word CONFIG_SYS_PIOD_PDR_VAL1 - .word (AT91_BASE_SYS + AT91_PIOD + PIO_PUDR) - .word CONFIG_SYS_PIOD_PPUDR_VAL - .word (AT91_BASE_SYS + AT91_PIOD + PIO_ASR) - .word CONFIG_SYS_PIOD_PPUDR_VAL -#elif defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9261) \ - || defined(CONFIG_ARCH_AT91SAM9G20) || defined(CONFIG_ARCH_AT91SAM9G10) - .word (AT91_BASE_SYS + AT91_PIOC + PIO_PDR) - .word CONFIG_SYS_PIOC_PDR_VAL1 - .word (AT91_BASE_SYS + AT91_PIOC + PIO_PUDR) - .word CONFIG_SYS_PIOC_PPUDR_VAL -#endif - -#if defined(AT91_MATRIX_EBI0CSA) - .word (AT91_BASE_SYS + AT91_MATRIX_EBI0CSA) - .word CONFIG_SYS_MATRIX_EBI0CSA_VAL -#else /* AT91_MATRIX_EBICSA */ - .word (AT91_BASE_SYS + AT91_MATRIX_EBICSA) - .word CONFIG_SYS_MATRIX_EBICSA_VAL -#endif - - /* flash */ - .word (AT91_BASE_SYS + AT91_SMC_MODE(0)) - .word CONFIG_SYS_SMC0_MODE0_VAL - - .word (AT91_BASE_SYS + AT91_SMC_CYCLE(0)) - .word CONFIG_SYS_SMC0_CYCLE0_VAL - - .word (AT91_BASE_SYS + AT91_SMC_PULSE(0)) - .word CONFIG_SYS_SMC0_PULSE0_VAL - - .word (AT91_BASE_SYS + AT91_SMC_SETUP(0)) - .word CONFIG_SYS_SMC0_SETUP0_VAL - -SMRDATA1: - .word (AT91_BASE_SYS + AT91_SDRAMC_MR) - .word CONFIG_SYS_SDRC_MR_VAL1 - .word (AT91_BASE_SYS + AT91_SDRAMC_TR) - .word CONFIG_SYS_SDRC_TR_VAL1 - .word (AT91_BASE_SYS + AT91_SDRAMC_CR) - .word CONFIG_SYS_SDRC_CR_VAL - .word (AT91_BASE_SYS + AT91_SDRAMC_MDR) - .word CONFIG_SYS_SDRC_MDR_VAL - .word (AT91_BASE_SYS + AT91_SDRAMC_MR) - .word CONFIG_SYS_SDRC_MR_VAL2 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL1 - .word (AT91_BASE_SYS + AT91_SDRAMC_MR) - .word CONFIG_SYS_SDRC_MR_VAL3 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL2 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL3 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL4 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL5 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL6 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL7 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL8 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL9 - .word (AT91_BASE_SYS + AT91_SDRAMC_MR) - .word CONFIG_SYS_SDRC_MR_VAL4 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL10 - .word (AT91_BASE_SYS + AT91_SDRAMC_MR) - .word CONFIG_SYS_SDRC_MR_VAL5 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL11 - .word (AT91_BASE_SYS + AT91_SDRAMC_TR) - .word CONFIG_SYS_SDRC_TR_VAL2 - .word AT91_SDRAM_BASE - .word CONFIG_SYS_SDRAM_VAL12 - /* User reset enable*/ - .word (AT91_BASE_SYS + AT91_RSTC_MR) - .word CONFIG_SYS_RSTC_RMR_VAL -#ifdef CONFIG_SYS_MATRIX_MCFG_REMAP - /* MATRIX_MCFG - REMAP all masters */ - .word (AT91_BASE_SYS + AT91_MATRIX_MCFG0) - .word 0x1FF -#endif - -SMRDATA2: - .word 0 diff --git a/arch/arm/mach-at91/at91sam926x_lowlevel_init.c b/arch/arm/mach-at91/at91sam926x_lowlevel_init.c new file mode 100644 index 0000000..211074c --- /dev/null +++ b/arch/arm/mach-at91/at91sam926x_lowlevel_init.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2008 Ronetix Ilko Iliev (www.ronetix.at) + * Copyright (C) 2009-2011 Jean-Christophe PLAGNIOL-VILLARD + * + * Under GPLv2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void inline access_sdram(void) +{ + writel(0x00000000, AT91_SDRAM_BASE); +} + +static void inline pmc_check_mckrdy(void) +{ + u32 r; + + do { + r = at91_sys_read(AT91_PMC_SR); + } while (!(r & AT91_PMC_MCKRDY)); +} + +void __naked __bare_init board_init_lowlevel(void) +{ + u32 r; + int i; + + at91_sys_write(AT91_WDT_MR, CONFIG_SYS_WDTC_WDMR_VAL); + + /* configure PIOx as EBI0 D[16-31] */ +#ifdef CONFIG_ARCH_AT91SAM9263 + __raw_writel(CONFIG_SYS_PIOD_PDR_VAL1, AT91_BASE_PIOD + PIO_PDR); + __raw_writel(CONFIG_SYS_PIOD_PPUDR_VAL, AT91_BASE_PIOD + PIO_PUDR); + __raw_writel(CONFIG_SYS_PIOD_PPUDR_VAL, AT91_BASE_PIOD + PIO_ASR); +#else + __raw_writel(CONFIG_SYS_PIOC_PDR_VAL1, AT91_BASE_PIOC + PIO_PDR); + __raw_writel(CONFIG_SYS_PIOC_PPUDR_VAL, AT91_BASE_PIOC + PIO_PUDR); +#endif + +#if defined(AT91_MATRIX_EBI0CSA) + at91_sys_write(AT91_MATRIX_EBI0CSA, CONFIG_SYS_MATRIX_EBI0CSA_VAL); +#else /* AT91_MATRIX_EBICSA */ + at91_sys_write(AT91_MATRIX_EBICSA, CONFIG_SYS_MATRIX_EBICSA_VAL); +#endif + + /* flash */ + at91_sys_write(AT91_SMC_MODE(0), CONFIG_SYS_SMC0_MODE0_VAL); + + at91_sys_write(AT91_SMC_CYCLE(0), CONFIG_SYS_SMC0_CYCLE0_VAL); + + at91_sys_write(AT91_SMC_PULSE(0), CONFIG_SYS_SMC0_PULSE0_VAL); + + at91_sys_write(AT91_SMC_SETUP(0), CONFIG_SYS_SMC0_SETUP0_VAL); + + /* + * PMC Check if the PLL is already initialized + */ + r = at91_sys_read(AT91_PMC_MCKR); + if (r & AT91_PMC_CSS) + goto end; + + /* + * Enable the Main Oscillator + */ + at91_sys_write(AT91_CKGR_MOR, CONFIG_SYS_MOR_VAL); + + do { + r = at91_sys_read(AT91_PMC_SR); + } while (!(r & AT91_PMC_MOSCS)); + + /* + * PLLAR: x MHz for PCK + */ + at91_sys_write(AT91_CKGR_PLLAR, CONFIG_SYS_PLLAR_VAL); + + do { + r = at91_sys_read(AT91_PMC_SR); + } while (!(r & AT91_PMC_LOCKA)); + + /* + * PCK/x = MCK Master Clock from SLOW + */ + at91_sys_write(AT91_PMC_MCKR, CONFIG_SYS_MCKR1_VAL); + + pmc_check_mckrdy(); + + /* + * PCK/x = MCK Master Clock from PLLA + */ + at91_sys_write(AT91_PMC_MCKR, CONFIG_SYS_MCKR2_VAL); + + pmc_check_mckrdy(); + + /* + * Init SDRAM + */ + + /* + * SDRAMC Check if Refresh Timer Counter is already initialized + */ + r = at91_sys_read(AT91_SDRAMC_TR); + if (r) + goto end; + + /* SDRAMC_MR : Normal Mode */ + at91_sys_write(AT91_SDRAMC_MR, AT91_SDRAMC_MODE_NORMAL); + + /* SDRAMC_TR - Refresh Timer register */ + at91_sys_write(AT91_SDRAMC_TR, CONFIG_SYS_SDRC_TR_VAL1); + + /* SDRAMC_CR - Configuration register*/ + at91_sys_write(AT91_SDRAMC_CR, CONFIG_SYS_SDRC_CR_VAL); + + /* Memory Device Type */ + at91_sys_write(AT91_SDRAMC_MDR, CONFIG_SYS_SDRC_MDR_VAL); + + /* SDRAMC_MR : Precharge All */ + at91_sys_write(AT91_SDRAMC_MR, AT91_SDRAMC_MODE_PRECHARGE); + + /* access SDRAM */ + access_sdram(); + + /* SDRAMC_MR : refresh */ + at91_sys_write(AT91_SDRAMC_MR, AT91_SDRAMC_MODE_REFRESH); + + /* access SDRAM 8 times */ + for (i = 0; i < 8; i++) + access_sdram(); + + /* SDRAMC_MR : Load Mode Register */ + at91_sys_write(AT91_SDRAMC_MR, AT91_SDRAMC_MODE_LMR); + + /* access SDRAM */ + access_sdram(); + + /* SDRAMC_MR : Normal Mode */ + at91_sys_write(AT91_SDRAMC_MR, AT91_SDRAMC_MODE_NORMAL); + + /* access SDRAM */ + access_sdram(); + + /* SDRAMC_TR : Refresh Timer Counter */ + at91_sys_write(AT91_SDRAMC_TR, CONFIG_SYS_SDRC_TR_VAL2); + + /* access SDRAM */ + access_sdram(); + + /* User reset enable*/ + at91_sys_write(AT91_RSTC_MR, CONFIG_SYS_RSTC_RMR_VAL); + +#ifdef CONFIG_SYS_MATRIX_MCFG_REMAP + /* MATRIX_MCFG - REMAP all masters */ + at91_sys_write(AT91_MATRIX_MCFG0, 0x1FF); +#endif + +end: + board_init_lowlevel_return(); +} diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 6b9fbc5..a6717f1 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -242,24 +242,19 @@ static struct at91_gpio_bank at91sam9g45_gpio[] = { { - .id = AT91SAM9G45_ID_PIOA, - .offset = AT91_PIOA, + .regbase = IOMEM(AT91_BASE_PIOA), .clock = &pioA_clk, }, { - .id = AT91SAM9G45_ID_PIOB, - .offset = AT91_PIOB, + .regbase = IOMEM(AT91_BASE_PIOB), .clock = &pioB_clk, }, { - .id = AT91SAM9G45_ID_PIOC, - .offset = AT91_PIOC, + .regbase = IOMEM(AT91_BASE_PIOC), .clock = &pioC_clk, }, { - .id = AT91SAM9G45_ID_PIODE, - .offset = AT91_PIOD, + .regbase = IOMEM(AT91_BASE_PIOD), .clock = &pioDE_clk, }, { - .id = AT91SAM9G45_ID_PIODE, - .offset = AT91_PIOE, + .regbase = IOMEM(AT91_BASE_PIOE), .clock = &pioDE_clk, } }; diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 1d47dcf..5f1a45a 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -24,6 +24,8 @@ void at91_add_device_sdram(u32 size) { arm_add_mem_device("ram0", AT91_CHIPSELECT_6, size); + add_mem_device("sram0", AT91SAM9G45_SRAM_BASE, + AT91SAM9G45_SRAM_SIZE, IORESOURCE_MEM_WRITEABLE); } /* -------------------------------------------------------------------- diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c index c34df05..06da5af 100644 --- a/arch/arm/mach-at91/gpio.c +++ b/arch/arm/mach-at91/gpio.c @@ -235,23 +235,14 @@ int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks) { - unsigned i; - struct at91_gpio_bank *last; + unsigned i; gpio = data; gpio_banks = nr_banks; - for (i = 0, last = NULL; i < nr_banks; i++, last = data, data++) { - data->chipbase = PIN_BASE + i * 32; - data->regbase = data->offset + - (void __iomem *)AT91_BASE_SYS; - + for (i = 0; i < nr_banks; i++, data++) { /* enable PIO controller's clock */ clk_enable(data->clock); - - /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */ - if (last && last->id == data->id) - last->next = data; } return 0; diff --git a/arch/arm/mach-at91/include/mach/at91rm9200.h b/arch/arm/mach-at91/include/mach/at91rm9200.h index 985977f..39b1e15 100644 --- a/arch/arm/mach-at91/include/mach/at91rm9200.h +++ b/arch/arm/mach-at91/include/mach/at91rm9200.h @@ -84,15 +84,16 @@ */ #define AT91_AIC (0xfffff000 - AT91_BASE_SYS) /* Advanced Interrupt Controller */ #define AT91_DBGU (0xfffff200 - AT91_BASE_SYS) /* Debug Unit */ -#define AT91_PIOA (0xfffff400 - AT91_BASE_SYS) /* PIO Controller A */ -#define AT91_PIOB (0xfffff600 - AT91_BASE_SYS) /* PIO Controller B */ -#define AT91_PIOC (0xfffff800 - AT91_BASE_SYS) /* PIO Controller C */ -#define AT91_PIOD (0xfffffa00 - AT91_BASE_SYS) /* PIO Controller D */ #define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) /* Power Management Controller */ #define AT91_ST (0xfffffd00 - AT91_BASE_SYS) /* System Timer */ #define AT91_RTC (0xfffffe00 - AT91_BASE_SYS) /* Real-Time Clock */ #define AT91_MC (0xffffff00 - AT91_BASE_SYS) /* Memory Controllers */ +#define AT91_BASE_PIOA 0xfffff400 /* PIO Controller A */ +#define AT91_BASE_PIOB 0xfffff600 /* PIO Controller B */ +#define AT91_BASE_PIOC 0xfffff800 /* PIO Controller C */ +#define AT91_BASE_PIOD 0xfffffa00 /* PIO Controller D */ + #define AT91_USART0 AT91RM9200_BASE_US0 #define AT91_USART1 AT91RM9200_BASE_US1 #define AT91_USART2 AT91RM9200_BASE_US2 diff --git a/arch/arm/mach-at91/include/mach/at91sam9260.h b/arch/arm/mach-at91/include/mach/at91sam9260.h index 7d166b7..72dc931 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9260.h +++ b/arch/arm/mach-at91/include/mach/at91sam9260.h @@ -87,9 +87,6 @@ #define AT91_CCFG (0xffffef10 - AT91_BASE_SYS) #define AT91_AIC (0xfffff000 - AT91_BASE_SYS) #define AT91_DBGU (0xfffff200 - AT91_BASE_SYS) -#define AT91_PIOA (0xfffff400 - AT91_BASE_SYS) -#define AT91_PIOB (0xfffff600 - AT91_BASE_SYS) -#define AT91_PIOC (0xfffff800 - AT91_BASE_SYS) #define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) #define AT91_RSTC (0xfffffd00 - AT91_BASE_SYS) #define AT91_SHDWC (0xfffffd10 - AT91_BASE_SYS) @@ -98,6 +95,10 @@ #define AT91_WDT (0xfffffd40 - AT91_BASE_SYS) #define AT91_GPBR (0xfffffd50 - AT91_BASE_SYS) +#define AT91_BASE_PIOA 0xfffff400 +#define AT91_BASE_PIOB 0xfffff600 +#define AT91_BASE_PIOC 0xfffff800 + #define AT91_USART0 AT91SAM9260_BASE_US0 #define AT91_USART1 AT91SAM9260_BASE_US1 #define AT91_USART2 AT91SAM9260_BASE_US2 @@ -126,6 +127,16 @@ #define AT91SAM9XE_FLASH_BASE 0x00200000 /* Internal FLASH base address */ #define AT91SAM9XE_SRAM_BASE 0x00300000 /* Internal SRAM base address */ +#define AT91SAM9G20_ROM_BASE 0x00100000 /* Internal ROM base address */ +#define AT91SAM9G20_ROM_SIZE SZ_32K /* Internal ROM size (32Kb) */ + +#define AT91SAM9G20_SRAM0_BASE 0x00200000 /* Internal SRAM 0 base address */ +#define AT91SAM9G20_SRAM0_SIZE SZ_16K /* Internal SRAM 0 size (16Kb) */ +#define AT91SAM9G20_SRAM1_BASE 0x00300000 /* Internal SRAM 1 base address */ +#define AT91SAM9G20_SRAM1_SIZE SZ_16K /* Internal SRAM 1 size (16Kb) */ + +#define AT91SAM9G20_UHP_BASE 0x00500000 /* USB Host controller */ + /* * Cpu Name */ diff --git a/arch/arm/mach-at91/include/mach/at91sam9261.h b/arch/arm/mach-at91/include/mach/at91sam9261.h index b303e07..3be8087 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9261.h +++ b/arch/arm/mach-at91/include/mach/at91sam9261.h @@ -73,9 +73,6 @@ #define AT91_MATRIX (0xffffee00 - AT91_BASE_SYS) #define AT91_AIC (0xfffff000 - AT91_BASE_SYS) #define AT91_DBGU (0xfffff200 - AT91_BASE_SYS) -#define AT91_PIOA (0xfffff400 - AT91_BASE_SYS) -#define AT91_PIOB (0xfffff600 - AT91_BASE_SYS) -#define AT91_PIOC (0xfffff800 - AT91_BASE_SYS) #define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) #define AT91_RSTC (0xfffffd00 - AT91_BASE_SYS) #define AT91_SHDWC (0xfffffd10 - AT91_BASE_SYS) @@ -84,6 +81,10 @@ #define AT91_WDT (0xfffffd40 - AT91_BASE_SYS) #define AT91_GPBR (0xfffffd50 - AT91_BASE_SYS) +#define AT91_BASE_PIOA 0xfffff400 +#define AT91_BASE_PIOB 0xfffff600 +#define AT91_BASE_PIOC 0xfffff800 + #define AT91_USART0 AT91SAM9261_BASE_US0 #define AT91_USART1 AT91SAM9261_BASE_US1 #define AT91_USART2 AT91SAM9261_BASE_US2 @@ -95,6 +96,9 @@ #define AT91SAM9261_SRAM_BASE 0x00300000 /* Internal SRAM base address */ #define AT91SAM9261_SRAM_SIZE 0x00028000 /* Internal SRAM size (160Kb) */ +#define AT91SAM9G10_SRAM_BASE AT91SAM9261_SRAM_BASE /* Internal SRAM base address */ +#define AT91SAM9G10_SRAM_SIZE 0x00004000 /* Internal SRAM size (16Kb) */ + #define AT91SAM9261_ROM_BASE 0x00400000 /* Internal ROM base address */ #define AT91SAM9261_ROM_SIZE SZ_32K /* Internal ROM size (32Kb) */ diff --git a/arch/arm/mach-at91/include/mach/at91sam9263.h b/arch/arm/mach-at91/include/mach/at91sam9263.h index 7bab1a4..64f4fcc 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9263.h +++ b/arch/arm/mach-at91/include/mach/at91sam9263.h @@ -87,11 +87,6 @@ #define AT91_CCFG (0xffffed10 - AT91_BASE_SYS) #define AT91_DBGU (0xffffee00 - AT91_BASE_SYS) #define AT91_AIC (0xfffff000 - AT91_BASE_SYS) -#define AT91_PIOA (0xfffff200 - AT91_BASE_SYS) -#define AT91_PIOB (0xfffff400 - AT91_BASE_SYS) -#define AT91_PIOC (0xfffff600 - AT91_BASE_SYS) -#define AT91_PIOD (0xfffff800 - AT91_BASE_SYS) -#define AT91_PIOE (0xfffffa00 - AT91_BASE_SYS) #define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) #define AT91_RSTC (0xfffffd00 - AT91_BASE_SYS) #define AT91_SHDWC (0xfffffd10 - AT91_BASE_SYS) @@ -101,6 +96,12 @@ #define AT91_RTT1 (0xfffffd50 - AT91_BASE_SYS) #define AT91_GPBR (0xfffffd60 - AT91_BASE_SYS) +#define AT91_BASE_PIOA 0xfffff200 +#define AT91_BASE_PIOB 0xfffff400 +#define AT91_BASE_PIOC 0xfffff600 +#define AT91_BASE_PIOD 0xfffff800 +#define AT91_BASE_PIOE 0xfffffa00 + #define AT91_USART0 AT91SAM9263_BASE_US0 #define AT91_USART1 AT91SAM9263_BASE_US1 #define AT91_USART2 AT91SAM9263_BASE_US2 diff --git a/arch/arm/mach-at91/include/mach/at91sam9g45.h b/arch/arm/mach-at91/include/mach/at91sam9g45.h index c5c7f49..18fa6c5 100644 --- a/arch/arm/mach-at91/include/mach/at91sam9g45.h +++ b/arch/arm/mach-at91/include/mach/at91sam9g45.h @@ -97,11 +97,6 @@ #define AT91_DMA (0xffffec00 - AT91_BASE_SYS) #define AT91_DBGU (0xffffee00 - AT91_BASE_SYS) #define AT91_AIC (0xfffff000 - AT91_BASE_SYS) -#define AT91_PIOA (0xfffff200 - AT91_BASE_SYS) -#define AT91_PIOB (0xfffff400 - AT91_BASE_SYS) -#define AT91_PIOC (0xfffff600 - AT91_BASE_SYS) -#define AT91_PIOD (0xfffff800 - AT91_BASE_SYS) -#define AT91_PIOE (0xfffffa00 - AT91_BASE_SYS) #define AT91_PMC (0xfffffc00 - AT91_BASE_SYS) #define AT91_RSTC (0xfffffd00 - AT91_BASE_SYS) #define AT91_SHDWC (0xfffffd10 - AT91_BASE_SYS) @@ -111,6 +106,12 @@ #define AT91_GPBR (0xfffffd60 - AT91_BASE_SYS) #define AT91_RTC (0xfffffdb0 - AT91_BASE_SYS) +#define AT91_BASE_PIOA 0xfffff200 +#define AT91_BASE_PIOB 0xfffff400 +#define AT91_BASE_PIOC 0xfffff600 +#define AT91_BASE_PIOD 0xfffff800 +#define AT91_BASE_PIOE 0xfffffa00 + #define AT91_USART0 AT91SAM9G45_BASE_US0 #define AT91_USART1 AT91SAM9G45_BASE_US1 #define AT91_USART2 AT91SAM9G45_BASE_US2 diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h index daeadbb..2619234 100644 --- a/arch/arm/mach-at91/include/mach/board.h +++ b/arch/arm/mach-at91/include/mach/board.h @@ -34,6 +34,16 @@ void atmel_nand_load_image(void *dest, int size, int pagesize, int blocksize); + /* USB Device */ +struct at91_udc_data { + int vbus_pin; /* high == host powering us */ + u8 vbus_active_low; /* vbus polarity */ + u8 vbus_polled; /* Use polling, not interrupt */ + int pullup_pin; /* active == D+ pulled up */ + u8 pullup_active_low; /* true == pullup_pin is active low */ +}; +extern void __init at91_add_device_udc(struct at91_udc_data *data); + /* NAND / SmartMedia */ struct atmel_nand_data { u8 enable_pin; /* chip enable */ diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h index f3239f5..95a4bd4 100644 --- a/arch/arm/mach-at91/include/mach/gpio.h +++ b/arch/arm/mach-at91/include/mach/gpio.h @@ -236,11 +236,7 @@ int at91_get_gpio_value(unsigned pin); struct at91_gpio_bank { - unsigned chipbase; /* bank's first GPIO number */ void __iomem *regbase; /* base of register bank */ - struct at91_gpio_bank *next; /* bank sharing same IRQ/clock/... */ - unsigned short id; /* peripheral ID */ - unsigned long offset; /* offset from system peripheral base */ struct clk *clock; }; diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index 27bf386..7da39cb 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -372,11 +372,9 @@ config MACH_FREESCALE_MX51_PDK bool "Freescale i.MX51 PDK" - select MACH_HAS_LOWLEVEL_INIT config MACH_EUKREA_CPUIMX51SD bool "EUKREA CPUIMX51" - select MACH_HAS_LOWLEVEL_INIT help Say Y here if you are using Eukrea's CPUIMX51 equipped with a Freescale i.MX51 Processor diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index 0b3b781..a9aa9e2 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -5,8 +5,8 @@ obj-$(CONFIG_ARCH_IMX27) += speed-imx27.o imx27.o iomux-v1.o obj-$(CONFIG_ARCH_IMX31) += speed-imx31.o imx31.o iomux-v2.o obj-$(CONFIG_ARCH_IMX35) += speed-imx35.o imx35.o iomux-v3.o -obj-$(CONFIG_ARCH_IMX51) += speed-imx51.o imx51.o iomux-v3.o -obj-$(CONFIG_ARCH_IMX53) += speed-imx53.o imx53.o iomux-v3.o +obj-$(CONFIG_ARCH_IMX51) += speed-imx51.o imx51.o iomux-v3.o imx5.o +obj-$(CONFIG_ARCH_IMX53) += speed-imx53.o imx53.o iomux-v3.o imx5.o obj-$(CONFIG_IMX_CLKO) += clko.o obj-$(CONFIG_IMX_IIM) += iim.o obj-$(CONFIG_NAND_IMX) += nand.o diff --git a/arch/arm/mach-imx/imx27.c b/arch/arm/mach-imx/imx27.c index 86039c4..1af291d 100644 --- a/arch/arm/mach-imx/imx27.c +++ b/arch/arm/mach-imx/imx27.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "gpio.h" @@ -38,11 +39,53 @@ int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32; +/* + * Initialize MAX on i.MX27. necessary to give the DMA engine + * higher priority to the memory than the CPU. Needed for proper + * audio support + */ +#define MAX_SLAVE_MPR_OFFSET 0x0 /* Master Priority register */ +#define MAX_SLAVE_AMPR_OFFSET 0x4 /* Alternate Master Priority register */ +#define MAX_SLAVE_PORT0_OFFSET 0x0 +#define MAX_SLAVE_PORT1_OFFSET 0x100 +#define MAX_SLAVE_PORT2_OFFSET 0x200 +#define MAX_MASTER_PRIO(master, prio) (((prio) << (master) * 4)) + +#define MASTER_IAHB 0 +#define MASTER_DAHB 1 +#define MASTER_EMMA 2 +#define MASTER_DMA 3 +#define MASTER_SLDC 4 +#define MASTER_CODEC 5 + +static void imx27_init_max(void) +{ + void __iomem *max_base = (void *)IMX_MAX_BASE; + u32 val; + + /* 0 is the highest priority */ + val = MAX_MASTER_PRIO(MASTER_IAHB, 5) | + MAX_MASTER_PRIO(MASTER_DAHB, 4) | + MAX_MASTER_PRIO(MASTER_EMMA, 1) | + MAX_MASTER_PRIO(MASTER_DMA, 2) | + MAX_MASTER_PRIO(MASTER_SLDC, 0) | + MAX_MASTER_PRIO(MASTER_CODEC, 3); + + writel(val, max_base + MAX_SLAVE_PORT0_OFFSET + MAX_SLAVE_MPR_OFFSET); + writel(val, max_base + MAX_SLAVE_PORT1_OFFSET + MAX_SLAVE_MPR_OFFSET); + writel(val, max_base + MAX_SLAVE_PORT2_OFFSET + MAX_SLAVE_MPR_OFFSET); + writel(val, max_base + MAX_SLAVE_PORT0_OFFSET + MAX_SLAVE_AMPR_OFFSET); + writel(val, max_base + MAX_SLAVE_PORT1_OFFSET + MAX_SLAVE_AMPR_OFFSET); + writel(val, max_base + MAX_SLAVE_PORT2_OFFSET + MAX_SLAVE_AMPR_OFFSET); +} + static int imx27_init(void) { add_generic_device("imx_iim", 0, NULL, IMX_IIM_BASE, SZ_4K, IORESOURCE_MEM, NULL); + imx27_init_max(); + return 0; } coredevice_initcall(imx27_init); diff --git a/arch/arm/mach-imx/imx5.c b/arch/arm/mach-imx/imx5.c new file mode 100644 index 0000000..9ec78b2 --- /dev/null +++ b/arch/arm/mach-imx/imx5.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +void imx5_setup_pll(void __iomem *base, int freq, u32 op, u32 mfd, u32 mfn) +{ + u32 r; + + /* + * If freq < 300MHz, we need to set dpdck0_2_en to 0 + */ + r = 0x00000232; + if (freq >= 300) + r |= 0x1000; + + writel(r, base + MX5_PLL_DP_CTL); + + writel(0x2, base + MX5_PLL_DP_CONFIG); + + writel(op, base + MX5_PLL_DP_OP); + writel(op, base + MX5_PLL_DP_HFS_OP); + + writel(mfd, base + MX5_PLL_DP_MFD); + writel(mfd, base + MX5_PLL_DP_HFS_MFD); + + writel(mfn, base + MX5_PLL_DP_MFN); + writel(mfn, base + MX5_PLL_DP_HFS_MFN); + + writel(0x00001232, base + MX5_PLL_DP_CTL); + + while (!(readl(base + MX5_PLL_DP_CTL) & 1)); +} + +void imx5_init_lowlevel(void) +{ + u32 r; + + /* ARM errata ID #468414 */ + __asm__ __volatile__("mrc 15, 0, %0, c1, c0, 1":"=r"(r)); + r |= (1 << 5); /* enable L1NEON bit */ + r &= ~(1 << 1); /* explicitly disable L2 cache */ + __asm__ __volatile__("mcr 15, 0, %0, c1, c0, 1" : : "r"(r)); + + /* reconfigure L2 cache aux control reg */ + r = 0xc0 | /* tag RAM */ + 0x4 | /* data RAM */ + (1 << 24) | /* disable write allocate delay */ + (1 << 23) | /* disable write allocate combine */ + (1 << 22); /* disable write allocate */ + + __asm__ __volatile__("mcr 15, 1, %0, c9, c0, 2" : : "r"(r)); + + __asm__ __volatile__("mrc 15, 0, %0, c1, c0, 1":"=r"(r)); + r |= 1 << 1; /* enable L2 cache */ + __asm__ __volatile__("mcr 15, 0, %0, c1, c0, 1" : : "r"(r)); +} diff --git a/arch/arm/mach-imx/imx51.c b/arch/arm/mach-imx/imx51.c index 2c1efed..2431e61 100644 --- a/arch/arm/mach-imx/imx51.c +++ b/arch/arm/mach-imx/imx51.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "gpio.h" @@ -176,3 +178,106 @@ } coredevice_initcall(imx51_boot_save_loc); + +#define setup_pll_1000(base) imx5_setup_pll((base), 1000, ((10 << 4) + ((1 - 1) << 0)), (12 - 1), 5) +#define setup_pll_800(base) imx5_setup_pll((base), 800, ((8 << 4) + ((1 - 1) << 0)), (3 - 1), 1) +#define setup_pll_665(base) imx5_setup_pll((base), 665, ((6 << 4) + ((1 - 1) << 0)), (96 - 1), 89) +#define setup_pll_400(base) imx5_setup_pll((base), 400, ((8 << 4) + ((2 - 1) << 0)), (3 - 1), 1) +#define setup_pll_455(base) imx5_setup_pll((base), 455, ((9 << 4) + ((2 - 1) << 0)), (48 - 1), 23) +#define setup_pll_216(base) imx5_setup_pll((base), 216, ((6 << 4) + ((3 - 1) << 0)), (4 - 1), 3) + +void imx51_init_lowlevel(void) +{ + void __iomem *ccm = (void __iomem *)MX51_CCM_BASE_ADDR; + u32 r; + + imx5_init_lowlevel(); + + /* disable write combine for TO 2 and lower revs */ + if (imx_silicon_revision() < MX51_CHIP_REV_3_0) { + __asm__ __volatile__("mrc 15, 1, %0, c9, c0, 1":"=r"(r)); + r |= (1 << 25); + __asm__ __volatile__("mcr 15, 1, %0, c9, c0, 1" : : "r"(r)); + } + + /* Gate of clocks to the peripherals first */ + writel(0x3fffffff, ccm + MX5_CCM_CCGR0); + writel(0x00000000, ccm + MX5_CCM_CCGR1); + writel(0x00000000, ccm + MX5_CCM_CCGR2); + writel(0x00000000, ccm + MX5_CCM_CCGR3); + writel(0x00030000, ccm + MX5_CCM_CCGR4); + writel(0x00fff030, ccm + MX5_CCM_CCGR5); + writel(0x00000300, ccm + MX5_CCM_CCGR6); + + /* Disable IPU and HSC dividers */ + writel(0x00060000, ccm + MX5_CCM_CCDR); + + /* Make sure to switch the DDR away from PLL 1 */ + writel(0x19239145, ccm + MX5_CCM_CBCDR); + /* make sure divider effective */ + while (readl(ccm + MX5_CCM_CDHIPR)); + + /* Switch ARM to step clock */ + writel(0x4, ccm + MX5_CCM_CCSR); + + setup_pll_800((void __iomem *)MX51_PLL1_BASE_ADDR); + setup_pll_665((void __iomem *)MX51_PLL3_BASE_ADDR); + + /* Switch peripheral to PLL 3 */ + writel(0x000010C0, ccm + MX5_CCM_CBCMR); + writel(0x13239145, ccm + MX5_CCM_CBCDR); + + setup_pll_665((void __iomem *)MX51_PLL2_BASE_ADDR); + + /* Switch peripheral to PLL2 */ + writel(0x19239145, ccm + MX5_CCM_CBCDR); + writel(0x000020C0, ccm + MX5_CCM_CBCMR); + + setup_pll_216((void __iomem *)MX51_PLL3_BASE_ADDR); + + /* Set the platform clock dividers */ + writel(0x00000124, MX51_ARM_BASE_ADDR + 0x14); + + /* Run TO 3.0 at Full speed, for other TO's wait till we increase VDDGP */ + if (imx_silicon_revision() == MX51_CHIP_REV_3_0) + writel(0x0, ccm + MX5_CCM_CACRR); + else + writel(0x1, ccm + MX5_CCM_CACRR); + + /* Switch ARM back to PLL 1 */ + writel(0x0, ccm + MX5_CCM_CCSR); + + /* setup the rest */ + /* Use lp_apm (24MHz) source for perclk */ + writel(0x000020C2, ccm + MX5_CCM_CBCMR); + /* ddr clock from PLL 1, all perclk dividers are 1 since using 24MHz */ + writel(0x59239100, ccm + MX5_CCM_CBCDR); + + /* Restore the default values in the Gate registers */ + writel(0xffffffff, ccm + MX5_CCM_CCGR0); + writel(0xffffffff, ccm + MX5_CCM_CCGR1); + writel(0xffffffff, ccm + MX5_CCM_CCGR2); + writel(0xffffffff, ccm + MX5_CCM_CCGR3); + writel(0xffffffff, ccm + MX5_CCM_CCGR4); + writel(0xffffffff, ccm + MX5_CCM_CCGR5); + writel(0xffffffff, ccm + MX5_CCM_CCGR6); + + /* Use PLL 2 for UART's, get 66.5MHz from it */ + writel(0xA5A2A020, ccm + MX5_CCM_CSCMR1); + writel(0x00C30321, ccm + MX5_CCM_CSCDR1); + + /* make sure divider effective */ + while (readl(ccm + MX5_CCM_CDHIPR)); + + writel(0x0, ccm + MX5_CCM_CCDR); + + writel(0x1, 0x73fa8074); + + r = readl(0x73f88000); + r |= 0x40; + writel(r, 0x73f88000); + + r = readl(0x73f88004); + r |= 0x40; + writel(r, 0x73f88004); +} diff --git a/arch/arm/mach-imx/imx53.c b/arch/arm/mach-imx/imx53.c index 64bec86..2fb18e7 100644 --- a/arch/arm/mach-imx/imx53.c +++ b/arch/arm/mach-imx/imx53.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -45,63 +46,17 @@ } coredevice_initcall(imx53_init); -static void setup_pll(void __iomem *base, int freq, u32 op, u32 mfd, u32 mfn) -{ - u32 r; +#define setup_pll_1000(base) imx5_setup_pll((base), 1000, ((10 << 4) + ((1 - 1) << 0)), (12 - 1), 5) +#define setup_pll_400(base) imx5_setup_pll((base), 400, ((8 << 4) + ((2 - 1) << 0)), (3 - 1), 1) +#define setup_pll_455(base) imx5_setup_pll((base), 455, ((9 << 4) + ((2 - 1) << 0)), (48 - 1), 23) +#define setup_pll_216(base) imx5_setup_pll((base), 216, ((8 << 4) + ((2 - 1) << 0)), (1 - 1), 1) - /* - * If freq < 300MHz, we need to set dpdck0_2_en to 0 - */ - r = 0x00000232; - if (freq >= 300) - r |= 0x1000; - - writel(r, base + MX5_PLL_DP_CTL); - - writel(0x2, base + MX5_PLL_DP_CONFIG); - - writel(op, base + MX5_PLL_DP_OP); - writel(op, base + MX5_PLL_DP_HFS_OP); - - writel(mfd, base + MX5_PLL_DP_MFD); - writel(mfd, base + MX5_PLL_DP_HFS_MFD); - - writel(mfn, base + MX5_PLL_DP_MFN); - writel(mfn, base + MX5_PLL_DP_HFS_MFN); - - writel(0x00001232, base + MX5_PLL_DP_CTL); - - while (!(readl(base + MX5_PLL_DP_CTL) & 1)); -} - -#define setup_pll_1000(base) setup_pll((base), 1000, ((10 << 4) + ((1 - 1) << 0)), (12 - 1), 5) -#define setup_pll_400(base) setup_pll((base), 400, ((8 << 4) + ((2 - 1) << 0)), (3 - 1), 1) -#define setup_pll_455(base) setup_pll((base), 455, ((9 << 4) + ((2 - 1) << 0)), (48 - 1), 23) -#define setup_pll_216(base) setup_pll((base), 216, ((8 << 4) + ((2 - 1) << 0)), (1 - 1), 1) - -int mx53_init_lowlevel(void) +void imx53_init_lowlevel(void) { void __iomem *ccm = (void __iomem *)MX53_CCM_BASE_ADDR; u32 r; - /* ARM errata ID #468414 */ - __asm__ __volatile__("mrc 15, 0, %0, c1, c0, 1":"=r"(r)); - r |= (1 << 5); /* enable L1NEON bit */ - r &= ~(1 << 1); /* explicitly disable L2 cache */ - __asm__ __volatile__("mcr 15, 0, %0, c1, c0, 1" : : "r"(r)); - - /* reconfigure L2 cache aux control reg */ - r = 0xc0 | /* tag RAM */ - 0x4 | /* data RAM */ - (1 << 24) | /* disable write allocate delay */ - (1 << 23) | /* disable write allocate combine */ - (1 << 22); /* disable write allocate */ - - __asm__ __volatile__("mcr 15, 1, %0, c9, c0, 2" : : "r"(r)); - - __asm__ __volatile__("mrc 15, 0, %0, c1, c0, 1":"=r"(r)); - r |= 1 << 1; /* enable L2 cache */ - __asm__ __volatile__("mcr 15, 0, %0, c1, c0, 1" : : "r"(r)); + imx5_init_lowlevel(); /* * AIPS setup - Only setup MPROTx registers. @@ -195,6 +150,4 @@ writel(0xffffffff, ccm + MX53_CCM_CCGR7); writel(0, ccm + MX5_CCM_CCDR); - - return 0; } diff --git a/arch/arm/mach-imx/include/mach/imx27-regs.h b/arch/arm/mach-imx/include/mach/imx27-regs.h index 6754c5a..3a4325e 100644 --- a/arch/arm/mach-imx/include/mach/imx27-regs.h +++ b/arch/arm/mach-imx/include/mach/imx27-regs.h @@ -33,6 +33,7 @@ #define IMX_IIM_BASE (0x28000 + IMX_IO_BASE) #define IMX_OTG_BASE (0x24000 + IMX_IO_BASE) #define IMX_FEC_BASE (0x2b000 + IMX_IO_BASE) +#define IMX_MAX_BASE (0x3f000 + IMX_IO_BASE) #define IMX_NFC_BASE (0xd8000000) #define IMX_ESD_BASE (0xd8001000) diff --git a/arch/arm/mach-imx/include/mach/imx5.h b/arch/arm/mach-imx/include/mach/imx5.h new file mode 100644 index 0000000..0491179 --- /dev/null +++ b/arch/arm/mach-imx/include/mach/imx5.h @@ -0,0 +1,9 @@ +#ifndef __MACH_MX5_H +#define __MACH_MX5_H + +void imx53_init_lowlevel(void); +void imx51_init_lowlevel(void); +void imx5_setup_pll(void __iomem *base, int freq, u32 op, u32 mfd, u32 mfn); +void imx5_init_lowlevel(void); + +#endif /* __MACH_MX53_H */ diff --git a/arch/arm/mach-imx/include/mach/imx53.h b/arch/arm/mach-imx/include/mach/imx53.h deleted file mode 100644 index b1f30d3..0000000 --- a/arch/arm/mach-imx/include/mach/imx53.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __MACH_MX53_H -#define __MACH_MX53_H - -int mx53_init_lowlevel(void); - -#endif /* __MACH_MX53_H */ diff --git a/arch/arm/mach-imx/include/mach/imxfb.h b/arch/arm/mach-imx/include/mach/imxfb.h index b71b7f4..ea39e31 100644 --- a/arch/arm/mach-imx/include/mach/imxfb.h +++ b/arch/arm/mach-imx/include/mach/imxfb.h @@ -63,6 +63,7 @@ */ struct imx_fb_platform_data { struct imx_fb_videomode *mode; + u_int num_modes; u_int cmap_greyscale:1, cmap_inverse:1, diff --git a/arch/arm/mach-mxs/Kconfig b/arch/arm/mach-mxs/Kconfig index caef7e0..15f7c74 100644 --- a/arch/arm/mach-mxs/Kconfig +++ b/arch/arm/mach-mxs/Kconfig @@ -5,11 +5,13 @@ default 0x41000000 if MACH_MX23EVK default 0x42000000 if MACH_CHUMBY default 0x47000000 if MACH_TX28 + default 0x47000000 if MACH_MX28EVK config BOARDINFO default "Freescale i.MX23-EVK" if MACH_MX23EVK default "Chumby Falconwing" if MACH_CHUMBY default "Karo TX28" if MACH_TX28 + default "Freescale i.MX28-EVK" if MACH_MX28EVK comment "Freescale i.MX System-on-Chip" @@ -57,6 +59,11 @@ help Say Y here if you are using the KARO TX28 CPU module. +config MACH_MX28EVK + bool "mx28-evk" + help + Say Y here if you are using the Freescale i.MX28-EVK board + endchoice endif diff --git a/arch/arm/mach-mxs/include/mach/iomux-imx28.h b/arch/arm/mach-mxs/include/mach/iomux-imx28.h index 1e6d421..1557126 100644 --- a/arch/arm/mach-mxs/include/mach/iomux-imx28.h +++ b/arch/arm/mach-mxs/include/mach/iomux-imx28.h @@ -302,6 +302,7 @@ #define PWM2 (FUNC(0) | PORTF(3, 18)) #define PWM1 (FUNC(0) | PORTF(3, 17)) +#define PWM1_DUART_TX (FUNC(2) | PORTF(3, 17)) #define PWM0 (FUNC(0) | PORTF(3, 16)) #define PWM0_I2C1_SCL (FUNC(1) | PORTF(3, 16)) diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig index 1174df0..73125a7 100644 --- a/arch/arm/mach-omap/Kconfig +++ b/arch/arm/mach-omap/Kconfig @@ -106,7 +106,7 @@ default "Texas Instrument's OMAP3EVM" if MACH_OMAP3EVM default "Texas Instrument's Panda" if MACH_PANDA default "Phytec phyCORE pcm049" if MACH_PCM049 - + default "Phytec phyCARD-A-L1" if MACH_PCAAL1 choice prompt "Select OMAP board" @@ -154,6 +154,14 @@ Say Y here if you are using Phytecs phyCORE pcm049 board based on OMAP4 +config MACH_PCAAL1 + bool "Phytec phyCARD-A-L1" + select MACH_HAS_LOWLEVEL_INIT + select OMAP_CLOCK_ALL + select HAS_OMAP_NAND + help + Say Y here if you are using a phyCARD-A-L1 PCA-A-L1 + endchoice if MACH_OMAP3EVM diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile index 07bf30a..9bd2b62 100644 --- a/arch/arm/mach-omap/Makefile +++ b/arch/arm/mach-omap/Makefile @@ -26,4 +26,5 @@ obj-$(CONFIG_OMAP3_CLOCK_CONFIG) += omap3_clock_core.o omap3_clock.o obj-$(CONFIG_OMAP_GPMC) += gpmc.o devices-gpmc-nand.o obj-$(CONFIG_SHELL_NONE) += xload.o +obj-$(CONFIG_I2C_TWL6030) += omap4_twl6030_mmc.o obj-y += gpio.o diff --git a/arch/arm/mach-omap/include/mach/generic.h b/arch/arm/mach-omap/include/mach/generic.h index a2dd229..c801a06 100644 --- a/arch/arm/mach-omap/include/mach/generic.h +++ b/arch/arm/mach-omap/include/mach/generic.h @@ -5,6 +5,7 @@ /* I2C controller revisions present on specific hardware */ #define OMAP_I2C_REV_ON_2430 0x36 #define OMAP_I2C_REV_ON_3430 0x3C +#define OMAP_I2C_REV_ON_4430 0x40 #ifdef CONFIG_ARCH_OMAP #define cpu_is_omap2430() (1) @@ -17,3 +18,9 @@ #else #define cpu_is_omap34xx() (0) #endif + +#ifdef CONFIG_ARCH_OMAP4 +#define cpu_is_omap4xxx() (1) +#else +#define cpu_is_omap4xxx() (0) +#endif diff --git a/arch/arm/mach-omap/include/mach/omap3-silicon.h b/arch/arm/mach-omap/include/mach/omap3-silicon.h index 67f7747..361d25e 100644 --- a/arch/arm/mach-omap/include/mach/omap3-silicon.h +++ b/arch/arm/mach-omap/include/mach/omap3-silicon.h @@ -115,6 +115,10 @@ /** Gives the silicon revision */ #define OMAP_TAP_BASE (OMAP_L4_WKUP_BASE + 0xA000) #define IDCODE_REG (OMAP_TAP_BASE + 0x204) +#define DIE_ID_0 (OMAP_TAP_BASE + 0x218) +#define DIE_ID_1 (OMAP_TAP_BASE + 0x21c) +#define DIE_ID_2 (OMAP_TAP_BASE + 0x220) +#define DIE_ID_3 (OMAP_TAP_BASE + 0x224) /** Masks to extract information from ID code register */ #define IDCODE_HAWKEYE_MASK 0x0FFFF000 diff --git a/arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h b/arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h new file mode 100644 index 0000000..e5e2d9c --- /dev/null +++ b/arch/arm/mach-omap/include/mach/omap4_twl6030_mmc.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2011 Alexander Aring + */ + +#ifndef __OMAP4_TWL6030_MMC_H__ +#define __OMAP4_TWL6030_MMC_H__ + +/* + * Sets up voltage for mmc slot. + */ +void set_up_mmc_voltage_omap4(void); + +/* __OMAP4_TWL6030_MMC_H__ */ +#endif diff --git a/arch/arm/mach-omap/omap4_twl6030_mmc.c b/arch/arm/mach-omap/omap4_twl6030_mmc.c new file mode 100644 index 0000000..5d87935 --- /dev/null +++ b/arch/arm/mach-omap/omap4_twl6030_mmc.c @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Alexander Aring +#include + +#include + +/* MMC voltage */ +#define OMAP4_CONTROL_PBIASLITE 0x4A100600 +#define OMAP4_MMC1_PBIASLITE_VMODE (1<<21) +#define OMAP4_MMC1_PBIASLITE_PWRDNZ (1<<22) +#define OMAP4_MMC1_PWRDNZ (1<<26) + +void set_up_mmc_voltage_omap4(void) +{ + u32 value; + + value = readl(OMAP4_CONTROL_PBIASLITE); + value &= ~(OMAP4_MMC1_PBIASLITE_PWRDNZ | OMAP4_MMC1_PWRDNZ); + writel(value, OMAP4_CONTROL_PBIASLITE); + + twl6030_mci_power_init(); + + value = readl(OMAP4_CONTROL_PBIASLITE); + value |= (OMAP4_MMC1_PBIASLITE_VMODE | OMAP4_MMC1_PBIASLITE_PWRDNZ | + OMAP4_MMC1_PWRDNZ); + writel(value, OMAP4_CONTROL_PBIASLITE); +} +EXPORT_SYMBOL(set_up_mmc_voltage_omap4); diff --git a/arch/arm/mach-pxa/include/mach/clock.h b/arch/arm/mach-pxa/include/mach/clock.h index 4326fca..c53432f 100644 --- a/arch/arm/mach-pxa/include/mach/clock.h +++ b/arch/arm/mach-pxa/include/mach/clock.h @@ -12,6 +12,7 @@ #define __MACH_CLOCK_H unsigned long pxa_get_uartclk(void); +unsigned long pxa_get_mmcclk(void); unsigned long pxa_get_lcdclk(void); #endif /* !__MACH_CLOCK_H */ diff --git a/arch/arm/mach-pxa/include/mach/mci_pxa2xx.h b/arch/arm/mach-pxa/include/mach/mci_pxa2xx.h new file mode 100644 index 0000000..b24bc58 --- /dev/null +++ b/arch/arm/mach-pxa/include/mach/mci_pxa2xx.h @@ -0,0 +1,10 @@ + +struct mci_host; +struct device_d; + +struct pxamci_platform_data { + int gpio_power; + int gpio_power_invert; + int (*init)(struct mci_host*, struct device_d*); + int (*setpower)(struct mci_host*, int on); +}; diff --git a/arch/arm/mach-pxa/speed-pxa27x.c b/arch/arm/mach-pxa/speed-pxa27x.c index 0317d53..534eb1d 100644 --- a/arch/arm/mach-pxa/speed-pxa27x.c +++ b/arch/arm/mach-pxa/speed-pxa27x.c @@ -19,6 +19,11 @@ return 14857000; } +unsigned long pxa_get_mmcclk(void) +{ + return 19500000; +} + /* * Return the current LCD clock frequency in units of 10kHz as */ diff --git a/arch/arm/mach-s3c24xx/Kconfig b/arch/arm/mach-s3c24xx/Kconfig deleted file mode 100644 index 80b65fb..0000000 --- a/arch/arm/mach-s3c24xx/Kconfig +++ /dev/null @@ -1,108 +0,0 @@ -if ARCH_S3C24xx - -config ARCH_TEXT_BASE - hex - default 0x31fc0000 - -config BOARDINFO - default "Mini 2440" if MACH_MINI2440 - default "Digi A9M2440" if MACH_A9M2440 - default "Digi A9M2410" if MACH_A9M2410 - -config CPU_S3C2410 - bool - -config CPU_S3C2440 - bool - -choice - - prompt "S3C24xx Board Type" - -config MACH_A9M2410 - bool "Digi A9M2410" - select CPU_S3C2410 - select MACH_HAS_LOWLEVEL_INIT - select S3C24XX_PLL_INIT - select S3C24XX_SDRAM_INIT - help - Say Y here if you are using Digi's Connect Core 9M equipped - with a Samsung S3C2410 Processor - -config MACH_A9M2440 - bool "Digi A9M2440" - select CPU_S3C2440 - select MACH_HAS_LOWLEVEL_INIT - select S3C24XX_PLL_INIT - help - Say Y here if you are using Digi's Connect Core 9M equipped - with a Samsung S3C2440 Processor - -config MACH_MINI2440 - bool "Mini 2440" - select CPU_S3C2440 - select MACH_HAS_LOWLEVEL_INIT - select MACH_DO_LOWLEVEL_INIT - select S3C24XX_PLL_INIT - select S3C24XX_SDRAM_INIT - select HAS_DM9000 - help - Say Y here if you are using Mini 2440 dev board equipped - with a Samsung S3C2440 Processor - -endchoice - -menu "Board specific settings " - -choice - prompt "A9M2440 baseboard" - depends on MACH_A9M2440 - -config MACH_A9M2410DEV - bool - prompt "A9M2410dev" - select HAS_CS8900 - help - Digi's evaluation board. - -endchoice - -source arch/arm/boards/mini2440/Kconfig - -endmenu - -menu "S3C24X0 Features " - -config S3C24XX_LOW_LEVEL_INIT - bool - -config S3C24XX_PLL_INIT - bool - prompt "Reconfigure PLL" - select S3C24XX_LOW_LEVEL_INIT - help - This adds generic code to reconfigure the internal PLL very early - after reset. - -config S3C24XX_SDRAM_INIT - bool - prompt "Initialize SDRAM" - select S3C24XX_LOW_LEVEL_INIT - help - This adds generic code to configure the SDRAM controller after reset. - The initialisation will be skipped if the code is already running - from SDRAM. - -config S3C24XX_NAND_BOOT - bool - prompt "Booting from NAND" - select MTD - select NAND - select NAND_S3C24X0 - help - Add generic support to boot from NAND flash. Image loading will be - skipped if the code is running from NOR or already from SDRAM. - -endmenu - -endif diff --git a/arch/arm/mach-s3c24xx/Makefile b/arch/arm/mach-s3c24xx/Makefile deleted file mode 100644 index 88d45fe..0000000 --- a/arch/arm/mach-s3c24xx/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-y += generic.o gpio-s3c24x0.o -obj-$(CONFIG_S3C24XX_LOW_LEVEL_INIT) += lowlevel-init.o diff --git a/arch/arm/mach-s3c24xx/generic.c b/arch/arm/mach-s3c24xx/generic.c deleted file mode 100644 index d2f2ac7..0000000 --- a/arch/arm/mach-s3c24xx/generic.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * 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 - */ -/** - * @file - * @brief Basic clock, sdram and timer handling for S3C24xx CPUs - */ - -#include -#include -#include -#include -#include -#include - -/** - * Calculate the current M-PLL clock. - * @return Current frequency in Hz - */ -uint32_t s3c24xx_get_mpllclk(void) -{ - uint32_t m, p, s, reg_val; - - reg_val = readl(MPLLCON); - m = ((reg_val & 0xFF000) >> 12) + 8; - p = ((reg_val & 0x003F0) >> 4) + 2; - s = reg_val & 0x3; -#ifdef CONFIG_CPU_S3C2410 - return (S3C24XX_CLOCK_REFERENCE * m) / (p << s); -#endif -#ifdef CONFIG_CPU_S3C2440 - return 2 * m * (S3C24XX_CLOCK_REFERENCE / (p << s)); -#endif -} - -/** - * Calculate the current U-PLL clock - * @return Current frequency in Hz - */ -uint32_t s3c24xx_get_upllclk(void) -{ - uint32_t m, p, s, reg_val; - - reg_val = readl(UPLLCON); - m = ((reg_val & 0xFF000) >> 12) + 8; - p = ((reg_val & 0x003F0) >> 4) + 2; - s = reg_val & 0x3; - - return (S3C24XX_CLOCK_REFERENCE * m) / (p << s); -} - -/** - * Calculate the FCLK frequency used for the ARM CPU core - * @return Current frequency in Hz - */ -uint32_t s3c24xx_get_fclk(void) -{ - return s3c24xx_get_mpllclk(); -} - -/** - * Calculate the HCLK frequency used for the AHB bus (CPU to main peripheral) - * @return Current frequency in Hz - */ -uint32_t s3c24xx_get_hclk(void) -{ - uint32_t f_clk; - - f_clk = s3c24xx_get_fclk(); -#ifdef CONFIG_CPU_S3C2410 - if (readl(CLKDIVN) & 0x02) - return f_clk >> 1; -#endif -#ifdef CONFIG_CPU_S3C2440 - switch(readl(CLKDIVN) & 0x06) { - case 2: - return f_clk >> 1; - case 4: - return f_clk >> 2; /* TODO consider CAMDIVN */ - case 6: - return f_clk / 3; /* TODO consider CAMDIVN */ - } -#endif - return f_clk; -} - -/** - * Calculate the PCLK frequency used for the slower peripherals - * @return Current frequency in Hz - */ -uint32_t s3c24xx_get_pclk(void) -{ - uint32_t p_clk; - - p_clk = s3c24xx_get_hclk(); - if (readl(CLKDIVN) & 0x01) - return p_clk >> 1; - return p_clk; -} - -/** - * Calculate the UCLK frequency used by the USB host device - * @return Current frequency in Hz - */ -uint32_t s3c24xx_get_uclk(void) -{ - return s3c24xx_get_upllclk(); -} - -/** - * Calculate the amount of connected and available memory - * @return Memory size in bytes - */ -uint32_t s3c24x0_get_memory_size(void) -{ - uint32_t reg, size; - - /* - * detect the current memory size - */ - reg = readl(BANKSIZE); - - switch (reg & 0x7) { - case 0: - size = 32 * 1024 * 1024; - break; - case 1: - size = 64 * 1024 * 1024; - break; - case 2: - size = 128 * 1024 * 1024; - break; - case 4: - size = 2 * 1024 * 1024; - break; - case 5: - size = 4 * 1024 * 1024; - break; - case 6: - size = 8 * 1024 * 1024; - break; - default: - size = 16 * 1024 * 1024; - break; - } - - /* - * Is bank7 also configured for SDRAM usage? - */ - if ((readl(BANKCON7) & (0x3 << 15)) == (0x3 << 15)) - size <<= 1; /* also count this bank */ - - return size; -} - -/** - * Show the user the current clock settings - */ -int s3c24xx_dump_clocks(void) -{ - printf("refclk: %7d kHz\n", S3C24XX_CLOCK_REFERENCE / 1000); - printf("mpll: %7d kHz\n", s3c24xx_get_mpllclk() / 1000); - printf("upll: %7d kHz\n", s3c24xx_get_upllclk() / 1000); - printf("fclk: %7d kHz\n", s3c24xx_get_fclk() / 1000); - printf("hclk: %7d kHz\n", s3c24xx_get_hclk() / 1000); - printf("pclk: %7d kHz\n", s3c24xx_get_pclk() / 1000); - printf("SDRAM1: CL%d@%dMHz\n", ((readl(BANKCON6) & 0xc) >> 2) + 2, s3c24xx_get_hclk() / 1000000); - if ((readl(BANKCON7) & (0x3 << 15)) == (0x3 << 15)) - printf("SDRAM2: CL%d@%dMHz\n", ((readl(BANKCON7) & 0xc) >> 2) + 2, - s3c24xx_get_hclk() / 1000000); - return 0; -} - -late_initcall(s3c24xx_dump_clocks); - -static uint64_t s3c24xx_clocksource_read(void) -{ - /* note: its a down counter */ - return 0xFFFF - readw(TCNTO4); -} - -static struct clocksource cs = { - .read = s3c24xx_clocksource_read, - .mask = CLOCKSOURCE_MASK(16), - .shift = 10, -}; - -static int clocksource_init (void) -{ - uint32_t p_clk = s3c24xx_get_pclk(); - - writel(0x00000000, TCON); /* stop all timers */ - writel(0x00ffffff, TCFG0); /* PCLK / (255 + 1) for timer 4 */ - writel(0x00030000, TCFG1); /* /16 */ - - writew(0xffff, TCNTB4); /* reload value is TOP */ - - writel(0x00600000, TCON); /* force a first reload */ - writel(0x00400000, TCON); - writel(0x00500000, TCON); /* enable timer 4 with auto reload */ - - cs.mult = clocksource_hz2mult(p_clk / ((255 + 1) * 16), cs.shift); - init_clock(&cs); - - return 0; -} -core_initcall(clocksource_init); - -void __noreturn reset_cpu(unsigned long addr) -{ - /* Disable watchdog */ - writew(0x0000, WTCON); - - /* Initialize watchdog timer count register */ - writew(0x0001, WTCNT); - - /* Enable watchdog timer; assert reset at timer timeout */ - writew(0x0021, WTCON); - - /* loop forever and wait for reset to happen */ - while(1) - ; -} -EXPORT_SYMBOL(reset_cpu); - -/** - -@page dev_s3c24xx_arch Samsung's S3C24xx Platforms in barebox - -@section s3c24xx_boards Boards using S3C24xx Processors - -@li @subpage arch/arm/boards/a9m2410/a9m2410.c -@li @subpage arch/arm/boards/a9m2440/a9m2440.c - -@section s3c24xx_arch Documentation for S3C24xx Architectures Files - -@li @subpage arch/arm/mach-s3c24xx/generic.c - -@section s3c24xx_mem_map SDRAM Memory Map - -SDRAM starts at address 0x3000.0000 up to the available amount of connected -SDRAM memory. Physically this CPU can handle up to 256MiB (two areas with -up to 128MiB each). - -@subsection s3c24xx_mem_generic_map Generic Map -- 0x0000.0000 Start of the internal SRAM when booting from NAND flash memory or CS signal to a NOR flash memory. -- 0x0800.0000 Start of I/O space. -- 0x3000.0000 Start of SDRAM area. - - 0x3000.0100 Start of the TAG list area. - - 0x3000.8000 Start of the linux kernel (physical address). -- 0x4000.0000 Start of internal SRAM, when booting from NOR flash memory -- 0x4800.0000 Start of the internal I/O area - -@section s3c24xx_asm_arm include/asm-arm/arch-s3c24xx directory guidelines -All S3C24xx common headers are located here. - -@note Do not add board specific header files/information here. -*/ - -/** @page dev_s3c24xx_mach Samsung's S3C24xx based platforms - -@par barebox Map - -The location of the @a barebox itself depends on the available amount of -installed SDRAM memory: - -- 0x30fc.0000 Start of @a barebox when 16MiB SDRAM is available -- 0x31fc.0000 Start of @a barebox when 32MiB SDRAM is available -- 0x33fc.0000 Start of @a barebox when 64MiB SDRAM is available - -Adjust the @p CONFIG_TEXT_BASE/CONFIG_ARCH_TEXT_BASE symbol in accordance to -the available memory. - -@note The RAM based filesystem and the stack resides always below the -@a barebox start address. - -@li @subpage dev_s3c24xx_wd_handling -@li @subpage dev_s3c24xx_pll_handling -@li @subpage dev_s3c24xx_sdram_handling -@li @subpage dev_s3c24xx_nandboot_handling -*/ diff --git a/arch/arm/mach-s3c24xx/gpio-s3c24x0.c b/arch/arm/mach-s3c24xx/gpio-s3c24x0.c deleted file mode 100644 index 946ec33..0000000 --- a/arch/arm/mach-s3c24xx/gpio-s3c24x0.c +++ /dev/null @@ -1,169 +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 - */ - -#include -#include -#include -#include -#include - -static const unsigned char group_offset[] = -{ - 0x00, /* GPA */ - 0x10, /* GPB */ - 0x20, /* GPC */ - 0x30, /* GPD */ - 0x40, /* GPE */ - 0x50, /* GPF */ - 0x60, /* GPG */ - 0x70, /* GPH */ -#ifdef CONFIG_CPU_S3C2440 - 0xd0, /* GPJ */ -#endif -}; - -void gpio_set_value(unsigned gpio, int value) -{ - unsigned group = gpio >> 5; - unsigned bit = gpio % 32; - unsigned offset; - uint32_t reg; - - offset = group_offset[group]; - - reg = readl(GPADAT + offset); - reg &= ~(1 << bit); - reg |= (!!value) << bit; - writel(reg, GPADAT + offset); -} - -int gpio_direction_input(unsigned gpio) -{ - unsigned group = gpio >> 5; - unsigned bit = gpio % 32; - unsigned offset; - uint32_t reg; - - offset = group_offset[group]; - - reg = readl(GPACON + offset); - reg &= ~(0x3 << (bit << 1)); - writel(reg, GPACON + offset); - - return 0; -} - - -int gpio_direction_output(unsigned gpio, int value) -{ - unsigned group = gpio >> 5; - unsigned bit = gpio % 32; - unsigned offset; - uint32_t reg; - - offset = group_offset[group]; - - /* value */ - gpio_set_value(gpio,value); - /* direction */ - if (group == 0) { /* GPA is special */ - reg = readl(GPACON); - reg &= ~(1 << bit); - writel(reg, GPACON); - } else { - reg = readl(GPACON + offset); - reg &= ~(0x3 << (bit << 1)); - reg |= 0x1 << (bit << 1); - writel(reg, GPACON + offset); - } - - return 0; -} - -int gpio_get_value(unsigned gpio) -{ - unsigned group = gpio >> 5; - unsigned bit = gpio % 32; - unsigned offset; - uint32_t reg; - - if (group == 0) /* GPA is special: no input mode available */ - return -ENODEV; - - offset = group_offset[group]; - - /* value */ - reg = readl(GPADAT + offset); - - return !!(reg & (1 << bit)); -} - -void s3c_gpio_mode(unsigned gpio_mode) -{ - unsigned group, func, bit, offset, gpio; - uint32_t reg; - - group = GET_GROUP(gpio_mode); - func = GET_FUNC(gpio_mode); - bit = GET_BIT(gpio_mode); - gpio = GET_GPIO_NO(gpio_mode); - - if (group == 0) { - /* GPA is special */ - switch (func) { - case 0: /* GPIO input */ - pr_debug("Cannot set GPA pin to GPIO input\n"); - break; - case 1: /* GPIO output */ - gpio_direction_output(bit, GET_GPIOVAL(gpio_mode)); - break; - default: - reg = readl(GPACON); - reg |= 1 << bit; - writel(reg, GPACON); - break; - } - return; - } - - offset = group_offset[group]; - - if (PU_PRESENT(gpio_mode)) { - reg = readl(GPACON + offset + 8); - if (GET_PU(gpio_mode)) - reg |= (1 << bit); /* set means _disabled_ */ - else - reg &= ~(1 << bit); - writel(reg, GPACON + offset + 8); - } - - switch (func) { - case 0: /* input */ - gpio_direction_input(gpio); - break; - case 1: /* output */ - gpio_direction_output(gpio, GET_GPIOVAL(gpio_mode)); - break; - case 2: /* function one */ - case 3: /* function two */ - reg = readl(GPACON + offset); - reg &= ~(0x3 << (bit << 1)); - reg |= func << (bit << 1); - writel(reg, GPACON + offset); - break; - } -} diff --git a/arch/arm/mach-s3c24xx/include/mach/fb.h b/arch/arm/mach-s3c24xx/include/mach/fb.h deleted file mode 100644 index 05e013a..0000000 --- a/arch/arm/mach-s3c24xx/include/mach/fb.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2010 Juergen Beisert - * Copyright (C) 2011 Alexey Galakhov - * - * 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_FB_H_ -# define __MACH_FB_H_ - -#include - -/** Proprietary flags corresponding to S3C24x0 LCDCON5 register */ - -/** ! INVVDEN - DE active high */ -#define FB_SYNC_DE_HIGH_ACT (1 << 23) -/** INVVCLK - invert CLK signal */ -#define FB_SYNC_CLK_INVERT (1 << 24) -/** INVVD - invert data */ -#define FB_SYNC_DATA_INVERT (1 << 25) -/** INVPWREN - use PWREN signal */ -#define FB_SYNC_INVERT_PWREN (1 << 26) -/** INVLEND - use LEND signal */ -#define FB_SYNC_INVERT_LEND (1 << 27) -/** PWREN - use PWREN signal */ -#define FB_SYNC_USE_PWREN (1 << 28) -/** ENLEND - use LEND signal */ -#define FB_SYNC_USE_LEND (1 << 29) -/** BSWP - swap bytes */ -#define FB_SYNC_SWAP_BYTES (1 << 30) -/** HWSWP - swap half words */ -#define FB_SYNC_SWAP_HW (1 << 31) - -struct s3c_fb_platform_data { - struct fb_videomode *mode_list; - unsigned mode_cnt; - - unsigned bits_per_pixel; - int passive_display; /**< enable support for STN or CSTN displays */ - - /** hook to enable backlight and stuff */ - void (*enable)(int enable); -}; - -#endif /* __MACH_FB_H_ */ diff --git a/arch/arm/mach-s3c24xx/include/mach/gpio.h b/arch/arm/mach-s3c24xx/include/mach/gpio.h deleted file mode 100644 index 37db4f5..0000000 --- a/arch/arm/mach-s3c24xx/include/mach/gpio.h +++ /dev/null @@ -1,31 +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 __ASM_MACH_GPIO_H -#define __ASM_MACH_GPIO_H - -#if defined(CONFIG_CPU_S3C2440) || defined(CONFIG_CPU_S3C2410) -# include -#endif - -void gpio_set_value(unsigned, int); -int gpio_direction_input(unsigned); -int gpio_direction_output(unsigned, int); -int gpio_get_value(unsigned); -void s3c_gpio_mode(unsigned); - -#endif /* __ASM_MACH_GPIO_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/iomux-s3c24x0.h b/arch/arm/mach-s3c24xx/include/mach/iomux-s3c24x0.h deleted file mode 100644 index 2c64a97..0000000 --- a/arch/arm/mach-s3c24xx/include/mach/iomux-s3c24x0.h +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright (C) 2010 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 __MACH_IOMUX_S3C24x0_H -#define __MACH_IOMUX_S3C24x0_H - -/* 3322222222221111111111 - * 10987654321098765432109876543210 - * ^^^^^_ Bit offset - * ^^^^______ Group Number - * ^^____________ Function - * ^______________ initial GPIO out value - * ^_______________ Pull up feature present - * ^________________ initial pull up setting - */ - - -#define PIN(group,bit) (group * 32 + bit) -#define FUNC(x) (((x) & 0x3) << 11) -#define GET_FUNC(x) (((x) >> 11) & 0x3) -#define GET_GROUP(x) (((x) >> 5) & 0xf) -#define GET_BIT(x) (((x) & 0x1ff) % 32) -#define GET_GPIOVAL(x) (((x) >> 13) & 0x1) -#define GET_GPIO_NO(x) ((x & 0x1ff)) -#define GPIO_OUT FUNC(1) -#define GPIO_IN FUNC(0) -#define GPIO_VAL(x) ((!!(x)) << 13) -#define PU (1 << 14) -#define PU_PRESENT(x) (!!((x) & (1 << 14))) -#define ENABLE_PU (0 << 15) -#define DISABLE_PU (1 << 15) -#define GET_PU(x) (!!((x) & DISABLE_PU)) - -/* - * Group 0: GPIO 0...31 - * Used GPIO: 0...22 - * These pins can also act as GPIO outputs - */ -#define GPA0_ADDR0 (PIN(0,0) | FUNC(2)) -#define GPA0_ADDR0_GPIO (PIN(0,0) | FUNC(0)) -#define GPA1_ADDR16 (PIN(0,1) | FUNC(2)) -#define GPA1_ADDR16_GPIO (PIN(0,1) | FUNC(0)) -#define GPA2_ADDR17 (PIN(0,2) | FUNC(2)) -#define GPA2_ADDR17_GPIO (PIN(0,2) | FUNC(0)) -#define GPA3_ADDR18 (PIN(0,3) | FUNC(2)) -#define GPA3_ADDR18_GPIO (PIN(0,3) | FUNC(0)) -#define GPA4_ADDR19 (PIN(0,4) | FUNC(2)) -#define GPA4_ADDR19_GPIO (PIN(0,4) | FUNC(0)) -#define GPA5_ADDR20 (PIN(0,5) | FUNC(2)) -#define GPA5_ADDR20_GPIO (PIN(0,5) | FUNC(0)) -#define GPA6_ADDR21 (PIN(0,6) | FUNC(2)) -#define GPA6_ADDR21_GPIO (PIN(0,6) | FUNC(0)) -#define GPA7_ADDR22 (PIN(0,7) | FUNC(2)) -#define GPA7_ADDR22_GPIO (PIN(0,7) | FUNC(0)) -#define GPA8_ADDR23 (PIN(0,8) | FUNC(2)) -#define GPA8_ADDR23_GPIO (PIN(0,8) | FUNC(0)) -#define GPA9_ADDR24 (PIN(0,9) | FUNC(2)) -#define GPA9_ADDR24_GPIO (PIN(0,9) | FUNC(0)) -#define GPA10_ADDR25 (PIN(0,10) | FUNC(2)) -#define GPA10_ADDR25_GPIO (PIN(0,10) | FUNC(0)) -#define GPA11_ADDR26 (PIN(0,11) | FUNC(2)) -#define GPA11_ADDR26_GPIO (PIN(0,11) | FUNC(0)) -#define GPA12_NGCS1 (PIN(0,12) | FUNC(2)) -#define GPA12_NGCS1_GPIO (PIN(0,12) | FUNC(0)) -#define GPA13_NGCS2 (PIN(0,13) | FUNC(2)) -#define GPA13_NGCS2_GPIO (PIN(0,13) | FUNC(0)) -#define GPA14_NGCS3 (PIN(0,14) | FUNC(2)) -#define GPA14_NGCS3_GPIO (PIN(0,14) | FUNC(0)) -#define GPA15_NGCS4 (PIN(0,15) | FUNC(2)) -#define GPA15_NGCS4_GPIO (PIN(0,15) | FUNC(0)) -#define GPA16_NGCS5 (PIN(0,16) | FUNC(2)) -#define GPA16_NGCS5_GPIO (PIN(0,16) | FUNC(0)) -#define GPA17_CLE (PIN(0,17) | FUNC(2)) -#define GPA17_CLE_GPIO (PIN(0,17) | FUNC(0)) -#define GPA18_ALE (PIN(0,18) | FUNC(2)) -#define GPA18_ALE_GPIO (PIN(0,18) | FUNC(0)) -#define GPA19_NFWE (PIN(0,19) | FUNC(2)) -#define GPA19_NFWE_GPIO (PIN(0,19) | FUNC(0)) -#define GPA20_NFRE (PIN(0,20) | FUNC(2)) -#define GPA20_NFRE_GPIO (PIN(0,20) | FUNC(0)) -#define GPA21_NRSTOUT (PIN(0,21) | FUNC(2)) -#define GPA21_NRSTOUT_GPIO (PIN(0,21) | FUNC(0)) -#define GPA22_NFCE (PIN(0,22) | FUNC(2)) -#define GPA22_NFCE_GPIO (PIN(0,22) | FUNC(0)) - -/* - * Group 1: GPIO 32...63 - * Used GPIO: 0...10 - * these pins can also act as GPIO inputs/outputs - */ -#define GPB0_TOUT0 (PIN(1,0) | FUNC(2) | PU) -#define GPB0_GPIO (PIN(1,0) | FUNC(0) | PU) -#define GPB1_TOUT1 (PIN(1,1) | FUNC(2) | PU) -#define GPB1_GPIO (PIN(1,1) | FUNC(0) | PU) -#define GPB2_TOUT2 (PIN(1,2) | FUNC(2) | PU) -#define GPB2_GPIO (PIN(1,2) | FUNC(0) | PU) -#define GPB3_TOUT3 (PIN(1,3) | FUNC(2) | PU) -#define GPB3_GPIO (PIN(1,3) | FUNC(0) | PU) -#define GPB4_TCLK0 (PIN(1,4) | FUNC(2) | PU) -#define GPB4_GPIO (PIN(1,4) | FUNC(0) | PU) -#define GPB5_NXBACK (PIN(1,5) | FUNC(2) | PU) -#define GPB5_GPIO (PIN(1,5) | FUNC(0) | PU) -#define GPB6_NXBREQ (PIN(1,6) | FUNC(2) | PU) -#define GPB6_GPIO (PIN(1,6) | FUNC(0) | PU) -#define GPB7_NXDACK1 (PIN(1,7) | FUNC(2) | PU) -#define GPB7_GPIO (PIN(1,7) | FUNC(0) | PU) -#define GPB8_NXDREQ1 (PIN(1,8) | FUNC(2) | PU) -#define GPB8_GPIO (PIN(1,8) | FUNC(0) | PU) -#define GPB9_NXDACK0 (PIN(1,9) | FUNC(2) | PU) -#define GPB9_GPIO (PIN(1,9) | FUNC(0) | PU) -#define GPB10_NXDREQ0 (PIN(1,10) | FUNC(2) | PU) -#define GPB10_GPIO (PIN(1,10) | FUNC(0) | PU) - -/* - * Group 1: GPIO 64...95 - * Used GPIO: 0...15 - * These pins can also act as GPIO inputs/outputs - */ -#define GPC0_LEND (PIN(2,0) | FUNC(2) | PU) -#define GPC0_GPIO (PIN(2,0) | FUNC(0) | PU) -#define GPC1_VCLK (PIN(2,1) | FUNC(2) | PU) -#define GPC1_GPIO (PIN(2,1) | FUNC(0) | PU) -#define GPC2_VLINE (PIN(2,2) | FUNC(2) | PU) -#define GPC2_GPIO (PIN(2,2) | FUNC(0) | PU) -#define GPC3_VFRAME (PIN(2,3) | FUNC(2) | PU) -#define GPC3_GPIO (PIN(2,3) | FUNC(0) | PU) -#define GPC4_VM (PIN(2,4) | FUNC(2) | PU) -#define GPC4_GPIO (PIN(2,4) | FUNC(0) | PU) -#define GPC5_LPCOE (PIN(2,5) | FUNC(2) | PU) -#define GPC5_GPIO (PIN(2,5) | FUNC(0) | PU) -#define GPC6_LPCREV (PIN(2,6) | FUNC(2) | PU) -#define GPC6_GPIO (PIN(2,6) | FUNC(0) | PU) -#define GPC7_LPCREVB (PIN(2,7) | FUNC(2) | PU) -#define GPC7_GPIO (PIN(2,7) | FUNC(0) | PU) -#define GPC8_VD0 (PIN(2,8) | FUNC(2) | PU) -#define GPC8_GPIO (PIN(2,8) | FUNC(0) | PU) -#define GPC9_VD1 (PIN(2,9) | FUNC(2) | PU) -#define GPC9_GPIO (PIN(2,9) | FUNC(0) | PU) -#define GPC10_VD2 (PIN(2,10) | FUNC(2) | PU) -#define GPC10_GPIO (PIN(2,10) | FUNC(0) | PU) -#define GPC11_VD3 (PIN(2,11) | FUNC(2) | PU) -#define GPC11_GPIO (PIN(2,11) | FUNC(0) | PU) -#define GPC12_VD4 (PIN(2,12) | FUNC(2) | PU) -#define GPC12_GPIO (PIN(2,12) | FUNC(0) | PU) -#define GPC13_VD5 (PIN(2,13) | FUNC(2) | PU) -#define GPC13_GPIO (PIN(2,13) | FUNC(0) | PU) -#define GPC14_VD6 (PIN(2,14) | FUNC(2) | PU) -#define GPC14_GPIO (PIN(2,14) | FUNC(0) | PU) -#define GPC15_VD7 (PIN(2,15) | FUNC(2) | PU) -#define GPC15_GPIO (PIN(2,15) | FUNC(0) | PU) - -/* - * Group 1: GPIO 96...127 - * Used GPIO: 0...15 - * These pins can also act as GPIO inputs/outputs - */ -#define GPD0_VD8 (PIN(3,0) | FUNC(2) | PU) -#define GPD0_GPIO (PIN(3,0) | FUNC(0) | PU) -#define GPD1_VD9 (PIN(3,1) | FUNC(2) | PU) -#define GPD1_GPIO (PIN(3,1) | FUNC(0) | PU) -#define GPD2_VD10 (PIN(3,2) | FUNC(2) | PU) -#define GPD2_GPIO (PIN(3,2) | FUNC(0) | PU) -#define GPD3_VD11 (PIN(3,3) | FUNC(2) | PU) -#define GPD3_GPIO (PIN(3,3) | FUNC(0) | PU) -#define GPD4_VD12 (PIN(3,4) | FUNC(2) | PU) -#define GPD4_GPIO (PIN(3,4) | FUNC(0) | PU) -#define GPD5_VD13 (PIN(3,5) | FUNC(2) | PU) -#define GPD5_GPIO (PIN(3,5) | FUNC(0) | PU) -#define GPD6_VD14 (PIN(3,6) | FUNC(2) | PU) -#define GPD6_GPIO (PIN(3,6) | FUNC(0) | PU) -#define GPD7_VD15 (PIN(3,7) | FUNC(2) | PU) -#define GPD7_GPIO (PIN(3,7) | FUNC(0) | PU) -#define GPD8_VD16 (PIN(3,8) | FUNC(2) | PU) -#define GPD8_GPIO (PIN(3,8) | FUNC(0) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPD8_SPIMISO1 (PIN(3,8) | FUNC(3) | PU) -#endif -#define GPD9_VD17 (PIN(3,9) | FUNC(2) | PU) -#define GPD9_GPIO (PIN(3,9) | FUNC(0) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPD9_SPIMOSI1 (PIN(3,9) | FUNC(3) | PU) -#endif -#define GPD10_VD18 (PIN(3,10) | FUNC(2) | PU) -#define GPD10_GPIO (PIN(3,10) | FUNC(0) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPD10_SPICLK (PIN(3,10) | FUNC(3) | PU) -#endif -#define GPD11_VD19 (PIN(3,11) | FUNC(2) | PU) -#define GPD11_GPIO (PIN(3,11) | FUNC(0) | PU) -#define GPD12_VD20 (PIN(3,12) | FUNC(2) | PU) -#define GPD12_GPIO (PIN(3,12) | FUNC(0) | PU) -#define GPD13_VD21 (PIN(3,13) | FUNC(2) | PU) -#define GPD13_GPIO (PIN(3,13) | FUNC(0) | PU) -#define GPD14_VD22 (PIN(3,14) | FUNC(2) | PU) -#define GPD14_GPIO (PIN(3,14) | FUNC(0) | PU) -#define GPD14_NSS1 (PIN(3,14) | FUNC(3) | PU) -#define GPD15_VD23 (PIN(3,15) | FUNC(2) | PU) -#define GPD15_GPIO (PIN(3,15) | FUNC(0) | PU) -#define GPD15_NSS0 (PIN(3,15) | FUNC(3) | PU) - -/* - * Group 1: GPIO 128...159 - * Used GPIO: 0...15 - * These pins can also act as GPIO inputs/outputs - */ -#define GPE0_I2SLRCK (PIN(4,0) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPE0_AC_SYNC (PIN(4,0) | FUNC(3) | PU) -#endif -#define GPE0_GPIO (PIN(4,0) | FUNC(0) | PU) -#define GPE1_I2SSCLK (PIN(4,1) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPE1_AC_BIT_CLK (PIN(4,1) | FUNC(3) | PU) -#endif -#define GPE1_GPIO (PIN(4,1) | FUNC(0) | PU) -#define GPE2_CDCLK (PIN(4,2) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPE2_AC_NRESET (PIN(4,2) | FUNC(3) | PU) -#endif -#define GPE2_GPIO (PIN(4,2) | FUNC(0) | PU) -#define GPE3_I2SDI (PIN(4,3) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPE3_AC_SDATA_IN (PIN(4,3) | FUNC(3) | PU) -#endif -#ifdef CONFIG_CPU_S3C2410 -# define GPE_NSS0 (PIN(4,3) | FUNC(3) | PU) -#endif -#define GPE3_GPIO (PIN(4,3) | FUNC(0) | PU) -#define GPE4_I2SDO (PIN(4,4) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPE4_AC_SDATA_OUT (PIN(4,4) | FUNC(3) | PU) -#endif -#ifdef CONFIG_CPU_S3C2440 -# define GPE4_I2SSDI (PIN(4,4) | FUNC(3) | PU) -#endif -#define GPE4_GPIO (PIN(4,4) | FUNC(0) | PU) -#define GPE5_SDCLK (PIN(4,5) | FUNC(2) | PU) -#define GPE5_GPIO (PIN(4,5) | FUNC(0) | PU) -#define GPE6_SDCMD (PIN(4,6) | FUNC(2) | PU) -#define GPE6_GPIO (PIN(4,6) | FUNC(0) | PU) -#define GPE7_SDDAT0 (PIN(4,7) | FUNC(2) | PU) -#define GPE7_GPIO (PIN(4,7) | FUNC(0) | PU) -#define GPE8_SDDAT1 (PIN(4,8) | FUNC(2) | PU) -#define GPE8_GPIO (PIN(4,8) | FUNC(0) | PU) -#define GPE9_SDDAT2 (PIN(4,9) | FUNC(2) | PU) -#define GPE9_GPIO (PIN(4,9) | FUNC(0) | PU) -#define GPE10_SDDAT3 (PIN(4,10) | FUNC(2) | PU) -#define GPE10_GPIO (PIN(4,10) | FUNC(0) | PU) -#define GPE11_SPIMISO0 (PIN(4,11) | FUNC(2) | PU) -#define GPE11_GPIO (PIN(4,11) | FUNC(0) | PU) -#define GPE12_SPIMOSI0 (PIN(4,12) | FUNC(2) | PU) -#define GPE12_GPIO (PIN(4,12) | FUNC(0) | PU) -#define GPE13_SPICLK0 (PIN(4,13) | FUNC(2) | PU) -#define GPE13_GPIO (PIN(4,13) | FUNC(0) | PU) -#define GPE14_IICSCL (PIN(4,14) | FUNC(2)) /* no pullup option */ -#define GPE14_GPIO (PIN(4,14) | FUNC(0)) /* no pullup option */ -#define GPE15_IICSDA (PIN(4,15) | FUNC(2)) /* no pullup option */ -#define GPE15_GPIO (PIN(4,15) | FUNC(0)) /* no pullup option */ - -/* - * Group 1: GPIO 160...191 - * Used GPIO: 0...7 - * These pins can also act as GPIO inputs/outputs - */ -#define GPF0_EINT0 (PIN(5,0) | FUNC(2) | PU) -#define GPF0_GPIO (PIN(5,0) | FUNC(0) | PU) -#define GPF1_EINT1 (PIN(5,1) | FUNC(2) | PU) -#define GPF1_GPIO (PIN(5,1) | FUNC(0) | PU) -#define GPF2_EINT2 (PIN(5,2) | FUNC(2) | PU) -#define GPF2_GPIO (PIN(5,2) | FUNC(0) | PU) -#define GPF3_EINT3 (PIN(5,3) | FUNC(2) | PU) -#define GPF3_GPIO (PIN(5,3) | FUNC(0) | PU) -#define GPF4_EINT4 (PIN(5,4) | FUNC(2) | PU) -#define GPF4_GPIO (PIN(5,4) | FUNC(0) | PU) -#define GPF5_EINT5 (PIN(5,5) | FUNC(2) | PU) -#define GPF5_GPIO (PIN(5,5) | FUNC(0) | PU) -#define GPF6_EINT6 (PIN(5,6) | FUNC(2) | PU) -#define GPF6_GPIO (PIN(5,6) | FUNC(0) | PU) -#define GPF7_EINT7 (PIN(5,7) | FUNC(2) | PU) -#define GPF7_GPIO (PIN(5,7) | FUNC(0) | PU) - -/* - * Group 1: GPIO 192..223 - * Used GPIO: 0...15 - * These pins can also act as GPIO inputs/outputs - */ -#define GPG0_EINT8 (PIN(6,0) | FUNC(2) | PU) -#define GPG0_GPIO (PIN(6,0) | FUNC(0) | PU) -#define GPG1_EINT9 (PIN(6,1) | FUNC(2) | PU) -#define GPG1_GPIO (PIN(6,1) | FUNC(0) | PU) -#define GPG2_EINT10 (PIN(6,2) | FUNC(2) | PU) -#define GPG2_NSS0 (PIN(6,2) | FUNC(3) | PU) -#define GPG2_GPIO (PIN(6,2) | FUNC(0) | PU) -#define GPG3_EINT11 (PIN(6,3) | FUNC(2) | PU) -#define GPG3_NSS1 (PIN(6,3) | FUNC(3) | PU) -#define GPG3_GPIO (PIN(6,3) | FUNC(0) | PU) -#define GPG4_EINT12 (PIN(6,4) | FUNC(2) | PU) -#define GPG4_LCD_PWREN (PIN(6,4) | FUNC(3) | PU) -#define GPG4_GPIO (PIN(6,4) | FUNC(0) | PU) -#define GPG5_EINT13 (PIN(6,5) | FUNC(2) | PU) -#define GPG5_SPIMISO1 (PIN(6,5) | FUNC(3) | PU) -#define GPG5_GPIO (PIN(6,5) | FUNC(0) | PU) -#define GPG6_EINT14 (PIN(6,6) | FUNC(2) | PU) -#define GPG6_SPIMOSI1 (PIN(6,6) | FUNC(3) | PU) -#define GPG6_GPIO (PIN(6,6) | FUNC(0) | PU) -#define GPG7_EINT15 (PIN(6,7) | FUNC(2) | PU) -#define GPG7_SPICLK1 (PIN(6,7) | FUNC(3) | PU) -#define GPG7_GPIO (PIN(6,7) | FUNC(0) | PU) -#define GPG8_EINT16 (PIN(6,8) | FUNC(2) | PU) -#define GPG8_GPIO (PIN(6,8) | FUNC(0) | PU) -#define GPG9_EINT17 (PIN(6,9) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPG9_NRTS1 (PIN(6,9) | FUNC(3) | PU) -#endif -#define GPG9_GPIO (PIN(6,9) | FUNC(0) | PU) -#define GPG10_EINT18 (PIN(6,10) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2440 -# define GPG10_NCTS1 (PIN(6,10) | FUNC(3) | PU) -#endif -#define GPG10_GPIO (PIN(6,10) | FUNC(0) | PU) -#define GPG11_EINT19 (PIN(6,11) | FUNC(2) | PU) -#define GPG11_TCLK (PIN(6,11) | FUNC(3) | PU) -#define GPG11_GPIO (PIN(6,11) | FUNC(0) | PU) -#define GPG12_EINT20 (PIN(6,12) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2410 -# define GPG12_XMON (PIN(6,12) | FUNC(3) | PU) -#endif -#define GPG12_GPIO (PIN(6,12) | FUNC(0) | PU) -#define GPG13_EINT21 (PIN(6,13) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2410 -# define GPG13_NXPON (PIN(6,13) | FUNC(3) | PU) -#endif -#define GPG13_GPIO (PIN(6,13) | FUNC(0) | PU) /* must be input in NAND boot mode */ -#define GPG14_EINT22 (PIN(6,14) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2410 -# define GPG14_YMON (PIN(6,14) | FUNC(3) | PU) -#endif -#define GPG14_GPIO (PIN(6,14) | FUNC(0) | PU) /* must be input in NAND boot mode */ -#define GPG15_EINT23 (PIN(6,15) | FUNC(2) | PU) -#ifdef CONFIG_CPU_S3C2410 -# define GPG15_YPON (PIN(6,15) | FUNC(3) | PU) -#endif -#define GPG15_GPIO (PIN(6,15) | FUNC(0) | PU) /* must be input in NAND boot mode */ - -/* - * Group 1: GPIO 224..255 - * Used GPIO: 0...15 - * These pins can also act as GPIO inputs/outputs - */ -#define GPH0_NCTS0 (PIN(7,0) | FUNC(2) | PU) -#define GPH0_GPIO (PIN(7,0) | FUNC(0) | PU) -#define GPH1_NRTS0 (PIN(7,1) | FUNC(2) | PU) -#define GPH1_GPIO (PIN(7,1) | FUNC(0) | PU) -#define GPH2_TXD0 (PIN(7,2) | FUNC(2) | PU) -#define GPH2_GPIO (PIN(7,2) | FUNC(0) | PU) -#define GPH3_RXD0 (PIN(7,3) | FUNC(2) | PU) -#define GPH3_GPIO (PIN(7,3) | FUNC(0) | PU) -#define GPH4_TXD1 (PIN(7,4) | FUNC(2) | PU) -#define GPH4_GPIO (PIN(7,4) | FUNC(0) | PU) -#define GPH5_RXD1 (PIN(7,5) | FUNC(2) | PU) -#define GPH5_GPIO (PIN(7,5) | FUNC(0) | PU) -#define GPH6_TXD2 (PIN(7,6) | FUNC(2) | PU) -#define GPH6_NRTS1 (PIN(7,6) | FUNC(3) | PU) -#define GPH6_GPIO (PIN(7,6) | FUNC(0) | PU) -#define GPH7_RXD2 (PIN(7,7) | FUNC(2) | PU) -#define GPH7_NCTS1 (PIN(7,7) | FUNC(3) | PU) -#define GPH7_GPIO (PIN(7,7) | FUNC(0) | PU) -#define GPH8_UEXTCLK (PIN(7,8) | FUNC(2) | PU) -#define GPH8_GPIO (PIN(7,8) | FUNC(0) | PU) -#define GPH9_CLOCKOUT0 (PIN(7,9) | FUNC(2) | PU) -#define GPH9_GPIO (PIN(7,9) | FUNC(0) | PU) -#define GPH10_CLKOUT1 (PIN(7,10) | FUNC(2) | PU) -#define GPH10_GPIO (PIN(7,10) | FUNC(0) | PU) - -#ifdef CONFIG_CPU_S3C2440 -/* - * Group 1: GPIO 256..287 - * Used GPIO: 0...12 - * These pins can also act as GPIO inputs/outputs - */ -#define GPJ0_CAMDATA0 (PIN(8,0) | FUNC(2) | PU) -#define GPJ0_GPIO (PIN(8,0) | FUNC(0) | PU) -#define GPJ1_CAMDATA1 (PIN(8,1) | FUNC(2) | PU) -#define GPJ1_GPIO (PIN(8,1) | FUNC(0) | PU) -#define GPJ2_CAMDATA2 (PIN(8,2) | FUNC(2) | PU) -#define GPJ2_GPIO (PIN(8,2) | FUNC(0) | PU) -#define GPJ3_CAMDATA3 (PIN(8,3) | FUNC(2) | PU) -#define GPJ3_GPIO (PIN(8,3) | FUNC(0) | PU) -#define GPJ4_CAMDATA4 (PIN(8,4) | FUNC(2) | PU) -#define GPJ4_GPIO (PIN(8,4) | FUNC(0) | PU) -#define GPJ5_CAMDATA5 (PIN(8,5) | FUNC(2) | PU) -#define GPJ5_GPIO (PIN(8,5) | FUNC(0) | PU) -#define GPJ6_CAMDATA6 (PIN(8,6) | FUNC(2) | PU) -#define GPJ6_GPIO (PIN(8,6) | FUNC(0) | PU) -#define GPJ7_CAMDATA7 (PIN(8,7) | FUNC(2) | PU) -#define GPJ7_GPIO (PIN(8,7) | FUNC(0) | PU) -#define GPJ8_CAMPCLK (PIN(8,8) | FUNC(2) | PU) -#define GPJ8_GPIO (PIN(8,8) | FUNC(0) | PU) -#define GPJ9_CAMVSYNC (PIN(8,9) | FUNC(2) | PU) -#define GPJ9_GPIO (PIN(8,9) | FUNC(0) | PU) -#define GPJ10_CAMHREF (PIN(8,10) | FUNC(2) | PU) -#define GPJ10_GPIO (PIN(8,10) | FUNC(0) | PU) -#define GPJ11_CAMCLKOUT (PIN(8,11) | FUNC(2) | PU) -#define GPJ11_GPIO (PIN(8,11) | FUNC(0) | PU) -#define GPJ12_CAMRESET (PIN(8,12) | FUNC(0) | PU) -#define GPJ12_GPIO (PIN(8,12) | FUNC(0) | PU) - -#endif - -#endif /* __MACH_IOMUX_S3C24x0_H */ diff --git a/arch/arm/mach-s3c24xx/include/mach/mci.h b/arch/arm/mach-s3c24xx/include/mach/mci.h deleted file mode 100644 index 6ba8961..0000000 --- a/arch/arm/mach-s3c24xx/include/mach/mci.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * (C) Copyright 2010 Juergen Beisert, Pengutronix - * - * This code is partially based on u-boot code: - * - * Copyright 2008, Freescale Semiconductor, Inc - * Andy Fleming - * - * Based (loosely) on the Linux code - * - * 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 __MACH_MMC_H_ -#define __MACH_MMC_H_ - -struct s3c_mci_platform_data { - unsigned caps; /**< supported operating modes (MMC_MODE_*) */ - unsigned voltages; /**< supported voltage range (MMC_VDD_*) */ - unsigned f_min; /**< min operating frequency in Hz (0 -> no limit) */ - unsigned f_max; /**< max operating frequency in Hz (0 -> no limit) */ - /* TODO */ - /* function to modify the voltage */ - /* function to switch the voltage */ - /* function to detect the presence of a SD card in the socket */ - unsigned gpio_detect; - unsigned detect_invert; -}; - -#endif /* __MACH_MMC_H_ */ diff --git a/arch/arm/mach-s3c24xx/include/mach/s3c24x0-iomap.h b/arch/arm/mach-s3c24xx/include/mach/s3c24x0-iomap.h deleted file mode 100644 index a990d80..0000000 --- a/arch/arm/mach-s3c24xx/include/mach/s3c24x0-iomap.h +++ /dev/null @@ -1,177 +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 - * - */ - -/* S3C2410 device base addresses */ -#define S3C24X0_SDRAM_BASE 0x30000000 -#define S3C24X0_SDRAM_END 0x40000000 -#define S3C24X0_MEMCTL_BASE 0x48000000 -#define S3C2410_USB_HOST_BASE 0x49000000 -#define S3C2410_INTERRUPT_BASE 0x4A000000 -#define S3C2410_DMA_BASE 0x4B000000 -#define S3C24X0_CLOCK_POWER_BASE 0x4C000000 -#define S3C2410_LCD_BASE 0x4D000000 -#define S3C24X0_NAND_BASE 0x4E000000 -#define S3C24X0_UART_BASE 0x50000000 -#define S3C24X0_TIMER_BASE 0x51000000 -#define S3C2410_USB_DEVICE_BASE 0x52000140 -#define S3C24X0_WATCHDOG_BASE 0x53000000 -#define S3C2410_I2C_BASE 0x54000000 -#define S3C2410_I2S_BASE 0x55000000 -#define S3C24X0_GPIO_BASE 0x56000000 -#define S3C2410_RTC_BASE 0x57000000 -#define S3C2410_ADC_BASE 0x58000000 -#define S3C2410_SPI_BASE 0x59000000 -#define S3C2410_SDI_BASE 0x5A000000 - -/* Clock control (direct access) */ - -#define LOCKTIME (S3C24X0_CLOCK_POWER_BASE) -#define MPLLCON (S3C24X0_CLOCK_POWER_BASE + 0x4) -#define UPLLCON (S3C24X0_CLOCK_POWER_BASE + 0x8) -#define CLKCON (S3C24X0_CLOCK_POWER_BASE + 0xc) -#define CLKSLOW (S3C24X0_CLOCK_POWER_BASE + 0x10) -#define CLKDIVN (S3C24X0_CLOCK_POWER_BASE + 0x14) - -/* Timer (direct access) */ -#define TCFG0 (S3C24X0_TIMER_BASE + 0x00) -#define TCFG1 (S3C24X0_TIMER_BASE + 0x04) -#define TCON (S3C24X0_TIMER_BASE + 0x08) -#define TCNTB0 (S3C24X0_TIMER_BASE + 0x0c) -#define TCMPB0 (S3C24X0_TIMER_BASE + 0x10) -#define TCNTO0 (S3C24X0_TIMER_BASE + 0x14) -#define TCNTB1 (S3C24X0_TIMER_BASE + 0x18) -#define TCMPB1 (S3C24X0_TIMER_BASE + 0x1c) -#define TCNTO1 (S3C24X0_TIMER_BASE + 0x20) -#define TCNTB2 (S3C24X0_TIMER_BASE + 0x24) -#define TCMPB2 (S3C24X0_TIMER_BASE + 0x28) -#define TCNTO2 (S3C24X0_TIMER_BASE + 0x2c) -#define TCNTB3 (S3C24X0_TIMER_BASE + 0x30) -#define TCMPB3 (S3C24X0_TIMER_BASE + 0x34) -#define TCNTO3 (S3C24X0_TIMER_BASE + 0x38) -#define TCNTB4 (S3C24X0_TIMER_BASE + 0x3c) -#define TCNTO4 (S3C24X0_TIMER_BASE + 0x40) - -/* Watchdog (direct access) */ -#define WTCON (S3C24X0_WATCHDOG_BASE) -#define WTDAT (S3C24X0_WATCHDOG_BASE + 0x04) -#define WTCNT (S3C24X0_WATCHDOG_BASE + 0x08) - -/* - * if we are booting from NAND, its internal SRAM occures at - * a different address than without this feature - */ -#ifdef CONFIG_S3C24XX_NAND_BOOT -# define NFC_RAM_AREA 0x00000000 -#else -# define NFC_RAM_AREA 0x40000000 -#endif -#define NFC_RAM_SIZE 4096 - -/* internal UARTs (driver based) */ -#define UART1_BASE (S3C24X0_UART_BASE) -#define UART1_SIZE 0x4000 -#define UART2_BASE (S3C24X0_UART_BASE + 0x4000) -#define UART2_SIZE 0x4000 -#define UART3_BASE (S3C24X0_UART_BASE + 0x8000) -#define UART3_SIZE 0x4000 - -/* CS configuration (direct access) */ -#define BWSCON (S3C24X0_MEMCTL_BASE) -#define BANKCON0 (S3C24X0_MEMCTL_BASE + 0x04) -#define BANKCON1 (S3C24X0_MEMCTL_BASE + 0x08) -#define BANKCON2 (S3C24X0_MEMCTL_BASE + 0x0c) -#define BANKCON3 (S3C24X0_MEMCTL_BASE + 0x10) -#define BANKCON4 (S3C24X0_MEMCTL_BASE + 0x14) -#define BANKCON5 (S3C24X0_MEMCTL_BASE + 0x18) -#define BANKCON6 (S3C24X0_MEMCTL_BASE + 0x1c) -#define BANKCON7 (S3C24X0_MEMCTL_BASE + 0x20) -#define REFRESH (S3C24X0_MEMCTL_BASE + 0x24) -#define BANKSIZE (S3C24X0_MEMCTL_BASE + 0x28) -#define MRSRB6 (S3C24X0_MEMCTL_BASE + 0x2c) -#define MRSRB7 (S3C24X0_MEMCTL_BASE + 0x30) - -/* GPIO registers (direct access) */ -#define GPACON (S3C24X0_GPIO_BASE) -#define GPADAT (S3C24X0_GPIO_BASE + 0x04) - -#define GPBCON (S3C24X0_GPIO_BASE + 0x10) -#define GPBDAT (S3C24X0_GPIO_BASE + 0x14) -#define GPBUP (S3C24X0_GPIO_BASE + 0x18) - -#define GPCCON (S3C24X0_GPIO_BASE + 0x20) -#define GPCDAT (S3C24X0_GPIO_BASE + 0x24) -#define GPCUP (S3C24X0_GPIO_BASE + 0x28) - -#define GPDCON (S3C24X0_GPIO_BASE + 0x30) -#define GPDDAT (S3C24X0_GPIO_BASE + 0x34) -#define GPDUP (S3C24X0_GPIO_BASE + 0x38) - -#define GPECON (S3C24X0_GPIO_BASE + 0x40) -#define GPEDAT (S3C24X0_GPIO_BASE + 0x44) -#define GPEUP (S3C24X0_GPIO_BASE + 0x48) - -#define GPFCON (S3C24X0_GPIO_BASE + 0x50) -#define GPFDAT (S3C24X0_GPIO_BASE + 0x54) -#define GPFUP (S3C24X0_GPIO_BASE + 0x58) - -#define GPGCON (S3C24X0_GPIO_BASE + 0x60) -#define GPGDAT (S3C24X0_GPIO_BASE + 0x64) -#define GPGUP (S3C24X0_GPIO_BASE + 0x68) - -#define GPHCON (S3C24X0_GPIO_BASE + 0x70) -#define GPHDAT (S3C24X0_GPIO_BASE + 0x74) -#define GPHUP (S3C24X0_GPIO_BASE + 0x78) - -#ifdef CONFIG_CPU_S3C2440 -# define GPJCON (S3C24X0_GPIO_BASE + 0xd0) -# define GPJDAT (S3C24X0_GPIO_BASE + 0xd4) -# define GPJUP (S3C24X0_GPIO_BASE + 0xd8) -#endif - -#define MISCCR (S3C24X0_GPIO_BASE + 0x80) -#define DCLKCON (S3C24X0_GPIO_BASE + 0x84) -#define EXTINT0 (S3C24X0_GPIO_BASE + 0x88) -#define EXTINT1 (S3C24X0_GPIO_BASE + 0x8c) -#define EXTINT2 (S3C24X0_GPIO_BASE + 0x90) -#define EINTFLT0 (S3C24X0_GPIO_BASE + 0x94) -#define EINTFLT1 (S3C24X0_GPIO_BASE + 0x98) -#define EINTFLT2 (S3C24X0_GPIO_BASE + 0x9c) -#define EINTFLT3 (S3C24X0_GPIO_BASE + 0xa0) -#define EINTMASK (S3C24X0_GPIO_BASE + 0xa4) -#define EINTPEND (S3C24X0_GPIO_BASE + 0xa8) -#define GSTATUS0 (S3C24X0_GPIO_BASE + 0xac) -#define GSTATUS1 (S3C24X0_GPIO_BASE + 0xb0) -#define GSTATUS2 (S3C24X0_GPIO_BASE + 0xb4) -#define GSTATUS3 (S3C24X0_GPIO_BASE + 0xb8) -#define GSTATUS4 (S3C24X0_GPIO_BASE + 0xbc) - -#ifdef CONFIG_CPU_S3C2440 -# define DSC0 (S3C24X0_GPIO_BASE + 0xc4) -# define DSC1 (S3C24X0_GPIO_BASE + 0xc8) -#endif - -/* external IO space */ -#define CS0_BASE 0x00000000 -#define CS1_BASE 0x08000000 -#define CS2_BASE 0x10000000 -#define CS3_BASE 0x18000000 -#define CS4_BASE 0x20000000 -#define CS5_BASE 0x28000000 -#define CS6_BASE 0x30000000 diff --git a/arch/arm/mach-s3c24xx/include/mach/s3c24x0-nand.h b/arch/arm/mach-s3c24xx/include/mach/s3c24x0-nand.h deleted file mode 100644 index 7610b4e..0000000 --- a/arch/arm/mach-s3c24xx/include/mach/s3c24x0-nand.h +++ /dev/null @@ -1,54 +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 - * - */ - -#ifdef CONFIG_S3C24XX_NAND_BOOT -extern void s3c24x0_nand_load_image(void*, int, int); -#endif - -/** - * Locate the timing bits for the NFCONF register - * @param setup is the TACLS clock count - * @param access is the TWRPH0 clock count - * @param hold is the TWRPH1 clock count - * - * @note A clock count of 0 means always 1 HCLK clock. - * @note Clock count settings depend on the NAND flash requirements and the current HCLK speed - */ -#ifdef CONFIG_CPU_S3C2410 -# define CALC_NFCONF_TIMING(setup, access, hold) \ - ((setup << 8) + (access << 4) + (hold << 0)) -#endif -#ifdef CONFIG_CPU_S3C2440 -# define CALC_NFCONF_TIMING(setup, access, hold) \ - ((setup << 12) + (access << 8) + (hold << 4)) -#endif - -/** - * Define platform specific data for the NAND controller and its device - */ -struct s3c24x0_nand_platform_data { - uint32_t nand_timing; /**< value for the NFCONF register (timing bits only) */ - char flash_bbt; /**< force a flash based BBT */ -}; - -/** - * @file - * @brief Basic declaration to use the s3c24x0 NAND driver - */ diff --git a/arch/arm/mach-s3c24xx/include/mach/s3c24xx-generic.h b/arch/arm/mach-s3c24xx/include/mach/s3c24xx-generic.h deleted file mode 100644 index b8abcf1..0000000 --- a/arch/arm/mach-s3c24xx/include/mach/s3c24xx-generic.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * (C) Copyright 2009 - * Juergen Beisert, Pengutronix - * - * (C) Copyright 2001-2004 - * Wolfgang Denk, DENX Software Engineering, wd@denx.de. - * - * (C) Copyright 2002 - * David Mueller, ELSOFT AG, d.mueller@elsoft.ch - * - * 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 - */ - -uint32_t s3c24xx_get_mpllclk(void); -uint32_t s3c24xx_get_upllclk(void); -uint32_t s3c24xx_get_fclk(void); -uint32_t s3c24xx_get_hclk(void); -uint32_t s3c24xx_get_pclk(void); -uint32_t s3c24xx_get_uclk(void); -uint32_t s3c24x0_get_memory_size(void); diff --git a/arch/arm/mach-s3c24xx/lowlevel-init.S b/arch/arm/mach-s3c24xx/lowlevel-init.S deleted file mode 100644 index e8004e5..0000000 --- a/arch/arm/mach-s3c24xx/lowlevel-init.S +++ /dev/null @@ -1,317 +0,0 @@ -/* - * (C) Copyright 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 - */ - -#include -#include - - .section ".text_bare_init.s3c24x0_disable_wd","ax" - -/* - * Disable the watchdog, else it continues to bark - */ -.globl s3c24x0_disable_wd -s3c24x0_disable_wd: - - ldr r0, =S3C24X0_WATCHDOG_BASE - mov r1, #0x0 - str r1, [r0] - mov pc, lr - -/** -@page dev_s3c24xx_wd_handling Watchdog handling - -The watchdog must be disabled very early, because if it resets the system -it is still active and will continue to reset the system. So, call this -routine very early in your board_init_lowlevel routine. -*/ - -/* - * S3C2410 PLL configuration - * ------------------------- - * - * Basic frequency calculation - * - * m * REFclk s = SDIV - * PLLclk = ------------ p = PDIV + 2 - * p * 2^s m = MDIV + 8 - * - * After reset the PLL of the s3c2410 processor uses: - * - * MPLL UPLL - * MDIV 0x5c 0x28 - * PDIV 0x08 0x08 - * SDIV 0x0 0x0 - * - * 100 * 12MHz 1200MHz - * MPLLclk = ------------- = -------- = 120MHz - * 10 * 2^0 10 - * - * 48 * 12MHz 576MHz - * UPLLclk = ------------- = -------- = 57,6MHz - * 10 * 2^0 10 - * - * Note: Do not use "r10" here in this code - */ - -#ifdef CONFIG_S3C24XX_PLL_INIT - - .section ".text_bare_init.s3c24x0_pll_init","ax" - -.globl s3c24x0_pll_init -s3c24x0_pll_init: - - mov r0, #S3C24X0_CLOCK_POWER_BASE - - /* configure internal clock ratio */ - mov r1, #BOARD_SPECIFIC_CLKDIVN - str r1, [r0, #20] - - /* enable all devices on this chip */ - mov r1, #0xFFFFFFF0 - str r1, [r0, #12] - - /* ??????? */ -#ifdef CONFIG_CPU_S3C2440 - mov r1, #0xFFFFFFFF -#endif -#ifdef CONFIG_CPU_S3C2410 - mov r1, #0x00FFFFFF -#endif - str r1, [r0, #0] - -#ifdef CONFIG_CPU_S3C2440 - /* - * Most of the time HDIVN is not 0, so we must use the - * asynchronous bus mode (refer datasheet "Clock and Power Management") - */ - mrc p15, 0, r1, c1, c0, 0 - orr r1, r1, #0xc0000000 - mcr p15, 0, r1, c1, c0, 0 -#endif - - /* configure UPLL */ - ldr r1, =BOARD_SPECIFIC_UPLL - str r1, [r0, #8] - - nop - nop - nop - nop - nop - nop - nop - nop - - /* configure MPLL */ - ldr r1, =BOARD_SPECIFIC_MPLL - str r1, [r0, #4] - - nop - nop - nop - nop - nop - nop - nop - nop - - mov pc, lr - -#endif - -/** -@page dev_s3c24xx_pll_handling PLL clock handling - -To control the speed of your machine the PLLs must be reconfigured after reset. - -For example the S3C2410 CPU wakes up after reset at 120MHz main PLL speed, -shared with all other system on chip components. Most of the time this -configuration is to slow for the CPU and to fast for the other components. - -PLL reprogramming can be done in the machine specific manner very early when -the CONFIG_S3C24XX_PLL_INIT and CONFIG_MACH_HAS_LOWLEVEL_INIT symbols are -defined. The board must provide a board_init_lowlevel() assembler function in -this case and calling the s3c24x0_pll_init() assembler function. - -If the s3c24x0_pll_init() is called a few further symbols must be defined to -setup the correct values for the machine. - -Define in the machine specific config.h the following symbols: - -- S3C24XX_CLOCK_REFERENCE with the frequency in Hz of your reference crystal. -- BOARD_SPECIFIC_CLKDIVN with the value for the main clock ratio register (CLKDIVN) -- BOARD_SPECIFIC_MPLL with the value for the main PLL setup register -- BOARD_SPECIFIC_UPLL with the value for the USB PLL setup register - -@note Valid values for the PLL settings can be found in the CPU manual. - -@par Background: PLL frequency calculation for the S3C2410 CPU (both PLLs) and S3C2440 (UPLL only) - -@f[ - f_{PLL} = \frac{m * f_{Ref}}{p * 2^s} -@f] - -With m = MDIV + 8, p = PDIV + 2 and s = SDIV. - -@par Background: PLL frequency calculation for the S3C2440 CPU (MPLL only) - -@f[ - f_{PLL} = \frac{2 * m * f_{Ref}}{p * 2^s} -@f] - -With m = MDIV + 8, p = PDIV + 2 and s = SDIV. - -@note This routine can be used for the S3C2410 and the S3C2440 CPU. - -*/ - -/* ----------------------------------------------------------------------- */ - -#ifdef CONFIG_S3C24XX_SDRAM_INIT - - .section ".text_bare_init.s3c24x0_sdram_init","ax" - - .globl s3c24x0_sdram_init -s3c24x0_sdram_init: - - adr r0, SDRAMDATA /* get the current relative address of the table */ - mov r1, #S3C24X0_MEMCTL_BASE - mov r2, #6 /* we *know* it contains 6 entries */ - - ldr r3, [r0], #4 /* write BSWCON first */ - str r3, [r1], #0x1c /* post add register offset for bank6 */ -/* - * Initializing the SDRAM controller is very simple: - * Just write some useful values into the SDRAM controller. - */ -0: ldr r3, [r0], #4 - str r3, [r1], #4 - subs r2, r2, #1 - bne 0b - - mov pc, lr - -SDRAMDATA: - .word BOARD_SPECIFIC_BWSCON - .word BOARD_SPECIFIC_BANKCON6 - .word BOARD_SPECIFIC_BANKCON7 - .word BOARD_SPECIFIC_REFRESH - .word BOARD_SPECIFIC_BANKSIZE - .word BOARD_SPECIFIC_MRSRB6 - .word BOARD_SPECIFIC_MRSRB7 - -#endif - -/** -@page dev_s3c24xx_sdram_handling SDRAM controller initialisation - -The SDRAM controller is very simple and its initialisation requires only a -few steps. barebox provides a generic routine to do this step. - -Enable CONFIG_S3C24XX_SDRAM_INIT and CONFIG_MACH_HAS_LOWLEVEL_INIT to be able -to call the generic s3c24x0_sdram_init() assembler function from within the -machine specific board_init_lowlevel() assembler function. - -To use the s3c24x0_sdram_init() assembler function a few symbols must be -defined to setup correct values for the machine. - -Define in the machine specific config.h the following list of symbols: - -- BOARD_SPECIFIC_BWSCON with the values for SDRAM banks 6 and 7 -- BOARD_SPECIFIC_BANKCON6 with the value for the BANKCON6 register -- BOARD_SPECIFIC_BANKCON7 with the value for the BANKCON7 register -- BOARD_SPECIFIC_REFRESH with the value for the REFRESH register -- BOARD_SPECIFIC_BANKSIZE with the value for the BANKSIZE register -- BOARD_SPECIFIC_MRSRB6 with the value for the MRSRB6 register -- BOARD_SPECIFIC_MRSRB7 with the value for the MRSRB7 register -*/ - -/* ----------------------------------------------------------------------- */ - -#ifdef CONFIG_S3C24XX_NAND_BOOT - - .section ".text_bare_init.s3c24x0_nand_boot","ax" - - .globl s3c24x0_nand_boot -s3c24x0_nand_boot: -/* - * In the case of NOR boot we are running from the same address space. - * Detect this case to handle it correctly. - */ - mov r1, #S3C24X0_MEMCTL_BASE - ldr r3, [r1] - and r3, r3, #0x6 - cmp r3, #0x0 /* check for NAND case */ - beq 2f - mov pc, lr /* NOR case: nothing to do here */ - -2: ldr sp, =TEXT_BASE /* Setup a temporary stack in SDRAM */ -/* - * We still run at a location we are not linked to. But lets still running - * from the internal SRAM, this may speed up the boot - */ - push {lr} - bl nand_boot - pop {lr} -/* - * Adjust the return address to the correct address in SDRAM - */ - ldr r1, =TEXT_BASE - add lr, lr, r1 - - mov pc, lr - -#endif - -/** -@page dev_s3c24xx_nandboot_handling Booting from NAND - -To be able to boot from NAND memory only, enable the S3C24x0 NAND driver. Also -enable CONFIG_S3C24XX_NAND_BOOT and CONFIG_MACH_HAS_LOWLEVEL_INIT to be -able to call the s3c24x0_nand_boot() assembler routine from within the -machine specific board_init_lowlevel() assembler function. - -@note This routine assumes an already working SDRAM controller and -an initialized stack pointer. - -@note Basicly this routine runs from inside the internal SRAM. After load of -the whole barebox image from the NAND flash memory into the SDRAM it adjusts -the link register to the final SDRAM adress and returns. - -@note In the NAND boot mode, ECC is not checked. So, the first x KBytes used -by barebox should have no bit error. - -Due to the fact the code to load the whole barebox from NAND must fit into -the first 4kiB of the barebox image, the shrinked NAND driver is very -minimalistic. Setup the NAND access timing is done in a safe manner, what -means: Slowest possible values are used. If you want to increase the speed you -should define the BOARD_DEFAULT_NAND_TIMING to a valid setting into the -NFCONF register and add it to your board specific config.h. Refer S3C24x0's -datasheet for further details. The macro #CALC_NFCONF_TIMING could help to -calculate the register setting in a hardware independent manner. - -@note The regular NAND driver uses a platform data structure to define the -NAND access timings. - -@note Its still possible to boot this image from NOR memory. If this routine -detects it is running from NOR instead of the internal SRAM it skips any -loading and returns immediately. - -*/ diff --git a/arch/arm/mach-samsung/Kconfig b/arch/arm/mach-samsung/Kconfig new file mode 100644 index 0000000..bc283dc --- /dev/null +++ b/arch/arm/mach-samsung/Kconfig @@ -0,0 +1,117 @@ +config ARCH_SAMSUNG + bool + +if ARCH_SAMSUNG + +config ARCH_TEXT_BASE + hex + default 0x31fc0000 if MACH_MINI2440 + default 0x31fc0000 if MACH_A9M2440 + default 0x31fc0000 if MACH_A9M2410 + +config BOARDINFO + default "Mini 2440" if MACH_MINI2440 + default "Digi A9M2440" if MACH_A9M2440 + default "Digi A9M2410" if MACH_A9M2410 + +if ARCH_S3C24xx + +config CPU_S3C2410 + bool + +config CPU_S3C2440 + bool + +choice + + prompt "S3C24xx Board Type" + +config MACH_A9M2410 + bool "Digi A9M2410" + select CPU_S3C2410 + select MACH_HAS_LOWLEVEL_INIT + select S3C24XX_PLL_INIT + select S3C24XX_SDRAM_INIT + help + Say Y here if you are using Digi's Connect Core 9M equipped + with a Samsung S3C2410 Processor + +config MACH_A9M2440 + bool "Digi A9M2440" + select CPU_S3C2440 + select MACH_HAS_LOWLEVEL_INIT + select S3C24XX_PLL_INIT + help + Say Y here if you are using Digi's Connect Core 9M equipped + with a Samsung S3C2440 Processor + +config MACH_MINI2440 + bool "Mini 2440" + select CPU_S3C2440 + select MACH_HAS_LOWLEVEL_INIT + select MACH_DO_LOWLEVEL_INIT + select S3C24XX_PLL_INIT + select S3C24XX_SDRAM_INIT + select HAS_DM9000 + help + Say Y here if you are using Mini 2440 dev board equipped + with a Samsung S3C2440 Processor + +endchoice + +menu "Board specific settings " + +choice + prompt "A9M2440 baseboard" + depends on MACH_A9M2440 + +config MACH_A9M2410DEV + bool + prompt "A9M2410dev" + select HAS_CS8900 + help + Digi's evaluation board. + +endchoice + +source arch/arm/boards/mini2440/Kconfig + +endmenu + +menu "S3C24X0 Features " + +config S3C24XX_LOW_LEVEL_INIT + bool + +config S3C24XX_PLL_INIT + bool + prompt "Reconfigure PLL" + select S3C24XX_LOW_LEVEL_INIT + help + This adds generic code to reconfigure the internal PLL very early + after reset. + +config S3C24XX_SDRAM_INIT + bool + prompt "Initialize SDRAM" + select S3C24XX_LOW_LEVEL_INIT + help + This adds generic code to configure the SDRAM controller after reset. + The initialisation will be skipped if the code is already running + from SDRAM. + +config S3C24XX_NAND_BOOT + bool + prompt "Booting from NAND" + select MTD + select NAND + select NAND_S3C24XX + help + Add generic support to boot from NAND flash. Image loading will be + skipped if the code is running from NOR or already from SDRAM. + +endmenu + +endif + +endif diff --git a/arch/arm/mach-samsung/Makefile b/arch/arm/mach-samsung/Makefile new file mode 100644 index 0000000..2ba5c3f --- /dev/null +++ b/arch/arm/mach-samsung/Makefile @@ -0,0 +1,3 @@ +obj-y += s3c-timer.o generic.o +obj-$(CONFIG_ARCH_S3C24xx) += gpio-s3c24x0.o s3c24xx-clocks.o +obj-$(CONFIG_S3C24XX_LOW_LEVEL_INIT) += lowlevel-init.o diff --git a/arch/arm/mach-samsung/generic.c b/arch/arm/mach-samsung/generic.c new file mode 100644 index 0000000..7706be2 --- /dev/null +++ b/arch/arm/mach-samsung/generic.c @@ -0,0 +1,164 @@ +/* + * 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 + */ +/** + * @file + * @brief Basic clock, sdram and timer handling for S3C24xx CPUs + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Calculate the amount of connected and available memory + * @return Memory size in bytes + */ +uint32_t s3c24xx_get_memory_size(void) +{ + uint32_t reg, size; + + /* + * detect the current memory size + */ + reg = readl(S3C_BANKSIZE); + + switch (reg & 0x7) { + case 0: + size = SZ_32M; + break; + case 1: + size = SZ_64M; + break; + case 2: + size = SZ_128M; + break; + case 4: + size = SZ_2M; + break; + case 5: + size = SZ_4M; + break; + case 6: + size = SZ_8M; + break; + default: + size = SZ_16M; + break; + } + + /* + * Is bank7 also configured for SDRAM usage? + */ + if ((readl(S3C_BANKCON7) & (0x3 << 15)) == (0x3 << 15)) + size <<= 1; /* also count this bank */ + + return size; +} + +void s3c24xx_disable_second_sdram_bank(void) +{ + writel(readl(S3C_BANKCON7) & ~(0x3 << 15), S3C_BANKCON7); + writel(readl(S3C_MISCCR) | (1 << 18), S3C_MISCCR); /* disable its clock */ +} + +#define S3C_WTCON (S3C_WATCHDOG_BASE) +#define S3C_WTDAT (S3C_WATCHDOG_BASE + 0x04) +#define S3C_WTCNT (S3C_WATCHDOG_BASE + 0x08) + +void __noreturn reset_cpu(unsigned long addr) +{ + /* Disable watchdog */ + writew(0x0000, S3C_WTCON); + + /* Initialize watchdog timer count register */ + writew(0x0001, S3C_WTCNT); + + /* Enable watchdog timer; assert reset at timer timeout */ + writew(0x0021, S3C_WTCON); + + /* loop forever and wait for reset to happen */ + while(1) + ; +} +EXPORT_SYMBOL(reset_cpu); + +/** + +@page dev_s3c24xx_arch Samsung's S3C24xx Platforms in barebox + +@section s3c24xx_boards Boards using S3C24xx Processors + +@li @subpage arch/arm/boards/a9m2410/a9m2410.c +@li @subpage arch/arm/boards/a9m2440/a9m2440.c + +@section s3c24xx_arch Documentation for S3C24xx Architectures Files + +@li @subpage arch/arm/mach-s3c24xx/generic.c + +@section s3c24xx_mem_map SDRAM Memory Map + +SDRAM starts at address 0x3000.0000 up to the available amount of connected +SDRAM memory. Physically this CPU can handle up to 256MiB (two areas with +up to 128MiB each). + +@subsection s3c24xx_mem_generic_map Generic Map +- 0x0000.0000 Start of the internal SRAM when booting from NAND flash memory or CS signal to a NOR flash memory. +- 0x0800.0000 Start of I/O space. +- 0x3000.0000 Start of SDRAM area. + - 0x3000.0100 Start of the TAG list area. + - 0x3000.8000 Start of the linux kernel (physical address). +- 0x4000.0000 Start of internal SRAM, when booting from NOR flash memory +- 0x4800.0000 Start of the internal I/O area + +@section s3c24xx_asm_arm include/asm-arm/arch-s3c24xx directory guidelines +All S3C24xx common headers are located here. + +@note Do not add board specific header files/information here. +*/ + +/** @page dev_s3c24xx_mach Samsung's S3C24xx based platforms + +@par barebox Map + +The location of the @a barebox itself depends on the available amount of +installed SDRAM memory: + +- 0x30fc.0000 Start of @a barebox when 16MiB SDRAM is available +- 0x31fc.0000 Start of @a barebox when 32MiB SDRAM is available +- 0x33fc.0000 Start of @a barebox when 64MiB SDRAM is available + +Adjust the @p CONFIG_TEXT_BASE/CONFIG_ARCH_TEXT_BASE symbol in accordance to +the available memory. + +@note The RAM based filesystem and the stack resides always below the +@a barebox start address. + +@li @subpage dev_s3c24xx_wd_handling +@li @subpage dev_s3c24xx_pll_handling +@li @subpage dev_s3c24xx_sdram_handling +@li @subpage dev_s3c24xx_nandboot_handling +*/ diff --git a/arch/arm/mach-samsung/gpio-s3c24x0.c b/arch/arm/mach-samsung/gpio-s3c24x0.c new file mode 100644 index 0000000..4f1c5cc --- /dev/null +++ b/arch/arm/mach-samsung/gpio-s3c24x0.c @@ -0,0 +1,170 @@ +/* + * 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 + +static const unsigned char group_offset[] = +{ + 0x00, /* GPA */ + 0x10, /* GPB */ + 0x20, /* GPC */ + 0x30, /* GPD */ + 0x40, /* GPE */ + 0x50, /* GPF */ + 0x60, /* GPG */ + 0x70, /* GPH */ +#ifdef CONFIG_CPU_S3C2440 + 0xd0, /* GPJ */ +#endif +}; + +void gpio_set_value(unsigned gpio, int value) +{ + unsigned group = gpio >> 5; + unsigned bit = gpio % 32; + unsigned offset; + uint32_t reg; + + offset = group_offset[group]; + + reg = readl(S3C_GPADAT + offset); + reg &= ~(1 << bit); + reg |= (!!value) << bit; + writel(reg, S3C_GPADAT + offset); +} + +int gpio_direction_input(unsigned gpio) +{ + unsigned group = gpio >> 5; + unsigned bit = gpio % 32; + unsigned offset; + uint32_t reg; + + offset = group_offset[group]; + + reg = readl(S3C_GPACON + offset); + reg &= ~(0x3 << (bit << 1)); + writel(reg, S3C_GPACON + offset); + + return 0; +} + + +int gpio_direction_output(unsigned gpio, int value) +{ + unsigned group = gpio >> 5; + unsigned bit = gpio % 32; + unsigned offset; + uint32_t reg; + + offset = group_offset[group]; + + /* value */ + gpio_set_value(gpio,value); + /* direction */ + if (group == 0) { /* GPA is special */ + reg = readl(S3C_GPACON); + reg &= ~(1 << bit); + writel(reg, S3C_GPACON); + } else { + reg = readl(S3C_GPACON + offset); + reg &= ~(0x3 << (bit << 1)); + reg |= 0x1 << (bit << 1); + writel(reg, S3C_GPACON + offset); + } + + return 0; +} + +int gpio_get_value(unsigned gpio) +{ + unsigned group = gpio >> 5; + unsigned bit = gpio % 32; + unsigned offset; + uint32_t reg; + + if (group == 0) /* GPA is special: no input mode available */ + return -ENODEV; + + offset = group_offset[group]; + + /* value */ + reg = readl(S3C_GPADAT + offset); + + return !!(reg & (1 << bit)); +} + +void s3c_gpio_mode(unsigned gpio_mode) +{ + unsigned group, func, bit, offset, gpio; + uint32_t reg; + + group = GET_GROUP(gpio_mode); + func = GET_FUNC(gpio_mode); + bit = GET_BIT(gpio_mode); + gpio = GET_GPIO_NO(gpio_mode); + + if (group == 0) { + /* GPA is special */ + switch (func) { + case 0: /* GPIO input */ + pr_debug("Cannot set GPA pin to GPIO input\n"); + break; + case 1: /* GPIO output */ + gpio_direction_output(bit, GET_GPIOVAL(gpio_mode)); + break; + default: + reg = readl(S3C_GPACON); + reg |= 1 << bit; + writel(reg, S3C_GPACON); + break; + } + return; + } + + offset = group_offset[group]; + + if (PU_PRESENT(gpio_mode)) { + reg = readl(S3C_GPACON + offset + 8); + if (GET_PU(gpio_mode)) + reg |= (1 << bit); /* set means _disabled_ */ + else + reg &= ~(1 << bit); + writel(reg, S3C_GPACON + offset + 8); + } + + switch (func) { + case 0: /* input */ + gpio_direction_input(gpio); + break; + case 1: /* output */ + gpio_direction_output(gpio, GET_GPIOVAL(gpio_mode)); + break; + case 2: /* function one */ + case 3: /* function two */ + reg = readl(S3C_GPACON + offset); + reg &= ~(0x3 << (bit << 1)); + reg |= func << (bit << 1); + writel(reg, S3C_GPACON + offset); + break; + } +} diff --git a/arch/arm/mach-samsung/include/mach/gpio.h b/arch/arm/mach-samsung/include/mach/gpio.h new file mode 100644 index 0000000..3723394 --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/gpio.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. + */ + +#ifndef __ASM_MACH_GPIO_H +#define __ASM_MACH_GPIO_H + +#ifdef CONFIG_ARCH_S3C24xx +# include +#endif + +void gpio_set_value(unsigned, int); +int gpio_direction_input(unsigned); +int gpio_direction_output(unsigned, int); +int gpio_get_value(unsigned); +void s3c_gpio_mode(unsigned); + +#endif /* __ASM_MACH_GPIO_H */ diff --git a/arch/arm/mach-samsung/include/mach/iomux-s3c24x0.h b/arch/arm/mach-samsung/include/mach/iomux-s3c24x0.h new file mode 100644 index 0000000..2c64a97 --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/iomux-s3c24x0.h @@ -0,0 +1,426 @@ +/* + * Copyright (C) 2010 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 __MACH_IOMUX_S3C24x0_H +#define __MACH_IOMUX_S3C24x0_H + +/* 3322222222221111111111 + * 10987654321098765432109876543210 + * ^^^^^_ Bit offset + * ^^^^______ Group Number + * ^^____________ Function + * ^______________ initial GPIO out value + * ^_______________ Pull up feature present + * ^________________ initial pull up setting + */ + + +#define PIN(group,bit) (group * 32 + bit) +#define FUNC(x) (((x) & 0x3) << 11) +#define GET_FUNC(x) (((x) >> 11) & 0x3) +#define GET_GROUP(x) (((x) >> 5) & 0xf) +#define GET_BIT(x) (((x) & 0x1ff) % 32) +#define GET_GPIOVAL(x) (((x) >> 13) & 0x1) +#define GET_GPIO_NO(x) ((x & 0x1ff)) +#define GPIO_OUT FUNC(1) +#define GPIO_IN FUNC(0) +#define GPIO_VAL(x) ((!!(x)) << 13) +#define PU (1 << 14) +#define PU_PRESENT(x) (!!((x) & (1 << 14))) +#define ENABLE_PU (0 << 15) +#define DISABLE_PU (1 << 15) +#define GET_PU(x) (!!((x) & DISABLE_PU)) + +/* + * Group 0: GPIO 0...31 + * Used GPIO: 0...22 + * These pins can also act as GPIO outputs + */ +#define GPA0_ADDR0 (PIN(0,0) | FUNC(2)) +#define GPA0_ADDR0_GPIO (PIN(0,0) | FUNC(0)) +#define GPA1_ADDR16 (PIN(0,1) | FUNC(2)) +#define GPA1_ADDR16_GPIO (PIN(0,1) | FUNC(0)) +#define GPA2_ADDR17 (PIN(0,2) | FUNC(2)) +#define GPA2_ADDR17_GPIO (PIN(0,2) | FUNC(0)) +#define GPA3_ADDR18 (PIN(0,3) | FUNC(2)) +#define GPA3_ADDR18_GPIO (PIN(0,3) | FUNC(0)) +#define GPA4_ADDR19 (PIN(0,4) | FUNC(2)) +#define GPA4_ADDR19_GPIO (PIN(0,4) | FUNC(0)) +#define GPA5_ADDR20 (PIN(0,5) | FUNC(2)) +#define GPA5_ADDR20_GPIO (PIN(0,5) | FUNC(0)) +#define GPA6_ADDR21 (PIN(0,6) | FUNC(2)) +#define GPA6_ADDR21_GPIO (PIN(0,6) | FUNC(0)) +#define GPA7_ADDR22 (PIN(0,7) | FUNC(2)) +#define GPA7_ADDR22_GPIO (PIN(0,7) | FUNC(0)) +#define GPA8_ADDR23 (PIN(0,8) | FUNC(2)) +#define GPA8_ADDR23_GPIO (PIN(0,8) | FUNC(0)) +#define GPA9_ADDR24 (PIN(0,9) | FUNC(2)) +#define GPA9_ADDR24_GPIO (PIN(0,9) | FUNC(0)) +#define GPA10_ADDR25 (PIN(0,10) | FUNC(2)) +#define GPA10_ADDR25_GPIO (PIN(0,10) | FUNC(0)) +#define GPA11_ADDR26 (PIN(0,11) | FUNC(2)) +#define GPA11_ADDR26_GPIO (PIN(0,11) | FUNC(0)) +#define GPA12_NGCS1 (PIN(0,12) | FUNC(2)) +#define GPA12_NGCS1_GPIO (PIN(0,12) | FUNC(0)) +#define GPA13_NGCS2 (PIN(0,13) | FUNC(2)) +#define GPA13_NGCS2_GPIO (PIN(0,13) | FUNC(0)) +#define GPA14_NGCS3 (PIN(0,14) | FUNC(2)) +#define GPA14_NGCS3_GPIO (PIN(0,14) | FUNC(0)) +#define GPA15_NGCS4 (PIN(0,15) | FUNC(2)) +#define GPA15_NGCS4_GPIO (PIN(0,15) | FUNC(0)) +#define GPA16_NGCS5 (PIN(0,16) | FUNC(2)) +#define GPA16_NGCS5_GPIO (PIN(0,16) | FUNC(0)) +#define GPA17_CLE (PIN(0,17) | FUNC(2)) +#define GPA17_CLE_GPIO (PIN(0,17) | FUNC(0)) +#define GPA18_ALE (PIN(0,18) | FUNC(2)) +#define GPA18_ALE_GPIO (PIN(0,18) | FUNC(0)) +#define GPA19_NFWE (PIN(0,19) | FUNC(2)) +#define GPA19_NFWE_GPIO (PIN(0,19) | FUNC(0)) +#define GPA20_NFRE (PIN(0,20) | FUNC(2)) +#define GPA20_NFRE_GPIO (PIN(0,20) | FUNC(0)) +#define GPA21_NRSTOUT (PIN(0,21) | FUNC(2)) +#define GPA21_NRSTOUT_GPIO (PIN(0,21) | FUNC(0)) +#define GPA22_NFCE (PIN(0,22) | FUNC(2)) +#define GPA22_NFCE_GPIO (PIN(0,22) | FUNC(0)) + +/* + * Group 1: GPIO 32...63 + * Used GPIO: 0...10 + * these pins can also act as GPIO inputs/outputs + */ +#define GPB0_TOUT0 (PIN(1,0) | FUNC(2) | PU) +#define GPB0_GPIO (PIN(1,0) | FUNC(0) | PU) +#define GPB1_TOUT1 (PIN(1,1) | FUNC(2) | PU) +#define GPB1_GPIO (PIN(1,1) | FUNC(0) | PU) +#define GPB2_TOUT2 (PIN(1,2) | FUNC(2) | PU) +#define GPB2_GPIO (PIN(1,2) | FUNC(0) | PU) +#define GPB3_TOUT3 (PIN(1,3) | FUNC(2) | PU) +#define GPB3_GPIO (PIN(1,3) | FUNC(0) | PU) +#define GPB4_TCLK0 (PIN(1,4) | FUNC(2) | PU) +#define GPB4_GPIO (PIN(1,4) | FUNC(0) | PU) +#define GPB5_NXBACK (PIN(1,5) | FUNC(2) | PU) +#define GPB5_GPIO (PIN(1,5) | FUNC(0) | PU) +#define GPB6_NXBREQ (PIN(1,6) | FUNC(2) | PU) +#define GPB6_GPIO (PIN(1,6) | FUNC(0) | PU) +#define GPB7_NXDACK1 (PIN(1,7) | FUNC(2) | PU) +#define GPB7_GPIO (PIN(1,7) | FUNC(0) | PU) +#define GPB8_NXDREQ1 (PIN(1,8) | FUNC(2) | PU) +#define GPB8_GPIO (PIN(1,8) | FUNC(0) | PU) +#define GPB9_NXDACK0 (PIN(1,9) | FUNC(2) | PU) +#define GPB9_GPIO (PIN(1,9) | FUNC(0) | PU) +#define GPB10_NXDREQ0 (PIN(1,10) | FUNC(2) | PU) +#define GPB10_GPIO (PIN(1,10) | FUNC(0) | PU) + +/* + * Group 1: GPIO 64...95 + * Used GPIO: 0...15 + * These pins can also act as GPIO inputs/outputs + */ +#define GPC0_LEND (PIN(2,0) | FUNC(2) | PU) +#define GPC0_GPIO (PIN(2,0) | FUNC(0) | PU) +#define GPC1_VCLK (PIN(2,1) | FUNC(2) | PU) +#define GPC1_GPIO (PIN(2,1) | FUNC(0) | PU) +#define GPC2_VLINE (PIN(2,2) | FUNC(2) | PU) +#define GPC2_GPIO (PIN(2,2) | FUNC(0) | PU) +#define GPC3_VFRAME (PIN(2,3) | FUNC(2) | PU) +#define GPC3_GPIO (PIN(2,3) | FUNC(0) | PU) +#define GPC4_VM (PIN(2,4) | FUNC(2) | PU) +#define GPC4_GPIO (PIN(2,4) | FUNC(0) | PU) +#define GPC5_LPCOE (PIN(2,5) | FUNC(2) | PU) +#define GPC5_GPIO (PIN(2,5) | FUNC(0) | PU) +#define GPC6_LPCREV (PIN(2,6) | FUNC(2) | PU) +#define GPC6_GPIO (PIN(2,6) | FUNC(0) | PU) +#define GPC7_LPCREVB (PIN(2,7) | FUNC(2) | PU) +#define GPC7_GPIO (PIN(2,7) | FUNC(0) | PU) +#define GPC8_VD0 (PIN(2,8) | FUNC(2) | PU) +#define GPC8_GPIO (PIN(2,8) | FUNC(0) | PU) +#define GPC9_VD1 (PIN(2,9) | FUNC(2) | PU) +#define GPC9_GPIO (PIN(2,9) | FUNC(0) | PU) +#define GPC10_VD2 (PIN(2,10) | FUNC(2) | PU) +#define GPC10_GPIO (PIN(2,10) | FUNC(0) | PU) +#define GPC11_VD3 (PIN(2,11) | FUNC(2) | PU) +#define GPC11_GPIO (PIN(2,11) | FUNC(0) | PU) +#define GPC12_VD4 (PIN(2,12) | FUNC(2) | PU) +#define GPC12_GPIO (PIN(2,12) | FUNC(0) | PU) +#define GPC13_VD5 (PIN(2,13) | FUNC(2) | PU) +#define GPC13_GPIO (PIN(2,13) | FUNC(0) | PU) +#define GPC14_VD6 (PIN(2,14) | FUNC(2) | PU) +#define GPC14_GPIO (PIN(2,14) | FUNC(0) | PU) +#define GPC15_VD7 (PIN(2,15) | FUNC(2) | PU) +#define GPC15_GPIO (PIN(2,15) | FUNC(0) | PU) + +/* + * Group 1: GPIO 96...127 + * Used GPIO: 0...15 + * These pins can also act as GPIO inputs/outputs + */ +#define GPD0_VD8 (PIN(3,0) | FUNC(2) | PU) +#define GPD0_GPIO (PIN(3,0) | FUNC(0) | PU) +#define GPD1_VD9 (PIN(3,1) | FUNC(2) | PU) +#define GPD1_GPIO (PIN(3,1) | FUNC(0) | PU) +#define GPD2_VD10 (PIN(3,2) | FUNC(2) | PU) +#define GPD2_GPIO (PIN(3,2) | FUNC(0) | PU) +#define GPD3_VD11 (PIN(3,3) | FUNC(2) | PU) +#define GPD3_GPIO (PIN(3,3) | FUNC(0) | PU) +#define GPD4_VD12 (PIN(3,4) | FUNC(2) | PU) +#define GPD4_GPIO (PIN(3,4) | FUNC(0) | PU) +#define GPD5_VD13 (PIN(3,5) | FUNC(2) | PU) +#define GPD5_GPIO (PIN(3,5) | FUNC(0) | PU) +#define GPD6_VD14 (PIN(3,6) | FUNC(2) | PU) +#define GPD6_GPIO (PIN(3,6) | FUNC(0) | PU) +#define GPD7_VD15 (PIN(3,7) | FUNC(2) | PU) +#define GPD7_GPIO (PIN(3,7) | FUNC(0) | PU) +#define GPD8_VD16 (PIN(3,8) | FUNC(2) | PU) +#define GPD8_GPIO (PIN(3,8) | FUNC(0) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPD8_SPIMISO1 (PIN(3,8) | FUNC(3) | PU) +#endif +#define GPD9_VD17 (PIN(3,9) | FUNC(2) | PU) +#define GPD9_GPIO (PIN(3,9) | FUNC(0) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPD9_SPIMOSI1 (PIN(3,9) | FUNC(3) | PU) +#endif +#define GPD10_VD18 (PIN(3,10) | FUNC(2) | PU) +#define GPD10_GPIO (PIN(3,10) | FUNC(0) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPD10_SPICLK (PIN(3,10) | FUNC(3) | PU) +#endif +#define GPD11_VD19 (PIN(3,11) | FUNC(2) | PU) +#define GPD11_GPIO (PIN(3,11) | FUNC(0) | PU) +#define GPD12_VD20 (PIN(3,12) | FUNC(2) | PU) +#define GPD12_GPIO (PIN(3,12) | FUNC(0) | PU) +#define GPD13_VD21 (PIN(3,13) | FUNC(2) | PU) +#define GPD13_GPIO (PIN(3,13) | FUNC(0) | PU) +#define GPD14_VD22 (PIN(3,14) | FUNC(2) | PU) +#define GPD14_GPIO (PIN(3,14) | FUNC(0) | PU) +#define GPD14_NSS1 (PIN(3,14) | FUNC(3) | PU) +#define GPD15_VD23 (PIN(3,15) | FUNC(2) | PU) +#define GPD15_GPIO (PIN(3,15) | FUNC(0) | PU) +#define GPD15_NSS0 (PIN(3,15) | FUNC(3) | PU) + +/* + * Group 1: GPIO 128...159 + * Used GPIO: 0...15 + * These pins can also act as GPIO inputs/outputs + */ +#define GPE0_I2SLRCK (PIN(4,0) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPE0_AC_SYNC (PIN(4,0) | FUNC(3) | PU) +#endif +#define GPE0_GPIO (PIN(4,0) | FUNC(0) | PU) +#define GPE1_I2SSCLK (PIN(4,1) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPE1_AC_BIT_CLK (PIN(4,1) | FUNC(3) | PU) +#endif +#define GPE1_GPIO (PIN(4,1) | FUNC(0) | PU) +#define GPE2_CDCLK (PIN(4,2) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPE2_AC_NRESET (PIN(4,2) | FUNC(3) | PU) +#endif +#define GPE2_GPIO (PIN(4,2) | FUNC(0) | PU) +#define GPE3_I2SDI (PIN(4,3) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPE3_AC_SDATA_IN (PIN(4,3) | FUNC(3) | PU) +#endif +#ifdef CONFIG_CPU_S3C2410 +# define GPE_NSS0 (PIN(4,3) | FUNC(3) | PU) +#endif +#define GPE3_GPIO (PIN(4,3) | FUNC(0) | PU) +#define GPE4_I2SDO (PIN(4,4) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPE4_AC_SDATA_OUT (PIN(4,4) | FUNC(3) | PU) +#endif +#ifdef CONFIG_CPU_S3C2440 +# define GPE4_I2SSDI (PIN(4,4) | FUNC(3) | PU) +#endif +#define GPE4_GPIO (PIN(4,4) | FUNC(0) | PU) +#define GPE5_SDCLK (PIN(4,5) | FUNC(2) | PU) +#define GPE5_GPIO (PIN(4,5) | FUNC(0) | PU) +#define GPE6_SDCMD (PIN(4,6) | FUNC(2) | PU) +#define GPE6_GPIO (PIN(4,6) | FUNC(0) | PU) +#define GPE7_SDDAT0 (PIN(4,7) | FUNC(2) | PU) +#define GPE7_GPIO (PIN(4,7) | FUNC(0) | PU) +#define GPE8_SDDAT1 (PIN(4,8) | FUNC(2) | PU) +#define GPE8_GPIO (PIN(4,8) | FUNC(0) | PU) +#define GPE9_SDDAT2 (PIN(4,9) | FUNC(2) | PU) +#define GPE9_GPIO (PIN(4,9) | FUNC(0) | PU) +#define GPE10_SDDAT3 (PIN(4,10) | FUNC(2) | PU) +#define GPE10_GPIO (PIN(4,10) | FUNC(0) | PU) +#define GPE11_SPIMISO0 (PIN(4,11) | FUNC(2) | PU) +#define GPE11_GPIO (PIN(4,11) | FUNC(0) | PU) +#define GPE12_SPIMOSI0 (PIN(4,12) | FUNC(2) | PU) +#define GPE12_GPIO (PIN(4,12) | FUNC(0) | PU) +#define GPE13_SPICLK0 (PIN(4,13) | FUNC(2) | PU) +#define GPE13_GPIO (PIN(4,13) | FUNC(0) | PU) +#define GPE14_IICSCL (PIN(4,14) | FUNC(2)) /* no pullup option */ +#define GPE14_GPIO (PIN(4,14) | FUNC(0)) /* no pullup option */ +#define GPE15_IICSDA (PIN(4,15) | FUNC(2)) /* no pullup option */ +#define GPE15_GPIO (PIN(4,15) | FUNC(0)) /* no pullup option */ + +/* + * Group 1: GPIO 160...191 + * Used GPIO: 0...7 + * These pins can also act as GPIO inputs/outputs + */ +#define GPF0_EINT0 (PIN(5,0) | FUNC(2) | PU) +#define GPF0_GPIO (PIN(5,0) | FUNC(0) | PU) +#define GPF1_EINT1 (PIN(5,1) | FUNC(2) | PU) +#define GPF1_GPIO (PIN(5,1) | FUNC(0) | PU) +#define GPF2_EINT2 (PIN(5,2) | FUNC(2) | PU) +#define GPF2_GPIO (PIN(5,2) | FUNC(0) | PU) +#define GPF3_EINT3 (PIN(5,3) | FUNC(2) | PU) +#define GPF3_GPIO (PIN(5,3) | FUNC(0) | PU) +#define GPF4_EINT4 (PIN(5,4) | FUNC(2) | PU) +#define GPF4_GPIO (PIN(5,4) | FUNC(0) | PU) +#define GPF5_EINT5 (PIN(5,5) | FUNC(2) | PU) +#define GPF5_GPIO (PIN(5,5) | FUNC(0) | PU) +#define GPF6_EINT6 (PIN(5,6) | FUNC(2) | PU) +#define GPF6_GPIO (PIN(5,6) | FUNC(0) | PU) +#define GPF7_EINT7 (PIN(5,7) | FUNC(2) | PU) +#define GPF7_GPIO (PIN(5,7) | FUNC(0) | PU) + +/* + * Group 1: GPIO 192..223 + * Used GPIO: 0...15 + * These pins can also act as GPIO inputs/outputs + */ +#define GPG0_EINT8 (PIN(6,0) | FUNC(2) | PU) +#define GPG0_GPIO (PIN(6,0) | FUNC(0) | PU) +#define GPG1_EINT9 (PIN(6,1) | FUNC(2) | PU) +#define GPG1_GPIO (PIN(6,1) | FUNC(0) | PU) +#define GPG2_EINT10 (PIN(6,2) | FUNC(2) | PU) +#define GPG2_NSS0 (PIN(6,2) | FUNC(3) | PU) +#define GPG2_GPIO (PIN(6,2) | FUNC(0) | PU) +#define GPG3_EINT11 (PIN(6,3) | FUNC(2) | PU) +#define GPG3_NSS1 (PIN(6,3) | FUNC(3) | PU) +#define GPG3_GPIO (PIN(6,3) | FUNC(0) | PU) +#define GPG4_EINT12 (PIN(6,4) | FUNC(2) | PU) +#define GPG4_LCD_PWREN (PIN(6,4) | FUNC(3) | PU) +#define GPG4_GPIO (PIN(6,4) | FUNC(0) | PU) +#define GPG5_EINT13 (PIN(6,5) | FUNC(2) | PU) +#define GPG5_SPIMISO1 (PIN(6,5) | FUNC(3) | PU) +#define GPG5_GPIO (PIN(6,5) | FUNC(0) | PU) +#define GPG6_EINT14 (PIN(6,6) | FUNC(2) | PU) +#define GPG6_SPIMOSI1 (PIN(6,6) | FUNC(3) | PU) +#define GPG6_GPIO (PIN(6,6) | FUNC(0) | PU) +#define GPG7_EINT15 (PIN(6,7) | FUNC(2) | PU) +#define GPG7_SPICLK1 (PIN(6,7) | FUNC(3) | PU) +#define GPG7_GPIO (PIN(6,7) | FUNC(0) | PU) +#define GPG8_EINT16 (PIN(6,8) | FUNC(2) | PU) +#define GPG8_GPIO (PIN(6,8) | FUNC(0) | PU) +#define GPG9_EINT17 (PIN(6,9) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPG9_NRTS1 (PIN(6,9) | FUNC(3) | PU) +#endif +#define GPG9_GPIO (PIN(6,9) | FUNC(0) | PU) +#define GPG10_EINT18 (PIN(6,10) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2440 +# define GPG10_NCTS1 (PIN(6,10) | FUNC(3) | PU) +#endif +#define GPG10_GPIO (PIN(6,10) | FUNC(0) | PU) +#define GPG11_EINT19 (PIN(6,11) | FUNC(2) | PU) +#define GPG11_TCLK (PIN(6,11) | FUNC(3) | PU) +#define GPG11_GPIO (PIN(6,11) | FUNC(0) | PU) +#define GPG12_EINT20 (PIN(6,12) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2410 +# define GPG12_XMON (PIN(6,12) | FUNC(3) | PU) +#endif +#define GPG12_GPIO (PIN(6,12) | FUNC(0) | PU) +#define GPG13_EINT21 (PIN(6,13) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2410 +# define GPG13_NXPON (PIN(6,13) | FUNC(3) | PU) +#endif +#define GPG13_GPIO (PIN(6,13) | FUNC(0) | PU) /* must be input in NAND boot mode */ +#define GPG14_EINT22 (PIN(6,14) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2410 +# define GPG14_YMON (PIN(6,14) | FUNC(3) | PU) +#endif +#define GPG14_GPIO (PIN(6,14) | FUNC(0) | PU) /* must be input in NAND boot mode */ +#define GPG15_EINT23 (PIN(6,15) | FUNC(2) | PU) +#ifdef CONFIG_CPU_S3C2410 +# define GPG15_YPON (PIN(6,15) | FUNC(3) | PU) +#endif +#define GPG15_GPIO (PIN(6,15) | FUNC(0) | PU) /* must be input in NAND boot mode */ + +/* + * Group 1: GPIO 224..255 + * Used GPIO: 0...15 + * These pins can also act as GPIO inputs/outputs + */ +#define GPH0_NCTS0 (PIN(7,0) | FUNC(2) | PU) +#define GPH0_GPIO (PIN(7,0) | FUNC(0) | PU) +#define GPH1_NRTS0 (PIN(7,1) | FUNC(2) | PU) +#define GPH1_GPIO (PIN(7,1) | FUNC(0) | PU) +#define GPH2_TXD0 (PIN(7,2) | FUNC(2) | PU) +#define GPH2_GPIO (PIN(7,2) | FUNC(0) | PU) +#define GPH3_RXD0 (PIN(7,3) | FUNC(2) | PU) +#define GPH3_GPIO (PIN(7,3) | FUNC(0) | PU) +#define GPH4_TXD1 (PIN(7,4) | FUNC(2) | PU) +#define GPH4_GPIO (PIN(7,4) | FUNC(0) | PU) +#define GPH5_RXD1 (PIN(7,5) | FUNC(2) | PU) +#define GPH5_GPIO (PIN(7,5) | FUNC(0) | PU) +#define GPH6_TXD2 (PIN(7,6) | FUNC(2) | PU) +#define GPH6_NRTS1 (PIN(7,6) | FUNC(3) | PU) +#define GPH6_GPIO (PIN(7,6) | FUNC(0) | PU) +#define GPH7_RXD2 (PIN(7,7) | FUNC(2) | PU) +#define GPH7_NCTS1 (PIN(7,7) | FUNC(3) | PU) +#define GPH7_GPIO (PIN(7,7) | FUNC(0) | PU) +#define GPH8_UEXTCLK (PIN(7,8) | FUNC(2) | PU) +#define GPH8_GPIO (PIN(7,8) | FUNC(0) | PU) +#define GPH9_CLOCKOUT0 (PIN(7,9) | FUNC(2) | PU) +#define GPH9_GPIO (PIN(7,9) | FUNC(0) | PU) +#define GPH10_CLKOUT1 (PIN(7,10) | FUNC(2) | PU) +#define GPH10_GPIO (PIN(7,10) | FUNC(0) | PU) + +#ifdef CONFIG_CPU_S3C2440 +/* + * Group 1: GPIO 256..287 + * Used GPIO: 0...12 + * These pins can also act as GPIO inputs/outputs + */ +#define GPJ0_CAMDATA0 (PIN(8,0) | FUNC(2) | PU) +#define GPJ0_GPIO (PIN(8,0) | FUNC(0) | PU) +#define GPJ1_CAMDATA1 (PIN(8,1) | FUNC(2) | PU) +#define GPJ1_GPIO (PIN(8,1) | FUNC(0) | PU) +#define GPJ2_CAMDATA2 (PIN(8,2) | FUNC(2) | PU) +#define GPJ2_GPIO (PIN(8,2) | FUNC(0) | PU) +#define GPJ3_CAMDATA3 (PIN(8,3) | FUNC(2) | PU) +#define GPJ3_GPIO (PIN(8,3) | FUNC(0) | PU) +#define GPJ4_CAMDATA4 (PIN(8,4) | FUNC(2) | PU) +#define GPJ4_GPIO (PIN(8,4) | FUNC(0) | PU) +#define GPJ5_CAMDATA5 (PIN(8,5) | FUNC(2) | PU) +#define GPJ5_GPIO (PIN(8,5) | FUNC(0) | PU) +#define GPJ6_CAMDATA6 (PIN(8,6) | FUNC(2) | PU) +#define GPJ6_GPIO (PIN(8,6) | FUNC(0) | PU) +#define GPJ7_CAMDATA7 (PIN(8,7) | FUNC(2) | PU) +#define GPJ7_GPIO (PIN(8,7) | FUNC(0) | PU) +#define GPJ8_CAMPCLK (PIN(8,8) | FUNC(2) | PU) +#define GPJ8_GPIO (PIN(8,8) | FUNC(0) | PU) +#define GPJ9_CAMVSYNC (PIN(8,9) | FUNC(2) | PU) +#define GPJ9_GPIO (PIN(8,9) | FUNC(0) | PU) +#define GPJ10_CAMHREF (PIN(8,10) | FUNC(2) | PU) +#define GPJ10_GPIO (PIN(8,10) | FUNC(0) | PU) +#define GPJ11_CAMCLKOUT (PIN(8,11) | FUNC(2) | PU) +#define GPJ11_GPIO (PIN(8,11) | FUNC(0) | PU) +#define GPJ12_CAMRESET (PIN(8,12) | FUNC(0) | PU) +#define GPJ12_GPIO (PIN(8,12) | FUNC(0) | PU) + +#endif + +#endif /* __MACH_IOMUX_S3C24x0_H */ diff --git a/arch/arm/mach-samsung/include/mach/s3c-busctl.h b/arch/arm/mach-samsung/include/mach/s3c-busctl.h new file mode 100644 index 0000000..4bcf0a7 --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c-busctl.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef __MACH_S3C_BUSCTL_H +# define __MACH_S3C_BUSCTL_H + +#define S3C_BWSCON (S3C_MEMCTL_BASE) +#define S3C_BANKCON0 (S3C_MEMCTL_BASE + 0x04) +#define S3C_BANKCON1 (S3C_MEMCTL_BASE + 0x08) +#define S3C_BANKCON2 (S3C_MEMCTL_BASE + 0x0c) +#define S3C_BANKCON3 (S3C_MEMCTL_BASE + 0x10) +#define S3C_BANKCON4 (S3C_MEMCTL_BASE + 0x14) +#define S3C_BANKCON5 (S3C_MEMCTL_BASE + 0x18) +#define S3C_BANKCON6 (S3C_MEMCTL_BASE + 0x1c) +#define S3C_BANKCON7 (S3C_MEMCTL_BASE + 0x20) +#define S3C_REFRESH (S3C_MEMCTL_BASE + 0x24) +#define S3C_BANKSIZE (S3C_MEMCTL_BASE + 0x28) +#define S3C_MRSRB6 (S3C_MEMCTL_BASE + 0x2c) +#define S3C_MRSRB7 (S3C_MEMCTL_BASE + 0x30) + +#endif /* __MACH_S3C_BUSCTL_H */ diff --git a/arch/arm/mach-samsung/include/mach/s3c-clocks.h b/arch/arm/mach-samsung/include/mach/s3c-clocks.h new file mode 100644 index 0000000..44b2a6c --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c-clocks.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef __MACH_S3C_CLOCKS_H +# define __MACH_S3C_CLOCKS_H + +#ifdef CONFIG_ARCH_S3C24xx +# define S3C_LOCKTIME (S3C_CLOCK_POWER_BASE) +# define S3C_MPLLCON (S3C_CLOCK_POWER_BASE + 0x4) +# define S3C_UPLLCON (S3C_CLOCK_POWER_BASE + 0x8) +# define S3C_CLKCON (S3C_CLOCK_POWER_BASE + 0xc) +# define S3C_CLKSLOW (S3C_CLOCK_POWER_BASE + 0x10) +# define S3C_CLKDIVN (S3C_CLOCK_POWER_BASE + 0x14) + +# define S3C_MPLLCON_GET_MDIV(x) ((((x) >> 12) & 0xff) + 8) +# define S3C_MPLLCON_GET_PDIV(x) ((((x) >> 4) & 0x3f) + 2) +# define S3C_MPLLCON_GET_SDIV(x) ((x) & 0x3) +#endif + +#endif /* __MACH_S3C_CLOCKS_H */ diff --git a/arch/arm/mach-samsung/include/mach/s3c-generic.h b/arch/arm/mach-samsung/include/mach/s3c-generic.h new file mode 100644 index 0000000..4ea3dd7 --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c-generic.h @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2009 + * Juergen Beisert, Pengutronix + * + * (C) Copyright 2001-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2002 + * David Mueller, ELSOFT AG, d.mueller@elsoft.ch + * + * 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 + */ + +uint32_t s3c_get_mpllclk(void); +uint32_t s3c_get_upllclk(void); +uint32_t s3c_get_fclk(void); +uint32_t s3c_get_hclk(void); +uint32_t s3c_get_pclk(void); +uint32_t s3c_get_uclk(void); +uint32_t s3c24xx_get_memory_size(void); +void s3c24xx_disable_second_sdram_bank(void); diff --git a/arch/arm/mach-samsung/include/mach/s3c-iomap.h b/arch/arm/mach-samsung/include/mach/s3c-iomap.h new file mode 100644 index 0000000..9e867f8 --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c-iomap.h @@ -0,0 +1,69 @@ +/* + * 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 + * + */ + +/* S3C2410 device base addresses */ +#define S3C_MEMCTL_BASE 0x48000000 +#define S3C2410_USB_HOST_BASE 0x49000000 +#define S3C2410_INTERRUPT_BASE 0x4A000000 +#define S3C2410_DMA_BASE 0x4B000000 +#define S3C_CLOCK_POWER_BASE 0x4C000000 +#define S3C2410_LCD_BASE 0x4D000000 +#define S3C24X0_NAND_BASE 0x4E000000 +#define S3C_UART_BASE 0x50000000 +#define S3C_TIMER_BASE 0x51000000 +#define S3C2410_USB_DEVICE_BASE 0x52000140 +#define S3C_WATCHDOG_BASE 0x53000000 +#define S3C2410_I2C_BASE 0x54000000 +#define S3C2410_I2S_BASE 0x55000000 +#define S3C_GPIO_BASE 0x56000000 +#define S3C2410_RTC_BASE 0x57000000 +#define S3C2410_ADC_BASE 0x58000000 +#define S3C2410_SPI_BASE 0x59000000 +#define S3C2410_SDI_BASE 0x5A000000 + +/* external IO space */ +#define S3C_CS0_BASE 0x00000000 +#define S3C_CS1_BASE 0x08000000 +#define S3C_CS2_BASE 0x10000000 +#define S3C_CS3_BASE 0x18000000 +#define S3C_CS4_BASE 0x20000000 +#define S3C_CS5_BASE 0x28000000 +#define S3C_CS6_BASE 0x30000000 + +#define S3C_SDRAM_BASE S3C_CS6_BASE +#define S3C_SDRAM_END (S3C_SDRAM_BASE + 0x10000000) + +/* + * if we are booting from NAND, its internal SRAM occures at + * a different address than without this feature + */ +#ifdef CONFIG_S3C24XX_NAND_BOOT +# define NFC_RAM_AREA 0x00000000 +#else +# define NFC_RAM_AREA 0x40000000 +#endif +#define NFC_RAM_SIZE 4096 + +#define S3C_UART1_BASE (S3C_UART_BASE) +#define S3C_UART1_SIZE 0x4000 +#define S3C_UART2_BASE (S3C_UART_BASE + 0x4000) +#define S3C_UART2_SIZE 0x4000 +#define S3C_UART3_BASE (S3C_UART_BASE + 0x8000) +#define S3C_UART3_SIZE 0x4000 diff --git a/arch/arm/mach-samsung/include/mach/s3c-mci.h b/arch/arm/mach-samsung/include/mach/s3c-mci.h new file mode 100644 index 0000000..6ba8961 --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c-mci.h @@ -0,0 +1,46 @@ +/* + * (C) Copyright 2010 Juergen Beisert, Pengutronix + * + * This code is partially based on u-boot code: + * + * Copyright 2008, Freescale Semiconductor, Inc + * Andy Fleming + * + * Based (loosely) on the Linux code + * + * 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 __MACH_MMC_H_ +#define __MACH_MMC_H_ + +struct s3c_mci_platform_data { + unsigned caps; /**< supported operating modes (MMC_MODE_*) */ + unsigned voltages; /**< supported voltage range (MMC_VDD_*) */ + unsigned f_min; /**< min operating frequency in Hz (0 -> no limit) */ + unsigned f_max; /**< max operating frequency in Hz (0 -> no limit) */ + /* TODO */ + /* function to modify the voltage */ + /* function to switch the voltage */ + /* function to detect the presence of a SD card in the socket */ + unsigned gpio_detect; + unsigned detect_invert; +}; + +#endif /* __MACH_MMC_H_ */ diff --git a/arch/arm/mach-samsung/include/mach/s3c24xx-fb.h b/arch/arm/mach-samsung/include/mach/s3c24xx-fb.h new file mode 100644 index 0000000..05e013a --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c24xx-fb.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2010 Juergen Beisert + * Copyright (C) 2011 Alexey Galakhov + * + * 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_FB_H_ +# define __MACH_FB_H_ + +#include + +/** Proprietary flags corresponding to S3C24x0 LCDCON5 register */ + +/** ! INVVDEN - DE active high */ +#define FB_SYNC_DE_HIGH_ACT (1 << 23) +/** INVVCLK - invert CLK signal */ +#define FB_SYNC_CLK_INVERT (1 << 24) +/** INVVD - invert data */ +#define FB_SYNC_DATA_INVERT (1 << 25) +/** INVPWREN - use PWREN signal */ +#define FB_SYNC_INVERT_PWREN (1 << 26) +/** INVLEND - use LEND signal */ +#define FB_SYNC_INVERT_LEND (1 << 27) +/** PWREN - use PWREN signal */ +#define FB_SYNC_USE_PWREN (1 << 28) +/** ENLEND - use LEND signal */ +#define FB_SYNC_USE_LEND (1 << 29) +/** BSWP - swap bytes */ +#define FB_SYNC_SWAP_BYTES (1 << 30) +/** HWSWP - swap half words */ +#define FB_SYNC_SWAP_HW (1 << 31) + +struct s3c_fb_platform_data { + struct fb_videomode *mode_list; + unsigned mode_cnt; + + unsigned bits_per_pixel; + int passive_display; /**< enable support for STN or CSTN displays */ + + /** hook to enable backlight and stuff */ + void (*enable)(int enable); +}; + +#endif /* __MACH_FB_H_ */ diff --git a/arch/arm/mach-samsung/include/mach/s3c24xx-gpio.h b/arch/arm/mach-samsung/include/mach/s3c24xx-gpio.h new file mode 100644 index 0000000..c835974 --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c24xx-gpio.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef __MACH_S3C24XX_GPIO_H +# define __MACH_S3C24XX_GPIO_H + +#define S3C_GPACON (S3C_GPIO_BASE) +#define S3C_GPADAT (S3C_GPIO_BASE + 0x04) + +#define S3C_GPBCON (S3C_GPIO_BASE + 0x10) +#define S3C_GPBDAT (S3C_GPIO_BASE + 0x14) +#define S3C_GPBUP (S3C_GPIO_BASE + 0x18) + +#define S3C_GPCCON (S3C_GPIO_BASE + 0x20) +#define S3C_GPCDAT (S3C_GPIO_BASE + 0x24) +#define S3C_GPCUP (S3C_GPIO_BASE + 0x28) + +#define S3C_GPDCON (S3C_GPIO_BASE + 0x30) +#define S3C_GPDDAT (S3C_GPIO_BASE + 0x34) +#define S3C_GPDUP (S3C_GPIO_BASE + 0x38) + +#define S3C_GPECON (S3C_GPIO_BASE + 0x40) +#define S3C_GPEDAT (S3C_GPIO_BASE + 0x44) +#define S3C_GPEUP (S3C_GPIO_BASE + 0x48) + +#define S3C_GPFCON (S3C_GPIO_BASE + 0x50) +#define S3C_GPFDAT (S3C_GPIO_BASE + 0x54) +#define S3C_GPFUP (S3C_GPIO_BASE + 0x58) + +#define S3C_GPGCON (S3C_GPIO_BASE + 0x60) +#define S3C_GPGDAT (S3C_GPIO_BASE + 0x64) +#define S3C_GPGUP (S3C_GPIO_BASE + 0x68) + +#define S3C_GPHCON (S3C_GPIO_BASE + 0x70) +#define S3C_GPHDAT (S3C_GPIO_BASE + 0x74) +#define S3C_GPHUP (S3C_GPIO_BASE + 0x78) + +#ifdef CONFIG_CPU_S3C2440 +# define S3C_GPJCON (S3C_GPIO_BASE + 0xd0) +# define S3C_GPJDAT (S3C_GPIO_BASE + 0xd4) +# define S3C_GPJUP (S3C_GPIO_BASE + 0xd8) +#endif + +#define S3C_MISCCR (S3C_GPIO_BASE + 0x80) +#define S3C_DCLKCON (S3C_GPIO_BASE + 0x84) +#define S3C_EXTINT0 (S3C_GPIO_BASE + 0x88) +#define S3C_EXTINT1 (S3C_GPIO_BASE + 0x8c) +#define S3C_EXTINT2 (S3C_GPIO_BASE + 0x90) +#define S3C_EINTFLT0 (S3C_GPIO_BASE + 0x94) +#define S3C_EINTFLT1 (S3C_GPIO_BASE + 0x98) +#define S3C_EINTFLT2 (S3C_GPIO_BASE + 0x9c) +#define S3C_EINTFLT3 (S3C_GPIO_BASE + 0xa0) +#define S3C_EINTMASK (S3C_GPIO_BASE + 0xa4) +#define S3C_EINTPEND (S3C_GPIO_BASE + 0xa8) +#define S3C_GSTATUS0 (S3C_GPIO_BASE + 0xac) +#define S3C_GSTATUS1 (S3C_GPIO_BASE + 0xb0) +#define S3C_GSTATUS2 (S3C_GPIO_BASE + 0xb4) +#define S3C_GSTATUS3 (S3C_GPIO_BASE + 0xb8) +#define S3C_GSTATUS4 (S3C_GPIO_BASE + 0xbc) + +#ifdef CONFIG_CPU_S3C2440 +# define S3C_DSC0 (S3C_GPIO_BASE + 0xc4) +# define S3C_DSC1 (S3C_GPIO_BASE + 0xc8) +#endif + +#endif /* __MACH_S3C24XX_GPIO_H */ diff --git a/arch/arm/mach-samsung/include/mach/s3c24xx-nand.h b/arch/arm/mach-samsung/include/mach/s3c24xx-nand.h new file mode 100644 index 0000000..7610b4e --- /dev/null +++ b/arch/arm/mach-samsung/include/mach/s3c24xx-nand.h @@ -0,0 +1,54 @@ +/* + * 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 + * + */ + +#ifdef CONFIG_S3C24XX_NAND_BOOT +extern void s3c24x0_nand_load_image(void*, int, int); +#endif + +/** + * Locate the timing bits for the NFCONF register + * @param setup is the TACLS clock count + * @param access is the TWRPH0 clock count + * @param hold is the TWRPH1 clock count + * + * @note A clock count of 0 means always 1 HCLK clock. + * @note Clock count settings depend on the NAND flash requirements and the current HCLK speed + */ +#ifdef CONFIG_CPU_S3C2410 +# define CALC_NFCONF_TIMING(setup, access, hold) \ + ((setup << 8) + (access << 4) + (hold << 0)) +#endif +#ifdef CONFIG_CPU_S3C2440 +# define CALC_NFCONF_TIMING(setup, access, hold) \ + ((setup << 12) + (access << 8) + (hold << 4)) +#endif + +/** + * Define platform specific data for the NAND controller and its device + */ +struct s3c24x0_nand_platform_data { + uint32_t nand_timing; /**< value for the NFCONF register (timing bits only) */ + char flash_bbt; /**< force a flash based BBT */ +}; + +/** + * @file + * @brief Basic declaration to use the s3c24x0 NAND driver + */ diff --git a/arch/arm/mach-samsung/lowlevel-init.S b/arch/arm/mach-samsung/lowlevel-init.S new file mode 100644 index 0000000..31c6196 --- /dev/null +++ b/arch/arm/mach-samsung/lowlevel-init.S @@ -0,0 +1,317 @@ +/* + * (C) Copyright 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 + */ + +#include +#include + + .section ".text_bare_init.s3c24x0_disable_wd","ax" + +/* + * Disable the watchdog, else it continues to bark + */ +.globl s3c24x0_disable_wd +s3c24x0_disable_wd: + + ldr r0, =S3C_WATCHDOG_BASE + mov r1, #0x0 + str r1, [r0] + mov pc, lr + +/** +@page dev_s3c24xx_wd_handling Watchdog handling + +The watchdog must be disabled very early, because if it resets the system +it is still active and will continue to reset the system. So, call this +routine very early in your board_init_lowlevel routine. +*/ + +/* + * S3C2410 PLL configuration + * ------------------------- + * + * Basic frequency calculation + * + * m * REFclk s = SDIV + * PLLclk = ------------ p = PDIV + 2 + * p * 2^s m = MDIV + 8 + * + * After reset the PLL of the s3c2410 processor uses: + * + * MPLL UPLL + * MDIV 0x5c 0x28 + * PDIV 0x08 0x08 + * SDIV 0x0 0x0 + * + * 100 * 12MHz 1200MHz + * MPLLclk = ------------- = -------- = 120MHz + * 10 * 2^0 10 + * + * 48 * 12MHz 576MHz + * UPLLclk = ------------- = -------- = 57,6MHz + * 10 * 2^0 10 + * + * Note: Do not use "r10" here in this code + */ + +#ifdef CONFIG_S3C24XX_PLL_INIT + + .section ".text_bare_init.s3c24x0_pll_init","ax" + +.globl s3c24x0_pll_init +s3c24x0_pll_init: + + mov r0, #S3C_CLOCK_POWER_BASE + + /* configure internal clock ratio */ + mov r1, #BOARD_SPECIFIC_CLKDIVN + str r1, [r0, #20] + + /* enable all devices on this chip */ + mov r1, #0xFFFFFFF0 + str r1, [r0, #12] + + /* ??????? */ +#ifdef CONFIG_CPU_S3C2440 + mov r1, #0xFFFFFFFF +#endif +#ifdef CONFIG_CPU_S3C2410 + mov r1, #0x00FFFFFF +#endif + str r1, [r0, #0] + +#ifdef CONFIG_CPU_S3C2440 + /* + * Most of the time HDIVN is not 0, so we must use the + * asynchronous bus mode (refer datasheet "Clock and Power Management") + */ + mrc p15, 0, r1, c1, c0, 0 + orr r1, r1, #0xc0000000 + mcr p15, 0, r1, c1, c0, 0 +#endif + + /* configure UPLL */ + ldr r1, =BOARD_SPECIFIC_UPLL + str r1, [r0, #8] + + nop + nop + nop + nop + nop + nop + nop + nop + + /* configure MPLL */ + ldr r1, =BOARD_SPECIFIC_MPLL + str r1, [r0, #4] + + nop + nop + nop + nop + nop + nop + nop + nop + + mov pc, lr + +#endif + +/** +@page dev_s3c24xx_pll_handling PLL clock handling + +To control the speed of your machine the PLLs must be reconfigured after reset. + +For example the S3C2410 CPU wakes up after reset at 120MHz main PLL speed, +shared with all other system on chip components. Most of the time this +configuration is to slow for the CPU and to fast for the other components. + +PLL reprogramming can be done in the machine specific manner very early when +the CONFIG_S3C24XX_PLL_INIT and CONFIG_MACH_HAS_LOWLEVEL_INIT symbols are +defined. The board must provide a board_init_lowlevel() assembler function in +this case and calling the s3c24x0_pll_init() assembler function. + +If the s3c24x0_pll_init() is called a few further symbols must be defined to +setup the correct values for the machine. + +Define in the machine specific config.h the following symbols: + +- S3C24XX_CLOCK_REFERENCE with the frequency in Hz of your reference crystal. +- BOARD_SPECIFIC_CLKDIVN with the value for the main clock ratio register (CLKDIVN) +- BOARD_SPECIFIC_MPLL with the value for the main PLL setup register +- BOARD_SPECIFIC_UPLL with the value for the USB PLL setup register + +@note Valid values for the PLL settings can be found in the CPU manual. + +@par Background: PLL frequency calculation for the S3C2410 CPU (both PLLs) and S3C2440 (UPLL only) + +@f[ + f_{PLL} = \frac{m * f_{Ref}}{p * 2^s} +@f] + +With m = MDIV + 8, p = PDIV + 2 and s = SDIV. + +@par Background: PLL frequency calculation for the S3C2440 CPU (MPLL only) + +@f[ + f_{PLL} = \frac{2 * m * f_{Ref}}{p * 2^s} +@f] + +With m = MDIV + 8, p = PDIV + 2 and s = SDIV. + +@note This routine can be used for the S3C2410 and the S3C2440 CPU. + +*/ + +/* ----------------------------------------------------------------------- */ + +#ifdef CONFIG_S3C24XX_SDRAM_INIT + + .section ".text_bare_init.s3c24x0_sdram_init","ax" + + .globl s3c24x0_sdram_init +s3c24x0_sdram_init: + + adr r0, SDRAMDATA /* get the current relative address of the table */ + mov r1, #S3C_MEMCTL_BASE + mov r2, #6 /* we *know* it contains 6 entries */ + + ldr r3, [r0], #4 /* write BSWCON first */ + str r3, [r1], #0x1c /* post add register offset for bank6 */ +/* + * Initializing the SDRAM controller is very simple: + * Just write some useful values into the SDRAM controller. + */ +0: ldr r3, [r0], #4 + str r3, [r1], #4 + subs r2, r2, #1 + bne 0b + + mov pc, lr + +SDRAMDATA: + .word BOARD_SPECIFIC_BWSCON + .word BOARD_SPECIFIC_BANKCON6 + .word BOARD_SPECIFIC_BANKCON7 + .word BOARD_SPECIFIC_REFRESH + .word BOARD_SPECIFIC_BANKSIZE + .word BOARD_SPECIFIC_MRSRB6 + .word BOARD_SPECIFIC_MRSRB7 + +#endif + +/** +@page dev_s3c24xx_sdram_handling SDRAM controller initialisation + +The SDRAM controller is very simple and its initialisation requires only a +few steps. barebox provides a generic routine to do this step. + +Enable CONFIG_S3C24XX_SDRAM_INIT and CONFIG_MACH_HAS_LOWLEVEL_INIT to be able +to call the generic s3c24x0_sdram_init() assembler function from within the +machine specific board_init_lowlevel() assembler function. + +To use the s3c24x0_sdram_init() assembler function a few symbols must be +defined to setup correct values for the machine. + +Define in the machine specific config.h the following list of symbols: + +- BOARD_SPECIFIC_BWSCON with the values for SDRAM banks 6 and 7 +- BOARD_SPECIFIC_BANKCON6 with the value for the BANKCON6 register +- BOARD_SPECIFIC_BANKCON7 with the value for the BANKCON7 register +- BOARD_SPECIFIC_REFRESH with the value for the REFRESH register +- BOARD_SPECIFIC_BANKSIZE with the value for the BANKSIZE register +- BOARD_SPECIFIC_MRSRB6 with the value for the MRSRB6 register +- BOARD_SPECIFIC_MRSRB7 with the value for the MRSRB7 register +*/ + +/* ----------------------------------------------------------------------- */ + +#ifdef CONFIG_S3C24XX_NAND_BOOT + + .section ".text_bare_init.s3c24x0_nand_boot","ax" + + .globl s3c24x0_nand_boot +s3c24x0_nand_boot: +/* + * In the case of NOR boot we are running from the same address space. + * Detect this case to handle it correctly. + */ + mov r1, #S3C_MEMCTL_BASE + ldr r3, [r1] + and r3, r3, #0x6 + cmp r3, #0x0 /* check for NAND case */ + beq 2f + mov pc, lr /* NOR case: nothing to do here */ + +2: ldr sp, =TEXT_BASE /* Setup a temporary stack in SDRAM */ +/* + * We still run at a location we are not linked to. But lets still running + * from the internal SRAM, this may speed up the boot + */ + push {lr} + bl nand_boot + pop {lr} +/* + * Adjust the return address to the correct address in SDRAM + */ + ldr r1, =TEXT_BASE + add lr, lr, r1 + + mov pc, lr + +#endif + +/** +@page dev_s3c24xx_nandboot_handling Booting from NAND + +To be able to boot from NAND memory only, enable the S3C24x0 NAND driver. Also +enable CONFIG_S3C24XX_NAND_BOOT and CONFIG_MACH_HAS_LOWLEVEL_INIT to be +able to call the s3c24x0_nand_boot() assembler routine from within the +machine specific board_init_lowlevel() assembler function. + +@note This routine assumes an already working SDRAM controller and +an initialized stack pointer. + +@note Basicly this routine runs from inside the internal SRAM. After load of +the whole barebox image from the NAND flash memory into the SDRAM it adjusts +the link register to the final SDRAM adress and returns. + +@note In the NAND boot mode, ECC is not checked. So, the first x KBytes used +by barebox should have no bit error. + +Due to the fact the code to load the whole barebox from NAND must fit into +the first 4kiB of the barebox image, the shrinked NAND driver is very +minimalistic. Setup the NAND access timing is done in a safe manner, what +means: Slowest possible values are used. If you want to increase the speed you +should define the BOARD_DEFAULT_NAND_TIMING to a valid setting into the +NFCONF register and add it to your board specific config.h. Refer S3C24x0's +datasheet for further details. The macro #CALC_NFCONF_TIMING could help to +calculate the register setting in a hardware independent manner. + +@note The regular NAND driver uses a platform data structure to define the +NAND access timings. + +@note Its still possible to boot this image from NOR memory. If this routine +detects it is running from NOR instead of the internal SRAM it skips any +loading and returns immediately. + +*/ diff --git a/arch/arm/mach-samsung/s3c-timer.c b/arch/arm/mach-samsung/s3c-timer.c new file mode 100644 index 0000000..6665c8c --- /dev/null +++ b/arch/arm/mach-samsung/s3c-timer.c @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define S3C_TCFG0 (S3C_TIMER_BASE + 0x00) +# define S3C_TCFG0_T4MASK 0xff00 +# define S3C_TCFG0_SET_PSCL234(x) ((x) << 8) +# define S3C_TCFG0_GET_PSCL234(x) (((x) >> 8) & 0xff) +#define S3C_TCFG1 (S3C_TIMER_BASE + 0x04) +# define S3C_TCFG1_T4MASK 0xf0000 +# define S3C_TCFG1_SET_T4MUX(x) ((x) << 16) +# define S3C_TCFG1_GET_T4MUX(x) (((x) >> 16) & 0xf) +#define S3C_TCON (S3C_TIMER_BASE + 0x08) +# define S3C_TCON_T4MASK (7 << 20) +# define S3C_TCON_T4START (1 << 20) +# define S3C_TCON_T4MANUALUPD (1 << 21) +# define S3C_TCON_T4RELOAD (1 <<22) +#define S3C_TCNTB4 (S3C_TIMER_BASE + 0x3c) +#define S3C_TCNTO4 (S3C_TIMER_BASE + 0x40) + +#define TIMER_WIDTH 16 +#define TIMER_SHIFT 10 +#define PRE_MUX 3 +#define PRE_MUX_ADD 1 +static const uint32_t max = 0x0000ffff; + +static void s3c_init_t4_clk_source(void) +{ + unsigned reg; + + reg = readl(S3C_TCON) & ~S3C_TCON_T4MASK; /* stop timer 4 */ + writel(reg, S3C_TCON); + reg = readl(S3C_TCFG0) & ~S3C_TCFG0_T4MASK; + reg |= S3C_TCFG0_SET_PSCL234(0); /* 0 means pre scaler is '256' */ + writel(reg, S3C_TCFG0); + reg = readl(S3C_TCFG1) & ~S3C_TCFG1_T4MASK; + reg |= S3C_TCFG1_SET_T4MUX(PRE_MUX); /* / 16 */ + writel(reg, S3C_TCFG1); +} + +static unsigned s3c_get_t4_clk(void) +{ + unsigned clk = s3c_get_pclk(); + unsigned pre = S3C_TCFG0_GET_PSCL234(readl(S3C_TCFG0)) + 1; + unsigned div = S3C_TCFG1_GET_T4MUX(readl(S3C_TCFG1)) + PRE_MUX_ADD; + + return clk / pre / (1 << div); +} + +static void s3c_timer_init(void) +{ + unsigned tcon; + + tcon = readl(S3C_TCON) & ~S3C_TCON_T4MASK; + + writel(max, S3C_TCNTB4); /* reload value */ + /* force a manual counter update */ + writel(tcon | S3C_TCON_T4MANUALUPD, S3C_TCON); +} + +static void s3c_timer_start(void) +{ + unsigned tcon; + + tcon = readl(S3C_TCON) & ~S3C_TCON_T4MANUALUPD; + tcon |= S3C_TCON_T4START | S3C_TCON_T4RELOAD; + writel(tcon, S3C_TCON); +} + +static uint64_t s3c_clocksource_read(void) +{ + /* note: its a down counter */ + return max - readl(S3C_TCNTO4); +} + +static struct clocksource cs = { + .read = s3c_clocksource_read, + .mask = CLOCKSOURCE_MASK(TIMER_WIDTH), + .shift = TIMER_SHIFT, +}; + +static int s3c_clk_src_init(void) +{ + /* select its clock source first */ + s3c_init_t4_clk_source(); + + s3c_timer_init(); + s3c_timer_start(); + + cs.mult = clocksource_hz2mult(s3c_get_t4_clk(), cs.shift); + init_clock(&cs); + + return 0; +} +core_initcall(s3c_clk_src_init); diff --git a/arch/arm/mach-samsung/s3c24xx-clocks.c b/arch/arm/mach-samsung/s3c24xx-clocks.c new file mode 100644 index 0000000..a99d1b9 --- /dev/null +++ b/arch/arm/mach-samsung/s3c24xx-clocks.c @@ -0,0 +1,140 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Calculate the current M-PLL clock. + * @return Current frequency in Hz + */ +uint32_t s3c_get_mpllclk(void) +{ + uint32_t m, p, s, reg_val; + + reg_val = readl(S3C_MPLLCON); + m = ((reg_val & 0xFF000) >> 12) + 8; + p = ((reg_val & 0x003F0) >> 4) + 2; + s = reg_val & 0x3; +#ifdef CONFIG_CPU_S3C2410 + return (S3C24XX_CLOCK_REFERENCE * m) / (p << s); +#endif +#ifdef CONFIG_CPU_S3C2440 + return 2 * m * (S3C24XX_CLOCK_REFERENCE / (p << s)); +#endif +} + +/** + * Calculate the current U-PLL clock + * @return Current frequency in Hz + */ +uint32_t s3c_get_upllclk(void) +{ + uint32_t m, p, s, reg_val; + + reg_val = readl(S3C_UPLLCON); + m = ((reg_val & 0xFF000) >> 12) + 8; + p = ((reg_val & 0x003F0) >> 4) + 2; + s = reg_val & 0x3; + + return (S3C24XX_CLOCK_REFERENCE * m) / (p << s); +} + +/** + * Calculate the FCLK frequency used for the ARM CPU core + * @return Current frequency in Hz + */ +uint32_t s3c_get_fclk(void) +{ + return s3c_get_mpllclk(); +} + +/** + * Calculate the HCLK frequency used for the AHB bus (CPU to main peripheral) + * @return Current frequency in Hz + */ +uint32_t s3c_get_hclk(void) +{ + uint32_t f_clk; + + f_clk = s3c_get_fclk(); +#ifdef CONFIG_CPU_S3C2410 + if (readl(S3C_CLKDIVN) & 0x02) + return f_clk >> 1; +#endif +#ifdef CONFIG_CPU_S3C2440 + switch(readl(S3C_CLKDIVN) & 0x06) { + case 2: + return f_clk >> 1; + case 4: + return f_clk >> 2; /* TODO consider CAMDIVN */ + case 6: + return f_clk / 3; /* TODO consider CAMDIVN */ + } +#endif + return f_clk; +} + +/** + * Calculate the PCLK frequency used for the slower peripherals + * @return Current frequency in Hz + */ +uint32_t s3c_get_pclk(void) +{ + uint32_t p_clk; + + p_clk = s3c_get_hclk(); + if (readl(S3C_CLKDIVN) & 0x01) + return p_clk >> 1; + return p_clk; +} + +/** + * Calculate the UCLK frequency used by the USB host device + * @return Current frequency in Hz + */ +uint32_t s3c24_get_uclk(void) +{ + return s3c_get_upllclk(); +} + +/** + * Show the user the current clock settings + */ +int s3c24xx_dump_clocks(void) +{ + printf("refclk: %7d kHz\n", S3C24XX_CLOCK_REFERENCE / 1000); + printf("mpll: %7d kHz\n", s3c_get_mpllclk() / 1000); + printf("upll: %7d kHz\n", s3c_get_upllclk() / 1000); + printf("fclk: %7d kHz\n", s3c_get_fclk() / 1000); + printf("hclk: %7d kHz\n", s3c_get_hclk() / 1000); + printf("pclk: %7d kHz\n", s3c_get_pclk() / 1000); + printf("SDRAM1: CL%d@%dMHz\n", ((readl(S3C_BANKCON6) & 0xc) >> 2) + 2, + s3c_get_hclk() / 1000000); + if ((readl(S3C_BANKCON7) & (0x3 << 15)) == (0x3 << 15)) + printf("SDRAM2: CL%d@%dMHz\n", + ((readl(S3C_BANKCON7) & 0xc) >> 2) + 2, + s3c_get_hclk() / 1000000); + return 0; +} + +late_initcall(s3c24xx_dump_clocks); diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types index d593026..38e901d 100644 --- a/arch/arm/tools/mach-types +++ b/arch/arm/tools/mach-types @@ -12,7 +12,7 @@ # # http://www.arm.linux.org.uk/developer/machines/?action=new # -# Last update: Tue Dec 6 15:54:16 2011 +# Last update: Thu Jan 5 07:57:22 2012 # # machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number # @@ -2814,7 +2814,7 @@ spyplug MACH_SPYPLUG SPYPLUG 2840 ginger MACH_GINGER GINGER 2841 tny_t3530 MACH_TNY_T3530 TNY_T3530 2842 -pca102 MACH_PCA102 PCA102 2843 +pcaal1 MACH_PCAAL1 PCAAL1 2843 spade MACH_SPADE SPADE 2844 mxc25_topaz MACH_MXC25_TOPAZ MXC25_TOPAZ 2845 t5325 MACH_T5325 T5325 2846 @@ -3664,7 +3664,7 @@ amp MACH_AMP AMP 3709 gnet_amp MACH_GNET_AMP GNET_AMP 3710 toques MACH_TOQUES TOQUES 3711 -apx4devkit MACH_APX4 APX4 3712 +apx4devkit MACH_APX4DEVKIT APX4DEVKIT 3712 dct_storm MACH_DCT_STORM DCT_STORM 3713 dm8168z3 MACH_Z3 Z3 3714 owl MACH_OWL OWL 3715 @@ -3843,3 +3843,63 @@ pov2 MACH_POV2 POV2 3889 ipod_touch_2g MACH_IPOD_TOUCH_2G IPOD_TOUCH_2G 3890 da850_pqab MACH_DA850_PQAB DA850_PQAB 3891 +fermi MACH_FERMI FERMI 3892 +ccardwmx28 MACH_CCARDWMX28 CCARDWMX28 3893 +ccardmx28 MACH_CCARDMX28 CCARDMX28 3894 +fs20_fcm2050 MACH_FS20_FCM2050 FS20_FCM2050 3895 +kinetis MACH_KINETIS KINETIS 3896 +kai MACH_KAI KAI 3897 +bcthb2 MACH_BCTHB2 BCTHB2 3898 +inels3_cu MACH_INELS3_CU INELS3_CU 3899 +da850_juniper MACH_JUNIPER JUNIPER 3900 +da850_apollo MACH_DA850_APOLLO DA850_APOLLO 3901 +tracnas MACH_TRACNAS TRACNAS 3902 +mityarm335x MACH_MITYARM335X MITYARM335X 3903 +xcgz7x MACH_XCGZ7X XCGZ7X 3904 +cubox MACH_CUBOX CUBOX 3905 +terminator MACH_TERMINATOR TERMINATOR 3906 +eye03 MACH_EYE03 EYE03 3907 +kota3 MACH_KOTA3 KOTA3 3908 +mx53_nitrogen_k MACH_MX5 MX5 3909 +pscpe MACH_PSCPE PSCPE 3910 +akt1100 MACH_AKT1100 AKT1100 3911 +pcaaxl2 MACH_PCAAXL2 PCAAXL2 3912 +primodd_ct MACH_PRIMODD_CT PRIMODD_CT 3913 +nsbc MACH_NSBC NSBC 3914 +meson2_skt MACH_MESON2_SKT MESON2_SKT 3915 +meson2_ref MACH_MESON2_REF MESON2_REF 3916 +ccardwmx28js MACH_CCARDWMX28JS CCARDWMX28JS 3917 +ccardmx28js MACH_CCARDMX28JS CCARDMX28JS 3918 +indico MACH_INDICO INDICO 3919 +msm8960dt MACH_MSM8960DT MSM8960DT 3920 +primods MACH_PRIMODS PRIMODS 3921 +beluga_m1388 MACH_BELUGA_M1388 BELUGA_M1388 3922 +primotd MACH_PRIMOTD PRIMOTD 3923 +varan_master MACH_VARAN_MASTER VARAN_MASTER 3924 +primodd MACH_PRIMODD PRIMODD 3925 +jetduo MACH_JETDUO JETDUO 3926 +mx53_umobo MACH_MX53_UMOBO MX53_UMOBO 3927 +trats MACH_TRATS TRATS 3928 +starcraft MACH_STARCRAFT STARCRAFT 3929 +qseven_tegra2 MACH_QSEVEN_TEGRA2 QSEVEN_TEGRA2 3930 +lichee_sun4i_devbd MACH_LICHEE_SUN4I_DEVBD LICHEE_SUN4I_DEVBD 3931 +movenow MACH_MOVENOW MOVENOW 3932 +golf_u MACH_GOLF_U GOLF_U 3933 +msm7627a_evb MACH_MSM7627A_EVB MSM7627A_EVB 3934 +rambo MACH_RAMBO RAMBO 3935 +golfu MACH_GOLFU GOLFU 3936 +mango310 MACH_MANGO310 MANGO310 3937 +dns343 MACH_DNS343 DNS343 3938 +var_som_om44 MACH_VAR_SOM_OM44 VAR_SOM_OM44 3939 +naon MACH_NAON NAON 3940 +vp4000 MACH_VP4000 VP4000 3941 +impcard MACH_IMPCARD IMPCARD 3942 +smoovcam MACH_SMOOVCAM SMOOVCAM 3943 +cobham3725 MACH_COBHAM3725 COBHAM3725 3944 +cobham3730 MACH_COBHAM3730 COBHAM3730 3945 +cobham3703 MACH_COBHAM3703 COBHAM3703 3946 +quetzal MACH_QUETZAL QUETZAL 3947 +apq8064_cdp MACH_APQ8064_CDP APQ8064_CDP 3948 +apq8064_mtp MACH_APQ8064_MTP APQ8064_MTP 3949 +apq8064_fluid MACH_APQ8064_FLUID APQ8064_FLUID 3950 +apq8064_liquid MACH_APQ8064_LIQUID APQ8064_LIQUID 3951 diff --git a/arch/blackfin/lib/blackfin_linux.c b/arch/blackfin/lib/blackfin_linux.c index 9da9ec4..458d1b1 100644 --- a/arch/blackfin/lib/blackfin_linux.c +++ b/arch/blackfin/lib/blackfin_linux.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -44,10 +45,11 @@ int (*appl)(char *cmdline); const char *cmdline = getenv("bootargs"); char *cmdlinedest = (char *) CMD_LINE_ADDR; - struct image_handle *os_handle = idata->os; - image_header_t *os_header = &os_handle->header; - appl = (int (*)(char *))image_get_ep(os_header); + if (!idata->os_res) + return -EINVAL; + + appl = (void *)(idata->os_address + idata->os_entry); printf("Starting Kernel at 0x%p\n", appl); icache_disable(); @@ -63,8 +65,10 @@ } static struct image_handler handler = { + .name = "Blackfin Linux", .bootm = do_bootm_linux, - .image_type = IH_OS_LINUX, + .filetype = filetype_uimage, + .ih_os = IH_OS_LINUX, }; static int bfinlinux_register_image_handler(void) diff --git a/arch/nios2/boards/generic/env/config b/arch/nios2/boards/generic/env/config index 5d23098..16adc49 100644 --- a/arch/nios2/boards/generic/env/config +++ b/arch/nios2/boards/generic/env/config @@ -5,7 +5,6 @@ root=flash kernel_loc=nor -kernelimage_type=uimage # use 'dhcp' todo dhcp in barebox and in kernel ip=none diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c index b5b344f..1cd43c8 100644 --- a/arch/nios2/lib/bootm.c +++ b/arch/nios2/lib/bootm.c @@ -31,17 +31,20 @@ #include #include #include +#include #include #define NIOS_MAGIC 0x534f494e /* enable command line and initrd passing */ static int do_bootm_linux(struct image_data *idata) { - image_header_t *os_header = &idata->os->header; void (*kernel)(int, int, int, const char *); const char *commandline = getenv ("bootargs"); - kernel = (void (*)(int, int, int, const char *))ntohl(os_header->ih_ep); + if (!idata->os_res) + return -EINVAL; + + kernel = (void *)(idata->os_address + idata->os_entry); /* kernel parameters passing * r4 : NIOS magic @@ -63,8 +66,10 @@ } static struct image_handler handler = { + .name = "NIOS2 Linux", .bootm = do_bootm_linux, - .image_type = IH_OS_LINUX, + .filetype = filetype_uimage, + .ih_os = IH_OS_LINUX, }; int nios2_register_image_handler(void) diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig new file mode 100644 index 0000000..a3cb337 --- /dev/null +++ b/arch/openrisc/Kconfig @@ -0,0 +1,29 @@ +config OPENRISC + bool + select HAVE_CONFIGURABLE_MEMORY_LAYOUT + default y + +# not used +config ARCH_TEXT_BASE + hex + default 0x00000000 + +config BOARDINFO + default "Openrisc simulator" if GENERIC + +choice + prompt "Select your board" + +config GENERIC + bool "Generic " + select OPENRISC + +endchoice + +source common/Kconfig +source commands/Kconfig +source net/Kconfig +source drivers/Kconfig +source fs/Kconfig +source lib/Kconfig +source crypto/Kconfig diff --git a/arch/openrisc/Makefile b/arch/openrisc/Makefile new file mode 100644 index 0000000..fd8bbbf --- /dev/null +++ b/arch/openrisc/Makefile @@ -0,0 +1,21 @@ +CPPFLAGS += -D__OR1K__ -ffixed-r10 -mhard-mul -mhard-div + +board-$(CONFIG_GENERIC) := generic + +KALLSYMS += --symbol-prefix=_ + +archprepare: maketools + +PHONY += maketools + +ifneq ($(board-y),) +BOARD := arch/openrisc/boards/$(board-y)/ +else +BOARD := +endif + +common-y += $(BOARD) +common-y += arch/openrisc/lib/ +common-y += arch/openrisc/cpu/ + +lds-y += arch/openrisc/cpu/barebox.lds diff --git a/arch/openrisc/boards/generic/Makefile b/arch/openrisc/boards/generic/Makefile new file mode 100644 index 0000000..d8a3d7f --- /dev/null +++ b/arch/openrisc/boards/generic/Makefile @@ -0,0 +1 @@ +obj-y += generic.o diff --git a/arch/openrisc/boards/generic/config.h b/arch/openrisc/boards/generic/config.h new file mode 100644 index 0000000..88d2929 --- /dev/null +++ b/arch/openrisc/boards/generic/config.h @@ -0,0 +1,28 @@ +#ifndef _GENERIC_NAMES_H_ +#define _GENERIC_NAMES_H_ + +#define CONFIG_SYS_CLK_FREQ 20000000 + +#define OPENRISC_TIMER_FREQ 20000000 + +#define OPENRISC_SOPC_MEMORY_BASE 0x00000000 +#define OPENRISC_SOPC_MEMORY_SIZE 0x02000000 + +#define OPENRISC_SOPC_UART_BASE 0x90000000 +#define CONFIG_SYS_UART_FREQ CONFIG_SYS_CLK_FREQ +#define CONFIG_SYS_UART_BAUD 115200 + +/* We reserve 256K for barebox */ +#define BAREBOX_RESERVED_SIZE 0x40000 + +/* Barebox will be at top of main memory */ +#define OPENRISC_SOPC_TEXT_BASE (OPENRISC_SOPC_MEMORY_BASE + OPENRISC_SOPC_MEMORY_SIZE - BAREBOX_RESERVED_SIZE) + +/* +* TEXT_BASE is defined here because STACK_BASE definition +* in include/asm-generic/memory_layout.h uses this name +*/ + +#define TEXT_BASE OPENRISC_SOPC_TEXT_BASE + +#endif diff --git a/arch/openrisc/boards/generic/env/config b/arch/openrisc/boards/generic/env/config new file mode 100644 index 0000000..9dee8d9 --- /dev/null +++ b/arch/openrisc/boards/generic/env/config @@ -0,0 +1,20 @@ +#!/bin/sh + +# can be either 'net' or 'flash' +kernel=flash +root=flash + +kernel_loc=nor +kernelimage_type=uimage + +# use 'dhcp' todo dhcp in barebox and in kernel +ip=none + +autoboot_timeout=3 + +nor_parts="256k(barebox),128k(env),4M(kernel),-(rootfs)" + +bootargs="console=ttyS0,9600" + +# set a fancy prompt (if support is compiled in) +PS1="\e[1;33mbarebox@\e[1;32mor32:\w\e[0m " diff --git a/arch/openrisc/boards/generic/generic.c b/arch/openrisc/boards/generic/generic.c new file mode 100644 index 0000000..6a9ce5b --- /dev/null +++ b/arch/openrisc/boards/generic/generic.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include + +static struct NS16550_plat serial_plat = { + .clock = 50000000, /* 48MHz (APLL96/2) */ + .shift = 0, +}; + +static int openrisc_console_init(void) +{ + /* Register the serial port */ + add_ns16550_device(-1, OPENRISC_SOPC_UART_BASE, 1024, IORESOURCE_MEM_8BIT, &serial_plat); + return 0; +} + +console_initcall(openrisc_console_init); diff --git a/arch/openrisc/configs/generic_defconfig b/arch/openrisc/configs/generic_defconfig new file mode 100644 index 0000000..68e0371 --- /dev/null +++ b/arch/openrisc/configs/generic_defconfig @@ -0,0 +1,20 @@ +CONFIG_LONGHELP=y +CONFIG_HUSH_FANCY_PROMPT=y +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT_GENERIC=y +CONFIG_CMD_EDIT=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_TIME=y +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_FLASH=y +# CONFIG_CMD_BOOTM is not set +CONFIG_CMD_RESET=y +CONFIG_CMD_GO=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_DRIVER_SERIAL_NS16550=y diff --git a/arch/openrisc/cpu/Makefile b/arch/openrisc/cpu/Makefile new file mode 100644 index 0000000..1cd7506 --- /dev/null +++ b/arch/openrisc/cpu/Makefile @@ -0,0 +1,5 @@ +obj-y += start.o +obj-y += cpu.o +obj-y += exceptions.o +obj-y += cache.o +extra-y += barebox.lds diff --git a/arch/openrisc/cpu/barebox.lds.S b/arch/openrisc/cpu/barebox.lds.S new file mode 100644 index 0000000..d3e02a6 --- /dev/null +++ b/arch/openrisc/cpu/barebox.lds.S @@ -0,0 +1,98 @@ +/* + * barebox - barebox.lds.S + * + * 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_FORMAT("elf32-or32", "elf32-or32", "elf32-or32") +__DYNAMIC = 0; + +MEMORY +{ + vectors : ORIGIN = 0, LENGTH = 0x2000 + ram : ORIGIN = TEXT_BASE, + LENGTH = BAREBOX_RESERVED_SIZE +} + +SECTIONS +{ + .vectors : + { + *(.vectors) + } > vectors + + . = ALIGN(4); + __start = .; + .text : AT (__start) { + _stext = .; + *(.text) + _etext = .; + *(.lit) + *(.shdata) + _endtext = .; + } > ram + + . = ALIGN(4); + .rodata : { + *(.rodata); + *(.rodata.*) + } > ram + + . = ALIGN(4); + . = .; + __barebox_cmd_start = .; + .barebox_cmd : { BAREBOX_CMDS } > ram + __barebox_cmd_end = .; + + __barebox_magicvar_start = .; + .barebox_magicvar : { BAREBOX_MAGICVARS } > ram + __barebox_magicvar_end = .; + + __barebox_initcalls_start = .; + .barebox_initcalls : { INITCALLS } > ram + __barebox_initcalls_end = .; + + ___usymtab_start = .; + __usymtab : { BAREBOX_SYMS } > ram + ___usymtab_end = .; + + __etext = .; /* End of text and rodata section */ + + . = ALIGN(4); + .data : { + sdata = .; + _sdata = .; + *(.data) + edata = .; + _edata = .; + } > ram + + . = ALIGN(4); + .bss : + { + __bss_start = .; + _bss_start = .; + *(.shbss) + *(.bss) + *(COMMON) + _bss_end = .; + __bss_stop = .; + } > ram + __end = .; +} diff --git a/arch/openrisc/cpu/cache.c b/arch/openrisc/cpu/cache.c new file mode 100644 index 0000000..81a0d13 --- /dev/null +++ b/arch/openrisc/cpu/cache.c @@ -0,0 +1,154 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * (C) Copyright 2011, Julius Baxter + * + * 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 + +void flush_dcache_range(unsigned long addr, unsigned long stop) +{ + ulong block_size = (mfspr(SPR_DCCFGR) & SPR_DCCFGR_CBS) ? 32 : 16; + + while (addr < stop) { + mtspr(SPR_DCBFR, addr); + addr += block_size; + } +} + +void invalidate_dcache_range(unsigned long addr, unsigned long stop) +{ + ulong block_size = (mfspr(SPR_DCCFGR) & SPR_DCCFGR_CBS) ? 32 : 16; + + while (addr < stop) { + mtspr(SPR_DCBIR, addr); + addr += block_size; + } +} + +static void invalidate_icache_range(unsigned long addr, unsigned long stop) +{ + ulong block_size = (mfspr(SPR_ICCFGR) & SPR_ICCFGR_CBS) ? 32 : 16; + + while (addr < stop) { + mtspr(SPR_ICBIR, addr); + addr += block_size; + } +} + +void flush_cache(unsigned long addr, unsigned long size) +{ + flush_dcache_range(addr, addr + size); + invalidate_icache_range(addr, addr + size); +} + +int icache_status(void) +{ + return mfspr(SPR_SR) & SPR_SR_ICE; +} + +int checkicache(void) +{ + unsigned long iccfgr; + unsigned long cache_set_size; + unsigned long cache_ways; + unsigned long cache_block_size; + + iccfgr = mfspr(SPR_ICCFGR); + cache_ways = 1 << (iccfgr & SPR_ICCFGR_NCW); + cache_set_size = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3); + cache_block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16; + + return cache_set_size * cache_ways * cache_block_size; +} + +int dcache_status(void) +{ + return mfspr(SPR_SR) & SPR_SR_DCE; +} + +int checkdcache(void) +{ + unsigned long dccfgr; + unsigned long cache_set_size; + unsigned long cache_ways; + unsigned long cache_block_size; + + dccfgr = mfspr(SPR_DCCFGR); + cache_ways = 1 << (dccfgr & SPR_DCCFGR_NCW); + cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3); + cache_block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16; + + return cache_set_size * cache_ways * cache_block_size; +} + +void dcache_enable(void) +{ + mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_DCE); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); +} + +void dcache_disable(void) +{ + mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_DCE); +} + +void icache_enable(void) +{ + mtspr(SPR_SR, mfspr(SPR_SR) | SPR_SR_ICE); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); + asm volatile("l.nop"); +} + +void icache_disable(void) +{ + mtspr(SPR_SR, mfspr(SPR_SR) & ~SPR_SR_ICE); +} + +int cache_init(void) +{ + if (mfspr(SPR_UPR) & SPR_UPR_ICP) { + icache_disable(); + invalidate_icache_range(0, checkicache()); + icache_enable(); + } + + if (mfspr(SPR_UPR) & SPR_UPR_DCP) { + dcache_disable(); + invalidate_dcache_range(0, checkdcache()); + dcache_enable(); + } + + return 0; +} + +core_initcall(cache_init); diff --git a/arch/openrisc/cpu/cpu.c b/arch/openrisc/cpu/cpu.c new file mode 100644 index 0000000..48f5d03 --- /dev/null +++ b/arch/openrisc/cpu/cpu.c @@ -0,0 +1,43 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * (C) Copyright 2011, Julius Baxter + * + * 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 + +int cleanup_before_linux(void) +{ + return 0; +} + +extern void __reset(void); + +void __noreturn reset_cpu(ulong ignored) +{ + __reset(); + /* not reached, __reset does not return */ + + /* Not reached */ + while (1); +} diff --git a/arch/openrisc/cpu/exceptions.c b/arch/openrisc/cpu/exceptions.c new file mode 100644 index 0000000..a979258 --- /dev/null +++ b/arch/openrisc/cpu/exceptions.c @@ -0,0 +1,84 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * (C) Copyright 2011, Julius Baxter + * + * 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 + +static const char * const excp_table[] = { + "Unknown exception", + "Reset", + "Bus Error", + "Data Page Fault", + "Instruction Page Fault", + "Tick Timer", + "Alignment", + "Illegal Instruction", + "External Interrupt", + "D-TLB Miss", + "I-TLB Miss", + "Range", + "System Call", + "Floating Point", + "Trap", +}; + +static void (*handlers[32])(void); + +void exception_install_handler(int exception, void (*handler)(void)) +{ + if (exception < 0 || exception > 31) + return; + + handlers[exception] = handler; +} + +void exception_free_handler(int exception) +{ + if (exception < 0 || exception > 31) + return; + + handlers[exception] = 0; +} + +static void exception_hang(int vect) +{ + printf("Unhandled exception at 0x%x ", vect & 0xff00); + + vect = ((vect >> 8) & 0xff); + if (vect < ARRAY_SIZE(excp_table)) + printf("(%s)\n", excp_table[vect]); + else + printf("(%s)\n", excp_table[0]); + + printf("EPCR: 0x%08lx\n", mfspr(SPR_EPCR_BASE)); + printf("EEAR: 0x%08lx\n", mfspr(SPR_EEAR_BASE)); + printf("ESR: 0x%08lx\n", mfspr(SPR_ESR_BASE)); + hang(); +} + +void exception_handler(int vect) +{ + int exception = vect >> 8; + + if (handlers[exception]) + handlers[exception](); + else + exception_hang(vect); +} diff --git a/arch/openrisc/cpu/start.S b/arch/openrisc/cpu/start.S new file mode 100644 index 0000000..056f116 --- /dev/null +++ b/arch/openrisc/cpu/start.S @@ -0,0 +1,335 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * (C) Copyright 2011, Julius Baxter + * + * 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 EXCEPTION_STACK_SIZE (128+128) + +#define HANDLE_EXCEPTION \ + l.addi r1, r1, -EXCEPTION_STACK_SIZE ;\ + l.sw 0x1c(r1), r9 ;\ + l.jal _exception_handler ;\ + l.nop ;\ + l.lwz r9, 0x1c(r1) ;\ + l.addi r1, r1, EXCEPTION_STACK_SIZE ;\ + l.rfe ;\ + l.nop + + .section .vectors, "ax" + .global __reset + + /* reset */ + .org 0x100 +__reset: + /* there is no guarantee r0 is hardwired to zero, clear it here */ + l.andi r0, r0, 0 + /* reset stack and frame pointers */ + l.andi r1, r0, 0 + l.andi r2, r0, 0 + + /* set supervisor mode */ + l.ori r3,r0,SPR_SR_SM + l.mtspr r0,r3,SPR_SR + + /* Relocate barebox */ + l.movhi r3,hi(__start) /* source start address */ + l.ori r3,r3,lo(__start) + l.movhi r4,hi(_stext) /* dest start address */ + l.ori r4,r4,lo(_stext) + l.movhi r5,hi(__end) /* dest end address */ + l.ori r5,r5,lo(__end) + +.L_reloc: + l.lwz r6,0(r3) + l.sw 0(r4),r6 + l.addi r3,r3,4 + l.sfltu r4,r5 + l.bf .L_reloc + l.addi r4,r4,4 /*delay slot */ + +#ifdef CONFIG_SYS_RELOCATE_VECTORS + /* Relocate vectors from 0xf0000000 to 0x00000000 */ + l.movhi r4, 0xf000 /* source */ + l.movhi r5, 0 /* destination */ + l.addi r6, r5, CONFIG_SYS_VECTORS_LEN /* length */ +.L_relocvectors: + l.lwz r7, 0(r4) + l.sw 0(r5), r7 + l.addi r5, r5, 4 + l.sfeq r5,r6 + l.bnf .L_relocvectors + l.addi r4,r4, 4 +#endif + + l.j _start + l.nop + + /* bus error */ + .org 0x200 + HANDLE_EXCEPTION + + /* data page fault */ + .org 0x300 + HANDLE_EXCEPTION + + /* instruction page fault */ + .org 0x400 + HANDLE_EXCEPTION + + /* tick timer */ + .org 0x500 + HANDLE_EXCEPTION + + /* alignment */ + .org 0x600 + HANDLE_EXCEPTION + + /* illegal instruction */ + .org 0x700 + HANDLE_EXCEPTION + + /* external interrupt */ + .org 0x800 + HANDLE_EXCEPTION + + /* D-TLB miss */ + .org 0x900 + HANDLE_EXCEPTION + + /* I-TLB miss */ + .org 0xa00 + HANDLE_EXCEPTION + + /* range */ + .org 0xb00 + HANDLE_EXCEPTION + + /* system call */ + .org 0xc00 + HANDLE_EXCEPTION + + /* floating point */ + .org 0xd00 + HANDLE_EXCEPTION + + /* trap */ + .org 0xe00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0xf00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1100 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1200 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1300 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1400 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1500 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1600 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1700 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1800 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1900 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1a00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1b00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1c00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1d00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1e00 + HANDLE_EXCEPTION + + /* reserved */ + .org 0x1f00 + HANDLE_EXCEPTION + + /* Startup routine */ + .text + .global _start +_start: + /* Init stack and frame pointers */ + l.movhi r1, hi(STACK_BASE) + l.ori r1, r1, lo(STACK_BASE) + l.or r2, r0, r1 + + /* clear BSS segments */ + l.movhi r4, hi(_bss_start) + l.ori r4, r4, lo(_bss_start) + l.movhi r5, hi(_bss_end) + l.ori r5, r5, lo(_bss_end) +.L_clear_bss: + l.sw 0(r4), r0 + l.sfltu r4,r5 + l.bf .L_clear_bss + l.addi r4,r4,4 + + /* Reset registers before jumping to board_init */ + l.andi r3, r0, 0 + l.andi r4, r0, 0 + l.andi r5, r0, 0 + l.andi r6, r0, 0 + l.andi r7, r0, 0 + l.andi r8, r0, 0 + l.andi r9, r0, 0 + l.andi r10, r0, 0 + l.andi r11, r0, 0 + l.andi r12, r0, 0 + l.andi r13, r0, 0 + l.andi r14, r0, 0 + l.andi r15, r0, 0 + l.andi r17, r0, 0 + l.andi r18, r0, 0 + l.andi r19, r0, 0 + l.andi r20, r0, 0 + l.andi r21, r0, 0 + l.andi r22, r0, 0 + l.andi r23, r0, 0 + l.andi r24, r0, 0 + l.andi r25, r0, 0 + l.andi r26, r0, 0 + l.andi r27, r0, 0 + l.andi r28, r0, 0 + l.andi r29, r0, 0 + l.andi r30, r0, 0 + l.andi r31, r0, 0 + + l.j start_barebox + l.nop + + .size _start, .-_start + +/* + * Store state onto stack and call the real exception handler + */ + .section .text + .extern exception_handler + .type _exception_handler,@function + +_exception_handler: + /* Store state (r9 already saved)*/ + l.sw 0x00(r1), r2 + l.sw 0x04(r1), r3 + l.sw 0x08(r1), r4 + l.sw 0x0c(r1), r5 + l.sw 0x10(r1), r6 + l.sw 0x14(r1), r7 + l.sw 0x18(r1), r8 + l.sw 0x20(r1), r10 + l.sw 0x24(r1), r11 + l.sw 0x28(r1), r12 + l.sw 0x2c(r1), r13 + l.sw 0x30(r1), r14 + l.sw 0x34(r1), r15 + l.sw 0x38(r1), r16 + l.sw 0x3c(r1), r17 + l.sw 0x40(r1), r18 + l.sw 0x44(r1), r19 + l.sw 0x48(r1), r20 + l.sw 0x4c(r1), r21 + l.sw 0x50(r1), r22 + l.sw 0x54(r1), r23 + l.sw 0x58(r1), r24 + l.sw 0x5c(r1), r25 + l.sw 0x60(r1), r26 + l.sw 0x64(r1), r27 + l.sw 0x68(r1), r28 + l.sw 0x6c(r1), r29 + l.sw 0x70(r1), r30 + l.sw 0x74(r1), r31 + + /* Save return address */ + l.or r14, r0, r9 + /* Call exception handler with the link address as argument */ + l.jal exception_handler + l.or r3, r0, r14 + /* Load return address */ + l.or r9, r0, r14 + + /* Restore state */ + l.lwz r2, 0x00(r1) + l.lwz r3, 0x04(r1) + l.lwz r4, 0x08(r1) + l.lwz r5, 0x0c(r1) + l.lwz r6, 0x10(r1) + l.lwz r7, 0x14(r1) + l.lwz r8, 0x18(r1) + l.lwz r10, 0x20(r1) + l.lwz r11, 0x24(r1) + l.lwz r12, 0x28(r1) + l.lwz r13, 0x2c(r1) + l.lwz r14, 0x30(r1) + l.lwz r15, 0x34(r1) + l.lwz r16, 0x38(r1) + l.lwz r17, 0x3c(r1) + l.lwz r18, 0x40(r1) + l.lwz r19, 0x44(r1) + l.lwz r20, 0x48(r1) + l.lwz r21, 0x4c(r1) + l.lwz r22, 0x50(r1) + l.lwz r23, 0x54(r1) + l.lwz r24, 0x58(r1) + l.lwz r25, 0x5c(r1) + l.lwz r26, 0x60(r1) + l.lwz r27, 0x64(r1) + l.lwz r28, 0x68(r1) + l.lwz r29, 0x6c(r1) + l.lwz r30, 0x70(r1) + l.lwz r31, 0x74(r1) + l.jr r9 + l.nop diff --git a/arch/openrisc/include/asm/barebox.h b/arch/openrisc/include/asm/barebox.h new file mode 100644 index 0000000..9dd1df8 --- /dev/null +++ b/arch/openrisc/include/asm/barebox.h @@ -0,0 +1,4 @@ +#ifndef _ASM_BAREBOX_H_ +#define _ASM_BAREBOX_H_ + +#endif /* _ASM_BAREBOX_H_ */ diff --git a/arch/openrisc/include/asm/bitops.h b/arch/openrisc/include/asm/bitops.h new file mode 100644 index 0000000..c001a5d --- /dev/null +++ b/arch/openrisc/include/asm/bitops.h @@ -0,0 +1,28 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * + * 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 __ASM_OPENRISC_BITOPS_H +#define __ASM_OPENRISC_BITOPS_H + +#define PLATFORM_FLS +#include +#define PLATFORM_FFS +#include + +#endif /* __ASM_GENERIC_BITOPS_H */ diff --git a/arch/openrisc/include/asm/bitops/ffs.h b/arch/openrisc/include/asm/bitops/ffs.h new file mode 100644 index 0000000..1de5295 --- /dev/null +++ b/arch/openrisc/include/asm/bitops/ffs.h @@ -0,0 +1,26 @@ +/* + * OpenRISC Linux + * + * Copyright (C) 2010-2011 Jonas Bonn + * + * 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 __ASM_OPENRISC_FFS_H +#define __ASM_OPENRISC_FFS_H + +static inline int ffs(int x) +{ + int ret; + + __asm__ ("l.ff1 %0,%1" + : "=r" (ret) + : "r" (x)); + + return ret; +} + +#endif /* __ASM_OPENRISC_FFS_H */ diff --git a/arch/openrisc/include/asm/bitops/fls.h b/arch/openrisc/include/asm/bitops/fls.h new file mode 100644 index 0000000..8c77c13 --- /dev/null +++ b/arch/openrisc/include/asm/bitops/fls.h @@ -0,0 +1,26 @@ +/* + * OpenRISC Linux + * + * Copyright (C) 2010-2011 Jonas Bonn + * + * 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 __ASM_OPENRISC_FLS_H +#define __ASM_OPENRISC_FLS_H + +static inline int fls(int x) +{ + int ret; + + __asm__ ("l.fl1 %0,%1" + : "=r" (ret) + : "r" (x)); + + return ret; +} + +#endif /* __ASM_OPENRISC_FLS_H */ diff --git a/arch/openrisc/include/asm/byteorder.h b/arch/openrisc/include/asm/byteorder.h new file mode 100644 index 0000000..60d14f7 --- /dev/null +++ b/arch/openrisc/include/asm/byteorder.h @@ -0,0 +1 @@ +#include diff --git a/arch/openrisc/include/asm/cache.h b/arch/openrisc/include/asm/cache.h new file mode 100644 index 0000000..05cf998 --- /dev/null +++ b/arch/openrisc/include/asm/cache.h @@ -0,0 +1,47 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * + * 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 __ASM_OPENRISC_CACHE_H_ +#define __ASM_OPENRISC_CACHE_H_ + +void flush_dcache_range(unsigned long addr, unsigned long stop); +void invalidate_dcache_range(unsigned long addr, unsigned long stop); +void flush_cache(unsigned long addr, unsigned long size); +int icache_status(void); +int checkicache(void); +int dcache_status(void); +int checkdcache(void); +void dcache_enable(void); +void dcache_disable(void); +void icache_enable(void); +void icache_disable(void); + +/* + * Valid L1 data cache line sizes for the OpenRISC architecture are + * 16 and 32 bytes. + * If the board configuration has not specified one we default to the + * largest of these values for alignment of DMA buffers. + */ +#ifdef CONFIG_SYS_CACHELINE_SIZE +#define ARCH_DMA_MINALIGN CONFIG_SYS_CACHELINE_SIZE +#else +#define ARCH_DMA_MINALIGN 32 +#endif + +#endif /* __ASM_OPENRISC_CACHE_H_ */ diff --git a/arch/openrisc/include/asm/common.h b/arch/openrisc/include/asm/common.h new file mode 100644 index 0000000..027dca2 --- /dev/null +++ b/arch/openrisc/include/asm/common.h @@ -0,0 +1,4 @@ +#ifndef _ASM_COMMON_H +#define __ASM_COMMON_H + +#endif /* _ASM_COMMON_H */ diff --git a/arch/openrisc/include/asm/elf.h b/arch/openrisc/include/asm/elf.h new file mode 100644 index 0000000..6a134a5 --- /dev/null +++ b/arch/openrisc/include/asm/elf.h @@ -0,0 +1,107 @@ +/* + * OpenRISC Linux + * + * Linux architectural port borrowing liberally from similar works of + * others. All original copyrights apply as per the original source + * declaration. + * + * OpenRISC implementation: + * Copyright (C) 2003 Matjaz Breskvar + * Copyright (C) 2010-2011 Jonas Bonn + * et al. + * + * 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 __ASM_OPENRISC_ELF_H +#define __ASM_OPENRISC_ELF_H + +/* + * ELF register definitions.. + */ +#include +#include + +/* The OR1K relocation types... not all relevant for module loader */ +#define R_OR32_NONE 0 +#define R_OR32_32 1 +#define R_OR32_16 2 +#define R_OR32_8 3 +#define R_OR32_CONST 4 +#define R_OR32_CONSTH 5 +#define R_OR32_JUMPTARG 6 +#define R_OR32_VTINHERIT 7 +#define R_OR32_VTENTRY 8 + +typedef unsigned long elf_greg_t; + +/* + * Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is + * thus exposed to user-space. + */ +#define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +/* A placeholder; OR32 does not have fp support yes, so no fp regs for now. */ +typedef unsigned long elf_fpregset_t; + +/* This should be moved to include/linux/elf.h */ +#define EM_OR32 0x8472 +#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_ARCH EM_OR32 +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB + +#ifdef __KERNEL__ + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ + +#define elf_check_arch(x) \ + (((x)->e_machine == EM_OR32) || ((x)->e_machine == EM_OPENRISC)) + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (0x08000000) + +/* + * Enable dump using regset. + * This covers all of general/DSP/FPU regs. + */ +#define CORE_DUMP_USE_REGSET + +#define ELF_EXEC_PAGESIZE 8192 + +extern void dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt); +#define ELF_CORE_COPY_REGS(dest, regs) dump_elf_thread(dest, regs); + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. This could be done in userspace, + but it's not easy, and we've already done it here. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. + + For the moment, we have only optimizations for the Intel generations, + but that could change... */ + +#define ELF_PLATFORM (NULL) + +#define SET_PERSONALITY(ex) set_personality(PER_LINUX) + +#endif /* __KERNEL__ */ +#endif diff --git a/arch/openrisc/include/asm/io.h b/arch/openrisc/include/asm/io.h new file mode 100644 index 0000000..19b260a --- /dev/null +++ b/arch/openrisc/include/asm/io.h @@ -0,0 +1,123 @@ +/* + * (C) Copyright 2011, Julius Baxter + * + * 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 __ASM_OPENRISC_IO_H +#define __ASM_OPENRISC_IO_H + +#include + +/* + * Given a physical address and a length, return a virtual address + * that can be used to access the memory range with the caching + * properties specified by "flags". + */ +#define MAP_NOCACHE (0) +#define MAP_WRCOMBINE (0) +#define MAP_WRBACK (0) +#define MAP_WRTHROUGH (0) + +static inline void * +map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags) +{ + return (void *)paddr; +} + +/* + * Take down a mapping set up by map_physmem(). + */ +static inline void unmap_physmem(void *vaddr, unsigned long flags) +{ + +} + +/* + * Change virtual addresses to physical addresses + */ +static inline phys_addr_t virt_to_phys(void *vaddr) +{ + return (phys_addr_t)(vaddr); +} + + +/* + * readX/writeX() are used to access memory mapped devices. On some + * architectures the memory mapped IO stuff needs to be accessed + * differently. On the openrisc architecture, we just read/write the + * memory location directly. + */ +#define readb(addr) (*(volatile unsigned char *) (addr)) +#define readw(addr) (*(volatile unsigned short *) (addr)) +#define readl(addr) (*(volatile unsigned int *) (addr)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl + +#define writeb(b, addr) ((*(volatile unsigned char *) (addr)) = (b)) +#define writew(b, addr) ((*(volatile unsigned short *) (addr)) = (b)) +#define writel(b, addr) ((*(volatile unsigned int *) (addr)) = (b)) +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel + +#define memset_io(a, b, c) memset((void *)(a), (b), (c)) +#define memcpy_fromio(a, b, c) memcpy((a), (void *)(b), (c)) +#define memcpy_toio(a, b, c) memcpy((void *)(a), (b), (c)) + +#define out_be32(a, v) __raw_writel((v), (void __iomem __force *)(a)) +#define out_be16(a, v) __raw_writew((v), (a)) + +#define in_be32(a) __raw_readl((const void __iomem __force *)(a)) +#define in_be16(a) __raw_readw(a) + +#define writel_be(v, a) out_be32((__force unsigned *)a, v) +#define readl_be(a) in_be32((__force unsigned *)a) + +/* + * Again, OpenRISC does not require mem IO specific function. + */ + + +#define IO_BASE 0x0 +#define IO_SPACE_LIMIT 0xffffffff + +#define inb(port) readb((port + IO_BASE)) +#define outb(value, port) writeb((value), (port + IO_BASE)) +#define inb_p(port) inb((port)) +#define outb_p(value, port) outb((value), (port)) + +/* + * Convert a physical pointer to a virtual kernel pointer for /dev/mem + * access + */ +#define xlate_dev_mem_ptr(p) __va(p) + +/* + * Convert a virtual cached pointer to an uncached pointer + */ +#define xlate_dev_kmem_ptr(p) p + +#define ioread8(addr) readb(addr) +#define ioread16(addr) readw(addr) +#define ioread32(addr) readl(addr) + +#define iowrite8(v, addr) writeb((v), (addr)) +#define iowrite16(v, addr) writew((v), (addr)) +#define iowrite32(v, addr) writel((v), (addr)) + +#endif diff --git a/arch/openrisc/include/asm/openrisc_exc.h b/arch/openrisc/include/asm/openrisc_exc.h new file mode 100644 index 0000000..33f6453 --- /dev/null +++ b/arch/openrisc/include/asm/openrisc_exc.h @@ -0,0 +1,41 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * + * 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 _OPENRISC_EXC_H_ +#define _OPENRISC_EXC_H_ + +#define EXC_RESET 0x01 +#define EXC_BUS_ERROR 0x02 +#define EXC_DATA_PAGE_FAULT 0x03 +#define EXC_INSTR_PAGE_FAULT 0x04 +#define EXC_TIMER 0x05 +#define EXC_ALIGNMENT 0x06 +#define EXC_ILLEGAL_INSTR 0x07 +#define EXC_EXT_IRQ 0x08 +#define EXC_DTLB_MISS 0x09 +#define EXC_ITLB_MISS 0x0a +#define EXC_RANGE 0x0b +#define EXC_SYSCALL 0x0c +#define EXC_FLOAT_POINT 0x0d +#define EXC_TRAP 0x0e + +void exception_install_handler(int exception, void (*handler)(void)); +void exception_free_handler(int exception); + +#endif diff --git a/arch/openrisc/include/asm/posix_types.h b/arch/openrisc/include/asm/posix_types.h new file mode 100644 index 0000000..7f4c942 --- /dev/null +++ b/arch/openrisc/include/asm/posix_types.h @@ -0,0 +1,71 @@ +/* + * Based on microblaze implementation: + * Copyright (C) 2003 John Williams + * Copyright (C) 2001,2002 NEC Corporation + * Copyright (C) 2001,2002 Miles Bader + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file COPYING in the main directory of this + * archive for more details. + * + * Written by Miles Bader + * Microblaze port by John Williams + */ + +#ifndef __ASM_OPENRISC_POSIX_TYPES_H +#define __ASM_OPENRISC_POSIX_TYPES_H + +typedef unsigned long __kernel_ino_t; +typedef unsigned long long __kernel_ino64_t; +typedef unsigned int __kernel_mode_t; +typedef unsigned int __kernel_nlink_t; +typedef long __kernel_off_t; +typedef long long __kernel_loff_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned int __kernel_uid_t; +typedef unsigned int __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char *__kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(fd, fd_set) \ + __set_bit(fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) +#undef __FD_CLR +#define __FD_CLR(fd, fd_set) \ + __clear_bit(fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) +#undef __FD_ISSET +#define __FD_ISSET(fd, fd_set) \ + __test_bit(fd, (void *)&((__kernel_fd_set *)fd_set)->fds_bits) +#undef __FD_ZERO +#define __FD_ZERO(fd_set) \ + memset(fd_set, 0, sizeof(*(fd_set *)fd_set)) + +#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */ + +#endif /* __ASM_OPENRISC_POSIX_TYPES_H */ diff --git a/arch/openrisc/include/asm/ptrace.h b/arch/openrisc/include/asm/ptrace.h new file mode 100644 index 0000000..ffdea52 --- /dev/null +++ b/arch/openrisc/include/asm/ptrace.h @@ -0,0 +1,131 @@ +/* + * OpenRISC Linux + * + * Linux architectural port borrowing liberally from similar works of + * others. All original copyrights apply as per the original source + * declaration. + * + * OpenRISC implementation: + * Copyright (C) 2003 Matjaz Breskvar + * Copyright (C) 2010-2011 Jonas Bonn + * et al. + * + * 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 __ASM_OPENRISC_PTRACE_H +#define __ASM_OPENRISC_PTRACE_H + +#include + +#ifndef __ASSEMBLY__ +/* + * This is the layout of the regset returned by the GETREGSET ptrace call + */ +struct user_regs_struct { + /* GPR R0-R31... */ + unsigned long gpr[32]; + unsigned long pc; + unsigned long sr; + unsigned long pad1; + unsigned long pad2; +}; +#endif + +#ifdef __KERNEL__ + +/* + * Make kernel PTrace/register structures opaque to userspace... userspace can + * access thread state via the regset mechanism. This allows us a bit of + * flexibility in how we order the registers on the stack, permitting some + * optimizations like packing call-clobbered registers together so that + * they share a cacheline (not done yet, though... future optimization). + */ + +#ifndef __ASSEMBLY__ +/* + * This struct describes how the registers are laid out on the kernel stack + * during a syscall or other kernel entry. + * + * This structure should always be cacheline aligned on the stack. + * FIXME: I don't think that's the case right now. The alignment is + * taken care of elsewhere... head.S, process.c, etc. + */ + +struct pt_regs { + union { + struct { + /* Named registers */ + long sr; /* Stored in place of r0 */ + long sp; /* r1 */ + }; + struct { + /* Old style */ + long offset[2]; + long gprs[30]; + }; + struct { + /* New style */ + long gpr[32]; + }; + }; + long pc; + long orig_gpr11; /* For restarting system calls */ + long syscallno; /* Syscall number (used by strace) */ + long dummy; /* Cheap alignment fix */ +}; +#endif /* __ASSEMBLY__ */ + +/* TODO: Rename this to REDZONE because that's what it is */ +#define STACK_FRAME_OVERHEAD 128 /* size of minimum stack frame */ + +#define instruction_pointer(regs) ((regs)->pc) +#define user_mode(regs) (((regs)->sr & SPR_SR_SM) == 0) +#define user_stack_pointer(regs) ((unsigned long)(regs)->sp) +#define profile_pc(regs) instruction_pointer(regs) + +/* + * Offsets used by 'ptrace' system call interface. + */ +#define PT_SR 0 +#define PT_SP 4 +#define PT_GPR2 8 +#define PT_GPR3 12 +#define PT_GPR4 16 +#define PT_GPR5 20 +#define PT_GPR6 24 +#define PT_GPR7 28 +#define PT_GPR8 32 +#define PT_GPR9 36 +#define PT_GPR10 40 +#define PT_GPR11 44 +#define PT_GPR12 48 +#define PT_GPR13 52 +#define PT_GPR14 56 +#define PT_GPR15 60 +#define PT_GPR16 64 +#define PT_GPR17 68 +#define PT_GPR18 72 +#define PT_GPR19 76 +#define PT_GPR20 80 +#define PT_GPR21 84 +#define PT_GPR22 88 +#define PT_GPR23 92 +#define PT_GPR24 96 +#define PT_GPR25 100 +#define PT_GPR26 104 +#define PT_GPR27 108 +#define PT_GPR28 112 +#define PT_GPR29 116 +#define PT_GPR30 120 +#define PT_GPR31 124 +#define PT_PC 128 +#define PT_ORIG_GPR11 132 +#define PT_SYSCALLNO 136 + +#endif /* __KERNEL__ */ + +#endif /* __ASM_OPENRISC_PTRACE_H */ diff --git a/arch/openrisc/include/asm/sections.h b/arch/openrisc/include/asm/sections.h new file mode 100644 index 0000000..2b8c516 --- /dev/null +++ b/arch/openrisc/include/asm/sections.h @@ -0,0 +1 @@ +#include diff --git a/arch/openrisc/include/asm/spr-defs.h b/arch/openrisc/include/asm/spr-defs.h new file mode 100644 index 0000000..cb0cdfa --- /dev/null +++ b/arch/openrisc/include/asm/spr-defs.h @@ -0,0 +1,567 @@ +/* + * SPR Definitions + * + * Copyright (C) 2000 Damjan Lampret + * Copyright (C) 2003 Matjaz Breskvar + * Copyright (C) 2008, 2010 Embecosm Limited + * Copyright (C) 2010-2011 Jonas Bonn + * et al. + * + * 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 file is part of OpenRISC 1000 Architectural Simulator. + */ + +#ifndef SPR_DEFS__H +#define SPR_DEFS__H + +/* Definition of special-purpose registers (SPRs) */ + +#define MAX_GRPS (32) +#define MAX_SPRS_PER_GRP_BITS (11) +#define MAX_SPRS_PER_GRP (1 << MAX_SPRS_PER_GRP_BITS) +#define MAX_SPRS (0x10000) + +/* Base addresses for the groups */ +#define SPRGROUP_SYS (0 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_DMMU (1 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_IMMU (2 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_DC (3 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_IC (4 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_MAC (5 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_D (6 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_PC (7 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_PM (8 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_PIC (9 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_TT (10 << MAX_SPRS_PER_GRP_BITS) +#define SPRGROUP_FP (11 << MAX_SPRS_PER_GRP_BITS) + +/* System control and status group */ +#define SPR_VR (SPRGROUP_SYS + 0) +#define SPR_UPR (SPRGROUP_SYS + 1) +#define SPR_CPUCFGR (SPRGROUP_SYS + 2) +#define SPR_DMMUCFGR (SPRGROUP_SYS + 3) +#define SPR_IMMUCFGR (SPRGROUP_SYS + 4) +#define SPR_DCCFGR (SPRGROUP_SYS + 5) +#define SPR_ICCFGR (SPRGROUP_SYS + 6) +#define SPR_DCFGR (SPRGROUP_SYS + 7) +#define SPR_PCCFGR (SPRGROUP_SYS + 8) +#define SPR_NPC (SPRGROUP_SYS + 16) +#define SPR_SR (SPRGROUP_SYS + 17) +#define SPR_PPC (SPRGROUP_SYS + 18) +#define SPR_FPCSR (SPRGROUP_SYS + 20) +#define SPR_EPCR_BASE (SPRGROUP_SYS + 32) +#define SPR_EPCR_LAST (SPRGROUP_SYS + 47) +#define SPR_EEAR_BASE (SPRGROUP_SYS + 48) +#define SPR_EEAR_LAST (SPRGROUP_SYS + 63) +#define SPR_ESR_BASE (SPRGROUP_SYS + 64) +#define SPR_ESR_LAST (SPRGROUP_SYS + 79) +#define SPR_GPR_BASE (SPRGROUP_SYS + 1024) + +/* Data MMU group */ +#define SPR_DMMUCR (SPRGROUP_DMMU + 0) +#define SPR_DTLBEIR (SPRGROUP_DMMU + 2) +#define SPR_DTLBMR_BASE(WAY) (SPRGROUP_DMMU + 0x200 + (WAY) * 0x100) +#define SPR_DTLBMR_LAST(WAY) (SPRGROUP_DMMU + 0x27f + (WAY) * 0x100) +#define SPR_DTLBTR_BASE(WAY) (SPRGROUP_DMMU + 0x280 + (WAY) * 0x100) +#define SPR_DTLBTR_LAST(WAY) (SPRGROUP_DMMU + 0x2ff + (WAY) * 0x100) + +/* Instruction MMU group */ +#define SPR_IMMUCR (SPRGROUP_IMMU + 0) +#define SPR_ITLBEIR (SPRGROUP_IMMU + 2) +#define SPR_ITLBMR_BASE(WAY) (SPRGROUP_IMMU + 0x200 + (WAY) * 0x100) +#define SPR_ITLBMR_LAST(WAY) (SPRGROUP_IMMU + 0x27f + (WAY) * 0x100) +#define SPR_ITLBTR_BASE(WAY) (SPRGROUP_IMMU + 0x280 + (WAY) * 0x100) +#define SPR_ITLBTR_LAST(WAY) (SPRGROUP_IMMU + 0x2ff + (WAY) * 0x100) + +/* Data cache group */ +#define SPR_DCCR (SPRGROUP_DC + 0) +#define SPR_DCBPR (SPRGROUP_DC + 1) +#define SPR_DCBFR (SPRGROUP_DC + 2) +#define SPR_DCBIR (SPRGROUP_DC + 3) +#define SPR_DCBWR (SPRGROUP_DC + 4) +#define SPR_DCBLR (SPRGROUP_DC + 5) +#define SPR_DCR_BASE(WAY) (SPRGROUP_DC + 0x200 + (WAY) * 0x200) +#define SPR_DCR_LAST(WAY) (SPRGROUP_DC + 0x3ff + (WAY) * 0x200) + +/* Instruction cache group */ +#define SPR_ICCR (SPRGROUP_IC + 0) +#define SPR_ICBPR (SPRGROUP_IC + 1) +#define SPR_ICBIR (SPRGROUP_IC + 2) +#define SPR_ICBLR (SPRGROUP_IC + 3) +#define SPR_ICR_BASE(WAY) (SPRGROUP_IC + 0x200 + (WAY) * 0x200) +#define SPR_ICR_LAST(WAY) (SPRGROUP_IC + 0x3ff + (WAY) * 0x200) + +/* MAC group */ +#define SPR_MACLO (SPRGROUP_MAC + 1) +#define SPR_MACHI (SPRGROUP_MAC + 2) + +/* Debug group */ +#define SPR_DVR(N) (SPRGROUP_D + (N)) +#define SPR_DCR(N) (SPRGROUP_D + 8 + (N)) +#define SPR_DMR1 (SPRGROUP_D + 16) +#define SPR_DMR2 (SPRGROUP_D + 17) +#define SPR_DWCR0 (SPRGROUP_D + 18) +#define SPR_DWCR1 (SPRGROUP_D + 19) +#define SPR_DSR (SPRGROUP_D + 20) +#define SPR_DRR (SPRGROUP_D + 21) + +/* Performance counters group */ +#define SPR_PCCR(N) (SPRGROUP_PC + (N)) +#define SPR_PCMR(N) (SPRGROUP_PC + 8 + (N)) + +/* Power management group */ +#define SPR_PMR (SPRGROUP_PM + 0) + +/* PIC group */ +#define SPR_PICMR (SPRGROUP_PIC + 0) +#define SPR_PICPR (SPRGROUP_PIC + 1) +#define SPR_PICSR (SPRGROUP_PIC + 2) + +/* Tick Timer group */ +#define SPR_TTMR (SPRGROUP_TT + 0) +#define SPR_TTCR (SPRGROUP_TT + 1) + +/* + * Bit definitions for the Version Register + */ +#define SPR_VR_VER 0xff000000 /* Processor version */ +#define SPR_VR_CFG 0x00ff0000 /* Processor configuration */ +#define SPR_VR_RES 0x0000ffc0 /* Reserved */ +#define SPR_VR_REV 0x0000003f /* Processor revision */ + +#define SPR_VR_VER_OFF 24 +#define SPR_VR_CFG_OFF 16 +#define SPR_VR_REV_OFF 0 + +/* + * Bit definitions for the Unit Present Register + */ +#define SPR_UPR_UP 0x00000001 /* UPR present */ +#define SPR_UPR_DCP 0x00000002 /* Data cache present */ +#define SPR_UPR_ICP 0x00000004 /* Instruction cache present */ +#define SPR_UPR_DMP 0x00000008 /* Data MMU present */ +#define SPR_UPR_IMP 0x00000010 /* Instruction MMU present */ +#define SPR_UPR_MP 0x00000020 /* MAC present */ +#define SPR_UPR_DUP 0x00000040 /* Debug unit present */ +#define SPR_UPR_PCUP 0x00000080 /* Performance counters unit present */ +#define SPR_UPR_PMP 0x00000100 /* Power management present */ +#define SPR_UPR_PICP 0x00000200 /* PIC present */ +#define SPR_UPR_TTP 0x00000400 /* Tick timer present */ +#define SPR_UPR_RES 0x00fe0000 /* Reserved */ +#define SPR_UPR_CUP 0xff000000 /* Context units present */ + +/* + * Bit definitions for the CPU configuration register + */ +#define SPR_CPUCFGR_NSGF 0x0000000f /* Number of shadow GPR files */ +#define SPR_CPUCFGR_CGF 0x00000010 /* Custom GPR file */ +#define SPR_CPUCFGR_OB32S 0x00000020 /* ORBIS32 supported */ +#define SPR_CPUCFGR_OB64S 0x00000040 /* ORBIS64 supported */ +#define SPR_CPUCFGR_OF32S 0x00000080 /* ORFPX32 supported */ +#define SPR_CPUCFGR_OF64S 0x00000100 /* ORFPX64 supported */ +#define SPR_CPUCFGR_OV64S 0x00000200 /* ORVDX64 supported */ +#define SPR_CPUCFGR_RES 0xfffffc00 /* Reserved */ + +/* + * Bit definitions for the Debug configuration register and other + * constants. + */ + +#define SPR_DCFGR_NDP 0x00000007 /* Number of matchpoints mask */ +#define SPR_DCFGR_NDP1 0x00000000 /* One matchpoint supported */ +#define SPR_DCFGR_NDP2 0x00000001 /* Two matchpoints supported */ +#define SPR_DCFGR_NDP3 0x00000002 /* Three matchpoints supported */ +#define SPR_DCFGR_NDP4 0x00000003 /* Four matchpoints supported */ +#define SPR_DCFGR_NDP5 0x00000004 /* Five matchpoints supported */ +#define SPR_DCFGR_NDP6 0x00000005 /* Six matchpoints supported */ +#define SPR_DCFGR_NDP7 0x00000006 /* Seven matchpoints supported */ +#define SPR_DCFGR_NDP8 0x00000007 /* Eight matchpoints supported */ +#define SPR_DCFGR_WPCI 0x00000008 /* Watchpoint counters implemented */ + +#define MATCHPOINTS_TO_NDP(n) (1 == n ? SPR_DCFGR_NDP1 : \ + 2 == n ? SPR_DCFGR_NDP2 : \ + 3 == n ? SPR_DCFGR_NDP3 : \ + 4 == n ? SPR_DCFGR_NDP4 : \ + 5 == n ? SPR_DCFGR_NDP5 : \ + 6 == n ? SPR_DCFGR_NDP6 : \ + 7 == n ? SPR_DCFGR_NDP7 : SPR_DCFGR_NDP8) +#define MAX_MATCHPOINTS 8 +#define MAX_WATCHPOINTS (MAX_MATCHPOINTS + 2) + +/* + * Bit definitions for the Supervision Register + */ +#define SPR_SR_SM 0x00000001 /* Supervisor Mode */ +#define SPR_SR_TEE 0x00000002 /* Tick timer Exception Enable */ +#define SPR_SR_IEE 0x00000004 /* Interrupt Exception Enable */ +#define SPR_SR_DCE 0x00000008 /* Data Cache Enable */ +#define SPR_SR_ICE 0x00000010 /* Instruction Cache Enable */ +#define SPR_SR_DME 0x00000020 /* Data MMU Enable */ +#define SPR_SR_IME 0x00000040 /* Instruction MMU Enable */ +#define SPR_SR_LEE 0x00000080 /* Little Endian Enable */ +#define SPR_SR_CE 0x00000100 /* CID Enable */ +#define SPR_SR_F 0x00000200 /* Condition Flag */ +#define SPR_SR_CY 0x00000400 /* Carry flag */ +#define SPR_SR_OV 0x00000800 /* Overflow flag */ +#define SPR_SR_OVE 0x00001000 /* Overflow flag Exception */ +#define SPR_SR_DSX 0x00002000 /* Delay Slot Exception */ +#define SPR_SR_EPH 0x00004000 /* Exception Prefix High */ +#define SPR_SR_FO 0x00008000 /* Fixed one */ +#define SPR_SR_SUMRA 0x00010000 /* Supervisor SPR read access */ +#define SPR_SR_RES 0x0ffe0000 /* Reserved */ +#define SPR_SR_CID 0xf0000000 /* Context ID */ + +/* + * Bit definitions for the Data MMU Control Register + */ +#define SPR_DMMUCR_P2S 0x0000003e /* Level 2 Page Size */ +#define SPR_DMMUCR_P1S 0x000007c0 /* Level 1 Page Size */ +#define SPR_DMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */ +#define SPR_DMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */ + +/* + * Bit definitions for the Instruction MMU Control Register + */ +#define SPR_IMMUCR_P2S 0x0000003e /* Level 2 Page Size */ +#define SPR_IMMUCR_P1S 0x000007c0 /* Level 1 Page Size */ +#define SPR_IMMUCR_VADDR_WIDTH 0x0000f800 /* Virtual ADDR Width */ +#define SPR_IMMUCR_PADDR_WIDTH 0x000f0000 /* Physical ADDR Width */ + +/* + * Bit definitions for the Data TLB Match Register + */ +#define SPR_DTLBMR_V 0x00000001 /* Valid */ +#define SPR_DTLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ +#define SPR_DTLBMR_CID 0x0000003c /* Context ID */ +#define SPR_DTLBMR_LRU 0x000000c0 /* Least Recently Used */ +#define SPR_DTLBMR_VPN 0xfffff000 /* Virtual Page Number */ + +/* + * Bit definitions for the Data TLB Translate Register + */ +#define SPR_DTLBTR_CC 0x00000001 /* Cache Coherency */ +#define SPR_DTLBTR_CI 0x00000002 /* Cache Inhibit */ +#define SPR_DTLBTR_WBC 0x00000004 /* Write-Back Cache */ +#define SPR_DTLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */ +#define SPR_DTLBTR_A 0x00000010 /* Accessed */ +#define SPR_DTLBTR_D 0x00000020 /* Dirty */ +#define SPR_DTLBTR_URE 0x00000040 /* User Read Enable */ +#define SPR_DTLBTR_UWE 0x00000080 /* User Write Enable */ +#define SPR_DTLBTR_SRE 0x00000100 /* Supervisor Read Enable */ +#define SPR_DTLBTR_SWE 0x00000200 /* Supervisor Write Enable */ +#define SPR_DTLBTR_PPN 0xfffff000 /* Physical Page Number */ + +/* + * Bit definitions for the Instruction TLB Match Register + */ +#define SPR_ITLBMR_V 0x00000001 /* Valid */ +#define SPR_ITLBMR_PL1 0x00000002 /* Page Level 1 (if 0 then PL2) */ +#define SPR_ITLBMR_CID 0x0000003c /* Context ID */ +#define SPR_ITLBMR_LRU 0x000000c0 /* Least Recently Used */ +#define SPR_ITLBMR_VPN 0xfffff000 /* Virtual Page Number */ + +/* + * Bit definitions for the Instruction TLB Translate Register + */ +#define SPR_ITLBTR_CC 0x00000001 /* Cache Coherency */ +#define SPR_ITLBTR_CI 0x00000002 /* Cache Inhibit */ +#define SPR_ITLBTR_WBC 0x00000004 /* Write-Back Cache */ +#define SPR_ITLBTR_WOM 0x00000008 /* Weakly-Ordered Memory */ +#define SPR_ITLBTR_A 0x00000010 /* Accessed */ +#define SPR_ITLBTR_D 0x00000020 /* Dirty */ +#define SPR_ITLBTR_SXE 0x00000040 /* User Read Enable */ +#define SPR_ITLBTR_UXE 0x00000080 /* User Write Enable */ +#define SPR_ITLBTR_PPN 0xfffff000 /* Physical Page Number */ + +/* + * Bit definitions for Data Cache Control register + */ +#define SPR_DCCR_EW 0x000000ff /* Enable ways */ + +/* + * Bit definitions for Insn Cache Control register + */ +#define SPR_ICCR_EW 0x000000ff /* Enable ways */ + +/* + * Bit definitions for Data Cache Configuration Register + */ + +#define SPR_DCCFGR_NCW 0x00000007 +#define SPR_DCCFGR_NCS 0x00000078 +#define SPR_DCCFGR_CBS 0x00000080 +#define SPR_DCCFGR_CWS 0x00000100 +#define SPR_DCCFGR_CCRI 0x00000200 +#define SPR_DCCFGR_CBIRI 0x00000400 +#define SPR_DCCFGR_CBPRI 0x00000800 +#define SPR_DCCFGR_CBLRI 0x00001000 +#define SPR_DCCFGR_CBFRI 0x00002000 +#define SPR_DCCFGR_CBWBRI 0x00004000 + +#define SPR_DCCFGR_NCW_OFF 0 +#define SPR_DCCFGR_NCS_OFF 3 +#define SPR_DCCFGR_CBS_OFF 7 + +/* + * Bit definitions for Instruction Cache Configuration Register + */ +#define SPR_ICCFGR_NCW 0x00000007 +#define SPR_ICCFGR_NCS 0x00000078 +#define SPR_ICCFGR_CBS 0x00000080 +#define SPR_ICCFGR_CCRI 0x00000200 +#define SPR_ICCFGR_CBIRI 0x00000400 +#define SPR_ICCFGR_CBPRI 0x00000800 +#define SPR_ICCFGR_CBLRI 0x00001000 + +#define SPR_ICCFGR_NCW_OFF 0 +#define SPR_ICCFGR_NCS_OFF 3 +#define SPR_ICCFGR_CBS_OFF 7 + +/* + * Bit definitions for Data MMU Configuration Register + */ +#define SPR_DMMUCFGR_NTW 0x00000003 +#define SPR_DMMUCFGR_NTS 0x0000001C +#define SPR_DMMUCFGR_NAE 0x000000E0 +#define SPR_DMMUCFGR_CRI 0x00000100 +#define SPR_DMMUCFGR_PRI 0x00000200 +#define SPR_DMMUCFGR_TEIRI 0x00000400 +#define SPR_DMMUCFGR_HTR 0x00000800 + +#define SPR_DMMUCFGR_NTW_OFF 0 +#define SPR_DMMUCFGR_NTS_OFF 2 + +/* + * Bit definitions for Instruction MMU Configuration Register + */ +#define SPR_IMMUCFGR_NTW 0x00000003 +#define SPR_IMMUCFGR_NTS 0x0000001C +#define SPR_IMMUCFGR_NAE 0x000000E0 +#define SPR_IMMUCFGR_CRI 0x00000100 +#define SPR_IMMUCFGR_PRI 0x00000200 +#define SPR_IMMUCFGR_TEIRI 0x00000400 +#define SPR_IMMUCFGR_HTR 0x00000800 + +#define SPR_IMMUCFGR_NTW_OFF 0 +#define SPR_IMMUCFGR_NTS_OFF 2 + +/* + * Bit definitions for Debug Control registers + */ +#define SPR_DCR_DP 0x00000001 /* DVR/DCR present */ +#define SPR_DCR_CC 0x0000000e /* Compare condition */ +#define SPR_DCR_SC 0x00000010 /* Signed compare */ +#define SPR_DCR_CT 0x000000e0 /* Compare to */ + +/* Bit results with SPR_DCR_CC mask */ +#define SPR_DCR_CC_MASKED 0x00000000 +#define SPR_DCR_CC_EQUAL 0x00000002 +#define SPR_DCR_CC_LESS 0x00000004 +#define SPR_DCR_CC_LESSE 0x00000006 +#define SPR_DCR_CC_GREAT 0x00000008 +#define SPR_DCR_CC_GREATE 0x0000000a +#define SPR_DCR_CC_NEQUAL 0x0000000c + +/* Bit results with SPR_DCR_CT mask */ +#define SPR_DCR_CT_DISABLED 0x00000000 +#define SPR_DCR_CT_IFEA 0x00000020 +#define SPR_DCR_CT_LEA 0x00000040 +#define SPR_DCR_CT_SEA 0x00000060 +#define SPR_DCR_CT_LD 0x00000080 +#define SPR_DCR_CT_SD 0x000000a0 +#define SPR_DCR_CT_LSEA 0x000000c0 +#define SPR_DCR_CT_LSD 0x000000e0 + +/* + * Bit definitions for Debug Mode 1 register + */ +#define SPR_DMR1_CW 0x000fffff /* Chain register pair data */ +#define SPR_DMR1_CW0_AND 0x00000001 +#define SPR_DMR1_CW0_OR 0x00000002 +#define SPR_DMR1_CW0 (SPR_DMR1_CW0_AND | SPR_DMR1_CW0_OR) +#define SPR_DMR1_CW1_AND 0x00000004 +#define SPR_DMR1_CW1_OR 0x00000008 +#define SPR_DMR1_CW1 (SPR_DMR1_CW1_AND | SPR_DMR1_CW1_OR) +#define SPR_DMR1_CW2_AND 0x00000010 +#define SPR_DMR1_CW2_OR 0x00000020 +#define SPR_DMR1_CW2 (SPR_DMR1_CW2_AND | SPR_DMR1_CW2_OR) +#define SPR_DMR1_CW3_AND 0x00000040 +#define SPR_DMR1_CW3_OR 0x00000080 +#define SPR_DMR1_CW3 (SPR_DMR1_CW3_AND | SPR_DMR1_CW3_OR) +#define SPR_DMR1_CW4_AND 0x00000100 +#define SPR_DMR1_CW4_OR 0x00000200 +#define SPR_DMR1_CW4 (SPR_DMR1_CW4_AND | SPR_DMR1_CW4_OR) +#define SPR_DMR1_CW5_AND 0x00000400 +#define SPR_DMR1_CW5_OR 0x00000800 +#define SPR_DMR1_CW5 (SPR_DMR1_CW5_AND | SPR_DMR1_CW5_OR) +#define SPR_DMR1_CW6_AND 0x00001000 +#define SPR_DMR1_CW6_OR 0x00002000 +#define SPR_DMR1_CW6 (SPR_DMR1_CW6_AND | SPR_DMR1_CW6_OR) +#define SPR_DMR1_CW7_AND 0x00004000 +#define SPR_DMR1_CW7_OR 0x00008000 +#define SPR_DMR1_CW7 (SPR_DMR1_CW7_AND | SPR_DMR1_CW7_OR) +#define SPR_DMR1_CW8_AND 0x00010000 +#define SPR_DMR1_CW8_OR 0x00020000 +#define SPR_DMR1_CW8 (SPR_DMR1_CW8_AND | SPR_DMR1_CW8_OR) +#define SPR_DMR1_CW9_AND 0x00040000 +#define SPR_DMR1_CW9_OR 0x00080000 +#define SPR_DMR1_CW9 (SPR_DMR1_CW9_AND | SPR_DMR1_CW9_OR) +#define SPR_DMR1_RES1 0x00300000 /* Reserved */ +#define SPR_DMR1_ST 0x00400000 /* Single-step trace*/ +#define SPR_DMR1_BT 0x00800000 /* Branch trace */ +#define SPR_DMR1_RES2 0xff000000 /* Reserved */ + +/* + * Bit definitions for Debug Mode 2 register. AWTC and WGB corrected by JPB + */ +#define SPR_DMR2_WCE0 0x00000001 /* Watchpoint counter 0 enable */ +#define SPR_DMR2_WCE1 0x00000002 /* Watchpoint counter 0 enable */ +#define SPR_DMR2_AWTC 0x00000ffc /* Assign watchpoints to counters */ +#define SPR_DMR2_AWTC_OFF 2 /* Bit offset to AWTC field */ +#define SPR_DMR2_WGB 0x003ff000 /* Watch generating breakpoint */ +#define SPR_DMR2_WGB_OFF 12 /* Bit offset to WGB field */ +#define SPR_DMR2_WBS 0xffc00000 /* Watchpoint status */ +#define SPR_DMR2_WBS_OFF 22 /* Bit offset to WBS field */ + +/* + * Bit definitions for Debug watchpoint counter registers + */ +#define SPR_DWCR_COUNT 0x0000ffff /* Count */ +#define SPR_DWCR_MATCH 0xffff0000 /* Match */ +#define SPR_DWCR_MATCH_OFF 16 /* Match bit offset */ + +/* + * Bit definitions for Debug stop register + * + */ +#define SPR_DSR_RSTE 0x00000001 /* Reset exception */ +#define SPR_DSR_BUSEE 0x00000002 /* Bus error exception */ +#define SPR_DSR_DPFE 0x00000004 /* Data Page Fault exception */ +#define SPR_DSR_IPFE 0x00000008 /* Insn Page Fault exception */ +#define SPR_DSR_TTE 0x00000010 /* Tick Timer exception */ +#define SPR_DSR_AE 0x00000020 /* Alignment exception */ +#define SPR_DSR_IIE 0x00000040 /* Illegal Instruction exception */ +#define SPR_DSR_IE 0x00000080 /* Interrupt exception */ +#define SPR_DSR_DME 0x00000100 /* DTLB miss exception */ +#define SPR_DSR_IME 0x00000200 /* ITLB miss exception */ +#define SPR_DSR_RE 0x00000400 /* Range exception */ +#define SPR_DSR_SCE 0x00000800 /* System call exception */ +#define SPR_DSR_FPE 0x00001000 /* Floating Point Exception */ +#define SPR_DSR_TE 0x00002000 /* Trap exception */ + +/* + * Bit definitions for Debug reason register + */ +#define SPR_DRR_RSTE 0x00000001 /* Reset exception */ +#define SPR_DRR_BUSEE 0x00000002 /* Bus error exception */ +#define SPR_DRR_DPFE 0x00000004 /* Data Page Fault exception */ +#define SPR_DRR_IPFE 0x00000008 /* Insn Page Fault exception */ +#define SPR_DRR_TTE 0x00000010 /* Tick Timer exception */ +#define SPR_DRR_AE 0x00000020 /* Alignment exception */ +#define SPR_DRR_IIE 0x00000040 /* Illegal Instruction exception */ +#define SPR_DRR_IE 0x00000080 /* Interrupt exception */ +#define SPR_DRR_DME 0x00000100 /* DTLB miss exception */ +#define SPR_DRR_IME 0x00000200 /* ITLB miss exception */ +#define SPR_DRR_RE 0x00000400 /* Range exception */ +#define SPR_DRR_SCE 0x00000800 /* System call exception */ +#define SPR_DRR_FPE 0x00001000 /* Floating Point Exception */ +#define SPR_DRR_TE 0x00002000 /* Trap exception */ + +/* + * Bit definitions for Performance counters mode registers + */ +#define SPR_PCMR_CP 0x00000001 /* Counter present */ +#define SPR_PCMR_UMRA 0x00000002 /* User mode read access */ +#define SPR_PCMR_CISM 0x00000004 /* Count in supervisor mode */ +#define SPR_PCMR_CIUM 0x00000008 /* Count in user mode */ +#define SPR_PCMR_LA 0x00000010 /* Load access event */ +#define SPR_PCMR_SA 0x00000020 /* Store access event */ +#define SPR_PCMR_IF 0x00000040 /* Instruction fetch event*/ +#define SPR_PCMR_DCM 0x00000080 /* Data cache miss event */ +#define SPR_PCMR_ICM 0x00000100 /* Insn cache miss event */ +#define SPR_PCMR_IFS 0x00000200 /* Insn fetch stall event */ +#define SPR_PCMR_LSUS 0x00000400 /* LSU stall event */ +#define SPR_PCMR_BS 0x00000800 /* Branch stall event */ +#define SPR_PCMR_DTLBM 0x00001000 /* DTLB miss event */ +#define SPR_PCMR_ITLBM 0x00002000 /* ITLB miss event */ +#define SPR_PCMR_DDS 0x00004000 /* Data dependency stall event */ +#define SPR_PCMR_WPE 0x03ff8000 /* Watchpoint events */ + +/* + * Bit definitions for the Power management register + */ +#define SPR_PMR_SDF 0x0000000f /* Slow down factor */ +#define SPR_PMR_DME 0x00000010 /* Doze mode enable */ +#define SPR_PMR_SME 0x00000020 /* Sleep mode enable */ +#define SPR_PMR_DCGE 0x00000040 /* Dynamic clock gating enable */ +#define SPR_PMR_SUME 0x00000080 /* Suspend mode enable */ + +/* + * Bit definitions for PICMR + */ +#define SPR_PICMR_IUM 0xfffffffc /* Interrupt unmask */ + +/* + * Bit definitions for PICPR + */ +#define SPR_PICPR_IPRIO 0xfffffffc /* Interrupt priority */ + +/* + * Bit definitions for PICSR + */ +#define SPR_PICSR_IS 0xffffffff /* Interrupt status */ + +/* + * Bit definitions for Tick Timer Control Register + */ +#define SPR_TTCR_CNT 0xffffffff /* Count, time period */ +#define SPR_TTMR_TP 0x0fffffff /* Time period */ +#define SPR_TTMR_IP 0x10000000 /* Interrupt Pending */ +#define SPR_TTMR_IE 0x20000000 /* Interrupt Enable */ +#define SPR_TTMR_DI 0x00000000 /* Disabled */ +#define SPR_TTMR_RT 0x40000000 /* Restart tick */ +#define SPR_TTMR_SR 0x80000000 /* Single run */ +#define SPR_TTMR_CR 0xc0000000 /* Continuous run */ +#define SPR_TTMR_M 0xc0000000 /* Tick mode */ + +/* + * Bit definitions for the FP Control Status Register + */ +#define SPR_FPCSR_FPEE 0x00000001 /* Floating Point Exception Enable */ +#define SPR_FPCSR_RM 0x00000006 /* Rounding Mode */ +#define SPR_FPCSR_OVF 0x00000008 /* Overflow Flag */ +#define SPR_FPCSR_UNF 0x00000010 /* Underflow Flag */ +#define SPR_FPCSR_SNF 0x00000020 /* SNAN Flag */ +#define SPR_FPCSR_QNF 0x00000040 /* QNAN Flag */ +#define SPR_FPCSR_ZF 0x00000080 /* Zero Flag */ +#define SPR_FPCSR_IXF 0x00000100 /* Inexact Flag */ +#define SPR_FPCSR_IVF 0x00000200 /* Invalid Flag */ +#define SPR_FPCSR_INF 0x00000400 /* Infinity Flag */ +#define SPR_FPCSR_DZF 0x00000800 /* Divide By Zero Flag */ +#define SPR_FPCSR_ALLF (SPR_FPCSR_OVF | SPR_FPCSR_UNF | SPR_FPCSR_SNF | \ + SPR_FPCSR_QNF | SPR_FPCSR_ZF | SPR_FPCSR_IXF | \ + SPR_FPCSR_IVF | SPR_FPCSR_INF | SPR_FPCSR_DZF) + +#define FPCSR_RM_RN (0<<1) +#define FPCSR_RM_RZ (1<<1) +#define FPCSR_RM_RIP (2<<1) +#define FPCSR_RM_RIN (3<<1) + +/* + * l.nop constants + */ +#define NOP_NOP 0x0000 /* Normal nop instruction */ +#define NOP_EXIT 0x0001 /* End of simulation */ +#define NOP_REPORT 0x0002 /* Simple report */ +#define NOP_PUTC 0x0004 /* Simputc instruction */ +#define NOP_CNT_RESET 0x0005 /* Reset statistics counters */ +#define NOP_GET_TICKS 0x0006 /* Get # ticks running */ +#define NOP_GET_PS 0x0007 /* Get picosecs/cycle */ +#define NOP_REPORT_FIRST 0x0400 /* Report with number */ +#define NOP_REPORT_LAST 0x03ff /* Report with number */ + +#endif /* SPR_DEFS__H */ diff --git a/arch/openrisc/include/asm/string.h b/arch/openrisc/include/asm/string.h new file mode 100644 index 0000000..73e2655 --- /dev/null +++ b/arch/openrisc/include/asm/string.h @@ -0,0 +1,4 @@ +#ifndef __ASM_OPENRISC_STRING_H +#define __ASM_OPENRISC_STRING_H + +#endif diff --git a/arch/openrisc/include/asm/swab.h b/arch/openrisc/include/asm/swab.h new file mode 100644 index 0000000..b07e1d5 --- /dev/null +++ b/arch/openrisc/include/asm/swab.h @@ -0,0 +1,4 @@ +#ifndef _ASM_SWAB_H +#define _ASM_SWAB_H + +#endif /* _ASM_SWAB_H */ diff --git a/arch/openrisc/include/asm/system.h b/arch/openrisc/include/asm/system.h new file mode 100644 index 0000000..d680363 --- /dev/null +++ b/arch/openrisc/include/asm/system.h @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2011, Julius Baxter + * + * 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 __ASM_OPENRISC_SYSTEM_H +#define __ASM_OPENRISC_SYSTEM_H + +#include + +static inline unsigned long mfspr(unsigned long add) +{ + unsigned long ret; + + __asm__ __volatile__ ("l.mfspr %0,r0,%1" : "=r" (ret) : "K" (add)); + + return ret; +} + +static inline void mtspr(unsigned long add, unsigned long val) +{ + __asm__ __volatile__ ("l.mtspr r0,%1,%0" : : "K" (add), "r" (val)); +} + +#endif /* __ASM_OPENRISC_SYSTEM_H */ diff --git a/arch/openrisc/include/asm/types.h b/arch/openrisc/include/asm/types.h new file mode 100644 index 0000000..55efa36 --- /dev/null +++ b/arch/openrisc/include/asm/types.h @@ -0,0 +1,79 @@ +/* + * (C) Copyright 2011, Julius Baxter + * + * 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 _ASM_TYPES_H +#define _ASM_TYPES_H + +/* + * This file is never included by application software unless + * explicitly requested (e.g., via linux/types.h) in which case the + * application is Linux specific so (user-) name space pollution is + * not a major issue. However, for interoperability, libraries still + * need to be careful to avoid a name clashes. + */ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +#endif + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +#define BITS_PER_LONG 32 + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; + +/*typedef unsigned long phys_addr_t;*/ +typedef unsigned long phys_size_t; +#endif /* __KERNEL__ */ + +#endif /* _ASM_TYPES_H */ diff --git a/arch/openrisc/lib/Makefile b/arch/openrisc/lib/Makefile new file mode 100644 index 0000000..aaf93cb --- /dev/null +++ b/arch/openrisc/lib/Makefile @@ -0,0 +1,6 @@ +obj-y += clock.o +obj-y += board.o +obj-y += cpuinfo.o +obj-y += muldi3.o +obj-y += lshrdi3.o +obj-y += ashldi3.o diff --git a/arch/openrisc/lib/ashldi3.S b/arch/openrisc/lib/ashldi3.S new file mode 100644 index 0000000..3e422fa --- /dev/null +++ b/arch/openrisc/lib/ashldi3.S @@ -0,0 +1,41 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * Extracted from gcc generated assembly. + * + * Extended precision shifts. + * + * R3/R4 (MSW, LSW) has 64 bit value + * R5 has shift count + * result in R11/R12 + * + */ + +.globl __ashldi3 + +__ashldi3: + l.sfeqi r5,0x0 + l.bf out /* if count = 0, go out */ + + l.addi r6,r0,0x20 /* r6 = 32 */ + l.sub r6,r6,r5 /* r6 = 32 - count */ + l.sfgtsi r6,0x0 /* if count >= 32 */ + l.bnf more_than_32 /* branch to more_than_32 */ + l.nop 0x0 + +less_than_32: + l.srl r6,r4,r6 /* r6 gets the bits moved from LSW to MSW */ + l.sll r3,r3,r5 /* shift MSW */ + l.sll r4,r4,r5 /* shift LSW */ + l.or r3,r6,r3 /* MSW gets bits shifted from LSW */ + +out: + l.ori r11,r3,0x0 + l.jr r9 + l.ori r12,r4,0x0 + +more_than_32: + l.sub r3,r0,r6 /* r3 = -r6, the number of bits above 32 */ + l.sll r3,r4,r3 /* MSW = LSW << r3 */ + l.j out /* go out */ + l.addi r4,r0,0x0 /* LSW = 0 */ diff --git a/arch/openrisc/lib/board.c b/arch/openrisc/lib/board.c new file mode 100644 index 0000000..a2158cb --- /dev/null +++ b/arch/openrisc/lib/board.c @@ -0,0 +1,42 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * 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 + +int openrisc_mem_malloc_init(void) +{ + + mem_malloc_init((void *)(OPENRISC_SOPC_TEXT_BASE - MALLOC_SIZE), + (void *)(OPENRISC_SOPC_TEXT_BASE - 1)); + + return 0; +} + +core_initcall(openrisc_mem_malloc_init); + +void arch_shutdown(void) +{ +} diff --git a/arch/openrisc/lib/clock.c b/arch/openrisc/lib/clock.c new file mode 100644 index 0000000..ab0a90d --- /dev/null +++ b/arch/openrisc/lib/clock.c @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * 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 + +static uint64_t openrisc_clocksource_read(void) +{ + return (uint64_t)(mfspr(SPR_TTCR)); +} + +static struct clocksource cs = { + .read = openrisc_clocksource_read, + .mask = 0xffffffff, + .shift = 12, +}; + +static int clocksource_init(void) +{ + mtspr(SPR_TTMR, SPR_TTMR_CR | 0xFFFFFF); + cs.mult = clocksource_hz2mult(OPENRISC_TIMER_FREQ, cs.shift); + + init_clock(&cs); + + return 0; +} + +core_initcall(clocksource_init); diff --git a/arch/openrisc/lib/cpuinfo.c b/arch/openrisc/lib/cpuinfo.c new file mode 100644 index 0000000..3ec44c1 --- /dev/null +++ b/arch/openrisc/lib/cpuinfo.c @@ -0,0 +1,156 @@ +/* + * (C) Copyright 2011, Stefan Kristiansson + * (C) Copyright 2011, Julius Baxter + * + * 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 + +static volatile int illegal_instruction; + +static void illegal_instruction_handler(void) +{ + ulong *epcr = (ulong *)mfspr(SPR_EPCR_BASE); + + /* skip over the illegal instruction */ + mtspr(SPR_EPCR_BASE, (ulong)(++epcr)); + illegal_instruction = 1; +} + +static int checkinstructions(void) +{ + ulong ra = 1, rb = 1, rc; + + exception_install_handler(EXC_ILLEGAL_INSTR, + illegal_instruction_handler); + + illegal_instruction = 0; + asm volatile("l.mul %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb)); + printf(" Hardware multiplier: %s\n", + illegal_instruction ? "no" : "yes"); + + illegal_instruction = 0; + asm volatile("l.div %0,%1,%2" : "=r" (rc) : "r" (ra), "r" (rb)); + printf(" Hardware divider: %s\n", + illegal_instruction ? "no" : "yes"); + + exception_free_handler(EXC_ILLEGAL_INSTR); + + return 0; +} + +int checkcpu(void) +{ + ulong upr = mfspr(SPR_UPR); + ulong vr = mfspr(SPR_VR); + ulong iccfgr = mfspr(SPR_ICCFGR); + ulong dccfgr = mfspr(SPR_DCCFGR); + ulong immucfgr = mfspr(SPR_IMMUCFGR); + ulong dmmucfgr = mfspr(SPR_DMMUCFGR); + ulong cpucfgr = mfspr(SPR_CPUCFGR); + uint ver = (vr & SPR_VR_VER) >> 24; + uint rev = vr & SPR_VR_REV; + uint block_size; + uint ways; + uint sets; + + printf("CPU: OpenRISC-%x00 (rev %d) @ %d MHz\n", + ver, rev, (CONFIG_SYS_CLK_FREQ / 1000000)); + + if (upr & SPR_UPR_DCP) { + block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16; + ways = 1 << (dccfgr & SPR_DCCFGR_NCW); + printf(" D-Cache: %d bytes, %d bytes/line, %d way(s)\n", + checkdcache(), block_size, ways); + } else { + printf(" D-Cache: no\n"); + } + + if (upr & SPR_UPR_ICP) { + block_size = (iccfgr & SPR_ICCFGR_CBS) ? 32 : 16; + ways = 1 << (iccfgr & SPR_ICCFGR_NCW); + printf(" I-Cache: %d bytes, %d bytes/line, %d way(s)\n", + checkicache(), block_size, ways); + } else { + printf(" I-Cache: no\n"); + } + + if (upr & SPR_UPR_DMP) { + sets = 1 << ((dmmucfgr & SPR_DMMUCFGR_NTS) >> 2); + ways = (dmmucfgr & SPR_DMMUCFGR_NTW) + 1; + printf(" DMMU: %d sets, %d way(s)\n", + sets, ways); + } else { + printf(" DMMU: no\n"); + } + + if (upr & SPR_UPR_IMP) { + sets = 1 << ((immucfgr & SPR_IMMUCFGR_NTS) >> 2); + ways = (immucfgr & SPR_IMMUCFGR_NTW) + 1; + printf(" IMMU: %d sets, %d way(s)\n", + sets, ways); + } else { + printf(" IMMU: no\n"); + } + + printf(" MAC unit: %s\n", + (upr & SPR_UPR_MP) ? "yes" : "no"); + printf(" Debug unit: %s\n", + (upr & SPR_UPR_DUP) ? "yes" : "no"); + printf(" Performance counters: %s\n", + (upr & SPR_UPR_PCUP) ? "yes" : "no"); + printf(" Power management: %s\n", + (upr & SPR_UPR_PMP) ? "yes" : "no"); + printf(" Interrupt controller: %s\n", + (upr & SPR_UPR_PICP) ? "yes" : "no"); + printf(" Timer: %s\n", + (upr & SPR_UPR_TTP) ? "yes" : "no"); + printf(" Custom unit(s): %s\n", + (upr & SPR_UPR_CUP) ? "yes" : "no"); + + printf(" Supported instructions:\n"); + printf(" ORBIS32: %s\n", + (cpucfgr & SPR_CPUCFGR_OB32S) ? "yes" : "no"); + printf(" ORBIS64: %s\n", + (cpucfgr & SPR_CPUCFGR_OB64S) ? "yes" : "no"); + printf(" ORFPX32: %s\n", + (cpucfgr & SPR_CPUCFGR_OF32S) ? "yes" : "no"); + printf(" ORFPX64: %s\n", + (cpucfgr & SPR_CPUCFGR_OF64S) ? "yes" : "no"); + + checkinstructions(); + + return 0; +} + +static int do_cpuinfo(struct command *cmdtp, int argc, char *argv[]) +{ + checkcpu(); + return 0; +} + +BAREBOX_CMD_START(cpuinfo) + .cmd = do_cpuinfo, + .usage = "Show info about CPU", +BAREBOX_CMD_END diff --git a/arch/openrisc/lib/lshrdi3.S b/arch/openrisc/lib/lshrdi3.S new file mode 100644 index 0000000..de30445 --- /dev/null +++ b/arch/openrisc/lib/lshrdi3.S @@ -0,0 +1,41 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * Extracted from gcc generated assembly. + * + * Extended precision shifts. + * + * R3/R4 (MSW, LSW) has 64 bit value + * R5 has shift count + * result in R11/R12 + * + */ + +.globl __lshrdi3 + +__lshrdi3: + l.sfeqi r5,0x0 + l.bf out /* if count = 0, go out */ + + l.addi r6,r0,0x20 /* r6 = 32 */ + l.sub r6,r6,r5 /* r6 = 32 - count */ + l.sfgtsi r6,0x0 /* if count >= 32 */ + l.bnf more_than_32 /* branch to more_than_32 */ + l.nop 0x0 + +less_than_32: + l.sll r6,r3,r6 /* r6 gets the bits moved from MSW to LSW */ + l.srl r4,r4,r5 /* shift LSW */ + l.srl r3,r3,r5 /* shift MSW */ + l.or r4,r6,r4 /* LSW gets bits shifted from MSW */ + + out: + l.ori r11,r3,0x0 + l.jr r9 + l.ori r12,r4,0x0 + +more_than_32: + l.sub r4,r0,r6 /* r4 = -r6, the number of bits above 32 */ + l.srl r4,r3,r4 /* LSW = MSW >> r4 */ + l.j out /* go out */ + l.addi r3,r0,0x0 /* MSW = 0 */ diff --git a/arch/openrisc/lib/muldi3.S b/arch/openrisc/lib/muldi3.S new file mode 100644 index 0000000..902338a --- /dev/null +++ b/arch/openrisc/lib/muldi3.S @@ -0,0 +1,58 @@ +/* + * (C) Copyright 2011 - Franck JULLIEN + * + * Extracted from gcc generated assembly. + * + * Multiply two quads. Hereafter, the illustration of what is going on : + * + * | r3 | r4 | + * | r5 | r6 | + * -------------------- + * | r4 * r6 | + * | r3 * r6 | | + + * | r5 * r4 | | + + * | r3 * r5 | | | + + * ------------------------------------------- = + * | 64 bits result | + * + */ + +.globl __muldi3 + +__muldi3: + /* starts with the full 64 bits mul (r4 * r6) */ + l.andi r7,r4,0xffff + l.srli r8,r4,0x10 + + l.andi r11,r6,0xffff + l.srli r12,r6,0x10 + + l.mul r13,r11,r7 + l.mul r11,r11,r8 + l.mul r7,r12,r7 + + l.srli r15,r13,0x10 + l.add r7,r7,r15 + l.add r7,r11,r7 + l.sfleu r11,r7 + l.bf no_carry + l.mul r8,r12,r8 + + l.movhi r15,0x1 + l.add r8,r8,r15 + +no_carry: + /* Now compute r3 * r6 */ + l.mul r6,r6,r3 + /* and r4 * r5 */ + l.mul r4,r4,r5 + /* finaly previous results and put the result in r11:r12 */ + l.srli r3,r7,0x10 + l.slli r7,r7,0x10 + l.andi r13,r13,0xffff + l.add r8,r8,r3 + l.add r11,r4,r6 + l.add r12,r7,r13 + l.add r11,r11,r8 + l.jr r9 + l.nop diff --git a/arch/ppc/boards/pcm030/pcm030.c b/arch/ppc/boards/pcm030/pcm030.c index 9c6ccb7..80f1cbe 100644 --- a/arch/ppc/boards/pcm030/pcm030.c +++ b/arch/ppc/boards/pcm030/pcm030.c @@ -191,12 +191,3 @@ } } } - -#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/lib/board.c b/arch/ppc/lib/board.c index 0e839eb..a840c75 100644 --- a/arch/ppc/lib/board.c +++ b/arch/ppc/lib/board.c @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/arch/ppc/lib/ppclinux.c b/arch/ppc/lib/ppclinux.c index 471b303..95dc83b 100644 --- a/arch/ppc/lib/ppclinux.c +++ b/arch/ppc/lib/ppclinux.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -11,235 +10,16 @@ #include #include -#ifdef CONFIG_OF_FLAT_TREE -#include -#endif -extern bd_t *bd; - -static int do_bootm_linux(struct image_data *idata) +static int do_bootm_linux(struct image_data *data) { - ulong sp; - ulong initrd_end = 0; - ulong cmd_start, cmd_end; - ulong initrd_high; - int initrd_copy_to_ram = 1; - char *cmdline; - const char *c; - bd_t *kbd; - void (*kernel)(bd_t *, ulong, ulong, ulong, ulong); -#ifdef CONFIG_OF_FLAT_TREE - char *of_flat_tree = NULL; -#endif - image_header_t *os_header = &idata->os->header; - image_header_t *initrd_header = NULL; - void *os_data = NULL; - void *initrd_data = NULL; - void *of_data = NULL; - struct image_handle *oftree_handle; - unsigned long os_len, initrd_len; + void (*kernel)(void *, void *, unsigned long, + unsigned long, unsigned long); - if (idata->initrd) - initrd_header = &idata->initrd->header; + if (!data->os_res) + return -EINVAL; - printf("entering %s: os_header: %p initrd_header: %p oftree: %s\n", - __FUNCTION__, os_header, initrd_header, idata->oftree); + kernel = (void *)(data->os_address + data->os_entry); - if (image_get_type(os_header) == IH_TYPE_MULTI) { - unsigned long *data = (unsigned long *)(idata->os->data); - unsigned long len1 = 0, len2 = 0; - - if (!*data) { - printf("multifile image with 0 entries???\n"); - return -1; - } - os_len = ntohl(*data); /* first one is the kernel */ - data++; - - if (*data) { - len1 = ntohl(*data); /* could be initrd or oftree */ - data++; - } - - if (*data) { - len2 = ntohl(*data); /* could be oftree */ - data++; - } - - while (*data) /* skip all remaining files */ - data++; - - data++; /* skip terminating zero */ - - os_data = (void *)ntohl(data); - - if (len2) { - initrd_data = (void *) - ((unsigned long)data + ((os_len + 3) & ~3)); - initrd_len = len1; - of_data = (void *) - ((unsigned long)initrd_data + ((initrd_len + 3) & ~3)); - } else if (len1) { - /* We could check here if this is a multifile image - * with only a kernel and an oftree. Original barebox - * did not do this, so leave it out for now. - */ - initrd_data = (void *)((unsigned long)data + ((os_len + 3) & ~3)); - initrd_len = len1; - } - } else { - os_data = idata->os->data; - printf("set os_data to %p\n", os_data); - } - - if (idata->initrd) - initrd_data = idata->initrd->data; - -#ifdef CONFIG_OF_FLAT_TREE - if (idata->oftree) { - /* The oftree can be given either as an barebox image or as a - * binary blob. First try to read it as an image. - */ - oftree_handle = map_image(idata->oftree, 1); - if (oftree_handle) { - of_data = oftree_handle->data; - } else { - of_data = read_file(idata->oftree, 0); - if (!of_data) { - printf("could not read %s: %s\n", idata->oftree, errno_str()); - return -1; - } - } - /* FIXME: check if this is really an oftree */ - } -#endif - printf("loading kernel.\n"); - - if ((c = getenv ("initrd_high")) != NULL) { - /* a value of "no" or a similar string will act like 0, - * turning the "load high" feature off. This is intentional. - */ - initrd_high = simple_strtoul(c, NULL, 16); - if (initrd_high == ~0) - initrd_copy_to_ram = 0; - } else { /* not set, no restrictions to load high */ - initrd_high = ~0; - } - -#ifdef CONFIG_LOGBUFFER - kbd=gd->bd; - /* Prevent initrd from overwriting logbuffer */ - if (initrd_high < (kbd->bi_memsize-LOGBUFF_LEN-LOGBUFF_OVERHEAD)) - initrd_high = kbd->bi_memsize-LOGBUFF_LEN-LOGBUFF_OVERHEAD; - debug ("## Logbuffer at 0x%08lX ", kbd->bi_memsize-LOGBUFF_LEN); -#endif - - /* - * Booting a (Linux) kernel image - * - * Allocate space for command line and board info - the - * address should be as high as possible within the reach of - * the kernel (see CFG_BOOTMAPSZ settings), but in unused - * memory, which means far enough below the current stack - * pointer. - */ - - asm( "mr %0,1": "=r"(sp) : ); - - debug ("## Current stack ends at 0x%08lX ", sp); - - sp -= 2048; /* just to be sure */ - if (sp > CFG_BOOTMAPSZ) - sp = CFG_BOOTMAPSZ; - sp &= ~0xF; - - debug ("=> set upper limit to 0x%08lX\n", sp); - - cmdline = (char *)((sp - CONFIG_CBSIZE) & ~0xF); - kbd = (bd_t *)(((ulong)cmdline - sizeof(bd_t)) & ~0xF); - - printf("cmdline: %p kbd: %p\n", cmdline, kbd); - - if ((c = getenv("bootargs")) == NULL) - c = ""; - - strcpy (cmdline, c); - - cmd_start = (ulong)cmdline; - cmd_end = cmd_start + strlen(cmdline); - - init_board_data(kbd); - -#ifdef DEBUG - printf ("## cmdline at 0x%08lX ... 0x%08lX\n", cmd_start, cmd_end); - -// do_bdinfo (NULL, 0, 0, NULL); -#endif - - if ((c = getenv ("clocks_in_mhz")) != NULL) { - /* convert all clock information to MHz */ - kbd->bi_intfreq /= 1000000L; - kbd->bi_busfreq /= 1000000L; -#if defined(CONFIG_MPC8220) - kbd->bi_inpfreq /= 1000000L; - kbd->bi_pcifreq /= 1000000L; - kbd->bi_pevfreq /= 1000000L; - kbd->bi_flbfreq /= 1000000L; - kbd->bi_vcofreq /= 1000000L; -#endif -#if defined(CONFIG_CPM2) - kbd->bi_cpmfreq /= 1000000L; - kbd->bi_brgfreq /= 1000000L; - kbd->bi_sccfreq /= 1000000L; - kbd->bi_vco /= 1000000L; -#endif -#if defined(CONFIG_MPC5xxx) - kbd->bi_ipbfreq /= 1000000L; - kbd->bi_pcifreq /= 1000000L; -#endif /* CONFIG_MPC5xxx */ - } - - kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))image_get_ep(os_header); /* FIXME */ - -#if defined(CFG_INIT_RAM_LOCK) && !defined(CONFIG_E500) - unlock_ram_in_cache(); -#endif - -#ifdef CONFIG_OF_FLAT_TREE - /* move of_flat_tree if needed */ - if (of_data) { - ulong of_start, of_len; - of_len = ((struct boot_param_header *)of_data)->totalsize; - /* provide extra 8k pad */ - if (initrd_data) - of_start = (unsigned long)initrd_data - of_len - 8192; - else - of_start = (ulong)kbd - of_len - 8192; - of_start &= ~(4096 - 1); /* align on page */ - debug ("## device tree at 0x%p ... 0x%p (len=%ld=0x%lX)\n", - of_data, of_data + of_len - 1, of_len, of_len); - - of_flat_tree = (char *)of_start; - printf (" Loading Device Tree to %08lx, end %08lx ... ", - of_start, of_start + of_len - 1); - memmove ((void *)of_start, (void *)of_data, of_len); - } -#endif - - /* - * Linux Kernel Parameters (passing board info data): - * r3: ptr to board info data - * r4: initrd_start or 0 if no initrd - * r5: initrd_end - unused if r4 is 0 - * r6: Start of command line string - * r7: End of command line string - */ -#ifdef CONFIG_OF_FLAT_TREE - if (!of_flat_tree) /* no device tree; boot old style */ -#endif - (*kernel) (kbd, (ulong)initrd_data, initrd_end, cmd_start, cmd_end); - /* does not return */ - -#ifdef CONFIG_OF_FLAT_TREE /* * Linux Kernel Parameters (passing device tree): * r3: ptr to OF flat tree, followed by the board info data @@ -248,11 +28,8 @@ * r6: NULL * r7: NULL */ - ft_setup(of_flat_tree, kbd, (long)initrd_data, initrd_end); - ft_cpu_setup(of_flat_tree, kbd); + kernel(data->oftree, kernel, 0, 0, 0); - (*kernel) ((bd_t *)of_flat_tree, (ulong)kernel, 0, 0, 0); -#endif reset_cpu(0); /* not reached */ @@ -260,8 +37,10 @@ } static struct image_handler handler = { + .name = "PowerPC Linux", .bootm = do_bootm_linux, - .image_type = IH_OS_LINUX, + .filetype = filetype_uimage, + .ih_os = IH_OS_LINUX, }; static int ppclinux_register_image_handler(void) @@ -270,4 +49,3 @@ } late_initcall(ppclinux_register_image_handler); - diff --git a/arch/ppc/lib/ticks.S b/arch/ppc/lib/ticks.S index 5d6c427..453d889 100644 --- a/arch/ppc/lib/ticks.S +++ b/arch/ppc/lib/ticks.S @@ -26,7 +26,6 @@ #include #include #include -#include /* * unsigned long long get_ticks(void); diff --git a/arch/ppc/mach-mpc5xxx/cpu.c b/arch/ppc/mach-mpc5xxx/cpu.c index d695b9b..62ddb1f 100644 --- a/arch/ppc/mach-mpc5xxx/cpu.c +++ b/arch/ppc/mach-mpc5xxx/cpu.c @@ -34,12 +34,9 @@ #include #include #include +#include #include -#if defined(CONFIG_OF_FLAT_TREE) -#include -#endif - int checkcpu (void) { ulong clock = get_cpu_clock(); @@ -83,27 +80,26 @@ /* ------------------------------------------------------------------------- */ -#ifdef CONFIG_OF_FLAT_TREE -void -ft_cpu_setup(void *blob, bd_t *bd) +#ifdef CONFIG_OFTREE +static int of_mpc5200_fixup(struct fdt_header *fdt) { - u32 *p; - int len; + char *cpu_path = "/cpus/PowerPC,5200@0"; + int div = in_8((void*)CFG_MBAR + 0x204) & 0x0020 ? 8 : 4; - /* Core XLB bus frequency */ - p = ft_get_prop(blob, "/cpus/" OF_CPU "/bus-frequency", &len); - if (p != NULL) - *p = cpu_to_be32(get_bus_clock()); - - /* SOC peripherals use the IPB bus frequency */ - p = ft_get_prop(blob, "/" OF_SOC "/bus-frequency", &len); - if (p != NULL) - *p = cpu_to_be32(get_ipb_clock()); - - p = ft_get_prop(blob, "/" OF_SOC "/ethernet@3000/mac-address", &len); - if (p != NULL) - memcpy(p, bd->bi_enetaddr, 6); + do_fixup_by_path_u32(fdt, cpu_path, "timebase-frequency", get_timebase_clock(), 1); + do_fixup_by_path_u32(fdt, cpu_path, "bus-frequency", get_bus_clock(), 1); + do_fixup_by_path_u32(fdt, cpu_path, "clock-frequency", get_cpu_clock(), 1); + do_fixup_by_path_u32(fdt, "/soc5200@f0000000", "bus-frequency", get_ipb_clock(), 1); + do_fixup_by_path_u32(fdt, "/soc5200@f0000000", "system-frequency", + get_bus_clock() * div, 1); + return 0; } + +static int of_register_mpc5200_fixup(void) +{ + return of_register_fixup(of_mpc5200_fixup); +} +late_initcall(of_register_mpc5200_fixup); #endif int cpu_init_board_data(bd_t *bd) diff --git a/commands/Kconfig b/commands/Kconfig index ebc9c7f..6f9ccb8 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -173,6 +173,13 @@ depends on NAND prompt "nand" +config CMD_NANDTEST + tristate + depends on NAND + depends on PARTITION + depends on NAND_ECC_HW || NAND_ECC_SOFT + prompt "nandtest" + endmenu menu "console " @@ -310,11 +317,41 @@ depends on CMD_BOOTM prompt "show image information" -config CMD_IMINFO +config CMD_BOOTM_VERBOSE bool - prompt "iminfo" + prompt "bootm verbose support" + depends on CMD_BOOTM help - Show information about uImages + support verbose bootm (-v switch) + +config CMD_BOOTM_INITRD + bool + prompt "bootm initrd support" + depends on CMD_BOOTM + help + support initrds in bootm + +config CMD_BOOTM_OFTREE + bool + depends on CMD_BOOTM + select OFTREE + prompt "bootm oftree support" + help + say yes here to support passing a flat device tree to the kernel + +config CMD_BOOTM_OFTREE_UIMAGE + bool + prompt "support passing oftree uImages" + depends on CMD_BOOTM_OFTREE + help + Support using oftree uImages. Without this only raw oftree + blobs can be used. + +config CMD_UIMAGE + tristate + prompt "uimage" + help + Show information about uImage and also extract and verify uImages. config CMD_BOOTZ tristate diff --git a/commands/Makefile b/commands/Makefile index aa013de..31442b5 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o -obj-$(CONFIG_CMD_IMINFO) += iminfo.o +obj-$(CONFIG_CMD_UIMAGE) += uimage.o obj-$(CONFIG_CMD_LINUX16) += linux16.o obj-$(CONFIG_CMD_LOADB) += loadb.o xyzModem.o obj-$(CONFIG_CMD_LOADY) += loadb.o xyzModem.o @@ -39,6 +39,7 @@ obj-$(CONFIG_CMD_SAVEENV) += saveenv.o obj-$(CONFIG_CMD_LOADENV) += loadenv.o obj-$(CONFIG_CMD_NAND) += nand.o +obj-$(CONFIG_CMD_NANDTEST) += nandtest.o obj-$(CONFIG_CMD_TRUE) += true.o obj-$(CONFIG_CMD_FALSE) += false.o obj-$(CONFIG_CMD_VERSION) += version.o @@ -47,6 +48,7 @@ obj-$(CONFIG_CMD_INSMOD) += insmod.o obj-$(CONFIG_CMD_BMP) += bmp.o obj-$(CONFIG_USB_GADGET_DFU) += dfu.o +obj-$(CONFIG_USB_GADGET_SERIAL) += usbserial.o obj-$(CONFIG_CMD_GPIO) += gpio.o obj-$(CONFIG_CMD_UNCOMPRESS) += uncompress.o obj-$(CONFIG_CMD_I2C) += i2c.o diff --git a/commands/bootm.c b/commands/bootm.c index f97a842..c23f4f3 100644 --- a/commands/bootm.c +++ b/commands/bootm.c @@ -25,7 +25,6 @@ * Boot support */ #include -#include #include #include #include @@ -38,53 +37,30 @@ #include #include #include +#include +#include #include #include +#include #include #include +#include +#include #include -struct image_handle_data* image_handle_data_get_by_num(struct image_handle* handle, int num) -{ - if (!handle || num < 0 || num >= handle->nb_data_entries) - return NULL; +static LIST_HEAD(handler_list); - return &handle->data_entries[num]; +#ifdef CONFIG_CMD_BOOTM_INITRD +static inline int bootm_initrd(struct image_data *data) +{ + return data->initrd ? 1 : 0; } - -int relocate_image(struct image_handle *handle, void *load_address) +#else +static inline int bootm_initrd(struct image_data *data) { - image_header_t *hdr = &handle->header; - unsigned long len = image_get_size(hdr); - struct image_handle_data *iha; - void *data; - int ret; - - iha = image_handle_data_get_by_num(handle, 0); - data = iha->data; - - switch (image_get_comp(hdr)) { - case IH_COMP_NONE: - if (load_address == data) { - printf (" XIP ... "); - } else { - memmove(load_address, data, len); - } - break; - default: - printf (" Uncompressing ... "); - ret = uncompress(data, len, NULL, NULL, load_address, NULL, - uncompress_err_stdout); - if (ret) - return ret; - break; - } - return 0; } -EXPORT_SYMBOL(relocate_image); - -static LIST_HEAD(handler_list); +#endif int register_image_handler(struct image_handler *handler) { @@ -92,144 +68,380 @@ return 0; } -/* - * generate a image_handle from a multi_image - * this image_handle can be freed by unmap_image - */ -static struct image_handle *get_fake_image_handle(struct image_data *data, int num) +#define UIMAGE_SOME_ADDRESS (UIMAGE_INVALID_ADDRESS - 1) + +static int bootm_open_os_uimage(struct image_data *data) { - struct image_handle *handle; - struct image_handle_data* iha; - image_header_t *header; + int ret; - iha = image_handle_data_get_by_num(data->os, num); + data->os = uimage_open(data->os_file); + if (!data->os) + return -EINVAL; - handle = xzalloc(sizeof(struct image_handle)); - header = &handle->header; - handle->data_entries = gen_image_handle_data(iha->data, iha->len); - handle->nb_data_entries = 1; - header->ih_size = cpu_to_uimage(iha->len); - handle->data = handle->data_entries[0].data; + if (data->verify) { + ret = uimage_verify(data->os); + if (ret) { + printf("Checking data crc failed with %s\n", + strerror(-ret)); + return ret; + } + } - return handle; + uimage_print_contents(data->os); + + if (data->os->header.ih_arch != IH_ARCH) { + printf("Unsupported Architecture 0x%x\n", + data->os->header.ih_arch); + return -EINVAL; + } + + if (data->os_address == UIMAGE_SOME_ADDRESS) + data->os_address = data->os->header.ih_load; + + if (data->os_address != UIMAGE_INVALID_ADDRESS) { + data->os_res = uimage_load_to_sdram(data->os, 0, + data->os_address); + if (!data->os_res) + return -ENOMEM; + } + + return 0; +} + +static int bootm_open_initrd_uimage(struct image_data *data) +{ + int ret; + + if (!data->initrd_file) + return 0; + + if (strcmp(data->os_file, data->initrd_file)) { + data->initrd = uimage_open(data->initrd_file); + if (!data->initrd) + return -EINVAL; + + if (data->verify) { + ret = uimage_verify(data->initrd); + if (ret) { + printf("Checking data crc failed with %s\n", + strerror(-ret)); + } + } + uimage_print_contents(data->initrd); + } else { + data->initrd = data->os; + } + + if (data->initrd_address == UIMAGE_SOME_ADDRESS) + data->initrd_address = data->initrd->header.ih_load; + + if (data->initrd_address != UIMAGE_INVALID_ADDRESS) { + data->initrd_res = uimage_load_to_sdram(data->initrd, + data->initrd_num, + data->initrd_address); + if (!data->initrd_res) + return -ENOMEM; + } + + return 0; +} + +#ifdef CONFIG_OFTREE +static int bootm_open_oftree(struct image_data *data, char *oftree, int num) +{ + enum filetype ft; + struct fdt_header *fdt; + int ret; + size_t size; + + ft = file_name_detect_type(oftree); + if ((int)ft < 0) + return ft; + + if (ft == filetype_uimage) { +#ifdef CONFIG_CMD_BOOTM_OFTREE_UIMAGE + struct uimage_handle *of_handle; + int release = 0; + + if (!strcmp(data->os_file, oftree)) { + of_handle = data->os; + } else if (!strcmp(data->initrd_file, oftree)) { + of_handle = data->initrd; + } else { + of_handle = uimage_open(oftree); + if (!of_handle) + return -ENODEV; + uimage_print_contents(of_handle); + release = 1; + } + + fdt = uimage_load_to_buf(of_handle, num, &size); + + if (release) + uimage_close(of_handle); +#else + return -EINVAL; +#endif + } else { + fdt = read_file(oftree, &size); + if (!fdt) { + perror("open"); + return -ENODEV; + } + } + + ft = file_detect_type(fdt); + if (ft != filetype_oftree) { + printf("%s is not a oftree but %s\n", oftree, + file_type_to_string(ft)); + } + + if (bootm_verbose(data)) + printf("Loading oftree from '%s'\n", oftree); + + fdt = xrealloc(fdt, size + 0x8000); + fdt_open_into(fdt, fdt, size + 0x8000); + + if (!fdt) { + printf("unable to read %s\n", oftree); + return -ENODEV; + } + + ret = of_fix_tree(fdt); + if (ret) + return ret; + + if (bootm_verbose(data) > 1) + fdt_print(fdt, "/"); + + data->oftree = fdt; + + return ret; +} +#endif + +static struct image_handler *bootm_find_handler(enum filetype filetype, + struct image_data *data) +{ + struct image_handler *handler; + + list_for_each_entry(handler, &handler_list, list) { + if (filetype != filetype_uimage && + handler->filetype == filetype) + return handler; + if (filetype == filetype_uimage && + handler->ih_os == data->os->header.ih_os) + return handler; + } + + return NULL; +} + +static void bootm_image_name_and_no(char *name, int *no) +{ + char *at; + + *no = 0; + + at = strchr(name, '@'); + if (!at) + return; + + *at++ = 0; + + *no = simple_strtoul(at, NULL, 10); } static int do_bootm(struct command *cmdtp, int argc, char *argv[]) { - int opt; - image_header_t *os_header; - struct image_handle *os_handle = NULL; + int opt; struct image_handler *handler; struct image_data data; - const char *initrdname = NULL; int ret = 1; + enum filetype os_type, initrd_type = filetype_unknown; + char *oftree = NULL; + int fallback = 0; memset(&data, 0, sizeof(struct image_data)); - data.verify = 1; - data.initrd_address = ~0; - while ((opt = getopt(argc, argv, "nr:L:")) > 0) { + data.initrd_address = UIMAGE_SOME_ADDRESS; + data.os_address = UIMAGE_SOME_ADDRESS; + data.verify = 0; + data.verbose = 0; + + while ((opt = getopt(argc, argv, "cL:r:a:e:vo:f")) > 0) { switch(opt) { - case 'n': - data.verify = 0; + case 'c': + data.verify = 1; break; +#ifdef CONFIG_CMD_BOOTM_INITRD case 'L': data.initrd_address = simple_strtoul(optarg, NULL, 0); break; case 'r': - initrdname = optarg; + data.initrd_file = optarg; + break; +#endif + case 'a': + data.os_address = simple_strtoul(optarg, NULL, 0); + break; + case 'e': + data.os_entry = simple_strtoul(optarg, NULL, 0); + break; + case 'v': + data.verbose++; + break; + case 'o': + oftree = optarg; + break; + case 'f': + fallback = 1; break; default: break; } } - if (optind == argc) { - ret = COMMAND_ERROR_USAGE; + if (optind == argc) + return COMMAND_ERROR_USAGE; + + data.os_file = argv[optind]; + + bootm_image_name_and_no(data.os_file, &data.os_num); + + os_type = file_name_detect_type(data.os_file); + if ((int)os_type < 0) { + printf("could not open %s: %s\n", data.os_file, + strerror(-os_type)); goto err_out; } - os_handle = map_image(argv[optind], data.verify); - if (!os_handle) - goto err_out; - data.os = os_handle; - - os_header = &os_handle->header; - - if (image_get_arch(os_header) != IH_ARCH) { - printf("Unsupported Architecture 0x%x\n", - image_get_arch(os_header)); + if (!fallback && os_type == filetype_unknown) { + printf("Unknown OS filetype (try -f)\n"); goto err_out; } - if (initrdname) { - /* check for multi image @ */ - if (initrdname[0] == '@') { - int num = simple_strtol(optarg + 1, NULL, 0); - - data.initrd = get_fake_image_handle(&data, num); - } else { - data.initrd = map_image(optarg, data.verify); - } - if (!data.initrd) + if (os_type == filetype_uimage) { + ret = bootm_open_os_uimage(&data); + if (ret) { + printf("loading initrd failed with %s\n", + strerror(-ret)); goto err_out; + } } - /* - * We have reached the point of no return: we are going to - * overwrite all exception vector code, so we cannot easily - * recover from any failures any more... - */ + if (bootm_initrd(&data)) { + bootm_image_name_and_no(data.initrd_file, &data.initrd_num); - puts ("OK\n"); + initrd_type = file_name_detect_type(data.initrd_file); + if ((int)initrd_type < 0) { + printf("could not open %s: %s\n", data.initrd_file, + strerror(-initrd_type)); + goto err_out; + } + if (initrd_type == filetype_uimage) { + ret = bootm_open_initrd_uimage(&data); + if (ret) { + printf("loading initrd failed with %s\n", + strerror(-ret)); + goto err_out; + } + } + } - /* - * FIXME: we do not check at all whether - * - we will write the image to sdram - * - we overwrite ourselves - * - kernel and initrd overlap - */ - ret = relocate_image(data.os, (void *)image_get_load(os_header)); - if (ret) - goto err_out; + if (bootm_verbose(&data)) { + printf("\nLoading OS %s '%s'", file_type_to_string(os_type), + data.os_file); + if (os_type == filetype_uimage && + data.os->header.ih_type == IH_TYPE_MULTI) + printf(", multifile image %d", data.os_num); + printf("\n"); + if (data.os_res) + printf("OS image is at 0x%08x-0x%08x\n", + data.os_res->start, + data.os_res->start + + data.os_res->size - 1); + else + printf("OS image not yet relocated\n"); - if (data.initrd) { - if (data.initrd && data.initrd_address == ~0) - data.initrd_address = uimage_to_cpu(data.initrd->header.ih_load); + if (data.initrd_file) { + printf("Loading initrd %s '%s'", + file_type_to_string(initrd_type), + data.initrd_file); + if (initrd_type == filetype_uimage && + data.initrd->header.ih_type == IH_TYPE_MULTI) + printf(", multifile image %d", data.initrd_num); + printf("\n"); + if (data.initrd_res) + printf("initrd is at 0x%08x-0x%08x\n", + data.initrd_res->start, + data.initrd_res->start + + data.initrd_res->size - 1); + else + printf("initrd image not yet relocated\n"); + } + } - data.initrd_size = image_get_data_size(&data.initrd->header); +#ifdef CONFIG_OFTREE + if (oftree) { + int oftree_num; - ret = relocate_image(data.initrd, (void *)data.initrd_address); + bootm_image_name_and_no(oftree, &oftree_num); + + ret = bootm_open_oftree(&data, oftree, oftree_num); if (ret) goto err_out; } +#endif + if (data.os_address == UIMAGE_SOME_ADDRESS) + data.os_address = UIMAGE_INVALID_ADDRESS; + if (data.initrd_address == UIMAGE_SOME_ADDRESS) + data.initrd_address = UIMAGE_INVALID_ADDRESS; - /* loop through the registered handlers */ - list_for_each_entry(handler, &handler_list, list) { - if (image_get_os(os_header) == handler->image_type) { - handler->bootm(&data); - printf("handler returned!\n"); - goto err_out; - } + handler = bootm_find_handler(os_type, &data); + if (!handler) { + printf("no image handler found for image type %s\n", + file_type_to_string(os_type)); + if (os_type == filetype_uimage) + printf("and os type: %d\n", data.os->header.ih_os); + goto err_out; } - printf("no image handler found for image type %d\n", - image_get_os(os_header)); + if (bootm_verbose(&data)) + printf("Passing control to %s handler\n", handler->name); + + ret = handler->bootm(&data); + + printf("handler failed with %s\n", strerror(-ret)); err_out: - if (os_handle) - unmap_image(os_handle); - if (data.initrd) - unmap_image(data.initrd); - return ret; + if (data.os_res) + release_sdram_region(data.os_res); + if (data.initrd_res) + release_sdram_region(data.initrd_res); + if (data.initrd && data.initrd != data.os) + uimage_close(data.initrd); + if (data.os) + uimage_close(data.os); + return 1; } BAREBOX_CMD_HELP_START(bootm) BAREBOX_CMD_HELP_USAGE("bootm [OPTIONS] image\n") BAREBOX_CMD_HELP_SHORT("Boot an application image.\n") -BAREBOX_CMD_HELP_OPT ("-n", "Do not verify the image (speeds up boot process)\n") +BAREBOX_CMD_HELP_OPT ("-c", "crc check uImage data\n") +#ifdef CONFIG_CMD_BOOTM_INITRD BAREBOX_CMD_HELP_OPT ("-r ","specify an initrd image\n") -BAREBOX_CMD_HELP_OPT ("-L ","specify initrd load address") +BAREBOX_CMD_HELP_OPT ("-L ","specify initrd load address\n") +#endif +BAREBOX_CMD_HELP_OPT ("-a ","specify os load address\n") +BAREBOX_CMD_HELP_OPT ("-e ","entry point to the image relative to start (0)\n") +#ifdef CONFIG_OFTREE +BAREBOX_CMD_HELP_OPT ("-o ","specify oftree\n") +#endif +#ifdef CONFIG_CMD_BOOTM_VERBOSE +BAREBOX_CMD_HELP_OPT ("-v","verbose\n") +#endif BAREBOX_CMD_HELP_END BAREBOX_CMD_START(bootm) @@ -240,13 +452,6 @@ BAREBOX_MAGICVAR(bootargs, "Linux Kernel parameters"); -#ifdef CONFIG_BZLIB -void bz_internal_error(int errcode) -{ - printf ("BZIP2 internal error %d\n", errcode); -} -#endif /* CONFIG_BZLIB */ - /** * @file * @brief Boot support for Linux diff --git a/commands/flash.c b/commands/flash.c index a3f3508..85efd06 100644 --- a/commands/flash.c +++ b/commands/flash.c @@ -56,11 +56,6 @@ size = s.st_size; - if (!filename) { - printf("missing filename\n"); - return 1; - } - fd = open(filename, O_WRONLY); if (fd < 0) { printf("open %s: %s", filename, errno_str()); @@ -132,11 +127,6 @@ size = s.st_size; - if (!filename) { - printf("missing filename\n"); - return 1; - } - fd = open(filename, O_WRONLY); if (fd < 0) { printf("open %s: %s", filename, errno_str()); diff --git a/commands/iminfo.c b/commands/iminfo.c deleted file mode 100644 index 2fde9bc..0000000 --- a/commands/iminfo.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -static int image_info(image_header_t *hdr) -{ - u32 len, checksum; - - if (image_get_magic(hdr) != IH_MAGIC) { - puts (" Bad Magic Number\n"); - return 1; - } - - len = image_get_header_size(); - - checksum = image_get_hcrc(hdr); - hdr->ih_hcrc = 0; - - if (crc32 (0, hdr, len) != checksum) { - puts (" Bad Header Checksum\n"); - return 1; - } - - image_print_contents(hdr, NULL); - - return 0; -} - -static int do_iminfo(struct command *cmdtp, int argc, char *argv[]) -{ - int rcode = 1; - int fd; - int ret; - image_header_t hdr; - - if (argc != 2) - return COMMAND_ERROR_USAGE; - - fd = open(argv[1], O_RDONLY); - if (fd < 0) { - perror("open"); - return 1; - } - - ret = read(fd, &hdr, sizeof(image_header_t)); - if (ret != sizeof(image_header_t)) - goto err_out; - - printf("Image at %s:\n", argv[1]); - image_info(&hdr); - -err_out: - close(fd); - - return rcode; -} - -BAREBOX_CMD_HELP_START(iminfo) -BAREBOX_CMD_HELP_USAGE("iminfo\n") -BAREBOX_CMD_HELP_SHORT("Print header information for an application image.\n") -BAREBOX_CMD_HELP_END - -BAREBOX_CMD_START(iminfo) - .cmd = do_iminfo, - .usage = "print header information for an application image", - BAREBOX_CMD_HELP(cmd_iminfo_help) -BAREBOX_CMD_END diff --git a/commands/linux_exec.c b/commands/linux_exec.c new file mode 100644 index 0000000..00c7e80 --- /dev/null +++ b/commands/linux_exec.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Jean-Christophe PLAGNIOL-VILLARD + * + * 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 + +static int do_linux_exec(struct command *cmdtp, int argc, char *argv[]) +{ + int ret; + char **newargv; + char *newenv[] = { NULL }; + int i, j; + + if (argc < 2) + return 1; + + newargv = xzalloc(sizeof(char*) * argc); + + for (j = 0, i = 1; i < argc; i++, j++) + newargv[j] = argv[i]; + + newargv[j] = NULL; + ret = linux_execve(argv[1], newargv, newenv); + + free(newargv); + + if (ret) + return 1; + + return 0; +} + +BAREBOX_CMD_HELP_START(linux_exec) +BAREBOX_CMD_HELP_USAGE("linux_exec ...\n") +BAREBOX_CMD_HELP_SHORT("Execute a command on the host\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(linux_exec) + .cmd = do_linux_exec, + .usage = "Execute a command on the host", + BAREBOX_CMD_HELP(cmd_linux_exec_help) +BAREBOX_CMD_END diff --git a/commands/ls.c b/commands/ls.c index 278a8bc..070aa90 100644 --- a/commands/ls.c +++ b/commands/ls.c @@ -68,7 +68,7 @@ if (stat(tmp, &s)) goto out; if (flags & LS_COLUMN) - string_list_add(&sl, d->d_name); + string_list_add_sorted(&sl, d->d_name); else ls_one(d->d_name, &s); } @@ -156,7 +156,7 @@ if (!(s.st_mode & S_IFDIR)) { if (flags & LS_COLUMN) - string_list_add(&sl, argv[o]); + string_list_add_sorted(&sl, argv[o]); else ls_one(argv[o], &s); } diff --git a/commands/nandtest.c b/commands/nandtest.c new file mode 100644 index 0000000..3a955e9 --- /dev/null +++ b/commands/nandtest.c @@ -0,0 +1,364 @@ +/* + * Based on nandtest.c source in mtd-utils package. + * + * 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 + +/* Max ECC Bits that can be corrected */ +#define MAX_ECC_BITS 8 + +/* + * Structures for flash memory information. + */ +static struct region_info_user memregion; +static struct mtd_info_user meminfo; +static struct mtd_ecc_stats oldstats, newstats; + +static int fd, seed; +/* Markbad option flag */ +static int markbad; + +/* ECC-Calculation stats */ +static unsigned int ecc_stats[MAX_ECC_BITS]; +static unsigned int ecc_stats_over; +static unsigned int ecc_failed_cnt; + +/* + * Implementation of pread with lseek and read. + */ +static ssize_t pread(int fd, void *buf, size_t count, off_t offset) +{ + int ret; + + /* Seek to offset */ + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) + perror("lseek"); + + /* Read from flash and put it into buf */ + ret = read(fd, buf, count); + if (ret < 0) + perror("read"); + + return 0; +} + +/* + * Implementation of pwrite with lseek and write. + */ +static ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) +{ + int ret; + + ret = lseek(fd, offset, SEEK_SET); + if (ret < 0) + perror("lseek"); + + /* Write buf to flash */ + ret = write(fd, buf, count); + if (ret < 0) { + perror("write"); + if (markbad) { + printf("Mark block bad at 0x%08x\n", + (unsigned)(offset + memregion.offset)); + ioctl(fd, MEMSETBADBLOCK, &offset); + } + } + + flush(fd); + return 0; +} + +/* + * Erase and write function. + * Param ofs: offset on flash_device. + * Param data: data to write on flash. + * Param rbuf: pointer to allocated buffer to copy readed data. + */ +static int erase_and_write(off_t ofs, unsigned char *data, unsigned char *rbuf) +{ + struct erase_info_user er; + int i, ret; + + printf("\r0x%08x: erasing... ", (unsigned)(ofs + memregion.offset)); + + er.start = ofs; + er.length = meminfo.erasesize; + + ret = erase(fd, er.length, er.start); + if (ret < 0) { + perror("erase"); + printf("Could't not erase flash at 0x%08x length 0x%08x.\n", + er.start, er.length); + return ret; + } + + printf("\r0x%08x: writing...", (unsigned)(ofs + memregion.offset)); + + /* Write data to given offset */ + pwrite(fd, data, meminfo.erasesize, ofs); + + printf("\r0x%08x: reading...", (unsigned)(ofs + memregion.offset)); + + /* Read data from offset */ + pread(fd, rbuf, meminfo.erasesize, ofs); + + ret = ioctl(fd, ECCGETSTATS, &newstats); + if (ret < 0) { + perror("ECCGETSTATS"); + return ret; + } + + if (newstats.corrected > oldstats.corrected) { + printf("\n %d bit(s) ECC corrected at 0x%08x\n", + newstats.corrected - oldstats.corrected, + (unsigned)(ofs + memregion.offset)); + if ((newstats.corrected-oldstats.corrected) >= MAX_ECC_BITS) { + /* Increment ECC stats that are over MAX_ECC_BITS */ + ecc_stats_over++; + } else { + /* Increment ECC stat value */ + ecc_stats[(newstats.corrected-oldstats.corrected)-1]++; + } + /* Set oldstats to newstats */ + oldstats.corrected = newstats.corrected; + } + if (newstats.failed > oldstats.failed) { + printf("\nECC failed at 0x%08x\n", + (unsigned)(ofs + memregion.offset)); + oldstats.failed = newstats.failed; + ecc_failed_cnt++; + } + + printf("\r0x%08x: checking...", (unsigned)(ofs + memregion.offset)); + + /* Compared written data with read data. + * If data is not identical, display a detailed + * debugging information. */ + ret = memcmp(data, rbuf, meminfo.erasesize); + if (ret < 0) { + printf("\ncompare failed. seed %d\n", seed); + for (i = 0; i < meminfo.erasesize; i++) { + if (data[i] != rbuf[i]) + printf("Byte 0x%x is %02x should be %02x\n", + i, rbuf[i], data[i]); + } + return ret; + } + return 0; +} + +/* Print stats of nandtest. */ +static void print_stats(int nr_passes, int length) +{ + int i; + printf("-------- Summary --------\n"); + printf("Tested blocks : %d\n", (length/meminfo.erasesize) + * nr_passes); + + for (i = 0; i < MAX_ECC_BITS; i++) + printf("ECC %d bit error(s) : %d\n", i+1, ecc_stats[i]); + + printf("ECC >%d bit error(s) : %d\n", MAX_ECC_BITS, ecc_stats_over); + printf("ECC corrections failed : %d\n", ecc_failed_cnt); + printf("-------------------------\n"); +} + +/* Main program. */ +static int do_nandtest(struct command *cmdtp, int argc, char *argv[]) +{ + int opt, length = -1, do_nandtest_dev = -1; + off_t flash_offset = 0; + off_t test_ofs; + unsigned int nr_passes = 1, pass; + int i; + int ret = -1; + unsigned char *wbuf, *rbuf; + + ecc_failed_cnt = 0; + ecc_stats_over = 0; + markbad = 0; + fd = -1; + + memset(ecc_stats, 0, MAX_ECC_BITS); + + while ((opt = getopt(argc, argv, "ms:p:o:l:t")) > 0) { + switch (opt) { + case 'm': + markbad = 1; + break; + case 's': + seed = simple_strtoul(optarg, NULL, 0); + break; + case 'p': + nr_passes = simple_strtoul(optarg, NULL, 0); + break; + case 'o': + flash_offset = simple_strtoul(optarg, NULL, 0); + break; + case 'l': + length = simple_strtoul(optarg, NULL, 0); + break; + case 't': + do_nandtest_dev = 1; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + /* Check if no device is given */ + if (optind >= argc) + return COMMAND_ERROR_USAGE; + + if (do_nandtest_dev == -1) { + printf("Please add -t parameter to start nandtest.\n"); + return 0; + } + + printf("Open device %s\n", argv[optind]); + + fd = open(argv[optind], O_RDWR); + if (fd < 0) { + perror("open"); + return COMMAND_ERROR_USAGE; + } + + /* Getting flash information. */ + + ret = ioctl(fd, MEMGETINFO, &meminfo); + if (ret < 0) { + perror("MEMGETINFO"); + goto err; + } + + ret = ioctl(fd, MEMGETREGIONINFO, &memregion); + if (ret < 0) { + perror("MEMGETREGIONINFO"); + goto err; + } + + ret = ioctl(fd, ECCGETSTATS, &oldstats); + if (ret < 0) { + perror("ECCGETSTATS"); + goto err; + } + + if (length == -1) { + length = meminfo.size; + length -= flash_offset; + } + + printf("Flash offset: 0x%08x\n", + (unsigned)(flash_offset+memregion.offset)); + printf("Length: 0x%08x\n", (unsigned)length); + printf("End address: 0x%08x\n", + (unsigned)(flash_offset+length+memregion.offset)); + printf("Erasesize: 0x%08x\n", (unsigned)(meminfo.erasesize)); + printf("Starting nandtest...\n"); + + if (flash_offset % meminfo.erasesize) { + printf("Offset 0x%08x not multiple of erase size 0x%08x\n", + (unsigned)flash_offset, meminfo.erasesize); + goto err; + } + if (length % meminfo.erasesize) { + printf("Length 0x%08x not multiple of erase size 0x%08x\n", + length, meminfo.erasesize); + goto err; + } + if (length + flash_offset > meminfo.size) { + printf("Length 0x%08x + offset 0x%08x exceeds " + "device size 0x%08x\n", + length, (unsigned)flash_offset, meminfo.size); + goto err; + } + + wbuf = malloc(meminfo.erasesize * 2); + if (!wbuf) { + printf("Could not allocate %d bytes for buffer\n", + meminfo.erasesize * 2); + goto err; + } + rbuf = wbuf + meminfo.erasesize; + + for (pass = 0; pass < nr_passes; pass++) { + for (test_ofs = flash_offset; + test_ofs < flash_offset+length; + test_ofs += meminfo.erasesize) { + + srand(seed); + seed = rand(); + + if (ioctl(fd, MEMGETBADBLOCK, (void *)test_ofs)) { + printf("\rBad block at 0x%08x\n", + (unsigned)(test_ofs + + memregion.offset)); + continue; + } + + for (i = 0; i < meminfo.erasesize; i++) + wbuf[i] = rand(); + + ret = erase_and_write(test_ofs, wbuf, rbuf); + if (ret < 0) + goto err2; + } + printf("\nFinished pass %d successfully\n", pass+1); + } + + print_stats(nr_passes, length); + + ret = close(fd); + if (ret < 0) { + perror("close"); + goto err2; + } + + free(wbuf); + + return 0; +err2: + free(wbuf); +err: + printf("Error occurred.\n"); + close(fd); + return 1; +} + +/* String for usage of nandtest */ +static const __maybe_unused char cmd_nandtest_help[] = +"Usage: nand [OPTION] \n" + " -t, Really do a nandtest on device.\n" + " -m, Mark blocks bad if they appear so.\n" + " -s , Supply random seed.\n" + " -p , Number of passes.\n" + " -o , Start offset on flash.\n" + " -l , Length of flash to test.\n"; + +BAREBOX_CMD_START(nandtest) + .cmd = do_nandtest, + .usage = "NAND Test", + BAREBOX_CMD_HELP(cmd_nandtest_help) +BAREBOX_CMD_END diff --git a/commands/uimage.c b/commands/uimage.c new file mode 100644 index 0000000..82efd78 --- /dev/null +++ b/commands/uimage.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int uimage_fd; + +static int uimage_flush(void *buf, unsigned int len) +{ + int ret; + + ret = write_full(uimage_fd, buf, len); + + return ret; +} + +static int do_uimage(struct command *cmdtp, int argc, char *argv[]) +{ + struct uimage_handle *handle; + int ret; + int verify = 0; + int fd; + int opt; + char *extract = NULL; + int info = 0; + int image_no = 0; + + while ((opt = getopt(argc, argv, "ve:in:")) > 0) { + switch (opt) { + case 'v': + verify = 1; + break; + case 'i': + info = 1; + break; + case 'e': + extract = optarg; + break; + case 'n': + image_no = simple_strtoul(optarg, NULL, 0); + break; + } + } + + if (optind == argc) + return COMMAND_ERROR_USAGE; + + handle = uimage_open(argv[optind]); + if (!handle) + return 1; + + if (info) { + printf("Image at %s:\n", argv[optind]); + uimage_print_contents(handle); + } + + if (verify) { + printf("verifying data crc... "); + ret = uimage_verify(handle); + if (ret) { + goto err; + printf("Bad Data CRC\n"); + } else { + printf("ok\n"); + } + } + + if (extract) { + fd = open(extract, O_WRONLY | O_CREAT | O_TRUNC); + if (fd < 0) { + perror("open"); + ret = fd; + goto err; + } + uimage_fd = fd; + ret = uimage_load(handle, image_no, uimage_flush); + if (ret) { + printf("loading uImage failed with %d\n", ret); + close(fd); + goto err; + } + + close(fd); + } +err: + uimage_close(handle); + + return ret ? 1 : 0; +} + +BAREBOX_CMD_HELP_START(uimage) +BAREBOX_CMD_HELP_USAGE("uimage [OPTIONS] \n") +BAREBOX_CMD_HELP_OPT ("-i", "show information about image\n") +BAREBOX_CMD_HELP_OPT ("-v", "verify image\n") +BAREBOX_CMD_HELP_OPT ("-e ", "extract image to \n") +BAREBOX_CMD_HELP_OPT ("-n ", "use image number in multifile images\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(uimage) + .cmd = do_uimage, + .usage = "extract/verify uImage", + BAREBOX_CMD_HELP(cmd_uimage_help) +BAREBOX_CMD_END diff --git a/commands/usbserial.c b/commands/usbserial.c new file mode 100644 index 0000000..eb31934 --- /dev/null +++ b/commands/usbserial.c @@ -0,0 +1,108 @@ +/* + * usbserial.c - usb serial gadget command + * + * Copyright (c) 2011 Eric Bénard , Eukréa Electromatique + * based on dfu.c which is : + * Copyright (c) 2009 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 + +static int do_usbserial(struct command *cmdtp, int argc, char *argv[]) +{ + int opt; + struct usb_serial_pdata pdata; + char *argstr; + char *manufacturer = "barebox"; + char *productname = CONFIG_BOARDINFO; + u16 idVendor = 0, idProduct = 0; + int mode = 0; + + while ((opt = getopt(argc, argv, "m:p:V:P:asd")) > 0) { + switch (opt) { + case 'm': + manufacturer = optarg; + break; + case 'p': + productname = optarg; + break; + case 'V': + idVendor = simple_strtoul(optarg, NULL, 0); + break; + case 'P': + idProduct = simple_strtoul(optarg, NULL, 0); + break; + case 'a': + mode = 0; + break; +#ifdef HAVE_OBEX + case 'o': + mode = 1; + break; +#endif + case 's': + mode = 2; + break; + case 'd': + usb_serial_unregister(); + return 0; + } + } + + argstr = argv[optind]; + + pdata.manufacturer = manufacturer; + pdata.productname = productname; + pdata.idVendor = idVendor; + pdata.idProduct = idProduct; + pdata.mode = mode; + + return usb_serial_register(&pdata); +} + +BAREBOX_CMD_HELP_START(usbserial) +BAREBOX_CMD_HELP_USAGE("usbserial [OPTIONS] \n") +BAREBOX_CMD_HELP_SHORT("Enable/disable a serial gadget on the USB device interface.\n") +BAREBOX_CMD_HELP_OPT ("-m ", "Manufacturer string (barebox)\n") +BAREBOX_CMD_HELP_OPT ("-p ", "product string (" CONFIG_BOARDINFO ")\n") +BAREBOX_CMD_HELP_OPT ("-V ", "vendor id\n") +BAREBOX_CMD_HELP_OPT ("-P ", "product id\n") +BAREBOX_CMD_HELP_OPT ("-a", "CDC ACM (default)\n") +#ifdef HAVE_OBEX +BAREBOX_CMD_HELP_OPT ("-o", "CDC OBEX\n") +#endif +BAREBOX_CMD_HELP_OPT ("-s", "Generic Serial\n") +BAREBOX_CMD_HELP_OPT ("-d", "Disable the serial gadget\n") +BAREBOX_CMD_HELP_END + +/** + * @page usbserial_command + */ + +BAREBOX_CMD_START(usbserial) + .cmd = do_usbserial, + .usage = "Serial gadget enable/disable", + BAREBOX_CMD_HELP(cmd_usbserial_help) +BAREBOX_CMD_END diff --git a/common/Kconfig b/common/Kconfig index 27464d1..ca4f099 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -159,6 +159,9 @@ config MALLOC_DLMALLOC bool "dlmalloc" +config MALLOC_TLSF + bool "tlsf" + config MALLOC_DUMMY bool "dummy malloc" depends on SHELL_NONE @@ -398,10 +401,6 @@ Enabling this options activates all consoles on startup, so you will get output and a prompt on all consoles simultaneously. -config OF_FLAT_TREE - bool - prompt "Open Firmware flat device tree support" - config PARTITION bool prompt "Enable Partitions" @@ -428,6 +427,34 @@ Enabling this option will give you a default environment when the environment found in the environment sector is invalid +config DEFAULT_ENVIRONMENT_COMPRESSED + bool + depends on DEFAULT_ENVIRONMENT + default y if ZLIB + default y if BZLIB + default y if LZO_DECOMPRESS + +if DEFAULT_ENVIRONMENT_COMPRESSED + +choice + prompt "compression" + +config DEFAULT_ENVIRONMENT_COMPRESSED_GZIP + bool "gzip" + depends on ZLIB + +config DEFAULT_ENVIRONMENT_COMPRESSED_BZIP2 + bool "bzip2" + depends on BZLIB + +config DEFAULT_ENVIRONMENT_COMPRESSED_LZO + bool "lzo" + depends on LZO_DECOMPRESS + +endchoice + +endif + config DEFAULT_ENVIRONMENT_GENERIC bool depends on DEFAULT_ENVIRONMENT diff --git a/common/Makefile b/common/Makefile index 9bce479..d1132c3 100644 --- a/common/Makefile +++ b/common/Makefile @@ -1,7 +1,6 @@ obj-$(CONFIG_SHELL_HUSH) += hush.o obj-$(CONFIG_SHELL_SIMPLE) += parser.o obj-$(CONFIG_GREGORIAN_CALENDER) += date.o -obj-$(CONFIG_OF_FLAT_TREE) += ft_build.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_ENV_HANDLING) += environment.o obj-$(CONFIG_AUTO_COMPLETE) += complete.o @@ -14,6 +13,8 @@ obj-y += memory.o obj-$(CONFIG_MALLOC_DLMALLOC) += dlmalloc.o +obj-$(CONFIG_MALLOC_TLSF) += tlsf_malloc.o +obj-$(CONFIG_MALLOC_TLSF) += tlsf.o obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o obj-y += clock.o obj-y += version.o @@ -23,6 +24,7 @@ obj-$(CONFIG_DIGEST) += digest.o obj-$(CONFIG_ENVIRONMENT_VARIABLES) += env.o obj-$(CONFIG_CMD_BOOTM) += image.o +obj-$(CONFIG_CMD_BOOTM) += uimage.o obj-y += startup.o obj-y += misc.o obj-y += memsize.o @@ -52,5 +54,30 @@ barebox_default_env: $(ENV_FILES) $(Q)$(srctree)/scripts/genenv $(srctree) $(objtree) $(DEFAULT_ENVIRONMENT_PATH) -include/generated/barebox_default_env.h: barebox_default_env +barebox_default_env_comp = +ifeq ($(CONFIG_DEFAULT_ENVIRONMENT_COMPRESSED_GZIP),y) +barebox_default_env_comp = .gz +endif +ifeq ($(CONFIG_DEFAULT_ENVIRONMENT_COMPRESSED_BZIP2),y) +barebox_default_env_comp = .bz2 +endif +ifeq ($(CONFIG_DEFAULT_ENVIRONMENT_COMPRESSED_LZO),y) +barebox_default_env_comp = .lzo +endif + +barebox_default_env.gz: barebox_default_env + $(call if_changed,gzip) + +barebox_default_env.bz2: barebox_default_env + $(call if_changed,bzip2) + +barebox_default_env.lzo: barebox_default_env + $(call if_changed,lzo) + +include/generated/barebox_default_env.h: barebox_default_env$(barebox_default_env_comp) $(Q)cat $< | $(objtree)/scripts/bin2c default_environment > $@ + $(Q)echo "const int default_environment_uncompress_size=`stat -c%s barebox_default_env`;" >> $@ + +CLEAN_FILES += include/generated/barebox_default_env.h barebox_default_env +CLEAN_FILES += barebox_default_env.gz barebox_default_env.bz2 +CLEAN_FILES += barebox_default_env.lzo diff --git a/common/clock.c b/common/clock.c index 79c06c8..f322db8 100644 --- a/common/clock.c +++ b/common/clock.c @@ -27,6 +27,7 @@ #include #include #include +#include static struct clocksource *current_clock; static uint64_t time_ns; @@ -139,6 +140,9 @@ int is_timeout(uint64_t start_ns, uint64_t time_offset_ns) { + if (time_offset_ns >= 100 * USECOND) + poller_call(); + if ((int64_t)(start_ns + time_offset_ns - get_time_ns()) < 0) return 1; else diff --git a/common/complete.c b/common/complete.c index 46ba871..6d5349b 100644 --- a/common/complete.c +++ b/common/complete.c @@ -27,6 +27,7 @@ #include #include #include +#include static int file_complete(struct string_list *sl, char *instr) { @@ -55,7 +56,7 @@ strcat(tmp, "/"); else strcat(tmp, " "); - string_list_add(sl, tmp); + string_list_add_sorted(sl, tmp); } } @@ -67,6 +68,69 @@ return 0; } +static int path_command_complete(struct string_list *sl, char *instr) +{ + struct stat s; + DIR *dir; + struct dirent *d; + char tmp[PATH_MAX]; + char *path, *p, *n; + + p = path = strdup(getenv("PATH")); + + if (!path) + return -1; + + while (p) { + n = strchr(p, ':'); + if (n) + *n++ = '\0'; + if (*p == '\0') { + p = n; + continue; + } + dir = opendir(p); + + /* We need to check all PATH dirs, so if one failed, + * try next */ + if (!dir) { + p = n; + continue; + } + + while ((d = readdir(dir))) { + if (!strcmp(d->d_name, ".") || + !strcmp(d->d_name, "..")) + continue; + + if (!strncmp(instr, d->d_name, strlen(instr))) { + strcpy(tmp, d->d_name); + if (!stat(tmp, &s) && + S_ISDIR(s.st_mode)) + continue; + else + strcat(tmp, " "); + + /* This function is called + * after command_complete, + * so we check if a double + * entry exist */ + if (string_list_contains + (sl, tmp) == 0) { + string_list_add_sorted(sl, tmp); + } + } + } + + closedir(dir); + p = n; + } + + free(path); + + return 0; +} + static int command_complete(struct string_list *sl, char *instr) { struct command *cmdtp; @@ -121,8 +185,10 @@ t++; file_complete(&sl, t); instr = t; - } else + } else { command_complete(&sl, instr); + path_command_complete(&sl, instr); + } pos = strlen(instr); diff --git a/common/console.c b/common/console.c index cab8689..88c4010 100644 --- a/common/console.c +++ b/common/console.c @@ -225,8 +225,6 @@ */ start = get_time_ns(); while (1) { - poller_call(); - if (tstc_raw()) { kfifo_putc(console_input_buffer, getc_raw()); diff --git a/common/filetype.c b/common/filetype.c index 5635d40..40faff3 100644 --- a/common/filetype.c +++ b/common/filetype.c @@ -36,6 +36,7 @@ [filetype_jffs2] = "JFFS2 image", [filetype_gzip] = "gzip compressed", [filetype_bzip2] = "bzip2 compressed", + [filetype_oftree] = "open firmware flat device tree", }; const char *file_type_to_string(enum filetype f) @@ -69,6 +70,8 @@ if (buf8[0] == 'B' && buf8[1] == 'Z' && buf8[2] == 'h' && buf8[3] > '0' && buf8[3] <= '9') return filetype_bzip2; + if (buf[0] == be32_to_cpu(0xd00dfeed)) + return filetype_oftree; return filetype_unknown; } diff --git a/common/ft_build.c b/common/ft_build.c deleted file mode 100644 index 9042f13..0000000 --- a/common/ft_build.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * OF flat tree builder - * Written by: Pantelis Antoniou - * Updated by: Matthew McClintock - * - * 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 - -#undef DEBUG - -/* align addr on a size boundary - adjust address up if needed -- Cort */ -#define _ALIGN(addr,size) (((addr)+(size)-1)&(~((size)-1))) -#ifndef CONFIG_OF_BOOT_CPU -#define CONFIG_OF_BOOT_CPU 0 -#endif -#define SIZE_OF_RSVMAP_ENTRY (2*sizeof(u64)) - -static void ft_put_word(struct ft_cxt *cxt, u32 v) -{ - memmove(cxt->p + sizeof(u32), cxt->p, cxt->p_end - cxt->p); - - *(u32 *) cxt->p = cpu_to_be32(v); - cxt->p += sizeof(u32); - cxt->p_end += sizeof(u32); -} - -static inline void ft_put_bin(struct ft_cxt *cxt, const void *data, int sz) -{ - int aligned_size = ((u8 *)_ALIGN((unsigned long)cxt->p + sz, - sizeof(u32))) - cxt->p; - - memmove(cxt->p + aligned_size, cxt->p, cxt->p_end - cxt->p); - - /* make sure the last bytes are zeroed */ - memset(cxt->p + aligned_size - (aligned_size % sizeof(u32)), 0, - (aligned_size % sizeof(u32))); - - memcpy(cxt->p, data, sz); - - cxt->p += aligned_size; - cxt->p_end += aligned_size; -} - -void ft_begin_node(struct ft_cxt *cxt, const char *name) -{ - ft_put_word(cxt, OF_DT_BEGIN_NODE); - ft_put_bin(cxt, name, strlen(name) + 1); -} - -void ft_end_node(struct ft_cxt *cxt) -{ - ft_put_word(cxt, OF_DT_END_NODE); -} - -void ft_nop(struct ft_cxt *cxt) -{ - ft_put_word(cxt, OF_DT_NOP); -} - -static int lookup_string(struct ft_cxt *cxt, const char *name) -{ - u8 *p; - - p = cxt->p; - while (p < cxt->p_end) { - if (strcmp((char *)p, name) == 0) - return p - cxt->p; - p += strlen((char *)p) + 1; - } - - return -1; -} - -void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz) -{ - int off = 0; - - off = lookup_string(cxt, name); - if (off == -1) { - memcpy(cxt->p_end, name, strlen(name) + 1); - off = cxt->p_end - cxt->p; - cxt->p_end += strlen(name) + 1; - } - - /* now put offset from beginning of *STRUCTURE* */ - /* will be fixed up at the end */ - ft_put_word(cxt, OF_DT_PROP); - ft_put_word(cxt, sz); - ft_put_word(cxt, off); - ft_put_bin(cxt, data, sz); -} - -void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str) -{ - ft_prop(cxt, name, str, strlen(str) + 1); -} - -void ft_prop_int(struct ft_cxt *cxt, const char *name, int val) -{ - u32 v = cpu_to_be32((u32) val); - - ft_prop(cxt, name, &v, sizeof(u32)); -} - -/* pick up and start working on a tree in place */ -void ft_init_cxt(struct ft_cxt *cxt, void *blob) -{ - struct boot_param_header *bph = blob; - - memset(cxt, 0, sizeof(*cxt)); - - cxt->bph = bph; - bph->boot_cpuid_phys = CONFIG_OF_BOOT_CPU; - - /* find beginning and end of reserve map table (zeros in last entry) */ - cxt->p_rsvmap = (u8 *)bph + bph->off_mem_rsvmap; - while ( ((uint64_t *)cxt->p_rsvmap)[0] != 0 && - ((uint64_t *)cxt->p_rsvmap)[1] != 0 ) { - cxt->p_rsvmap += SIZE_OF_RSVMAP_ENTRY; - } - - cxt->p_start = (u8 *)bph + bph->off_dt_struct; - cxt->p_end = (u8 *)bph + bph->totalsize; - cxt->p = (u8 *)bph + bph->off_dt_strings; -} - -/* add a reserver physical area to the rsvmap */ -void ft_add_rsvmap(struct ft_cxt *cxt, u64 physstart, u64 physend) -{ - memmove(cxt->p_rsvmap + SIZE_OF_RSVMAP_ENTRY, cxt->p_rsvmap, - cxt->p_end - cxt->p_rsvmap); - - ((u64 *)cxt->p_rsvmap)[0] = cpu_to_be64(physstart); - ((u64 *)cxt->p_rsvmap)[1] = cpu_to_be64(physend); - ((u64 *)cxt->p_rsvmap)[2] = 0; - ((u64 *)cxt->p_rsvmap)[3] = 0; - - cxt->p_rsvmap += SIZE_OF_RSVMAP_ENTRY; - cxt->p_start += SIZE_OF_RSVMAP_ENTRY; - cxt->p += SIZE_OF_RSVMAP_ENTRY; - cxt->p_end += SIZE_OF_RSVMAP_ENTRY; -} - -void ft_end_tree(struct ft_cxt *cxt) -{ - ft_put_word(cxt, OF_DT_END); -} - -/* update the boot param header with correct values */ -void ft_finalize_tree(struct ft_cxt *cxt) { - struct boot_param_header *bph = cxt->bph; - - bph->totalsize = cxt->p_end - (u8 *)bph; - bph->off_dt_struct = cxt->p_start - (u8 *)bph; - bph->off_dt_strings = cxt->p - (u8 *)bph; - bph->dt_strings_size = cxt->p_end - cxt->p; -} - -static inline int isprint(int c) -{ - return c >= 0x20 && c <= 0x7e; -} - -static int is_printable_string(const void *data, int len) -{ - const char *s = data; - const char *ss; - - /* zero length is not */ - if (len == 0) - return 0; - - /* must terminate with zero */ - if (s[len - 1] != '\0') - return 0; - - ss = s; - while (*s && isprint(*s)) - s++; - - /* not zero, or not done yet */ - if (*s != '\0' || (s + 1 - ss) < len) - return 0; - - return 1; -} - -static void print_data(const void *data, int len) -{ - int i; - const u8 *s; - - /* no data, don't print */ - if (len == 0) - return; - - if (is_printable_string(data, len)) { - puts(" = \""); - puts(data); - puts("\""); - return; - } - - switch (len) { - case 1: /* byte */ - printf(" = <%02x>", (*(u8 *) data) & 0xff); - break; - case 2: /* half-word */ - printf(" = <%04x>", be16_to_cpu(*(u16 *) data) & 0xffff); - break; - case 4: /* word */ - printf(" = <%x>", be32_to_cpu(*(u32 *) data) & 0xffffffffU); - break; - case 8: /* double-word */ - printf(" = <%qx>", be64_to_cpu(*(uint64_t *) data)); - break; - default: /* anything else... hexdump */ - printf(" = ["); - for (i = 0, s = data; i < len; i++) - printf("%02x%s", s[i], i < len - 1 ? " " : ""); - printf("]"); - - break; - } -} - -void ft_dump_blob(const void *bphp) -{ - const struct boot_param_header *bph = bphp; - const uint64_t *p_rsvmap = (const uint64_t *) - ((const char *)bph + be32_to_cpu(bph->off_mem_rsvmap)); - const u32 *p_struct = (const u32 *) - ((const char *)bph + be32_to_cpu(bph->off_dt_struct)); - const u32 *p_strings = (const u32 *) - ((const char *)bph + be32_to_cpu(bph->off_dt_strings)); - u32 tag; - const u32 *p; - const char *s, *t; - int depth, sz, shift; - int i; - uint64_t addr, size; - - if (be32_to_cpu(bph->magic) != OF_DT_HEADER) { - /* not valid tree */ - return; - } - - depth = 0; - shift = 4; - - for (i = 0;; i++) { - addr = be64_to_cpu(p_rsvmap[i * 2]); - size = be64_to_cpu(p_rsvmap[i * 2 + 1]); - if (addr == 0 && size == 0) - break; - - printf("/memreserve/ %qx %qx;\n", addr, size); - } - - p = p_struct; - while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { - - /* printf("tag: 0x%08x (%d)\n", tag, p - p_struct); */ - - if (tag == OF_DT_BEGIN_NODE) { - s = (const char *)p; - p = (u32 *) _ALIGN((unsigned long)p + strlen(s) + 1, 4); - - printf("%*s%s {\n", depth * shift, "", s); - - depth++; - continue; - } - - if (tag == OF_DT_END_NODE) { - depth--; - - printf("%*s};\n", depth * shift, ""); - continue; - } - - if (tag == OF_DT_NOP) { - printf("%*s[NOP]\n", depth * shift, ""); - continue; - } - - if (tag != OF_DT_PROP) { - fprintf(stderr, "%*s ** Unknown tag 0x%08x at 0x%p\n", - depth * shift, "", tag, --p); - break; - } - sz = be32_to_cpu(*p++); - s = (const char *)p_strings + be32_to_cpu(*p++); - t = (const char *)p; - p = (const u32 *)_ALIGN((unsigned long)p + sz, 4); - printf("%*s%s", depth * shift, "", s); - print_data(t, sz); - printf(";\n"); - } -} - -void ft_backtrack_node(struct ft_cxt *cxt) -{ - int i = 4; - - while (be32_to_cpu(*(u32 *) (cxt->p - i)) != OF_DT_END_NODE) - i += 4; - - memmove (cxt->p - i, cxt->p, cxt->p_end - cxt->p); - - cxt->p_end -= i; - cxt->p -= i; -} - -void *ft_get_prop(void *bphp, const char *propname, int *szp) -{ - struct boot_param_header *bph = bphp; - uint32_t *p_struct = - (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_struct)); - uint32_t *p_strings = - (uint32_t *) ((char *)bph + be32_to_cpu(bph->off_dt_strings)); - uint32_t version = be32_to_cpu(bph->version); - uint32_t tag; - uint32_t *p; - char *s, *t; - char *ss; - int sz; - static char path[256], prop[256]; - - path[0] = '\0'; - - p = p_struct; - while ((tag = be32_to_cpu(*p++)) != OF_DT_END) { - - if (tag == OF_DT_BEGIN_NODE) { - s = (char *)p; - p = (uint32_t *) _ALIGN((unsigned long)p + strlen(s) + - 1, 4); - strcat(path, s); - strcat(path, "/"); - continue; - } - - if (tag == OF_DT_END_NODE) { - path[strlen(path) - 1] = '\0'; - ss = strrchr(path, '/'); - if (ss != NULL) - ss[1] = '\0'; - continue; - } - - if (tag == OF_DT_NOP) - continue; - - if (tag != OF_DT_PROP) - break; - - sz = be32_to_cpu(*p++); - s = (char *)p_strings + be32_to_cpu(*p++); - if (version < 0x10 && sz >= 8) - p = (uint32_t *) _ALIGN((unsigned long)p, 8); - t = (char *)p; - p = (uint32_t *) _ALIGN((unsigned long)p + sz, 4); - - strcpy(prop, path); - strcat(prop, s); - - if (strcmp(prop, propname) == 0) { - *szp = sz; - return t; - } - } - - return NULL; -} - -/********************************************************************/ - -/* Function that returns a character from the environment */ -extern uchar(*env_get_char) (int); - -#define BDM(x) { .name = #x, .offset = offsetof(bd_t, bi_ ##x ) } - -#ifdef CONFIG_OF_HAS_BD_T -static const struct { - const char *name; - int offset; -} bd_map[] = { - BDM(memstart), - BDM(memsize), - BDM(flashstart), - BDM(flashsize), - BDM(flashoffset), - BDM(sramstart), - BDM(sramsize), -#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) \ - || defined(CONFIG_E500) - BDM(immr_base), -#endif -#if defined(CONFIG_MPC5xxx) - BDM(mbar_base), -#endif -#if defined(CONFIG_MPC83XX) - BDM(immrbar), -#endif -#if defined(CONFIG_MPC8220) - BDM(mbar_base), - BDM(inpfreq), - BDM(pcifreq), - BDM(pevfreq), - BDM(flbfreq), - BDM(vcofreq), -#endif - BDM(bootflags), - BDM(ip_addr), - BDM(intfreq), - BDM(busfreq), -#ifdef CONFIG_CPM2 - BDM(cpmfreq), - BDM(brgfreq), - BDM(sccfreq), - BDM(vco), -#endif -#if defined(CONFIG_MPC5xxx) - BDM(ipbfreq), - BDM(pcifreq), -#endif - BDM(baudrate), -}; -#endif - -void ft_setup(void *blob, bd_t * bd, ulong initrd_start, ulong initrd_end) -{ - u32 *p; - int len; - struct ft_cxt cxt; - ulong clock; -#if defined(CONFIG_OF_HAS_BAREBOX_ENV) - int k, nxt; -#endif -#if defined(CONFIG_OF_HAS_BD_T) - u8 *end; -#endif -#if defined(CONFIG_OF_HAS_BAREBOX_ENV) || defined(CONFIG_OF_HAS_BD_T) - int i; - static char tmpenv[256]; -#endif - - /* disable OF tree; booting old kernel */ - if (getenv("disable_of") != NULL) { - memcpy(blob, bd, sizeof(*bd)); - return; - } - -#ifdef DEBUG - printf ("recieved oftree\n"); - ft_dump_blob(blob); -#endif - - ft_init_cxt(&cxt, blob); - - if (initrd_start && initrd_end) - ft_add_rsvmap(&cxt, initrd_start, initrd_end - initrd_start + 1); - - /* back into root */ - ft_backtrack_node(&cxt); - -#ifdef CONFIG_OF_HAS_BAREBOX_ENV - ft_begin_node(&cxt, "barebox-env"); - - for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) { - char *s, *lval, *rval; - - for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) ; - s = tmpenv; - for (k = i; k < nxt && s < &tmpenv[sizeof(tmpenv) - 1]; ++k) - *s++ = env_get_char(k); - *s++ = '\0'; - lval = tmpenv; - s = strchr(tmpenv, '='); - if (s != NULL) { - *s++ = '\0'; - rval = s; - } else - continue; - ft_prop_str(&cxt, lval, rval); - } - - ft_end_node(&cxt); -#endif - - ft_begin_node(&cxt, "chosen"); - ft_prop_str(&cxt, "name", "chosen"); - - ft_prop_str(&cxt, "bootargs", getenv("bootargs")); - ft_prop_int(&cxt, "linux,platform", 0x600); /* what is this? */ - if (initrd_start && initrd_end) { - ft_prop_int(&cxt, "linux,initrd-start", initrd_start); - ft_prop_int(&cxt, "linux,initrd-end", initrd_end); - } -#ifdef OF_STDOUT_PATH - ft_prop_str(&cxt, "linux,stdout-path", OF_STDOUT_PATH); -#endif - - ft_end_node(&cxt); - - ft_end_node(&cxt); /* end root */ - - ft_end_tree(&cxt); - ft_finalize_tree(&cxt); - -#ifdef CONFIG_OF_HAS_BD_T - /* paste the bd_t at the end of the flat tree */ - end = (char *)blob + - be32_to_cpu(((struct boot_param_header *)blob)->totalsize); - memcpy(end, bd, sizeof(*bd)); -#endif - -#ifdef CONFIG_PPC - -#ifdef CONFIG_OF_HAS_BD_T - for (i = 0; i < sizeof(bd_map)/sizeof(bd_map[0]); i++) { - uint32_t v; - - sprintf(tmpenv, "/bd_t/%s", bd_map[i].name); - v = *(uint32_t *)((char *)bd + bd_map[i].offset); - - p = ft_get_prop(blob, tmpenv, &len); - if (p != NULL) - *p = cpu_to_be32(v); - } - - p = ft_get_prop(blob, "/bd_t/enetaddr", &len); - if (p != NULL) - memcpy(p, bd->bi_enetaddr, 6); - - p = ft_get_prop(blob, "/bd_t/ethspeed", &len); - if (p != NULL) - *p = cpu_to_be32((uint32_t) bd->bi_ethspeed); -#endif - - clock = bd->bi_intfreq; - p = ft_get_prop(blob, "/cpus/" OF_CPU "/clock-frequency", &len); - if (p != NULL) - *p = cpu_to_be32(clock); - -#ifdef OF_TBCLK - clock = OF_TBCLK; - p = ft_get_prop(blob, "/cpus/" OF_CPU "/timebase-frequency", &len); - if (p != NULL) - *p = cpu_to_be32(clock); -#endif -#endif /* __powerpc__ */ - -#ifdef CONFIG_OF_BOARD_SETUP - ft_board_setup(blob, bd); -#endif - - /* in case the size changed in the platform code */ - ft_finalize_tree(&cxt); - -#ifdef DEBUG - printf("final OF-tree\n"); - ft_dump_blob(blob); -#endif -} - -#if 0 -static int oftree_handler_cmdline_parse(struct image_data *data, int opt, - char *optarg) -{ - switch(opt) { - case 'o': - printf("using oftree %s\n", optarg); - data->oftree = optarg; - return 0; - default: - return 1; - } -} - -static struct image_handler of_handler = { - .cmdline_options = "o:", - .cmdline_parse = oftree_handler_cmdline_parse, - .help_string = " -o use oftree", -}; - -static int oftree_register_image_handler(void) -{ - return register_image_handler(&of_handler); -} - -late_initcall(oftree_register_image_handler); -#endif diff --git a/common/image.c b/common/image.c index d68889b..e7d2242 100644 --- a/common/image.c +++ b/common/image.c @@ -144,290 +144,3 @@ return get_table_entry_name(comp_name, "Unknown Compression", comp); } #endif - -/** - * image_multi_count - get component (sub-image) count - * @hdr: pointer to the header of the multi component image - * - * image_multi_count() returns number of components in a multi - * component image. - * - * Note: no checking of the image type is done, caller must pass - * a valid multi component image. - * - * returns: - * number of components - */ -ulong image_multi_count(void *data) -{ - ulong i, count = 0; - uint32_t *size; - - /* get start of the image payload, which in case of multi - * component images that points to a table of component sizes */ - size = (uint32_t *)data; - - /* count non empty slots */ - for (i = 0; size[i]; ++i) - count++; - - return count; -} - -/** - * image_multi_getimg - get component data address and size - * @hdr: pointer to the header of the multi component image - * @idx: index of the requested component - * @data: pointer to a ulong variable, will hold component data address - * @len: pointer to a ulong variable, will hold component size - * - * image_multi_getimg() returns size and data address for the requested - * component in a multi component image. - * - * Note: no checking of the image type is done, caller must pass - * a valid multi component image. - * - * returns: - * data address and size of the component, if idx is valid - * 0 in data and len, if idx is out of range - */ -void image_multi_getimg(void *data, ulong idx, - ulong *img_data, ulong *len) -{ - int i; - uint32_t *size; - ulong offset, count, tmp_img_data; - - /* get number of component */ - count = image_multi_count(data); - - /* get start of the image payload, which in case of multi - * component images that points to a table of component sizes */ - size = (uint32_t *)data; - - /* get address of the proper component data start, which means - * skipping sizes table (add 1 for last, null entry) */ - tmp_img_data = (ulong)data + (count + 1) * sizeof (uint32_t); - - if (idx < count) { - *len = uimage_to_cpu(size[idx]); - offset = 0; - - /* go over all indices preceding requested component idx */ - for (i = 0; i < idx; i++) { - /* add up i-th component size, rounding up to 4 bytes */ - offset += (uimage_to_cpu(size[i]) + 3) & ~3 ; - } - - /* calculate idx-th component data address */ - *img_data = tmp_img_data + offset; - } else { - *len = 0; - *img_data = 0; - } -} - -static void image_print_type(const image_header_t *hdr) -{ - const char *os, *arch, *type, *comp; - - os = image_get_os_name(image_get_os(hdr)); - arch = image_get_arch_name(image_get_arch(hdr)); - type = image_get_type_name(image_get_type(hdr)); - comp = image_get_comp_name(image_get_comp(hdr)); - - printf ("%s %s %s (%s)\n", arch, os, type, comp); -} - -#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || !defined(__BAREBOX__) -static void image_print_time(time_t timestamp) -{ -#if defined(__BAREBOX__) - struct rtc_time tm; - - to_tm(timestamp, &tm); - printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n", - tm.tm_year, tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); -#else - printf("%s", ctime(×tamp)); -#endif -} -#endif /* CONFIG_TIMESTAMP || CONFIG_CMD_DATE || !__BAREBOX__ */ - -void image_print_size(uint32_t size) -{ -#ifdef __BAREBOX__ - printf("%d Bytes = %s\n", size, size_human_readable(size)); -#else - printf("%d Bytes = %.2f kB = %.2f MB\n", - size, (double)size / 1.024e3, - (double)size / 1.048576e6); -#endif -} - -void image_print_contents(const image_header_t *hdr, void *data) -{ - const char *p; - int type; - -#ifdef __BAREBOX__ - p = " "; -#else - p = ""; -#endif - - printf("%sImage Name: %.*s\n", p, IH_NMLEN, image_get_name(hdr)); -#if defined(CONFIG_TIMESTAMP) || defined(CONFIG_CMD_DATE) || !defined(__BAREBOX__) - printf("%sCreated: ", p); - image_print_time((time_t)image_get_time(hdr)); -#endif - printf ("%sImage Type: ", p); - image_print_type(hdr); - printf ("%sData Size: ", p); - image_print_size(image_get_data_size(hdr)); - printf ("%sLoad Address: %08x\n", p, image_get_load(hdr)); - printf ("%sEntry Point: %08x\n", p, image_get_ep(hdr)); - - type = image_get_type(hdr); - if (data && (type == IH_TYPE_MULTI || type == IH_TYPE_SCRIPT)) { - int i; - ulong img_data, len; - ulong count = image_multi_count(data); - - printf ("%sContents:\n", p); - for (i = 0; i < count; i++) { - image_multi_getimg(data, i, &img_data, &len); - - printf("%s Image %d: ", p, i); - image_print_size(len); - - if (image_get_type(hdr) != IH_TYPE_SCRIPT && i > 0) { - /* - * the user may need to know offsets - * if planning to do something with - * multiple files - */ - printf("%s Offset = 0x%08lx\n", p, img_data); - } - } - } -} - -#ifdef __BAREBOX__ -struct image_handle *map_image(const char *filename, int verify) -{ - int fd; - uint32_t checksum, len; - struct image_handle *handle; - image_header_t *header; - int type; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - printf("could not open: %s\n", errno_str()); - return NULL; - } - - handle = xzalloc(sizeof(struct image_handle)); - header = &handle->header; - - if (read(fd, header, image_get_header_size()) < 0) { - printf("could not read: %s\n", errno_str()); - goto err_out; - } - - if (image_get_magic(header) != IH_MAGIC) { - puts ("Bad Magic Number\n"); - goto err_out; - } - - checksum = image_get_hcrc(header); - header->ih_hcrc = 0; - - if (crc32 (0, (uchar *)header, image_get_header_size()) != checksum) { - puts ("Bad Header Checksum\n"); - goto err_out; - } - len = image_get_size(header); - - handle->data = memmap(fd, PROT_READ); - if (handle->data == (void *)-1) { - handle->data = xmalloc(len); - handle->flags = IH_MALLOC; - if (read(fd, handle->data, len) < 0) { - printf("could not read: %s\n", errno_str()); - goto err_out; - } - } else { - handle->data = (void *)((unsigned long)handle->data + - image_get_header_size()); - } - - type = image_get_type(header); - if (type == IH_TYPE_MULTI) { - struct image_handle_data *data_entries; - int i; - ulong img_data; - ulong count = image_multi_count(handle->data); - - data_entries = xzalloc(sizeof(struct image_handle_data) * count); - - for (i = 0; i < count; i++) { - image_multi_getimg(handle->data, i, &img_data, - &data_entries[i].len); - - data_entries[i].data = (void*)img_data; - } - handle->data_entries = data_entries; - handle->nb_data_entries = count; - } else { - handle->data_entries = gen_image_handle_data(handle->data, len); - handle->nb_data_entries = 1; - } - - if (verify) { - puts (" Verifying Checksum ... "); - if (crc32 (0, handle->data, len) != image_get_dcrc(header)) { - printf ("Bad Data CRC\n"); - goto err_out; - } - puts ("OK\n"); - } - - image_print_contents(header, handle->data); - - close(fd); - - return handle; -err_out: - close(fd); - if (handle->flags & IH_MALLOC) - free(handle->data); - free(handle->data_entries); - free(handle); - return NULL; -} -EXPORT_SYMBOL(map_image); - -void unmap_image(struct image_handle *handle) -{ - if (handle->flags & IH_MALLOC) - free(handle->data); - free(handle->data_entries); - free(handle); -} -EXPORT_SYMBOL(unmap_image); - -struct image_handle_data * gen_image_handle_data(void* data, ulong len) -{ - struct image_handle_data *iha; - - iha = xzalloc(sizeof(struct image_handle_data)); - iha->data = data; - iha->len = len; - - return iha; -} -EXPORT_SYMBOL(gen_image_handle_data); -#endif diff --git a/common/memory.c b/common/memory.c index f0ae1cc..faff33b 100644 --- a/common/memory.c +++ b/common/memory.c @@ -47,11 +47,19 @@ return malloc_end; } +#ifdef CONFIG_MALLOC_TLSF +#include +tlsf_pool tlsf_mem_pool; +#endif + void mem_malloc_init(void *start, void *end) { malloc_start = (unsigned long)start; malloc_end = (unsigned long)end; malloc_brk = malloc_start; +#ifdef CONFIG_MALLOC_TLSF + tlsf_mem_pool = tlsf_create(start, (char *)end - (char *)start); +#endif } #ifndef __SANDBOX__ diff --git a/common/oftree.c b/common/oftree.c index 2a2f464..a657d31 100644 --- a/common/oftree.c +++ b/common/oftree.c @@ -293,20 +293,28 @@ return 0; } -struct fdt_header *of_get_fixed_tree(void) +int of_fix_tree(struct fdt_header *fdt) { struct of_fixup *of_fixup; int ret; - if (!barebox_fdt) - return NULL; - list_for_each_entry(of_fixup, &of_fixup_list, list) { - ret = of_fixup->fixup(barebox_fdt); + ret = of_fixup->fixup(fdt); if (ret) - return NULL; + return ret; } - return barebox_fdt; + return 0; } +struct fdt_header *of_get_fixed_tree(void) +{ + int ret; + + if (!barebox_fdt) + return NULL; + ret = of_fix_tree(barebox_fdt); + if (ret) + return NULL; + return barebox_fdt; +} diff --git a/common/startup.c b/common/startup.c index 13783fb..180fdc3 100644 --- a/common/startup.c +++ b/common/startup.c @@ -64,10 +64,35 @@ #ifdef CONFIG_DEFAULT_ENVIRONMENT #include +#ifdef CONFIG_DEFAULT_ENVIRONMENT_COMPRESSED +#include +void *defaultenv; +#else +#define defaultenv default_environment +#endif + static int register_default_env(void) { - add_mem_device("defaultenv", (unsigned long)default_environment, - sizeof(default_environment), +#ifdef CONFIG_DEFAULT_ENVIRONMENT_COMPRESSED + int ret; + void *tmp; + + tmp = xzalloc(default_environment_size); + memcpy(tmp, default_environment, default_environment_size); + + defaultenv = xzalloc(default_environment_uncompress_size); + + ret = uncompress(tmp, default_environment_size, NULL, NULL, + defaultenv, NULL, uncompress_err_stdout); + + free(tmp); + + if (ret) + return ret; +#endif + + add_mem_device("defaultenv", (unsigned long)defaultenv, + default_environment_uncompress_size, IORESOURCE_MEM_WRITEABLE); return 0; } diff --git a/common/tlsf.c b/common/tlsf.c new file mode 100644 index 0000000..c810e8d --- /dev/null +++ b/common/tlsf.c @@ -0,0 +1,969 @@ +#include +#include +#include +#include +#include + +#include "tlsf.h" +#include "tlsfbits.h" + +#ifdef DEBUG +#define tlsf_assert(expr) \ + ((expr) ? (void)(0) : printf("%s\n", __stringify(expr))) +#else +#define tlsf_assert(expr) (void)(0) +#endif + +/* +** Constants. +*/ + +/* Public constants: may be modified. */ +enum tlsf_public +{ + /* log2 of number of linear subdivisions of block sizes. */ + SL_INDEX_COUNT_LOG2 = 5, +}; + +/* Private constants: do not modify. */ +enum tlsf_private +{ +#if defined (TLSF_64BIT) + /* All allocation sizes and addresses are aligned to 8 bytes. */ + ALIGN_SIZE_LOG2 = 3, +#else + /* All allocation sizes and addresses are aligned to 4 bytes. */ + ALIGN_SIZE_LOG2 = 2, +#endif + ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2), + + /* + ** We support allocations of sizes up to (1 << FL_INDEX_MAX) bits. + ** However, because we linearly subdivide the second-level lists, and + ** our minimum size granularity is 4 bytes, it doesn't make sense to + ** create first-level lists for sizes smaller than SL_INDEX_COUNT * 4, + ** or (1 << (SL_INDEX_COUNT_LOG2 + 2)) bytes, as there we will be + ** trying to split size ranges into more slots than we have available. + ** Instead, we calculate the minimum threshold size, and place all + ** blocks below that size into the 0th first-level list. + */ + +#if defined (TLSF_64BIT) + /* + ** TODO: We can increase this to support larger sizes, at the expense + ** of more overhead in the TLSF structure. + */ + FL_INDEX_MAX = 32, +#else + FL_INDEX_MAX = 30, +#endif + SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2), + FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2), + FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1), + + SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT), +}; + +/* +** Cast and min/max macros. +*/ + +#define tlsf_cast(t, exp) ((t) (exp)) +#define tlsf_min(a, b) ((a) < (b) ? (a) : (b)) +#define tlsf_max(a, b) ((a) > (b) ? (a) : (b)) + +/* +** Set assert macro, if it has not been provided by the user. +*/ +#if !defined (tlsf_assert) +#define tlsf_assert assert +#endif + +/* +** Static assertion mechanism. +*/ + +#define _tlsf_glue2(x, y) x ## y +#define _tlsf_glue(x, y) _tlsf_glue2(x, y) +#define tlsf_static_assert(exp) \ + typedef char _tlsf_glue(static_assert, __LINE__) [(exp) ? 1 : -1] + +#ifndef __BAREBOX__ +/* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */ +tlsf_static_assert(sizeof(int) * CHAR_BIT == 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64); + +/* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */ +tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT); + +/* Ensure we've properly tuned our sizes. */ +tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT); +#endif + +/* +** Data structures and associated constants. +*/ + +/* +** Block header structure. +** +** There are several implementation subtleties involved: +** - The prev_phys_block field is only valid if the previous block is free. +** - The prev_phys_block field is actually stored at the end of the +** previous block. It appears at the beginning of this structure only to +** simplify the implementation. +** - The next_free / prev_free fields are only valid if the block is free. +*/ +typedef struct block_header_t +{ + /* Points to the previous physical block. */ + struct block_header_t* prev_phys_block; + + /* The size of this block, excluding the block header. */ + size_t size; + + /* Next and previous free blocks. */ + struct block_header_t* next_free; + struct block_header_t* prev_free; +} block_header_t; + +/* +** Since block sizes are always at least a multiple of 4, the two least +** significant bits of the size field are used to store the block status: +** - bit 0: whether block is busy or free +** - bit 1: whether previous block is busy or free +*/ +static const size_t block_header_free_bit = 1 << 0; +static const size_t block_header_prev_free_bit = 1 << 1; + +/* +** The size of the block header exposed to used blocks is the size field. +** The prev_phys_block field is stored *inside* the previous free block. +*/ +static const size_t block_header_overhead = sizeof(size_t); + +/* User data starts directly after the size field in a used block. */ +static const size_t block_start_offset = + offsetof(block_header_t, size) + sizeof(size_t); + +/* +** A free block must be large enough to store its header minus the size of +** the prev_phys_block field, and no larger than the number of addressable +** bits for FL_INDEX. +*/ +static const size_t block_size_min = + sizeof(block_header_t) - sizeof(block_header_t*); +static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX; + + +/* The TLSF pool structure. */ +typedef struct pool_t +{ + /* Empty lists point at this block to indicate they are free. */ + block_header_t block_null; + + /* Bitmaps for free lists. */ + unsigned int fl_bitmap; + unsigned int sl_bitmap[FL_INDEX_COUNT]; + + /* Head of free lists. */ + block_header_t* blocks[FL_INDEX_COUNT][SL_INDEX_COUNT]; +} pool_t; + +/* A type used for casting when doing pointer arithmetic. */ +typedef ptrdiff_t tlsfptr_t; + +/* +** block_header_t member functions. +*/ + +static size_t block_size(const block_header_t* block) +{ + return block->size & ~(block_header_free_bit | block_header_prev_free_bit); +} + +static void block_set_size(block_header_t* block, size_t size) +{ + const size_t oldsize = block->size; + block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit)); +} + +static int block_is_last(const block_header_t* block) +{ + return 0 == block_size(block); +} + +static int block_is_free(const block_header_t* block) +{ + return tlsf_cast(int, block->size & block_header_free_bit); +} + +static void block_set_free(block_header_t* block) +{ + block->size |= block_header_free_bit; +} + +static void block_set_used(block_header_t* block) +{ + block->size &= ~block_header_free_bit; +} + +static int block_is_prev_free(const block_header_t* block) +{ + return tlsf_cast(int, block->size & block_header_prev_free_bit); +} + +static void block_set_prev_free(block_header_t* block) +{ + block->size |= block_header_prev_free_bit; +} + +static void block_set_prev_used(block_header_t* block) +{ + block->size &= ~block_header_prev_free_bit; +} + +static block_header_t* block_from_ptr(const void* ptr) +{ + return tlsf_cast(block_header_t*, + tlsf_cast(unsigned char*, ptr) - block_start_offset); +} + +static void* block_to_ptr(const block_header_t* block) +{ + return tlsf_cast(void*, + tlsf_cast(unsigned char*, block) + block_start_offset); +} + +/* Return location of next block after block of given size. */ +static block_header_t* offset_to_block(const void* ptr, size_t size) +{ + return tlsf_cast(block_header_t*, tlsf_cast(tlsfptr_t, ptr) + size); +} + +/* Return location of previous block. */ +static block_header_t* block_prev(const block_header_t* block) +{ + return block->prev_phys_block; +} + +/* Return location of next existing block. */ +static block_header_t* block_next(const block_header_t* block) +{ + block_header_t* next = offset_to_block(block_to_ptr(block), + block_size(block) - block_header_overhead); + tlsf_assert(!block_is_last(block)); + return next; +} + +/* Link a new block with its physical neighbor, return the neighbor. */ +static block_header_t* block_link_next(block_header_t* block) +{ + block_header_t* next = block_next(block); + next->prev_phys_block = block; + return next; +} + +static void block_mark_as_free(block_header_t* block) +{ + /* Link the block to the next block, first. */ + block_header_t* next = block_link_next(block); + block_set_prev_free(next); + block_set_free(block); +} + +static void block_mark_as_used(block_header_t* block) +{ + block_header_t* next = block_next(block); + block_set_prev_used(next); + block_set_used(block); +} + +static size_t align_up(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return (x + (align - 1)) & ~(align - 1); +} + +static size_t align_down(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return x - (x & (align - 1)); +} + +static void* align_ptr(const void* ptr, size_t align) +{ + const tlsfptr_t aligned = + (tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1); + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return tlsf_cast(void*, aligned); +} + +/* +** Adjust an allocation size to be aligned to word size, and no smaller +** than internal minimum. +*/ +static size_t adjust_request_size(size_t size, size_t align) +{ + size_t adjust = 0; + if (size && size < block_size_max) + { + const size_t aligned = align_up(size, align); + adjust = tlsf_max(aligned, block_size_min); + } + return adjust; +} + +/* +** TLSF utility functions. In most cases, these are direct translations of +** the documentation found in the white paper. +*/ + +static void mapping_insert(size_t size, int* fli, int* sli) +{ + int fl, sl; + if (size < SMALL_BLOCK_SIZE) + { + /* Store small blocks in first list. */ + fl = 0; + sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + } + else + { + fl = tlsf_fls_sizet(size); + sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ (1 << SL_INDEX_COUNT_LOG2); + fl -= (FL_INDEX_SHIFT - 1); + } + *fli = fl; + *sli = sl; +} + +/* This version rounds up to the next block size (for allocations) */ +static void mapping_search(size_t size, int* fli, int* sli) +{ + if (size >= (1 << SL_INDEX_COUNT_LOG2)) + { + const size_t round = (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1; + size += round; + } + mapping_insert(size, fli, sli); +} + +static block_header_t* search_suitable_block(pool_t* pool, int* fli, int* sli) +{ + int fl = *fli; + int sl = *sli; + + /* + ** First, search for a block in the list associated with the given + ** fl/sl index. + */ + unsigned int sl_map = pool->sl_bitmap[fl] & (~0 << sl); + if (!sl_map) + { + /* No block exists. Search in the next largest first-level list. */ + const unsigned int fl_map = pool->fl_bitmap & (~0 << (fl + 1)); + if (!fl_map) + { + /* No free blocks available, memory has been exhausted. */ + return 0; + } + + fl = tlsf_ffs(fl_map); + *fli = fl; + sl_map = pool->sl_bitmap[fl]; + } + tlsf_assert(sl_map && "internal error - second level bitmap is null"); + sl = tlsf_ffs(sl_map); + *sli = sl; + + /* Return the first block in the free list. */ + return pool->blocks[fl][sl]; +} + +/* Remove a free block from the free list.*/ +static void remove_free_block(pool_t* pool, block_header_t* block, int fl, int sl) +{ + block_header_t* prev = block->prev_free; + block_header_t* next = block->next_free; + tlsf_assert(prev && "prev_free field can not be null"); + tlsf_assert(next && "next_free field can not be null"); + next->prev_free = prev; + prev->next_free = next; + + /* If this block is the head of the free list, set new head. */ + if (pool->blocks[fl][sl] == block) + { + pool->blocks[fl][sl] = next; + + /* If the new head is null, clear the bitmap. */ + if (next == &pool->block_null) + { + pool->sl_bitmap[fl] &= ~(1 << sl); + + /* If the second bitmap is now empty, clear the fl bitmap. */ + if (!pool->sl_bitmap[fl]) + { + pool->fl_bitmap &= ~(1 << fl); + } + } + } +} + +/* Insert a free block into the free block list. */ +static void insert_free_block(pool_t* pool, block_header_t* block, int fl, int sl) +{ + block_header_t* current = pool->blocks[fl][sl]; + tlsf_assert(current && "free list cannot have a null entry"); + tlsf_assert(block && "cannot insert a null entry into the free list"); + block->next_free = current; + block->prev_free = &pool->block_null; + current->prev_free = block; + + tlsf_assert(block_to_ptr(block) == align_ptr(block_to_ptr(block), ALIGN_SIZE) + && "block not aligned properly"); + /* + ** Insert the new block at the head of the list, and mark the first- + ** and second-level bitmaps appropriately. + */ + pool->blocks[fl][sl] = block; + pool->fl_bitmap |= (1 << fl); + pool->sl_bitmap[fl] |= (1 << sl); +} + +/* Remove a given block from the free list. */ +static void block_remove(pool_t* pool, block_header_t* block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(pool, block, fl, sl); +} + +/* Insert a given block into the free list. */ +static void block_insert(pool_t* pool, block_header_t* block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + insert_free_block(pool, block, fl, sl); +} + +static int block_can_split(block_header_t* block, size_t size) +{ + return block_size(block) >= sizeof(block_header_t) + size; +} + +/* Split a block into two, the second of which is free. */ +static block_header_t* block_split(block_header_t* block, size_t size) +{ + /* Calculate the amount of space left in the remaining block. */ + block_header_t* remaining = + offset_to_block(block_to_ptr(block), size - block_header_overhead); + + const size_t remain_size = block_size(block) - (size + block_header_overhead); + + tlsf_assert(block_to_ptr(remaining) == align_ptr(block_to_ptr(remaining), ALIGN_SIZE) + && "remaining block not aligned properly"); + + tlsf_assert(block_size(block) == remain_size + size + block_header_overhead); + block_set_size(remaining, remain_size); + tlsf_assert(block_size(remaining) >= block_size_min && "block split with invalid size"); + + block_set_size(block, size); + block_mark_as_free(remaining); + + return remaining; +} + +/* Absorb a free block's storage into an adjacent previous free block. */ +static block_header_t* block_absorb(block_header_t* prev, block_header_t* block) +{ + tlsf_assert(!block_is_last(prev) && "previous block can't be last!"); + /* Note: Leaves flags untouched. */ + prev->size += block_size(block) + block_header_overhead; + block_link_next(prev); + return prev; +} + +/* Merge a just-freed block with an adjacent previous free block. */ +static block_header_t* block_merge_prev(pool_t* pool, block_header_t* block) +{ + if (block_is_prev_free(block)) + { + block_header_t* prev = block_prev(block); + tlsf_assert(prev && "prev physical block can't be null"); + tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such"); + block_remove(pool, prev); + block = block_absorb(prev, block); + } + + return block; +} + +/* Merge a just-freed block with an adjacent free block. */ +static block_header_t* block_merge_next(pool_t* pool, block_header_t* block) +{ + block_header_t* next = block_next(block); + tlsf_assert(next && "next physical block can't be null"); + + if (block_is_free(next)) + { + tlsf_assert(!block_is_last(block) && "previous block can't be last!"); + block_remove(pool, next); + block = block_absorb(block, next); + } + + return block; +} + +/* Trim any trailing block space off the end of a block, return to pool. */ +static void block_trim_free(pool_t* pool, block_header_t* block, size_t size) +{ + tlsf_assert(block_is_free(block) && "block must be free"); + if (block_can_split(block, size)) + { + block_header_t* remaining_block = block_split(block, size); + block_link_next(block); + block_set_prev_free(remaining_block); + block_insert(pool, remaining_block); + } +} + +/* Trim any trailing block space off the end of a used block, return to pool. */ +static void block_trim_used(pool_t* pool, block_header_t* block, size_t size) +{ + tlsf_assert(!block_is_free(block) && "block must be used"); + if (block_can_split(block, size)) + { + /* If the next block is free, we must coalesce. */ + block_header_t* remaining_block = block_split(block, size); + block_set_prev_used(remaining_block); + + remaining_block = block_merge_next(pool, remaining_block); + block_insert(pool, remaining_block); + } +} + +static block_header_t* block_trim_free_leading(pool_t* pool, block_header_t* block, size_t size) +{ + block_header_t* remaining_block = block; + if (block_can_split(block, size)) + { + /* We want the 2nd block. */ + remaining_block = block_split(block, size - block_header_overhead); + block_set_prev_free(remaining_block); + + block_link_next(block); + block_insert(pool, block); + } + + return remaining_block; +} + +static block_header_t* block_locate_free(pool_t* pool, size_t size) +{ + int fl = 0, sl = 0; + block_header_t* block = 0; + + if (size) + { + mapping_search(size, &fl, &sl); + block = search_suitable_block(pool, &fl, &sl); + } + + if (block) + { + tlsf_assert(block_size(block) >= size); + remove_free_block(pool, block, fl, sl); + } + + return block; +} + +static void* block_prepare_used(pool_t* pool, block_header_t* block, size_t size) +{ + void* p = 0; + if (block) + { + block_trim_free(pool, block, size); + block_mark_as_used(block); + p = block_to_ptr(block); + } + return p; +} + +/* Clear structure and point all empty lists at the null block. */ +static void pool_construct(pool_t* pool) +{ + int i, j; + + pool->block_null.next_free = &pool->block_null; + pool->block_null.prev_free = &pool->block_null; + + pool->fl_bitmap = 0; + for (i = 0; i < FL_INDEX_COUNT; ++i) + { + pool->sl_bitmap[i] = 0; + for (j = 0; j < SL_INDEX_COUNT; ++j) + { + pool->blocks[i][j] = &pool->block_null; + } + } +} + +/* +** Debugging utilities. +*/ + +typedef struct integrity_t +{ + int prev_status; + int status; +} integrity_t; + +#define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } } + +static void integrity_walker(void* ptr, size_t size, int used, void* user) +{ + block_header_t* block = block_from_ptr(ptr); + integrity_t* integ = tlsf_cast(integrity_t*, user); + const int this_prev_status = block_is_prev_free(block) ? 1 : 0; + const int this_status = block_is_free(block) ? 1 : 0; + const size_t this_block_size = block_size(block); + + int status = 0; + tlsf_insist(integ->prev_status == this_prev_status && "prev status incorrect"); + tlsf_insist(size == this_block_size && "block size incorrect"); + + integ->prev_status = this_status; + integ->status += status; +} + +int tlsf_check_heap(tlsf_pool tlsf) +{ + int i, j; + + pool_t* pool = tlsf_cast(pool_t*, tlsf); + int status = 0; + + /* Check that the blocks are physically correct. */ + integrity_t integ = { 0, 0 }; + tlsf_walk_heap(tlsf, integrity_walker, &integ); + status = integ.status; + + /* Check that the free lists and bitmaps are accurate. */ + for (i = 0; i < FL_INDEX_COUNT; ++i) + { + for (j = 0; j < SL_INDEX_COUNT; ++j) + { + const int fl_map = pool->fl_bitmap & (1 << i); + const int sl_list = pool->sl_bitmap[i]; + const int sl_map = sl_list & (1 << j); + const block_header_t* block = pool->blocks[i][j]; + + /* Check that first- and second-level lists agree. */ + if (!fl_map) + { + tlsf_insist(!sl_map && "second-level map must be null"); + } + + if (!sl_map) + { + tlsf_insist(block == &pool->block_null && "block list must be null"); + continue; + } + + /* Check that there is at least one free block. */ + tlsf_insist(sl_list && "no free blocks in second-level map"); + tlsf_insist(block != &pool->block_null && "block should not be null"); + + while (block != &pool->block_null) + { + int fli, sli; + tlsf_insist(block_is_free(block) && "block should be free"); + tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced"); + tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced"); + tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free"); + tlsf_insist(block_size(block) >= block_size_min && "block not minimum size"); + + mapping_insert(block_size(block), &fli, &sli); + tlsf_insist(fli == i && sli == j && "block size indexed in wrong list"); + block = block->next_free; + } + } + } + + return status; +} + +#undef tlsf_insist + +static void default_walker(void* ptr, size_t size, int used, void* user) +{ + (void)user; + printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr)); +} + +void tlsf_walk_heap(tlsf_pool pool, tlsf_walker walker, void* user) +{ + tlsf_walker heap_walker = walker ? walker : default_walker; + block_header_t* block = + offset_to_block(pool, sizeof(pool_t) - block_header_overhead); + + while (block && !block_is_last(block)) + { + heap_walker( + block_to_ptr(block), + block_size(block), + !block_is_free(block), + user); + block = block_next(block); + } +} + +size_t tlsf_block_size(void* ptr) +{ + size_t size = 0; + if (ptr) + { + const block_header_t* block = block_from_ptr(ptr); + size = block_size(block); + } + return size; +} + +/* +** Overhead of the TLSF structures in a given memory block passed to +** tlsf_create, equal to the size of a pool_t plus overhead of the initial +** free block and the sentinel block. +*/ +size_t tlsf_overhead() +{ + const size_t pool_overhead = sizeof(pool_t) + 2 * block_header_overhead; + return pool_overhead; +} + +/* +** TLSF main interface. Right out of the white paper. +*/ + +tlsf_pool tlsf_create(void* mem, size_t bytes) +{ + block_header_t* block; + block_header_t* next; + + const size_t pool_overhead = tlsf_overhead(); + const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE); + pool_t* pool = tlsf_cast(pool_t*, mem); + +#ifdef DEBUG + /* Verify ffs/fls work properly. */ + int rv = 0; + rv += (tlsf_ffs(0) == -1) ? 0 : 0x1; + rv += (tlsf_fls(0) == -1) ? 0 : 0x2; + rv += (tlsf_ffs(1) == 0) ? 0 : 0x4; + rv += (tlsf_fls(1) == 0) ? 0 : 0x8; + rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10; + rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20; + rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40; + rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80; + +#if defined (TLSF_64BIT) + rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100; + rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200; + rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400; + if (rv) + { + printf("tlsf_create: %x ffs/fls tests failed!\n", rv); + return 0; + } +#endif +#endif + + if (pool_bytes < block_size_min || pool_bytes > block_size_max) + { +#if defined (TLSF_64BIT) + printf("tlsf_create: Pool size must be at least %d bytes.\n", + (unsigned int)(pool_overhead + block_size_min)); +#else + printf("tlsf_create: Pool size must be between %u and %u bytes.\n", + (unsigned int)(pool_overhead + block_size_min), + (unsigned int)(pool_overhead + block_size_max)); +#endif + return 0; + } + + /* Construct a valid pool object. */ + pool_construct(pool); + + /* + ** Create the main free block. Offset the start of the block slightly + ** so that the prev_phys_block field falls inside of the pool + ** structure - it will never be used. + */ + block = offset_to_block( + tlsf_cast(void*, pool), sizeof(pool_t) - block_header_overhead); + block_set_size(block, pool_bytes); + block_set_free(block); + block_set_prev_used(block); + block_insert(pool, block); + + /* Split the block to create a zero-size pool sentinel block. */ + next = block_link_next(block); + block_set_size(next, 0); + block_set_used(next); + block_set_prev_free(next); + + return tlsf_cast(tlsf_pool, pool); +} + +void tlsf_destroy(tlsf_pool pool) +{ + /* Nothing to do. */ + pool = pool; +} + +void* tlsf_malloc(tlsf_pool tlsf, size_t size) +{ + pool_t* pool = tlsf_cast(pool_t*, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + block_header_t* block = block_locate_free(pool, adjust); + return block_prepare_used(pool, block, adjust); +} + +void* tlsf_memalign(tlsf_pool tlsf, size_t align, size_t size) +{ + pool_t* pool = tlsf_cast(pool_t*, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + /* + ** We must allocate an additional minimum block size bytes so that if + ** our free block will leave an alignment gap which is smaller, we can + ** trim a leading free block and release it back to the heap. We must + ** do this because the previous physical block is in use, therefore + ** the prev_phys_block field is not valid, and we can't simply adjust + ** the size of that block. + */ + const size_t gap_minimum = sizeof(block_header_t); + const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align); + + /* If alignment is less than or equals base alignment, we're done. */ + const size_t aligned_size = (align <= ALIGN_SIZE) ? adjust : size_with_gap; + + block_header_t* block = block_locate_free(pool, aligned_size); + + /* This can't be a static assert. */ + tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead); + + if (block) + { + void* ptr = block_to_ptr(block); + void* aligned = align_ptr(ptr, align); + size_t gap = tlsf_cast(size_t, + tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + + /* If gap size is too small, offset to next aligned boundary. */ + if (gap && gap < gap_minimum) + { + const size_t gap_remain = gap_minimum - gap; + const size_t offset = tlsf_max(gap_remain, align); + const void* next_aligned = tlsf_cast(void*, + tlsf_cast(tlsfptr_t, aligned) + offset); + + aligned = align_ptr(next_aligned, align); + gap = tlsf_cast(size_t, + tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + } + + if (gap) + { + tlsf_assert(gap >= gap_minimum && "gap size too small"); + block = block_trim_free_leading(pool, block, gap); + } + } + + return block_prepare_used(pool, block, adjust); +} + +void tlsf_free(tlsf_pool tlsf, void* ptr) +{ + /* Don't attempt to free a NULL pointer. */ + if (ptr) + { + pool_t* pool = tlsf_cast(pool_t*, tlsf); + block_header_t* block = block_from_ptr(ptr); + block_mark_as_free(block); + block = block_merge_prev(pool, block); + block = block_merge_next(pool, block); + block_insert(pool, block); + } +} + +/* +** The TLSF block information provides us with enough information to +** provide a reasonably intelligent implementation of realloc, growing or +** shrinking the currently allocated block as required. +** +** This routine handles the somewhat esoteric edge cases of realloc: +** - a non-zero size with a null pointer will behave like malloc +** - a zero size with a non-null pointer will behave like free +** - a request that cannot be satisfied will leave the original buffer +** untouched +** - an extended buffer size will leave the newly-allocated area with +** contents undefined +*/ +void* tlsf_realloc(tlsf_pool tlsf, void* ptr, size_t size) +{ + pool_t* pool = tlsf_cast(pool_t*, tlsf); + void* p = 0; + + /* Zero-size requests are treated as free. */ + if (ptr && size == 0) + { + tlsf_free(tlsf, ptr); + } + /* Requests with NULL pointers are treated as malloc. */ + else if (!ptr) + { + p = tlsf_malloc(tlsf, size); + } + else + { + block_header_t* block = block_from_ptr(ptr); + block_header_t* next = block_next(block); + + const size_t cursize = block_size(block); + const size_t combined = cursize + block_size(next) + block_header_overhead; + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + /* + ** If the next block is used, or when combined with the current + ** block, does not offer enough space, we must reallocate and copy. + */ + if (adjust > cursize && (!block_is_free(next) || adjust > combined)) + { + p = tlsf_malloc(tlsf, size); + if (p) + { + const size_t minsize = tlsf_min(cursize, size); + memcpy(p, ptr, minsize); + tlsf_free(tlsf, ptr); + } + } + else + { + /* Do we need to expand to the next block? */ + if (adjust > cursize) + { + block_merge_next(pool, block); + block_mark_as_used(block); + } + + /* Trim the resulting block and return the original pointer. */ + block_trim_used(pool, block, adjust); + p = ptr; + } + } + + return p; +} diff --git a/common/tlsf_malloc.c b/common/tlsf_malloc.c new file mode 100644 index 0000000..2fe443b --- /dev/null +++ b/common/tlsf_malloc.c @@ -0,0 +1,99 @@ +/* + * tlsf wrapper for barebox + * + * Copyright (C) 2011 Antony Pavlov + * + * This file is part of barebox. + * 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 + +extern tlsf_pool tlsf_mem_pool; + +void *malloc(size_t bytes) +{ + return tlsf_malloc(tlsf_mem_pool, bytes); +} +EXPORT_SYMBOL(malloc); + +/* + * calloc calls malloc, then zeroes out the allocated chunk. + */ +void *calloc(size_t n, size_t elem_size) +{ + void *mem; + size_t sz; + + sz = n * elem_size; + mem = malloc(sz); + memset(mem, 0, sz); + + return mem; +} +EXPORT_SYMBOL(calloc); + +void free(void *mem) +{ + tlsf_free(tlsf_mem_pool, mem); +} +EXPORT_SYMBOL(free); + +void *realloc(void *oldmem, size_t bytes) +{ + return tlsf_realloc(tlsf_mem_pool, oldmem, bytes); +} +EXPORT_SYMBOL(realloc); + +void *memalign(size_t alignment, size_t bytes) +{ + return tlsf_memalign(tlsf_mem_pool, alignment, bytes); +} +EXPORT_SYMBOL(memalign); + +struct malloc_stats { + size_t free; + size_t used; +}; + +static void malloc_walker(void* ptr, size_t size, int used, void *user) +{ + struct malloc_stats *s = user; + + if (used) + s->used += size; + else + s->free += size; +} + +void malloc_stats(void) +{ + struct malloc_stats s; + + s.used = 0; + s.free = 0; + + tlsf_walk_heap(tlsf_mem_pool, malloc_walker, &s); + + printf("used: %10d\nfree: %10d\n", s.used, s.free); +} diff --git a/common/tlsfbits.h b/common/tlsfbits.h new file mode 100644 index 0000000..93466e4 --- /dev/null +++ b/common/tlsfbits.h @@ -0,0 +1,55 @@ +#ifndef INCLUDED_tlsfbits +#define INCLUDED_tlsfbits + +#include + +/* +** Architecture-specific bit manipulation routines. +** +** TLSF achieves O(1) cost for malloc and free operations by limiting +** the search for a free block to a free list of guaranteed size +** adequate to fulfill the request, combined with efficient free list +** queries using bitmasks and architecture-specific bit-manipulation +** routines. +** +** Most modern processors provide instructions to count leading zeroes +** in a word, find the lowest and highest set bit, etc. These +** specific implementations will be used when available, falling back +** to a reasonably efficient generic implementation. +** +** NOTE: TLSF spec relies on ffs/fls returning value 0..31. +** ffs/fls return 1-32 by default, returning 0 for error. +*/ + +static int tlsf_ffs(unsigned int word) +{ + return ffs(word) - 1; +} + +static int tlsf_fls(unsigned int word) +{ + return fls(word) - 1; +} + +/* Possibly 64-bit version of tlsf_fls. */ +#if defined (TLSF_64BIT) +tlsf_decl int tlsf_fls_sizet(size_t size) +{ + int high = (int)(size >> 32); + int bits = 0; + if (high) + { + bits = 32 + tlsf_fls(high); + } + else + { + bits = tlsf_fls((int)size & 0xffffffff); + + } + return bits; +} +#else +#define tlsf_fls_sizet tlsf_fls +#endif + +#endif diff --git a/common/uimage.c b/common/uimage.c new file mode 100644 index 0000000..28791b5 --- /dev/null +++ b/common/uimage.c @@ -0,0 +1,505 @@ +/* + * uimage.c - uimage handling code + * + * Copyright (c) 2011 Sascha Hauer , Pengutronix + * + * partly based on U-Boot uImage code + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_UIMAGE_MULTI +static inline int uimage_is_multi_image(struct uimage_handle *handle) +{ + return (handle->header.ih_type == IH_TYPE_MULTI) ? 1 : 0; +} +#else +static inline int uimage_is_multi_image(struct uimage_handle *handle) +{ + return 0; +} +#endif + +void uimage_print_contents(struct uimage_handle *handle) +{ + struct image_header *hdr = &handle->header; +#if defined(CONFIG_TIMESTAMP) + struct rtc_time tm; +#endif + printf(" Image Name: %.*s\n", IH_NMLEN, hdr->ih_name); +#if defined(CONFIG_TIMESTAMP) + printf(" Created: "); + to_tm(hdr->ih_time, &tm); + printf("%4d-%02d-%02d %2d:%02d:%02d UTC\n", + tm.tm_year, tm.tm_mon, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); +#endif +#if defined(CONFIG_CMD_BOOTM_SHOW_TYPE) + printf(" OS: %s\n", image_get_os_name(hdr->ih_os)); + printf(" Architecture: %s\n", image_get_arch_name(hdr->ih_arch)); + printf(" Type: %s\n", image_get_type_name(hdr->ih_type)); + printf(" Compression: %s\n", image_get_comp_name(hdr->ih_comp)); +#endif + printf(" Data Size: %d Bytes = %s\n", hdr->ih_size, + size_human_readable(hdr->ih_size)); + printf(" Load Address: %08x\n", hdr->ih_load); + printf(" Entry Point: %08x\n", hdr->ih_ep); + + if (uimage_is_multi_image(handle)) { + int i; + + printf(" Contents:\n"); + + for (i = 0; i < handle->nb_data_entries; i++) { + struct uimage_handle_data *data = &handle->ihd[i]; + + printf(" Image %d: %ld (%s)\n", i, + data->len, size_human_readable(data->len)); + } + } +} +EXPORT_SYMBOL(uimage_print_contents); + +size_t uimage_get_size(struct uimage_handle *handle, unsigned int image_no) +{ + if (image_no >= handle->nb_data_entries) + return -EINVAL; + + return handle->ihd[image_no].len; +} +EXPORT_SYMBOL(uimage_get_size); + +/* + * open a uimage. This will check the header contents and + * return a handle to the uImage + */ +struct uimage_handle *uimage_open(const char *filename) +{ + int fd; + uint32_t checksum; + struct uimage_handle *handle; + struct image_header *header; + int i; + int ret; + + fd = open(filename, O_RDONLY); + if (fd < 0) { + printf("could not open: %s\n", errno_str()); + return NULL; + } + + handle = xzalloc(sizeof(struct uimage_handle)); + header = &handle->header; + + if (read(fd, header, sizeof(*header)) < 0) { + printf("could not read: %s\n", errno_str()); + goto err_out; + } + + if (uimage_to_cpu(header->ih_magic) != IH_MAGIC) { + printf("Bad Magic Number\n"); + goto err_out; + } + + checksum = uimage_to_cpu(header->ih_hcrc); + header->ih_hcrc = 0; + + if (crc32(0, header, sizeof(*header)) != checksum) { + printf("Bad Header Checksum\n"); + goto err_out; + } + + /* convert header to cpu native endianess */ + header->ih_magic = uimage_to_cpu(header->ih_magic); + header->ih_hcrc = uimage_to_cpu(header->ih_hcrc); + header->ih_time = uimage_to_cpu(header->ih_time); + header->ih_size = uimage_to_cpu(header->ih_size); + header->ih_load = uimage_to_cpu(header->ih_load); + header->ih_ep = uimage_to_cpu(header->ih_ep); + header->ih_dcrc = uimage_to_cpu(header->ih_dcrc); + + if (header->ih_name[0]) { + handle->name = xzalloc(IH_NMLEN + 1); + strncpy(handle->name, header->ih_name, IH_NMLEN); + } else { + handle->name = xstrdup(filename); + } + + if (uimage_is_multi_image(handle)) { + size_t offset; + + for (i = 0; i < MAX_MULTI_IMAGE_COUNT; i++) { + u32 size; + + ret = read(fd, &size, sizeof(size)); + if (ret < 0) + goto err_out; + + if (!size) + break; + + handle->ihd[i].len = uimage_to_cpu(size); + } + + handle->nb_data_entries = i; + + /* offset of the first image in a multifile image */ + offset = 0; + + for (i = 0; i < handle->nb_data_entries; i++) { + handle->ihd[i].offset = offset; + offset += (handle->ihd[i].len + 3) & ~3; + } + + handle->data_offset = sizeof(struct image_header) + + sizeof(u32) * (handle->nb_data_entries + 1); + } else { + handle->ihd[0].offset = 0; + handle->ihd[0].len = header->ih_size; + handle->nb_data_entries = 1; + handle->data_offset = sizeof(struct image_header); + } + + /* + * fd is now at the first data word + */ + handle->fd = fd; + + return handle; +err_out: + close(fd); + free(handle); + return NULL; +} +EXPORT_SYMBOL(uimage_open); + +/* + * close a uImage previously opened with uimage_open + */ +void uimage_close(struct uimage_handle *handle) +{ + close(handle->fd); + free(handle->name); + free(handle); +} +EXPORT_SYMBOL(uimage_close); + +static int uimage_fd; + +static int uimage_fill(void *buf, unsigned int len) +{ + return read_full(uimage_fd, buf, len); +} + +static int uncompress_copy(unsigned char *inbuf_unused, int len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *outbuf_unused, + int *pos, + void(*error_fn)(char *x)) +{ + int ret; + void *buf = xmalloc(PAGE_SIZE); + + while (len) { + int now = min(len, PAGE_SIZE); + ret = fill(buf, now); + if (ret < 0) + goto err; + ret = flush(buf, now); + if (ret < 0) + goto err; + len -= now; + } + + ret = 0; +err: + free(buf); + return ret; +} + +/* + * Verify the data crc of an uImage + */ +int uimage_verify(struct uimage_handle *handle) +{ + u32 crc = 0; + int len, ret; + void *buf; + + ret = lseek(handle->fd, sizeof(struct image_header), SEEK_SET); + if (ret < 0) + return ret; + + buf = xmalloc(PAGE_SIZE); + + len = handle->header.ih_size; + while (len) { + int now = min(len, PAGE_SIZE); + ret = read(handle->fd, buf, now); + if (ret < 0) + goto err; + crc = crc32(crc, buf, now); + len -= ret; + } + + if (crc != handle->header.ih_dcrc) { + printf("Bad Data CRC: 0x%08x != 0x%08x\n", + crc, handle->header.ih_dcrc); + ret = -EINVAL; + goto err; + } + + ret = 0; +err: + free(buf); + + return ret; +} +EXPORT_SYMBOL(uimage_verify); + +/* + * Load a uimage, flushing output to flush function + */ +int uimage_load(struct uimage_handle *handle, unsigned int image_no, + int(*flush)(void*, unsigned int)) +{ + image_header_t *hdr = &handle->header; + struct uimage_handle_data *iha; + int ret; + int (*uncompress_fn)(unsigned char *inbuf, int len, + int(*fill)(void*, unsigned int), + int(*flush)(void*, unsigned int), + unsigned char *output, + int *pos, + void(*error)(char *x)); + + if (image_no >= handle->nb_data_entries) + return -EINVAL; + + iha = &handle->ihd[image_no]; + + ret = lseek(handle->fd, iha->offset + handle->data_offset, + SEEK_SET); + if (ret < 0) + return ret; + + if (hdr->ih_comp == IH_COMP_NONE) + uncompress_fn = uncompress_copy; + else + uncompress_fn = uncompress; + + uimage_fd = handle->fd; + + ret = uncompress_fn(NULL, iha->len, uimage_fill, flush, + NULL, NULL, + uncompress_err_stdout); + return ret; +} +EXPORT_SYMBOL(uimage_load); + +static void *uimage_buf; +static size_t uimage_size; +static struct resource *uimage_resource; + +static int uimage_sdram_flush(void *buf, unsigned int len) +{ + if (uimage_size + len > uimage_resource->size) { + resource_size_t start = uimage_resource->start; + resource_size_t size = uimage_resource->size + len; + release_sdram_region(uimage_resource); + + uimage_resource = request_sdram_region("uimage", + start, size); + if (!uimage_resource) { + printf("unable to request SDRAM 0x%08x-0x%08x\n", + start, start + size - 1); + return -ENOMEM; + } + } + + memcpy(uimage_buf + uimage_size, buf, len); + + uimage_size += len; + + return len; +} + +#define BUFSIZ (PAGE_SIZE * 2) + +struct resource *file_to_sdram(const char *filename, unsigned long adr) +{ + struct resource *res; + size_t size = BUFSIZ; + size_t ofs = 0; + int fd; + + fd = open(filename, O_RDONLY); + if (fd < 0) + return NULL; + + while (1) { + size_t now; + + res = request_sdram_region("image", adr, size); + if (!res) { + printf("unable to request SDRAM 0x%08lx-0x%08lx\n", + adr, adr + size - 1); + goto out; + } + + now = read_full(fd, (void *)(res->start + ofs), BUFSIZ); + if (now < 0) { + release_sdram_region(res); + res = NULL; + goto out; + } + if (now < BUFSIZ) + goto out; + + release_sdram_region(res); + + ofs += BUFSIZ; + size += BUFSIZ; + } +out: + close(fd); + + return res; +} + +/* + * Load an uImage to a dynamically allocated sdram resource. + * the resource must be freed afterwards with release_sdram_region + */ +struct resource *uimage_load_to_sdram(struct uimage_handle *handle, + int image_no, unsigned long load_address) +{ + int ret; + size_t size; + resource_size_t start = (resource_size_t)load_address; + + uimage_buf = (void *)load_address; + uimage_size = 0; + + size = uimage_get_size(handle, image_no); + if (size < 0) + return NULL; + + uimage_resource = request_sdram_region("uimage", + start, size); + if (!uimage_resource) { + printf("unable to request SDRAM 0x%08x-0x%08x\n", + start, start + size - 1); + return NULL; + } + + ret = uimage_load(handle, image_no, uimage_sdram_flush); + if (ret) { + release_sdram_region(uimage_resource); + return NULL; + } + + return uimage_resource; +} +EXPORT_SYMBOL(uimage_load_to_sdram); + +void *uimage_load_to_buf(struct uimage_handle *handle, int image_no, + size_t *outsize) +{ + u32 size; + int ret; + struct uimage_handle_data *ihd; + char ftbuf[128]; + enum filetype ft; + void *buf; + + if (image_no >= handle->nb_data_entries) + return NULL; + + ihd = &handle->ihd[image_no]; + + ret = lseek(handle->fd, ihd->offset + handle->data_offset, + SEEK_SET); + if (ret < 0) + return NULL; + + if (handle->header.ih_comp == IH_COMP_NONE) { + buf = malloc(ihd->len); + if (!buf) + return NULL; + + ret = read_full(handle->fd, buf, ihd->len); + if (ret < ihd->len) { + free(buf); + return NULL; + } + goto out; + } + + ret = read(handle->fd, ftbuf, 128); + if (ret < 0) + return NULL; + + ft = file_detect_type(ftbuf); + if ((int)ft < 0) + return NULL; + + if (ft != filetype_gzip) + return NULL; + + ret = lseek(handle->fd, ihd->offset + handle->data_offset + + ihd->len - 4, + SEEK_SET); + if (ret < 0) + return NULL; + + ret = read(handle->fd, &size, 4); + if (ret < 0) + return NULL; + + size = le32_to_cpu(size); + + ret = lseek(handle->fd, ihd->offset + handle->data_offset, + SEEK_SET); + if (ret < 0) + return NULL; + + buf = malloc(size); + ret = uncompress_fd_to_buf(handle->fd, buf, uncompress_err_stdout); + if (ret) { + free(buf); + return NULL; + } + +out: + if (outsize) + *outsize = size; + + return buf; +} diff --git a/defaultenv/bin/_update b/defaultenv/bin/_update index 1bcb71c..9e88dea 100644 --- a/defaultenv/bin/_update +++ b/defaultenv/bin/_update @@ -44,7 +44,7 @@ if [ x$mode = xtftp ]; then tftp $image $part || exit 1 else - cp $image $part || exit 1 + cp -v $image $part || exit 1 fi protect $part diff --git a/defaultenv/bin/boot b/defaultenv/bin/boot index 90ebf9a..1120757 100644 --- a/defaultenv/bin/boot +++ b/defaultenv/bin/boot @@ -72,35 +72,12 @@ bootargs="${bootargs} mtdparts=${mtdparts}" fi -if [ ! -e /dev/ram0.kernelraw ]; then - # arm raw kernel images are usually located at sdram start + 0x8000 - addpart /dev/ram0 8M@0x8000(kernelraw) -fi - -if [ ! -e /dev/ram0.kernel ]; then - # Here we can safely put the kernel without risking of overwriting it - # while extracting - addpart /dev/ram0 8M@8M(kernel) -fi - if [ x$kernel_loc = xnfs -o x$kernel_loc = xtftp ]; then if [ x$ip = xdhcp ]; then dhcp fi - if [ $kernelimage_type = uimage ]; then - netload="/dev/ram0.kernel" - elif [ $kernelimage_type = zimage ]; then - netload="/dev/ram0.kernel" - elif [ $kernelimage_type = raw ]; then - netload="/dev/ram0.kernelraw" - elif [ $kernelimage_type = raw_lzo ]; then - netload="/dev/ram0.kernel" - else - echo "error: set kernelimage_type to one of 'uimage', 'zimage', 'raw' or 'raw_lzo'" - exit 1 - fi - $kernel_loc $kernelimage $netload || exit 1 - kdev="$netload" + kdev=/image + $kernel_loc $kernelimage $kdev || exit 1 elif [ x$kernel_loc = xnor ]; then kdev="/dev/nor0.kernel" elif [ x$kernel_loc = xnand ]; then @@ -112,18 +89,6 @@ exit 1 fi -echo "booting kernel of type $kernelimage_type from $kdev" +echo "booting kernel from $kdev" -if [ x$kernelimage_type = xuimage ]; then - bootm $bootm_opt $kdev -elif [ x$kernelimage_type = xzimage ]; then - bootz $kdev -elif [ x$kernelimage_type = xraw ]; then - if [ $kernel_loc != net ]; then - cp $kdev /dev/ram0.kernelraw - fi - bootu /dev/ram0.kernelraw -elif [ x$kernelimage_type = xraw_lzo ]; then - uncompress $kdev /dev/ram0.kernelraw - bootu /dev/ram0.kernelraw -fi +bootm $bootm_opt $kdev diff --git a/defaultenv/bin/init b/defaultenv/bin/init index b66f7d9..b371c42 100644 --- a/defaultenv/bin/init +++ b/defaultenv/bin/init @@ -21,7 +21,7 @@ fi if [ -f /env/bin/init_board ]; then - /env/bin/init_board + . /env/bin/init_board fi echo diff --git a/defaultenv/config b/defaultenv/config index 0aaead5..9866273 100644 --- a/defaultenv/config +++ b/defaultenv/config @@ -31,14 +31,9 @@ # where is the kernel image in case of 'kernel_loc=disk' kernel_part=disk0.2 -# 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 bareboximage=barebox-${machine}.bin diff --git a/drivers/base/resource.c b/drivers/base/resource.c index 5c9c16c..d2f7a07 100644 --- a/drivers/base/resource.c +++ b/drivers/base/resource.c @@ -69,7 +69,7 @@ } EXPORT_SYMBOL(add_generic_device_res); -#ifdef CONFIG_DRIVER_NET_DM9000 +#ifdef CONFIG_DRIVER_NET_DM9K struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata) { diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 2a1ae7a..cbc3a84 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -57,26 +57,6 @@ /* This will be the driver name */ #define DRIVER_NAME "i2c-omap" -#define OMAP_I2C_REV_REG 0x00 -#define OMAP_I2C_IE_REG 0x04 -#define OMAP_I2C_STAT_REG 0x08 -#define OMAP_I2C_IV_REG 0x0c -/* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */ -#define OMAP_I2C_WE_REG 0x0c -#define OMAP_I2C_SYSS_REG 0x10 -#define OMAP_I2C_BUF_REG 0x14 -#define OMAP_I2C_CNT_REG 0x18 -#define OMAP_I2C_DATA_REG 0x1c -#define OMAP_I2C_SYSC_REG 0x20 -#define OMAP_I2C_CON_REG 0x24 -#define OMAP_I2C_OA_REG 0x28 -#define OMAP_I2C_SA_REG 0x2c -#define OMAP_I2C_PSC_REG 0x30 -#define OMAP_I2C_SCLL_REG 0x34 -#define OMAP_I2C_SCLH_REG 0x38 -#define OMAP_I2C_SYSTEST_REG 0x3c -#define OMAP_I2C_BUFSTAT_REG 0x40 - /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ #define OMAP_I2C_IE_XDR (1 << 14) /* TX Buffer drain int enable */ #define OMAP_I2C_IE_RDR (1 << 13) /* RX Buffer drain int enable */ @@ -168,6 +148,8 @@ struct omap_i2c_struct { void *base; + u8 *regs; + u8 reg_shift; struct resource *ioarea; u32 speed; /* Speed of bus in Khz */ u16 cmd_err; @@ -190,16 +172,90 @@ }; #define to_omap_i2c_struct(a) container_of(a, struct omap_i2c_struct, adapter) +enum { + OMAP_I2C_REV_REG = 0, + OMAP_I2C_IE_REG, + OMAP_I2C_STAT_REG, + OMAP_I2C_IV_REG, + OMAP_I2C_WE_REG, + OMAP_I2C_SYSS_REG, + OMAP_I2C_BUF_REG, + OMAP_I2C_CNT_REG, + OMAP_I2C_DATA_REG, + OMAP_I2C_SYSC_REG, + OMAP_I2C_CON_REG, + OMAP_I2C_OA_REG, + OMAP_I2C_SA_REG, + OMAP_I2C_PSC_REG, + OMAP_I2C_SCLL_REG, + OMAP_I2C_SCLH_REG, + OMAP_I2C_SYSTEST_REG, + OMAP_I2C_BUFSTAT_REG, + OMAP_I2C_REVNB_LO, + OMAP_I2C_REVNB_HI, + OMAP_I2C_IRQSTATUS_RAW, + OMAP_I2C_IRQENABLE_SET, + OMAP_I2C_IRQENABLE_CLR, +}; + +static const u8 reg_map[] = { + [OMAP_I2C_REV_REG] = 0x00, + [OMAP_I2C_IE_REG] = 0x01, + [OMAP_I2C_STAT_REG] = 0x02, + [OMAP_I2C_IV_REG] = 0x03, + [OMAP_I2C_WE_REG] = 0x03, + [OMAP_I2C_SYSS_REG] = 0x04, + [OMAP_I2C_BUF_REG] = 0x05, + [OMAP_I2C_CNT_REG] = 0x06, + [OMAP_I2C_DATA_REG] = 0x07, + [OMAP_I2C_SYSC_REG] = 0x08, + [OMAP_I2C_CON_REG] = 0x09, + [OMAP_I2C_OA_REG] = 0x0a, + [OMAP_I2C_SA_REG] = 0x0b, + [OMAP_I2C_PSC_REG] = 0x0c, + [OMAP_I2C_SCLL_REG] = 0x0d, + [OMAP_I2C_SCLH_REG] = 0x0e, + [OMAP_I2C_SYSTEST_REG] = 0x0f, + [OMAP_I2C_BUFSTAT_REG] = 0x10, +}; + +static const u8 omap4_reg_map[] = { + [OMAP_I2C_REV_REG] = 0x04, + [OMAP_I2C_IE_REG] = 0x2c, + [OMAP_I2C_STAT_REG] = 0x28, + [OMAP_I2C_IV_REG] = 0x34, + [OMAP_I2C_WE_REG] = 0x34, + [OMAP_I2C_SYSS_REG] = 0x90, + [OMAP_I2C_BUF_REG] = 0x94, + [OMAP_I2C_CNT_REG] = 0x98, + [OMAP_I2C_DATA_REG] = 0x9c, + [OMAP_I2C_SYSC_REG] = 0x10, + [OMAP_I2C_CON_REG] = 0xa4, + [OMAP_I2C_OA_REG] = 0xa8, + [OMAP_I2C_SA_REG] = 0xac, + [OMAP_I2C_PSC_REG] = 0xb0, + [OMAP_I2C_SCLL_REG] = 0xb4, + [OMAP_I2C_SCLH_REG] = 0xb8, + [OMAP_I2C_SYSTEST_REG] = 0xbc, + [OMAP_I2C_BUFSTAT_REG] = 0xc0, + [OMAP_I2C_REVNB_LO] = 0x00, + [OMAP_I2C_REVNB_HI] = 0x04, + [OMAP_I2C_IRQSTATUS_RAW] = 0x24, + [OMAP_I2C_IRQENABLE_SET] = 0x2c, + [OMAP_I2C_IRQENABLE_CLR] = 0x30, +}; static inline void omap_i2c_write_reg(struct omap_i2c_struct *i2c_omap, int reg, u16 val) { - __raw_writew(val, i2c_omap->base + reg); + __raw_writew(val, i2c_omap->base + + (i2c_omap->regs[reg] << i2c_omap->reg_shift)); } static inline u16 omap_i2c_read_reg(struct omap_i2c_struct *i2c_omap, int reg) { - return __raw_readw(i2c_omap->base + reg); + return __raw_readw(i2c_omap->base + + (i2c_omap->regs[reg] << i2c_omap->reg_shift)); } static void omap_i2c_unidle(struct omap_i2c_struct *i2c_omap) @@ -228,6 +284,9 @@ u16 iv; i2c_omap->iestate = omap_i2c_read_reg(i2c_omap, OMAP_I2C_IE_REG); + + /* Barebox driver don't need to clear interrupts here */ + /* omap_i2c_write_reg(i2c_omap, OMAP_I2C_IE_REG, 0); */ if (i2c_omap->rev < OMAP_I2C_REV_2) { iv = omap_i2c_read_reg(i2c_omap, OMAP_I2C_IV_REG); /* Read clears */ @@ -299,7 +358,7 @@ /* omap1 handling is missing here */ - if (cpu_is_omap2430() || cpu_is_omap34xx()) { + if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap4xxx()) { /* * HSI2C controller internal clk rate should be 19.2 Mhz for @@ -472,7 +531,8 @@ dev->buf_len--; /* Data reg from 2430 is 8 bit wide */ if (!cpu_is_omap2430() && - !cpu_is_omap34xx()) { + !cpu_is_omap34xx() && + !cpu_is_omap4xxx()) { if (dev->buf_len) { *dev->buf++ = w >> 8; dev->buf_len--; @@ -512,7 +572,8 @@ dev->buf_len--; /* Data reg from 2430 is 8 bit wide */ if (!cpu_is_omap2430() && - !cpu_is_omap34xx()) { + !cpu_is_omap34xx() && + !cpu_is_omap4xxx()) { if (dev->buf_len) { w |= *dev->buf++ << 8; dev->buf_len--; @@ -650,7 +711,8 @@ while (ret){ ret = omap_i2c_isr(i2c_omap); if (is_timeout(start, MSECOND)) { - dev_err(adapter->dev, "timed out on polling for" + dev_err(adapter->dev, + "timed out on polling for " "open i2c message handling\n"); return -ETIMEDOUT; } @@ -725,6 +787,14 @@ goto err_free_mem; } + if (cpu_is_omap4xxx()) { + i2c_omap->regs = (u8 *)omap4_reg_map; + i2c_omap->reg_shift = 0; + } else { + i2c_omap->regs = (u8 *)reg_map; + i2c_omap->reg_shift = 2; + } + if (pdev->platform_data != NULL) speed = *(u32 *)pdev->platform_data; else @@ -738,7 +808,7 @@ i2c_omap->rev = omap_i2c_read_reg(i2c_omap, OMAP_I2C_REV_REG) & 0xff; /* i2c_omap->base = OMAP2_I2C_BASE3; */ - if (cpu_is_omap2430() || cpu_is_omap34xx()) { + if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap4xxx()) { u16 s; /* Set up the fifo size - Get total size */ @@ -750,8 +820,13 @@ * size. This is to ensure that we can handle the status on int * call back latencies. */ + i2c_omap->fifo_size = (i2c_omap->fifo_size / 2); - i2c_omap->b_hw = 1; /* Enable hardware fixes */ + + if (i2c_omap->rev >= OMAP_I2C_REV_ON_4430) + i2c_omap->b_hw = 0; /* Disable hardware fixes */ + else + i2c_omap->b_hw = 1; /* Enable hardware fixes */ } /* reset ASAP, clearing any IRQs */ diff --git a/drivers/mci/Kconfig b/drivers/mci/Kconfig index 6ed21cd..8279e5d 100644 --- a/drivers/mci/Kconfig +++ b/drivers/mci/Kconfig @@ -72,6 +72,13 @@ Enable this entry to add support to read and write SD cards on a OMAP4 based system. +config MCI_PXA + bool "PXA" + depends on ARCH_PXA + help + Enable this entry to add support to read and write SD cards on a + XScale PXA25x / PXA27x based system. + config MCI_ATMEL bool "ATMEL (AT91)" depends on ARCH_AT91 diff --git a/drivers/mci/Makefile b/drivers/mci/Makefile index d7482dc..b7bb846 100644 --- a/drivers/mci/Makefile +++ b/drivers/mci/Makefile @@ -4,5 +4,7 @@ obj-$(CONFIG_MCI_IMX) += imx.o obj-$(CONFIG_MCI_IMX_ESDHC) += imx-esdhc.o obj-$(CONFIG_MCI_OMAP_HSMMC) += omap_hsmmc.o +obj-$(CONFIG_I2C_TWL6030) += twl6030.o +obj-$(CONFIG_MCI_PXA) += pxamci.o obj-$(CONFIG_MCI_ATMEL) += atmel_mci.o obj-$(CONFIG_MCI_SPI) += mci_spi.o diff --git a/drivers/mci/omap_hsmmc.c b/drivers/mci/omap_hsmmc.c index d171c1d..e671bbe 100644 --- a/drivers/mci/omap_hsmmc.c +++ b/drivers/mci/omap_hsmmc.c @@ -33,6 +33,12 @@ #include +#if defined(CONFIG_I2C_TWL6030) && \ + defined(CONFIG_MCI_OMAP_HSMMC) && \ + defined(CONFIG_ARCH_OMAP4) +#include +#endif + struct hsmmc { unsigned char res1[0x10]; unsigned int sysconfig; /* 0x10 */ @@ -215,6 +221,17 @@ unsigned int dsor; uint64_t start; +/* + * Fix voltage for mmc, if booting from nand. + * It's necessary to do this here, because + * you need to set up this at probetime. + */ +#if defined(CONFIG_I2C_TWL6030) && \ + defined(CONFIG_MCI_OMAP_HSMMC) && \ + defined(CONFIG_ARCH_OMAP4) + set_up_mmc_voltage_omap4(); +#endif + writel(readl(&mmc_base->sysconfig) | MMC_SOFTRESET, &mmc_base->sysconfig); diff --git a/drivers/mci/pxamci.c b/drivers/mci/pxamci.c new file mode 100644 index 0000000..75b61f0 --- /dev/null +++ b/drivers/mci/pxamci.c @@ -0,0 +1,369 @@ +/* + * PXA MCI driver + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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. + * + * Insprired by linux kernel driver + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "pxamci.h" + +#define DRIVER_NAME "pxa-mmc" + +static void clk_enable(void) +{ + CKEN |= CKEN_MMC; +} + +static int pxamci_set_power(struct pxamci_host *host, int on) +{ + mci_dbg("on=%d\n", on); + if (host->pdata && host->pdata->gpio_power > 0) + gpio_set_value(host->pdata->gpio_power, + !!on ^ host->pdata->gpio_power_invert); + else if (host->pdata && host->pdata->setpower) + host->pdata->setpower(&host->mci, on); + return 0; +} + +static void pxamci_start_clock(struct pxamci_host *host) +{ + mmc_writel(START_CLOCK, MMC_STRPCL); +} + +static void pxamci_stop_clock(struct pxamci_host *host) +{ + uint64_t start = get_time_ns(); + unsigned stat; + + stat = mmc_readl(MMC_STAT); + if (stat & STAT_CLK_EN) + writel(STOP_CLOCK, host->base + MMC_STRPCL); + while (!is_timeout(start, 10 * MSECOND) && stat & STAT_CLK_EN) + stat = mmc_readl(MMC_STAT); + + if (stat & STAT_CLK_EN) + mci_err("unable to stop clock\n"); +} + +static void pxamci_setup_data(struct pxamci_host *host, struct mci_data *data) +{ + static const unsigned int timeout = 100000000; /* 10ms */ + + mci_dbg("nbblocks=%d, blocksize=%d\n", data->blocks, data->blocksize); + mmc_writel(data->blocks, MMC_NOB); + mmc_writel(data->blocksize, MMC_BLKLEN); + mmc_writel((timeout + 255) / 256, MMC_RDTO); +} + +static int pxamci_read_data(struct pxamci_host *host, unsigned char *dst, + unsigned len) +{ + int trf_len, trf_len1, trf_len4, ret = 0; + uint64_t start; + u32 *dst4; + + mci_dbg("dst=%p, len=%u\n", dst, len); + while (!ret && len > 0) { + trf_len = min_t(int, len, MMC_FIFO_LENGTH); + + for (start = get_time_ns(), ret = -ETIMEDOUT; + ret && !is_timeout(start, 10 * MSECOND);) + if (mmc_readl(MMC_I_REG) & RXFIFO_RD_REQ) + ret = 0; + trf_len1 = trf_len % 4; + trf_len4 = trf_len / 4; + for (dst4 = (u32 *)dst; !ret && trf_len4 > 0; trf_len4--) + *dst4++ = mmc_readl(MMC_RXFIFO); + for (dst = (u8 *)dst4; !ret && trf_len1 > 0; trf_len1--) + *dst++ = mmc_readb(MMC_RXFIFO); + len -= trf_len; + } + + if (!ret) + for (start = get_time_ns(), ret = -ETIMEDOUT; + ret && !is_timeout(start, 10 * MSECOND);) + if (mmc_readl(MMC_STAT) & STAT_DATA_TRAN_DONE) + ret = 0; + mci_dbg("ret=%d, remain=%d, stat=%x, mmc_i_reg=%x\n", + ret, len, mmc_readl(MMC_STAT), mmc_readl(MMC_I_REG)); + return ret; +} + +static int pxamci_write_data(struct pxamci_host *host, const unsigned char *src, + unsigned len) +{ + uint64_t start; + int trf_len, partial = 0, ret = 0; + unsigned stat; + + mci_dbg("src=%p, len=%u\n", src, len); + while (!ret && len > 0) { + trf_len = min_t(int, len, MMC_FIFO_LENGTH); + partial = trf_len < MMC_FIFO_LENGTH; + + for (start = get_time_ns(), ret = -ETIMEDOUT; + ret && !is_timeout(start, 10 * MSECOND);) + if (mmc_readl(MMC_I_REG) & TXFIFO_WR_REQ) + ret = 0; + for (; !ret && trf_len > 0; trf_len--, len--) + mmc_writeb(*src++, MMC_TXFIFO); + if (partial) + mmc_writeb(BUF_PART_FULL, MMC_PRTBUF); + } + + if (!ret) + for (start = get_time_ns(), ret = -ETIMEDOUT; + ret && !is_timeout(start, 100 * MSECOND);) { + stat = mmc_readl(MMC_STAT); + stat &= STAT_DATA_TRAN_DONE | STAT_PRG_DONE; + if (stat == (STAT_DATA_TRAN_DONE | STAT_PRG_DONE)) + ret = 0; + } + mci_dbg("ret=%d, remain=%d, stat=%x, mmc_i_reg=%x\n", + ret, len, mmc_readl(MMC_STAT), mmc_readl(MMC_I_REG)); + return ret; +} + +static int pxamci_transfer_data(struct pxamci_host *host, + struct mci_data *data) +{ + int nbbytes = data->blocks * data->blocksize; + int ret; + unsigned err_mask = STAT_CRC_READ_ERROR | STAT_CRC_WRITE_ERROR | + STAT_READ_TIME_OUT; + + if (data->flags & MMC_DATA_WRITE) + ret = pxamci_write_data(host, data->src, nbbytes); + else + ret = pxamci_read_data(host, data->dest, nbbytes); + + if (!ret && (mmc_readl(MMC_STAT) & err_mask)) + ret = -EILSEQ; + return ret; +} + +static void pxamci_start_cmd(struct pxamci_host *host, struct mci_cmd *cmd, + unsigned int cmdat) +{ + mci_dbg("cmd=(idx=%d,type=%d,clkrt=%d)\n", cmd->cmdidx, cmd->resp_type, + host->clkrt); + if (cmd->resp_type & MMC_RSP_BUSY) + cmdat |= CMDAT_BUSY; + + switch (cmd->resp_type) { + /* r1, r1b, r6, r7 */ + case MMC_RSP_R1: + case MMC_RSP_R1b: + cmdat |= CMDAT_RESP_SHORT; + break; + case MMC_RSP_R2: + cmdat |= CMDAT_RESP_R2; + break; + case MMC_RSP_R3: + cmdat |= CMDAT_RESP_R3; + break; + default: + break; + } + + mmc_writel(cmd->cmdidx, MMC_CMD); + mmc_writel(cmd->cmdarg >> 16, MMC_ARGH); + mmc_writel(cmd->cmdarg & 0xffff, MMC_ARGL); + mmc_writel(host->clkrt, MMC_CLKRT); + pxamci_start_clock(host); + mmc_writel(cmdat, MMC_CMDAT); +} + +static int pxamci_cmd_response(struct pxamci_host *host, struct mci_cmd *cmd) +{ + unsigned v, stat; + int i; + + /* + * Did I mention this is Sick. We always need to + * discard the upper 8 bits of the first 16-bit word. + */ + v = mmc_readl(MMC_RES) & 0xffff; + for (i = 0; i < 4; i++) { + u32 w1 = mmc_readl(MMC_RES) & 0xffff; + u32 w2 = mmc_readl(MMC_RES) & 0xffff; + cmd->response[i] = v << 24 | w1 << 8 | w2 >> 8; + v = w2; + } + + stat = mmc_readl(MMC_STAT); + if (stat & STAT_TIME_OUT_RESPONSE) + return -ETIMEDOUT; + if (stat & STAT_RES_CRC_ERR && cmd->resp_type & MMC_RSP_CRC) { + /* + * workaround for erratum #42: + * Intel PXA27x Family Processor Specification Update Rev 001 + * A bogus CRC error can appear if the msb of a 136 bit + * response is a one. + */ + if (cpu_is_pxa27x() && cmd->resp_type & MMC_RSP_136 && + cmd->response[0] & 0x80000000) + pr_debug("ignoring CRC from command %d - *risky*\n", + cmd->cmdidx); + else + return -EILSEQ; + } + + return 0; +} + +static int pxamci_mmccmd(struct pxamci_host *host, struct mci_cmd *cmd, + struct mci_data *data, unsigned int cmddat) +{ + int ret = 0; + uint64_t start; + + pxamci_start_cmd(host, cmd, cmddat); + for (start = get_time_ns(), ret = -ETIMEDOUT; + ret && !is_timeout(start, 10 * MSECOND);) + if (mmc_readl(MMC_STAT) & STAT_END_CMD_RES) + ret = 0; + + if (!ret && data) + ret = pxamci_transfer_data(host, data); + + if (!ret) + ret = pxamci_cmd_response(host, cmd); + return ret; +} + +static int pxamci_request(struct mci_host *mci, struct mci_cmd *cmd, + struct mci_data *data) +{ + struct pxamci_host *host = to_pxamci(mci); + unsigned int cmdat; + int ret; + + pxamci_stop_clock(host); + + cmdat = host->cmdat; + host->cmdat &= ~CMDAT_INIT; + + if (data) { + pxamci_setup_data(host, data); + + cmdat &= ~CMDAT_BUSY; + cmdat |= CMDAT_DATAEN; + if (data->flags & MMC_DATA_WRITE) + cmdat |= CMDAT_WRITE; + } + + ret = pxamci_mmccmd(host, cmd, data, cmdat); + return ret; +} + +static void pxamci_set_ios(struct mci_host *mci, struct device_d *dev, + unsigned bus_width, unsigned clock) +{ + struct pxamci_host *host = to_pxamci(mci); + unsigned int clk_in = pxa_get_mmcclk(); + int fact; + + mci_dbg("bus_width=%d, clock=%u\n", bus_width, clock); + if (clock) + fact = min_t(int, clk_in / clock, 1 << 6); + else + fact = 1 << 6; + fact = max_t(int, fact, 1); + + /* + * We calculate clkrt here, and will write it on the next command + * MMC card clock = mmcclk / (2 ^ clkrt) + */ + /* to handle (19.5MHz, 26MHz) */ + host->clkrt = fls(fact) - 1; + + if (bus_width == 4) + host->cmdat |= CMDAT_SD_4DAT; + else + host->cmdat &= ~CMDAT_SD_4DAT; + host->cmdat |= CMDAT_INIT; + + clk_enable(); + pxamci_set_power(host, 1); +} + +static int pxamci_init(struct mci_host *mci, struct device_d *dev) +{ + struct pxamci_host *host = to_pxamci(mci); + + if (host->pdata && host->pdata->init) + return host->pdata->init(mci, dev); + return 0; +} + +static int pxamci_probe(struct device_d *dev) +{ + struct pxamci_host *host; + int gpio_power = -1; + + host = xzalloc(sizeof(*host)); + host->base = dev_request_mem_region(dev, 0); + + host->mci.init = pxamci_init; + host->mci.send_cmd = pxamci_request; + host->mci.set_ios = pxamci_set_ios; + host->mci.host_caps = MMC_MODE_4BIT; + host->mci.hw_dev = dev; + host->mci.voltages = MMC_VDD_32_33 | MMC_VDD_33_34; + + /* + * Calculate minimum clock rate, rounding up. + */ + host->mci.f_min = pxa_get_mmcclk() >> 6; + host->mci.f_max = pxa_get_mmcclk(); + + /* + * Ensure that the host controller is shut down, and setup + * with our defaults. + */ + pxamci_stop_clock(host); + mmc_writel(0, MMC_SPI); + mmc_writel(64, MMC_RESTO); + mmc_writel(0, MMC_I_MASK); + + host->pdata = dev->platform_data; + if (host->pdata) + gpio_power = host->pdata->gpio_power; + + if (gpio_power > 0) + gpio_direction_output(gpio_power, + host->pdata->gpio_power_invert); + + mci_register(&host->mci); + return 0; +} + +static struct driver_d pxamci_driver = { + .name = DRIVER_NAME, + .probe = pxamci_probe, +}; + +static int __init pxamci_init_driver(void) +{ + register_driver(&pxamci_driver); + return 0; +} + +device_initcall(pxamci_init_driver); diff --git a/drivers/mci/pxamci.h b/drivers/mci/pxamci.h new file mode 100644 index 0000000..18d12a3 --- /dev/null +++ b/drivers/mci/pxamci.h @@ -0,0 +1,99 @@ +/* + * PXA MCI driver + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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. + * + * Insprired by linux kernel driver + */ + +#define MMC_FIFO_LENGTH 32 + +#define MMC_STRPCL 0x0000 +#define STOP_CLOCK (1 << 0) +#define START_CLOCK (2 << 0) + +#define MMC_STAT 0x0004 +#define STAT_END_CMD_RES (1 << 13) +#define STAT_PRG_DONE (1 << 12) +#define STAT_DATA_TRAN_DONE (1 << 11) +#define STAT_CLK_EN (1 << 8) +#define STAT_RECV_FIFO_FULL (1 << 7) +#define STAT_XMIT_FIFO_EMPTY (1 << 6) +#define STAT_RES_CRC_ERR (1 << 5) +#define STAT_SPI_READ_ERROR_TOKEN (1 << 4) +#define STAT_CRC_READ_ERROR (1 << 3) +#define STAT_CRC_WRITE_ERROR (1 << 2) +#define STAT_TIME_OUT_RESPONSE (1 << 1) +#define STAT_READ_TIME_OUT (1 << 0) + +#define MMC_CLKRT 0x0008 /* 3 bit */ + +#define MMC_SPI 0x000c +#define SPI_CS_ADDRESS (1 << 3) +#define SPI_CS_EN (1 << 2) +#define CRC_ON (1 << 1) +#define SPI_EN (1 << 0) + +#define MMC_CMDAT 0x0010 +#define CMDAT_SDIO_INT_EN (1 << 11) +#define CMDAT_SD_4DAT (1 << 8) +#define CMDAT_DMAEN (1 << 7) +#define CMDAT_INIT (1 << 6) +#define CMDAT_BUSY (1 << 5) +#define CMDAT_STREAM (1 << 4) /* 1 = stream */ +#define CMDAT_WRITE (1 << 3) /* 1 = write */ +#define CMDAT_DATAEN (1 << 2) +#define CMDAT_RESP_NONE (0 << 0) +#define CMDAT_RESP_SHORT (1 << 0) +#define CMDAT_RESP_R2 (2 << 0) +#define CMDAT_RESP_R3 (3 << 0) + +#define MMC_RESTO 0x0014 /* 7 bit */ +#define MMC_RDTO 0x0018 /* 16 bit */ +#define MMC_BLKLEN 0x001c /* 10 bit */ +#define MMC_NOB 0x0020 /* 16 bit */ + +#define MMC_PRTBUF 0x0024 +#define BUF_PART_FULL (1 << 0) + +#define MMC_I_REG 0x002c +#define TXFIFO_WR_REQ (1 << 6) +#define RXFIFO_RD_REQ (1 << 5) +#define CLK_IS_OFF (1 << 4) +#define STOP_CMD (1 << 3) +#define END_CMD_RES (1 << 2) +#define PRG_DONE (1 << 1) +#define DATA_TRAN_DONE (1 << 0) + +#define MMC_I_MASK 0x0028 +#define MMC_CMD 0x0030 +#define MMC_ARGH 0x0034 /* 16 bit */ +#define MMC_ARGL 0x0038 /* 16 bit */ +#define MMC_RES 0x003c /* 16 bit */ +#define MMC_RXFIFO 0x0040 /* 8 bit */ +#define MMC_TXFIFO 0x0044 /* 8 bit */ + +struct pxamci_host { + struct mci_host mci; + void __iomem *base; + struct pxamci_platform_data *pdata; + + unsigned int cmdat; + int clkrt; +}; + +#define to_pxamci(mci) container_of(mci, struct pxamci_host, mci) + +#define mmc_readb(reg) readb(host->base + (reg)) +#define mmc_readl(reg) readl(host->base + (reg)) +#define mmc_writeb(val, reg) writeb((val), host->base + (reg)) +#define mmc_writel(val, reg) writel((val), host->base + (reg)) + +#define mci_dbg(fmt, arg...) \ + dev_dbg(host->mci.hw_dev, "%s: " fmt, __func__, ## arg) +#define mci_err(fmt, arg...) \ + dev_err(host->mci.hw_dev, "%s: " fmt, __func__, ## arg) diff --git a/drivers/mci/s3c.c b/drivers/mci/s3c.c index 89c8168..7babab4 100644 --- a/drivers/mci/s3c.c +++ b/drivers/mci/s3c.c @@ -40,9 +40,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #define SDICON 0x0 # define SDICON_SDRESET (1 << 8) @@ -191,7 +191,7 @@ if (nc == 0) return 0; - clock = s3c24xx_get_pclk(); + clock = s3c_get_pclk(); /* Calculate the required prescaler value to get the requested frequency */ mci_psc = (clock + (nc >> 2)) / nc; @@ -760,8 +760,8 @@ struct s3c_mci_platform_data *pd = hw_dev->platform_data; /* TODO replace by the global func: enable the SDI unit clock */ - writel(readl(S3C24X0_CLOCK_POWER_BASE + 0x0c) | 0x200, - S3C24X0_CLOCK_POWER_BASE + 0x0c); + writel(readl(S3C_CLOCK_POWER_BASE + 0x0c) | 0x200, + S3C_CLOCK_POWER_BASE + 0x0c); if (pd == NULL) { pr_err("Missing platform data\n"); @@ -775,8 +775,8 @@ /* feed forward the platform specific values */ mci_pdata.voltages = pd->voltages; mci_pdata.host_caps = pd->caps; - mci_pdata.f_min = pd->f_min == 0 ? s3c24xx_get_pclk() / 256 : pd->f_min; - mci_pdata.f_max = pd->f_max == 0 ? s3c24xx_get_pclk() / 2 : pd->f_max; + mci_pdata.f_min = pd->f_min == 0 ? s3c_get_pclk() / 256 : pd->f_min; + mci_pdata.f_max = pd->f_max == 0 ? s3c_get_pclk() / 2 : pd->f_max; /* * Start the clock to let the engine and the card finishes its startup diff --git a/drivers/mci/twl6030.c b/drivers/mci/twl6030.c new file mode 100644 index 0000000..4a875bd --- /dev/null +++ b/drivers/mci/twl6030.c @@ -0,0 +1,29 @@ +/* + * MCI pmic power. + */ + +#include +#include +#include + +static int twl6030_mci_write(u8 address, u8 data) +{ + int ret; + struct twl6030 *twl6030 = twl6030_get(); + + ret = twl6030_reg_write(twl6030, address, data); + if (ret != 0) + printf("TWL6030:MCI:Write[0x%x] Error %d\n", address, ret); + + return ret; +} + +void twl6030_mci_power_init(void) +{ + twl6030_mci_write(TWL6030_PMCS_VMMC_CFG_VOLTAGE, + TWL6030_VMMC_VSEL_0 | TWL6030_VMMC_VSEL_2 | + TWL6030_VMMC_VSEL_4); + twl6030_mci_write(TWL6030_PMCS_VMMC_CFG_STATE, + TWL6030_VMMC_STATE0 | TWL6030_VMMC_GRP_APP); +} + diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 96440d8..87797de 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -16,10 +16,19 @@ depends on I2C bool "LP3972 driver" +config I2C_TWLCORE + bool + config I2C_TWL4030 depends on I2C + depends on USB_TWL4030 + select I2C_TWLCORE bool "TWL4030 driver" - select GPIO + +config I2C_TWL6030 + depends on I2C + select I2C_TWLCORE + bool "TWL6030 driver" config DRIVER_SPI_MC13783 depends on SPI diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index d411f23..1171335 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -2,5 +2,7 @@ obj-$(CONFIG_I2C_MC34704) += mc34704.o obj-$(CONFIG_I2C_MC9SDZ60) += mc9sdz60.o obj-$(CONFIG_I2C_LP3972) += lp3972.o +obj-$(CONFIG_I2C_TWLCORE) += twl-core.o obj-$(CONFIG_I2C_TWL4030) += twl4030.o +obj-$(CONFIG_I2C_TWL6030) += twl6030.o obj-$(CONFIG_DRIVER_SPI_MC13783) += mc13783.o diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c new file mode 100644 index 0000000..cb2c03d --- /dev/null +++ b/drivers/mfd/twl-core.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 Alexander Aring + * + * Based on: + * Copyright (C) 2010 Michael Grzeschik + * + * This file is released under the GPLv2 + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define to_twlcore(a) container_of(a, struct twlcore, cdev) + +static struct twlcore *twl_dev; + +struct twlcore *twlcore_get(void) +{ + return twl_dev; +} +EXPORT_SYMBOL(twlcore_get); + +int twlcore_reg_read(struct twlcore *twlcore, u16 reg, u8 *val) +{ + int ret; + struct i2c_msg xfer_msg[2]; + struct i2c_msg *msg; + int i2c_addr; + unsigned char buf = reg & 0xff; + + i2c_addr = twlcore->client->addr + (reg / 0x100); + + /* [MSG1] fill the register address data */ + msg = &xfer_msg[0]; + msg->addr = i2c_addr; + msg->len = 1; + msg->flags = 0; + msg->buf = &buf; + /* [MSG2] fill the data rx buffer */ + msg = &xfer_msg[1]; + msg->addr = i2c_addr; + msg->flags = I2C_M_RD; + msg->len = 1; /* only n bytes */ + msg->buf = val; + ret = i2c_transfer(twlcore->client->adapter, xfer_msg, 2); + + /* i2c_transfer returns number of messages transferred */ + if (ret < 0) { + pr_err("%s: failed to transfer all messages: %s\n", + __func__, strerror(-ret)); + return ret; + } + return 0; +} +EXPORT_SYMBOL(twlcore_reg_read); + +int twlcore_reg_write(struct twlcore *twlcore, u16 reg, u8 val) +{ + int ret; + struct i2c_msg xfer_msg[1]; + struct i2c_msg *msg; + int i2c_addr; + u8 buf[2]; + + buf[0] = reg & 0xff; + buf[1] = val; + + i2c_addr = twlcore->client->addr + (reg / 0x100); + + /* + * [MSG1]: fill the register address data + * fill the data Tx buffer + */ + msg = xfer_msg; + msg->addr = i2c_addr; + msg->len = 2; + msg->flags = 0; + msg->buf = buf; + /* over write the first byte of buffer with the register address */ + ret = i2c_transfer(twlcore->client->adapter, xfer_msg, 1); + + /* i2c_transfer returns number of messages transferred */ + if (ret < 0) { + pr_err("%s: failed to transfer all messages: %s\n", + __func__, strerror(-ret)); + return ret; + } + return 0; +} +EXPORT_SYMBOL(twlcore_reg_write); + +int twlcore_set_bits(struct twlcore *twlcore, u16 reg, u8 mask, u8 val) +{ + u8 tmp; + int ret; + + ret = twlcore_reg_read(twlcore, reg, &tmp); + tmp = (tmp & ~mask) | val; + + if (ret) + ret = twlcore_reg_write(twlcore, reg, tmp); + + return ret; +} +EXPORT_SYMBOL(twlcore_set_bits); + +static ssize_t twl_read(struct cdev *cdev, void *_buf, size_t count, + ulong offset, ulong flags) +{ + struct twlcore *priv = to_twlcore(cdev); + u8 *buf = _buf; + size_t i; + int ret; + + for (i = 0; i < count; i++) { + ret = twlcore_reg_read(priv, offset, buf); + if (ret) + return (ssize_t)ret; + buf++; + offset++; + } + + return count; +} + +static ssize_t twl_write(struct cdev *cdev, const void *_buf, size_t count, + ulong offset, ulong flags) +{ + struct twlcore *twlcore = to_twlcore(cdev); + const u8 *buf = _buf; + size_t i; + int ret; + + for (i = 0; i < count; i++) { + ret = twlcore_reg_write(twlcore, offset, *buf); + if (ret) + return (ssize_t)ret; + buf++; + offset++; + } + + return count; +} + +struct file_operations twl_fops = { + .lseek = dev_lseek_default, + .read = twl_read, + .write = twl_write, +}; +EXPORT_SYMBOL(twl_fops); diff --git a/drivers/mfd/twl4030.c b/drivers/mfd/twl4030.c index 6a06bd4..191c91f 100644 --- a/drivers/mfd/twl4030.c +++ b/drivers/mfd/twl4030.c @@ -29,145 +29,19 @@ } EXPORT_SYMBOL(twl4030_get); -int twl4030_reg_read(struct twl4030 *twl4030, u16 reg, u8 *val) -{ - int ret; - struct i2c_msg xfer_msg[2]; - struct i2c_msg *msg; - int i2c_addr; - unsigned char buf = reg & 0xff; - - i2c_addr = twl4030->client->addr + (reg / 0x100); - - /* [MSG1] fill the register address data */ - msg = &xfer_msg[0]; - msg->addr = i2c_addr; - msg->len = 1; - msg->flags = 0; /* Read the register value */ - msg->buf = &buf; - /* [MSG2] fill the data rx buffer */ - msg = &xfer_msg[1]; - msg->addr = i2c_addr; - msg->flags = I2C_M_RD; /* Read the register value */ - msg->len = 1; /* only n bytes */ - msg->buf = val; - ret = i2c_transfer(twl4030->client->adapter, xfer_msg, 2); - - /* i2c_transfer returns number of messages transferred */ - if (ret < 0) { - pr_err("%s: failed to transfer all messages: %s\n", __func__, strerror(-ret)); - return ret; - } - return 0; -} -EXPORT_SYMBOL(twl4030_reg_read); - -int twl4030_reg_write(struct twl4030 *twl4030, u16 reg, u8 val) -{ - int ret; - struct i2c_msg xfer_msg[1]; - struct i2c_msg *msg; - int i2c_addr; - u8 buf[2]; - - buf[0] = reg & 0xff; - buf[1] = val; - - i2c_addr = twl4030->client->addr + (reg / 0x100); - - /* - * [MSG1]: fill the register address data - * fill the data Tx buffer - */ - msg = xfer_msg; - msg->addr = i2c_addr; - msg->len = 2; - msg->flags = 0; - msg->buf = buf; - /* over write the first byte of buffer with the register address */ - ret = i2c_transfer(twl4030->client->adapter, xfer_msg, 1); - - /* i2c_transfer returns number of messages transferred */ - if (ret < 0) { - pr_err("%s: failed to transfer all messages: %s\n", __func__, strerror(-ret)); - return ret; - } - return 0; -} -EXPORT_SYMBOL(twl4030_reg_write); - -int twl4030_set_bits(struct twl4030 *twl4030, enum twl4030_reg reg, u8 mask, u8 val) -{ - u8 tmp; - int err; - - err = twl4030_reg_read(twl4030, reg, &tmp); - tmp = (tmp & ~mask) | val; - - if (!err) - err = twl4030_reg_write(twl4030, reg, tmp); - - return err; -} -EXPORT_SYMBOL(twl4030_set_bits); - -static ssize_t twl_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags) -{ - struct twl4030 *priv = to_twl4030(cdev); - u8 *buf = _buf; - size_t i = count; - int err; - - while (i) { - err = twl4030_reg_read(priv, offset, buf); - if (err) - return (ssize_t)err; - buf++; - i--; - offset++; - } - - return count; -} - -static ssize_t twl_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags) -{ - struct twl4030 *twl4030 = to_twl4030(cdev); - const u8 *buf = _buf; - size_t i = count; - int err; - - while (i) { - err = twl4030_reg_write(twl4030, offset, *buf); - if (err) - return (ssize_t)err; - buf++; - i--; - offset++; - } - - return count; -} - -static struct file_operations twl_fops = { - .lseek = dev_lseek_default, - .read = twl_read, - .write = twl_write, -}; - static int twl_probe(struct device_d *dev) { if (twl_dev) return -EBUSY; twl_dev = xzalloc(sizeof(struct twl4030)); - twl_dev->cdev.name = DRIVERNAME; - twl_dev->client = to_i2c_client(dev); - twl_dev->cdev.size = 1024; - twl_dev->cdev.dev = dev; - twl_dev->cdev.ops = &twl_fops; + twl_dev->core.cdev.name = DRIVERNAME; + twl_dev->core.client = to_i2c_client(dev); + twl_dev->core.cdev.size = 1024; + twl_dev->core.cdev.dev = dev; + twl_dev->core.cdev.ops = &twl_fops; - devfs_create(&twl_dev->cdev); + devfs_create(&(twl_dev->core.cdev)); return 0; } @@ -179,8 +53,8 @@ static int twl_init(void) { - register_driver(&twl_driver); - return 0; + register_driver(&twl_driver); + return 0; } device_initcall(twl_init); diff --git a/drivers/mfd/twl6030.c b/drivers/mfd/twl6030.c new file mode 100644 index 0000000..7ecfed8 --- /dev/null +++ b/drivers/mfd/twl6030.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Alexander Aring + * + * This file is released under the GPLv2 + */ + +#include +#include +#include +#include +#include + +#include +#include + +#define DRIVERNAME "twl6030" + +#define to_twl6030(a) container_of(a, struct twl6030, cdev) + +static struct twl6030 *twl_dev; + +struct twl6030 *twl6030_get(void) +{ + return twl_dev; +} +EXPORT_SYMBOL(twl6030_get); + +static int twl_probe(struct device_d *dev) +{ + if (twl_dev) + return -EBUSY; + + twl_dev = xzalloc(sizeof(struct twl6030)); + twl_dev->core.cdev.name = DRIVERNAME; + twl_dev->core.client = to_i2c_client(dev); + twl_dev->core.cdev.size = 1024; + twl_dev->core.cdev.dev = dev; + twl_dev->core.cdev.ops = &twl_fops; + + devfs_create(&(twl_dev->core.cdev)); + + return 0; +} + +static struct driver_d twl_driver = { + .name = DRIVERNAME, + .probe = twl_probe, +}; + +static int twl_init(void) +{ + register_driver(&twl_driver); + return 0; +} + +device_initcall(twl_init); diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 562f0cd..0a4ca31 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -3,6 +3,24 @@ if MTD +config MTD_WRITE + bool + default y + prompt "Support writing to MTD devices" + +config MTD_OOB_DEVICE + bool + select NAND_READ_OOB if NAND + default y + prompt "Create a device for reading the OOB data" + +config MTD_RAW_DEVICE + bool + select NAND_READ_OOB if NAND + default n + prompt "mtdraw device to read/write both data+oob" + +source "drivers/mtd/devices/Kconfig" source "drivers/mtd/nand/Kconfig" source "drivers/mtd/ubi/Kconfig" diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 85bed11..4f97d9a 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -1,3 +1,7 @@ -obj-$(CONFIG_NAND) += nand/ -obj-$(CONFIG_UBI) += ubi/ +obj-$(CONFIG_NAND) += nand/ +obj-$(CONFIG_UBI) += ubi/ +obj-y += devices/ obj-$(CONFIG_PARTITION_NEED_MTD) += partition.o +obj-$(CONFIG_MTD) += core.o +obj-$(CONFIG_MTD_OOB_DEVICE) += mtdoob.o +obj-$(CONFIG_MTD_RAW_DEVICE) += mtdraw.o diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c new file mode 100644 index 0000000..f25863d --- /dev/null +++ b/drivers/mtd/core.c @@ -0,0 +1,241 @@ +/* + * (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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtd.h" + +static LIST_HEAD(mtd_register_hooks); + +static ssize_t mtd_read(struct cdev *cdev, void* buf, size_t count, + ulong offset, ulong flags) +{ + struct mtd_info *mtd = cdev->priv; + size_t retlen; + int ret; + + debug("mtd_read: 0x%08lx 0x%08x\n", offset, count); + + ret = mtd->read(mtd, offset, count, &retlen, buf); + + if(ret) { + printf("err %d\n", ret); + return ret; + } + return retlen; +} + +#define NOTALIGNED(x) (x & (mtd->writesize - 1)) != 0 +#define MTDPGALG(x) ((x) & ~(mtd->writesize - 1)) + +#ifdef CONFIG_MTD_WRITE +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 mtd_write(struct cdev* cdev, const void *buf, size_t _count, + ulong offset, ulong flags) +{ + struct mtd_info *mtd = cdev->priv; + size_t retlen, now; + int ret = 0; + void *wrbuf = NULL; + size_t count = _count; + + if (NOTALIGNED(offset)) { + printf("offset 0x%0lx not page aligned\n", offset); + return -EINVAL; + } + + dev_dbg(cdev->dev, "write: 0x%08lx 0x%08x\n", offset, count); + while (count) { + now = count > mtd->writesize ? mtd->writesize : count; + + if (NOTALIGNED(now)) { + dev_dbg(cdev->dev, "not aligned: %d %ld\n", + mtd->writesize, + (offset % mtd->writesize)); + wrbuf = xmalloc(mtd->writesize); + memset(wrbuf, 0xff, mtd->writesize); + memcpy(wrbuf + (offset % mtd->writesize), buf, now); + if (!all_ff(wrbuf, mtd->writesize)) + ret = mtd->write(mtd, MTDPGALG(offset), + mtd->writesize, &retlen, + wrbuf); + free(wrbuf); + } else { + if (!all_ff(buf, mtd->writesize)) + ret = mtd->write(mtd, offset, now, &retlen, + buf); + dev_dbg(cdev->dev, + "offset: 0x%08lx 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; +} +#endif + +int mtd_ioctl(struct cdev *cdev, int request, void *buf) +{ + struct mtd_info *mtd = cdev->priv; + struct mtd_info_user *user = buf; + + switch (request) { + case MEMGETBADBLOCK: + dev_dbg(cdev->dev, "MEMGETBADBLOCK: 0x%08lx\n", (off_t)buf); + return mtd->block_isbad(mtd, (off_t)buf); +#ifdef CONFIG_MTD_WRITE + case MEMSETBADBLOCK: + dev_dbg(cdev->dev, "MEMSETBADBLOCK: 0x%08lx\n", (off_t)buf); + return mtd->block_markbad(mtd, (off_t)buf); +#endif + case MEMGETINFO: + user->type = mtd->type; + user->flags = mtd->flags; + user->size = mtd->size; + user->erasesize = mtd->erasesize; + user->oobsize = mtd->oobsize; + user->mtd = mtd; + /* The below fields are obsolete */ + user->ecctype = -1; + user->eccsize = 0; + return 0; + } + + return 0; +} + +#ifdef CONFIG_MTD_WRITE +static ssize_t mtd_erase(struct cdev *cdev, size_t count, unsigned long offset) +{ + struct mtd_info *mtd = cdev->priv; + struct erase_info erase; + int ret; + + memset(&erase, 0, sizeof(erase)); + erase.mtd = mtd; + erase.addr = offset; + erase.len = mtd->erasesize; + + while (count > 0) { + dev_dbg(cdev->dev, "erase %d %d\n", erase.addr, erase.len); + + ret = mtd->block_isbad(mtd, erase.addr); + if (ret > 0) { + printf("Skipping bad block at 0x%08x\n", erase.addr); + } else { + ret = mtd->erase(mtd, &erase); + if (ret) + return ret; + } + + erase.addr += mtd->erasesize; + count -= count > mtd->erasesize ? mtd->erasesize : count; + } + + return 0; +} +#endif + +static struct file_operations mtd_ops = { + .read = mtd_read, +#ifdef CONFIG_MTD_WRITE + .write = mtd_write, + .erase = mtd_erase, +#endif + .ioctl = mtd_ioctl, + .lseek = dev_lseek_default, +}; + +int add_mtd_device(struct mtd_info *mtd, char *devname) +{ + char str[16]; + struct mtddev_hook *hook; + + if (!devname) + devname = "mtd"; + strcpy(mtd->class_dev.name, devname); + mtd->class_dev.id = -1; + register_device(&mtd->class_dev); + + mtd->cdev.ops = &mtd_ops; + mtd->cdev.size = mtd->size; + mtd->cdev.name = asprintf("%s%d", devname, 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); + sprintf(str, "%u", mtd->erasesize); + dev_add_param_fixed(&mtd->class_dev, "erasesize", str); + sprintf(str, "%u", mtd->writesize); + dev_add_param_fixed(&mtd->class_dev, "writesize", str); + sprintf(str, "%u", mtd->oobsize); + dev_add_param_fixed(&mtd->class_dev, "oobsize", str); + + devfs_create(&mtd->cdev); + + list_for_each_entry(hook, &mtd_register_hooks, hook) + if (hook->add_mtd_device) + hook->add_mtd_device(mtd, devname); + + return 0; +} + +int del_mtd_device (struct mtd_info *mtd) +{ + struct mtddev_hook *hook; + + list_for_each_entry(hook, &mtd_register_hooks, hook) + if (hook->del_mtd_device) + hook->del_mtd_device(mtd); + unregister_device(&mtd->class_dev); + free(mtd->param_size.value); + free(mtd->cdev.name); + return 0; +} + +void mtdcore_add_hook(struct mtddev_hook *hook) +{ + list_add(&hook->hook, &mtd_register_hooks); +} diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig new file mode 100644 index 0000000..e6d747c --- /dev/null +++ b/drivers/mtd/devices/Kconfig @@ -0,0 +1,16 @@ +menu "Self contained MTD devices" + depends on MTD!=n + +config MTD_DOCG3 + bool "M-Systems Disk-On-Chip G3" + select BCH + select BITREV + ---help--- + This provides an MTD device driver for the M-Systems DiskOnChip + G3 devices. + + The driver provides access to G3 DiskOnChip, distributed by + M-Systems and now Sandisk. The support is very experimental, + and doesn't give access to any write operations. + +endmenu diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile new file mode 100644 index 0000000..164a72e --- /dev/null +++ b/drivers/mtd/devices/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the self containted memory technology device drivers. +# + +obj-$(CONFIG_MTD_DOCG3) += docg3.o diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c new file mode 100644 index 0000000..f7e33dc --- /dev/null +++ b/drivers/mtd/devices/docg3.c @@ -0,0 +1,1196 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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. + * + * Taken from linux kernel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "docg3.h" + +static unsigned reliable_mode; + +/** + * struct docg3_bch - BCH engine + */ +static struct bch_control *docg3_bch; +struct mtd_info *docg3_floors[DOC_MAX_NBFLOORS]; + +static inline u8 doc_readb(struct docg3 *docg3, u16 reg) +{ + u8 val = readb(docg3->base + reg); + + doc_dbg("readb(%04x) -> %02x\n", reg, val); + return val; +} + +static inline u16 doc_readw(struct docg3 *docg3, u16 reg) +{ + u16 val = readw(docg3->base + reg); + + doc_dbg("readb(%04x) -> %04x\n", reg, val); + return val; +} + +static inline void doc_writeb(struct docg3 *docg3, u8 val, u16 reg) +{ + doc_dbg("writeb(%02x into %04x)\n", val, reg); + writeb(val, docg3->base + reg); +} + +static inline void doc_writew(struct docg3 *docg3, u16 val, u16 reg) +{ + doc_dbg("writew(%04x into %04x)\n", val, reg); + writew(val, docg3->base + reg); +} + +static inline void doc_flash_command(struct docg3 *docg3, u8 cmd) +{ + doc_writeb(docg3, cmd, DOC_FLASHCOMMAND); +} + +static inline void doc_flash_sequence(struct docg3 *docg3, u8 seq) +{ + doc_writeb(docg3, seq, DOC_FLASHSEQUENCE); +} + +static inline void doc_flash_address(struct docg3 *docg3, u8 addr) +{ + doc_writeb(docg3, addr, DOC_FLASHADDRESS); +} + +static int doc_register_readb(struct docg3 *docg3, int reg) +{ + u8 val; + + doc_writew(docg3, reg, DOC_READADDRESS); + val = doc_readb(docg3, reg); + doc_vdbg("Read register %04x : %02x\n", reg, val); + return val; +} + +static int doc_register_readw(struct docg3 *docg3, int reg) +{ + u16 val; + + doc_writew(docg3, reg, DOC_READADDRESS); + val = doc_readw(docg3, reg); + doc_vdbg("Read register %04x : %04x\n", reg, val); + return val; +} + +static void doc_delay(struct docg3 *docg3, int nbNOPs) +{ + int i; + + doc_vdbg("NOP x %d\n", nbNOPs); + for (i = 0; i < nbNOPs; i++) + doc_writeb(docg3, 0, DOC_NOP); +} + +static int is_prot_seq_error(struct docg3 *docg3) +{ + int ctrl; + + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + return ctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR); +} + +static int doc_is_ready(struct docg3 *docg3) +{ + int ctrl; + + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + return ctrl & DOC_CTRL_FLASHREADY; +} + +static int doc_wait_ready(struct docg3 *docg3) +{ + int maxWaitCycles = 100; + + do { + doc_delay(docg3, 4); + } while (!doc_is_ready(docg3) && maxWaitCycles--); + doc_delay(docg3, 2); + if (maxWaitCycles > 0) + return 0; + else + return -EIO; +} + +static int doc_reset_seq(struct docg3 *docg3) +{ + int ret; + + doc_writeb(docg3, 0x10, DOC_FLASHCONTROL); + doc_flash_sequence(docg3, DOC_SEQ_RESET); + doc_flash_command(docg3, DOC_CMD_RESET); + doc_delay(docg3, 2); + ret = doc_wait_ready(docg3); + + doc_dbg("doc_reset_seq() -> isReady=%s\n", ret ? "false" : "true"); + return ret; +} + +static void doc_read_data_area(struct docg3 *docg3, void *buf, int len, + int first) +{ + int i, cdr, len4; + u16 data16, *dst16; + u8 data8, *dst8; + + doc_dbg("doc_read_data_area(buf=%p, len=%d)\n", buf, len); + cdr = len & 0x3; + len4 = len - cdr; + + if (first) + doc_writew(docg3, DOC_IOSPACE_DATA, DOC_READADDRESS); + dst16 = buf; + for (i = 0; i < len4; i += 2) { + data16 = doc_readw(docg3, DOC_IOSPACE_DATA); + if (dst16) { + *dst16 = data16; + dst16++; + } + } + + if (cdr) { + doc_writew(docg3, DOC_IOSPACE_DATA | DOC_READADDR_ONE_BYTE, + DOC_READADDRESS); + doc_delay(docg3, 1); + dst8 = (u8 *)dst16; + for (i = 0; i < cdr; i++) { + data8 = doc_readb(docg3, DOC_IOSPACE_DATA); + if (dst8) { + *dst8 = data8; + dst8++; + } + } + } +} + +static void doc_set_reliable_mode(struct docg3 *docg3) +{ + static char *strmode[] = { "normal", "fast", "reliable", "invalid" }; + + doc_dbg("doc_set_reliable_mode(%s)\n", strmode[docg3->reliable]); + switch (docg3->reliable) { + case 0: + break; + case 1: + doc_flash_sequence(docg3, DOC_SEQ_SET_FASTMODE); + doc_flash_command(docg3, DOC_CMD_FAST_MODE); + break; + case 2: + doc_flash_sequence(docg3, DOC_SEQ_SET_RELIABLEMODE); + doc_flash_command(docg3, DOC_CMD_FAST_MODE); + doc_flash_command(docg3, DOC_CMD_RELIABLE_MODE); + break; + default: + doc_err("doc_set_reliable_mode(): invalid mode\n"); + break; + } + doc_delay(docg3, 2); +} + +static void doc_set_asic_mode(struct docg3 *docg3, u8 mode) +{ + int i; + + for (i = 0; i < 12; i++) + doc_readb(docg3, DOC_IOSPACE_IPL); + + mode |= DOC_ASICMODE_MDWREN; + doc_dbg("doc_set_asic_mode(%02x)\n", mode); + doc_writeb(docg3, mode, DOC_ASICMODE); + doc_writeb(docg3, ~mode, DOC_ASICMODECONFIRM); + doc_delay(docg3, 1); +} + +static void doc_set_device_id(struct docg3 *docg3, int id) +{ + u8 ctrl; + + doc_dbg("doc_set_device_id(%d)\n", id); + doc_writeb(docg3, id, DOC_DEVICESELECT); + ctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + + ctrl &= ~DOC_CTRL_VIOLATION; + ctrl |= DOC_CTRL_CE; + doc_writeb(docg3, ctrl, DOC_FLASHCONTROL); +} + +static int doc_set_extra_page_mode(struct docg3 *docg3) +{ + int fctrl; + + doc_dbg("doc_set_extra_page_mode()\n"); + doc_flash_sequence(docg3, DOC_SEQ_PAGE_SIZE_532); + doc_flash_command(docg3, DOC_CMD_PAGE_SIZE_532); + doc_delay(docg3, 2); + + fctrl = doc_register_readb(docg3, DOC_FLASHCONTROL); + if (fctrl & (DOC_CTRL_PROTECTION_ERROR | DOC_CTRL_SEQUENCE_ERROR)) + return -EIO; + else + return 0; +} + +static void doc_setup_addr_sector(struct docg3 *docg3, int sector) +{ + doc_delay(docg3, 1); + doc_flash_address(docg3, sector & 0xff); + doc_flash_address(docg3, (sector >> 8) & 0xff); + doc_flash_address(docg3, (sector >> 16) & 0xff); + doc_delay(docg3, 1); +} + +static int doc_read_seek(struct docg3 *docg3, int block0, int block1, int page, + int wear, int ofs) +{ + int sector, ret = 0; + + doc_dbg("doc_seek(blocks=(%d,%d), page=%d, ofs=%d, wear=%d)\n", + block0, block1, page, ofs, wear); + + if (!wear && (ofs < 2 * DOC_LAYOUT_PAGE_SIZE)) { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE1); + doc_flash_command(docg3, DOC_CMD_READ_PLANE1); + doc_delay(docg3, 2); + } else { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE2); + doc_flash_command(docg3, DOC_CMD_READ_PLANE2); + doc_delay(docg3, 2); + } + + doc_set_reliable_mode(docg3); + if (wear) + ret = doc_set_extra_page_mode(docg3); + if (ret) + goto out; + + doc_flash_sequence(docg3, DOC_SEQ_READ); + sector = (block0 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_setup_addr_sector(docg3, sector); + + sector = (block1 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_setup_addr_sector(docg3, sector); + doc_delay(docg3, 1); + +out: + return ret; +} + +static int doc_read_page_ecc_init(struct docg3 *docg3, int len) +{ + doc_writew(docg3, DOC_ECCCONF0_READ_MODE + | DOC_ECCCONF0_BCH_ENABLE | DOC_ECCCONF0_HAMMING_ENABLE + | (len & DOC_ECCCONF0_DATA_BYTES_MASK), + DOC_ECCCONF0); + doc_delay(docg3, 4); + doc_register_readb(docg3, DOC_FLASHCONTROL); + return doc_wait_ready(docg3); +} + +static void doc_hamming_ecc_init(struct docg3 *docg3, int nb_bytes) +{ + u8 ecc_conf1; + + ecc_conf1 = doc_register_readb(docg3, DOC_ECCCONF1); + ecc_conf1 &= ~DOC_ECCCONF1_HAMMING_BITS_MASK; + ecc_conf1 |= (nb_bytes & DOC_ECCCONF1_HAMMING_BITS_MASK); + doc_writeb(docg3, ecc_conf1, DOC_ECCCONF1); +} + +static int doc_ecc_bch_fix_data(struct docg3 *docg3, void *buf, u8 *hwecc) +{ + u8 ecc[DOC_ECC_BCH_SIZE]; + int errorpos[DOC_ECC_BCH_T], i, numerrs; + + for (i = 0; i < DOC_ECC_BCH_SIZE; i++) + ecc[i] = bitrev8(hwecc[i]); + numerrs = decode_bch(docg3_bch, NULL, DOC_ECC_BCH_COVERED_BYTES, + NULL, ecc, NULL, errorpos); + BUG_ON(numerrs == -EINVAL); + if (numerrs < 0) + goto out; + + for (i = 0; i < numerrs; i++) + errorpos[i] = (errorpos[i] & ~7) | (7 - (errorpos[i] & 7)); + for (i = 0; i < numerrs; i++) + if (errorpos[i] < DOC_ECC_BCH_COVERED_BYTES*8) + /* error is located in data, correct it */ + change_bit(errorpos[i], buf); +out: + doc_dbg("doc_ecc_bch_fix_data: flipped %d bits\n", numerrs); + return numerrs; +} + +static int doc_read_page_prepare(struct docg3 *docg3, int block0, int block1, + int page, int offset) +{ + int wear_area = 0, ret = 0; + + doc_dbg("doc_read_page_prepare(blocks=(%d,%d), page=%d, ofsInPage=%d)\n", + block0, block1, page, offset); + if (offset >= DOC_LAYOUT_WEAR_OFFSET) + wear_area = 1; + if (!wear_area && offset > (DOC_LAYOUT_PAGE_OOB_SIZE * 2)) + return -EINVAL; + + doc_set_device_id(docg3, docg3->device_id); + ret = doc_reset_seq(docg3); + if (ret) + goto err; + + /* Program the flash address block and page */ + ret = doc_read_seek(docg3, block0, block1, page, wear_area, offset); + if (ret) + goto err; + + doc_flash_command(docg3, DOC_CMD_READ_ALL_PLANES); + doc_delay(docg3, 2); + doc_wait_ready(docg3); + + doc_flash_command(docg3, DOC_CMD_SET_ADDR_READ); + doc_delay(docg3, 1); + if (offset >= DOC_LAYOUT_PAGE_SIZE * 2) + offset -= 2 * DOC_LAYOUT_PAGE_SIZE; + doc_flash_address(docg3, offset >> 2); + doc_delay(docg3, 1); + doc_wait_ready(docg3); + + doc_flash_command(docg3, DOC_CMD_READ_FLASH); + + return 0; +err: + doc_writeb(docg3, 0, DOC_DATAEND); + doc_delay(docg3, 2); + return -EIO; +} + +static int doc_read_page_getbytes(struct docg3 *docg3, int len, u_char *buf, + int first) +{ + doc_read_data_area(docg3, buf, len, first); + doc_delay(docg3, 2); + return len; +} + +static void doc_get_bch_hw_ecc(struct docg3 *docg3, u8 *hwecc) +{ + int i; + + for (i = 0; i < DOC_ECC_BCH_SIZE; i++) + hwecc[i] = doc_register_readb(docg3, DOC_BCH_HW_ECC(i)); +} + +static void doc_page_finish(struct docg3 *docg3) +{ + doc_writeb(docg3, 0, DOC_DATAEND); + doc_delay(docg3, 2); +} + +static void doc_read_page_finish(struct docg3 *docg3) +{ + doc_page_finish(docg3); + doc_set_device_id(docg3, 0); +} + +static void calc_block_sector(loff_t from, int *block0, int *block1, int *page, + int *ofs, int reliable) +{ + uint sector, pages_biblock; + + pages_biblock = DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_NBPLANES; + if (reliable == 1 || reliable == 2) + pages_biblock /= 2; + + sector = from / DOC_LAYOUT_PAGE_SIZE; + *block0 = sector / pages_biblock * DOC_LAYOUT_NBPLANES; + *block1 = *block0 + 1; + *page = sector % pages_biblock; + *page /= DOC_LAYOUT_NBPLANES; + if (reliable == 1 || reliable == 2) + *page *= 2; + if (sector % 2) + *ofs = DOC_LAYOUT_PAGE_OOB_SIZE; + else + *ofs = 0; +} + +static int doc_read_oob(struct mtd_info *mtd, loff_t from, + struct mtd_oob_ops *ops) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, ret, ofs = 0; + u8 *oobbuf = ops->oobbuf; + u8 *buf = ops->datbuf; + size_t len, ooblen, nbdata, nboob; + u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; + + if (buf) + len = ops->len; + else + len = 0; + if (oobbuf) + ooblen = ops->ooblen; + else + ooblen = 0; + + if (oobbuf && ops->mode == MTD_OOB_PLACE) + oobbuf += ops->ooboffs; + + doc_dbg("doc_read_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n", + from, ops->mode, buf, len, oobbuf, ooblen); + if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % DOC_LAYOUT_OOB_SIZE) || + (from % DOC_LAYOUT_PAGE_SIZE)) + return -EINVAL; + + ret = -EINVAL; + calc_block_sector(from + len, &block0, &block1, &page, &ofs, + docg3->reliable); + if (block1 > docg3->max_block) + goto err; + + ops->oobretlen = 0; + ops->retlen = 0; + ret = 0; + while (!ret && (len > 0 || ooblen > 0)) { + calc_block_sector(from, &block0, &block1, &page, &ofs, + docg3->reliable); + nbdata = min_t(size_t, len, (size_t)DOC_LAYOUT_PAGE_SIZE); + nboob = min_t(size_t, ooblen, (size_t)DOC_LAYOUT_OOB_SIZE); + ret = doc_read_page_prepare(docg3, block0, block1, page, ofs); + if (ret < 0) + goto err; + ret = doc_read_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); + if (ret < 0) + goto err_in_read; + ret = doc_read_page_getbytes(docg3, nbdata, buf, 1); + if (ret < nbdata) + goto err_in_read; + doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE - nbdata, + NULL, 0); + ret = doc_read_page_getbytes(docg3, nboob, oobbuf, 0); + if (ret < nboob) + goto err_in_read; + doc_read_page_getbytes(docg3, DOC_LAYOUT_OOB_SIZE - nboob, + NULL, 0); + + doc_get_bch_hw_ecc(docg3, hwecc); + eccconf1 = doc_register_readb(docg3, DOC_ECCCONF1); + + if (nboob >= DOC_LAYOUT_OOB_SIZE) { + doc_dbg("OOB - INFO: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + oobbuf[0], oobbuf[1], oobbuf[2], oobbuf[3], + oobbuf[4], oobbuf[5], oobbuf[6]); + doc_dbg("OOB - HAMMING: %02x\n", oobbuf[7]); + doc_dbg("OOB - BCH_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + oobbuf[8], oobbuf[9], oobbuf[10], oobbuf[11], + oobbuf[12], oobbuf[13], oobbuf[14]); + doc_dbg("OOB - UNUSED: %02x\n", oobbuf[15]); + } + doc_dbg("ECC checks: ECCConf1=%x\n", eccconf1); + doc_dbg("ECC HW_ECC: %02x:%02x:%02x:%02x:%02x:%02x:%02x\n", + hwecc[0], hwecc[1], hwecc[2], hwecc[3], hwecc[4], + hwecc[5], hwecc[6]); + + ret = -EIO; + if (is_prot_seq_error(docg3)) + goto err_in_read; + ret = 0; + if ((block0 >= DOC_LAYOUT_BLOCK_FIRST_DATA) && + (eccconf1 & DOC_ECCCONF1_BCH_SYNDROM_ERR) && + (eccconf1 & DOC_ECCCONF1_PAGE_IS_WRITTEN) && + (ops->mode != MTD_OOB_RAW) && + (nbdata == DOC_LAYOUT_PAGE_SIZE)) { + ret = doc_ecc_bch_fix_data(docg3, buf, hwecc); + if (ret < 0) { + mtd->ecc_stats.failed++; + ret = -EBADMSG; + } + if (ret > 0) { + mtd->ecc_stats.corrected += ret; + ret = -EUCLEAN; + } + } + + doc_read_page_finish(docg3); + ops->retlen += nbdata; + ops->oobretlen += nboob; + buf += nbdata; + oobbuf += nboob; + len -= nbdata; + ooblen -= nboob; + from += DOC_LAYOUT_PAGE_SIZE; + } + + return ret; +err_in_read: + doc_read_page_finish(docg3); +err: + return ret; +} + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_oob_ops ops; + size_t ret; + + memset(&ops, 0, sizeof(ops)); + ops.datbuf = buf; + ops.len = len; + ops.mode = MTD_OOB_AUTO; + + ret = doc_read_oob(mtd, from, &ops); + *retlen = ops.retlen; + return ret; +} + +static int doc_reload_bbt(struct docg3 *docg3) +{ + int block = DOC_LAYOUT_BLOCK_BBT; + int ret = 0, nbpages, page; + u_char *buf = docg3->bbt; + + nbpages = DIV_ROUND_UP(docg3->max_block + 1, 8 * DOC_LAYOUT_PAGE_SIZE); + for (page = 0; !ret && (page < nbpages); page++) { + ret = doc_read_page_prepare(docg3, block, block + 1, + page + DOC_LAYOUT_PAGE_BBT, 0); + if (!ret) + ret = doc_read_page_ecc_init(docg3, + DOC_LAYOUT_PAGE_SIZE); + if (!ret) + doc_read_page_getbytes(docg3, DOC_LAYOUT_PAGE_SIZE, + buf, 1); + buf += DOC_LAYOUT_PAGE_SIZE; + } + doc_read_page_finish(docg3); + return ret; +} + +static int doc_block_isbad(struct mtd_info *mtd, loff_t from) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, ofs, is_good; + + calc_block_sector(from, &block0, &block1, &page, &ofs, + docg3->reliable); + doc_dbg("doc_block_isbad(from=%lld) => block=(%d,%d), page=%d, ofs=%d\n", + from, block0, block1, page, ofs); + + if (block0 < DOC_LAYOUT_BLOCK_FIRST_DATA) + return 0; + if (block1 > docg3->max_block) + return -EINVAL; + + is_good = docg3->bbt[block0 >> 3] & (1 << (block0 & 0x7)); + return !is_good; +} + +#ifdef MTD_WRITE +static int doc_guess_autoecc(struct mtd_oob_ops *ops) +{ + int autoecc; + + switch (ops->mode) { + case MTD_OOB_PLACE: + case MTD_OOB_AUTO: + autoecc = 1; + break; + case MTD_OOB_RAW: + autoecc = 0; + break; + default: + autoecc = -EINVAL; + } + return autoecc; +} + +static void doc_fill_autooob(u8 *dst, u8 *oobsrc) +{ + memcpy(dst, oobsrc, DOC_LAYOUT_OOB_PAGEINFO_SZ); + dst[DOC_LAYOUT_OOB_UNUSED_OFS] = oobsrc[DOC_LAYOUT_OOB_PAGEINFO_SZ]; +} + +static int doc_backup_oob(struct docg3 *docg3, loff_t to, + struct mtd_oob_ops *ops) +{ + int ooblen = ops->ooblen, autoecc; + + if (ooblen != DOC_LAYOUT_OOB_SIZE) + return -EINVAL; + autoecc = doc_guess_autoecc(ops); + if (autoecc < 0) + return autoecc; + + docg3->oob_write_ofs = to; + docg3->oob_autoecc = autoecc; + if (ops->mode == MTD_OOB_AUTO) { + doc_fill_autooob(docg3->oob_write_buf, ops->oobbuf); + ops->oobretlen = 8; + } else { + memcpy(docg3->oob_write_buf, ops->oobbuf, DOC_LAYOUT_OOB_SIZE); + ops->oobretlen = DOC_LAYOUT_OOB_SIZE; + } + return 0; +} + +static void doc_write_data_area(struct docg3 *docg3, const void *buf, int len) +{ + int i, cdr, len4; + u16 *src16; + u8 *src8; + + doc_dbg("doc_write_data_area(buf=%p, len=%d)\n", buf, len); + cdr = len & 0x3; + len4 = len - cdr; + + doc_writew(docg3, DOC_IOSPACE_DATA, DOC_READADDRESS); + src16 = (u16 *)buf; + for (i = 0; i < len4; i += 2) { + doc_writew(docg3, *src16, DOC_IOSPACE_DATA); + src16++; + } + + src8 = (u8 *)src16; + for (i = 0; i < cdr; i++) { + doc_writew(docg3, DOC_IOSPACE_DATA | DOC_READADDR_ONE_BYTE, + DOC_READADDRESS); + doc_writeb(docg3, *src8, DOC_IOSPACE_DATA); + src8++; + } +} + +static void doc_setup_writeaddr_sector(struct docg3 *docg3, int sector, int ofs) +{ + ofs = ofs >> 2; + doc_delay(docg3, 1); + doc_flash_address(docg3, ofs & 0xff); + doc_flash_address(docg3, sector & 0xff); + doc_flash_address(docg3, (sector >> 8) & 0xff); + doc_flash_address(docg3, (sector >> 16) & 0xff); + doc_delay(docg3, 1); +} + +static int doc_write_seek(struct docg3 *docg3, int block0, int block1, int page, + int ofs) +{ + int ret = 0, sector; + + doc_dbg("doc_write_seek(blocks=(%d,%d), page=%d, ofs=%d)\n", + block0, block1, page, ofs); + + doc_set_reliable_mode(docg3); + + if (ofs < 2 * DOC_LAYOUT_PAGE_SIZE) { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE1); + doc_flash_command(docg3, DOC_CMD_READ_PLANE1); + doc_delay(docg3, 2); + } else { + doc_flash_sequence(docg3, DOC_SEQ_SET_PLANE2); + doc_flash_command(docg3, DOC_CMD_READ_PLANE2); + doc_delay(docg3, 2); + } + + doc_flash_sequence(docg3, DOC_SEQ_PAGE_SETUP); + doc_flash_command(docg3, DOC_CMD_PROG_CYCLE1); + + sector = (block0 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_setup_writeaddr_sector(docg3, sector, ofs); + + doc_flash_command(docg3, DOC_CMD_PROG_CYCLE3); + doc_delay(docg3, 2); + ret = doc_wait_ready(docg3); + if (ret) + goto out; + + doc_flash_command(docg3, DOC_CMD_PROG_CYCLE1); + sector = (block1 << DOC_ADDR_BLOCK_SHIFT) + (page & DOC_ADDR_PAGE_MASK); + doc_setup_writeaddr_sector(docg3, sector, ofs); + doc_delay(docg3, 1); + +out: + return ret; +} + +static int doc_write_page_ecc_init(struct docg3 *docg3, int len) +{ + doc_writew(docg3, DOC_ECCCONF0_WRITE_MODE + | DOC_ECCCONF0_BCH_ENABLE | DOC_ECCCONF0_HAMMING_ENABLE + | (len & DOC_ECCCONF0_DATA_BYTES_MASK), + DOC_ECCCONF0); + doc_delay(docg3, 4); + doc_register_readb(docg3, DOC_FLASHCONTROL); + return doc_wait_ready(docg3); +} + +static void doc_write_page_putbytes(struct docg3 *docg3, int len, + const u_char *buf) +{ + doc_write_data_area(docg3, buf, len); + doc_delay(docg3, 2); +} + +static void doc_ecc_disable(struct docg3 *docg3) +{ + doc_writew(docg3, DOC_ECCCONF0_READ_MODE, DOC_ECCCONF0); + doc_delay(docg3, 4); +} + +static int doc_get_op_status(struct docg3 *docg3) +{ + u8 status; + + doc_flash_sequence(docg3, DOC_SEQ_PLANES_STATUS); + doc_flash_command(docg3, DOC_CMD_PLANES_STATUS); + doc_delay(docg3, 5); + + doc_ecc_disable(docg3); + doc_read_data_area(docg3, &status, 1, 1); + return status; +} + +static int doc_write_erase_wait_status(struct docg3 *docg3) +{ + int status, ret = 0; + + if (!doc_is_ready(docg3)) + mdelay(3000); + if (!doc_is_ready(docg3)) { + doc_dbg("Timeout reached and the chip is still not ready\n"); + ret = -EAGAIN; + goto out; + } + + status = doc_get_op_status(docg3); + if (status & DOC_PLANES_STATUS_FAIL) { + doc_dbg("Erase/Write failed on (a) plane(s), status = %x\n", + status); + ret = -EIO; + } + +out: + doc_page_finish(docg3); + return ret; +} + +static int doc_erase_block(struct docg3 *docg3, int block0, int block1) +{ + int ret, sector; + + doc_dbg("doc_erase_block(blocks=(%d,%d))\n", block0, block1); + ret = doc_reset_seq(docg3); + if (ret) + return -EIO; + + doc_set_reliable_mode(docg3); + doc_flash_sequence(docg3, DOC_SEQ_ERASE); + + sector = block0 << DOC_ADDR_BLOCK_SHIFT; + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_setup_addr_sector(docg3, sector); + sector = block1 << DOC_ADDR_BLOCK_SHIFT; + doc_flash_command(docg3, DOC_CMD_PROG_BLOCK_ADDR); + doc_setup_addr_sector(docg3, sector); + doc_delay(docg3, 1); + + doc_flash_command(docg3, DOC_CMD_ERASECYCLE2); + doc_delay(docg3, 2); + + if (is_prot_seq_error(docg3)) { + doc_err("Erase blocks %d,%d error\n", block0, block1); + return -EIO; + } + + return doc_write_erase_wait_status(docg3); +} + +static int doc_erase(struct mtd_info *mtd, struct erase_info *info) +{ + struct docg3 *docg3 = mtd->priv; + uint64_t len; + int block0, block1, page, ret, ofs = 0; + + doc_dbg("doc_erase(from=%d, len=%d\n", info->addr, info->len); + doc_set_device_id(docg3, docg3->device_id); + + info->state = MTD_ERASE_PENDING; + calc_block_sector(info->addr + info->len, &block0, &block1, &page, + &ofs, docg3->reliable); + ret = -EINVAL; + if (block1 > docg3->max_block || page || ofs) + goto reset_err; + + ret = 0; + calc_block_sector(info->addr, &block0, &block1, &page, &ofs, + docg3->reliable); + doc_set_reliable_mode(docg3); + for (len = info->len; !ret && len > 0; len -= mtd->erasesize) { + info->state = MTD_ERASING; + ret = doc_erase_block(docg3, block0, block1); + block0 += 2; + block1 += 2; + } + + if (ret) + goto reset_err; + + info->state = MTD_ERASE_DONE; + return 0; + +reset_err: + info->state = MTD_ERASE_FAILED; + return ret; +} + +static int doc_write_page(struct docg3 *docg3, loff_t to, const u_char *buf, + const u_char *oob, int autoecc) +{ + int block0, block1, page, ret, ofs = 0; + u8 hwecc[DOC_ECC_BCH_SIZE], hamming; + + doc_dbg("doc_write_page(to=%lld)\n", to); + calc_block_sector(to, &block0, &block1, &page, &ofs, docg3->reliable); + + doc_set_device_id(docg3, docg3->device_id); + ret = doc_reset_seq(docg3); + if (ret) + goto err; + + /* Program the flash address block and page */ + ret = doc_write_seek(docg3, block0, block1, page, ofs); + if (ret) + goto err; + + doc_write_page_ecc_init(docg3, DOC_ECC_BCH_TOTAL_BYTES); + doc_delay(docg3, 2); + doc_write_page_putbytes(docg3, DOC_LAYOUT_PAGE_SIZE, buf); + + if (oob && autoecc) { + doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_PAGEINFO_SZ, oob); + doc_delay(docg3, 2); + oob += DOC_LAYOUT_OOB_UNUSED_OFS; + + hamming = doc_register_readb(docg3, DOC_HAMMINGPARITY); + doc_delay(docg3, 2); + doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_HAMMING_SZ, + &hamming); + doc_delay(docg3, 2); + + doc_get_bch_hw_ecc(docg3, hwecc); + doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_BCH_SZ, hwecc); + doc_delay(docg3, 2); + + doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_UNUSED_SZ, oob); + } + if (oob && !autoecc) + doc_write_page_putbytes(docg3, DOC_LAYOUT_OOB_SIZE, oob); + + doc_delay(docg3, 2); + doc_page_finish(docg3); + doc_delay(docg3, 2); + doc_flash_command(docg3, DOC_CMD_PROG_CYCLE2); + doc_delay(docg3, 2); + + /* + * The wait status will perform another doc_page_finish() call, but that + * seems to please the docg3, so leave it. + */ + ret = doc_write_erase_wait_status(docg3); + return ret; +err: + doc_read_page_finish(docg3); + return ret; +} + +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, + struct mtd_oob_ops *ops) +{ + struct docg3 *docg3 = mtd->priv; + int block0, block1, page, ret, pofs = 0, autoecc, oobdelta; + u8 *oobbuf = ops->oobbuf; + u8 *buf = ops->datbuf; + size_t len, ooblen; + u8 oob[DOC_LAYOUT_OOB_SIZE] __aligned(4); + + if (buf) + len = ops->len; + else + len = 0; + if (oobbuf) + ooblen = ops->ooblen; + else + ooblen = 0; + + if (oobbuf && ops->mode == MTD_OOB_PLACE) + oobbuf += ops->ooboffs; + + doc_dbg("doc_write_oob(from=%lld, mode=%d, data=(%p:%zu), oob=(%p:%zu))\n", + ofs, ops->mode, buf, len, oobbuf, ooblen); + switch (ops->mode) { + case MTD_OOB_PLACE: + case MTD_OOB_RAW: + oobdelta = mtd->oobsize; + break; + case MTD_OOB_AUTO: + oobdelta = mtd->ecclayout->oobavail; + break; + default: + oobdelta = 0; + } + if ((len % DOC_LAYOUT_PAGE_SIZE) || (ooblen % oobdelta) || + (ofs % DOC_LAYOUT_PAGE_SIZE)) + return -EINVAL; + if (len && ooblen && + (len / DOC_LAYOUT_PAGE_SIZE) != (ooblen / oobdelta)) + return -EINVAL; + + ret = -EINVAL; + calc_block_sector(ofs + len, &block0, &block1, &page, &pofs, + docg3->reliable); + if (block1 > docg3->max_block) + goto err; + + ops->oobretlen = 0; + ops->retlen = 0; + ret = 0; + if (len == 0 && ooblen == 0) + return -EINVAL; + if (len == 0 && ooblen > 0) + return doc_backup_oob(docg3, ofs, ops); + + autoecc = doc_guess_autoecc(ops); + if (autoecc < 0) + return autoecc; + + while (!ret && len > 0) { + memset(oob, 0, sizeof(oob)); + if (ofs == docg3->oob_write_ofs) + memcpy(oob, docg3->oob_write_buf, DOC_LAYOUT_OOB_SIZE); + else if (ooblen > 0 && ops->mode == MTD_OOB_AUTO) + doc_fill_autooob(oob, oobbuf); + else if (ooblen > 0) + memcpy(oob, oobbuf, DOC_LAYOUT_OOB_SIZE); + ret = doc_write_page(docg3, ofs, buf, oob, autoecc); + + ofs += DOC_LAYOUT_PAGE_SIZE; + len -= DOC_LAYOUT_PAGE_SIZE; + buf += DOC_LAYOUT_PAGE_SIZE; + if (ooblen) { + oobbuf += oobdelta; + ooblen -= oobdelta; + ops->oobretlen += oobdelta; + } + ops->retlen += DOC_LAYOUT_PAGE_SIZE; + } +err: + doc_set_device_id(docg3, 0); + return ret; +} + +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct docg3 *docg3 = mtd->priv; + int ret; + struct mtd_oob_ops ops; + + doc_dbg("doc_write(to=%lld, len=%zu)\n", to, len); + ops.datbuf = (char *)buf; + ops.len = len; + ops.mode = MTD_OOB_PLACE; + ops.oobbuf = NULL; + ops.ooblen = 0; + ops.ooboffs = 0; + + ret = doc_write_oob(mtd, to, &ops); + *retlen = ops.retlen; + return ret; +} +#endif + +static void __init doc_set_driver_info(int chip_id, struct mtd_info *mtd) +{ + struct docg3 *docg3 = mtd->priv; + int cfg; + + cfg = doc_register_readb(docg3, DOC_CONFIGURATION); + docg3->if_cfg = (cfg & DOC_CONF_IF_CFG ? 1 : 0); + docg3->reliable = reliable_mode; + + switch (chip_id) { + case DOC_CHIPID_G3: + mtd->name = asprintf("DiskOnChip G3 floor %d", + docg3->device_id); + docg3->max_block = 2047; + break; + } + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->size = (docg3->max_block + 1) * DOC_LAYOUT_BLOCK_SIZE; + if (docg3->reliable == 2) + mtd->size /= 2; + mtd->erasesize = DOC_LAYOUT_BLOCK_SIZE * DOC_LAYOUT_NBPLANES; + if (docg3->reliable == 2) + mtd->erasesize /= 2; + mtd->writesize = DOC_LAYOUT_PAGE_SIZE; + mtd->oobsize = DOC_LAYOUT_OOB_SIZE; + mtd->read = doc_read; + mtd->read_oob = doc_read_oob; + mtd->block_isbad = doc_block_isbad; +#ifdef MTD_WRITE + mtd->erase = doc_erase; + mtd->write = doc_write; + mtd->write_oob = doc_write_oob; +#endif +} + +static struct mtd_info *doc_probe_device(void __iomem *base, int floor, + struct device_d *dev) +{ + int ret, bbt_nbpages; + u16 chip_id, chip_id_inv; + struct docg3 *docg3; + struct mtd_info *mtd; + + ret = -ENOMEM; + docg3 = kzalloc(sizeof(struct docg3), GFP_KERNEL); + if (!docg3) + goto nomem1; + mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd) + goto nomem2; + mtd->priv = docg3; + bbt_nbpages = DIV_ROUND_UP(docg3->max_block + 1, + 8 * DOC_LAYOUT_PAGE_SIZE); + docg3->bbt = kzalloc(bbt_nbpages * DOC_LAYOUT_PAGE_SIZE, GFP_KERNEL); + if (!docg3->bbt) + goto nomem3; + + docg3->dev = dev; + docg3->device_id = floor; + docg3->base = base; + doc_set_device_id(docg3, docg3->device_id); + if (!floor) + doc_set_asic_mode(docg3, DOC_ASICMODE_RESET); + doc_set_asic_mode(docg3, DOC_ASICMODE_NORMAL); + + chip_id = doc_register_readw(docg3, DOC_CHIPID); + chip_id_inv = doc_register_readw(docg3, DOC_CHIPID_INV); + + ret = 0; + if (chip_id != (u16)(~chip_id_inv)) + goto nomem3; + + switch (chip_id) { + case DOC_CHIPID_G3: + doc_info("Found a G3 DiskOnChip at addr %p, floor %d\n", + base, floor); + break; + default: + doc_err("Chip id %04x is not a DiskOnChip G3 chip\n", chip_id); + goto nomem3; + } + + doc_set_driver_info(chip_id, mtd); + + doc_hamming_ecc_init(docg3, DOC_LAYOUT_OOB_PAGEINFO_SZ); + doc_reload_bbt(docg3); + return mtd; + +nomem3: + kfree(mtd); +nomem2: + kfree(docg3); +nomem1: + return ERR_PTR(ret); +} + +static int __init docg3_probe(struct device_d *dev) +{ + struct mtd_info *mtd; + void __iomem *base; + int ret, floor, found = 0; + + base = dev_request_mem_region(dev, 0); + + ret = -ENOMEM; + docg3_bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T, + DOC_ECC_BCH_PRIMPOLY); + if (!docg3_bch) + goto nomem2; + + /* for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) { */ + for (floor = 0; floor < 2; floor++) { + mtd = doc_probe_device(base, floor, dev); + if (IS_ERR(mtd)) { + ret = PTR_ERR(mtd); + goto err_probe; + } + if (!mtd) { + if (floor == 0) + goto notfound; + else + continue; + } + docg3_floors[floor] = mtd; + ret = add_mtd_device(mtd, NULL); + if (ret) + goto err_probe; + found++; + } + + if (ret) + goto err_probe; + if (!found) + goto notfound; + + return 0; + +notfound: + ret = -ENODEV; + dev_info(dev, "No supported DiskOnChip found\n"); +err_probe: + free_bch(docg3_bch); +nomem2: + return ret; +} + +static struct driver_d g3_driver = { + .name = "docg3", + .probe = docg3_probe, +}; + +static int __init docg3_init(void) +{ + return register_driver(&g3_driver); +} + +device_initcall(docg3_init); diff --git a/drivers/mtd/devices/docg3.h b/drivers/mtd/devices/docg3.h new file mode 100644 index 0000000..97eafe3 --- /dev/null +++ b/drivers/mtd/devices/docg3.h @@ -0,0 +1,283 @@ +/* + * Handles the M-Systems DiskOnChip G3 chip + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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. + * + */ + +#ifndef _MTD_DOCG3_H +#define _MTD_DOCG3_H + +/* + * Flash memory areas : + * - 0x0000 .. 0x07ff : IPL + * - 0x0800 .. 0x0fff : Data area + * - 0x1000 .. 0x17ff : Registers + * - 0x1800 .. 0x1fff : Unknown + */ +#define DOC_IOSPACE_IPL 0x0000 +#define DOC_IOSPACE_DATA 0x0800 +#define DOC_IOSPACE_SIZE 0x2000 + +/* + * DOC G3 layout and adressing scheme + * A page address for the block "b", plane "P" and page "p": + * address = [bbbb bPpp pppp] + */ + +#define DOC_ADDR_PAGE_MASK 0x3f +#define DOC_ADDR_BLOCK_SHIFT 6 +#define DOC_LAYOUT_NBPLANES 2 +#define DOC_LAYOUT_PAGES_PER_BLOCK 64 +#define DOC_LAYOUT_PAGE_SIZE 512 +#define DOC_LAYOUT_OOB_SIZE 16 +#define DOC_LAYOUT_WEAR_SIZE 8 +#define DOC_LAYOUT_PAGE_OOB_SIZE \ + (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_SIZE) +#define DOC_LAYOUT_WEAR_OFFSET (DOC_LAYOUT_PAGE_OOB_SIZE * 2) +#define DOC_LAYOUT_BLOCK_SIZE \ + (DOC_LAYOUT_PAGES_PER_BLOCK * DOC_LAYOUT_PAGE_SIZE) + +/* + * ECC related constants + */ +#define DOC_ECC_BCH_M 14 +#define DOC_ECC_BCH_T 4 +#define DOC_ECC_BCH_PRIMPOLY 0x4443 +#define DOC_ECC_BCH_SIZE 7 +#define DOC_ECC_BCH_COVERED_BYTES \ + (DOC_LAYOUT_PAGE_SIZE + DOC_LAYOUT_OOB_PAGEINFO_SZ + \ + DOC_LAYOUT_OOB_HAMMING_SZ) +#define DOC_ECC_BCH_TOTAL_BYTES \ + (DOC_ECC_BCH_COVERED_BYTES + DOC_LAYOUT_OOB_BCH_SZ) + +/* + * Blocks distribution + */ +#define DOC_LAYOUT_BLOCK_BBT 0 +#define DOC_LAYOUT_BLOCK_OTP 0 +#define DOC_LAYOUT_BLOCK_FIRST_DATA 6 + +#define DOC_LAYOUT_PAGE_BBT 4 + +/* + * Extra page OOB (16 bytes wide) layout + */ +#define DOC_LAYOUT_OOB_PAGEINFO_OFS 0 +#define DOC_LAYOUT_OOB_HAMMING_OFS 7 +#define DOC_LAYOUT_OOB_BCH_OFS 8 +#define DOC_LAYOUT_OOB_UNUSED_OFS 15 +#define DOC_LAYOUT_OOB_PAGEINFO_SZ 7 +#define DOC_LAYOUT_OOB_HAMMING_SZ 1 +#define DOC_LAYOUT_OOB_BCH_SZ 7 +#define DOC_LAYOUT_OOB_UNUSED_SZ 1 + + +#define DOC_CHIPID_G3 0x200 +#define DOC_ERASE_MARK 0xaa +#define DOC_MAX_NBFLOORS 4 +/* + * Flash registers + */ +#define DOC_CHIPID 0x1000 +#define DOC_TEST 0x1004 +#define DOC_BUSLOCK 0x1006 +#define DOC_ENDIANCONTROL 0x1008 +#define DOC_DEVICESELECT 0x100a +#define DOC_ASICMODE 0x100c +#define DOC_CONFIGURATION 0x100e +#define DOC_INTERRUPTCONTROL 0x1010 +#define DOC_READADDRESS 0x101a +#define DOC_DATAEND 0x101e +#define DOC_INTERRUPTSTATUS 0x1020 + +#define DOC_FLASHSEQUENCE 0x1032 +#define DOC_FLASHCOMMAND 0x1034 +#define DOC_FLASHADDRESS 0x1036 +#define DOC_FLASHCONTROL 0x1038 +#define DOC_NOP 0x103e + +#define DOC_ECCCONF0 0x1040 +#define DOC_ECCCONF1 0x1042 +#define DOC_ECCPRESET 0x1044 +#define DOC_HAMMINGPARITY 0x1046 +#define DOC_BCH_HW_ECC(idx) (0x1048 + idx) + +#define DOC_PROTECTION 0x1056 +#define DOC_DPS0_KEY 0x105c +#define DOC_DPS1_KEY 0x105e +#define DOC_DPS0_ADDRLOW 0x1060 +#define DOC_DPS0_ADDRHIGH 0x1062 +#define DOC_DPS1_ADDRLOW 0x1064 +#define DOC_DPS1_ADDRHIGH 0x1066 +#define DOC_DPS0_STATUS 0x106c +#define DOC_DPS1_STATUS 0x106e + +#define DOC_ASICMODECONFIRM 0x1072 +#define DOC_CHIPID_INV 0x1074 +#define DOC_POWERMODE 0x107c + +/* + * Flash sequences + * A sequence is preset before one or more commands are input to the chip. + */ +#define DOC_SEQ_RESET 0x00 +#define DOC_SEQ_PAGE_SIZE_532 0x03 +#define DOC_SEQ_SET_FASTMODE 0x05 +#define DOC_SEQ_SET_RELIABLEMODE 0x09 +#define DOC_SEQ_READ 0x12 +#define DOC_SEQ_SET_PLANE1 0x0e +#define DOC_SEQ_SET_PLANE2 0x10 +#define DOC_SEQ_PAGE_SETUP 0x1d +#define DOC_SEQ_ERASE 0x27 +#define DOC_SEQ_PLANES_STATUS 0x31 + +/* + * Flash commands + */ +#define DOC_CMD_READ_PLANE1 0x00 +#define DOC_CMD_SET_ADDR_READ 0x05 +#define DOC_CMD_READ_ALL_PLANES 0x30 +#define DOC_CMD_READ_PLANE2 0x50 +#define DOC_CMD_READ_FLASH 0xe0 +#define DOC_CMD_PAGE_SIZE_532 0x3c + +#define DOC_CMD_PROG_BLOCK_ADDR 0x60 +#define DOC_CMD_PROG_CYCLE1 0x80 +#define DOC_CMD_PROG_CYCLE2 0x10 +#define DOC_CMD_PROG_CYCLE3 0x11 +#define DOC_CMD_ERASECYCLE2 0xd0 +#define DOC_CMD_READ_STATUS 0x70 +#define DOC_CMD_PLANES_STATUS 0x71 + +#define DOC_CMD_RELIABLE_MODE 0x22 +#define DOC_CMD_FAST_MODE 0xa2 + +#define DOC_CMD_RESET 0xff + +/* + * Flash register : DOC_FLASHCONTROL + */ +#define DOC_CTRL_VIOLATION 0x20 +#define DOC_CTRL_CE 0x10 +#define DOC_CTRL_UNKNOWN_BITS 0x08 +#define DOC_CTRL_PROTECTION_ERROR 0x04 +#define DOC_CTRL_SEQUENCE_ERROR 0x02 +#define DOC_CTRL_FLASHREADY 0x01 + +/* + * Flash register : DOC_ASICMODE + */ +#define DOC_ASICMODE_RESET 0x00 +#define DOC_ASICMODE_NORMAL 0x01 +#define DOC_ASICMODE_POWERDOWN 0x02 +#define DOC_ASICMODE_MDWREN 0x04 +#define DOC_ASICMODE_BDETCT_RESET 0x08 +#define DOC_ASICMODE_RSTIN_RESET 0x10 +#define DOC_ASICMODE_RAM_WE 0x20 + +/* + * Flash register : DOC_ECCCONF0 + */ +#define DOC_ECCCONF0_WRITE_MODE 0x0000 +#define DOC_ECCCONF0_READ_MODE 0x8000 +#define DOC_ECCCONF0_AUTO_ECC_ENABLE 0x4000 +#define DOC_ECCCONF0_HAMMING_ENABLE 0x1000 +#define DOC_ECCCONF0_BCH_ENABLE 0x0800 +#define DOC_ECCCONF0_DATA_BYTES_MASK 0x07ff + +/* + * Flash register : DOC_ECCCONF1 + */ +#define DOC_ECCCONF1_BCH_SYNDROM_ERR 0x80 +#define DOC_ECCCONF1_UNKOWN1 0x40 +#define DOC_ECCCONF1_PAGE_IS_WRITTEN 0x20 +#define DOC_ECCCONF1_UNKOWN3 0x10 +#define DOC_ECCCONF1_HAMMING_BITS_MASK 0x0f + +/* + * Flash register : DOC_PROTECTION + */ +#define DOC_PROTECT_FOUNDRY_OTP_LOCK 0x01 +#define DOC_PROTECT_CUSTOMER_OTP_LOCK 0x02 +#define DOC_PROTECT_LOCK_INPUT 0x04 +#define DOC_PROTECT_STICKY_LOCK 0x08 +#define DOC_PROTECT_PROTECTION_ENABLED 0x10 +#define DOC_PROTECT_IPL_DOWNLOAD_LOCK 0x20 +#define DOC_PROTECT_PROTECTION_ERROR 0x80 + +/* + * Flash register : DOC_DPS0_STATUS and DOC_DPS1_STATUS + */ +#define DOC_DPS_OTP_PROTECTED 0x01 +#define DOC_DPS_READ_PROTECTED 0x02 +#define DOC_DPS_WRITE_PROTECTED 0x04 +#define DOC_DPS_HW_LOCK_ENABLED 0x08 +#define DOC_DPS_KEY_OK 0x80 + +/* + * Flash register : DOC_CONFIGURATION + */ +#define DOC_CONF_IF_CFG 0x80 +#define DOC_CONF_MAX_ID_MASK 0x30 +#define DOC_CONF_VCCQ_3V 0x01 + +/* + * Flash register : DOC_READADDRESS + */ +#define DOC_READADDR_INC 0x8000 +#define DOC_READADDR_ONE_BYTE 0x4000 +#define DOC_READADDR_ADDR_MASK 0x1fff + +/* + * Flash register : DOC_POWERMODE + */ +#define DOC_POWERDOWN_READY 0x80 + +/* + * Status of erase and write operation + */ +#define DOC_PLANES_STATUS_FAIL 0x01 +#define DOC_PLANES_STATUS_PLANE0_KO 0x02 +#define DOC_PLANES_STATUS_PLANE1_KO 0x04 + +/* + * DPS key management + * + * Each floor of docg3 has 2 protection areas: DPS0 and DPS1. These areas span + * across block boundaries, and define whether these blocks can be read or + * written. + * The definition is dynamically stored in page 0 of blocks (2,3) for DPS0, and + * page 0 of blocks (4,5) for DPS1. + */ +#define DOC_LAYOUT_DPS_KEY_LENGTH 8 + +struct docg3 { + struct device_d *dev; + void __iomem *base; + unsigned int device_id:4; + unsigned int if_cfg:1; + unsigned int reliable:2; + int max_block; + u8 *bbt; + loff_t oob_write_ofs; + int oob_autoecc; + u8 oob_write_buf[DOC_LAYOUT_OOB_SIZE]; +}; + +#define doc_err(fmt, arg...) dev_err(docg3->dev, fmt, ## arg) +#define doc_info(fmt, arg...) dev_info(docg3->dev, fmt, ## arg) +#define doc_dbg(fmt, arg...) dev_dbg(docg3->dev, fmt, ## arg) +#define doc_vdbg(fmt, arg...) dev_dbg(docg3->dev, fmt, ## arg) + +#endif diff --git a/drivers/mtd/mtd.h b/drivers/mtd/mtd.h new file mode 100644 index 0000000..c8af6e3 --- /dev/null +++ b/drivers/mtd/mtd.h @@ -0,0 +1,42 @@ +/* + * MTD devices registration + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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. + * + */ + +/** + * mtddev_hook - hook to register additional mtd devices + * @add_mtd_device: called when a MTD driver calls add_mtd_device() + * @del_mtd_device: called when a MTD driver calls del_mtd_device() + * + * Provide a hook to be called whenether a add_mtd_device() is called. + * Additionnal devices like mtdoob and mtdraw subscribe to the service. + */ +struct mtddev_hook { + struct list_head hook; + int (*add_mtd_device)(struct mtd_info *mtd, char *devname); + int (*del_mtd_device)(struct mtd_info *mtd); +}; +struct cdev; + +/** + * mtdcore_add_hook - add a hook to MTD registration/unregistration + * @hook: the hook + * + * Normally called in a coredevice_initcall() to add another MTD layout (such as + * mtdraw, ...) + */ +void mtdcore_add_hook(struct mtddev_hook *hook); + +int mtd_ioctl(struct cdev *cdev, int request, void *buf); diff --git a/drivers/mtd/mtdoob.c b/drivers/mtd/mtdoob.c new file mode 100644 index 0000000..be656a4 --- /dev/null +++ b/drivers/mtd/mtdoob.c @@ -0,0 +1,97 @@ +/* + * MTD oob device + * + * Copyright (C) 2011 Sascha Hauer + * + * 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. + * + * Adds a character devices : + * - mtdoob + */ + +#include +#include +#include +#include +#include +#include + +#include "mtd.h" + +struct mtdoob { + struct cdev cdev; + struct mtd_info *mtd; +}; + +static struct mtd_info *to_mtd(struct cdev *cdev) +{ + struct mtdoob *mtdoob = cdev->priv; + return mtdoob->mtd; +} + +static ssize_t mtd_read_oob(struct cdev *cdev, void *buf, size_t count, + ulong offset, ulong flags) +{ + struct mtd_info *mtd = to_mtd(cdev); + struct mtd_oob_ops ops; + int ret; + + if (count < mtd->oobsize) + return -EINVAL; + + ops.mode = MTD_OOB_RAW; + ops.ooboffs = 0; + ops.ooblen = mtd->oobsize; + ops.oobbuf = buf; + ops.datbuf = NULL; + ops.len = mtd->oobsize; + + offset /= mtd->oobsize; + ret = mtd->read_oob(mtd, offset * mtd->writesize, &ops); + if (ret) + return ret; + + return mtd->oobsize; +} + +static struct file_operations mtd_ops_oob = { + .read = mtd_read_oob, + .ioctl = mtd_ioctl, + .lseek = dev_lseek_default, +}; + +static int add_mtdoob_device(struct mtd_info *mtd, char *devname) +{ + struct mtdoob *mtdoob; + + mtdoob = xzalloc(sizeof(*mtdoob)); + mtdoob->cdev.ops = &mtd_ops_oob; + mtdoob->cdev.size = (mtd->size / mtd->writesize) * mtd->oobsize; + mtdoob->cdev.name = asprintf("%s_oob%d", devname, mtd->class_dev.id); + mtdoob->cdev.priv = mtdoob; + mtdoob->cdev.dev = &mtd->class_dev; + mtdoob->mtd = mtd; + devfs_create(&mtdoob->cdev); + + return 0; +} + +static struct mtddev_hook mtdoob_hook = { + .add_mtd_device = add_mtdoob_device, +}; + +static int __init register_mtdoob(void) +{ + mtdcore_add_hook(&mtdoob_hook); + return 0; +} + +coredevice_initcall(register_mtdoob); diff --git a/drivers/mtd/mtdraw.c b/drivers/mtd/mtdraw.c new file mode 100644 index 0000000..b1cce3d --- /dev/null +++ b/drivers/mtd/mtdraw.c @@ -0,0 +1,303 @@ +/* + * MTD raw device + * + * Copyright (C) 2011 Robert Jarzmik + * + * 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. + * + * Adds a character devices : + * - mtdraw + * + * Device mtd_raw provides acces to the MTD "pages+OOB". For example if a MTD + * has pages of 512 bytes and OOB of 16 bytes, mtd_oob will be made of blocks + * of 528 bytes, with page data being followed by OOB. + * The layout will be: ... . + * This means that a read at offset 516 of 20 bytes will give the 12 last bytes + * of the OOB of page0, and the 8 first bytes of page1. + * Same thing applies for writes, which have to be page+oob aligned (ie. offset + * and size should be multiples of (mtd->writesize + mtd->oobsize)). + */ + +#include +#include +#include +#include +#include +#include + +#include "mtd.h" + +/* Must be a multiple of the largest NAND page size */ +#define RAW_WRITEBUF_SIZE 4096 + +/** + * mtdraw - mtdraw device private data + * @cdev: character device "mtdraw" + * @mtd: MTD device to handle read/writes/erases + * + * @writebuf: buffer to handle unaligned writes (ie. writes of sizes which are + * not multiples of MTD (writesize+oobsize) + * @write_fill: number of bytes in writebuf + * @write_ofs: offset in character device (mtdraw) where last write(s) stored + * bytes because of unaligned writes (ie. remain of writesize+oobsize write) + * + * The mtdraw device must allow unaligned writes. This is enabled by a write buffer which gathers data to issue mtd->write_oob() with full page+oob data. + * Suppose writesize=512, oobsize=16. + * A first write of 512 bytes triggers: + * - write_ofs = offset of write() + * - write_fill = 512 + * - copy of the 512 provided bytes into writebuf + * - no actual mtd->write if done + * A second write of 512 bytes triggers: + * - copy of the 16 first bytes into writebuf + * - a mtd->write_oob() from writebuf + * - empty writebuf + * - copy the remaining 496 bytes into writebuf + * => write_fill = 496, write_ofs = offset + 528 + * Etc ... + */ +struct mtdraw { + struct cdev cdev; + struct mtd_info *mtd; + void *writebuf; + int write_fill; + int write_ofs; +}; + +static struct mtdraw *to_mtdraw(struct cdev *cdev) +{ + return cdev->priv; +} + +static struct mtd_info *to_mtd(struct cdev *cdev) +{ + struct mtdraw *mtdraw = to_mtdraw(cdev); + return mtdraw->mtd; +} + +static ssize_t mtdraw_read_unaligned(struct mtd_info *mtd, void *dst, + size_t count, int skip, ulong offset) +{ + struct mtd_oob_ops ops; + ssize_t ret; + int partial = 0; + void *tmp = dst; + + if (skip || count < mtd->writesize + mtd->oobsize) + partial = 1; + if (partial) + tmp = malloc(mtd->writesize + mtd->oobsize); + if (!tmp) + return -ENOMEM; + ops.mode = MTD_OOB_RAW; + ops.datbuf = tmp; + ops.len = mtd->writesize; + ops.oobbuf = tmp + mtd->writesize; + ops.ooblen = mtd->oobsize; + ret = mtd->read_oob(mtd, offset, &ops); + if (ret) + goto err; + if (partial) + memcpy(dst, tmp + skip, count); + ret = count; +err: + if (partial) + free(tmp); + + return ret; +} + +static ssize_t mtdraw_read(struct cdev *cdev, void *buf, size_t count, + ulong offset, ulong flags) +{ + struct mtd_info *mtd = to_mtd(cdev); + ssize_t retlen = 0, ret = 1, toread; + ulong numpage; + int skip; + + numpage = offset / (mtd->writesize + mtd->oobsize); + skip = offset % (mtd->writesize + mtd->oobsize); + + while (ret > 0 && count > 0) { + toread = min_t(int, count, mtd->writesize + mtd->oobsize); + ret = mtdraw_read_unaligned(mtd, buf, toread, + skip, numpage++ * mtd->writesize); + buf += ret; + skip = 0; + count -= ret; + retlen += ret; + } + if (ret < 0) + printf("err %d\n", ret); + else + ret = retlen; + return ret; +} + +#ifdef CONFIG_MTD_WRITE +static ssize_t mtdraw_blkwrite(struct mtd_info *mtd, const void *buf, + ulong offset) +{ + struct mtd_oob_ops ops; + int ret; + + ops.mode = MTD_OOB_RAW; + ops.datbuf = (void *)buf; + ops.len = mtd->writesize; + ops.oobbuf = (void *)buf + mtd->writesize; + ops.ooblen = mtd->oobsize; + ret = mtd->write_oob(mtd, offset, &ops); + if (!ret) + ret = ops.retlen + ops.oobretlen; + return ret; +} + +static void mtdraw_fillbuf(struct mtdraw *mtdraw, const void *src, int nbbytes) +{ + memcpy(mtdraw->writebuf + mtdraw->write_fill, src, nbbytes); + mtdraw->write_fill += nbbytes; +} + +static ssize_t mtdraw_write(struct cdev *cdev, const void *buf, size_t count, + ulong offset, ulong flags) +{ + struct mtdraw *mtdraw = to_mtdraw(cdev); + struct mtd_info *mtd = to_mtd(cdev); + int bsz = mtd->writesize + mtd->oobsize; + ulong numpage; + size_t retlen = 0, tofill; + int ret = 0; + + if (mtdraw->write_fill && + mtdraw->write_ofs + mtdraw->write_fill != offset) + return -EINVAL; + if (mtdraw->write_fill == 0 && offset % bsz) + return -EINVAL; + + if (mtdraw->write_fill) { + tofill = min_t(size_t, count, bsz - mtdraw->write_fill); + mtdraw_fillbuf(mtdraw, buf, tofill); + offset += tofill; + count -= tofill; + retlen += tofill; + } + + if (mtdraw->write_fill == bsz) { + ret = mtdraw_blkwrite(mtd, mtdraw->writebuf, mtdraw->write_ofs); + retlen += ret; + mtdraw->write_fill = 0; + } + + numpage = offset / (mtd->writesize + mtd->oobsize); + while (ret >= 0 && count >= bsz) { + ret = mtdraw_blkwrite(mtd, buf + retlen, + mtd->writesize * numpage++); + count -= ret; + retlen += ret; + offset += ret; + } + + if (ret >= 0 && count) { + mtdraw->write_ofs = offset - mtdraw->write_fill; + mtdraw_fillbuf(mtdraw, buf + retlen, count); + } + + if (ret < 0) { + printf("err %d\n", ret); + return ret; + } else { + return retlen; + } +} + +static ssize_t mtdraw_erase(struct cdev *cdev, size_t count, ulong offset) +{ + struct mtd_info *mtd = to_mtd(cdev); + struct erase_info erase; + int ret; + + offset = offset / (mtd->writesize + mtd->oobsize) * mtd->writesize; + count = count / (mtd->writesize + mtd->oobsize) * mtd->writesize; + + memset(&erase, 0, sizeof(erase)); + erase.mtd = mtd; + erase.addr = offset; + erase.len = mtd->erasesize; + + while (count > 0) { + debug("erase %d %d\n", erase.addr, erase.len); + + ret = mtd->block_isbad(mtd, erase.addr); + if (ret > 0) { + printf("Skipping bad block at 0x%08x\n", erase.addr); + } else { + ret = mtd->erase(mtd, &erase); + if (ret) + return ret; + } + + erase.addr += mtd->erasesize; + count -= count > mtd->erasesize ? mtd->erasesize : count; + } + + return 0; +} +#else +static ssize_t mtdraw_write(struct cdev *cdev, const void *buf, size_t count, + ulong offset, ulong flags) +{ + return 0; +} +static ssize_t mtdraw_erase(struct cdev *cdev, size_t count, ulong offset) +{ + return 0; +} +#endif + +static const struct file_operations mtd_raw_fops = { + .read = mtdraw_read, + .write = mtdraw_write, + .erase = mtdraw_erase, + .ioctl = mtd_ioctl, + .lseek = dev_lseek_default, +}; + +static int add_mtdraw_device(struct mtd_info *mtd, char *devname) +{ + struct mtdraw *mtdraw; + + mtdraw = xzalloc(sizeof(*mtdraw)); + mtdraw->writebuf = xmalloc(RAW_WRITEBUF_SIZE); + mtdraw->mtd = mtd; + + mtdraw->cdev.ops = (struct file_operations *)&mtd_raw_fops; + mtdraw->cdev.size = mtd->size / mtd->writesize * + (mtd->writesize + mtd->oobsize); + mtdraw->cdev.name = asprintf("%sraw%d", devname, mtd->class_dev.id); + mtdraw->cdev.priv = mtdraw; + mtdraw->cdev.dev = &mtd->class_dev; + mtdraw->cdev.mtd = mtd; + devfs_create(&mtdraw->cdev); + + return 0; +} + +static struct mtddev_hook mtdraw_hook = { + .add_mtd_device = add_mtdraw_device, +}; + +static int __init register_mtdraw(void) +{ + mtdcore_add_hook(&mtdraw_hook); + return 0; +} + +coredevice_initcall(register_mtdraw); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 1cc29a8..926a64b 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -8,11 +8,6 @@ if NAND -config NAND_WRITE - bool - default y - prompt "Support writing to Nand" - config NAND_ECC_SOFT bool default y @@ -53,12 +48,6 @@ Say y here to include support for bad block tables. This speeds up the process of checking for bad blocks -config NAND_OOB_DEVICE - bool - select NAND_READ_OOB - default y - prompt "create a device for reading the OOB data" - config NAND_IMX bool prompt "i.MX NAND driver" @@ -76,9 +65,9 @@ prompt "Atmel (AT91SAM9xxx) NAND driver" depends on ARCH_AT91 -config NAND_S3C24X0 +config NAND_S3C24XX bool - prompt "Samsung S3C24X0 NAND driver" + prompt "Samsung S3C24XX NAND driver" depends on ARCH_S3C24xx help Add support for processor's NAND device controller. diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 149cbbf..5c6d8b3 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -1,7 +1,7 @@ # Generic NAND options -obj-$(CONFIG_NAND) += nand.o nand_ecc.o -obj-$(CONFIG_NAND_WRITE) += nand_write.o +obj-$(CONFIG_NAND) += nand_ecc.o +obj-$(CONFIG_MTD_WRITE) += nand_write.o obj-$(CONFIG_NAND_ECC_SOFT) += nand_ecc.o nand_swecc.o obj-$(CONFIG_NAND_ECC_HW) += nand_hwecc.o obj-$(CONFIG_NAND_ECC_HW_SYNDROME) += nand_hwecc_syndrome.o @@ -14,4 +14,4 @@ obj-$(CONFIG_NAND_IMX) += nand_imx.o obj-$(CONFIG_NAND_OMAP_GPMC) += nand_omap_gpmc.o nand_omap_bch_decoder.o obj-$(CONFIG_NAND_ATMEL) += atmel_nand.o -obj-$(CONFIG_NAND_S3C24X0) += nand_s3c2410.o +obj-$(CONFIG_NAND_S3C24XX) += nand_s3c24xx.o diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 8cc1b51..3213de2 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -36,18 +36,6 @@ #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) @@ -148,30 +136,16 @@ */ static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *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); + memcpy_fromio(buf, chip->IO_ADDR_R, len); } static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { - struct nand_chip *nand_chip = mtd->priv; + struct nand_chip *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); + memcpy_toio(chip->IO_ADDR_W, buf, len); } /* @@ -188,7 +162,6 @@ { 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 */ @@ -417,14 +390,11 @@ nand_chip->chip_delay = 20; /* 20us command delay time */ - if (host->board->bus_width_16) { /* 16-bit bus width */ + 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; - } + + nand_chip->read_buf = atmel_read_buf; + nand_chip->write_buf = atmel_write_buf; atmel_nand_enable(host); @@ -485,7 +455,7 @@ goto err_scan_tail; } - add_mtd_device(mtd); + add_mtd_device(mtd, "nand"); if (!res) return res; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 2433945..6da68dc 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -1358,7 +1358,7 @@ At least as nand_bbt.c is currently written. */ if ((ret = nand_scan_bbt(mtd, NULL))) return ret; - add_mtd_device(mtd); + add_mtd_device(mtd, "nand"); #ifdef CONFIG_MTD_PARTITIONS if (!no_autopart) add_mtd_partitions(mtd, parts, numparts); @@ -1418,7 +1418,7 @@ 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); + add_mtd_device(mtd, "nand"); #ifdef CONFIG_MTD_PARTITIONS if (!no_autopart) add_mtd_partitions(mtd, parts, numparts); diff --git a/drivers/mtd/nand/nand-bb.c b/drivers/mtd/nand/nand-bb.c index dbfb8e3..bd30438 100644 --- a/drivers/mtd/nand/nand-bb.c +++ b/drivers/mtd/nand/nand-bb.c @@ -45,6 +45,7 @@ size_t raw_size; size_t size; off_t offset; + unsigned long flags; void *writebuf; struct cdev cdev; @@ -89,7 +90,7 @@ /* Must be a multiple of the largest NAND page size */ #define BB_WRITEBUF_SIZE 4096 -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE static int nand_bb_write_buf(struct nand_bb *bb, size_t count) { int ret, now; @@ -164,13 +165,14 @@ } #endif -static int nand_bb_open(struct cdev *cdev) +static int nand_bb_open(struct cdev *cdev, unsigned long flags) { struct nand_bb *bb = cdev->priv; if (bb->open) return -EBUSY; + bb->flags = flags; bb->open = 1; bb->offset = 0; bb->needs_write = 0; @@ -183,7 +185,7 @@ { struct nand_bb *bb = cdev->priv; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE if (bb->needs_write) nand_bb_write_buf(bb, bb->offset % BB_WRITEBUF_SIZE); #endif @@ -211,11 +213,44 @@ return 0; } +static off_t nand_bb_lseek(struct cdev *cdev, off_t __offset) +{ + struct nand_bb *bb = cdev->priv; + unsigned long raw_pos = 0; + uint32_t offset = __offset; + int ret; + + /* lseek only in readonly mode */ + if (bb->flags & O_ACCMODE) + return -ENOSYS; + while (raw_pos < bb->raw_size) { + off_t now = min(offset, bb->info.erasesize); + + ret = cdev_ioctl(bb->cdev_parent, MEMGETBADBLOCK, (void *)raw_pos); + if (ret < 0) + return ret; + if (!ret) { + offset -= now; + raw_pos += now; + } else { + raw_pos += bb->info.erasesize; + } + + if (!offset) { + bb->offset = raw_pos; + return __offset; + } + } + + return -EINVAL; +} + static struct file_operations nand_bb_ops = { .open = nand_bb_open, .close = nand_bb_close, .read = nand_bb_read, -#ifdef CONFIG_NAND_WRITE + .lseek = nand_bb_lseek, +#ifdef CONFIG_MTD_WRITE .write = nand_bb_write, .erase = nand_bb_erase, #endif diff --git a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c deleted file mode 100644 index 130e2af..0000000 --- a/drivers/mtd/nand/nand.c +++ /dev/null @@ -1,290 +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%08lx 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 - -#ifdef CONFIG_NAND_WRITE -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%0lx not page aligned\n", offset); - return -EINVAL; - } - - debug("write: 0x%08lx 0x%08x\n", offset, count); - - while (count) { - now = count > info->writesize ? info->writesize : count; - - if (NOTALIGNED(now)) { - debug("not aligned: %d %ld\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%08lx 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; -} -#endif - -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%08lx\n", (off_t)buf); - return info->block_isbad(info, (off_t)buf); -#ifdef CONFIG_NAND_WRITE - case MEMSETBADBLOCK: - debug("MEMSETBADBLOCK: 0x%08lx\n", (off_t)buf); - return info->block_markbad(info, (off_t)buf); -#endif - case MEMGETINFO: - user->type = info->type; - user->flags = info->flags; - 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; -} - -#ifdef CONFIG_NAND_WRITE -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; -} -#endif - -#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, -#ifdef CONFIG_NAND_WRITE - .write = nand_write, - .erase = nand_erase, -#endif - .ioctl = nand_ioctl, - .lseek = dev_lseek_default, -}; - -#ifdef CONFIG_NAND_OOB_DEVICE -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, -}; - -static int nand_init_oob_cdev(struct mtd_info *mtd) -{ - struct nand_chip *chip = mtd->priv; - - mtd->cdev_oob.ops = &nand_ops_oob; - mtd->cdev_oob.size = (mtd->size >> chip->page_shift) * mtd->oobsize; - mtd->cdev_oob.name = asprintf("nand_oob%d", mtd->class_dev.id); - mtd->cdev_oob.priv = mtd; - mtd->cdev_oob.dev = &mtd->class_dev; - devfs_create(&mtd->cdev_oob); - - return 0; -} - -static void nand_exit_oob_cdev(struct mtd_info *mtd) -{ - free(mtd->cdev_oob.name); -} -#else - -static int nand_init_oob_cdev(struct mtd_info *mtd) -{ - return 0; -} - -static void nand_exit_oob_cdev(struct mtd_info *mtd) -{ - return; -} -#endif - -int add_mtd_device(struct mtd_info *mtd) -{ - char str[16]; - - strcpy(mtd->class_dev.name, "nand"); - 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); - sprintf(str, "%u", mtd->erasesize); - dev_add_param_fixed(&mtd->class_dev, "erasesize", str); - sprintf(str, "%u", mtd->writesize); - dev_add_param_fixed(&mtd->class_dev, "writesize", str); - sprintf(str, "%u", mtd->oobsize); - dev_add_param_fixed(&mtd->class_dev, "oobsize", str); - - devfs_create(&mtd->cdev); - - nand_init_oob_cdev(mtd); - - return 0; -} - -int del_mtd_device (struct mtd_info *mtd) -{ - unregister_device(&mtd->class_dev); - nand_exit_oob_cdev(mtd); - 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 index ec0f4a3..c4eca0d 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1006,7 +1006,7 @@ chip->read_word = nand_read_word; if (!chip->block_bad) chip->block_bad = nand_block_bad; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE if (!chip->block_markbad) chip->block_markbad = nand_default_block_markbad; if (!chip->write_buf) @@ -1168,7 +1168,7 @@ if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) chip->erase_cmd = multi_erase_cmd; @@ -1297,7 +1297,7 @@ } } -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE if (!chip->write_page) chip->write_page = nand_write_page; #endif @@ -1308,7 +1308,7 @@ */ if (!chip->ecc.read_page_raw) chip->ecc.read_page_raw = nand_read_page_raw; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE if (!chip->ecc.write_page_raw) chip->ecc.write_page_raw = nand_write_page_raw; #endif @@ -1335,7 +1335,7 @@ printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " "This is not recommended !!\n"); chip->ecc.read_page = nand_read_page_raw; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE chip->ecc.write_page = nand_write_page_raw; chip->ecc.write_oob = nand_write_oob_std; #endif @@ -1401,7 +1401,7 @@ /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE mtd->erase = nand_erase; mtd->write = nand_write; mtd->write_oob = nand_write_oob; @@ -1413,7 +1413,7 @@ mtd->lock = NULL; mtd->unlock = NULL; mtd->block_isbad = nand_block_isbad; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE mtd->block_markbad = nand_block_markbad; #endif /* propagate ecc.layout to mtd_info */ diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index bf3a7db..c1696ee 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -557,7 +557,7 @@ * (Re)write the bad block table * */ -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE static int write_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) diff --git a/drivers/mtd/nand/nand_hwecc.c b/drivers/mtd/nand/nand_hwecc.c index 5ead49c..a48efa1 100644 --- a/drivers/mtd/nand/nand_hwecc.c +++ b/drivers/mtd/nand/nand_hwecc.c @@ -61,7 +61,7 @@ * @chip: nand chip info structure * @buf: data buffer */ -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { @@ -94,7 +94,7 @@ if (!chip->ecc.read_oob) chip->ecc.read_oob = nand_read_oob_std; #endif -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE if (!chip->ecc.write_oob) chip->ecc.write_oob = nand_write_oob_std; if (!chip->ecc.write_page) diff --git a/drivers/mtd/nand/nand_hwecc_syndrome.c b/drivers/mtd/nand/nand_hwecc_syndrome.c index dd067c9..1493b88 100644 --- a/drivers/mtd/nand/nand_hwecc_syndrome.c +++ b/drivers/mtd/nand/nand_hwecc_syndrome.c @@ -72,7 +72,7 @@ * The hw generator calculates the error syndrome automatically. Therefor * we need a special oob layout and handling. */ -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE static void nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { @@ -155,7 +155,7 @@ * @chip: nand chip info structure * @page: page number to write */ -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE static int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page) { @@ -216,7 +216,7 @@ chip->ecc.read_page = nand_read_page_syndrome; if (!chip->ecc.read_oob) chip->ecc.read_oob = nand_read_oob_syndrome; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE if (!chip->ecc.write_page) chip->ecc.write_page = nand_write_page_syndrome; if (!chip->ecc.write_oob) diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c index c8c69d6..85cfbed 100644 --- a/drivers/mtd/nand/nand_imx.c +++ b/drivers/mtd/nand/nand_imx.c @@ -1176,7 +1176,7 @@ goto escan; } - add_mtd_device(mtd); + add_mtd_device(mtd, "nand"); dev->priv = host; diff --git a/drivers/mtd/nand/nand_omap_gpmc.c b/drivers/mtd/nand/nand_omap_gpmc.c index d5e642a..9fb1132 100644 --- a/drivers/mtd/nand/nand_omap_gpmc.c +++ b/drivers/mtd/nand/nand_omap_gpmc.c @@ -956,7 +956,7 @@ dev_set_param(pdev, "eccmode", ecc_mode_strings[pdata->ecc_mode]); /* We are all set to register with the system now! */ - err = add_mtd_device(minfo); + err = add_mtd_device(minfo, "nand"); if (err) { dev_dbg(pdev, "device registration failed\n"); goto out_release_mem; diff --git a/drivers/mtd/nand/nand_s3c2410.c b/drivers/mtd/nand/nand_s3c2410.c deleted file mode 100644 index c5f5d97..0000000 --- a/drivers/mtd/nand/nand_s3c2410.c +++ /dev/null @@ -1,665 +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 NFSTAT 0x20 -#define NFECC 0x2C - -/* S3C2440 specific bits */ -#define NFSTAT_BUSY (1) -#define NFCONT_nFCE (1 << 1) -#define NFCONT_INITECC (1 << 4) -#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; - - void __iomem *base; -}; - -/** - * oob placement block for use with hardware ecc generation on small page - */ -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(void __iomem *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(void __iomem *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(void __iomem *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(void __iomem *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(void __iomem *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(void __iomem *host) -{ -#ifdef CONFIG_CPU_S3C2410 - writew(NFCONF_nFCE, host + NFCONF); -#endif -#ifdef CONFIG_CPU_S3C2440 - writew(NFCONT_nFCE, host + NFCONT); -#endif -} - -/* ----------------------------------------------------------------------- */ - -#ifdef CONFIG_CPU_S3C2440 -/** - * Read one block of data from the NAND port - * @param[in] mtd Instance data - * @param[out] buf buffer to write data to - * @param[in] len byte count - * - * This is a special block read variant for the S3C2440 CPU. - */ -static void s3c2440_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct s3c24x0_nand_host *host = nand_chip->priv; - - readsl(host->base + NFDATA, buf, len >> 2); - - /* cleanup any fractional read */ - if (len & 3) { - buf += len & ~3; - - for (; len & 3; len--) - *buf++ = readb(host->base + NFDATA); - } -} - -/** - * Write one block of data to the NAND port - * @param[in] mtd Instance data - * @param[out] buf buffer to read data from - * @param[in] len byte count - * - * This is a special block write variant for the S3C2440 CPU. - */ -static void s3c2440_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, - int len) -{ - struct nand_chip *nand_chip = mtd->priv; - struct s3c24x0_nand_host *host = nand_chip->priv; - - writesl(host->base + NFDATA, buf, len >> 2); - - /* cleanup any fractional write */ - if (len & 3) { - buf += len & ~3; - - for (; len & 3; len--, buf++) - writeb(*buf, host->base + NFDATA); - } -} -#endif - -/** - * Check the ECC and try to repair the data if possible - * @param[in] mtd_info Not used - * @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: This routine works always on a 24 bit ECC - */ -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) - 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; - -#ifdef CONFIG_CPU_S3C2410 - writel(readl(host->base + NFCONF) | NFCONF_INITECC , host->base + NFCONF); -#endif -#ifdef CONFIG_CPU_S3C2440 - writel(readl(host->base + NFCONT) | NFCONT_INITECC , host->base + NFCONT); -#endif -} - -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; - -#ifdef CONFIG_CPU_S3C2410 - ecc_code[0] = readb(host->base + NFECC); - ecc_code[1] = readb(host->base + NFECC + 1); - ecc_code[2] = readb(host->base + NFECC + 2); -#endif -#ifdef CONFIG_CPU_S3C2440 - unsigned long ecc = readl(host->base + NFECC); - - ecc_code[0] = ecc; - ecc_code[1] = ecc >> 8; - ecc_code[2] = ecc >> 16; -#endif - 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 s3c24x0_nand_platform_data *pdata = dev->platform_data; - 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_request_mem_region(dev, 0); - - /* structures must be linked */ - chip = &host->nand; - mtd = &host->mtd; - mtd->priv = chip; - - /* init the default settings */ - - /* 50 us command delay time */ - chip->chip_delay = 50; - chip->priv = host; - - chip->IO_ADDR_R = chip->IO_ADDR_W = host->base + NFDATA; - -#ifdef CONFIG_CPU_S3C2440 - chip->read_buf = s3c2440_nand_read_buf; - chip->write_buf = s3c2440_nand_write_buf; -#endif - 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; - - /* - * Setup ECC handling in accordance to the kernel - * - 1 times 512 bytes with 24 bit ECC for small page - * - 8 times 256 bytes with 24 bit ECC each for large page - */ - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.bytes = 3; /* always 24 bit ECC per turn */ -#ifdef CONFIG_CPU_S3C2440 - if (readl(host->base) & 0x8) { - /* large page (2048 bytes per page) */ - chip->ecc.size = 256; - } else -#endif - { - /* small page (512 bytes per page) */ - chip->ecc.size = 512; - chip->ecc.layout = &nand_hw_eccoob; - } - - if (pdata->flash_bbt) { - /* use a flash based bbt */ - chip->options |= NAND_USE_FLASH_BBT; - } - - 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(void __iomem *host) -{ - while (!(readw(host + NFSTAT) & NFSTAT_BUSY)) - ; -} - -/** - * Convert a page offset into a page address for the NAND - * @param host Where to write the address to - * @param offs Page's offset in the NAND - * @param ps Page size (512 or 2048) - * @param c Address cycle count (3, 4 or 5) - * - * Uses the offset of the page to generate an page address into the NAND. This - * differs when using a 512 byte or 2048 bytes per page NAND. - * The collumn part of the page address to be generated is always forced to '0'. - */ -static void __nand_boot_init nfc_addr(void __iomem *host, uint32_t offs, - int ps, int c) -{ - send_addr(host, 0); /* collumn part 1 */ - - if (ps == 512) { - send_addr(host, offs >> 9); - send_addr(host, offs >> 17); - if (c > 3) - send_addr(host, offs >> 25); - } else { - send_addr(host, 0); /* collumn part 2 */ - send_addr(host, offs >> 11); - send_addr(host, offs >> 19); - if (c > 4) - send_addr(host, offs >> 27); - send_cmd(host, NAND_CMD_READSTART); - } -} - -/** - * Load a sequential count of pages 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 - * - * This function must be located in the first 4kiB of the barebox image - * (guess why). - */ -void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page) -{ - void __iomem *host = (void __iomem *)S3C24X0_NAND_BASE; - unsigned pagesize; - int i, cycle; - - /* - * 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); - - /* use the current NAND hardware configuration */ - switch (readl(S3C24X0_NAND_BASE) & 0xf) { - case 0x6: /* 8 bit, 4 addr cycles, 512 bpp, normal NAND */ - pagesize = 512; - cycle = 4; - break; - case 0xc: /* 8 bit, 4 addr cycles, 2048 bpp, advanced NAND */ - pagesize = 2048; - cycle = 4; - break; - case 0xe: /* 8 bit, 5 addr cycles, 2048 bpp, advanced NAND */ - pagesize = 2048; - cycle = 5; - break; - default: - /* we cannot output an error message here :-( */ - disable_nand_controller(host); - return; - } - - 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, pagesize, cycle); - wait_for_completion(host); - /* copy one page (do *not* use readsb() here!)*/ - for (i = 0; i < pagesize; i++) - writeb(readb(host + NFDATA), (void __iomem *)(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; - - if (argc < 3) - return COMMAND_ERROR_USAGE; - - dest = (void *)strtoul_suffix(argv[1], NULL, 0); - size = strtoul_suffix(argv[2], NULL, 0); - - s3c24x0_nand_load_image(dest, size, 0); - - /* re-enable the controller again, as this was a test only */ - enable_nand_controller((void *)S3C24X0_NAND_BASE, - BOARD_DEFAULT_NAND_TIMING); - - 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); - -/** - * @file - * @brief Support for various kinds of NAND devices - * - * ECC handling in this driver (in accordance to the current 2.6.38 kernel): - * - for small page NANDs it generates 3 ECC bytes out of 512 data bytes - * - for large page NANDs it generates 24 ECC bytes out of 2048 data bytes - * - * As small page NANDs are using 48 bits ECC per default, this driver uses a - * local OOB layout description, to shrink it down to 24 bits. This is a bad - * idea, but we cannot change it here, as the kernel is using this layout. - * - * For large page NANDs this driver uses the default layout, as the kernel does. - */ diff --git a/drivers/mtd/nand/nand_s3c24xx.c b/drivers/mtd/nand/nand_s3c24xx.c new file mode 100644 index 0000000..e55aef0 --- /dev/null +++ b/drivers/mtd/nand/nand_s3c24xx.c @@ -0,0 +1,665 @@ +/* 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 NFSTAT 0x20 +#define NFECC 0x2C + +/* S3C2440 specific bits */ +#define NFSTAT_BUSY (1) +#define NFCONT_nFCE (1 << 1) +#define NFCONT_INITECC (1 << 4) +#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; + + void __iomem *base; +}; + +/** + * oob placement block for use with hardware ecc generation on small page + */ +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(void __iomem *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(void __iomem *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(void __iomem *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(void __iomem *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(void __iomem *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(void __iomem *host) +{ +#ifdef CONFIG_CPU_S3C2410 + writew(NFCONF_nFCE, host + NFCONF); +#endif +#ifdef CONFIG_CPU_S3C2440 + writew(NFCONT_nFCE, host + NFCONT); +#endif +} + +/* ----------------------------------------------------------------------- */ + +#ifdef CONFIG_CPU_S3C2440 +/** + * Read one block of data from the NAND port + * @param[in] mtd Instance data + * @param[out] buf buffer to write data to + * @param[in] len byte count + * + * This is a special block read variant for the S3C2440 CPU. + */ +static void s3c2440_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct s3c24x0_nand_host *host = nand_chip->priv; + + readsl(host->base + NFDATA, buf, len >> 2); + + /* cleanup any fractional read */ + if (len & 3) { + buf += len & ~3; + + for (; len & 3; len--) + *buf++ = readb(host->base + NFDATA); + } +} + +/** + * Write one block of data to the NAND port + * @param[in] mtd Instance data + * @param[out] buf buffer to read data from + * @param[in] len byte count + * + * This is a special block write variant for the S3C2440 CPU. + */ +static void s3c2440_nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, + int len) +{ + struct nand_chip *nand_chip = mtd->priv; + struct s3c24x0_nand_host *host = nand_chip->priv; + + writesl(host->base + NFDATA, buf, len >> 2); + + /* cleanup any fractional write */ + if (len & 3) { + buf += len & ~3; + + for (; len & 3; len--, buf++) + writeb(*buf, host->base + NFDATA); + } +} +#endif + +/** + * Check the ECC and try to repair the data if possible + * @param[in] mtd_info Not used + * @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: This routine works always on a 24 bit ECC + */ +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) + 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; + +#ifdef CONFIG_CPU_S3C2410 + writel(readl(host->base + NFCONF) | NFCONF_INITECC , host->base + NFCONF); +#endif +#ifdef CONFIG_CPU_S3C2440 + writel(readl(host->base + NFCONT) | NFCONT_INITECC , host->base + NFCONT); +#endif +} + +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; + +#ifdef CONFIG_CPU_S3C2410 + ecc_code[0] = readb(host->base + NFECC); + ecc_code[1] = readb(host->base + NFECC + 1); + ecc_code[2] = readb(host->base + NFECC + 2); +#endif +#ifdef CONFIG_CPU_S3C2440 + unsigned long ecc = readl(host->base + NFECC); + + ecc_code[0] = ecc; + ecc_code[1] = ecc >> 8; + ecc_code[2] = ecc >> 16; +#endif + 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 s3c24x0_nand_platform_data *pdata = dev->platform_data; + 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_request_mem_region(dev, 0); + + /* structures must be linked */ + chip = &host->nand; + mtd = &host->mtd; + mtd->priv = chip; + + /* init the default settings */ + + /* 50 us command delay time */ + chip->chip_delay = 50; + chip->priv = host; + + chip->IO_ADDR_R = chip->IO_ADDR_W = host->base + NFDATA; + +#ifdef CONFIG_CPU_S3C2440 + chip->read_buf = s3c2440_nand_read_buf; + chip->write_buf = s3c2440_nand_write_buf; +#endif + 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; + + /* + * Setup ECC handling in accordance to the kernel + * - 1 times 512 bytes with 24 bit ECC for small page + * - 8 times 256 bytes with 24 bit ECC each for large page + */ + chip->ecc.mode = NAND_ECC_HW; + chip->ecc.bytes = 3; /* always 24 bit ECC per turn */ +#ifdef CONFIG_CPU_S3C2440 + if (readl(host->base) & 0x8) { + /* large page (2048 bytes per page) */ + chip->ecc.size = 256; + } else +#endif + { + /* small page (512 bytes per page) */ + chip->ecc.size = 512; + chip->ecc.layout = &nand_hw_eccoob; + } + + if (pdata->flash_bbt) { + /* use a flash based bbt */ + chip->options |= NAND_USE_FLASH_BBT; + } + + 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, "nand"); + +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(void __iomem *host) +{ + while (!(readw(host + NFSTAT) & NFSTAT_BUSY)) + ; +} + +/** + * Convert a page offset into a page address for the NAND + * @param host Where to write the address to + * @param offs Page's offset in the NAND + * @param ps Page size (512 or 2048) + * @param c Address cycle count (3, 4 or 5) + * + * Uses the offset of the page to generate an page address into the NAND. This + * differs when using a 512 byte or 2048 bytes per page NAND. + * The collumn part of the page address to be generated is always forced to '0'. + */ +static void __nand_boot_init nfc_addr(void __iomem *host, uint32_t offs, + int ps, int c) +{ + send_addr(host, 0); /* collumn part 1 */ + + if (ps == 512) { + send_addr(host, offs >> 9); + send_addr(host, offs >> 17); + if (c > 3) + send_addr(host, offs >> 25); + } else { + send_addr(host, 0); /* collumn part 2 */ + send_addr(host, offs >> 11); + send_addr(host, offs >> 19); + if (c > 4) + send_addr(host, offs >> 27); + send_cmd(host, NAND_CMD_READSTART); + } +} + +/** + * Load a sequential count of pages 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 + * + * This function must be located in the first 4kiB of the barebox image + * (guess why). + */ +void __nand_boot_init s3c24x0_nand_load_image(void *dest, int size, int page) +{ + void __iomem *host = (void __iomem *)S3C24X0_NAND_BASE; + unsigned pagesize; + int i, cycle; + + /* + * 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); + + /* use the current NAND hardware configuration */ + switch (readl(S3C24X0_NAND_BASE) & 0xf) { + case 0x6: /* 8 bit, 4 addr cycles, 512 bpp, normal NAND */ + pagesize = 512; + cycle = 4; + break; + case 0xc: /* 8 bit, 4 addr cycles, 2048 bpp, advanced NAND */ + pagesize = 2048; + cycle = 4; + break; + case 0xe: /* 8 bit, 5 addr cycles, 2048 bpp, advanced NAND */ + pagesize = 2048; + cycle = 5; + break; + default: + /* we cannot output an error message here :-( */ + disable_nand_controller(host); + return; + } + + 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, pagesize, cycle); + wait_for_completion(host); + /* copy one page (do *not* use readsb() here!)*/ + for (i = 0; i < pagesize; i++) + writeb(readb(host + NFDATA), (void __iomem *)(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; + + if (argc < 3) + return COMMAND_ERROR_USAGE; + + dest = (void *)strtoul_suffix(argv[1], NULL, 0); + size = strtoul_suffix(argv[2], NULL, 0); + + s3c24x0_nand_load_image(dest, size, 0); + + /* re-enable the controller again, as this was a test only */ + enable_nand_controller((void *)S3C24X0_NAND_BASE, + BOARD_DEFAULT_NAND_TIMING); + + 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); + +/** + * @file + * @brief Support for various kinds of NAND devices + * + * ECC handling in this driver (in accordance to the current 2.6.38 kernel): + * - for small page NANDs it generates 3 ECC bytes out of 512 data bytes + * - for large page NANDs it generates 24 ECC bytes out of 2048 data bytes + * + * As small page NANDs are using 48 bits ECC per default, this driver uses a + * local OOB layout description, to shrink it down to 24 bits. This is a bad + * idea, but we cannot change it here, as the kernel is using this layout. + * + * For large page NANDs this driver uses the default layout, as the kernel does. + */ diff --git a/drivers/mtd/nand/nand_swecc.c b/drivers/mtd/nand/nand_swecc.c index a5edffa..95dfbd8 100644 --- a/drivers/mtd/nand/nand_swecc.c +++ b/drivers/mtd/nand/nand_swecc.c @@ -57,7 +57,7 @@ * @chip: nand chip info structure * @buf: data buffer */ -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *buf) { @@ -85,7 +85,7 @@ chip->ecc.correct = nand_correct_data; chip->ecc.read_page = nand_read_page_swecc; chip->ecc.read_oob = nand_read_oob_std; -#ifdef CONFIG_NAND_WRITE +#ifdef CONFIG_MTD_WRITE chip->ecc.write_page = nand_write_page_swecc; chip->ecc.write_oob = nand_write_oob_std; #endif diff --git a/drivers/mtd/nand/nomadik_nand.c b/drivers/mtd/nand/nomadik_nand.c index c1e93ad..05d61c2 100644 --- a/drivers/mtd/nand/nomadik_nand.c +++ b/drivers/mtd/nand/nomadik_nand.c @@ -220,7 +220,7 @@ } pr_info("Registering %s as whole device\n", mtd->name); - add_mtd_device(mtd); + add_mtd_device(mtd, "nand"); return 0; diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 96ae16e..95bef1f 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -81,7 +81,7 @@ return err; } -static int ubi_volume_cdev_open(struct cdev *cdev) +static int ubi_volume_cdev_open(struct cdev *cdev, unsigned long flags) { struct ubi_volume_cdev_priv *priv = cdev->priv; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 19e35db..b236d17 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -46,8 +46,8 @@ This option enables support for the SMSC LAN91C111 ethernet chip. -config DRIVER_NET_DM9000 - bool "Davicom dm9000 ethernet driver" +config DRIVER_NET_DM9K + bool "Davicom dm9k[E|A|B] ethernet driver" depends on HAS_DM9000 select MIIDEV diff --git a/drivers/net/Makefile b/drivers/net/Makefile index f02618b..a84d3dc 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -1,7 +1,7 @@ obj-$(CONFIG_DRIVER_NET_CS8900) += cs8900.o obj-$(CONFIG_DRIVER_NET_SMC911X) += smc911x.o obj-$(CONFIG_DRIVER_NET_SMC91111) += smc91111.o -obj-$(CONFIG_DRIVER_NET_DM9000) += dm9000.o +obj-$(CONFIG_DRIVER_NET_DM9K) += dm9k.o obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c deleted file mode 100644 index f327781..0000000 --- a/drivers/net/dm9000.c +++ /dev/null @@ -1,564 +0,0 @@ -/* - * dm9000.c - * - * A Davicom DM9000 ISA NIC fast Ethernet driver for Linux. - * Copyright (C) 1997 Sten Wang - * - * 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. - * - * (C)Copyright 1997-1998 DAVICOM Semiconductor,Inc. All Rights Reserved. - * - * V0.11 06/20/2001 REG_0A bit3=1, default enable BP with DA match - * 06/22/2001 Support DM9801 progrmming - * E3: R25 = ((R24 + NF) & 0x00ff) | 0xf000 - * E4: R25 = ((R24 + NF) & 0x00ff) | 0xc200 - * R17 = (R17 & 0xfff0) | NF + 3 - * E5: R25 = ((R24 + NF - 3) & 0x00ff) | 0xc200 - * R17 = (R17 & 0xfff0) | NF - * - * v1.00 modify by simon 2001.9.5 - * change for kernel 2.4.x - * - * v1.1 11/09/2001 fix force mode bug - * - * v1.2 03/18/2003 Weilun Huang : - * Fixed phy reset. - * Added tx/rx 32 bit mode. - * Cleaned up for kernel merge. - * - * - * - * 12/15/2003 Initial port to barebox by Sascha Hauer - * - * - * ... see commit logs - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DM9000_ID 0x90000A46 -#define DM9000_PKT_MAX 1536 /* Received packet max size */ -#define DM9000_PKT_RDY 0x01 /* Packet ready to receive */ - -#define DM9000_NCR 0x00 -#define DM9000_NSR 0x01 -#define DM9000_TCR 0x02 -#define DM9000_TSR1 0x03 -#define DM9000_TSR2 0x04 -#define DM9000_RCR 0x05 -#define DM9000_RSR 0x06 -#define DM9000_ROCR 0x07 -#define DM9000_BPTR 0x08 -#define DM9000_FCTR 0x09 -#define DM9000_FCR 0x0A -#define DM9000_EPCR 0x0B -#define DM9000_EPAR 0x0C -#define DM9000_EPDRL 0x0D -#define DM9000_EPDRH 0x0E -#define DM9000_WCR 0x0F - -#define DM9000_PAR 0x10 -#define DM9000_MAR 0x16 - -#define DM9000_GPCR 0x1e -#define DM9000_GPR 0x1f -#define DM9000_TRPAL 0x22 -#define DM9000_TRPAH 0x23 -#define DM9000_RWPAL 0x24 -#define DM9000_RWPAH 0x25 - -#define DM9000_VIDL 0x28 -#define DM9000_VIDH 0x29 -#define DM9000_PIDL 0x2A -#define DM9000_PIDH 0x2B - -#define DM9000_CHIPR 0x2C -#define DM9000_SMCR 0x2F - -#define DM9000_PHY 0x40 /* PHY address 0x01 */ - -#define DM9000_MRCMDX 0xF0 -#define DM9000_MRCMD 0xF2 -#define DM9000_MRRL 0xF4 -#define DM9000_MRRH 0xF5 -#define DM9000_MWCMDX 0xF6 -#define DM9000_MWCMD 0xF8 -#define DM9000_MWRL 0xFA -#define DM9000_MWRH 0xFB -#define DM9000_TXPLL 0xFC -#define DM9000_TXPLH 0xFD -#define DM9000_ISR 0xFE -#define DM9000_IMR 0xFF - -#define NCR_EXT_PHY (1<<7) -#define NCR_WAKEEN (1<<6) -#define NCR_FCOL (1<<4) -#define NCR_FDX (1<<3) -#define NCR_LBK (3<<1) -#define NCR_RST (1<<0) - -#define NSR_SPEED (1<<7) -#define NSR_LINKST (1<<6) -#define NSR_WAKEST (1<<5) -#define NSR_TX2END (1<<3) -#define NSR_TX1END (1<<2) -#define NSR_RXOV (1<<1) - -#define TCR_TJDIS (1<<6) -#define TCR_EXCECM (1<<5) -#define TCR_PAD_DIS2 (1<<4) -#define TCR_CRC_DIS2 (1<<3) -#define TCR_PAD_DIS1 (1<<2) -#define TCR_CRC_DIS1 (1<<1) -#define TCR_TXREQ (1<<0) - -#define TSR_TJTO (1<<7) -#define TSR_LC (1<<6) -#define TSR_NC (1<<5) -#define TSR_LCOL (1<<4) -#define TSR_COL (1<<3) -#define TSR_EC (1<<2) - -#define RCR_WTDIS (1<<6) -#define RCR_DIS_LONG (1<<5) -#define RCR_DIS_CRC (1<<4) -#define RCR_ALL (1<<3) -#define RCR_RUNT (1<<2) -#define RCR_PRMSC (1<<1) -#define RCR_RXEN (1<<0) - -#define RSR_RF (1<<7) -#define RSR_MF (1<<6) -#define RSR_LCS (1<<5) -#define RSR_RWTO (1<<4) -#define RSR_PLE (1<<3) -#define RSR_AE (1<<2) -#define RSR_CE (1<<1) -#define RSR_FOE (1<<0) - -#define FCTR_HWOT(ot) (( ot & 0xf ) << 4 ) -#define FCTR_LWOT(ot) ( ot & 0xf ) - -#define IMR_PAR (1<<7) -#define IMR_ROOM (1<<3) -#define IMR_ROM (1<<2) -#define IMR_PTM (1<<1) -#define IMR_PRM (1<<0) - -struct dm9000_priv { - void __iomem *iobase; - void __iomem *iodata; - struct mii_device miidev; - int buswidth; - int srom; -}; - -#ifdef CONFIG_DM9000_DEBUG -static void -dump_regs(void) -{ - debug("\n"); - debug("NCR (0x00): %02x\n", DM9000_ior(0)); - debug("NSR (0x01): %02x\n", DM9000_ior(1)); - debug("TCR (0x02): %02x\n", DM9000_ior(2)); - debug("TSRI (0x03): %02x\n", DM9000_ior(3)); - debug("TSRII (0x04): %02x\n", DM9000_ior(4)); - debug("RCR (0x05): %02x\n", DM9000_ior(5)); - debug("RSR (0x06): %02x\n", DM9000_ior(6)); - debug("ISR (0xFE): %02x\n", DM9000_ior(ISR)); - debug("\n"); -} -#endif - -static u8 DM9000_ior(struct dm9000_priv *priv, int reg) -{ - writeb(reg, priv->iobase); - return readb(priv->iodata); -} - -static void DM9000_iow(struct dm9000_priv *priv, int reg, u8 value) -{ - writeb(reg, priv->iobase); - writeb(value, priv->iodata); -} - -static int dm9000_phy_read(struct mii_device *mdev, int addr, int reg) -{ - int val; - struct eth_device *edev = mdev->edev; - struct dm9000_priv *priv = edev->priv; - - /* Fill the phyxcer register into REG_0C */ - DM9000_iow(priv, DM9000_EPAR, DM9000_PHY | reg); - DM9000_iow(priv, DM9000_EPCR, 0xc); /* Issue phyxcer read command */ - udelay(100); /* Wait read complete */ - DM9000_iow(priv, DM9000_EPCR, 0x0); /* Clear phyxcer read command */ - val = (DM9000_ior(priv, DM9000_EPDRH) << 8) | DM9000_ior(priv, DM9000_EPDRL); - - /* The read data keeps on REG_0D & REG_0E */ - debug("phy_read(%d): %d\n", reg, val); - return val; -} - -static int dm9000_phy_write(struct mii_device *mdev, int addr, int reg, int val) -{ - struct eth_device *edev = mdev->edev; - struct dm9000_priv *priv = edev->priv; - - /* Fill the phyxcer register into REG_0C */ - DM9000_iow(priv, DM9000_EPAR, DM9000_PHY | reg); - - /* Fill the written data into REG_0D & REG_0E */ - DM9000_iow(priv, DM9000_EPDRL, (val & 0xff)); - DM9000_iow(priv, DM9000_EPDRH, ((val >> 8) & 0xff)); - DM9000_iow(priv, DM9000_EPCR, 0xa); /* Issue phyxcer write command */ - udelay(500); /* Wait write complete */ - DM9000_iow(priv, DM9000_EPCR, 0x0); /* Clear phyxcer write command */ - - debug("phy_write(reg:%d, value:%d)\n", reg, value); - - return 0; -} - -static int dm9000_check_id(struct dm9000_priv *priv) -{ - u32 id_val; - id_val = DM9000_ior(priv, DM9000_VIDL); - id_val |= DM9000_ior(priv, DM9000_VIDH) << 8; - id_val |= DM9000_ior(priv, DM9000_PIDL) << 16; - id_val |= DM9000_ior(priv, DM9000_PIDH) << 24; - if (id_val == DM9000_ID) { - printf("dm9000 i/o: 0x%p, id: 0x%x \n", priv->iobase, - id_val); - return 0; - } else { - printf("dm9000 not found at 0x%p id: 0x%08x\n", - priv->iobase, id_val); - return -1; - } -} - -static void dm9000_reset(struct dm9000_priv *priv) -{ - debug("resetting\n"); - DM9000_iow(priv, DM9000_NCR, NCR_RST); - udelay(1000); /* delay 1ms */ -} - -static int dm9000_eth_open(struct eth_device *edev) -{ - struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv; - - miidev_wait_aneg(&priv->miidev); - miidev_print_status(&priv->miidev); - return 0; -} - -static int dm9000_eth_send (struct eth_device *edev, - void *packet, int length) -{ - struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv; - char *data_ptr; - u32 tmplen, i; - uint64_t tmo; - - debug("eth_send: length: %d\n", length); - - for (i = 0; i < length; i++) { - if (i % 8 == 0) - debug("\nSend: 02x: ", i); - debug("%02x ", ((unsigned char *) packet)[i]); - } debug("\n"); - - /* Move data to DM9000 TX RAM */ - data_ptr = (char *) packet; - writeb(DM9000_MWCMD, priv->iobase); - - switch (priv->buswidth) { - case IORESOURCE_MEM_8BIT: - for (i = 0; i < length; i++) - writeb(data_ptr[i] & 0xff, priv->iodata); - break; - case IORESOURCE_MEM_16BIT: - tmplen = (length + 1) / 2; - for (i = 0; i < tmplen; i++) - writew(((u16 *)data_ptr)[i], priv->iodata); - break; - case IORESOURCE_MEM_32BIT: - tmplen = (length + 3) / 4; - for (i = 0; i < tmplen; i++) - writel(((u32 *) data_ptr)[i], priv->iodata); - break; - default: - /* dm9000_probe makes sure this cannot happen */ - return -EINVAL; - } - - /* Set TX length to DM9000 */ - DM9000_iow(priv, DM9000_TXPLL, length & 0xff); - DM9000_iow(priv, DM9000_TXPLH, (length >> 8) & 0xff); - - /* Issue TX polling command */ - DM9000_iow(priv, DM9000_TCR, TCR_TXREQ); /* Cleared after TX complete */ - - /* wait for end of transmission */ - tmo = get_time_ns(); - while (DM9000_ior(priv, DM9000_TCR) & TCR_TXREQ) { - if (is_timeout(tmo, 5 * SECOND)) { - printf("transmission timeout\n"); - break; - } - } - debug("transmit done\n\n"); - return 0; -} - -static void dm9000_eth_halt (struct eth_device *edev) -{ - debug("eth_halt\n"); -#if 0 - phy_write(0, 0x8000); /* PHY RESET */ - DM9000_iow(DM9000_GPR, 0x01); /* Power-Down PHY */ - DM9000_iow(DM9000_IMR, 0x80); /* Disable all interrupt */ - DM9000_iow(DM9000_RCR, 0x00); /* Disable RX */ -#endif -} - -static int dm9000_eth_rx (struct eth_device *edev) -{ - struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv; - u8 rxbyte, *rdptr = (u8 *) NetRxPackets[0]; - u16 RxStatus, RxLen = 0; - u32 tmplen, i; - u32 tmpdata; - - /* Check packet ready or not */ - DM9000_ior(priv, DM9000_MRCMDX); /* Dummy read */ - rxbyte = readb(priv->iodata); /* Got most updated data */ - if (rxbyte == 0) - return 0; - - /* Status check: this byte must be 0 or 1 */ - if (rxbyte > 1) { - DM9000_iow(priv, DM9000_RCR, 0x00); /* Stop Device */ - DM9000_iow(priv, DM9000_ISR, 0x80); /* Stop INT request */ - debug("rx status check: %d\n", rxbyte); - } - debug("receiving packet\n"); - - /* A packet ready now & Get status/length */ - writeb(DM9000_MRCMD, priv->iobase); - - /* Move data from DM9000 */ - /* Read received packet from RX SRAM */ - switch (priv->buswidth) { - case IORESOURCE_MEM_8BIT: - RxStatus = readb(priv->iodata) + (readb(priv->iodata) << 8); - RxLen = readb(priv->iodata) + (readb(priv->iodata) << 8); - for (i = 0; i < RxLen; i++) - rdptr[i] = readb(priv->iodata); - break; - case IORESOURCE_MEM_16BIT: - RxStatus = readw(priv->iodata); - RxLen = readw(priv->iodata); - tmplen = (RxLen + 1) / 2; - for (i = 0; i < tmplen; i++) - ((u16 *) rdptr)[i] = readw(priv->iodata); - break; - case IORESOURCE_MEM_32BIT: - tmpdata = readl(priv->iodata); - RxStatus = tmpdata; - RxLen = tmpdata >> 16; - tmplen = (RxLen + 3) / 4; - for (i = 0; i < tmplen; i++) - ((u32 *) rdptr)[i] = readl(priv->iodata); - break; - default: - /* dm9000_probe makes sure this cannot happen */ - return -EINVAL; - } - - if ((RxStatus & 0xbf00) || (RxLen < 0x40) - || (RxLen > DM9000_PKT_MAX)) { - if (RxStatus & 0x100) { - printf("rx fifo error\n"); - } - if (RxStatus & 0x200) { - printf("rx crc error\n"); - } - if (RxStatus & 0x8000) { - printf("rx length error\n"); - } - if (RxLen > DM9000_PKT_MAX) { - printf("rx length too big\n"); - dm9000_reset(priv); - } - } else { - - /* Pass to upper layer */ - debug("passing packet to upper layer\n"); - net_receive(NetRxPackets[0], RxLen); - return RxLen; - } - return 0; -} - -static u16 read_srom_word(struct dm9000_priv *priv, int offset) -{ - DM9000_iow(priv, DM9000_EPAR, offset); - DM9000_iow(priv, DM9000_EPCR, 0x4); - udelay(200); - DM9000_iow(priv, DM9000_EPCR, 0x0); - return (DM9000_ior(priv, DM9000_EPDRL) + (DM9000_ior(priv, DM9000_EPDRH) << 8)); -} - -static int dm9000_get_ethaddr(struct eth_device *edev, unsigned char *adr) -{ - struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv; - int i, oft; - - if (priv->srom) { - for (i = 0; i < 3; i++) - ((u16 *) adr)[i] = read_srom_word(priv, i); - } else { - for (i = 0, oft = 0x10; i < 6; i++, oft++) - adr[i] = DM9000_ior(priv, oft); - } - - return 0; -} - -static int dm9000_set_ethaddr(struct eth_device *edev, unsigned char *adr) -{ - struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv; - int i, oft; - - debug("%s\n", __FUNCTION__); - - for (i = 0, oft = 0x10; i < 6; i++, oft++) - DM9000_iow(priv, oft, adr[i]); - for (i = 0, oft = 0x16; i < 8; i++, oft++) - DM9000_iow(priv, oft, 0xff); - -#if 0 - for (i = 0; i < 5; i++) - printf ("%02x:", adr[i]); - printf ("%02x\n", adr[5]); -#endif - return 0; -} - -static int dm9000_init_dev(struct eth_device *edev) -{ - struct dm9000_priv *priv = (struct dm9000_priv *)edev->priv; - - miidev_restart_aneg(&priv->miidev); - return 0; -} - -static int dm9000_probe(struct device_d *dev) -{ - struct eth_device *edev; - struct dm9000_priv *priv; - struct dm9000_platform_data *pdata; - - debug("dm9000_eth_init()\n"); - - edev = xzalloc(sizeof(struct eth_device) + sizeof(struct dm9000_priv)); - dev->type_data = edev; - edev->priv = (struct dm9000_priv *)(edev + 1); - - if (!dev->platform_data) { - printf("dm9000: no platform_data\n"); - return -ENODEV; - } - - if (dev->num_resources < 2) { - printf("dm9000: need 2 resources base and data"); - return -ENODEV; - } - - pdata = dev->platform_data; - - priv = edev->priv; - - priv->buswidth = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; - priv->iodata = dev_request_mem_region(dev, 1); - priv->iobase = dev_request_mem_region(dev, 0); - priv->srom = pdata->srom; - - edev->init = dm9000_init_dev; - edev->open = dm9000_eth_open; - edev->send = dm9000_eth_send; - edev->recv = dm9000_eth_rx; - edev->halt = dm9000_eth_halt; - edev->set_ethaddr = dm9000_set_ethaddr; - edev->get_ethaddr = dm9000_get_ethaddr; - edev->parent = dev; - - /* RESET device */ - dm9000_reset(priv); - if(dm9000_check_id(priv)) - return -1; - - /* Program operating register */ - DM9000_iow(priv, DM9000_NCR, 0x0); /* only intern phy supported by now */ - DM9000_iow(priv, DM9000_TCR, 0); /* TX Polling clear */ - DM9000_iow(priv, DM9000_BPTR, 0x3f); /* Less 3Kb, 200us */ - DM9000_iow(priv, DM9000_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); /* Flow Control : High/Low Water */ - DM9000_iow(priv, DM9000_FCR, 0x0); /* SH FIXME: This looks strange! Flow Control */ - DM9000_iow(priv, DM9000_SMCR, 0); /* Special Mode */ - DM9000_iow(priv, DM9000_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); /* clear TX status */ - DM9000_iow(priv, DM9000_ISR, 0x0f); /* Clear interrupt status */ - - /* Activate DM9000 */ - DM9000_iow(priv, DM9000_GPCR, 0x01); /* Let GPIO0 output */ - DM9000_iow(priv, DM9000_GPR, 0x00); /* Enable PHY */ - DM9000_iow(priv, DM9000_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); /* RX enable */ - DM9000_iow(priv, DM9000_IMR, IMR_PAR); /* Enable TX/RX interrupt mask */ - - priv->miidev.read = dm9000_phy_read; - priv->miidev.write = dm9000_phy_write; - priv->miidev.address = 0; - priv->miidev.flags = 0; - priv->miidev.edev = edev; - priv->miidev.parent = dev; - - mii_register(&priv->miidev); - eth_register(edev); - - return 0; -} - -static struct driver_d dm9000_driver = { - .name = "dm9000", - .probe = dm9000_probe, -}; - -static int dm9000_init(void) -{ - register_driver(&dm9000_driver); - return 0; -} - -device_initcall(dm9000_init); - diff --git a/drivers/net/dm9k.c b/drivers/net/dm9k.c new file mode 100644 index 0000000..983edd4 --- /dev/null +++ b/drivers/net/dm9k.c @@ -0,0 +1,799 @@ +/* + * Copyright (C) 2011 Juergen Beisert, Pengutronix + * + * Davicom DM9000(E/A/B) NIC fast Ethernet driver for Barebox + * + * In some ways inspired by code + * + * Copyright (C) 1997 Sten Wang + * 1997-1998 DAVICOM Semiconductor,Inc. + * 2003 Weilun Huang + * 2003 + * + * 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. + */ + +#undef DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DM9K_ID 0x90000A46 +#define CHIPR_DM9000A 0x19 +#define CHIPR_DM9000B 0x1A + +#define DM9K_PKT_NONE 0x00 /* no packet received (end marker) */ +#define DM9K_PKT_RDY 0x01 /* packet ready to read */ +#define DM9K_PKT_ERR 0x02 /* chip error */ +#define DM9K_PKT_MAX 1536 /* packet max size */ + +#define DM9K_NCR 0x00 +# define NCR_EXT_PHY (1 << 7) +# define NCR_WAKEEN (1 << 6) +# define NCR_FCOL (1 << 4) +# define NCR_FDX (1 << 3) +# define NCR_LBK (3 << 1) +# define NCR_RST (1 << 0) + +#define DM9K_NSR 0x01 +# define NSR_SPEED (1 << 7) +# define NSR_LINKST (1 << 6) +# define NSR_WAKEST (1 << 5) +# define NSR_TX2END (1 << 3) +# define NSR_TX1END (1 << 2) +# define NSR_RXOV (1 << 1) + +#define DM9K_TCR 0x02 +# define TCR_TJDIS (1 << 6) +# define TCR_EXCECM (1 << 5) +# define TCR_PAD_DIS2 (1 << 4) +# define TCR_CRC_DIS2 (1 << 3) +# define TCR_PAD_DIS1 (1 << 2) +# define TCR_CRC_DIS1 (1 << 1) +# define TCR_TXREQ (1 << 0) + +#define DM9K_TSR1 0x03 +#define DM9K_TSR2 0x04 +# define TSR_TJTO (1 << 7) +# define TSR_LC (1 << 6) +# define TSR_NC (1 << 5) +# define TSR_LCOL (1 << 4) +# define TSR_COL (1 << 3) +# define TSR_EC (1 << 2) + +#define DM9K_RCR 0x05 +# define RCR_WTDIS (1 << 6) +# define RCR_DIS_LONG (1 << 5) +# define RCR_DIS_CRC (1 << 4) +# define RCR_ALL (1 << 3) +# define RCR_RUNT (1 << 2) +# define RCR_PRMSC (1 << 1) +# define RCR_RXEN (1 << 0) + +#define DM9K_RSR 0x06 +# define RSR_RF (1 << 7) +# define RSR_MF (1 << 6) +# define RSR_LCS (1 << 5) +# define RSR_RWTO (1 << 4) +# define RSR_PLE (1 << 3) +# define RSR_AE (1 << 2) +# define RSR_CE (1 << 1) +# define RSR_FOE (1 << 0) +# define RSR_ERR_MASK (RSR_FOE | RSR_CE | RSR_AE | RSR_PLE | RSR_RWTO | RSR_LCS | RSR_RF) + +#define DM9K_ROCR 0x07 +#define DM9K_BPTR 0x08 +#define DM9K_FCTR 0x09 +#define DM9K_FCR 0x0A +#define DM9K_EPCR 0x0B +#define DM9K_EPAR 0x0C +#define DM9K_EPDRL 0x0D +#define DM9K_EPDRH 0x0E +#define DM9K_WCR 0x0F + +#define DM9K_PAR 0x10 +#define DM9K_MAR 0x16 + +#define DM9K_GPCR 0x1e +#define DM9K_GPR 0x1f +#define DM9K_TRPAL 0x22 +#define DM9K_TRPAH 0x23 +#define DM9K_RWPAL 0x24 +#define DM9K_RWPAH 0x25 + +#define DM9K_VIDL 0x28 +#define DM9K_VIDH 0x29 +#define DM9K_PIDL 0x2A +#define DM9K_PIDH 0x2B + +#define DM9K_CHIPR 0x2C +#define DM9K_SMCR 0x2F + +#define DM9K_PHY 0x40 /* PHY address 0x01 */ + +#define DM9K_MRCMDX 0xF0 +#define DM9K_MRCMD 0xF2 +#define DM9K_MRRL 0xF4 +#define DM9K_MRRH 0xF5 +#define DM9K_MWCMDX 0xF6 +#define DM9K_MWCMD 0xF8 +#define DM9K_MWRL 0xFA +#define DM9K_MWRH 0xFB +#define DM9K_TXPLL 0xFC +#define DM9K_TXPLH 0xFD + +#define DM9K_ISR 0xFE +# define ISR_IOM0 (1 << 7) /* 0: 16 bit, 1: 8 bit*/ +# define ISR_LNKCHG (1 << 5) /* link status change */ +# define ISR_UDRUN (1 << 4) /* transmit underrun */ +# define ISR_ROO (1 << 3) /* receive overflow counter overflow */ +# define ISR_ROS (1 << 2) /* receive overflow */ +# define ISR_PT (1 << 1) /* packet transmitted */ +# define ISR_PR (1 << 0) /* packet received */ +# define ISR_CLEAR_MASK (ISR_PR | ISR_PT | ISR_ROS | ISR_ROO | ISR_UDRUN | ISR_LNKCHG) + +#define DM9K_IMR 0xFF +# define IMR_PAR (1 << 7) +# define IMR_ROOM (1 << 3) +# define IMR_ROM (1 << 2) +# define IMR_PTM (1 << 1) +# define IMR_PRM (1 << 0) + +#define FCTR_HWOT(ot) (( ot & 0xf ) << 4 ) +#define FCTR_LWOT(ot) ( ot & 0xf ) + +struct dm9k { + void __iomem *iobase; + void __iomem *iodata; + struct mii_device miidev; + int buswidth; + int srom; + uint8_t pckt[2048]; +}; + +/* ------------------ register access functions -------------------------- */ + +static uint8_t dm9k_ior(struct dm9k *priv, int reg) +{ + writeb(reg, priv->iobase); + return readb(priv->iodata); +} + +static void dm9k_iow(struct dm9k *priv, int reg, uint8_t value) +{ + writeb(reg, priv->iobase); + writeb(value, priv->iodata); +} + +/* ------------------- data move functions ---------------------------- */ + +static void dm9k_wd_8(void __iomem *port, const void *src, int length) +{ + const uint8_t *from = (const uint8_t *)src; + + while (length--) + writeb(*from++, port); +} + +static void dm9k_rd_8(void __iomem *port, void *dst, unsigned length) +{ + uint8_t *to = (uint8_t *)dst; + + while (length--) + *to++ = readb(port); +} + +static void dm9k_dump_8(void __iomem *port, unsigned length) +{ + while (length--) + readb(port); +} + +static unsigned dm9k_read_packet_status_8(void __iomem *port, unsigned *status) +{ + uint16_t st, le; + + dm9k_rd_8(port, &st, sizeof(st)); + dm9k_rd_8(port, &le, sizeof(le)); + + *status = st >> 8; + return le; +} + +static void dm9k_wd_16(void __iomem *port, const void *src, int length) +{ + const uint16_t *from = (const uint16_t *)src; + + length += 1; + length /= 2; + while (length--) + writew(*from++, port); +} + +static void dm9k_rd_16(void __iomem *port, void *dst, unsigned length) +{ + uint16_t *to = (uint16_t *)dst; + + length += 1; + length >>= 1; + while (length--) + *to++ = readw(port); +} + +static void dm9k_dump_16(void __iomem *port, unsigned length) +{ + length += 1; + length >>= 1; + while (length--) + readw(port); +} + +static unsigned dm9k_read_packet_status_16(void __iomem *port, unsigned *status) +{ + *status = readw(port) >> 8; + return le16_to_cpu(readw(port)); +} + +static void dm9k_wd_32(void __iomem *port, const void *src, int length) +{ + const uint32_t *from = (const uint32_t *)src; + + length += 3; + length /= 4; + while (length--) + writel(*from++, port); +} + +static void dm9k_rd_32(void __iomem *port, void *dst, unsigned length) +{ + uint32_t *to = (uint32_t *)dst; + + length += 3; + length >>= 2; + while (length--) + *to++ = readl(port); +} + +static void dm9k_dump_32(void __iomem *port, unsigned length) +{ + length += 3; + length >>= 2; + while (length--) + readl(port); +} + +static unsigned dm9k_read_packet_status_32(void __iomem *port, unsigned *status) +{ + uint32_t tmp = readl(port); + + *status = (tmp >> 8) & 0xff; + return tmp >> 16; +} + +static unsigned dm9k_read_packet_status(int b_width, void __iomem *port, unsigned *status) +{ + unsigned rc; + + switch (b_width) { + case IORESOURCE_MEM_8BIT: + rc = dm9k_read_packet_status_8(port, status); + break; + case IORESOURCE_MEM_16BIT: + rc = dm9k_read_packet_status_16(port, status); + break; + case IORESOURCE_MEM_32BIT: + rc = dm9k_read_packet_status_32(port, status); + break; + default: + rc = -EINVAL; + } + + return rc; +} + +static void dm9k_dump(int b_width, void __iomem *port, unsigned length) +{ + switch (b_width) { + case IORESOURCE_MEM_8BIT: + dm9k_dump_8(port, length); + break; + case IORESOURCE_MEM_16BIT: + dm9k_dump_16(port, length); + break; + case IORESOURCE_MEM_32BIT: + dm9k_dump_32(port, length); + break; + } +} + +static void dm9k_rd(int b_width, void __iomem *port, void *dst, unsigned length) +{ + switch (b_width) { + case IORESOURCE_MEM_8BIT: + dm9k_rd_8(port, dst, length); + break; + case IORESOURCE_MEM_16BIT: + dm9k_rd_16(port, dst, length); + break; + case IORESOURCE_MEM_32BIT: + dm9k_rd_32(port, dst, length); + break; + } +} + +static void dm9k_wd(int b_width, void __iomem *port, const void *src, int length) +{ + switch (b_width) { + case IORESOURCE_MEM_8BIT: + dm9k_wd_8(port, src, length); + break; + case IORESOURCE_MEM_16BIT: + dm9k_wd_16(port, src, length); + break; + case IORESOURCE_MEM_32BIT: + dm9k_wd_32(port, src, length); + break; + } +} + +/* ----------------- end of data move functions -------------------------- */ + +static int dm9k_phy_read(struct mii_device *mdev, int addr, int reg) +{ + unsigned val; + struct eth_device *edev = mdev->edev; + struct device_d *dev = edev->parent; + struct dm9k *priv = edev->priv; + + /* Fill the phyxcer register into REG_0C */ + dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg); + dm9k_iow(priv, DM9K_EPCR, 0xc); /* Issue phyxcer read command */ + udelay(100); /* Wait read complete */ + dm9k_iow(priv, DM9K_EPCR, 0x0); /* Clear phyxcer read command */ + val = dm9k_ior(priv, DM9K_EPDRH); + val <<= 8; + val |= dm9k_ior(priv, DM9K_EPDRL); + + /* The read data keeps on REG_0D & REG_0E */ + dev_dbg(dev, "phy_read(%d): %d\n", reg, val); + return val; +} + +static int dm9k_phy_write(struct mii_device *mdev, int addr, int reg, int val) +{ + struct eth_device *edev = mdev->edev; + struct device_d *dev = edev->parent; + struct dm9k *priv = edev->priv; + + /* Fill the phyxcer register into REG_0C */ + dm9k_iow(priv, DM9K_EPAR, DM9K_PHY | reg); + + /* Fill the written data into REG_0D & REG_0E */ + dm9k_iow(priv, DM9K_EPDRL, val); + dm9k_iow(priv, DM9K_EPDRH, val >> 8); + dm9k_iow(priv, DM9K_EPCR, 0xa); /* Issue phyxcer write command */ + udelay(500); /* Wait write complete */ + dm9k_iow(priv, DM9K_EPCR, 0x0); /* Clear phyxcer write command */ + + dev_dbg(dev, "phy_write(reg:%d, value:%d)\n", reg, val); + + return 0; +} + +static int dm9k_check_id(struct dm9k *priv) +{ + struct device_d *dev = priv->miidev.parent; + u32 id; + char c; + + id = dm9k_ior(priv, DM9K_VIDL); + id |= dm9k_ior(priv, DM9K_VIDH) << 8; + id |= dm9k_ior(priv, DM9K_PIDL) << 16; + id |= dm9k_ior(priv, DM9K_PIDH) << 24; + + if (id != DM9K_ID) { + dev_err(dev, "dm9000 not found at 0x%p id: 0x%08x\n", + priv->iobase, id); + return -ENODEV; + } + + id = dm9k_ior(priv, DM9K_CHIPR); + dev_dbg(dev, "dm9000 revision 0x%02x\n", id); + + switch (id) { + case CHIPR_DM9000A: + c = 'A'; + break; + case CHIPR_DM9000B: + c = 'B'; + break; + default: + c = 'E'; + } + dev_info(dev, "Found DM9000%c at i/o: 0x%p\n", c, priv->iobase); + + return 0; +} + +static void dm9k_enable(struct dm9k *priv) +{ + /* only intern phy supported by now */ + dm9k_iow(priv, DM9K_NCR, 0x00); + /* TX Polling clear */ + dm9k_iow(priv, DM9K_TCR, 0x00); + /* Less 3Kb, 200us */ + dm9k_iow(priv, DM9K_BPTR, 0x3f); + /* Flow Control : High/Low Water */ + dm9k_iow(priv, DM9K_FCTR, FCTR_HWOT(3) | FCTR_LWOT(8)); + /* SH FIXME: This looks strange! Flow Control */ + dm9k_iow(priv, DM9K_FCR, 0x00); + /* Special Mode */ + dm9k_iow(priv, DM9K_SMCR, 0x00); + /* clear TX status */ + dm9k_iow(priv, DM9K_NSR, NSR_WAKEST | NSR_TX2END | NSR_TX1END); + /* Clear interrupt status */ + dm9k_iow(priv, DM9K_IMR, IMR_PAR); + dm9k_iow(priv, DM9K_ISR, ISR_CLEAR_MASK); + + /* Activate DM9000 */ + dm9k_iow(priv, DM9K_GPCR, 0x01); /* Let GPIO0 output */ + dm9k_iow(priv, DM9K_GPR, 0x00); /* Enable PHY */ + /* RX enable */ + dm9k_iow(priv, DM9K_RCR, RCR_DIS_LONG | RCR_DIS_CRC | RCR_RXEN); + /* Enable TX/RX interrupt mask */ + dm9k_iow(priv, DM9K_IMR, IMR_PAR | IMR_PRM | IMR_PTM); +} + +static void dm9k_reset(struct dm9k *priv) +{ + struct device_d *dev = priv->miidev.parent; + + dev_dbg(dev, "%s\n", __func__); + dm9k_iow(priv, DM9K_NCR, NCR_RST); + udelay(1000); /* delay 1ms */ +} + +static int dm9k_eth_open(struct eth_device *edev) +{ + struct dm9k *priv = (struct dm9k *)edev->priv; + + miidev_wait_aneg(&priv->miidev); + miidev_print_status(&priv->miidev); + return 0; +} + +static void dm9k_write_length(struct dm9k *priv, unsigned length) +{ + dm9k_iow(priv, DM9K_TXPLL, length); + dm9k_iow(priv, DM9K_TXPLH, length >> 8); +} + +static int dm9k_wait_for_trans_end(struct dm9k *priv) +{ + struct device_d *dev = priv->miidev.parent; + static const uint64_t toffs = 1 * SECOND; + uint8_t status; + uint64_t start = get_time_ns(); + + do { + status = dm9k_ior(priv, DM9K_NSR); + if (status & (NSR_TX1END | NSR_TX2END)) { + dev_dbg(dev, "transmit done\n"); + return 0; + } + status = dm9k_ior(priv, DM9K_ISR); + if (status & IMR_PTM) { + /* Clear Tx bit in ISR */ + dm9k_iow(priv, DM9K_ISR, IMR_PTM); + dev_dbg(dev, "transmit done\n"); + return 0; + } + } while (!is_timeout(start, toffs)); + + return -ETIMEDOUT; +} + +static int dm9k_eth_send(struct eth_device *edev, void *packet, int length) +{ + struct dm9k *priv = (struct dm9k *)edev->priv; + struct device_d *dev = priv->miidev.parent; + + dev_dbg(dev, "%s: %d bytes\n", __func__, length); + + /* arm the Tx bit */ + dm9k_iow(priv, DM9K_ISR, IMR_PTM); + + /* Prepare for TX-data */ + writeb(DM9K_MWCMD, priv->iobase); + + /* Move the packet into the DM9k's TX RAM */ + dm9k_wd(priv->buswidth, priv->iodata, packet, length); + + /* Set TX length of the packet */ + dm9k_write_length(priv, length); + + /* Issue TX polling command */ + dm9k_iow(priv, DM9K_TCR, TCR_TXREQ); /* Cleared after TX complete */ + + /* wait for end of transmission */ + return dm9k_wait_for_trans_end(priv); +} + +static int dm9k_check_for_rx_packet(struct dm9k *priv) +{ + uint8_t status; + struct device_d *dev = priv->miidev.parent; + + status = dm9k_ior(priv, DM9K_ISR); + if (!(status & ISR_PR)) + return 0; /* no packet */ + + dev_dbg(dev, "Packet present\n"); + dm9k_iow(priv, DM9K_ISR, ISR_PR); /* clear PR status latched in bit 0 */ + return 1; /* packet present */ +} + +static int dm9k_validate_entry(struct dm9k *priv) +{ + struct device_d *dev = priv->miidev.parent; + + uint8_t p_stat; + /* + * setup read pointer to current packet + * but without address increment + */ + dm9k_ior(priv, DM9K_MRCMDX); + + /* read the entry's status according to the app note */ + p_stat = readb(priv->iodata) & 0x03; + dev_dbg(dev, "%s packet status %02X\n", __func__, p_stat); + + switch (p_stat) { + case DM9K_PKT_NONE: /* there is no packet (or the last in the chain) */ + return 0; + + case DM9K_PKT_ERR: /* chip in invalid state. Needs a software reset */ + dev_dbg(dev, "Confused chip.\n"); + dm9k_iow(priv, DM9K_RCR, 0x00); /* Stop Device */ + dm9k_iow(priv, DM9K_ISR, 0x80); /* Stop INT request */ + dm9k_reset(priv); + dm9k_enable(priv); + return 0; + } + + return 1; /* entry is valid */ +} + +static int dm9k_eth_rx(struct eth_device *edev) +{ + struct dm9k *priv = (struct dm9k *)edev->priv; + struct device_d *dev = edev->parent; + unsigned rx_stat = 0, rx_len = 0; + bool p_valid; + + if (dm9k_check_for_rx_packet(priv) == 0) + return 0; /* no data present */ + + do { + if (!dm9k_validate_entry(priv)) + return 0; + + /* assume this packet is valid */ + p_valid = true; + + /* read with automatic address increment now */ + writeb(DM9K_MRCMD, priv->iobase); + rx_len = dm9k_read_packet_status(priv->buswidth, priv->iodata, &rx_stat); + if (rx_len < 0x40) { + dev_dbg(dev, "Packet too short (%u bytes)\n", rx_len); + p_valid = false; + } + + /* validate packet */ + if (rx_stat & RSR_ERR_MASK) { + if (rx_stat & RSR_FOE) + dev_warn(dev, "rx fifo overflow error\n"); + if (rx_stat & RSR_CE) + dev_warn(dev, "rx crc error\n"); + if (rx_stat & RSR_AE) + dev_warn(dev, "rx Alignment Error error\n"); + if (rx_stat & RSR_PLE) + dev_warn(dev, "rx Physical Layer Error error\n"); + if (rx_stat & RSR_RWTO) + dev_warn(dev, "rx Receive Watchdog Time Out error\n"); + if (rx_stat & RSR_LCS) + dev_warn(dev, "rx Late Collision Seen error\n"); + if (rx_stat & RSR_RF) + dev_warn(dev, "rx length error (runt frame)\n"); + p_valid = false; + } + + if (rx_len > DM9K_PKT_MAX) { + dev_warn(dev, "rx length too big\n"); + /* discard packet */ + dm9k_dump(priv->buswidth, priv->iodata, rx_len); + dm9k_reset(priv); + dm9k_enable(priv); + return 0; + } + + if (p_valid == true) { + dev_dbg(dev, "Receiving packet\n"); + dm9k_rd(priv->buswidth, priv->iodata, priv->pckt, rx_len); + dev_dbg(dev, "passing %u bytes packet to upper layer\n", rx_len); + net_receive(priv->pckt, rx_len); + } else { + dev_dbg(dev, "Discarding packet\n"); + dm9k_dump(priv->buswidth, priv->iodata, rx_len); /* discard packet */ + } + } while (1); + + return 0; +} + + +static void dm9k_eth_halt(struct eth_device *edev) +{ + struct dm9k *priv = (struct dm9k *)edev->priv; + + dm9k_iow(priv, DM9K_GPR, 0x01); /* Power-Down PHY */ + dm9k_iow(priv, DM9K_IMR, 0x80); /* Disable all interrupt */ + dm9k_iow(priv, DM9K_RCR, 0x00); /* Disable RX */ +} + +static u16 read_srom_word(struct dm9k *priv, int offset) +{ + dm9k_iow(priv, DM9K_EPAR, offset); + dm9k_iow(priv, DM9K_EPCR, 0x4); + udelay(200); + dm9k_iow(priv, DM9K_EPCR, 0x0); + return (dm9k_ior(priv, DM9K_EPDRL) + (dm9k_ior(priv, DM9K_EPDRH) << 8)); +} + +static int dm9k_get_ethaddr(struct eth_device *edev, unsigned char *adr) +{ + struct dm9k *priv = (struct dm9k *)edev->priv; + int i, oft; + + if (priv->srom) { + for (i = 0; i < 3; i++) + ((u16 *) adr)[i] = read_srom_word(priv, i); + } else { + for (i = 0, oft = DM9K_PAR; i < 6; i++, oft++) + adr[i] = dm9k_ior(priv, oft); + } + + return 0; +} + +static int dm9k_set_ethaddr(struct eth_device *edev, unsigned char *adr) +{ + struct dm9k *priv = (struct dm9k *)edev->priv; + int i, oft; + + for (i = 0, oft = DM9K_PAR; i < 6; i++, oft++) + dm9k_iow(priv, oft, adr[i]); + for (i = 0, oft = DM9K_MAR; i < 8; i++, oft++) + dm9k_iow(priv, oft, 0xff); + + return 0; +} + +static int dm9k_init_dev(struct eth_device *edev) +{ + struct dm9k *priv = (struct dm9k *)edev->priv; + + miidev_restart_aneg(&priv->miidev); + return 0; +} + +static int dm9k_probe(struct device_d *dev) +{ + unsigned io_mode; + struct eth_device *edev; + struct dm9k *priv; + struct dm9000_platform_data *pdata; + + if (!dev->platform_data) { + dev_err(dev, "No platform_data\n"); + return -ENODEV; + } + + if (dev->num_resources < 2) { + dev_err(dev, "Need 2 resources base and data"); + return -ENODEV; + } + + edev = xzalloc(sizeof(struct eth_device) + sizeof(struct dm9k)); + dev->type_data = edev; + edev->priv = (struct dm9k *)(edev + 1); + + pdata = dev->platform_data; + + priv = edev->priv; + + priv->buswidth = dev->resource[0].flags & IORESOURCE_MEM_TYPE_MASK; + priv->iodata = dev_request_mem_region(dev, 1); + priv->iobase = dev_request_mem_region(dev, 0); + priv->srom = pdata->srom; + + edev->init = dm9k_init_dev; + edev->open = dm9k_eth_open; + edev->send = dm9k_eth_send; + edev->recv = dm9k_eth_rx; + edev->halt = dm9k_eth_halt; + edev->set_ethaddr = dm9k_set_ethaddr; + edev->get_ethaddr = dm9k_get_ethaddr; + edev->parent = dev; + + priv->miidev.read = dm9k_phy_read; + priv->miidev.write = dm9k_phy_write; + priv->miidev.address = 0; + priv->miidev.flags = 0; + priv->miidev.edev = edev; + priv->miidev.parent = dev; + + /* RESET device */ + dm9k_reset(priv); + if(dm9k_check_id(priv)) + return -ENODEV; + + io_mode = dm9k_ior(priv, DM9K_ISR) >> 6; + switch (io_mode) { + case 0: + dev_dbg(dev, "16 bit data bus\n"); + if (priv->buswidth != IORESOURCE_MEM_16BIT) + dev_err(dev, + "Wrong databus width defined at compile time\n"); + break; + case 1: + dev_dbg(dev, "32 bit data bus\n"); + if (priv->buswidth != IORESOURCE_MEM_32BIT) + dev_err(dev, + "Wrong databus width defined at compile time\n"); + break; + case 2: + dev_dbg(dev, "8 bit data bus\n"); + if (priv->buswidth != IORESOURCE_MEM_32BIT) + dev_err(dev, + "Wrong databus width defined at compile time\n"); + break; + default: + dev_warn(dev, "Unknown data width\n"); + } + + dm9k_enable(priv); + + mii_register(&priv->miidev); + eth_register(edev); + + return 0; +} + +static struct driver_d dm9k_driver = { + .name = "dm9000", + .probe = dm9k_probe, +}; + +static int dm9k_init(void) +{ + register_driver(&dm9k_driver); + return 0; +} + +device_initcall(dm9k_init); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 592d543..186b596 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -78,16 +78,16 @@ help Enable this to get support for AMBA PL010 based serial devices -config DRIVER_SERIAL_S3C24X0 - bool "Samsung S3C24X0 serial driver" +config DRIVER_SERIAL_S3C + bool "Samsung S3C serial driver" depends on ARCH_S3C24xx default y help - Say Y here if you want to use the CONS on a S3C24X0 CPU + Say Y here if you want to use the CONS on a Samsung S3C CPU -config DRIVER_SERIAL_S3C24X0_AUTOSYNC +config DRIVER_SERIAL_S3C_AUTOSYNC bool "Enable auto flow" - depends on DRIVER_SERIAL_S3C24X0 + depends on DRIVER_SERIAL_S3C help Say Y here if you want to use the auto flow feature of this UART. RTS and CTS will be handled by the hardware when enabled. diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index a702125..e2d56b9 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_DRIVER_SERIAL_BLACKFIN) += serial_blackfin.o obj-$(CONFIG_DRIVER_SERIAL_NS16550) += serial_ns16550.o obj-$(CONFIG_DRIVER_SERIAL_PL010) += serial_pl010.o -obj-$(CONFIG_DRIVER_SERIAL_S3C24X0) += serial_s3c24x0.o +obj-$(CONFIG_DRIVER_SERIAL_S3C) += serial_s3c.o obj-$(CONFIG_DRIVER_SERIAL_ALTERA) += serial_altera.o obj-$(CONFIG_DRIVER_SERIAL_ALTERA_JTAG) += serial_altera_jtag.o obj-$(CONFIG_DRIVER_SERIAL_PXA) += serial_pxa.o diff --git a/drivers/serial/serial_s3c.c b/drivers/serial/serial_s3c.c new file mode 100644 index 0000000..b7e0987 --- /dev/null +++ b/drivers/serial/serial_s3c.c @@ -0,0 +1,188 @@ +/* + * (c) 2009...2011 Juergen Beisert + * + * Based on code from: + * (c) 2004 Sascha Hauer + * + * 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 + +/* Note: Offsets are for little endian access */ +#define ULCON 0x00 /* line control */ +#define UCON 0x04 /* UART control */ +#define UFCON 0x08 /* FIFO control */ +#define UMCON 0x0c /* modem control */ +#define UTRSTAT 0x10 /* Rx/Tx status */ +#define UERSTAT 0x14 /* error status */ +#define UFSTAT 0x18 /* FIFO status */ +#define UMSTAT 0x1c /* modem status */ +#define UTXH 0x20 /* transmitt */ +#define URXH 0x24 /* receive */ +#define UBRDIV 0x28 /* baudrate generator */ + +static unsigned s3c_get_arch_uart_input_clock(void __iomem *base) +{ + unsigned reg = readw(base + UCON); + + switch (reg & 0xc00) { + case 0x000: + case 0x800: + return s3c_get_pclk(); + case 0x400: + break; /* TODO UEXTCLK */ + case 0xc00: + break; /* TODO FCLK/n */ + } + + return 0; /* not nice, but we can't emit an error message! */ +} + +static int s3c_serial_setbaudrate(struct console_device *cdev, int baudrate) +{ + struct device_d *dev = cdev->dev; + void __iomem *base = dev->priv; + unsigned val; + + val = s3c_get_arch_uart_input_clock(base) / (16 * baudrate) - 1; + writew(val, base + UBRDIV); + + return 0; +} + +static int s3c_serial_init_port(struct console_device *cdev) +{ + struct device_d *dev = cdev->dev; + void __iomem *base = dev->priv; + + /* FIFO enable, Tx/Rx FIFO clear */ + writeb(0x07, base + UFCON); + writeb(0x00, base + UMCON); + + /* Normal,No parity,1 stop,8 bit */ + writeb(0x03, base + ULCON); + /* + * tx=level,rx=edge,disable timeout int.,enable rx error int., + * normal,interrupt or polling + */ + writew(0x0245, base + UCON); + +#ifdef CONFIG_DRIVER_SERIAL_S3C_AUTOSYNC + writeb(0x10, base + UMCON); /* enable auto flow control */ +#else + writeb(0x01, base + UMCON); /* RTS up */ +#endif + + return 0; +} + +static void s3c_serial_putc(struct console_device *cdev, char c) +{ + struct device_d *dev = cdev->dev; + void __iomem *base = dev->priv; + + /* Wait for Tx FIFO not full */ + while (!(readb(base + UTRSTAT) & 0x2)) + ; + + writeb(c, base + UTXH); +} + +static int s3c_serial_tstc(struct console_device *cdev) +{ + struct device_d *dev = cdev->dev; + void __iomem *base = dev->priv; + + /* If receive fifo is empty, return false */ + if (readb(base + UTRSTAT) & 0x1) + return 1; + + return 0; +} + +static int s3c_serial_getc(struct console_device *cdev) +{ + struct device_d *dev = cdev->dev; + void __iomem *base = dev->priv; + + /* wait for a character */ + while (!(readb(base + UTRSTAT) & 0x1)) + ; + + return readb(base + URXH); +} + +static void s3c_serial_flush(struct console_device *cdev) +{ + struct device_d *dev = cdev->dev; + void __iomem *base = dev->priv; + + while (!(readb(base + UTRSTAT) & 0x4)) + ; +} + +static int s3c_serial_probe(struct device_d *dev) +{ + struct console_device *cdev; + + cdev = xzalloc(sizeof(struct console_device)); + dev->type_data = cdev; + dev->priv = dev_request_mem_region(dev, 0); + cdev->dev = dev; + cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; + cdev->tstc = s3c_serial_tstc; + cdev->putc = s3c_serial_putc; + cdev->getc = s3c_serial_getc; + cdev->flush = s3c_serial_flush; + cdev->setbrg = s3c_serial_setbaudrate; + + s3c_serial_init_port(cdev); + + /* Enable UART */ + console_register(cdev); + + return 0; +} + +static void s3c_serial_remove(struct device_d *dev) +{ + struct console_device *cdev = dev->type_data; + + s3c_serial_flush(cdev); + free(cdev); + dev->type_data = NULL; +} + +static struct driver_d s3c_serial_driver = { + .name = "s3c_serial", + .probe = s3c_serial_probe, + .remove = s3c_serial_remove, +}; + +static int s3c_serial_init(void) +{ + register_driver(&s3c_serial_driver); + return 0; +} + +console_initcall(s3c_serial_init); diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c deleted file mode 100644 index 1e27d48..0000000 --- a/drivers/serial/serial_s3c24x0.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * (c) 2009 Juergen Beisert - * - * Based on code from: - * (c) 2004 Sascha Hauer - * - * 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 - -/* Note: Offsets are for little endian access */ -#define ULCON 0x00 /* line control */ -#define UCON 0x04 /* UART control */ -#define UFCON 0x08 /* FIFO control */ -#define UMCON 0x0c /* modem control */ -#define UTRSTAT 0x10 /* Rx/Tx status */ -#define UERSTAT 0x14 /* error status */ -#define UFSTAT 0x18 /* FIFO status */ -#define UMSTAT 0x1c /* modem status */ -#define UTXH 0x20 /* transmitt */ -#define URXH 0x24 /* receive */ -#define UBRDIV 0x28 /* baudrate generator */ - -static int s3c24x0_serial_setbaudrate(struct console_device *cdev, int baudrate) -{ - struct device_d *dev = cdev->dev; - void __iomem *base = dev->priv; - unsigned val; - - /* value is calculated so : PCLK / (16 * baudrate) -1 */ - val = s3c24xx_get_pclk() / (16 * baudrate) - 1; - writew(val, base + UBRDIV); - - return 0; -} - -static int s3c24x0_serial_init_port(struct console_device *cdev) -{ - struct device_d *dev = cdev->dev; - void __iomem *base = dev->priv; - - /* FIFO enable, Tx/Rx FIFO clear */ - writeb(0x07, base + UFCON); - writeb(0x00, base + UMCON); - - /* Normal,No parity,1 stop,8 bit */ - writeb(0x03, base + ULCON); - /* - * tx=level,rx=edge,disable timeout int.,enable rx error int., - * normal,interrupt or polling - */ - writew(0x0245, base + UCON); - -#ifdef CONFIG_DRIVER_SERIAL_S3C24X0_AUTOSYNC - writeb(0x10, base + UMCON); /* enable auto flow control */ -#else - writeb(0x01, base + UMCON); /* RTS up */ -#endif - - return 0; -} - -static void s3c24x0_serial_putc(struct console_device *cdev, char c) -{ - struct device_d *dev = cdev->dev; - void __iomem *base = dev->priv; - - /* Wait for Tx FIFO not full */ - while (!(readb(base + UTRSTAT) & 0x2)) - ; - - writeb(c, base + UTXH); -} - -static int s3c24x0_serial_tstc(struct console_device *cdev) -{ - struct device_d *dev = cdev->dev; - void __iomem *base = dev->priv; - - /* If receive fifo is empty, return false */ - if (readb(base + UTRSTAT) & 0x1) - return 1; - - return 0; -} - -static int s3c24x0_serial_getc(struct console_device *cdev) -{ - struct device_d *dev = cdev->dev; - void __iomem *base = dev->priv; - - /* wait for a character */ - while (!(readb(base + UTRSTAT) & 0x1)) - ; - - return readb(base + URXH); -} - -static void s3c24x0_serial_flush(struct console_device *cdev) -{ - struct device_d *dev = cdev->dev; - void __iomem *base = dev->priv; - - while (!(readb(base + UTRSTAT) & 0x4)) - ; -} - -static int s3c24x0_serial_probe(struct device_d *dev) -{ - struct console_device *cdev; - - cdev = xzalloc(sizeof(struct console_device)); - dev->type_data = cdev; - dev->priv = dev_request_mem_region(dev, 0); - cdev->dev = dev; - cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; - cdev->tstc = s3c24x0_serial_tstc; - cdev->putc = s3c24x0_serial_putc; - cdev->getc = s3c24x0_serial_getc; - cdev->flush = s3c24x0_serial_flush; - cdev->setbrg = s3c24x0_serial_setbaudrate; - - s3c24x0_serial_init_port(cdev); - - /* Enable UART */ - console_register(cdev); - - return 0; -} - -static void s3c24x0_serial_remove(struct device_d *dev) -{ - struct console_device *cdev = dev->type_data; - - s3c24x0_serial_flush(cdev); - free(cdev); - dev->type_data = NULL; -} - -static struct driver_d s3c24x0_serial_driver = { - .name = "s3c24x0_serial", - .probe = s3c24x0_serial_probe, - .remove = s3c24x0_serial_remove, -}; - -static int s3c24x0_serial_init(void) -{ - register_driver(&s3c24x0_serial_driver); - return 0; -} - -console_initcall(s3c24x0_serial_init); diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 472c591..797d19f 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -15,6 +15,13 @@ depends on ARCH_IMX select USB_GADGET_DUALSPEED +config USB_GADGET_DRIVER_AT91 + bool + prompt "at91 gadget driver" + depends on ARCH_AT91 + select USB_GADGET_DUALSPEED + select POLLER + config USB_GADGET_DRIVER_PXA27X bool prompt "PXA27x gadget driver" @@ -23,8 +30,7 @@ select POLLER endchoice -choice - prompt "USB Gadget drivers" +comment "USB Gadget drivers" config USB_GADGET_DFU bool @@ -35,7 +41,5 @@ depends on EXPERIMENTAL prompt "Serial Gadget" -endchoice - endif diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index e034786..367d7ce 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -3,4 +3,5 @@ obj-$(CONFIG_USB_GADGET_SERIAL) += u_serial.o serial.o f_serial.o f_acm.o obj-$(CONFIG_USB_GADGET_DFU) += dfu.o obj-$(CONFIG_USB_GADGET_DRIVER_ARC) += fsl_udc.o +obj-$(CONFIG_USB_GADGET_DRIVER_AT91) += at91_udc.o obj-$(CONFIG_USB_GADGET_DRIVER_PXA27X) += pxa27x_udc.o diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c new file mode 100644 index 0000000..bb0d614 --- /dev/null +++ b/drivers/usb/gadget/at91_udc.c @@ -0,0 +1,1538 @@ +/* + * at91_udc -- driver for at91-series USB peripheral controller + * + * Copyright (C) 2004 by Thomas Rathbone + * Copyright (C) 2005 by HP Labs + * Copyright (C) 2005 by David Brownell + * + * 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. + */ + +#undef VERBOSE_DEBUG +#undef PACKET_TRACE + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "at91_udc.h" + + +/* + * This controller is simple and PIO-only. It's used in many AT91-series + * full speed USB controllers, including the at91rm9200 (arm920T, with MMU), + * at91sam926x (arm926ejs, with MMU), and several no-mmu versions. + * + * This driver expects the board has been wired with two GPIOs suppporting + * a VBUS sensing IRQ, and a D+ pullup. (They may be omitted, but the + * testing hasn't covered such cases.) + * + * The pullup is most important (so it's integrated on sam926x parts). It + * provides software control over whether the host enumerates the device. + * + * The VBUS sensing helps during enumeration, and allows both USB clocks + * (and the transceiver) to stay gated off until they're necessary, saving + * power. During USB suspend, the 48 MHz clock is gated off in hardware; + * it may also be gated off by software during some Linux sleep states. + */ + +#define DRIVER_VERSION "3 May 2006" + +#define driver_name "at91_udc" +static const char ep0name[] = "ep0"; + +#define at91_udp_read(udc, reg) \ + __raw_readl((udc)->udp_baseaddr + (reg)) +#define at91_udp_write(udc, reg, val) \ + __raw_writel((val), (udc)->udp_baseaddr + (reg)) + +/*-------------------------------------------------------------------------*/ + +static void done(struct at91_ep *ep, struct at91_request *req, int status) +{ + unsigned stopped = ep->stopped; + struct at91_udc *udc = ep->udc; + + list_del_init(&req->queue); + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + if (status && status != -ESHUTDOWN) + VDBG(udc, "%s done %p, status %d\n", ep->ep.name, req, status); + + ep->stopped = 1; + req->req.complete(&ep->ep, &req->req); + ep->stopped = stopped; + + /* ep0 is always ready; other endpoints need a non-empty queue */ + if (list_empty(&ep->queue) && ep->int_mask != (1 << 0)) + at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask); +} + +/*-------------------------------------------------------------------------*/ + +/* bits indicating OUT fifo has data ready */ +#define RX_DATA_READY (AT91_UDP_RX_DATA_BK0 | AT91_UDP_RX_DATA_BK1) + +/* + * Endpoint FIFO CSR bits have a mix of bits, making it unsafe to just write + * back most of the value you just read (because of side effects, including + * bits that may change after reading and before writing). + * + * Except when changing a specific bit, always write values which: + * - clear SET_FX bits (setting them could change something) + * - set CLR_FX bits (clearing them could change something) + * + * There are also state bits like FORCESTALL, EPEDS, DIR, and EPTYPE + * that shouldn't normally be changed. + * + * NOTE at91sam9260 docs mention synch between UDPCK and MCK clock domains, + * implying a need to wait for one write to complete (test relevant bits) + * before starting the next write. This shouldn't be an issue given how + * infrequently we write, except maybe for write-then-read idioms. + */ +#define SET_FX (AT91_UDP_TXPKTRDY) +#define CLR_FX (RX_DATA_READY | AT91_UDP_RXSETUP \ + | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP) + +/* pull OUT packet data from the endpoint's fifo */ +static int read_fifo (struct at91_ep *ep, struct at91_request *req) +{ + u32 __iomem *creg = ep->creg; + u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); + u32 csr; + u8 *buf; + unsigned int count, bufferspace, is_done; + + buf = req->req.buf + req->req.actual; + bufferspace = req->req.length - req->req.actual; + + /* + * there might be nothing to read if ep_queue() calls us, + * or if we already emptied both pingpong buffers + */ +rescan: + csr = __raw_readl(creg); + if ((csr & RX_DATA_READY) == 0) + return 0; + + count = (csr & AT91_UDP_RXBYTECNT) >> 16; + if (count > ep->ep.maxpacket) + count = ep->ep.maxpacket; + if (count > bufferspace) { + DBG(ep->udc, "%s buffer overflow\n", ep->ep.name); + req->req.status = -EOVERFLOW; + count = bufferspace; + } + readsb(dreg, buf, count); + + /* release and swap pingpong mem bank */ + csr |= CLR_FX; + if (ep->is_pingpong) { + if (ep->fifo_bank == 0) { + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); + ep->fifo_bank = 1; + } else { + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK1); + ep->fifo_bank = 0; + } + } else + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); + __raw_writel(csr, creg); + + req->req.actual += count; + is_done = (count < ep->ep.maxpacket); + if (count == bufferspace) + is_done = 1; + + PACKET("%s %p out/%d%s\n", ep->ep.name, &req->req, count, + is_done ? " (done)" : ""); + + /* + * avoid extra trips through IRQ logic for packets already in + * the fifo ... maybe preventing an extra (expensive) OUT-NAK + */ + if (is_done) + done(ep, req, 0); + else if (ep->is_pingpong) { + /* + * One dummy read to delay the code because of a HW glitch: + * CSR returns bad RXCOUNT when read too soon after updating + * RX_DATA_BK flags. + */ + csr = __raw_readl(creg); + + bufferspace -= count; + buf += count; + goto rescan; + } + + return is_done; +} + +/* load fifo for an IN packet */ +static int write_fifo(struct at91_ep *ep, struct at91_request *req) +{ + u32 __iomem *creg = ep->creg; + u32 csr = __raw_readl(creg); + u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); + unsigned total, count, is_last; + u8 *buf; + + /* + * TODO: allow for writing two packets to the fifo ... that'll + * reduce the amount of IN-NAKing, but probably won't affect + * throughput much. (Unlike preventing OUT-NAKing!) + */ + + /* + * If ep_queue() calls us, the queue is empty and possibly in + * odd states like TXCOMP not yet cleared (we do it, saving at + * least one IRQ) or the fifo not yet being free. Those aren't + * issues normally (IRQ handler fast path). + */ + if (unlikely(csr & (AT91_UDP_TXCOMP | AT91_UDP_TXPKTRDY))) { + if (csr & AT91_UDP_TXCOMP) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_TXCOMP); + __raw_writel(csr, creg); + csr = __raw_readl(creg); + } + if (csr & AT91_UDP_TXPKTRDY) + return 0; + } + + buf = req->req.buf + req->req.actual; + total = req->req.length - req->req.actual; + if (ep->ep.maxpacket < total) { + count = ep->ep.maxpacket; + is_last = 0; + } else { + count = total; + is_last = (count < ep->ep.maxpacket) || !req->req.zero; + } + + /* + * Write the packet, maybe it's a ZLP. + * + * NOTE: incrementing req->actual before we receive the ACK means + * gadget driver IN bytecounts can be wrong in fault cases. That's + * fixable with PIO drivers like this one (save "count" here, and + * do the increment later on TX irq), but not for most DMA hardware. + * + * So all gadget drivers must accept that potential error. Some + * hardware supports precise fifo status reporting, letting them + * recover when the actual bytecount matters (e.g. for USB Test + * and Measurement Class devices). + */ + writesb(dreg, buf, count); + csr &= ~SET_FX; + csr |= CLR_FX | AT91_UDP_TXPKTRDY; + writel(csr, creg); + req->req.actual += count; + + PACKET("%s %p in/%d%s\n", ep->ep.name, &req->req, count, + is_last ? " (done)" : ""); + if (is_last) + done(ep, req, 0); + return is_last; +} + +static void nuke(struct at91_ep *ep, int status) +{ + struct at91_request *req; + + /* terminate any request in the queue */ + ep->stopped = 1; + if (list_empty(&ep->queue)) + return; + + VDBG(udc, "%s %s\n", __func__, ep->ep.name); + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct at91_request, queue); + done(ep, req, status); + } +} + +/*-------------------------------------------------------------------------*/ + +static int at91_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *udc = ep->udc; + u16 maxpacket; + u32 tmp; + + if (!_ep || !ep + || !desc || ep->desc + || _ep->name == ep0name + || desc->bDescriptorType != USB_DT_ENDPOINT + || (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0 + || maxpacket > ep->maxpacket) { + DBG(udc, "bad ep or descriptor\n"); + return -EINVAL; + } + + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { + DBG(udc, "bogus device state\n"); + return -ESHUTDOWN; + } + + tmp = usb_endpoint_type(desc); + switch (tmp) { + case USB_ENDPOINT_XFER_CONTROL: + DBG(udc, "only one control endpoint\n"); + return -EINVAL; + case USB_ENDPOINT_XFER_INT: + if (maxpacket > 64) + goto bogus_max; + break; + case USB_ENDPOINT_XFER_BULK: + switch (maxpacket) { + case 8: + case 16: + case 32: + case 64: + goto ok; + } +bogus_max: + DBG(udc, "bogus maxpacket %d\n", maxpacket); + return -EINVAL; + case USB_ENDPOINT_XFER_ISOC: + if (!ep->is_pingpong) { + DBG(udc, "iso requires double buffering\n"); + return -EINVAL; + } + break; + } + +ok: + + /* initialize endpoint to match this descriptor */ + ep->is_in = usb_endpoint_dir_in(desc); + ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC); + ep->stopped = 0; + if (ep->is_in) + tmp |= 0x04; + tmp <<= 8; + tmp |= AT91_UDP_EPEDS; + __raw_writel(tmp, ep->creg); + + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + /* + * reset/init endpoint fifo. NOTE: leaves fifo_bank alone, + * since endpoint resets don't reset hw pingpong state. + */ + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); + + return 0; +} + +static int at91_ep_disable (struct usb_ep * _ep) +{ + struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *udc = ep->udc; + + if (ep == &ep->udc->ep[0]) + return -EINVAL; + + nuke(ep, -ESHUTDOWN); + + /* restore the endpoint's pristine config */ + ep->desc = NULL; + ep->ep.maxpacket = ep->maxpacket; + + /* reset fifos and endpoint */ + if (ep->udc->clocked) { + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); + __raw_writel(0, ep->creg); + } + + return 0; +} + +/* + * this is a PIO-only driver, so there's nothing + * interesting for request or buffer allocation. + */ + +static struct usb_request * +at91_ep_alloc_request(struct usb_ep *_ep) +{ + struct at91_request *req; + + req = xzalloc(sizeof *req); + + INIT_LIST_HEAD(&req->queue); + return &req->req; +} + +static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) +{ + struct at91_request *req; + + req = container_of(_req, struct at91_request, req); + BUG_ON(!list_empty(&req->queue)); + kfree(req); +} + +static int at91_ep_queue(struct usb_ep *_ep, + struct usb_request *_req) +{ + struct at91_request *req; + struct at91_ep *ep; + struct at91_udc *udc; + int status; + + req = container_of(_req, struct at91_request, req); + ep = container_of(_ep, struct at91_ep, ep); + + if (!_req || !_req->complete + || !_req->buf || !list_empty(&req->queue)) { + DBG(udc, "invalid request\n"); + return -EINVAL; + } + + if (!_ep || (!ep->desc && ep->ep.name != ep0name)) { + DBG(udc, "invalid ep\n"); + return -EINVAL; + } + + udc = ep->udc; + + if (!udc || !udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) { + DBG(udc, "invalid device\n"); + return -EINVAL; + } + + _req->status = -EINPROGRESS; + _req->actual = 0; + + /* try to kickstart any empty and idle queue */ + if (list_empty(&ep->queue) && !ep->stopped) { + int is_ep0; + + /* + * If this control request has a non-empty DATA stage, this + * will start that stage. It works just like a non-control + * request (until the status stage starts, maybe early). + * + * If the data stage is empty, then this starts a successful + * IN/STATUS stage. (Unsuccessful ones use set_halt.) + */ + is_ep0 = (ep->ep.name == ep0name); + if (is_ep0) { + u32 tmp; + + if (!udc->req_pending) { + status = -EINVAL; + goto done; + } + + /* + * defer changing CONFG until after the gadget driver + * reconfigures the endpoints. + */ + if (udc->wait_for_config_ack) { + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); + tmp ^= AT91_UDP_CONFG; + VDBG(udc, "toggle config\n"); + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); + } + if (req->req.length == 0) { +ep0_in_status: + PACKET("ep0 in/status\n"); + status = 0; + tmp = __raw_readl(ep->creg); + tmp &= ~SET_FX; + tmp |= CLR_FX | AT91_UDP_TXPKTRDY; + __raw_writel(tmp, ep->creg); + udc->req_pending = 0; + goto done; + } + } + + if (ep->is_in) + status = write_fifo(ep, req); + else { + status = read_fifo(ep, req); + + /* IN/STATUS stage is otherwise triggered by irq */ + if (status && is_ep0) + goto ep0_in_status; + } + } else + status = 0; + + if (req && !status) { + list_add_tail (&req->queue, &ep->queue); + } +done: + return (status < 0) ? status : 0; +} + +static int at91_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct at91_ep *ep; + struct at91_request *req; + + ep = container_of(_ep, struct at91_ep, ep); + if (!_ep || ep->ep.name == ep0name) + return -EINVAL; + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry (req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + return -EINVAL; + } + + done(ep, req, -ECONNRESET); + return 0; +} + +static int at91_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct at91_ep *ep = container_of(_ep, struct at91_ep, ep); + struct at91_udc *udc = ep->udc; + u32 __iomem *creg; + u32 csr; + int status = 0; + + if (!_ep || ep->is_iso || !ep->udc->clocked) + return -EINVAL; + + creg = ep->creg; + + csr = __raw_readl(creg); + + /* + * fail with still-busy IN endpoints, ensuring correct sequencing + * of data tx then stall. note that the fifo rx bytecount isn't + * completely accurate as a tx bytecount. + */ + if (ep->is_in && (!list_empty(&ep->queue) || (csr >> 16) != 0)) + status = -EAGAIN; + else { + csr |= CLR_FX; + csr &= ~SET_FX; + if (value) { + csr |= AT91_UDP_FORCESTALL; + VDBG(udc, "halt %s\n", ep->ep.name); + } else { + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); + csr &= ~AT91_UDP_FORCESTALL; + } + __raw_writel(csr, creg); + } + + return status; +} + +static const struct usb_ep_ops at91_ep_ops = { + .enable = at91_ep_enable, + .disable = at91_ep_disable, + .alloc_request = at91_ep_alloc_request, + .free_request = at91_ep_free_request, + .queue = at91_ep_queue, + .dequeue = at91_ep_dequeue, + .set_halt = at91_ep_set_halt, + /* there's only imprecise fifo status reporting */ +}; + +/*-------------------------------------------------------------------------*/ + +static int at91_get_frame(struct usb_gadget *gadget) +{ + struct at91_udc *udc = to_udc(gadget); + + if (!to_udc(gadget)->clocked) + return -EINVAL; + return at91_udp_read(udc, AT91_UDP_FRM_NUM) & AT91_UDP_NUM; +} + +static int at91_wakeup(struct usb_gadget *gadget) +{ + struct at91_udc *udc = to_udc(gadget); + u32 glbstate; + int status = -EINVAL; + + DBG(udc, "%s\n", __func__ ); + + if (!udc->clocked || !udc->suspended) + goto done; + + /* NOTE: some "early versions" handle ESR differently ... */ + + glbstate = at91_udp_read(udc, AT91_UDP_GLB_STAT); + if (!(glbstate & AT91_UDP_ESR)) + goto done; + glbstate |= AT91_UDP_ESR; + at91_udp_write(udc, AT91_UDP_GLB_STAT, glbstate); + +done: + return status; +} + +/* reinit == restore initial software state */ +static void udc_reinit(struct at91_udc *udc) +{ + u32 i; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct at91_ep *ep = &udc->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + ep->desc = NULL; + ep->stopped = 0; + ep->fifo_bank = 0; + ep->ep.maxpacket = ep->maxpacket; + ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i); + /* initialize one queue per endpoint */ + INIT_LIST_HEAD(&ep->queue); + } +} + +static void stop_activity(struct at91_udc *udc) +{ + struct usb_gadget_driver *driver = udc->driver; + int i; + + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->suspended = 0; + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct at91_ep *ep = &udc->ep[i]; + ep->stopped = 1; + nuke(ep, -ESHUTDOWN); + } + if (driver) { + driver->disconnect(&udc->gadget); + } + + udc_reinit(udc); +} + +static void clk_on(struct at91_udc *udc) +{ + if (udc->clocked) + return; + udc->clocked = 1; + clk_enable(udc->iclk); + clk_enable(udc->fclk); +} + +static void clk_off(struct at91_udc *udc) +{ + if (!udc->clocked) + return; + udc->clocked = 0; + udc->gadget.speed = USB_SPEED_UNKNOWN; + clk_disable(udc->fclk); + clk_disable(udc->iclk); +} + +/* + * activate/deactivate link with host; minimize power usage for + * inactive links by cutting clocks and transceiver power. + */ +static void pullup(struct at91_udc *udc, int is_on) +{ + int active = !udc->board.pullup_active_low; + + if (!udc->enabled || !udc->vbus) + is_on = 0; + DBG(udc, "%sactive\n", is_on ? "" : "in"); + + if (is_on) { + clk_on(udc); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_TXVC, 0); + if (cpu_is_at91rm9200()) + gpio_set_value(udc->board.pullup_pin, active); + else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc |= AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { + u32 usbpucr; + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr |= AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } + } else { + stop_activity(udc); + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + if (cpu_is_at91rm9200()) + gpio_set_value(udc->board.pullup_pin, !active); + else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) { + u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC); + + txvc &= ~AT91_UDP_TXVC_PUON; + at91_udp_write(udc, AT91_UDP_TXVC, txvc); + } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { + u32 usbpucr; + usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR); + usbpucr &= ~AT91_MATRIX_USBPUCR_PUON; + at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr); + } + clk_off(udc); + } +} + +/* vbus is here! turn everything on that's ready */ +static int at91_vbus_session(struct usb_gadget *gadget, int is_active) +{ + struct at91_udc *udc = to_udc(gadget); + + /* VDBG(udc, "vbus %s\n", is_active ? "on" : "off"); */ + udc->vbus = (is_active != 0); + if (udc->driver) + pullup(udc, is_active); + else + pullup(udc, 0); + return 0; +} + +static int at91_pullup(struct usb_gadget *gadget, int is_on) +{ + struct at91_udc *udc = to_udc(gadget); + + udc->enabled = is_on = !!is_on; + pullup(udc, is_on); + return 0; +} + +static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) +{ + struct at91_udc *udc = to_udc(gadget); + + udc->selfpowered = (is_on != 0); + return 0; +} + +static const struct usb_gadget_ops at91_udc_ops = { + .get_frame = at91_get_frame, + .wakeup = at91_wakeup, + .set_selfpowered = at91_set_selfpowered, + .vbus_session = at91_vbus_session, + .pullup = at91_pullup, + + /* + * VBUS-powered devices may also also want to support bigger + * power budgets after an appropriate SET_CONFIGURATION. + */ + /* .vbus_power = at91_vbus_power, */ +}; + +/*-------------------------------------------------------------------------*/ + +static int handle_ep(struct at91_ep *ep) +{ + struct at91_request *req; + u32 __iomem *creg = ep->creg; + u32 csr = __raw_readl(creg); + + if (!list_empty(&ep->queue)) + req = list_entry(ep->queue.next, + struct at91_request, queue); + else + req = NULL; + + if (ep->is_in) { + if (csr & (AT91_UDP_STALLSENT | AT91_UDP_TXCOMP)) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_TXCOMP); + __raw_writel(csr, creg); + } + if (req) + return write_fifo(ep, req); + + } else { + if (csr & AT91_UDP_STALLSENT) { + /* STALLSENT bit == ISOERR */ + if (ep->is_iso && req) + req->req.status = -EILSEQ; + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_STALLSENT); + __raw_writel(csr, creg); + csr = __raw_readl(creg); + } + if (req && (csr & RX_DATA_READY)) + return read_fifo(ep, req); + } + return 0; +} + +union setup { + u8 raw[8]; + struct usb_ctrlrequest r; +}; + +static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) +{ + u32 __iomem *creg = ep->creg; + u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0)); + unsigned rxcount, i = 0; + u32 tmp; + union setup pkt; + int status = 0; + + /* read and ack SETUP; hard-fail for bogus packets */ + rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16; + if (likely(rxcount == 8)) { + while (rxcount--) + pkt.raw[i++] = __raw_readb(dreg); + if (pkt.r.bRequestType & USB_DIR_IN) { + csr |= AT91_UDP_DIR; + ep->is_in = 1; + } else { + csr &= ~AT91_UDP_DIR; + ep->is_in = 0; + } + } else { + /* REVISIT this happens sometimes under load; why?? */ + ERR(udc, "SETUP len %d, csr %08x\n", rxcount, csr); + status = -EINVAL; + } + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_RXSETUP); + __raw_writel(csr, creg); + udc->wait_for_addr_ack = 0; + udc->wait_for_config_ack = 0; + ep->stopped = 0; + if (unlikely(status != 0)) + goto stall; + +#define w_index le16_to_cpu(pkt.r.wIndex) +#define w_value le16_to_cpu(pkt.r.wValue) +#define w_length le16_to_cpu(pkt.r.wLength) + + VDBG(udc, "SETUP %02x.%02x v%04x i%04x l%04x\n", + pkt.r.bRequestType, pkt.r.bRequest, + w_value, w_index, w_length); + + /* + * A few standard requests get handled here, ones that touch + * hardware ... notably for device and endpoint features. + */ + udc->req_pending = 1; + csr = __raw_readl(creg); + csr |= CLR_FX; + csr &= ~SET_FX; + switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) { + + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_SET_ADDRESS: + __raw_writel(csr | AT91_UDP_TXPKTRDY, creg); + udc->addr = w_value; + udc->wait_for_addr_ack = 1; + udc->req_pending = 0; + /* FADDR is set later, when we ack host STATUS */ + return; + + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_SET_CONFIGURATION: + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG; + if (pkt.r.wValue) + udc->wait_for_config_ack = (tmp == 0); + else + udc->wait_for_config_ack = (tmp != 0); + if (udc->wait_for_config_ack) + VDBG(udc, "wait for config\n"); + /* CONFG is toggled later, if gadget driver succeeds */ + break; + + /* + * Hosts may set or clear remote wakeup status, and + * devices may report they're VBUS powered. + */ + case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_GET_STATUS: + tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED); + if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR) + tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP); + PACKET("get device status\n"); + __raw_writeb(tmp, dreg); + __raw_writeb(0, dreg); + goto write_in; + /* then STATUS starts later, automatically */ + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_SET_FEATURE: + if (w_value != USB_DEVICE_REMOTE_WAKEUP) + goto stall; + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); + tmp |= AT91_UDP_ESR; + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); + goto succeed; + case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8) + | USB_REQ_CLEAR_FEATURE: + if (w_value != USB_DEVICE_REMOTE_WAKEUP) + goto stall; + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); + tmp &= ~AT91_UDP_ESR; + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); + goto succeed; + + /* + * Interfaces have no feature settings; this is pretty useless. + * we won't even insist the interface exists... + */ + case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) + | USB_REQ_GET_STATUS: + PACKET("get interface status\n"); + __raw_writeb(0, dreg); + __raw_writeb(0, dreg); + goto write_in; + /* then STATUS starts later, automatically */ + case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) + | USB_REQ_SET_FEATURE: + case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8) + | USB_REQ_CLEAR_FEATURE: + goto stall; + + /* + * Hosts may clear bulk/intr endpoint halt after the gadget + * driver sets it (not widely used); or set it (for testing) + */ + case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) + | USB_REQ_GET_STATUS: + tmp = w_index & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc)) + goto stall; + + if (tmp) { + if ((w_index & USB_DIR_IN)) { + if (!ep->is_in) + goto stall; + } else if (ep->is_in) + goto stall; + } + PACKET("get %s status\n", ep->ep.name); + if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL) + tmp = (1 << USB_ENDPOINT_HALT); + else + tmp = 0; + __raw_writeb(tmp, dreg); + __raw_writeb(0, dreg); + goto write_in; + /* then STATUS starts later, automatically */ + case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) + | USB_REQ_SET_FEATURE: + tmp = w_index & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) + goto stall; + if (!ep->desc || ep->is_iso) + goto stall; + if ((w_index & USB_DIR_IN)) { + if (!ep->is_in) + goto stall; + } else if (ep->is_in) + goto stall; + + tmp = __raw_readl(ep->creg); + tmp &= ~SET_FX; + tmp |= CLR_FX | AT91_UDP_FORCESTALL; + __raw_writel(tmp, ep->creg); + goto succeed; + case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8) + | USB_REQ_CLEAR_FEATURE: + tmp = w_index & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) + goto stall; + if (tmp == 0) + goto succeed; + if (!ep->desc || ep->is_iso) + goto stall; + if ((w_index & USB_DIR_IN)) { + if (!ep->is_in) + goto stall; + } else if (ep->is_in) + goto stall; + + at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask); + at91_udp_write(udc, AT91_UDP_RST_EP, 0); + tmp = __raw_readl(ep->creg); + tmp |= CLR_FX; + tmp &= ~(SET_FX | AT91_UDP_FORCESTALL); + __raw_writel(tmp, ep->creg); + if (!list_empty(&ep->queue)) + handle_ep(ep); + goto succeed; + } + +#undef w_value +#undef w_index +#undef w_length + + /* pass request up to the gadget driver */ + if (udc->driver) { + status = udc->driver->setup(&udc->gadget, &pkt.r); + } + else + status = -ENODEV; + if (status < 0) { +stall: + VDBG(udc, "req %02x.%02x protocol STALL; stat %d\n", + pkt.r.bRequestType, pkt.r.bRequest, status); + csr |= AT91_UDP_FORCESTALL; + __raw_writel(csr, creg); + udc->req_pending = 0; + } + return; + +succeed: + /* immediate successful (IN) STATUS after zero length DATA */ + PACKET("ep0 in/status\n"); +write_in: + csr |= AT91_UDP_TXPKTRDY; + __raw_writel(csr, creg); + udc->req_pending = 0; +} + +static void handle_ep0(struct at91_udc *udc) +{ + struct at91_ep *ep0 = &udc->ep[0]; + u32 __iomem *creg = ep0->creg; + u32 csr = __raw_readl(creg); + struct at91_request *req; + + if (unlikely(csr & AT91_UDP_STALLSENT)) { + nuke(ep0, -EPROTO); + udc->req_pending = 0; + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_STALLSENT | AT91_UDP_FORCESTALL); + __raw_writel(csr, creg); + VDBG(udc, "ep0 stalled\n"); + csr = __raw_readl(creg); + } + if (csr & AT91_UDP_RXSETUP) { + nuke(ep0, 0); + udc->req_pending = 0; + handle_setup(udc, ep0, csr); + return; + } + + if (list_empty(&ep0->queue)) + req = NULL; + else + req = list_entry(ep0->queue.next, struct at91_request, queue); + + /* host ACKed an IN packet that we sent */ + if (csr & AT91_UDP_TXCOMP) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_TXCOMP); + + /* write more IN DATA? */ + if (req && ep0->is_in) { + if (handle_ep(ep0)) + udc->req_pending = 0; + + /* + * Ack after: + * - last IN DATA packet (including GET_STATUS) + * - IN/STATUS for OUT DATA + * - IN/STATUS for any zero-length DATA stage + * except for the IN DATA case, the host should send + * an OUT status later, which we'll ack. + */ + } else { + udc->req_pending = 0; + __raw_writel(csr, creg); + + /* + * SET_ADDRESS takes effect only after the STATUS + * (to the original address) gets acked. + */ + if (udc->wait_for_addr_ack) { + u32 tmp; + + at91_udp_write(udc, AT91_UDP_FADDR, + AT91_UDP_FEN | udc->addr); + tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT); + tmp &= ~AT91_UDP_FADDEN; + if (udc->addr) + tmp |= AT91_UDP_FADDEN; + at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp); + + udc->wait_for_addr_ack = 0; + VDBG(udc, "address %d\n", udc->addr); + } + } + } + + /* OUT packet arrived ... */ + else if (csr & AT91_UDP_RX_DATA_BK0) { + csr |= CLR_FX; + csr &= ~(SET_FX | AT91_UDP_RX_DATA_BK0); + + /* OUT DATA stage */ + if (!ep0->is_in) { + if (req) { + if (handle_ep(ep0)) { + /* send IN/STATUS */ + PACKET("ep0 in/status\n"); + csr = __raw_readl(creg); + csr &= ~SET_FX; + csr |= CLR_FX | AT91_UDP_TXPKTRDY; + __raw_writel(csr, creg); + udc->req_pending = 0; + } + } else if (udc->req_pending) { + /* + * AT91 hardware has a hard time with this + * "deferred response" mode for control-OUT + * transfers. (For control-IN it's fine.) + * + * The normal solution leaves OUT data in the + * fifo until the gadget driver is ready. + * We couldn't do that here without disabling + * the IRQ that tells about SETUP packets, + * e.g. when the host gets impatient... + * + * Working around it by copying into a buffer + * would almost be a non-deferred response, + * except that it wouldn't permit reliable + * stalling of the request. Instead, demand + * that gadget drivers not use this mode. + */ + DBG(udc, "no control-OUT deferred responses!\n"); + __raw_writel(csr | AT91_UDP_FORCESTALL, creg); + udc->req_pending = 0; + } + + /* STATUS stage for control-IN; ack. */ + } else { + PACKET("ep0 out/status ACK\n"); + __raw_writel(csr, creg); + + /* "early" status stage */ + if (req) + done(ep0, req, 0); + } + } +} + +static void at91_udc_irq (void *_udc) +{ + struct at91_udc *udc = _udc; + u32 rescans = 5; + + while (rescans--) { + u32 status; + + status = at91_udp_read(udc, AT91_UDP_ISR); + if (!status) + break; + + /* USB reset irq: not maskable */ + if (status & AT91_UDP_ENDBUSRES) { + at91_udp_write(udc, AT91_UDP_IDR, ~MINIMUS_INTERRUPTUS); + /* Atmel code clears this irq twice */ + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_ENDBUSRES); + VDBG(udc, "end bus reset\n"); + udc->addr = 0; + stop_activity(udc); + + /* enable ep0 */ + at91_udp_write(udc, AT91_UDP_CSR(0), + AT91_UDP_EPEDS | AT91_UDP_EPTYPE_CTRL); + udc->gadget.speed = USB_SPEED_FULL; + udc->suspended = 0; + + /* + * NOTE: this driver keeps clocks off unless the + * USB host is present. That saves power, but for + * boards that don't support VBUS detection, both + * clocks need to be active most of the time. + */ + + /* host initiated suspend (3+ms bus idle) */ + } else if (status & AT91_UDP_RXSUSP) { + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP); + /* VDBG(udc, "bus suspend\n"); */ + if (udc->suspended) + continue; + udc->suspended = 1; + + /* + * NOTE: when suspending a VBUS-powered device, the + * gadget driver should switch into slow clock mode + * and then into standby to avoid drawing more than + * 500uA power (2500uA for some high-power configs). + */ + if (udc->driver && udc->driver->suspend) { + udc->driver->suspend(&udc->gadget); + } + + /* host initiated resume */ + } else if (status & AT91_UDP_RXRSM) { + at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM); + at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM); + /* VDBG(udc, "bus resume\n"); */ + if (!udc->suspended) + continue; + udc->suspended = 0; + + /* + * NOTE: for a VBUS-powered device, the gadget driver + * would normally want to switch out of slow clock + * mode into normal mode. + */ + if (udc->driver && udc->driver->resume) { + udc->driver->resume(&udc->gadget); + } + + /* endpoint IRQs are cleared by handling them */ + } else { + int i; + unsigned mask = 1; + struct at91_ep *ep = &udc->ep[1]; + + if (status & mask) + handle_ep0(udc); + for (i = 1; i < NUM_ENDPOINTS; i++) { + mask <<= 1; + if (status & mask) + handle_ep(ep); + ep++; + } + } + } +} + +/*-------------------------------------------------------------------------*/ + +static struct at91_udc controller = { + .gadget = { + .ops = &at91_udc_ops, + .ep0 = &controller.ep[0].ep, + .name = driver_name, + }, + .ep[0] = { + .ep = { + .name = ep0name, + .ops = &at91_ep_ops, + }, + .udc = &controller, + .maxpacket = 8, + .int_mask = 1 << 0, + }, + .ep[1] = { + .ep = { + .name = "ep1", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 64, + .int_mask = 1 << 1, + }, + .ep[2] = { + .ep = { + .name = "ep2", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 64, + .int_mask = 1 << 2, + }, + .ep[3] = { + .ep = { + /* could actually do bulk too */ + .name = "ep3-int", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .maxpacket = 8, + .int_mask = 1 << 3, + }, + .ep[4] = { + .ep = { + .name = "ep4", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 256, + .int_mask = 1 << 4, + }, + .ep[5] = { + .ep = { + .name = "ep5", + .ops = &at91_ep_ops, + }, + .udc = &controller, + .is_pingpong = 1, + .maxpacket = 256, + .int_mask = 1 << 5, + }, + /* ep6 and ep7 are also reserved (custom silicon might use them) */ +}; + +static void at91_udc_irq (void *_udc); + +static void at91_update_vbus(struct at91_udc *udc, u32 value) +{ + if (value == udc->gpio_vbus_val) + return; + + if (value) + dev_set_param(udc->dev, "vbus", "1"); + else + dev_set_param(udc->dev, "vbus", "0"); + + udc->gpio_vbus_val = value; +} + +int usb_gadget_poll(void) +{ + struct at91_udc *udc = &controller; + u32 value; + + if (!udc->udp_baseaddr) + return 0; + + value = gpio_get_value(udc->board.vbus_pin); + value ^= udc->board.vbus_active_low; + + if (!value) { + at91_update_vbus(udc, value); + return 0; + } + at91_update_vbus(udc, value); + + value = at91_udp_read(udc, AT91_UDP_ISR) & (~(AT91_UDP_SOFINT)); + if (value) + at91_udc_irq(udc); + + return value; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct at91_udc *udc = &controller; + int retval; + + if (!udc->iclk) + return -ENODEV; + + if (!driver + || driver->speed < USB_SPEED_FULL + || !driver->bind + || !driver->setup) { + DBG(udc, "bad parameter.\n"); + return -EINVAL; + } + + if (udc->driver) { + DBG(udc, "UDC already has a gadget driver\n"); + return -EBUSY; + } + + udc->driver = driver; + udc->enabled = 1; + udc->selfpowered = 1; + + retval = driver->bind(&udc->gadget); + if (retval) { + DBG(udc, "bind() returned %d\n", retval); + udc->driver = NULL; + udc->enabled = 0; + udc->selfpowered = 0; + return retval; + } + + pullup(udc, 1); + + DBG(udc, "bound to %s\n", driver->function); + return 0; +} +EXPORT_SYMBOL (usb_gadget_register_driver); + +int usb_gadget_unregister_driver (struct usb_gadget_driver *driver) +{ + struct at91_udc *udc = &controller; + + if (!driver || driver != udc->driver || !driver->unbind) + return -EINVAL; + + udc->enabled = 0; + at91_udp_write(udc, AT91_UDP_IDR, ~0); + pullup(udc, 0); + + driver->unbind(&udc->gadget); + udc->driver = NULL; + + DBG(udc, "unbound from %s\n", driver->function); + return 0; +} +EXPORT_SYMBOL (usb_gadget_unregister_driver); + +/*-------------------------------------------------------------------------*/ + +static void at91_udc_poller(struct poller_struct *poller) +{ + usb_gadget_poll(); +} + +static struct poller_struct poller = { + .func = at91_udc_poller +}; + +static int __init at91udc_probe(struct device_d *dev) +{ + struct at91_udc *udc; + int retval; + + if (!dev->platform_data) { + /* small (so we copy it) but critical! */ + DBG(udc, "missing platform_data\n"); + return -ENODEV; + } + + /* init software state */ + udc = &controller; + udc->dev = dev; + udc->board = *(struct at91_udc_data *) dev->platform_data; + udc->enabled = 0; + + /* rm9200 needs manual D+ pullup; off by default */ + if (cpu_is_at91rm9200()) { + if (udc->board.pullup_pin <= 0) { + DBG(udc, "no D+ pullup?\n"); + retval = -ENODEV; + goto fail0; + } + retval = gpio_request(udc->board.pullup_pin, "udc_pullup"); + if (retval) { + DBG(udc, "D+ pullup is busy\n"); + goto fail0; + } + gpio_direction_output(udc->board.pullup_pin, + udc->board.pullup_active_low); + } + + /* newer chips have more FIFO memory than rm9200 */ + if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) { + udc->ep[0].maxpacket = 64; + udc->ep[3].maxpacket = 64; + udc->ep[4].maxpacket = 512; + udc->ep[5].maxpacket = 512; + } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) { + udc->ep[3].maxpacket = 64; + } else if (cpu_is_at91sam9263()) { + udc->ep[0].maxpacket = 64; + udc->ep[3].maxpacket = 64; + } + + udc->udp_baseaddr = dev_request_mem_region(dev, 0); + if (!udc->udp_baseaddr) { + retval = -ENOMEM; + goto fail0a; + } + + udc_reinit(udc); + + /* get interface and function clocks */ + udc->iclk = clk_get(dev, "udc_clk"); + udc->fclk = clk_get(dev, "udpck"); + if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { + DBG(udc, "clocks missing\n"); + retval = -ENODEV; + /* NOTE: we "know" here that refcounts on these are NOPs */ + goto fail0a; + } + + /* don't do anything until we have both gadget driver and VBUS */ + clk_enable(udc->iclk); + at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS); + at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff); + /* Clear all pending interrupts - UDP may be used by bootloader. */ + at91_udp_write(udc, AT91_UDP_ICR, 0xffffffff); + clk_disable(udc->iclk); + + if (udc->board.vbus_pin > 0) { + /* + * Get the initial state of VBUS - we cannot expect + * a pending interrupt. + */ + udc->vbus = at91_get_gpio_value(udc->board.vbus_pin); + DBG(udc, "VBUS detection: host:%s \n", + udc->vbus ? "present":"absent"); + } else { + DBG(udc, "no VBUS detection, assuming always-on\n"); + udc->vbus = 1; + } + + dev_add_param(dev, "vbus", NULL, NULL, 0); + dev_set_param(dev, "vbus", "0"); + + poller_register(&poller); + + INFO(udc, "%s version %s\n", driver_name, DRIVER_VERSION); + return 0; + +fail0a: + if (cpu_is_at91rm9200()) + gpio_free(udc->board.pullup_pin); +fail0: + DBG(udc, "%s probe failed, %d\n", driver_name, retval); + return retval; +} + + +static struct driver_d at91_udc_driver = { + .name = driver_name, + .probe = at91udc_probe, +}; + +static int at91_udc_init(void) +{ + register_driver(&at91_udc_driver); + return 0; +} +device_initcall(at91_udc_init); diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h new file mode 100644 index 0000000..e592cc5 --- /dev/null +++ b/drivers/usb/gadget/at91_udc.h @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2004 by Thomas Rathbone, HP Labs + * Copyright (C) 2005 by Ivan Kokshaysky + * Copyright (C) 2006 by SAN People + * + * 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 AT91_UDC_H +#define AT91_UDC_H + +/* + * USB Device Port (UDP) registers. + * Based on AT91RM9200 datasheet revision E. + */ + +#define AT91_UDP_FRM_NUM 0x00 /* Frame Number Register */ +#define AT91_UDP_NUM (0x7ff << 0) /* Frame Number */ +#define AT91_UDP_FRM_ERR (1 << 16) /* Frame Error */ +#define AT91_UDP_FRM_OK (1 << 17) /* Frame OK */ + +#define AT91_UDP_GLB_STAT 0x04 /* Global State Register */ +#define AT91_UDP_FADDEN (1 << 0) /* Function Address Enable */ +#define AT91_UDP_CONFG (1 << 1) /* Configured */ +#define AT91_UDP_ESR (1 << 2) /* Enable Send Resume */ +#define AT91_UDP_RSMINPR (1 << 3) /* Resume has been sent */ +#define AT91_UDP_RMWUPE (1 << 4) /* Remote Wake Up Enable */ + +#define AT91_UDP_FADDR 0x08 /* Function Address Register */ +#define AT91_UDP_FADD (0x7f << 0) /* Function Address Value */ +#define AT91_UDP_FEN (1 << 8) /* Function Enable */ + +#define AT91_UDP_IER 0x10 /* Interrupt Enable Register */ +#define AT91_UDP_IDR 0x14 /* Interrupt Disable Register */ +#define AT91_UDP_IMR 0x18 /* Interrupt Mask Register */ + +#define AT91_UDP_ISR 0x1c /* Interrupt Status Register */ +#define AT91_UDP_EP(n) (1 << (n)) /* Endpoint Interrupt Status */ +#define AT91_UDP_RXSUSP (1 << 8) /* USB Suspend Interrupt Status */ +#define AT91_UDP_RXRSM (1 << 9) /* USB Resume Interrupt Status */ +#define AT91_UDP_EXTRSM (1 << 10) /* External Resume Interrupt Status [AT91RM9200 only] */ +#define AT91_UDP_SOFINT (1 << 11) /* Start of Frame Interrupt Status */ +#define AT91_UDP_ENDBUSRES (1 << 12) /* End of Bus Reset Interrupt Status */ +#define AT91_UDP_WAKEUP (1 << 13) /* USB Wakeup Interrupt Status [AT91RM9200 only] */ + +#define AT91_UDP_ICR 0x20 /* Interrupt Clear Register */ +#define AT91_UDP_RST_EP 0x28 /* Reset Endpoint Register */ + +#define AT91_UDP_CSR(n) (0x30+((n)*4)) /* Endpoint Control/Status Registers 0-7 */ +#define AT91_UDP_TXCOMP (1 << 0) /* Generates IN packet with data previously written in DPR */ +#define AT91_UDP_RX_DATA_BK0 (1 << 1) /* Receive Data Bank 0 */ +#define AT91_UDP_RXSETUP (1 << 2) /* Send STALL to the host */ +#define AT91_UDP_STALLSENT (1 << 3) /* Stall Sent / Isochronous error (Isochronous endpoints) */ +#define AT91_UDP_TXPKTRDY (1 << 4) /* Transmit Packet Ready */ +#define AT91_UDP_FORCESTALL (1 << 5) /* Force Stall */ +#define AT91_UDP_RX_DATA_BK1 (1 << 6) /* Receive Data Bank 1 */ +#define AT91_UDP_DIR (1 << 7) /* Transfer Direction */ +#define AT91_UDP_EPTYPE (7 << 8) /* Endpoint Type */ +#define AT91_UDP_EPTYPE_CTRL (0 << 8) +#define AT91_UDP_EPTYPE_ISO_OUT (1 << 8) +#define AT91_UDP_EPTYPE_BULK_OUT (2 << 8) +#define AT91_UDP_EPTYPE_INT_OUT (3 << 8) +#define AT91_UDP_EPTYPE_ISO_IN (5 << 8) +#define AT91_UDP_EPTYPE_BULK_IN (6 << 8) +#define AT91_UDP_EPTYPE_INT_IN (7 << 8) +#define AT91_UDP_DTGLE (1 << 11) /* Data Toggle */ +#define AT91_UDP_EPEDS (1 << 15) /* Endpoint Enable/Disable */ +#define AT91_UDP_RXBYTECNT (0x7ff << 16) /* Number of bytes in FIFO */ + +#define AT91_UDP_FDR(n) (0x50+((n)*4)) /* Endpoint FIFO Data Registers 0-7 */ + +#define AT91_UDP_TXVC 0x74 /* Transceiver Control Register */ +#define AT91_UDP_TXVC_TXVDIS (1 << 8) /* Transceiver Disable */ +#define AT91_UDP_TXVC_PUON (1 << 9) /* PullUp On [AT91SAM9260 only] */ + +/*-------------------------------------------------------------------------*/ + +/* + * controller driver data structures + */ + +#define NUM_ENDPOINTS 6 + +/* + * hardware won't disable bus reset, or resume while the controller + * is suspended ... watching suspend helps keep the logic symmetric. + */ +#define MINIMUS_INTERRUPTUS \ + (AT91_UDP_ENDBUSRES | AT91_UDP_RXRSM | AT91_UDP_RXSUSP) + +struct at91_ep { + struct usb_ep ep; + struct list_head queue; + struct at91_udc *udc; + void __iomem *creg; + + unsigned maxpacket:16; + u8 int_mask; + unsigned is_pingpong:1; + + unsigned stopped:1; + unsigned is_in:1; + unsigned is_iso:1; + unsigned fifo_bank:1; + + const struct usb_endpoint_descriptor + *desc; +}; + +/* + * driver is non-SMP, and just blocks IRQs whenever it needs + * access protection for chip registers or driver state + */ +struct at91_udc { + struct usb_gadget gadget; + struct at91_ep ep[NUM_ENDPOINTS]; + struct usb_gadget_driver *driver; + unsigned vbus:1; + unsigned enabled:1; + unsigned clocked:1; + unsigned suspended:1; + unsigned req_pending:1; + unsigned wait_for_addr_ack:1; + unsigned wait_for_config_ack:1; + unsigned selfpowered:1; + unsigned active_suspend:1; + u8 addr; + u32 gpio_vbus_val; + struct at91_udc_data board; + struct clk *iclk, *fclk; + struct device_d *dev; + void __iomem *udp_baseaddr; + int udp_irq; +}; + +static inline struct at91_udc *to_udc(struct usb_gadget *g) +{ + return container_of(g, struct at91_udc, gadget); +} + +struct at91_request { + struct usb_request req; + struct list_head queue; +}; + +/*-------------------------------------------------------------------------*/ + +#ifdef VERBOSE_DEBUG +# define VDBG DBG +#else +# define VDBG(stuff...) do{}while(0) +#endif + +#ifdef PACKET_TRACE +# define PACKET VDBG +#else +# define PACKET(stuff...) do{}while(0) +#endif + +#define ERR(udc, stuff...) dev_err((udc)->dev, ##stuff) +#define WARNING(udc, stuff...) dev_warn((udc)->dev, ##stuff) +#define INFO(udc, stuff...) dev_info((udc)->dev, ##stuff) +#define DBG(udc, stuff...) dev_dbg((udc)->dev, ##stuff) + +#endif diff --git a/drivers/usb/gadget/dfu.c b/drivers/usb/gadget/dfu.c index 0a0d244..f26c1e4 100644 --- a/drivers/usb/gadget/dfu.c +++ b/drivers/usb/gadget/dfu.c @@ -67,6 +67,7 @@ static int dfufd = -EINVAL;; static struct usb_dfu_dev *dfu_devs; static int dfu_num_alt; +static int dfudetach; /* USB DFU functional descriptor */ static struct usb_dfu_func_descriptor usb_dfu_func = { @@ -204,6 +205,9 @@ dstat->bStatus = dfu->dfu_status; dstat->bState = dfu->dfu_state; dstat->iString = 0; + dstat->bwPollTimeout[0] = 10; + dstat->bwPollTimeout[1] = 0; + dstat->bwPollTimeout[2] = 0; return sizeof(*dstat); } @@ -425,6 +429,8 @@ * least the Linux USB stack likes to send a number of resets * in a row :( */ dfu->dfu_state = DFU_STATE_dfuMANIFEST_WAIT_RST; + value = 0; + dfudetach = 1; break; default: dfu->dfu_state = DFU_STATE_dfuERROR; @@ -690,11 +696,12 @@ while (1) { usb_gadget_poll(); - if (ctrlc()) + if (ctrlc() || dfudetach) goto out; } out: + dfudetach = 0; usb_composite_unregister(&dfu_driver); return 0; diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 43b4992..218aed2 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -407,7 +407,7 @@ { struct f_acm *acm = func_to_acm(f); - printf("acm ttyGS%d deactivated\n", acm->port_num); + VDBG(cdev, "acm ttyGS%d deactivated\n", acm->port_num); gserial_disconnect(&acm->port); usb_ep_disable(acm->notify); acm->notify->driver_data = NULL; @@ -473,7 +473,7 @@ int status; if (acm->notify_req) { - printf("acm ttyGS%d serial state %04x\n", + VDBG(cdev, "acm ttyGS%d serial state %04x\n", acm->port_num, acm->serial_state); status = acm_cdc_notify(acm, USB_CDC_NOTIFY_SERIAL_STATE, 0, &acm->serial_state, sizeof(acm->serial_state)); diff --git a/drivers/usb/gadget/fsl_udc.c b/drivers/usb/gadget/fsl_udc.c index fbc6e4e..5b64ec2 100644 --- a/drivers/usb/gadget/fsl_udc.c +++ b/drivers/usb/gadget/fsl_udc.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -233,6 +234,7 @@ #define USB_MODE_CTRL_MODE_DEVICE 0x00000002 #define USB_MODE_CTRL_MODE_HOST 0x00000003 #define USB_MODE_CTRL_MODE_RSV 0x00000001 +#define USB_MODE_CTRL_MODE_MASK 0x00000003 #define USB_MODE_SETUP_LOCK_OFF 0x00000008 #define USB_MODE_STREAM_DISABLE 0x00000010 /* Endpoint Flush Register */ @@ -603,7 +605,8 @@ static int dr_controller_setup(struct fsl_udc *udc) { - unsigned int tmp, portctrl; + unsigned int tmp, portctrl, ep_num; + unsigned int max_no_of_ep; uint64_t to; /* Config PHY interface */ @@ -647,6 +650,7 @@ /* Set the controller as device mode */ tmp = readl(&dr_regs->usbmode); + tmp &= ~USB_MODE_CTRL_MODE_MASK; /* clear mode bits */ tmp |= USB_MODE_CTRL_MODE_DEVICE; /* Disable Setup Lockout */ tmp |= USB_MODE_SETUP_LOCK_OFF; @@ -659,6 +663,14 @@ tmp &= USB_EP_LIST_ADDRESS_MASK; writel(tmp, &dr_regs->endpointlistaddr); + max_no_of_ep = (0x0000001F & readl(&dr_regs->dccparams)); + for (ep_num = 1; ep_num < max_no_of_ep; ep_num++) { + tmp = readl(&dr_regs->endptctrl[ep_num]); + tmp &= ~(EPCTRL_TX_TYPE | EPCTRL_RX_TYPE); + tmp |= (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT) + | (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT); + writel(tmp, &dr_regs->endptctrl[ep_num]); + } VDBG("vir[qh_base] is %p phy[qh_base] is 0x%8x reg is 0x%8x", udc->ep_qh, (int)tmp, readl(&dr_regs->endpointlistaddr)); @@ -725,12 +737,14 @@ if (ep_num) tmp_epctrl |= EPCTRL_TX_DATA_TOGGLE_RST; tmp_epctrl |= EPCTRL_TX_ENABLE; + tmp_epctrl &= ~EPCTRL_TX_TYPE; tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_TX_EP_TYPE_SHIFT); } else { if (ep_num) tmp_epctrl |= EPCTRL_RX_DATA_TOGGLE_RST; tmp_epctrl |= EPCTRL_RX_ENABLE; + tmp_epctrl &= ~EPCTRL_RX_TYPE; tmp_epctrl |= ((unsigned int)(ep_type) << EPCTRL_RX_EP_TYPE_SHIFT); } @@ -887,7 +901,7 @@ case USB_ENDPOINT_XFER_ISOC: /* Calculate transactions needed for high bandwidth iso */ mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x8ff; /* bit 0~10 */ + max = max & 0x7ff; /* bit 0~10 */ /* 3 transactions at most */ if (mult > 3) goto en_done; @@ -924,7 +938,6 @@ (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", max); en_done: - printf("%s: %d\n", __func__, retval); return retval; } @@ -948,10 +961,13 @@ /* disable ep on controller */ ep_num = ep_index(ep); epctrl = readl(&dr_regs->endptctrl[ep_num]); - if (ep_is_in(ep)) - epctrl &= ~EPCTRL_TX_ENABLE; - else - epctrl &= ~EPCTRL_RX_ENABLE; + if (ep_is_in(ep)) { + epctrl &= ~(EPCTRL_TX_ENABLE | EPCTRL_TX_TYPE); + epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT; + } else { + epctrl &= ~(EPCTRL_RX_ENABLE | EPCTRL_TX_TYPE); + epctrl |= EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT; + } writel(epctrl, &dr_regs->endptctrl[ep_num]); udc = (struct fsl_udc *)ep->udc; @@ -1921,7 +1937,7 @@ /* Disable ISR for OTG host mode */ if (udc->stopped) - return 0; + return -EIO; irq_src = readl(&dr_regs->usbsts) & readl(&dr_regs->usbintr); /* Clear notification bits */ @@ -1999,7 +2015,7 @@ /* bind udc driver to gadget driver */ retval = driver->bind(&udc_controller->gadget); if (retval) { - VDBG("bind to %s --> %d", driver->driver.name, retval); + VDBG("bind to gadget --> %d", retval); udc_controller->driver = NULL; goto out; } @@ -2231,6 +2247,15 @@ return 0; } +static void fsl_udc_poller(struct poller_struct *poller) +{ + usb_gadget_poll(); +} + +static struct poller_struct poller = { + .func = fsl_udc_poller +}; + static int fsl_udc_probe(struct device_d *dev) { int ret, i; @@ -2293,6 +2318,8 @@ struct_ep_setup(udc_controller, i * 2 + 1, name, 1); } + poller_register(&poller); + return 0; err_out: return ret; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index f6a712b..98a501b 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "u_serial.h" @@ -52,7 +53,9 @@ }; static int use_acm = 1; +#ifdef HAVE_OBEX static int use_obex = 0; +#endif static unsigned n_ports = 1; static int serial_bind_config(struct usb_configuration *c) @@ -63,8 +66,10 @@ for (i = 0; i < n_ports && status == 0; i++) { if (use_acm) status = acm_bind_config(c, i); +#ifdef HAVE_OBEX else if (use_obex) status = obex_bind_config(c, i); +#endif else status = gser_bind_config(c, i); } @@ -100,7 +105,7 @@ int gcnum; struct usb_gadget *gadget = cdev->gadget; int status; -printf("%s\n", __func__); + status = gserial_setup(cdev->gadget, n_ports); if (status < 0) return status; @@ -174,24 +179,56 @@ .bind = gs_bind, }; -static int __init gserial_init(void) +int usb_serial_register(struct usb_serial_pdata *pdata) { /* We *could* export two configs; that'd be much cleaner... * but neither of these product IDs was defined that way. */ + + /* + * PXA CPU suffer a silicon bug which prevents them from being a + * compound device, forbiding the ACM configurations. + */ +#ifdef CONFIG_ARCH_PXA2XX + use_acm = 0; +#endif + switch (pdata->mode) { + case 1: +#ifdef HAVE_OBEX + use_obex = 1; +#endif + use_acm = 0; + break; + case 2: +#ifdef HAVE_OBEX + use_obex = 1; +#endif + use_acm = 0; + break; + default: +#ifdef HAVE_OBEX + use_obex = 0; +#endif + use_acm = 1; + } + if (use_acm) { serial_config_driver.label = "CDC ACM config"; serial_config_driver.bConfigurationValue = 2; device_desc.bDeviceClass = USB_CLASS_COMM; device_desc.idProduct = cpu_to_le16(GS_CDC_PRODUCT_ID); - } else if (use_obex) { + } +#ifdef HAVE_OBEX + else if (use_obex) { serial_config_driver.label = "CDC OBEX config"; serial_config_driver.bConfigurationValue = 3; device_desc.bDeviceClass = USB_CLASS_COMM; device_desc.idProduct = cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID); - } else { + } +#endif + else { serial_config_driver.label = "Generic Serial config"; serial_config_driver.bConfigurationValue = 1; device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; @@ -199,9 +236,17 @@ cpu_to_le16(GS_PRODUCT_ID); } strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label; + if (pdata->idVendor) + device_desc.idVendor = pdata->idVendor; + if (pdata->idProduct) + device_desc.idProduct = pdata->idProduct; + strings_dev[STRING_MANUFACTURER_IDX].s = pdata->manufacturer; + strings_dev[STRING_PRODUCT_IDX].s = pdata->productname; return usb_composite_register(&gserial_driver); } -late_initcall(gserial_init); - +void usb_serial_unregister(void) +{ + usb_composite_unregister(&gserial_driver); +} diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 49aedc2..e310c3a 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "u_serial.h" @@ -107,8 +108,6 @@ #define GS_CLOSE_TIMEOUT 15 /* seconds */ - - #ifdef VERBOSE_DEBUG #define pr_vdebug(fmt, arg...) \ pr_debug(fmt, ##arg) @@ -370,6 +369,7 @@ struct usb_ep *in; struct usb_request *req; int status; + uint64_t to; if (list_empty(pool)) return; @@ -382,8 +382,12 @@ *(unsigned char *)req->buf = c; status = usb_ep_queue(in, req); - while (status >= 0 && list_empty(pool)) + to = get_time_ns(); + while (status >= 0 && list_empty(pool)) { status = usb_gadget_poll(); + if (is_timeout(to, 300 * MSECOND)) + break; + } } static int serial_tstc(struct console_device *cdev) @@ -399,11 +403,16 @@ struct gs_port *port = container_of(cdev, struct gs_port, cdev); unsigned char ch; + uint64_t to; if (!port->port_usb) return -EIO; - while (kfifo_getc(port->recv_fifo, &ch)) + to = get_time_ns(); + while (kfifo_getc(port->recv_fifo, &ch)) { usb_gadget_poll(); + if (is_timeout(to, 300 * MSECOND)) + break; + } return ch; } @@ -420,8 +429,6 @@ int status; struct console_device *cdev; - printf("%s %p %d\n", __func__, gser, port_num); - /* we "know" gserial_cleanup() hasn't been called */ port = ports[port_num].port; @@ -451,7 +458,7 @@ port->recv_fifo = kfifo_alloc(1024); - printf("gserial_connect: start ttyGS%d\n", port->port_num); + /*printf("gserial_connect: start ttyGS%d\n", port->port_num);*/ gs_start_io(port); if (gser->connect) gser->connect(gser); @@ -508,7 +515,6 @@ struct gs_port *port = gser->ioport; struct console_device *cdev; - printf("%s\n", __func__); if (!port) return; diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 96e09e2..439d8eb 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -3,6 +3,7 @@ config USB_EHCI_OMAP depends on ARCH_OMAP3 + depends on USB_TWL4030 bool "OMAP EHCI driver" config USB_OHCI diff --git a/drivers/usb/otg/twl4030.c b/drivers/usb/otg/twl4030.c index 4077169..123f0a5 100644 --- a/drivers/usb/otg/twl4030.c +++ b/drivers/usb/otg/twl4030.c @@ -118,10 +118,10 @@ twl4030_reg_write(twl4030, TWL4030_PM_RECEIVER_VUSB1V8_TYPE, 0x00); /* disable access to power configuration registers */ - twl4030_reg_write(twl4030, TWL4030_PM_MASTER_PROTECT_KEY, 0x0 ); + twl4030_reg_write(twl4030, TWL4030_PM_MASTER_PROTECT_KEY, 0x0); - twl4030_reg_write(twl4030, TWL4030_BASEADD_LED, 0x33); /* FIXME *need to enable LED to get USB power? */ - + /* FIXME *need to enable LED to get USB power? */ + twl4030_reg_write(twl4030, TWL4030_BASEADD_LED, 0x33); } static void twl4030_phy_power(void) diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index df2157e..4a05af9 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -27,7 +27,7 @@ Say 'Y' here to enable framebuffer and splash screen support for i.MX23 and i.MX28 based systems. -config DRIVER_VIDEO_S3C +config DRIVER_VIDEO_S3C24XX bool "S3C244x framebuffer driver" depends on ARCH_S3C24xx help diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 123c46f..913c78d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -3,5 +3,5 @@ obj-$(CONFIG_DRIVER_VIDEO_STM) += stm.o obj-$(CONFIG_DRIVER_VIDEO_IMX) += imx.o obj-$(CONFIG_DRIVER_VIDEO_IMX_IPU) += imx-ipu-fb.o -obj-$(CONFIG_DRIVER_VIDEO_S3C) += s3c.o +obj-$(CONFIG_DRIVER_VIDEO_S3C24XX) += s3c24xx.o obj-$(CONFIG_DRIVER_VIDEO_PXA) += pxa.o diff --git a/drivers/video/imx.c b/drivers/video/imx.c index 7ffbcb5..452e558 100644 --- a/drivers/video/imx.c +++ b/drivers/video/imx.c @@ -303,6 +303,14 @@ unsigned long long tmp; struct imxfb_info *fbi = info->priv; u32 pcr; + int i; + + for (i = 0; i < info->num_modes; i++) { + if (!strcmp(fbi->mode[i].mode.name, mode->name)) { + fbi->pcr = fbi->mode[i].pcr; + break; + } + } /* physical screen start address */ writel(VPW_VPW(mode->xres * info->bits_per_pixel / 8 / 4), @@ -390,6 +398,7 @@ .fb_setcolreg = imxfb_setcolreg, .fb_enable = imxfb_enable_controller, .fb_disable = imxfb_disable_controller, + .fb_activate_var = imxfb_activate_var, }; #ifdef CONFIG_IMXFB_DRIVER_VIDEO_IMX_OVERLAY @@ -524,7 +533,8 @@ struct imxfb_info *fbi; struct fb_info *info; struct imx_fb_platform_data *pdata = dev->platform_data; - int ret; + struct fb_videomode *mode_list; + int ret, i; if (!pdata) return -ENODEV; @@ -542,6 +552,14 @@ writel(readl(IMX_CCM_BASE + CCM_CGCR1) & ~(1 << 29), IMX_CCM_BASE + CCM_CGCR1); #endif + if (!pdata->num_modes) { + dev_err(dev, "no modes. bailing out\n"); + return -EINVAL; + } + + mode_list = xzalloc(sizeof(*mode_list) * pdata->num_modes); + for (i = 0; i < pdata->num_modes; i++) + mode_list[i] = pdata->mode[i].mode; fbi = xzalloc(sizeof(*fbi)); info = &fbi->info; @@ -555,6 +573,8 @@ fbi->enable = pdata->enable; fbi->dev = dev; info->priv = fbi; + info->mode_list = mode_list; + info->num_modes = pdata->num_modes; info->mode = &pdata->mode->mode; info->xres = pdata->mode->mode.xres; info->yres = pdata->mode->mode.yres; diff --git a/drivers/video/s3c.c b/drivers/video/s3c.c deleted file mode 100644 index b17aeb6..0000000 --- a/drivers/video/s3c.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright (C) 2010 Juergen Beisert - * Copyright (C) 2011 Alexey Galakhov - * - * This driver is based on a patch found in the web: - * (C) Copyright 2006 by OpenMoko, Inc. - * Author: Harald Welte - * - * 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 - -#define LCDCON1 0x00 -# define PNRMODE(x) (((x) & 3) << 5) -# define BPPMODE(x) (((x) & 0xf) << 1) -# define SET_CLKVAL(x) (((x) & 0x3ff) << 8) -# define GET_CLKVAL(x) (((x) >> 8) & 0x3ff) -# define ENVID (1 << 0) - -#define LCDCON2 0x04 -# define SET_VBPD(x) (((x) & 0xff) << 24) -# define SET_LINEVAL(x) (((x) & 0x3ff) << 14) -# define SET_VFPD(x) (((x) & 0xff) << 6) -# define SET_VSPW(x) ((x) & 0x3f) - -#define LCDCON3 0x08 -# define SET_HBPD(x) (((x) & 0x7f) << 19) -# define SET_HOZVAL(x) (((x) & 0x7ff) << 8) -# define SET_HFPD(x) ((x) & 0xff) - -#define LCDCON4 0x0c -# define SET_HSPW(x) ((x) & 0xff) - -#define LCDCON5 0x10 -# define BPP24BL (1 << 12) -# define FRM565 (1 << 11) -# define INV_CLK (1 << 10) -# define INV_HS (1 << 9) -# define INV_VS (1 << 8) -# define INV_DTA (1 << 7) -# define INV_DE (1 << 6) -# define INV_PWREN (1 << 5) -# define INV_LEND (1 << 4) -# define ENA_PWREN (1 << 3) -# define ENA_LEND (1 << 2) -# define BSWP (1 << 1) -# define HWSWP (1 << 0) - -#define LCDSADDR1 0x14 -# define SET_LCDBANK(x) (((x) & 0x1ff) << 21) -# define GET_LCDBANK(x) (((x) >> 21) & 0x1ff) -# define SET_LCDBASEU(x) ((x) & 0x1fffff) -# define GET_LCDBASEU(x) ((x) & 0x1fffff) - -#define LCDSADDR2 0x18 -# define SET_LCDBASEL(x) ((x) & 0x1fffff) -# define GET_LCDBASEL(x) ((x) & 0x1fffff) - -#define LCDSADDR3 0x1c -# define SET_OFFSIZE(x) (((x) & 0x7ff) << 11) -# define GET_OFFSIZE(x) (((x) >> 11) & 0x7ff) -# define SET_PAGE_WIDTH(x) ((x) & 0x3ff) -# define GET_PAGE_WIDTH(x) ((x) & 0x3ff) - -#define RED_LUT 0x20 -#define GREEN_LUT 0x24 -#define BLUE_LUT 0x28 - -#define DITHMODE 0x4c - -#define TPAL 0x50 - -#define LCDINTPND 0x54 -#define LCDSRCPND 0x58 -#define LCDINTMSK 0x5c -# define FIWSEL (1 << 2) -# define INT_FrSyn (1 << 1) -# define INT_FiCnt (1 << 0) - -#define TCONSEL 0x60 - -#define RED 0 -#define GREEN 1 -#define BLUE 2 -#define TRANSP 3 - -struct s3cfb_info { - void __iomem *base; - unsigned memory_size; - struct fb_info info; - struct device_d *hw_dev; - int passive_display; - void (*enable)(int enable); -}; - -/* the RGB565 true colour mode */ -static const struct fb_bitfield def_rgb565[] = { - [RED] = { - .offset = 11, - .length = 5, - }, - [GREEN] = { - .offset = 5, - .length = 6, - }, - [BLUE] = { - .offset = 0, - .length = 5, - }, - [TRANSP] = { /* no support for transparency */ - .length = 0, - } -}; - -/* the RGB888 true colour mode */ -static const struct fb_bitfield def_rgb888[] = { - [RED] = { - .offset = 16, - .length = 8, - }, - [GREEN] = { - .offset = 8, - .length = 8, - }, - [BLUE] = { - .offset = 0, - .length = 8, - }, - [TRANSP] = { /* no support for transparency */ - .length = 0, - } -}; - -/** - * @param fb_info Framebuffer information - */ -static void s3cfb_enable_controller(struct fb_info *fb_info) -{ - struct s3cfb_info *fbi = fb_info->priv; - uint32_t con1; - - con1 = readl(fbi->base + LCDCON1); - - con1 |= ENVID; - - writel(con1, fbi->base + LCDCON1); - - if (fbi->enable) - fbi->enable(1); -} - -/** - * @param fb_info Framebuffer information - */ -static void s3cfb_disable_controller(struct fb_info *fb_info) -{ - struct s3cfb_info *fbi = fb_info->priv; - uint32_t con1; - - if (fbi->enable) - fbi->enable(0); - - con1 = readl(fbi->base + LCDCON1); - - con1 &= ~ENVID; - - writel(con1, fbi->base + LCDCON1); -} - -/** - * Prepare the video hardware for a specified video mode - * @param fb_info Framebuffer information - * @param mode The video mode description to initialize - * @return 0 on success - */ -static int s3cfb_activate_var(struct fb_info *fb_info) -{ - struct s3cfb_info *fbi = fb_info->priv; - struct fb_videomode *mode = fb_info->mode; - unsigned size, hclk, div; - uint32_t con1, con2, con3, con4, con5 = 0; - - if (fbi->passive_display != 0) { - dev_err(fbi->hw_dev, "Passive displays are currently not supported\n"); - return -EINVAL; - } - - /* - * we need at least this amount of memory for the framebuffer - */ - size = mode->xres * mode->yres * (fb_info->bits_per_pixel >> 3); - if (fbi->memory_size != size || fb_info->screen_base == NULL) { - if (fb_info->screen_base) - free(fb_info->screen_base); - fbi->memory_size = 0; - fb_info->screen_base = malloc(size); - if (! fb_info->screen_base) - return -ENOMEM; - memset(fb_info->screen_base, 0, size); - fbi->memory_size = size; - } - - /* ensure video output is _off_ */ - writel(0x00000000, fbi->base + LCDCON1); - - hclk = s3c24xx_get_hclk() / 1000U; /* hclk in kHz */ - div = hclk / PICOS2KHZ(mode->pixclock); - if (div < 3) - div = 3; - /* pixel clock is: (hclk) / ((div + 1) * 2) */ - div += 1; - div >>= 1; - div -= 1; - - con1 = PNRMODE(3) | SET_CLKVAL(div); /* PNRMODE=3 is TFT */ - - switch (fb_info->bits_per_pixel) { - case 16: - con1 |= BPPMODE(12); - con5 |= FRM565; - con5 |= HWSWP; - fb_info->red = def_rgb565[RED]; - fb_info->green = def_rgb565[GREEN]; - fb_info->blue = def_rgb565[BLUE]; - fb_info->transp = def_rgb565[TRANSP]; - break; - case 24: - con1 |= BPPMODE(13); - /* con5 |= BPP24BL; */ /* FIXME maybe needed, check alignment */ - fb_info->red = def_rgb888[RED]; - fb_info->green = def_rgb888[GREEN]; - fb_info->blue = def_rgb888[BLUE]; - fb_info->transp = def_rgb888[TRANSP]; - break; - default: - dev_err(fbi->hw_dev, "Invalid bits per pixel value: %u\n", fb_info->bits_per_pixel); - return -EINVAL; - } - - /* 'normal' in register description means positive logic */ - if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) - con5 |= INV_HS; - if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) - con5 |= INV_VS; - if (!(mode->sync & FB_SYNC_DE_HIGH_ACT)) - con5 |= INV_DE; - if (mode->sync & FB_SYNC_CLK_INVERT) - con5 |= INV_CLK; /* display should latch at the rising edge */ - if (mode->sync & FB_SYNC_DATA_INVERT) - con5 |= INV_DTA; - if (mode->sync & FB_SYNC_INVERT_PWREN) - con5 |= INV_PWREN; - if (mode->sync & FB_SYNC_INVERT_LEND) - con5 |= INV_LEND; - if (mode->sync & FB_SYNC_USE_PWREN) - con5 |= ENA_PWREN; /* FIXME should this be done conditionally/later? */ - if (mode->sync & FB_SYNC_USE_LEND) - con5 |= ENA_LEND; - if (mode->sync & FB_SYNC_SWAP_BYTES) - con5 ^= BSWP; - if (mode->sync & FB_SYNC_SWAP_HW) - con5 ^= HWSWP; - - /* vertical timing */ - con2 = SET_VBPD(mode->upper_margin - 1) | - SET_LINEVAL(mode->yres - 1) | - SET_VFPD(mode->lower_margin - 1) | - SET_VSPW(mode->vsync_len - 1); - - /* horizontal timing */ - con3 = SET_HBPD(mode->left_margin - 1) | - SET_HOZVAL(mode->xres - 1) | - SET_HFPD(mode->right_margin - 1); - con4 = SET_HSPW(mode->hsync_len - 1); - - /* basic timing setup */ - writel(con1, fbi->base + LCDCON1); - dev_dbg(fbi->hw_dev, "writing %08X into %p (con1)\n", con1, fbi->base + LCDCON1); - writel(con2, fbi->base + LCDCON2); - dev_dbg(fbi->hw_dev, "writing %08X into %p (con2)\n", con2, fbi->base + LCDCON2); - writel(con3, fbi->base + LCDCON3); - dev_dbg(fbi->hw_dev, "writing %08X into %p (con3)\n", con3, fbi->base + LCDCON3); - writel(con4, fbi->base + LCDCON4); - dev_dbg(fbi->hw_dev, "writing %08X into %p (con4)\n", con4, fbi->base + LCDCON4); - writel(con5, fbi->base + LCDCON5); - dev_dbg(fbi->hw_dev, "writing %08X into %p (con5)\n", con5, fbi->base + LCDCON5); - - dev_dbg(fbi->hw_dev, "setting up the fb baseadress to %p\n", fb_info->screen_base); - - /* framebuffer memory setup */ - writel((unsigned)fb_info->screen_base >> 1, fbi->base + LCDSADDR1); - size = mode->xres * (fb_info->bits_per_pixel >> 3) * (mode->yres); - writel(SET_LCDBASEL(((unsigned)fb_info->screen_base + size) >> 1), fbi->base + LCDSADDR2); - writel(SET_OFFSIZE(0) | - SET_PAGE_WIDTH((mode->xres * fb_info->bits_per_pixel) >> 4), - fbi->base + LCDSADDR3); - writel(FIWSEL | INT_FrSyn | INT_FiCnt, fbi->base + LCDINTMSK); - - return 0; -} - -/** - * Print some information about the current hardware state - * @param hw_dev S3C video device - */ -#ifdef CONFIG_DRIVER_VIDEO_S3C_VERBOSE -static void s3cfb_info(struct device_d *hw_dev) -{ - uint32_t con1, addr1, addr2, addr3; - struct s3cfb_info *fbi = hw_dev->priv; - - con1 = readl(fbi->base + LCDCON1); - addr1 = readl(fbi->base + LCDSADDR1); - addr2 = readl(fbi->base + LCDSADDR2); - addr3 = readl(fbi->base + LCDSADDR3); - - printf(" Video hardware info:\n"); - printf(" Video clock is running at %u Hz\n", s3c24xx_get_hclk() / ((GET_CLKVAL(con1) + 1) * 2)); - printf(" Video memory bank starts at 0x%08X\n", GET_LCDBANK(addr1) << 22); - printf(" Video memory bank offset: 0x%08X\n", GET_LCDBASEU(addr1)); - printf(" Video memory end: 0x%08X\n", GET_LCDBASEU(addr2)); - printf(" Virtual screen offset size: %u half words\n", GET_OFFSIZE(addr3)); - printf(" Virtual screen page width: %u half words\n", GET_PAGE_WIDTH(addr3)); -} -#endif - -/* - * There is only one video hardware instance available. - * It makes no sense to dynamically allocate this data - */ -static struct fb_ops s3cfb_ops = { - .fb_activate_var = s3cfb_activate_var, - .fb_enable = s3cfb_enable_controller, - .fb_disable = s3cfb_disable_controller, -}; - -static struct s3cfb_info fbi = { - .info = { - .fbops = &s3cfb_ops, - }, -}; - -static int s3cfb_probe(struct device_d *hw_dev) -{ - struct s3c_fb_platform_data *pdata = hw_dev->platform_data; - int ret; - - if (! pdata) - return -ENODEV; - - fbi.base = dev_request_mem_region(hw_dev, 0); - writel(0, fbi.base + LCDCON1); - writel(0, fbi.base + LCDCON5); /* FIXME not 0 for some displays */ - - /* just init */ - fbi.info.priv = &fbi; - - /* add runtime hardware info */ - fbi.hw_dev = hw_dev; - hw_dev->priv = &fbi; - - /* add runtime video info */ - fbi.info.mode_list = pdata->mode_list; - fbi.info.num_modes = pdata->mode_cnt; - fbi.info.mode = &fbi.info.mode_list[1]; - fbi.info.xres = fbi.info.mode->xres; - fbi.info.yres = fbi.info.mode->yres; - if (pdata->bits_per_pixel) - fbi.info.bits_per_pixel = pdata->bits_per_pixel; - else - fbi.info.bits_per_pixel = 16; - fbi.passive_display = pdata->passive_display; - fbi.enable = pdata->enable; - - ret = register_framebuffer(&fbi.info); - if (ret != 0) { - dev_err(hw_dev, "Failed to register framebuffer\n"); - return -EINVAL; - } - - return 0; -} - -static struct driver_d s3cfb_driver = { - .name = "s3c_fb", - .probe = s3cfb_probe, -#ifdef CONFIG_DRIVER_VIDEO_S3C_VERBOSE - .info = s3cfb_info, -#endif -}; - -static int s3cfb_init(void) -{ - return register_driver(&s3cfb_driver); -} - -device_initcall(s3cfb_init); - -/** - * The S3C244x LCD controller supports passive (CSTN/STN) and active (TFT) LC displays - * - * The driver itself currently supports only active TFT LC displays in the follwing manner: - * - * * True colours - * - 16 bpp - * - 24 bpp (untested) - */ diff --git a/drivers/video/s3c24xx.c b/drivers/video/s3c24xx.c new file mode 100644 index 0000000..564ccbd --- /dev/null +++ b/drivers/video/s3c24xx.c @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2010 Juergen Beisert + * Copyright (C) 2011 Alexey Galakhov + * + * This driver is based on a patch found in the web: + * (C) Copyright 2006 by OpenMoko, Inc. + * Author: Harald Welte + * + * 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 LCDCON1 0x00 +# define PNRMODE(x) (((x) & 3) << 5) +# define BPPMODE(x) (((x) & 0xf) << 1) +# define SET_CLKVAL(x) (((x) & 0x3ff) << 8) +# define GET_CLKVAL(x) (((x) >> 8) & 0x3ff) +# define ENVID (1 << 0) + +#define LCDCON2 0x04 +# define SET_VBPD(x) (((x) & 0xff) << 24) +# define SET_LINEVAL(x) (((x) & 0x3ff) << 14) +# define SET_VFPD(x) (((x) & 0xff) << 6) +# define SET_VSPW(x) ((x) & 0x3f) + +#define LCDCON3 0x08 +# define SET_HBPD(x) (((x) & 0x7f) << 19) +# define SET_HOZVAL(x) (((x) & 0x7ff) << 8) +# define SET_HFPD(x) ((x) & 0xff) + +#define LCDCON4 0x0c +# define SET_HSPW(x) ((x) & 0xff) + +#define LCDCON5 0x10 +# define BPP24BL (1 << 12) +# define FRM565 (1 << 11) +# define INV_CLK (1 << 10) +# define INV_HS (1 << 9) +# define INV_VS (1 << 8) +# define INV_DTA (1 << 7) +# define INV_DE (1 << 6) +# define INV_PWREN (1 << 5) +# define INV_LEND (1 << 4) +# define ENA_PWREN (1 << 3) +# define ENA_LEND (1 << 2) +# define BSWP (1 << 1) +# define HWSWP (1 << 0) + +#define LCDSADDR1 0x14 +# define SET_LCDBANK(x) (((x) & 0x1ff) << 21) +# define GET_LCDBANK(x) (((x) >> 21) & 0x1ff) +# define SET_LCDBASEU(x) ((x) & 0x1fffff) +# define GET_LCDBASEU(x) ((x) & 0x1fffff) + +#define LCDSADDR2 0x18 +# define SET_LCDBASEL(x) ((x) & 0x1fffff) +# define GET_LCDBASEL(x) ((x) & 0x1fffff) + +#define LCDSADDR3 0x1c +# define SET_OFFSIZE(x) (((x) & 0x7ff) << 11) +# define GET_OFFSIZE(x) (((x) >> 11) & 0x7ff) +# define SET_PAGE_WIDTH(x) ((x) & 0x3ff) +# define GET_PAGE_WIDTH(x) ((x) & 0x3ff) + +#define RED_LUT 0x20 +#define GREEN_LUT 0x24 +#define BLUE_LUT 0x28 + +#define DITHMODE 0x4c + +#define TPAL 0x50 + +#define LCDINTPND 0x54 +#define LCDSRCPND 0x58 +#define LCDINTMSK 0x5c +# define FIWSEL (1 << 2) +# define INT_FrSyn (1 << 1) +# define INT_FiCnt (1 << 0) + +#define TCONSEL 0x60 + +#define RED 0 +#define GREEN 1 +#define BLUE 2 +#define TRANSP 3 + +struct s3cfb_info { + void __iomem *base; + unsigned memory_size; + struct fb_info info; + struct device_d *hw_dev; + int passive_display; + void (*enable)(int enable); +}; + +/* the RGB565 true colour mode */ +static const struct fb_bitfield def_rgb565[] = { + [RED] = { + .offset = 11, + .length = 5, + }, + [GREEN] = { + .offset = 5, + .length = 6, + }, + [BLUE] = { + .offset = 0, + .length = 5, + }, + [TRANSP] = { /* no support for transparency */ + .length = 0, + } +}; + +/* the RGB888 true colour mode */ +static const struct fb_bitfield def_rgb888[] = { + [RED] = { + .offset = 16, + .length = 8, + }, + [GREEN] = { + .offset = 8, + .length = 8, + }, + [BLUE] = { + .offset = 0, + .length = 8, + }, + [TRANSP] = { /* no support for transparency */ + .length = 0, + } +}; + +/** + * @param fb_info Framebuffer information + */ +static void s3cfb_enable_controller(struct fb_info *fb_info) +{ + struct s3cfb_info *fbi = fb_info->priv; + uint32_t con1; + + con1 = readl(fbi->base + LCDCON1); + + con1 |= ENVID; + + writel(con1, fbi->base + LCDCON1); + + if (fbi->enable) + fbi->enable(1); +} + +/** + * @param fb_info Framebuffer information + */ +static void s3cfb_disable_controller(struct fb_info *fb_info) +{ + struct s3cfb_info *fbi = fb_info->priv; + uint32_t con1; + + if (fbi->enable) + fbi->enable(0); + + con1 = readl(fbi->base + LCDCON1); + + con1 &= ~ENVID; + + writel(con1, fbi->base + LCDCON1); +} + +/** + * Prepare the video hardware for a specified video mode + * @param fb_info Framebuffer information + * @param mode The video mode description to initialize + * @return 0 on success + */ +static int s3cfb_activate_var(struct fb_info *fb_info) +{ + struct s3cfb_info *fbi = fb_info->priv; + struct fb_videomode *mode = fb_info->mode; + unsigned size, hclk, div; + uint32_t con1, con2, con3, con4, con5 = 0; + + if (fbi->passive_display != 0) { + dev_err(fbi->hw_dev, "Passive displays are currently not supported\n"); + return -EINVAL; + } + + /* + * we need at least this amount of memory for the framebuffer + */ + size = mode->xres * mode->yres * (fb_info->bits_per_pixel >> 3); + if (fbi->memory_size != size || fb_info->screen_base == NULL) { + if (fb_info->screen_base) + free(fb_info->screen_base); + fbi->memory_size = 0; + fb_info->screen_base = malloc(size); + if (! fb_info->screen_base) + return -ENOMEM; + memset(fb_info->screen_base, 0, size); + fbi->memory_size = size; + } + + /* ensure video output is _off_ */ + writel(0x00000000, fbi->base + LCDCON1); + + hclk = s3c_get_hclk() / 1000U; /* hclk in kHz */ + div = hclk / PICOS2KHZ(mode->pixclock); + if (div < 3) + div = 3; + /* pixel clock is: (hclk) / ((div + 1) * 2) */ + div += 1; + div >>= 1; + div -= 1; + + con1 = PNRMODE(3) | SET_CLKVAL(div); /* PNRMODE=3 is TFT */ + + switch (fb_info->bits_per_pixel) { + case 16: + con1 |= BPPMODE(12); + con5 |= FRM565; + con5 |= HWSWP; + fb_info->red = def_rgb565[RED]; + fb_info->green = def_rgb565[GREEN]; + fb_info->blue = def_rgb565[BLUE]; + fb_info->transp = def_rgb565[TRANSP]; + break; + case 24: + con1 |= BPPMODE(13); + /* con5 |= BPP24BL; */ /* FIXME maybe needed, check alignment */ + fb_info->red = def_rgb888[RED]; + fb_info->green = def_rgb888[GREEN]; + fb_info->blue = def_rgb888[BLUE]; + fb_info->transp = def_rgb888[TRANSP]; + break; + default: + dev_err(fbi->hw_dev, "Invalid bits per pixel value: %u\n", fb_info->bits_per_pixel); + return -EINVAL; + } + + /* 'normal' in register description means positive logic */ + if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) + con5 |= INV_HS; + if (!(mode->sync & FB_SYNC_VERT_HIGH_ACT)) + con5 |= INV_VS; + if (!(mode->sync & FB_SYNC_DE_HIGH_ACT)) + con5 |= INV_DE; + if (mode->sync & FB_SYNC_CLK_INVERT) + con5 |= INV_CLK; /* display should latch at the rising edge */ + if (mode->sync & FB_SYNC_DATA_INVERT) + con5 |= INV_DTA; + if (mode->sync & FB_SYNC_INVERT_PWREN) + con5 |= INV_PWREN; + if (mode->sync & FB_SYNC_INVERT_LEND) + con5 |= INV_LEND; + if (mode->sync & FB_SYNC_USE_PWREN) + con5 |= ENA_PWREN; /* FIXME should this be done conditionally/later? */ + if (mode->sync & FB_SYNC_USE_LEND) + con5 |= ENA_LEND; + if (mode->sync & FB_SYNC_SWAP_BYTES) + con5 ^= BSWP; + if (mode->sync & FB_SYNC_SWAP_HW) + con5 ^= HWSWP; + + /* vertical timing */ + con2 = SET_VBPD(mode->upper_margin - 1) | + SET_LINEVAL(mode->yres - 1) | + SET_VFPD(mode->lower_margin - 1) | + SET_VSPW(mode->vsync_len - 1); + + /* horizontal timing */ + con3 = SET_HBPD(mode->left_margin - 1) | + SET_HOZVAL(mode->xres - 1) | + SET_HFPD(mode->right_margin - 1); + con4 = SET_HSPW(mode->hsync_len - 1); + + /* basic timing setup */ + writel(con1, fbi->base + LCDCON1); + dev_dbg(fbi->hw_dev, "writing %08X into %p (con1)\n", con1, fbi->base + LCDCON1); + writel(con2, fbi->base + LCDCON2); + dev_dbg(fbi->hw_dev, "writing %08X into %p (con2)\n", con2, fbi->base + LCDCON2); + writel(con3, fbi->base + LCDCON3); + dev_dbg(fbi->hw_dev, "writing %08X into %p (con3)\n", con3, fbi->base + LCDCON3); + writel(con4, fbi->base + LCDCON4); + dev_dbg(fbi->hw_dev, "writing %08X into %p (con4)\n", con4, fbi->base + LCDCON4); + writel(con5, fbi->base + LCDCON5); + dev_dbg(fbi->hw_dev, "writing %08X into %p (con5)\n", con5, fbi->base + LCDCON5); + + dev_dbg(fbi->hw_dev, "setting up the fb baseadress to %p\n", fb_info->screen_base); + + /* framebuffer memory setup */ + writel((unsigned)fb_info->screen_base >> 1, fbi->base + LCDSADDR1); + size = mode->xres * (fb_info->bits_per_pixel >> 3) * (mode->yres); + writel(SET_LCDBASEL(((unsigned)fb_info->screen_base + size) >> 1), fbi->base + LCDSADDR2); + writel(SET_OFFSIZE(0) | + SET_PAGE_WIDTH((mode->xres * fb_info->bits_per_pixel) >> 4), + fbi->base + LCDSADDR3); + writel(FIWSEL | INT_FrSyn | INT_FiCnt, fbi->base + LCDINTMSK); + + return 0; +} + +/** + * Print some information about the current hardware state + * @param hw_dev S3C video device + */ +#ifdef CONFIG_DRIVER_VIDEO_S3C_VERBOSE +static void s3cfb_info(struct device_d *hw_dev) +{ + uint32_t con1, addr1, addr2, addr3; + struct s3cfb_info *fbi = hw_dev->priv; + + con1 = readl(fbi->base + LCDCON1); + addr1 = readl(fbi->base + LCDSADDR1); + addr2 = readl(fbi->base + LCDSADDR2); + addr3 = readl(fbi->base + LCDSADDR3); + + printf(" Video hardware info:\n"); + printf(" Video clock is running at %u Hz\n", s3c_get_hclk() / ((GET_CLKVAL(con1) + 1) * 2)); + printf(" Video memory bank starts at 0x%08X\n", GET_LCDBANK(addr1) << 22); + printf(" Video memory bank offset: 0x%08X\n", GET_LCDBASEU(addr1)); + printf(" Video memory end: 0x%08X\n", GET_LCDBASEU(addr2)); + printf(" Virtual screen offset size: %u half words\n", GET_OFFSIZE(addr3)); + printf(" Virtual screen page width: %u half words\n", GET_PAGE_WIDTH(addr3)); +} +#endif + +/* + * There is only one video hardware instance available. + * It makes no sense to dynamically allocate this data + */ +static struct fb_ops s3cfb_ops = { + .fb_activate_var = s3cfb_activate_var, + .fb_enable = s3cfb_enable_controller, + .fb_disable = s3cfb_disable_controller, +}; + +static struct s3cfb_info fbi = { + .info = { + .fbops = &s3cfb_ops, + }, +}; + +static int s3cfb_probe(struct device_d *hw_dev) +{ + struct s3c_fb_platform_data *pdata = hw_dev->platform_data; + int ret; + + if (! pdata) + return -ENODEV; + + fbi.base = dev_request_mem_region(hw_dev, 0); + writel(0, fbi.base + LCDCON1); + writel(0, fbi.base + LCDCON5); /* FIXME not 0 for some displays */ + + /* just init */ + fbi.info.priv = &fbi; + + /* add runtime hardware info */ + fbi.hw_dev = hw_dev; + hw_dev->priv = &fbi; + + /* add runtime video info */ + fbi.info.mode_list = pdata->mode_list; + fbi.info.num_modes = pdata->mode_cnt; + fbi.info.mode = &fbi.info.mode_list[1]; + fbi.info.xres = fbi.info.mode->xres; + fbi.info.yres = fbi.info.mode->yres; + if (pdata->bits_per_pixel) + fbi.info.bits_per_pixel = pdata->bits_per_pixel; + else + fbi.info.bits_per_pixel = 16; + fbi.passive_display = pdata->passive_display; + fbi.enable = pdata->enable; + + ret = register_framebuffer(&fbi.info); + if (ret != 0) { + dev_err(hw_dev, "Failed to register framebuffer\n"); + return -EINVAL; + } + + return 0; +} + +static struct driver_d s3cfb_driver = { + .name = "s3c_fb", + .probe = s3cfb_probe, +#ifdef CONFIG_DRIVER_VIDEO_S3C_VERBOSE + .info = s3cfb_info, +#endif +}; + +static int s3cfb_init(void) +{ + return register_driver(&s3cfb_driver); +} + +device_initcall(s3cfb_init); + +/** + * The S3C244x LCD controller supports passive (CSTN/STN) and active (TFT) LC displays + * + * The driver itself currently supports only active TFT LC displays in the follwing manner: + * + * * True colours + * - 16 bpp + * - 24 bpp (untested) + */ diff --git a/fs/devfs-core.c b/fs/devfs-core.c index 9bc3126..5f22ce7 100644 --- a/fs/devfs-core.c +++ b/fs/devfs-core.c @@ -63,7 +63,7 @@ return NULL; if (cdev->ops->open) { - ret = cdev->ops->open(cdev); + ret = cdev->ops->open(cdev, flags); if (ret) return NULL; } diff --git a/fs/devfs.c b/fs/devfs.c index 66f7ca4..2e70cc5 100644 --- a/fs/devfs.c +++ b/fs/devfs.c @@ -116,7 +116,7 @@ f->inode = cdev; if (cdev->ops->open) { - ret = cdev->ops->open(cdev); + ret = cdev->ops->open(cdev, f->flags); if (ret) return ret; } diff --git a/include/boot.h b/include/boot.h index b67e034..a17bf25 100644 --- a/include/boot.h +++ b/include/boot.h @@ -2,25 +2,73 @@ #define __BOOT_H #include +#include +#include #include struct image_data { - struct image_handle *os; - struct image_handle *initrd; - const char *oftree; - int verify; + /* simplest case. barebox has already loaded the os here */ + struct resource *os_res; + + /* if os is an uImage this will be provided */ + struct uimage_handle *os; + int os_num; + + /* otherwise only the filename will be provided */ + char *os_file; + + /* + * The address the user wants to load the os image to. + * May be UIMAGE_INVALID_ADDRESS to indicate that the + * user has not specified any address. In this case the + * handler may choose a suitable address + */ + unsigned long os_address; + + /* entry point to the os. relative to the start of the image */ + unsigned long os_entry; + + /* if initrd is already loaded this resource will be !NULL */ + struct resource *initrd_res; + + /* if initrd is an uImage this will be provided */ + struct uimage_handle *initrd; + int initrd_num; + + /* otherwise only the filename will be provided */ + char *initrd_file; + unsigned long initrd_address; - unsigned long initrd_size; + + struct fdt_header *oftree; + + int verify; + int verbose; }; struct image_handler { + const char *name; + struct list_head list; - int image_type; + int ih_os; + + enum filetype filetype; int (*bootm)(struct image_data *data); }; int register_image_handler(struct image_handler *handle); -#endif /* __BOOT_H */ +#ifdef CONFIG_CMD_BOOTM_VERBOSE +static inline int bootm_verbose(struct image_data *data) +{ + return data->verbose; +} +#else +static inline int bootm_verbose(struct image_data *data) +{ + return 0; +} +#endif +#endif /* __BOOT_H */ diff --git a/include/common.h b/include/common.h index d594e63..2f37dd8 100644 --- a/include/common.h +++ b/include/common.h @@ -81,8 +81,6 @@ }) #endif -typedef void (interrupt_handler_t)(void *); - #include /* boot information for Linux kernel */ /* @@ -93,8 +91,6 @@ void __noreturn hang (void); void __noreturn panic(const char *fmt, ...); -/* */ -void initdram (int); char *size_human_readable(ulong size); /* common/main.c */ @@ -133,7 +129,6 @@ unsigned long flags; }; -int spec_str_to_info(const char *str, struct memarea_info *info); int parse_area_spec(const char *str, ulong *start, ulong *size); /* Just like simple_strtoul(), but this one honors a K/M/G suffix */ diff --git a/include/driver.h b/include/driver.h index bbe7248..1751d3c 100644 --- a/include/driver.h +++ b/include/driver.h @@ -232,7 +232,7 @@ IORESOURCE_MEM | flags, pdata); } -#ifdef CONFIG_DRIVER_NET_DM9000 +#ifdef CONFIG_DRIVER_NET_DM9K struct device_d *add_dm9000_device(int id, resource_size_t base, resource_size_t data, int flags, void *pdata); #else @@ -366,7 +366,7 @@ int (*ioctl)(struct cdev*, int, void *); off_t (*lseek)(struct cdev*, off_t); - int (*open)(struct cdev*); + int (*open)(struct cdev*, unsigned long flags); int (*close)(struct cdev*); int (*flush)(struct cdev*); int (*erase)(struct cdev*, size_t count, unsigned long offset); diff --git a/include/filetype.h b/include/filetype.h index 64d32ef..88f31df 100644 --- a/include/filetype.h +++ b/include/filetype.h @@ -14,6 +14,7 @@ filetype_jffs2, filetype_gzip, filetype_bzip2, + filetype_oftree, }; const char *file_type_to_string(enum filetype f); diff --git a/include/ft_build.h b/include/ft_build.h deleted file mode 100644 index 1fb6b4d..0000000 --- a/include/ft_build.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * OF Flat tree builder - * - */ - -#ifndef FT_BUILD_H -#define FT_BUILD_H - -#include -#include - -/* Definitions used by the flattened device tree */ -#define OF_DT_HEADER 0xd00dfeed /* marker */ -#define OF_DT_BEGIN_NODE 0x1 /* Start of node, full name */ -#define OF_DT_END_NODE 0x2 /* End node */ -#define OF_DT_PROP 0x3 /* Property: name off, size, - * content */ -#define OF_DT_NOP 0x4 /* nop */ -#define OF_DT_END 0x9 - -#define OF_DT_VERSION 0x10 - -struct boot_param_header { - u32 magic; /* magic word OF_DT_HEADER */ - u32 totalsize; /* total size of DT block */ - u32 off_dt_struct; /* offset to structure */ - u32 off_dt_strings; /* offset to strings */ - u32 off_mem_rsvmap; /* offset to memory reserve map */ - u32 version; /* format version */ - u32 last_comp_version; /* last compatible version */ - /* version 2 fields below */ - u32 boot_cpuid_phys; /* Physical CPU id we're booting on */ - /* version 3 fields below */ - u32 dt_strings_size; /* size of the DT strings block */ -}; - -struct ft_cxt { - struct boot_param_header *bph; - u8 *p_rsvmap; - u8 *p_start; /* pointer to beginning of dt_struct */ - u8 *p_end; /* pointer to end of dt_strings */ - u8 *p; /* pointer to end of dt_struct and beginning of dt_strings */ -}; - -void ft_begin_node(struct ft_cxt *cxt, const char *name); -void ft_init_cxt(struct ft_cxt *cxt, void *blob); -void ft_end_node(struct ft_cxt *cxt); - -void ft_end_tree(struct ft_cxt *cxt); -void ft_finalize_tree(struct ft_cxt *cxt); - -void ft_nop(struct ft_cxt *cxt); -void ft_prop(struct ft_cxt *cxt, const char *name, const void *data, int sz); -void ft_prop_str(struct ft_cxt *cxt, const char *name, const char *str); -void ft_prop_int(struct ft_cxt *cxt, const char *name, int val); -void ft_begin(struct ft_cxt *cxt, void *blob, int max_size); -void ft_add_rsvmap(struct ft_cxt *cxt, u64 physaddr, u64 size); - -void ft_setup(void *blob, bd_t * bd, ulong initrd_start, ulong initrd_end); - -void ft_dump_blob(const void *bphp); -void ft_merge_blob(struct ft_cxt *cxt, void *blob); -void *ft_get_prop(void *bphp, const char *propname, int *szp); - -void ft_board_setup(void *blob, bd_t *bd); -void ft_cpu_setup(void *blob, bd_t *bd); -void ft_pci_setup(void *blob, bd_t *bd); - -#endif diff --git a/include/image.h b/include/image.h index f3a9949..35ff01b 100644 --- a/include/image.h +++ b/include/image.h @@ -188,20 +188,6 @@ uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t; -struct image_handle_data { - void *data; - ulong len; -}; - -struct image_handle { - image_header_t header; - void *data; - struct image_handle_data *data_entries; - int nb_data_entries; -#define IH_MALLOC 1 - int flags; -}; - #if defined(CONFIG_CMD_BOOTM_SHOW_TYPE) || !defined(__BAREBOX__) const char *image_get_os_name(uint8_t os); const char *image_get_arch_name(uint8_t arch); @@ -232,121 +218,34 @@ #define uimage_to_cpu(x) be32_to_cpu(x) #define cpu_to_uimage(x) cpu_to_be32(x) -static inline uint32_t image_get_header_size(void) -{ - return sizeof(image_header_t); -} +struct uimage_handle_data { + size_t offset; /* offset in the image */ + ulong len; +}; -#define image_get_hdr_u32(x) \ -static inline uint32_t image_get_##x(const image_header_t *hdr) \ -{ \ - return uimage_to_cpu(hdr->ih_##x); \ -} +struct uimage_handle *uimage_open(const char *filename); +void uimage_close(struct uimage_handle *handle); +int uimage_verify(struct uimage_handle *handle); +int uimage_load(struct uimage_handle *handle, unsigned int image_no, + int(*flush)(void*, unsigned int)); +void uimage_print_contents(struct uimage_handle *handle); +size_t uimage_get_size(struct uimage_handle *handle, unsigned int image_no); +struct resource *uimage_load_to_sdram(struct uimage_handle *handle, + int image_no, unsigned long load_address); +void *uimage_load_to_buf(struct uimage_handle *handle, int image_no, + size_t *size); +struct resource *file_to_sdram(const char *filename, unsigned long adr); +#define MAX_MULTI_IMAGE_COUNT 16 -image_get_hdr_u32(magic); /* image_get_magic */ -image_get_hdr_u32(hcrc); /* image_get_hcrc */ -image_get_hdr_u32(time); /* image_get_time */ -image_get_hdr_u32(size); /* image_get_size */ -image_get_hdr_u32(load); /* image_get_load */ -image_get_hdr_u32(ep); /* image_get_ep */ -image_get_hdr_u32(dcrc); /* image_get_dcrc */ +struct uimage_handle { + struct image_header header; + char *name; + struct uimage_handle_data ihd[MAX_MULTI_IMAGE_COUNT]; + int nb_data_entries; + size_t data_offset; + int fd; +}; -#define image_get_hdr_u8(x) \ -static inline uint8_t image_get_##x(const image_header_t *hdr) \ -{ \ - return hdr->ih_##x; \ -} -image_get_hdr_u8(os); /* image_get_os */ -image_get_hdr_u8(arch); /* image_get_arch */ -image_get_hdr_u8(type); /* image_get_type */ -image_get_hdr_u8(comp); /* image_get_comp */ - -static inline char *image_get_name(const image_header_t *hdr) -{ - return (char*)hdr->ih_name; -} - -static inline uint32_t image_get_data_size(const image_header_t *hdr) -{ - return image_get_size(hdr); -} - -/** - * image_get_data - get image payload start address - * @hdr: image header - * - * image_get_data() returns address of the image payload. For single - * component images it is image data start. For multi component - * images it points to the null terminated table of sub-images sizes. - * - * returns: - * image payload data start address - */ -static inline ulong image_get_data(const image_header_t *hdr) -{ - return ((ulong)hdr + image_get_header_size()); -} - -static inline uint32_t image_get_image_size(const image_header_t *hdr) -{ - return (image_get_size(hdr) + image_get_header_size()); -} - -static inline ulong image_get_image_end(const image_header_t *hdr) -{ - return ((ulong)hdr + image_get_image_size(hdr)); -} - -#define image_set_hdr_u32(x) \ -static inline void image_set_##x(image_header_t *hdr, uint32_t val) \ -{ \ - hdr->ih_##x = cpu_to_uimage(val); \ -} - -image_set_hdr_u32(magic); /* image_set_magic */ -image_set_hdr_u32(hcrc); /* image_set_hcrc */ -image_set_hdr_u32(time); /* image_set_time */ -image_set_hdr_u32(size); /* image_set_size */ -image_set_hdr_u32(load); /* image_set_load */ -image_set_hdr_u32(ep); /* image_set_ep */ -image_set_hdr_u32(dcrc); /* image_set_dcrc */ - -#define image_set_hdr_u8(x) \ -static inline void image_set_##x(image_header_t *hdr, uint8_t val) \ -{ \ - hdr->ih_##x = val; \ -} - -image_set_hdr_u8(os); /* image_set_os */ -image_set_hdr_u8(arch); /* image_set_arch */ -image_set_hdr_u8(type); /* image_set_type */ -image_set_hdr_u8(comp); /* image_set_comp */ - -static inline void image_set_name(image_header_t *hdr, const char *name) -{ - strncpy(image_get_name(hdr), name, IH_NMLEN); -} - -ulong image_multi_count(void *data); -void image_multi_getimg(void *data, ulong idx, - ulong *img_data, ulong *len); - -void image_print_size(uint32_t size); - -void image_print_contents(const image_header_t *hdr, void *data); - -/* - * Load an image into memory. Returns a pointer to the loaded - * image. - */ -struct image_handle *map_image(const char *filename, int verify); -void unmap_image(struct image_handle *handle); -struct image_handle_data* gen_image_handle_data(void* data, ulong len); - -/* - * Relocate an image to load_address by uncompressing - * or just copying. - */ -int relocate_image(struct image_handle *handle, void *load_address); +#define UIMAGE_INVALID_ADDRESS (~0) #endif /* __IMAGE_H__ */ diff --git a/include/keyboard.h b/include/keyboard.h deleted file mode 100644 index 88ae12b..0000000 --- a/include/keyboard.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __KEYBOARD_H -#define __KEYBOARD_H - -#ifdef CONFIG_PS2MULT -#include -#endif - -#if !defined(kbd_request_region) || \ - !defined(kbd_request_irq) || \ - !defined(kbd_read_input) || \ - !defined(kbd_read_status) || \ - !defined(kbd_write_output) || \ - !defined(kbd_write_command) -#error PS/2 low level routines not defined -#endif - -extern int kbd_init (void); -extern void handle_scancode(unsigned char scancode); -extern int kbd_init_hw(void); -extern void pckbd_leds(unsigned char leds); - -#endif /* __KEYBOARD_H */ diff --git a/include/libbb.h b/include/libbb.h index 2d17c3f..110e8ec 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -32,4 +32,7 @@ char *simple_itoa(unsigned int i); +int write_full(int fd, void *buf, size_t size); +int read_full(int fd, void *buf, size_t size); + #endif /* __LIBBB_H */ diff --git a/include/linux/bch.h b/include/linux/bch.h new file mode 100644 index 0000000..295b4ef --- /dev/null +++ b/include/linux/bch.h @@ -0,0 +1,79 @@ +/* + * Generic binary BCH encoding/decoding library + * + * 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., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright © 2011 Parrot S.A. + * + * Author: Ivan Djelic + * + * Description: + * + * This library provides runtime configurable encoding/decoding of binary + * Bose-Chaudhuri-Hocquenghem (BCH) codes. +*/ +#ifndef _BCH_H +#define _BCH_H + +#include + +/** + * struct bch_control - BCH control structure + * @m: Galois field order + * @n: maximum codeword size in bits (= 2^m-1) + * @t: error correction capability in bits + * @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t) + * @ecc_bytes: ecc max size (m*t bits) in bytes + * @a_pow_tab: Galois field GF(2^m) exponentiation lookup table + * @a_log_tab: Galois field GF(2^m) log lookup table + * @mod8_tab: remainder generator polynomial lookup tables + * @ecc_buf: ecc parity words buffer + * @ecc_buf2: ecc parity words buffer + * @xi_tab: GF(2^m) base for solving degree 2 polynomial roots + * @syn: syndrome buffer + * @cache: log-based polynomial representation buffer + * @elp: error locator polynomial + * @poly_2t: temporary polynomials of degree 2t + */ +struct bch_control { + unsigned int m; + unsigned int n; + unsigned int t; + unsigned int ecc_bits; + unsigned int ecc_bytes; +/* private: */ + uint16_t *a_pow_tab; + uint16_t *a_log_tab; + uint32_t *mod8_tab; + uint32_t *ecc_buf; + uint32_t *ecc_buf2; + unsigned int *xi_tab; + unsigned int *syn; + int *cache; + struct gf_poly *elp; + struct gf_poly *poly_2t[4]; +}; + +struct bch_control *init_bch(int m, int t, unsigned int prim_poly); + +void free_bch(struct bch_control *bch); + +void encode_bch(struct bch_control *bch, const uint8_t *data, + unsigned int len, uint8_t *ecc); + +int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, + const uint8_t *recv_ecc, const uint8_t *calc_ecc, + const unsigned int *syn, unsigned int *errloc); + +#endif /* _BCH_H */ diff --git a/include/linux/bitrev.h b/include/linux/bitrev.h new file mode 100644 index 0000000..7ffe03f --- /dev/null +++ b/include/linux/bitrev.h @@ -0,0 +1,16 @@ +#ifndef _LINUX_BITREV_H +#define _LINUX_BITREV_H + +#include + +extern u8 const byte_rev_table[256]; + +static inline u8 bitrev8(u8 byte) +{ + return byte_rev_table[byte]; +} + +extern u16 bitrev16(u16 in); +extern u32 bitrev32(u32 in); + +#endif /* _LINUX_BITREV_H */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 29591e2..71d3c6f 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -202,7 +202,6 @@ struct device_d class_dev; struct device_d *dev; struct cdev cdev; - struct cdev cdev_oob; struct param_d param_size; char *size_str; @@ -220,7 +219,7 @@ } /* Kernel-side ioctl definitions */ -extern int add_mtd_device(struct mtd_info *mtd); +extern int add_mtd_device(struct mtd_info *mtd, char *devname); extern int del_mtd_device (struct mtd_info *mtd); extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); diff --git a/include/mfd/twl-core.h b/include/mfd/twl-core.h new file mode 100644 index 0000000..2ab6169 --- /dev/null +++ b/include/mfd/twl-core.h @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2011 Alexander Aring + * + * Based on: + * Copyright (C) 2010 Michael Grzeschik + * Copyright (C) 2010 Sascha Hauer + * + * This file is released under the GPLv2 + * + */ + +#ifndef __I2C_TWLCORE_H__ +#define __I2C_TWLCORE_H__ + +#include +#include +#include + +struct twlcore { + struct cdev cdev; + struct i2c_client *client; +}; + +extern struct file_operations twl_fops; + +extern int twlcore_reg_read(struct twlcore *twlcore, u16 reg, u8 *val); +extern int twlcore_reg_write(struct twlcore *twlcore, u16 reg, u8 val); +extern int twlcore_set_bits(struct twlcore *twlcore, u16 reg, u8 mask, u8 val); + +#endif /* __I2C_TWLCORE_H__ */ diff --git a/include/mfd/twl4030.h b/include/mfd/twl4030.h index 3fef4d9..bc54ea6 100644 --- a/include/mfd/twl4030.h +++ b/include/mfd/twl4030.h @@ -6,12 +6,10 @@ * */ -#ifndef __I2C_TWL4030_H -#define __I2C_TWL4030_H +#ifndef __I2C_TWL4030_H__ +#define __I2C_TWL4030_H__ -#include -#include -#include +#include /* LED */ #define TWL4030_LED_LEDEN_LEDAON (1 << 0) @@ -76,7 +74,7 @@ TWL4030_PM_RECEIVER_VAUX2_VSEL_18 = 0x05, TWL4030_PM_RECEIVER_VAUX3_VSEL_28 = 0x03, TWL4030_PM_RECEIVER_VPLL2_VSEL_18 = 0x05, - TWL4030_PM_RECEIVER_VDAC_VSEL_18 = 0x03, + TWL4030_PM_RECEIVER_VDAC_VSEL_18 = 0x03, TWL4030_PM_RECEIVER_VMMC1_VSEL_30 = 0x02, /* @@ -448,14 +446,27 @@ }; struct twl4030 { - struct cdev cdev; - struct i2c_client *client; + struct twlcore core; }; extern struct twl4030 *twl4030_get(void); -extern int twl4030_reg_read(struct twl4030 *twl4030, u16 reg, u8 *val); -extern int twl4030_reg_write(struct twl4030 *twl4030, u16 reg, u8 val); -extern int twl4030_set_bits(struct twl4030 *twl4030, enum twl4030_reg reg, u8 mask, u8 val); +static inline int twl4030_reg_read(struct twl4030 *twl4030, + enum twl4030_reg reg, u8 *val) +{ + return twlcore_reg_read(&(twl4030->core), reg, val); +} -#endif /* __I2C_TWL4030_H */ +static inline int twl4030_reg_write(struct twl4030 *twl4030, + enum twl4030_reg reg, u8 val) +{ + return twlcore_reg_write(&(twl4030->core), reg, val); +} + +static inline int twl4030_set_bits(struct twl4030 *twl4030, + enum twl4030_reg reg, u8 mask, u8 val) +{ + return twlcore_set_bits(&(twl4030->core), reg, mask, val); +} + +#endif /* __I2C_TWL4030_H__ */ diff --git a/include/mfd/twl6030.h b/include/mfd/twl6030.h new file mode 100644 index 0000000..f1278d4 --- /dev/null +++ b/include/mfd/twl6030.h @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2011 Alexander Aring + * + * This file is released under the GPLv2 + * + */ + +#ifndef __I2C_TWL6030_H__ +#define __I2C_TWL6030_H__ + +#include + +/* VMMC_CFG_VOLTAGE */ +#define TWL6030_VMMC_VSEL_0 (1 << 0) +#define TWL6030_VMMC_VSEL_1 (1 << 1) +#define TWL6030_VMMC_VSEL_2 (1 << 2) +#define TWL6030_VMMC_VSEL_3 (1 << 3) +#define TWL6030_VMMC_VSEL_4 (1 << 4) +#define TWL6030_VMMC_WR_S (1 << 7) + +/* VMMC_CFG_STATE (W) */ +#define TWL6030_VMMC_STATE0 (1 << 0) +#define TWL6030_VMMC_STATE1 (1 << 1) +#define TWL6030_VMMC_GRP_APP (1 << 5) +#define TWL6030_VMMC_GRP_CON (1 << 6) +#define TWL6030_VMMC_GRP_MOD (1 << 7) + +enum twl6030_reg { + /* RTC */ + TWL6030_RTC_SECONDS = 0x0000, + TWL6030_RTC_MINUTES = 0x0001, + TWL6030_RTC_HOURS = 0x0002, + TWL6030_RTC_DAYS = 0x0003, + TWL6030_RTC_MONTHS = 0x0004, + TWL6030_RTC_YEARS = 0x0005, + TWL6030_RTC_WEEKS = 0x0006, + TWL6030_RTC_ALARM_SECONDS = 0x0008, + TWL6030_RTC_ALARM_MINUTES = 0x0009, + TWL6030_RTC_ALARM_HOURS = 0x000A, + TWL6030_RTC_ALARM_DAYS = 0x000B, + TWL6030_RTC_ALARM_MONTHS = 0x000C, + TWL6030_RTC_ALARM_YEARS = 0x000D, + TWL6030_RTC_CTRL = 0x0010, + TWL6030_RTC_STATUS = 0x0011, + TWL6030_RTC_INTERRUPTS = 0x0012, + TWL6030_RTC_COMP_LSB = 0x0013, + TWL6030_RTC_COMP_MSB = 0x0014, + TWL6030_RTC_RESET_STATUS = 0x0016, + /* MEM */ + TWL6030_MEM_VALIDITY0 = 0x0017, + TWL6030_MEM_VALIDITY1 = 0x0018, + TWL6030_MEM_VALIDITY2 = 0x0019, + TWL6030_MEM_VALIDITY3 = 0x001A, + TWL6030_MEM_VALIDITY4 = 0x001B, + TWL6030_MEM_VALIDITY5 = 0x001C, + TWL6030_MEM_VALIDITY6 = 0x001D, + TWL6030_MEM_VALIDITY7 = 0x001E, + /* PMC Master */ + TWL6030_PMCM_START = 0x001F, + TWL6030_PMCM_MSK = 0x0020, + TWL6030_PMCM_HW = 0x0021, + TWL6030_PMCM_TURNOFF = 0x0022, + TWL6030_PMCM_VBAT_THRESHOLD_LO = 0x0023, + TWL6030_PMCM_VBAT_THRESHOLD_HI = 0x0024, + TWL6030_PMCM_DEV_ON = 0x0025, + TWL6030_PMCM_PWR_GRP_STATE = 0x0027, + TWL6030_PMCM_CFG_VBATLOWV = 0x0028, + TWL6030_PMCM_STS_BOOT = 0x0029, + TWL6030_PMCM_SENS_TRANSITION = 0x002A, + TWL6030_PMCM_SEQ_CFG = 0x002B, + TWL6030_PMCM_PRIMARY_WATCHDOG_CFG = 0x002C, + TWL6030_PMCM_KEY_PRESS_DURATION_CFG = 0x002D, + /* PMC Slave MISC */ + TWL6030_PMCS_ADDRESS_ALL = 0x0031, + TWL6030_PMCS_ADDRESS_REF = 0x0032, + TWL6030_PMCS_ADDRESS_PROV = 0x0033, + TWL6030_PMCS_ADDRESS_CLK_RST = 0x0034, + /* PMC Slave SMPS */ + TWL6030_PMCS_V1V29_CFG_GRP = 0x0040, + TWL6030_PMCS_V1V29_CFG_TRANS = 0x0041, + TWL6030_PMCS_V1V29_CFG_STATE = 0x0042, + TWL6030_PMCS_V1V29_CFG_VOLTAGE = 0x0044, + TWL6030_PMCS_V1V8_CFG_GRP = 0x0046, + TWL6030_PMCS_V1V8_CFG_TRANS = 0x0047, + TWL6030_PMCS_V1V8_CFG_STATE = 0x0048, + TWL6030_PMCS_V1V8_CFG_VOLTAGE = 0x004A, + TWL6030_PMCS_V2V1_CFG_GRP = 0x004C, + TWL6030_PMCS_V2V1_CFG_TRANS = 0x004D, + TWL6030_PMCS_V2V1_CFG_STATE = 0x004E, + TWL6030_PMCS_V2V1_CFG_VOLTAGE = 0x0050, + TWL6030_PMCS_VCORE1_CFG_GRP = 0x0052, + TWL6030_PMCS_VCORE1_CFG_TRANS = 0x0053, + TWL6030_PMCS_VCORE1_CFG_STATE = 0x0054, + TWL6030_PMCS_VCORE1_CFG_STEP = 0x0057, + TWL6030_PMCS_VCORE2_CFG_GRP = 0x0058, + TWL6030_PMCS_VCORE2_CFG_TRANS = 0x0059, + TWL6030_PMCS_VCORE2_CFG_STATE = 0x005A, + TWL6030_PMCS_VCORE2_CFG_STEP = 0x005D, + TWL6030_PMCS_VCORE3_CFG_GRP = 0x005E, + TWL6030_PMCS_VCORE3_CFG_TRANS = 0x005F, + TWL6030_PMCS_VCORE3_CFG_STATE = 0x0060, + TWL6030_PMCS_VCORE3_CFG_STEP = 0x0063, + TWL6030_PMCS_VMEM_CFG_GRP = 0x0064, + TWL6030_PMCS_VMEM_CFG_TRANS = 0x0065, + TWL6030_PMCS_VMEM_CFG_STATE = 0x0066, + TWL6030_PMCS_VMEM_CFG_VOLTAGE = 0x0068, + /* PMC Slave LDO */ + TWL6030_PMCS_VANA_CFG_GRP = 0x0080, + TWL6030_PMCS_VANA_CFG_TRANS = 0x0081, + TWL6030_PMCS_VANA_CFG_STATE = 0x0082, + TWL6030_PMCS_VANA_CFG_VOLTAGE = 0x0083, + TWL6030_PMCS_VAUX1_CFG_GRP = 0x0084, + TWL6030_PMCS_VAUX1_CFG_TRANS = 0x0085, + TWL6030_PMCS_VAUX1_CFG_STATE = 0x0086, + TWL6030_PMCS_VAUX1_CFG_VOLTAGE = 0x0087, + TWL6030_PMCS_VAUX2_CFG_GRP = 0x0088, + TWL6030_PMCS_VAUX2_CFG_TRANS = 0x0089, + TWL6030_PMCS_VAUX2_CFG_STATE = 0x008A, + TWL6030_PMCS_VAUX2_CFG_VOLTAGE = 0x008B, + TWL6030_PMCS_VAUX3_CFG_GRP = 0x008C, + TWL6030_PMCS_VAUX3_CFG_TRANS = 0x008D, + TWL6030_PMCS_VAUX3_CFG_STATE = 0x008E, + TWL6030_PMCS_VAUX3_CFG_VOLTAGE = 0x008F, + TWL6030_PMCS_VCXIO_CFG_GRP = 0x0090, + TWL6030_PMCS_VCXIO_CFG_TRANS = 0x0091, + TWL6030_PMCS_VCXIO_CFG_STATE = 0x0092, + TWL6030_PMCS_VCXIO_CFG_VOLTAGE = 0x0093, + TWL6030_PMCS_VDAC_CFG_GRP = 0x0094, + TWL6030_PMCS_VDAC_CFG_TRANS = 0x0095, + TWL6030_PMCS_VDAC_CFG_STATE = 0x0096, + TWL6030_PMCS_VDAC_CFG_VOLTAGE = 0x0097, + TWL6030_PMCS_VMMC_CFG_GRP = 0x0098, + TWL6030_PMCS_VMMC_CFG_TRANS = 0x0099, + TWL6030_PMCS_VMMC_CFG_STATE = 0x009A, + TWL6030_PMCS_VMMC_CFG_VOLTAGE = 0x009B, + TWL6030_PMCS_VPP_CFG_GRP = 0x009C, + TWL6030_PMCS_VPP_CFG_TRANS = 0x009D, + TWL6030_PMCS_VPP_CFG_STATE = 0x009E, + TWL6030_PMCS_VPP_CFG_VOLTAGE = 0x009F, + TWL6030_PMCS_VUSB_CFG_GRP = 0x00A0, + TWL6030_PMCS_VUSB_CFG_TRANS = 0x00A1, + TWL6030_PMCS_VUSB_CFG_STATE = 0x00A2, + TWL6030_PMCS_VUSB_CFG_VOLTAGE = 0x00A3, + TWL6030_PMCS_VUSIM_CFG_GRP = 0x00A4, + TWL6030_PMCS_VUSIM_CFG_TRANS = 0x00A5, + TWL6030_PMCS_VUSIM_CFG_STATE = 0x00A6, + TWL6030_PMCS_VUSIM_CFG_VOLTAGE = 0x00A7, + /* Resource Register Map */ + TWL6030_PMCS_REGEN1_CFG_GRP = 0x00AD, + TWL6030_PMCS_REGEN1_CFG_TRANS = 0x00AE, + TWL6030_PMCS_REGEN1_CFG_STATE = 0x00AF, + TWL6030_PMCS_REGEN2_CFG_GRP = 0x00B0, + TWL6030_PMCS_REGEN2_CFG_TRANS = 0x00B1, + TWL6030_PMCS_REGEN2_CFG_STATE = 0x00B2, + TWL6030_PMCS_SYSEN_CFG_GRP = 0x00B3, + TWL6030_PMCS_SYSEN_CFG_TRANS = 0x00B4, + TWL6030_PMCS_SYSEN_CFG_STATE = 0x00B5, + TWL6030_PMCS_NRESPWRON_CFG_GRP = 0x00B6, + TWL6030_PMCS_NRESPWRON_CFG_TRANS = 0x00B7, + TWL6030_PMCS_NRESPWRON_CFG_STATE = 0x00B8, + TWL6030_PMCS_CLK32KAO_CFG_GRP = 0x00B9, + TWL6030_PMCS_CLK32KAO_CFG_TRANS = 0x00BA, + TWL6030_PMCS_CLK32KAO_CFG_STATE = 0x00BB, + TWL6030_PMCS_CLK32KG_CFG_GRP = 0x00BC, + TWL6030_PMCS_CLK32KG_CFG_TRANS = 0x00BD, + TWL6030_PMCS_CLK32KG_CFG_STATE = 0x00BE, + TWL6030_PMCS_CLK32KAUDIO_CFG_GRP = 0x00BF, + TWL6030_PMCS_CLK32KAUDIO_CFG_TRANS = 0x00C0, + TWL6030_PMCS_CLK32KAUDIO_CFG_STATE = 0x00C1, + TWL6030_PMCS_VRTC_CFG_GRP = 0x00C2, + TWL6030_PMCS_VRTC_CFG_TRANS = 0x00C3, + TWL6030_PMCS_VRTC_CFG_STATE = 0x00C4, + TWL6030_PMCS_BIAS_CFG_GRP = 0x00C5, + TWL6030_PMCS_BIAS_CFG_TRANS = 0x00C6, + TWL6030_PMCS_BIAS_CFG_STATE = 0x00C7, + TWL6030_PMCS_VBATMIN_CFG_GRP = 0x00C8, + TWL6030_PMCS_VBATMIN_CFG_TRANS = 0x00C9, + TWL6030_PMCS_VBATMIN_CFG_STATE = 0x00CA, + TWL6030_PMCS_RC6MHZ_CFG_GRP = 0x00CB, + TWL6030_PMCS_RC6MHZ_CFG_TRANS = 0x00CC, + TWL6030_PMCS_RC6MHZ_CFG_STATE = 0x00CD, + TWL6030_PMCS_TMP_CFG_GRP = 0x00CE, + TWL6030_PMCS_TMP_CFG_TRANS = 0x00CF, + TWL6030_PMCS_TMP_CFG_STATE = 0x00D0, + /* Misc Register */ + TWL6030_PMC_SMPS_OFFSET = 0x00E0, + TWL6030_PMC_SMPS_MULT = 0x00E3, + TWL6030_PMC_SMPS_MISC1 = 0x00E4, + TWL6030_PMC_SMPS_MISC2 = 0x00E5, + TWL6030_PMC_SMPS_BBSPOR_CFG = 0x00E6, + TWL6030_PMC_SMPS_TMP_CFG = 0x00E7, + TWL6030_PMC_SMPS_FORCE_SMPS_CLK = 0x00E8, + TWL6030_PMC_SMPS_SIMDEBOUNCING = 0x00EB, + TWL6030_PMC_SMPS_SIMCTRL = 0x00EC, + TWL6030_PMC_SMPS_MMCDEBOUNCING = 0x00ED, + TWL6030_PMC_SMPS_MMCCTRL = 0x00EE, + TWL6030_PMC_SMPS_BATDEBOUNCING = 0x00EF, + /* Pull-up | Pull-down | High-Z */ + TWL6030_PMC_CFG_INPUT_PUPD1 = 0x00F0, + TWL6030_PMC_CFG_INPUT_PUPD2 = 0x00F1, + TWL6030_PMC_CFG_INPUT_PUPD3 = 0x00F2, + TWL6030_PMC_CFG_INPUT_PUPD4 = 0x00F3, + TWL6030_PMC_CFG_LDO_PD1 = 0x00F4, + TWL6030_PMC_CFG_LDO_PD2 = 0x00F5, + TWL6030_PMC_CFG_SMPS_PD = 0x00F6, + /* OTG Backup */ + TWL6030_OTG_BACKUP_REG = 0x00FA, + /* USB OTG */ + TWL6030_OTG_USB_VENDORID_LO = 0x0100, + TWL6030_OTG_USB_VENDORID_HI = 0x0101, + TWL6030_OTG_USB_PRODUCTID_LO = 0x0102, + TWL6030_OTG_USB_PRODUCTID_HI = 0x0103, + TWL6030_OTG_USB_VBUS_CTRL_SET = 0x0104, + TWL6030_OTG_USB_VBUS_CTRL_CLR = 0x0105, + TWL6030_OTG_USB_ID_CTRL_SET = 0x0106, + TWL6030_OTG_USB_ID_CTRL_CLR = 0x0107, + TWL6030_OTG_USB_VBUS_INT_SRC = 0x0108, + TWL6030_OTG_USB_VBUS_INT_LATCH_SET = 0x0109, + TWL6030_OTG_USB_VBUS_INT_LATCH_CLR = 0x010A, + TWL6030_OTG_USB_VBUS_INT_EN_LO_SET = 0x010B, + TWL6030_OTG_USB_VBUS_INT_EN_LO_CLR = 0x010C, + TWL6030_OTG_USB_VBUS_INT_EN_HI_SET = 0x010D, + TWL6030_OTG_USB_VBUS_INT_EN_HI_CLR = 0x010E, + TWL6030_OTG_USB_ID_INT_SRC = 0x010F, + TWL6030_OTG_USB_ID_INT_LATCH_SET = 0x0110, + TWL6030_OTG_USB_ID_INT_LATCH_CLR = 0x0111, + TWL6030_OTG_USB_ID_INT_EN_LO_SET = 0x0112, + TWL6030_OTG_USB_ID_INT_EN_LO_CLR = 0x0113, + TWL6030_OTG_USB_ID_INT_EN_HI_SET = 0x0114, + TWL6030_OTG_USB_ID_INT_EN_HI_CLR = 0x0115, + TWL6030_OTG_USB_ADP_CTRL = 0x0116, + TWL6030_OTG_USB_ADP_HIGH = 0x0117, + TWL6030_OTG_USB_ADP_LOW = 0x0118, + TWL6030_OTG_USB_ADP_RISE = 0x0119, + /* GPADC Control */ + TWL6030_GPADC_CTRL = 0x012E, + TWL6030_GPADC_RTSELECT_LSB = 0x0130, + TWL6030_GPADC_RTSELECT_ISB = 0x0131, + TWL6030_GPADC_RTSELECT_MSB = 0x0132, + TWL6030_GPADC_CTRL_P1 = 0x0133, + TWL6030_GPADC_CTRL_P2 = 0x0134, + /* GPADC Real Time */ + TWL6030_GPADC_RTCH0_LO = 0x0135, + TWL6030_GPADC_RTCH0_HI = 0x0136, + TWL6030_GPADC_RTCH1_LO = 0x0137, + TWL6030_GPADC_RTCH1_HI = 0x0138, + TWL6030_GPADC_RTCH2_LO = 0x0139, + TWL6030_GPADC_RTCH2_HI = 0x013A, + TWL6030_GPADC_RTCH3_LO = 0x013B, + TWL6030_GPADC_RTCH3_HI = 0x013C, + TWL6030_GPADC_RTCH4_LO = 0x013D, + TWL6030_GPADC_RTCH4_HI = 0x013E, + TWL6030_GPADC_RTCH5_LO = 0x013F, + TWL6030_GPADC_RTCH5_HI = 0x0140, + TWL6030_GPADC_RTCH6_LO = 0x0141, + TWL6030_GPADC_RTCH6_HI = 0x0142, + TWL6030_GPADC_RTCH7_LO = 0x0143, + TWL6030_GPADC_RTCH7_HI = 0x0144, + TWL6030_GPADC_RTCH8_LO = 0x0145, + TWL6030_GPADC_RTCH8_HI = 0x0146, + TWL6030_GPADC_RTCH9_LO = 0x0147, + TWL6030_GPADC_RTCH9_HI = 0x0148, + TWL6030_GPADC_RTCH10_LO = 0x0149, + TWL6030_GPADC_RTCH10_HI = 0x014A, + TWL6030_GPADC_RTCH11_LO = 0x014B, + TWL6030_GPADC_RTCH11_HI = 0x014C, + TWL6030_GPADC_RTCH12_LO = 0x014D, + TWL6030_GPADC_RTCH12_HI = 0x014E, + TWL6030_GPADC_RTCH13_LO = 0x014F, + TWL6030_GPADC_RTCH13_HI = 0x0150, + TWL6030_GPADC_RTCH14_LO = 0x0151, + TWL6030_GPADC_RTCH14_HI = 0x0152, + TWL6030_GPADC_RTCH15_LO = 0x0153, + TWL6030_GPADC_RTCH15_HI = 0x0154, + TWL6030_GPADC_RTCH16_LO = 0x0155, + TWL6030_GPADC_RTCH16_HI = 0x0156, + /* GPADC General Purpose */ + TWL6030_GPADC_GPCH0_LO = 0x0157, + TWL6030_GPADC_GPCH0_HI = 0x0158, + TWL6030_GPADC_GPCH1_LO = 0x0159, + TWL6030_GPADC_GPCH1_HI = 0x015A, + TWL6030_GPADC_GPCH2_LO = 0x015B, + TWL6030_GPADC_GPCH2_HI = 0x015C, + TWL6030_GPADC_GPCH3_LO = 0x015D, + TWL6030_GPADC_GPCH3_HI = 0x015E, + TWL6030_GPADC_GPCH4_LO = 0x015F, + TWL6030_GPADC_GPCH4_HI = 0x0160, + TWL6030_GPADC_GPCH5_LO = 0x0161, + TWL6030_GPADC_GPCH5_HI = 0x0162, + TWL6030_GPADC_GPCH6_LO = 0x0163, + TWL6030_GPADC_GPCH6_HI = 0x0164, + TWL6030_GPADC_GPCH7_LO = 0x0165, + TWL6030_GPADC_GPCH7_HI = 0x0166, + TWL6030_GPADC_GPCH8_LO = 0x0167, + TWL6030_GPADC_GPCH8_HI = 0x0168, + TWL6030_GPADC_GPCH9_LO = 0x0169, + TWL6030_GPADC_GPCH9_HI = 0x016A, + TWL6030_GPADC_GPCH10_LO = 0x016B, + TWL6030_GPADC_GPCH10_HI = 0x016C, + TWL6030_GPADC_GPCH11_LO = 0x016D, + TWL6030_GPADC_GPCH11_HI = 0x016E, + TWL6030_GPADC_GPCH12_LO = 0x016F, + TWL6030_GPADC_GPCH12_HI = 0x0170, + TWL6030_GPADC_GPCH13_LO = 0x0171, + TWL6030_GPADC_GPCH13_HI = 0x0172, + TWL6030_GPADC_GPCH14_LO = 0x0173, + TWL6030_GPADC_GPCH14_HI = 0x0174, + TWL6030_GPADC_GPCH15_LO = 0x0175, + TWL6030_GPADC_GPCH15_HI = 0x0176, + TWL6030_GPADC_GPCH16_LO = 0x0177, + TWL6030_GPADC_GPCH16_HI = 0x0178, + /* Auxiliaries Register */ + TWL6030_AUX_TOGGLE1 = 0x0190, + TWL6030_AUX_TOGGLE2 = 0x0191, + TWL6030_AUX_TOGGLE3 = 0x0192, + TWL6030_AUX_PWDNSTATUS1 = 0x0193, + TWL6030_AUX_PWDNSTATUS2 = 0x0194, + TWL6030_AUX_VIBCTRL = 0x019B, + TWL6030_AUX_VIBMODE = 0x019C, + /* PWM Register */ + TWL6030_PWM_PWM1ON = 0x019C, + TWL6030_PWM_PWM1OFF = 0x019C, + TWL6030_PWM_PWM2ON = 0x019C, + TWL6030_PWM_PWM2OFF = 0x019C, + /* Gas Gauge Register */ + TWL6030_FG_REG_00 = 0x01C0, + TWL6030_FG_REG_01 = 0x01C1, + TWL6030_FG_REG_02 = 0x01C2, + TWL6030_FG_REG_03 = 0x01C3, + TWL6030_FG_REG_04 = 0x01C4, + TWL6030_FG_REG_05 = 0x01C5, + TWL6030_FG_REG_06 = 0x01C6, + TWL6030_FG_REG_07 = 0x01C7, + TWL6030_FG_REG_08 = 0x01C8, + TWL6030_FG_REG_09 = 0x01C9, + TWL6030_FG_REG_10 = 0x01CA, + TWL6030_FG_REG_11 = 0x01CB, + /* Interfaces Interrupts */ + TWL6030_INT_STS_A = 0x01D0, + TWL6030_INT_STS_B = 0x01D1, + TWL6030_INT_STS_C = 0x01D2, + TWL6030_INT_MSK_LINE_A = 0x01D3, + TWL6030_INT_MSK_LINE_B = 0x01D4, + TWL6030_INT_MSK_LINE_C = 0x01D5, + TWL6030_INT_MSK_STS_A = 0x01D6, + TWL6030_INT_MSK_STS_B = 0x01D7, + TWL6030_INT_MSK_STS_C = 0x01D8, + /* Charger Regisers */ + TWL6030_CHR_CONTROLLER_INT_MASK = 0x01E0, + TWL6030_CHR_CONTROLLER_CTRL1 = 0x01E1, + TWL6030_CHR_CONTROLLER_WDG = 0x01E2, + TWL6030_CHR_CONTROLLER_STAT1 = 0x01E3, + TWL6030_CHR_CHARGERUSB_INT_STATUS = 0x01E4, + TWL6030_CHR_CHARGERUSB_INT_MASK = 0x01E5, + TWL6030_CHR_CHARGERUSB_STATUS_INT1 = 0x01E6, + TWL6030_CHR_CHARGERUSB_STATUS_INT2 = 0x01E7, + TWL6030_CHR_CHARGERUSB_CTRL1 = 0x01E8, + TWL6030_CHR_CHARGERUSB_CTRL2 = 0x01E9, + TWL6030_CHR_CHARGERUSB_CTRL3 = 0x01EA, + TWL6030_CHR_CHARGERUSB_STAT1 = 0x01EB, + TWL6030_CHR_CHARGERUSB_VOREG = 0x01EC, + TWL6030_CHR_CHARGERUSB_VICHRG = 0x01ED, + TWL6030_CHR_CHARGERUSB_CINLIMIT = 0x01EE, + TWL6030_CHR_CHARGERUSB_CTRLLIMIT1 = 0x01EF, + TWL6030_CHR_CHARGERUSB_CTRLLIMIT2 = 0x01F0, + TWL6030_CHR_ANTICOLLAPSE_CTRL1 = 0x01F1, + TWL6030_CHR_ANTICOLLAPSE_CTRL2 = 0x01F2, + TWL6030_CHR_ANTICOLLAPSE_STAT1 = 0x01F3, + TWL6030_CHR_LED_PWM_CTRL1 = 0x01F4, + TWL6030_CHR_LED_PWM_CTRL2 = 0x01F5, + /* JTAG */ + TWL6030_JTAG_JTAGVERNUM = 0x0287, + TWL6030_JTAG_EPROM_REV = 0x02DF, + /* GPADC Trimming */ + TWL6030_GPADC_TRIM1 = 0x02CD, + TWL6030_GPADC_TRIM2 = 0x02CE, + TWL6030_GPADC_TRIM3 = 0x02CF, + TWL6030_GPADC_TRIM4 = 0x02D0, + TWL6030_GPADC_TRIM5 = 0x02D1, + TWL6030_GPADC_TRIM6 = 0x02D2, + TWL6030_GPADC_TRIM7 = 0x02D3, + TWL6030_GPADC_TRIM8 = 0x02D4, + TWL6030_GPADC_TRIM9 = 0x02D5, + TWL6030_GPADC_TRIM10 = 0x02D6, + TWL6030_GPADC_TRIM11 = 0x02D7, + TWL6030_GPADC_TRIM12 = 0x02D8, + TWL6030_GPADC_TRIM13 = 0x02D9, + TWL6030_GPADC_TRIM14 = 0x02DA, + TWL6030_GPADC_TRIM15 = 0x02DB, + TWL6030_GPADC_TRIM16 = 0x02DC, + TWL6030_GPADC_TRIM17 = 0x02DD, + TWL6030_GPADC_TRIM18 = 0x02DE, +}; + +struct twl6030 { + struct twlcore core; +}; + +extern struct twl6030 *twl6030_get(void); + +static inline int twl6030_reg_read(struct twl6030 *twl6030, + enum twl6030_reg reg, u8 *val) +{ + return twlcore_reg_read(&twl6030->core, reg, val); +} + +static inline int twl6030_reg_write(struct twl6030 *twl6030, + enum twl6030_reg reg, u8 val) +{ + return twlcore_reg_write(&twl6030->core, reg, val); +} + +static inline int twl6030_set_bits(struct twl6030 *twl6030, + enum twl6030_reg reg, u8 mask, u8 val) +{ + return twlcore_set_bits(&twl6030->core, reg, mask, val); +} + +#endif /* __I2C_TWL6030_H__ */ diff --git a/include/of.h b/include/of.h index c2661ef..609b3b5 100644 --- a/include/of.h +++ b/include/of.h @@ -8,6 +8,7 @@ int fdt_print(struct fdt_header *working_fdt, const char *pathp); struct fdt_header *of_get_fixed_tree(void); +int of_fix_tree(struct fdt_header *fdt); int of_register_fixup(int (*fixup)(struct fdt_header *)); int fdt_find_and_setprop(struct fdt_header *fdt, const char *node, const char *prop, diff --git a/include/stringlist.h b/include/stringlist.h index 3453e9a..c923542 100644 --- a/include/stringlist.h +++ b/include/stringlist.h @@ -9,6 +9,8 @@ }; int string_list_add(struct string_list *sl, char *str); +int string_list_add_sorted(struct string_list *sl, char *str); +int string_list_contains(struct string_list *sl, char *str); void string_list_print_by_column(struct string_list *sl); static inline void string_list_init(struct string_list *sl) diff --git a/include/tlsf.h b/include/tlsf.h new file mode 100644 index 0000000..d575e16 --- /dev/null +++ b/include/tlsf.h @@ -0,0 +1,52 @@ +#ifndef INCLUDED_tlsf +#define INCLUDED_tlsf + +/* +** Two Level Segregated Fit memory allocator, version 1.9. +** Written by Matthew Conte, and placed in the Public Domain. +** http://tlsf.baisoku.org +** +** Based on the original documentation by Miguel Masmano: +** http://rtportal.upv.es/rtmalloc/allocators/tlsf/index.shtml +** +** Please see the accompanying Readme.txt for implementation +** notes and caveats. +** +** This implementation was written to the specification +** of the document, therefore no GPL restrictions apply. +*/ + +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Create/destroy a memory pool. */ +typedef void* tlsf_pool; +tlsf_pool tlsf_create(void* mem, size_t bytes); +void tlsf_destroy(tlsf_pool pool); + +/* malloc/memalign/realloc/free replacements. */ +void* tlsf_malloc(tlsf_pool pool, size_t bytes); +void* tlsf_memalign(tlsf_pool pool, size_t align, size_t bytes); +void* tlsf_realloc(tlsf_pool pool, void* ptr, size_t size); +void tlsf_free(tlsf_pool pool, void* ptr); + +/* Debugging. */ +typedef void (*tlsf_walker)(void* ptr, size_t size, int used, void* user); +void tlsf_walk_heap(tlsf_pool pool, tlsf_walker walker, void* user); +/* Returns nonzero if heap check fails. */ +int tlsf_check_heap(tlsf_pool pool); + +/* Returns internal block size, not original request size */ +size_t tlsf_block_size(void* ptr); + +/* Overhead of per-pool internal structures. */ +size_t tlsf_overhead(void); + +#if defined(__cplusplus) +}; +#endif + +#endif diff --git a/include/usb/usbserial.h b/include/usb/usbserial.h new file mode 100644 index 0000000..43c839c --- /dev/null +++ b/include/usb/usbserial.h @@ -0,0 +1,19 @@ +#ifndef _USB_SERIAL_H +#define _USB_SERIAL_H + +struct usb_serial_pdata { + char *manufacturer; + char *productname; + u16 idVendor; + u16 idProduct; + int mode; +}; + +int usb_serial_register(struct usb_serial_pdata *pdata); +void usb_serial_unregister(void); + +/* OBEX support is missing in barebox */ +/* #define HAVE_OBEX */ + +#endif /* _USB_SERIAL_H */ + diff --git a/include/watchdog.h b/include/watchdog.h deleted file mode 100644 index 9265be9..0000000 --- a/include/watchdog.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * (C) Copyright 2001 - * Erik Theisen, Wave 7 Optics, etheisen@mindspring.com. - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* - * Watchdog functions and macros. - */ -#ifndef _WATCHDOG_H_ -#define _WATCHDOG_H_ - -#if defined(CONFIG_HW_WATCHDOG) && defined(CONFIG_WATCHDOG) -# error "Configuration error: CONFIG_HW_WATCHDOG and CONFIG_WATCHDOG can't be used together." -#endif - -#if defined(__ASSEMBLY__) && defined(__NIOS__) -# error "Configuration error: WATCHDOG_RESET inside assembler not supported for Nios platforms." -#endif - -/* - * Hardware watchdog - */ -#ifdef CONFIG_HW_WATCHDOG - #if defined(__ASSEMBLY__) - #define WATCHDOG_RESET bl hw_watchdog_reset - #else - extern void hw_watchdog_reset(void); - - #define WATCHDOG_RESET hw_watchdog_reset - #endif /* __ASSEMBLY__ */ -#else - /* - * Maybe a software watchdog? - */ - #if defined(CONFIG_WATCHDOG) - #if defined(__ASSEMBLY__) - #define WATCHDOG_RESET bl watchdog_reset - #else - extern void watchdog_reset(void); - - #define WATCHDOG_RESET watchdog_reset - #endif - #else - /* - * No hardware or software watchdog. - */ - #if defined(__ASSEMBLY__) - #define WATCHDOG_RESET /*XXX DO_NOT_DEL_THIS_COMMENT*/ - #else - #define WATCHDOG_RESET() {} - #endif /* __ASSEMBLY__ */ - #endif /* CONFIG_WATCHDOG && !__ASSEMBLY__ */ -#endif /* CONFIG_HW_WATCHDOG */ - -/* - * Prototypes from $(CPU)/cpu.c. - */ - -/* MPC 8xx */ -#if (defined(CONFIG_8xx) || defined(CONFIG_MPC860)) && !defined(__ASSEMBLY__) - void reset_8xx_watchdog(volatile immap_t *immr); -#endif - -/* MPC 5xx */ -#if defined(CONFIG_5xx) && !defined(__ASSEMBLY__) - void reset_5xx_watchdog(volatile immap_t *immr); -#endif - -/* AMCC 4xx */ -#if defined(CONFIG_4xx) && !defined(__ASSEMBLY__) - void reset_4xx_watchdog(void); -#endif - -#endif /* _WATCHDOG_H_ */ diff --git a/lib/Kconfig b/lib/Kconfig index e16dd35..3339a9a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -19,4 +19,11 @@ config OFTREE select FDT bool + +config BCH + bool + +config BITREV + bool + endmenu diff --git a/lib/Makefile b/lib/Makefile index ae76b4c..7799e69 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -31,3 +31,5 @@ obj-$(CONFIG_PROCESS_ESCAPE_SEQUENCE) += process_escape_sequence.o obj-$(CONFIG_FDT) += fdt/ obj-y += uncompress.o +obj-$(CONFIG_BCH) += bch.o +obj-$(CONFIG_BITREV) += bitrev.o diff --git a/lib/bch.c b/lib/bch.c new file mode 100644 index 0000000..5797c3f --- /dev/null +++ b/lib/bch.c @@ -0,0 +1,1366 @@ +/* + * Generic binary BCH encoding/decoding library + * + * 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. + * + * Copyright © 2011 Parrot S.A. + * + * Author: Ivan Djelic + * + * Description: + * + * This library provides runtime configurable encoding/decoding of binary + * Bose-Chaudhuri-Hocquenghem (BCH) codes. + * + * Call init_bch to get a pointer to a newly allocated bch_control structure for + * the given m (Galois field order), t (error correction capability) and + * (optional) primitive polynomial parameters. + * + * Call encode_bch to compute and store ecc parity bytes to a given buffer. + * Call decode_bch to detect and locate errors in received data. + * + * On systems supporting hw BCH features, intermediate results may be provided + * to decode_bch in order to skip certain steps. See decode_bch() documentation + * for details. + * + * Option CONFIG_BCH_CONST_PARAMS can be used to force fixed values of + * parameters m and t; thus allowing extra compiler optimizations and providing + * better (up to 2x) encoding performance. Using this option makes sense when + * (m,t) are fixed and known in advance, e.g. when using BCH error correction + * on a particular NAND flash device. + * + * Algorithmic details: + * + * Encoding is performed by processing 32 input bits in parallel, using 4 + * remainder lookup tables. + * + * The final stage of decoding involves the following internal steps: + * a. Syndrome computation + * b. Error locator polynomial computation using Berlekamp-Massey algorithm + * c. Error locator root finding (by far the most expensive step) + * + * In this implementation, step c is not performed using the usual Chien search. + * Instead, an alternative approach described in [1] is used. It consists in + * factoring the error locator polynomial using the Berlekamp Trace algorithm + * (BTA) down to a certain degree (4), after which ad hoc low-degree polynomial + * solving techniques [2] are used. The resulting algorithm, called BTZ, yields + * much better performance than Chien search for usual (m,t) values (typically + * m >= 13, t < 32, see [1]). + * + * [1] B. Biswas, V. Herbert. Efficient root finding of polynomials over fields + * of characteristic 2, in: Western European Workshop on Research in Cryptology + * - WEWoRC 2009, Graz, Austria, LNCS, Springer, July 2009, to appear. + * [2] [Zin96] V.A. Zinoviev. On the solution of equations of degree 10 over + * finite fields GF(2^q). In Rapport de recherche INRIA no 2829, 1996. + * + * Taken from the linux kernel. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_BCH_CONST_PARAMS) +#define GF_M(_p) (CONFIG_BCH_CONST_M) +#define GF_T(_p) (CONFIG_BCH_CONST_T) +#define GF_N(_p) ((1 << (CONFIG_BCH_CONST_M))-1) +#else +#define GF_M(_p) ((_p)->m) +#define GF_T(_p) ((_p)->t) +#define GF_N(_p) ((_p)->n) +#endif + +#define BCH_ECC_WORDS(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32) +#define BCH_ECC_BYTES(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8) + +#ifndef dbg +#define dbg(_fmt, args...) do {} while (0) +#endif + +/* + * represent a polynomial over GF(2^m) + */ +struct gf_poly { + unsigned int deg; /* polynomial degree */ + unsigned int c[0]; /* polynomial terms */ +}; + +/* given its degree, compute a polynomial size in bytes */ +#define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int)) + +/* polynomial of degree 1 */ +struct gf_poly_deg1 { + struct gf_poly poly; + unsigned int c[2]; +}; + +/* + * same as encode_bch(), but process input data one byte at a time + */ +static void encode_bch_unaligned(struct bch_control *bch, + const unsigned char *data, unsigned int len, + uint32_t *ecc) +{ + int i; + const uint32_t *p; + const int l = BCH_ECC_WORDS(bch)-1; + + while (len--) { + p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff); + + for (i = 0; i < l; i++) + ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++); + + ecc[l] = (ecc[l] << 8)^(*p); + } +} + +/* + * convert ecc bytes to aligned, zero-padded 32-bit ecc words + */ +static void load_ecc8(struct bch_control *bch, uint32_t *dst, + const uint8_t *src) +{ + uint8_t pad[4] = {0, 0, 0, 0}; + unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; + + for (i = 0; i < nwords; i++, src += 4) + dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3]; + + memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords); + dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3]; +} + +/* + * convert 32-bit ecc words to ecc bytes + */ +static void store_ecc8(struct bch_control *bch, uint8_t *dst, + const uint32_t *src) +{ + uint8_t pad[4]; + unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; + + for (i = 0; i < nwords; i++) { + *dst++ = (src[i] >> 24); + *dst++ = (src[i] >> 16) & 0xff; + *dst++ = (src[i] >> 8) & 0xff; + *dst++ = (src[i] >> 0) & 0xff; + } + pad[0] = (src[nwords] >> 24); + pad[1] = (src[nwords] >> 16) & 0xff; + pad[2] = (src[nwords] >> 8) & 0xff; + pad[3] = (src[nwords] >> 0) & 0xff; + memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords); +} + +/** + * encode_bch - calculate BCH ecc parity of data + * @bch: BCH control structure + * @data: data to encode + * @len: data length in bytes + * @ecc: ecc parity data, must be initialized by caller + * + * The @ecc parity array is used both as input and output parameter, in order to + * allow incremental computations. It should be of the size indicated by member + * @ecc_bytes of @bch, and should be initialized to 0 before the first call. + * + * The exact number of computed ecc parity bits is given by member @ecc_bits of + * @bch; it may be less than m*t for large values of t. + */ +void encode_bch(struct bch_control *bch, const uint8_t *data, + unsigned int len, uint8_t *ecc) +{ + const unsigned int l = BCH_ECC_WORDS(bch)-1; + unsigned int i, mlen; + unsigned long m; + uint32_t w, r[l+1]; + const uint32_t * const tab0 = bch->mod8_tab; + const uint32_t * const tab1 = tab0 + 256*(l+1); + const uint32_t * const tab2 = tab1 + 256*(l+1); + const uint32_t * const tab3 = tab2 + 256*(l+1); + const uint32_t *pdata, *p0, *p1, *p2, *p3; + + if (ecc) { + /* load ecc parity bytes into internal 32-bit buffer */ + load_ecc8(bch, bch->ecc_buf, ecc); + } else { + memset(bch->ecc_buf, 0, sizeof(r)); + } + + /* process first unaligned data bytes */ + m = ((unsigned long)data) & 3; + if (m) { + mlen = (len < (4-m)) ? len : 4-m; + encode_bch_unaligned(bch, data, mlen, bch->ecc_buf); + data += mlen; + len -= mlen; + } + + /* process 32-bit aligned data words */ + pdata = (uint32_t *)data; + mlen = len/4; + data += 4*mlen; + len -= 4*mlen; + memcpy(r, bch->ecc_buf, sizeof(r)); + + /* + * split each 32-bit word into 4 polynomials of weight 8 as follows: + * + * 31 ...24 23 ...16 15 ... 8 7 ... 0 + * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt + * tttttttt mod g = r0 (precomputed) + * zzzzzzzz 00000000 mod g = r1 (precomputed) + * yyyyyyyy 00000000 00000000 mod g = r2 (precomputed) + * xxxxxxxx 00000000 00000000 00000000 mod g = r3 (precomputed) + * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt mod g = r0^r1^r2^r3 + */ + while (mlen--) { + /* input data is read in big-endian format */ + w = r[0]^cpu_to_be32(*pdata++); + p0 = tab0 + (l+1)*((w >> 0) & 0xff); + p1 = tab1 + (l+1)*((w >> 8) & 0xff); + p2 = tab2 + (l+1)*((w >> 16) & 0xff); + p3 = tab3 + (l+1)*((w >> 24) & 0xff); + + for (i = 0; i < l; i++) + r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i]; + + r[l] = p0[l]^p1[l]^p2[l]^p3[l]; + } + memcpy(bch->ecc_buf, r, sizeof(r)); + + /* process last unaligned bytes */ + if (len) + encode_bch_unaligned(bch, data, len, bch->ecc_buf); + + /* store ecc parity bytes into original parity buffer */ + if (ecc) + store_ecc8(bch, ecc, bch->ecc_buf); +} +EXPORT_SYMBOL_GPL(encode_bch); + +static inline int modulo(struct bch_control *bch, unsigned int v) +{ + const unsigned int n = GF_N(bch); + while (v >= n) { + v -= n; + v = (v & n) + (v >> GF_M(bch)); + } + return v; +} + +/* + * shorter and faster modulo function, only works when v < 2N. + */ +static inline int mod_s(struct bch_control *bch, unsigned int v) +{ + const unsigned int n = GF_N(bch); + return (v < n) ? v : v-n; +} + +static inline int deg(unsigned int poly) +{ + /* polynomial degree is the most-significant bit index */ + return fls(poly)-1; +} + +static inline int parity(unsigned int x) +{ + /* + * public domain code snippet, lifted from + * http://www-graphics.stanford.edu/~seander/bithacks.html + */ + x ^= x >> 1; + x ^= x >> 2; + x = (x & 0x11111111U) * 0x11111111U; + return (x >> 28) & 1; +} + +/* Galois field basic operations: multiply, divide, inverse, etc. */ + +static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a, + unsigned int b) +{ + return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ + bch->a_log_tab[b])] : 0; +} + +static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a) +{ + return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0; +} + +static inline unsigned int gf_div(struct bch_control *bch, unsigned int a, + unsigned int b) +{ + return a ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ + GF_N(bch)-bch->a_log_tab[b])] : 0; +} + +static inline unsigned int gf_inv(struct bch_control *bch, unsigned int a) +{ + return bch->a_pow_tab[GF_N(bch)-bch->a_log_tab[a]]; +} + +static inline unsigned int a_pow(struct bch_control *bch, int i) +{ + return bch->a_pow_tab[modulo(bch, i)]; +} + +static inline int a_log(struct bch_control *bch, unsigned int x) +{ + return bch->a_log_tab[x]; +} + +static inline int a_ilog(struct bch_control *bch, unsigned int x) +{ + return mod_s(bch, GF_N(bch)-bch->a_log_tab[x]); +} + +/* + * compute 2t syndromes of ecc polynomial, i.e. ecc(a^j) for j=1..2t + */ +static void compute_syndromes(struct bch_control *bch, uint32_t *ecc, + unsigned int *syn) +{ + int i, j, s; + unsigned int m; + uint32_t poly; + const int t = GF_T(bch); + + s = bch->ecc_bits; + + /* make sure extra bits in last ecc word are cleared */ + m = ((unsigned int)s) & 31; + if (m) + ecc[s/32] &= ~((1u << (32-m))-1); + memset(syn, 0, 2*t*sizeof(*syn)); + + /* compute v(a^j) for j=1 .. 2t-1 */ + do { + poly = *ecc++; + s -= 32; + while (poly) { + i = deg(poly); + for (j = 0; j < 2*t; j += 2) + syn[j] ^= a_pow(bch, (j+1)*(i+s)); + + poly ^= (1 << i); + } + } while (s > 0); + + /* v(a^(2j)) = v(a^j)^2 */ + for (j = 0; j < t; j++) + syn[2*j+1] = gf_sqr(bch, syn[j]); +} + +static void gf_poly_copy(struct gf_poly *dst, struct gf_poly *src) +{ + memcpy(dst, src, GF_POLY_SZ(src->deg)); +} + +static int compute_error_locator_polynomial(struct bch_control *bch, + const unsigned int *syn) +{ + const unsigned int t = GF_T(bch); + const unsigned int n = GF_N(bch); + unsigned int i, j, tmp, l, pd = 1, d = syn[0]; + struct gf_poly *elp = bch->elp; + struct gf_poly *pelp = bch->poly_2t[0]; + struct gf_poly *elp_copy = bch->poly_2t[1]; + int k, pp = -1; + + memset(pelp, 0, GF_POLY_SZ(2*t)); + memset(elp, 0, GF_POLY_SZ(2*t)); + + pelp->deg = 0; + pelp->c[0] = 1; + elp->deg = 0; + elp->c[0] = 1; + + /* use simplified binary Berlekamp-Massey algorithm */ + for (i = 0; (i < t) && (elp->deg <= t); i++) { + if (d) { + k = 2*i-pp; + gf_poly_copy(elp_copy, elp); + /* e[i+1](X) = e[i](X)+di*dp^-1*X^2(i-p)*e[p](X) */ + tmp = a_log(bch, d)+n-a_log(bch, pd); + for (j = 0; j <= pelp->deg; j++) { + if (pelp->c[j]) { + l = a_log(bch, pelp->c[j]); + elp->c[j+k] ^= a_pow(bch, tmp+l); + } + } + /* compute l[i+1] = max(l[i]->c[l[p]+2*(i-p]) */ + tmp = pelp->deg+k; + if (tmp > elp->deg) { + elp->deg = tmp; + gf_poly_copy(pelp, elp_copy); + pd = d; + pp = 2*i; + } + } + /* di+1 = S(2i+3)+elp[i+1].1*S(2i+2)+...+elp[i+1].lS(2i+3-l) */ + if (i < t-1) { + d = syn[2*i+2]; + for (j = 1; j <= elp->deg; j++) + d ^= gf_mul(bch, elp->c[j], syn[2*i+2-j]); + } + } + dbg("elp=%s\n", gf_poly_str(elp)); + return (elp->deg > t) ? -1 : (int)elp->deg; +} + +/* + * solve a m x m linear system in GF(2) with an expected number of solutions, + * and return the number of found solutions + */ +static int solve_linear_system(struct bch_control *bch, unsigned int *rows, + unsigned int *sol, int nsol) +{ + const int m = GF_M(bch); + unsigned int tmp, mask; + int rem, c, r, p, k, param[m]; + + k = 0; + mask = 1 << m; + + /* Gaussian elimination */ + for (c = 0; c < m; c++) { + rem = 0; + p = c-k; + /* find suitable row for elimination */ + for (r = p; r < m; r++) { + if (rows[r] & mask) { + if (r != p) { + tmp = rows[r]; + rows[r] = rows[p]; + rows[p] = tmp; + } + rem = r+1; + break; + } + } + if (rem) { + /* perform elimination on remaining rows */ + tmp = rows[p]; + for (r = rem; r < m; r++) { + if (rows[r] & mask) + rows[r] ^= tmp; + } + } else { + /* elimination not needed, store defective row index */ + param[k++] = c; + } + mask >>= 1; + } + /* rewrite system, inserting fake parameter rows */ + if (k > 0) { + p = k; + for (r = m-1; r >= 0; r--) { + if ((r > m-1-k) && rows[r]) + /* system has no solution */ + return 0; + + rows[r] = (p && (r == param[p-1])) ? + p--, 1u << (m-r) : rows[r-p]; + } + } + + if (nsol != (1 << k)) + /* unexpected number of solutions */ + return 0; + + for (p = 0; p < nsol; p++) { + /* set parameters for p-th solution */ + for (c = 0; c < k; c++) + rows[param[c]] = (rows[param[c]] & ~1)|((p >> c) & 1); + + /* compute unique solution */ + tmp = 0; + for (r = m-1; r >= 0; r--) { + mask = rows[r] & (tmp|1); + tmp |= parity(mask) << (m-r); + } + sol[p] = tmp >> 1; + } + return nsol; +} + +/* + * this function builds and solves a linear system for finding roots of a degree + * 4 affine monic polynomial X^4+aX^2+bX+c over GF(2^m). + */ +static int find_affine4_roots(struct bch_control *bch, unsigned int a, + unsigned int b, unsigned int c, + unsigned int *roots) +{ + int i, j, k; + const int m = GF_M(bch); + unsigned int mask = 0xff, t, rows[16] = {0,}; + + j = a_log(bch, b); + k = a_log(bch, a); + rows[0] = c; + + /* buid linear system to solve X^4+aX^2+bX+c = 0 */ + for (i = 0; i < m; i++) { + rows[i+1] = bch->a_pow_tab[4*i]^ + (a ? bch->a_pow_tab[mod_s(bch, k)] : 0)^ + (b ? bch->a_pow_tab[mod_s(bch, j)] : 0); + j++; + k += 2; + } + /* + * transpose 16x16 matrix before passing it to linear solver + * warning: this code assumes m < 16 + */ + for (j = 8; j != 0; j >>= 1, mask ^= (mask << j)) { + for (k = 0; k < 16; k = (k+j+1) & ~j) { + t = ((rows[k] >> j)^rows[k+j]) & mask; + rows[k] ^= (t << j); + rows[k+j] ^= t; + } + } + return solve_linear_system(bch, rows, roots, 4); +} + +/* + * compute root r of a degree 1 polynomial over GF(2^m) (returned as log(1/r)) + */ +static int find_poly_deg1_roots(struct bch_control *bch, struct gf_poly *poly, + unsigned int *roots) +{ + int n = 0; + + if (poly->c[0]) + /* poly[X] = bX+c with c!=0, root=c/b */ + roots[n++] = mod_s(bch, GF_N(bch)-bch->a_log_tab[poly->c[0]]+ + bch->a_log_tab[poly->c[1]]); + return n; +} + +/* + * compute roots of a degree 2 polynomial over GF(2^m) + */ +static int find_poly_deg2_roots(struct bch_control *bch, struct gf_poly *poly, + unsigned int *roots) +{ + int n = 0, i, l0, l1, l2; + unsigned int u, v, r; + + if (poly->c[0] && poly->c[1]) { + + l0 = bch->a_log_tab[poly->c[0]]; + l1 = bch->a_log_tab[poly->c[1]]; + l2 = bch->a_log_tab[poly->c[2]]; + + /* using z=a/bX, transform aX^2+bX+c into z^2+z+u (u=ac/b^2) */ + u = a_pow(bch, l0+l2+2*(GF_N(bch)-l1)); + /* + * let u = sum(li.a^i) i=0..m-1; then compute r = sum(li.xi): + * r^2+r = sum(li.(xi^2+xi)) = sum(li.(a^i+Tr(a^i).a^k)) = + * u + sum(li.Tr(a^i).a^k) = u+a^k.Tr(sum(li.a^i)) = u+a^k.Tr(u) + * i.e. r and r+1 are roots iff Tr(u)=0 + */ + r = 0; + v = u; + while (v) { + i = deg(v); + r ^= bch->xi_tab[i]; + v ^= (1 << i); + } + /* verify root */ + if ((gf_sqr(bch, r)^r) == u) { + /* reverse z=a/bX transformation and compute log(1/r) */ + roots[n++] = modulo(bch, 2*GF_N(bch)-l1- + bch->a_log_tab[r]+l2); + roots[n++] = modulo(bch, 2*GF_N(bch)-l1- + bch->a_log_tab[r^1]+l2); + } + } + return n; +} + +/* + * compute roots of a degree 3 polynomial over GF(2^m) + */ +static int find_poly_deg3_roots(struct bch_control *bch, struct gf_poly *poly, + unsigned int *roots) +{ + int i, n = 0; + unsigned int a, b, c, a2, b2, c2, e3, tmp[4]; + + if (poly->c[0]) { + /* transform polynomial into monic X^3 + a2X^2 + b2X + c2 */ + e3 = poly->c[3]; + c2 = gf_div(bch, poly->c[0], e3); + b2 = gf_div(bch, poly->c[1], e3); + a2 = gf_div(bch, poly->c[2], e3); + + /* (X+a2)(X^3+a2X^2+b2X+c2) = X^4+aX^2+bX+c (affine) */ + c = gf_mul(bch, a2, c2); /* c = a2c2 */ + b = gf_mul(bch, a2, b2)^c2; /* b = a2b2 + c2 */ + a = gf_sqr(bch, a2)^b2; /* a = a2^2 + b2 */ + + /* find the 4 roots of this affine polynomial */ + if (find_affine4_roots(bch, a, b, c, tmp) == 4) { + /* remove a2 from final list of roots */ + for (i = 0; i < 4; i++) { + if (tmp[i] != a2) + roots[n++] = a_ilog(bch, tmp[i]); + } + } + } + return n; +} + +/* + * compute roots of a degree 4 polynomial over GF(2^m) + */ +static int find_poly_deg4_roots(struct bch_control *bch, struct gf_poly *poly, + unsigned int *roots) +{ + int i, l, n = 0; + unsigned int a, b, c, d, e = 0, f, a2, b2, c2, e4; + + if (poly->c[0] == 0) + return 0; + + /* transform polynomial into monic X^4 + aX^3 + bX^2 + cX + d */ + e4 = poly->c[4]; + d = gf_div(bch, poly->c[0], e4); + c = gf_div(bch, poly->c[1], e4); + b = gf_div(bch, poly->c[2], e4); + a = gf_div(bch, poly->c[3], e4); + + /* use Y=1/X transformation to get an affine polynomial */ + if (a) { + /* first, eliminate cX by using z=X+e with ae^2+c=0 */ + if (c) { + /* compute e such that e^2 = c/a */ + f = gf_div(bch, c, a); + l = a_log(bch, f); + l += (l & 1) ? GF_N(bch) : 0; + e = a_pow(bch, l/2); + /* + * use transformation z=X+e: + * z^4+e^4 + a(z^3+ez^2+e^2z+e^3) + b(z^2+e^2) +cz+ce+d + * z^4 + az^3 + (ae+b)z^2 + (ae^2+c)z+e^4+be^2+ae^3+ce+d + * z^4 + az^3 + (ae+b)z^2 + e^4+be^2+d + * z^4 + az^3 + b'z^2 + d' + */ + d = a_pow(bch, 2*l)^gf_mul(bch, b, f)^d; + b = gf_mul(bch, a, e)^b; + } + /* now, use Y=1/X to get Y^4 + b/dY^2 + a/dY + 1/d */ + if (d == 0) + /* assume all roots have multiplicity 1 */ + return 0; + + c2 = gf_inv(bch, d); + b2 = gf_div(bch, a, d); + a2 = gf_div(bch, b, d); + } else { + /* polynomial is already affine */ + c2 = d; + b2 = c; + a2 = b; + } + /* find the 4 roots of this affine polynomial */ + if (find_affine4_roots(bch, a2, b2, c2, roots) == 4) { + for (i = 0; i < 4; i++) { + /* post-process roots (reverse transformations) */ + f = a ? gf_inv(bch, roots[i]) : roots[i]; + roots[i] = a_ilog(bch, f^e); + } + n = 4; + } + return n; +} + +/* + * build monic, log-based representation of a polynomial + */ +static void gf_poly_logrep(struct bch_control *bch, + const struct gf_poly *a, int *rep) +{ + int i, d = a->deg, l = GF_N(bch)-a_log(bch, a->c[a->deg]); + + /* represent 0 values with -1; warning, rep[d] is not set to 1 */ + for (i = 0; i < d; i++) + rep[i] = a->c[i] ? mod_s(bch, a_log(bch, a->c[i])+l) : -1; +} + +/* + * compute polynomial Euclidean division remainder in GF(2^m)[X] + */ +static void gf_poly_mod(struct bch_control *bch, struct gf_poly *a, + const struct gf_poly *b, int *rep) +{ + int la, p, m; + unsigned int i, j, *c = a->c; + const unsigned int d = b->deg; + + if (a->deg < d) + return; + + /* reuse or compute log representation of denominator */ + if (!rep) { + rep = bch->cache; + gf_poly_logrep(bch, b, rep); + } + + for (j = a->deg; j >= d; j--) { + if (c[j]) { + la = a_log(bch, c[j]); + p = j-d; + for (i = 0; i < d; i++, p++) { + m = rep[i]; + if (m >= 0) + c[p] ^= bch->a_pow_tab[mod_s(bch, + m+la)]; + } + } + } + a->deg = d-1; + while (!c[a->deg] && a->deg) + a->deg--; +} + +/* + * compute polynomial Euclidean division quotient in GF(2^m)[X] + */ +static void gf_poly_div(struct bch_control *bch, struct gf_poly *a, + const struct gf_poly *b, struct gf_poly *q) +{ + if (a->deg >= b->deg) { + q->deg = a->deg-b->deg; + /* compute a mod b (modifies a) */ + gf_poly_mod(bch, a, b, NULL); + /* quotient is stored in upper part of polynomial a */ + memcpy(q->c, &a->c[b->deg], (1+q->deg)*sizeof(unsigned int)); + } else { + q->deg = 0; + q->c[0] = 0; + } +} + +/* + * compute polynomial GCD (Greatest Common Divisor) in GF(2^m)[X] + */ +static struct gf_poly *gf_poly_gcd(struct bch_control *bch, struct gf_poly *a, + struct gf_poly *b) +{ + struct gf_poly *tmp; + + dbg("gcd(%s,%s)=", gf_poly_str(a), gf_poly_str(b)); + + if (a->deg < b->deg) { + tmp = b; + b = a; + a = tmp; + } + + while (b->deg > 0) { + gf_poly_mod(bch, a, b, NULL); + tmp = b; + b = a; + a = tmp; + } + + dbg("%s\n", gf_poly_str(a)); + + return a; +} + +/* + * Given a polynomial f and an integer k, compute Tr(a^kX) mod f + * This is used in Berlekamp Trace algorithm for splitting polynomials + */ +static void compute_trace_bk_mod(struct bch_control *bch, int k, + const struct gf_poly *f, struct gf_poly *z, + struct gf_poly *out) +{ + const int m = GF_M(bch); + int i, j; + + /* z contains z^2j mod f */ + z->deg = 1; + z->c[0] = 0; + z->c[1] = bch->a_pow_tab[k]; + + out->deg = 0; + memset(out, 0, GF_POLY_SZ(f->deg)); + + /* compute f log representation only once */ + gf_poly_logrep(bch, f, bch->cache); + + for (i = 0; i < m; i++) { + /* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */ + for (j = z->deg; j >= 0; j--) { + out->c[j] ^= z->c[j]; + z->c[2*j] = gf_sqr(bch, z->c[j]); + z->c[2*j+1] = 0; + } + if (z->deg > out->deg) + out->deg = z->deg; + + if (i < m-1) { + z->deg *= 2; + /* z^(2(i+1)) mod f = (z^(2^i) mod f)^2 mod f */ + gf_poly_mod(bch, z, f, bch->cache); + } + } + while (!out->c[out->deg] && out->deg) + out->deg--; + + dbg("Tr(a^%d.X) mod f = %s\n", k, gf_poly_str(out)); +} + +/* + * factor a polynomial using Berlekamp Trace algorithm (BTA) + */ +static void factor_polynomial(struct bch_control *bch, int k, struct gf_poly *f, + struct gf_poly **g, struct gf_poly **h) +{ + struct gf_poly *f2 = bch->poly_2t[0]; + struct gf_poly *q = bch->poly_2t[1]; + struct gf_poly *tk = bch->poly_2t[2]; + struct gf_poly *z = bch->poly_2t[3]; + struct gf_poly *gcd; + + dbg("factoring %s...\n", gf_poly_str(f)); + + *g = f; + *h = NULL; + + /* tk = Tr(a^k.X) mod f */ + compute_trace_bk_mod(bch, k, f, z, tk); + + if (tk->deg > 0) { + /* compute g = gcd(f, tk) (destructive operation) */ + gf_poly_copy(f2, f); + gcd = gf_poly_gcd(bch, f2, tk); + if (gcd->deg < f->deg) { + /* compute h=f/gcd(f,tk); this will modify f and q */ + gf_poly_div(bch, f, gcd, q); + /* store g and h in-place (clobbering f) */ + *h = &((struct gf_poly_deg1 *)f)[gcd->deg].poly; + gf_poly_copy(*g, gcd); + gf_poly_copy(*h, q); + } + } +} + +/* + * find roots of a polynomial, using BTZ algorithm; see the beginning of this + * file for details + */ +static int find_poly_roots(struct bch_control *bch, unsigned int k, + struct gf_poly *poly, unsigned int *roots) +{ + int cnt; + struct gf_poly *f1, *f2; + + switch (poly->deg) { + /* handle low degree polynomials with ad hoc techniques */ + case 1: + cnt = find_poly_deg1_roots(bch, poly, roots); + break; + case 2: + cnt = find_poly_deg2_roots(bch, poly, roots); + break; + case 3: + cnt = find_poly_deg3_roots(bch, poly, roots); + break; + case 4: + cnt = find_poly_deg4_roots(bch, poly, roots); + break; + default: + /* factor polynomial using Berlekamp Trace Algorithm (BTA) */ + cnt = 0; + if (poly->deg && (k <= GF_M(bch))) { + factor_polynomial(bch, k, poly, &f1, &f2); + if (f1) + cnt += find_poly_roots(bch, k+1, f1, roots); + if (f2) + cnt += find_poly_roots(bch, k+1, f2, roots+cnt); + } + break; + } + return cnt; +} + +#if defined(USE_CHIEN_SEARCH) +/* + * exhaustive root search (Chien) implementation - not used, included only for + * reference/comparison tests + */ +static int chien_search(struct bch_control *bch, unsigned int len, + struct gf_poly *p, unsigned int *roots) +{ + int m; + unsigned int i, j, syn, syn0, count = 0; + const unsigned int k = 8*len+bch->ecc_bits; + + /* use a log-based representation of polynomial */ + gf_poly_logrep(bch, p, bch->cache); + bch->cache[p->deg] = 0; + syn0 = gf_div(bch, p->c[0], p->c[p->deg]); + + for (i = GF_N(bch)-k+1; i <= GF_N(bch); i++) { + /* compute elp(a^i) */ + for (j = 1, syn = syn0; j <= p->deg; j++) { + m = bch->cache[j]; + if (m >= 0) + syn ^= a_pow(bch, m+j*i); + } + if (syn == 0) { + roots[count++] = GF_N(bch)-i; + if (count == p->deg) + break; + } + } + return (count == p->deg) ? count : 0; +} +#define find_poly_roots(_p, _k, _elp, _loc) chien_search(_p, len, _elp, _loc) +#endif /* USE_CHIEN_SEARCH */ + +/** + * decode_bch - decode received codeword and find bit error locations + * @bch: BCH control structure + * @data: received data, ignored if @calc_ecc is provided + * @len: data length in bytes, must always be provided + * @recv_ecc: received ecc, if NULL then assume it was XORed in @calc_ecc + * @calc_ecc: calculated ecc, if NULL then calc_ecc is computed from @data + * @syn: hw computed syndrome data (if NULL, syndrome is calculated) + * @errloc: output array of error locations + * + * Returns: + * The number of errors found, or -EBADMSG if decoding failed, or -EINVAL if + * invalid parameters were provided + * + * Depending on the available hw BCH support and the need to compute @calc_ecc + * separately (using encode_bch()), this function should be called with one of + * the following parameter configurations - + * + * by providing @data and @recv_ecc only: + * decode_bch(@bch, @data, @len, @recv_ecc, NULL, NULL, @errloc) + * + * by providing @recv_ecc and @calc_ecc: + * decode_bch(@bch, NULL, @len, @recv_ecc, @calc_ecc, NULL, @errloc) + * + * by providing ecc = recv_ecc XOR calc_ecc: + * decode_bch(@bch, NULL, @len, NULL, ecc, NULL, @errloc) + * + * by providing syndrome results @syn: + * decode_bch(@bch, NULL, @len, NULL, NULL, @syn, @errloc) + * + * Once decode_bch() has successfully returned with a positive value, error + * locations returned in array @errloc should be interpreted as follows - + * + * if (errloc[n] >= 8*len), then n-th error is located in ecc (no need for + * data correction) + * + * if (errloc[n] < 8*len), then n-th error is located in data and can be + * corrected with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8); + * + * Note that this function does not perform any data correction by itself, it + * merely indicates error locations. + */ +int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, + const uint8_t *recv_ecc, const uint8_t *calc_ecc, + const unsigned int *syn, unsigned int *errloc) +{ + const unsigned int ecc_words = BCH_ECC_WORDS(bch); + unsigned int nbits; + int i, err, nroots; + uint32_t sum; + + /* sanity check: make sure data length can be handled */ + if (8*len > (bch->n-bch->ecc_bits)) + return -EINVAL; + + /* if caller does not provide syndromes, compute them */ + if (!syn) { + if (!calc_ecc) { + /* compute received data ecc into an internal buffer */ + if (!data || !recv_ecc) + return -EINVAL; + encode_bch(bch, data, len, NULL); + } else { + /* load provided calculated ecc */ + load_ecc8(bch, bch->ecc_buf, calc_ecc); + } + /* load received ecc or assume it was XORed in calc_ecc */ + if (recv_ecc) { + load_ecc8(bch, bch->ecc_buf2, recv_ecc); + /* XOR received and calculated ecc */ + for (i = 0, sum = 0; i < (int)ecc_words; i++) { + bch->ecc_buf[i] ^= bch->ecc_buf2[i]; + sum |= bch->ecc_buf[i]; + } + if (!sum) + /* no error found */ + return 0; + } + compute_syndromes(bch, bch->ecc_buf, bch->syn); + syn = bch->syn; + } + + err = compute_error_locator_polynomial(bch, syn); + if (err > 0) { + nroots = find_poly_roots(bch, 1, bch->elp, errloc); + if (err != nroots) + err = -1; + } + if (err > 0) { + /* post-process raw error locations for easier correction */ + nbits = (len*8)+bch->ecc_bits; + for (i = 0; i < err; i++) { + if (errloc[i] >= nbits) { + err = -1; + break; + } + errloc[i] = nbits-1-errloc[i]; + errloc[i] = (errloc[i] & ~7)|(7-(errloc[i] & 7)); + } + } + return (err >= 0) ? err : -EBADMSG; +} +EXPORT_SYMBOL_GPL(decode_bch); + +/* + * generate Galois field lookup tables + */ +static int build_gf_tables(struct bch_control *bch, unsigned int poly) +{ + unsigned int i, x = 1; + const unsigned int k = 1 << deg(poly); + + /* primitive polynomial must be of degree m */ + if (k != (1u << GF_M(bch))) + return -1; + + for (i = 0; i < GF_N(bch); i++) { + bch->a_pow_tab[i] = x; + bch->a_log_tab[x] = i; + if (i && (x == 1)) + /* polynomial is not primitive (a^i=1 with 0a_pow_tab[GF_N(bch)] = 1; + bch->a_log_tab[0] = 0; + + return 0; +} + +/* + * compute generator polynomial remainder tables for fast encoding + */ +static void build_mod8_tables(struct bch_control *bch, const uint32_t *g) +{ + int i, j, b, d; + uint32_t data, hi, lo, *tab; + const int l = BCH_ECC_WORDS(bch); + const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32); + const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32); + + memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab)); + + for (i = 0; i < 256; i++) { + /* p(X)=i is a small polynomial of weight <= 8 */ + for (b = 0; b < 4; b++) { + /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */ + tab = bch->mod8_tab + (b*256+i)*l; + data = i << (8*b); + while (data) { + d = deg(data); + /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */ + data ^= g[0] >> (31-d); + for (j = 0; j < ecclen; j++) { + hi = (d < 31) ? g[j] << (d+1) : 0; + lo = (j+1 < plen) ? + g[j+1] >> (31-d) : 0; + tab[j] ^= hi|lo; + } + } + } + } +} + +/* + * build a base for factoring degree 2 polynomials + */ +static int build_deg2_base(struct bch_control *bch) +{ + const int m = GF_M(bch); + int i, j, r; + unsigned int sum, x, y, remaining, ak = 0, xi[m]; + + /* find k s.t. Tr(a^k) = 1 and 0 <= k < m */ + for (i = 0; i < m; i++) { + for (j = 0, sum = 0; j < m; j++) + sum ^= a_pow(bch, i*(1 << j)); + + if (sum) { + ak = bch->a_pow_tab[i]; + break; + } + } + /* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */ + remaining = m; + memset(xi, 0, sizeof(xi)); + + for (x = 0; (x <= GF_N(bch)) && remaining; x++) { + y = gf_sqr(bch, x)^x; + for (i = 0; i < 2; i++) { + r = a_log(bch, y); + if (y && (r < m) && !xi[r]) { + bch->xi_tab[r] = x; + xi[r] = 1; + remaining--; + dbg("x%d = %x\n", r, x); + break; + } + y ^= ak; + } + } + /* should not happen but check anyway */ + return remaining ? -1 : 0; +} + +static void *bch_alloc(size_t size, int *err) +{ + void *ptr; + + ptr = kmalloc(size, GFP_KERNEL); + if (ptr == NULL) + *err = 1; + return ptr; +} + +/* + * compute generator polynomial for given (m,t) parameters. + */ +static uint32_t *compute_generator_polynomial(struct bch_control *bch) +{ + const unsigned int m = GF_M(bch); + const unsigned int t = GF_T(bch); + int n, err = 0; + unsigned int i, j, nbits, r, word, *roots; + struct gf_poly *g; + uint32_t *genpoly; + + g = bch_alloc(GF_POLY_SZ(m*t), &err); + roots = bch_alloc((bch->n+1)*sizeof(*roots), &err); + genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err); + + if (err) { + kfree(genpoly); + genpoly = NULL; + goto finish; + } + + /* enumerate all roots of g(X) */ + memset(roots , 0, (bch->n+1)*sizeof(*roots)); + for (i = 0; i < t; i++) { + for (j = 0, r = 2*i+1; j < m; j++) { + roots[r] = 1; + r = mod_s(bch, 2*r); + } + } + /* build generator polynomial g(X) */ + g->deg = 0; + g->c[0] = 1; + for (i = 0; i < GF_N(bch); i++) { + if (roots[i]) { + /* multiply g(X) by (X+root) */ + r = bch->a_pow_tab[i]; + g->c[g->deg+1] = 1; + for (j = g->deg; j > 0; j--) + g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1]; + + g->c[0] = gf_mul(bch, g->c[0], r); + g->deg++; + } + } + /* store left-justified binary representation of g(X) */ + n = g->deg+1; + i = 0; + + while (n > 0) { + nbits = (n > 32) ? 32 : n; + for (j = 0, word = 0; j < nbits; j++) { + if (g->c[n-1-j]) + word |= 1u << (31-j); + } + genpoly[i++] = word; + n -= nbits; + } + bch->ecc_bits = g->deg; + +finish: + kfree(g); + kfree(roots); + + return genpoly; +} + +/** + * init_bch - initialize a BCH encoder/decoder + * @m: Galois field order, should be in the range 5-15 + * @t: maximum error correction capability, in bits + * @prim_poly: user-provided primitive polynomial (or 0 to use default) + * + * Returns: + * a newly allocated BCH control structure if successful, NULL otherwise + * + * This initialization can take some time, as lookup tables are built for fast + * encoding/decoding; make sure not to call this function from a time critical + * path. Usually, init_bch() should be called on module/driver init and + * free_bch() should be called to release memory on exit. + * + * You may provide your own primitive polynomial of degree @m in argument + * @prim_poly, or let init_bch() use its default polynomial. + * + * Once init_bch() has successfully returned a pointer to a newly allocated + * BCH control structure, ecc length in bytes is given by member @ecc_bytes of + * the structure. + */ +struct bch_control *init_bch(int m, int t, unsigned int prim_poly) +{ + int err = 0; + unsigned int i, words; + uint32_t *genpoly; + struct bch_control *bch = NULL; + + const int min_m = 5; + const int max_m = 15; + + /* default primitive polynomials */ + static const unsigned int prim_poly_tab[] = { + 0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b, + 0x402b, 0x8003, + }; + +#if defined(CONFIG_BCH_CONST_PARAMS) + if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) { + printk(KERN_ERR "bch encoder/decoder was configured to support " + "parameters m=%d, t=%d only!\n", + CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T); + goto fail; + } +#endif + if ((m < min_m) || (m > max_m)) + /* + * values of m greater than 15 are not currently supported; + * supporting m > 15 would require changing table base type + * (uint16_t) and a small patch in matrix transposition + */ + goto fail; + + /* sanity checks */ + if ((t < 1) || (m*t >= ((1 << m)-1))) + /* invalid t value */ + goto fail; + + /* select a primitive polynomial for generating GF(2^m) */ + if (prim_poly == 0) + prim_poly = prim_poly_tab[m-min_m]; + + bch = kzalloc(sizeof(*bch), GFP_KERNEL); + if (bch == NULL) + goto fail; + + bch->m = m; + bch->t = t; + bch->n = (1 << m)-1; + words = DIV_ROUND_UP(m*t, 32); + bch->ecc_bytes = DIV_ROUND_UP(m*t, 8); + bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err); + bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err); + bch->mod8_tab = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err); + bch->ecc_buf = bch_alloc(words*sizeof(*bch->ecc_buf), &err); + bch->ecc_buf2 = bch_alloc(words*sizeof(*bch->ecc_buf2), &err); + bch->xi_tab = bch_alloc(m*sizeof(*bch->xi_tab), &err); + bch->syn = bch_alloc(2*t*sizeof(*bch->syn), &err); + bch->cache = bch_alloc(2*t*sizeof(*bch->cache), &err); + bch->elp = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err); + + for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) + bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err); + + if (err) + goto fail; + + err = build_gf_tables(bch, prim_poly); + if (err) + goto fail; + + /* use generator polynomial for computing encoding tables */ + genpoly = compute_generator_polynomial(bch); + if (genpoly == NULL) + goto fail; + + build_mod8_tables(bch, genpoly); + kfree(genpoly); + + err = build_deg2_base(bch); + if (err) + goto fail; + + return bch; + +fail: + free_bch(bch); + return NULL; +} +EXPORT_SYMBOL_GPL(init_bch); + +/** + * free_bch - free the BCH control structure + * @bch: BCH control structure to release + */ +void free_bch(struct bch_control *bch) +{ + unsigned int i; + + if (bch) { + kfree(bch->a_pow_tab); + kfree(bch->a_log_tab); + kfree(bch->mod8_tab); + kfree(bch->ecc_buf); + kfree(bch->ecc_buf2); + kfree(bch->xi_tab); + kfree(bch->syn); + kfree(bch->cache); + kfree(bch->elp); + + for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) + kfree(bch->poly_2t[i]); + + kfree(bch); + } +} +EXPORT_SYMBOL_GPL(free_bch); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ivan Djelic "); +MODULE_DESCRIPTION("Binary BCH encoder/decoder"); diff --git a/lib/bitrev.c b/lib/bitrev.c new file mode 100644 index 0000000..2662760 --- /dev/null +++ b/lib/bitrev.c @@ -0,0 +1,68 @@ +/* + * Bit reversal module + * + * Copyright (C) Akinobu Mita + * + * 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. + * + * Taken from linux kernel. + */ +#include +#include + +const u8 byte_rev_table[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, +}; + +u16 bitrev16(u16 x) +{ + return (bitrev8(x & 0xff) << 8) | bitrev8(x >> 8); +} + +/** + * bitrev32 - reverse the order of bits in a u32 value + * @x: value to be bit-reversed + */ +u32 bitrev32(u32 x) +{ + return (bitrev16(x & 0xffff) << 16) | bitrev16(x >> 16); +} diff --git a/lib/libbb.c b/lib/libbb.c index 3d02202..9a0a60b 100644 --- a/lib/libbb.c +++ b/lib/libbb.c @@ -127,3 +127,53 @@ return p + 1; } EXPORT_SYMBOL(simple_itoa); + +/* + * write_full - write to filedescriptor + * + * Like write, but guarantees to write the full buffer out, else + * it returns with an error. + */ +int write_full(int fd, void *buf, size_t size) +{ + size_t insize = size; + int now; + + while (size) { + now = write(fd, buf, size); + if (now <= 0) + return now; + size -= now; + buf += now; + } + + return insize; +} +EXPORT_SYMBOL(write_full); + +/* + * read_full - read from filedescriptor + * + * Like read, but this function only returns less bytes than + * requested when the end of file is reached. + */ +int read_full(int fd, void *buf, size_t size) +{ + size_t insize = size; + int now; + int total = 0; + + while (size) { + now = read(fd, buf, size); + if (now == 0) + return total; + if (now < 0) + return now; + total += now; + size -= now; + buf += now; + } + + return insize; +} +EXPORT_SYMBOL(read_full); diff --git a/lib/readline_simple.c b/lib/readline_simple.c index 9dd2154..1a40d11 100644 --- a/lib/readline_simple.c +++ b/lib/readline_simple.c @@ -1,5 +1,4 @@ #include -#include static char erase_seq[] = "\b \b"; /* erase sequence */ static char tab_seq[] = " "; /* used to expand TABs */ @@ -64,7 +63,6 @@ return (-2); /* timed out */ } #endif - WATCHDOG_RESET(); /* Trigger watchdog, if needed */ #ifdef CONFIG_SHOW_ACTIVITY while (!tstc()) { diff --git a/lib/stringlist.c b/lib/stringlist.c index 9ccf8fa..a8ff979 100644 --- a/lib/stringlist.c +++ b/lib/stringlist.c @@ -3,6 +3,15 @@ #include #include +static int string_list_compare(struct list_head *a, struct list_head *b) +{ + char *astr, *bstr; + astr = (char *)list_entry(a, struct string_list, list)->str; + bstr = (char *)list_entry(b, struct string_list, list)->str; + + return strcmp(astr, bstr); +} + int string_list_add(struct string_list *sl, char *str) { struct string_list *new; @@ -16,6 +25,31 @@ return 0; } +int string_list_add_sorted(struct string_list *sl, char *str) +{ + struct string_list *new; + + new = xmalloc(sizeof(struct string_list) + strlen(str) + 1); + + strcpy(new->str, str); + + list_add_sort(&new->list, &sl->list, string_list_compare); + + return 0; +} + +int string_list_contains(struct string_list *sl, char *str) +{ + struct string_list *entry; + + list_for_each_entry(entry, &sl->list, list) { + if (!strcmp(str, entry->str)) + return 1; + } + + return 0; +} + void string_list_print_by_column(struct string_list *sl) { int len = 0, num, i; diff --git a/lib/uncompress.c b/lib/uncompress.c index beb96d1..cdfebe9 100644 --- a/lib/uncompress.c +++ b/lib/uncompress.c @@ -158,3 +158,11 @@ NULL, error_fn); } + +int uncompress_fd_to_buf(int infd, void *output, + void(*error_fn)(char *x)) +{ + uncompress_infd = infd; + + return uncompress(NULL, 0, fill_fd, NULL, output, NULL, error_fn); +} diff --git a/net/net.c b/net/net.c index 8416861..26ba44e 100644 --- a/net/net.c +++ b/net/net.c @@ -28,7 +28,6 @@ */ #include #include -#include #include #include #include diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 95e7746..912cfd8 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -1,7 +1,7 @@ #### # kbuild: Generic definitions -# Convinient variables +# Convenient variables comma := , squote := ' empty := @@ -21,10 +21,21 @@ basetarget = $(basename $(notdir $@)) ### +# filename of first prerequisite with directory and extension stripped +baseprereq = $(basename $(notdir $<)) + +### # Escape single quote for use in echo statements escsq = $(subst $(squote),'\$(squote)',$1) ### +# Easy method for doing a status message + kecho := : + quiet_kecho := echo +silent_kecho := : +kecho := $($(quiet)kecho) + +### # filechk is used to check if the content of a generated file is updated. # Sample usage: # define filechk_sample @@ -41,13 +52,13 @@ # to specify a valid file as first prerequisite (often the kbuild file) define filechk $(Q)set -e; \ - echo ' CHK $@'; \ + $(kecho) ' CHK $@'; \ mkdir -p $(dir $@); \ $(filechk_$(1)) < $< > $@.tmp; \ if [ -r $@ ] && cmp -s $@ $@.tmp; then \ rm -f $@.tmp; \ else \ - echo ' UPD $@'; \ + $(kecho) ' UPD $@'; \ mv -f $@.tmp $@; \ fi endef @@ -56,56 +67,95 @@ # gcc support functions # See documentation in Documentation/kbuild/makefiles.txt +# cc-cross-prefix +# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-) +# Return first prefix where a prefix$(CC) is found in PATH. +# If no $(CC) found in PATH with listed prefixes return nothing +cc-cross-prefix = \ + $(word 1, $(foreach c,$(1), \ + $(shell set -e; \ + if (which $(strip $(c))$(CC)) > /dev/null 2>&1 ; then \ + echo $(c); \ + fi))) + # output directory for tests below TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/) -# as-option -# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,) +# try-run +# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise) +# Exit code chooses option. "$$TMP" is can be used as temporary file and +# is automatically cleaned up. +try-run = $(shell set -e; \ + TMP="$(TMPOUT).$$$$.tmp"; \ + TMPO="$(TMPOUT).$$$$.o"; \ + if ($(1)) >/dev/null 2>&1; \ + then echo "$(2)"; \ + else echo "$(3)"; \ + fi; \ + rm -f "$$TMP" "$$TMPO") -as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \ - -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \ - else echo "$(2)"; fi ;) +# as-option +# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) + +as-option = $(call try-run,\ + $(CC) $(CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) # as-instr -# Usage: cflags-y += $(call as-instr, instr, option1, option2) +# Usage: cflags-y += $(call as-instr,instr,option1,option2) -as-instr = $(shell if echo -e "$(1)" | \ - $(CC) $(AFLAGS) -c -xassembler - \ - -o $(TMPOUT)astest$$$$.out > /dev/null 2>&1; \ - then rm $(TMPOUT)astest$$$$.out; echo "$(2)"; \ - else echo "$(3)"; fi) +as-instr = $(call try-run,\ + /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) # cc-option -# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586) +# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) -cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;) +cc-option = $(call try-run,\ + $(CC) $(KBUILD_CPPFLAGS) $(CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) # cc-option-yn -# Usage: flag := $(call cc-option-yn, -march=winchip-c6) -cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \ - > /dev/null 2>&1; then echo "y"; else echo "n"; fi;) +# Usage: flag := $(call cc-option-yn,-march=winchip-c6) +cc-option-yn = $(call try-run,\ + $(CC) $(KBUILD_CPPFLAGS) $(CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) # cc-option-align # Prefix align with either -falign or -malign cc-option-align = $(subst -functions=0,,\ $(call cc-option,-falign-functions=0,-malign-functions=0)) +# cc-disable-warning +# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) +cc-disable-warning = $(call try-run,\ + $(CC) $(KBUILD_CPPFLAGS) $(CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) + # cc-version -# Usage gcc-ver := $(call cc-version, $(CC)) +# Usage gcc-ver := $(call cc-version) cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) +# cc-fullversion +# Usage gcc-ver := $(call cc-fullversion) +cc-fullversion = $(shell $(CONFIG_SHELL) \ + $(srctree)/scripts/gcc-version.sh -p $(CC)) + # cc-ifversion # Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) -cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \ - echo $(3); fi;) +cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) + +# cc-ldoption +# Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) +cc-ldoption = $(call try-run,\ + $(CC) $(1) -nostdlib -xc /dev/null -o "$$TMP",$(1),$(2)) # ld-option -# Usage: ldflags += $(call ld-option, -Wl$(comma)--hash-style=both) -ld-option = $(shell if $(CC) $(1) -nostdlib -xc /dev/null \ - -o $(TMPOUT)ldtest$$$$.out > /dev/null 2>&1; \ - then rm $(TMPOUT)ldtest$$$$.out; echo "$(1)"; \ - else echo "$(2)"; fi) +# Usage: LDFLAGS += $(call ld-option, -X) +ld-option = $(call try-run,\ + $(CC) /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) + +# ar-option +# Usage: KBUILD_ARFLAGS := $(call ar-option,D) +# Important: no spaces around options +ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2)) + +###### ### # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj= @@ -113,15 +163,29 @@ # $(Q)$(MAKE) $(build)=dir build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj -# Prefix -I with $(srctree) if it is not an absolute path -addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1) +### +# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj= +# Usage: +# $(Q)$(MAKE) $(modbuiltin)=dir +modbuiltin := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.modbuiltin obj + +# Prefix -I with $(srctree) if it is not an absolute path. +# skip if -I has no parameter +addtree = $(if $(patsubst -I%,%,$(1)), \ +$(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)) + # Find all -I options and call addtree flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o))) -# If quiet is set, only print short version of command +# echo command. +# Short version is used, if $(quiet) equals `quiet_', otherwise full one. +echo-cmd = $(if $($(quiet)cmd_$(1)),\ + echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) + +# printing commands cmd = @$(echo-cmd) $(cmd_$(1)) -# Add $(obj)/ for paths that is not absolute +# Add $(obj)/ for paths that are not absolute objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) ### @@ -133,16 +197,14 @@ # See Documentation/kbuild/makefiles.txt for more info ifneq ($(KBUILD_NOCMDDEP),1) -# Check if both arguments has same arguments. Result in empty string if equal +# Check if both arguments has same arguments. Result is empty string if equal. # User may override this check using make KBUILD_NOCMDDEP=1 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ $(filter-out $(cmd_$@), $(cmd_$(1))) ) +else +arg-check = $(if $(strip $(cmd_$@)),,1) endif -# echo command. Short version is $(quiet) equals quiet, otherwise full command -echo-cmd = $(if $($(quiet)cmd_$(1)), \ - echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) - # >'< substitution is for echo to work, # >$< substitution to preserve $ when reloading .cmd file # note: when using inline perl scripts [perl -e '...$$t=1;...'] @@ -153,15 +215,14 @@ # PHONY targets skipped in both cases. any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) -# Execute command if command has changed or prerequisitei(s) are updated +# Execute command if command has changed or prerequisite(s) are updated. # if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ @set -e; \ $(echo-cmd) $(cmd_$(1)); \ echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd) -# execute the command and also postprocess generated .d dependencies -# file +# Execute the command and also postprocess generated .d dependencies file. if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \ @set -e; \ $(echo-cmd) $(cmd_$(1)); \ @@ -170,8 +231,8 @@ mv -f $(dot-target).tmp $(dot-target).cmd) # Usage: $(call if_changed_rule,foo) -# will check if $(cmd_foo) changed, or any of the prequisites changed, -# and if so will execute $(rule_foo) +# Will check if $(cmd_foo) or any of the prerequisites changed, +# and if so will execute $(rule_foo). if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \ @set -e; \ $(rule_$(1))) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index d7e2563..b842c48 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -160,6 +160,71 @@ # --------------------------------------------------------------------------- quiet_cmd_gzip = GZIP $@ -cmd_gzip = gzip -f -9 < $< > $@ +cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \ + (rm -f $@ ; false) +# Bzip2 +# --------------------------------------------------------------------------- +# Bzip2 and LZMA do not include size in file... so we have to fake that; +# append the size as a 32-bit littleendian number as gzip does. +size_append = printf $(shell \ +dec_size=0; \ +for F in $1; do \ + fsize=$$(stat -c "%s" $$F); \ + dec_size=$$(expr $$dec_size + $$fsize); \ +done; \ +printf "%08x\n" $$dec_size | \ + sed 's/\(..\)/\1 /g' | { \ + read ch0 ch1 ch2 ch3; \ + for ch in $$ch3 $$ch2 $$ch1 $$ch0; do \ + printf '%s%03o' '\\' $$((0x$$ch)); \ + done; \ + } \ +) + +quiet_cmd_bzip2 = BZIP2 $@ +cmd_bzip2 = (cat $(filter-out FORCE,$^) | \ + bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + +# Lzma +# --------------------------------------------------------------------------- + +quiet_cmd_lzma = LZMA $@ +cmd_lzma = (cat $(filter-out FORCE,$^) | \ + lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + +quiet_cmd_lzo = LZO $@ +cmd_lzo = (cat $(filter-out FORCE,$^) | \ + lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + +# XZ +# --------------------------------------------------------------------------- +# Use xzkern to compress the kernel image and xzmisc to compress other things. +# +# xzkern uses a big LZMA2 dictionary since it doesn't increase memory usage +# of the kernel decompressor. A BCJ filter is used if it is available for +# the target architecture. xzkern also appends uncompressed size of the data +# using size_append. The .xz format has the size information available at +# the end of the file too, but it's in more complex format and it's good to +# avoid changing the part of the boot code that reads the uncompressed size. +# Note that the bytes added by size_append will make the xz tool think that +# the file is corrupt. This is expected. +# +# xzmisc doesn't use size_append, so it can be used to create normal .xz +# files. xzmisc uses smaller LZMA2 dictionary than xzkern, because a very +# big dictionary would increase the memory usage too much in the multi-call +# decompression mode. A BCJ filter isn't used either. +quiet_cmd_xzkern = XZKERN $@ +cmd_xzkern = (cat $(filter-out FORCE,$^) | \ + sh $(srctree)/scripts/xz_wrap.sh && \ + $(call size_append, $(filter-out FORCE,$^))) > $@ || \ + (rm -f $@ ; false) + +quiet_cmd_xzmisc = XZMISC $@ +cmd_xzmisc = (cat $(filter-out FORCE,$^) | \ + xz --check=crc32 --lzma2=dict=1MiB) > $@ || \ + (rm -f $@ ; false) diff --git a/scripts/mkimage.c b/scripts/mkimage.c index b219cb8..64290cf 100644 --- a/scripts/mkimage.c +++ b/scripts/mkimage.c @@ -62,6 +62,246 @@ image_header_t header; image_header_t *hdr = &header; +static inline uint32_t image_get_header_size(void) +{ + return sizeof(image_header_t); +} + +#define image_get_hdr_u32(x) \ +static inline uint32_t image_get_##x(const image_header_t *hdr) \ +{ \ + return uimage_to_cpu(hdr->ih_##x); \ +} + +image_get_hdr_u32(magic); /* image_get_magic */ +image_get_hdr_u32(hcrc); /* image_get_hcrc */ +image_get_hdr_u32(time); /* image_get_time */ +image_get_hdr_u32(size); /* image_get_size */ +image_get_hdr_u32(load); /* image_get_load */ +image_get_hdr_u32(ep); /* image_get_ep */ +image_get_hdr_u32(dcrc); /* image_get_dcrc */ + +#define image_get_hdr_u8(x) \ +static inline uint8_t image_get_##x(const image_header_t *hdr) \ +{ \ + return hdr->ih_##x; \ +} +image_get_hdr_u8(os); /* image_get_os */ +image_get_hdr_u8(arch); /* image_get_arch */ +image_get_hdr_u8(type); /* image_get_type */ +image_get_hdr_u8(comp); /* image_get_comp */ + +static inline char *image_get_name(const image_header_t *hdr) +{ + return (char*)hdr->ih_name; +} + +static inline uint32_t image_get_data_size(const image_header_t *hdr) +{ + return image_get_size(hdr); +} + +/** + * image_get_data - get image payload start address + * @hdr: image header + * + * image_get_data() returns address of the image payload. For single + * component images it is image data start. For multi component + * images it points to the null terminated table of sub-images sizes. + * + * returns: + * image payload data start address + */ +static inline ulong image_get_data(const image_header_t *hdr) +{ + return ((ulong)hdr + image_get_header_size()); +} + +static inline uint32_t image_get_image_size(const image_header_t *hdr) +{ + return (image_get_size(hdr) + image_get_header_size()); +} + +static inline ulong image_get_image_end(const image_header_t *hdr) +{ + return ((ulong)hdr + image_get_image_size(hdr)); +} + +#define image_set_hdr_u32(x) \ +static inline void image_set_##x(image_header_t *hdr, uint32_t val) \ +{ \ + hdr->ih_##x = cpu_to_uimage(val); \ +} + +image_set_hdr_u32(magic); /* image_set_magic */ +image_set_hdr_u32(hcrc); /* image_set_hcrc */ +image_set_hdr_u32(time); /* image_set_time */ +image_set_hdr_u32(size); /* image_set_size */ +image_set_hdr_u32(load); /* image_set_load */ +image_set_hdr_u32(ep); /* image_set_ep */ +image_set_hdr_u32(dcrc); /* image_set_dcrc */ + +#define image_set_hdr_u8(x) \ +static inline void image_set_##x(image_header_t *hdr, uint8_t val) \ +{ \ + hdr->ih_##x = val; \ +} + +image_set_hdr_u8(os); /* image_set_os */ +image_set_hdr_u8(arch); /* image_set_arch */ +image_set_hdr_u8(type); /* image_set_type */ +image_set_hdr_u8(comp); /* image_set_comp */ + +static inline void image_set_name(image_header_t *hdr, const char *name) +{ + strncpy(image_get_name(hdr), name, IH_NMLEN); +} + +/** + * image_multi_count - get component (sub-image) count + * @hdr: pointer to the header of the multi component image + * + * image_multi_count() returns number of components in a multi + * component image. + * + * Note: no checking of the image type is done, caller must pass + * a valid multi component image. + * + * returns: + * number of components + */ +static ulong image_multi_count(void *data) +{ + ulong i, count = 0; + uint32_t *size; + + /* get start of the image payload, which in case of multi + * component images that points to a table of component sizes */ + size = (uint32_t *)data; + + /* count non empty slots */ + for (i = 0; size[i]; ++i) + count++; + + return count; +} + +/** + * image_multi_getimg - get component data address and size + * @hdr: pointer to the header of the multi component image + * @idx: index of the requested component + * @data: pointer to a ulong variable, will hold component data address + * @len: pointer to a ulong variable, will hold component size + * + * image_multi_getimg() returns size and data address for the requested + * component in a multi component image. + * + * Note: no checking of the image type is done, caller must pass + * a valid multi component image. + * + * returns: + * data address and size of the component, if idx is valid + * 0 in data and len, if idx is out of range + */ +static void image_multi_getimg(void *data, ulong idx, + ulong *img_data, ulong *len) +{ + int i; + uint32_t *size; + ulong offset, count, tmp_img_data; + + /* get number of component */ + count = image_multi_count(data); + + /* get start of the image payload, which in case of multi + * component images that points to a table of component sizes */ + size = (uint32_t *)data; + + /* get address of the proper component data start, which means + * skipping sizes table (add 1 for last, null entry) */ + tmp_img_data = (ulong)data + (count + 1) * sizeof (uint32_t); + + if (idx < count) { + *len = uimage_to_cpu(size[idx]); + offset = 0; + + /* go over all indices preceding requested component idx */ + for (i = 0; i < idx; i++) { + /* add up i-th component size, rounding up to 4 bytes */ + offset += (uimage_to_cpu(size[i]) + 3) & ~3 ; + } + + /* calculate idx-th component data address */ + *img_data = tmp_img_data + offset; + } else { + *len = 0; + *img_data = 0; + } +} + +static void image_print_type(const image_header_t *hdr) +{ + const char *os, *arch, *type, *comp; + + os = image_get_os_name(image_get_os(hdr)); + arch = image_get_arch_name(image_get_arch(hdr)); + type = image_get_type_name(image_get_type(hdr)); + comp = image_get_comp_name(image_get_comp(hdr)); + + printf ("%s %s %s (%s)\n", arch, os, type, comp); +} + +static void image_print_time(time_t timestamp) +{ + printf("%s", ctime(×tamp)); +} + +static void image_print_size(uint32_t size) +{ + printf("%d Bytes = %.2f kB = %.2f MB\n", + size, (double)size / 1.024e3, + (double)size / 1.048576e6); +} + +static void image_print_contents(const image_header_t *hdr, void *data) +{ + int type; + + printf("Image Name: %.*s\n", IH_NMLEN, image_get_name(hdr)); + printf("Created: "); + image_print_time((time_t)image_get_time(hdr)); + printf ("Image Type: "); + image_print_type(hdr); + printf ("Data Size: "); + image_print_size(image_get_data_size(hdr)); + printf ("Load Address: %08x\n", image_get_load(hdr)); + printf ("Entry Point: %08x\n", image_get_ep(hdr)); + + type = image_get_type(hdr); + if (data && (type == IH_TYPE_MULTI || type == IH_TYPE_SCRIPT)) { + int i; + ulong img_data, len; + ulong count = image_multi_count(data); + + printf ("Contents:\n"); + for (i = 0; i < count; i++) { + image_multi_getimg(data, i, &img_data, &len); + + printf(" Image %d: ", i); + image_print_size(len); + + if (image_get_type(hdr) != IH_TYPE_SCRIPT && i > 0) { + /* + * the user may need to know offsets + * if planning to do something with + * multiple files + */ + printf(" Offset = 0x%08lx\n", img_data); + } + } + } +} + int main (int argc, char **argv) {