diff options
503 files changed, 22111 insertions, 4592 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf index d88af57..35167e1 100644 --- a/.checkpatch.conf +++ b/.checkpatch.conf @@ -18,3 +18,6 @@ # Not Linux, so we don't recommend usleep_range() over udelay() --ignore USLEEP_RANGE + +# Ignore networking block comment style +--ignore NETWORKING_BLOCK_COMMENT_STYLE @@ -22,9 +22,9 @@ # VERSION = 2013 -PATCHLEVEL = 04 +PATCHLEVEL = 07 SUBLEVEL = -EXTRAVERSION = +EXTRAVERSION = -rc2 ifneq "$(SUBLEVEL)" "" U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) else @@ -247,6 +247,7 @@ OBJS := $(addprefix $(obj),$(OBJS)) HAVE_VENDOR_COMMON_LIB = $(if $(wildcard board/$(VENDOR)/common/Makefile),y,n) LIBS-y += lib/libgeneric.o +LIBS-y += lib/rsa/librsa.o LIBS-y += lib/lzma/liblzma.o LIBS-y += lib/lzo/liblzo.o LIBS-y += lib/zlib/libz.o @@ -746,7 +747,7 @@ endif # config.mk # ARM relocations should all be R_ARM_RELATIVE. checkarmreloc: $(obj)u-boot @if test "R_ARM_RELATIVE" != \ - "`readelf -r $< | cut -d ' ' -f 4 | grep R_ARM | sort -u`"; \ + "`$(CROSS_COMPILE)readelf -r $< | cut -d ' ' -f 4 | grep R_ARM | sort -u`"; \ then echo "$< contains relocations other than \ R_ARM_RELATIVE"; false; fi @@ -831,7 +832,8 @@ clean: $(obj)tools/mk{smdk5250,}spl \ $(obj)tools/mxsboot \ $(obj)tools/ncb $(obj)tools/ubsha1 \ - $(obj)tools/kernel-doc/docproc + $(obj)tools/kernel-doc/docproc \ + $(obj)tools/proftool @rm -f $(obj)board/cray/L1/{bootscript.c,bootscript.image} \ $(obj)board/matrix_vision/*/bootscript.img \ $(obj)board/voiceblue/eeprom \ @@ -413,11 +413,22 @@ The following options need to be configured: See Freescale App Note 4493 for more information about this erratum. + CONFIG_A003399_NOR_WORKAROUND + Enables a workaround for IFC erratum A003399. It is only + requred during NOR boot. + CONFIG_SYS_FSL_CORENET_SNOOPVEC_COREONLY This is the value to write into CCSR offset 0x18600 according to the A004510 workaround. + CONFIG_SYS_FSL_DSP_M2_RAM_ADDR + This value denotes start offset of M2 memory + which is directly connected to the DSP core. + + CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT + This value denotes start offset of DSP CCSR space. + - Generic CPU options: CONFIG_SYS_BIG_ENDIAN, CONFIG_SYS_LITTLE_ENDIAN @@ -843,7 +854,7 @@ The following options need to be configured: CONFIG_CMD_FDOS * Dos diskette Support CONFIG_CMD_FLASH flinfo, erase, protect CONFIG_CMD_FPGA FPGA device initialization support - CONFIG_CMD_FUSE Device fuse support + CONFIG_CMD_FUSE * Device fuse support CONFIG_CMD_GETTIME * Get time since boot CONFIG_CMD_GO * the 'go' command (exec code) CONFIG_CMD_GREPENV * search environment @@ -853,7 +864,7 @@ The following options need to be configured: CONFIG_CMD_IDE * IDE harddisk support CONFIG_CMD_IMI iminfo CONFIG_CMD_IMLS List all images found in NOR flash - CONFIG_CMD_IMLS_NAND List all images found in NAND flash + CONFIG_CMD_IMLS_NAND * List all images found in NAND flash CONFIG_CMD_IMMAP * IMMR dump support CONFIG_CMD_IMPORTENV * import an environment CONFIG_CMD_INI * import data from an ini file into the env @@ -861,23 +872,24 @@ The following options need to be configured: CONFIG_CMD_ITEST Integer/string test of 2 values CONFIG_CMD_JFFS2 * JFFS2 Support CONFIG_CMD_KGDB * kgdb - CONFIG_CMD_LDRINFO ldrinfo (display Blackfin loader) + CONFIG_CMD_LDRINFO * ldrinfo (display Blackfin loader) CONFIG_CMD_LINK_LOCAL * link-local IP address auto-configuration (169.254.*.*) CONFIG_CMD_LOADB loadb CONFIG_CMD_LOADS loads - CONFIG_CMD_MD5SUM print md5 message digest + CONFIG_CMD_MD5SUM * print md5 message digest (requires CONFIG_CMD_MEMORY and CONFIG_MD5) CONFIG_CMD_MEMINFO * Display detailed memory information CONFIG_CMD_MEMORY md, mm, nm, mw, cp, cmp, crc, base, loop, loopw - CONFIG_CMD_MEMTEST mtest + CONFIG_CMD_MEMTEST * mtest CONFIG_CMD_MISC Misc functions like sleep etc CONFIG_CMD_MMC * MMC memory mapped support CONFIG_CMD_MII * MII utility commands CONFIG_CMD_MTDPARTS * MTD partition support CONFIG_CMD_NAND * NAND support CONFIG_CMD_NET bootp, tftpboot, rarpboot + CONFIG_CMD_NFS NFS support CONFIG_CMD_PCA953X * PCA953x I2C gpio commands CONFIG_CMD_PCA953X_INFO * PCA953x I2C gpio info command CONFIG_CMD_PCI * pciinfo @@ -896,7 +908,7 @@ The following options need to be configured: CONFIG_CMD_SETGETDCR Support for DCR Register access (4xx only) CONFIG_CMD_SF * Read/write/erase SPI NOR flash - CONFIG_CMD_SHA1SUM print sha1 memory digest + CONFIG_CMD_SHA1SUM * print sha1 memory digest (requires CONFIG_CMD_MEMORY) CONFIG_CMD_SOFTSWITCH * Soft switch setting command for BF60x CONFIG_CMD_SOURCE "source" command Support @@ -908,6 +920,7 @@ The following options need to be configured: CONFIG_CMD_USB * USB support CONFIG_CMD_CDP * Cisco Discover Protocol support CONFIG_CMD_MFSL * Microblaze FSL support + CONFIG_CMD_XIMG Load part of Multi Image EXAMPLE: If you want all functions except of network @@ -1209,7 +1222,23 @@ The following options need to be configured: If this option is set, the driver enables cache flush. - TPM Support: - CONFIG_GENERIC_LPC_TPM + CONFIG_TPM + Support TPM devices. + + CONFIG_TPM_TIS_I2C + Support for i2c bus TPM devices. Only one device + per system is supported at this time. + + CONFIG_TPM_TIS_I2C_BUS_NUMBER + Define the the i2c bus number for the TPM device + + CONFIG_TPM_TIS_I2C_SLAVE_ADDRESS + Define the TPM's address on the i2c bus + + CONFIG_TPM_TIS_I2C_BURST_LIMITATION + Define the burst count bytes upper limit + + CONFIG_TPM_TIS_LPC Support for generic parallel port TPM devices. Only one device per system is supported at this time. @@ -1245,6 +1274,9 @@ The following options need to be configured: CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the txfilltuning field in the EHCI controller on reset. + CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum + interval for usb hub power-on delay.(minimum 100msec) + - USB Device: Define the below if you wish to use the USB console. Once firmware is rebuilt from a serial console issue the @@ -1360,6 +1392,12 @@ The following options need to be configured: CONFIG_DFU_NAND This enables support for exposing NAND devices via DFU. + CONFIG_SYS_DFU_DATA_BUF_SIZE + Dfu transfer uses a buffer before writing data to the + raw storage device. Make the size (in bytes) of this buffer + configurable. The size of this buffer is also configurable + through the "dfu_bufsiz" environment variable. + CONFIG_SYS_DFU_MAX_FILE_SIZE When updating files rather than the raw storage device, we use a static buffer to copy the file into and then write @@ -1413,6 +1451,11 @@ CBFS (Coreboot Filesystem) support Export function i8042_kbd_init, i8042_tstc and i8042_getc for cfb_console. Supports cursor blinking. + CONFIG_CROS_EC_KEYB + Enables a Chrome OS keyboard using the CROS_EC interface. + This uses CROS_EC to communicate with a second microcontroller + which provides key scans on request. + - Video support: CONFIG_VIDEO @@ -1605,14 +1648,6 @@ CBFS (Coreboot Filesystem) support => vertically centered image at x = dspWidth - bmpWidth - 9 - CONFIG_SPLASH_SCREEN_PREPARE - - If this option is set then the board_splash_screen_prepare() - function, which must be defined in your code, is called as part - of the splash screen display sequence. It gives the board an - opportunity to prepare the splash image data before it is - processed and sent to the frame buffer by U-Boot. - - Gzip compressed BMP image support: CONFIG_VIDEO_BMP_GZIP If this option is set, additionally to standard BMP @@ -2490,6 +2525,11 @@ CBFS (Coreboot Filesystem) support Define this option to include a destructive SPI flash test ('sf test'). + CONFIG_SPI_FLASH_BAR Ban/Extended Addr Reg + + Define this option to use the Bank addr/Extended addr + support on SPI flashes which has size > 16Mbytes. + - SystemACE Support: CONFIG_SYSTEMACE @@ -2541,6 +2581,16 @@ CBFS (Coreboot Filesystem) support Note: There is also a sha1sum command, which should perhaps be deprecated in favour of 'hash sha1'. +- Signing support: + CONFIG_RSA + + This enables the RSA algorithm used for FIT image verification + in U-Boot. See doc/uImage/signature for more information. + + The signing part is build into mkimage regardless of this + option. + + - Show boot progress: CONFIG_SHOW_BOOT_PROGRESS @@ -2765,6 +2815,11 @@ FIT uImage format: most specific compatibility entry of U-Boot's fdt's root node. The order of entries in the configuration's fdt is ignored. + CONFIG_FIT_SIGNATURE + This option enables signature verification of FIT uImages, + using a hash signed and verified using RSA. See + doc/uImage.FIT/signature.txt for more details. + - Standalone program support: CONFIG_STANDALONE_LOAD_ADDR @@ -2916,12 +2971,30 @@ FIT uImage format: Address, size and partition on the MMC to load U-Boot from when the MMC is being used in raw mode. + CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR + Sector to load kernel uImage from when MMC is being + used in raw mode (for Falcon mode) + + CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, + CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS + Sector and number of sectors to load kernel argument + parameters from when MMC is being used in raw mode + (for falcon mode) + CONFIG_SPL_FAT_SUPPORT Support for fs/fat/libfat.o in SPL binary CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME Filename to read to load U-Boot when reading from FAT + CONFIG_SPL_FAT_LOAD_KERNEL_NAME + Filename to read to load kernel uImage when reading + from FAT (for Falcon mode) + + CONFIG_SPL_FAT_LOAD_ARGS_NAME + Filename to read to load kernel argument parameters + when reading from FAT (for Falcon mode) + CONFIG_SPL_MPC83XX_WAIT_FOR_NAND Set this for NAND SPL on PPC mpc83xx targets, so that start.S waits for the rest of the SPL to load before @@ -2985,6 +3058,14 @@ FIT uImage format: CONFIG_SPL_LIBGENERIC_SUPPORT Support for lib/libgeneric.o in SPL binary + CONFIG_SPL_ENV_SUPPORT + Support for the environment operating in SPL binary + + CONFIG_SPL_NET_SUPPORT + Support for the net/libnet.o in SPL binary. + It conflicts with SPL env from storage medium specified by + CONFIG_ENV_IS_xxx but CONFIG_ENV_IS_NOWHERE + CONFIG_SPL_PAD_TO Image offset to which the SPL should be padded before appending the SPL payload. By default, this is defined as @@ -3611,6 +3692,57 @@ but it can not erase, write this NOR flash by SRIO or PCIE interface. You will probably want to define these to avoid a really noisy system when storing the env in UBI. +- CONFIG_ENV_IS_IN_MMC: + + Define this if you have an MMC device which you want to use for the + environment. + + - CONFIG_SYS_MMC_ENV_DEV: + + Specifies which MMC device the environment is stored in. + + - CONFIG_SYS_MMC_ENV_PART (optional): + + Specifies which MMC partition the environment is stored in. If not + set, defaults to partition 0, the user area. Common values might be + 1 (first MMC boot partition), 2 (second MMC boot partition). + + - CONFIG_ENV_OFFSET: + - CONFIG_ENV_SIZE: + + These two #defines specify the offset and size of the environment + area within the specified MMC device. + + If offset is positive (the usual case), it is treated as relative to + the start of the MMC partition. If offset is negative, it is treated + as relative to the end of the MMC partition. This can be useful if + your board may be fitted with different MMC devices, which have + different sizes for the MMC partitions, and you always want the + environment placed at the very end of the partition, to leave the + maximum possible space before it, to store other data. + + These two values are in units of bytes, but must be aligned to an + MMC sector boundary. + + - CONFIG_ENV_OFFSET_REDUND (optional): + + Specifies a second storage area, of CONFIG_ENV_SIZE size, used to + hold a redundant copy of the environment data. This provides a + valid backup copy in case the other copy is corrupted, e.g. due + to a power failure during a "saveenv" operation. + + This value may also be positive or negative; this is handled in the + same way as CONFIG_ENV_OFFSET. + + This value is also in units of bytes, but must also be aligned to + an MMC sector boundary. + + - CONFIG_ENV_SIZE_REDUND (optional): + + This value need not be set, even when CONFIG_ENV_OFFSET_REDUND is + set. If this value is set, it must be set to the same value as + CONFIG_ENV_SIZE. + - CONFIG_SYS_SPI_INIT_OFFSET Defines offset to the initial SPI buffer area in DPRAM. The @@ -3864,6 +3996,9 @@ Low Level (hardware related) configuration options: a second time. Useful for platforms that are pre-booted by coreboot or similar. +- CONFIG_PCI_INDIRECT_BRIDGE: + Enable support for indirect PCI bridges. + - CONFIG_SYS_SRIO: Chip has SRIO or not @@ -3873,6 +4008,9 @@ Low Level (hardware related) configuration options: - CONFIG_SRIO2: Board has SRIO 2 port available +- CONFIG_SRIO_PCIE_BOOT_MASTER + Board can support master function for Boot from SRIO and PCIE + - CONFIG_SYS_SRIOn_MEM_VIRT: Virtual Address of SRIO port 'n' memory region @@ -3983,6 +4121,11 @@ Low Level (hardware related) configuration options: that is executed before the actual U-Boot. E.g. when compiling a NAND SPL. +- CONFIG_SYS_MPC85XX_NO_RESETVEC + Only for 85xx systems. If this variable is specified, the section + .resetvec is not kept and the section .bootpg is placed in the + previous 4k of the .text section. + - CONFIG_ARCH_MAP_SYSMEM Generally U-Boot (and in particular the md command) uses effective address. It is therefore not necessary to regard diff --git a/arch/arm/cpu/armv7/s5p-common/timer.c b/arch/arm/cpu/armv7/s5p-common/timer.c index 4adfaae..637593c 100644 --- a/arch/arm/cpu/armv7/s5p-common/timer.c +++ b/arch/arm/cpu/armv7/s5p-common/timer.c @@ -95,7 +95,7 @@ unsigned long get_timer(unsigned long base) return time_ms - base; } -unsigned long timer_get_us(void) +unsigned long __attribute__((no_instrument_function)) timer_get_us(void) { static unsigned long base_time_us; diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi index f98243c..4fff5e3 100644 --- a/arch/arm/dts/exynos5250.dtsi +++ b/arch/arm/dts/exynos5250.dtsi @@ -229,4 +229,7 @@ interrupts = <0 54 0>; id = <3>; }; + + gpio: gpio { + }; }; diff --git a/arch/arm/include/asm/arch-am33xx/omap.h b/arch/arm/include/asm/arch-am33xx/omap.h index db15159..e7576c1 100644 --- a/arch/arm/include/asm/arch-am33xx/omap.h +++ b/arch/arm/include/asm/arch-am33xx/omap.h @@ -31,8 +31,10 @@ #ifdef CONFIG_AM33XX #define NON_SECURE_SRAM_START 0x402F0400 #define NON_SECURE_SRAM_END 0x40310000 +#define SRAM_SCRATCH_SPACE_ADDR 0x4030C000 #elif defined(CONFIG_TI814X) #define NON_SECURE_SRAM_START 0x40300000 #define NON_SECURE_SRAM_END 0x40320000 +#define SRAM_SCRATCH_SPACE_ADDR 0x4031B800 #endif #endif diff --git a/arch/arm/include/asm/arch-exynos/cpu.h b/arch/arm/include/asm/arch-exynos/cpu.h index 8685c42..1ff231b 100644 --- a/arch/arm/include/asm/arch-exynos/cpu.h +++ b/arch/arm/include/asm/arch-exynos/cpu.h @@ -177,7 +177,7 @@ static inline char *s5p_get_cpu_name(void) } #define IS_SAMSUNG_TYPE(type, id) \ -static inline int cpu_is_##type(void) \ +static inline int __attribute__((no_instrument_function)) cpu_is_##type(void) \ { \ return (s5p_cpu_id >> 12) == id; \ } @@ -186,7 +186,8 @@ IS_SAMSUNG_TYPE(exynos4, 0x4) IS_SAMSUNG_TYPE(exynos5, 0x5) #define IS_EXYNOS_TYPE(type, id) \ -static inline int proid_is_##type(void) \ +static inline int __attribute__((no_instrument_function)) \ + proid_is_##type(void) \ { \ return s5p_cpu_id == id; \ } @@ -196,9 +197,10 @@ IS_EXYNOS_TYPE(exynos4412, 0x4412) IS_EXYNOS_TYPE(exynos5250, 0x5250) #define SAMSUNG_BASE(device, base) \ -static inline unsigned int samsung_get_base_##device(void) \ +static inline unsigned int __attribute__((no_instrument_function)) \ + samsung_get_base_##device(void) \ { \ - if (cpu_is_exynos4()) { \ + if (cpu_is_exynos4()) { \ if (proid_is_exynos4412()) \ return EXYNOS4X12_##base; \ return EXYNOS4_##base; \ diff --git a/arch/arm/include/asm/arch-omap4/omap.h b/arch/arm/include/asm/arch-omap4/omap.h index 66afd92..9fd00ff 100644 --- a/arch/arm/include/asm/arch-omap4/omap.h +++ b/arch/arm/include/asm/arch-omap4/omap.h @@ -127,6 +127,7 @@ struct s32ktimer { */ #define NON_SECURE_SRAM_START 0x40304000 #define NON_SECURE_SRAM_END 0x4030E000 /* Not inclusive */ +#define SRAM_SCRATCH_SPACE_ADDR NON_SECURE_SRAM_START /* base address for indirect vectors (internal boot mode) */ #define SRAM_ROM_VECT_BASE 0x4030D000 diff --git a/arch/arm/include/asm/arch-omap5/omap.h b/arch/arm/include/asm/arch-omap5/omap.h index 817c1ff..5e6d82e 100644 --- a/arch/arm/include/asm/arch-omap5/omap.h +++ b/arch/arm/include/asm/arch-omap5/omap.h @@ -176,6 +176,7 @@ struct s32ktimer { #define NON_SECURE_SRAM_START 0x40300000 #define NON_SECURE_SRAM_END 0x40320000 /* Not inclusive */ #endif +#define SRAM_SCRATCH_SPACE_ADDR NON_SECURE_SRAM_START /* base address for indirect vectors (internal boot mode) */ #define SRAM_ROM_VECT_BASE 0x4031F000 diff --git a/arch/arm/include/asm/omap_common.h b/arch/arm/include/asm/omap_common.h index 787e614..0dbe81b 100644 --- a/arch/arm/include/asm/omap_common.h +++ b/arch/arm/include/asm/omap_common.h @@ -642,7 +642,6 @@ static inline u8 is_omap54xx(void) /* * SRAM scratch space entries */ -#define SRAM_SCRATCH_SPACE_ADDR NON_SECURE_SRAM_START #define OMAP_SRAM_SCRATCH_OMAP_REV SRAM_SCRATCH_SPACE_ADDR #define OMAP_SRAM_SCRATCH_EMIF_SIZE (SRAM_SCRATCH_SPACE_ADDR + 0x4) #define OMAP_SRAM_SCRATCH_EMIF_T_NUM (SRAM_SCRATCH_SPACE_ADDR + 0xC) diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 1b6e0ac..0325d08 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -68,12 +68,19 @@ void arch_lmb_reserve(struct lmb *lmb) gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp); } -static void announce_and_cleanup(void) +/** + * announce_and_cleanup() - Print message and prepare for kernel boot + * + * @fake: non-zero to do everything except actually boot + */ +static void announce_and_cleanup(int fake) { - printf("\nStarting kernel ...\n\n"); + printf("\nStarting kernel ...%s\n\n", fake ? + "(fake run for tracing)" : ""); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_HANDOFF, "start_kernel"); #ifdef CONFIG_BOOTSTAGE_FDT - bootstage_fdt_add_report(); + if (flag == BOOTM_STATE_OS_FAKE_GO) + bootstage_fdt_add_report(); #endif #ifdef CONFIG_BOOTSTAGE_REPORT bootstage_report(); @@ -225,12 +232,13 @@ static void boot_prep_linux(bootm_headers_t *images) } /* Subcommand: GO */ -static void boot_jump_linux(bootm_headers_t *images) +static void boot_jump_linux(bootm_headers_t *images, int flag) { unsigned long machid = gd->bd->bi_arch_number; char *s; void (*kernel_entry)(int zero, int arch, uint params); unsigned long r2; + int fake = (flag & BOOTM_STATE_OS_FAKE_GO); kernel_entry = (void (*)(int, int, uint))images->ep; @@ -243,14 +251,15 @@ static void boot_jump_linux(bootm_headers_t *images) debug("## Transferring control to Linux (at address %08lx)" \ "...\n", (ulong) kernel_entry); bootstage_mark(BOOTSTAGE_ID_RUN_OS); - announce_and_cleanup(); + announce_and_cleanup(fake); if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len) r2 = (unsigned long)images->ft_addr; else r2 = gd->bd->bi_boot_params; - kernel_entry(0, machid, r2); + if (!fake) + kernel_entry(0, machid, r2); } /* Main Entry point for arm bootm implementation @@ -270,13 +279,13 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) return 0; } - if (flag & BOOTM_STATE_OS_GO) { - boot_jump_linux(images); + if (flag & (BOOTM_STATE_OS_GO | BOOTM_STATE_OS_FAKE_GO)) { + boot_jump_linux(images, flag); return 0; } boot_prep_linux(images); - boot_jump_linux(images); + boot_jump_linux(images, flag); return 0; } @@ -291,21 +300,23 @@ struct zimage_header { #define LINUX_ARM_ZIMAGE_MAGIC 0x016f2818 -int bootz_setup(void *image, void **start, void **end) +int bootz_setup(ulong image, ulong *start, ulong *end) { - struct zimage_header *zi = (struct zimage_header *)image; + struct zimage_header *zi; + zi = (struct zimage_header *)map_sysmem(image, 0); if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) { puts("Bad Linux ARM zImage magic!\n"); return 1; } - *start = (void *)zi->zi_start; - *end = (void *)zi->zi_end; + *start = zi->zi_start; + *end = zi->zi_end; - debug("Kernel image @ 0x%08x [ 0x%08x - 0x%08x ]\n", - (uint32_t)image, (uint32_t)*start, (uint32_t)*end); + printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start, + *end); return 0; } + #endif /* CONFIG_CMD_BOOTZ */ diff --git a/arch/avr32/lib/bootm.c b/arch/avr32/lib/bootm.c index 87f3f9c..eedab9d 100644 --- a/arch/avr32/lib/bootm.c +++ b/arch/avr32/lib/bootm.c @@ -187,6 +187,15 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima struct tag *params, *params_start; char *commandline = getenv("bootargs"); + /* + * allow the PREP bootm subcommand, it is required for bootm to work + * + * TODO: Andreas Bießmann <andreas.devel@googlemail.com> refactor the + * do_bootm_linux() for avr32 + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; diff --git a/arch/blackfin/lib/boot.c b/arch/blackfin/lib/boot.c index 768a882..5644d58 100644 --- a/arch/blackfin/lib/boot.c +++ b/arch/blackfin/lib/boot.c @@ -42,6 +42,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima int (*appl) (char *cmdline); char *cmdline; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; diff --git a/arch/m68k/cpu/mcf5445x/speed.c b/arch/m68k/cpu/mcf5445x/speed.c index aa73e1f..0276d4d 100644 --- a/arch/m68k/cpu/mcf5445x/speed.c +++ b/arch/m68k/cpu/mcf5445x/speed.c @@ -122,17 +122,17 @@ void setup_5441x_clocks(void) vco = ((in_be32(&pll->pcr) & PLL_CR_FBKDIV_BITS) + 1) * CONFIG_SYS_INPUT_CLKSRC; - gd->vco_clk = vco; + gd->arch.vco_clk = vco; - gd->inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */ + gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC; /* Input clock */ pdr = in_be32(&pll->pdr); temp = (pdr & PLL_DR_OUTDIV1_BITS) + 1; gd->cpu_clk = vco / temp; /* cpu clock */ - gd->flb_clk = vco / temp; /* FlexBus clock */ - gd->flb_clk >>= 1; + gd->arch.flb_clk = vco / temp; /* FlexBus clock */ + gd->arch.flb_clk >>= 1; if (in_be16(ccm->misccr2) & 2) /* fsys/4 */ - gd->flb_clk >>= 1; + gd->arch.flb_clk >>= 1; temp = ((pdr & PLL_DR_OUTDIV2_BITS) >> 5) + 1; gd->bus_clk = vco / temp; /* bus clock */ diff --git a/arch/m68k/include/asm/m5235.h b/arch/m68k/include/asm/m5235.h index 71a40d3..a573f1c 100644 --- a/arch/m68k/include/asm/m5235.h +++ b/arch/m68k/include/asm/m5235.h @@ -134,7 +134,7 @@ #define SDRAMC_DCR_RC(x) (((x)&0xFF)<<8) /* Bit definitions and macros for SDRAMC_DARCn */ -#define SDRAMC_DARCn_BA(x) (((x)&0xFFFC)<<18) +#define SDRAMC_DARCn_BA(x) ((x)&0xFFFC0000) #define SDRAMC_DARCn_RE (0x00008000) #define SDRAMC_DARCn_CASL_MASK (0x00003000) #define SDRAMC_DARCn_CASL_C0 (0x00000000) diff --git a/arch/m68k/lib/board.c b/arch/m68k/lib/board.c index b2e3068..efc9fcc 100644 --- a/arch/m68k/lib/board.c +++ b/arch/m68k/lib/board.c @@ -403,14 +403,14 @@ void board_init_r (gd_t *id, ulong dest_addr) gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ - debug ("Now running in RAM - U-Boot at: %08lx\n", dest_addr); - WATCHDOG_RESET (); gd->reloc_off = dest_addr - CONFIG_SYS_MONITOR_BASE; serial_initialize(); + debug("Now running in RAM - U-Boot at: %08lx\n", dest_addr); + monitor_flash_len = (ulong)&__init_end - dest_addr; #if defined(CONFIG_NEEDS_MANUAL_RELOC) diff --git a/arch/m68k/lib/bootm.c b/arch/m68k/lib/bootm.c index 56b6512..cc45167 100644 --- a/arch/m68k/lib/bootm.c +++ b/arch/m68k/lib/bootm.c @@ -75,6 +75,12 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima void (*kernel) (bd_t *, ulong, ulong, ulong, ulong); struct lmb *lmb = &images->lmb; + /* + * allow the PREP bootm subcommand, it is required for bootm to work + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; diff --git a/arch/microblaze/lib/bootm.c b/arch/microblaze/lib/bootm.c index 3842709..c5dfc9e 100644 --- a/arch/microblaze/lib/bootm.c +++ b/arch/microblaze/lib/bootm.c @@ -40,6 +40,12 @@ int do_bootm_linux(int flag, int argc, char * const argv[], char *commandline = getenv("bootargs"); ulong rd_data_start, rd_data_end; + /* + * allow the PREP bootm subcommand, it is required for bootm to work + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -62,8 +68,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootstage_mark(BOOTSTAGE_ID_RUN_OS); - if (!of_flat_tree && argc > 3) - of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16); + if (!of_flat_tree && argc > 1) + of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16); /* fixup the initrd now that we know where it should be */ if (images->rd_start && images->rd_end && of_flat_tree) diff --git a/arch/mips/include/asm/errno.h b/arch/mips/include/asm/errno.h index 1665a63..4c82b50 100644 --- a/arch/mips/include/asm/errno.h +++ b/arch/mips/include/asm/errno.h @@ -1,143 +1 @@ -/* - * 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. - * - * Copyright (C) 1995, 1999, 2001, 2002 by Ralf Baechle - */ -#ifndef _ASM_MIPS_ERRNO_H -#define _ASM_MIPS_ERRNO_H - -/* - * These first 34 error codes are from Linux 2.6, <asm-generic/errno-base.h> - */ -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Argument list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ - -/* - * These error numbers are intended to be MIPS ABI compatible - */ -#define ENOMSG 35 /* No message of desired type */ -#define EIDRM 36 /* Identifier removed */ -#define ECHRNG 37 /* Channel number out of range */ -#define EL2NSYNC 38 /* Level 2 not synchronized */ -#define EL3HLT 39 /* Level 3 halted */ -#define EL3RST 40 /* Level 3 reset */ -#define ELNRNG 41 /* Link number out of range */ -#define EUNATCH 42 /* Protocol driver not attached */ -#define ENOCSI 43 /* No CSI structure available */ -#define EL2HLT 44 /* Level 2 halted */ -#define EDEADLK 45 /* Resource deadlock would occur */ -#define ENOLCK 46 /* No record locks available */ -#define EBADE 50 /* Invalid exchange */ -#define EBADR 51 /* Invalid request descriptor */ -#define EXFULL 52 /* Exchange full */ -#define ENOANO 53 /* No anode */ -#define EBADRQC 54 /* Invalid request code */ -#define EBADSLT 55 /* Invalid slot */ -#define EDEADLOCK 56 /* File locking deadlock error */ -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EDOTDOT 73 /* RFS specific error */ -#define EMULTIHOP 74 /* Multihop attempted */ -#define EBADMSG 77 /* Not a data message */ -#define ENAMETOOLONG 78 /* File name too long */ -#define EOVERFLOW 79 /* Value too large for defined data type */ -#define ENOTUNIQ 80 /* Name not unique on network */ -#define EBADFD 81 /* File descriptor in bad state */ -#define EREMCHG 82 /* Remote address changed */ -#define ELIBACC 83 /* Can not access a needed shared library */ -#define ELIBBAD 84 /* Accessing a corrupted shared library */ -#define ELIBSCN 85 /* .lib section in a.out corrupted */ -#define ELIBMAX 86 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 87 /* Cannot exec a shared library directly */ -#define EILSEQ 88 /* Illegal byte sequence */ -#define ENOSYS 89 /* Function not implemented */ -#define ELOOP 90 /* Too many symbolic links encountered */ -#define ERESTART 91 /* Interrupted system call should be restarted */ -#define ESTRPIPE 92 /* Streams pipe error */ -#define ENOTEMPTY 93 /* Directory not empty */ -#define EUSERS 94 /* Too many users */ -#define ENOTSOCK 95 /* Socket operation on non-socket */ -#define EDESTADDRREQ 96 /* Destination address required */ -#define EMSGSIZE 97 /* Message too long */ -#define EPROTOTYPE 98 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 99 /* Protocol not available */ -#define EPROTONOSUPPORT 120 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 121 /* Socket type not supported */ -#define EOPNOTSUPP 122 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 123 /* Protocol family not supported */ -#define EAFNOSUPPORT 124 /* Address family not supported by protocol */ -#define EADDRINUSE 125 /* Address already in use */ -#define EADDRNOTAVAIL 126 /* Cannot assign requested address */ -#define ENETDOWN 127 /* Network is down */ -#define ENETUNREACH 128 /* Network is unreachable */ -#define ENETRESET 129 /* Network dropped connection because of reset */ -#define ECONNABORTED 130 /* Software caused connection abort */ -#define ECONNRESET 131 /* Connection reset by peer */ -#define ENOBUFS 132 /* No buffer space available */ -#define EISCONN 133 /* Transport endpoint is already connected */ -#define ENOTCONN 134 /* Transport endpoint is not connected */ -#define EUCLEAN 135 /* Structure needs cleaning */ -#define ENOTNAM 137 /* Not a XENIX named type file */ -#define ENAVAIL 138 /* No XENIX semaphores available */ -#define EISNAM 139 /* Is a named type file */ -#define EREMOTEIO 140 /* Remote I/O error */ -#define EINIT 141 /* Reserved */ -#define EREMDEV 142 /* Error 142 */ -#define ESHUTDOWN 143 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 144 /* Too many references: cannot splice */ -#define ETIMEDOUT 145 /* Connection timed out */ -#define ECONNREFUSED 146 /* Connection refused */ -#define EHOSTDOWN 147 /* Host is down */ -#define EHOSTUNREACH 148 /* No route to host */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define EALREADY 149 /* Operation already in progress */ -#define EINPROGRESS 150 /* Operation now in progress */ -#define ESTALE 151 /* Stale NFS file handle */ -#define ECANCELED 158 /* AIO operation canceled */ - -#endif /* _ASM_MIPS_ERRNO_H */ +#include <asm-generic/errno.h> diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h index 3864c80..50a882c 100644 --- a/arch/mips/include/asm/io.h +++ b/arch/mips/include/asm/io.h @@ -184,19 +184,19 @@ extern void iounmap(void *addr); * 24-31 on SNI. * XXX more SNI hacks. */ -#define readb(addr) (*(volatile unsigned char *)(addr)) -#define readw(addr) __ioswab16((*(volatile unsigned short *)(addr))) -#define readl(addr) __ioswab32((*(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)) = (__ioswab16(b)) -#define writel(b,addr) (*(volatile unsigned int *)(addr)) = (__ioswab32(b)) -#define __raw_writeb writeb -#define __raw_writew writew -#define __raw_writel writel +#define __raw_readb(addr) (*(volatile unsigned char *)(addr)) +#define __raw_readw(addr) (*(volatile unsigned short *)(addr)) +#define __raw_readl(addr) (*(volatile unsigned int *)(addr)) +#define readb(addr) __raw_readb((addr)) +#define readw(addr) __ioswab16(__raw_readw((addr))) +#define readl(addr) __ioswab32(__raw_readl((addr))) + +#define __raw_writeb(b, addr) (*(volatile unsigned char *)(addr)) = (b) +#define __raw_writew(b, addr) (*(volatile unsigned short *)(addr)) = (b) +#define __raw_writel(b, addr) (*(volatile unsigned int *)(addr)) = (b) +#define writeb(b, addr) __raw_writeb((b), (addr)) +#define writew(b, addr) __raw_writew(__ioswab16(b), (addr)) +#define writel(b, addr) __raw_writel(__ioswab32(b), (addr)) #define memset_io(a,b,c) memset((void *)(a),(b),(c)) #define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) diff --git a/arch/nds32/lib/bootm.c b/arch/nds32/lib/bootm.c index 03f58bf..65ae1eb 100644 --- a/arch/nds32/lib/bootm.c +++ b/arch/nds32/lib/bootm.c @@ -58,6 +58,12 @@ int do_bootm_linux(int flag, int argc, char *argv[], bootm_headers_t *images) char *commandline = getenv("bootargs"); #endif + /* + * allow the PREP bootm subcommand, it is required for bootm to work + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; diff --git a/arch/nios2/lib/bootm.c b/arch/nios2/lib/bootm.c index f32be52..51597ea 100644 --- a/arch/nios2/lib/bootm.c +++ b/arch/nios2/lib/bootm.c @@ -40,11 +40,17 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima if (images->ft_len) of_flat_tree = images->ft_addr; #endif - if (!of_flat_tree && argc > 3) - of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16); + if (!of_flat_tree && argc > 1) + of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16); if (of_flat_tree) initrd_end = (ulong)of_flat_tree; + /* + * allow the PREP bootm subcommand, it is required for bootm to work + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; diff --git a/arch/openrisc/lib/bootm.c b/arch/openrisc/lib/bootm.c index 2c5d9ae..24ca0a7 100644 --- a/arch/openrisc/lib/bootm.c +++ b/arch/openrisc/lib/bootm.c @@ -41,6 +41,12 @@ int do_bootm_linux(int flag, int argc, char * const argv[], void (*kernel) (unsigned int); ulong rd_data_start, rd_data_end; + /* + * allow the PREP bootm subcommand, it is required for bootm to work + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -63,8 +69,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], show_boot_progress(15); - if (!of_flat_tree && argc > 3) - of_flat_tree = (char *)simple_strtoul(argv[3], NULL, 16); + if (!of_flat_tree && argc > 1) + of_flat_tree = (char *)simple_strtoul(argv[1], NULL, 16); #ifdef DEBUG printf("## Transferring control to Linux (at address 0x%08lx) " \ "ramdisk 0x%08lx, FDT 0x%08lx...\n", diff --git a/arch/powerpc/cpu/mpc8260/commproc.c b/arch/powerpc/cpu/mpc8260/commproc.c index 22cef3e..484bd17 100644 --- a/arch/powerpc/cpu/mpc8260/commproc.c +++ b/arch/powerpc/cpu/mpc8260/commproc.c @@ -43,7 +43,7 @@ m8260_cpm_reset(void) } while ((immr->im_cpm.cp_cpcr & CPM_CR_FLG) && ++count < 1000000); #ifdef CONFIG_HARD_I2C - *((unsigned short*)(&immr->im_dprambase[PROFF_I2C_BASE])) = 0; + immr->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)] = 0; #endif } diff --git a/arch/powerpc/cpu/mpc8260/cpu.c b/arch/powerpc/cpu/mpc8260/cpu.c index f8bc5a9..22e1a23 100644 --- a/arch/powerpc/cpu/mpc8260/cpu.c +++ b/arch/powerpc/cpu/mpc8260/cpu.c @@ -106,7 +106,7 @@ int checkcpu (void) * in the mask. */ m = immr & (IMMR_PARTNUM_MSK | IMMR_MASKNUM_MSK); - k = *((ushort *) & immap->im_dprambase[PROFF_REVNUM]); + k = immap->im_dprambase16[PROFF_REVNUM / sizeof(u16)]; switch (m) { case 0x0000: diff --git a/arch/powerpc/cpu/mpc8260/i2c.c b/arch/powerpc/cpu/mpc8260/i2c.c index b720b1f..e2341e9 100644 --- a/arch/powerpc/cpu/mpc8260/i2c.c +++ b/arch/powerpc/cpu/mpc8260/i2c.c @@ -221,14 +221,14 @@ void i2c_init(int speed, int slaveadd) i2c_init_board(); #endif - dpaddr = *((unsigned short *) (&immap->im_dprambase[PROFF_I2C_BASE])); + dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)]; if (dpaddr == 0) { /* need to allocate dual port ram */ dpaddr = m8260_cpm_dpalloc(64 + (NUM_RX_BDS * sizeof(I2C_BD)) + (NUM_TX_BDS * sizeof(I2C_BD)) + MAX_TX_SPACE, 64); - *((unsigned short *)(&immap->im_dprambase[PROFF_I2C_BASE])) = + immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)] = dpaddr; } @@ -305,7 +305,7 @@ void i2c_newio(i2c_state_t *state) debug("[I2C] i2c_newio\n"); - dpaddr = *((unsigned short *)(&immap->im_dprambase[PROFF_I2C_BASE])); + dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)]; iip = (iic_t *)&immap->im_dprambase[dpaddr]; state->rx_idx = 0; state->tx_idx = 0; @@ -480,7 +480,7 @@ int i2c_doio(i2c_state_t *state) return I2CERR_QUEUE_EMPTY; } - dpaddr = *((unsigned short *)(&immap->im_dprambase[PROFF_I2C_BASE])); + dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)]; iip = (iic_t *)&immap->im_dprambase[dpaddr]; iip->iic_rbptr = iip->iic_rbase; iip->iic_tbptr = iip->iic_tbase; diff --git a/arch/powerpc/cpu/mpc8260/serial_smc.c b/arch/powerpc/cpu/mpc8260/serial_smc.c index feba1f6..9410e4c 100644 --- a/arch/powerpc/cpu/mpc8260/serial_smc.c +++ b/arch/powerpc/cpu/mpc8260/serial_smc.c @@ -105,7 +105,7 @@ static int mpc8260_smc_serial_init(void) /* initialize pointers to SMC */ sp = (smc_t *) &(im->im_smc[SMC_INDEX]); - *(ushort *)(&im->im_dprambase[PROFF_SMC_BASE]) = PROFF_SMC; + im->im_dprambase16[PROFF_SMC_BASE / sizeof(u16)] = PROFF_SMC; up = (smc_uart_t *)&im->im_dprambase[PROFF_SMC]; /* Disable transmitter/receiver. */ @@ -331,7 +331,7 @@ kgdb_serial_init (void) /* initialize pointers to SMC */ sp = (smc_t *) &(im->im_smc[KGDB_SMC_INDEX]); - *(ushort *)(&im->im_dprambase[KGDB_PROFF_SMC_BASE]) = KGDB_PROFF_SMC; + im->im_dprambase16[KGDB_PROFF_SMC_BASE / sizeof(u16)] = KGDB_PROFF_SMC; up = (smc_uart_t *)&im->im_dprambase[KGDB_PROFF_SMC]; /* Disable transmitter/receiver. */ diff --git a/arch/powerpc/cpu/mpc8260/spi.c b/arch/powerpc/cpu/mpc8260/spi.c index dc98ea7..01b492e 100644 --- a/arch/powerpc/cpu/mpc8260/spi.c +++ b/arch/powerpc/cpu/mpc8260/spi.c @@ -146,7 +146,7 @@ void spi_init_f (void) immr = (immap_t *) CONFIG_SYS_IMMR; cp = (cpm8260_t *) &immr->im_cpm; - *(ushort *)(&immr->im_dprambase[PROFF_SPI_BASE]) = PROFF_SPI; + immr->im_dprambase16[PROFF_SPI_BASE / sizeof(u16)] = PROFF_SPI; spi = (spi_t *)&immr->im_dprambase[PROFF_SPI]; /* 1 */ diff --git a/arch/powerpc/cpu/mpc85xx/Makefile b/arch/powerpc/cpu/mpc85xx/Makefile index 2318064..4669883 100644 --- a/arch/powerpc/cpu/mpc85xx/Makefile +++ b/arch/powerpc/cpu/mpc85xx/Makefile @@ -73,6 +73,7 @@ COBJS-$(CONFIG_P1014) += ddr-gen3.o COBJS-$(CONFIG_P1020) += ddr-gen3.o COBJS-$(CONFIG_P1021) += ddr-gen3.o COBJS-$(CONFIG_P1022) += ddr-gen3.o +COBJS-$(CONFIG_P1023) += ddr-gen3.o COBJS-$(CONFIG_P1024) += ddr-gen3.o COBJS-$(CONFIG_P1025) += ddr-gen3.o COBJS-$(CONFIG_P2010) += ddr-gen3.o diff --git a/arch/powerpc/cpu/mpc85xx/cmd_errata.c b/arch/powerpc/cpu/mpc85xx/cmd_errata.c index 422782c..a7ed877 100644 --- a/arch/powerpc/cpu/mpc85xx/cmd_errata.c +++ b/arch/powerpc/cpu/mpc85xx/cmd_errata.c @@ -258,6 +258,9 @@ static int do_errata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #ifdef CONFIG_SYS_FSL_ERRATUM_USB14 puts("Work-around for Erratum USB14 enabled\n"); #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006593 + puts("Work-around for Erratum A006593 enabled\n"); +#endif return 0; } diff --git a/arch/powerpc/cpu/mpc85xx/cpu.c b/arch/powerpc/cpu/mpc85xx/cpu.c index 6ce483e..fbee753 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu.c +++ b/arch/powerpc/cpu/mpc85xx/cpu.c @@ -121,16 +121,16 @@ int checkcpu (void) switch(ver) { case PVR_VER_E500_V1: case PVR_VER_E500_V2: - puts("E500"); + puts("e500"); break; case PVR_VER_E500MC: - puts("E500MC"); + puts("e500mc"); break; case PVR_VER_E5500: - puts("E5500"); + puts("e5500"); break; case PVR_VER_E6500: - puts("E6500"); + puts("e6500"); break; default: puts("Unknown"); @@ -341,7 +341,7 @@ phys_size_t initdram(int board_type) #if defined(CONFIG_SPD_EEPROM) || defined(CONFIG_DDR_SPD) return fsl_ddr_sdram_size(); #else - return CONFIG_SYS_SDRAM_SIZE * 1024 * 1024; + return (phys_size_t)CONFIG_SYS_SDRAM_SIZE * 1024 * 1024; #endif } #else /* CONFIG_SYS_RAMBOOT */ diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init.c b/arch/powerpc/cpu/mpc85xx/cpu_init.c index 4067f05..3c8f59c 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init.c @@ -172,6 +172,9 @@ static void enable_cpc(void) #ifdef CONFIG_SYS_FSL_ERRATUM_CPC_A003 setbits_be32(&cpc->cpchdbcr0, CPC_HDBCR0_DATA_ECC_SCRUB_DIS); #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_A006593 + setbits_be32(&cpc->cpchdbcr0, 1 << (31 - 21)); +#endif out_be32(&cpc->cpccsr0, CPC_CSR0_CE | CPC_CSR0_PE); /* Read back to sync write */ @@ -564,7 +567,7 @@ skip_l2: #ifdef CONFIG_SYS_SRIO srio_init(); -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER char *s = getenv("bootmaster"); if (s) { if (!strcmp(s, "SRIO1")) { diff --git a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c index 234fde4..837c034 100644 --- a/arch/powerpc/cpu/mpc85xx/cpu_init_early.c +++ b/arch/powerpc/cpu/mpc85xx/cpu_init_early.c @@ -25,7 +25,7 @@ DECLARE_GLOBAL_DATA_PTR; -#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT) +#ifdef CONFIG_A003399_NOR_WORKAROUND void setup_ifc(void) { struct fsl_ifc *ifc_regs = (void *)CONFIG_SYS_IFC_ADDR; @@ -99,7 +99,7 @@ void cpu_init_early_f(void) #ifdef CONFIG_SYS_FSL_ERRATUM_P1010_A003549 ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); #endif -#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT) +#ifdef CONFIG_A003399_NOR_WORKAROUND ccsr_l2cache_t *l2cache = (void *)CONFIG_SYS_MPC85xx_L2_ADDR; u32 *dst, *src; void (*setup_ifc_sram)(void); @@ -138,7 +138,7 @@ void cpu_init_early_f(void) * Work Around for IFC Erratum A003399, issue will hit only when execution * from NOR Flash */ -#if defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) && !defined(CONFIG_SYS_RAMBOOT) +#ifdef CONFIG_A003399_NOR_WORKAROUND #define SRAM_BASE_ADDR (0x00000000) /* TLB for SRAM */ mas0 = MAS0_TLBSEL(1) | MAS0_ESEL(9); @@ -180,5 +180,9 @@ void cpu_init_early_f(void) invalidate_tlb(1); +#if defined(CONFIG_SYS_PPC_E500_DEBUG_TLB) && !defined(CONFIG_SPL_BUILD) && !defined(CONFIG_NAND_SPL) + disable_tlb(CONFIG_SYS_PPC_E500_DEBUG_TLB); +#endif + init_tlbs(); } diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c index 288f7b2..bb95f3d 100644 --- a/arch/powerpc/cpu/mpc85xx/fdt.c +++ b/arch/powerpc/cpu/mpc85xx/fdt.c @@ -663,7 +663,7 @@ void ft_cpu_setup(void *blob, bd_t *bd) #ifdef CONFIG_FSL_CORENET do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-1.0", "clock-frequency", CONFIG_SYS_CLK_FREQ, 1); - do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-2", + do_fixup_by_compat_u32(blob, "fsl,qoriq-clockgen-2.0", "clock-frequency", CONFIG_SYS_CLK_FREQ, 1); do_fixup_by_compat_u32(blob, "fsl,mpic", "clock-frequency", get_bus_freq(0)/2, 1); diff --git a/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c index 6dadeb8..ec96e81 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c @@ -228,7 +228,7 @@ void fsl_serdes_init(void) break; } - if (srds1_io_sel > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds1_io_sel >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[SRDS1_IO_SEL] = %d\n", srds1_io_sel); return; } @@ -237,7 +237,7 @@ void fsl_serdes_init(void) serdes1_prtcl_map |= (1 << lane_prtcl); } - if (srds2_io_sel > ARRAY_SIZE(serdes2_cfg_tbl)) { + if (srds2_io_sel >= ARRAY_SIZE(serdes2_cfg_tbl)) { printf("Invalid PORDEVSR[SRDS2_IO_SEL] = %d\n", srds2_io_sel); return; } diff --git a/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c index 7c49097..3483366 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c @@ -68,7 +68,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } @@ -77,7 +77,7 @@ void fsl_serdes_init(void) serdes1_prtcl_map |= (1 << lane_prtcl); } - if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c index 76288cd..c9eea15 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c @@ -53,7 +53,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL] = %x\n", srds1_cfg); - if (srds1_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds1_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL] = %d\n", srds1_cfg); return ; } diff --git a/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c index 2582637..49a0290 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c @@ -53,7 +53,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c index f480c26..7af6aff 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c @@ -62,7 +62,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c b/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c index 2ff5d9a..fcccb52 100644 --- a/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c @@ -57,7 +57,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/p1010_serdes.c b/arch/powerpc/cpu/mpc85xx/p1010_serdes.c index e8a0387..1f7dba0 100644 --- a/arch/powerpc/cpu/mpc85xx/p1010_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1010_serdes.c @@ -54,7 +54,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } @@ -63,7 +63,7 @@ void fsl_serdes_init(void) serdes1_prtcl_map |= (1 << lane_prtcl); } - if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/p1021_serdes.c b/arch/powerpc/cpu/mpc85xx/p1021_serdes.c index 1849c16..d6d2696 100644 --- a/arch/powerpc/cpu/mpc85xx/p1021_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1021_serdes.c @@ -73,7 +73,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/p1022_serdes.c b/arch/powerpc/cpu/mpc85xx/p1022_serdes.c index e4c9c22..ed49920 100644 --- a/arch/powerpc/cpu/mpc85xx/p1022_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1022_serdes.c @@ -93,7 +93,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } @@ -102,7 +102,7 @@ void fsl_serdes_init(void) serdes1_prtcl_map |= (1 << lane_prtcl); } - if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/p1023_serdes.c b/arch/powerpc/cpu/mpc85xx/p1023_serdes.c index c8ab5d6..0b4ae90 100644 --- a/arch/powerpc/cpu/mpc85xx/p1023_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p1023_serdes.c @@ -41,7 +41,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/p2020_serdes.c b/arch/powerpc/cpu/mpc85xx/p2020_serdes.c index 389ff6b..01af333 100644 --- a/arch/powerpc/cpu/mpc85xx/p2020_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p2020_serdes.c @@ -61,7 +61,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc85xx/p2041_serdes.c b/arch/powerpc/cpu/mpc85xx/p2041_serdes.c index eec4ffe..87335c9 100644 --- a/arch/powerpc/cpu/mpc85xx/p2041_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p2041_serdes.c @@ -90,7 +90,7 @@ int is_serdes_prtcl_valid(u32 prtcl) u32 svr = get_svr(); u32 ver = SVR_SOC_VER(svr); - if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) + if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl)) return 0; /* P2040[e] does not support XAUI */ diff --git a/arch/powerpc/cpu/mpc85xx/p3041_serdes.c b/arch/powerpc/cpu/mpc85xx/p3041_serdes.c index fba9ff2..a36dcd5 100644 --- a/arch/powerpc/cpu/mpc85xx/p3041_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p3041_serdes.c @@ -139,7 +139,7 @@ enum srds_prtcl serdes_get_prtcl(int cfg, int lane) int is_serdes_prtcl_valid(u32 prtcl) { int i; - if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) + if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl)) return 0; for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/p4080_serdes.c b/arch/powerpc/cpu/mpc85xx/p4080_serdes.c index 87bd795..94ec445 100644 --- a/arch/powerpc/cpu/mpc85xx/p4080_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p4080_serdes.c @@ -86,7 +86,7 @@ enum srds_prtcl serdes_get_prtcl(int cfg, int lane) int is_serdes_prtcl_valid(u32 prtcl) { int i; - if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) + if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl)) return 0; for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/p5020_serdes.c b/arch/powerpc/cpu/mpc85xx/p5020_serdes.c index fba9ff2..a36dcd5 100644 --- a/arch/powerpc/cpu/mpc85xx/p5020_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p5020_serdes.c @@ -139,7 +139,7 @@ enum srds_prtcl serdes_get_prtcl(int cfg, int lane) int is_serdes_prtcl_valid(u32 prtcl) { int i; - if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) + if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl)) return 0; for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/p5040_serdes.c b/arch/powerpc/cpu/mpc85xx/p5040_serdes.c index 890b88e..d646e85 100644 --- a/arch/powerpc/cpu/mpc85xx/p5040_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/p5040_serdes.c @@ -105,7 +105,7 @@ int is_serdes_prtcl_valid(u32 prtcl) { int i; - if (prtcl > ARRAY_SIZE(serdes_cfg_tbl)) + if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl)) return 0; for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/start.S b/arch/powerpc/cpu/mpc85xx/start.S index 4f0480b..2657982 100644 --- a/arch/powerpc/cpu/mpc85xx/start.S +++ b/arch/powerpc/cpu/mpc85xx/start.S @@ -1795,7 +1795,7 @@ clear_bss: stw r0,0(r3) addi r3,r3,4 cmplw 0,r3,r4 - bne 5b + blt 5b 6: mr r3,r9 /* Init Data pointer */ diff --git a/arch/powerpc/cpu/mpc85xx/t1040_serdes.c b/arch/powerpc/cpu/mpc85xx/t1040_serdes.c index 8261e03..19add9f 100644 --- a/arch/powerpc/cpu/mpc85xx/t1040_serdes.c +++ b/arch/powerpc/cpu/mpc85xx/t1040_serdes.c @@ -81,7 +81,7 @@ int is_serdes_prtcl_valid(int serdes, u32 prtcl) { int i; - if (prtcl > (ARRAY_SIZE(serdes_cfg_tbl[serdes]))) + if (prtcl >= ARRAY_SIZE(serdes_cfg_tbl[serdes])) return 0; for (i = 0; i < SRDS_MAX_LANES; i++) { diff --git a/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds index f2b7bff..20284ed 100644 --- a/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds +++ b/arch/powerpc/cpu/mpc85xx/u-boot-spl.lds @@ -26,6 +26,13 @@ #include "config.h" /* CONFIG_BOARDDIR */ OUTPUT_ARCH(powerpc) +#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC +PHDRS +{ + text PT_LOAD; + bss PT_LOAD; +} +#endif SECTIONS { . = CONFIG_SPL_TEXT_BASE; @@ -60,7 +67,7 @@ SECTIONS #if defined(CONFIG_FSL_IFC) /* Restrict bootpg at 4K boundry for IFC */ .bootpg ADDR(.text) + 0x1000 : { - start.o (.bootpg) + arch/powerpc/cpu/mpc85xx/start.o (.bootpg) } #define RESET_VECTOR_OFFSET 0x1ffc /* IFC has 8K sram */ #elif defined(CONFIG_FSL_ELBC) @@ -68,9 +75,16 @@ SECTIONS #else #error unknown NAND controller #endif +#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC + .bootpg ADDR(.text) - 0x1000 : + { + KEEP(*(.bootpg)) + } :text = 0xffff +#else .resetvec ADDR(.text) + RESET_VECTOR_OFFSET : { KEEP(*(.resetvec)) } = 0xffff +#endif /* * Make sure that the bss segment isn't linked at 0x0, otherwise its @@ -78,10 +92,12 @@ SECTIONS */ . |= 0x10; + . = ALIGN(4); __bss_start = .; .bss : { *(.sbss*) *(.bss*) } + . = ALIGN(4); __bss_end = .; } diff --git a/arch/powerpc/cpu/mpc85xx/u-boot.lds b/arch/powerpc/cpu/mpc85xx/u-boot.lds index 0503dce..2643563 100644 --- a/arch/powerpc/cpu/mpc85xx/u-boot.lds +++ b/arch/powerpc/cpu/mpc85xx/u-boot.lds @@ -95,6 +95,13 @@ SECTIONS . = ALIGN(256); __init_end = .; +#ifdef CONFIG_SYS_MPC85XX_NO_RESETVEC + .bootpg ADDR(.text) - 0x1000 : + { + KEEP(arch/powerpc/cpu/mpc85xx/start.o (.bootpg)) + } :text = 0xffff + . = ADDR(.text) + 0x80000; +#else .bootpg RESET_VECTOR_ADDRESS - 0xffc : { arch/powerpc/cpu/mpc85xx/start.o (.bootpg) @@ -117,6 +124,7 @@ SECTIONS #if (RESET_VECTOR_ADDRESS == 0xfffffffc) . |= 0x10; #endif +#endif __bss_start = .; .bss (NOLOAD) : diff --git a/arch/powerpc/cpu/mpc86xx/cpu.c b/arch/powerpc/cpu/mpc86xx/cpu.c index c553415..5ed3eb2 100644 --- a/arch/powerpc/cpu/mpc86xx/cpu.c +++ b/arch/powerpc/cpu/mpc86xx/cpu.c @@ -78,7 +78,7 @@ checkcpu(void) major = PVR_E600_MAJ(pvr); minor = PVR_E600_MIN(pvr); - printf("E600 Core %d", (msscr0 & 0x20) ? 1 : 0 ); + printf("e600 Core %d", (msscr0 & 0x20) ? 1 : 0); if (gur->pordevsr & MPC86xx_PORDEVSR_CORE1TE) puts("\n Core1Translation Enabled"); debug(" (MSSCR0=%x, PORDEVSR=%x)", msscr0, gur->pordevsr); diff --git a/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c b/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c index 0dc1975..0342e34 100644 --- a/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c +++ b/arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c @@ -64,7 +64,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } @@ -73,7 +73,7 @@ void fsl_serdes_init(void) serdes1_prtcl_map |= (1 << lane_prtcl); } - if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c b/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c index 3ae9069..21c5ddb 100644 --- a/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c +++ b/arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c @@ -73,7 +73,7 @@ void fsl_serdes_init(void) debug("PORDEVSR[IO_SEL_SRDS] = %x\n", srds_cfg); - if (srds_cfg > ARRAY_SIZE(serdes1_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes1_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } @@ -82,7 +82,7 @@ void fsl_serdes_init(void) serdes1_prtcl_map |= (1 << lane_prtcl); } - if (srds_cfg > ARRAY_SIZE(serdes2_cfg_tbl)) { + if (srds_cfg >= ARRAY_SIZE(serdes2_cfg_tbl)) { printf("Invalid PORDEVSR[IO_SEL_SRDS] = %d\n", srds_cfg); return; } diff --git a/arch/powerpc/cpu/mpc8xx/cpu.c b/arch/powerpc/cpu/mpc8xx/cpu.c index b6b733d..dc33eb3 100644 --- a/arch/powerpc/cpu/mpc8xx/cpu.c +++ b/arch/powerpc/cpu/mpc8xx/cpu.c @@ -78,7 +78,8 @@ static int check_CPU (long clock, uint pvr, uint immr) if ((pvr >> 16) != 0x0050) return -1; - k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]); + k = (immr << 16) | + immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]; m = 0; suf = ""; @@ -194,7 +195,8 @@ static int check_CPU (long clock, uint pvr, uint immr) if ((pvr >> 16) != 0x0050) return -1; - k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]); + k = (immr << 16) | + immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]; m = 0; switch (k) { @@ -253,7 +255,8 @@ static int check_CPU (long clock, uint pvr, uint immr) if ((pvr >> 16) != 0x0050) return -1; - k = (immr << 16) | in_be16((ushort *)&immap->im_cpm.cp_dparam[0xB0]); + k = (immr << 16) | + in_be16(&immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]); m = 0; switch (k) { @@ -312,7 +315,8 @@ static int check_CPU (long clock, uint pvr, uint immr) if ((pvr >> 16) != 0x0050) return -1; - k = (immr << 16) | *((ushort *) & immap->im_cpm.cp_dparam[0xB0]); + k = (immr << 16) | + immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]; m = 0; switch (k) { diff --git a/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c index 56b319f..4e8a441 100644 --- a/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c +++ b/arch/powerpc/cpu/mpc8xxx/fsl_ifc.c @@ -26,7 +26,7 @@ void print_ifc_regs(void) int i, j; printf("IFC Controller Registers\n"); - for (i = 0; i < FSL_IFC_BANK_COUNT; i++) { + for (i = 0; i < CONFIG_SYS_FSL_IFC_BANK_COUNT; i++) { printf("CSPR%d:0x%08X\tAMASK%d:0x%08X\tCSOR%d:0x%08X\n", i, get_ifc_cspr(i), i, get_ifc_amask(i), i, get_ifc_csor(i)); @@ -43,7 +43,7 @@ void init_early_memctl_regs(void) set_ifc_ftim(IFC_CS0, IFC_FTIM2, CONFIG_SYS_CS0_FTIM2); set_ifc_ftim(IFC_CS0, IFC_FTIM3, CONFIG_SYS_CS0_FTIM3); -#if !defined(CONFIG_SYS_FSL_ERRATUM_IFC_A003399) || defined(CONFIG_SYS_RAMBOOT) +#ifndef CONFIG_A003399_NOR_WORKAROUND #ifdef CONFIG_SYS_CSPR0_EXT set_ifc_cspr_ext(IFC_CS0, CONFIG_SYS_CSPR0_EXT); #endif @@ -94,4 +94,60 @@ void init_early_memctl_regs(void) set_ifc_amask(IFC_CS3, CONFIG_SYS_AMASK3); set_ifc_csor(IFC_CS3, CONFIG_SYS_CSOR3); #endif + +#ifdef CONFIG_SYS_CSPR4_EXT + set_ifc_cspr_ext(IFC_CS4, CONFIG_SYS_CSPR4_EXT); +#endif +#if defined(CONFIG_SYS_CSPR4) && defined(CONFIG_SYS_CSOR4) + set_ifc_ftim(IFC_CS4, IFC_FTIM0, CONFIG_SYS_CS4_FTIM0); + set_ifc_ftim(IFC_CS4, IFC_FTIM1, CONFIG_SYS_CS4_FTIM1); + set_ifc_ftim(IFC_CS4, IFC_FTIM2, CONFIG_SYS_CS4_FTIM2); + set_ifc_ftim(IFC_CS4, IFC_FTIM3, CONFIG_SYS_CS4_FTIM3); + + set_ifc_cspr(IFC_CS4, CONFIG_SYS_CSPR4); + set_ifc_amask(IFC_CS4, CONFIG_SYS_AMASK4); + set_ifc_csor(IFC_CS4, CONFIG_SYS_CSOR4); +#endif + +#ifdef CONFIG_SYS_CSPR5_EXT + set_ifc_cspr_ext(IFC_CS5, CONFIG_SYS_CSPR5_EXT); +#endif +#if defined(CONFIG_SYS_CSPR5) && defined(CONFIG_SYS_CSOR5) + set_ifc_ftim(IFC_CS5, IFC_FTIM0, CONFIG_SYS_CS5_FTIM0); + set_ifc_ftim(IFC_CS5, IFC_FTIM1, CONFIG_SYS_CS5_FTIM1); + set_ifc_ftim(IFC_CS5, IFC_FTIM2, CONFIG_SYS_CS5_FTIM2); + set_ifc_ftim(IFC_CS5, IFC_FTIM3, CONFIG_SYS_CS5_FTIM3); + + set_ifc_cspr(IFC_CS5, CONFIG_SYS_CSPR5); + set_ifc_amask(IFC_CS5, CONFIG_SYS_AMASK5); + set_ifc_csor(IFC_CS5, CONFIG_SYS_CSOR5); +#endif + +#ifdef CONFIG_SYS_CSPR6_EXT + set_ifc_cspr_ext(IFC_CS6, CONFIG_SYS_CSPR6_EXT); +#endif +#if defined(CONFIG_SYS_CSPR6) && defined(CONFIG_SYS_CSOR6) + set_ifc_ftim(IFC_CS6, IFC_FTIM0, CONFIG_SYS_CS6_FTIM0); + set_ifc_ftim(IFC_CS6, IFC_FTIM1, CONFIG_SYS_CS6_FTIM1); + set_ifc_ftim(IFC_CS6, IFC_FTIM2, CONFIG_SYS_CS6_FTIM2); + set_ifc_ftim(IFC_CS6, IFC_FTIM3, CONFIG_SYS_CS6_FTIM3); + + set_ifc_cspr(IFC_CS6, CONFIG_SYS_CSPR6); + set_ifc_amask(IFC_CS6, CONFIG_SYS_AMASK6); + set_ifc_csor(IFC_CS6, CONFIG_SYS_CSOR6); +#endif + +#ifdef CONFIG_SYS_CSPR7_EXT + set_ifc_cspr_ext(IFC_CS7, CONFIG_SYS_CSPR7_EXT); +#endif +#if defined(CONFIG_SYS_CSPR7) && defined(CONFIG_SYS_CSOR7) + set_ifc_ftim(IFC_CS7, IFC_FTIM0, CONFIG_SYS_CS7_FTIM0); + set_ifc_ftim(IFC_CS7, IFC_FTIM1, CONFIG_SYS_CS7_FTIM1); + set_ifc_ftim(IFC_CS7, IFC_FTIM2, CONFIG_SYS_CS7_FTIM2); + set_ifc_ftim(IFC_CS7, IFC_FTIM3, CONFIG_SYS_CS7_FTIM3); + + set_ifc_cspr(IFC_CS7, CONFIG_SYS_CSPR7); + set_ifc_amask(IFC_CS7, CONFIG_SYS_AMASK7); + set_ifc_csor(IFC_CS7, CONFIG_SYS_CSOR7); +#endif } diff --git a/arch/powerpc/cpu/mpc8xxx/srio.c b/arch/powerpc/cpu/mpc8xxx/srio.c index 6e6f7dc..90d1065 100644 --- a/arch/powerpc/cpu/mpc8xxx/srio.c +++ b/arch/powerpc/cpu/mpc8xxx/srio.c @@ -24,7 +24,7 @@ #include <asm/fsl_srio.h> #include <asm/errno.h> -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER #define SRIO_PORT_ACCEPT_ALL 0x10000001 #define SRIO_IB_ATMU_AR 0x80f55000 #define SRIO_OB_ATMU_AR_MAINT 0x80077000 @@ -299,7 +299,7 @@ void srio_init(void) } } -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER void srio_boot_master(int port) { struct ccsr_rio *srio = (void *)CONFIG_SYS_FSL_SRIO_ADDR; diff --git a/arch/powerpc/include/asm/8xx_immap.h b/arch/powerpc/include/asm/8xx_immap.h index 40679cb..01129ed 100644 --- a/arch/powerpc/include/asm/8xx_immap.h +++ b/arch/powerpc/include/asm/8xx_immap.h @@ -485,7 +485,12 @@ typedef struct comm_proc { * Some processors don't have all of it populated. */ u_char cp_dpmem[0x1C00]; /* BD / Data / ucode */ - u_char cp_dparam[0x400]; /* Parameter RAM */ + + /* Parameter RAM */ + union { + u_char cp_dparam[0x400]; + u16 cp_dparam16[0x200]; + }; } cpm8xx_t; /* Internal memory map. diff --git a/arch/powerpc/include/asm/config_mpc85xx.h b/arch/powerpc/include/asm/config_mpc85xx.h index 1009a31..1d46b14 100644 --- a/arch/powerpc/include/asm/config_mpc85xx.h +++ b/arch/powerpc/include/asm/config_mpc85xx.h @@ -139,6 +139,7 @@ #define CONFIG_SYS_FSL_SEC_COMPAT 4 #define CONFIG_SYS_FSL_ERRATUM_ESDHC111 #define CONFIG_NUM_DDR_CONTROLLERS 1 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT 4 #define CONFIG_SYS_CCSRBAR_DEFAULT 0xff700000 #define CONFIG_SYS_FSL_PCIE_COMPAT "fsl,qoriq-pcie-v2.2" #define CONFIG_SYS_FSL_USB_INTERNAL_UTMI_PHY @@ -337,7 +338,6 @@ #define CONFIG_SYS_FSL_ERRATUM_CPU_A003999 #define CONFIG_SYS_FSL_ERRATUM_DDR_A003 #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER #define CONFIG_SYS_FSL_SRIO_MAX_PORTS 2 #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM 9 #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM 5 @@ -371,7 +371,6 @@ #define CONFIG_SYS_FSL_ERRATUM_CPU_A003999 #define CONFIG_SYS_FSL_ERRATUM_DDR_A003 #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER #define CONFIG_SYS_FSL_SRIO_MAX_PORTS 2 #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM 9 #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM 5 @@ -413,7 +412,6 @@ #define CONFIG_SYS_P4080_ERRATUM_SERDES_A005 #define CONFIG_SYS_FSL_ERRATUM_CPU_A003999 #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER #define CONFIG_SYS_FSL_SRIO_MAX_PORTS 2 #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM 9 #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM 5 @@ -449,7 +447,6 @@ #define CONFIG_SYS_FSL_ERRATUM_USB14 #define CONFIG_SYS_FSL_ERRATUM_DDR_A003 #define CONFIG_SYS_FSL_ERRATUM_DDR_A003474 -#define CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER #define CONFIG_SYS_FSL_SRIO_MAX_PORTS 2 #define CONFIG_SYS_FSL_SRIO_OB_WIN_NUM 9 #define CONFIG_SYS_FSL_SRIO_IB_WIN_NUM 5 @@ -494,6 +491,9 @@ #define CONFIG_TSECV2 #define CONFIG_SYS_FSL_SEC_COMPAT 4 #define CONFIG_NUM_DDR_CONTROLLERS 1 +#define CONFIG_SYS_FSL_DSP_M2_RAM_ADDR 0xb0000000 +#define CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT 0xff600000 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT 3 #define CONFIG_SYS_CCSRBAR_DEFAULT 0xff700000 #define CONFIG_NAND_FSL_IFC #define CONFIG_SYS_FSL_ERRATUM_ESDHC111 @@ -506,6 +506,7 @@ #define CONFIG_TSECV2 #define CONFIG_SYS_FSL_SEC_COMPAT 4 #define CONFIG_NUM_DDR_CONTROLLERS 2 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT 3 #define CONFIG_SYS_CCSRBAR_DEFAULT 0xff700000 #define CONFIG_NAND_FSL_IFC #define CONFIG_SYS_FSL_ERRATUM_ESDHC111 @@ -541,6 +542,7 @@ #define CONFIG_SYS_FSL_SEC_COMPAT 4 #define CONFIG_SYS_NUM_FMAN 2 #define CONFIG_SYS_FSL_DDR_VER FSL_DDR_VER_4_7 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT 8 #define CONFIG_SYS_FMAN_V3 #define CONFIG_SYS_FM_MURAM_SIZE 0x60000 #define CONFIG_SYS_FSL_TBCLK_DIV 16 @@ -553,6 +555,7 @@ #define CONFIG_SYS_FSL_ERRATUM_A004468 #define CONFIG_SYS_FSL_ERRATUM_A_004934 #define CONFIG_SYS_FSL_ERRATUM_A005871 +#define CONFIG_SYS_FSL_ERRATUM_A006593 #define CONFIG_SYS_CCSRBAR_DEFAULT 0xfe000000 #define CONFIG_SYS_FSL_PCI_VER_3_X @@ -566,6 +569,7 @@ #define CONFIG_SYS_FSL_SEC_COMPAT 4 #define CONFIG_SYS_NUM_FMAN 1 #define CONFIG_SYS_FSL_DDR_VER FSL_DDR_VER_4_7 +#define CONFIG_SYS_FSL_IFC_BANK_COUNT 4 #define CONFIG_SYS_FMAN_V3 #define CONFIG_SYS_FM_MURAM_SIZE 0x60000 #define CONFIG_SYS_FSL_TBCLK_DIV 16 @@ -573,6 +577,7 @@ #define CONFIG_SYS_FSL_USB1_PHY_ENABLE #define CONFIG_SYS_FSL_ERRATUM_A_004934 #define CONFIG_SYS_FSL_ERRATUM_A005871 +#define CONFIG_SYS_FSL_ERRATUM_A006593 #define CONFIG_SYS_CCSRBAR_DEFAULT 0xfe000000 #ifdef CONFIG_PPC_B4860 diff --git a/arch/powerpc/include/asm/fsl_ifc.h b/arch/powerpc/include/asm/fsl_ifc.h index ba41b73..3baf4cc 100644 --- a/arch/powerpc/include/asm/fsl_ifc.h +++ b/arch/powerpc/include/asm/fsl_ifc.h @@ -21,6 +21,7 @@ #ifndef __ASM_PPC_FSL_IFC_H #define __ASM_PPC_FSL_IFC_H +#ifdef CONFIG_FSL_IFC #include <config.h> #include <common.h> @@ -798,13 +799,15 @@ extern void init_early_memctl_regs(void); #define set_ifc_ftim(i, j, v) \ (out_be32(&(IFC_BASE_ADDR)->ftim_cs[i].ftim[j], v)) -#define FSL_IFC_BANK_COUNT 4 - enum ifc_chip_sel { IFC_CS0, IFC_CS1, IFC_CS2, IFC_CS3, + IFC_CS4, + IFC_CS5, + IFC_CS6, + IFC_CS7, }; enum ifc_ftims { @@ -907,6 +910,49 @@ struct fsl_ifc_gpcm { u32 res4[0x1F3]; }; +#ifdef CONFIG_SYS_FSL_IFC_BANK_COUNT +#if (CONFIG_SYS_FSL_IFC_BANK_COUNT <= 8) +#define IFC_CSPR_REG_LEN 148 +#define IFC_AMASK_REG_LEN 144 +#define IFC_CSOR_REG_LEN 144 +#define IFC_FTIM_REG_LEN 576 + +#define IFC_CSPR_USED_LEN sizeof(struct fsl_ifc_cspr) * \ + CONFIG_SYS_FSL_IFC_BANK_COUNT +#define IFC_AMASK_USED_LEN sizeof(struct fsl_ifc_amask) * \ + CONFIG_SYS_FSL_IFC_BANK_COUNT +#define IFC_CSOR_USED_LEN sizeof(struct fsl_ifc_csor) * \ + CONFIG_SYS_FSL_IFC_BANK_COUNT +#define IFC_FTIM_USED_LEN sizeof(struct fsl_ifc_ftim) * \ + CONFIG_SYS_FSL_IFC_BANK_COUNT +#else +#error IFC BANK count not vaild +#endif +#else +#error IFC BANK count not defined +#endif + +struct fsl_ifc_cspr { + u32 cspr_ext; + u32 cspr; + u32 res; +}; + +struct fsl_ifc_amask { + u32 amask; + u32 res[0x2]; +}; + +struct fsl_ifc_csor { + u32 csor; + u32 csor_ext; + u32 res; +}; + +struct fsl_ifc_ftim { + u32 ftim[4]; + u32 res[0x8]; +}; /* * IFC Controller Registers @@ -914,44 +960,30 @@ struct fsl_ifc_gpcm { struct fsl_ifc { u32 ifc_rev; u32 res1[0x2]; - struct { - u32 cspr_ext; - u32 cspr; - u32 res2; - } cspr_cs[FSL_IFC_BANK_COUNT]; - u32 res3[0x19]; - struct { - u32 amask; - u32 res4[0x2]; - } amask_cs[FSL_IFC_BANK_COUNT]; - u32 res5[0x17]; - struct { - u32 csor_ext; - u32 csor; - u32 res6; - } csor_cs[FSL_IFC_BANK_COUNT]; - u32 res7[0x19]; - struct { - u32 ftim[4]; - u32 res8[0x8]; - } ftim_cs[FSL_IFC_BANK_COUNT]; - u32 res9[0x60]; + struct fsl_ifc_cspr cspr_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; + u8 res2[IFC_CSPR_REG_LEN - IFC_CSPR_USED_LEN]; + struct fsl_ifc_amask amask_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; + u8 res3[IFC_AMASK_REG_LEN - IFC_AMASK_USED_LEN]; + struct fsl_ifc_csor csor_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; + u8 res4[IFC_CSOR_REG_LEN - IFC_CSOR_USED_LEN]; + struct fsl_ifc_ftim ftim_cs[CONFIG_SYS_FSL_IFC_BANK_COUNT]; + u8 res5[IFC_FTIM_REG_LEN - IFC_FTIM_USED_LEN]; u32 rb_stat; - u32 res10[0x2]; + u32 res6[0x2]; u32 ifc_gcr; - u32 res11[0x2]; + u32 res7[0x2]; u32 cm_evter_stat; - u32 res12[0x2]; + u32 res8[0x2]; u32 cm_evter_en; - u32 res13[0x2]; + u32 res9[0x2]; u32 cm_evter_intr_en; - u32 res14[0x2]; + u32 res10[0x2]; u32 cm_erattr0; u32 cm_erattr1; - u32 res15[0x2]; + u32 res11[0x2]; u32 ifc_ccr; u32 ifc_csr; - u32 res16[0x2EB]; + u32 res12[0x2EB]; struct fsl_ifc_nand ifc_nand; struct fsl_ifc_nor ifc_nor; struct fsl_ifc_gpcm ifc_gpcm; @@ -961,6 +993,7 @@ struct fsl_ifc { #undef CSPR_MSEL_NOR #define CSPR_MSEL_NOR CSPR_MSEL_GPCM #endif +#endif /* CONFIG_FSL_IFC */ #endif /* __ASSEMBLY__ */ #endif /* __ASM_PPC_FSL_IFC_H */ diff --git a/arch/powerpc/include/asm/fsl_law.h b/arch/powerpc/include/asm/fsl_law.h index 90b264d..bea1636 100644 --- a/arch/powerpc/include/asm/fsl_law.h +++ b/arch/powerpc/include/asm/fsl_law.h @@ -82,11 +82,16 @@ enum law_trgt_if { #ifndef CONFIG_MPC8641 LAW_TRGT_IF_PCIE_1 = 0x02, #endif +#if defined(CONFIG_BSC9131) + LAW_TRGT_IF_OCN_DSP = 0x03, +#else #if !defined(CONFIG_MPC8572) && !defined(CONFIG_P2020) LAW_TRGT_IF_PCIE_3 = 0x03, #endif +#endif LAW_TRGT_IF_LBC = 0x04, LAW_TRGT_IF_CCSR = 0x08, + LAW_TRGT_IF_DSP_CCSR = 0x09, LAW_TRGT_IF_DDR_INTRLV = 0x0b, LAW_TRGT_IF_RIO = 0x0c, LAW_TRGT_IF_RIO_2 = 0x0d, diff --git a/arch/powerpc/include/asm/immap_8260.h b/arch/powerpc/include/asm/immap_8260.h index 4974ae5..c7021a7 100644 --- a/arch/powerpc/include/asm/immap_8260.h +++ b/arch/powerpc/include/asm/immap_8260.h @@ -526,13 +526,18 @@ typedef struct immap { /* Some references are into the unique and known dpram spaces, * others are from the generic base. */ -#define im_dprambase im_dpram1 - u_char im_dpram1[16*1024]; - char res1[16*1024]; - u_char im_dpram2[4*1024]; - char res2[8*1024]; - u_char im_dpram3[4*1024]; - char res3[16*1024]; + union { + struct { + u_char im_dpram1[16 * 1024]; + char res1[16 * 1024]; + u_char im_dpram2[4 * 1024]; + char res2[8 * 1024]; + u_char im_dpram3[4 * 1024]; + char res3[16 * 1024]; + }; + u8 im_dprambase[64 * 1024]; + u16 im_dprambase16[32 * 1024]; + }; sysconf8260_t im_siu_conf; /* SIU Configuration */ memctl8260_t im_memctl; /* Memory Controller */ diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h index 4052037..db70d04 100644 --- a/arch/powerpc/include/asm/immap_85xx.h +++ b/arch/powerpc/include/asm/immap_85xx.h @@ -1839,11 +1839,13 @@ typedef struct ccsr_gur { #define FSL_CORENET2_RCWSR4_SRDS3_PRTCL_SHIFT 11 #define FSL_CORENET2_RCWSR4_SRDS4_PRTCL 0x000000f8 #define FSL_CORENET2_RCWSR4_SRDS4_PRTCL_SHIFT 3 +#define FSL_CORENET_RCWSR6_BOOT_LOC 0x0f800000 #elif defined(CONFIG_PPC_B4860) || defined(CONFIG_PPC_B4420) #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL 0xfe000000 #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT 25 #define FSL_CORENET2_RCWSR4_SRDS2_PRTCL 0x00ff0000 #define FSL_CORENET2_RCWSR4_SRDS2_PRTCL_SHIFT 16 +#define FSL_CORENET_RCWSR6_BOOT_LOC 0x0f800000 #elif defined(CONFIG_PPC_T1040) #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL 0xff000000 #define FSL_CORENET2_RCWSR4_SRDS1_PRTCL_SHIFT 24 @@ -2160,7 +2162,7 @@ typedef struct ccsr_gur { u32 porbmsr; /* POR boot mode status */ #define MPC85xx_PORBMSR_HA 0x00070000 #define MPC85xx_PORBMSR_HA_SHIFT 16 -#define MPC85XX_PORBMSR_ROMLOC_SHIFT 24 +#define MPC85xx_PORBMSR_ROMLOC_SHIFT 24 #define PORBMSR_ROMLOC_SPI 0x6 #define PORBMSR_ROMLOC_SDHC 0x7 #define PORBMSR_ROMLOC_NAND_2K 0x9 diff --git a/arch/powerpc/lib/bootm.c b/arch/powerpc/lib/bootm.c index dd6c98c..d4ad323 100644 --- a/arch/powerpc/lib/bootm.c +++ b/arch/powerpc/lib/bootm.c @@ -256,11 +256,6 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima return 0; } - if (flag & BOOTM_STATE_OS_GO) { - boot_jump_linux(images); - return 0; - } - boot_prep_linux(images); ret = boot_body_linux(images); if (ret) diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c index dd8d495..e9385de 100644 --- a/arch/sandbox/cpu/cpu.c +++ b/arch/sandbox/cpu/cpu.c @@ -37,7 +37,7 @@ void __udelay(unsigned long usec) os_usleep(usec); } -unsigned long timer_get_us(void) +unsigned long __attribute__((no_instrument_function)) timer_get_us(void) { return os_get_nsec() / 1000; } diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c index d075407..541e450 100644 --- a/arch/sandbox/cpu/os.c +++ b/arch/sandbox/cpu/os.c @@ -152,7 +152,7 @@ void os_usleep(unsigned long usec) usleep(usec); } -u64 os_get_nsec(void) +u64 __attribute__((no_instrument_function)) os_get_nsec(void) { #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) struct timespec tp; diff --git a/arch/sh/lib/bootm.c b/arch/sh/lib/bootm.c index 57273fa..4fdc7aa 100644 --- a/arch/sh/lib/bootm.c +++ b/arch/sh/lib/bootm.c @@ -79,6 +79,12 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t *ima unsigned long size = images->ep - (unsigned long)param; char *bootargs = getenv("bootargs"); + /* + * allow the PREP bootm subcommand, it is required for bootm to work + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; diff --git a/arch/sparc/lib/bootm.c b/arch/sparc/lib/bootm.c index 1a9343c..9e5fb40 100644 --- a/arch/sparc/lib/bootm.c +++ b/arch/sparc/lib/bootm.c @@ -99,6 +99,12 @@ int do_bootm_linux(int flag, int argc, char * const argv[], bootm_headers_t * im void (*kernel) (struct linux_romvec *, void *); int ret; + /* + * allow the PREP bootm subcommand, it is required for bootm to work + */ + if (flag & BOOTM_STATE_OS_PREP) + return 0; + if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; diff --git a/arch/x86/include/asm/global_data.h b/arch/x86/include/asm/global_data.h index 4fdb080..9a2056a 100644 --- a/arch/x86/include/asm/global_data.h +++ b/arch/x86/include/asm/global_data.h @@ -40,7 +40,7 @@ struct arch_global_data { #include <asm-generic/global_data.h> #ifndef __ASSEMBLY__ -static inline gd_t *get_fs_gd_ptr(void) +static inline __attribute__((no_instrument_function)) gd_t *get_fs_gd_ptr(void) { gd_t *gd_ptr; diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h index 6030633..b459a63 100644 --- a/arch/x86/include/asm/msr.h +++ b/arch/x86/include/asm/msr.h @@ -85,7 +85,8 @@ static inline unsigned long long native_read_tscp(unsigned int *aux) #define EAX_EDX_RET(val, low, high) "=A" (val) #endif -static inline unsigned long long native_read_msr(unsigned int msr) +static inline __attribute__((no_instrument_function)) + unsigned long long native_read_msr(unsigned int msr) { DECLARE_ARGS(val, low, high); diff --git a/arch/x86/include/asm/u-boot-x86.h b/arch/x86/include/asm/u-boot-x86.h index 22e0934..709dc84 100644 --- a/arch/x86/include/asm/u-boot-x86.h +++ b/arch/x86/include/asm/u-boot-x86.h @@ -64,7 +64,7 @@ void board_init_f_r_trampoline(ulong) __attribute__ ((noreturn)); void board_init_f_r(void) __attribute__ ((noreturn)); /* Read the time stamp counter */ -static inline uint64_t rdtsc(void) +static inline __attribute__((no_instrument_function)) uint64_t rdtsc(void) { uint32_t high, low; __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)); diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c index 2520228..b84e35a 100644 --- a/arch/x86/lib/bootm.c +++ b/arch/x86/lib/bootm.c @@ -48,6 +48,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], size_t len; #endif + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -63,6 +65,8 @@ int do_bootm_linux(int flag, int argc, char * const argv[], } #if defined(CONFIG_FIT) } else if (images->fit_uname_os) { + int ret; + ret = fit_image_get_data(images->fit_hdr_os, images->fit_noffset_os, &data, &len); if (ret) { diff --git a/arch/x86/lib/gcc.c b/arch/x86/lib/gcc.c index 4043431..497ad75 100644 --- a/arch/x86/lib/gcc.c +++ b/arch/x86/lib/gcc.c @@ -28,7 +28,9 @@ #define WRAP_LIBGCC_CALL(type, name) \ type __normal_##name(type a, type b) __attribute__((regparm(0))); \ type __wrap_##name(type a, type b); \ - type __wrap_##name(type a, type b) { return __normal_##name(a, b); } + type __attribute__((no_instrument_function)) \ + __wrap_##name(type a, type b) \ + { return __normal_##name(a, b); } WRAP_LIBGCC_CALL(long long, __divdi3) WRAP_LIBGCC_CALL(unsigned long long, __udivdi3) diff --git a/arch/x86/lib/tsc_timer.c b/arch/x86/lib/tsc_timer.c index c509801..0688973 100644 --- a/arch/x86/lib/tsc_timer.c +++ b/arch/x86/lib/tsc_timer.c @@ -37,7 +37,7 @@ void timer_set_base(u64 base) * restart. This yields a free running counter guaranteed to take almost 6 * years to wrap around even at 100GHz clock rate. */ -u64 get_ticks(void) +u64 __attribute__((no_instrument_function)) get_ticks(void) { u64 now_tick = rdtsc(); @@ -50,7 +50,7 @@ u64 get_ticks(void) #define PLATFORM_INFO_MSR 0xce /* Get the speed of the TSC timer in MHz */ -unsigned long get_tbclk_mhz(void) +unsigned __attribute__((no_instrument_function)) long get_tbclk_mhz(void) { u32 ratio; u64 platform_info = native_read_msr(PLATFORM_INFO_MSR); @@ -75,7 +75,7 @@ ulong get_timer(ulong base) return get_ms_timer() - base; } -ulong timer_get_us(void) +ulong __attribute__((no_instrument_function)) timer_get_us(void) { return get_ticks() / get_tbclk_mhz(); } diff --git a/board/ait/cam_enc_4xx/cam_enc_4xx.c b/board/ait/cam_enc_4xx/cam_enc_4xx.c index 644c445..80a7822 100644 --- a/board/ait/cam_enc_4xx/cam_enc_4xx.c +++ b/board/ait/cam_enc_4xx/cam_enc_4xx.c @@ -120,7 +120,7 @@ int board_eth_init(bd_t *bis) #ifdef CONFIG_NAND_DAVINCI static int davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { struct nand_chip *this = mtd->priv; int i, eccsize = chip->ecc.size; @@ -167,8 +167,9 @@ davinci_std_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, return 0; } -static void davinci_std_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) +static int davinci_std_write_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required) { unsigned char davinci_ecc_buf[NAND_MAX_OOBSIZE]; struct nand_chip *this = mtd->priv; @@ -218,6 +219,7 @@ static void davinci_std_write_page_syndrome(struct mtd_info *mtd, i = mtd->oobsize - (oob - chip->oob_poi); if (i) chip->write_buf(mtd, oob, i); + return 0; } static int davinci_std_write_oob_syndrome(struct mtd_info *mtd, @@ -239,7 +241,7 @@ static int davinci_std_write_oob_syndrome(struct mtd_info *mtd, } static int davinci_std_read_oob_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, int page, int sndcmd) + struct nand_chip *chip, int page) { struct nand_chip *this = mtd->priv; uint8_t *buf = chip->oob_poi; @@ -249,7 +251,7 @@ static int davinci_std_read_oob_syndrome(struct mtd_info *mtd, chip->read_buf(mtd, bufpoi, mtd->oobsize); - return 1; + return 0; } static void nand_dm365evm_select_chip(struct mtd_info *mtd, int chip) diff --git a/board/atmel/at91sam9n12ek/at91sam9n12ek.c b/board/atmel/at91sam9n12ek/at91sam9n12ek.c index 8752794..3013a42 100644 --- a/board/atmel/at91sam9n12ek/at91sam9n12ek.c +++ b/board/atmel/at91sam9n12ek/at91sam9n12ek.c @@ -33,6 +33,7 @@ #include <lcd.h> #include <atmel_hlcdc.h> #include <atmel_mci.h> +#include <netdev.h> #ifdef CONFIG_LCD_INFO #include <nand.h> @@ -190,6 +191,30 @@ int board_mmc_init(bd_t *bd) } #endif +#ifdef CONFIG_KS8851_MLL +void at91sam9n12ek_ks8851_hw_init(void) +{ + struct at91_smc *smc = (struct at91_smc *)ATMEL_BASE_SMC; + + writel(AT91_SMC_SETUP_NWE(2) | AT91_SMC_SETUP_NCS_WR(0) | + AT91_SMC_SETUP_NRD(1) | AT91_SMC_SETUP_NCS_RD(0), + &smc->cs[2].setup); + writel(AT91_SMC_PULSE_NWE(7) | AT91_SMC_PULSE_NCS_WR(7) | + AT91_SMC_PULSE_NRD(7) | AT91_SMC_PULSE_NCS_RD(7), + &smc->cs[2].pulse); + writel(AT91_SMC_CYCLE_NWE(9) | AT91_SMC_CYCLE_NRD(9), + &smc->cs[2].cycle); + writel(AT91_SMC_MODE_RM_NRD | AT91_SMC_MODE_WM_NWE | + AT91_SMC_MODE_EXNW_DISABLE | + AT91_SMC_MODE_BAT | AT91_SMC_MODE_DBW_16 | + AT91_SMC_MODE_TDF_CYCLE(1), + &smc->cs[2].mode); + + /* Configure NCS2 PIN */ + at91_set_b_periph(AT91_PIO_PORTD, 19, 0); +} +#endif + int board_early_init_f(void) { /* Enable clocks for all PIOs */ @@ -217,9 +242,20 @@ int board_init(void) at91_lcd_hw_init(); #endif +#ifdef CONFIG_KS8851_MLL + at91sam9n12ek_ks8851_hw_init(); +#endif + return 0; } +#ifdef CONFIG_KS8851_MLL +int board_eth_init(bd_t *bis) +{ + return ks8851_mll_initialize(0, CONFIG_KS8851_MLL_BASEADDR); +} +#endif + int dram_init(void) { gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, diff --git a/board/compulab/cm_t35/cm_t35.c b/board/compulab/cm_t35/cm_t35.c index b0b80e5..95098af 100644 --- a/board/compulab/cm_t35/cm_t35.c +++ b/board/compulab/cm_t35/cm_t35.c @@ -120,7 +120,7 @@ static inline int splash_load_from_nand(void) } #endif /* CONFIG_CMD_NAND */ -int board_splash_screen_prepare(void) +int splash_screen_prepare(void) { char *env_splashimage_value; u32 bmp_load_addr; diff --git a/board/eltec/elppc/misc.c b/board/eltec/elppc/misc.c index 89f1b1d..4c3656e 100644 --- a/board/eltec/elppc/misc.c +++ b/board/eltec/elppc/misc.c @@ -207,9 +207,14 @@ int misc_init_r (void) buf[4] = eerev.etheraddr[5]; buf[5] = eerev.etheraddr[4]; - *(unsigned short *) &buf[20] = 0x48B2; - *(unsigned short *) &buf[22] = 0x0004; - *(unsigned short *) &buf[24] = 0x1433; + buf[20] = 0x48; + buf[21] = 0xB2; + + buf[22] = 0x00; + buf[23] = 0x04; + + buf[24] = 0x14; + buf[25] = 0x33; printf ("\nSRom: Writing i82559 info ........ "); if (eepro100_srom_store ((unsigned short *) buf) == -1) diff --git a/board/freescale/b4860qds/tlb.c b/board/freescale/b4860qds/tlb.c index 29cc41b..1416f98 100644 --- a/board/freescale/b4860qds/tlb.c +++ b/board/freescale/b4860qds/tlb.c @@ -52,6 +52,15 @@ struct fsl_e_tlb_entry tlb_table[] = { SET_TLB_ENTRY(1, CONFIG_SYS_INIT_L3_ADDR, CONFIG_SYS_INIT_L3_ADDR, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 0, BOOKE_PAGESZ_1M, 1), +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) + /* + * SRIO_PCIE_BOOT-SLAVE. When slave boot, the address of the + * space is at 0xfff00000, it covered the 0xfffff000. + */ + SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR, + CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_W|MAS2_G, + 0, 0, BOOKE_PAGESZ_1M, 1), #else SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, @@ -137,6 +146,16 @@ struct fsl_e_tlb_entry tlb_table[] = { MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 16, BOOKE_PAGESZ_256M, 1), #endif +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE + /* + * SRIO_PCIE_BOOT-SLAVE. 1M space from 0xffe00000 for + * fetching ucode and ENV from master + */ + SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR, + CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_G, + 0, 17, BOOKE_PAGESZ_1M, 1), +#endif }; int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/board/freescale/bsc9131rdb/Makefile b/board/freescale/bsc9131rdb/Makefile index 6f4cb26..2e829ad 100644 --- a/board/freescale/bsc9131rdb/Makefile +++ b/board/freescale/bsc9131rdb/Makefile @@ -24,12 +24,28 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifdef MINIMAL + +COBJS-y += spl_minimal.o tlb.o law.o + +else + COBJS-y += $(BOARD).o COBJS-y += ddr.o COBJS-y += law.o COBJS-y += tlb.o #COBJS-y += bsc9131rdb_mux.o +endif + SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(COBJS-y)) SOBJS := $(addprefix $(obj),$(SOBJS)) diff --git a/board/freescale/bsc9131rdb/README b/board/freescale/bsc9131rdb/README index 065faa3..4902b98 100644 --- a/board/freescale/bsc9131rdb/README +++ b/board/freescale/bsc9131rdb/README @@ -89,10 +89,14 @@ NAND boot Building U-boot -------------- To build the u-boot for BSC9131RDB: -1. NAND Flash +1. NAND Flash with sysclk 66MHz(J16 on RDB closed, default) make BSC9131RDB_NAND -2. SPI Flash +2. NAND Flash with sysclk 100MHz(J16 on RDB open) + make BSC9131RDB_NAND_SYSCLK100 +3. SPI Flash with sysclk 66MHz(J16 on RDB closed, default) make BSC9131RDB_SPIFLASH +4. SPI Flash with sysclk 100MHz(J16 on RDB open) + make BSC9131RDB_SPIFLASH_SYSCLK100 Memory map ----------- @@ -107,6 +111,16 @@ Memory map 0xFF70_0000 0xFF7F_FFFF PA CCSR 1M 0xFF80_0000 0xFFFF_FFFF Boot Page & NAND Buffer 8M +DDR Memory map +--------------- + 0x0000_0000 0x36FF_FFFF Memory passed onto Linux + 0x3700_0000 0x37FF_FFFF PowerPC-DSP shared control area + 0x3800_0000 0x4FFF_FFFF DSP Private area + + Out of 880M, passed onto Linux, 1hugetlb page of 256M is reserved for + data communcation between PowerPC and DSP core. + Rest is PowerPC private area. + Flashing Images --------------- To place a new u-boot image in the NAND flash and then boot diff --git a/board/freescale/bsc9131rdb/law.c b/board/freescale/bsc9131rdb/law.c index 201c147..0432780 100644 --- a/board/freescale/bsc9131rdb/law.c +++ b/board/freescale/bsc9131rdb/law.c @@ -26,6 +26,10 @@ struct law_entry law_table[] = { SET_LAW(CONFIG_SYS_NAND_BASE_PHYS, LAW_SIZE_1M, LAW_TRGT_IF_IFC), + SET_LAW(CONFIG_SYS_FSL_DSP_CCSRBAR_PHYS, LAW_SIZE_1M, + LAW_TRGT_IF_DSP_CCSR), + SET_LAW(CONFIG_SYS_FSL_DSP_M2_RAM_ADDR, LAW_SIZE_16M, + LAW_TRGT_IF_OCN_DSP), }; int num_law_entries = ARRAY_SIZE(law_table); diff --git a/board/freescale/bsc9131rdb/spl_minimal.c b/board/freescale/bsc9131rdb/spl_minimal.c new file mode 100644 index 0000000..301115e --- /dev/null +++ b/board/freescale/bsc9131rdb/spl_minimal.c @@ -0,0 +1,118 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <ns16550.h> +#include <asm/io.h> +#include <nand.h> +#include <linux/compiler.h> +#include <asm/fsl_law.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Fixed sdram init -- doesn't use serial presence detect. + */ +static void sdram_init(void) +{ + ccsr_ddr_t *ddr = (ccsr_ddr_t *)CONFIG_SYS_MPC8xxx_DDR_ADDR; + + __raw_writel(CONFIG_SYS_DDR_CS0_BNDS, &ddr->cs0_bnds); + __raw_writel(CONFIG_SYS_DDR_CS0_CONFIG, &ddr->cs0_config); +#if CONFIG_CHIP_SELECTS_PER_CTRL > 1 + __raw_writel(CONFIG_SYS_DDR_CS1_BNDS, &ddr->cs1_bnds); + __raw_writel(CONFIG_SYS_DDR_CS1_CONFIG, &ddr->cs1_config); +#endif + __raw_writel(CONFIG_SYS_DDR_TIMING_3_800, &ddr->timing_cfg_3); + __raw_writel(CONFIG_SYS_DDR_TIMING_0_800, &ddr->timing_cfg_0); + __raw_writel(CONFIG_SYS_DDR_TIMING_1_800, &ddr->timing_cfg_1); + __raw_writel(CONFIG_SYS_DDR_TIMING_2_800, &ddr->timing_cfg_2); + + __raw_writel(CONFIG_SYS_DDR_CONTROL_2, &ddr->sdram_cfg_2); + __raw_writel(CONFIG_SYS_DDR_MODE_1_800, &ddr->sdram_mode); + __raw_writel(CONFIG_SYS_DDR_MODE_2_800, &ddr->sdram_mode_2); + + __raw_writel(CONFIG_SYS_DDR_INTERVAL_800, &ddr->sdram_interval); + __raw_writel(CONFIG_SYS_DDR_DATA_INIT, &ddr->sdram_data_init); + __raw_writel(CONFIG_SYS_DDR_CLK_CTRL_800, &ddr->sdram_clk_cntl); + + __raw_writel(CONFIG_SYS_DDR_WRLVL_CONTROL_800, &ddr->ddr_wrlvl_cntl); + __raw_writel(CONFIG_SYS_DDR_TIMING_4, &ddr->timing_cfg_4); + __raw_writel(CONFIG_SYS_DDR_TIMING_5, &ddr->timing_cfg_5); + __raw_writel(CONFIG_SYS_DDR_ZQ_CONTROL, &ddr->ddr_zq_cntl); + + /* Set, but do not enable the memory */ + __raw_writel(CONFIG_SYS_DDR_CONTROL & ~SDRAM_CFG_MEM_EN, &ddr->sdram_cfg); + + asm volatile("sync;isync"); + udelay(500); + + /* Let the controller go */ + out_be32(&ddr->sdram_cfg, in_be32(&ddr->sdram_cfg) | SDRAM_CFG_MEM_EN); + + set_next_law(CONFIG_SYS_NAND_DDR_LAW, LAW_SIZE_1G, LAW_TRGT_IF_DDR_1); +} + +void board_init_f(ulong bootflag) +{ + u32 plat_ratio; + ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + + /* initialize selected port with appropriate baud rate */ + plat_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_PLAT_RATIO; + plat_ratio >>= 1; + gd->bus_clk = CONFIG_SYS_CLK_FREQ * plat_ratio; + + NS16550_init((NS16550_t)CONFIG_SYS_NS16550_COM1, + gd->bus_clk / 16 / CONFIG_BAUDRATE); + + puts("\nNAND boot... "); + + /* Initialize the DDR3 */ + sdram_init(); + + /* copy code to RAM and jump to it - this should not return */ + /* NOTE - code has to be copied out of NAND buffer before + * other blocks can be read. + */ + relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE); +} + +void board_init_r(gd_t *gd, ulong dest_addr) +{ + nand_boot(); +} + +void putc(char c) +{ + if (c == '\n') + NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, '\r'); + + NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, c); +} + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} diff --git a/board/freescale/bsc9131rdb/tlb.c b/board/freescale/bsc9131rdb/tlb.c index 5b68f4a..c05a556 100644 --- a/board/freescale/bsc9131rdb/tlb.c +++ b/board/freescale/bsc9131rdb/tlb.c @@ -44,15 +44,26 @@ struct fsl_e_tlb_entry tlb_table[] = { /* TLB 1 */ /* *I*** - Covers boot page */ SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, - MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, - 0, 0, BOOKE_PAGESZ_4K, 1), + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 0, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SPL_NAND_MINIMAL + SET_TLB_ENTRY(1, 0xffffe000, 0xffffe000, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 10, BOOKE_PAGESZ_4K, 1), +#endif /* *I*G* - CCSRBAR (PA) */ SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 1, BOOKE_PAGESZ_1M, 1), -#if defined(CONFIG_SYS_RAMBOOT) + /* CCSRBAR (DSP) */ + SET_TLB_ENTRY(1, CONFIG_SYS_FSL_DSP_CCSRBAR, + CONFIG_SYS_FSL_DSP_CCSRBAR_PHYS, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 2, BOOKE_PAGESZ_1M, 1), + +#if defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL) SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE, MAS3_SX|MAS3_SW|MAS3_SR, 0, 0, 8, BOOKE_PAGESZ_1G, 1), diff --git a/board/freescale/bsc9132qds/Makefile b/board/freescale/bsc9132qds/Makefile index 267400b..72b1917 100644 --- a/board/freescale/bsc9132qds/Makefile +++ b/board/freescale/bsc9132qds/Makefile @@ -24,11 +24,28 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifdef MINIMAL + +COBJS-y += spl_minimal.o tlb.o law.o + +else + + COBJS-y += $(BOARD).o COBJS-y += ddr.o COBJS-y += law.o COBJS-y += tlb.o +endif + SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(COBJS-y)) SOBJS := $(addprefix $(obj),$(SOBJS)) diff --git a/board/freescale/bsc9132qds/bsc9132qds.c b/board/freescale/bsc9132qds/bsc9132qds.c index 6e1b558..ddc9d0a 100644 --- a/board/freescale/bsc9132qds/bsc9132qds.c +++ b/board/freescale/bsc9132qds/bsc9132qds.c @@ -258,7 +258,7 @@ int misc_init_r(void) u8 val; ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); u32 porbmsr = in_be32(&gur->porbmsr); - u32 romloc = (porbmsr >> MPC85XX_PORBMSR_ROMLOC_SHIFT) & 0xf; + u32 romloc = (porbmsr >> MPC85xx_PORBMSR_ROMLOC_SHIFT) & 0xf; /*Configure 1588 clock-in source from RF Card*/ val = QIXIS_READ_I2C(brdcfg[5]); @@ -360,7 +360,7 @@ void ft_board_setup(void *blob, bd_t *bd) ccsr_gur_t *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR); u32 porbmsr = in_be32(&gur->porbmsr); - u32 romloc = (porbmsr >> MPC85XX_PORBMSR_ROMLOC_SHIFT) & 0xf; + u32 romloc = (porbmsr >> MPC85xx_PORBMSR_ROMLOC_SHIFT) & 0xf; if (!(hwconfig("uart2") && hwconfig("usb1"))) { /* If uart2 is there in hwconfig remove usb node from diff --git a/board/freescale/bsc9132qds/law.c b/board/freescale/bsc9132qds/law.c index dc23658..b4bce99 100644 --- a/board/freescale/bsc9132qds/law.c +++ b/board/freescale/bsc9132qds/law.c @@ -25,11 +25,13 @@ #include <asm/mmu.h> struct law_entry law_table[] = { -#ifndef CONFIG_SYS_NO_FLASH SET_LAW(CONFIG_SYS_FLASH_BASE_PHYS, LAW_SIZE_128M, LAW_TRGT_IF_IFC), -#endif +#ifdef CONFIG_SYS_NAND_BASE_PHYS SET_LAW(CONFIG_SYS_NAND_BASE_PHYS, LAW_SIZE_1M, LAW_TRGT_IF_IFC), +#endif +#ifdef CONFIG_SYS_FPGA_BASE_PHYS SET_LAW(CONFIG_SYS_FPGA_BASE_PHYS, LAW_SIZE_128K, LAW_TRGT_IF_IFC), +#endif }; int num_law_entries = ARRAY_SIZE(law_table); diff --git a/board/freescale/bsc9132qds/spl_minimal.c b/board/freescale/bsc9132qds/spl_minimal.c new file mode 100644 index 0000000..62dee52 --- /dev/null +++ b/board/freescale/bsc9132qds/spl_minimal.c @@ -0,0 +1,130 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <common.h> +#include <ns16550.h> +#include <asm/io.h> +#include <nand.h> +#include <linux/compiler.h> +#include <asm/fsl_law.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/global_data.h> + +DECLARE_GLOBAL_DATA_PTR; + +static void sdram_init(void) +{ + ccsr_ddr_t *ddr = (ccsr_ddr_t *)CONFIG_SYS_MPC8xxx_DDR_ADDR; +#if CONFIG_DDR_CLK_FREQ == 100000000 + __raw_writel(CONFIG_SYS_DDR_CS0_BNDS, &ddr->cs0_bnds); + __raw_writel(CONFIG_SYS_DDR_CS0_CONFIG, &ddr->cs0_config); + __raw_writel(CONFIG_SYS_DDR_CONTROL_800 | SDRAM_CFG_32_BE, &ddr->sdram_cfg); + __raw_writel(CONFIG_SYS_DDR_CONTROL_2_800, &ddr->sdram_cfg_2); + __raw_writel(CONFIG_SYS_DDR_DATA_INIT, &ddr->sdram_data_init); + + __raw_writel(CONFIG_SYS_DDR_TIMING_3_800, &ddr->timing_cfg_3); + __raw_writel(CONFIG_SYS_DDR_TIMING_0_800, &ddr->timing_cfg_0); + __raw_writel(CONFIG_SYS_DDR_TIMING_1_800, &ddr->timing_cfg_1); + __raw_writel(CONFIG_SYS_DDR_TIMING_2_800, &ddr->timing_cfg_2); + __raw_writel(CONFIG_SYS_DDR_MODE_1_800, &ddr->sdram_mode); + __raw_writel(CONFIG_SYS_DDR_MODE_2_800, &ddr->sdram_mode_2); + __raw_writel(CONFIG_SYS_DDR_INTERVAL_800, &ddr->sdram_interval); + __raw_writel(CONFIG_SYS_DDR_CLK_CTRL_800, &ddr->sdram_clk_cntl); + __raw_writel(CONFIG_SYS_DDR_WRLVL_CONTROL_800, &ddr->ddr_wrlvl_cntl); + + __raw_writel(CONFIG_SYS_DDR_TIMING_4_800, &ddr->timing_cfg_4); + __raw_writel(CONFIG_SYS_DDR_TIMING_5_800, &ddr->timing_cfg_5); + __raw_writel(CONFIG_SYS_DDR_ZQ_CONTROL, &ddr->ddr_zq_cntl); +#elif CONFIG_DDR_CLK_FREQ == 133000000 + __raw_writel(CONFIG_SYS_DDR_CS0_BNDS, &ddr->cs0_bnds); + __raw_writel(CONFIG_SYS_DDR_CS0_CONFIG, &ddr->cs0_config); + __raw_writel(CONFIG_SYS_DDR_CONTROL_1333 | SDRAM_CFG_32_BE, &ddr->sdram_cfg); + __raw_writel(CONFIG_SYS_DDR_CONTROL_2_1333, &ddr->sdram_cfg_2); + __raw_writel(CONFIG_SYS_DDR_DATA_INIT, &ddr->sdram_data_init); + + __raw_writel(CONFIG_SYS_DDR_TIMING_3_1333, &ddr->timing_cfg_3); + __raw_writel(CONFIG_SYS_DDR_TIMING_0_1333, &ddr->timing_cfg_0); + __raw_writel(CONFIG_SYS_DDR_TIMING_1_1333, &ddr->timing_cfg_1); + __raw_writel(CONFIG_SYS_DDR_TIMING_2_1333, &ddr->timing_cfg_2); + __raw_writel(CONFIG_SYS_DDR_MODE_1_1333, &ddr->sdram_mode); + __raw_writel(CONFIG_SYS_DDR_MODE_2_1333, &ddr->sdram_mode_2); + __raw_writel(CONFIG_SYS_DDR_INTERVAL_1333, &ddr->sdram_interval); + __raw_writel(CONFIG_SYS_DDR_CLK_CTRL_1333, &ddr->sdram_clk_cntl); + __raw_writel(CONFIG_SYS_DDR_WRLVL_CONTROL_1333, &ddr->ddr_wrlvl_cntl); + + __raw_writel(CONFIG_SYS_DDR_TIMING_4_1333, &ddr->timing_cfg_4); + __raw_writel(CONFIG_SYS_DDR_TIMING_5_1333, &ddr->timing_cfg_5); + __raw_writel(CONFIG_SYS_DDR_ZQ_CONTROL, &ddr->ddr_zq_cntl); +#else + puts("Not a valid DDR Freq Found! Please Reset\n"); +#endif + asm volatile("sync;isync"); + udelay(500); + + /* Let the controller go */ + out_be32(&ddr->sdram_cfg, in_be32(&ddr->sdram_cfg) | SDRAM_CFG_MEM_EN); + + set_next_law(CONFIG_SYS_NAND_DDR_LAW, LAW_SIZE_1G, LAW_TRGT_IF_DDR_1); +} + +void board_init_f(ulong bootflag) +{ + u32 plat_ratio; + ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + + /* initialize selected port with appropriate baud rate */ + plat_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_PLAT_RATIO; + plat_ratio >>= 1; + gd->bus_clk = CONFIG_SYS_CLK_FREQ * plat_ratio; + + NS16550_init((NS16550_t)CONFIG_SYS_NS16550_COM1, + gd->bus_clk / 16 / CONFIG_BAUDRATE); + + puts("\nNAND boot... "); + + /* Initialize the DDR3 */ + sdram_init(); + + /* copy code to RAM and jump to it - this should not return */ + /* NOTE - code has to be copied out of NAND buffer before + * other blocks can be read. + */ + relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE); +} + +void board_init_r(gd_t *gd, ulong dest_addr) +{ + nand_boot(); +} + +void putc(char c) +{ + if (c == '\n') + NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, '\r'); + + NS16550_putc((NS16550_t)CONFIG_SYS_NS16550_COM1, c); +} + +void puts(const char *str) +{ + while (*str) + putc(*str++); +} diff --git a/board/freescale/bsc9132qds/tlb.c b/board/freescale/bsc9132qds/tlb.c index 0e4545f..0ec9a85 100644 --- a/board/freescale/bsc9132qds/tlb.c +++ b/board/freescale/bsc9132qds/tlb.c @@ -44,14 +44,20 @@ struct fsl_e_tlb_entry tlb_table[] = { /* TLB 1 */ /* *I*** - Covers boot page */ SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, - MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, - 0, 0, BOOKE_PAGESZ_4K, 1), + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 0, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SPL_NAND_MINIMAL + SET_TLB_ENTRY(1, 0xffffe000, 0xffffe000, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 10, BOOKE_PAGESZ_4K, 1), +#endif /* *I*G* - CCSRBAR (PA) */ SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 1, BOOKE_PAGESZ_1M, 1), +#ifndef CONFIG_SPL_BUILD SET_TLB_ENTRY(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS, MAS3_SX|MAS3_SR, MAS2_W|MAS2_G, 0, 3, BOOKE_PAGESZ_64M, 1), @@ -61,12 +67,6 @@ struct fsl_e_tlb_entry tlb_table[] = { MAS3_SX|MAS3_SR, MAS2_W|MAS2_G, 0, 4, BOOKE_PAGESZ_64M, 1), -#if defined(CONFIG_SYS_RAMBOOT) - SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE, - MAS3_SX|MAS3_SW|MAS3_SR, 0, - 0, 8, BOOKE_PAGESZ_1G, 1), -#endif - #ifdef CONFIG_PCI /* *I*G* - PCI */ SET_TLB_ENTRY(1, CONFIG_SYS_PCIE1_MEM_VIRT, CONFIG_SYS_PCIE1_MEM_PHYS, @@ -78,15 +78,26 @@ struct fsl_e_tlb_entry tlb_table[] = { MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 7, BOOKE_PAGESZ_64K, 1), #endif +#endif + +#if defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL) + SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 8, BOOKE_PAGESZ_1G, 1), +#endif +#ifdef CONFIG_SYS_FPGA_BASE /* *I*G - Board FPGA */ SET_TLB_ENTRY(1, CONFIG_SYS_FPGA_BASE, CONFIG_SYS_FPGA_BASE_PHYS, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 9, BOOKE_PAGESZ_256K, 1), +#endif +#ifdef CONFIG_SYS_NAND_BASE_PHYS SET_TLB_ENTRY(1, CONFIG_SYS_NAND_BASE, CONFIG_SYS_NAND_BASE_PHYS, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 5, BOOKE_PAGESZ_1M, 1), +#endif }; int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/board/freescale/common/Makefile b/board/freescale/common/Makefile index 72bb56c..37236d0 100644 --- a/board/freescale/common/Makefile +++ b/board/freescale/common/Makefile @@ -29,6 +29,15 @@ endif LIB = $(obj)libfreescale.o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifndef MINIMAL COBJS-$(CONFIG_FSL_CADMUS) += cadmus.o COBJS-$(CONFIG_FSL_VIA) += cds_via.o COBJS-$(CONFIG_FMAN_ENET) += fman.o @@ -68,6 +77,7 @@ SUBLIB-$(CONFIG_P3041DS) += p_corenet/libp_corenet.o SUBLIB-$(CONFIG_P4080DS) += p_corenet/libp_corenet.o SUBLIB-$(CONFIG_P5020DS) += p_corenet/libp_corenet.o SUBLIB-$(CONFIG_P5040DS) += p_corenet/libp_corenet.o +endif SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(COBJS-y)) diff --git a/board/freescale/common/pixis.c b/board/freescale/common/pixis.c index 8d07061..fbb709d 100644 --- a/board/freescale/common/pixis.c +++ b/board/freescale/common/pixis.c @@ -480,6 +480,7 @@ static int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const ar || unknown_param) { #ifdef CONFIG_SYS_LONGHELP puts(cmdtp->help); + putc('\n'); #endif return 1; } @@ -512,6 +513,7 @@ static int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const ar && set_px_mpxpll(mpxpll))) { #ifdef CONFIG_SYS_LONGHELP puts(cmdtp->help); + putc('\n'); #endif return 1; } diff --git a/board/freescale/p1010rdb/Makefile b/board/freescale/p1010rdb/Makefile index 4c705b6..e6563be 100644 --- a/board/freescale/p1010rdb/Makefile +++ b/board/freescale/p1010rdb/Makefile @@ -24,11 +24,27 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).o +MINIMAL= + +ifdef CONFIG_SPL_BUILD +ifdef CONFIG_SPL_INIT_MINIMAL +MINIMAL=y +endif +endif + +ifdef MINIMAL + +COBJS-y += spl_minimal.o tlb.o law.o + +else + COBJS-y += $(BOARD).o COBJS-y += ddr.o COBJS-y += law.o COBJS-y += tlb.o +endif + SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) OBJS := $(addprefix $(obj),$(COBJS-y)) SOBJS := $(addprefix $(obj),$(SOBJS)) diff --git a/nand_spl/board/freescale/p1010rdb/nand_boot.c b/board/freescale/p1010rdb/spl_minimal.c index 3c7bc2b..c909e0e 100644 --- a/nand_spl/board/freescale/p1010rdb/nand_boot.c +++ b/board/freescale/p1010rdb/spl_minimal.c @@ -31,11 +31,18 @@ DECLARE_GLOBAL_DATA_PTR; -unsigned long ddr_freq_mhz; void sdram_init(void) { ccsr_ddr_t *ddr = (ccsr_ddr_t *)CONFIG_SYS_MPC8xxx_DDR_ADDR; + ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + u32 ddr_ratio; + unsigned long ddr_freq_mhz; + + ddr_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO; + ddr_ratio = ddr_ratio >> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; + ddr_freq_mhz = (CONFIG_SYS_CLK_FREQ * ddr_ratio) / 0x1000000; + /* mask off E bit */ u32 svr = SVR_SOC_VER(mfspr(SPRN_SVR)); @@ -81,6 +88,7 @@ void sdram_init(void) __raw_writel((CONFIG_SYS_DDR_CS0_BNDS >> 1) & 0x0fff0fff, &ddr->cs0_bnds); } + asm volatile("sync;isync"); udelay(500); /* Let the controller go */ @@ -91,7 +99,7 @@ void sdram_init(void) void board_init_f(ulong bootflag) { - u32 plat_ratio, ddr_ratio; + u32 plat_ratio; ccsr_gur_t *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR; /* initialize selected port with appropriate baud rate */ @@ -99,10 +107,6 @@ void board_init_f(ulong bootflag) plat_ratio >>= 1; gd->bus_clk = CONFIG_SYS_CLK_FREQ * plat_ratio; - ddr_ratio = in_be32(&gur->porpllsr) & MPC85xx_PORPLLSR_DDR_RATIO; - ddr_ratio = ddr_ratio >> MPC85xx_PORPLLSR_DDR_RATIO_SHIFT; - ddr_freq_mhz = (CONFIG_SYS_CLK_FREQ * ddr_ratio) / 0x1000000; - NS16550_init((NS16550_t)CONFIG_SYS_NS16550_COM1, gd->bus_clk / 16 / CONFIG_BAUDRATE); @@ -115,8 +119,8 @@ void board_init_f(ulong bootflag) /* NOTE - code has to be copied out of NAND buffer before * other blocks can be read. */ - relocate_code(CONFIG_SYS_NAND_U_BOOT_RELOC_SP, 0, - CONFIG_SYS_NAND_U_BOOT_RELOC); + + relocate_code(CONFIG_SPL_RELOC_STACK, 0, CONFIG_SPL_RELOC_TEXT_BASE); } void board_init_r(gd_t *gd, ulong dest_addr) diff --git a/board/freescale/p1010rdb/tlb.c b/board/freescale/p1010rdb/tlb.c index 4256bf4..078717a 100644 --- a/board/freescale/p1010rdb/tlb.c +++ b/board/freescale/p1010rdb/tlb.c @@ -44,15 +44,20 @@ struct fsl_e_tlb_entry tlb_table[] = { /* TLB 1 */ /* *I*** - Covers boot page */ SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, - MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, - 0, 0, BOOKE_PAGESZ_4K, 1), + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 0, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SPL_NAND_MINIMAL + SET_TLB_ENTRY(1, 0xffffe000, 0xffffe000, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 10, BOOKE_PAGESZ_4K, 1), +#endif /* *I*G* - CCSRBAR */ SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS, MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 1, BOOKE_PAGESZ_1M, 1), -#ifndef CONFIG_NAND_SPL +#ifndef CONFIG_SPL_BUILD #ifndef CONFIG_SDCARD SET_TLB_ENTRY(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS, MAS3_SX|MAS3_SR, MAS2_W|MAS2_G, @@ -88,7 +93,7 @@ struct fsl_e_tlb_entry tlb_table[] = { 0, 7, BOOKE_PAGESZ_1M, 1), #endif -#if defined(CONFIG_SYS_RAMBOOT) +#if defined(CONFIG_SYS_RAMBOOT) || defined(CONFIG_SPL) SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, CONFIG_SYS_DDR_SDRAM_BASE, MAS3_SX|MAS3_SW|MAS3_SR, 0, 0, 8, BOOKE_PAGESZ_1G, 1) diff --git a/board/freescale/p1023rdb/Makefile b/board/freescale/p1023rdb/Makefile new file mode 100644 index 0000000..45c4f8b --- /dev/null +++ b/board/freescale/p1023rdb/Makefile @@ -0,0 +1,33 @@ +# +# Copyright 2013 Freescale Semiconductor, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).o + +COBJS-y += $(BOARD).o +COBJS-y += ddr.o +COBJS-y += law.o +COBJS-y += tlb.o + +SRCS := $(SOBJS:.o=.S) $(COBJS-y:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS-y)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/freescale/p1023rdb/ddr.c b/board/freescale/p1023rdb/ddr.c new file mode 100644 index 0000000..7ed275a --- /dev/null +++ b/board/freescale/p1023rdb/ddr.c @@ -0,0 +1,105 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/mmu.h> +#include <asm/immap_85xx.h> +#include <asm/processor.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_ddr_dimm_params.h> +#include <asm/io.h> +#include <asm/fsl_law.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* CONFIG_SYS_DDR_RAW_TIMING */ +/* + * Hynix H5TQ1G83TFR-H9C + */ +dimm_params_t ddr_raw_timing = { + .n_ranks = 1, + .rank_density = 536870912u, + .capacity = 536870912u, + .primary_sdram_width = 32, + .ec_sdram_width = 0, + .registered_dimm = 0, + .mirrored_dimm = 0, + .n_row_addr = 14, + .n_col_addr = 10, + .n_banks_per_sdram_device = 8, + .edc_config = 0, + .burst_lengths_bitmask = 0x0c, + + .tCKmin_X_ps = 1875, + .caslat_X = 0x1e << 4, /* 5,6,7,8 */ + .tAA_ps = 13125, + .tWR_ps = 18000, + .tRCD_ps = 13125, + .tRRD_ps = 7500, + .tRP_ps = 13125, + .tRAS_ps = 37500, + .tRC_ps = 50625, + .tRFC_ps = 160000, + .tWTR_ps = 7500, + .tRTP_ps = 7500, + .refresh_rate_ps = 7800000, + .tFAW_ps = 37500, +}; + +int fsl_ddr_get_dimm_params(dimm_params_t *pdimm, + unsigned int controller_number, + unsigned int dimm_number) +{ + const char dimm_model[] = "Fixed DDR on board"; + + if ((controller_number == 0) && (dimm_number == 0)) { + memcpy(pdimm, &ddr_raw_timing, sizeof(dimm_params_t)); + memset(pdimm->mpart, 0, sizeof(pdimm->mpart)); + memcpy(pdimm->mpart, dimm_model, sizeof(dimm_model) - 1); + } + + return 0; +} + +void fsl_ddr_board_options(memctl_options_t *popts, + dimm_params_t *pdimm, + unsigned int ctrl_num) +{ + int i; + popts->clk_adjust = 6; + popts->cpo_override = 0x1f; + popts->write_data_delay = 2; + popts->half_strength_driver_enable = 1; + /* Write leveling override */ + popts->wrlvl_en = 1; + popts->wrlvl_override = 1; + popts->wrlvl_sample = 0xf; + popts->wrlvl_start = 0x8; + popts->trwt_override = 1; + popts->trwt = 0; + + for (i = 0; i < CONFIG_CHIP_SELECTS_PER_CTRL; i++) { + popts->cs_local_opts[i].odt_rd_cfg = FSL_DDR_ODT_NEVER; + popts->cs_local_opts[i].odt_wr_cfg = FSL_DDR_ODT_CS; + } +} + diff --git a/drivers/tpm/slb9635_i2c/compatibility.h b/board/freescale/p1023rdb/law.c index 62dc9fa..331662c 100644 --- a/drivers/tpm/slb9635_i2c/compatibility.h +++ b/board/freescale/p1023rdb/law.c @@ -1,10 +1,5 @@ /* - * Copyright (C) 2011 Infineon Technologies - * - * Authors: - * Peter Huewe <huewe.external@infineon.com> - * - * Version: 2.1.1 + * Copyright 2013 Freescale Semiconductor, Inc. * * See file CREDITS for list of people who contributed to this * project. @@ -25,27 +20,15 @@ * MA 02111-1307 USA */ -#ifndef _COMPATIBILITY_H_ -#define _COMPATIBILITY_H_ - -/* all includes from U-Boot */ -#include <linux/types.h> -#include <linux/unaligned/be_byteshift.h> -#include <asm-generic/errno.h> -#include <compiler.h> #include <common.h> +#include <asm/fsl_law.h> +#include <asm/mmu.h> -/* extended error numbers from linux (see errno.h) */ -#define ECANCELED 125 /* Operation Canceled */ - -#define msleep(t) udelay((t)*1000) - -/* Timer frequency. Corresponds to msec timer resolution*/ -#define HZ 1000 - -#define dev_dbg(dev, format, arg...) debug(format, ##arg) -#define dev_err(dev, format, arg...) printf(format, ##arg) -#define dev_info(dev, format, arg...) debug(format, ##arg) -#define dbg_printf debug +struct law_entry law_table[] = { + SET_LAW(CONFIG_SYS_NAND_BASE_PHYS, LAW_SIZE_1M, LAW_TRGT_IF_LBC), + SET_LAW(CONFIG_SYS_QMAN_MEM_PHYS, LAW_SIZE_4M, + LAW_TRGT_IF_DPAA_SWP_SRAM), + SET_LAW(CONFIG_SYS_FLASH_BASE_PHYS, LAW_SIZE_256M, LAW_TRGT_IF_LBC), +}; -#endif +int num_law_entries = ARRAY_SIZE(law_table); diff --git a/board/freescale/p1023rdb/p1023rdb.c b/board/freescale/p1023rdb/p1023rdb.c new file mode 100644 index 0000000..918398b --- /dev/null +++ b/board/freescale/p1023rdb/p1023rdb.c @@ -0,0 +1,161 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * Authors: Roy Zang <tie-fei.zang@freescale.com> + * Chunhe Lan <Chunhe.Lan@freescale.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <pci.h> +#include <asm/io.h> +#include <asm/cache.h> +#include <asm/processor.h> +#include <asm/mmu.h> +#include <asm/immap_85xx.h> +#include <asm/fsl_pci.h> +#include <asm/fsl_ddr_sdram.h> +#include <asm/fsl_portals.h> +#include <libfdt.h> +#include <fdt_support.h> +#include <netdev.h> +#include <malloc.h> +#include <fm_eth.h> +#include <fsl_mdio.h> +#include <miiphy.h> +#include <phy.h> +#include <asm/fsl_dtsec.h> + +DECLARE_GLOBAL_DATA_PTR; + +int board_early_init_f(void) +{ + fsl_lbc_t *lbc = LBC_BASE_ADDR; + + /* Set ABSWP to implement conversion of addresses in the LBC */ + setbits_be32(&lbc->lbcr, CONFIG_SYS_LBC_LBCR); + + return 0; +} + +int checkboard(void) +{ + printf("Board: P1023 RDB\n"); + + return 0; +} + +#ifdef CONFIG_PCI +void pci_init_board(void) +{ + fsl_pcie_init_board(0); +} +#endif + +int board_early_init_r(void) +{ + const unsigned int flashbase = CONFIG_SYS_FLASH_BASE; + const u8 flash_esel = find_tlb_idx((void *)flashbase, 1); + + /* + * Remap Boot flash + PROMJET region to caching-inhibited + * so that flash can be erased properly. + */ + + /* Flush d-cache and invalidate i-cache of any FLASH data */ + flush_dcache(); + invalidate_icache(); + + /* invalidate existing TLB entry for flash + promjet */ + disable_tlb(flash_esel); + + set_tlb(1, flashbase, CONFIG_SYS_FLASH_BASE_PHYS, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, flash_esel, BOOKE_PAGESZ_256M, 1); + + setup_portals(); + + return 0; +} + +unsigned long get_board_sys_clk(ulong dummy) +{ + return gd->bus_clk; +} + +unsigned long get_board_ddr_clk(ulong dummy) +{ + return gd->mem_clk; +} + +int board_eth_init(bd_t *bis) +{ + ccsr_gur_t *gur = (ccsr_gur_t *)CONFIG_SYS_MPC85xx_GUTS_ADDR; + struct fsl_pq_mdio_info dtsec_mdio_info; + + /* + * Need to set dTSEC 1 pin multiplexing to TSEC. The default setting + * is not correct. + */ + setbits_be32(&gur->pmuxcr, MPC85xx_PMUXCR_TSEC1_1); + + dtsec_mdio_info.regs = + (struct tsec_mii_mng *)CONFIG_SYS_FM1_DTSEC1_MDIO_ADDR; + dtsec_mdio_info.name = DEFAULT_FM_MDIO_NAME; + + /* Register the 1G MDIO bus */ + fsl_pq_mdio_init(bis, &dtsec_mdio_info); + + fm_info_set_phy_address(FM1_DTSEC1, CONFIG_SYS_FM1_DTSEC1_PHY_ADDR); + fm_info_set_phy_address(FM1_DTSEC2, CONFIG_SYS_FM1_DTSEC2_PHY_ADDR); + + fm_info_set_mdio(FM1_DTSEC1, + miiphy_get_dev_by_name(DEFAULT_FM_MDIO_NAME)); + fm_info_set_mdio(FM1_DTSEC2, + miiphy_get_dev_by_name(DEFAULT_FM_MDIO_NAME)); + +#ifdef CONFIG_FMAN_ENET + cpu_eth_init(bis); +#endif + + return pci_eth_init(bis); +} + +#if defined(CONFIG_OF_BOARD_SETUP) +void ft_board_setup(void *blob, bd_t *bd) +{ + phys_addr_t base; + phys_size_t size; + + ft_cpu_setup(blob, bd); + + base = getenv_bootm_low(); + size = getenv_bootm_size(); + + fdt_fixup_memory(blob, (u64)base, (u64)size); + +#ifdef CONFIG_HAS_FSL_DR_USB + fdt_fixup_dr_usb(blob, bd); +#endif + + fdt_fixup_fman_ethernet(blob); +} +#endif diff --git a/board/freescale/p1023rdb/tlb.c b/board/freescale/p1023rdb/tlb.c new file mode 100644 index 0000000..3417c0f --- /dev/null +++ b/board/freescale/p1023rdb/tlb.c @@ -0,0 +1,115 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/mmu.h> + +struct fsl_e_tlb_entry tlb_table[] = { + /* TLB 0 - for temp stack in cache */ + SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR, CONFIG_SYS_INIT_RAM_ADDR, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 4 * 1024, + CONFIG_SYS_INIT_RAM_ADDR + 4 * 1024, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 8 * 1024, + CONFIG_SYS_INIT_RAM_ADDR + 8 * 1024, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 12 * 1024, + CONFIG_SYS_INIT_RAM_ADDR + 12 * 1024, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 0, BOOKE_PAGESZ_4K, 0), + + /* TLB 1 */ + /* *I*** - Covers boot page */ + SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I, + 0, 0, BOOKE_PAGESZ_4K, 1), + + /* *I*G* - CCSRBAR */ + SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 1, BOOKE_PAGESZ_4M, 1), + + /* W**G* - Flash, localbus */ + /* This will be changed to *I*G* after relocation to RAM. */ + SET_TLB_ENTRY(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_W|MAS2_G, + 0, 2, BOOKE_PAGESZ_256M, 1), + + /* *I*G* - PCI */ + SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_MEM_VIRT, CONFIG_SYS_PCIE3_MEM_PHYS, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 3, BOOKE_PAGESZ_1G, 1), + + /* *I*G* - PCI */ + SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_MEM_VIRT + 0x40000000, + CONFIG_SYS_PCIE3_MEM_PHYS + 0x40000000, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 4, BOOKE_PAGESZ_256M, 1), + + SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_MEM_VIRT + 0x50000000, + CONFIG_SYS_PCIE3_MEM_PHYS + 0x50000000, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 5, BOOKE_PAGESZ_256M, 1), + + /* *I*G* - PCI I/O */ + SET_TLB_ENTRY(1, CONFIG_SYS_PCIE3_IO_VIRT, CONFIG_SYS_PCIE3_IO_PHYS, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 6, BOOKE_PAGESZ_256K, 1), + + /* Bman/Qman */ + SET_TLB_ENTRY(1, CONFIG_SYS_BMAN_MEM_BASE, CONFIG_SYS_BMAN_MEM_PHYS, + MAS3_SW|MAS3_SR, 0, + 0, 7, BOOKE_PAGESZ_1M, 1), + SET_TLB_ENTRY(1, CONFIG_SYS_BMAN_MEM_BASE + 0x00100000, + CONFIG_SYS_BMAN_MEM_PHYS + 0x00100000, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 8, BOOKE_PAGESZ_1M, 1), + SET_TLB_ENTRY(1, CONFIG_SYS_QMAN_MEM_BASE, CONFIG_SYS_QMAN_MEM_PHYS, + MAS3_SW|MAS3_SR, MAS2_M, + 0, 9, BOOKE_PAGESZ_1M, 1), + SET_TLB_ENTRY(1, CONFIG_SYS_QMAN_MEM_BASE + 0x00100000, + CONFIG_SYS_QMAN_MEM_PHYS + 0x00100000, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 10, BOOKE_PAGESZ_1M, 1), + + SET_TLB_ENTRY(1, CONFIG_SYS_NAND_BASE, CONFIG_SYS_NAND_BASE_PHYS, + MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, + 0, 11, BOOKE_PAGESZ_16K, 1), + +#ifdef CONFIG_SYS_RAMBOOT + SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE, + CONFIG_SYS_DDR_SDRAM_BASE, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 12, BOOKE_PAGESZ_256M, 1), + + SET_TLB_ENTRY(1, CONFIG_SYS_DDR_SDRAM_BASE + 0x10000000, + CONFIG_SYS_DDR_SDRAM_BASE + 0x10000000, + MAS3_SX|MAS3_SW|MAS3_SR, 0, + 0, 13, BOOKE_PAGESZ_256M, 1), +#endif +}; + +int num_tlb_entries = ARRAY_SIZE(tlb_table); diff --git a/board/freescale/t4qds/tlb.c b/board/freescale/t4qds/tlb.c index 92c01cf..a138d5a 100644 --- a/board/freescale/t4qds/tlb.c +++ b/board/freescale/t4qds/tlb.c @@ -55,6 +55,15 @@ struct fsl_e_tlb_entry tlb_table[] = { SET_TLB_ENTRY(1, CONFIG_SYS_INIT_L3_ADDR, CONFIG_SYS_INIT_L3_ADDR, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 0, BOOKE_PAGESZ_1M, 1), +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) + /* + * SRIO_PCIE_BOOT-SLAVE. When slave boot, the address of the + * space is at 0xfff00000, it covered the 0xfffff000. + */ + SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR, + CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_W|MAS2_G, + 0, 0, BOOKE_PAGESZ_1M, 1), #else SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, @@ -130,6 +139,16 @@ struct fsl_e_tlb_entry tlb_table[] = { SET_TLB_ENTRY(1, QIXIS_BASE, QIXIS_BASE_PHYS, MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G, 0, 17, BOOKE_PAGESZ_4K, 1), +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE + /* + * SRIO_PCIE_BOOT-SLAVE. 1M space from 0xffe00000 for + * fetching ucode and ENV from master + */ + SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR, + CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS, + MAS3_SX|MAS3_SW|MAS3_SR, MAS2_G, + 0, 18, BOOKE_PAGESZ_1M, 1), +#endif }; diff --git a/board/ifm/ac14xx/ac14xx.c b/board/ifm/ac14xx/ac14xx.c index 7442591..dc2aff0 100644 --- a/board/ifm/ac14xx/ac14xx.c +++ b/board/ifm/ac14xx/ac14xx.c @@ -23,6 +23,10 @@ #include <i2c.h> #endif +static int eeprom_diag; +static int mac_diag; +static int gpio_diag; + DECLARE_GLOBAL_DATA_PTR; static void gpio_configure(void) @@ -37,7 +41,7 @@ static void gpio_configure(void) /* * out_be32(&gpioregs->gpdir, 0xC2293020); - * workaround for a hardware affect: configure direction in pieces, + * workaround for a hardware effect: configure direction in pieces, * setting all outputs at once drops the reset line too low and * makes us lose the MII connection (breaks ethernet for us) */ @@ -126,8 +130,6 @@ static u32 gpio_querykbd(void) /* excerpt from the recovery's hw_info.h */ -static int eeprom_diag = 1; - struct __attribute__ ((__packed__)) eeprom_layout { char magic[3]; /** 'ifm' */ u8 len[2]; /** content length without magic/len fields */ @@ -209,6 +211,7 @@ static int read_eeprom(void) int mac_read_from_eeprom(void) { const u8 *mac; + const char *mac_txt; if (read_eeprom()) { printf("I2C EEPROM read failed.\n"); @@ -230,8 +233,13 @@ int mac_read_from_eeprom(void) if (mac && is_valid_ether_addr(mac)) { eth_setenv_enetaddr("ethaddr", mac); - printf("DIAG: %s() MAC value [%s]\n", - __func__, getenv("ethaddr")); + if (mac_diag) { + mac_txt = getenv("ethaddr"); + if (mac_txt) + printf("DIAG: MAC value [%s]\n", mac_txt); + else + printf("DIAG: failed to setup MAC env\n"); + } } return 0; @@ -326,42 +334,38 @@ int misc_init_r(void) gpio_configure(); /* - * check the GPIO keyboard, - * enforced start of the recovery when + * enforce the start of the recovery system when * - the appropriate keys were pressed - * - a previous installation was aborted or has failed * - "some" external software told us to + * - a previous installation was aborted or has failed */ want_recovery = 0; keys = gpio_querykbd(); - printf("GPIO keyboard status [0x%08X]\n", keys); - /* XXX insist in the _exact_ combination? */ + if (gpio_diag) + printf("GPIO keyboard status [0x%02X]\n", keys); if ((keys & GPIOKEY_BITS_RECOVERY) == GPIOKEY_BITS_RECOVERY) { - printf("GPIO keyboard requested RECOVERY\n"); - /* XXX TODO - * refine the logic to detect the first keypress, and - * wait to recheck IF it was the recovery combination? - */ + printf("detected recovery request (keyboard)\n"); want_recovery = 1; } - s = getenv("install_in_progress"); + s = getenv("want_recovery"); if ((s != NULL) && (*s != '\0')) { - printf("previous installation aborted, running RECOVERY\n"); + printf("detected recovery request (environment)\n"); want_recovery = 1; } - s = getenv("install_failed"); + s = getenv("install_in_progress"); if ((s != NULL) && (*s != '\0')) { - printf("previous installation FAILED, running RECOVERY\n"); + printf("previous installation has not completed\n"); want_recovery = 1; } - s = getenv("want_recovery"); + s = getenv("install_failed"); if ((s != NULL) && (*s != '\0')) { - printf("running RECOVERY according to the request\n"); + printf("previous installation has failed\n"); want_recovery = 1; } - - if (want_recovery) + if (want_recovery) { + printf("enforced start of the recovery system\n"); setenv("bootcmd", "run recovery"); + } /* * boot the recovery system without waiting; boot the diff --git a/board/raspberrypi/rpi_b/rpi_b.c b/board/raspberrypi/rpi_b/rpi_b.c index 6b3e095..16d442a 100644 --- a/board/raspberrypi/rpi_b/rpi_b.c +++ b/board/raspberrypi/rpi_b/rpi_b.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2012 Stephen Warren + * (C) Copyright 2012-2013 Stephen Warren * * See file CREDITS for list of people who contributed to this * project. @@ -15,6 +15,8 @@ */ #include <common.h> +#include <config.h> +#include <lcd.h> #include <asm/arch/mbox.h> #include <asm/arch/sdhci.h> #include <asm/global_data.h> @@ -77,3 +79,13 @@ int board_mmc_init(void) return bcm2835_sdhci_init(BCM2835_SDHCI_BASE, msg_clk->get_clock_rate.body.resp.rate_hz); } + +void ft_board_setup(void *blob, bd_t *bd) +{ + /* + * For now, we simply always add the simplefb DT node. Later, we + * should be more intelligent, and e.g. only do this if no enabled DT + * node exists for the "real" graphics driver. + */ + lcd_dt_simplefb_add_node(blob); +} diff --git a/board/samsung/dts/exynos5250-snow.dts b/board/samsung/dts/exynos5250-snow.dts index fdc047a..dca3386 100644 --- a/board/samsung/dts/exynos5250-snow.dts +++ b/board/samsung/dts/exynos5250-snow.dts @@ -38,6 +38,33 @@ console = "/serial@12C30000"; }; + i2c4: i2c@12ca0000 { + cros-ec@1e { + reg = <0x1e>; + compatible = "google,cros-ec"; + i2c-max-frequency = <100000>; + ec-interrupt = <&gpio 782 1>; + }; + + power-regulator@48 { + compatible = "ti,tps65090"; + reg = <0x48>; + }; + }; + + spi@131b0000 { + spi-max-frequency = <1000000>; + spi-deactivate-delay = <100>; + cros-ec@0 { + reg = <0>; + compatible = "google,cros-ec"; + spi-max-frequency = <5000000>; + ec-interrupt = <&gpio 782 1>; + optimise-flash-write; + status = "disabled"; + }; + }; + sound@12d60000 { samsung,i2s-epll-clock-frequency = <192000000>; samsung,i2s-sampling-rate = <48000>; @@ -95,4 +122,58 @@ samsung,dc-value = <25>; }; + cros-ec-keyb { + compatible = "google,cros-ec-keyb"; + google,key-rows = <8>; + google,key-columns = <13>; + google,repeat-delay-ms = <240>; + google,repeat-rate-ms = <30>; + google,ghost-filter; + /* + * Keymap entries take the form of 0xRRCCKKKK where + * RR=Row CC=Column KKKK=Key Code + * The values below are for a US keyboard layout and + * are taken from the Linux driver. Note that the + * 102ND key is not used for US keyboards. + */ + linux,keymap = < + /* CAPSLCK F1 B F10 */ + 0x0001003a 0x0002003b 0x00030030 0x00040044 + /* N = R_ALT ESC */ + 0x00060031 0x0008000d 0x000a0064 0x01010001 + /* F4 G F7 H */ + 0x0102003e 0x01030022 0x01040041 0x01060023 + /* ' F9 BKSPACE L_CTRL */ + 0x01080028 0x01090043 0x010b000e 0x0200001d + /* TAB F3 T F6 */ + 0x0201000f 0x0202003d 0x02030014 0x02040040 + /* ] Y 102ND [ */ + 0x0205001b 0x02060015 0x02070056 0x0208001a + /* F8 GRAVE F2 5 */ + 0x02090042 0x03010029 0x0302003c 0x03030006 + /* F5 6 - \ */ + 0x0304003f 0x03060007 0x0308000c 0x030b002b + /* R_CTRL A D F */ + 0x04000061 0x0401001e 0x04020020 0x04030021 + /* S K J ; */ + 0x0404001f 0x04050025 0x04060024 0x04080027 + /* L ENTER Z C */ + 0x04090026 0x040b001c 0x0501002c 0x0502002e + /* V X , M */ + 0x0503002f 0x0504002d 0x05050033 0x05060032 + /* L_SHIFT / . SPACE */ + 0x0507002a 0x05080035 0x05090034 0x050B0039 + /* 1 3 4 2 */ + 0x06010002 0x06020004 0x06030005 0x06040003 + /* 8 7 0 9 */ + 0x06050009 0x06060008 0x0608000b 0x0609000a + /* L_ALT DOWN RIGHT Q */ + 0x060a0038 0x060b006c 0x060c006a 0x07010010 + /* E R W I */ + 0x07020012 0x07030013 0x07040011 0x07050017 + /* U R_SHIFT P O */ + 0x07060016 0x07070036 0x07080019 0x07090018 + /* UP LEFT */ + 0x070b0067 0x070c0069>; + }; }; diff --git a/board/samsung/smdk5250/exynos5-dt.c b/board/samsung/smdk5250/exynos5-dt.c index 8131505..aacf43e 100644 --- a/board/samsung/smdk5250/exynos5-dt.c +++ b/board/samsung/smdk5250/exynos5-dt.c @@ -21,6 +21,7 @@ */ #include <common.h> +#include <cros_ec.h> #include <fdtdec.h> #include <asm/io.h> #include <errno.h> @@ -69,6 +70,13 @@ static void boot_temp_check(void) } #endif +struct local_info { + struct cros_ec_dev *cros_ec_dev; /* Pointer to cros_ec device */ + int cros_ec_err; /* Error for cros_ec, 0 if ok */ +}; + +static struct local_info local; + #ifdef CONFIG_USB_EHCI_EXYNOS int board_usb_vbus_init(void) { @@ -97,6 +105,20 @@ static void board_enable_audio_codec(void) } #endif +struct cros_ec_dev *board_get_cros_ec_dev(void) +{ + return local.cros_ec_dev; +} + +static int board_init_cros_ec_devices(const void *blob) +{ + local.cros_ec_err = cros_ec_init(blob, &local.cros_ec_dev); + if (local.cros_ec_err) + return -1; /* Will report in board_late_init() */ + + return 0; +} + int board_init(void) { gd->bd->bi_boot_params = (PHYS_SDRAM_1 + 0x100UL); @@ -112,6 +134,10 @@ int board_init(void) #ifdef CONFIG_EXYNOS_SPI spi_init(); #endif + + if (board_init_cros_ec_devices(gd->fdt_blob)) + return -1; + #ifdef CONFIG_USB_EHCI_EXYNOS board_usb_vbus_init(); #endif @@ -421,3 +447,22 @@ void exynos_set_dp_phy(unsigned int onoff) set_dp_phy_ctrl(onoff); } #endif + +#ifdef CONFIG_BOARD_LATE_INIT +int board_late_init(void) +{ + stdio_print_current_devices(); + + if (local.cros_ec_err) { + /* Force console on */ + gd->flags &= ~GD_FLG_SILENT; + + printf("cros-ec communications failure %d\n", + local.cros_ec_err); + puts("\nPlease reset with Power+Refresh\n\n"); + panic("Cannot init cros-ec device"); + return -1; + } + return 0; +} +#endif diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c index fb98df0..fdbe26c 100644 --- a/board/ti/am335x/board.c +++ b/board/ti/am335x/board.c @@ -273,6 +273,15 @@ static struct emif_regs ddr3_evm_emif_reg_data = { .emif_ddr_phy_ctlr_1 = MT41J512M8RH125_EMIF_READ_LATENCY | PHY_EN_DYN_PWRDN, }; + +#ifdef CONFIG_SPL_OS_BOOT +int spl_start_uboot(void) +{ + /* break into full u-boot on 'c' */ + return (serial_tstc() && serial_getc() == 'c'); +} +#endif + #endif /* @@ -834,6 +834,7 @@ P1022DS_36BIT_SPIFLASH powerpc mpc85xx p1022ds freesca P1022DS_SDCARD powerpc mpc85xx p1022ds freescale - P1022DS:SDCARD P1022DS_36BIT_SDCARD powerpc mpc85xx p1022ds freescale - P1022DS:36BIT,SDCARD P1022DS_36BIT powerpc mpc85xx p1022ds freescale - P1022DS:36BIT +P1023RDB powerpc mpc85xx p1023rdb freescale - P1023RDB P1023RDS powerpc mpc85xx p1023rds freescale - P1023RDS P1023RDS_NAND powerpc mpc85xx p1023rds freescale - P1023RDS:NAND P1024RDB powerpc mpc85xx p1_p2_rdb_pc freescale - p1_p2_rdb_pc:P1024RDB @@ -903,8 +904,13 @@ P5040DS_NAND powerpc mpc85xx corenet_ds freescale - P5040DS_SDCARD powerpc mpc85xx corenet_ds freescale - P5040DS:RAMBOOT_PBL,SDCARD,SYS_TEXT_BASE=0xFFF80000 P5040DS_SPIFLASH powerpc mpc85xx corenet_ds freescale - P5040DS:RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 BSC9131RDB_SPIFLASH powerpc mpc85xx bsc9131rdb freescale - BSC9131RDB:BSC9131RDB,SPIFLASH +BSC9131RDB_SPIFLASH_SYSCLK100 powerpc mpc85xx bsc9131rdb freescale - BSC9131RDB:BSC9131RDB,SPIFLASH,SYS_CLK_100 +BSC9131RDB_NAND powerpc mpc85xx bsc9131rdb freescale - BSC9131RDB:BSC9131RDB,NAND +BSC9131RDB_NAND_SYSCLK100 powerpc mpc85xx bsc9131rdb freescale - BSC9131RDB:BSC9131RDB,NAND,SYS_CLK_100 BSC9132QDS_NOR_DDRCLK100 powerpc mpc85xx bsc9132qds freescale - BSC9132QDS:BSC9132QDS,SYS_CLK_100_DDR_100 BSC9132QDS_NOR_DDRCLK133 powerpc mpc85xx bsc9132qds freescale - BSC9132QDS:BSC9132QDS,SYS_CLK_100_DDR_133 +BSC9132QDS_NAND_DDRCLK100 powerpc mpc85xx bsc9132qds freescale - BSC9132QDS:BSC9132QDS,NAND,SYS_CLK_100_DDR_100 +BSC9132QDS_NAND_DDRCLK133 powerpc mpc85xx bsc9132qds freescale - BSC9132QDS:BSC9132QDS,NAND,SYS_CLK_100_DDR_133 BSC9132QDS_SDCARD_DDRCLK100 powerpc mpc85xx bsc9132qds freescale - BSC9132QDS:BSC9132QDS,SDCARD,SYS_CLK_100_DDR_100 BSC9132QDS_SDCARD_DDRCLK133 powerpc mpc85xx bsc9132qds freescale - BSC9132QDS:BSC9132QDS,SDCARD,SYS_CLK_100_DDR_133 BSC9132QDS_SPIFLASH_DDRCLK100 powerpc mpc85xx bsc9132qds freescale - BSC9132QDS:BSC9132QDS,SPIFLASH,SYS_CLK_100_DDR_100 @@ -915,12 +921,14 @@ stxssa_4M powerpc mpc85xx stxssa stx T4240QDS powerpc mpc85xx t4qds freescale - T4240QDS:PPC_T4240 T4240QDS_SDCARD powerpc mpc85xx t4qds freescale - T4240QDS:PPC_T4240,RAMBOOT_PBL,SDCARD,SYS_TEXT_BASE=0xFFF80000 T4240QDS_SPIFLASH powerpc mpc85xx t4qds freescale - T4240QDS:PPC_T4240,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 +T4240QDS_SRIO_PCIE_BOOT powerpc mpc85xx t4qds freescale - T4240QDS:PPC_T4240,SRIO_PCIE_BOOT_SLAVE,SYS_TEXT_BASE=0xFFF80000 T4160QDS powerpc mpc85xx t4qds freescale - T4240QDS:PPC_T4160 T4160QDS_SDCARD powerpc mpc85xx t4qds freescale - T4240QDS:PPC_T4160,RAMBOOT_PBL,SDCARD,SYS_TEXT_BASE=0xFFF80000 T4160QDS_SPIFLASH powerpc mpc85xx t4qds freescale - T4240QDS:PPC_T4160,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 B4860QDS powerpc mpc85xx b4860qds freescale - B4860QDS:PPC_B4860 B4860QDS_NAND powerpc mpc85xx b4860qds freescale - B4860QDS:PPC_B4860,RAMBOOT_PBL,NAND,SYS_TEXT_BASE=0xFFF80000 B4860QDS_SPIFLASH powerpc mpc85xx b4860qds freescale - B4860QDS:PPC_B4860,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 +B4860QDS_SRIO_PCIE_BOOT powerpc mpc85xx b4860qds freescale - B4860QDS:PPC_B4860,SRIO_PCIE_BOOT_SLAVE,SYS_TEXT_BASE=0xFFF80000 B4420QDS powerpc mpc85xx b4860qds freescale - B4860QDS:PPC_B4420 B4420QDS_NAND powerpc mpc85xx b4860qds freescale - B4860QDS:PPC_B4420,RAMBOOT_PBL,NAND,SYS_TEXT_BASE=0xFFF80000 B4420QDS_SPIFLASH powerpc mpc85xx b4860qds freescale - B4860QDS:PPC_B4420,RAMBOOT_PBL,SPIFLASH,SYS_TEXT_BASE=0xFFF80000 diff --git a/common/Makefile b/common/Makefile index 3ba4316..53c92ef 100644 --- a/common/Makefile +++ b/common/Makefile @@ -44,13 +44,11 @@ COBJS-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o COBJS-y += cmd_boot.o COBJS-$(CONFIG_CMD_BOOTM) += cmd_bootm.o COBJS-y += cmd_help.o -COBJS-y += cmd_nvedit.o COBJS-y += cmd_version.o # environment COBJS-y += env_attr.o COBJS-y += env_callback.o -COBJS-y += env_common.o COBJS-y += env_flags.o COBJS-$(CONFIG_ENV_IS_IN_DATAFLASH) += env_dataflash.o COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += env_eeprom.o @@ -171,6 +169,7 @@ COBJS-$(CONFIG_CMD_SPIBOOTLDR) += cmd_spibootldr.o COBJS-$(CONFIG_CMD_STRINGS) += cmd_strings.o COBJS-$(CONFIG_CMD_TERMINAL) += cmd_terminal.o COBJS-$(CONFIG_CMD_TIME) += cmd_time.o +COBJS-$(CONFIG_CMD_TRACE) += cmd_trace.o COBJS-$(CONFIG_SYS_HUSH_PARSER) += cmd_test.o COBJS-$(CONFIG_CMD_TPM) += cmd_tpm.o COBJS-$(CONFIG_CMD_TSI148) += cmd_tsi148.o @@ -191,20 +190,13 @@ COBJS-$(CONFIG_CMD_ZIP) += cmd_zip.o COBJS-$(CONFIG_CMD_ZFS) += cmd_zfs.o # others -ifdef CONFIG_DDR_SPD -SPD := y -endif -ifdef CONFIG_SPD_EEPROM -SPD := y -endif -COBJS-$(SPD) += ddr_spd.o -COBJS-$(CONFIG_HWCONFIG) += hwconfig.o COBJS-$(CONFIG_BOOTSTAGE) += bootstage.o COBJS-$(CONFIG_CONSOLE_MUX) += iomux.o COBJS-y += flash.o COBJS-$(CONFIG_CMD_KGDB) += kgdb.o kgdb_stubs.o COBJS-$(CONFIG_I2C_EDID) += edid.o COBJS-$(CONFIG_KALLSYMS) += kallsyms.o +COBJS-y += splash.o COBJS-$(CONFIG_LCD) += lcd.o COBJS-$(CONFIG_LYNXKDI) += lynxkdi.o COBJS-$(CONFIG_MENU) += menu.o @@ -216,24 +208,43 @@ COBJS-$(CONFIG_CMD_GPT) += cmd_gpt.o endif ifdef CONFIG_SPL_BUILD -COBJS-y += cmd_nvedit.o -COBJS-y += env_common.o COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += xyzModem.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += cmd_nvedit.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_attr.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_callback.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_common.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_flags.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += env_nowhere.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o +# environment +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_attr.o +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_flags.o +COBJS-$(CONFIG_SPL_ENV_SUPPORT) += env_callback.o +ifneq ($(CONFIG_SPL_NET_SUPPORT),y) +COBJS-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o +COBJS-$(CONFIG_ENV_IS_IN_MMC) += env_mmc.o +COBJS-$(CONFIG_ENV_IS_IN_NAND) += env_nand.o +COBJS-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o +COBJS-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o +else +COBJS-y += env_nowhere.o +endif endif +# core command +COBJS-y += cmd_nvedit.o +#environment +COBJS-y += env_common.o +#others +ifdef CONFIG_DDR_SPD +SPD := y +endif +ifdef CONFIG_SPD_EEPROM +SPD := y +endif +COBJS-$(SPD) += ddr_spd.o +COBJS-$(CONFIG_HWCONFIG) += hwconfig.o COBJS-$(CONFIG_BOUNCE_BUFFER) += bouncebuf.o COBJS-y += console.o COBJS-y += dlmalloc.o COBJS-y += image.o COBJS-$(CONFIG_OF_LIBFDT) += image-fdt.o COBJS-$(CONFIG_FIT) += image-fit.o +COBJS-$(CONFIG_FIT_SIGNATURE) += image-sig.o COBJS-y += memsize.o COBJS-y += stdio.o diff --git a/common/board_f.c b/common/board_f.c index 81edbdf..ab4242a 100644 --- a/common/board_f.c +++ b/common/board_f.c @@ -53,6 +53,7 @@ #include <os.h> #include <post.h> #include <spi.h> +#include <trace.h> #include <watchdog.h> #include <asm/errno.h> #include <asm/io.h> @@ -421,19 +422,18 @@ static int setup_dest_addr(void) #endif gd->ram_top += get_effective_memsize(); gd->ram_top = board_get_usable_ram_top(gd->mon_len); - gd->dest_addr = gd->ram_top; + gd->relocaddr = gd->ram_top; debug("Ram top: %08lX\n", (ulong)gd->ram_top); #if defined(CONFIG_MP) && (defined(CONFIG_MPC86xx) || defined(CONFIG_E500)) /* * We need to make sure the location we intend to put secondary core * boot code is reserved and not used by any part of u-boot */ - if (gd->dest_addr > determine_mp_bootpg(NULL)) { - gd->dest_addr = determine_mp_bootpg(NULL); - debug("Reserving MP boot page to %08lx\n", gd->dest_addr); + if (gd->relocaddr > determine_mp_bootpg(NULL)) { + gd->relocaddr = determine_mp_bootpg(NULL); + debug("Reserving MP boot page to %08lx\n", gd->relocaddr); } #endif - gd->dest_addr_sp = gd->dest_addr; return 0; } @@ -441,9 +441,9 @@ static int setup_dest_addr(void) static int reserve_logbuffer(void) { /* reserve kernel log buffer */ - gd->dest_addr -= LOGBUFF_RESERVE; + gd->relocaddr -= LOGBUFF_RESERVE; debug("Reserving %dk for kernel logbuffer at %08lx\n", LOGBUFF_LEN, - gd->dest_addr); + gd->relocaddr); return 0; } #endif @@ -455,9 +455,9 @@ static int reserve_pram(void) ulong reg; reg = getenv_ulong("pram", 10, CONFIG_PRAM); - gd->dest_addr -= (reg << 10); /* size is in kB */ + gd->relocaddr -= (reg << 10); /* size is in kB */ debug("Reserving %ldk for protected RAM at %08lx\n", reg, - gd->dest_addr); + gd->relocaddr); return 0; } #endif /* CONFIG_PRAM */ @@ -465,7 +465,7 @@ static int reserve_pram(void) /* Round memory pointer down to next 4 kB limit */ static int reserve_round_4k(void) { - gd->dest_addr &= ~(4096 - 1); + gd->relocaddr &= ~(4096 - 1); return 0; } @@ -475,12 +475,12 @@ static int reserve_mmu(void) { /* reserve TLB table */ gd->arch.tlb_size = 4096 * 4; - gd->dest_addr -= gd->arch.tlb_size; + gd->relocaddr -= gd->arch.tlb_size; /* round down to next 64 kB limit */ - gd->dest_addr &= ~(0x10000 - 1); + gd->relocaddr &= ~(0x10000 - 1); - gd->arch.tlb_addr = gd->dest_addr; + gd->arch.tlb_addr = gd->relocaddr; debug("TLB table from %08lx to %08lx\n", gd->arch.tlb_addr, gd->arch.tlb_addr + gd->arch.tlb_size); return 0; @@ -494,20 +494,32 @@ static int reserve_lcd(void) gd->fb_base = CONFIG_FB_ADDR; #else /* reserve memory for LCD display (always full pages) */ - gd->dest_addr = lcd_setmem(gd->dest_addr); - gd->fb_base = gd->dest_addr; + gd->relocaddr = lcd_setmem(gd->relocaddr); + gd->fb_base = gd->relocaddr; #endif /* CONFIG_FB_ADDR */ return 0; } #endif /* CONFIG_LCD */ +static int reserve_trace(void) +{ +#ifdef CONFIG_TRACE + gd->relocaddr -= CONFIG_TRACE_BUFFER_SIZE; + gd->trace_buff = map_sysmem(gd->relocaddr, CONFIG_TRACE_BUFFER_SIZE); + debug("Reserving %dk for trace data at: %08lx\n", + CONFIG_TRACE_BUFFER_SIZE >> 10, gd->relocaddr); +#endif + + return 0; +} + #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \ && !defined(CONFIG_ARM) && !defined(CONFIG_X86) static int reserve_video(void) { /* reserve memory for video display (always full pages) */ - gd->dest_addr = video_setmem(gd->dest_addr); - gd->fb_base = gd->dest_addr; + gd->relocaddr = video_setmem(gd->relocaddr); + gd->fb_base = gd->relocaddr; return 0; } @@ -519,15 +531,18 @@ static int reserve_uboot(void) * reserve memory for U-Boot code, data & bss * round down to next 4 kB limit */ - gd->dest_addr -= gd->mon_len; - gd->dest_addr &= ~(4096 - 1); + gd->relocaddr -= gd->mon_len; + gd->relocaddr &= ~(4096 - 1); #ifdef CONFIG_E500 /* round down to next 64 kB limit so that IVPR stays aligned */ - gd->dest_addr &= ~(65536 - 1); + gd->relocaddr &= ~(65536 - 1); #endif debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, - gd->dest_addr); + gd->relocaddr); + + gd->start_addr_sp = gd->relocaddr; + return 0; } @@ -535,20 +550,20 @@ static int reserve_uboot(void) /* reserve memory for malloc() area */ static int reserve_malloc(void) { - gd->dest_addr_sp = gd->dest_addr - TOTAL_MALLOC_LEN; + gd->start_addr_sp = gd->start_addr_sp - TOTAL_MALLOC_LEN; debug("Reserving %dk for malloc() at: %08lx\n", - TOTAL_MALLOC_LEN >> 10, gd->dest_addr_sp); + TOTAL_MALLOC_LEN >> 10, gd->start_addr_sp); return 0; } /* (permanently) allocate a Board Info struct */ static int reserve_board(void) { - gd->dest_addr_sp -= sizeof(bd_t); - gd->bd = (bd_t *)map_sysmem(gd->dest_addr_sp, sizeof(bd_t)); + gd->start_addr_sp -= sizeof(bd_t); + gd->bd = (bd_t *)map_sysmem(gd->start_addr_sp, sizeof(bd_t)); memset(gd->bd, '\0', sizeof(bd_t)); debug("Reserving %zu Bytes for Board Info at: %08lx\n", - sizeof(bd_t), gd->dest_addr_sp); + sizeof(bd_t), gd->start_addr_sp); return 0; } #endif @@ -563,10 +578,10 @@ static int setup_machine(void) static int reserve_global_data(void) { - gd->dest_addr_sp -= sizeof(gd_t); - gd->new_gd = (gd_t *)map_sysmem(gd->dest_addr_sp, sizeof(gd_t)); + gd->start_addr_sp -= sizeof(gd_t); + gd->new_gd = (gd_t *)map_sysmem(gd->start_addr_sp, sizeof(gd_t)); debug("Reserving %zu Bytes for Global Data at: %08lx\n", - sizeof(gd_t), gd->dest_addr_sp); + sizeof(gd_t), gd->start_addr_sp); return 0; } @@ -580,10 +595,10 @@ static int reserve_fdt(void) if (gd->fdt_blob) { gd->fdt_size = ALIGN(fdt_totalsize(gd->fdt_blob) + 0x1000, 32); - gd->dest_addr_sp -= gd->fdt_size; - gd->new_fdt = map_sysmem(gd->dest_addr_sp, gd->fdt_size); + gd->start_addr_sp -= gd->fdt_size; + gd->new_fdt = map_sysmem(gd->start_addr_sp, gd->fdt_size); debug("Reserving %lu Bytes for FDT at: %08lx\n", - gd->fdt_size, gd->dest_addr_sp); + gd->fdt_size, gd->start_addr_sp); } return 0; @@ -593,8 +608,8 @@ static int reserve_stacks(void) { #ifdef CONFIG_SPL_BUILD # ifdef CONFIG_ARM - gd->dest_addr_sp -= 128; /* leave 32 words for abort-stack */ - gd->irq_sp = gd->dest_addr_sp; + gd->start_addr_sp -= 128; /* leave 32 words for abort-stack */ + gd->irq_sp = gd->start_addr_sp; # endif #else # ifdef CONFIG_PPC @@ -602,9 +617,9 @@ static int reserve_stacks(void) # endif /* setup stack pointer for exceptions */ - gd->dest_addr_sp -= 16; - gd->dest_addr_sp &= ~0xf; - gd->irq_sp = gd->dest_addr_sp; + gd->start_addr_sp -= 16; + gd->start_addr_sp &= ~0xf; + gd->irq_sp = gd->start_addr_sp; /* * Handle architecture-specific things here @@ -613,18 +628,18 @@ static int reserve_stacks(void) */ # ifdef CONFIG_ARM # ifdef CONFIG_USE_IRQ - gd->dest_addr_sp -= (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ); + gd->start_addr_sp -= (CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ); debug("Reserving %zu Bytes for IRQ stack at: %08lx\n", - CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, gd->dest_addr_sp); + CONFIG_STACKSIZE_IRQ + CONFIG_STACKSIZE_FIQ, gd->start_addr_sp); /* 8-byte alignment for ARM ABI compliance */ - gd->dest_addr_sp &= ~0x07; + gd->start_addr_sp &= ~0x07; # endif /* leave 3 words for abort-stack, plus 1 for alignment */ - gd->dest_addr_sp -= 16; + gd->start_addr_sp -= 16; # elif defined(CONFIG_PPC) /* Clear initial stack frame */ - s = (ulong *) gd->dest_addr_sp; + s = (ulong *) gd->start_addr_sp; *s = 0; /* Terminate back chain */ *++s = 0; /* NULL return address */ # endif /* Architecture specific code */ @@ -635,7 +650,7 @@ static int reserve_stacks(void) static int display_new_sp(void) { - debug("New Stack Pointer is: %08lx\n", gd->dest_addr_sp); + debug("New Stack Pointer is: %08lx\n", gd->start_addr_sp); return 0; } @@ -757,15 +772,13 @@ static int reloc_fdt(void) static int setup_reloc(void) { - gd->relocaddr = gd->dest_addr; - gd->start_addr_sp = gd->dest_addr_sp; - gd->reloc_off = gd->dest_addr - CONFIG_SYS_TEXT_BASE; + gd->reloc_off = gd->relocaddr - CONFIG_SYS_TEXT_BASE; memcpy(gd->new_gd, (char *)gd, sizeof(gd_t)); debug("Relocation Offset is: %08lx\n", gd->reloc_off); debug("Relocating to %08lx, new gd at %08lx, sp at %08lx\n", - gd->dest_addr, (ulong)map_to_sysmem(gd->new_gd), - gd->dest_addr_sp); + gd->relocaddr, (ulong)map_to_sysmem(gd->new_gd), + gd->start_addr_sp); return 0; } @@ -794,7 +807,7 @@ static int jump_to_copy(void) #elif defined(CONFIG_SANDBOX) board_init_r(gd->new_gd, 0); #else - relocate_code(gd->dest_addr_sp, gd->new_gd, gd->dest_addr); + relocate_code(gd->start_addr_sp, gd->new_gd, gd->relocaddr); #endif return 0; @@ -818,8 +831,9 @@ static init_fnc_t init_sequence_f[] = { #ifdef CONFIG_SANDBOX setup_ram_buf, #endif - setup_fdt, setup_mon_len, + setup_fdt, + trace_early_init, #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx) /* TODO: can this go into arch_cpu_init()? */ probecpu, @@ -851,12 +865,6 @@ static init_fnc_t init_sequence_f[] = { #ifdef CONFIG_ARM timer_init, /* initialize timer */ #endif -#ifdef CONFIG_BOARD_POSTCLK_INIT - board_postclk_init, -#endif -#ifdef CONFIG_FSL_ESDHC - get_clocks, -#endif #ifdef CONFIG_SYS_ALLOC_DPRAM #if !defined(CONFIG_CPM2) dpram_init, @@ -865,6 +873,9 @@ static init_fnc_t init_sequence_f[] = { #if defined(CONFIG_BOARD_POSTCLK_INIT) board_postclk_init, #endif +#ifdef CONFIG_FSL_ESDHC + get_clocks, +#endif env_init, /* initialize environment */ #if defined(CONFIG_8xx_CPUCLK_DEFAULT) /* get CPU and bus clocks according to the environment variable */ @@ -966,6 +977,7 @@ static init_fnc_t init_sequence_f[] = { #ifdef CONFIG_LCD reserve_lcd, #endif + reserve_trace, /* TODO: Why the dependency on CONFIG_8xx? */ #if defined(CONFIG_VIDEO) && (!defined(CONFIG_PPC) || defined(CONFIG_8xx)) \ && !defined(CONFIG_ARM) && !defined(CONFIG_X86) diff --git a/common/board_r.c b/common/board_r.c index fd1fd31..f7a036e 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -58,6 +58,7 @@ #include <serial.h> #include <spi.h> #include <stdio_dev.h> +#include <trace.h> #include <watchdog.h> #ifdef CONFIG_ADDR_MAP #include <asm/mmu.h> @@ -106,6 +107,15 @@ static int initr_secondary_cpu(void) return 0; } +static int initr_trace(void) +{ +#ifdef CONFIG_TRACE + trace_init(gd->trace_buff, CONFIG_TRACE_BUFFER_SIZE); +#endif + + return 0; +} + static int initr_reloc(void) { gd->flags |= GD_FLG_RELOC; /* tell others: relocation done */ @@ -137,7 +147,7 @@ static int initr_reloc_global_data(void) #ifdef CONFIG_SYS_SYM_OFFSETS monitor_flash_len = _end_ofs; #elif !defined(CONFIG_SANDBOX) - monitor_flash_len = (ulong)&__init_end - gd->dest_addr; + monitor_flash_len = (ulong)&__init_end - gd->relocaddr; #endif #if defined(CONFIG_MPC85xx) || defined(CONFIG_MPC86xx) /* @@ -145,7 +155,7 @@ static int initr_reloc_global_data(void) * We need to update it to point to the same CPU entry in RAM. * TODO: why not just add gd->reloc_ofs? */ - gd->arch.cpu += gd->dest_addr - CONFIG_SYS_MONITOR_BASE; + gd->arch.cpu += gd->relocaddr - CONFIG_SYS_MONITOR_BASE; /* * If we didn't know the cpu mask & # cores, we can save them of @@ -161,7 +171,7 @@ static int initr_reloc_global_data(void) * in SRAM mode and initialize that cache from SRAM mode back to being * a cache in cpu_init_r. */ - gd->env_addr += gd->dest_addr - CONFIG_SYS_MONITOR_BASE; + gd->env_addr += gd->relocaddr - CONFIG_SYS_MONITOR_BASE; #endif return 0; } @@ -178,7 +188,7 @@ static int initr_trap(void) /* * Setup trap handlers */ - trap_init(gd->dest_addr); + trap_init(gd->relocaddr); return 0; } @@ -263,7 +273,7 @@ static int initr_malloc(void) ulong malloc_start; /* The malloc area is immediately below the monitor copy in DRAM */ - malloc_start = gd->dest_addr - TOTAL_MALLOC_LEN; + malloc_start = gd->relocaddr - TOTAL_MALLOC_LEN; mem_malloc_init((ulong)map_sysmem(malloc_start, TOTAL_MALLOC_LEN), TOTAL_MALLOC_LEN); return 0; @@ -276,7 +286,7 @@ __weak int power_init_board(void) static int initr_announce(void) { - debug("Now running in RAM - U-Boot at: %08lx\n", gd->dest_addr); + debug("Now running in RAM - U-Boot at: %08lx\n", gd->relocaddr); return 0; } @@ -711,6 +721,7 @@ static int run_main_loop(void) * TODO: perhaps reset the watchdog in the initcall function after each call? */ init_fnc_t init_sequence_r[] = { + initr_trace, initr_reloc, /* TODO: could x86/PPC have this also perhaps? */ #ifdef CONFIG_ARM diff --git a/common/bootstage.c b/common/bootstage.c index c5c6996..94a32a9 100644 --- a/common/bootstage.c +++ b/common/bootstage.c @@ -49,6 +49,7 @@ static int next_id = BOOTSTAGE_ID_USER; enum { BOOTSTAGE_VERSION = 0, BOOTSTAGE_MAGIC = 0xb00757a3, + BOOTSTAGE_DIGITS = 9, }; struct bootstage_hdr { @@ -165,21 +166,6 @@ uint32_t bootstage_accum(enum bootstage_id id) return duration; } -static void print_time(unsigned long us_time) -{ - char str[15], *s; - int grab = 3; - - /* We don't seem to have %'d in U-Boot */ - sprintf(str, "%12lu", us_time); - for (s = str + 3; *s; s += grab) { - if (s != str + 3) - putc(s[-1] != ' ' ? ',' : ' '); - printf("%.*s", grab, s); - grab = 3; - } -} - /** * Get a record name as a printable string * @@ -208,10 +194,10 @@ static uint32_t print_time_record(enum bootstage_id id, if (prev == -1U) { printf("%11s", ""); - print_time(rec->time_us); + print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS); } else { - print_time(rec->time_us); - print_time(rec->time_us - prev); + print_grouped_ull(rec->time_us, BOOTSTAGE_DIGITS); + print_grouped_ull(rec->time_us - prev, BOOTSTAGE_DIGITS); } printf(" %s\n", get_record_name(buf, sizeof(buf), rec)); @@ -445,9 +431,9 @@ int bootstage_unstash(void *base, int size) } if (hdr->count * sizeof(*rec) > hdr->size) { - debug("%s: Bootstage has %d records needing %d bytes, but " + debug("%s: Bootstage has %d records needing %lu bytes, but " "only %d bytes is available\n", __func__, hdr->count, - hdr->count * sizeof(*rec), hdr->size); + (ulong)hdr->count * sizeof(*rec), hdr->size); return -1; } diff --git a/common/cmd_bmp.c b/common/cmd_bmp.c index 5a52edd..a7c5fbd 100644 --- a/common/cmd_bmp.c +++ b/common/cmd_bmp.c @@ -31,6 +31,7 @@ #include <command.h> #include <asm/byteorder.h> #include <malloc.h> +#include <splash.h> #include <video.h> static int bmp_info (ulong addr); @@ -38,14 +39,19 @@ static int bmp_info (ulong addr); /* * Allocate and decompress a BMP image using gunzip(). * - * Returns a pointer to the decompressed image data. Must be freed by - * the caller after use. + * Returns a pointer to the decompressed image data. This pointer is + * aligned to 32-bit-aligned-address + 2. + * See doc/README.displaying-bmps for explanation. + * + * The allocation address is passed to 'alloc_addr' and must be freed + * by the caller after use. * * Returns NULL if decompression failed, or if the decompressed data * didn't contain a valid BMP signature. */ #ifdef CONFIG_VIDEO_BMP_GZIP -bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp) +bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp, + void **alloc_addr) { void *dst; unsigned long len; @@ -55,12 +61,19 @@ bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp) * Decompress bmp image */ len = CONFIG_SYS_VIDEO_LOGO_MAX_SIZE; - dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE); + /* allocate extra 3 bytes for 32-bit-aligned-address + 2 alignment */ + dst = malloc(CONFIG_SYS_VIDEO_LOGO_MAX_SIZE + 3); if (dst == NULL) { puts("Error: malloc in gunzip failed!\n"); return NULL; } - if (gunzip(dst, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)addr, &len) != 0) { + + bmp = dst; + + /* align to 32-bit-aligned-address + 2 */ + bmp = (bmp_image_t *)((((unsigned int)dst + 1) & ~3) + 2); + + if (gunzip(bmp, CONFIG_SYS_VIDEO_LOGO_MAX_SIZE, (uchar *)addr, &len) != 0) { free(dst); return NULL; } @@ -68,8 +81,6 @@ bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp) puts("Image could be truncated" " (increase CONFIG_SYS_VIDEO_LOGO_MAX_SIZE)!\n"); - bmp = dst; - /* * Check for bmp mark 'BM' */ @@ -81,10 +92,12 @@ bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp) debug("Gzipped BMP image detected!\n"); + *alloc_addr = dst; return bmp; } #else -bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp) +bmp_image_t *gunzip_bmp(unsigned long addr, unsigned long *lenp, + void **alloc_addr) { return NULL; } @@ -113,6 +126,8 @@ static int do_bmp_display(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar ulong addr; int x = 0, y = 0; + splash_get_pos(&x, &y); + switch (argc) { case 1: /* use load_addr as default address */ addr = load_addr; @@ -189,11 +204,12 @@ U_BOOT_CMD( static int bmp_info(ulong addr) { bmp_image_t *bmp=(bmp_image_t *)addr; + void *bmp_alloc_addr = NULL; unsigned long len; if (!((bmp->header.signature[0]=='B') && (bmp->header.signature[1]=='M'))) - bmp = gunzip_bmp(addr, &len); + bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); if (bmp == NULL) { printf("There is no valid bmp file at the given address\n"); @@ -205,8 +221,8 @@ static int bmp_info(ulong addr) printf("Bits per pixel: %d\n", le16_to_cpu(bmp->header.bit_count)); printf("Compression : %d\n", le32_to_cpu(bmp->header.compression)); - if ((unsigned long)bmp != addr) - free(bmp); + if (bmp_alloc_addr) + free(bmp_alloc_addr); return(0); } @@ -225,11 +241,12 @@ int bmp_display(ulong addr, int x, int y) { int ret; bmp_image_t *bmp = (bmp_image_t *)addr; + void *bmp_alloc_addr = NULL; unsigned long len; if (!((bmp->header.signature[0]=='B') && (bmp->header.signature[1]=='M'))) - bmp = gunzip_bmp(addr, &len); + bmp = gunzip_bmp(addr, &len, &bmp_alloc_addr); if (!bmp) { printf("There is no valid bmp file at the given address\n"); @@ -244,8 +261,8 @@ int bmp_display(ulong addr, int x, int y) # error bmp_display() requires CONFIG_LCD or CONFIG_VIDEO #endif - if ((unsigned long)bmp != addr) - free(bmp); + if (bmp_alloc_addr) + free(bmp_alloc_addr); return ret; } diff --git a/common/cmd_bootm.c b/common/cmd_bootm.c index 15f4599..2694c66 100644 --- a/common/cmd_bootm.c +++ b/common/cmd_bootm.c @@ -93,11 +93,6 @@ static int do_imls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); static void fixup_silent_linux(void); #endif -static image_header_t *image_get_kernel(ulong img_addr, int verify); -#if defined(CONFIG_FIT) -static int fit_check_kernel(const void *fit, int os_noffset, int verify); -#endif - static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], bootm_headers_t *images, ulong *os_data, ulong *os_len); @@ -109,9 +104,18 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, * - verified image architecture (PPC) and type (KERNEL or MULTI), * - loaded (first part of) image to header load address, * - disabled interrupts. + * + * @flag: Flags indicating what to do (BOOTM_STATE_...) + * @argc: Number of arguments. Note that the arguments are shifted down + * so that 0 is the first argument not processed by U-Boot, and + * argc is adjusted accordingly. This avoids confusion as to how + * many arguments are available for the OS. + * @images: Pointers to os/initrd/fdt + * @return 1 on error. On success the OS boots so this function does + * not return. */ typedef int boot_os_fn(int flag, int argc, char * const argv[], - bootm_headers_t *images); /* pointers to os/initrd/fdt */ + bootm_headers_t *images); #ifdef CONFIG_BOOTM_LINUX extern boot_os_fn do_bootm_linux; @@ -204,15 +208,21 @@ static inline void boot_start_lmb(bootm_headers_t *images) { } static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - const void *os_hdr; - int ret; - memset((void *)&images, 0, sizeof(images)); images.verify = getenv_yesno("verify"); boot_start_lmb(&images); bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start"); + images.state = BOOTM_STATE_START; + + return 0; +} + +static int bootm_find_os(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + const void *os_hdr; /* get kernel image header, start address and length */ os_hdr = boot_get_kernel(cmdtp, flag, argc, argv, @@ -275,6 +285,8 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] images.ep = image_get_ep(&images.legacy_hdr_os_copy); #if defined(CONFIG_FIT) } else if (images.fit_uname_os) { + int ret; + ret = fit_image_get_entry(images.fit_hdr_os, images.fit_noffset_os, &images.ep); if (ret) { @@ -292,42 +304,71 @@ static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[] images.ep += images.os.load; } + images.os.start = (ulong)os_hdr; + + return 0; +} + +static int bootm_find_ramdisk(int flag, int argc, char * const argv[]) +{ + int ret; + + /* find ramdisk */ + ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH, + &images.rd_start, &images.rd_end); + if (ret) { + puts("Ramdisk image is corrupt or invalid\n"); + return 1; + } + + return 0; +} + +#if defined(CONFIG_OF_LIBFDT) +static int bootm_find_fdt(int flag, int argc, char * const argv[]) +{ + int ret; + + /* find flattened device tree */ + ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images, + &images.ft_addr, &images.ft_len); + if (ret) { + puts("Could not find a valid device tree\n"); + return 1; + } + + set_working_fdt_addr(images.ft_addr); + + return 0; +} +#endif + +static int bootm_find_other(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ if (((images.os.type == IH_TYPE_KERNEL) || (images.os.type == IH_TYPE_KERNEL_NOLOAD) || (images.os.type == IH_TYPE_MULTI)) && (images.os.os == IH_OS_LINUX)) { - /* find ramdisk */ - ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH, - &images.rd_start, &images.rd_end); - if (ret) { - puts("Ramdisk image is corrupt or invalid\n"); + if (bootm_find_ramdisk(flag, argc, argv)) return 1; - } #if defined(CONFIG_OF_LIBFDT) - /* find flattened device tree */ - ret = boot_get_fdt(flag, argc, argv, &images, - &images.ft_addr, &images.ft_len); - if (ret) { - puts("Could not find a valid device tree\n"); + if (bootm_find_fdt(flag, argc, argv)) return 1; - } - - set_working_fdt_addr(images.ft_addr); #endif } - images.os.start = (ulong)os_hdr; - images.state = BOOTM_STATE_START; - return 0; } #define BOOTM_ERR_RESET -1 #define BOOTM_ERR_OVERLAP -2 #define BOOTM_ERR_UNIMPLEMENTED -3 -static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) +static int bootm_load_os(bootm_headers_t *images, unsigned long *load_end, + int boot_progress) { + image_info_t os = images->os; uint8_t comp = os.comp; ulong load = os.load; ulong blob_start = os.start; @@ -336,12 +377,15 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) ulong image_len = os.image_len; __maybe_unused uint unc_len = CONFIG_SYS_BOOTM_LEN; int no_overlap = 0; + void *load_buf, *image_buf; #if defined(CONFIG_LZMA) || defined(CONFIG_LZO) int ret; #endif /* defined(CONFIG_LZMA) || defined(CONFIG_LZO) */ const char *type_name = genimg_get_type_name(os.type); + load_buf = map_sysmem(load, image_len); + image_buf = map_sysmem(image_start, image_len); switch (comp) { case IH_COMP_NONE: if (load == blob_start || load == image_start) { @@ -349,17 +393,14 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) no_overlap = 1; } else { printf(" Loading %s ... ", type_name); - memmove_wd((void *)load, (void *)image_start, - image_len, CHUNKSZ); + memmove_wd(load_buf, image_buf, image_len, CHUNKSZ); } *load_end = load + image_len; - puts("OK\n"); break; #ifdef CONFIG_GZIP case IH_COMP_GZIP: printf(" Uncompressing %s ... ", type_name); - if (gunzip((void *)load, unc_len, - (uchar *)image_start, &image_len) != 0) { + if (gunzip(load_buf, unc_len, image_buf, &image_len) != 0) { puts("GUNZIP: uncompress, out-of-mem or overwrite " "error - must RESET board to recover\n"); if (boot_progress) @@ -378,9 +419,9 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) * use slower decompression algorithm which requires * at most 2300 KB of memory. */ - int i = BZ2_bzBuffToBuffDecompress((char *)load, - &unc_len, (char *)image_start, image_len, - CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); + int i = BZ2_bzBuffToBuffDecompress(load_buf, &unc_len, + image_buf, image_len, + CONFIG_SYS_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf("BUNZIP2: uncompress or overwrite error %d " "- must RESET board to recover\n", i); @@ -397,9 +438,8 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) SizeT lzma_len = unc_len; printf(" Uncompressing %s ... ", type_name); - ret = lzmaBuffToBuffDecompress( - (unsigned char *)load, &lzma_len, - (unsigned char *)image_start, image_len); + ret = lzmaBuffToBuffDecompress(load_buf, &lzma_len, + image_buf, image_len); unc_len = lzma_len; if (ret != SZ_OK) { printf("LZMA: uncompress or overwrite error %d " @@ -415,9 +455,8 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) case IH_COMP_LZO: printf(" Uncompressing %s ... ", type_name); - ret = lzop_decompress((const unsigned char *)image_start, - image_len, (unsigned char *)load, - &unc_len); + ret = lzop_decompress(image_buf, image_len, load_buf, + &unc_len); if (ret != LZO_E_OK) { printf("LZO: uncompress or overwrite error %d " "- must RESET board to recover\n", ret); @@ -446,13 +485,23 @@ static int bootm_load_os(image_info_t os, ulong *load_end, int boot_progress) debug("images.os.load = 0x%lx, load_end = 0x%lx\n", load, *load_end); - return BOOTM_ERR_OVERLAP; + /* Check what type of image this is. */ + if (images->legacy_hdr_valid) { + if (image_get_type(&images->legacy_hdr_os_copy) + == IH_TYPE_MULTI) + puts("WARNING: legacy format multi component image overwritten\n"); + return BOOTM_ERR_OVERLAP; + } else { + puts("ERROR: new format image overwritten - must RESET the board to recover\n"); + bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); + return BOOTM_ERR_RESET; + } } return 0; } -static int bootm_start_standalone(ulong iflag, int argc, char * const argv[]) +static int bootm_start_standalone(int argc, char * const argv[]) { char *s; int (*appl)(int, char * const []); @@ -463,7 +512,7 @@ static int bootm_start_standalone(ulong iflag, int argc, char * const argv[]) return 0; } appl = (int (*)(int, char * const []))(ulong)ntohl(images.ep); - (*appl)(argc-1, &argv[1]); + (*appl)(argc, argv); return 0; } @@ -481,108 +530,245 @@ static cmd_tbl_t cmd_bootm_sub[] = { U_BOOT_CMD_MKENT(cmdline, 0, 1, (void *)BOOTM_STATE_OS_CMDLINE, "", ""), U_BOOT_CMD_MKENT(bdt, 0, 1, (void *)BOOTM_STATE_OS_BD_T, "", ""), U_BOOT_CMD_MKENT(prep, 0, 1, (void *)BOOTM_STATE_OS_PREP, "", ""), + U_BOOT_CMD_MKENT(fake, 0, 1, (void *)BOOTM_STATE_OS_FAKE_GO, "", ""), U_BOOT_CMD_MKENT(go, 0, 1, (void *)BOOTM_STATE_OS_GO, "", ""), }; +static int boot_selected_os(int argc, char * const argv[], int state, + bootm_headers_t *images, boot_os_fn *boot_fn) +{ + if (images->os.type == IH_TYPE_STANDALONE) { + /* This may return when 'autostart' is 'no' */ + bootm_start_standalone(argc, argv); + return 0; + } +#ifdef CONFIG_SILENT_CONSOLE + if (images->os.os == IH_OS_LINUX) + fixup_silent_linux(); +#endif + arch_preboot_os(); + boot_fn(state, argc, argv, images); + if (state == BOOTM_STATE_OS_FAKE_GO) /* We expect to return */ + return 0; + bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); +#ifdef DEBUG + puts("\n## Control returned to monitor - resetting...\n"); +#endif + return BOOTM_ERR_RESET; +} + +/** + * bootm_disable_interrupts() - Disable interrupts in preparation for load/boot + * + * @return interrupt flag (0 if interrupts were disabled, non-zero if they were + * enabled) + */ +static ulong bootm_disable_interrupts(void) +{ + ulong iflag; + + /* + * 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... + */ + iflag = disable_interrupts(); +#ifdef CONFIG_NETCONSOLE + /* Stop the ethernet stack if NetConsole could have left it up */ + eth_halt(); +#endif + +#if defined(CONFIG_CMD_USB) + /* + * turn off USB to prevent the host controller from writing to the + * SDRAM while Linux is booting. This could happen (at least for OHCI + * controller), because the HCCA (Host Controller Communication Area) + * lies within the SDRAM and the host controller writes continously to + * this area (as busmaster!). The HccaFrameNumber is for example + * updated every 1 ms within the HCCA structure in SDRAM! For more + * details see the OpenHCI specification. + */ + usb_stop(); +#endif + return iflag; +} + +/** + * Execute selected states of the bootm command. + * + * Note the arguments to this state must be the first argument, Any 'bootm' + * or sub-command arguments must have already been taken. + * + * Note that if states contains more than one flag it MUST contain + * BOOTM_STATE_START, since this handles and consumes the command line args. + * + * Also note that aside from boot_os_fn functions and bootm_load_os no other + * functions we store the return value of in 'ret' may use a negative return + * value, without special handling. + * + * @param cmdtp Pointer to bootm command table entry + * @param flag Command flags (CMD_FLAG_...) + * @param argc Number of subcommand arguments (0 = no arguments) + * @param argv Arguments + * @param states Mask containing states to run (BOOTM_STATE_...) + * @param images Image header information + * @param boot_progress 1 to show boot progress, 0 to not do this + * @return 0 if ok, something else on error. Some errors will cause this + * function to perform a reboot! If states contains BOOTM_STATE_OS_GO + * then the intent is to boot an OS, so this function will not return + * unless the image type is standalone. + */ +static int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[], int states, bootm_headers_t *images, + int boot_progress) +{ + boot_os_fn *boot_fn; + ulong iflag = 0; + int ret = 0, need_boot_fn; + + images->state |= states; + + /* + * Work through the states and see how far we get. We stop on + * any error. + */ + if (states & BOOTM_STATE_START) + ret = bootm_start(cmdtp, flag, argc, argv); + + if (!ret && (states & BOOTM_STATE_FINDOS)) + ret = bootm_find_os(cmdtp, flag, argc, argv); + + if (!ret && (states & BOOTM_STATE_FINDOTHER)) { + ret = bootm_find_other(cmdtp, flag, argc, argv); + argc = 0; /* consume the args */ + } + + /* Load the OS */ + if (!ret && (states & BOOTM_STATE_LOADOS)) { + ulong load_end; + + iflag = bootm_disable_interrupts(); + ret = bootm_load_os(images, &load_end, 0); + if (ret == 0) + lmb_reserve(&images->lmb, images->os.load, + (load_end - images->os.load)); + else if (ret && ret != BOOTM_ERR_OVERLAP) + goto err; + else if (ret == BOOTM_ERR_OVERLAP) + ret = 0; + } + + /* Relocate the ramdisk */ +#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH + if (!ret && (states & BOOTM_STATE_RAMDISK)) { + ulong rd_len = images->rd_end - images->rd_start; + + ret = boot_ramdisk_high(&images->lmb, images->rd_start, + rd_len, &images->initrd_start, &images->initrd_end); + if (!ret) { + setenv_hex("initrd_start", images->initrd_start); + setenv_hex("initrd_end", images->initrd_end); + } + } +#endif +#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) + if (!ret && (states & BOOTM_STATE_FDT)) { + boot_fdt_add_mem_rsv_regions(&images->lmb, images->ft_addr); + ret = boot_relocate_fdt(&images->lmb, &images->ft_addr, + &images->ft_len); + } +#endif + + /* From now on, we need the OS boot function */ + if (ret) + return ret; + boot_fn = boot_os[images->os.os]; + need_boot_fn = states & (BOOTM_STATE_OS_CMDLINE | + BOOTM_STATE_OS_BD_T | BOOTM_STATE_OS_PREP | + BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO); + if (boot_fn == NULL && need_boot_fn) { + if (iflag) + enable_interrupts(); + printf("ERROR: booting os '%s' (%d) is not supported\n", + genimg_get_os_name(images->os.os), images->os.os); + bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); + return 1; + } + + /* Call various other states that are not generally used */ + if (!ret && (states & BOOTM_STATE_OS_CMDLINE)) + ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, images); + if (!ret && (states & BOOTM_STATE_OS_BD_T)) + ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, images); + if (!ret && (states & BOOTM_STATE_OS_PREP)) + ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, images); + + /* Check for unsupported subcommand. */ + if (ret) { + puts("subcommand not supported\n"); + return ret; + } + + +#ifdef CONFIG_TRACE + /* Pretend to run the OS, then run a user command */ + if (!ret && (states & BOOTM_STATE_OS_FAKE_GO)) { + char *cmd_list = getenv("fakegocmd"); + + ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_FAKE_GO, + images, boot_fn); + if (!ret && cmd_list) + ret = run_command_list(cmd_list, -1, flag); + } +#endif + /* Now run the OS! We hope this doesn't return */ + if (!ret && (states & BOOTM_STATE_OS_GO)) { + ret = boot_selected_os(argc, argv, BOOTM_STATE_OS_GO, + images, boot_fn); + if (ret) + goto err; + } + + return ret; + + /* Deal with any fallout */ +err: + if (iflag) + enable_interrupts(); + + if (ret == BOOTM_ERR_UNIMPLEMENTED) + bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); + else if (ret == BOOTM_ERR_RESET) + do_reset(cmdtp, flag, argc, argv); + + return ret; +} + static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; long state; cmd_tbl_t *c; - boot_os_fn *boot_fn; - c = find_cmd_tbl(argv[1], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); + c = find_cmd_tbl(argv[0], &cmd_bootm_sub[0], ARRAY_SIZE(cmd_bootm_sub)); + argc--; argv++; if (c) { state = (long)c->cmd; - - /* treat start special since it resets the state machine */ - if (state == BOOTM_STATE_START) { - argc--; - argv++; - return bootm_start(cmdtp, flag, argc, argv); - } + if (state == BOOTM_STATE_START) + state |= BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER; } else { /* Unrecognized command */ return CMD_RET_USAGE; } - if (images.state < BOOTM_STATE_START || - images.state >= state) { + if (state != BOOTM_STATE_START && images.state >= state) { printf("Trying to execute a command out of order\n"); return CMD_RET_USAGE; } - images.state |= state; - boot_fn = boot_os[images.os.os]; - - switch (state) { - ulong load_end; - case BOOTM_STATE_START: - /* should never occur */ - break; - case BOOTM_STATE_LOADOS: - ret = bootm_load_os(images.os, &load_end, 0); - if (ret) - return ret; - - lmb_reserve(&images.lmb, images.os.load, - (load_end - images.os.load)); - break; -#ifdef CONFIG_SYS_BOOT_RAMDISK_HIGH - case BOOTM_STATE_RAMDISK: - { - ulong rd_len = images.rd_end - images.rd_start; - - ret = boot_ramdisk_high(&images.lmb, images.rd_start, - rd_len, &images.initrd_start, &images.initrd_end); - if (ret) - return ret; - - setenv_hex("initrd_start", images.initrd_start); - setenv_hex("initrd_end", images.initrd_end); - } - break; -#endif -#if defined(CONFIG_OF_LIBFDT) && defined(CONFIG_LMB) - case BOOTM_STATE_FDT: - { - boot_fdt_add_mem_rsv_regions(&images.lmb, - images.ft_addr); - ret = boot_relocate_fdt(&images.lmb, - &images.ft_addr, &images.ft_len); - break; - } -#endif - case BOOTM_STATE_OS_CMDLINE: - ret = boot_fn(BOOTM_STATE_OS_CMDLINE, argc, argv, &images); - if (ret) - printf("cmdline subcommand not supported\n"); - break; - case BOOTM_STATE_OS_BD_T: - ret = boot_fn(BOOTM_STATE_OS_BD_T, argc, argv, &images); - if (ret) - printf("bdt subcommand not supported\n"); - break; - case BOOTM_STATE_OS_PREP: - ret = boot_fn(BOOTM_STATE_OS_PREP, argc, argv, &images); - if (ret) - printf("prep subcommand not supported\n"); - break; - case BOOTM_STATE_OS_GO: - disable_interrupts(); -#ifdef CONFIG_NETCONSOLE - /* - * Stop the ethernet stack if NetConsole could have - * left it up - */ - eth_halt(); -#endif - arch_preboot_os(); - boot_fn(BOOTM_STATE_OS_GO, argc, argv, &images); - break; - } + ret = do_bootm_states(cmdtp, flag, argc, argv, state, &images, 0); return ret; } @@ -593,10 +779,6 @@ static int do_bootm_subcommand(cmd_tbl_t *cmdtp, int flag, int argc, int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - ulong iflag; - ulong load_end = 0; - int ret; - boot_os_fn *boot_fn; #ifdef CONFIG_NEEDS_MANUAL_RELOC static int relocated = 0; @@ -617,11 +799,12 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) #endif /* determine if we have a sub command */ - if (argc > 1) { + argc--; argv++; + if (argc > 0) { char *endp; - simple_strtoul(argv[1], &endp, 16); - /* endp pointing to NULL means that argv[1] was just a + simple_strtoul(argv[0], &endp, 16); + /* endp pointing to NULL means that argv[0] was just a * valid number, pass it along to the normal bootm processing * * If endp is ':' or '#' assume a FIT identifier so pass @@ -633,101 +816,10 @@ int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) return do_bootm_subcommand(cmdtp, flag, argc, argv); } - if (bootm_start(cmdtp, flag, argc, argv)) - return 1; - - /* - * 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... - */ - iflag = disable_interrupts(); - -#ifdef CONFIG_NETCONSOLE - /* Stop the ethernet stack if NetConsole could have left it up */ - eth_halt(); -#endif - -#if defined(CONFIG_CMD_USB) - /* - * turn off USB to prevent the host controller from writing to the - * SDRAM while Linux is booting. This could happen (at least for OHCI - * controller), because the HCCA (Host Controller Communication Area) - * lies within the SDRAM and the host controller writes continously to - * this area (as busmaster!). The HccaFrameNumber is for example - * updated every 1 ms within the HCCA structure in SDRAM! For more - * details see the OpenHCI specification. - */ - usb_stop(); -#endif - - ret = bootm_load_os(images.os, &load_end, 1); - - if (ret < 0) { - if (ret == BOOTM_ERR_RESET) - do_reset(cmdtp, flag, argc, argv); - if (ret == BOOTM_ERR_OVERLAP) { - if (images.legacy_hdr_valid) { - image_header_t *hdr; - hdr = &images.legacy_hdr_os_copy; - if (image_get_type(hdr) == IH_TYPE_MULTI) - puts("WARNING: legacy format multi " - "component image " - "overwritten\n"); - } else { - puts("ERROR: new format image overwritten - " - "must RESET the board to recover\n"); - bootstage_error(BOOTSTAGE_ID_OVERWRITTEN); - do_reset(cmdtp, flag, argc, argv); - } - } - if (ret == BOOTM_ERR_UNIMPLEMENTED) { - if (iflag) - enable_interrupts(); - bootstage_error(BOOTSTAGE_ID_DECOMP_UNIMPL); - return 1; - } - } - - lmb_reserve(&images.lmb, images.os.load, (load_end - images.os.load)); - - if (images.os.type == IH_TYPE_STANDALONE) { - if (iflag) - enable_interrupts(); - /* This may return when 'autostart' is 'no' */ - bootm_start_standalone(iflag, argc, argv); - return 0; - } - - bootstage_mark(BOOTSTAGE_ID_CHECK_BOOT_OS); - -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) - if (images.os.os == IH_OS_LINUX) - fixup_silent_linux(); -#endif - - boot_fn = boot_os[images.os.os]; - - if (boot_fn == NULL) { - if (iflag) - enable_interrupts(); - printf("ERROR: booting os '%s' (%d) is not supported\n", - genimg_get_os_name(images.os.os), images.os.os); - bootstage_error(BOOTSTAGE_ID_CHECK_BOOT_OS); - return 1; - } - - arch_preboot_os(); - - boot_fn(0, argc, argv, &images); - - bootstage_error(BOOTSTAGE_ID_BOOT_OS_RETURNED); -#ifdef DEBUG - puts("\n## Control returned to monitor - resetting...\n"); -#endif - do_reset(cmdtp, flag, argc, argv); - - return 1; + return do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START | + BOOTM_STATE_FINDOS | BOOTM_STATE_FINDOTHER | + BOOTM_STATE_LOADOS | BOOTM_STATE_OS_PREP | + BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO, &images, 1); } int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) @@ -797,54 +889,6 @@ static image_header_t *image_get_kernel(ulong img_addr, int verify) } /** - * fit_check_kernel - verify FIT format kernel subimage - * @fit_hdr: pointer to the FIT image header - * os_noffset: kernel subimage node offset within FIT image - * @verify: data CRC verification flag - * - * fit_check_kernel() verifies integrity of the kernel subimage and from - * specified FIT image. - * - * returns: - * 1, on success - * 0, on failure - */ -#if defined(CONFIG_FIT) -static int fit_check_kernel(const void *fit, int os_noffset, int verify) -{ - fit_image_print(fit, os_noffset, " "); - - if (verify) { - puts(" Verifying Hash Integrity ... "); - if (!fit_image_verify(fit, os_noffset)) { - puts("Bad Data Hash\n"); - bootstage_error(BOOTSTAGE_ID_FIT_CHECK_HASH); - return 0; - } - puts("OK\n"); - } - bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_ARCH); - - if (!fit_image_check_target_arch(fit, os_noffset)) { - puts("Unsupported Architecture\n"); - bootstage_error(BOOTSTAGE_ID_FIT_CHECK_ARCH); - return 0; - } - - bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_KERNEL); - if (!fit_image_check_type(fit, os_noffset, IH_TYPE_KERNEL) && - !fit_image_check_type(fit, os_noffset, IH_TYPE_KERNEL_NOLOAD)) { - puts("Not a kernel image\n"); - bootstage_error(BOOTSTAGE_ID_FIT_CHECK_KERNEL); - return 0; - } - - bootstage_mark(BOOTSTAGE_ID_FIT_CHECKED); - return 1; -} -#endif /* CONFIG_FIT */ - -/** * boot_get_kernel - find kernel image * @os_data: pointer to a ulong variable, will hold os data start address * @os_len: pointer to a ulong variable, will hold os data length @@ -864,32 +908,28 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, ulong img_addr; const void *buf; #if defined(CONFIG_FIT) - const void *fit_hdr; const char *fit_uname_config = NULL; const char *fit_uname_kernel = NULL; - const void *data; - size_t len; - int cfg_noffset; int os_noffset; #endif /* find out kernel image address */ - if (argc < 2) { + if (argc < 1) { img_addr = load_addr; debug("* kernel: default image load address = 0x%08lx\n", load_addr); #if defined(CONFIG_FIT) - } else if (fit_parse_conf(argv[1], load_addr, &img_addr, + } else if (fit_parse_conf(argv[0], load_addr, &img_addr, &fit_uname_config)) { debug("* kernel: config '%s' from image at 0x%08lx\n", fit_uname_config, img_addr); - } else if (fit_parse_subimage(argv[1], load_addr, &img_addr, + } else if (fit_parse_subimage(argv[0], load_addr, &img_addr, &fit_uname_kernel)) { debug("* kernel: subimage '%s' from image at 0x%08lx\n", fit_uname_kernel, img_addr); #endif } else { - img_addr = simple_strtoul(argv[1], NULL, 16); + img_addr = simple_strtoul(argv[0], NULL, 16); debug("* kernel: cmdline image address = 0x%08lx\n", img_addr); } @@ -946,85 +986,18 @@ static const void *boot_get_kernel(cmd_tbl_t *cmdtp, int flag, int argc, break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: - fit_hdr = buf; - printf("## Booting kernel from FIT Image at %08lx ...\n", - img_addr); - - if (!fit_check_format(fit_hdr)) { - puts("Bad FIT kernel image format!\n"); - bootstage_error(BOOTSTAGE_ID_FIT_FORMAT); - return NULL; - } - bootstage_mark(BOOTSTAGE_ID_FIT_FORMAT); - - if (!fit_uname_kernel) { - /* - * no kernel image node unit name, try to get config - * node first. If config unit node name is NULL - * fit_conf_get_node() will try to find default config - * node - */ - bootstage_mark(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); -#ifdef CONFIG_FIT_BEST_MATCH - if (fit_uname_config) - cfg_noffset = - fit_conf_get_node(fit_hdr, - fit_uname_config); - else - cfg_noffset = - fit_conf_find_compat(fit_hdr, - gd->fdt_blob); -#else - cfg_noffset = fit_conf_get_node(fit_hdr, - fit_uname_config); -#endif - if (cfg_noffset < 0) { - bootstage_error(BOOTSTAGE_ID_FIT_NO_UNIT_NAME); - return NULL; - } - /* save configuration uname provided in the first - * bootm argument - */ - images->fit_uname_cfg = fdt_get_name(fit_hdr, - cfg_noffset, - NULL); - printf(" Using '%s' configuration\n", - images->fit_uname_cfg); - bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); - - os_noffset = fit_conf_get_kernel_node(fit_hdr, - cfg_noffset); - fit_uname_kernel = fit_get_name(fit_hdr, os_noffset, - NULL); - } else { - /* get kernel component image node offset */ - bootstage_mark(BOOTSTAGE_ID_FIT_UNIT_NAME); - os_noffset = fit_image_get_node(fit_hdr, - fit_uname_kernel); - } - if (os_noffset < 0) { - bootstage_error(BOOTSTAGE_ID_FIT_CONFIG); - return NULL; - } - - printf(" Trying '%s' kernel subimage\n", fit_uname_kernel); - - bootstage_mark(BOOTSTAGE_ID_FIT_CHECK_SUBIMAGE); - if (!fit_check_kernel(fit_hdr, os_noffset, images->verify)) - return NULL; - - /* get kernel image data address and length */ - if (fit_image_get_data(fit_hdr, os_noffset, &data, &len)) { - puts("Could not find kernel subimage data!\n"); - bootstage_error(BOOTSTAGE_ID_FIT_KERNEL_INFO_ERR); + os_noffset = fit_image_load(images, FIT_KERNEL_PROP, + img_addr, + &fit_uname_kernel, &fit_uname_config, + IH_ARCH_DEFAULT, IH_TYPE_KERNEL, + BOOTSTAGE_ID_FIT_KERNEL_START, + FIT_LOAD_IGNORED, os_data, os_len); + if (os_noffset < 0) return NULL; - } - bootstage_mark(BOOTSTAGE_ID_FIT_KERNEL_INFO); - *os_len = len; - *os_data = (ulong)data; - images->fit_hdr_os = (void *)fit_hdr; + images->fit_hdr_os = map_sysmem(img_addr, 0); images->fit_uname_os = fit_uname_kernel; + images->fit_uname_cfg = fit_uname_config; images->fit_noffset_os = os_noffset; break; #endif @@ -1472,6 +1445,19 @@ static void fixup_silent_linux(void) } #endif /* CONFIG_SILENT_CONSOLE */ +#if defined(CONFIG_BOOTM_NETBSD) || defined(CONFIG_BOOTM_PLAN9) +static void copy_args(char *dest, int argc, char * const argv[], char delim) +{ + int i; + + for (i = 0; i < argc; i++) { + if (i > 0) + *dest++ = delim; + strcpy(dest, argv[i]); + dest += strlen(argv[i]); + } +} +#endif /*******************************************************************/ /* OS booting routines */ @@ -1487,6 +1473,8 @@ static int do_bootm_netbsd(int flag, int argc, char * const argv[], char *consdev; char *cmdline; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1527,20 +1515,14 @@ static int do_bootm_netbsd(int flag, int argc, char * const argv[], consdev = "scc3"; #endif - if (argc > 2) { + if (argc > 0) { ulong len; int i; - for (i = 2, len = 0; i < argc; i += 1) + for (i = 0, len = 0; i < argc; i += 1) len += strlen(argv[i]) + 1; cmdline = malloc(len); - - for (i = 2, len = 0; i < argc; i += 1) { - if (i > 2) - cmdline[len++] = ' '; - strcpy(&cmdline[len], argv[i]); - len += strlen(argv[i]); - } + copy_args(cmdline, argc, argv, ' '); } else if ((cmdline = getenv("bootargs")) == NULL) { cmdline = ""; } @@ -1572,6 +1554,8 @@ static int do_bootm_lynxkdi(int flag, int argc, char * const argv[], { image_header_t *hdr = &images->legacy_hdr_os_copy; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1594,6 +1578,8 @@ static int do_bootm_rtems(int flag, int argc, char * const argv[], { void (*entry_point)(bd_t *); + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1627,6 +1613,8 @@ static int do_bootm_ose(int flag, int argc, char * const argv[], { void (*entry_point)(void); + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1659,7 +1647,10 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[], bootm_headers_t *images) { void (*entry_point)(void); + char *s; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1670,6 +1661,20 @@ static int do_bootm_plan9(int flag, int argc, char * const argv[], } #endif + /* See README.plan9 */ + s = getenv("confaddr"); + if (s != NULL) { + char *confaddr = (char *)simple_strtoul(s, NULL, 16); + + if (argc > 0) { + copy_args(confaddr, argc, argv, '\n'); + } else { + s = getenv("bootargs"); + if (s != NULL) + strcpy(confaddr, s); + } + } + entry_point = (void (*)(void))images->ep; printf("## Transferring control to Plan 9 (at address %08lx) ...\n", @@ -1693,6 +1698,8 @@ static int do_bootm_vxworks(int flag, int argc, char * const argv[], { char str[80]; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1716,6 +1723,8 @@ static int do_bootm_qnxelf(int flag, int argc, char * const argv[], char *local_args[2]; char str[16]; + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1741,6 +1750,8 @@ static int do_bootm_integrity(int flag, int argc, char * const argv[], { void (*entry_point)(void); + if (flag & BOOTM_STATE_OS_PREP) + return 0; if ((flag != 0) && (flag != BOOTM_STATE_OS_GO)) return 1; @@ -1770,15 +1781,13 @@ static int do_bootm_integrity(int flag, int argc, char * const argv[], #ifdef CONFIG_CMD_BOOTZ -static int __bootz_setup(void *image, void **start, void **end) +int __weak bootz_setup(ulong image, ulong *start, ulong *end) { /* Please define bootz_setup() for your platform */ puts("Your platform's zImage format isn't supported yet!\n"); return -1; } -int bootz_setup(void *image, void **start, void **end) - __attribute__((weak, alias("__bootz_setup"))); /* * zImage booting support @@ -1787,96 +1796,66 @@ static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[], bootm_headers_t *images) { int ret; - void *zi_start, *zi_end; - - memset(images, 0, sizeof(bootm_headers_t)); + ulong zi_start, zi_end; - boot_start_lmb(images); + ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START, + images, 1); /* Setup Linux kernel zImage entry point */ - if (argc < 2) { + if (!argc) { images->ep = load_addr; debug("* kernel: default image load address = 0x%08lx\n", load_addr); } else { - images->ep = simple_strtoul(argv[1], NULL, 16); + images->ep = simple_strtoul(argv[0], NULL, 16); debug("* kernel: cmdline image address = 0x%08lx\n", images->ep); } - ret = bootz_setup((void *)images->ep, &zi_start, &zi_end); + ret = bootz_setup(images->ep, &zi_start, &zi_end); if (ret != 0) return 1; lmb_reserve(&images->lmb, images->ep, zi_end - zi_start); - /* Find ramdisk */ - ret = boot_get_ramdisk(argc, argv, images, IH_INITRD_ARCH, - &images->rd_start, &images->rd_end); - if (ret) { - puts("Ramdisk image is corrupt or invalid\n"); + /* + * Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not + * have a header that provide this informaiton. + */ + if (bootm_find_ramdisk(flag, argc, argv)) return 1; - } #if defined(CONFIG_OF_LIBFDT) - /* find flattened device tree */ - ret = boot_get_fdt(flag, argc, argv, images, - &images->ft_addr, &images->ft_len); - if (ret) { - puts("Could not find a valid device tree\n"); + if (bootm_find_fdt(flag, argc, argv)) return 1; - } - - set_working_fdt_addr(images->ft_addr); #endif return 0; } -static int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { - bootm_headers_t images; + int ret; + + /* Consume 'bootz' */ + argc--; argv++; if (bootz_start(cmdtp, flag, argc, argv, &images)) return 1; /* - * 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... + * We are doing the BOOTM_STATE_LOADOS state ourselves, so must + * disable interrupts ourselves */ - disable_interrupts(); + bootm_disable_interrupts(); -#ifdef CONFIG_NETCONSOLE - /* Stop the ethernet stack if NetConsole could have left it up */ - eth_halt(); -#endif + images.os.os = IH_OS_LINUX; + ret = do_bootm_states(cmdtp, flag, argc, argv, + BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | + BOOTM_STATE_OS_GO, + &images, 1); -#if defined(CONFIG_CMD_USB) - /* - * turn off USB to prevent the host controller from writing to the - * SDRAM while Linux is booting. This could happen (at least for OHCI - * controller), because the HCCA (Host Controller Communication Area) - * lies within the SDRAM and the host controller writes continously to - * this area (as busmaster!). The HccaFrameNumber is for example - * updated every 1 ms within the HCCA structure in SDRAM! For more - * details see the OpenHCI specification. - */ - usb_stop(); -#endif - -#if defined(CONFIG_SILENT_CONSOLE) && !defined(CONFIG_SILENT_U_BOOT_ONLY) - fixup_silent_linux(); -#endif - arch_preboot_os(); - - do_bootm_linux(0, argc, argv, &images); -#ifdef DEBUG - puts("\n## Control returned to monitor - resetting...\n"); -#endif - do_reset(cmdtp, flag, argc, argv); - - return 1; + return ret; } #ifdef CONFIG_SYS_LONGHELP diff --git a/common/cmd_elf.c b/common/cmd_elf.c index ab9c7e3..f741f6b 100644 --- a/common/cmd_elf.c +++ b/common/cmd_elf.c @@ -156,16 +156,16 @@ int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) * If we don't know where the image is then we're done. */ - if (argc < 2) + if (argc < 1) addr = load_addr; else - addr = simple_strtoul(argv[1], NULL, 16); + addr = simple_strtoul(argv[0], NULL, 16); #if defined(CONFIG_CMD_NET) /* * Check to see if we need to tftp the image ourselves before starting */ - if ((argc == 2) && (strcmp(argv[1], "tftp") == 0)) { + if ((argc == 1) && (strcmp(argv[0], "tftp") == 0)) { if (NetLoop(TFTPGET) <= 0) return 1; printf("Automatic boot of VxWorks image at address 0x%08lx ...\n", diff --git a/common/cmd_fitupd.c b/common/cmd_fitupd.c index 7a3789e..618ff7c 100644 --- a/common/cmd_fitupd.c +++ b/common/cmd_fitupd.c @@ -8,13 +8,12 @@ #include <common.h> #include <command.h> +#include <net.h> #if !defined(CONFIG_UPDATE_TFTP) #error "CONFIG_UPDATE_TFTP required" #endif -extern int update_tftp(ulong addr); - static int do_fitupd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { ulong addr = 0UL; diff --git a/common/cmd_ide.c b/common/cmd_ide.c index 78b4aa7..59e95df 100644 --- a/common/cmd_ide.c +++ b/common/cmd_ide.c @@ -830,7 +830,7 @@ static void ide_ident(block_dev_desc_t *dev_desc) /* ------------------------------------------------------------------------- */ -ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) +ulong ide_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer) { ulong n = 0; unsigned char c; @@ -844,7 +844,7 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) lba48 = 1; } #endif - debug("ide_read dev %d start %lX, blocks " LBAF " buffer at %lX\n", + debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n", device, blknr, blkcnt, (ulong) buffer); ide_led(DEVICE_LED(device), 1); /* LED on */ @@ -934,8 +934,8 @@ ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer) if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) != ATA_STAT_DRQ) { - printf("Error (no IRQ) dev %d blk %ld: status %#02x\n", - device, blknr, c); + printf("Error (no IRQ) dev %d blk " LBAF ": status " + "%#02x\n", device, blknr, c); break; } @@ -954,7 +954,7 @@ IDE_READ_E: /* ------------------------------------------------------------------------- */ -ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) +ulong ide_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer) { ulong n = 0; unsigned char c; @@ -1022,8 +1022,8 @@ ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer) if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) != ATA_STAT_DRQ) { - printf("Error (no IRQ) dev %d blk %ld: status %#02x\n", - device, blknr, c); + printf("Error (no IRQ) dev %d blk " LBAF ": status " + "%#02x\n", device, blknr, c); goto WR_OUT; } diff --git a/common/cmd_immap.c b/common/cmd_immap.c index fdf9489..bb15795 100644 --- a/common/cmd_immap.c +++ b/common/cmd_immap.c @@ -535,7 +535,7 @@ do_i2cinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) volatile iic_t *iip; uint dpaddr; - dpaddr = *((unsigned short *) (&immap->im_dprambase[PROFF_I2C_BASE])); + dpaddr = immap->im_dprambase16[PROFF_I2C_BASE / sizeof(u16)]; if (dpaddr == 0) iip = NULL; else diff --git a/common/cmd_mem.c b/common/cmd_mem.c index 6df00b1..77eafa0 100644 --- a/common/cmd_mem.c +++ b/common/cmd_mem.c @@ -551,6 +551,8 @@ static int do_mem_loop(cmd_tbl_t *cmdtp, int flag, int argc, *cp++; } unmap_sysmem(buf); + + return 0; } #ifdef CONFIG_LOOPW diff --git a/common/cmd_nand.c b/common/cmd_nand.c index e9d3d3c..886212a 100644 --- a/common/cmd_nand.c +++ b/common/cmd_nand.c @@ -62,8 +62,8 @@ static int nand_dump(nand_info_t *nand, ulong off, int only_oob, int repeat) ops.oobbuf = oobbuf; ops.len = nand->writesize; ops.ooblen = nand->oobsize; - ops.mode = MTD_OOB_RAW; - i = nand->read_oob(nand, addr, &ops); + ops.mode = MTD_OPS_RAW; + i = mtd_read_oob(nand, addr, &ops); if (i < 0) { printf("Error (%d) reading page %08lx\n", i, off); free(datbuf); @@ -404,13 +404,13 @@ static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count, .oobbuf = ((u8 *)addr) + nand->writesize, .len = nand->writesize, .ooblen = nand->oobsize, - .mode = MTD_OOB_RAW + .mode = MTD_OPS_RAW }; if (read) - ret = nand->read_oob(nand, off, &ops); + ret = mtd_read_oob(nand, off, &ops); else - ret = nand->write_oob(nand, off, &ops); + ret = mtd_write_oob(nand, off, &ops); if (ret) { printf("%s: error at offset %llx, ret %d\n", @@ -425,6 +425,31 @@ static int raw_access(nand_info_t *nand, ulong addr, loff_t off, ulong count, return ret; } +/* Adjust a chip/partition size down for bad blocks so we don't + * read/write past the end of a chip/partition by accident. + */ +static void adjust_size_for_badblocks(loff_t *size, loff_t offset, int dev) +{ + /* We grab the nand info object here fresh because this is usually + * called after arg_off_size() which can change the value of dev. + */ + nand_info_t *nand = &nand_info[dev]; + loff_t maxoffset = offset + *size; + int badblocks = 0; + + /* count badblocks in NAND from offset to offset + size */ + for (; offset < maxoffset; offset += nand->erasesize) { + if (nand_block_isbad(nand, offset)) + badblocks++; + } + /* adjust size if any bad blocks found */ + if (badblocks) { + *size -= badblocks * nand->erasesize; + printf("size adjusted to 0x%llx (%d bad blocks)\n", + (unsigned long long)*size, badblocks); + } +} + static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int i, ret = 0; @@ -642,6 +667,9 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) &off, &size, &maxsize) != 0) return 1; + /* size is unspecified */ + if (argc < 5) + adjust_size_for_badblocks(&size, off, dev); rwsize = size; } @@ -680,13 +708,13 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) mtd_oob_ops_t ops = { .oobbuf = (u8 *)addr, .ooblen = rwsize, - .mode = MTD_OOB_RAW + .mode = MTD_OPS_RAW }; if (read) - ret = nand->read_oob(nand, off, &ops); + ret = mtd_read_oob(nand, off, &ops); else - ret = nand->write_oob(nand, off, &ops); + ret = mtd_write_oob(nand, off, &ops); } else if (raw) { ret = raw_access(nand, addr, off, pagecount, read); } else { @@ -729,7 +757,7 @@ static int do_nand(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) while (argc > 0) { addr = simple_strtoul(*argv, NULL, 16); - if (nand->block_markbad(nand, addr)) { + if (mtd_block_markbad(nand, addr)) { printf("block 0x%08lx NOT marked " "as bad! ERROR %d\n", addr, ret); diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c index a0d25e5..06cc140 100644 --- a/common/cmd_onenand.c +++ b/common/cmd_onenand.c @@ -83,7 +83,7 @@ static int onenand_block_read(loff_t from, size_t len, ops.len = blocksize; while (blocks) { - ret = mtd->block_isbad(mtd, ofs); + ret = mtd_block_isbad(mtd, ofs); if (ret) { printk("Bad blocks %d at 0x%x\n", (u32)(ofs >> this->erase_shift), (u32)ofs); @@ -97,7 +97,7 @@ static int onenand_block_read(loff_t from, size_t len, ops.datbuf = buf; ops.retlen = 0; - ret = mtd->read_oob(mtd, ofs, &ops); + ret = mtd_read_oob(mtd, ofs, &ops); if (ret) { printk("Read failed 0x%x, %d\n", (u32)ofs, ret); ofs += blocksize; @@ -118,7 +118,7 @@ static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf, struct mtd_oob_ops ops = { .len = mtd->writesize, .ooblen = mtd->oobsize, - .mode = MTD_OOB_AUTO, + .mode = MTD_OPS_AUTO_OOB, }; int page, ret = 0; for (page = 0; page < (mtd->erasesize / mtd->writesize); page ++) { @@ -126,7 +126,7 @@ static int onenand_write_oneblock_withoob(loff_t to, const u_char * buf, buf += mtd->writesize; ops.oobbuf = (u_char *)buf; buf += mtd->oobsize; - ret = mtd->write_oob(mtd, to, &ops); + ret = mtd_write_oob(mtd, to, &ops); if (ret) break; to += mtd->writesize; @@ -156,7 +156,7 @@ static int onenand_block_write(loff_t to, size_t len, ofs = to; while (blocks) { - ret = mtd->block_isbad(mtd, ofs); + ret = mtd_block_isbad(mtd, ofs); if (ret) { printk("Bad blocks %d at 0x%x\n", (u32)(ofs >> this->erase_shift), (u32)ofs); @@ -165,7 +165,7 @@ static int onenand_block_write(loff_t to, size_t len, } if (!withoob) - ret = mtd->write(mtd, ofs, blocksize, &_retlen, buf); + ret = mtd_write(mtd, ofs, blocksize, &_retlen, buf); else ret = onenand_write_oneblock_withoob(ofs, buf, &_retlen); if (ret) { @@ -195,7 +195,7 @@ static int onenand_block_erase(u32 start, u32 size, int force) int blocksize = 1 << this->erase_shift; for (ofs = start; ofs < (start + size); ofs += blocksize) { - ret = mtd->block_isbad(mtd, ofs); + ret = mtd_block_isbad(mtd, ofs); if (ret && !force) { printf("Skip erase bad block %d at 0x%x\n", (u32)(ofs >> this->erase_shift), (u32)ofs); @@ -206,7 +206,7 @@ static int onenand_block_erase(u32 start, u32 size, int force) instr.len = blocksize; instr.priv = force; instr.mtd = mtd; - ret = mtd->erase(mtd, &instr); + ret = mtd_erase(mtd, &instr); if (ret) { printf("erase failed block %d at 0x%x\n", (u32)(ofs >> this->erase_shift), (u32)ofs); @@ -261,7 +261,7 @@ static int onenand_block_test(u32 start, u32 size) while (blocks < end_block) { printf("\rTesting block %d at 0x%x", (u32)(ofs >> this->erase_shift), (u32)ofs); - ret = mtd->block_isbad(mtd, ofs); + ret = mtd_block_isbad(mtd, ofs); if (ret) { printf("Skip erase bad block %d at 0x%x\n", (u32)(ofs >> this->erase_shift), (u32)ofs); @@ -270,19 +270,19 @@ static int onenand_block_test(u32 start, u32 size) instr.addr = ofs; instr.len = blocksize; - ret = mtd->erase(mtd, &instr); + ret = mtd_erase(mtd, &instr); if (ret) { printk("Erase failed 0x%x, %d\n", (u32)ofs, ret); goto next; } - ret = mtd->write(mtd, ofs, blocksize, &retlen, buf); + ret = mtd_write(mtd, ofs, blocksize, &retlen, buf); if (ret) { printk("Write failed 0x%x, %d\n", (u32)ofs, ret); goto next; } - ret = mtd->read(mtd, ofs, blocksize, &retlen, verify_buf); + ret = mtd_read(mtd, ofs, blocksize, &retlen, verify_buf); if (ret) { printk("Read failed 0x%x, %d\n", (u32)ofs, ret); goto next; @@ -324,7 +324,7 @@ static int onenand_dump(struct mtd_info *mtd, ulong off, int only_oob) ops.len = mtd->writesize; ops.ooblen = mtd->oobsize; ops.retlen = 0; - i = mtd->read_oob(mtd, addr, &ops); + i = mtd_read_oob(mtd, addr, &ops); if (i < 0) { printf("Error (%d) reading page %08lx\n", i, off); free(datbuf); @@ -373,7 +373,7 @@ static int do_onenand_bad(cmd_tbl_t * cmdtp, int flag, int argc, char * const ar /* Currently only one OneNAND device is supported */ printf("\nDevice %d bad blocks:\n", 0); for (ofs = 0; ofs < mtd->size; ofs += mtd->erasesize) { - if (mtd->block_isbad(mtd, ofs)) + if (mtd_block_isbad(mtd, ofs)) printf(" %08x\n", (u32)ofs); } @@ -530,7 +530,7 @@ static int do_onenand_markbad(cmd_tbl_t * cmdtp, int flag, int argc, char * cons while (argc > 0) { addr = simple_strtoul(*argv, NULL, 16); - if (mtd->block_markbad(mtd, addr)) { + if (mtd_block_markbad(mtd, addr)) { printf("block 0x%08lx NOT marked " "as bad! ERROR %d\n", addr, ret); diff --git a/common/cmd_pxe.c b/common/cmd_pxe.c index 2dbd49c..1fb75d8 100644 --- a/common/cmd_pxe.c +++ b/common/cmd_pxe.c @@ -26,12 +26,21 @@ #define MAX_TFTP_PATH_LEN 127 +const char *pxe_default_paths[] = { +#ifdef CONFIG_SYS_SOC + "default-" CONFIG_SYS_ARCH "-" CONFIG_SYS_SOC, +#endif + "default-" CONFIG_SYS_ARCH, + "default", + NULL +}; + /* * Like getenv, but prints an error if envvar isn't defined in the * environment. It always returns what getenv does, so it can be used in * place of getenv without changing error handling otherwise. */ -static char *from_env(char *envvar) +static char *from_env(const char *envvar) { char *ret; @@ -55,37 +64,21 @@ static char *from_env(char *envvar) */ static int format_mac_pxe(char *outbuf, size_t outbuf_len) { - size_t ethaddr_len; - char *p, *ethaddr; - - ethaddr = from_env("ethaddr"); + uchar ethaddr[6]; - if (!ethaddr) - return -ENOENT; - - ethaddr_len = strlen(ethaddr); - - /* - * ethaddr_len + 4 gives room for "01-", ethaddr, and a NUL byte at - * the end. - */ - if (outbuf_len < ethaddr_len + 4) { - printf("outbuf is too small (%d < %d)\n", - outbuf_len, ethaddr_len + 4); + if (outbuf_len < 21) { + printf("outbuf is too small (%d < 21)\n", outbuf_len); return -EINVAL; } - strcpy(outbuf, "01-"); - - for (p = outbuf + 3; *ethaddr; ethaddr++, p++) { - if (*ethaddr == ':') - *p = '-'; - else - *p = tolower(*ethaddr); - } + if (!eth_getenv_enetaddr_by_index("eth", eth_get_dev_index(), + ethaddr)) + return -ENOENT; - *p = '\0'; + sprintf(outbuf, "01-%02x-%02x-%02x-%02x-%02x-%02x", + ethaddr[0], ethaddr[1], ethaddr[2], + ethaddr[3], ethaddr[4], ethaddr[5]); return 1; } @@ -131,14 +124,14 @@ static int get_bootfile_path(const char *file_path, char *bootfile_path, return 1; } -static int (*do_getfile)(char *file_path, char *file_addr); +static int (*do_getfile)(const char *file_path, char *file_addr); -static int do_get_tftp(char *file_path, char *file_addr) +static int do_get_tftp(const char *file_path, char *file_addr) { char *tftp_argv[] = {"tftp", NULL, NULL, NULL}; tftp_argv[1] = file_addr; - tftp_argv[2] = file_path; + tftp_argv[2] = (void *)file_path; if (do_tftpb(NULL, 0, 3, tftp_argv)) return -ENOENT; @@ -148,12 +141,12 @@ static int do_get_tftp(char *file_path, char *file_addr) static char *fs_argv[5]; -static int do_get_ext2(char *file_path, char *file_addr) +static int do_get_ext2(const char *file_path, char *file_addr) { #ifdef CONFIG_CMD_EXT2 fs_argv[0] = "ext2load"; fs_argv[3] = file_addr; - fs_argv[4] = file_path; + fs_argv[4] = (void *)file_path; if (!do_ext2load(NULL, 0, 5, fs_argv)) return 1; @@ -161,12 +154,12 @@ static int do_get_ext2(char *file_path, char *file_addr) return -ENOENT; } -static int do_get_fat(char *file_path, char *file_addr) +static int do_get_fat(const char *file_path, char *file_addr) { #ifdef CONFIG_CMD_FAT fs_argv[0] = "fatload"; fs_argv[3] = file_addr; - fs_argv[4] = file_path; + fs_argv[4] = (void *)file_path; if (!do_fat_fsload(NULL, 0, 5, fs_argv)) return 1; @@ -182,7 +175,7 @@ static int do_get_fat(char *file_path, char *file_addr) * * Returns 1 for success, or < 0 on error. */ -static int get_relfile(char *file_path, void *file_addr) +static int get_relfile(const char *file_path, void *file_addr) { size_t path_len; char relfile[MAX_TFTP_PATH_LEN+1]; @@ -221,7 +214,7 @@ static int get_relfile(char *file_path, void *file_addr) * * Returns 1 on success, or < 0 for error. */ -static int get_pxe_file(char *file_path, void *file_addr) +static int get_pxe_file(const char *file_path, void *file_addr) { unsigned long config_file_size; char *tftp_filesize; @@ -258,7 +251,7 @@ static int get_pxe_file(char *file_path, void *file_addr) * * Returns 1 on success or < 0 on error. */ -static int get_pxelinux_path(char *file, void *pxefile_addr_r) +static int get_pxelinux_path(const char *file, void *pxefile_addr_r) { size_t base_len = strlen(PXELINUX_DIR); char path[MAX_TFTP_PATH_LEN+1]; @@ -355,7 +348,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { char *pxefile_addr_str; unsigned long pxefile_addr_r; - int err; + int err, i = 0; do_getfile = do_get_tftp; @@ -376,16 +369,23 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) * Keep trying paths until we successfully get a file we're looking * for. */ - if (pxe_uuid_path((void *)pxefile_addr_r) > 0 - || pxe_mac_path((void *)pxefile_addr_r) > 0 - || pxe_ipaddr_paths((void *)pxefile_addr_r) > 0 - || get_pxelinux_path("default", (void *)pxefile_addr_r) > 0) { - + if (pxe_uuid_path((void *)pxefile_addr_r) > 0 || + pxe_mac_path((void *)pxefile_addr_r) > 0 || + pxe_ipaddr_paths((void *)pxefile_addr_r) > 0) { printf("Config file found\n"); return 0; } + while (pxe_default_paths[i]) { + if (get_pxelinux_path(pxe_default_paths[i], + (void *)pxefile_addr_r) > 0) { + printf("Config file found\n"); + return 0; + } + i++; + } + printf("Config file not found\n"); return 1; @@ -398,7 +398,7 @@ do_pxe_get(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) * * Returns 1 on success or < 0 on error. */ -static int get_relfile_envaddr(char *file_path, char *envaddr_name) +static int get_relfile_envaddr(const char *file_path, const char *envaddr_name) { unsigned long file_addr; char *envaddr; @@ -445,14 +445,17 @@ static int get_relfile_envaddr(char *file_path, char *envaddr_name) * list - lets these form a list, which a pxe_menu struct will hold. */ struct pxe_label { + char num[4]; char *name; char *menu; char *kernel; char *append; char *initrd; char *fdt; + int ipappend; int attempted; int localboot; + int localboot_val; struct list_head list; }; @@ -533,21 +536,9 @@ static void label_destroy(struct pxe_label *label) static void label_print(void *data) { struct pxe_label *label = data; - const char *c = label->menu ? label->menu : label->kernel; - - printf("%s:\t%s\n", label->name, c); - - if (label->kernel) - printf("\t\tkernel: %s\n", label->kernel); - - if (label->append) - printf("\t\tappend: %s\n", label->append); + const char *c = label->menu ? label->menu : label->name; - if (label->initrd) - printf("\t\tinitrd: %s\n", label->initrd); - - if (label->fdt) - printf("\tfdt: %s\n", label->fdt); + printf("%s:\t%s\n", label->num, c); } /* @@ -591,34 +582,43 @@ static int label_localboot(struct pxe_label *label) * If the label specifies an 'append' line, its contents will overwrite that * of the 'bootargs' environment variable. */ -static void label_boot(struct pxe_label *label) +static int label_boot(struct pxe_label *label) { char *bootm_argv[] = { "bootm", NULL, NULL, NULL, NULL }; + char initrd_str[22]; + char mac_str[29] = ""; + char ip_str[68] = ""; + char *bootargs; int bootm_argc = 3; + int len = 0; label_print(label); label->attempted = 1; if (label->localboot) { - label_localboot(label); - return; + if (label->localboot_val >= 0) + label_localboot(label); + return 0; } if (label->kernel == NULL) { printf("No kernel given, skipping %s\n", label->name); - return; + return 1; } if (label->initrd) { if (get_relfile_envaddr(label->initrd, "ramdisk_addr_r") < 0) { printf("Skipping %s for failure retrieving initrd\n", label->name); - return; + return 1; } - bootm_argv[2] = getenv("ramdisk_addr_r"); + bootm_argv[2] = initrd_str; + strcpy(bootm_argv[2], getenv("ramdisk_addr_r")); + strcat(bootm_argv[2], ":"); + strcat(bootm_argv[2], getenv("filesize")); } else { bootm_argv[2] = "-"; } @@ -626,11 +626,43 @@ static void label_boot(struct pxe_label *label) if (get_relfile_envaddr(label->kernel, "kernel_addr_r") < 0) { printf("Skipping %s for failure retrieving kernel\n", label->name); - return; + return 1; + } + + if (label->ipappend & 0x1) { + sprintf(ip_str, " ip=%s:%s:%s:%s", + getenv("ipaddr"), getenv("serverip"), + getenv("gatewayip"), getenv("netmask")); + len += strlen(ip_str); + } + + if (label->ipappend & 0x2) { + int err; + strcpy(mac_str, " BOOTIF="); + err = format_mac_pxe(mac_str + 8, sizeof(mac_str) - 8); + if (err < 0) + mac_str[0] = '\0'; + len += strlen(mac_str); } if (label->append) - setenv("bootargs", label->append); + len += strlen(label->append); + + if (len) { + bootargs = malloc(len + 1); + if (!bootargs) + return 1; + bootargs[0] = '\0'; + if (label->append) + strcpy(bootargs, label->append); + strcat(bootargs, ip_str); + strcat(bootargs, mac_str); + + setenv("bootargs", bootargs); + printf("append: %s\n", bootargs); + + free(bootargs); + } bootm_argv[1] = getenv("kernel_addr_r"); @@ -654,7 +686,7 @@ static void label_boot(struct pxe_label *label) if (get_relfile_envaddr(label->fdt, "fdt_addr_r") < 0) { printf("Skipping %s for failure retrieving fdt\n", label->name); - return; + return 1; } } else bootm_argv[3] = getenv("fdt_addr"); @@ -663,6 +695,12 @@ static void label_boot(struct pxe_label *label) bootm_argc = 4; do_bootm(NULL, 0, bootm_argc, bootm_argv); + +#ifdef CONFIG_CMD_BOOTZ + /* Try booting a zImage if do_bootm returns */ + do_bootz(NULL, 0, bootm_argc, bootm_argv); +#endif + return 1; } /* @@ -685,6 +723,8 @@ enum token_type { T_PROMPT, T_INCLUDE, T_FDT, + T_ONTIMEOUT, + T_IPAPPEND, T_INVALID }; @@ -713,6 +753,8 @@ static const struct token keywords[] = { {"initrd", T_INITRD}, {"include", T_INCLUDE}, {"fdt", T_FDT}, + {"ontimeout", T_ONTIMEOUT,}, + {"ipappend", T_IPAPPEND,}, {NULL, T_INVALID} }; @@ -903,7 +945,6 @@ static int parse_integer(char **c, int *dst) { struct token t; char *s = *c; - unsigned long temp; get_token(c, &t, L_SLITERAL); @@ -912,12 +953,7 @@ static int parse_integer(char **c, int *dst) return -EINVAL; } - if (strict_strtoul(t.val, 10, &temp) < 0) { - printf("Expected unsigned integer: %s\n", t.val); - return -EINVAL; - } - - *dst = (int)temp; + *dst = simple_strtol(t.val, NULL, 10); free(t.val); @@ -1016,10 +1052,8 @@ static int parse_label_menu(char **c, struct pxe_menu *cfg, switch (t.type) { case T_DEFAULT: - if (cfg->default_label) - free(cfg->default_label); - - cfg->default_label = strdup(label->name); + if (!cfg->default_label) + cfg->default_label = strdup(label->name); if (!cfg->default_label) return -ENOMEM; @@ -1108,7 +1142,12 @@ static int parse_label(char **c, struct pxe_menu *cfg) break; case T_LOCALBOOT: - err = parse_integer(c, &label->localboot); + label->localboot = 1; + err = parse_integer(c, &label->localboot_val); + break; + + case T_IPAPPEND: + err = parse_integer(c, &label->ipappend); break; case T_EOL: @@ -1164,6 +1203,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) err = 0; switch (t.type) { case T_MENU: + cfg->prompt = 1; err = parse_menu(&p, cfg, b, nest_level); break; @@ -1176,6 +1216,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) break; case T_DEFAULT: + case T_ONTIMEOUT: err = parse_sliteral(&p, &label_name); if (label_name) { @@ -1193,7 +1234,7 @@ static int parse_pxefile_top(char *p, struct pxe_menu *cfg, int nest_level) break; case T_PROMPT: - err = parse_integer(&p, &cfg->prompt); + eol_or_eof(&p); break; case T_EOL: @@ -1276,6 +1317,8 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg) struct list_head *pos; struct menu *m; int err; + int i = 1; + char *default_num = NULL; /* * Create a menu and add items for all the labels. @@ -1289,18 +1332,23 @@ static struct menu *pxe_menu_to_menu(struct pxe_menu *cfg) list_for_each(pos, &cfg->labels) { label = list_entry(pos, struct pxe_label, list); - if (menu_item_add(m, label->name, label) != 1) { + sprintf(label->num, "%d", i++); + if (menu_item_add(m, label->num, label) != 1) { menu_destroy(m); return NULL; } + if (cfg->default_label && + (strcmp(label->name, cfg->default_label) == 0)) + default_num = label->num; + } /* * After we've created items for each label in the menu, set the * menu's default label if one was specified. */ - if (cfg->default_label) { - err = menu_default_set(m, cfg->default_label); + if (default_num) { + err = menu_default_set(m, default_num); if (err != 1) { if (err != -ENOENT) { menu_destroy(m); @@ -1367,10 +1415,13 @@ static void handle_pxe_menu(struct pxe_menu *cfg) * we give up. */ - if (err == 1) - label_boot(choice); - else if (err != -ENOENT) + if (err == 1) { + err = label_boot(choice); + if (!err) + return; + } else if (err != -ENOENT) { return; + } boot_unattempted_labels(cfg); } diff --git a/common/cmd_sf.c b/common/cmd_sf.c index 0a17782..19b0dc9 100644 --- a/common/cmd_sf.c +++ b/common/cmd_sf.c @@ -234,7 +234,7 @@ static int do_spi_flash_read_write(int argc, char * const argv[]) unsigned long len; void *buf; char *endp; - int ret; + int ret = 1; if (argc < 4) return -1; @@ -264,19 +264,23 @@ static int do_spi_flash_read_write(int argc, char * const argv[]) if (strcmp(argv[0], "update") == 0) ret = spi_flash_update(flash, offset, len, buf); - else if (strcmp(argv[0], "read") == 0) - ret = spi_flash_read(flash, offset, len, buf); - else - ret = spi_flash_write(flash, offset, len, buf); + else if (strncmp(argv[0], "read", 4) == 0 || + strncmp(argv[0], "write", 5) == 0) { + int read; + + read = strncmp(argv[0], "read", 4) == 0; + if (read) + ret = spi_flash_read(flash, offset, len, buf); + else + ret = spi_flash_write(flash, offset, len, buf); + + printf("SF: %zu bytes @ %#x %s: %s\n", (size_t)len, (u32)offset, + read ? "Read" : "Written", ret ? "ERROR" : "OK"); + } unmap_physmem(buf, len); - if (ret) { - printf("SPI flash %s failed\n", argv[0]); - return 1; - } - - return 0; + return ret == 0 ? 0 : 1; } static int do_spi_flash_erase(int argc, char * const argv[]) @@ -305,12 +309,10 @@ static int do_spi_flash_erase(int argc, char * const argv[]) } ret = spi_flash_erase(flash, offset, len); - if (ret) { - printf("SPI flash %s failed\n", argv[0]); - return 1; - } + printf("SF: %zu bytes @ %#x Erased: %s\n", (size_t)len, (u32)offset, + ret ? "ERROR" : "OK"); - return 0; + return ret == 0 ? 0 : 1; } #ifdef CONFIG_CMD_SF_TEST diff --git a/common/cmd_trace.c b/common/cmd_trace.c new file mode 100644 index 0000000..ec3137a --- /dev/null +++ b/common/cmd_trace.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <command.h> +#include <trace.h> +#include <asm/io.h> + +static int get_args(int argc, char * const argv[], char **buff, + size_t *buff_ptr, size_t *buff_size) +{ + if (argc < 2) + return -1; + if (argc < 4) { + *buff_size = getenv_ulong("profsize", 16, 0); + *buff = map_sysmem(getenv_ulong("profbase", 16, 0), + *buff_size); + *buff_ptr = getenv_ulong("profoffset", 16, 0); + } else { + *buff_size = simple_strtoul(argv[3], NULL, 16); + *buff = map_sysmem(simple_strtoul(argv[2], NULL, 16), + *buff_size); + *buff_ptr = 0; + }; + return 0; +} + +static int create_func_list(int argc, char * const argv[]) +{ + size_t buff_size, avail, buff_ptr, used; + unsigned int needed; + char *buff; + int err; + + if (get_args(argc, argv, &buff, &buff_ptr, &buff_size)) + return -1; + + avail = buff_size - buff_ptr; + err = trace_list_functions(buff + buff_ptr, avail, &needed); + if (err) + printf("Error: truncated (%#x bytes needed)\n", needed); + used = min(avail, needed); + printf("Function trace dumped to %08lx, size %#zx\n", + (ulong)map_to_sysmem(buff + buff_ptr), used); + setenv_hex("profbase", map_to_sysmem(buff)); + setenv_hex("profsize", buff_size); + setenv_hex("profoffset", buff_ptr + used); + + return 0; +} + +static int create_call_list(int argc, char * const argv[]) +{ + size_t buff_size, avail, buff_ptr, used; + unsigned int needed; + char *buff; + int err; + + if (get_args(argc, argv, &buff, &buff_ptr, &buff_size)) + return -1; + + avail = buff_size - buff_ptr; + err = trace_list_calls(buff + buff_ptr, avail, &needed); + if (err) + printf("Error: truncated (%#x bytes needed)\n", needed); + used = min(avail, needed); + printf("Call list dumped to %08lx, size %#zx\n", + (ulong)map_to_sysmem(buff + buff_ptr), used); + + setenv_hex("profbase", map_to_sysmem(buff)); + setenv_hex("profsize", buff_size); + setenv_hex("profoffset", buff_ptr + used); + + return 0; +} + +int do_trace(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + const char *cmd = argc < 2 ? NULL : argv[1]; + + if (!cmd) + return cmd_usage(cmdtp); + switch (*cmd) { + case 'p': + trace_set_enabled(0); + break; + case 'c': + if (create_call_list(argc, argv)) + return cmd_usage(cmdtp); + break; + case 'r': + trace_set_enabled(1); + break; + case 'f': + if (create_func_list(argc, argv)) + return cmd_usage(cmdtp); + break; + case 's': + trace_print_stats(); + break; + default: + return CMD_RET_USAGE; + } + + return 0; +} + +U_BOOT_CMD( + trace, 4, 1, do_trace, + "trace utility commands", + "stats - display tracing statistics\n" + "trace pause - pause tracing\n" + "trace resume - resume tracing\n" + "trace funclist [<addr> <size>] - dump function list into buffer\n" + "trace calls [<addr> <size>] " + "- dump function call trace into buffer" +); diff --git a/common/env_mmc.c b/common/env_mmc.c index 9ca098f..5d3a769 100644 --- a/common/env_mmc.c +++ b/common/env_mmc.c @@ -53,11 +53,19 @@ DECLARE_GLOBAL_DATA_PTR; __weak int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr) { - *env_addr = CONFIG_ENV_OFFSET; + s64 offset; + + offset = CONFIG_ENV_OFFSET; #ifdef CONFIG_ENV_OFFSET_REDUND if (copy) - *env_addr = CONFIG_ENV_OFFSET_REDUND; + offset = CONFIG_ENV_OFFSET_REDUND; #endif + + if (offset < 0) + offset += mmc->capacity; + + *env_addr = offset; + return 0; } diff --git a/common/env_onenand.c b/common/env_onenand.c index faa903d..e8bde37 100644 --- a/common/env_onenand.c +++ b/common/env_onenand.c @@ -68,7 +68,7 @@ void env_relocate_spec(void) /* Check OneNAND exist */ if (mtd->writesize) /* Ignore read fail */ - mtd->read(mtd, env_addr, ONENAND_MAX_ENV_SIZE, + mtd_read(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen, (u_char *)buf); else mtd->writesize = MAX_ONENAND_PAGESIZE; @@ -113,12 +113,12 @@ int saveenv(void) #endif instr.addr = env_addr; instr.mtd = mtd; - if (mtd->erase(mtd, &instr)) { + if (mtd_erase(mtd, &instr)) { printf("OneNAND: erase failed at 0x%08llx\n", env_addr); return 1; } - if (mtd->write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen, + if (mtd_write(mtd, env_addr, ONENAND_MAX_ENV_SIZE, &retlen, (u_char *)&env_new)) { printf("OneNAND: write failed at 0x%llx\n", instr.addr); return 2; diff --git a/common/fdt_support.c b/common/fdt_support.c index 416100e..9a6f6b7 100644 --- a/common/fdt_support.c +++ b/common/fdt_support.c @@ -458,7 +458,7 @@ void fdt_fixup_ethernet(void *fdt) { int node, i, j; char enet[16], *tmp, *end; - char mac[16] = "ethaddr"; + char mac[16]; const char *path; unsigned char mac_addr[6]; @@ -467,6 +467,7 @@ void fdt_fixup_ethernet(void *fdt) return; i = 0; + strcpy(mac, "ethaddr"); while ((tmp = getenv(mac)) != NULL) { sprintf(enet, "ethernet%d", i); path = fdt_getprop(fdt, node, enet, NULL); diff --git a/common/image-fdt.c b/common/image-fdt.c index 158c9cf..203404a 100644 --- a/common/image-fdt.c +++ b/common/image-fdt.c @@ -211,51 +211,11 @@ error: return 1; } -#if defined(CONFIG_FIT) -/** - * fit_check_fdt - verify FIT format FDT subimage - * @fit_hdr: pointer to the FIT header - * fdt_noffset: FDT subimage node offset within FIT image - * @verify: data CRC verification flag - * - * fit_check_fdt() verifies integrity of the FDT subimage and from - * specified FIT image. - * - * returns: - * 1, on success - * 0, on failure - */ -static int fit_check_fdt(const void *fit, int fdt_noffset, int verify) -{ - fit_image_print(fit, fdt_noffset, " "); - - if (verify) { - puts(" Verifying Hash Integrity ... "); - if (!fit_image_verify(fit, fdt_noffset)) { - fdt_error("Bad Data Hash"); - return 0; - } - puts("OK\n"); - } - - if (!fit_image_check_type(fit, fdt_noffset, IH_TYPE_FLATDT)) { - fdt_error("Not a FDT image"); - return 0; - } - - if (!fit_image_check_comp(fit, fdt_noffset, IH_COMP_NONE)) { - fdt_error("FDT image is compressed"); - return 0; - } - - return 1; -} -#endif - /** * boot_get_fdt - main fdt handling routine * @argc: command argument count * @argv: command argument list + * @arch: architecture (IH_ARCH_...) * @images: pointer to the bootm images structure * @of_flat_tree: pointer to a char* variable, will hold fdt start address * @of_size: pointer to a ulong variable, will hold fdt length @@ -273,32 +233,31 @@ static int fit_check_fdt(const void *fit, int fdt_noffset, int verify) * 1, if fdt image is found but corrupted * of_flat_tree and of_size are set to 0 if no fdt exists */ -int boot_get_fdt(int flag, int argc, char * const argv[], +int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch, bootm_headers_t *images, char **of_flat_tree, ulong *of_size) { const image_header_t *fdt_hdr; ulong fdt_addr; char *fdt_blob = NULL; ulong image_start, image_data, image_end; - ulong load_start, load_end; + ulong load, load_end; void *buf; #if defined(CONFIG_FIT) - void *fit_hdr; - const char *fit_uname_config = NULL; + const char *fit_uname_config = images->fit_uname_cfg; const char *fit_uname_fdt = NULL; ulong default_addr; - int cfg_noffset; int fdt_noffset; - const void *data; - size_t size; #endif + const char *select = NULL; *of_flat_tree = NULL; *of_size = 0; - if (argc > 3 || genimg_has_config(images)) { + if (argc > 2) + select = argv[2]; + if (select || genimg_has_config(images)) { #if defined(CONFIG_FIT) - if (argc > 3) { + if (select) { /* * If the FDT blob comes from the FIT image and the * FIT image address is omitted in the command line @@ -312,18 +271,18 @@ int boot_get_fdt(int flag, int argc, char * const argv[], else default_addr = load_addr; - if (fit_parse_conf(argv[3], default_addr, + if (fit_parse_conf(select, default_addr, &fdt_addr, &fit_uname_config)) { debug("* fdt: config '%s' from image at 0x%08lx\n", fit_uname_config, fdt_addr); - } else if (fit_parse_subimage(argv[3], default_addr, + } else if (fit_parse_subimage(select, default_addr, &fdt_addr, &fit_uname_fdt)) { debug("* fdt: subimage '%s' from image at 0x%08lx\n", fit_uname_fdt, fdt_addr); } else #endif { - fdt_addr = simple_strtoul(argv[3], NULL, 16); + fdt_addr = simple_strtoul(select, NULL, 16); debug("* fdt: cmdline image address = 0x%08lx\n", fdt_addr); } @@ -333,31 +292,15 @@ int boot_get_fdt(int flag, int argc, char * const argv[], * command argument */ fdt_addr = map_to_sysmem(images->fit_hdr_os); - fit_uname_config = images->fit_uname_cfg; - debug("* fdt: using config '%s' from image at 0x%08lx\n", - fit_uname_config, fdt_addr); - - /* - * Check whether configuration has FDT blob defined, - * if not quit silently. - */ - fit_hdr = images->fit_hdr_os; - cfg_noffset = fit_conf_get_node(fit_hdr, - fit_uname_config); - if (cfg_noffset < 0) { - debug("* fdt: no such config\n"); + fdt_noffset = fit_get_node_from_config(images, + FIT_FDT_PROP, + fdt_addr); + if (fdt_noffset == -ENOLINK) return 0; - } - - fdt_noffset = fit_conf_get_fdt_node(fit_hdr, - cfg_noffset); - if (fdt_noffset < 0) { - debug("* fdt: no fdt in config\n"); - return 0; - } + else if (fdt_noffset < 0) + return 1; } #endif - debug("## Checking for 'FDT'/'FDT Image' at %08lx\n", fdt_addr); @@ -387,29 +330,28 @@ int boot_get_fdt(int flag, int argc, char * const argv[], image_data = (ulong)image_get_data(fdt_hdr); image_end = image_get_image_end(fdt_hdr); - load_start = image_get_load(fdt_hdr); - load_end = load_start + image_get_data_size(fdt_hdr); + load = image_get_load(fdt_hdr); + load_end = load + image_get_data_size(fdt_hdr); - if (load_start == image_start || - load_start == image_data) { + if (load == image_start || + load == image_data) { fdt_blob = (char *)image_data; break; } - if ((load_start < image_end) && - (load_end > image_start)) { + if ((load < image_end) && (load_end > image_start)) { fdt_error("fdt overwritten"); goto error; } debug(" Loading FDT from 0x%08lx to 0x%08lx\n", - image_data, load_start); + image_data, load); - memmove((void *)load_start, + memmove((void *)load, (void *)image_data, image_get_data_size(fdt_hdr)); - fdt_blob = (char *)load_start; + fdt_addr = load; break; case IMAGE_FORMAT_FIT: /* @@ -420,107 +362,20 @@ int boot_get_fdt(int flag, int argc, char * const argv[], #if defined(CONFIG_FIT) /* check FDT blob vs FIT blob */ if (fit_check_format(buf)) { - /* - * FIT image - */ - fit_hdr = buf; - printf("## Flattened Device Tree from FIT Image at %08lx\n", - fdt_addr); - - if (!fit_uname_fdt) { - /* - * no FDT blob image node unit name, - * try to get config node first. If - * config unit node name is NULL - * fit_conf_get_node() will try to - * find default config node - */ - cfg_noffset = fit_conf_get_node(fit_hdr, - fit_uname_config); - - if (cfg_noffset < 0) { - fdt_error("Could not find configuration node\n"); - goto error; - } - - fit_uname_config = fdt_get_name(fit_hdr, - cfg_noffset, NULL); - printf(" Using '%s' configuration\n", - fit_uname_config); - - fdt_noffset = fit_conf_get_fdt_node( - fit_hdr, - cfg_noffset); - fit_uname_fdt = fit_get_name(fit_hdr, - fdt_noffset, NULL); - } else { - /* - * get FDT component image node - * offset - */ - fdt_noffset = fit_image_get_node( - fit_hdr, - fit_uname_fdt); - } - if (fdt_noffset < 0) { - fdt_error("Could not find subimage node\n"); - goto error; - } - - printf(" Trying '%s' FDT blob subimage\n", - fit_uname_fdt); - - if (!fit_check_fdt(fit_hdr, fdt_noffset, - images->verify)) - goto error; - - /* get ramdisk image data address and length */ - if (fit_image_get_data(fit_hdr, fdt_noffset, - &data, &size)) { - fdt_error("Could not find FDT subimage data"); - goto error; - } + ulong load, len; - /* - * verify that image data is a proper FDT - * blob - */ - if (fdt_check_header((char *)data) != 0) { - fdt_error("Subimage data is not a FTD"); - goto error; - } - - /* - * move image data to the load address, - * make sure we don't overwrite initial image - */ - image_start = (ulong)fit_hdr; - image_end = fit_get_end(fit_hdr); - - if (fit_image_get_load(fit_hdr, fdt_noffset, - &load_start) == 0) { - load_end = load_start + size; + fdt_noffset = fit_image_load(images, + FIT_FDT_PROP, + fdt_addr, &fit_uname_fdt, + &fit_uname_config, + arch, IH_TYPE_FLATDT, + BOOTSTAGE_ID_FIT_FDT_START, + FIT_LOAD_OPTIONAL, &load, &len); - if ((load_start < image_end) && - (load_end > image_start)) { - fdt_error("FDT overwritten"); - goto error; - } - - printf(" Loading FDT from 0x%08lx to 0x%08lx\n", - (ulong)data, load_start); - - memmove((void *)load_start, - (void *)data, size); - - fdt_blob = (char *)load_start; - } else { - fdt_blob = (char *)data; - } - - images->fit_hdr_fdt = fit_hdr; + images->fit_hdr_fdt = map_sysmem(fdt_addr, 0); images->fit_uname_fdt = fit_uname_fdt; images->fit_noffset_fdt = fdt_noffset; + fdt_addr = load; break; } else #endif @@ -528,7 +383,6 @@ int boot_get_fdt(int flag, int argc, char * const argv[], /* * FDT blob */ - fdt_blob = buf; debug("* fdt: raw FDT blob\n"); printf("## Flattened Device Tree blob at %08lx\n", (long)fdt_addr); @@ -539,8 +393,8 @@ int boot_get_fdt(int flag, int argc, char * const argv[], goto error; } - printf(" Booting using the fdt blob at 0x%p\n", fdt_blob); - + printf(" Booting using the fdt blob at %#08lx\n", fdt_addr); + fdt_blob = map_sysmem(fdt_addr, 0); } else if (images->legacy_hdr_valid && image_check_type(&images->legacy_hdr_os_copy, IH_TYPE_MULTI)) { diff --git a/common/image-fit.c b/common/image-fit.c index 254feec..e28dd05 100644 --- a/common/image-fit.c +++ b/common/image-fit.c @@ -31,6 +31,9 @@ #include <time.h> #else #include <common.h> +#include <errno.h> +#include <asm/io.h> +DECLARE_GLOBAL_DATA_PTR; #endif /* !USE_HOSTCC*/ #include <bootstage.h> @@ -231,42 +234,45 @@ void fit_print_contents(const void *fit) * @fit: pointer to the FIT format image header * @noffset: offset of the hash node * @p: pointer to prefix string + * @type: Type of information to print ("hash" or "sign") * * fit_image_print_data() lists properies for the processed hash node * + * This function avoid using puts() since it prints a newline on the host + * but does not in U-Boot. + * * returns: * no returned results */ -static void fit_image_print_data(const void *fit, int noffset, const char *p) +static void fit_image_print_data(const void *fit, int noffset, const char *p, + const char *type) { - char *algo; + const char *keyname; uint8_t *value; int value_len; - int i, ret; - - /* - * Check subnode name, must be equal to "hash". - * Multiple hash nodes require unique unit node - * names, e.g. hash@1, hash@2, etc. - */ - if (strncmp(fit_get_name(fit, noffset, NULL), - FIT_HASH_NODENAME, - strlen(FIT_HASH_NODENAME)) != 0) - return; + char *algo; + int required; + int ret, i; - debug("%s Hash node: '%s'\n", p, + debug("%s %s node: '%s'\n", p, type, fit_get_name(fit, noffset, NULL)); - - printf("%s Hash algo: ", p); + printf("%s %s algo: ", p, type); if (fit_image_hash_get_algo(fit, noffset, &algo)) { printf("invalid/unsupported\n"); return; } - printf("%s\n", algo); + printf("%s", algo); + keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + required = fdt_getprop(fit, noffset, "required", NULL) != NULL; + if (keyname) + printf(":%s", keyname); + if (required) + printf(" (required)"); + printf("\n"); ret = fit_image_hash_get_value(fit, noffset, &value, &value_len); - printf("%s Hash value: ", p); + printf("%s %s value: ", p, type); if (ret) { printf("unavailable\n"); } else { @@ -275,7 +281,18 @@ static void fit_image_print_data(const void *fit, int noffset, const char *p) printf("\n"); } - debug("%s Hash len: %d\n", p, value_len); + debug("%s %s len: %d\n", p, type, value_len); + + /* Signatures have a time stamp */ + if (IMAGE_ENABLE_TIMESTAMP && keyname) { + time_t timestamp; + + printf("%s Timestamp: ", p); + if (fit_get_timestamp(fit, noffset, ×tamp)) + printf("unavailable\n"); + else + genimg_print_time(timestamp); + } } /** @@ -300,8 +317,12 @@ static void fit_image_print_verification_data(const void *fit, int noffset, * names, e.g. hash@1, hash@2, signature@1, signature@2, etc. */ name = fit_get_name(fit, noffset, NULL); - if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) - fit_image_print_data(fit, noffset, p); + if (!strncmp(name, FIT_HASH_NODENAME, strlen(FIT_HASH_NODENAME))) { + fit_image_print_data(fit, noffset, p, "Hash"); + } else if (!strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + fit_image_print_data(fit, noffset, p, "Sign"); + } } /** @@ -348,10 +369,13 @@ void fit_image_print(const void *fit, int image_noffset, const char *p) #ifndef USE_HOSTCC printf("%s Data Start: ", p); - if (ret) + if (ret) { printf("unavailable\n"); - else - printf("0x%08lx\n", (ulong)data); + } else { + void *vdata = (void *)data; + + printf("0x%08lx\n", (ulong)map_to_sysmem(vdata)); + } #endif printf("%s Data Size: ", p); @@ -938,13 +962,23 @@ int fit_image_verify(const void *fit, int image_noffset) { const void *data; size_t size; - int noffset; + int noffset = 0; char *err_msg = ""; + int verify_all = 1; + int ret; /* Get image data and data length */ if (fit_image_get_data(fit, image_noffset, &data, &size)) { err_msg = "Can't get image data/size"; - return 0; + goto error; + } + + /* Verify all required signatures */ + if (IMAGE_ENABLE_VERIFY && + fit_image_verify_required_sigs(fit, image_noffset, data, size, + gd_fdt_blob(), &verify_all)) { + err_msg = "Unable to verify required signature"; + goto error; } /* Process all hash subnodes of the component image node */ @@ -964,6 +998,15 @@ int fit_image_verify(const void *fit, int image_noffset) &err_msg)) goto error; puts("+ "); + } else if (IMAGE_ENABLE_VERIFY && verify_all && + !strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_image_check_sig(fit, noffset, data, + size, -1, &err_msg); + if (ret) + puts("- "); + else + puts("+ "); } } @@ -1349,63 +1392,6 @@ int fit_conf_get_prop_node(const void *fit, int noffset, } /** - * fit_conf_get_kernel_node - get kernel image node offset that corresponds to - * a given configuration - * @fit: pointer to the FIT format image header - * @noffset: configuration node offset - * - * fit_conf_get_kernel_node() retrives kernel image node unit name from - * configuration FIT_KERNEL_PROP property and translates it to the node - * offset. - * - * returns: - * image node offset when found (>=0) - * negative number on failure (FDT_ERR_* code) - */ -int fit_conf_get_kernel_node(const void *fit, int noffset) -{ - return fit_conf_get_prop_node(fit, noffset, FIT_KERNEL_PROP); -} - -/** - * fit_conf_get_ramdisk_node - get ramdisk image node offset that corresponds to - * a given configuration - * @fit: pointer to the FIT format image header - * @noffset: configuration node offset - * - * fit_conf_get_ramdisk_node() retrives ramdisk image node unit name from - * configuration FIT_KERNEL_PROP property and translates it to the node - * offset. - * - * returns: - * image node offset when found (>=0) - * negative number on failure (FDT_ERR_* code) - */ -int fit_conf_get_ramdisk_node(const void *fit, int noffset) -{ - return fit_conf_get_prop_node(fit, noffset, FIT_RAMDISK_PROP); -} - -/** - * fit_conf_get_fdt_node - get fdt image node offset that corresponds to - * a given configuration - * @fit: pointer to the FIT format image header - * @noffset: configuration node offset - * - * fit_conf_get_fdt_node() retrives fdt image node unit name from - * configuration FIT_KERNEL_PROP property and translates it to the node - * offset. - * - * returns: - * image node offset when found (>=0) - * negative number on failure (FDT_ERR_* code) - */ -int fit_conf_get_fdt_node(const void *fit, int noffset) -{ - return fit_conf_get_prop_node(fit, noffset, FIT_FDT_PROP); -} - -/** * fit_conf_print - prints out the FIT configuration details * @fit: pointer to the FIT format image header * @noffset: offset of the configuration node @@ -1448,22 +1434,7 @@ void fit_conf_print(const void *fit, int noffset, const char *p) printf("%s FDT: %s\n", p, uname); } -/** - * fit_check_ramdisk - verify FIT format ramdisk subimage - * @fit_hdr: pointer to the FIT ramdisk header - * @rd_noffset: ramdisk subimage node offset within FIT image - * @arch: requested ramdisk image architecture type - * @verify: data CRC verification flag - * - * fit_check_ramdisk() verifies integrity of the ramdisk subimage and from - * specified FIT image. - * - * returns: - * 1, on success - * 0, on failure - */ -int fit_check_ramdisk(const void *fit, int rd_noffset, uint8_t arch, - int verify) +int fit_image_select(const void *fit, int rd_noffset, int verify) { fit_image_print(fit, rd_noffset, " "); @@ -1471,22 +1442,226 @@ int fit_check_ramdisk(const void *fit, int rd_noffset, uint8_t arch, puts(" Verifying Hash Integrity ... "); if (!fit_image_verify(fit, rd_noffset)) { puts("Bad Data Hash\n"); - bootstage_error(BOOTSTAGE_ID_FIT_RD_HASH); - return 0; + return -EACCES; } puts("OK\n"); } - bootstage_mark(BOOTSTAGE_ID_FIT_RD_CHECK_ALL); - if (!fit_image_check_os(fit, rd_noffset, IH_OS_LINUX) || - !fit_image_check_arch(fit, rd_noffset, arch) || - !fit_image_check_type(fit, rd_noffset, IH_TYPE_RAMDISK)) { - printf("No Linux %s Ramdisk Image\n", - genimg_get_arch_name(arch)); - bootstage_error(BOOTSTAGE_ID_FIT_RD_CHECK_ALL); - return 0; + return 0; +} + +int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name, + ulong addr) +{ + int cfg_noffset; + void *fit_hdr; + int noffset; + + debug("* %s: using config '%s' from image at 0x%08lx\n", + prop_name, images->fit_uname_cfg, addr); + + /* Check whether configuration has this property defined */ + fit_hdr = map_sysmem(addr, 0); + cfg_noffset = fit_conf_get_node(fit_hdr, images->fit_uname_cfg); + if (cfg_noffset < 0) { + debug("* %s: no such config\n", prop_name); + return -ENOENT; } - bootstage_mark(BOOTSTAGE_ID_FIT_RD_CHECK_ALL_OK); - return 1; + noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name); + if (noffset < 0) { + debug("* %s: no '%s' in config\n", prop_name, prop_name); + return -ENOLINK; + } + + return noffset; +} + +int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr, + const char **fit_unamep, const char **fit_uname_configp, + int arch, int image_type, int bootstage_id, + enum fit_load_op load_op, ulong *datap, ulong *lenp) +{ + int cfg_noffset, noffset; + const char *fit_uname; + const char *fit_uname_config; + const void *fit; + const void *buf; + size_t size; + int type_ok, os_ok; + ulong load, data, len; + int ret; + + fit = map_sysmem(addr, 0); + fit_uname = fit_unamep ? *fit_unamep : NULL; + fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL; + printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr); + + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT); + if (!fit_check_format(fit)) { + printf("Bad FIT %s image format!\n", prop_name); + bootstage_error(bootstage_id + BOOTSTAGE_SUB_FORMAT); + return -ENOEXEC; + } + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT_OK); + if (fit_uname) { + /* get ramdisk component image node offset */ + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_UNIT_NAME); + noffset = fit_image_get_node(fit, fit_uname); + } else { + /* + * no image node unit name, try to get config + * node first. If config unit node name is NULL + * fit_conf_get_node() will try to find default config node + */ + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_NO_UNIT_NAME); + if (IMAGE_ENABLE_BEST_MATCH && !fit_uname_config) { + cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob()); + } else { + cfg_noffset = fit_conf_get_node(fit, + fit_uname_config); + } + if (cfg_noffset < 0) { + puts("Could not find configuration node\n"); + bootstage_error(bootstage_id + + BOOTSTAGE_SUB_NO_UNIT_NAME); + return -ENOENT; + } + fit_uname_config = fdt_get_name(fit, cfg_noffset, NULL); + printf(" Using '%s' configuration\n", fit_uname_config); + if (image_type == IH_TYPE_KERNEL) { + /* Remember (and possibly verify) this config */ + images->fit_uname_cfg = fit_uname_config; + if (IMAGE_ENABLE_VERIFY && images->verify) { + puts(" Verifying Hash Integrity ... "); + if (!fit_config_verify(fit, cfg_noffset)) { + puts("Bad Data Hash\n"); + bootstage_error(bootstage_id + + BOOTSTAGE_SUB_HASH); + return -EACCES; + } + puts("OK\n"); + } + bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); + } + + noffset = fit_conf_get_prop_node(fit, cfg_noffset, + prop_name); + fit_uname = fit_get_name(fit, noffset, NULL); + } + if (noffset < 0) { + puts("Could not find subimage node\n"); + bootstage_error(bootstage_id + BOOTSTAGE_SUB_SUBNODE); + return -ENOENT; + } + + printf(" Trying '%s' %s subimage\n", fit_uname, prop_name); + + ret = fit_image_select(fit, noffset, images->verify); + if (ret) { + bootstage_error(bootstage_id + BOOTSTAGE_SUB_HASH); + return ret; + } + + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH); + if (!fit_image_check_target_arch(fit, noffset)) { + puts("Unsupported Architecture\n"); + bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ARCH); + return -ENOEXEC; + } + + if (image_type == IH_TYPE_FLATDT && + !fit_image_check_comp(fit, noffset, IH_COMP_NONE)) { + puts("FDT image is compressed"); + return -EPROTONOSUPPORT; + } + + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL); + type_ok = fit_image_check_type(fit, noffset, image_type) || + (image_type == IH_TYPE_KERNEL && + fit_image_check_type(fit, noffset, + IH_TYPE_KERNEL_NOLOAD)); + os_ok = image_type == IH_TYPE_FLATDT || + fit_image_check_os(fit, noffset, IH_OS_LINUX); + if (!type_ok || !os_ok) { + printf("No Linux %s %s Image\n", genimg_get_arch_name(arch), + genimg_get_type_name(image_type)); + bootstage_error(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL); + return -EIO; + } + + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL_OK); + + /* get image data address and length */ + if (fit_image_get_data(fit, noffset, &buf, &size)) { + printf("Could not find %s subimage data!\n", prop_name); + bootstage_error(bootstage_id + BOOTSTAGE_SUB_GET_DATA); + return -ENOENT; + } + len = (ulong)size; + + /* verify that image data is a proper FDT blob */ + if (image_type == IH_TYPE_FLATDT && fdt_check_header((char *)buf)) { + puts("Subimage data is not a FDT"); + return -ENOEXEC; + } + + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_GET_DATA_OK); + + /* + * Work-around for eldk-4.2 which gives this warning if we try to + * case in the unmap_sysmem() call: + * warning: initialization discards qualifiers from pointer target type + */ + { + void *vbuf = (void *)buf; + + data = map_to_sysmem(vbuf); + } + + if (load_op == FIT_LOAD_IGNORED) { + /* Don't load */ + } else if (fit_image_get_load(fit, noffset, &load)) { + if (load_op == FIT_LOAD_REQUIRED) { + printf("Can't get %s subimage load address!\n", + prop_name); + bootstage_error(bootstage_id + BOOTSTAGE_SUB_LOAD); + return -EBADF; + } + } else { + ulong image_start, image_end; + ulong load_end; + void *dst; + + /* + * move image data to the load address, + * make sure we don't overwrite initial image + */ + image_start = addr; + image_end = addr + fit_get_size(fit); + + load_end = load + len; + if (image_type != IH_TYPE_KERNEL && + load < image_end && load_end > image_start) { + printf("Error: %s overwritten\n", prop_name); + return -EXDEV; + } + + printf(" Loading %s from 0x%08lx to 0x%08lx\n", + prop_name, data, load); + + dst = map_sysmem(load, len); + memmove(dst, buf, len); + data = load; + } + bootstage_mark(bootstage_id + BOOTSTAGE_SUB_LOAD); + + *datap = data; + *lenp = len; + if (fit_unamep) + *fit_unamep = (char *)fit_uname; + if (fit_uname_configp) + *fit_uname_configp = (char *)fit_uname_config; + + return noffset; } diff --git a/common/image-sig.c b/common/image-sig.c new file mode 100644 index 0000000..5d907cf --- /dev/null +++ b/common/image-sig.c @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 USE_HOSTCC +#include "mkimage.h" +#include <time.h> +#else +#include <common.h> +#include <malloc.h> +DECLARE_GLOBAL_DATA_PTR; +#endif /* !USE_HOSTCC*/ +#include <image.h> +#include <rsa.h> + +#define IMAGE_MAX_HASHED_NODES 100 + +struct image_sig_algo image_sig_algos[] = { + { + "sha1,rsa2048", + rsa_sign, + rsa_add_verify_data, + rsa_verify, + } +}; + +struct image_sig_algo *image_get_sig_algo(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(image_sig_algos); i++) { + if (!strcmp(image_sig_algos[i].name, name)) + return &image_sig_algos[i]; + } + + return NULL; +} + +/** + * fit_region_make_list() - Make a list of image regions + * + * Given a list of fdt_regions, create a list of image_regions. This is a + * simple conversion routine since the FDT and image code use different + * structures. + * + * @fit: FIT image + * @fdt_regions: Pointer to FDT regions + * @count: Number of FDT regions + * @region: Pointer to image regions, which must hold @count records. If + * region is NULL, then (except for an SPL build) the array will be + * allocated. + * @return: Pointer to image regions + */ +struct image_region *fit_region_make_list(const void *fit, + struct fdt_region *fdt_regions, int count, + struct image_region *region) +{ + int i; + + debug("Hash regions:\n"); + debug("%10s %10s\n", "Offset", "Size"); + + /* + * Use malloc() except in SPL (to save code size). In SPL the caller + * must allocate the array. + */ +#ifndef CONFIG_SPL_BUILD + if (!region) + region = calloc(sizeof(*region), count); +#endif + if (!region) + return NULL; + for (i = 0; i < count; i++) { + debug("%10x %10x\n", fdt_regions[i].offset, + fdt_regions[i].size); + region[i].data = fit + fdt_regions[i].offset; + region[i].size = fdt_regions[i].size; + } + + return region; +} + +static int fit_image_setup_verify(struct image_sign_info *info, + const void *fit, int noffset, int required_keynode, + char **err_msgp) +{ + char *algo_name; + + if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { + *err_msgp = "Can't get hash algo property"; + return -1; + } + memset(info, '\0', sizeof(*info)); + info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info->fit = (void *)fit; + info->node_offset = noffset; + info->algo = image_get_sig_algo(algo_name); + info->fdt_blob = gd_fdt_blob(); + info->required_keynode = required_keynode; + printf("%s:%s", algo_name, info->keyname); + + if (!info->algo) { + *err_msgp = "Unknown signature algorithm"; + return -1; + } + + return 0; +} + +int fit_image_check_sig(const void *fit, int noffset, const void *data, + size_t size, int required_keynode, char **err_msgp) +{ + struct image_sign_info info; + struct image_region region; + uint8_t *fit_value; + int fit_value_len; + + *err_msgp = NULL; + if (fit_image_setup_verify(&info, fit, noffset, required_keynode, + err_msgp)) + return -1; + + if (fit_image_hash_get_value(fit, noffset, &fit_value, + &fit_value_len)) { + *err_msgp = "Can't get hash value property"; + return -1; + } + + region.data = data; + region.size = size; + + if (info.algo->verify(&info, ®ion, 1, fit_value, fit_value_len)) { + *err_msgp = "Verification failed"; + return -1; + } + + return 0; +} + +static int fit_image_verify_sig(const void *fit, int image_noffset, + const char *data, size_t size, const void *sig_blob, + int sig_offset) +{ + int noffset; + char *err_msg = ""; + int verified = 0; + int ret; + + /* Process all hash subnodes of the component image node */ + for (noffset = fdt_first_subnode(fit, image_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + const char *name = fit_get_name(fit, noffset, NULL); + + if (!strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_image_check_sig(fit, noffset, data, + size, -1, &err_msg); + if (ret) { + puts("- "); + } else { + puts("+ "); + verified = 1; + break; + } + } + } + + if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) { + err_msg = "Corrupted or truncated tree"; + goto error; + } + + return verified ? 0 : -EPERM; + +error: + printf(" error!\n%s for '%s' hash node in '%s' image node\n", + err_msg, fit_get_name(fit, noffset, NULL), + fit_get_name(fit, image_noffset, NULL)); + return -1; +} + +int fit_image_verify_required_sigs(const void *fit, int image_noffset, + const char *data, size_t size, const void *sig_blob, + int *no_sigsp) +{ + int verify_count = 0; + int noffset; + int sig_node; + + /* Work out what we need to verify */ + *no_sigsp = 1; + sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); + if (sig_node < 0) { + debug("%s: No signature node found: %s\n", __func__, + fdt_strerror(sig_node)); + return 0; + } + + for (noffset = fdt_first_subnode(sig_blob, sig_node); + noffset >= 0; + noffset = fdt_next_subnode(sig_blob, noffset)) { + const char *required; + int ret; + + required = fdt_getprop(sig_blob, noffset, "required", NULL); + if (!required || strcmp(required, "image")) + continue; + ret = fit_image_verify_sig(fit, image_noffset, data, size, + sig_blob, noffset); + if (ret) { + printf("Failed to verify required signature '%s'\n", + fit_get_name(sig_blob, noffset, NULL)); + return ret; + } + verify_count++; + } + + if (verify_count) + *no_sigsp = 0; + + return 0; +} + +int fit_config_check_sig(const void *fit, int noffset, int required_keynode, + char **err_msgp) +{ + char * const exc_prop[] = {"data"}; + const char *prop, *end, *name; + struct image_sign_info info; + const uint32_t *strings; + uint8_t *fit_value; + int fit_value_len; + int max_regions; + int i, prop_len; + char path[200]; + int count; + + debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(), + fit_get_name(fit, noffset, NULL), + fit_get_name(gd_fdt_blob(), required_keynode, NULL)); + *err_msgp = NULL; + if (fit_image_setup_verify(&info, fit, noffset, required_keynode, + err_msgp)) + return -1; + + if (fit_image_hash_get_value(fit, noffset, &fit_value, + &fit_value_len)) { + *err_msgp = "Can't get hash value property"; + return -1; + } + + /* Count the number of strings in the property */ + prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len); + end = prop ? prop + prop_len : prop; + for (name = prop, count = 0; name < end; name++) + if (!*name) + count++; + if (!count) { + *err_msgp = "Can't get hashed-nodes property"; + return -1; + } + + /* Add a sanity check here since we are using the stack */ + if (count > IMAGE_MAX_HASHED_NODES) { + *err_msgp = "Number of hashed nodes exceeds maximum"; + return -1; + } + + /* Create a list of node names from those strings */ + char *node_inc[count]; + + debug("Hash nodes (%d):\n", count); + for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) { + debug(" '%s'\n", name); + node_inc[i] = (char *)name; + } + + /* + * Each node can generate one region for each sub-node. Allow for + * 7 sub-nodes (hash@1, signature@1, etc.) and some extra. + */ + max_regions = 20 + count * 7; + struct fdt_region fdt_regions[max_regions]; + + /* Get a list of regions to hash */ + count = fdt_find_regions(fit, node_inc, count, + exc_prop, ARRAY_SIZE(exc_prop), + fdt_regions, max_regions - 1, + path, sizeof(path), 0); + if (count < 0) { + *err_msgp = "Failed to hash configuration"; + return -1; + } + if (count == 0) { + *err_msgp = "No data to hash"; + return -1; + } + if (count >= max_regions - 1) { + *err_msgp = "Too many hash regions"; + return -1; + } + + /* Add the strings */ + strings = fdt_getprop(fit, noffset, "hashed-strings", NULL); + if (strings) { + fdt_regions[count].offset = fdt_off_dt_strings(fit) + + fdt32_to_cpu(strings[0]); + fdt_regions[count].size = fdt32_to_cpu(strings[1]); + count++; + } + + /* Allocate the region list on the stack */ + struct image_region region[count]; + + fit_region_make_list(fit, fdt_regions, count, region); + if (info.algo->verify(&info, region, count, fit_value, + fit_value_len)) { + *err_msgp = "Verification failed"; + return -1; + } + + return 0; +} + +static int fit_config_verify_sig(const void *fit, int conf_noffset, + const void *sig_blob, int sig_offset) +{ + int noffset; + char *err_msg = ""; + int verified = 0; + int ret; + + /* Process all hash subnodes of the component conf node */ + for (noffset = fdt_first_subnode(fit, conf_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + const char *name = fit_get_name(fit, noffset, NULL); + + if (!strncmp(name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_config_check_sig(fit, noffset, sig_offset, + &err_msg); + if (ret) { + puts("- "); + } else { + puts("+ "); + verified = 1; + break; + } + } + } + + if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) { + err_msg = "Corrupted or truncated tree"; + goto error; + } + + return verified ? 0 : -EPERM; + +error: + printf(" error!\n%s for '%s' hash node in '%s' config node\n", + err_msg, fit_get_name(fit, noffset, NULL), + fit_get_name(fit, conf_noffset, NULL)); + return -1; +} + +int fit_config_verify_required_sigs(const void *fit, int conf_noffset, + const void *sig_blob) +{ + int noffset; + int sig_node; + + /* Work out what we need to verify */ + sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME); + if (sig_node < 0) { + debug("%s: No signature node found: %s\n", __func__, + fdt_strerror(sig_node)); + return 0; + } + + for (noffset = fdt_first_subnode(sig_blob, sig_node); + noffset >= 0; + noffset = fdt_next_subnode(sig_blob, noffset)) { + const char *required; + int ret; + + required = fdt_getprop(sig_blob, noffset, "required", NULL); + if (!required || strcmp(required, "conf")) + continue; + ret = fit_config_verify_sig(fit, conf_noffset, sig_blob, + noffset); + if (ret) { + printf("Failed to verify required signature '%s'\n", + fit_get_name(sig_blob, noffset, NULL)); + return ret; + } + } + + return 0; +} + +int fit_config_verify(const void *fit, int conf_noffset) +{ + return !fit_config_verify_required_sigs(fit, conf_noffset, + gd_fdt_blob()); +} diff --git a/common/image.c b/common/image.c index e91c89e..327006e 100644 --- a/common/image.c +++ b/common/image.c @@ -51,6 +51,7 @@ #include <u-boot/md5.h> #include <sha1.h> +#include <asm/errno.h> #include <asm/io.h> #ifdef CONFIG_CMD_BDI @@ -810,29 +811,28 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images, char *end; #endif #if defined(CONFIG_FIT) - void *fit_hdr; - const char *fit_uname_config = NULL; + const char *fit_uname_config = images->fit_uname_cfg; const char *fit_uname_ramdisk = NULL; ulong default_addr; int rd_noffset; - int cfg_noffset; - const void *data; - size_t size; #endif + const char *select = NULL; *rd_start = 0; *rd_end = 0; + if (argc >= 2) + select = argv[1]; /* * Look for a '-' which indicates to ignore the * ramdisk argument */ - if ((argc >= 3) && (strcmp(argv[2], "-") == 0)) { + if (select && strcmp(select, "-") == 0) { debug("## Skipping init Ramdisk\n"); rd_len = rd_data = 0; - } else if (argc >= 3 || genimg_has_config(images)) { + } else if (select || genimg_has_config(images)) { #if defined(CONFIG_FIT) - if (argc >= 3) { + if (select) { /* * If the init ramdisk comes from the FIT image and * the FIT image address is omitted in the command @@ -844,12 +844,12 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images, else default_addr = load_addr; - if (fit_parse_conf(argv[2], default_addr, - &rd_addr, &fit_uname_config)) { + if (fit_parse_conf(select, default_addr, + &rd_addr, &fit_uname_config)) { debug("* ramdisk: config '%s' from image at " "0x%08lx\n", fit_uname_config, rd_addr); - } else if (fit_parse_subimage(argv[2], default_addr, + } else if (fit_parse_subimage(select, default_addr, &rd_addr, &fit_uname_ramdisk)) { debug("* ramdisk: subimage '%s' from image at " "0x%08lx\n", @@ -857,7 +857,7 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images, } else #endif { - rd_addr = simple_strtoul(argv[2], NULL, 16); + rd_addr = simple_strtoul(select, NULL, 16); debug("* ramdisk: cmdline image address = " "0x%08lx\n", rd_addr); @@ -865,32 +865,16 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images, #if defined(CONFIG_FIT) } else { /* use FIT configuration provided in first bootm - * command argument + * command argument. If the property is not defined, + * quit silently. */ rd_addr = map_to_sysmem(images->fit_hdr_os); - fit_uname_config = images->fit_uname_cfg; - debug("* ramdisk: using config '%s' from image " - "at 0x%08lx\n", - fit_uname_config, rd_addr); - - /* - * Check whether configuration has ramdisk defined, - * if not, don't try to use it, quit silently. - */ - fit_hdr = images->fit_hdr_os; - cfg_noffset = fit_conf_get_node(fit_hdr, - fit_uname_config); - if (cfg_noffset < 0) { - debug("* ramdisk: no such config\n"); - return 1; - } - - rd_noffset = fit_conf_get_ramdisk_node(fit_hdr, - cfg_noffset); - if (rd_noffset < 0) { - debug("* ramdisk: no ramdisk in config\n"); + rd_noffset = fit_get_node_from_config(images, + FIT_RAMDISK_PROP, rd_addr); + if (rd_noffset == -ENOLINK) return 0; - } + else if (rd_noffset < 0) + return 1; } #endif @@ -921,94 +905,26 @@ int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images, break; #if defined(CONFIG_FIT) case IMAGE_FORMAT_FIT: - fit_hdr = buf; - printf("## Loading init Ramdisk from FIT " - "Image at %08lx ...\n", rd_addr); - - bootstage_mark(BOOTSTAGE_ID_FIT_RD_FORMAT); - if (!fit_check_format(fit_hdr)) { - puts("Bad FIT ramdisk image format!\n"); - bootstage_error( - BOOTSTAGE_ID_FIT_RD_FORMAT); + rd_noffset = fit_image_load(images, FIT_RAMDISK_PROP, + rd_addr, &fit_uname_ramdisk, + &fit_uname_config, arch, + IH_TYPE_RAMDISK, + BOOTSTAGE_ID_FIT_RD_START, + FIT_LOAD_REQUIRED, &rd_data, &rd_len); + if (rd_noffset < 0) return 1; - } - bootstage_mark(BOOTSTAGE_ID_FIT_RD_FORMAT_OK); - - if (!fit_uname_ramdisk) { - /* - * no ramdisk image node unit name, try to get config - * node first. If config unit node name is NULL - * fit_conf_get_node() will try to find default config node - */ - bootstage_mark( - BOOTSTAGE_ID_FIT_RD_NO_UNIT_NAME); - cfg_noffset = fit_conf_get_node(fit_hdr, - fit_uname_config); - if (cfg_noffset < 0) { - puts("Could not find configuration " - "node\n"); - bootstage_error( - BOOTSTAGE_ID_FIT_RD_NO_UNIT_NAME); - return 1; - } - fit_uname_config = fdt_get_name(fit_hdr, - cfg_noffset, NULL); - printf(" Using '%s' configuration\n", - fit_uname_config); - - rd_noffset = fit_conf_get_ramdisk_node(fit_hdr, - cfg_noffset); - fit_uname_ramdisk = fit_get_name(fit_hdr, - rd_noffset, NULL); - } else { - /* get ramdisk component image node offset */ - bootstage_mark( - BOOTSTAGE_ID_FIT_RD_UNIT_NAME); - rd_noffset = fit_image_get_node(fit_hdr, - fit_uname_ramdisk); - } - if (rd_noffset < 0) { - puts("Could not find subimage node\n"); - bootstage_error(BOOTSTAGE_ID_FIT_RD_SUBNODE); - return 1; - } - - printf(" Trying '%s' ramdisk subimage\n", - fit_uname_ramdisk); - - bootstage_mark(BOOTSTAGE_ID_FIT_RD_CHECK); - if (!fit_check_ramdisk(fit_hdr, rd_noffset, arch, - images->verify)) - return 1; - - /* get ramdisk image data address and length */ - if (fit_image_get_data(fit_hdr, rd_noffset, &data, - &size)) { - puts("Could not find ramdisk subimage data!\n"); - bootstage_error(BOOTSTAGE_ID_FIT_RD_GET_DATA); - return 1; - } - bootstage_mark(BOOTSTAGE_ID_FIT_RD_GET_DATA_OK); - - rd_data = (ulong)data; - rd_len = size; - - if (fit_image_get_load(fit_hdr, rd_noffset, &rd_load)) { - puts("Can't get ramdisk subimage load " - "address!\n"); - bootstage_error(BOOTSTAGE_ID_FIT_RD_LOAD); - return 1; - } - bootstage_mark(BOOTSTAGE_ID_FIT_RD_LOAD); - images->fit_hdr_rd = fit_hdr; + images->fit_hdr_rd = map_sysmem(rd_addr, 0); images->fit_uname_rd = fit_uname_ramdisk; images->fit_noffset_rd = rd_noffset; break; #endif default: #ifdef CONFIG_SUPPORT_RAW_INITRD - if (argc >= 3 && (end = strchr(argv[2], ':'))) { + end = NULL; + if (select) + end = strchr(select, ':'); + if (end) { rd_len = simple_strtoul(++end, NULL, 16); rd_data = rd_addr; } else diff --git a/common/lcd.c b/common/lcd.c index edae835..50ea4d6 100644 --- a/common/lcd.c +++ b/common/lcd.c @@ -43,6 +43,8 @@ #include <lcd.h> #include <watchdog.h> +#include <splash.h> + #if defined(CONFIG_CPU_PXA25X) || defined(CONFIG_CPU_PXA27X) || \ defined(CONFIG_CPU_MONAHANS) #define CONFIG_CPU_PXA @@ -57,6 +59,10 @@ #include <atmel_lcdc.h> #endif +#if defined(CONFIG_LCD_DT_SIMPLEFB) +#include <libfdt.h> +#endif + /************************************************************************/ /* ** FONT DATA */ /************************************************************************/ @@ -1068,18 +1074,6 @@ int lcd_display_bitmap(ulong bmp_image, int x, int y) } #endif -#ifdef CONFIG_SPLASH_SCREEN_PREPARE -static inline int splash_screen_prepare(void) -{ - return board_splash_screen_prepare(); -} -#else -static inline int splash_screen_prepare(void) -{ - return 0; -} -#endif - static void *lcd_logo(void) { #ifdef CONFIG_SPLASH_SCREEN @@ -1092,26 +1086,11 @@ static void *lcd_logo(void) do_splash = 0; if (splash_screen_prepare()) - return (void *)gd->fb_base; + return (void *)lcd_base; addr = simple_strtoul (s, NULL, 16); -#ifdef CONFIG_SPLASH_SCREEN_ALIGN - s = getenv("splashpos"); - if (s != NULL) { - if (s[0] == 'm') - x = BMP_ALIGN_CENTER; - else - x = simple_strtol(s, NULL, 0); - - s = strchr(s + 1, ','); - if (s != NULL) { - if (s[1] == 'm') - y = BMP_ALIGN_CENTER; - else - y = simple_strtol (s + 1, NULL, 0); - } - } -#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ + + splash_get_pos(&x, &y); if (bmp_display(addr, x, y) == 0) return (void *)lcd_base; @@ -1182,3 +1161,86 @@ int lcd_get_screen_columns(void) { return CONSOLE_COLS; } + +#if defined(CONFIG_LCD_DT_SIMPLEFB) +static int lcd_dt_simplefb_configure_node(void *blob, int off) +{ + u32 stride; + fdt32_t cells[2]; + int ret; + static const char format[] = +#if LCD_BPP == LCD_COLOR16 + "r5g6b5"; +#else + ""; +#endif + + if (!format[0]) + return -1; + + stride = panel_info.vl_col * 2; + + cells[0] = cpu_to_fdt32(gd->fb_base); + cells[1] = cpu_to_fdt32(stride * panel_info.vl_row); + ret = fdt_setprop(blob, off, "reg", cells, sizeof(cells[0]) * 2); + if (ret < 0) + return -1; + + cells[0] = cpu_to_fdt32(panel_info.vl_col); + ret = fdt_setprop(blob, off, "width", cells, sizeof(cells[0])); + if (ret < 0) + return -1; + + cells[0] = cpu_to_fdt32(panel_info.vl_row); + ret = fdt_setprop(blob, off, "height", cells, sizeof(cells[0])); + if (ret < 0) + return -1; + + cells[0] = cpu_to_fdt32(stride); + ret = fdt_setprop(blob, off, "stride", cells, sizeof(cells[0])); + if (ret < 0) + return -1; + + ret = fdt_setprop(blob, off, "format", format, strlen(format) + 1); + if (ret < 0) + return -1; + + ret = fdt_delprop(blob, off, "status"); + if (ret < 0) + return -1; + + return 0; +} + +int lcd_dt_simplefb_add_node(void *blob) +{ + static const char compat[] = "simple-framebuffer"; + static const char disabled[] = "disabled"; + int off, ret; + + off = fdt_add_subnode(blob, 0, "framebuffer"); + if (off < 0) + return -1; + + ret = fdt_setprop(blob, off, "status", disabled, sizeof(disabled)); + if (ret < 0) + return -1; + + ret = fdt_setprop(blob, off, "compatible", compat, sizeof(compat)); + if (ret < 0) + return -1; + + return lcd_dt_simplefb_configure_node(blob, off); +} + +int lcd_dt_simplefb_enable_existing_node(void *blob) +{ + int off; + + off = fdt_node_offset_by_compatible(blob, -1, "simple-framebuffer"); + if (off < 0) + return -1; + + return lcd_dt_simplefb_configure_node(blob, off); +} +#endif diff --git a/common/main.c b/common/main.c index 953ef29..56da214 100644 --- a/common/main.c +++ b/common/main.c @@ -28,26 +28,15 @@ /* #define DEBUG */ #include <common.h> -#include <watchdog.h> #include <command.h> #include <fdtdec.h> -#include <malloc.h> -#include <version.h> -#ifdef CONFIG_MODEM_SUPPORT -#include <malloc.h> /* for free() prototype */ -#endif - -#ifdef CONFIG_SYS_HUSH_PARSER #include <hush.h> -#endif - -#ifdef CONFIG_OF_CONTROL -#include <fdtdec.h> -#endif - +#include <malloc.h> +#include <menu.h> #include <post.h> +#include <version.h> +#include <watchdog.h> #include <linux/ctype.h> -#include <menu.h> DECLARE_GLOBAL_DATA_PTR; @@ -57,13 +46,18 @@ DECLARE_GLOBAL_DATA_PTR; void inline __show_boot_progress (int val) {} void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress"))); -#if defined(CONFIG_UPDATE_TFTP) -int update_tftp (ulong addr); -#endif /* CONFIG_UPDATE_TFTP */ - #define MAX_DELAY_STOP_STR 32 -#undef DEBUG_PARSER +#define DEBUG_PARSER 0 /* set to 1 to debug */ + +#define debug_parser(fmt, args...) \ + debug_cond(DEBUG_PARSER, fmt, ##args) + +#ifndef DEBUG_BOOTKEYS +#define DEBUG_BOOTKEYS 0 +#endif +#define debug_bootkeys(fmt, args...) \ + debug_cond(DEBUG_BOOTKEYS, fmt, ##args) char console_buffer[CONFIG_SYS_CBSIZE + 1]; /* console I/O buffer */ @@ -93,10 +87,7 @@ extern void mdm_init(void); /* defined in board.c */ */ #if defined(CONFIG_BOOTDELAY) # if defined(CONFIG_AUTOBOOT_KEYED) -#ifndef CONFIG_MENU -static inline -#endif -int abortboot(int bootdelay) +static int abortboot_keyed(int bootdelay) { int abort = 0; uint64_t etime = endtick(bootdelay); @@ -152,11 +143,9 @@ int abortboot(int bootdelay) presskey_max = presskey_max > delaykey[i].len ? presskey_max : delaykey[i].len; -# if DEBUG_BOOTKEYS - printf("%s key:<%s>\n", - delaykey[i].retry ? "delay" : "stop", - delaykey[i].str ? delaykey[i].str : "NULL"); -# endif + debug_bootkeys("%s key:<%s>\n", + delaykey[i].retry ? "delay" : "stop", + delaykey[i].str ? delaykey[i].str : "NULL"); } /* In order to keep up with incoming data, check timeout only @@ -181,10 +170,9 @@ int abortboot(int bootdelay) memcmp (presskey + presskey_len - delaykey[i].len, delaykey[i].str, delaykey[i].len) == 0) { -# if DEBUG_BOOTKEYS - printf("got %skey\n", - delaykey[i].retry ? "delay" : "stop"); -# endif + debug_bootkeys("got %skey\n", + delaykey[i].retry ? "delay" : + "stop"); # ifdef CONFIG_BOOT_RETRY_TIME /* don't retry auto boot */ @@ -196,10 +184,8 @@ int abortboot(int bootdelay) } } while (!abort && get_ticks() <= etime); -# if DEBUG_BOOTKEYS if (!abort) - puts("key timeout\n"); -# endif + debug_bootkeys("key timeout\n"); #ifdef CONFIG_SILENT_CONSOLE if (abort) @@ -215,10 +201,7 @@ int abortboot(int bootdelay) static int menukey = 0; #endif -#ifndef CONFIG_MENU -static inline -#endif -int abortboot(int bootdelay) +static int abortboot_normal(int bootdelay) { int abort = 0; unsigned long ts; @@ -275,6 +258,15 @@ int abortboot(int bootdelay) return abort; } # endif /* CONFIG_AUTOBOOT_KEYED */ + +static int abortboot(int bootdelay) +{ +#ifdef CONFIG_AUTOBOOT_KEYED + return abortboot_keyed(bootdelay); +#else + return abortboot_normal(bootdelay); +#endif +} #endif /* CONFIG_BOOTDELAY */ /* @@ -342,93 +334,35 @@ static void process_fdt_options(const void *blob) } #endif /* CONFIG_OF_CONTROL */ - -/****************************************************************************/ - -void main_loop (void) +#ifdef CONFIG_BOOTDELAY +static void process_boot_delay(void) { -#ifndef CONFIG_SYS_HUSH_PARSER - static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; - int len; - int rc = 1; - int flag; -#endif -#if defined(CONFIG_BOOTDELAY) && defined(CONFIG_OF_CONTROL) +#ifdef CONFIG_OF_CONTROL char *env; #endif -#if defined(CONFIG_BOOTDELAY) char *s; int bootdelay; -#endif -#ifdef CONFIG_PREBOOT - char *p; -#endif #ifdef CONFIG_BOOTCOUNT_LIMIT unsigned long bootcount = 0; unsigned long bootlimit = 0; - char *bcs; - char bcs_set[16]; #endif /* CONFIG_BOOTCOUNT_LIMIT */ - bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop"); - #ifdef CONFIG_BOOTCOUNT_LIMIT bootcount = bootcount_load(); bootcount++; bootcount_store (bootcount); - sprintf (bcs_set, "%lu", bootcount); - setenv ("bootcount", bcs_set); - bcs = getenv ("bootlimit"); - bootlimit = bcs ? simple_strtoul (bcs, NULL, 10) : 0; + setenv_ulong("bootcount", bootcount); + bootlimit = getenv_ulong("bootlimit", 10, 0); #endif /* CONFIG_BOOTCOUNT_LIMIT */ -#ifdef CONFIG_MODEM_SUPPORT - debug ("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init); - if (do_mdm_init) { - char *str = strdup(getenv("mdm_cmd")); - setenv ("preboot", str); /* set or delete definition */ - if (str != NULL) - free (str); - mdm_init(); /* wait for modem connection */ - } -#endif /* CONFIG_MODEM_SUPPORT */ - -#ifdef CONFIG_VERSION_VARIABLE - { - setenv ("ver", version_string); /* set version variable */ - } -#endif /* CONFIG_VERSION_VARIABLE */ - -#ifdef CONFIG_SYS_HUSH_PARSER - u_boot_hush_start (); -#endif - -#if defined(CONFIG_HUSH_INIT_VAR) - hush_init_var (); -#endif - -#ifdef CONFIG_PREBOOT - if ((p = getenv ("preboot")) != NULL) { -# ifdef CONFIG_AUTOBOOT_KEYED - int prev = disable_ctrlc(1); /* disable Control C checking */ -# endif - - run_command_list(p, -1, 0); - -# ifdef CONFIG_AUTOBOOT_KEYED - disable_ctrlc(prev); /* restore Control C checking */ -# endif - } -#endif /* CONFIG_PREBOOT */ - -#if defined(CONFIG_UPDATE_TFTP) - update_tftp (0UL); -#endif /* CONFIG_UPDATE_TFTP */ - -#if defined(CONFIG_BOOTDELAY) s = getenv ("bootdelay"); bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY; +#ifdef CONFIG_OF_CONTROL + bootdelay = fdtdec_get_config_int(gd->fdt_blob, "bootdelay", + bootdelay); +#endif + debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay); #if defined(CONFIG_MENU_SHOW) @@ -474,26 +408,88 @@ void main_loop (void) debug ("### main_loop: bootcmd=\"%s\"\n", s ? s : "<UNDEFINED>"); if (bootdelay != -1 && s && !abortboot(bootdelay)) { -# ifdef CONFIG_AUTOBOOT_KEYED +#ifdef CONFIG_AUTOBOOT_KEYED int prev = disable_ctrlc(1); /* disable Control C checking */ -# endif +#endif run_command_list(s, -1, 0); -# ifdef CONFIG_AUTOBOOT_KEYED +#ifdef CONFIG_AUTOBOOT_KEYED disable_ctrlc(prev); /* restore Control C checking */ -# endif +#endif } -# ifdef CONFIG_MENUKEY +#ifdef CONFIG_MENUKEY if (menukey == CONFIG_MENUKEY) { s = getenv("menucmd"); if (s) run_command_list(s, -1, 0); } #endif /* CONFIG_MENUKEY */ +} #endif /* CONFIG_BOOTDELAY */ +void main_loop(void) +{ +#ifndef CONFIG_SYS_HUSH_PARSER + static char lastcommand[CONFIG_SYS_CBSIZE] = { 0, }; + int len; + int rc = 1; + int flag; +#endif +#ifdef CONFIG_PREBOOT + char *p; +#endif + + bootstage_mark_name(BOOTSTAGE_ID_MAIN_LOOP, "main_loop"); + +#ifdef CONFIG_MODEM_SUPPORT + debug("DEBUG: main_loop: do_mdm_init=%d\n", do_mdm_init); + if (do_mdm_init) { + char *str = strdup(getenv("mdm_cmd")); + setenv("preboot", str); /* set or delete definition */ + if (str != NULL) + free(str); + mdm_init(); /* wait for modem connection */ + } +#endif /* CONFIG_MODEM_SUPPORT */ + +#ifdef CONFIG_VERSION_VARIABLE + { + setenv("ver", version_string); /* set version variable */ + } +#endif /* CONFIG_VERSION_VARIABLE */ + +#ifdef CONFIG_SYS_HUSH_PARSER + u_boot_hush_start(); +#endif + +#if defined(CONFIG_HUSH_INIT_VAR) + hush_init_var(); +#endif + +#ifdef CONFIG_PREBOOT + p = getenv("preboot"); + if (p != NULL) { +# ifdef CONFIG_AUTOBOOT_KEYED + int prev = disable_ctrlc(1); /* disable Control C checking */ +# endif + + run_command_list(p, -1, 0); + +# ifdef CONFIG_AUTOBOOT_KEYED + disable_ctrlc(prev); /* restore Control C checking */ +# endif + } +#endif /* CONFIG_PREBOOT */ + +#if defined(CONFIG_UPDATE_TFTP) + update_tftp(0UL); +#endif /* CONFIG_UPDATE_TFTP */ + +#ifdef CONFIG_BOOTDELAY + process_boot_delay(); +#endif /* * Main Loop for Monitor Command Processing */ @@ -1080,20 +1076,20 @@ int readline_into_buffer(const char *const prompt, char *buffer, int timeout) * Special character handling */ switch (c) { - case '\r': /* Enter */ + case '\r': /* Enter */ case '\n': *p = '\0'; puts ("\r\n"); - return (p - p_buf); + return p - p_buf; - case '\0': /* nul */ + case '\0': /* nul */ continue; - case 0x03: /* ^C - break */ + case 0x03: /* ^C - break */ p_buf[0] = '\0'; /* discard input */ - return (-1); + return -1; - case 0x15: /* ^U - erase line */ + case 0x15: /* ^U - erase line */ while (col > plen) { puts (erase_seq); --col; @@ -1102,15 +1098,15 @@ int readline_into_buffer(const char *const prompt, char *buffer, int timeout) n = 0; continue; - case 0x17: /* ^W - erase word */ + case 0x17: /* ^W - erase word */ p=delete_char(p_buf, p, &col, &n, plen); while ((n > 0) && (*p != ' ')) { p=delete_char(p_buf, p, &col, &n, plen); } continue; - case 0x08: /* ^H - backspace */ - case 0x7F: /* DEL - backspace */ + case 0x08: /* ^H - backspace */ + case 0x7F: /* DEL - backspace */ p=delete_char(p_buf, p, &col, &n, plen); continue; @@ -1119,7 +1115,7 @@ int readline_into_buffer(const char *const prompt, char *buffer, int timeout) * Must be a normal character then */ if (n < CONFIG_SYS_CBSIZE-2) { - if (c == '\t') { /* expand TABs */ + if (c == '\t') { /* expand TABs */ #ifdef CONFIG_AUTO_COMPLETE /* if auto completion triggered just continue */ *p = '\0'; @@ -1134,7 +1130,7 @@ int readline_into_buffer(const char *const prompt, char *buffer, int timeout) char buf[2]; /* - * Echo input using puts() to force am + * Echo input using puts() to force an * LCD flush if we are using an LCD */ ++col; @@ -1192,9 +1188,7 @@ int parse_line (char *line, char *argv[]) { int nargs = 0; -#ifdef DEBUG_PARSER - printf ("parse_line: \"%s\"\n", line); -#endif + debug_parser("parse_line: \"%s\"\n", line); while (nargs < CONFIG_SYS_MAXARGS) { /* skip any white space */ @@ -1203,10 +1197,8 @@ int parse_line (char *line, char *argv[]) if (*line == '\0') { /* end of line, no more args */ argv[nargs] = NULL; -#ifdef DEBUG_PARSER - printf ("parse_line: nargs=%d\n", nargs); -#endif - return (nargs); + debug_parser("parse_line: nargs=%d\n", nargs); + return nargs; } argv[nargs++] = line; /* begin of argument string */ @@ -1217,10 +1209,8 @@ int parse_line (char *line, char *argv[]) if (*line == '\0') { /* end of line, no more args */ argv[nargs] = NULL; -#ifdef DEBUG_PARSER - printf ("parse_line: nargs=%d\n", nargs); -#endif - return (nargs); + debug_parser("parse_line: nargs=%d\n", nargs); + return nargs; } *line++ = '\0'; /* terminate current arg */ @@ -1228,9 +1218,7 @@ int parse_line (char *line, char *argv[]) printf ("** Too many args (max. %d) **\n", CONFIG_SYS_MAXARGS); -#ifdef DEBUG_PARSER - printf ("parse_line: nargs=%d\n", nargs); -#endif + debug_parser("parse_line: nargs=%d\n", nargs); return (nargs); } @@ -1248,12 +1236,10 @@ static void process_macros (const char *input, char *output) /* 1 = waiting for '(' or '{' */ /* 2 = waiting for ')' or '}' */ /* 3 = waiting for ''' */ -#ifdef DEBUG_PARSER char *output_start = output; - printf ("[PROCESS_MACROS] INPUT len %d: \"%s\"\n", strlen (input), - input); -#endif + debug_parser("[PROCESS_MACROS] INPUT len %zd: \"%s\"\n", strlen(input), + input); prev = '\0'; /* previous character */ @@ -1341,10 +1327,8 @@ static void process_macros (const char *input, char *output) else *(output - 1) = 0; -#ifdef DEBUG_PARSER - printf ("[PROCESS_MACROS] OUTPUT len %d: \"%s\"\n", - strlen (output_start), output_start); -#endif + debug_parser("[PROCESS_MACROS] OUTPUT len %zd: \"%s\"\n", + strlen(output_start), output_start); } /**************************************************************************** @@ -1375,12 +1359,12 @@ static int builtin_run_command(const char *cmd, int flag) int repeatable = 1; int rc = 0; -#ifdef DEBUG_PARSER - printf ("[RUN_COMMAND] cmd[%p]=\"", cmd); - puts (cmd ? cmd : "NULL"); /* use puts - string may be loooong */ - puts ("\"\n"); -#endif - + debug_parser("[RUN_COMMAND] cmd[%p]=\"", cmd); + if (DEBUG_PARSER) { + /* use puts - string may be loooong */ + puts(cmd ? cmd : "NULL"); + puts("\"\n"); + } clear_ctrlc(); /* forget any previous Control C */ if (!cmd || !*cmd) { @@ -1398,9 +1382,7 @@ static int builtin_run_command(const char *cmd, int flag) * repeatable commands */ -#ifdef DEBUG_PARSER - printf ("[PROCESS_SEPARATORS] %s\n", cmd); -#endif + debug_parser("[PROCESS_SEPARATORS] %s\n", cmd); while (*str) { /* @@ -1429,9 +1411,7 @@ static int builtin_run_command(const char *cmd, int flag) } else str = sep; /* no more commands for next pass */ -#ifdef DEBUG_PARSER - printf ("token: \"%s\"\n", token); -#endif + debug_parser("token: \"%s\"\n", token); /* find macros in this token and replace them */ process_macros (token, finaltoken); diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c index 7efdcb8..170fa38 100644 --- a/common/spl/spl_mmc.c +++ b/common/spl/spl_mmc.c @@ -32,7 +32,7 @@ DECLARE_GLOBAL_DATA_PTR; -static void mmc_load_image_raw(struct mmc *mmc) +static int mmc_load_image_raw(struct mmc *mmc, unsigned long sector) { unsigned long err; u32 image_size_sectors; @@ -42,10 +42,7 @@ static void mmc_load_image_raw(struct mmc *mmc) sizeof(struct image_header)); /* read image header to find the image size & load address */ - err = mmc->block_dev.block_read(0, - CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, 1, - header); - + err = mmc->block_dev.block_read(0, sector, 1, header); if (err == 0) goto end; @@ -56,19 +53,33 @@ static void mmc_load_image_raw(struct mmc *mmc) mmc->read_bl_len; /* Read the header too to avoid extra memcpy */ - err = mmc->block_dev.block_read(0, - CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR, - image_size_sectors, (void *)spl_image.load_addr); + err = mmc->block_dev.block_read(0, sector, image_size_sectors, + (void *)spl_image.load_addr); end: - if (err == 0) { + if (err == 0) printf("spl: mmc blk read err - %lu\n", err); - hang(); + + return (err == 0); +} + +#ifdef CONFIG_SPL_OS_BOOT +static int mmc_load_image_raw_os(struct mmc *mmc) +{ + if (!mmc->block_dev.block_read(0, + CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR, + CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS, + (void *)CONFIG_SYS_SPL_ARGS_ADDR)) { + printf("mmc args blk read error\n"); + return -1; } + + return mmc_load_image_raw(mmc, CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR); } +#endif #ifdef CONFIG_SPL_FAT_SUPPORT -static void mmc_load_image_fat(struct mmc *mmc) +static int mmc_load_image_fat(struct mmc *mmc, const char *filename) { int err; struct image_header *header; @@ -76,32 +87,41 @@ static void mmc_load_image_fat(struct mmc *mmc) header = (struct image_header *)(CONFIG_SYS_TEXT_BASE - sizeof(struct image_header)); - err = fat_register_device(&mmc->block_dev, - CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION); - if (err) { - printf("spl: fat register err - %d\n", err); - hang(); - } - - err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, - header, sizeof(struct image_header)); + err = file_fat_read(filename, header, sizeof(struct image_header)); if (err <= 0) goto end; spl_parse_image_header(header); - err = file_fat_read(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, - (u8 *)spl_image.load_addr, 0); + err = file_fat_read(filename, (u8 *)spl_image.load_addr, 0); end: + if (err <= 0) + printf("spl: error reading image %s, err - %d\n", + filename, err); + + return (err <= 0); +} + +#ifdef CONFIG_SPL_OS_BOOT +static int mmc_load_image_fat_os(struct mmc *mmc) +{ + int err; + + err = file_fat_read(CONFIG_SPL_FAT_LOAD_ARGS_NAME, + (void *)CONFIG_SYS_SPL_ARGS_ADDR, 0); if (err <= 0) { printf("spl: error reading image %s, err - %d\n", - CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME, err); - hang(); + CONFIG_SPL_FAT_LOAD_ARGS_NAME, err); + return -1; } + + return mmc_load_image_fat(mmc, CONFIG_SPL_FAT_LOAD_KERNEL_NAME); } #endif +#endif + void spl_mmc_load_image(void) { struct mmc *mmc; @@ -121,17 +141,36 @@ void spl_mmc_load_image(void) printf("spl: mmc init failed: err - %d\n", err); hang(); } + boot_mode = spl_boot_mode(); if (boot_mode == MMCSD_MODE_RAW) { debug("boot mode - RAW\n"); - mmc_load_image_raw(mmc); +#ifdef CONFIG_SPL_OS_BOOT + if (spl_start_uboot() || mmc_load_image_raw_os(mmc)) +#endif + err = mmc_load_image_raw(mmc, + CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR); #ifdef CONFIG_SPL_FAT_SUPPORT } else if (boot_mode == MMCSD_MODE_FAT) { debug("boot mode - FAT\n"); - mmc_load_image_fat(mmc); + + err = fat_register_device(&mmc->block_dev, + CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION); + if (err) { + printf("spl: fat register err - %d\n", err); + hang(); + } + +#ifdef CONFIG_SPL_OS_BOOT + if (spl_start_uboot() || mmc_load_image_fat_os(mmc)) +#endif + err = mmc_load_image_fat(mmc, CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME); #endif } else { puts("spl: wrong MMC boot mode\n"); hang(); } + + if (err) + hang(); } diff --git a/common/splash.c b/common/splash.c new file mode 100644 index 0000000..18885f1 --- /dev/null +++ b/common/splash.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2013, Boundary Devices <info@boundarydevices.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., http://www.fsf.org/about/contact/ + * + */ + +#include <common.h> +#include <splash.h> + +int __splash_screen_prepare(void) +{ + return 0; +} + +int splash_screen_prepare(void) + __attribute__ ((weak, alias("__splash_screen_prepare"))); + + +#ifdef CONFIG_SPLASH_SCREEN_ALIGN +void splash_get_pos(int *x, int *y) +{ + char *s = getenv("splashpos"); + + if (!s) + return; + + if (s[0] == 'm') + *x = BMP_ALIGN_CENTER; + else + *x = simple_strtol(s, NULL, 0); + + s = strchr(s + 1, ','); + if (s != NULL) { + if (s[1] == 'm') + *y = BMP_ALIGN_CENTER; + else + *y = simple_strtol(s + 1, NULL, 0); + } +} +#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ diff --git a/common/usb_hub.c b/common/usb_hub.c index 0d79ec3..774ba63 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -53,6 +53,10 @@ #include <asm/4xx_pci.h> #endif +#ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY +#define CONFIG_USB_HUB_MIN_POWER_ON_DELAY 100 +#endif + #define USB_BUFSIZ 512 static struct usb_hub_device hub_dev[USB_MAX_HUB]; @@ -148,8 +152,8 @@ static void usb_hub_power_on(struct usb_hub_device *hub) debug("port %d returns %lX\n", i + 1, dev->status); } - /* Wait at least 100 msec for power to become stable */ - mdelay(max(pgood_delay, (unsigned)100)); + /* Wait for power to become stable */ + mdelay(max(pgood_delay, CONFIG_USB_HUB_MIN_POWER_ON_DELAY)); } void usb_hub_reset(void) @@ -485,7 +489,11 @@ static int usb_hub_configure(struct usb_device *dev) i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); - + /* + * The following hack causes a ghost device problem + * to Faraday EHCI + */ +#ifndef CONFIG_USB_EHCI_FARADAY /* EM interference sometimes causes bad shielded USB * devices to be shutdown by the hub, this hack enables * them again. Works at least with mouse driver */ @@ -497,6 +505,7 @@ static int usb_hub_configure(struct usb_device *dev) "re-enabling...\n", i + 1); usb_hub_port_connect_change(dev, i); } +#endif } if (portstatus & USB_PORT_STAT_SUSPEND) { debug("port %d suspend change\n", i + 1); diff --git a/common/usb_kbd.c b/common/usb_kbd.c index b962849..3174b5e 100644 --- a/common/usb_kbd.c +++ b/common/usb_kbd.c @@ -461,8 +461,13 @@ static int usb_kbd_probe(struct usb_device *dev, unsigned int ifnum) usb_set_idle(dev, iface->desc.bInterfaceNumber, REPEAT_RATE, 0); debug("USB KBD: enable interrupt pipe...\n"); - usb_submit_int_msg(dev, pipe, data->new, maxp > 8 ? 8 : maxp, - ep->bInterval); + if (usb_submit_int_msg(dev, pipe, data->new, maxp > 8 ? 8 : maxp, + ep->bInterval) < 0) { + printf("Failed to get keyboard state from device %04x:%04x\n", + dev->descriptor.idVendor, dev->descriptor.idProduct); + /* Abort, we don't want to use that non-functional keyboard. */ + return 0; + } /* Success. */ return 1; @@ -496,6 +501,7 @@ int drv_usb_kbd_init(void) if (old_dev) { /* Already registered, just return ok. */ debug("USB KBD: is already registered.\n"); + usb_kbd_deregister(); return 1; } diff --git a/common/usb_storage.c b/common/usb_storage.c index 457970f..4599d03 100644 --- a/common/usb_storage.c +++ b/common/usb_storage.c @@ -170,9 +170,9 @@ int usb_stor_get_info(struct usb_device *dev, struct us_data *us, block_dev_desc_t *dev_desc); int usb_storage_probe(struct usb_device *dev, unsigned int ifnum, struct us_data *ss); -unsigned long usb_stor_read(int device, unsigned long blknr, +unsigned long usb_stor_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer); -unsigned long usb_stor_write(int device, unsigned long blknr, +unsigned long usb_stor_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer); struct usb_device * usb_get_dev_index(int index); void uhci_show_temp_int_td(void); @@ -1054,7 +1054,7 @@ static void usb_bin_fixup(struct usb_device_descriptor descriptor, } #endif /* CONFIG_USB_BIN_FIXUP */ -unsigned long usb_stor_read(int device, unsigned long blknr, +unsigned long usb_stor_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer) { lbaint_t start, blks; @@ -1127,7 +1127,7 @@ retry_it: return blkcnt; } -unsigned long usb_stor_write(int device, unsigned long blknr, +unsigned long usb_stor_write(int device, lbaint_t blknr, lbaint_t blkcnt, const void *buffer) { lbaint_t start, blks; @@ -210,6 +210,11 @@ CPPFLAGS += -ffunction-sections -fdata-sections LDFLAGS_FINAL += --gc-sections endif +# TODO(sjg@chromium.org): Is this correct on Mac OS? +ifdef CONFIG_FIT_SIGNATURE +HOSTLIBS += -lssl -lcrypto +endif + ifneq ($(CONFIG_SYS_TEXT_BASE),) CPPFLAGS += -DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE) endif @@ -268,6 +273,16 @@ CFLAGS += $(CFLAGS_WARN) CFLAGS_STACK := $(call cc-option,-fstack-usage) CFLAGS += $(CFLAGS_STACK) +BCURDIR = $(subst $(SRCTREE)/,,$(CURDIR:$(obj)%=%)) + +ifeq ($(findstring examples/,$(BCURDIR)),) +ifeq ($(CONFIG_SPL_BUILD),) +ifdef FTRACE +CFLAGS += -finstrument-functions -DFTRACE +endif +endif +endif + # $(CPPFLAGS) sets -g, which causes gcc to pass a suitable -g<format> # option to the assembler. AFLAGS_DEBUG := @@ -330,7 +345,6 @@ export CONFIG_SYS_TEXT_BASE PLATFORM_CPPFLAGS PLATFORM_RELFLAGS CPPFLAGS CFLAGS ######################################################################### # Allow boards to use custom optimize flags on a per dir/file basis -BCURDIR = $(subst $(SRCTREE)/,,$(CURDIR:$(obj)%=%)) ALL_AFLAGS = $(AFLAGS) $(AFLAGS_$(BCURDIR)/$(@F)) $(AFLAGS_$(BCURDIR)) ALL_CFLAGS = $(CFLAGS) $(CFLAGS_$(BCURDIR)/$(@F)) $(CFLAGS_$(BCURDIR)) EXTRA_CPPFLAGS = $(CPPFLAGS_$(BCURDIR)/$(@F)) $(CPPFLAGS_$(BCURDIR)) diff --git a/disk/part_efi.c b/disk/part_efi.c index 5986589..fb5e9f0 100644 --- a/disk/part_efi.c +++ b/disk/part_efi.c @@ -372,7 +372,7 @@ int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, u32 offset = (u32)le32_to_cpu(gpt_h->first_usable_lba); ulong start; int i, k; - size_t name_len; + size_t efiname_len, dosname_len; #ifdef CONFIG_PARTITION_UUIDS char *str_uuid; #endif @@ -420,9 +420,14 @@ int gpt_fill_pte(gpt_header *gpt_h, gpt_entry *gpt_e, sizeof(gpt_entry_attributes)); /* partition name */ - name_len = sizeof(gpt_e[i].partition_name) + efiname_len = sizeof(gpt_e[i].partition_name) / sizeof(efi_char16_t); - for (k = 0; k < name_len; k++) + dosname_len = sizeof(partitions[i].name); + + memset(gpt_e[i].partition_name, 0, + sizeof(gpt_e[i].partition_name)); + + for (k = 0; k < min(dosname_len, efiname_len); k++) gpt_e[i].partition_name[k] = (efi_char16_t)(partitions[i].name[k]); diff --git a/doc/README.SPL b/doc/README.SPL index 4e1cb28..ac9a213 100644 --- a/doc/README.SPL +++ b/doc/README.SPL @@ -77,7 +77,7 @@ an SPL CPU in boards.cfg as follows: normal_cpu:spl_cpu -This this case CPU will be set to "normal_cpu" during the main u-boot +This case CPU will be set to "normal_cpu" during the main u-boot build and "spl_cpu" during the SPL build. diff --git a/doc/README.plan9 b/doc/README.plan9 new file mode 100644 index 0000000..2d3d0e0 --- /dev/null +++ b/doc/README.plan9 @@ -0,0 +1,18 @@ +Plan 9 from Bell Labs kernel images require additional setup to pass +configuration information to the kernel. An environment variable named +confaddr must be defined with the same value as CONFADDR (see mem.h). +Use of this facility is optional, but should be preferable to manual +configuration. + +When booting an image, arguments supplied to the bootm command will be +copied to CONFADDR. If no arguments are specified, the contents of the +bootargs environment variable will be copied. + +If no command line arguments or bootargs are defined, CONFADDR is left +uninitialized to permit manual configuration. For example, PC-style +configuration could be simulated by issuing a fatload in bootcmd: + + # setenv bootcmd fatload mmc 0 $confaddr plan9.ini; ...; bootm + +Steven Stallion +June 2013 diff --git a/doc/README.splashprepare b/doc/README.splashprepare new file mode 100644 index 0000000..61b4ec5 --- /dev/null +++ b/doc/README.splashprepare @@ -0,0 +1,8 @@ +--------------------------------------------------------------------- +Splash Screen +--------------------------------------------------------------------- +The splash_screen_prepare() function is a weak function defined in +common/splash.c. It is called as part of the splash screen display +sequence. It gives the board an opportunity to prepare the splash +image data before it is processed and sent to the frame buffer by +U-Boot. Define your own version to use this feature. diff --git a/doc/README.srio-pcie-boot-corenet b/doc/README.srio-pcie-boot-corenet index cd7e7ee..2b1f76b 100644 --- a/doc/README.srio-pcie-boot-corenet +++ b/doc/README.srio-pcie-boot-corenet @@ -21,13 +21,13 @@ Environment of the SRIO or PCIE boot: e) Slave's RCW should configure the SerDes for SRIO or PCIE boot port, set the boot location to SRIO or PCIE, and holdoff all the cores. - ---------- ----------- ----------- - | | | | | | - | | | | | | + ----------- ----------- ----------- + | | | | | | + | | | | | | | NorFlash|<----->| Master |SRIO or PCIE | Slave |<---->[EEPROM] - | | | |<===========>| | - | | | | | | - ---------- ----------- ----------- + | | | |<===========>| | + | | | | | | + ----------- ----------- ----------- The example based on P4080DS platform: Two P4080DS platforms can be used to implement the boot from SRIO or PCIE. @@ -87,26 +87,32 @@ How to use this feature: Please refer to the examples given above. 2. U-Boot image's compilation. - For master, U-Boot image should be generated normally. + For master, U-Boot image should be generated normally. - For example, master U-Boot image used on P4080DS should be compiled with + For example, master U-Boot image used on P4080DS should be compiled with make P4080DS_config. - For slave, U-Boot image should be generated specifically by + For slave, U-Boot image should be generated specifically by make xxxx_SRIO_PCIE_BOOT_config. - For example, slave U-Boot image used on P4080DS should be compiled with + For example, slave U-Boot image used on P4080DS should be compiled with make P4080DS_SRIO_PCIE_BOOT_config. 3. Necessary modifications based on a specific environment. - For a specific environment, the addresses of the slave's U-Boot image, - UCode, ENV stored in master's NorFlash, and any other configurations - can be modified in the file: - include/configs/corenet_ds.h. + For a specific environment, the addresses of the slave's U-Boot image, + UCode, ENV stored in master's NorFlash, and any other configurations + can be modified in the file: + include/configs/corenet_ds.h. 4. Set and save the environment variable "bootmaster" with "SRIO1", "SRIO2" or "PCIE1", "PCIE2", "PCIE3" for master, and then restart it in order to perform the role as a master for boot from SRIO or PCIE. + +NOTE: When the Slave's ENV parameters are stored in Master's NorFlash, + it can fetch them through PCIE or SRIO interface. But the ENV + parameters can not be modified by "saveenv" or other commands under + the Slave's u-boot environment, because the Slave can not erase, + write Master's NorFlash by PCIE or SRIO link. diff --git a/doc/README.trace b/doc/README.trace new file mode 100644 index 0000000..b535c06 --- /dev/null +++ b/doc/README.trace @@ -0,0 +1,361 @@ +# +# Copyright (c) 2013 The Chromium OS Authors. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundatio; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +Tracing in U-Boot +================= + +U-Boot supports a simple tracing feature which allows a record of excecution +to be collected and sent to a host machine for analysis. At present the +main use for this is to profile boot time. + + +Overview +-------- + +The trace feature uses GCC's instrument-functions feature to trace all +function entry/exit points. These are then recorded in a memory buffer. +The memory buffer can be saved to the host over a network link using +tftpput or by writing to an attached memory device such as MMC. + +On the host, the file is first converted with a tool called 'proftool', +which extracts useful information from it. The resulting trace output +resembles that emitted by Linux's ftrace feature, so can be visually +displayed by pytimechart. + + +Quick-start using Sandbox +------------------------- + +Sandbox is a build of U-Boot that can run under Linux so it is a convenient +way of trying out tracing before you use it on your actual board. To do +this, follow these steps: + +Add the following to include/configs/sandbox.h (if not already there) + +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE (16 << 20) +#define CONFIG_TRACE_EARLY_SIZE (8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR 0x00100000 + +Build sandbox U-Boot with tracing enabled: + +$ make FTRACE=1 O=sandbox sandbox_config +$ make FTRACE=1 O=sandbox + +Run sandbox, wait for a bit of trace information to appear, and then capture +a trace: + +$ ./sandbox/u-boot + + +U-Boot 2013.04-rc2-00100-ga72fcef (Apr 17 2013 - 19:25:24) + +DRAM: 128 MiB +trace: enabled +Using default environment + +In: serial +Out: serial +Err: serial +=>trace stats + 671,406 function sites + 69,712 function calls + 0 untracked function calls + 73,373 traced function calls + 16 maximum observed call depth + 15 call depth limit + 66,491 calls not traced due to depth +=>trace stats + 671,406 function sites + 1,279,450 function calls + 0 untracked function calls + 950,490 traced function calls (333217 dropped due to overflow) + 16 maximum observed call depth + 15 call depth limit + 1,275,767 calls not traced due to depth +=>trace calls 0 e00000 +Call list dumped to 00000000, size 0xae0a40 +=>print +baudrate=115200 +profbase=0 +profoffset=ae0a40 +profsize=e00000 +stderr=serial +stdin=serial +stdout=serial + +Environment size: 117/8188 bytes +=>sb save host 0 trace 0 ${profoffset} +11405888 bytes written in 10 ms (1.1 GiB/s) +=>reset + + +Then run proftool to convert the trace information to ftrace format. + +$ ./sandbox/tools/proftool -m sandbox/System.map -p trace dump-ftrace >trace.txt + +Finally run pytimechart to display it: + +$ pytimechart trace.txt + +Using this tool you can zoom and pan across the trace, with the function +calls on the left and little marks representing the start and end of each +function. + + +CONFIG Options +-------------- + +- CONFIG_TRACE + Enables the trace feature in U-Boot. + +- CONFIG_CMD_TRACE + Enables the trace command. + +- CONFIG_TRACE_BUFFER_SIZE + Size of trace buffer to allocate for U-Boot. This buffer is + used after relocation, as a place to put function tracing + information. The address of the buffer is determined by + the relocation code. + +- CONFIG_TRACE_EARLY + Define this to start tracing early, before relocation. + +- CONFIG_TRACE_EARLY_SIZE + Size of 'early' trace buffer. Before U-Boot has relocated + it doesn't have a proper trace buffer. On many boards + you can define an area of memory to use for the trace + buffer until the 'real' trace buffer is available after + relocation. The contents of this buffer are then copied to + the real buffer. + +- CONFIG_TRACE_EARLY_ADDR + Address of early trace buffer + + +Building U-Boot with Tracing Enabled +------------------------------------ + +Pass 'FTRACE=1' to the U-Boot Makefile to actually instrument the code. +This is kept as a separate option so that it is easy to enable/disable +instrumenting from the command line instead of having to change board +config files. + + +Collecting Trace Data +--------------------- + +When you run U-Boot on your board it will collect trace data up to the +limit of the trace buffer size you have specified. Once that is exhausted +no more data will be collected. + +Collecting trace data has an affect on execution time/performance. You +will notice this particularly with trvial functions - the overhead of +recording their execution may even exceed their normal execution time. +In practice this doesn't matter much so long as you are aware of the +effect. Once you have done your optimisations, turn off tracing before +doing end-to-end timing. + +The best time to start tracing is right at the beginning of U-Boot. The +best time to stop tracing is right at the end. In practice it is hard +to achieve these ideals. + +This implementation enables tracing early in board_init_f(). This means +that it captures most of the board init process, missing only the +early architecture-specific init. However, it also misses the entire +SPL stage if there is one. + +U-Boot typically ends with a 'bootm' command which loads and runs an +OS. There is useful trace data in the execution of that bootm +command. Therefore this implementation provides a way to collect trace +data after bootm has finished processing, but just before it jumps to +the OS. In practical terms, U-Boot runs the 'fakegocmd' environment +variable at this point. This variable should have a short script which +collects the trace data and writes it somewhere. + +Trace data collection relies on a microsecond timer, accesed through +timer_get_us(). So the first think you should do is make sure that +this produces sensible results for your board. Suitable sources for +this timer include high resolution timers, PWMs or profile timers if +available. Most modern SOCs have a suitable timer for this. Make sure +that you mark this timer (and anything it calls) with +__attribute__((no_instrument_function)) so that the trace library can +use it without causing an infinite loop. + + +Commands +-------- + +The trace command has variable sub-commands: + +- stats + Display tracing statistics + +- pause + Pause tracing + +- resume + Resume tracing + +- funclist [<addr> <size>] + Dump a list of functions into the buffer + +- calls [<addr> <size>] + Dump function call trace into buffer + +If the address and size are not given, these are obtained from environment +variables (see below). In any case the environment variables are updated +after the command runs. + + +Environment Variables +--------------------- + +The following are used: + +- profbase + Base address of trace output buffer + +- profoffset + Offset of first unwritten byte in trace output buffer + +- profsize + Size of trace output buffer + +All of these are set by the 'trace calls' command. + +These variables keep track of the amount of data written to the trace +output buffer by the 'trace' command. The trace commands which write data +to the output buffer can use these to specify the buffer to write to, and +update profoffset each time. This allows successive commands to append data +to the same buffer, for example: + + trace funclist 10000 e00000 + trace calls + +(the latter command appends more data to the buffer). + + +- fakegocmd + Specifies commands to run just before booting the OS. This + is a useful time to write the trace data to the host for + processing. + + +Writing Out Trace Data +---------------------- + +Once the trace data is in an output buffer in memory there are various ways +to transmit it to the host. Notably you can use tftput to send the data +over a network link: + +fakegocmd=trace pause; usb start; set autoload n; bootp; + trace calls 10000000 1000000; + tftpput ${profbase} ${profoffset} 192.168.1.4:/tftpboot/calls + +This starts up USB (to talk to an attached USB Ethernet dongle), writes +a trace log to address 10000000 and sends it to a host machine using +TFTP. After this, U-Boot will boot the OS normally, albeit a little +later. + + +Converting Trace Output Data +---------------------------- + +The trace output data is kept in a binary format which is not documented +here. To convert it into something useful, you can use proftool. + +This tool must be given the U-Boot map file and the trace data received +from running that U-Boot. It produces a text output file. + +Options + -m <map_file> + Specify U-Boot map file + + -p <trace_file> + Specifiy profile/trace file + +Commands: + +- dump-ftrace + Write a text dump of the file in Linux ftrace format to stdout + + +Viewing the Trace Data +---------------------- + +You can use pytimechart for this (sudo apt-get pytimechart might work on +your Debian-style machine, and use your favourite search engine to obtain +documentation). It expects the file to have a .txt extension. The program +has terse user interface but is very convenient for viewing U-Boot +profile information. + + +Workflow Suggestions +-------------------- + +The following suggestions may be helpful if you are trying to reduce boot +time: + +1. Enable CONFIG_BOOTSTAGE and CONFIG_BOOTSTAGE_REPORT. This should get +you are helpful overall snapshot of the boot time. + +2. Build U-Boot with tracing and run it. Note the difference in boot time +(it is common for tracing to add 10% to the time) + +3. Collect the trace information as descibed above. Use this to find where +all the time is being spent. + +4. Take a look at that code and see if you can optimise it. Perhaps it is +possible to speed up the initialisation of a device, or remove an unused +feature. + +5. Rebuild, run and collect again. Compare your results. + +6. Keep going until you run out of steam, or your boot is fast enough. + + +Configuring Trace +----------------- + +There are a few parameters in the code that you may want to consider. +There is a function call depth limit (set to 15 by default). When the +stack depth goes above this then no tracing information is recorded. +The maximum depth reached is recorded and displayed by the 'trace stats' +command. + + +Future Work +----------- + +Tracing could be a little tidier in some areas, for example providing +run-time configuration options for trace. + +Some other features that might be useful: + +- Trace filter to select which functions are recorded +- Sample-based profiling using a timer interrupt +- Better control over trace depth +- Compression of trace information + + +Simon Glass <sjg@chromium.org> +April 2013 diff --git a/doc/device-tree-bindings/input/cros-ec-keyb.txt b/doc/device-tree-bindings/input/cros-ec-keyb.txt new file mode 100644 index 0000000..3118276 --- /dev/null +++ b/doc/device-tree-bindings/input/cros-ec-keyb.txt @@ -0,0 +1,79 @@ +CROS_EC Keyboard + +The CROS_EC (Matrix Keyboard Protocol) allows communcation with a secondary +micro used for keyboard, and possible other features. + +The CROS_EC keyboard uses this protocol to receive key scans and produce input +in U-Boot. + +Required properties : +- compatible : "google,cros-ec-keyb" +- google,key-rows : Number of key rows +- google,key-columns : Number of key columns + +Optional properties, in addition to those specified by the shared +matrix-keyboard bindings: + +- linux,fn-keymap: a second keymap, same specification as the + matrix-keyboard-controller spec but to be used when the KEY_FN modifier + key is pressed. +- google,repeat-delay-ms : delay in milliseconds before repeat starts +- google,repeat-rate-ms : delay between each subsequent key press +- google,ghost-filter : enable ghost filtering for this device + +Example, taken from daisy: + +cros-ec-keyb { + compatible = "google,cros-ec-keyb"; + google,key-rows = <8>; + google,key-columns = <13>; + google,ghost-filter; + google,repeat-delay-ms = <240>; + google,repeat-rate-ms = <30>; + /* + * Keymap entries take the form of 0xRRCCKKKK where + * RR=Row CC=Column KKKK=Key Code + * The values below are for a US keyboard layout and + * are taken from the Linux driver. Note that the + * 102ND key is not used for US keyboards. + */ + linux,keymap = < + /* CAPSLCK F1 B F10 */ + 0x0001003a 0x0002003c 0x00030030 0x00040044 + /* N = R_ALT ESC */ + 0x00060031 0x0008000d 0x000a0064 0x01010001 + /* F4 G F7 H */ + 0x0102003e 0x01030022 0x01040041 0x01060023 + /* ' F9 BKSPACE L_CTRL */ + 0x01080028 0x01090043 0x010b000e 0x0200001d + /* TAB F3 T F6 */ + 0x0201000f 0x0202003d 0x02030014 0x02040040 + /* ] Y 102ND [ */ + 0x0205001b 0x02060015 0x02070056 0x0208001a + /* F8 GRAVE F2 5 */ + 0x02090042 0x03010029 0x0302003c 0x03030006 + /* F5 6 - \ */ + 0x0304003f 0x03060007 0x0308000c 0x030b002b + /* R_CTRL A D F */ + 0x04000061 0x0401001e 0x04020020 0x04030021 + /* S K J ; */ + 0x0404001f 0x04050025 0x04060024 0x04080027 + /* L ENTER Z C */ + 0x04090026 0x040b001c 0x0501002c 0x0502002e + /* V X , M */ + 0x0503002f 0x0504002d 0x05050033 0x05060032 + /* L_SHIFT / . SPACE */ + 0x0507002a 0x05080035 0x05090034 0x050B0039 + /* 1 3 4 2 */ + 0x06010002 0x06020004 0x06030005 0x06040003 + /* 8 7 0 9 */ + 0x06050009 0x06060008 0x0608000b 0x0609000a + /* L_ALT DOWN RIGHT Q */ + 0x060a0038 0x060b006c 0x060c006a 0x07010010 + /* E R W I */ + 0x07020012 0x07030013 0x07040011 0x07050017 + /* U R_SHIFT P O */ + 0x07060016 0x07070036 0x07080019 0x07090018 + /* UP LEFT */ + 0x070b0067 0x070c0069>; +}; diff --git a/doc/device-tree-bindings/misc/cros-ec.txt b/doc/device-tree-bindings/misc/cros-ec.txt new file mode 100644 index 0000000..07ea7cd --- /dev/null +++ b/doc/device-tree-bindings/misc/cros-ec.txt @@ -0,0 +1,38 @@ +Chrome OS CROS_EC Binding +====================== + +The device tree node which describes the operation of the CROS_EC interface +is as follows: + +Required properties : +- compatible = "google,cros-ec" + +Optional properties : +- spi-max-frequency : Sets the maximum frequency (in Hz) for SPI bus + operation +- i2c-max-frequency : Sets the maximum frequency (in Hz) for I2C bus + operation +- ec-interrupt : Selects the EC interrupt, defined as a GPIO according + to the platform +- optimise-flash-write : Boolean property - if present then flash blocks + containing all 0xff will not be written, since we assume that the EC + uses that pattern for erased blocks + +The CROS_EC node should appear as a subnode of the interrupt that connects it +to the EC (e.g. i2c, spi, lpc). The reg property (as usual) will indicate +the unit address on that bus. + + +Example +======= + + spi@131b0000 { + cros-ec@0 { + reg = <0>; + compatible = "google,cros-ec"; + spi-max-frequency = <5000000>; + ec-interrupt = <&gpio 174 1>; + optimise-flash-write; + status = "disabled"; + }; + }; diff --git a/doc/device-tree-bindings/video/simple-framebuffer.txt b/doc/device-tree-bindings/video/simple-framebuffer.txt new file mode 100644 index 0000000..3ea4605 --- /dev/null +++ b/doc/device-tree-bindings/video/simple-framebuffer.txt @@ -0,0 +1,25 @@ +Simple Framebuffer + +A simple frame-buffer describes a raw memory region that may be rendered to, +with the assumption that the display hardware has already been set up to scan +out from that buffer. + +Required properties: +- compatible: "simple-framebuffer" +- reg: Should contain the location and size of the framebuffer memory. +- width: The width of the framebuffer in pixels. +- height: The height of the framebuffer in pixels. +- stride: The number of bytes in each line of the framebuffer. +- format: The format of the framebuffer surface. Valid values are: + - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b). + +Example: + + framebuffer { + compatible = "simple-framebuffer"; + reg = <0x1d385000 (1600 * 1200 * 2)>; + width = <1600>; + height = <1200>; + stride = <(1600 * 2)>; + format = "r5g6b5"; + }; diff --git a/doc/mkimage.1 b/doc/mkimage.1 index 39652c8..14374da 100644 --- a/doc/mkimage.1 +++ b/doc/mkimage.1 @@ -4,7 +4,17 @@ mkimage \- Generate image for U-Boot .SH SYNOPSIS .B mkimage -.RB [\fIoptions\fP] +.RB "\-l [" "uimage file name" "]" + +.B mkimage +.RB [\fIoptions\fP] " \-f [" "image tree source file" "]" " [" "uimage file name" "]" + +.B mkimage +.RB [\fIoptions\fP] " \-F [" "uimage file name" "]" + +.B mkimage +.RB [\fIoptions\fP] " (legacy mode)" + .SH "DESCRIPTION" The .B mkimage @@ -26,7 +36,8 @@ etc. The new .I FIT (Flattened Image Tree) format allows for more flexibility in handling images of various types and also -enhances integrity protection of images with stronger checksums. +enhances integrity protection of images with stronger checksums. It also +supports verified boot. .SH "OPTIONS" @@ -67,6 +78,10 @@ Set load address with a hex number. Set entry point with a hex number. .TP +.BI "\-l" +List the contents of an image. + +.TP .BI "\-n [" "image name" "]" Set image name to 'image name'. @@ -82,6 +97,12 @@ Set XIP (execute in place) flag. .B Create FIT image: .TP +.BI "\-c [" "comment" "]" +Specifies a comment to be added when signing. This is typically a useful +message which describes how the image was signed or some other useful +information. + +.TP .BI "\-D [" "dtc options" "]" Provide special options to the device tree compiler that is used to create the image. @@ -91,6 +112,33 @@ create the image. Image tree source file that describes the structure and contents of the FIT image. +.TP +.BI "\-F" +Indicates that an existing FIT image should be modified. No dtc +compilation is performed and the -f flag should not be given. +This can be used to sign images with additional keys after initial image +creation. + +.TP +.BI "\-k [" "key_directory" "]" +Specifies the directory containing keys to use for signing. This directory +should contain a private key file <name>.key for use with signing and a +certificate <name>.crt (containing the public key) for use with verification. + +.TP +.BI "\-K [" "key_destination" "]" +Specifies a compiled device tree binary file (typically .dtb) to write +public key information into. When a private key is used to sign an image, +the corresponding public key is written into this file for for run-time +verification. Typically the file here is the device tree binary used by +CONFIG_OF_CONTROL in U-Boot. + +.TP +.BI "\-r +Specifies that keys used to sign the FIT are required. This means that they +must be verified for the image to boot. Without this option, the verification +will be optional (useful for testing but not for release). + .SH EXAMPLES List image information: @@ -109,10 +157,29 @@ Create FIT image with compressed PowerPC Linux kernel: .nf .B mkimage -f kernel.its kernel.itb .fi +.P +Create FIT image with compressed kernel and sign it with keys in the +/public/signing-keys directory. Add corresponding public keys into u-boot.dtb, +skipping those for which keys cannot be found. Also add a comment. +.nf +.B mkimage -f kernel.its -k /public/signing-keys -K u-boot.dtb \\\\ +-c "Kernel 3.8 image for production devices" kernel.itb +.fi + +.P +Update an existing FIT image, signing it with additional keys. +Add corresponding public keys into u-boot.dtb. This will resign all images +with keys that are available in the new directory. Images that request signing +with unavailable keys are skipped. +.nf +.B mkimage -F -k /secret/signing-keys -K u-boot.dtb \\\\ +-c "Kernel 3.8 image for production devices" kernel.itb +.fi .SH HOMEPAGE http://www.denx.de/wiki/U-Boot/WebHome .PP .SH AUTHOR This manual page was written by Nobuhiro Iwamatsu <iwamatsu@nigauri.org> -and Wolfgang Denk <wd@denx.de> +and Wolfgang Denk <wd@denx.de>. It was updated for image signing by +Simon Glass <sjg@chromium.org>. diff --git a/doc/uImage.FIT/sign-configs.its b/doc/uImage.FIT/sign-configs.its new file mode 100644 index 0000000..3c17f04 --- /dev/null +++ b/doc/uImage.FIT/sign-configs.its @@ -0,0 +1,45 @@ +/dts-v1/; + +/ { + description = "Chrome OS kernel image with one or more FDT blobs"; + #address-cells = <1>; + + images { + kernel@1 { + data = /incbin/("test-kernel.bin"); + type = "kernel_noload"; + arch = "sandbox"; + os = "linux"; + compression = "lzo"; + load = <0x4>; + entry = <0x8>; + kernel-version = <1>; + hash@1 { + algo = "sha1"; + }; + }; + fdt@1 { + description = "snow"; + data = /incbin/("sandbox-kernel.dtb"); + type = "flat_dt"; + arch = "sandbox"; + compression = "none"; + fdt-version = <1>; + hash@1 { + algo = "sha1"; + }; + }; + }; + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + signature@1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + sign-images = "fdt", "kernel"; + }; + }; + }; +}; diff --git a/doc/uImage.FIT/sign-images.its b/doc/uImage.FIT/sign-images.its new file mode 100644 index 0000000..f69326a --- /dev/null +++ b/doc/uImage.FIT/sign-images.its @@ -0,0 +1,42 @@ +/dts-v1/; + +/ { + description = "Chrome OS kernel image with one or more FDT blobs"; + #address-cells = <1>; + + images { + kernel@1 { + data = /incbin/("test-kernel.bin"); + type = "kernel_noload"; + arch = "sandbox"; + os = "linux"; + compression = "none"; + load = <0x4>; + entry = <0x8>; + kernel-version = <1>; + signature@1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + }; + }; + fdt@1 { + description = "snow"; + data = /incbin/("sandbox-kernel.dtb"); + type = "flat_dt"; + arch = "sandbox"; + compression = "none"; + fdt-version = <1>; + signature@1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + }; + }; + }; + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + }; + }; +}; diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt new file mode 100644 index 0000000..bc9f3fa --- /dev/null +++ b/doc/uImage.FIT/signature.txt @@ -0,0 +1,382 @@ +U-Boot FIT Signature Verification +================================= + +Introduction +------------ +FIT supports hashing of images so that these hashes can be checked on +loading. This protects against corruption of the image. However it does not +prevent the substitution of one image for another. + +The signature feature allows the hash to be signed with a private key such +that it can be verified using a public key later. Provided that the private +key is kept secret and the public key is stored in a non-volatile place, +any image can be verified in this way. + +See verified-boot.txt for more general information on verified boot. + + +Concepts +-------- +Some familiarity with public key cryptography is assumed in this section. + +The procedure for signing is as follows: + + - hash an image in the FIT + - sign the hash with a private key to produce a signature + - store the resulting signature in the FIT + +The procedure for verification is: + + - read the FIT + - obtain the public key + - extract the signature from the FIT + - hash the image from the FIT + - verify (with the public key) that the extracted signature matches the + hash + +The signing is generally performed by mkimage, as part of making a firmware +image for the device. The verification is normally done in U-Boot on the +device. + + +Algorithms +---------- +In principle any suitable algorithm can be used to sign and verify a hash. +At present only one class of algorithms is supported: SHA1 hashing with RSA. +This works by hashing the image to produce a 20-byte hash. + +While it is acceptable to bring in large cryptographic libraries such as +openssl on the host side (e.g. mkimage), it is not desirable for U-Boot. +For the run-time verification side, it is important to keep code and data +size as small as possible. + +For this reason the RSA image verification uses pre-processed public keys +which can be used with a very small amount of code - just some extraction +of data from the FDT and exponentiation mod n. Code size impact is a little +under 5KB on Tegra Seaboard, for example. + +It is relatively straightforward to add new algorithms if required. If +another RSA variant is needed, then it can be added to the table in +image-sig.c. If another algorithm is needed (such as DSA) then it can be +placed alongside rsa.c, and its functions added to the table in image-sig.c +also. + + +Creating an RSA key and certificate +----------------------------------- +To create a new public key, size 2048 bits: + +$ openssl genrsa -F4 -out keys/dev.key 2048 + +To create a certificate for this: + +$ openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt + +If you like you can look at the public key also: + +$ openssl rsa -in keys/dev.key -pubout + + +Device Tree Bindings +-------------------- +The following properties are required in the FIT's signature node(s) to +allow thes signer to operate. These should be added to the .its file. +Signature nodes sit at the same level as hash nodes and are called +signature@1, signature@2, etc. + +- algo: Algorithm name (e.g. "sha1,rs2048") + +- key-name-hint: Name of key to use for signing. The keys will normally be in +a single directory (parameter -k to mkimage). For a given key <name>, its +private key is stored in <name>.key and the certificate is stored in +<name>.crt. + +When the image is signed, the following properties are added (mandatory): + +- value: The signature data (e.g. 256 bytes for 2048-bit RSA) + +When the image is signed, the following properties are optional: + +- timestamp: Time when image was signed (standard Unix time_t format) + +- signer-name: Name of the signer (e.g. "mkimage") + +- signer-version: Version string of the signer (e.g. "2013.01") + +- comment: Additional information about the signer or image + +For config bindings (see Signed Configurations below), the following +additional properties are optional: + +- sign-images: A list of images to sign, each being a property of the conf +node that contains then. The default is "kernel,fdt" which means that these +two images will be looked up in the config and signed if present. + +For config bindings, these properties are added by the signer: + +- hashed-nodes: A list of nodes which were hashed by the signer. Each is + a string - the full path to node. A typical value might be: + + hashed-nodes = "/", "/configurations/conf@1", "/images/kernel@1", + "/images/kernel@1/hash@1", "/images/fdt@1", + "/images/fdt@1/hash@1"; + +- hashed-strings: The start and size of the string region of the FIT that + was hashed + +Example: See sign-images.its for an example image tree source file and +sign-configs.its for config signing. + + +Public Key Storage +------------------ +In order to verify an image that has been signed with a public key we need to +have a trusted public key. This cannot be stored in the signed image, since +it would be easy to alter. For this implementation we choose to store the +public key in U-Boot's control FDT (using CONFIG_OF_CONTROL). + +Public keys should be stored as sub-nodes in a /signature node. Required +properties are: + +- algo: Algorithm name (e.g. "sha1,rs2048") + +Optional properties are: + +- key-name-hint: Name of key used for signing. This is only a hint since it +is possible for the name to be changed. Verification can proceed by checking +all available signing keys until one matches. + +- required: If present this indicates that the key must be verified for the +image / configuration to be considered valid. Only required keys are +normally verified by the FIT image booting algorithm. Valid values are +"image" to force verification of all images, and "conf" to force verfication +of the selected configuration (which then relies on hashes in the images to +verify those). + +Each signing algorithm has its own additional properties. + +For RSA the following are mandatory: + +- rsa,num-bits: Number of key bits (e.g. 2048) +- rsa,modulus: Modulus (N) as a big-endian multi-word integer +- rsa,r-squared: (2^num-bits)^2 as a big-endian multi-word integer +- rsa,n0-inverse: -1 / modulus[0] mod 2^32 + + +Signed Configurations +--------------------- +While signing images is useful, it does not provide complete protection +against several types of attack. For example, it it possible to create a +FIT with the same signed images, but with the configuration changed such +that a different one is selected (mix and match attack). It is also possible +to substitute a signed image from an older FIT version into a newer FIT +(roll-back attack). + +As an example, consider this FIT: + +/ { + images { + kernel@1 { + data = <data for kernel1> + signature@1 { + algo = "sha1,rsa2048"; + value = <...kernel signature 1...> + }; + }; + kernel@2 { + data = <data for kernel2> + signature@1 { + algo = "sha1,rsa2048"; + value = <...kernel signature 2...> + }; + }; + fdt@1 { + data = <data for fdt1>; + signature@1 { + algo = "sha1,rsa2048"; + vaue = <...fdt signature 1...> + }; + }; + fdt@2 { + data = <data for fdt2>; + signature@1 { + algo = "sha1,rsa2048"; + vaue = <...fdt signature 2...> + }; + }; + }; + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + }; + conf@1 { + kernel = "kernel@2"; + fdt = "fdt@2"; + }; + }; +}; + +Since both kernels are signed it is easy for an attacker to add a new +configuration 3 with kernel 1 and fdt 2: + + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + }; + conf@1 { + kernel = "kernel@2"; + fdt = "fdt@2"; + }; + conf@3 { + kernel = "kernel@1"; + fdt = "fdt@2"; + }; + }; + +With signed images, nothing protects against this. Whether it gains an +advantage for the attacker is debatable, but it is not secure. + +To solved this problem, we support signed configurations. In this case it +is the configurations that are signed, not the image. Each image has its +own hash, and we include the hash in the configuration signature. + +So the above example is adjusted to look like this: + +/ { + images { + kernel@1 { + data = <data for kernel1> + hash@1 { + algo = "sha1"; + value = <...kernel hash 1...> + }; + }; + kernel@2 { + data = <data for kernel2> + hash@1 { + algo = "sha1"; + value = <...kernel hash 2...> + }; + }; + fdt@1 { + data = <data for fdt1>; + hash@1 { + algo = "sha1"; + value = <...fdt hash 1...> + }; + }; + fdt@2 { + data = <data for fdt2>; + hash@1 { + algo = "sha1"; + value = <...fdt hash 2...> + }; + }; + }; + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + signature@1 { + algo = "sha1,rsa2048"; + value = <...conf 1 signature...>; + }; + }; + conf@2 { + kernel = "kernel@2"; + fdt = "fdt@2"; + signature@1 { + algo = "sha1,rsa2048"; + value = <...conf 1 signature...>; + }; + }; + }; +}; + + +You can see that we have added hashes for all images (since they are no +longer signed), and a signature to each configuration. In the above example, +mkimage will sign configurations/conf@1, the kernel and fdt that are +pointed to by the configuration (/images/kernel@1, /images/kernel@1/hash@1, +/images/fdt@1, /images/fdt@1/hash@1) and the root structure of the image +(so that it isn't possible to add or remove root nodes). The signature is +written into /configurations/conf@1/signature@1/value. It can easily be +verified later even if the FIT has been signed with other keys in the +meantime. + + +Verification +------------ +FITs are verified when loaded. After the configuration is selected a list +of required images is produced. If there are 'required' public keys, then +each image must be verified against those keys. This means that every image +that might be used by the target needs to be signed with 'required' keys. + +This happens automatically as part of a bootm command when FITs are used. + + +Enabling FIT Verification +------------------------- +In addition to the options to enable FIT itself, the following CONFIGs must +be enabled: + +CONFIG_FIT_SIGNATURE - enable signing and verfication in FITs +CONFIG_RSA - enable RSA algorithm for signing + + +Testing +------- +An easy way to test signing and verfication is to use the test script +provided in test/vboot/vboot_test.sh. This uses sandbox (a special version +of U-Boot which runs under Linux) to show the operation of a 'bootm' +command loading and verifying images. + +A sample run is show below: + +$ make O=sandbox sandbox_config +$ make O=sandbox +$ O=sandbox ./test/vboot/vboot_test.sh +Simple Verified Boot Test +========================= + +Please see doc/uImage.FIT/verified-boot.txt for more information + +Build keys +Build FIT with signed images +Test Verified Boot Run: unsigned signatures:: OK +Sign images +Test Verified Boot Run: signed images: OK +Build FIT with signed configuration +Test Verified Boot Run: unsigned config: OK +Sign images +Test Verified Boot Run: signed config: OK + +Test passed + + +Future Work +----------- +- Roll-back protection using a TPM is done using the tpm command. This can +be scripted, but we might consider a default way of doing this, built into +bootm. + + +Possible Future Work +-------------------- +- Add support for other RSA/SHA variants, such as rsa4096,sha512. +- Other algorithms besides RSA +- More sandbox tests for failure modes +- Passwords for keys/certificates +- Perhaps implement OAEP +- Enhance bootm to permit scripted signature verification (so that a script +can verify an image but not actually boot it) + + +Simon Glass +sjg@chromium.org +1-1-13 diff --git a/doc/uImage.FIT/verified-boot.txt b/doc/uImage.FIT/verified-boot.txt new file mode 100644 index 0000000..3c83fbc --- /dev/null +++ b/doc/uImage.FIT/verified-boot.txt @@ -0,0 +1,104 @@ +U-Boot Verified Boot +==================== + +Introduction +------------ +Verified boot here means the verification of all software loaded into a +machine during the boot process to ensure that it is authorised and correct +for that machine. + +Verified boot extends from the moment of system reset to as far as you wish +into the boot process. An example might be loading U-Boot from read-only +memory, then loading a signed kernel, then using the kernel's dm-verity +driver to mount a signed root filesystem. + +A key point is that it is possible to field-upgrade the software on machines +which use verified boot. Since the machine will only run software that has +been correctly signed, it is safe to read software from an updatable medium. +It is also possible to add a secondary signed firmware image, in read-write +memory, so that firmware can easily be upgraded in a secure manner. + + +Signing +------- +Verified boot uses cryptographic algorithms to 'sign' software images. +Images are signed using a private key known only to the signer, but can +be verified using a public key. As its name suggests the public key can be +made available without risk to the verification process. The private and +public keys are mathematically related. For more information on how this +works look up "public key cryptography" and "RSA" (a particular algorithm). + +The signing and verification process looks something like this: + + + Signing Verification + ======= ============ + + +--------------+ * + | RSA key pair | * +---------------+ + | .key .crt | * | Public key in | + +--------------+ +------> public key ----->| trusted place | + | | * +---------------+ + | | * | + v | * v + +---------+ | * +--------------+ + | |----------+ * | | + | signer | * | U-Boot | + | |----------+ * | signature |--> yes/no + +---------+ | * | verification | + ^ | * | | + | | * +--------------+ + | | * ^ + +----------+ | * | + | Software | +----> signed image -------------+ + | image | * + +----------+ * + + +The signature algorithm relies only on the public key to do its work. Using +this key it checks the signature that it finds in the image. If it verifies +then we know that the image is OK. + +The public key from the signer allows us to verify and therefore trust +software from updatable memory. + +It is critical that the public key be secure and cannot be tampered with. +It can be stored in read-only memory, or perhaps protected by other on-chip +crypto provided by some modern SOCs. If the public key can ben changed, then +the verification is worthless. + + +Chaining Images +--------------- +The above method works for a signer providing images to a run-time U-Boot. +It is also possible to extend this scheme to a second level, like this: + +1. Master private key is used by the signer to sign a first-stage image. +2. Master public key is placed in read-only memory. +2. Secondary private key is created and used to sign second-stage images. +3. Secondary public key is placed in first stage images +4. We use the master public key to verify the first-stage image. We then +use the secondary public key in the first-stage image to verify the second- +state image. +5. This chaining process can go on indefinitely. It is recommended to use a +different key at each stage, so that a compromise in one place will not +affect the whole change. + + +Flattened Image Tree (FIT) +-------------------------- +The FIT format is alreay widely used in U-Boot. It is a flattened device +tree (FDT) in a particular format, with images contained within. FITs +include hashes to verify images, so it is relatively straightforward to +add signatures as well. + +The public key can be stored in U-Boot's CONFIG_OF_CONTROL device tree in +a standard place. Then when a FIT it loaded it can be verified using that +public key. Multiple keys and multiple signatures are supported. + +See signature.txt for more information. + + +Simon Glass +sjg@chromium.org +1-1-13 diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 6af6890..0521752 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -20,6 +20,7 @@ */ #include <common.h> +#include <errno.h> #include <malloc.h> #include <mmc.h> #include <fat.h> @@ -41,8 +42,34 @@ static int dfu_find_alt_num(const char *s) return ++i; } -static unsigned char __aligned(CONFIG_SYS_CACHELINE_SIZE) - dfu_buf[DFU_DATA_BUF_SIZE]; +static unsigned char *dfu_buf; +static unsigned long dfu_buf_size = CONFIG_SYS_DFU_DATA_BUF_SIZE; + +static unsigned char *dfu_free_buf(void) +{ + free(dfu_buf); + dfu_buf = NULL; + return dfu_buf; +} + +static unsigned char *dfu_get_buf(void) +{ + char *s; + + if (dfu_buf != NULL) + return dfu_buf; + + s = getenv("dfu_bufsiz"); + dfu_buf_size = s ? (unsigned long)simple_strtol(s, NULL, 16) : + CONFIG_SYS_DFU_DATA_BUF_SIZE; + + dfu_buf = memalign(CONFIG_SYS_CACHELINE_SIZE, dfu_buf_size); + if (dfu_buf == NULL) + printf("%s: Could not memalign 0x%lx bytes\n", + __func__, dfu_buf_size); + + return dfu_buf; +} static int dfu_write_buffer_drain(struct dfu_entity *dfu) { @@ -87,8 +114,10 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) dfu->offset = 0; dfu->bad_skip = 0; dfu->i_blk_seq_num = 0; - dfu->i_buf_start = dfu_buf; - dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf_start = dfu_get_buf(); + if (dfu->i_buf_start == NULL) + return -ENOMEM; + dfu->i_buf_end = dfu_get_buf() + dfu_buf_size; dfu->i_buf = dfu->i_buf_start; dfu->inited = 1; @@ -148,11 +177,12 @@ int dfu_write(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) printf("\nDFU complete CRC32: 0x%08x\n", dfu->crc); /* clear everything */ + dfu_free_buf(); dfu->crc = 0; dfu->offset = 0; dfu->i_blk_seq_num = 0; dfu->i_buf_start = dfu_buf; - dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf_end = dfu_buf; dfu->i_buf = dfu->i_buf_start; dfu->inited = 0; @@ -218,7 +248,11 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) __func__, dfu->name, buf, size, blk_seq_num, dfu->i_buf); if (!dfu->inited) { - ret = dfu->read_medium(dfu, 0, buf, &dfu->r_left); + dfu->i_buf_start = dfu_get_buf(); + if (dfu->i_buf_start == NULL) + return -ENOMEM; + + ret = dfu->read_medium(dfu, 0, dfu->i_buf_start, &dfu->r_left); if (ret != 0) { debug("%s: failed to get r_left\n", __func__); return ret; @@ -229,8 +263,7 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) dfu->i_blk_seq_num = 0; dfu->crc = 0; dfu->offset = 0; - dfu->i_buf_start = dfu_buf; - dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf_end = dfu_get_buf() + dfu_buf_size; dfu->i_buf = dfu->i_buf_start; dfu->b_left = 0; @@ -257,11 +290,12 @@ int dfu_read(struct dfu_entity *dfu, void *buf, int size, int blk_seq_num) debug("%s: %s CRC32: 0x%x\n", __func__, dfu->name, dfu->crc); puts("\nUPLOAD ... done\nCtrl+C to exit ...\n"); + dfu_free_buf(); dfu->i_blk_seq_num = 0; dfu->crc = 0; dfu->offset = 0; dfu->i_buf_start = dfu_buf; - dfu->i_buf_end = dfu_buf + sizeof(dfu_buf); + dfu->i_buf_end = dfu_buf; dfu->i_buf = dfu->i_buf_start; dfu->b_left = 0; diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index e2f3978..e7ee077 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -98,6 +98,8 @@ static int mmc_file_op(enum dfu_mmc_op op, struct dfu_entity *dfu, op == DFU_OP_READ ? "load" : "write", dfu->data.mmc.dev, dfu->data.mmc.part, (unsigned int) buf, dfu->name); + if (op == DFU_OP_WRITE) + sprintf(cmd_buf + strlen(cmd_buf), " %ld", *len); break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, diff --git a/drivers/dfu/dfu_nand.c b/drivers/dfu/dfu_nand.c index 7dc89b2..07dee89 100644 --- a/drivers/dfu/dfu_nand.c +++ b/drivers/dfu/dfu_nand.c @@ -63,12 +63,26 @@ static int nand_block_op(enum dfu_nand_op op, struct dfu_entity *dfu, nand = &nand_info[nand_curr_device]; - if (op == DFU_OP_READ) + if (op == DFU_OP_READ) { ret = nand_read_skip_bad(nand, start, &count, &actual, lim, buf); - else + } else { + nand_erase_options_t opts; + + memset(&opts, 0, sizeof(opts)); + opts.offset = start; + opts.length = count; + opts.spread = 1; + opts.quiet = 1; + opts.lim = lim; + /* first erase */ + ret = nand_erase_opts(nand, &opts); + if (ret) + return ret; + /* then write */ ret = nand_write_skip_bad(nand, start, &count, &actual, lim, buf, 0); + } if (ret != 0) { printf("%s: nand_%s_skip_bad call failed at %llx!\n", diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c index f3adf64..bb8e644 100644 --- a/drivers/hwmon/lm63.c +++ b/drivers/hwmon/lm63.c @@ -133,8 +133,7 @@ int dtt_init_one(int sensor) /* * Setup PWM Lookup-Table */ - for (i = 0; i < sizeof(pwm_lookup) / sizeof(struct pwm_lookup_entry); - i++) { + for (i = 0; i < ARRAY_SIZE(pwm_lookup); i++) { int address = DTT_PWM_LOOKUP_BASE + 2 * i; val = pwm_lookup[i].temp; if (is_lm64(sensor)) diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 0805e86..4331190 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -27,6 +27,7 @@ LIB := $(obj)libinput.o COBJS-$(CONFIG_I8042_KBD) += i8042.o COBJS-$(CONFIG_TEGRA_KEYBOARD) += tegra-kbc.o +COBJS-$(CONFIG_CROS_EC_KEYB) += cros_ec_keyb.o ifdef CONFIG_PS2KBD COBJS-y += keyboard.o pc_keyb.o COBJS-$(CONFIG_PS2MULT) += ps2mult.o ps2ser.o diff --git a/drivers/input/cros_ec_keyb.c b/drivers/input/cros_ec_keyb.c new file mode 100644 index 0000000..c197308 --- /dev/null +++ b/drivers/input/cros_ec_keyb.c @@ -0,0 +1,261 @@ +/* + * Chromium OS Matrix Keyboard + * + * Copyright (c) 2012 The Chromium OS Authors. + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <cros_ec.h> +#include <fdtdec.h> +#include <input.h> +#include <key_matrix.h> +#include <stdio_dev.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum { + KBC_MAX_KEYS = 8, /* Maximum keys held down at once */ +}; + +static struct keyb { + struct cros_ec_dev *dev; /* The CROS_EC device */ + struct input_config input; /* The input layer */ + struct key_matrix matrix; /* The key matrix layer */ + int key_rows; /* Number of keyboard rows */ + int key_cols; /* Number of keyboard columns */ + unsigned int repeat_delay_ms; /* Time before autorepeat starts */ + unsigned int repeat_rate_ms; /* Autorepeat rate in ms */ + int ghost_filter; /* 1 to enable ghost filter, else 0 */ + int inited; /* 1 if keyboard is ready */ +} config; + + +/** + * Check the keyboard controller and return a list of key matrix positions + * for which a key is pressed + * + * @param config Keyboard config + * @param keys List of keys that we have detected + * @param max_count Maximum number of keys to return + * @return number of pressed keys, 0 for none + */ +static int check_for_keys(struct keyb *config, + struct key_matrix_key *keys, int max_count) +{ + struct key_matrix_key *key; + struct mbkp_keyscan scan; + unsigned int row, col, bit, data; + int num_keys; + + if (cros_ec_scan_keyboard(config->dev, &scan)) { + debug("%s: keyboard scan failed\n", __func__); + return -1; + } + + for (col = num_keys = bit = 0; col < config->matrix.num_cols; + col++) { + for (row = 0; row < config->matrix.num_rows; row++) { + unsigned int mask = 1 << (bit & 7); + + data = scan.data[bit / 8]; + if ((data & mask) && num_keys < max_count) { + key = keys + num_keys++; + key->row = row; + key->col = col; + key->valid = 1; + } + bit++; + } + } + + return num_keys; +} + +/** + * Test if keys are available to be read + * + * @return 0 if no keys available, 1 if keys are available + */ +static int kbd_tstc(void) +{ + /* Just get input to do this for us */ + return config.inited ? input_tstc(&config.input) : 0; +} + +/** + * Read a key + * + * @return ASCII key code, or 0 if no key, or -1 if error + */ +static int kbd_getc(void) +{ + /* Just get input to do this for us */ + return config.inited ? input_getc(&config.input) : 0; +} + +/** + * Check the keyboard, and send any keys that are pressed. + * + * This is called by input_tstc() and input_getc() when they need more + * characters + * + * @param input Input configuration + * @return 1, to indicate that we have something to look at + */ +int cros_ec_kbc_check(struct input_config *input) +{ + static struct key_matrix_key last_keys[KBC_MAX_KEYS]; + static int last_num_keys; + struct key_matrix_key keys[KBC_MAX_KEYS]; + int keycodes[KBC_MAX_KEYS]; + int num_keys, num_keycodes; + int irq_pending, sent; + + /* + * Loop until the EC has no more keyscan records, or we have + * received at least one character. This means we know that tstc() + * will always return non-zero if keys have been pressed. + * + * Without this loop, a key release (which generates no new ascii + * characters) will cause us to exit this function, and just tstc() + * may return 0 before all keys have been read from the EC. + */ + do { + irq_pending = cros_ec_interrupt_pending(config.dev); + if (irq_pending) { + num_keys = check_for_keys(&config, keys, KBC_MAX_KEYS); + last_num_keys = num_keys; + memcpy(last_keys, keys, sizeof(keys)); + } else { + /* + * EC doesn't want to be asked, so use keys from last + * time. + */ + num_keys = last_num_keys; + memcpy(keys, last_keys, sizeof(keys)); + } + + if (num_keys < 0) + return -1; + num_keycodes = key_matrix_decode(&config.matrix, keys, + num_keys, keycodes, KBC_MAX_KEYS); + sent = input_send_keycodes(input, keycodes, num_keycodes); + } while (irq_pending && !sent); + + return 1; +} + +/** + * Decode MBKP keyboard details from the device tree + * + * @param blob Device tree blob + * @param node Node to decode from + * @param config Configuration data read from fdt + * @return 0 if ok, -1 on error + */ +static int cros_ec_keyb_decode_fdt(const void *blob, int node, + struct keyb *config) +{ + /* + * Get keyboard rows and columns - at present we are limited to + * 8 columns by the protocol (one byte per row scan) + */ + config->key_rows = fdtdec_get_int(blob, node, "google,key-rows", 0); + config->key_cols = fdtdec_get_int(blob, node, "google,key-columns", 0); + if (!config->key_rows || !config->key_cols || + config->key_rows * config->key_cols / 8 + > CROS_EC_KEYSCAN_COLS) { + debug("%s: Invalid key matrix size %d x %d\n", __func__, + config->key_rows, config->key_cols); + return -1; + } + config->repeat_delay_ms = fdtdec_get_int(blob, node, + "google,repeat-delay-ms", 0); + config->repeat_rate_ms = fdtdec_get_int(blob, node, + "google,repeat-rate-ms", 0); + config->ghost_filter = fdtdec_get_bool(blob, node, + "google,ghost-filter"); + return 0; +} + +/** + * Set up the keyboard. This is called by the stdio device handler. + * + * We want to do this init when the keyboard is actually used rather than + * at start-up, since keyboard input may not currently be selected. + * + * @return 0 if ok, -1 on error + */ +static int cros_ec_init_keyboard(void) +{ + const void *blob = gd->fdt_blob; + int node; + + config.dev = board_get_cros_ec_dev(); + if (!config.dev) { + debug("%s: no cros_ec device: cannot init keyboard\n", + __func__); + return -1; + } + node = fdtdec_next_compatible(blob, 0, COMPAT_GOOGLE_CROS_EC_KEYB); + if (node < 0) { + debug("%s: Node not found\n", __func__); + return -1; + } + if (cros_ec_keyb_decode_fdt(blob, node, &config)) + return -1; + input_set_delays(&config.input, config.repeat_delay_ms, + config.repeat_rate_ms); + if (key_matrix_init(&config.matrix, config.key_rows, + config.key_cols, config.ghost_filter)) { + debug("%s: cannot init key matrix\n", __func__); + return -1; + } + if (key_matrix_decode_fdt(&config.matrix, gd->fdt_blob, node)) { + debug("%s: Could not decode key matrix from fdt\n", __func__); + return -1; + } + config.inited = 1; + debug("%s: Matrix keyboard %dx%d ready\n", __func__, config.key_rows, + config.key_cols); + + return 0; +} + +int drv_keyboard_init(void) +{ + struct stdio_dev dev; + + if (input_init(&config.input, 0)) { + debug("%s: Cannot set up input\n", __func__); + return -1; + } + config.input.read_keys = cros_ec_kbc_check; + + memset(&dev, '\0', sizeof(dev)); + strcpy(dev.name, "cros-ec-keyb"); + dev.flags = DEV_FLAGS_INPUT | DEV_FLAGS_SYSTEM; + dev.getc = kbd_getc; + dev.tstc = kbd_tstc; + dev.start = cros_ec_init_keyboard; + + /* Register the device. cros_ec_init_keyboard() will be called soon */ + return input_stdio_register(&dev); +} diff --git a/drivers/input/key_matrix.c b/drivers/input/key_matrix.c index 946a186..c900e45 100644 --- a/drivers/input/key_matrix.c +++ b/drivers/input/key_matrix.c @@ -154,54 +154,42 @@ static uchar *create_keymap(struct key_matrix *config, u32 *data, int len, return map; } -int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, - int node) +int key_matrix_decode_fdt(struct key_matrix *config, const void *blob, int node) { const struct fdt_property *prop; - const char prefix[] = "linux,"; - int plen = sizeof(prefix) - 1; - int offset; - - /* Check each property name for ones that we understand */ - for (offset = fdt_first_property_offset(blob, node); - offset > 0; - offset = fdt_next_property_offset(blob, offset)) { - const char *name; - int len; - - prop = fdt_get_property_by_offset(blob, offset, NULL); - name = fdt_string(blob, fdt32_to_cpu(prop->nameoff)); - len = strlen(name); - - /* Name needs to match "1,<type>keymap" */ - debug("%s: property '%s'\n", __func__, name); - if (strncmp(name, prefix, plen) || - len < plen + 6 || - strcmp(name + len - 6, "keymap")) - continue; + int proplen; + uchar *plain_keycode; - len -= plen + 6; - if (len == 0) { - config->plain_keycode = create_keymap(config, - (u32 *)prop->data, fdt32_to_cpu(prop->len), - KEY_FN, &config->fn_pos); - } else if (0 == strncmp(name + plen, "fn-", len)) { - config->fn_keycode = create_keymap(config, - (u32 *)prop->data, fdt32_to_cpu(prop->len), - -1, NULL); - } else { - debug("%s: unrecognised property '%s'\n", __func__, - name); - } + prop = fdt_get_property(blob, node, "linux,keymap", &proplen); + /* Basic keymap is required */ + if (!prop) { + debug("%s: cannot find keycode-plain map\n", __func__); + return -1; } - debug("%s: Decoded key maps %p, %p from fdt\n", __func__, - config->plain_keycode, config->fn_keycode); - if (!config->plain_keycode) { - debug("%s: cannot find keycode-plain map\n", __func__); + plain_keycode = create_keymap(config, (u32 *)prop->data, + proplen, KEY_FN, &config->fn_pos); + config->plain_keycode = plain_keycode; + /* Conversion error -> fail */ + if (!config->plain_keycode) + return -1; + + prop = fdt_get_property(blob, node, "linux,fn-keymap", &proplen); + /* fn keymap is optional */ + if (!prop) + goto done; + + config->fn_keycode = create_keymap(config, (u32 *)prop->data, + proplen, -1, NULL); + /* Conversion error -> fail */ + if (!config->fn_keycode) { + free(plain_keycode); return -1; } +done: + debug("%s: Decoded key maps %p, %p from fdt\n", __func__, + config->plain_keycode, config->fn_keycode); return 0; } diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 5d869b4..5fbff8a 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,6 +28,10 @@ LIB := $(obj)libmisc.o COBJS-$(CONFIG_ALI152X) += ali512x.o COBJS-$(CONFIG_DS4510) += ds4510.o COBJS-$(CONFIG_CBMEM_CONSOLE) += cbmem_console.o +COBJS-$(CONFIG_CROS_EC) += cros_ec.o +COBJS-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o +COBJS-$(CONFIG_CROS_EC_I2C) += cros_ec_i2c.o +COBJS-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o COBJS-$(CONFIG_FSL_IIM) += fsl_iim.o COBJS-$(CONFIG_GPIO_LED) += gpio_led.o COBJS-$(CONFIG_FSL_MC9SDZ60) += mc9sdz60.o diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c new file mode 100644 index 0000000..6e774d9 --- /dev/null +++ b/drivers/misc/cros_ec.c @@ -0,0 +1,1304 @@ +/* + * Chromium OS cros_ec driver + * + * Copyright (c) 2012 The Chromium OS Authors. + * 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 + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <command.h> +#include <i2c.h> +#include <cros_ec.h> +#include <fdtdec.h> +#include <malloc.h> +#include <spi.h> +#include <asm/io.h> +#include <asm-generic/gpio.h> + +#ifdef DEBUG_TRACE +#define debug_trace(fmt, b...) debug(fmt, #b) +#else +#define debug_trace(fmt, b...) +#endif + +enum { + /* Timeout waiting for a flash erase command to complete */ + CROS_EC_CMD_TIMEOUT_MS = 5000, + /* Timeout waiting for a synchronous hash to be recomputed */ + CROS_EC_CMD_HASH_TIMEOUT_MS = 2000, +}; + +static struct cros_ec_dev static_dev, *last_dev; + +DECLARE_GLOBAL_DATA_PTR; + +/* Note: depends on enum ec_current_image */ +static const char * const ec_current_image_name[] = {"unknown", "RO", "RW"}; + +void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len) +{ +#ifdef DEBUG + int i; + + printf("%s: ", name); + if (cmd != -1) + printf("cmd=%#x: ", cmd); + for (i = 0; i < len; i++) + printf("%02x ", data[i]); + printf("\n"); +#endif +} + +/* + * Calculate a simple 8-bit checksum of a data block + * + * @param data Data block to checksum + * @param size Size of data block in bytes + * @return checksum value (0 to 255) + */ +int cros_ec_calc_checksum(const uint8_t *data, int size) +{ + int csum, i; + + for (i = csum = 0; i < size; i++) + csum += data[i]; + return csum & 0xff; +} + +static int send_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const void *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + int ret; + + switch (dev->interface) { +#ifdef CONFIG_CROS_EC_SPI + case CROS_EC_IF_SPI: + ret = cros_ec_spi_command(dev, cmd, cmd_version, + (const uint8_t *)dout, dout_len, + dinp, din_len); + break; +#endif +#ifdef CONFIG_CROS_EC_I2C + case CROS_EC_IF_I2C: + ret = cros_ec_i2c_command(dev, cmd, cmd_version, + (const uint8_t *)dout, dout_len, + dinp, din_len); + break; +#endif +#ifdef CONFIG_CROS_EC_LPC + case CROS_EC_IF_LPC: + ret = cros_ec_lpc_command(dev, cmd, cmd_version, + (const uint8_t *)dout, dout_len, + dinp, din_len); + break; +#endif + case CROS_EC_IF_NONE: + default: + ret = -1; + } + + return ret; +} + +/** + * Send a command to the CROS-EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev CROS-EC device + * @param cmd Command to send (EC_CMD_...) + * @param cmd_version Version of command to send (EC_VER_...) + * @param dout Output data (may be NULL If dout_len=0) + * @param dout_len Size of output data in bytes + * @param dinp Response data (may be NULL If din_len=0). + * If not NULL, it will be updated to point to the data + * and will always be double word aligned (64-bits) + * @param din_len Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd, + int cmd_version, const void *dout, int dout_len, uint8_t **dinp, + int din_len) +{ + uint8_t *din; + int len; + + if (cmd_version != 0 && !dev->cmd_version_is_supported) { + debug("%s: Command version >0 unsupported\n", __func__); + return -1; + } + len = send_command(dev, cmd, cmd_version, dout, dout_len, + &din, din_len); + + /* If the command doesn't complete, wait a while */ + if (len == -EC_RES_IN_PROGRESS) { + struct ec_response_get_comms_status *resp; + ulong start; + + /* Wait for command to complete */ + start = get_timer(0); + do { + int ret; + + mdelay(50); /* Insert some reasonable delay */ + ret = send_command(dev, EC_CMD_GET_COMMS_STATUS, 0, + NULL, 0, + (uint8_t **)&resp, sizeof(*resp)); + if (ret < 0) + return ret; + + if (get_timer(start) > CROS_EC_CMD_TIMEOUT_MS) { + debug("%s: Command %#02x timeout\n", + __func__, cmd); + return -EC_RES_TIMEOUT; + } + } while (resp->flags & EC_COMMS_STATUS_PROCESSING); + + /* OK it completed, so read the status response */ + /* not sure why it was 0 for the last argument */ + len = send_command(dev, EC_CMD_RESEND_RESPONSE, 0, + NULL, 0, &din, din_len); + } + + debug("%s: len=%d, dinp=%p, *dinp=%p\n", __func__, len, dinp, *dinp); + if (dinp) { + /* If we have any data to return, it must be 64bit-aligned */ + assert(len <= 0 || !((uintptr_t)din & 7)); + *dinp = din; + } + + return len; +} + +/** + * Send a command to the CROS-EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev CROS-EC device + * @param cmd Command to send (EC_CMD_...) + * @param cmd_version Version of command to send (EC_VER_...) + * @param dout Output data (may be NULL If dout_len=0) + * @param dout_len Size of output data in bytes + * @param din Response data (may be NULL If din_len=0). + * It not NULL, it is a place for ec_command() to copy the + * data to. + * @param din_len Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const void *dout, int dout_len, + void *din, int din_len) +{ + uint8_t *in_buffer; + int len; + + assert((din_len == 0) || din); + len = ec_command_inptr(dev, cmd, cmd_version, dout, dout_len, + &in_buffer, din_len); + if (len > 0) { + /* + * If we were asked to put it somewhere, do so, otherwise just + * disregard the result. + */ + if (din && in_buffer) { + assert(len <= din_len); + memmove(din, in_buffer, len); + } + } + return len; +} + +int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan) +{ + if (ec_command(dev, EC_CMD_CROS_EC_STATE, 0, NULL, 0, scan, + sizeof(scan->data)) < sizeof(scan->data)) + return -1; + + return 0; +} + +int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen) +{ + struct ec_response_get_version *r; + + if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, + (uint8_t **)&r, sizeof(*r)) < sizeof(*r)) + return -1; + + if (maxlen > sizeof(r->version_string_ro)) + maxlen = sizeof(r->version_string_ro); + + switch (r->current_image) { + case EC_IMAGE_RO: + memcpy(id, r->version_string_ro, maxlen); + break; + case EC_IMAGE_RW: + memcpy(id, r->version_string_rw, maxlen); + break; + default: + return -1; + } + + id[maxlen - 1] = '\0'; + return 0; +} + +int cros_ec_read_version(struct cros_ec_dev *dev, + struct ec_response_get_version **versionp) +{ + if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, + (uint8_t **)versionp, sizeof(**versionp)) + < sizeof(**versionp)) + return -1; + + return 0; +} + +int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp) +{ + if (ec_command_inptr(dev, EC_CMD_GET_BUILD_INFO, 0, NULL, 0, + (uint8_t **)strp, EC_HOST_PARAM_SIZE) < 0) + return -1; + + return 0; +} + +int cros_ec_read_current_image(struct cros_ec_dev *dev, + enum ec_current_image *image) +{ + struct ec_response_get_version *r; + + if (ec_command_inptr(dev, EC_CMD_GET_VERSION, 0, NULL, 0, + (uint8_t **)&r, sizeof(*r)) < sizeof(*r)) + return -1; + + *image = r->current_image; + return 0; +} + +static int cros_ec_wait_on_hash_done(struct cros_ec_dev *dev, + struct ec_response_vboot_hash *hash) +{ + struct ec_params_vboot_hash p; + ulong start; + + start = get_timer(0); + while (hash->status == EC_VBOOT_HASH_STATUS_BUSY) { + mdelay(50); /* Insert some reasonable delay */ + + p.cmd = EC_VBOOT_HASH_GET; + if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), + hash, sizeof(*hash)) < 0) + return -1; + + if (get_timer(start) > CROS_EC_CMD_HASH_TIMEOUT_MS) { + debug("%s: EC_VBOOT_HASH_GET timeout\n", __func__); + return -EC_RES_TIMEOUT; + } + } + return 0; +} + + +int cros_ec_read_hash(struct cros_ec_dev *dev, + struct ec_response_vboot_hash *hash) +{ + struct ec_params_vboot_hash p; + int rv; + + p.cmd = EC_VBOOT_HASH_GET; + if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), + hash, sizeof(*hash)) < 0) + return -1; + + /* If the EC is busy calculating the hash, fidget until it's done. */ + rv = cros_ec_wait_on_hash_done(dev, hash); + if (rv) + return rv; + + /* If the hash is valid, we're done. Otherwise, we have to kick it off + * again and wait for it to complete. Note that we explicitly assume + * that hashing zero bytes is always wrong, even though that would + * produce a valid hash value. */ + if (hash->status == EC_VBOOT_HASH_STATUS_DONE && hash->size) + return 0; + + debug("%s: No valid hash (status=%d size=%d). Compute one...\n", + __func__, hash->status, hash->size); + + p.cmd = EC_VBOOT_HASH_RECALC; + p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; + p.nonce_size = 0; + p.offset = EC_VBOOT_HASH_OFFSET_RW; + + if (ec_command(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), + hash, sizeof(*hash)) < 0) + return -1; + + rv = cros_ec_wait_on_hash_done(dev, hash); + if (rv) + return rv; + + debug("%s: hash done\n", __func__); + + return 0; +} + +static int cros_ec_invalidate_hash(struct cros_ec_dev *dev) +{ + struct ec_params_vboot_hash p; + struct ec_response_vboot_hash *hash; + + /* We don't have an explict command for the EC to discard its current + * hash value, so we'll just tell it to calculate one that we know is + * wrong (we claim that hashing zero bytes is always invalid). + */ + p.cmd = EC_VBOOT_HASH_RECALC; + p.hash_type = EC_VBOOT_HASH_TYPE_SHA256; + p.nonce_size = 0; + p.offset = 0; + p.size = 0; + + debug("%s:\n", __func__); + + if (ec_command_inptr(dev, EC_CMD_VBOOT_HASH, 0, &p, sizeof(p), + (uint8_t **)&hash, sizeof(*hash)) < 0) + return -1; + + /* No need to wait for it to finish */ + return 0; +} + +int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd, + uint8_t flags) +{ + struct ec_params_reboot_ec p; + + p.cmd = cmd; + p.flags = flags; + + if (ec_command_inptr(dev, EC_CMD_REBOOT_EC, 0, &p, sizeof(p), NULL, 0) + < 0) + return -1; + + if (!(flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN)) { + /* + * EC reboot will take place immediately so delay to allow it + * to complete. Note that some reboot types (EC_REBOOT_COLD) + * will reboot the AP as well, in which case we won't actually + * get to this point. + */ + /* + * TODO(rspangler@chromium.org): Would be nice if we had a + * better way to determine when the reboot is complete. Could + * we poll a memory-mapped LPC value? + */ + udelay(50000); + } + + return 0; +} + +int cros_ec_interrupt_pending(struct cros_ec_dev *dev) +{ + /* no interrupt support : always poll */ + if (!fdt_gpio_isvalid(&dev->ec_int)) + return 1; + + return !gpio_get_value(dev->ec_int.gpio); +} + +int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_cros_ec_info *info) +{ + if (ec_command(dev, EC_CMD_CROS_EC_INFO, 0, NULL, 0, info, + sizeof(*info)) < sizeof(*info)) + return -1; + + return 0; +} + +int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr) +{ + struct ec_response_host_event_mask *resp; + + /* + * Use the B copy of the event flags, because the main copy is already + * used by ACPI/SMI. + */ + if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_GET_B, 0, NULL, 0, + (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) + return -1; + + if (resp->mask & EC_HOST_EVENT_MASK(EC_HOST_EVENT_INVALID)) + return -1; + + *events_ptr = resp->mask; + return 0; +} + +int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events) +{ + struct ec_params_host_event_mask params; + + params.mask = events; + + /* + * Use the B copy of the event flags, so it affects the data returned + * by cros_ec_get_host_events(). + */ + if (ec_command_inptr(dev, EC_CMD_HOST_EVENT_CLEAR_B, 0, + ¶ms, sizeof(params), NULL, 0) < 0) + return -1; + + return 0; +} + +int cros_ec_flash_protect(struct cros_ec_dev *dev, + uint32_t set_mask, uint32_t set_flags, + struct ec_response_flash_protect *resp) +{ + struct ec_params_flash_protect params; + + params.mask = set_mask; + params.flags = set_flags; + + if (ec_command(dev, EC_CMD_FLASH_PROTECT, EC_VER_FLASH_PROTECT, + ¶ms, sizeof(params), + resp, sizeof(*resp)) < sizeof(*resp)) + return -1; + + return 0; +} + +static int cros_ec_check_version(struct cros_ec_dev *dev) +{ + struct ec_params_hello req; + struct ec_response_hello *resp; + +#ifdef CONFIG_CROS_EC_LPC + /* LPC has its own way of doing this */ + if (dev->interface == CROS_EC_IF_LPC) + return cros_ec_lpc_check_version(dev); +#endif + + /* + * TODO(sjg@chromium.org). + * There is a strange oddity here with the EC. We could just ignore + * the response, i.e. pass the last two parameters as NULL and 0. + * In this case we won't read back very many bytes from the EC. + * On the I2C bus the EC gets upset about this and will try to send + * the bytes anyway. This means that we will have to wait for that + * to complete before continuing with a new EC command. + * + * This problem is probably unique to the I2C bus. + * + * So for now, just read all the data anyway. + */ + dev->cmd_version_is_supported = 1; + if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), + (uint8_t **)&resp, sizeof(*resp)) > 0) { + /* It appears to understand new version commands */ + dev->cmd_version_is_supported = 1; + } else { + dev->cmd_version_is_supported = 0; + if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, + sizeof(req), (uint8_t **)&resp, + sizeof(*resp)) < 0) { + debug("%s: Failed both old and new command style\n", + __func__); + return -1; + } + } + + return 0; +} + +int cros_ec_test(struct cros_ec_dev *dev) +{ + struct ec_params_hello req; + struct ec_response_hello *resp; + + req.in_data = 0x12345678; + if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), + (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) { + printf("ec_command_inptr() returned error\n"); + return -1; + } + if (resp->out_data != req.in_data + 0x01020304) { + printf("Received invalid handshake %x\n", resp->out_data); + return -1; + } + + return 0; +} + +int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region, + uint32_t *offset, uint32_t *size) +{ + struct ec_params_flash_region_info p; + struct ec_response_flash_region_info *r; + int ret; + + p.region = region; + ret = ec_command_inptr(dev, EC_CMD_FLASH_REGION_INFO, + EC_VER_FLASH_REGION_INFO, + &p, sizeof(p), (uint8_t **)&r, sizeof(*r)); + if (ret != sizeof(*r)) + return -1; + + if (offset) + *offset = r->offset; + if (size) + *size = r->size; + + return 0; +} + +int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, uint32_t size) +{ + struct ec_params_flash_erase p; + + p.offset = offset; + p.size = size; + return ec_command_inptr(dev, EC_CMD_FLASH_ERASE, 0, &p, sizeof(p), + NULL, 0); +} + +/** + * Write a single block to the flash + * + * Write a block of data to the EC flash. The size must not exceed the flash + * write block size which you can obtain from cros_ec_flash_write_burst_size(). + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to write for a particular region. + * + * Attempting to write to the region where the EC is currently running from + * will result in an error. + * + * @param dev CROS-EC device + * @param data Pointer to data buffer to write + * @param offset Offset within flash to write to. + * @param size Number of bytes to write + * @return 0 if ok, -1 on error + */ +static int cros_ec_flash_write_block(struct cros_ec_dev *dev, + const uint8_t *data, uint32_t offset, uint32_t size) +{ + struct ec_params_flash_write p; + + p.offset = offset; + p.size = size; + assert(data && p.size <= sizeof(p.data)); + memcpy(p.data, data, p.size); + + return ec_command_inptr(dev, EC_CMD_FLASH_WRITE, 0, + &p, sizeof(p), NULL, 0) >= 0 ? 0 : -1; +} + +/** + * Return optimal flash write burst size + */ +static int cros_ec_flash_write_burst_size(struct cros_ec_dev *dev) +{ + struct ec_params_flash_write p; + return sizeof(p.data); +} + +/** + * Check if a block of data is erased (all 0xff) + * + * This function is useful when dealing with flash, for checking whether a + * data block is erased and thus does not need to be programmed. + * + * @param data Pointer to data to check (must be word-aligned) + * @param size Number of bytes to check (must be word-aligned) + * @return 0 if erased, non-zero if any word is not erased + */ +static int cros_ec_data_is_erased(const uint32_t *data, int size) +{ + assert(!(size & 3)); + size /= sizeof(uint32_t); + for (; size > 0; size -= 4, data++) + if (*data != -1U) + return 0; + + return 1; +} + +int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data, + uint32_t offset, uint32_t size) +{ + uint32_t burst = cros_ec_flash_write_burst_size(dev); + uint32_t end, off; + int ret; + + /* + * TODO: round up to the nearest multiple of write size. Can get away + * without that on link right now because its write size is 4 bytes. + */ + end = offset + size; + for (off = offset; off < end; off += burst, data += burst) { + uint32_t todo; + + /* If the data is empty, there is no point in programming it */ + todo = min(end - off, burst); + if (dev->optimise_flash_write && + cros_ec_data_is_erased((uint32_t *)data, todo)) + continue; + + ret = cros_ec_flash_write_block(dev, data, off, todo); + if (ret) + return ret; + } + + return 0; +} + +/** + * Read a single block from the flash + * + * Read a block of data from the EC flash. The size must not exceed the flash + * write block size which you can obtain from cros_ec_flash_write_burst_size(). + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to read for a particular region. + * + * @param dev CROS-EC device + * @param data Pointer to data buffer to read into + * @param offset Offset within flash to read from + * @param size Number of bytes to read + * @return 0 if ok, -1 on error + */ +static int cros_ec_flash_read_block(struct cros_ec_dev *dev, uint8_t *data, + uint32_t offset, uint32_t size) +{ + struct ec_params_flash_read p; + + p.offset = offset; + p.size = size; + + return ec_command(dev, EC_CMD_FLASH_READ, 0, + &p, sizeof(p), data, size) >= 0 ? 0 : -1; +} + +int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset, + uint32_t size) +{ + uint32_t burst = cros_ec_flash_write_burst_size(dev); + uint32_t end, off; + int ret; + + end = offset + size; + for (off = offset; off < end; off += burst, data += burst) { + ret = cros_ec_flash_read_block(dev, data, off, + min(end - off, burst)); + if (ret) + return ret; + } + + return 0; +} + +int cros_ec_flash_update_rw(struct cros_ec_dev *dev, + const uint8_t *image, int image_size) +{ + uint32_t rw_offset, rw_size; + int ret; + + if (cros_ec_flash_offset(dev, EC_FLASH_REGION_RW, &rw_offset, &rw_size)) + return -1; + if (image_size > rw_size) + return -1; + + /* Invalidate the existing hash, just in case the AP reboots + * unexpectedly during the update. If that happened, the EC RW firmware + * would be invalid, but the EC would still have the original hash. + */ + ret = cros_ec_invalidate_hash(dev); + if (ret) + return ret; + + /* + * Erase the entire RW section, so that the EC doesn't see any garbage + * past the new image if it's smaller than the current image. + * + * TODO: could optimize this to erase just the current image, since + * presumably everything past that is 0xff's. But would still need to + * round up to the nearest multiple of erase size. + */ + ret = cros_ec_flash_erase(dev, rw_offset, rw_size); + if (ret) + return ret; + + /* Write the image */ + ret = cros_ec_flash_write(dev, image, rw_offset, image_size); + if (ret) + return ret; + + return 0; +} + +int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block) +{ + struct ec_params_vbnvcontext p; + int len; + + p.op = EC_VBNV_CONTEXT_OP_READ; + + len = ec_command(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, + &p, sizeof(p), block, EC_VBNV_BLOCK_SIZE); + if (len < EC_VBNV_BLOCK_SIZE) + return -1; + + return 0; +} + +int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block) +{ + struct ec_params_vbnvcontext p; + int len; + + p.op = EC_VBNV_CONTEXT_OP_WRITE; + memcpy(p.block, block, sizeof(p.block)); + + len = ec_command_inptr(dev, EC_CMD_VBNV_CONTEXT, EC_VER_VBNV_CONTEXT, + &p, sizeof(p), NULL, 0); + if (len < 0) + return -1; + + return 0; +} + +int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state) +{ + struct ec_params_ldo_set params; + + params.index = index; + params.state = state; + + if (ec_command_inptr(dev, EC_CMD_LDO_SET, 0, + ¶ms, sizeof(params), + NULL, 0)) + return -1; + + return 0; +} + +int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state) +{ + struct ec_params_ldo_get params; + struct ec_response_ldo_get *resp; + + params.index = index; + + if (ec_command_inptr(dev, EC_CMD_LDO_GET, 0, + ¶ms, sizeof(params), + (uint8_t **)&resp, sizeof(*resp)) < sizeof(*resp)) + return -1; + + *state = resp->state; + + return 0; +} + +/** + * Decode MBKP details from the device tree and allocate a suitable device. + * + * @param blob Device tree blob + * @param node Node to decode from + * @param devp Returns a pointer to the new allocated device + * @return 0 if ok, -1 on error + */ +static int cros_ec_decode_fdt(const void *blob, int node, + struct cros_ec_dev **devp) +{ + enum fdt_compat_id compat; + struct cros_ec_dev *dev; + int parent; + + /* See what type of parent we are inside (this is expensive) */ + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -1; + } + + dev = &static_dev; + dev->node = node; + dev->parent_node = parent; + + compat = fdtdec_lookup(blob, parent); + switch (compat) { +#ifdef CONFIG_CROS_EC_SPI + case COMPAT_SAMSUNG_EXYNOS_SPI: + dev->interface = CROS_EC_IF_SPI; + if (cros_ec_spi_decode_fdt(dev, blob)) + return -1; + break; +#endif +#ifdef CONFIG_CROS_EC_I2C + case COMPAT_SAMSUNG_S3C2440_I2C: + dev->interface = CROS_EC_IF_I2C; + if (cros_ec_i2c_decode_fdt(dev, blob)) + return -1; + break; +#endif +#ifdef CONFIG_CROS_EC_LPC + case COMPAT_INTEL_LPC: + dev->interface = CROS_EC_IF_LPC; + break; +#endif + default: + debug("%s: Unknown compat id %d\n", __func__, compat); + return -1; + } + + fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int); + dev->optimise_flash_write = fdtdec_get_bool(blob, node, + "optimise-flash-write"); + *devp = dev; + + return 0; +} + +int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp) +{ + char id[MSG_BYTES]; + struct cros_ec_dev *dev; + int node = 0; + + *cros_ecp = NULL; + do { + node = fdtdec_next_compatible(blob, node, + COMPAT_GOOGLE_CROS_EC); + if (node < 0) { + debug("%s: Node not found\n", __func__); + return 0; + } + } while (!fdtdec_get_is_enabled(blob, node)); + + if (cros_ec_decode_fdt(blob, node, &dev)) { + debug("%s: Failed to decode device.\n", __func__); + return -CROS_EC_ERR_FDT_DECODE; + } + + switch (dev->interface) { +#ifdef CONFIG_CROS_EC_SPI + case CROS_EC_IF_SPI: + if (cros_ec_spi_init(dev, blob)) { + debug("%s: Could not setup SPI interface\n", __func__); + return -CROS_EC_ERR_DEV_INIT; + } + break; +#endif +#ifdef CONFIG_CROS_EC_I2C + case CROS_EC_IF_I2C: + if (cros_ec_i2c_init(dev, blob)) + return -CROS_EC_ERR_DEV_INIT; + break; +#endif +#ifdef CONFIG_CROS_EC_LPC + case CROS_EC_IF_LPC: + if (cros_ec_lpc_init(dev, blob)) + return -CROS_EC_ERR_DEV_INIT; + break; +#endif + case CROS_EC_IF_NONE: + default: + return 0; + } + + /* we will poll the EC interrupt line */ + fdtdec_setup_gpio(&dev->ec_int); + if (fdt_gpio_isvalid(&dev->ec_int)) + gpio_direction_input(dev->ec_int.gpio); + + if (cros_ec_check_version(dev)) { + debug("%s: Could not detect CROS-EC version\n", __func__); + return -CROS_EC_ERR_CHECK_VERSION; + } + + if (cros_ec_read_id(dev, id, sizeof(id))) { + debug("%s: Could not read KBC ID\n", __func__); + return -CROS_EC_ERR_READ_ID; + } + + /* Remember this device for use by the cros_ec command */ + last_dev = *cros_ecp = dev; + debug("Google Chrome EC CROS-EC driver ready, id '%s'\n", id); + + return 0; +} + +#ifdef CONFIG_CMD_CROS_EC +int cros_ec_decode_region(int argc, char * const argv[]) +{ + if (argc > 0) { + if (0 == strcmp(*argv, "rw")) + return EC_FLASH_REGION_RW; + else if (0 == strcmp(*argv, "ro")) + return EC_FLASH_REGION_RO; + + debug("%s: Invalid region '%s'\n", __func__, *argv); + } else { + debug("%s: Missing region parameter\n", __func__); + } + + return -1; +} + +/** + * Perform a flash read or write command + * + * @param dev CROS-EC device to read/write + * @param is_write 1 do to a write, 0 to do a read + * @param argc Number of arguments + * @param argv Arguments (2 is region, 3 is address) + * @return 0 for ok, 1 for a usage error or -ve for ec command error + * (negative EC_RES_...) + */ +static int do_read_write(struct cros_ec_dev *dev, int is_write, int argc, + char * const argv[]) +{ + uint32_t offset, size = -1U, region_size; + unsigned long addr; + char *endp; + int region; + int ret; + + region = cros_ec_decode_region(argc - 2, argv + 2); + if (region == -1) + return 1; + if (argc < 4) + return 1; + addr = simple_strtoul(argv[3], &endp, 16); + if (*argv[3] == 0 || *endp != 0) + return 1; + if (argc > 4) { + size = simple_strtoul(argv[4], &endp, 16); + if (*argv[4] == 0 || *endp != 0) + return 1; + } + + ret = cros_ec_flash_offset(dev, region, &offset, ®ion_size); + if (ret) { + debug("%s: Could not read region info\n", __func__); + return ret; + } + if (size == -1U) + size = region_size; + + ret = is_write ? + cros_ec_flash_write(dev, (uint8_t *)addr, offset, size) : + cros_ec_flash_read(dev, (uint8_t *)addr, offset, size); + if (ret) { + debug("%s: Could not %s region\n", __func__, + is_write ? "write" : "read"); + return ret; + } + + return 0; +} + +static int do_cros_ec(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct cros_ec_dev *dev = last_dev; + const char *cmd; + int ret = 0; + + if (argc < 2) + return CMD_RET_USAGE; + + cmd = argv[1]; + if (0 == strcmp("init", cmd)) { + ret = cros_ec_init(gd->fdt_blob, &dev); + if (ret) { + printf("Could not init cros_ec device (err %d)\n", ret); + return 1; + } + return 0; + } + + /* Just use the last allocated device; there should be only one */ + if (!last_dev) { + printf("No CROS-EC device available\n"); + return 1; + } + if (0 == strcmp("id", cmd)) { + char id[MSG_BYTES]; + + if (cros_ec_read_id(dev, id, sizeof(id))) { + debug("%s: Could not read KBC ID\n", __func__); + return 1; + } + printf("%s\n", id); + } else if (0 == strcmp("info", cmd)) { + struct ec_response_cros_ec_info info; + + if (cros_ec_info(dev, &info)) { + debug("%s: Could not read KBC info\n", __func__); + return 1; + } + printf("rows = %u\n", info.rows); + printf("cols = %u\n", info.cols); + printf("switches = %#x\n", info.switches); + } else if (0 == strcmp("curimage", cmd)) { + enum ec_current_image image; + + if (cros_ec_read_current_image(dev, &image)) { + debug("%s: Could not read KBC image\n", __func__); + return 1; + } + printf("%d\n", image); + } else if (0 == strcmp("hash", cmd)) { + struct ec_response_vboot_hash hash; + int i; + + if (cros_ec_read_hash(dev, &hash)) { + debug("%s: Could not read KBC hash\n", __func__); + return 1; + } + + if (hash.hash_type == EC_VBOOT_HASH_TYPE_SHA256) + printf("type: SHA-256\n"); + else + printf("type: %d\n", hash.hash_type); + + printf("offset: 0x%08x\n", hash.offset); + printf("size: 0x%08x\n", hash.size); + + printf("digest: "); + for (i = 0; i < hash.digest_size; i++) + printf("%02x", hash.hash_digest[i]); + printf("\n"); + } else if (0 == strcmp("reboot", cmd)) { + int region; + enum ec_reboot_cmd cmd; + + if (argc >= 3 && !strcmp(argv[2], "cold")) + cmd = EC_REBOOT_COLD; + else { + region = cros_ec_decode_region(argc - 2, argv + 2); + if (region == EC_FLASH_REGION_RO) + cmd = EC_REBOOT_JUMP_RO; + else if (region == EC_FLASH_REGION_RW) + cmd = EC_REBOOT_JUMP_RW; + else + return CMD_RET_USAGE; + } + + if (cros_ec_reboot(dev, cmd, 0)) { + debug("%s: Could not reboot KBC\n", __func__); + return 1; + } + } else if (0 == strcmp("events", cmd)) { + uint32_t events; + + if (cros_ec_get_host_events(dev, &events)) { + debug("%s: Could not read host events\n", __func__); + return 1; + } + printf("0x%08x\n", events); + } else if (0 == strcmp("clrevents", cmd)) { + uint32_t events = 0x7fffffff; + + if (argc >= 3) + events = simple_strtol(argv[2], NULL, 0); + + if (cros_ec_clear_host_events(dev, events)) { + debug("%s: Could not clear host events\n", __func__); + return 1; + } + } else if (0 == strcmp("read", cmd)) { + ret = do_read_write(dev, 0, argc, argv); + if (ret > 0) + return CMD_RET_USAGE; + } else if (0 == strcmp("write", cmd)) { + ret = do_read_write(dev, 1, argc, argv); + if (ret > 0) + return CMD_RET_USAGE; + } else if (0 == strcmp("erase", cmd)) { + int region = cros_ec_decode_region(argc - 2, argv + 2); + uint32_t offset, size; + + if (region == -1) + return CMD_RET_USAGE; + if (cros_ec_flash_offset(dev, region, &offset, &size)) { + debug("%s: Could not read region info\n", __func__); + ret = -1; + } else { + ret = cros_ec_flash_erase(dev, offset, size); + if (ret) { + debug("%s: Could not erase region\n", + __func__); + } + } + } else if (0 == strcmp("regioninfo", cmd)) { + int region = cros_ec_decode_region(argc - 2, argv + 2); + uint32_t offset, size; + + if (region == -1) + return CMD_RET_USAGE; + ret = cros_ec_flash_offset(dev, region, &offset, &size); + if (ret) { + debug("%s: Could not read region info\n", __func__); + } else { + printf("Region: %s\n", region == EC_FLASH_REGION_RO ? + "RO" : "RW"); + printf("Offset: %x\n", offset); + printf("Size: %x\n", size); + } + } else if (0 == strcmp("vbnvcontext", cmd)) { + uint8_t block[EC_VBNV_BLOCK_SIZE]; + char buf[3]; + int i, len; + unsigned long result; + + if (argc <= 2) { + ret = cros_ec_read_vbnvcontext(dev, block); + if (!ret) { + printf("vbnv_block: "); + for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) + printf("%02x", block[i]); + putc('\n'); + } + } else { + /* + * TODO(clchiou): Move this to a utility function as + * cmd_spi might want to call it. + */ + memset(block, 0, EC_VBNV_BLOCK_SIZE); + len = strlen(argv[2]); + buf[2] = '\0'; + for (i = 0; i < EC_VBNV_BLOCK_SIZE; i++) { + if (i * 2 >= len) + break; + buf[0] = argv[2][i * 2]; + if (i * 2 + 1 >= len) + buf[1] = '0'; + else + buf[1] = argv[2][i * 2 + 1]; + strict_strtoul(buf, 16, &result); + block[i] = result; + } + ret = cros_ec_write_vbnvcontext(dev, block); + } + if (ret) { + debug("%s: Could not %s VbNvContext\n", __func__, + argc <= 2 ? "read" : "write"); + } + } else if (0 == strcmp("test", cmd)) { + int result = cros_ec_test(dev); + + if (result) + printf("Test failed with error %d\n", result); + else + puts("Test passed\n"); + } else if (0 == strcmp("version", cmd)) { + struct ec_response_get_version *p; + char *build_string; + + ret = cros_ec_read_version(dev, &p); + if (!ret) { + /* Print versions */ + printf("RO version: %1.*s\n", + sizeof(p->version_string_ro), + p->version_string_ro); + printf("RW version: %1.*s\n", + sizeof(p->version_string_rw), + p->version_string_rw); + printf("Firmware copy: %s\n", + (p->current_image < + ARRAY_SIZE(ec_current_image_name) ? + ec_current_image_name[p->current_image] : + "?")); + ret = cros_ec_read_build_info(dev, &build_string); + if (!ret) + printf("Build info: %s\n", build_string); + } + } else if (0 == strcmp("ldo", cmd)) { + uint8_t index, state; + char *endp; + + if (argc < 3) + return CMD_RET_USAGE; + index = simple_strtoul(argv[2], &endp, 10); + if (*argv[2] == 0 || *endp != 0) + return CMD_RET_USAGE; + if (argc > 3) { + state = simple_strtoul(argv[3], &endp, 10); + if (*argv[3] == 0 || *endp != 0) + return CMD_RET_USAGE; + ret = cros_ec_set_ldo(dev, index, state); + } else { + ret = cros_ec_get_ldo(dev, index, &state); + if (!ret) { + printf("LDO%d: %s\n", index, + state == EC_LDO_STATE_ON ? + "on" : "off"); + } + } + + if (ret) { + debug("%s: Could not access LDO%d\n", __func__, index); + return ret; + } + } else { + return CMD_RET_USAGE; + } + + if (ret < 0) { + printf("Error: CROS-EC command failed (error %d)\n", ret); + ret = 1; + } + + return ret; +} + +U_BOOT_CMD( + crosec, 5, 1, do_cros_ec, + "CROS-EC utility command", + "init Re-init CROS-EC (done on startup automatically)\n" + "crosec id Read CROS-EC ID\n" + "crosec info Read CROS-EC info\n" + "crosec curimage Read CROS-EC current image\n" + "crosec hash Read CROS-EC hash\n" + "crosec reboot [rw | ro | cold] Reboot CROS-EC\n" + "crosec events Read CROS-EC host events\n" + "crosec clrevents [mask] Clear CROS-EC host events\n" + "crosec regioninfo <ro|rw> Read image info\n" + "crosec erase <ro|rw> Erase EC image\n" + "crosec read <ro|rw> <addr> [<size>] Read EC image\n" + "crosec write <ro|rw> <addr> [<size>] Write EC image\n" + "crosec vbnvcontext [hexstring] Read [write] VbNvContext from EC\n" + "crosec ldo <idx> [<state>] Switch/Read LDO state\n" + "crosec test run tests on cros_ec\n" + "crosec version Read CROS-EC version" +); +#endif diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c new file mode 100644 index 0000000..b0060ac --- /dev/null +++ b/drivers/misc/cros_ec_i2c.c @@ -0,0 +1,199 @@ +/* + * Chromium OS cros_ec driver - I2C interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * 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 + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <i2c.h> +#include <cros_ec.h> + +#ifdef DEBUG_TRACE +#define debug_trace(fmt, b...) debug(fmt, #b) +#else +#define debug_trace(fmt, b...) +#endif + +int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + int old_bus = 0; + /* version8, cmd8, arglen8, out8[dout_len], csum8 */ + int out_bytes = dout_len + 4; + /* response8, arglen8, in8[din_len], checksum8 */ + int in_bytes = din_len + 3; + uint8_t *ptr; + /* Receive input data, so that args will be dword aligned */ + uint8_t *in_ptr; + int ret; + + old_bus = i2c_get_bus_num(); + + /* + * Sanity-check I/O sizes given transaction overhead in internal + * buffers. + */ + if (out_bytes > sizeof(dev->dout)) { + debug("%s: Cannot send %d bytes\n", __func__, dout_len); + return -1; + } + if (in_bytes > sizeof(dev->din)) { + debug("%s: Cannot receive %d bytes\n", __func__, din_len); + return -1; + } + assert(dout_len >= 0); + assert(dinp); + + /* + * Copy command and data into output buffer so we can do a single I2C + * burst transaction. + */ + ptr = dev->dout; + + /* + * in_ptr starts of pointing to a dword-aligned input data buffer. + * We decrement it back by the number of header bytes we expect to + * receive, so that the first parameter of the resulting input data + * will be dword aligned. + */ + in_ptr = dev->din + sizeof(int64_t); + if (!dev->cmd_version_is_supported) { + /* Send an old-style command */ + *ptr++ = cmd; + out_bytes = dout_len + 1; + in_bytes = din_len + 2; + in_ptr--; /* Expect just a status byte */ + } else { + *ptr++ = EC_CMD_VERSION0 + cmd_version; + *ptr++ = cmd; + *ptr++ = dout_len; + in_ptr -= 2; /* Expect status, length bytes */ + } + memcpy(ptr, dout, dout_len); + ptr += dout_len; + + if (dev->cmd_version_is_supported) + *ptr++ = (uint8_t) + cros_ec_calc_checksum(dev->dout, dout_len + 3); + + /* Set to the proper i2c bus */ + if (i2c_set_bus_num(dev->bus_num)) { + debug("%s: Cannot change to I2C bus %d\n", __func__, + dev->bus_num); + return -1; + } + + /* Send output data */ + cros_ec_dump_data("out", -1, dev->dout, out_bytes); + ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes); + if (ret) { + debug("%s: Cannot complete I2C write to 0x%x\n", + __func__, dev->addr); + ret = -1; + } + + if (!ret) { + ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes); + if (ret) { + debug("%s: Cannot complete I2C read from 0x%x\n", + __func__, dev->addr); + ret = -1; + } + } + + /* Return to original bus number */ + i2c_set_bus_num(old_bus); + if (ret) + return ret; + + if (*in_ptr != EC_RES_SUCCESS) { + debug("%s: Received bad result code %d\n", __func__, *in_ptr); + return -(int)*in_ptr; + } + + if (dev->cmd_version_is_supported) { + int len, csum; + + len = in_ptr[1]; + if (len + 3 > sizeof(dev->din)) { + debug("%s: Received length %#02x too large\n", + __func__, len); + return -1; + } + csum = cros_ec_calc_checksum(in_ptr, 2 + len); + if (csum != in_ptr[2 + len]) { + debug("%s: Invalid checksum rx %#02x, calced %#02x\n", + __func__, in_ptr[2 + din_len], csum); + return -1; + } + din_len = min(din_len, len); + cros_ec_dump_data("in", -1, in_ptr, din_len + 3); + } else { + cros_ec_dump_data("in (old)", -1, in_ptr, in_bytes); + } + + /* Return pointer to dword-aligned input data, if any */ + *dinp = dev->din + sizeof(int64_t); + + return din_len; +} + +int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob) +{ + /* Decode interface-specific FDT params */ + dev->max_frequency = fdtdec_get_int(blob, dev->node, + "i2c-max-frequency", 100000); + dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node); + if (dev->bus_num == -1) { + debug("%s: Failed to read bus number\n", __func__); + return -1; + } + dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1); + if (dev->addr == -1) { + debug("%s: Failed to read device address\n", __func__); + return -1; + } + + return 0; +} + +/** + * Initialize I2C protocol. + * + * @param dev CROS_EC device + * @param blob Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob) +{ + i2c_init(dev->max_frequency, dev->addr); + + dev->cmd_version_is_supported = 0; + + return 0; +} diff --git a/drivers/misc/cros_ec_lpc.c b/drivers/misc/cros_ec_lpc.c new file mode 100644 index 0000000..cf0435b --- /dev/null +++ b/drivers/misc/cros_ec_lpc.c @@ -0,0 +1,283 @@ +/* + * Chromium OS cros_ec driver - LPC interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * 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 + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <command.h> +#include <cros_ec.h> +#include <asm/io.h> + +#ifdef DEBUG_TRACE +#define debug_trace(fmt, b...) debug(fmt, ##b) +#else +#define debug_trace(fmt, b...) +#endif + +static int wait_for_sync(struct cros_ec_dev *dev) +{ + unsigned long start; + + start = get_timer(0); + while (inb(EC_LPC_ADDR_HOST_CMD) & EC_LPC_STATUS_BUSY_MASK) { + if (get_timer(start) > 1000) { + debug("%s: Timeout waiting for CROS_EC sync\n", + __func__); + return -1; + } + } + + return 0; +} + +/** + * Send a command to a LPC CROS_EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev CROS_EC device + * @param cmd Command to send (EC_CMD_...) + * @param cmd_version Version of command to send (EC_VER_...) + * @param dout Output data (may be NULL If dout_len=0) + * @param dout_len Size of output data in bytes + * @param dinp Place to put pointer to response data + * @param din_len Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +static int old_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + int ret, i; + + if (dout_len > EC_OLD_PARAM_SIZE) { + debug("%s: Cannot send %d bytes\n", __func__, dout_len); + return -1; + } + + if (din_len > EC_OLD_PARAM_SIZE) { + debug("%s: Cannot receive %d bytes\n", __func__, din_len); + return -1; + } + + if (wait_for_sync(dev)) { + debug("%s: Timeout waiting ready\n", __func__); + return -1; + } + + debug_trace("cmd: %02x, ", cmd); + for (i = 0; i < dout_len; i++) { + debug_trace("%02x ", dout[i]); + outb(dout[i], EC_LPC_ADDR_OLD_PARAM + i); + } + outb(cmd, EC_LPC_ADDR_HOST_CMD); + debug_trace("\n"); + + if (wait_for_sync(dev)) { + debug("%s: Timeout waiting ready\n", __func__); + return -1; + } + + ret = inb(EC_LPC_ADDR_HOST_DATA); + if (ret) { + debug("%s: CROS_EC result code %d\n", __func__, ret); + return -ret; + } + + debug_trace("resp: %02x, ", ret); + for (i = 0; i < din_len; i++) { + dev->din[i] = inb(EC_LPC_ADDR_OLD_PARAM + i); + debug_trace("%02x ", dev->din[i]); + } + debug_trace("\n"); + *dinp = dev->din; + + return din_len; +} + +int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + const int cmd_addr = EC_LPC_ADDR_HOST_CMD; + const int data_addr = EC_LPC_ADDR_HOST_DATA; + const int args_addr = EC_LPC_ADDR_HOST_ARGS; + const int param_addr = EC_LPC_ADDR_HOST_PARAM; + + struct ec_lpc_host_args args; + uint8_t *d; + int csum; + int i; + + /* Fall back to old-style command interface if args aren't supported */ + if (!dev->cmd_version_is_supported) + return old_lpc_command(dev, cmd, dout, dout_len, dinp, + din_len); + + if (dout_len > EC_HOST_PARAM_SIZE) { + debug("%s: Cannot send %d bytes\n", __func__, dout_len); + return -1; + } + + /* Fill in args */ + args.flags = EC_HOST_ARGS_FLAG_FROM_HOST; + args.command_version = cmd_version; + args.data_size = dout_len; + + /* Calculate checksum */ + csum = cmd + args.flags + args.command_version + args.data_size; + for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) + csum += *d; + + args.checksum = (uint8_t)csum; + + if (wait_for_sync(dev)) { + debug("%s: Timeout waiting ready\n", __func__); + return -1; + } + + /* Write args */ + for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++) + outb(*d, args_addr + i); + + /* Write data, if any */ + debug_trace("cmd: %02x, ver: %02x", cmd, cmd_version); + for (i = 0, d = (uint8_t *)dout; i < dout_len; i++, d++) { + outb(*d, param_addr + i); + debug_trace("%02x ", *d); + } + + outb(cmd, cmd_addr); + debug_trace("\n"); + + if (wait_for_sync(dev)) { + debug("%s: Timeout waiting for response\n", __func__); + return -1; + } + + /* Check result */ + i = inb(data_addr); + if (i) { + debug("%s: CROS_EC result code %d\n", __func__, i); + return -i; + } + + /* Read back args */ + for (i = 0, d = (uint8_t *)&args; i < sizeof(args); i++, d++) + *d = inb(args_addr + i); + + /* + * If EC didn't modify args flags, then somehow we sent a new-style + * command to an old EC, which means it would have read its params + * from the wrong place. + */ + if (!(args.flags & EC_HOST_ARGS_FLAG_TO_HOST)) { + debug("%s: CROS_EC protocol mismatch\n", __func__); + return -EC_RES_INVALID_RESPONSE; + } + + if (args.data_size > din_len) { + debug("%s: CROS_EC returned too much data %d > %d\n", + __func__, args.data_size, din_len); + return -EC_RES_INVALID_RESPONSE; + } + + /* Read data, if any */ + for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) { + *d = inb(param_addr + i); + debug_trace("%02x ", *d); + } + debug_trace("\n"); + + /* Verify checksum */ + csum = cmd + args.flags + args.command_version + args.data_size; + for (i = 0, d = (uint8_t *)dev->din; i < args.data_size; i++, d++) + csum += *d; + + if (args.checksum != (uint8_t)csum) { + debug("%s: CROS_EC response has invalid checksum\n", __func__); + return -EC_RES_INVALID_CHECKSUM; + } + *dinp = dev->din; + + /* Return actual amount of data received */ + return args.data_size; +} + +/** + * Initialize LPC protocol. + * + * @param dev CROS_EC device + * @param blob Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob) +{ + int byte, i; + + /* See if we can find an EC at the other end */ + byte = 0xff; + byte &= inb(EC_LPC_ADDR_HOST_CMD); + byte &= inb(EC_LPC_ADDR_HOST_DATA); + for (i = 0; i < EC_HOST_PARAM_SIZE && (byte == 0xff); i++) + byte &= inb(EC_LPC_ADDR_HOST_PARAM + i); + if (byte == 0xff) { + debug("%s: CROS_EC device not found on LPC bus\n", + __func__); + return -1; + } + + return 0; +} + +/* + * Test if LPC command args are supported. + * + * The cheapest way to do this is by looking for the memory-mapped + * flag. This is faster than sending a new-style 'hello' command and + * seeing whether the EC sets the EC_HOST_ARGS_FLAG_FROM_HOST flag + * in args when it responds. + */ +int cros_ec_lpc_check_version(struct cros_ec_dev *dev) +{ + if (inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID) == 'E' && + inb(EC_LPC_ADDR_MEMMAP + EC_MEMMAP_ID + 1) + == 'C' && + (inb(EC_LPC_ADDR_MEMMAP + + EC_MEMMAP_HOST_CMD_FLAGS) & + EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED)) { + dev->cmd_version_is_supported = 1; + } else { + /* We are going to use the old IO ports */ + dev->cmd_version_is_supported = 0; + } + debug("lpc: version %s\n", dev->cmd_version_is_supported ? + "new" : "old"); + + return 0; +} diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c new file mode 100644 index 0000000..e15c833 --- /dev/null +++ b/drivers/misc/cros_ec_spi.c @@ -0,0 +1,161 @@ +/* + * Chromium OS cros_ec driver - SPI interface + * + * Copyright (c) 2012 The Chromium OS Authors. + * 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 + */ + +/* + * The Matrix Keyboard Protocol driver handles talking to the keyboard + * controller chip. Mostly this is for keyboard functions, but some other + * things have slipped in, so we provide generic services to talk to the + * KBC. + */ + +#include <common.h> +#include <cros_ec.h> +#include <spi.h> + +/** + * Send a command to a LPC CROS_EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev CROS_EC device + * @param cmd Command to send (EC_CMD_...) + * @param cmd_version Version of command to send (EC_VER_...) + * @param dout Output data (may be NULL If dout_len=0) + * @param dout_len Size of output data in bytes + * @param dinp Returns pointer to response data. This will be + * untouched unless we return a value > 0. + * @param din_len Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len) +{ + int in_bytes = din_len + 4; /* status, length, checksum, trailer */ + uint8_t *out; + uint8_t *p; + int csum, len; + int rv; + + /* + * Sanity-check input size to make sure it plus transaction overhead + * fits in the internal device buffer. + */ + if (in_bytes > sizeof(dev->din)) { + debug("%s: Cannot receive %d bytes\n", __func__, din_len); + return -1; + } + + /* We represent message length as a byte */ + if (dout_len > 0xff) { + debug("%s: Cannot send %d bytes\n", __func__, dout_len); + return -1; + } + + /* + * Clear input buffer so we don't get false hits for MSG_HEADER + */ + memset(dev->din, '\0', in_bytes); + + if (spi_claim_bus(dev->spi)) { + debug("%s: Cannot claim SPI bus\n", __func__); + return -1; + } + + out = dev->dout; + out[0] = cmd_version; + out[1] = cmd; + out[2] = (uint8_t)dout_len; + memcpy(out + 3, dout, dout_len); + csum = cros_ec_calc_checksum(out, 3) + + cros_ec_calc_checksum(dout, dout_len); + out[3 + dout_len] = (uint8_t)csum; + + /* + * Send output data and receive input data starting such that the + * message body will be dword aligned. + */ + p = dev->din + sizeof(int64_t) - 2; + len = dout_len + 4; + cros_ec_dump_data("out", cmd, out, len); + rv = spi_xfer(dev->spi, max(len, in_bytes) * 8, out, p, + SPI_XFER_BEGIN | SPI_XFER_END); + + spi_release_bus(dev->spi); + + if (rv) { + debug("%s: Cannot complete SPI transfer\n", __func__); + return -1; + } + + len = min(p[1], din_len); + cros_ec_dump_data("in", -1, p, len + 3); + + /* Response code is first byte of message */ + if (p[0] != EC_RES_SUCCESS) { + printf("%s: Returned status %d\n", __func__, p[0]); + return -(int)(p[0]); + } + + /* Check checksum */ + csum = cros_ec_calc_checksum(p, len + 2); + if (csum != p[len + 2]) { + debug("%s: Invalid checksum rx %#02x, calced %#02x\n", __func__, + p[2 + len], csum); + return -1; + } + + /* Anything else is the response data */ + *dinp = p + 2; + + return len; +} + +int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob) +{ + /* Decode interface-specific FDT params */ + dev->max_frequency = fdtdec_get_int(blob, dev->node, + "spi-max-frequency", 500000); + dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0); + + return 0; +} + +/** + * Initialize SPI protocol. + * + * @param dev CROS_EC device + * @param blob Device tree blob + * @return 0 if ok, -1 on error + */ +int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob) +{ + dev->spi = spi_setup_slave_fdt(blob, dev->parent_node, + dev->cs, dev->max_frequency, 0); + if (!dev->spi) { + debug("%s: Could not setup SPI slave\n", __func__); + return -1; + } + + return 0; +} diff --git a/drivers/mmc/fsl_esdhc.c b/drivers/mmc/fsl_esdhc.c index 861f4b9..973b19f 100644 --- a/drivers/mmc/fsl_esdhc.c +++ b/drivers/mmc/fsl_esdhc.c @@ -178,7 +178,7 @@ static int esdhc_setup_data(struct mmc *mmc, struct mmc_data *data) int timeout; struct fsl_esdhc_cfg *cfg = (struct fsl_esdhc_cfg *)mmc->priv; struct fsl_esdhc *regs = (struct fsl_esdhc *)cfg->esdhc_base; -#ifdef CONFIG_SYS_FSL_ESDHC_USE_PIO +#ifndef CONFIG_SYS_FSL_ESDHC_USE_PIO uint wml_value; wml_value = data->blocksize/4; @@ -310,6 +310,9 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) /* Figure out the transfer arguments */ xfertyp = esdhc_xfertyp(cmd, data); + /* Mask all irqs */ + esdhc_write32(®s->irqsigen, 0); + /* Send the command */ esdhc_write32(®s->cmdarg, cmd->cmdarg); #if defined(CONFIG_FSL_USDHC) @@ -320,15 +323,11 @@ esdhc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) esdhc_write32(®s->xfertyp, xfertyp); #endif - /* Mask all irqs */ - esdhc_write32(®s->irqsigen, 0); - /* Wait for the command to complete */ while (!(esdhc_read32(®s->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE))) ; irqstat = esdhc_read32(®s->irqstat); - esdhc_write32(®s->irqstat, irqstat); /* Reset CMD and DATA portions on error */ if (irqstat & (CMD_ERR | IRQSTAT_CTOE)) { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index a492bbb..73f7195 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -254,7 +254,7 @@ err_out: } static unsigned long -mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt) +mmc_berase(int dev_num, lbaint_t start, lbaint_t blkcnt) { int err = 0; struct mmc *mmc = find_mmc_device(dev_num); @@ -266,7 +266,8 @@ mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt) if ((start % mmc->erase_grp_size) || (blkcnt % mmc->erase_grp_size)) printf("\n\nCaution! Your devices Erase group is 0x%x\n" - "The erase range would be change to 0x%lx~0x%lx\n\n", + "The erase range would be change to " + "0x" LBAF "~0x" LBAF "\n\n", mmc->erase_grp_size, start & ~(mmc->erase_grp_size - 1), ((start + blkcnt + mmc->erase_grp_size) & ~(mmc->erase_grp_size - 1)) - 1); @@ -289,22 +290,24 @@ mmc_berase(int dev_num, unsigned long start, lbaint_t blkcnt) } static ulong -mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) +mmc_write_blocks(struct mmc *mmc, lbaint_t start, lbaint_t blkcnt, const void*src) { struct mmc_cmd cmd; struct mmc_data data; int timeout = 1000; if ((start + blkcnt) > mmc->block_dev.lba) { - printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", + printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", start + blkcnt, mmc->block_dev.lba); return 0; } - if (blkcnt > 1) - cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; - else + if (blkcnt == 0) + return 0; + else if (blkcnt == 1) cmd.cmdidx = MMC_CMD_WRITE_SINGLE_BLOCK; + else + cmd.cmdidx = MMC_CMD_WRITE_MULTIPLE_BLOCK; if (mmc->high_capacity) cmd.cmdarg = start; @@ -344,7 +347,7 @@ mmc_write_blocks(struct mmc *mmc, ulong start, lbaint_t blkcnt, const void*src) } static ulong -mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) +mmc_bwrite(int dev_num, lbaint_t start, lbaint_t blkcnt, const void*src) { lbaint_t cur, blocks_todo = blkcnt; @@ -367,7 +370,7 @@ mmc_bwrite(int dev_num, ulong start, lbaint_t blkcnt, const void*src) return blkcnt; } -static int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, +static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, lbaint_t blkcnt) { struct mmc_cmd cmd; @@ -406,7 +409,7 @@ static int mmc_read_blocks(struct mmc *mmc, void *dst, ulong start, return blkcnt; } -static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) +static ulong mmc_bread(int dev_num, lbaint_t start, lbaint_t blkcnt, void *dst) { lbaint_t cur, blocks_todo = blkcnt; @@ -418,7 +421,7 @@ static ulong mmc_bread(int dev_num, ulong start, lbaint_t blkcnt, void *dst) return 0; if ((start + blkcnt) > mmc->block_dev.lba) { - printf("MMC: block number 0x%lx exceeds max(0x%lx)\n", + printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", start + blkcnt, mmc->block_dev.lba); return 0; } @@ -700,16 +703,49 @@ static int mmc_change_freq(struct mmc *mmc) return 0; } +static int mmc_set_capacity(struct mmc *mmc, int part_num) +{ + switch (part_num) { + case 0: + mmc->capacity = mmc->capacity_user; + break; + case 1: + case 2: + mmc->capacity = mmc->capacity_boot; + break; + case 3: + mmc->capacity = mmc->capacity_rpmb; + break; + case 4: + case 5: + case 6: + case 7: + mmc->capacity = mmc->capacity_gp[part_num - 4]; + break; + default: + return -1; + } + + mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len); + + return 0; +} + int mmc_switch_part(int dev_num, unsigned int part_num) { struct mmc *mmc = find_mmc_device(dev_num); + int ret; if (!mmc) return -1; - return mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, - (mmc->part_config & ~PART_ACCESS_MASK) - | (part_num & PART_ACCESS_MASK)); + ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, + (mmc->part_config & ~PART_ACCESS_MASK) + | (part_num & PART_ACCESS_MASK)); + if (ret) + return ret; + + return mmc_set_capacity(mmc, part_num); } int mmc_getcd(struct mmc *mmc) @@ -917,7 +953,7 @@ static void mmc_set_bus_width(struct mmc *mmc, uint width) static int mmc_startup(struct mmc *mmc) { - int err; + int err, i; uint mult, freq; u64 cmult, csize, capacity; struct mmc_cmd cmd; @@ -1035,8 +1071,12 @@ static int mmc_startup(struct mmc *mmc) cmult = (mmc->csd[2] & 0x00038000) >> 15; } - mmc->capacity = (csize + 1) << (cmult + 2); - mmc->capacity *= mmc->read_bl_len; + mmc->capacity_user = (csize + 1) << (cmult + 2); + mmc->capacity_user *= mmc->read_bl_len; + mmc->capacity_boot = 0; + mmc->capacity_rpmb = 0; + for (i = 0; i < 4; i++) + mmc->capacity_gp[i] = 0; if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) mmc->read_bl_len = MMC_MAX_BLOCK_LEN; @@ -1075,7 +1115,7 @@ static int mmc_startup(struct mmc *mmc) | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; capacity *= MMC_MAX_BLOCK_LEN; if ((capacity >> 20) > 2 * 1024) - mmc->capacity = capacity; + mmc->capacity_user = capacity; } switch (ext_csd[EXT_CSD_REV]) { @@ -1117,8 +1157,25 @@ static int mmc_startup(struct mmc *mmc) if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || ext_csd[EXT_CSD_BOOT_MULT]) mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; + + mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; + + mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; + + for (i = 0; i < 4; i++) { + int idx = EXT_CSD_GP_SIZE_MULT + i * 3; + mmc->capacity_gp[i] = (ext_csd[idx + 2] << 16) + + (ext_csd[idx + 1] << 8) + ext_csd[idx]; + mmc->capacity_gp[i] *= + ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; + mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; + } } + err = mmc_set_capacity(mmc, mmc->part_num); + if (err) + return err; + if (IS_SD(mmc)) err = sd_change_freq(mmc); else diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c index 1eaea04..c5631bf 100644 --- a/drivers/mmc/sdhci.c +++ b/drivers/mmc/sdhci.c @@ -486,8 +486,10 @@ int add_sdhci(struct sdhci_host *host, u32 max_clk, u32 min_clk) mmc->voltages |= host->voltages; mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT; - if (caps & SDHCI_CAN_DO_8BIT) - mmc->host_caps |= MMC_MODE_8BIT; + if ((host->version & SDHCI_SPEC_VER_MASK) >= SDHCI_SPEC_300) { + if (caps & SDHCI_CAN_DO_8BIT) + mmc->host_caps |= MMC_MODE_8BIT; + } if (host->host_caps) mmc->host_caps |= host->host_caps; diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile index 543c845..99f39fc 100644 --- a/drivers/mtd/Makefile +++ b/drivers/mtd/Makefile @@ -25,7 +25,9 @@ include $(TOPDIR)/config.mk LIB := $(obj)libmtd.o -COBJS-$(CONFIG_MTD_DEVICE) += mtdcore.o +ifneq (,$(findstring y,$(CONFIG_MTD_DEVICE)$(CONFIG_CMD_NAND)$(CONFIG_CMD_ONENAND))) +COBJS-y += mtdcore.o +endif COBJS-$(CONFIG_MTD_PARTITIONS) += mtdpart.o COBJS-$(CONFIG_MTD_CONCAT) += mtdconcat.o COBJS-$(CONFIG_HAS_DATAFLASH) += at45.o diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c index 25f8752..25a5710 100644 --- a/drivers/mtd/cfi_flash.c +++ b/drivers/mtd/cfi_flash.c @@ -1797,7 +1797,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum) }; int i; - for (i = 0; i < sizeof(modes) / sizeof(modes[0]); i++) { + for (i = 0; i < ARRAY_SIZE(modes); i++) { info->vendor = modes[i]; info->start[0] = (ulong)map_physmem(base, @@ -1883,8 +1883,7 @@ static int __flash_detect_cfi (flash_info_t * info, struct cfi_qry *qry) /* Issue FLASH reset command */ flash_cmd_reset(info); - for (cfi_offset=0; - cfi_offset < sizeof(flash_offset_cfi) / sizeof(uint); + for (cfi_offset = 0; cfi_offset < ARRAY_SIZE(flash_offset_cfi); cfi_offset++) { flash_write_cmd (info, 0, flash_offset_cfi[cfi_offset], FLASH_CMD_CFI); @@ -2336,7 +2335,7 @@ void flash_protect_default(void) #endif #if defined(CONFIG_SYS_FLASH_AUTOPROTECT_LIST) - for (i = 0; i < (sizeof(apl) / sizeof(struct apl_s)); i++) { + for (i = 0; i < ARRAY_SIZE(apl); i++) { debug("autoprotecting from %08lx to %08lx\n", apl[i].start, apl[i].start + apl[i].size - 1); flash_protect(FLAG_PROTECT_SET, diff --git a/drivers/mtd/cfi_mtd.c b/drivers/mtd/cfi_mtd.c index 8d74fa9..bbb71a1 100644 --- a/drivers/mtd/cfi_mtd.c +++ b/drivers/mtd/cfi_mtd.c @@ -244,12 +244,12 @@ int cfi_mtd_init(void) mtd->size = fi->size; mtd->writesize = 1; - mtd->erase = cfi_mtd_erase; - mtd->read = cfi_mtd_read; - mtd->write = cfi_mtd_write; - mtd->sync = cfi_mtd_sync; - mtd->lock = cfi_mtd_lock; - mtd->unlock = cfi_mtd_unlock; + mtd->_erase = cfi_mtd_erase; + mtd->_read = cfi_mtd_read; + mtd->_write = cfi_mtd_write; + mtd->_sync = cfi_mtd_sync; + mtd->_lock = cfi_mtd_lock; + mtd->_unlock = cfi_mtd_unlock; mtd->priv = fi; if (add_mtd_device(mtd)) diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c index e6d9384..31e4289 100644 --- a/drivers/mtd/mtdconcat.c +++ b/drivers/mtd/mtdconcat.c @@ -70,14 +70,14 @@ concat_read(struct mtd_info *mtd, loff_t from, size_t len, /* Entire transaction goes into this subdev */ size = len; - err = subdev->read(subdev, from, size, &retsize, buf); + err = mtd_read(subdev, from, size, &retsize, buf); /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -105,9 +105,6 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len, int err = -EINVAL; int i; - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - *retlen = 0; for (i = 0; i < concat->num_subdev; i++) { @@ -124,11 +121,7 @@ concat_write(struct mtd_info *mtd, loff_t to, size_t len, else size = len; - if (!(subdev->flags & MTD_WRITEABLE)) - err = -EROFS; - else - err = subdev->write(subdev, to, size, &retsize, buf); - + err = mtd_write(subdev, to, size, &retsize, buf); if (err) break; @@ -165,16 +158,16 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) if (from + devops.len > subdev->size) devops.len = subdev->size - from; - err = subdev->read_oob(subdev, from, &devops); + err = mtd_read_oob(subdev, from, &devops); ops->retlen += devops.retlen; ops->oobretlen += devops.oobretlen; /* Save information about bitflips! */ if (unlikely(err)) { - if (err == -EBADMSG) { + if (mtd_is_eccerr(err)) { mtd->ecc_stats.failed++; ret = err; - } else if (err == -EUCLEAN) { + } else if (mtd_is_bitflip(err)) { mtd->ecc_stats.corrected++; /* Do not overwrite -EBADMSG !! */ if (!ret) @@ -225,7 +218,7 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) if (to + devops.len > subdev->size) devops.len = subdev->size - to; - err = subdev->write_oob(subdev, to, &devops); + err = mtd_write_oob(subdev, to, &devops); ops->retlen += devops.retlen; if (err) return err; @@ -271,7 +264,7 @@ static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) * FIXME: Allow INTERRUPTIBLE. Which means * not having the wait_queue head on the stack. */ - err = mtd->erase(mtd, erase); + err = mtd_erase(mtd, erase); if (!err) { set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&waitq, &wait); @@ -294,15 +287,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) uint64_t length, offset = 0; struct erase_info *erase; - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - - if (instr->addr > concat->mtd.size) - return -EINVAL; - - if (instr->len + instr->addr > concat->mtd.size) - return -EINVAL; - /* * Check for proper erase block alignment of the to-be-erased area. * It is easier to do this based on the super device's erase @@ -350,8 +334,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) return -EINVAL; } - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - /* make a local copy of instr to avoid modifying the caller's struct */ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); @@ -390,10 +372,6 @@ static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) else erase->len = length; - if (!(subdev->flags & MTD_WRITEABLE)) { - err = -EROFS; - break; - } length -= erase->len; if ((err = concat_dev_erase(subdev, erase))) { /* sanity check: should never happen since @@ -429,9 +407,6 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct mtd_concat *concat = CONCAT(mtd); int i, err = -EINVAL; - if ((len + ofs) > mtd->size) - return -EINVAL; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; uint64_t size; @@ -446,7 +421,7 @@ static int concat_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) else size = len; - err = subdev->lock(subdev, ofs, size); + err = mtd_lock(subdev, ofs, size); if (err) break; @@ -467,9 +442,6 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) struct mtd_concat *concat = CONCAT(mtd); int i, err = 0; - if ((len + ofs) > mtd->size) - return -EINVAL; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; uint64_t size; @@ -484,7 +456,7 @@ static int concat_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) else size = len; - err = subdev->unlock(subdev, ofs, size); + err = mtd_unlock(subdev, ofs, size); if (err) break; @@ -507,7 +479,7 @@ static void concat_sync(struct mtd_info *mtd) for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; - subdev->sync(subdev); + mtd_sync(subdev); } } @@ -516,12 +488,9 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs) struct mtd_concat *concat = CONCAT(mtd); int i, res = 0; - if (!concat->subdev[0]->block_isbad) + if (!mtd_can_have_bb(concat->subdev[0])) return res; - if (ofs > mtd->size) - return -EINVAL; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; @@ -530,7 +499,7 @@ static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs) continue; } - res = subdev->block_isbad(subdev, ofs); + res = mtd_block_isbad(subdev, ofs); break; } @@ -542,12 +511,9 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs) struct mtd_concat *concat = CONCAT(mtd); int i, err = -EINVAL; - if (!concat->subdev[0]->block_markbad) + if (!mtd_can_have_bb(concat->subdev[0])) return 0; - if (ofs > mtd->size) - return -EINVAL; - for (i = 0; i < concat->num_subdev; i++) { struct mtd_info *subdev = concat->subdev[i]; @@ -556,7 +522,7 @@ static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs) continue; } - err = subdev->block_markbad(subdev, ofs); + err = mtd_block_markbad(subdev, ofs); if (!err) mtd->ecc_stats.badblocks++; break; @@ -609,14 +575,14 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->mtd.subpage_sft = subdev[0]->subpage_sft; concat->mtd.oobsize = subdev[0]->oobsize; concat->mtd.oobavail = subdev[0]->oobavail; - if (subdev[0]->read_oob) - concat->mtd.read_oob = concat_read_oob; - if (subdev[0]->write_oob) - concat->mtd.write_oob = concat_write_oob; - if (subdev[0]->block_isbad) - concat->mtd.block_isbad = concat_block_isbad; - if (subdev[0]->block_markbad) - concat->mtd.block_markbad = concat_block_markbad; + if (subdev[0]->_read_oob) + concat->mtd._read_oob = concat_read_oob; + if (subdev[0]->_write_oob) + concat->mtd._write_oob = concat_write_oob; + if (subdev[0]->_block_isbad) + concat->mtd._block_isbad = concat_block_isbad; + if (subdev[0]->_block_markbad) + concat->mtd._block_markbad = concat_block_markbad; concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks; @@ -653,8 +619,8 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c if (concat->mtd.writesize != subdev[i]->writesize || concat->mtd.subpage_sft != subdev[i]->subpage_sft || concat->mtd.oobsize != subdev[i]->oobsize || - !concat->mtd.read_oob != !subdev[i]->read_oob || - !concat->mtd.write_oob != !subdev[i]->write_oob) { + !concat->mtd._read_oob != !subdev[i]->_read_oob || + !concat->mtd._write_oob != !subdev[i]->_write_oob) { kfree(concat); printk("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); @@ -669,12 +635,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c concat->num_subdev = num_devs; concat->mtd.name = name; - concat->mtd.erase = concat_erase; - concat->mtd.read = concat_read; - concat->mtd.write = concat_write; - concat->mtd.sync = concat_sync; - concat->mtd.lock = concat_lock; - concat->mtd.unlock = concat_unlock; + concat->mtd._erase = concat_erase; + concat->mtd._read = concat_read; + concat->mtd._write = concat_write; + concat->mtd._sync = concat_sync; + concat->mtd._lock = concat_lock; + concat->mtd._unlock = concat_unlock; /* * Combine the erase block size info of the subdevices: diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 3a81ada..49c0814 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -25,6 +25,11 @@ int add_mtd_device(struct mtd_info *mtd) mtd->index = i; mtd->usecount = 0; + /* default value if not set by driver */ + if (mtd->bitflip_threshold == 0) + mtd->bitflip_threshold = mtd->ecc_strength; + + /* No need to get a refcount on the module containing the notifier, since we hold the mtd_table_mutex */ @@ -186,3 +191,189 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset, } } #endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */ + + /* + * Erase is an asynchronous operation. Device drivers are supposed + * to call instr->callback() whenever the operation completes, even + * if it completes with a failure. + * Callers are supposed to pass a callback function and wait for it + * to be called before writing to the block. + */ +int mtd_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + if (instr->addr > mtd->size || instr->len > mtd->size - instr->addr) + return -EINVAL; + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; + if (!instr->len) { + instr->state = MTD_ERASE_DONE; + mtd_erase_callback(instr); + return 0; + } + return mtd->_erase(mtd, instr); +} + +int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, + u_char *buf) +{ + if (from < 0 || from > mtd->size || len > mtd->size - from) + return -EINVAL; + if (!len) + return 0; + return mtd->_read(mtd, from, len, retlen, buf); +} + +int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, + const u_char *buf) +{ + *retlen = 0; + if (to < 0 || to > mtd->size || len > mtd->size - to) + return -EINVAL; + if (!mtd->_write || !(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (!len) + return 0; + return mtd->_write(mtd, to, len, retlen, buf); +} + +/* + * In blackbox flight recorder like scenarios we want to make successful writes + * in interrupt context. panic_write() is only intended to be called when its + * known the kernel is about to panic and we need the write to succeed. Since + * the kernel is not going to be running for much longer, this function can + * break locks and delay to ensure the write succeeds (but not sleep). + */ +int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, + const u_char *buf) +{ + *retlen = 0; + if (!mtd->_panic_write) + return -EOPNOTSUPP; + if (to < 0 || to > mtd->size || len > mtd->size - to) + return -EINVAL; + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (!len) + return 0; + return mtd->_panic_write(mtd, to, len, retlen, buf); +} + +int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ + ops->retlen = ops->oobretlen = 0; + if (!mtd->_read_oob) + return -EOPNOTSUPP; + return mtd->_read_oob(mtd, from, ops); +} + +/* + * Method to access the protection register area, present in some flash + * devices. The user data is one time programmable but the factory data is read + * only. + */ +int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, + size_t len) +{ + if (!mtd->_get_fact_prot_info) + return -EOPNOTSUPP; + if (!len) + return 0; + return mtd->_get_fact_prot_info(mtd, buf, len); +} + +int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + *retlen = 0; + if (!mtd->_read_fact_prot_reg) + return -EOPNOTSUPP; + if (!len) + return 0; + return mtd->_read_fact_prot_reg(mtd, from, len, retlen, buf); +} + +int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf, + size_t len) +{ + if (!mtd->_get_user_prot_info) + return -EOPNOTSUPP; + if (!len) + return 0; + return mtd->_get_user_prot_info(mtd, buf, len); +} + +int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + *retlen = 0; + if (!mtd->_read_user_prot_reg) + return -EOPNOTSUPP; + if (!len) + return 0; + return mtd->_read_user_prot_reg(mtd, from, len, retlen, buf); +} + +int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, u_char *buf) +{ + *retlen = 0; + if (!mtd->_write_user_prot_reg) + return -EOPNOTSUPP; + if (!len) + return 0; + return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf); +} + +int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) +{ + if (!mtd->_lock_user_prot_reg) + return -EOPNOTSUPP; + if (!len) + return 0; + return mtd->_lock_user_prot_reg(mtd, from, len); +} + +/* Chip-supported device locking */ +int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + if (!mtd->_lock) + return -EOPNOTSUPP; + if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + return -EINVAL; + if (!len) + return 0; + return mtd->_lock(mtd, ofs, len); +} + +int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + if (!mtd->_unlock) + return -EOPNOTSUPP; + if (ofs < 0 || ofs > mtd->size || len > mtd->size - ofs) + return -EINVAL; + if (!len) + return 0; + return mtd->_unlock(mtd, ofs, len); +} + +int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs) +{ + if (!mtd->_block_isbad) + return 0; + if (ofs < 0 || ofs > mtd->size) + return -EINVAL; + return mtd->_block_isbad(mtd, ofs); +} + +int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs) +{ + if (!mtd->_block_markbad) + return -EOPNOTSUPP; + if (ofs < 0 || ofs > mtd->size) + return -EINVAL; + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + return mtd->_block_markbad(mtd, ofs); +} + diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index cbfc679..9dfe7bb 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -52,17 +52,11 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len, int res; stats = part->master->ecc_stats; - - if (from >= mtd->size) - len = 0; - else if (from + len > mtd->size) - len = mtd->size - from; - res = part->master->read(part->master, from + part->offset, - len, retlen, buf); + res = mtd_read(part->master, from + part->offset, len, retlen, buf); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; } return res; @@ -78,12 +72,12 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, return -EINVAL; if (ops->datbuf && from + ops->len > mtd->size) return -EINVAL; - res = part->master->read_oob(part->master, from + part->offset, ops); + res = mtd_read_oob(part->master, from + part->offset, ops); if (unlikely(res)) { - if (res == -EUCLEAN) + if (mtd_is_bitflip(res)) mtd->ecc_stats.corrected++; - if (res == -EBADMSG) + if (mtd_is_eccerr(res)) mtd->ecc_stats.failed++; } return res; @@ -93,58 +87,35 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_user_prot_reg(part->master, from, - len, retlen, buf); + return mtd_read_user_prot_reg(part->master, from, len, retlen, buf); } static int part_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf, size_t len) { struct mtd_part *part = PART(mtd); - return part->master->get_user_prot_info(part->master, buf, len); + return mtd_get_user_prot_info(part->master, buf, len); } static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->read_fact_prot_reg(part->master, from, - len, retlen, buf); + return mtd_read_fact_prot_reg(part->master, from, len, retlen, buf); } static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, size_t len) { struct mtd_part *part = PART(mtd); - return part->master->get_fact_prot_info(part->master, buf, len); + return mtd_get_fact_prot_info(part->master, buf, len); } static int part_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - if (to >= mtd->size) - len = 0; - else if (to + len > mtd->size) - len = mtd->size - to; - return part->master->write(part->master, to + part->offset, - len, retlen, buf); -} - -static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) -{ - struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - if (to >= mtd->size) - len = 0; - else if (to + len > mtd->size) - len = mtd->size - to; - return part->master->panic_write(part->master, to + part->offset, - len, retlen, buf); + return mtd_write(part->master, to + part->offset, len, retlen, buf); } static int part_write_oob(struct mtd_info *mtd, loff_t to, @@ -152,41 +123,34 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to, { struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - if (to >= mtd->size) return -EINVAL; if (ops->datbuf && to + ops->len > mtd->size) return -EINVAL; - return part->master->write_oob(part->master, to + part->offset, ops); + return mtd_write_oob(part->master, to + part->offset, ops); } static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { struct mtd_part *part = PART(mtd); - return part->master->write_user_prot_reg(part->master, from, - len, retlen, buf); + return mtd_write_user_prot_reg(part->master, from, len, retlen, buf); } static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len) { struct mtd_part *part = PART(mtd); - return part->master->lock_user_prot_reg(part->master, from, len); + return mtd_lock_user_prot_reg(part->master, from, len); } static int part_erase(struct mtd_info *mtd, struct erase_info *instr) { struct mtd_part *part = PART(mtd); int ret; - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - if (instr->addr >= mtd->size) - return -EINVAL; + instr->addr += part->offset; - ret = part->master->erase(part->master, instr); + ret = mtd_erase(part->master, instr); if (ret) { if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) instr->fail_addr -= part->offset; @@ -197,7 +161,7 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr) void mtd_erase_callback(struct erase_info *instr) { - if (instr->mtd->erase == part_erase) { + if (instr->mtd->_erase == part_erase) { struct mtd_part *part = PART(instr->mtd); if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) @@ -211,32 +175,26 @@ void mtd_erase_callback(struct erase_info *instr) static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = PART(mtd); - if ((len + ofs) > mtd->size) - return -EINVAL; - return part->master->lock(part->master, ofs + part->offset, len); + return mtd_lock(part->master, ofs + part->offset, len); } static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) { struct mtd_part *part = PART(mtd); - if ((len + ofs) > mtd->size) - return -EINVAL; - return part->master->unlock(part->master, ofs + part->offset, len); + return mtd_unlock(part->master, ofs + part->offset, len); } static void part_sync(struct mtd_info *mtd) { struct mtd_part *part = PART(mtd); - part->master->sync(part->master); + mtd_sync(part->master); } static int part_block_isbad(struct mtd_info *mtd, loff_t ofs) { struct mtd_part *part = PART(mtd); - if (ofs >= mtd->size) - return -EINVAL; ofs += part->offset; - return part->master->block_isbad(part->master, ofs); + return mtd_block_isbad(part->master, ofs); } static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) @@ -244,12 +202,8 @@ static int part_block_markbad(struct mtd_info *mtd, loff_t ofs) struct mtd_part *part = PART(mtd); int res; - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - if (ofs >= mtd->size) - return -EINVAL; ofs += part->offset; - res = part->master->block_markbad(part->master, ofs); + res = mtd_block_markbad(part->master, ofs); if (!res) mtd->ecc_stats.badblocks++; return res; @@ -303,39 +257,36 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, slave->mtd.name = part->name; slave->mtd.owner = master->owner; - slave->mtd.read = part_read; - slave->mtd.write = part_write; - - if (master->panic_write) - slave->mtd.panic_write = part_panic_write; - - if (master->read_oob) - slave->mtd.read_oob = part_read_oob; - if (master->write_oob) - slave->mtd.write_oob = part_write_oob; - if (master->read_user_prot_reg) - slave->mtd.read_user_prot_reg = part_read_user_prot_reg; - if (master->read_fact_prot_reg) - slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; - if (master->write_user_prot_reg) - slave->mtd.write_user_prot_reg = part_write_user_prot_reg; - if (master->lock_user_prot_reg) - slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; - if (master->get_user_prot_info) - slave->mtd.get_user_prot_info = part_get_user_prot_info; - if (master->get_fact_prot_info) - slave->mtd.get_fact_prot_info = part_get_fact_prot_info; - if (master->sync) - slave->mtd.sync = part_sync; - if (master->lock) - slave->mtd.lock = part_lock; - if (master->unlock) - slave->mtd.unlock = part_unlock; - if (master->block_isbad) - slave->mtd.block_isbad = part_block_isbad; - if (master->block_markbad) - slave->mtd.block_markbad = part_block_markbad; - slave->mtd.erase = part_erase; + slave->mtd._read = part_read; + slave->mtd._write = part_write; + + if (master->_read_oob) + slave->mtd._read_oob = part_read_oob; + if (master->_write_oob) + slave->mtd._write_oob = part_write_oob; + if (master->_read_user_prot_reg) + slave->mtd._read_user_prot_reg = part_read_user_prot_reg; + if (master->_read_fact_prot_reg) + slave->mtd._read_fact_prot_reg = part_read_fact_prot_reg; + if (master->_write_user_prot_reg) + slave->mtd._write_user_prot_reg = part_write_user_prot_reg; + if (master->_lock_user_prot_reg) + slave->mtd._lock_user_prot_reg = part_lock_user_prot_reg; + if (master->_get_user_prot_info) + slave->mtd._get_user_prot_info = part_get_user_prot_info; + if (master->_get_fact_prot_info) + slave->mtd._get_fact_prot_info = part_get_fact_prot_info; + if (master->_sync) + slave->mtd._sync = part_sync; + if (master->_lock) + slave->mtd._lock = part_lock; + if (master->_unlock) + slave->mtd._unlock = part_unlock; + if (master->_block_isbad) + slave->mtd._block_isbad = part_block_isbad; + if (master->_block_markbad) + slave->mtd._block_markbad = part_block_markbad; + slave->mtd._erase = part_erase; slave->master = master; slave->offset = part->offset; slave->index = partno; @@ -416,12 +367,11 @@ static struct mtd_part *add_one_partition(struct mtd_info *master, } slave->mtd.ecclayout = master->ecclayout; - if (master->block_isbad) { + if (master->_block_isbad) { uint64_t offs = 0; while (offs < slave->mtd.size) { - if (master->block_isbad(master, - offs + slave->offset)) + if (mtd_block_isbad(master, offs + slave->offset)) slave->mtd.ecc_stats.badblocks++; offs += slave->mtd.erasesize; } diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 8821704..bb81e84 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -83,6 +83,7 @@ COBJS-$(CONFIG_NAND_DOCG4) += docg4.o else # minimal SPL drivers COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o +COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o COBJS-$(CONFIG_NAND_MXC) += mxc_nand_spl.o endif # drivers diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 994dd9f..3bfbaf8 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -489,7 +489,7 @@ normal_check: } static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int page) + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { struct atmel_nand_host *host = chip->priv; int eccsize = chip->ecc.size; @@ -529,8 +529,9 @@ static int atmel_nand_pmecc_read_page(struct mtd_info *mtd, return 0; } -static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) +static int atmel_nand_pmecc_write_page(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, + int oob_required) { struct atmel_nand_host *host = chip->priv; uint32_t *eccpos = chip->ecc.layout->eccpos; @@ -557,7 +558,7 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, if (!timeout) { printk(KERN_ERR "atmel_nand : Timeout to read PMECC status, fail to write PMECC in oob\n"); - return; + goto out; } for (i = 0; i < host->pmecc_sector_number; i++) { @@ -570,6 +571,8 @@ static void atmel_nand_pmecc_write_page(struct mtd_info *mtd, } } chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); +out: + return 0; } static void atmel_pmecc_core_init(struct mtd_info *mtd) @@ -706,6 +709,7 @@ static int atmel_pmecc_nand_init_params(struct nand_chip *nand, nand->ecc.read_page = atmel_nand_pmecc_read_page; nand->ecc.write_page = atmel_nand_pmecc_write_page; + nand->ecc.strength = cap; atmel_pmecc_core_init(mtd); @@ -775,9 +779,10 @@ static int atmel_nand_calculate(struct mtd_info *mtd, * mtd: mtd info structure * chip: nand chip info structure * buf: buffer to store read data + * oob_required: caller expects OOB data read to chip->oob_poi */ -static int atmel_nand_read_page(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int page) +static int atmel_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; diff --git a/drivers/mtd/nand/bfin_nand.c b/drivers/mtd/nand/bfin_nand.c index c7ddbb2..7e755e8 100644 --- a/drivers/mtd/nand/bfin_nand.c +++ b/drivers/mtd/nand/bfin_nand.c @@ -374,9 +374,11 @@ int board_nand_init(struct nand_chip *chip) if (!NAND_IS_512()) { chip->ecc.bytes = 3; chip->ecc.size = 256; + chip->ecc.strength = 1; } else { chip->ecc.bytes = 6; chip->ecc.size = 512; + chip->ecc.strength = 2; } chip->ecc.mode = NAND_ECC_HW; chip->ecc.calculate = bfin_nfc_calculate_ecc; diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index e8506dd..90f5985 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -607,12 +607,13 @@ void davinci_nand_init(struct nand_chip *nand) { nand->chip_delay = 0; #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - nand->options |= NAND_USE_FLASH_BBT; + nand->bbt_options |= NAND_BBT_USE_FLASH; #endif #ifdef CONFIG_SYS_NAND_HW_ECC nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = 512; nand->ecc.bytes = 3; + nand->ecc.strength = 1; nand->ecc.calculate = nand_davinci_calculate_ecc; nand->ecc.correct = nand_davinci_correct_data; nand->ecc.hwctl = nand_davinci_enable_hwecc; @@ -623,6 +624,7 @@ void davinci_nand_init(struct nand_chip *nand) nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; nand->ecc.size = 512; nand->ecc.bytes = 10; + nand->ecc.strength = 4; nand->ecc.calculate = nand_davinci_4bit_calculate_ecc; nand->ecc.correct = nand_davinci_4bit_correct_data; nand->ecc.hwctl = nand_davinci_4bit_enable_hwecc; diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index edf3a099..4cd741e 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -134,7 +134,7 @@ static struct rs_control *rs_decoder; /* * The HW decoder in the DoC ASIC's provides us a error syndrome, - * which we must convert to a standard syndrom usable by the generic + * which we must convert to a standard syndrome usable by the generic * Reed-Solomon library code. * * Fabrice Bellard figured this out in the old docecc code. I added @@ -154,7 +154,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc) ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2); parity = ecc[1]; - /* Initialize the syndrom buffer */ + /* Initialize the syndrome buffer */ for (i = 0; i < NROOTS; i++) s[i] = ds[0]; /* @@ -1033,7 +1033,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); else WriteDOC(DOC_ECC_DIS, docptr, ECCConf); - if (no_ecc_failures && (ret == -EBADMSG)) { + if (no_ecc_failures && mtd_is_eccerr(ret)) { printk(KERN_ERR "suppressing ECC failure\n"); ret = 0; } @@ -1073,7 +1073,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch size_t retlen; for (offs = 0; offs < mtd->size; offs += mtd->erasesize) { - ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf); + ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf); if (retlen != mtd->writesize) continue; if (ret) { @@ -1098,7 +1098,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf, const ch /* Only one mediaheader was found. We want buf to contain a mediaheader on return, so we'll have to re-read the one we found. */ offs = doc->mh0_page << this->page_shift; - ret = mtd->read(mtd, offs, mtd->writesize, &retlen, buf); + ret = mtd_read(mtd, offs, mtd->writesize, &retlen, buf); if (retlen != mtd->writesize) { /* Insanity. Give up. */ printk(KERN_ERR "Read DiskOnChip Media Header once, but can't reread it???\n"); @@ -1658,7 +1658,8 @@ static int __init doc_probe(unsigned long physadr) nand->ecc.mode = NAND_ECC_HW_SYNDROME; nand->ecc.size = 512; nand->ecc.bytes = 6; - nand->options = NAND_USE_FLASH_BBT; + nand->ecc.strength = 2; + nand->bbt_options = NAND_BBT_USE_FLASH; doc->physadr = physadr; doc->virtadr = virtadr; diff --git a/drivers/mtd/nand/docg4.c b/drivers/mtd/nand/docg4.c index 7dd9953..09f01c8 100644 --- a/drivers/mtd/nand/docg4.c +++ b/drivers/mtd/nand/docg4.c @@ -487,7 +487,7 @@ static void docg4_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) } static int docg4_read_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page, int sndcmd) + int page) { struct docg4_priv *doc = nand->priv; void __iomem *docptr = CONFIG_SYS_NAND_BASE; @@ -577,7 +577,7 @@ static void docg4_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) writew(p[i], nand->IO_ADDR_W); } -static void write_page(struct mtd_info *mtd, struct nand_chip *nand, +static int write_page(struct mtd_info *mtd, struct nand_chip *nand, const uint8_t *buf, int use_ecc) { void __iomem *docptr = CONFIG_SYS_NAND_BASE; @@ -626,16 +626,18 @@ static void write_page(struct mtd_info *mtd, struct nand_chip *nand, write_nop(docptr); writew(0, docptr + DOC_DATAEND); write_nop(docptr); + + return 0; } -static void docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf) +static int docg4_write_page_raw(struct mtd_info *mtd, struct nand_chip *nand, + const uint8_t *buf, int oob_required) { return write_page(mtd, nand, buf, 0); } -static void docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, - const uint8_t *buf) +static int docg4_write_page(struct mtd_info *mtd, struct nand_chip *nand, + const uint8_t *buf, int oob_required) { return write_page(mtd, nand, buf, 1); } @@ -706,13 +708,13 @@ static int read_page(struct mtd_info *mtd, struct nand_chip *nand, static int docg4_read_page_raw(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { return read_page(mtd, nand, buf, page, 0); } static int docg4_read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { return read_page(mtd, nand, buf, page, 1); } @@ -779,7 +781,7 @@ static int read_factory_bbt(struct mtd_info *mtd) return -ENOMEM; read_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); - status = docg4_read_page(mtd, nand, buf, DOCG4_FACTORY_BBT_PAGE); + status = docg4_read_page(mtd, nand, buf, 0, DOCG4_FACTORY_BBT_PAGE); if (status) goto exit; @@ -858,7 +860,7 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) /* write first page of block */ write_page_prologue(CONFIG_SYS_NAND_BASE, g4_addr); - docg4_write_page(mtd, nand, buf); + docg4_write_page(mtd, nand, buf, 1); ret = pageprog(mtd); if (!ret) mtd->ecc_stats.badblocks++; @@ -959,8 +961,8 @@ int docg4_nand_init(struct mtd_info *mtd, struct nand_chip *nand, int devnum) nand->ecc.size = DOCG4_PAGE_SIZE; nand->ecc.prepad = 8; nand->ecc.bytes = 8; - nand->options = - NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE | NAND_NO_AUTOINCR; + nand->ecc.strength = DOCG4_T; + nand->options = NAND_BUSWIDTH_16 | NAND_NO_SUBPAGE_WRITE; nand->controller = &nand->hwcontrol; /* methods */ diff --git a/drivers/mtd/nand/docg4_spl.c b/drivers/mtd/nand/docg4_spl.c index 95e856c..734cbeb 100644 --- a/drivers/mtd/nand/docg4_spl.c +++ b/drivers/mtd/nand/docg4_spl.c @@ -113,7 +113,6 @@ static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr) int g4_index = 0; uint16_t flash_status; uint16_t *buf; - uint16_t discard, magic_high, magic_low; /* flash_offset must be aligned to the start of a block */ if (flash_offset & 0x3ffff) @@ -154,9 +153,9 @@ static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr) * The IPL on the palmtreo680 requires that this contain a 32 bit magic * number, or the load aborts. We'll ignore it. */ - discard = readw(docptr + 0x103c); /* hw quirk; 1st read discarded */ - magic_low = readw(docptr + 0x103c); - magic_high = readw(docptr + DOCG4_MYSTERY_REG); + readw(docptr + 0x103c); /* hw quirk; 1st read discarded */ + readw(docptr + 0x103c); /* lower 16 bits of magic number */ + readw(docptr + DOCG4_MYSTERY_REG); /* upper 16 bits of magic number */ writew(0, docptr + DOC_DATAEND); write_nop(docptr); write_nop(docptr); @@ -183,15 +182,15 @@ static int docg4_load_block_reliable(uint32_t flash_offset, void *dest_addr) write_nop(docptr); /* read the 512 bytes of page data, 2 bytes at a time */ - discard = readw(docptr + 0x103c); + readw(docptr + 0x103c); /* hw quirk */ for (i = 0; i < 256; i++) *buf++ = readw(docptr + 0x103c); /* read oob, but discard it */ for (i = 0; i < 7; i++) - discard = readw(docptr + 0x103c); - discard = readw(docptr + DOCG4_OOB_6_7); - discard = readw(docptr + DOCG4_OOB_6_7); + readw(docptr + 0x103c); + readw(docptr + DOCG4_OOB_6_7); + readw(docptr + DOCG4_OOB_6_7); writew(0, docptr + DOC_DATAEND); write_nop(docptr); diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c index 834a8a6..0fa776a 100644 --- a/drivers/mtd/nand/fsl_elbc_nand.c +++ b/drivers/mtd/nand/fsl_elbc_nand.c @@ -640,9 +640,8 @@ static int fsl_elbc_wait(struct mtd_info *mtd, struct nand_chip *chip) return fsl_elbc_read_byte(mtd); } -static int fsl_elbc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int page) +static int fsl_elbc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) { fsl_elbc_read_buf(mtd, buf, mtd->writesize); fsl_elbc_read_buf(mtd, chip->oob_poi, mtd->oobsize); @@ -656,12 +655,13 @@ static int fsl_elbc_read_page(struct mtd_info *mtd, /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static void fsl_elbc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf) +static int fsl_elbc_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) { fsl_elbc_write_buf(mtd, buf, mtd->writesize); fsl_elbc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } static struct fsl_elbc_ctrl *elbc_ctrl; @@ -747,8 +747,8 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr) nand->bbt_md = &bbt_mirror_descr; /* set up nand options */ - nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | - NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE; + nand->options = NAND_NO_SUBPAGE_WRITE; + nand->bbt_options = NAND_BBT_USE_FLASH; nand->controller = &elbc_ctrl->controller; nand->priv = priv; @@ -756,20 +756,8 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr) nand->ecc.read_page = fsl_elbc_read_page; nand->ecc.write_page = fsl_elbc_write_page; -#ifdef CONFIG_FSL_ELBC_FMR - priv->fmr = CONFIG_FSL_ELBC_FMR; -#else priv->fmr = (15 << FMR_CWTO_SHIFT) | (2 << FMR_AL_SHIFT); - /* - * Hardware expects small page has ECCM0, large page has ECCM1 - * when booting from NAND. Board config can override if not - * booting from NAND. - */ - if (or & OR_FCM_PGS) - priv->fmr |= FMR_ECCM; -#endif - /* If CS Base Register selects full hardware ECC then use it */ if ((br & BR_DECC) == BR_DECC_CHK_GEN) { nand->ecc.mode = NAND_ECC_HW; @@ -781,16 +769,32 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr) nand->ecc.size = 512; nand->ecc.bytes = 3; nand->ecc.steps = 1; + nand->ecc.strength = 1; } else { /* otherwise fall back to default software ECC */ nand->ecc.mode = NAND_ECC_SOFT; } + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + return ret; + /* Large-page-specific setup */ - if (or & OR_FCM_PGS) { + if (mtd->writesize == 2048) { + setbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, + OR_FCM_PGS); + in_be32(&elbc_ctrl->regs->bank[priv->bank].or); + priv->page_size = 1; nand->badblock_pattern = &largepage_memorybased; + /* + * Hardware expects small page has ECCM0, large page has + * ECCM1 when booting from NAND, and we follow that even + * when not booting from NAND. + */ + priv->fmr |= FMR_ECCM; + /* adjust ecc setup if needed */ if ((br & BR_DECC) == BR_DECC_CHK_GEN) { nand->ecc.steps = 4; @@ -798,12 +802,14 @@ static int fsl_elbc_chip_init(int devnum, u8 *addr) &fsl_elbc_oob_lp_eccm1 : &fsl_elbc_oob_lp_eccm0; } + } else if (mtd->writesize == 512) { + clrbits_be32(&elbc_ctrl->regs->bank[priv->bank].or, + OR_FCM_PGS); + in_be32(&elbc_ctrl->regs->bank[priv->bank].or); + } else { + return -ENODEV; } - ret = nand_scan_ident(mtd, 1, NULL); - if (ret) - return ret; - ret = nand_scan_tail(mtd); if (ret) return ret; diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index b13d8a9..439822c 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -21,6 +21,7 @@ #include <common.h> #include <malloc.h> +#include <nand.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> @@ -41,7 +42,6 @@ struct fsl_ifc_ctrl; /* mtd information per set */ struct fsl_ifc_mtd { - struct mtd_info mtd; struct nand_chip chip; struct fsl_ifc_ctrl *ctrl; @@ -686,9 +686,8 @@ static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) return nand_fsr; } -static int fsl_ifc_read_page(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int page) +static int fsl_ifc_read_page(struct mtd_info *mtd, struct nand_chip *chip, + uint8_t *buf, int oob_required, int page) { struct fsl_ifc_mtd *priv = chip->priv; struct fsl_ifc_ctrl *ctrl = priv->ctrl; @@ -705,12 +704,13 @@ static int fsl_ifc_read_page(struct mtd_info *mtd, /* ECC will be calculated automatically, and errors will be detected in * waitfunc. */ -static void fsl_ifc_write_page(struct mtd_info *mtd, - struct nand_chip *chip, - const uint8_t *buf) +static int fsl_ifc_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) { fsl_ifc_write_buf(mtd, buf, mtd->writesize); fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } static void fsl_ifc_ctrl_init(void) @@ -794,11 +794,14 @@ static void fsl_ifc_sram_init(void) out_be32(&ifc_ctrl->regs->csor_cs[cs].csor_ext, csor_ext); } -int board_nand_init(struct nand_chip *nand) +static int fsl_ifc_chip_init(int devnum, u8 *addr) { + struct mtd_info *mtd = &nand_info[devnum]; + struct nand_chip *nand; struct fsl_ifc_mtd *priv; struct nand_ecclayout *layout; uint32_t cspr = 0, csor = 0, ver = 0; + int ret; if (!ifc_ctrl) { fsl_ifc_ctrl_init(); @@ -811,18 +814,18 @@ int board_nand_init(struct nand_chip *nand) return -ENOMEM; priv->ctrl = ifc_ctrl; - priv->vbase = nand->IO_ADDR_R; + priv->vbase = addr; /* Find which chip select it is connected to. */ for (priv->bank = 0; priv->bank < MAX_BANKS; priv->bank++) { - phys_addr_t base_addr = virt_to_phys(nand->IO_ADDR_R); + phys_addr_t phys_addr = virt_to_phys(addr); cspr = in_be32(&ifc_ctrl->regs->cspr_cs[priv->bank].cspr); csor = in_be32(&ifc_ctrl->regs->csor_cs[priv->bank].csor); if ((cspr & CSPR_V) && (cspr & CSPR_MSEL) == CSPR_MSEL_NAND && - (cspr & CSPR_BA) == CSPR_PHYS_ADDR(base_addr)) { + (cspr & CSPR_BA) == CSPR_PHYS_ADDR(phys_addr)) { ifc_ctrl->cs_nand = priv->bank << IFC_NAND_CSEL_SHIFT; break; } @@ -835,6 +838,9 @@ int board_nand_init(struct nand_chip *nand) return -ENODEV; } + nand = &priv->chip; + mtd->priv = nand; + ifc_ctrl->chips[priv->bank] = priv; /* fill in nand_chip structure */ @@ -852,8 +858,8 @@ int board_nand_init(struct nand_chip *nand) nand->bbt_md = &bbt_mirror_descr; /* set up nand options */ - nand->options = NAND_NO_READRDY | NAND_NO_AUTOINCR | - NAND_USE_FLASH_BBT | NAND_NO_SUBPAGE_WRITE; + nand->options = NAND_NO_SUBPAGE_WRITE; + nand->bbt_options = NAND_BBT_USE_FLASH; if (cspr & CSPR_PORT_SIZE_16) { nand->read_byte = fsl_ifc_read_byte16; @@ -884,11 +890,13 @@ int board_nand_init(struct nand_chip *nand) bbt_mirror_descr.offs = 0; } + nand->ecc.strength = 4; priv->bufnum_mask = 15; break; case CSOR_NAND_PGS_2K: layout = &oob_2048_ecc4; + nand->ecc.strength = 4; priv->bufnum_mask = 3; break; @@ -896,8 +904,10 @@ int board_nand_init(struct nand_chip *nand) if ((csor & CSOR_NAND_ECC_MODE_MASK) == CSOR_NAND_ECC_MODE_4) { layout = &oob_4096_ecc4; + nand->ecc.strength = 4; } else { layout = &oob_4096_ecc8; + nand->ecc.strength = 8; nand->ecc.bytes = 16; } @@ -921,5 +931,31 @@ int board_nand_init(struct nand_chip *nand) if (ver == FSL_IFC_V1_1_0) fsl_ifc_sram_init(); + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + return ret; + + ret = nand_scan_tail(mtd); + if (ret) + return ret; + + ret = nand_register(devnum); + if (ret) + return ret; return 0; } + +#ifndef CONFIG_SYS_NAND_BASE_LIST +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#endif + +static unsigned long base_address[CONFIG_SYS_MAX_NAND_DEVICE] = + CONFIG_SYS_NAND_BASE_LIST; + +void board_nand_init(void) +{ + int i; + + for (i = 0; i < CONFIG_SYS_MAX_NAND_DEVICE; i++) + fsl_ifc_chip_init(i, (u8 *)base_address[i]); +} diff --git a/nand_spl/nand_boot_fsl_ifc.c b/drivers/mtd/nand/fsl_ifc_spl.c index 44972c5..8537c4c 100644 --- a/nand_spl/nand_boot_fsl_ifc.c +++ b/drivers/mtd/nand/fsl_ifc_spl.c @@ -1,5 +1,5 @@ /* - * NAND boot for FSL Integrated Flash Controller, NAND Flash Control Machine + * NAND boot for Freescale Integrated Flash Controller, NAND FCM * * Copyright 2011 Freescale Semiconductor, Inc. * Author: Dipen Dudhat <dipen.dudhat@freescale.com> @@ -46,9 +46,9 @@ static inline int check_read_ecc(uchar *buf, u32 *eccstat, unsigned int bufnum, int page_size) { u32 reg = eccstat[bufnum / 4]; - int errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; + int errors = (reg >> ((3 - bufnum % 4) * 8)) & 0xf; - if (errors == 15) { /* uncorrectable */ + if (errors == 0xf) { /* uncorrectable */ /* Blank pages fail hw ECC checks */ if (is_blank(buf, page_size)) return 1; @@ -123,30 +123,17 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst) csor = CONFIG_SYS_NAND_CSOR; cspr = CONFIG_SYS_NAND_CSPR; - if (!(csor & CSOR_NAND_ECC_DEC_EN)) { - /* soft ECC in SPL is unimplemented */ - puts("WARNING: soft ECC not checked in SPL\n"); - } else { - u32 hwcsor; - - /* make sure board is configured with ECC on boot */ - hwcsor = in_be32(&ifc->csor_cs[0].csor); - if (!(hwcsor & CSOR_NAND_ECC_DEC_EN)) - puts("WARNING: ECC not checked in SPL, " - "check board cfg\n"); - } - port_size = (cspr & CSPR_PORT_SIZE_16) ? 16 : 8; if (csor & CSOR_NAND_PGS_4K) { page_size = 4096; - bufnum_mask = 1; + bufnum_mask = 0x1; } else if (csor & CSOR_NAND_PGS_2K) { page_size = 2048; - bufnum_mask = 3; + bufnum_mask = 0x3; } else { page_size = 512; - bufnum_mask = 15; + bufnum_mask = 0xf; if (port_size == 8) bad_marker = 5; @@ -174,8 +161,8 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst) out_be32(&ifc->ifc_nand.nand_fir1, 0x0); out_be32(&ifc->ifc_nand.nand_fcr0, - (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | - (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); + (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | + (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); } else { out_be32(&ifc->ifc_nand.nand_fir0, (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | @@ -185,7 +172,7 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst) out_be32(&ifc->ifc_nand.nand_fir1, 0x0); out_be32(&ifc->ifc_nand.nand_fcr0, - NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); + NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); } /* Program FBCR = 0 for full page read */ @@ -206,7 +193,7 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst) out_be32(&ifc->ifc_nand.col0, 0); /* start read */ out_be32(&ifc->ifc_nand.nandseq_strt, - IFC_NAND_SEQ_STRT_FIR_STRT); + IFC_NAND_SEQ_STRT_FIR_STRT); /* wait for read to complete */ nand_wait(&buf[sram_addr], bufnum, page_size); @@ -241,7 +228,6 @@ static void nand_load(unsigned int offs, int uboot_size, uchar *dst) void nand_boot(void) { __attribute__((noreturn)) void (*uboot)(void); - /* * Load U-Boot image from NAND into RAM */ @@ -257,15 +243,16 @@ void nand_boot(void) (uchar *)CONFIG_NAND_ENV_DST + CONFIG_ENV_SIZE); #endif #endif - /* * Jump to U-Boot image */ +#ifdef CONFIG_SPL_FLUSH_IMAGE /* * Clean d-cache and invalidate i-cache, to * make sure that no stale data is executed. */ flush_cache(CONFIG_SYS_NAND_U_BOOT_DST, CONFIG_SYS_NAND_U_BOOT_SIZE); +#endif uboot = (void *)CONFIG_SYS_NAND_U_BOOT_START; uboot(); } diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index 7a61d88..fab2aeb 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -341,6 +341,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller expects OOB data read to chip->oob_poi * @page: page number to read * * This routine is needed for fsmc verison 8 as reading from NAND chip has to be @@ -350,7 +351,7 @@ void fsmc_enable_hwecc(struct mtd_info *mtd, int mode) * max of 8 bits) */ static int fsmc_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { struct fsmc_eccplace *fsmc_eccpl; int i, j, s, stat, eccsize = chip->ecc.size; @@ -452,6 +453,7 @@ int fsmc_nand_init(struct nand_chip *nand) switch (fsmc_version) { case FSMC_VER8: nand->ecc.bytes = 13; + nand->ecc.strength = 8; nand->ecc.correct = fsmc_bch8_correct_data; nand->ecc.read_page = fsmc_read_page_hwecc; if (mtd->writesize == 512) @@ -466,6 +468,7 @@ int fsmc_nand_init(struct nand_chip *nand) break; default: nand->ecc.bytes = 3; + nand->ecc.strength = 1; nand->ecc.layout = &fsmc_ecc1_layout; nand->ecc.correct = nand_correct_data; break; diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c index 3ec34f3..9421e56 100644 --- a/drivers/mtd/nand/jz4740_nand.c +++ b/drivers/mtd/nand/jz4740_nand.c @@ -253,9 +253,10 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.mode = NAND_ECC_HW_OOB_FIRST; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; + nand->ecc.strength = 4; nand->ecc.layout = &qi_lb60_ecclayout_2gb; nand->chip_delay = 50; - nand->options = NAND_USE_FLASH_BBT; + nand->bbt_options |= NAND_BBT_USE_FLASH; return 0; } diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index e6b7a70..e53f341 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -621,7 +621,7 @@ int board_nand_init(struct nand_chip *chip) chip->write_buf = mpc5121_nfc_write_buf; chip->verify_buf = mpc5121_nfc_verify_buf; chip->select_chip = mpc5121_nfc_select_chip; - chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT; + chip->bbt_options = NAND_BBT_USE_FLASH; chip->ecc.mode = NAND_ECC_SOFT; /* Reset NAND Flash controller */ diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index eeba521..ac435f2 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -396,7 +396,7 @@ static void mxc_nand_enable_hwecc(struct mtd_info *mtd, int mode) #if defined(MXC_NFC_V2_1) || defined(MXC_NFC_V3_2) static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page, int sndcmd) + int page) { struct mxc_nand_host *host = chip->priv; uint8_t *buf = chip->oob_poi; @@ -450,6 +450,7 @@ static int mxc_nand_read_oob_syndrome(struct mtd_info *mtd, static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct mxc_nand_host *host = chip->priv; @@ -494,6 +495,7 @@ static int mxc_nand_read_page_raw_syndrome(struct mtd_info *mtd, static int mxc_nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { struct mxc_nand_host *host = chip->priv; @@ -583,9 +585,10 @@ static int mxc_nand_write_oob_syndrome(struct mtd_info *mtd, return status & NAND_STATUS_FAIL ? -EIO : 0; } -static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, +static int mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, + int oob_required) { struct mxc_nand_host *host = chip->priv; int eccsize = chip->ecc.size; @@ -619,11 +622,13 @@ static void mxc_nand_write_page_raw_syndrome(struct mtd_info *mtd, size = mtd->oobsize - (oob - chip->oob_poi); if (size) chip->write_buf(mtd, oob, size); + return 0; } -static void mxc_nand_write_page_syndrome(struct mtd_info *mtd, +static int mxc_nand_write_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, + int oob_required) { struct mxc_nand_host *host = chip->priv; int i, n, eccsize = chip->ecc.size; @@ -662,6 +667,7 @@ static void mxc_nand_write_page_syndrome(struct mtd_info *mtd, i = mtd->oobsize - (oob - chip->oob_poi); if (i) chip->write_buf(mtd, oob, i); + return 0; } static int mxc_nand_correct_data(struct mtd_info *mtd, u_char *dat, @@ -1188,7 +1194,7 @@ int board_nand_init(struct nand_chip *this) #endif #ifdef CONFIG_SYS_NAND_USE_FLASH_BBT - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; #endif @@ -1236,6 +1242,13 @@ int board_nand_init(struct nand_chip *this) this->ecc.mode = NAND_ECC_HW; } + if (this->ecc.mode == NAND_ECC_HW) { + if (is_mxc_nfc_1()) + this->ecc.strength = 1; + else + this->ecc.strength = 4; + } + host->pagesize_2k = 0; this->ecc.size = 512; diff --git a/drivers/mtd/nand/mxs_nand.c b/drivers/mtd/nand/mxs_nand.c index 398e4dd..866cabd 100644 --- a/drivers/mtd/nand/mxs_nand.c +++ b/drivers/mtd/nand/mxs_nand.c @@ -553,7 +553,8 @@ static uint8_t mxs_nand_read_byte(struct mtd_info *mtd) * Read a page from NAND. */ static int mxs_nand_ecc_read_page(struct mtd_info *mtd, struct nand_chip *nand, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, + int page) { struct mxs_nand_info *nand_info = nand->priv; struct mxs_dma_desc *d; @@ -698,8 +699,9 @@ rtn: /* * Write a page to NAND. */ -static void mxs_nand_ecc_write_page(struct mtd_info *mtd, - struct nand_chip *nand, const uint8_t *buf) +static int mxs_nand_ecc_write_page(struct mtd_info *mtd, + struct nand_chip *nand, const uint8_t *buf, + int oob_required) { struct mxs_nand_info *nand_info = nand->priv; struct mxs_dma_desc *d; @@ -755,6 +757,7 @@ static void mxs_nand_ecc_write_page(struct mtd_info *mtd, rtn: mxs_nand_return_dma_descs(nand_info); + return 0; } /* @@ -770,7 +773,7 @@ static int mxs_nand_hook_read_oob(struct mtd_info *mtd, loff_t from, struct mxs_nand_info *nand_info = chip->priv; int ret; - if (ops->mode == MTD_OOB_RAW) + if (ops->mode == MTD_OPS_RAW) nand_info->raw_oob_mode = 1; else nand_info->raw_oob_mode = 0; @@ -795,7 +798,7 @@ static int mxs_nand_hook_write_oob(struct mtd_info *mtd, loff_t to, struct mxs_nand_info *nand_info = chip->priv; int ret; - if (ops->mode == MTD_OOB_RAW) + if (ops->mode == MTD_OPS_RAW) nand_info->raw_oob_mode = 1; else nand_info->raw_oob_mode = 0; @@ -873,7 +876,7 @@ static int mxs_nand_hook_block_markbad(struct mtd_info *mtd, loff_t ofs) * what to do. */ static int mxs_nand_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *nand, - int page, int cmd) + int page) { struct mxs_nand_info *nand_info = nand->priv; @@ -1006,19 +1009,19 @@ static int mxs_nand_scan_bbt(struct mtd_info *mtd) writel(BCH_CTRL_COMPLETE_IRQ_EN, &bch_regs->hw_bch_ctrl_set); /* Hook some operations at the MTD level. */ - if (mtd->read_oob != mxs_nand_hook_read_oob) { - nand_info->hooked_read_oob = mtd->read_oob; - mtd->read_oob = mxs_nand_hook_read_oob; + if (mtd->_read_oob != mxs_nand_hook_read_oob) { + nand_info->hooked_read_oob = mtd->_read_oob; + mtd->_read_oob = mxs_nand_hook_read_oob; } - if (mtd->write_oob != mxs_nand_hook_write_oob) { - nand_info->hooked_write_oob = mtd->write_oob; - mtd->write_oob = mxs_nand_hook_write_oob; + if (mtd->_write_oob != mxs_nand_hook_write_oob) { + nand_info->hooked_write_oob = mtd->_write_oob; + mtd->_write_oob = mxs_nand_hook_write_oob; } - if (mtd->block_markbad != mxs_nand_hook_block_markbad) { - nand_info->hooked_block_markbad = mtd->block_markbad; - mtd->block_markbad = mxs_nand_hook_block_markbad; + if (mtd->_block_markbad != mxs_nand_hook_block_markbad) { + nand_info->hooked_block_markbad = mtd->_block_markbad; + mtd->_block_markbad = mxs_nand_hook_block_markbad; } /* We use the reference implementation for bad block management. */ @@ -1172,6 +1175,7 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.mode = NAND_ECC_HW; nand->ecc.bytes = 9; nand->ecc.size = 512; + nand->ecc.strength = 8; return 0; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index a2d06be..9e05cef 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -21,7 +21,7 @@ * TODO: * Enable cached programming for 2k page size chips * Check, if mtd->ecctype should be set to MTD_ECC_HW - * if we have HW ecc support. + * if we have HW ECC support. * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * BBT table is not serialized, has to be fixed @@ -134,21 +134,14 @@ static int check_offs_len(struct mtd_info *mtd, ret = -EINVAL; } - /* Do not allow past end of device */ - if (ofs + len > mtd->size) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: Past end of device\n", - __func__); - ret = -EINVAL; - } - return ret; } /** * nand_release_device - [GENERIC] release chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Deselect, release chip lock and wake up anyone waiting on the device + * Deselect, release chip lock and wake up anyone waiting on the device. */ static void nand_release_device(struct mtd_info *mtd) { @@ -160,9 +153,9 @@ static void nand_release_device(struct mtd_info *mtd) /** * nand_read_byte - [DEFAULT] read one byte from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth. */ uint8_t nand_read_byte(struct mtd_info *mtd) { @@ -172,10 +165,11 @@ uint8_t nand_read_byte(struct mtd_info *mtd) /** * nand_read_byte16 - [DEFAULT] read one byte endianess aware from the chip - * @mtd: MTD device structure + * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip + * @mtd: MTD device structure + * + * Default read function for 16bit buswidth with endianness conversion. * - * Default read function for 16bit buswith with - * endianess conversion */ static uint8_t nand_read_byte16(struct mtd_info *mtd) { @@ -185,10 +179,9 @@ static uint8_t nand_read_byte16(struct mtd_info *mtd) /** * nand_read_word - [DEFAULT] read one word from the chip - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Default read function for 16bit buswith without - * endianess conversion + * Default read function for 16bit buswidth without endianness conversion. */ static u16 nand_read_word(struct mtd_info *mtd) { @@ -198,8 +191,8 @@ static u16 nand_read_word(struct mtd_info *mtd) /** * nand_select_chip - [DEFAULT] control CE line - * @mtd: MTD device structure - * @chipnr: chipnumber to select, -1 for deselect + * @mtd: MTD device structure + * @chipnr: chipnumber to select, -1 for deselect * * Default select function for 1 chip devices. */ @@ -221,11 +214,11 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr) /** * nand_write_buf - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 8bit buswith + * Default write function for 8bit buswidth. */ void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -238,11 +231,11 @@ void nand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 8bit buswith + * Default read function for 8bit buswidth. */ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -255,11 +248,11 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 8bit buswith + * Default verify function for 8bit buswidth. */ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -274,11 +267,11 @@ static int nand_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_write_buf16 - [DEFAULT] write buffer to chip - * @mtd: MTD device structure - * @buf: data buffer - * @len: number of bytes to write + * @mtd: MTD device structure + * @buf: data buffer + * @len: number of bytes to write * - * Default write function for 16bit buswith + * Default write function for 16bit buswidth. */ void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -294,11 +287,11 @@ void nand_write_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_read_buf16 - [DEFAULT] read chip data into buffer - * @mtd: MTD device structure - * @buf: buffer to store date - * @len: number of bytes to read + * @mtd: MTD device structure + * @buf: buffer to store date + * @len: number of bytes to read * - * Default read function for 16bit buswith + * Default read function for 16bit buswidth. */ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) { @@ -313,11 +306,11 @@ void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len) /** * nand_verify_buf16 - [DEFAULT] Verify chip data against buffer - * @mtd: MTD device structure - * @buf: buffer containing the data to compare - * @len: number of bytes to compare + * @mtd: MTD device structure + * @buf: buffer containing the data to compare + * @len: number of bytes to compare * - * Default verify function for 16bit buswith + * Default verify function for 16bit buswidth. */ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) { @@ -335,19 +328,19 @@ static int nand_verify_buf16(struct mtd_info *mtd, const uint8_t *buf, int len) /** * nand_block_bad - [DEFAULT] Read bad block marker from the chip - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected * * Check, if the block is bad. */ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) { - int page, chipnr, res = 0; + int page, chipnr, res = 0, i = 0; struct nand_chip *chip = mtd->priv; u16 bad; - if (chip->options & NAND_BBT_SCANLASTPAGE) + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) ofs += mtd->erasesize - mtd->writesize; page = (int)(ofs >> chip->page_shift) & chip->pagemask; @@ -361,23 +354,29 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) chip->select_chip(mtd, chipnr); } - if (chip->options & NAND_BUSWIDTH_16) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos & 0xFE, - page); - bad = cpu_to_le16(chip->read_word(mtd)); - if (chip->badblockpos & 0x1) - bad >>= 8; - else - bad &= 0xFF; - } else { - chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, page); - bad = chip->read_byte(mtd); - } + do { + if (chip->options & NAND_BUSWIDTH_16) { + chip->cmdfunc(mtd, NAND_CMD_READOOB, + chip->badblockpos & 0xFE, page); + bad = cpu_to_le16(chip->read_word(mtd)); + if (chip->badblockpos & 0x1) + bad >>= 8; + else + bad &= 0xFF; + } else { + chip->cmdfunc(mtd, NAND_CMD_READOOB, chip->badblockpos, + page); + bad = chip->read_byte(mtd); + } - if (likely(chip->badblockbits == 8)) - res = bad != 0xFF; - else - res = hweight8(bad) < chip->badblockbits; + if (likely(chip->badblockbits == 8)) + res = bad != 0xFF; + else + res = hweight8(bad) < chip->badblockbits; + ofs += mtd->writesize; + page = (int)(ofs >> chip->page_shift) & chip->pagemask; + i++; + } while (!res && i < 2 && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE)); if (getchip) nand_release_device(mtd); @@ -387,57 +386,83 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) /** * nand_default_block_markbad - [DEFAULT] mark a block bad - * @mtd: MTD device structure - * @ofs: offset from device start + * @mtd: MTD device structure + * @ofs: offset from device start * - * This is the default implementation, which can be overridden by - * a hardware specific driver. + * This is the default implementation, which can be overridden by a hardware + * specific driver. We try operations in the following order, according to our + * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): + * (1) erase the affected block, to allow OOB marker to be written cleanly + * (2) update in-memory BBT + * (3) write bad block marker to OOB area of affected block + * (4) update flash-based BBT + * Note that we retain the first error encountered in (3) or (4), finish the + * procedures, and dump the error in the end. */ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) { struct nand_chip *chip = mtd->priv; uint8_t buf[2] = { 0, 0 }; - int block, ret, i = 0; + int block, res, ret = 0, i = 0; + int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); - if (chip->options & NAND_BBT_SCANLASTPAGE) - ofs += mtd->erasesize - mtd->writesize; + if (write_oob) { + struct erase_info einfo; + + /* Attempt erase before marking OOB */ + memset(&einfo, 0, sizeof(einfo)); + einfo.mtd = mtd; + einfo.addr = ofs; + einfo.len = 1 << chip->phys_erase_shift; + nand_erase_nand(mtd, &einfo, 0); + } /* Get block number */ block = (int)(ofs >> chip->bbt_erase_shift); + /* Mark block bad in memory-based BBT */ if (chip->bbt) chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); - /* Do we have a flash based bad block table ? */ - if (chip->options & NAND_USE_FLASH_BBT) - ret = nand_update_bbt(mtd, ofs); - else { + /* Write bad block marker to OOB */ + if (write_oob) { + struct mtd_oob_ops ops; + loff_t wr_ofs = ofs; + nand_get_device(chip, mtd, FL_WRITING); - /* Write to first two pages and to byte 1 and 6 if necessary. - * If we write to more than one location, the first error - * encountered quits the procedure. We write two bytes per - * location, so we dont have to mess with 16 bit access. - */ - do { - chip->ops.len = chip->ops.ooblen = 2; - chip->ops.datbuf = NULL; - chip->ops.oobbuf = buf; - chip->ops.ooboffs = chip->badblockpos & ~0x01; + ops.datbuf = NULL; + ops.oobbuf = buf; + ops.ooboffs = chip->badblockpos; + if (chip->options & NAND_BUSWIDTH_16) { + ops.ooboffs &= ~0x01; + ops.len = ops.ooblen = 2; + } else { + ops.len = ops.ooblen = 1; + } + ops.mode = MTD_OPS_PLACE_OOB; - ret = nand_do_write_oob(mtd, ofs, &chip->ops); + /* Write to first/last page(s) if necessary */ + if (chip->bbt_options & NAND_BBT_SCANLASTPAGE) + wr_ofs += mtd->erasesize - mtd->writesize; + do { + res = nand_do_write_oob(mtd, wr_ofs, &ops); + if (!ret) + ret = res; - if (!ret && (chip->options & NAND_BBT_SCANBYTE1AND6)) { - chip->ops.ooboffs = NAND_SMALL_BADBLOCK_POS - & ~0x01; - ret = nand_do_write_oob(mtd, ofs, &chip->ops); - } i++; - ofs += mtd->writesize; - } while (!ret && (chip->options & NAND_BBT_SCAN2NDPAGE) && - i < 2); + wr_ofs += mtd->writesize; + } while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2); nand_release_device(mtd); } + + /* Update flash-based bad block table */ + if (chip->bbt_options & NAND_BBT_USE_FLASH) { + res = nand_update_bbt(mtd, ofs); + if (!ret) + ret = res; + } + if (!ret) mtd->ecc_stats.badblocks++; @@ -446,16 +471,16 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) /** * nand_check_wp - [GENERIC] check if the chip is write protected - * @mtd: MTD device structure - * Check, if the device is write protected + * @mtd: MTD device structure * - * The function expects, that the device is already selected + * Check, if the device is write protected. The function expects, that the + * device is already selected. */ static int nand_check_wp(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; - /* broken xD cards report WP despite being writable */ + /* Broken xD cards report WP despite being writable */ if (chip->options & NAND_BROKEN_XD) return 0; @@ -466,10 +491,10 @@ static int nand_check_wp(struct mtd_info *mtd) /** * nand_block_checkbad - [GENERIC] Check if a block is marked bad - * @mtd: MTD device structure - * @ofs: offset from device start - * @getchip: 0, if the chip is already selected - * @allowbbt: 1, if its allowed to access the bbt area + * @mtd: MTD device structure + * @ofs: offset from device start + * @getchip: 0, if the chip is already selected + * @allowbbt: 1, if its allowed to access the bbt area * * Check, if the block is bad. Either by reading the bad block table or * calling of the scan function. @@ -491,10 +516,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, return nand_isbad_bbt(mtd, ofs, allowbbt); } -/* - * Wait for the ready pin, after a command - * The timeout is catched later. - */ +/* Wait for the ready pin, after a command. The timeout is caught later. */ void nand_wait_ready(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; @@ -503,7 +525,7 @@ void nand_wait_ready(struct mtd_info *mtd) time_start = get_timer(0); - /* wait until command is processed or timeout occures */ + /* Wait until command is processed or timeout occurs */ while (get_timer(time_start) < timeo) { if (chip->dev_ready) if (chip->dev_ready(mtd)) @@ -513,13 +535,13 @@ void nand_wait_ready(struct mtd_info *mtd) /** * nand_command - [DEFAULT] Send command to NAND device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * - * Send command to NAND device. This function is used for small page - * devices (256/512 Bytes per page) + * Send command to NAND device. This function is used for small page devices + * (256/512 Bytes per page). */ static void nand_command(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -528,9 +550,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, int ctrl = NAND_CTRL_CLE | NAND_CTRL_CHANGE; uint32_t rst_sts_cnt = CONFIG_SYS_NAND_RESET_CNT; - /* - * Write out the command to the device. - */ + /* Write out the command to the device */ if (command == NAND_CMD_SEQIN) { int readcmd; @@ -550,9 +570,7 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, } chip->cmd_ctrl(mtd, command, ctrl); - /* - * Address cycle, when necessary - */ + /* Address cycle, when necessary */ ctrl = NAND_CTRL_ALE | NAND_CTRL_CHANGE; /* Serially input address */ if (column != -1) { @@ -573,8 +591,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status and sequential in needs no delay + * Program and erase have their own busy handlers status and sequential + * in needs no delay */ switch (command) { @@ -608,8 +626,10 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, return; } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -617,14 +637,14 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, /** * nand_command_lp - [DEFAULT] Send command to NAND large page device - * @mtd: MTD device structure - * @command: the command to be sent - * @column: the column address for this command, -1 if none - * @page_addr: the page address for this command, -1 if none + * @mtd: MTD device structure + * @command: the command to be sent + * @column: the column address for this command, -1 if none + * @page_addr: the page address for this command, -1 if none * * Send command to NAND device. This is the version for the new large page - * devices We dont have the separate regions as we have in the small page - * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. + * devices. We don't have the separate regions as we have in the small page + * devices. We must emulate NAND_CMD_READOOB to keep the code compatible. */ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) @@ -667,8 +687,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); /* - * program and erase have their own busy handlers - * status, sequential in, and deplete1 need no delay + * Program and erase have their own busy handlers status, sequential + * in, and deplete1 need no delay. */ switch (command) { @@ -682,14 +702,12 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, case NAND_CMD_DEPLETE1: return; - /* - * read error status commands require only a short delay - */ case NAND_CMD_STATUS_ERROR: case NAND_CMD_STATUS_ERROR0: case NAND_CMD_STATUS_ERROR1: case NAND_CMD_STATUS_ERROR2: case NAND_CMD_STATUS_ERROR3: + /* Read error status commands require only a short delay */ udelay(chip->chip_delay); return; @@ -723,7 +741,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, default: /* * If we don't have access to the busy pin, we apply the given - * command delay + * command delay. */ if (!chip->dev_ready) { udelay(chip->chip_delay); @@ -731,8 +749,10 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, } } - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ + /* + * Apply this short delay always to ensure that we do wait tWB in + * any case on any machine. + */ ndelay(100); nand_wait_ready(mtd); @@ -740,9 +760,9 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, /** * nand_get_device - [GENERIC] Get chip for selected access - * @chip: the nand chip descriptor - * @mtd: MTD device structure - * @new_state: the state which is requested + * @chip: the nand chip descriptor + * @mtd: MTD device structure + * @new_state: the state which is requested * * Get the device and lock it for exclusive access */ @@ -754,13 +774,13 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) } /** - * nand_wait - [DEFAULT] wait until the command is done - * @mtd: MTD device structure - * @chip: NAND chip structure + * nand_wait - [DEFAULT] wait until the command is done + * @mtd: MTD device structure + * @chip: NAND chip structure * - * Wait for command done. This applies to erase and program only - * Erase can take up to 400ms and program up to 20ms according to - * general NAND and SmartMedia specs + * Wait for command done. This applies to erase and program only. Erase can + * take up to 400ms and program up to 20ms according to general NAND and + * SmartMedia specs. */ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) { @@ -804,34 +824,37 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) } /** - * nand_read_page_raw - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_raw - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { chip->read_buf(mtd, buf, mtd->writesize); - chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); + if (oob_required) + chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); return 0; } /** - * nand_read_page_raw_syndrome - [Intern] read raw page data without ecc - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_raw_syndrome - [INTERN] read raw page data without ecc + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read * * We need a special oob layout and handling even when OOB isn't used. */ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, - uint8_t *buf, int page) + struct nand_chip *chip, uint8_t *buf, + int oob_required, int page) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -864,14 +887,15 @@ static int nand_read_page_raw_syndrome(struct mtd_info *mtd, } /** - * nand_read_page_swecc - [REPLACABLE] software ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_swecc - [REPLACEABLE] software ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read */ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -881,7 +905,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, uint8_t *ecc_code = chip->buffers->ecccode; uint32_t *eccpos = chip->ecc.layout->eccpos; - chip->ecc.read_page_raw(mtd, chip, buf, page); + chip->ecc.read_page_raw(mtd, chip, buf, 1, page); for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); @@ -905,12 +929,12 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_subpage - [REPLACABLE] software ecc based sub-page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @data_offs: offset of requested data within the page - * @readlen: data length - * @bufpoi: buffer to store read data + * nand_read_subpage - [REPLACEABLE] software ECC based sub-page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @data_offs: offset of requested data within the page + * @readlen: data length + * @bufpoi: buffer to store read data */ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi) @@ -923,12 +947,12 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1; int index = 0; - /* Column address wihin the page aligned to ECC size (256bytes). */ + /* Column address within the page aligned to ECC size (256bytes) */ start_step = data_offs / chip->ecc.size; end_step = (data_offs + readlen - 1) / chip->ecc.size; num_steps = end_step - start_step + 1; - /* Data size aligned to ECC ecc.size*/ + /* Data size aligned to ECC ecc.size */ datafrag_len = num_steps * chip->ecc.size; eccfrag_len = num_steps * chip->ecc.bytes; @@ -940,13 +964,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, p = bufpoi + data_col_addr; chip->read_buf(mtd, p, datafrag_len); - /* Calculate ECC */ + /* Calculate ECC */ for (i = 0; i < eccfrag_len ; i += chip->ecc.bytes, p += chip->ecc.size) chip->ecc.calculate(mtd, p, &chip->buffers->ecccalc[i]); - /* The performance is faster if to position offsets - according to ecc.pos. Let make sure here that - there are no gaps in ecc positions */ + /* + * The performance is faster if we position offsets according to + * ecc.pos. Let's make sure that there are no gaps in ECC positions. + */ for (i = 0; i < eccfrag_len - 1; i++) { if (eccpos[i + start_step * chip->ecc.bytes] + 1 != eccpos[i + start_step * chip->ecc.bytes + 1]) { @@ -958,8 +983,10 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_RNDOUT, mtd->writesize, -1); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); } else { - /* send the command to read the particular ecc bytes */ - /* take care about buswidth alignment in read_buf */ + /* + * Send the command to read the particular ECC bytes take care + * about buswidth alignment in read_buf. + */ index = start_step * chip->ecc.bytes; aligned_pos = eccpos[index] & ~(busw - 1); @@ -992,16 +1019,17 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_hwecc - [REPLACEABLE] hardware ECC based page read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read * - * Not for syndrome calculating ecc controllers which need a special oob layout + * Not for syndrome calculating ECC controllers which need a special oob layout. */ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1037,21 +1065,21 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_read_page_hwecc_oob_first - [REPLACABLE] hw ecc, read oob first - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_hwecc_oob_first - [REPLACEABLE] hw ecc, read oob first + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read * - * Hardware ECC for large page chips, require OOB to be read first. - * For this ECC mode, the write_page method is re-used from ECC_HW. - * These methods read/write ECC from the OOB area, unlike the - * ECC_HW_SYNDROME support with multiple ECC steps, follows the - * "infix ECC" scheme and reads/writes ECC from the data area, by - * overwriting the NAND manufacturer bad block markings. + * Hardware ECC for large page chips, require OOB to be read first. For this + * ECC mode, the write_page method is re-used from ECC_HW. These methods + * read/write ECC from the OOB area, unlike the ECC_HW_SYNDROME support with + * multiple ECC steps, follows the "infix ECC" scheme and reads/writes ECC from + * the data area, by overwriting the NAND manufacturer bad block markings. */ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int page) + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1086,17 +1114,18 @@ static int nand_read_page_hwecc_oob_first(struct mtd_info *mtd, } /** - * nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: buffer to store read data - * @page: page number to read + * nand_read_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page read + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1141,29 +1170,29 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_transfer_oob - [Internal] Transfer oob to client buffer - * @chip: nand chip structure - * @oob: oob destination address - * @ops: oob ops structure - * @len: size of oob to transfer + * nand_transfer_oob - [INTERN] Transfer oob to client buffer + * @chip: nand chip structure + * @oob: oob destination address + * @ops: oob ops structure + * @len: size of oob to transfer */ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, struct mtd_oob_ops *ops, size_t len) { switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(oob, chip->oob_poi + ops->ooboffs, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, roffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Read request not from offset 0 ? */ + /* Read request not from offset 0? */ if (unlikely(roffs)) { if (roffs >= free->length) { roffs -= free->length; @@ -1189,26 +1218,23 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, } /** - * nand_do_read_ops - [Internal] Read data with ECC - * - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob ops structure + * nand_do_read_ops - [INTERN] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob ops structure * * Internal function. Called with chip held. */ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int chipnr, page, realpage, col, bytes, aligned; + int chipnr, page, realpage, col, bytes, aligned, oob_required; struct nand_chip *chip = mtd->priv; struct mtd_ecc_stats stats; - int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; - int sndcmd = 1; int ret = 0; uint32_t readlen = ops->len; uint32_t oobreadlen = ops->ooblen; - uint32_t max_oobsize = ops->mode == MTD_OOB_AUTO ? + uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *bufpoi, *oob, *buf; @@ -1225,6 +1251,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, buf = ops->datbuf; oob = ops->oobbuf; + oob_required = oob ? 1 : 0; while (1) { WATCHDOG_RESET(); @@ -1232,41 +1259,46 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, bytes = min(mtd->writesize - col, readlen); aligned = (bytes == mtd->writesize); - /* Is the current page in the buffer ? */ + /* Is the current page in the buffer? */ if (realpage != chip->pagebuf || oob) { bufpoi = aligned ? buf : chip->buffers->databuf; - if (likely(sndcmd)) { - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); - sndcmd = 0; - } + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); /* Now read the page into the buffer */ - if (unlikely(ops->mode == MTD_OOB_RAW)) - ret = chip->ecc.read_page_raw(mtd, chip, - bufpoi, page); + if (unlikely(ops->mode == MTD_OPS_RAW)) + ret = chip->ecc.read_page_raw(mtd, chip, bufpoi, + oob_required, + page); else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) && !oob) ret = chip->ecc.read_subpage(mtd, chip, col, bytes, bufpoi); else ret = chip->ecc.read_page(mtd, chip, bufpoi, - page); - if (ret < 0) + oob_required, page); + if (ret < 0) { + if (!aligned) + /* Invalidate page cache */ + chip->pagebuf = -1; break; + } /* Transfer not aligned data */ if (!aligned) { if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && - !(mtd->ecc_stats.failed - stats.failed)) + !(mtd->ecc_stats.failed - stats.failed) && + (ops->mode != MTD_OPS_RAW)) chip->pagebuf = realpage; + else + /* Invalidate page cache */ + chip->pagebuf = -1; memcpy(buf, chip->buffers->databuf + col, bytes); } buf += bytes; if (unlikely(oob)) { - int toread = min(oobreadlen, max_oobsize); if (toread) { @@ -1275,20 +1307,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, oobreadlen -= toread; } } - - if (!(chip->options & NAND_NO_READRDY)) { - /* - * Apply delay or wait for ready/busy pin. Do - * this before the AUTOINCR check, so no - * problems arise if a chip which does auto - * increment is marked as NOAUTOINCR by the - * board driver. - */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; @@ -1299,7 +1317,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, if (!readlen) break; - /* For subsequent reads align to page boundary. */ + /* For subsequent reads align to page boundary */ col = 0; /* Increment page address */ realpage++; @@ -1311,12 +1329,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); } - - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ - if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) - sndcmd = 1; } ops->retlen = ops->len - (size_t) readlen; @@ -1334,69 +1346,55 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /** * nand_read - [MTD Interface] MTD compatibility function for nand_do_read_ecc - * @mtd: MTD device structure - * @from: offset to read from - * @len: number of bytes to read - * @retlen: pointer to variable to store the number of read bytes - * @buf: the databuffer to put data + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data * - * Get hold of the chip and call nand_do_read + * Get hold of the chip and call nand_do_read. */ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; - /* Do not allow reads past end of device */ - if ((from + len) > mtd->size) - return -EINVAL; - if (!len) - return 0; - nand_get_device(chip, mtd, FL_READING); - - chip->ops.len = len; - chip->ops.datbuf = buf; - chip->ops.oobbuf = NULL; - - ret = nand_do_read_ops(mtd, from, &chip->ops); - - *retlen = chip->ops.retlen; - + ops.len = len; + ops.datbuf = buf; + ops.oobbuf = NULL; + ops.mode = MTD_OPS_PLACE_OOB; + ret = nand_do_read_ops(mtd, from, &ops); + *retlen = ops.retlen; nand_release_device(mtd); - return ret; } /** - * nand_read_oob_std - [REPLACABLE] the most common OOB data read function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * nand_read_oob_std - [REPLACEABLE] the most common OOB data read function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read */ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, - int page, int sndcmd) + int page) { - if (sndcmd) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - sndcmd = 0; - } + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); - return sndcmd; + return 0; } /** - * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC + * nand_read_oob_syndrome - [REPLACEABLE] OOB data read function for HW ECC * with syndromes - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to read - * @sndcmd: flag whether to issue read command or not + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to read */ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - int page, int sndcmd) + int page) { uint8_t *buf = chip->oob_poi; int length = mtd->oobsize; @@ -1423,14 +1421,14 @@ static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, if (length > 0) chip->read_buf(mtd, bufpoi, length); - return 1; + return 0; } /** - * nand_write_oob_std - [REPLACABLE] the most common OOB data write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * nand_write_oob_std - [REPLACEABLE] the most common OOB data write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1450,11 +1448,11 @@ static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, } /** - * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC - * with syndrome - only for large page flash ! - * @mtd: mtd info structure - * @chip: nand chip info structure - * @page: page number to write + * nand_write_oob_syndrome - [REPLACEABLE] OOB data write function for HW ECC + * with syndrome - only for large page flash + * @mtd: mtd info structure + * @chip: nand chip info structure + * @page: page number to write */ static int nand_write_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page) @@ -1509,27 +1507,30 @@ static int nand_write_oob_syndrome(struct mtd_info *mtd, } /** - * nand_do_read_oob - [Intern] NAND read out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operations description structure + * nand_do_read_oob - [INTERN] NAND read out-of-band + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operations description structure * - * NAND read out-of-band data from the spare area + * NAND read out-of-band data from the spare area. */ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { - int page, realpage, chipnr, sndcmd = 1; + int page, realpage, chipnr; struct nand_chip *chip = mtd->priv; - int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; + struct mtd_ecc_stats stats; int readlen = ops->ooblen; int len; uint8_t *buf = ops->oobbuf; + int ret = 0; MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); - if (ops->mode == MTD_OOB_AUTO) + stats = mtd->ecc_stats; + + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; @@ -1558,24 +1559,17 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, while (1) { WATCHDOG_RESET(); - sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); + if (ops->mode == MTD_OPS_RAW) + ret = chip->ecc.read_oob_raw(mtd, chip, page); + else + ret = chip->ecc.read_oob(mtd, chip, page); + + if (ret < 0) + break; len = min(len, readlen); buf = nand_transfer_oob(chip, buf, ops, len); - if (!(chip->options & NAND_NO_READRDY)) { - /* - * Apply delay or wait for ready/busy pin. Do this - * before the AUTOINCR check, so no problems arise if a - * chip which does auto increment is marked as - * NOAUTOINCR by the board driver. - */ - if (!chip->dev_ready) - udelay(chip->chip_delay); - else - nand_wait_ready(mtd); - } - readlen -= len; if (!readlen) break; @@ -1590,25 +1584,26 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, chip->select_chip(mtd, -1); chip->select_chip(mtd, chipnr); } - - /* Check, if the chip supports auto page increment - * or if we have hit a block boundary. - */ - if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck)) - sndcmd = 1; } - ops->oobretlen = ops->ooblen; - return 0; + ops->oobretlen = ops->ooblen - readlen; + + if (ret < 0) + return ret; + + if (mtd->ecc_stats.failed - stats.failed) + return -EBADMSG; + + return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; } /** * nand_read_oob - [MTD Interface] NAND read data and/or out-of-band - * @mtd: MTD device structure - * @from: offset to read from - * @ops: oob operation description structure + * @mtd: MTD device structure + * @from: offset to read from + * @ops: oob operation description structure * - * NAND read data and/or out-of-band data + * NAND read data and/or out-of-band data. */ static int nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) @@ -1628,9 +1623,9 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, nand_get_device(chip, mtd, FL_READING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: @@ -1649,31 +1644,36 @@ out: /** - * nand_write_page_raw - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_raw - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB * - * Not for syndrome calculating ecc controllers, which use a special oob layout + * Not for syndrome calculating ECC controllers, which use a special oob layout. */ -static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) +static int nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) { chip->write_buf(mtd, buf, mtd->writesize); - chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + if (oob_required) + chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } /** - * nand_write_page_raw_syndrome - [Intern] raw page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_raw_syndrome - [INTERN] raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB * * We need a special oob layout and handling even when ECC isn't checked. */ -static void nand_write_page_raw_syndrome(struct mtd_info *mtd, +static int nand_write_page_raw_syndrome(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) + const uint8_t *buf, int oob_required) { int eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1701,15 +1701,18 @@ static void nand_write_page_raw_syndrome(struct mtd_info *mtd, size = mtd->oobsize - (oob - chip->oob_poi); if (size) chip->write_buf(mtd, oob, size); + + return 0; } /** - * nand_write_page_swecc - [REPLACABLE] software ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_swecc - [REPLACEABLE] software ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB */ -static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) +static int nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1718,24 +1721,25 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip, const uint8_t *p = buf; uint32_t *eccpos = chip->ecc.layout->eccpos; - /* Software ecc calculation */ + /* Software ECC calculation */ for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) chip->ecc.calculate(mtd, p, &ecc_calc[i]); for (i = 0; i < chip->ecc.total; i++) chip->oob_poi[eccpos[i]] = ecc_calc[i]; - chip->ecc.write_page_raw(mtd, chip, buf); + return chip->ecc.write_page_raw(mtd, chip, buf, 1); } /** - * nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_hwecc - [REPLACEABLE] hardware ECC based page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB */ -static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf) +static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1754,19 +1758,23 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, chip->oob_poi[eccpos[i]] = ecc_calc[i]; chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); + + return 0; } /** - * nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write - * @mtd: mtd info structure - * @chip: nand chip info structure - * @buf: data buffer + * nand_write_page_syndrome - [REPLACEABLE] hardware ECC syndrome based page write + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB * - * The hw generator calculates the error syndrome automatically. Therefor - * we need a special oob layout and handling. + * The hw generator calculates the error syndrome automatically. Therefore we + * need a special oob layout and handling. */ -static void nand_write_page_syndrome(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) +static int nand_write_page_syndrome(struct mtd_info *mtd, + struct nand_chip *chip, + const uint8_t *buf, int oob_required) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -1798,32 +1806,39 @@ static void nand_write_page_syndrome(struct mtd_info *mtd, i = mtd->oobsize - (oob - chip->oob_poi); if (i) chip->write_buf(mtd, oob, i); + + return 0; } /** * nand_write_page - [REPLACEABLE] write one page - * @mtd: MTD device structure - * @chip: NAND chip descriptor - * @buf: the data to write - * @page: page number to write - * @cached: cached programming - * @raw: use _raw version of write_page + * @mtd: MTD device structure + * @chip: NAND chip descriptor + * @buf: the data to write + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * @cached: cached programming + * @raw: use _raw version of write_page */ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, int cached, int raw) + const uint8_t *buf, int oob_required, int page, + int cached, int raw) { int status; chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) - chip->ecc.write_page_raw(mtd, chip, buf); + status = chip->ecc.write_page_raw(mtd, chip, buf, oob_required); else - chip->ecc.write_page(mtd, chip, buf); + status = chip->ecc.write_page(mtd, chip, buf, oob_required); + + if (status < 0) + return status; /* - * Cached progamming disabled for now, Not sure if its worth the - * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s) + * Cached progamming disabled for now. Not sure if it's worth the + * trouble. The speed gain is not very impressive. (2.3->2.6Mib/s). */ cached = 0; @@ -1833,7 +1848,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, status = chip->waitfunc(mtd, chip); /* * See if operation failed and additional status checks are - * available + * available. */ if ((status & NAND_STATUS_FAIL) && (chip->errstat)) status = chip->errstat(mtd, chip, FL_WRITING, status, @@ -1852,34 +1867,45 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (chip->verify_buf(mtd, buf, mtd->writesize)) return -EIO; + + /* Make sure the next page prog is preceded by a status read */ + chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); #endif return 0; } /** - * nand_fill_oob - [Internal] Transfer client buffer to oob - * @chip: nand chip structure - * @oob: oob data buffer - * @len: oob data write length - * @ops: oob ops structure + * nand_fill_oob - [INTERN] Transfer client buffer to oob + * @mtd: MTD device structure + * @oob: oob data buffer + * @len: oob data write length + * @ops: oob ops structure */ -static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, - struct mtd_oob_ops *ops) +static uint8_t *nand_fill_oob(struct mtd_info *mtd, uint8_t *oob, size_t len, + struct mtd_oob_ops *ops) { + struct nand_chip *chip = mtd->priv; + + /* + * Initialise to all 0xFF, to avoid the possibility of left over OOB + * data from a previous OOB read. + */ + memset(chip->oob_poi, 0xff, mtd->oobsize); + switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_RAW: memcpy(chip->oob_poi + ops->ooboffs, oob, len); return oob + len; - case MTD_OOB_AUTO: { + case MTD_OPS_AUTO_OOB: { struct nand_oobfree *free = chip->ecc.layout->oobfree; uint32_t boffs = 0, woffs = ops->ooboffs; size_t bytes = 0; for (; free->length && len; free++, len -= bytes) { - /* Write request not from offset 0 ? */ + /* Write request not from offset 0? */ if (unlikely(woffs)) { if (woffs >= free->length) { woffs -= free->length; @@ -1907,12 +1933,12 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, size_t len, #define NOTALIGNED(x) ((x & (chip->subpagesize - 1)) != 0) /** - * nand_do_write_ops - [Internal] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operations description structure + * nand_do_write_ops - [INTERN] NAND write with ECC + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operations description structure * - * NAND write with ECC + * NAND write with ECC. */ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -1922,12 +1948,13 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, uint32_t writelen = ops->len; uint32_t oobwritelen = ops->ooblen; - uint32_t oobmaxlen = ops->mode == MTD_OOB_AUTO ? + uint32_t oobmaxlen = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; uint8_t *oob = ops->oobbuf; uint8_t *buf = ops->datbuf; int ret, subpage; + int oob_required = oob ? 1 : 0; ops->retlen = 0; if (!writelen) @@ -1957,10 +1984,6 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, (chip->pagebuf << chip->page_shift) < (to + ops->len)) chip->pagebuf = -1; - /* If we're not given explicit OOB data, let it be 0xFF */ - if (likely(!oob)) - memset(chip->oob_poi, 0xff, mtd->oobsize); - /* Don't allow multipage oob writes with offset */ if (oob && ops->ooboffs && (ops->ooboffs + ops->ooblen > oobmaxlen)) return -EINVAL; @@ -1972,8 +1995,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, int cached = writelen > bytes && page != blockmask; uint8_t *wbuf = buf; - /* Partial page write ? */ - if (unlikely(column || writelen < (mtd->writesize - 1))) { + /* Partial page write? */ + if (unlikely(column || writelen < mtd->writesize)) { cached = 0; bytes = min_t(int, bytes - column, (int) writelen); chip->pagebuf = -1; @@ -1984,12 +2007,15 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, if (unlikely(oob)) { size_t len = min(oobwritelen, oobmaxlen); - oob = nand_fill_oob(chip, oob, len, ops); + oob = nand_fill_oob(mtd, oob, len, ops); oobwritelen -= len; + } else { + /* We still need to erase leftover OOB data */ + memset(chip->oob_poi, 0xff, mtd->oobsize); } - ret = chip->write_page(mtd, chip, wbuf, page, cached, - (ops->mode == MTD_OOB_RAW)); + ret = chip->write_page(mtd, chip, wbuf, oob_required, page, + cached, (ops->mode == MTD_OPS_RAW)); if (ret) break; @@ -2018,48 +2044,39 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, /** * nand_write - [MTD Interface] NAND write with ECC - * @mtd: MTD device structure - * @to: offset to write to - * @len: number of bytes to write - * @retlen: pointer to variable to store the number of written bytes - * @buf: the data to write + * @mtd: MTD device structure + * @to: offset to write to + * @len: number of bytes to write + * @retlen: pointer to variable to store the number of written bytes + * @buf: the data to write * - * NAND write with ECC + * NAND write with ECC. */ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const uint8_t *buf) { struct nand_chip *chip = mtd->priv; + struct mtd_oob_ops ops; int ret; - /* Do not allow writes past end of device */ - if ((to + len) > mtd->size) - return -EINVAL; - if (!len) - return 0; - nand_get_device(chip, mtd, FL_WRITING); - - chip->ops.len = len; - chip->ops.datbuf = (uint8_t *)buf; - chip->ops.oobbuf = NULL; - - ret = nand_do_write_ops(mtd, to, &chip->ops); - - *retlen = chip->ops.retlen; - + ops.len = len; + ops.datbuf = (uint8_t *)buf; + ops.oobbuf = NULL; + ops.mode = MTD_OPS_PLACE_OOB; + ret = nand_do_write_ops(mtd, to, &ops); + *retlen = ops.retlen; nand_release_device(mtd); - return ret; } /** * nand_do_write_oob - [MTD Interface] NAND write out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure * - * NAND write out-of-band + * NAND write out-of-band. */ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2070,7 +2087,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, MTDDEBUG(MTD_DEBUG_LEVEL3, "%s: to = 0x%08x, len = %i\n", __func__, (unsigned int)to, (int)ops->ooblen); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) len = chip->ecc.layout->oobavail; else len = mtd->oobsize; @@ -2120,10 +2137,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, if (page == chip->pagebuf) chip->pagebuf = -1; - memset(chip->oob_poi, 0xff, mtd->oobsize); - nand_fill_oob(chip, ops->oobbuf, ops->ooblen, ops); - status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); - memset(chip->oob_poi, 0xff, mtd->oobsize); + nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops); + + if (ops->mode == MTD_OPS_RAW) + status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask); + else + status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); if (status) return status; @@ -2135,9 +2154,9 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, /** * nand_write_oob - [MTD Interface] NAND write data and/or out-of-band - * @mtd: MTD device structure - * @to: offset to write to - * @ops: oob operation description structure + * @mtd: MTD device structure + * @to: offset to write to + * @ops: oob operation description structure */ static int nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops) @@ -2157,9 +2176,9 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, nand_get_device(chip, mtd, FL_WRITING); switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: - case MTD_OOB_RAW: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: + case MTD_OPS_RAW: break; default: @@ -2177,11 +2196,11 @@ out: } /** - * single_erease_cmd - [GENERIC] NAND standard block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * single_erase_cmd - [GENERIC] NAND standard block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * Standard erase command for NAND chips + * Standard erase command for NAND chips. */ static void single_erase_cmd(struct mtd_info *mtd, int page) { @@ -2192,12 +2211,11 @@ static void single_erase_cmd(struct mtd_info *mtd, int page) } /** - * multi_erease_cmd - [GENERIC] AND specific block erase command function - * @mtd: MTD device structure - * @page: the page address of the block which will be erased + * multi_erase_cmd - [GENERIC] AND specific block erase command function + * @mtd: MTD device structure + * @page: the page address of the block which will be erased * - * AND multi block erase command function - * Erase 4 consecutive blocks + * AND multi block erase command function. Erase 4 consecutive blocks. */ static void multi_erase_cmd(struct mtd_info *mtd, int page) { @@ -2212,10 +2230,10 @@ static void multi_erase_cmd(struct mtd_info *mtd, int page) /** * nand_erase - [MTD Interface] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction + * @mtd: MTD device structure + * @instr: erase instruction * - * Erase one ore more blocks + * Erase one ore more blocks. */ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) { @@ -2224,12 +2242,12 @@ static int nand_erase(struct mtd_info *mtd, struct erase_info *instr) #define BBT_PAGE_MASK 0xffffff3f /** - * nand_erase_nand - [Internal] erase block(s) - * @mtd: MTD device structure - * @instr: erase instruction - * @allowbbt: allow erasing the bbt area + * nand_erase_nand - [INTERN] erase block(s) + * @mtd: MTD device structure + * @instr: erase instruction + * @allowbbt: allow erasing the bbt area * - * Erase one ore more blocks + * Erase one ore more blocks. */ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, int allowbbt) @@ -2247,8 +2265,6 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, if (check_offs_len(mtd, instr->addr, instr->len)) return -EINVAL; - instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN; - /* Grab the lock and see if the device is available */ nand_get_device(chip, mtd, FL_ERASING); @@ -2274,7 +2290,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, * If BBT requires refresh, set the BBT page mask to see if the BBT * should be rewritten. Otherwise the mask is set to 0xffffffff which * can not be matched. This is also done when the bbt is actually - * erased to avoid recusrsive updates + * erased to avoid recursive updates. */ if (chip->options & BBT_AUTO_REFRESH && !allowbbt) bbt_masked_page = chip->bbt_td->pages[chipnr] & BBT_PAGE_MASK; @@ -2286,20 +2302,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, while (len) { WATCHDOG_RESET(); - /* - * heck if we have a bad block, we do not erase bad blocks ! - */ + /* Check if we have a bad block, we do not erase bad blocks! */ if (!instr->scrub && nand_block_checkbad(mtd, ((loff_t) page) << chip->page_shift, 0, allowbbt)) { - printk(KERN_WARNING "%s: attempt to erase a bad block " - "at page 0x%08x\n", __func__, page); + pr_warn("%s: attempt to erase a bad block at page 0x%08x\n", + __func__, page); instr->state = MTD_ERASE_FAILED; goto erase_exit; } /* * Invalidate the page cache, if we erase the block which - * contains the current cached page + * contains the current cached page. */ if (page <= chip->pagebuf && chip->pagebuf < (page + pages_per_block)) @@ -2329,7 +2343,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh, set the BBT rewrite flag to the - * page being erased + * page being erased. */ if (bbt_masked_page != 0xffffffff && (page & BBT_PAGE_MASK) == bbt_masked_page) @@ -2348,7 +2362,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, /* * If BBT requires refresh and BBT-PERCHIP, set the BBT - * page mask to see if this BBT should be rewritten + * page mask to see if this BBT should be rewritten. */ if (bbt_masked_page != 0xffffffff && (chip->bbt_td->options & NAND_BBT_PERCHIP)) @@ -2371,7 +2385,7 @@ erase_exit: /* * If BBT requires refresh and erase was successful, rewrite any - * selected bad block tables + * selected bad block tables. */ if (bbt_masked_page == 0xffffffff || ret) return ret; @@ -2379,7 +2393,7 @@ erase_exit: for (chipnr = 0; chipnr < chip->numchips; chipnr++) { if (!rewrite_bbt[chipnr]) continue; - /* update the BBT for chip */ + /* Update the BBT for chip */ MTDDEBUG(MTD_DEBUG_LEVEL0, "%s: nand_update_bbt " "(%d:0x%0llx 0x%0x)\n", __func__, chipnr, rewrite_bbt[chipnr], chip->bbt_td->pages[chipnr]); @@ -2392,9 +2406,9 @@ erase_exit: /** * nand_sync - [MTD Interface] sync - * @mtd: MTD device structure + * @mtd: MTD device structure * - * Sync is actually a wait for chip ready function + * Sync is actually a wait for chip ready function. */ static void nand_sync(struct mtd_info *mtd) { @@ -2410,22 +2424,18 @@ static void nand_sync(struct mtd_info *mtd) /** * nand_block_isbad - [MTD Interface] Check if block at offset is bad - * @mtd: MTD device structure - * @offs: offset relative to mtd start + * @mtd: MTD device structure + * @offs: offset relative to mtd start */ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) { - /* Check for invalid offset */ - if (offs > mtd->size) - return -EINVAL; - return nand_block_checkbad(mtd, offs, 1, 0); } /** * nand_block_markbad - [MTD Interface] Mark block at the given offset as bad - * @mtd: MTD device structure - * @ofs: offset relative to mtd start + * @mtd: MTD device structure + * @ofs: offset relative to mtd start */ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) { @@ -2434,7 +2444,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) ret = nand_block_isbad(mtd, ofs); if (ret) { - /* If it was bad already, return success and do nothing. */ + /* If it was bad already, return success and do nothing */ if (ret > 0) return 0; return ret; @@ -2443,9 +2453,51 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) return chip->block_markbad(mtd, ofs); } -/* - * Set default functions + /** + * nand_onfi_set_features- [REPLACEABLE] set features for ONFI nand + * @mtd: MTD device structure + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. */ +static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip, + int addr, uint8_t *subfeature_param) +{ + int status; + + if (!chip->onfi_version) + return -EINVAL; + + chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1); + chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + status = chip->waitfunc(mtd, chip); + if (status & NAND_STATUS_FAIL) + return -EIO; + return 0; +} + +/** + * nand_onfi_get_features- [REPLACEABLE] get features for ONFI nand + * @mtd: MTD device structure + * @chip: nand chip info structure + * @addr: feature address. + * @subfeature_param: the subfeature parameters, a four bytes array. + */ +static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip, + int addr, uint8_t *subfeature_param) +{ + if (!chip->onfi_version) + return -EINVAL; + + /* clear the sub feature parameters */ + memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN); + + chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1); + chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN); + return 0; +} + +/* Set default functions */ static void nand_set_defaults(struct nand_chip *chip, int busw) { /* check for proper chip_delay setup, set 20us if not */ @@ -2483,23 +2535,21 @@ static void nand_set_defaults(struct nand_chip *chip, int busw) } #ifdef CONFIG_SYS_NAND_ONFI_DETECTION -/* - * sanitize ONFI strings so we can safely print them - */ +/* Sanitize ONFI strings so we can safely print them */ static void sanitize_string(char *s, size_t len) { ssize_t i; - /* null terminate */ + /* Null terminate */ s[len - 1] = 0; - /* remove non printable chars */ + /* Remove non printable chars */ for (i = 0; i < len - 1; i++) { if (s[i] < ' ' || s[i] > 127) s[i] = '?'; } - /* remove trailing spaces */ + /* Remove trailing spaces */ strim(s); } @@ -2516,7 +2566,7 @@ static u16 onfi_crc16(u16 crc, u8 const *p, size_t len) } /* - * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise + * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise. */ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int *busw) @@ -2525,20 +2575,18 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int i; int val; - /* try ONFI for unknow chip or LP */ + /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I') return 0; - MTDDEBUG(MTD_DEBUG_LEVEL0, "ONFI flash detected\n"); chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, - "ONFI param page %d valid\n", i); + pr_info("ONFI param page %d valid\n", i); break; } } @@ -2546,7 +2594,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, if (i == 3) return 0; - /* check version */ + /* Check version */ val = le16_to_cpu(p->revision); if (val & (1 << 5)) chip->onfi_version = 23; @@ -2562,8 +2610,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->onfi_version = 0; if (!chip->onfi_version) { - printk(KERN_INFO "%s: unsupported ONFI version: %d\n", - __func__, val); + pr_info("%s: unsupported ONFI version: %d\n", __func__, val); return 0; } @@ -2580,8 +2627,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, if (le16_to_cpu(p->features) & 1) *busw = NAND_BUSWIDTH_16; - chip->options |= NAND_NO_READRDY | NAND_NO_AUTOINCR; - + pr_info("ONFI flash detected\n"); return 1; } #else @@ -2594,7 +2640,248 @@ static inline int nand_flash_detect_onfi(struct mtd_info *mtd, #endif /* - * Get the flash and manufacturer id and lookup if the type is supported + * nand_id_has_period - Check if an ID string has a given wraparound period + * @id_data: the ID string + * @arrlen: the length of the @id_data array + * @period: the period of repitition + * + * Check if an ID string is repeated within a given sequence of bytes at + * specific repetition interval period (e.g., {0x20,0x01,0x7F,0x20} has a + * period of 2). This is a helper function for nand_id_len(). Returns non-zero + * if the repetition has a period of @period; otherwise, returns zero. + */ +static int nand_id_has_period(u8 *id_data, int arrlen, int period) +{ + int i, j; + for (i = 0; i < period; i++) + for (j = i + period; j < arrlen; j += period) + if (id_data[i] != id_data[j]) + return 0; + return 1; +} + +/* + * nand_id_len - Get the length of an ID string returned by CMD_READID + * @id_data: the ID string + * @arrlen: the length of the @id_data array + + * Returns the length of the ID string, according to known wraparound/trailing + * zero patterns. If no pattern exists, returns the length of the array. + */ +static int nand_id_len(u8 *id_data, int arrlen) +{ + int last_nonzero, period; + + /* Find last non-zero byte */ + for (last_nonzero = arrlen - 1; last_nonzero >= 0; last_nonzero--) + if (id_data[last_nonzero]) + break; + + /* All zeros */ + if (last_nonzero < 0) + return 0; + + /* Calculate wraparound period */ + for (period = 1; period < arrlen; period++) + if (nand_id_has_period(id_data, arrlen, period)) + break; + + /* There's a repeated pattern */ + if (period < arrlen) + return period; + + /* There are trailing zeros */ + if (last_nonzero < arrlen - 1) + return last_nonzero + 1; + + /* No pattern detected */ + return arrlen; +} + +/* + * Many new NAND share similar device ID codes, which represent the size of the + * chip. The rest of the parameters must be decoded according to generic or + * manufacturer-specific "extended ID" decoding patterns. + */ +static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip, + u8 id_data[8], int *busw) +{ + int extid, id_len; + /* The 3rd id byte holds MLC / multichip data */ + chip->cellinfo = id_data[2]; + /* The 4th id byte is the important one */ + extid = id_data[3]; + + id_len = nand_id_len(id_data, 8); + + /* + * Field definitions are in the following datasheets: + * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) + * New Samsung (6 byte ID): Samsung K9GAG08U0F (p.44) + * Hynix MLC (6 byte ID): Hynix H27UBG8T2B (p.22) + * + * Check for ID length, non-zero 6th byte, cell type, and Hynix/Samsung + * ID to decide what to do. + */ + if (id_len == 6 && id_data[0] == NAND_MFR_SAMSUNG && + (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + id_data[5] != 0x00) { + /* Calc pagesize */ + mtd->writesize = 2048 << (extid & 0x03); + extid >>= 2; + /* Calc oobsize */ + switch (((extid >> 2) & 0x04) | (extid & 0x03)) { + case 1: + mtd->oobsize = 128; + break; + case 2: + mtd->oobsize = 218; + break; + case 3: + mtd->oobsize = 400; + break; + case 4: + mtd->oobsize = 436; + break; + case 5: + mtd->oobsize = 512; + break; + case 6: + default: /* Other cases are "reserved" (unknown) */ + mtd->oobsize = 640; + break; + } + extid >>= 2; + /* Calc blocksize */ + mtd->erasesize = (128 * 1024) << + (((extid >> 1) & 0x04) | (extid & 0x03)); + *busw = 0; + } else if (id_len == 6 && id_data[0] == NAND_MFR_HYNIX && + (chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { + unsigned int tmp; + + /* Calc pagesize */ + mtd->writesize = 2048 << (extid & 0x03); + extid >>= 2; + /* Calc oobsize */ + switch (((extid >> 2) & 0x04) | (extid & 0x03)) { + case 0: + mtd->oobsize = 128; + break; + case 1: + mtd->oobsize = 224; + break; + case 2: + mtd->oobsize = 448; + break; + case 3: + mtd->oobsize = 64; + break; + case 4: + mtd->oobsize = 32; + break; + case 5: + mtd->oobsize = 16; + break; + default: + mtd->oobsize = 640; + break; + } + extid >>= 2; + /* Calc blocksize */ + tmp = ((extid >> 1) & 0x04) | (extid & 0x03); + if (tmp < 0x03) + mtd->erasesize = (128 * 1024) << tmp; + else if (tmp == 0x03) + mtd->erasesize = 768 * 1024; + else + mtd->erasesize = (64 * 1024) << tmp; + *busw = 0; + } else { + /* Calc pagesize */ + mtd->writesize = 1024 << (extid & 0x03); + extid >>= 2; + /* Calc oobsize */ + mtd->oobsize = (8 << (extid & 0x01)) * + (mtd->writesize >> 9); + extid >>= 2; + /* Calc blocksize. Blocksize is multiples of 64KiB */ + mtd->erasesize = (64 * 1024) << (extid & 0x03); + extid >>= 2; + /* Get buswidth information */ + *busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; + } +} + + /* + * Old devices have chip data hardcoded in the device ID table. nand_decode_id + * decodes a matching ID table entry and assigns the MTD size parameters for + * the chip. + */ +static void nand_decode_id(struct mtd_info *mtd, struct nand_chip *chip, + const struct nand_flash_dev *type, u8 id_data[8], + int *busw) +{ + int maf_id = id_data[0]; + + mtd->erasesize = type->erasesize; + mtd->writesize = type->pagesize; + mtd->oobsize = mtd->writesize / 32; + *busw = type->options & NAND_BUSWIDTH_16; + + /* + * Check for Spansion/AMD ID + repeating 5th, 6th byte since + * some Spansion chips have erasesize that conflicts with size + * listed in nand_ids table. + * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) + */ + if (maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && id_data[5] == 0x00 + && id_data[6] == 0x00 && id_data[7] == 0x00 + && mtd->writesize == 512) { + mtd->erasesize = 128 * 1024; + mtd->erasesize <<= ((id_data[3] & 0x03) << 1); + } +} + + /* + * Set the bad block marker/indicator (BBM/BBI) patterns according to some + * heuristic patterns using various detected parameters (e.g., manufacturer, + * page size, cell-type information). + */ +static void nand_decode_bbm_options(struct mtd_info *mtd, + struct nand_chip *chip, u8 id_data[8]) +{ + int maf_id = id_data[0]; + + /* Set the bad block position */ + if (mtd->writesize > 512 || (chip->options & NAND_BUSWIDTH_16)) + chip->badblockpos = NAND_LARGE_BADBLOCK_POS; + else + chip->badblockpos = NAND_SMALL_BADBLOCK_POS; + + /* + * Bad block marker is stored in the last page of each block on Samsung + * and Hynix MLC devices; stored in first two pages of each block on + * Micron devices with 2KiB pages and on SLC Samsung, Hynix, Toshiba, + * AMD/Spansion, and Macronix. All others scan only the first page. + */ + if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + (maf_id == NAND_MFR_SAMSUNG || + maf_id == NAND_MFR_HYNIX)) + chip->bbt_options |= NAND_BBT_SCANLASTPAGE; + else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && + (maf_id == NAND_MFR_SAMSUNG || + maf_id == NAND_MFR_HYNIX || + maf_id == NAND_MFR_TOSHIBA || + maf_id == NAND_MFR_AMD || + maf_id == NAND_MFR_MACRONIX)) || + (mtd->writesize == 2048 && + maf_id == NAND_MFR_MICRON)) + chip->bbt_options |= NAND_BBT_SCAN2NDPAGE; +} + +/* + * Get the flash and manufacturer id and lookup if the type is supported. */ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, @@ -2605,14 +2892,13 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, const char *name; int i, maf_idx; u8 id_data[8]; - int ret; /* Select the device */ chip->select_chip(mtd, 0); /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) - * after power-up + * after power-up. */ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); @@ -2623,7 +2909,8 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, *maf_id = chip->read_byte(mtd); *dev_id = chip->read_byte(mtd); - /* Try again to make sure, as some systems the bus-hold or other + /* + * Try again to make sure, as some systems the bus-hold or other * interface concerns can cause random data which looks like a * possibly credible NAND flash to appear. If the two results do * not match, ignore the device completely. @@ -2631,13 +2918,14 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - for (i = 0; i < 2; i++) + /* Read entire ID string */ + for (i = 0; i < 8; i++) id_data[i] = chip->read_byte(mtd); if (id_data[0] != *maf_id || id_data[1] != *dev_id) { - printk(KERN_INFO "%s: second ID read did not match " - "%02x,%02x against %02x,%02x\n", __func__, - *maf_id, *dev_id, id_data[0], id_data[1]); + pr_info("%s: second ID read did not match " + "%02x,%02x against %02x,%02x\n", __func__, + *maf_id, *dev_id, id_data[0], id_data[1]); return ERR_PTR(-ENODEV); } @@ -2651,18 +2939,10 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->onfi_version = 0; if (!type->name || !type->pagesize) { /* Check is chip is ONFI compliant */ - ret = nand_flash_detect_onfi(mtd, chip, &busw); - if (ret) + if (nand_flash_detect_onfi(mtd, chip, &busw)) goto ident_done; } - chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); - - /* Read entire ID string */ - - for (i = 0; i < 8; i++) - id_data[i] = chip->read_byte(mtd); - if (!type->name) return ERR_PTR(-ENODEV); @@ -2672,101 +2952,25 @@ static const struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, chip->chipsize = (uint64_t)type->chipsize << 20; if (!type->pagesize && chip->init_size) { - /* set the pagesize, oobsize, erasesize by the driver*/ + /* Set the pagesize, oobsize, erasesize by the driver */ busw = chip->init_size(mtd, chip, id_data); } else if (!type->pagesize) { - int extid; - /* The 3rd id byte holds MLC / multichip data */ - chip->cellinfo = id_data[2]; - /* The 4th id byte is the important one */ - extid = id_data[3]; - - /* - * Field definitions are in the following datasheets: - * Old style (4,5 byte ID): Samsung K9GAG08U0M (p.32) - * New style (6 byte ID): Samsung K9GBG08U0M (p.40) - * - * Check for wraparound + Samsung ID + nonzero 6th byte - * to decide what to do. - */ - if (id_data[0] == id_data[6] && id_data[1] == id_data[7] && - id_data[0] == NAND_MFR_SAMSUNG && - (chip->cellinfo & NAND_CI_CELLTYPE_MSK) && - id_data[5] != 0x00) { - /* Calc pagesize */ - mtd->writesize = 2048 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - switch (extid & 0x03) { - case 1: - mtd->oobsize = 128; - break; - case 2: - mtd->oobsize = 218; - break; - case 3: - mtd->oobsize = 400; - break; - default: - mtd->oobsize = 436; - break; - } - extid >>= 2; - /* Calc blocksize */ - mtd->erasesize = (128 * 1024) << - (((extid >> 1) & 0x04) | (extid & 0x03)); - busw = 0; - } else { - /* Calc pagesize */ - mtd->writesize = 1024 << (extid & 0x03); - extid >>= 2; - /* Calc oobsize */ - mtd->oobsize = (8 << (extid & 0x01)) * - (mtd->writesize >> 9); - extid >>= 2; - /* Calc blocksize. Blocksize is multiples of 64KiB */ - mtd->erasesize = (64 * 1024) << (extid & 0x03); - extid >>= 2; - /* Get buswidth information */ - busw = (extid & 0x01) ? NAND_BUSWIDTH_16 : 0; - } + /* Decode parameters from extended ID */ + nand_decode_ext_id(mtd, chip, id_data, &busw); } else { - /* - * Old devices have chip data hardcoded in the device id table - */ - mtd->erasesize = type->erasesize; - mtd->writesize = type->pagesize; - mtd->oobsize = mtd->writesize / 32; - busw = type->options & NAND_BUSWIDTH_16; - - /* - * Check for Spansion/AMD ID + repeating 5th, 6th byte since - * some Spansion chips have erasesize that conflicts with size - * listed in nand_ids table - * Data sheet (5 byte ID): Spansion S30ML-P ORNAND (p.39) - */ - if (*maf_id == NAND_MFR_AMD && id_data[4] != 0x00 && - id_data[5] == 0x00 && id_data[6] == 0x00 && - id_data[7] == 0x00 && mtd->writesize == 512) { - mtd->erasesize = 128 * 1024; - mtd->erasesize <<= ((id_data[3] & 0x03) << 1); - } + nand_decode_id(mtd, chip, type, id_data, &busw); } /* Get chip options, preserve non chip based options */ chip->options |= type->options; - /* Check if chip is a not a samsung device. Do not clear the - * options for chips which are not having an extended id. + /* + * Check if chip is not a Samsung device. Do not clear the + * options for chips which do not have an extended id. */ if (*maf_id != NAND_MFR_SAMSUNG && !type->pagesize) chip->options &= ~NAND_SAMSUNG_LP_OPTIONS; ident_done: - /* - * Set chip as a default. Board drivers can override it, if necessary - */ - chip->options |= NAND_NO_AUTOINCR; - /* Try to identify manufacturer */ for (maf_idx = 0; nand_manuf_ids[maf_idx].id != 0x0; maf_idx++) { if (nand_manuf_ids[maf_idx].id == *maf_id) @@ -2775,21 +2979,23 @@ ident_done: /* * Check, if buswidth is correct. Hardware drivers should set - * chip correct ! + * chip correct! */ if (busw != (chip->options & NAND_BUSWIDTH_16)) { - printk(KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, - *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); - printk(KERN_WARNING "NAND bus width %d instead %d bit\n", - (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, - busw ? 16 : 8); + pr_info("NAND device: Manufacturer ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, + *dev_id, nand_manuf_ids[maf_idx].name, mtd->name); + pr_warn("NAND bus width %d instead %d bit\n", + (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, + busw ? 16 : 8); return ERR_PTR(-EINVAL); } + nand_decode_bbm_options(mtd, chip, id_data); + /* Calculate the address shift from the page size */ chip->page_shift = ffs(mtd->writesize) - 1; - /* Convert chipsize to number of pages per chip -1. */ + /* Convert chipsize to number of pages per chip -1 */ chip->pagemask = (chip->chipsize >> chip->page_shift) - 1; chip->bbt_erase_shift = chip->phys_erase_shift = @@ -2803,73 +3009,38 @@ ident_done: chip->badblockbits = 8; - /* Set the bad block position */ - if (mtd->writesize > 512 || (busw & NAND_BUSWIDTH_16)) - chip->badblockpos = NAND_LARGE_BADBLOCK_POS; - else - chip->badblockpos = NAND_SMALL_BADBLOCK_POS; - - /* - * Bad block marker is stored in the last page of each block - * on Samsung and Hynix MLC devices; stored in first two pages - * of each block on Micron devices with 2KiB pages and on - * SLC Samsung, Hynix, Toshiba and AMD/Spansion. All others scan - * only the first page. - */ - if ((chip->cellinfo & NAND_CI_CELLTYPE_MSK) && - (*maf_id == NAND_MFR_SAMSUNG || - *maf_id == NAND_MFR_HYNIX)) - chip->options |= NAND_BBT_SCANLASTPAGE; - else if ((!(chip->cellinfo & NAND_CI_CELLTYPE_MSK) && - (*maf_id == NAND_MFR_SAMSUNG || - *maf_id == NAND_MFR_HYNIX || - *maf_id == NAND_MFR_TOSHIBA || - *maf_id == NAND_MFR_AMD)) || - (mtd->writesize == 2048 && - *maf_id == NAND_MFR_MICRON)) - chip->options |= NAND_BBT_SCAN2NDPAGE; - - /* - * Numonyx/ST 2K pages, x8 bus use BOTH byte 1 and 6 - */ - if (!(busw & NAND_BUSWIDTH_16) && - *maf_id == NAND_MFR_STMICRO && - mtd->writesize == 2048) { - chip->options |= NAND_BBT_SCANBYTE1AND6; - chip->badblockpos = 0; - } - /* Check for AND chips with 4 page planes */ if (chip->options & NAND_4PAGE_ARRAY) chip->erase_cmd = multi_erase_cmd; else chip->erase_cmd = single_erase_cmd; - /* Do not replace user supplied command function ! */ + /* Do not replace user supplied command function! */ if (mtd->writesize > 512 && chip->cmdfunc == nand_command) chip->cmdfunc = nand_command_lp; - /* TODO onfi flash name */ name = type->name; #ifdef CONFIG_SYS_NAND_ONFI_DETECTION if (chip->onfi_version) name = chip->onfi_params.model; #endif - MTDDEBUG(MTD_DEBUG_LEVEL0, "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, *dev_id, - nand_manuf_ids[maf_idx].name, name); + pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)," + " page size: %d, OOB size: %d\n", + *maf_id, *dev_id, nand_manuf_ids[maf_idx].name, + name, + mtd->writesize, mtd->oobsize); return type; } /** * nand_scan_ident - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * @table: Alternative NAND ID table + * @mtd: MTD device structure + * @maxchips: number of chips to scan for + * @table: alternative NAND ID table * - * This is the first phase of the normal nand_scan() function. It - * reads the flash ID and sets up MTD fields accordingly. + * This is the first phase of the normal nand_scan() function. It reads the + * flash ID and sets up MTD fields accordingly. * * The mtd->owner field must be set to the module of the caller. */ @@ -2891,7 +3062,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, if (IS_ERR(type)) { #ifndef CONFIG_SYS_NAND_QUIET_TEST - printk(KERN_WARNING "No NAND device found!!!\n"); + pr_warn("No NAND device found\n"); #endif chip->select_chip(mtd, -1); return PTR_ERR(type); @@ -2911,7 +3082,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, } #ifdef DEBUG if (i > 1) - printk(KERN_INFO "%d NAND chips detected\n", i); + pr_info("%d NAND chips detected\n", i); #endif /* Store the number of chips and calc total size for mtd */ @@ -2924,17 +3095,21 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, /** * nand_scan_tail - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure + * @mtd: MTD device structure * - * This is the second phase of the normal nand_scan() function. It - * fills out all the uninitialized function pointers with the defaults - * and scans for a bad block table if appropriate. + * This is the second phase of the normal nand_scan() function. It fills out + * all the uninitialized function pointers with the defaults and scans for a + * bad block table if appropriate. */ int nand_scan_tail(struct mtd_info *mtd) { int i; struct nand_chip *chip = mtd->priv; + /* New bad blocks should be marked in OOB, flash-based BBT, or both */ + BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && + !(chip->bbt_options & NAND_BBT_USE_FLASH)); + if (!(chip->options & NAND_OWN_BUFFERS)) chip->buffers = memalign(ARCH_DMA_MINALIGN, sizeof(*chip->buffers)); @@ -2945,7 +3120,7 @@ int nand_scan_tail(struct mtd_info *mtd) chip->oob_poi = chip->buffers->databuf + mtd->writesize; /* - * If no default placement scheme is given, select an appropriate one + * If no default placement scheme is given, select an appropriate one. */ if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) { switch (mtd->oobsize) { @@ -2962,16 +3137,22 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.layout = &nand_oob_128; break; default: - printk(KERN_WARNING "No oob scheme defined for " - "oobsize %d\n", mtd->oobsize); + pr_warn("No oob scheme defined for oobsize %d\n", + mtd->oobsize); } } if (!chip->write_page) chip->write_page = nand_write_page; + /* set for ONFI nand */ + if (!chip->onfi_set_features) + chip->onfi_set_features = nand_onfi_set_features; + if (!chip->onfi_get_features) + chip->onfi_get_features = nand_onfi_get_features; + /* - * check ECC mode, default to software if 3byte/512byte hardware ECC is + * Check ECC mode, default to software if 3byte/512byte hardware ECC is * selected and we have 256 byte pagesize fallback to software ECC */ @@ -2980,15 +3161,15 @@ int nand_scan_tail(struct mtd_info *mtd) /* Similar to NAND_ECC_HW, but a separate read_page handle */ if (!chip->ecc.calculate || !chip->ecc.correct || !chip->ecc.hwctl) { - printk(KERN_WARNING "No ECC functions supplied; " - "Hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; " + "hardware ECC not possible\n"); BUG(); } if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc_oob_first; case NAND_ECC_HW: - /* Use standard hwecc read page function ? */ + /* Use standard hwecc read page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_hwecc; if (!chip->ecc.write_page) @@ -3009,11 +3190,11 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.read_page == nand_read_page_hwecc || !chip->ecc.write_page || chip->ecc.write_page == nand_write_page_hwecc)) { - printk(KERN_WARNING "No ECC functions supplied; " - "Hardware ECC not possible\n"); + pr_warn("No ECC functions supplied; " + "hardware ECC not possible\n"); BUG(); } - /* Use standard syndrome read/write page function ? */ + /* Use standard syndrome read/write page function? */ if (!chip->ecc.read_page) chip->ecc.read_page = nand_read_page_syndrome; if (!chip->ecc.write_page) @@ -3027,11 +3208,16 @@ int nand_scan_tail(struct mtd_info *mtd) if (!chip->ecc.write_oob) chip->ecc.write_oob = nand_write_oob_syndrome; - if (mtd->writesize >= chip->ecc.size) + if (mtd->writesize >= chip->ecc.size) { + if (!chip->ecc.strength) { + pr_warn("Driver must set ecc.strength when using hardware ECC\n"); + BUG(); + } break; - printk(KERN_WARNING "%d byte HW ECC not possible on " - "%d byte page size, fallback to SW ECC\n", - chip->ecc.size, mtd->writesize); + } + pr_warn("%d byte HW ECC not possible on " + "%d byte page size, fallback to SW ECC\n", + chip->ecc.size, mtd->writesize); chip->ecc.mode = NAND_ECC_SOFT; case NAND_ECC_SOFT: @@ -3047,11 +3233,12 @@ int nand_scan_tail(struct mtd_info *mtd) if (!chip->ecc.size) chip->ecc.size = 256; chip->ecc.bytes = 3; + chip->ecc.strength = 1; break; case NAND_ECC_SOFT_BCH: if (!mtd_nand_has_bch()) { - printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n"); + pr_warn("CONFIG_MTD_ECC_BCH not enabled\n"); return -EINVAL; } chip->ecc.calculate = nand_bch_calculate_ecc; @@ -3066,8 +3253,8 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Board driver should supply ecc.size and ecc.bytes values to * select how many bits are correctable; see nand_bch_init() - * for details. - * Otherwise, default to 4 bits for large page devices + * for details. Otherwise, default to 4 bits for large page + * devices. */ if (!chip->ecc.size && (mtd->oobsize >= 64)) { chip->ecc.size = 512; @@ -3078,13 +3265,14 @@ int nand_scan_tail(struct mtd_info *mtd) chip->ecc.bytes, &chip->ecc.layout); if (!chip->ecc.priv) - printk(KERN_WARNING "BCH ECC initialization failed!\n"); - + pr_warn("BCH ECC initialization failed!\n"); + chip->ecc.strength = + chip->ecc.bytes * 8 / fls(8 * chip->ecc.size); break; case NAND_ECC_NONE: - printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " - "This is not recommended !!\n"); + pr_warn("NAND_ECC_NONE selected by board driver. " + "This is not recommended !!\n"); chip->ecc.read_page = nand_read_page_raw; chip->ecc.write_page = nand_write_page_raw; chip->ecc.read_oob = nand_read_oob_std; @@ -3096,14 +3284,19 @@ int nand_scan_tail(struct mtd_info *mtd) break; default: - printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n", - chip->ecc.mode); + pr_warn("Invalid NAND_ECC_MODE %d\n", chip->ecc.mode); BUG(); } + /* For many systems, the standard OOB write also works for raw */ + if (!chip->ecc.read_oob_raw) + chip->ecc.read_oob_raw = chip->ecc.read_oob; + if (!chip->ecc.write_oob_raw) + chip->ecc.write_oob_raw = chip->ecc.write_oob; + /* * The number of bytes available for a client to place data into - * the out of band area + * the out of band area. */ chip->ecc.layout->oobavail = 0; for (i = 0; chip->ecc.layout->oobfree[i].length @@ -3114,19 +3307,16 @@ int nand_scan_tail(struct mtd_info *mtd) /* * Set the number of read / write steps for one page depending on ECC - * mode + * mode. */ chip->ecc.steps = mtd->writesize / chip->ecc.size; if (chip->ecc.steps * chip->ecc.size != mtd->writesize) { - printk(KERN_WARNING "Invalid ecc parameters\n"); + pr_warn("Invalid ECC parameters\n"); BUG(); } chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; - /* - * Allow subpage writes up to ecc.steps. Not possible for MLC - * FLASH. - */ + /* Allow subpage writes up to ecc.steps. Not possible for MLC flash */ if (!(chip->options & NAND_NO_SUBPAGE_WRITE) && !(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) { switch (chip->ecc.steps) { @@ -3159,21 +3349,29 @@ int nand_scan_tail(struct mtd_info *mtd) mtd->type = MTD_NANDFLASH; mtd->flags = (chip->options & NAND_ROM) ? MTD_CAP_ROM : MTD_CAP_NANDFLASH; - mtd->erase = nand_erase; - mtd->point = NULL; - mtd->unpoint = NULL; - mtd->read = nand_read; - mtd->write = nand_write; - mtd->read_oob = nand_read_oob; - mtd->write_oob = nand_write_oob; - mtd->sync = nand_sync; - mtd->lock = NULL; - mtd->unlock = NULL; - mtd->block_isbad = nand_block_isbad; - mtd->block_markbad = nand_block_markbad; - - /* propagate ecc.layout to mtd_info */ + mtd->_erase = nand_erase; + mtd->_point = NULL; + mtd->_unpoint = NULL; + mtd->_read = nand_read; + mtd->_write = nand_write; + mtd->_read_oob = nand_read_oob; + mtd->_write_oob = nand_write_oob; + mtd->_sync = nand_sync; + mtd->_lock = NULL; + mtd->_unlock = NULL; + mtd->_block_isbad = nand_block_isbad; + mtd->_block_markbad = nand_block_markbad; + + /* propagate ecc info to mtd_info */ mtd->ecclayout = chip->ecc.layout; + mtd->ecc_strength = chip->ecc.strength; + /* + * Initialize bitflip_threshold to its default prior scan_bbt() call. + * scan_bbt() might invoke mtd_read(), thus bitflip_threshold must be + * properly set. + */ + if (!mtd->bitflip_threshold) + mtd->bitflip_threshold = mtd->ecc_strength; /* Check, if we should skip the bad block table scan */ if (chip->options & NAND_SKIP_BBTSCAN) @@ -3184,15 +3382,13 @@ int nand_scan_tail(struct mtd_info *mtd) /** * nand_scan - [NAND Interface] Scan for the NAND device - * @mtd: MTD device structure - * @maxchips: Number of chips to scan for - * - * This fills out all the uninitialized function pointers - * with the defaults. - * The flash ID is read and the mtd/chip structures are - * filled with the appropriate values. - * The mtd->owner field must be set to the module of the caller + * @mtd: MTD device structure + * @maxchips: number of chips to scan for * + * This fills out all the uninitialized function pointers with the defaults. + * The flash ID is read and the mtd/chip structures are filled with the + * appropriate values. The mtd->owner field must be set to the module of the + * caller. */ int nand_scan(struct mtd_info *mtd, int maxchips) { @@ -3206,8 +3402,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) /** * nand_release - [NAND Interface] Free resources held by the NAND device - * @mtd: MTD device structure -*/ + * @mtd: MTD device structure + */ void nand_release(struct mtd_info *mtd) { struct nand_chip *chip = mtd->priv; diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index 74a7061..8ef5845 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -4,7 +4,7 @@ * Overview: * Bad block table support for the NAND driver * - * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) + * Copyright © 2004 Thomas Gleixner (tglx@linutronix.de) * * 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 @@ -14,7 +14,7 @@ * * When nand_scan_bbt is called, then it tries to find the bad block table * depending on the options in the BBT descriptor(s). If no flash based BBT - * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * (NAND_BBT_USE_FLASH) is specified then the device is scanned for factory * marked good / bad blocks. This information is used to create a memory BBT. * Once a new bad block is discovered then the "factory" information is updated * on the device. @@ -22,7 +22,7 @@ * BBT on flash. If a BBT is found then the contents are read and the memory * based BBT is created. If a mirrored BBT is selected then the mirror is * searched too and the versions are compared. If the mirror has a greater - * version number than the mirror BBT is used to build the memory based BBT. + * version number, then the mirror BBT is used to build the memory based BBT. * If the tables are not versioned, then we "or" the bad block information. * If one of the BBTs is out of date or does not exist it is (re)created. * If no BBT exists at all then the device is scanned for factory marked @@ -36,9 +36,9 @@ * The table is marked in the OOB area with an ident pattern and a version * number which indicates which of both tables is more up to date. If the NAND * controller needs the complete OOB area for the ECC information then the - * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern - * and the version byte into the data area and the OOB area will remain - * untouched. + * option NAND_BBT_NO_OOB should be used (along with NAND_BBT_USE_FLASH, of + * course): it moves the ident pattern and the version byte into the data area + * and the OOB area will remain untouched. * * The table uses 2 bits per block * 11b: block is good @@ -63,126 +63,81 @@ #include <malloc.h> #include <linux/compat.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/bbm.h> #include <linux/mtd/nand.h> #include <linux/mtd/nand_ecc.h> #include <linux/bitops.h> +#include <linux/string.h> #include <asm/errno.h> static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) { - int ret; - - ret = memcmp(buf, td->pattern, td->len); - if (!ret) - return ret; - return -1; + if (memcmp(buf, td->pattern, td->len)) + return -1; + return 0; } /** * check_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @len: the length of buffer to search - * @paglen: the pagelength - * @td: search pattern descriptor - * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. - * If the SCAN_EMPTY option is set then check, if all bytes except the - * pattern area contain 0xff + * @buf: the buffer to search + * @len: the length of buffer to search + * @paglen: the pagelength + * @td: search pattern descriptor * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. If the SCAN_EMPTY option is set then check, if + * all bytes except the pattern area contain 0xff. + */ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td) { - int i, end = 0; + int end = 0; uint8_t *p = buf; if (td->options & NAND_BBT_NO_OOB) return check_pattern_no_oob(buf, td); end = paglen + td->offs; - if (td->options & NAND_BBT_SCANEMPTY) { - for (i = 0; i < end; i++) { - if (p[i] != 0xff) - return -1; - } - } + if (td->options & NAND_BBT_SCANEMPTY) + if (memchr_inv(p, 0xff, end)) + return -1; p += end; /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - - /* Check both positions 1 and 6 for pattern? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - if (td->options & NAND_BBT_SCANEMPTY) { - p += td->len; - end += NAND_SMALL_BADBLOCK_POS - td->offs; - /* Check region between positions 1 and 6 */ - for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; - i++) { - if (*p++ != 0xff) - return -1; - } - } - else { - p += NAND_SMALL_BADBLOCK_POS - td->offs; - } - /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[i] != td->pattern[i]) - return -1; - } - } + if (memcmp(p, td->pattern, td->len)) + return -1; if (td->options & NAND_BBT_SCANEMPTY) { p += td->len; end += td->len; - for (i = end; i < len; i++) { - if (*p++ != 0xff) - return -1; - } + if (memchr_inv(p, 0xff, len - end)) + return -1; } return 0; } /** * check_short_pattern - [GENERIC] check if a pattern is in the buffer - * @buf: the buffer to search - * @td: search pattern descriptor + * @buf: the buffer to search + * @td: search pattern descriptor * - * Check for a pattern at the given place. Used to search bad block - * tables and good / bad block identifiers. Same as check_pattern, but - * no optional empty check - * -*/ + * Check for a pattern at the given place. Used to search bad block tables and + * good / bad block identifiers. Same as check_pattern, but no optional empty + * check. + */ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td) { - int i; - uint8_t *p = buf; - /* Compare the pattern */ - for (i = 0; i < td->len; i++) { - if (p[td->offs + i] != td->pattern[i]) - return -1; - } - /* Need to check location 1 AND 6? */ - if (td->options & NAND_BBT_SCANBYTE1AND6) { - for (i = 0; i < td->len; i++) { - if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) - return -1; - } - } + if (memcmp(buf + td->offs, td->pattern, td->len)) + return -1; return 0; } /** * add_marker_len - compute the length of the marker in data area - * @td: BBT descriptor used for computation + * @td: BBT descriptor used for computation * - * The length will be 0 if the markeris located in OOB area. + * The length will be 0 if the marker is located in OOB area. */ static u32 add_marker_len(struct nand_bbt_descr *td) { @@ -199,34 +154,33 @@ static u32 add_marker_len(struct nand_bbt_descr *td) /** * read_bbt - [GENERIC] Read the bad block table starting from page - * @mtd: MTD device structure - * @buf: temporary buffer - * @page: the starting page - * @num: the number of bbt descriptors to read - * @td: the bbt describtion table - * @offs: offset in the memory table + * @mtd: MTD device structure + * @buf: temporary buffer + * @page: the starting page + * @num: the number of bbt descriptors to read + * @td: the bbt describtion table + * @offs: offset in the memory table * * Read the bad block table starting from page. - * */ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, struct nand_bbt_descr *td, int offs) { - int res, i, j, act = 0; + int res, ret = 0, i, j, act = 0; struct nand_chip *this = mtd->priv; size_t retlen, len, totlen; loff_t from; int bits = td->options & NAND_BBT_NRBITS_MSK; - uint8_t msk = (uint8_t) ((1 << bits) - 1); + uint8_t msk = (uint8_t)((1 << bits) - 1); u32 marker_len; int reserved_block_code = td->reserved_block_code; totlen = (num * bits) >> 3; marker_len = add_marker_len(td); - from = ((loff_t) page) << this->page_shift; + from = ((loff_t)page) << this->page_shift; while (totlen) { - len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); + len = min(totlen, (size_t)(1 << this->bbt_erase_shift)); if (marker_len) { /* * In case the BBT marker is not in the OOB area it @@ -236,13 +190,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, from += marker_len; marker_len = 0; } - res = mtd->read(mtd, from, len, &retlen, buf); + res = mtd_read(mtd, from, len, &retlen, buf); if (res < 0) { - if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error reading bad block table\n"); + if (mtd_is_eccerr(res)) { + pr_info("nand_bbt: ECC error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + return res; + } else if (mtd_is_bitflip(res)) { + pr_info("nand_bbt: corrected error in BBT at " + "0x%012llx\n", from & ~mtd->writesize); + ret = res; + } else { + pr_info("nand_bbt: error reading BBT\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n"); } /* Analyse data */ @@ -253,17 +214,16 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, if (tmp == msk) continue; if (reserved_block_code && (tmp == reserved_block_code)) { - printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", - (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); + pr_info("nand_read_bbt: reserved block at 0x%012llx\n", + (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06); mtd->ecc_stats.bbtblocks++; continue; } - MTDDEBUG(MTD_DEBUG_LEVEL0, "nand_read_bbt: " \ - "Bad block at 0x%012llx\n", + pr_info("nand_read_bbt: Bad block at 0x%012llx\n", (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift); - /* Factory marked bad or worn out ? */ + /* Factory marked bad or worn out? */ if (tmp == 0) this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); else @@ -274,20 +234,20 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, totlen -= len; from += len; } - return 0; + return ret; } /** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @chip: read the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @chip: read the table for a specific chip, -1 read all chips; applies only if + * NAND_BBT_PERCHIP option is set * - * Read the bad block table for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. -*/ + * Read the bad block table for all chips starting at a given page. We assume + * that the bbt bits are in consecutive order. + */ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip) { struct nand_chip *this = mtd->priv; @@ -313,10 +273,8 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc return 0; } -/* - * BBT marker is in the first page, no OOB. - */ -static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +/* BBT marker is in the first page, no OOB */ +static int scan_read_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, struct nand_bbt_descr *td) { size_t retlen; @@ -326,70 +284,73 @@ static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, if (td->options & NAND_BBT_VERSION) len++; - return mtd->read(mtd, offs, len, &retlen, buf); + return mtd_read(mtd, offs, len, &retlen, buf); } -/* - * Scan read raw data from flash +/** + * scan_read_oob - [GENERIC] Scan data+OOB region to buffer + * @mtd: MTD device structure + * @buf: temporary buffer + * @offs: offset at which to scan + * @len: length of data region to read + * + * Scan read data from data+OOB. May traverse multiple pages, interleaving + * page,OOB,page,OOB,... in buf. Completes transfer and returns the "strongest" + * ECC condition (error or bitflip). May quit on the first (non-ECC) error. */ -static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len) { struct mtd_oob_ops ops; - int res; + int res, ret = 0; - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; - while (len > 0) { - if (len <= mtd->writesize) { - ops.oobbuf = buf + len; - ops.datbuf = buf; - ops.len = len; - return mtd->read_oob(mtd, offs, &ops); - } else { - ops.oobbuf = buf + mtd->writesize; - ops.datbuf = buf; - ops.len = mtd->writesize; - res = mtd->read_oob(mtd, offs, &ops); + ops.datbuf = buf; + ops.len = min(len, (size_t)mtd->writesize); + ops.oobbuf = buf + ops.len; - if (res) + res = mtd_read_oob(mtd, offs, &ops); + if (res) { + if (!mtd_is_bitflip_or_eccerr(res)) return res; + else if (mtd_is_eccerr(res) || !ret) + ret = res; } buf += mtd->oobsize + mtd->writesize; len -= mtd->writesize; + offs += mtd->writesize; } - return 0; + return ret; } -static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read(struct mtd_info *mtd, uint8_t *buf, loff_t offs, size_t len, struct nand_bbt_descr *td) { if (td->options & NAND_BBT_NO_OOB) - return scan_read_raw_data(mtd, buf, offs, td); + return scan_read_data(mtd, buf, offs, td); else - return scan_read_raw_oob(mtd, buf, offs, len); + return scan_read_oob(mtd, buf, offs, len); } -/* - * Scan write data with oob to flash - */ +/* Scan write data with oob to flash */ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len, uint8_t *buf, uint8_t *oob) { struct mtd_oob_ops ops; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooboffs = 0; ops.ooblen = mtd->oobsize; ops.datbuf = buf; ops.oobbuf = oob; ops.len = len; - return mtd->write_oob(mtd, offs, &ops); + return mtd_write_oob(mtd, offs, &ops); } static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) @@ -403,65 +364,60 @@ static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * - * Read the bad block table(s) for all chips starting at a given page - * We assume that the bbt bits are in consecutive order. + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * -*/ -static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, - struct nand_bbt_descr *td, struct nand_bbt_descr *md) + * Read the bad block table(s) for all chips starting at a given page. We + * assume that the bbt bits are in consecutive order. + */ +static void read_abs_bbts(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, struct nand_bbt_descr *md) { struct nand_chip *this = mtd->priv; /* Read the primary version, if available */ if (td->options & NAND_BBT_VERSION) { - scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, + scan_read(mtd, buf, (loff_t)td->pages[0] << this->page_shift, mtd->writesize, td); td->version[0] = buf[bbt_get_ver_offs(mtd, td)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - td->pages[0], td->version[0]); + pr_info("Bad block table at page %d, version 0x%02X\n", + td->pages[0], td->version[0]); } /* Read the mirror version, if available */ if (md && (md->options & NAND_BBT_VERSION)) { - scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, - mtd->writesize, td); + scan_read(mtd, buf, (loff_t)md->pages[0] << this->page_shift, + mtd->writesize, md); md->version[0] = buf[bbt_get_ver_offs(mtd, md)]; - printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n", - md->pages[0], md->version[0]); + pr_info("Bad block table at page %d, version 0x%02X\n", + md->pages[0], md->version[0]); } - return 1; } -/* - * Scan a given block full - */ +/* Scan a given block full */ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd, loff_t offs, uint8_t *buf, size_t readlen, - int scanlen, int len) + int scanlen, int numpages) { int ret, j; - ret = scan_read_raw_oob(mtd, buf, offs, readlen); - if (ret) + ret = scan_read_oob(mtd, buf, offs, readlen); + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; - for (j = 0; j < len; j++, buf += scanlen) { + for (j = 0; j < numpages; j++, buf += scanlen) { if (check_pattern(buf, scanlen, mtd->writesize, bd)) return 1; } return 0; } -/* - * Scan a given block partially - */ +/* Scan a given block partially */ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, - loff_t offs, uint8_t *buf, int len) + loff_t offs, uint8_t *buf, int numpages) { struct mtd_oob_ops ops; int j, ret; @@ -470,16 +426,16 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, ops.oobbuf = buf; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; - for (j = 0; j < len; j++) { + for (j = 0; j < numpages; j++) { /* - * Read the full oob until read_oob is fixed to - * handle single byte reads for 16 bit - * buswidth + * Read the full oob until read_oob is fixed to handle single + * byte reads for 16 bit buswidth. */ - ret = mtd->read_oob(mtd, offs, &ops); - if (ret) + ret = mtd_read_oob(mtd, offs, &ops); + /* Ignore ECC errors when checking for BBM */ + if (ret && !mtd_is_bitflip_or_eccerr(ret)) return ret; if (check_short_pattern(buf, bd)) @@ -492,32 +448,32 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd, /** * create_bbt - [GENERIC] Create a bad block table by scanning the device - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern - * @chip: create the table for a specific chip, -1 read all chips. - * Applies only if NAND_BBT_PERCHIP option is set + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern + * @chip: create the table for a specific chip, -1 read all chips; applies only + * if NAND_BBT_PERCHIP option is set * - * Create a bad block table by scanning the device - * for the given good/bad block identify pattern + * Create a bad block table by scanning the device for the given good/bad block + * identify pattern. */ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip) { struct nand_chip *this = mtd->priv; - int i, numblocks, len, scanlen; + int i, numblocks, numpages, scanlen; int startblock; loff_t from; size_t readlen; - MTDDEBUG(MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n"); + pr_info("Scanning device for bad blocks\n"); if (bd->options & NAND_BBT_SCANALLPAGES) - len = 1 << (this->bbt_erase_shift - this->page_shift); + numpages = 1 << (this->bbt_erase_shift - this->page_shift); else if (bd->options & NAND_BBT_SCAN2NDPAGE) - len = 2; + numpages = 2; else - len = 1; + numpages = 1; if (!(bd->options & NAND_BBT_SCANEMPTY)) { /* We need only read few bytes from the OOB area */ @@ -526,18 +482,20 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, } else { /* Full page content should be read */ scanlen = mtd->writesize + mtd->oobsize; - readlen = len * mtd->writesize; + readlen = numpages * mtd->writesize; } if (chip == -1) { - /* Note that numblocks is 2 * (real numblocks) here, see i+=2 - * below as it makes shifting and masking less painful */ + /* + * Note that numblocks is 2 * (real numblocks) here, see i+=2 + * below as it makes shifting and masking less painful + */ numblocks = mtd->size >> (this->bbt_erase_shift - 1); startblock = 0; from = 0; } else { if (chip >= this->numchips) { - printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n", + pr_warn("create_bbt(): chipnr (%d) > available chips (%d)\n", chip + 1, this->numchips); return -EINVAL; } @@ -547,8 +505,8 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, from = (loff_t)startblock << (this->bbt_erase_shift - 1); } - if (this->options & NAND_BBT_SCANLASTPAGE) - from += mtd->erasesize - (mtd->writesize * len); + if (this->bbt_options & NAND_BBT_SCANLASTPAGE) + from += mtd->erasesize - (mtd->writesize * numpages); for (i = startblock; i < numblocks;) { int ret; @@ -557,17 +515,16 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, if (bd->options & NAND_BBT_SCANALLPAGES) ret = scan_block_full(mtd, bd, from, buf, readlen, - scanlen, len); + scanlen, numpages); else - ret = scan_block_fast(mtd, bd, from, buf, len); + ret = scan_block_fast(mtd, bd, from, buf, numpages); if (ret < 0) return ret; if (ret) { this->bbt[i >> 3] |= 0x03 << (i & 0x6); - MTDDEBUG(MTD_DEBUG_LEVEL0, - "Bad eraseblock %d at 0x%012llx\n", + pr_warn("Bad eraseblock %d at 0x%012llx\n", i >> 1, (unsigned long long)from); mtd->ecc_stats.badblocks++; } @@ -580,20 +537,18 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, /** * search_bbt - [GENERIC] scan the device for a specific bad block table - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table * - * Read the bad block table by searching for a given ident pattern. - * Search is preformed either from the beginning up or from the end of - * the device downwards. The search starts always at the start of a - * block. - * If the option NAND_BBT_PERCHIP is given, each chip is searched - * for a bbt, which contains the bad block information of this chip. - * This is necessary to provide support for certain DOC devices. + * Read the bad block table by searching for a given ident pattern. Search is + * preformed either from the beginning up or from the end of the device + * downwards. The search starts always at the start of a block. If the option + * NAND_BBT_PERCHIP is given, each chip is searched for a bbt, which contains + * the bad block information of this chip. This is necessary to provide support + * for certain DOC devices. * - * The bbt ident pattern resides in the oob area of the first page - * in a block. + * The bbt ident pattern resides in the oob area of the first page in a block. */ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td) { @@ -604,7 +559,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr int bbtblocks; int blocktopage = this->bbt_erase_shift - this->page_shift; - /* Search direction top -> down ? */ + /* Search direction top -> down? */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = (mtd->size >> this->bbt_erase_shift) - 1; dir = -1; @@ -613,7 +568,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr dir = 1; } - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; bbtblocks = this->chipsize >> this->bbt_erase_shift; @@ -634,7 +589,7 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr loff_t offs = (loff_t)actblock << this->bbt_erase_shift; /* Read first page */ - scan_read_raw(mtd, buf, offs, mtd->writesize, td); + scan_read(mtd, buf, offs, mtd->writesize, td); if (!check_pattern(buf, scanlen, mtd->writesize, td)) { td->pages[i] = actblock << blocktopage; if (td->options & NAND_BBT_VERSION) { @@ -649,10 +604,9 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /* Check, if we found a bbt for each requested chip */ for (i = 0; i < chips; i++) { if (td->pages[i] == -1) - printk(KERN_WARNING "Bad block table not found for chip %d\n", i); + pr_warn("Bad block table not found for chip %d\n", i); else - MTDDEBUG(MTD_DEBUG_LEVEL0, "Bad block table found " \ - "at page %d, version 0x%02X\n", td->pages[i], + pr_info("Bad block table found at page %d, version 0x%02X\n", td->pages[i], td->version[i]); } return 0; @@ -660,14 +614,16 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr /** * search_read_bbts - [GENERIC] scan the device for bad block table(s) - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror * - * Search and read the bad block table(s) -*/ -static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md) + * Search and read the bad block table(s). + */ +static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf, + struct nand_bbt_descr *td, + struct nand_bbt_descr *md) { /* Search the primary table */ search_bbt(mtd, buf, td); @@ -675,23 +631,18 @@ static int search_read_bbts(struct mtd_info *mtd, uint8_t * buf, struct nand_bbt /* Search the mirror table */ if (md) search_bbt(mtd, buf, md); - - /* Force result check */ - return 1; } /** * write_bbt - [GENERIC] (Re)write the bad block table + * @mtd: MTD device structure + * @buf: temporary buffer + * @td: descriptor for the bad block table + * @md: descriptor for the bad block table mirror + * @chipsel: selector for a specific chip, -1 for all * - * @mtd: MTD device structure - * @buf: temporary buffer - * @td: descriptor for the bad block table - * @md: descriptor for the bad block table mirror - * @chipsel: selector for a specific chip, -1 for all - * - * (Re)write the bad block table - * -*/ + * (Re)write the bad block table. + */ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, struct nand_bbt_descr *md, int chipsel) @@ -710,14 +661,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, ops.ooblen = mtd->oobsize; ops.ooboffs = 0; ops.datbuf = NULL; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; if (!rcode) rcode = 0xff; - /* Write bad block table per chip rather than per device ? */ + /* Write bad block table per chip rather than per device? */ if (td->options & NAND_BBT_PERCHIP) { numblocks = (int)(this->chipsize >> this->bbt_erase_shift); - /* Full device write or specific chip ? */ + /* Full device write or specific chip? */ if (chipsel == -1) { nrchips = this->numchips; } else { @@ -731,8 +682,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, /* Loop through the chips */ for (; chip < nrchips; chip++) { - - /* There was already a version of the table, reuse the page + /* + * There was already a version of the table, reuse the page * This applies for absolute placement too, as we have the * page nr. in td->pages. */ @@ -741,8 +692,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, goto write; } - /* Automatic placement of the bad block table */ - /* Search direction top -> down ? */ + /* + * Automatic placement of the bad block table. Search direction + * top -> down? + */ if (td->options & NAND_BBT_LASTBLOCK) { startblock = numblocks * (chip + 1) - 1; dir = -1; @@ -766,7 +719,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (!md || md->pages[chip] != page) goto write; } - printk(KERN_ERR "No space left to write bad block table\n"); + pr_err("No space left to write bad block table\n"); return -ENOSPC; write: @@ -791,29 +744,27 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, bbtoffs = chip * (numblocks >> 2); - to = ((loff_t) page) << this->page_shift; + to = ((loff_t)page) << this->page_shift; - /* Must we save the block contents ? */ + /* Must we save the block contents? */ if (td->options & NAND_BBT_SAVECONTENT) { /* Make it block aligned */ - to &= ~((loff_t) ((1 << this->bbt_erase_shift) - 1)); + to &= ~((loff_t)((1 << this->bbt_erase_shift) - 1)); len = 1 << this->bbt_erase_shift; - res = mtd->read(mtd, to, len, &retlen, buf); + res = mtd_read(mtd, to, len, &retlen, buf); if (res < 0) { if (retlen != len) { - printk(KERN_INFO "nand_bbt: Error " - "reading block for writing " - "the bad block table\n"); + pr_info("nand_bbt: error reading block " + "for writing the bad block table\n"); return res; } - printk(KERN_WARNING "nand_bbt: ECC error " - "while reading block for writing " - "bad block table\n"); + pr_warn("nand_bbt: ECC error while reading " + "block for writing bad block table\n"); } /* Read oob data */ ops.ooblen = (len >> this->page_shift) * mtd->oobsize; ops.oobbuf = &buf[len]; - res = mtd->read_oob(mtd, to + mtd->writesize, &ops); + res = mtd_read_oob(mtd, to + mtd->writesize, &ops); if (res < 0 || ops.oobretlen != ops.ooblen) goto outerr; @@ -821,19 +772,19 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, pageoffs = page - (int)(to >> this->page_shift); offs = pageoffs << this->page_shift; /* Preset the bbt area with 0xff */ - memset(&buf[offs], 0xff, (size_t) (numblocks >> sft)); + memset(&buf[offs], 0xff, (size_t)(numblocks >> sft)); ooboffs = len + (pageoffs * mtd->oobsize); } else if (td->options & NAND_BBT_NO_OOB) { ooboffs = 0; offs = td->len; - /* the version byte */ + /* The version byte */ if (td->options & NAND_BBT_VERSION) offs++; /* Calc length */ - len = (size_t) (numblocks >> sft); + len = (size_t)(numblocks >> sft); len += offs; - /* Make it page aligned ! */ + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len); @@ -841,8 +792,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, memcpy(buf, td->pattern, td->len); } else { /* Calc length */ - len = (size_t) (numblocks >> sft); - /* Make it page aligned ! */ + len = (size_t)(numblocks >> sft); + /* Make it page aligned! */ len = ALIGN(len, mtd->writesize); /* Preset the buffer with 0xff */ memset(buf, 0xff, len + @@ -856,13 +807,13 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (td->options & NAND_BBT_VERSION) buf[ooboffs + td->veroffs] = td->version[chip]; - /* walk through the memory table */ + /* Walk through the memory table */ for (i = 0; i < numblocks;) { uint8_t dat; dat = this->bbt[bbtoffs + (i >> 2)]; for (j = 0; j < 4; j++, i++) { int sftcnt = (i << (3 - sft)) & sftmsk; - /* Do not store the reserved bbt blocks ! */ + /* Do not store the reserved bbt blocks! */ buf[offs + (i >> sft)] &= ~(msk[dat & 0x03] << sftcnt); dat >>= 2; @@ -883,8 +834,8 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, if (res < 0) goto outerr; - printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " - "0x%02X\n", (unsigned long long)to, td->version[chip]); + pr_info("Bad block table written to 0x%012llx, version 0x%02X\n", + (unsigned long long)to, td->version[chip]); /* Mark it as used */ td->pages[chip] = page; @@ -892,19 +843,18 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf, return 0; outerr: - printk(KERN_WARNING - "nand_bbt: Error while writing bad block table %d\n", res); + pr_warn("nand_bbt: error while writing bad block table %d\n", res); return res; } /** * nand_memory_bbt - [GENERIC] create a memory based bad block table - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The function creates a memory based bbt by scanning the device - * for manufacturer / software marked good / bad blocks -*/ + * The function creates a memory based bbt by scanning the device for + * manufacturer / software marked good / bad blocks. + */ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -915,25 +865,24 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b /** * check_create - [GENERIC] create and write bbt(s) if necessary - * @mtd: MTD device structure - * @buf: temporary buffer - * @bd: descriptor for the good/bad block search pattern + * @mtd: MTD device structure + * @buf: temporary buffer + * @bd: descriptor for the good/bad block search pattern * - * The function checks the results of the previous call to read_bbt - * and creates / updates the bbt(s) if necessary - * Creation is necessary if no bbt was found for the chip/device - * Update is necessary if one of the tables is missing or the - * version nr. of one table is less than the other -*/ + * The function checks the results of the previous call to read_bbt and creates + * / updates the bbt(s) if necessary. Creation is necessary if no bbt was found + * for the chip/device. Update is necessary if one of the tables is missing or + * the version nr. of one table is less than the other. + */ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd) { - int i, chips, writeops, chipsel, res; + int i, chips, writeops, create, chipsel, res, res2; struct nand_chip *this = mtd->priv; struct nand_bbt_descr *td = this->bbt_td; struct nand_bbt_descr *md = this->bbt_md; struct nand_bbt_descr *rd, *rd2; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) chips = this->numchips; else @@ -941,86 +890,98 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc for (i = 0; i < chips; i++) { writeops = 0; + create = 0; rd = NULL; rd2 = NULL; - /* Per chip or per device ? */ + res = res2 = 0; + /* Per chip or per device? */ chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; - /* Mirrored table available ? */ + /* Mirrored table available? */ if (md) { if (td->pages[i] == -1 && md->pages[i] == -1) { + create = 1; writeops = 0x03; - goto create; - } - - if (td->pages[i] == -1) { + } else if (td->pages[i] == -1) { rd = md; - td->version[i] = md->version[i]; - writeops = 1; - goto writecheck; - } - - if (md->pages[i] == -1) { + writeops = 0x01; + } else if (md->pages[i] == -1) { rd = td; - md->version[i] = td->version[i]; - writeops = 2; - goto writecheck; - } - - if (td->version[i] == md->version[i]) { + writeops = 0x02; + } else if (td->version[i] == md->version[i]) { rd = td; if (!(td->options & NAND_BBT_VERSION)) rd2 = md; - goto writecheck; - } - - if (((int8_t) (td->version[i] - md->version[i])) > 0) { + } else if (((int8_t)(td->version[i] - md->version[i])) > 0) { rd = td; - md->version[i] = td->version[i]; - writeops = 2; + writeops = 0x02; } else { rd = md; - td->version[i] = md->version[i]; - writeops = 1; + writeops = 0x01; } - - goto writecheck; - } else { if (td->pages[i] == -1) { + create = 1; writeops = 0x01; - goto create; + } else { + rd = td; } - rd = td; - goto writecheck; } - create: - /* Create the bad block table by scanning the device ? */ - if (!(td->options & NAND_BBT_CREATE)) - continue; - /* Create the table in memory by scanning the chip(s) */ - if (!(this->options & NAND_CREATE_EMPTY_BBT)) - create_bbt(mtd, buf, bd, chipsel); - - td->version[i] = 1; - if (md) - md->version[i] = 1; - writecheck: - /* read back first ? */ - if (rd) - read_abs_bbt(mtd, buf, rd, chipsel); - /* If they weren't versioned, read both. */ - if (rd2) - read_abs_bbt(mtd, buf, rd2, chipsel); - - /* Write the bad block table to the device ? */ + if (create) { + /* Create the bad block table by scanning the device? */ + if (!(td->options & NAND_BBT_CREATE)) + continue; + + /* Create the table in memory by scanning the chip(s) */ + if (!(this->bbt_options & NAND_BBT_CREATE_EMPTY)) + create_bbt(mtd, buf, bd, chipsel); + + td->version[i] = 1; + if (md) + md->version[i] = 1; + } + + /* Read back first? */ + if (rd) { + res = read_abs_bbt(mtd, buf, rd, chipsel); + if (mtd_is_eccerr(res)) { + /* Mark table as invalid */ + rd->pages[i] = -1; + rd->version[i] = 0; + i--; + continue; + } + } + /* If they weren't versioned, read both */ + if (rd2) { + res2 = read_abs_bbt(mtd, buf, rd2, chipsel); + if (mtd_is_eccerr(res2)) { + /* Mark table as invalid */ + rd2->pages[i] = -1; + rd2->version[i] = 0; + i--; + continue; + } + } + + /* Scrub the flash table(s)? */ + if (mtd_is_bitflip(res) || mtd_is_bitflip(res2)) + writeops = 0x03; + + /* Update version numbers before writing */ + if (md) { + td->version[i] = max(td->version[i], md->version[i]); + md->version[i] = td->version[i]; + } + + /* Write the bad block table to the device? */ if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) return res; } - /* Write the mirror bad block table to the device ? */ + /* Write the mirror bad block table to the device? */ if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); if (res < 0) @@ -1032,20 +993,19 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc /** * mark_bbt_regions - [GENERIC] mark the bad block table regions - * @mtd: MTD device structure - * @td: bad block table descriptor + * @mtd: MTD device structure + * @td: bad block table descriptor * - * The bad block table regions are marked as "bad" to prevent - * accidental erasures / writes. The regions are identified by - * the mark 0x02. -*/ + * The bad block table regions are marked as "bad" to prevent accidental + * erasures / writes. The regions are identified by the mark 0x02. + */ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) { struct nand_chip *this = mtd->priv; int i, j, chips, block, nrblocks, update; uint8_t oldval, newval; - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chips = this->numchips; nrblocks = (int)(this->chipsize >> this->bbt_erase_shift); @@ -1082,9 +1042,11 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) update = 1; block += 2; } - /* If we want reserved blocks to be recorded to flash, and some - new ones have been marked, then we need to update the stored - bbts. This should only happen once. */ + /* + * If we want reserved blocks to be recorded to flash, and some + * new ones have been marked, then we need to update the stored + * bbts. This should only happen once. + */ if (update && td->reserved_block_code) nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); } @@ -1092,8 +1054,8 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td) /** * verify_bbt_descr - verify the bad block description - * @mtd: MTD device structure - * @bd: the table to verify + * @mtd: MTD device structure + * @bd: the table to verify * * This functions performs a few sanity checks on the bad block description * table. @@ -1111,16 +1073,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) pattern_len = bd->len; bits = bd->options & NAND_BBT_NRBITS_MSK; - BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && - !(this->options & NAND_USE_FLASH_BBT)); + BUG_ON((this->bbt_options & NAND_BBT_NO_OOB) && + !(this->bbt_options & NAND_BBT_USE_FLASH)); BUG_ON(!bits); if (bd->options & NAND_BBT_VERSION) pattern_len++; if (bd->options & NAND_BBT_NO_OOB) { - BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); - BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); + BUG_ON(!(this->bbt_options & NAND_BBT_USE_FLASH)); + BUG_ON(!(this->bbt_options & NAND_BBT_NO_OOB)); BUG_ON(bd->offs); if (bd->options & NAND_BBT_VERSION) BUG_ON(bd->veroffs != bd->len); @@ -1140,18 +1102,16 @@ static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s) - * @mtd: MTD device structure - * @bd: descriptor for the good/bad block search pattern - * - * The function checks, if a bad block table(s) is/are already - * available. If not it scans the device for manufacturer - * marked good / bad blocks and writes the bad block table(s) to - * the selected place. + * @mtd: MTD device structure + * @bd: descriptor for the good/bad block search pattern * - * The bad block table memory is allocated here. It must be freed - * by calling the nand_free_bbt function. + * The function checks, if a bad block table(s) is/are already available. If + * not it scans the device for manufacturer marked good / bad blocks and writes + * the bad block table(s) to the selected place. * -*/ + * The bad block table memory is allocated here. It must be freed by calling + * the nand_free_bbt function. + */ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) { struct nand_chip *this = mtd->priv; @@ -1161,19 +1121,21 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) struct nand_bbt_descr *md = this->bbt_md; len = mtd->size >> (this->bbt_erase_shift + 2); - /* Allocate memory (2bit per block) and clear the memory bad block table */ + /* + * Allocate memory (2bit per block) and clear the memory bad block + * table. + */ this->bbt = kzalloc(len, GFP_KERNEL); - if (!this->bbt) { - printk(KERN_ERR "nand_scan_bbt: Out of memory\n"); + if (!this->bbt) return -ENOMEM; - } - /* If no primary table decriptor is given, scan the device - * to build a memory based bad block table + /* + * If no primary table decriptor is given, scan the device to build a + * memory based bad block table. */ if (!td) { if ((res = nand_memory_bbt(mtd, bd))) { - printk(KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n"); + pr_err("nand_bbt: can't scan flash and build the RAM-based BBT\n"); kfree(this->bbt); this->bbt = NULL; } @@ -1187,22 +1149,20 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len += (len >> this->page_shift) * mtd->oobsize; buf = vmalloc(len); if (!buf) { - printk(KERN_ERR "nand_bbt: Out of memory\n"); kfree(this->bbt); this->bbt = NULL; return -ENOMEM; } - /* Is the bbt at a given page ? */ + /* Is the bbt at a given page? */ if (td->options & NAND_BBT_ABSPAGE) { - res = read_abs_bbts(mtd, buf, td, md); + read_abs_bbts(mtd, buf, td, md); } else { /* Search the bad block table using a pattern in oob */ - res = search_read_bbts(mtd, buf, td, md); + search_read_bbts(mtd, buf, td, md); } - if (res) - res = check_create(mtd, buf, bd); + res = check_create(mtd, buf, bd); /* Prevent the bbt regions from erasing / writing */ mark_bbt_region(mtd, td); @@ -1215,15 +1175,15 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) /** * nand_update_bbt - [NAND Interface] update bad block table(s) - * @mtd: MTD device structure - * @offs: the offset of the newly marked block + * @mtd: MTD device structure + * @offs: the offset of the newly marked block * - * The function updates the bad block table(s) -*/ + * The function updates the bad block table(s). + */ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) { struct nand_chip *this = mtd->priv; - int len, res = 0, writeops = 0; + int len, res = 0; int chip, chipsel; uint8_t *buf; struct nand_bbt_descr *td = this->bbt_td; @@ -1236,14 +1196,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) len = (1 << this->bbt_erase_shift); len += (len >> this->page_shift) * mtd->oobsize; buf = kmalloc(len, GFP_KERNEL); - if (!buf) { - printk(KERN_ERR "nand_update_bbt: Out of memory\n"); + if (!buf) return -ENOMEM; - } - writeops = md != NULL ? 0x03 : 0x01; - - /* Do we have a bbt per chip ? */ + /* Do we have a bbt per chip? */ if (td->options & NAND_BBT_PERCHIP) { chip = (int)(offs >> this->chip_shift); chipsel = chip; @@ -1256,14 +1212,14 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) if (md) md->version[chip]++; - /* Write the bad block table to the device ? */ - if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) { + /* Write the bad block table to the device? */ + if (td->options & NAND_BBT_WRITE) { res = write_bbt(mtd, buf, td, md, chipsel); if (res < 0) goto out; } - /* Write the mirror bad block table to the device ? */ - if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) { + /* Write the mirror bad block table to the device? */ + if (md && (md->options & NAND_BBT_WRITE)) { res = write_bbt(mtd, buf, md, td, chipsel); } @@ -1272,8 +1228,10 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs) return res; } -/* Define some generic bad / good block scan pattern which are used - * while scanning a device for factory marked good / bad blocks. */ +/* + * Define some generic bad / good block scan pattern which are used + * while scanning a device for factory marked good / bad blocks. + */ static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 }; @@ -1285,8 +1243,7 @@ static struct nand_bbt_descr agand_flashbased = { .pattern = scan_agand_pattern }; -/* Generic flash bbt decriptors -*/ +/* Generic flash bbt descriptors */ static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' }; static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' }; @@ -1296,7 +1253,7 @@ static struct nand_bbt_descr bbt_main_descr = { .offs = 8, .len = 4, .veroffs = 12, - .maxblocks = 4, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, .pattern = bbt_pattern }; @@ -1306,55 +1263,51 @@ static struct nand_bbt_descr bbt_mirror_descr = { .offs = 8, .len = 4, .veroffs = 12, - .maxblocks = 4, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, .pattern = mirror_pattern }; -static struct nand_bbt_descr bbt_main_no_bbt_descr = { +static struct nand_bbt_descr bbt_main_no_oob_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | NAND_BBT_NO_OOB, .len = 4, .veroffs = 4, - .maxblocks = 4, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, .pattern = bbt_pattern }; -static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { +static struct nand_bbt_descr bbt_mirror_no_oob_descr = { .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP | NAND_BBT_NO_OOB, .len = 4, .veroffs = 4, - .maxblocks = 4, + .maxblocks = NAND_BBT_SCAN_MAXBLOCKS, .pattern = mirror_pattern }; -#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ - NAND_BBT_SCANBYTE1AND6) +#define BADBLOCK_SCAN_MASK (~NAND_BBT_NO_OOB) /** - * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure - * @this: NAND chip to create descriptor for + * nand_create_badblock_pattern - [INTERN] Creates a BBT descriptor structure + * @this: NAND chip to create descriptor for * * This function allocates and initializes a nand_bbt_descr for BBM detection - * based on the properties of "this". The new descriptor is stored in + * based on the properties of @this. The new descriptor is stored in * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when * passed to this function. - * */ -static int nand_create_default_bbt_descr(struct nand_chip *this) +static int nand_create_badblock_pattern(struct nand_chip *this) { struct nand_bbt_descr *bd; if (this->badblock_pattern) { - printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); + pr_warn("Bad block pattern already allocated; not replacing\n"); return -EINVAL; } bd = kzalloc(sizeof(*bd), GFP_KERNEL); - if (!bd) { - printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); + if (!bd) return -ENOMEM; - } - bd->options = this->options & BBT_SCAN_OPTIONS; + bd->options = this->bbt_options & BADBLOCK_SCAN_MASK; bd->offs = this->badblockpos; bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; bd->pattern = scan_ff_pattern; @@ -1365,22 +1318,20 @@ static int nand_create_default_bbt_descr(struct nand_chip *this) /** * nand_default_bbt - [NAND Interface] Select a default bad block table for the device - * @mtd: MTD device structure - * - * This function selects the default bad block table - * support for the device and calls the nand_scan_bbt function + * @mtd: MTD device structure * -*/ + * This function selects the default bad block table support for the device and + * calls the nand_scan_bbt function. + */ int nand_default_bbt(struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - /* Default for AG-AND. We must use a flash based - * bad block table as the devices have factory marked - * _good_ blocks. Erasing those blocks leads to loss - * of the good / bad information, so we _must_ store - * this information in a good / bad table during - * startup + /* + * Default for AG-AND. We must use a flash based bad block table as the + * devices have factory marked _good_ blocks. Erasing those blocks + * leads to loss of the good / bad information, so we _must_ store this + * information in a good / bad table during startup. */ if (this->options & NAND_IS_AND) { /* Use the default pattern descriptors */ @@ -1388,17 +1339,17 @@ int nand_default_bbt(struct mtd_info *mtd) this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; } - this->options |= NAND_USE_FLASH_BBT; + this->bbt_options |= NAND_BBT_USE_FLASH; return nand_scan_bbt(mtd, &agand_flashbased); } - /* Is a flash based bad block table requested ? */ - if (this->options & NAND_USE_FLASH_BBT) { + /* Is a flash based bad block table requested? */ + if (this->bbt_options & NAND_BBT_USE_FLASH) { /* Use the default pattern descriptors */ if (!this->bbt_td) { - if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { - this->bbt_td = &bbt_main_no_bbt_descr; - this->bbt_md = &bbt_mirror_no_bbt_descr; + if (this->bbt_options & NAND_BBT_NO_OOB) { + this->bbt_td = &bbt_main_no_oob_descr; + this->bbt_md = &bbt_mirror_no_oob_descr; } else { this->bbt_td = &bbt_main_descr; this->bbt_md = &bbt_mirror_descr; @@ -1410,18 +1361,17 @@ int nand_default_bbt(struct mtd_info *mtd) } if (!this->badblock_pattern) - nand_create_default_bbt_descr(this); + nand_create_badblock_pattern(this); return nand_scan_bbt(mtd, this->badblock_pattern); } /** * nand_isbad_bbt - [NAND Interface] Check if a block is bad - * @mtd: MTD device structure - * @offs: offset in the device - * @allowbbt: allow access to bad block table region - * -*/ + * @mtd: MTD device structure + * @offs: offset in the device + * @allowbbt: allow access to bad block table region + */ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) { struct nand_chip *this = mtd->priv; diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 3953549..f856778 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -71,14 +71,15 @@ const struct nand_flash_dev nand_flash_ids[] = { * These are the new chips with large page size. The pagesize and the * erasesize is determined from the extended id bytes */ -#define LP_OPTIONS (NAND_SAMSUNG_LP_OPTIONS | NAND_NO_READRDY | NAND_NO_AUTOINCR) +#define LP_OPTIONS NAND_SAMSUNG_LP_OPTIONS #define LP_OPTIONS16 (LP_OPTIONS | NAND_BUSWIDTH_16) - /*512 Megabit */ + /* 512 Megabit */ {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 1,8V 8-bit", 0xA0, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 3,3V 8-bit", 0xD0, 0, 64, 0, LP_OPTIONS}, + {"NAND 64MiB 3,3V 8-bit", 0xF0, 0, 64, 0, LP_OPTIONS}, {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, LP_OPTIONS16}, {"NAND 64MiB 1,8V 16-bit", 0xB0, 0, 64, 0, LP_OPTIONS16}, {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, LP_OPTIONS16}, @@ -157,9 +158,7 @@ const struct nand_flash_dev nand_flash_ids[] = { * writes possible, but not implemented now */ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, - NAND_IS_AND | NAND_NO_AUTOINCR |NAND_NO_READRDY | NAND_4PAGE_ARRAY | - BBT_AUTO_REFRESH - }, + NAND_IS_AND | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH}, {NULL,} }; @@ -176,6 +175,9 @@ const struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_STMICRO, "ST Micro"}, {NAND_MFR_HYNIX, "Hynix"}, {NAND_MFR_MICRON, "Micron"}, - {NAND_MFR_AMD, "AMD"}, + {NAND_MFR_AMD, "AMD/Spansion"}, + {NAND_MFR_MACRONIX, "Macronix"}, + {NAND_MFR_EON, "Eon"}, {0x0, "Unknown"} }; + diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index 4727f9c..1d22b52 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -120,8 +120,12 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) WATCHDOG_RESET(); + if (opts->lim && (erase.addr >= (opts->offset + opts->lim))) { + puts("Size of erase exceeds limit\n"); + return -EFBIG; + } if (!opts->scrub && bbtest) { - int ret = meminfo->block_isbad(meminfo, erase.addr); + int ret = mtd_block_isbad(meminfo, erase.addr); if (ret > 0) { if (!opts->quiet) printf("\rSkipping bad block at " @@ -144,7 +148,7 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) erased_length++; - result = meminfo->erase(meminfo, &erase); + result = mtd_erase(meminfo, &erase); if (result != 0) { printf("\n%s: MTD Erase failure: %d\n", mtd_device, result); @@ -153,15 +157,16 @@ int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts) /* format for JFFS2 ? */ if (opts->jffs2 && chip->ecc.layout->oobavail >= 8) { - chip->ops.ooblen = 8; - chip->ops.datbuf = NULL; - chip->ops.oobbuf = (uint8_t *)&cleanmarker; - chip->ops.ooboffs = 0; - chip->ops.mode = MTD_OOB_AUTO; + struct mtd_oob_ops ops; + ops.ooblen = 8; + ops.datbuf = NULL; + ops.oobbuf = (uint8_t *)&cleanmarker; + ops.ooboffs = 0; + ops.mode = MTD_OPS_AUTO_OOB; - result = meminfo->write_oob(meminfo, + result = mtd_write_oob(meminfo, erase.addr, - &chip->ops); + &ops); if (result != 0) { printf("\n%s: MTD writeoob failure: %d\n", mtd_device, result); @@ -458,7 +463,8 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length, static size_t drop_ffs(const nand_info_t *nand, const u_char *buf, const size_t *len) { - size_t i, l = *len; + size_t l = *len; + ssize_t i; for (i = l - 1; i >= 0; i--) if (buf[i] != 0xFF) @@ -604,7 +610,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, ops.len = pagesize; ops.ooblen = nand->oobsize; - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooboffs = 0; pages = write_size / pagesize_oob; @@ -614,7 +620,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, ops.datbuf = p_buffer; ops.oobbuf = ops.datbuf + pagesize; - rval = nand->write_oob(nand, offset, &ops); + rval = mtd_write_oob(nand, offset, &ops); if (rval != 0) break; diff --git a/drivers/mtd/nand/ndfc.c b/drivers/mtd/nand/ndfc.c index 213d2c9..94b9033 100644 --- a/drivers/mtd/nand/ndfc.c +++ b/drivers/mtd/nand/ndfc.c @@ -216,6 +216,7 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = 256; nand->ecc.bytes = 3; + nand->ecc.strength = 1; nand->select_chip = ndfc_select_chip; #ifdef CONFIG_SYS_NAND_BUSWIDTH_16BIT diff --git a/drivers/mtd/nand/nomadik.c b/drivers/mtd/nand/nomadik.c index b76f4cb..dc8e513 100644 --- a/drivers/mtd/nand/nomadik.c +++ b/drivers/mtd/nand/nomadik.c @@ -212,6 +212,7 @@ int board_nand_init(struct nand_chip *chip) chip->ecc.mode = NAND_ECC_HW; chip->ecc.bytes = 3; chip->ecc.size = 512; + chip->ecc.strength = 1; chip->ecc.layout = &nomadik_ecc_layout; chip->ecc.calculate = nomadik_ecc_calculate; chip->ecc.hwctl = nomadik_ecc_hwctl; diff --git a/drivers/mtd/nand/omap_gpmc.c b/drivers/mtd/nand/omap_gpmc.c index bc1bcad..5d08822 100644 --- a/drivers/mtd/nand/omap_gpmc.c +++ b/drivers/mtd/nand/omap_gpmc.c @@ -590,11 +590,12 @@ static int omap_correct_data_bch(struct mtd_info *mtd, uint8_t *dat, * @mtd: mtd info structure * @chip: nand chip info structure * @buf: buffer to store read data + * @oob_required: caller expects OOB data read to chip->oob_poi * @page: page number to read * */ static int omap_read_page_bch(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page) + uint8_t *buf, int oob_required, int page) { int i, eccsize = chip->ecc.size; int eccbytes = chip->ecc.bytes; @@ -804,6 +805,7 @@ void omap_nand_switch_ecc(uint32_t hardware, uint32_t eccstrength) nand->ecc.hwctl = NULL; nand->ecc.correct = NULL; nand->ecc.calculate = NULL; + nand->ecc.strength = eccstrength; /* Setup the ecc configurations again */ if (hardware) { @@ -901,7 +903,7 @@ int board_nand_init(struct nand_chip *nand) nand->IO_ADDR_W = (void __iomem *)&gpmc_cfg->cs[cs].nand_cmd; nand->cmd_ctrl = omap_nand_hwcontrol; - nand->options = NAND_NO_PADDING | NAND_CACHEPRG | NAND_NO_AUTOINCR; + nand->options = NAND_NO_PADDING | NAND_CACHEPRG; /* If we are 16 bit dev, our gpmc config tells us that */ if ((readl(&gpmc_cfg->cs[cs].config1) & 0x3000) == 0x1000) nand->options |= NAND_BUSWIDTH_16; @@ -934,6 +936,7 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.layout = &hw_bch8_nand_oob; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; + nand->ecc.strength = 8; nand->ecc.hwctl = omap_enable_ecc_bch; nand->ecc.correct = omap_correct_data_bch; nand->ecc.calculate = omap_calculate_ecc_bch; @@ -952,6 +955,7 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.hwctl = omap_enable_hwecc; nand->ecc.correct = omap_correct_data; nand->ecc.calculate = omap_calculate_ecc; + nand->ecc.strength = 1; omap_hwecc_init(nand); #endif #endif diff --git a/drivers/mtd/nand/s3c2410_nand.c b/drivers/mtd/nand/s3c2410_nand.c index e1a459b..1187b9f 100644 --- a/drivers/mtd/nand/s3c2410_nand.c +++ b/drivers/mtd/nand/s3c2410_nand.c @@ -173,14 +173,13 @@ int board_nand_init(struct nand_chip *nand) nand->ecc.mode = NAND_ECC_HW; nand->ecc.size = CONFIG_SYS_NAND_ECCSIZE; nand->ecc.bytes = CONFIG_SYS_NAND_ECCBYTES; + nand->ecc.strength = 1; #else nand->ecc.mode = NAND_ECC_SOFT; #endif #ifdef CONFIG_S3C2410_NAND_BBT - nand->options = NAND_USE_FLASH_BBT; -#else - nand->options = 0; + nand->bbt_options |= NAND_BBT_USE_FLASH; #endif debug("end of nand_init\n"); diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c index 4d94cc6..6afbec6 100644 --- a/drivers/mtd/nand/tegra_nand.c +++ b/drivers/mtd/nand/tegra_nand.c @@ -707,7 +707,7 @@ static int nand_rw_page(struct mtd_info *mtd, struct nand_chip *chip, * -EIO when command timeout */ static int nand_read_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int page) + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { return nand_rw_page(mtd, chip, buf, page, 1, 0); } @@ -719,8 +719,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, * @param chip nand chip info structure * @param buf data buffer */ -static void nand_write_page_hwecc(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) +static int nand_write_page_hwecc(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required) { int page; struct nand_drv *info; @@ -731,6 +731,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, (readl(&info->reg->addr_reg2) << 16); nand_rw_page(mtd, chip, (uint8_t *)buf, page, 1, 1); + return 0; } @@ -746,7 +747,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, * -EIO when command timeout */ static int nand_read_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, uint8_t *buf, int page) + struct nand_chip *chip, uint8_t *buf, int oob_required, int page) { return nand_rw_page(mtd, chip, buf, page, 0, 0); } @@ -758,8 +759,8 @@ static int nand_read_page_raw(struct mtd_info *mtd, * @param chip nand chip info structure * @param buf data buffer */ -static void nand_write_page_raw(struct mtd_info *mtd, - struct nand_chip *chip, const uint8_t *buf) +static int nand_write_page_raw(struct mtd_info *mtd, + struct nand_chip *chip, const uint8_t *buf, int oob_required) { int page; struct nand_drv *info; @@ -769,6 +770,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, (readl(&info->reg->addr_reg2) << 16); nand_rw_page(mtd, chip, (uint8_t *)buf, page, 0, 1); + return 0; } /** @@ -873,19 +875,13 @@ static int nand_rw_oob(struct mtd_info *mtd, struct nand_chip *chip, * @param mtd mtd info structure * @param chip nand chip info structure * @param page page number to read - * @param sndcmd flag whether to issue read command or not - * @return 1 - issue read command next time - * 0 - not to issue */ static int nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip, - int page, int sndcmd) + int page) { - if (sndcmd) { - chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); - sndcmd = 0; - } + chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); nand_rw_oob(mtd, chip, page, 0, 0); - return sndcmd; + return 0; } /** @@ -1018,6 +1014,7 @@ int tegra_nand_init(struct nand_chip *nand, int devnum) nand->ecc.write_page_raw = nand_write_page_raw; nand->ecc.read_oob = nand_read_oob; nand->ecc.write_oob = nand_write_oob; + nand->ecc.strength = 1; nand->select_chip = nand_select_chip; nand->dev_ready = nand_dev_ready; nand->priv = &nand_ctrl; diff --git a/drivers/mtd/nand/tegra_nand.h b/drivers/mtd/nand/tegra_nand.h index 7e74be7..622b869 100644 --- a/drivers/mtd/nand/tegra_nand.h +++ b/drivers/mtd/nand/tegra_nand.h @@ -224,7 +224,7 @@ enum { #define BCH_DEC_STATUS_MAX_CORR_CNT_MASK (0x1f << 8) #define BCH_DEC_STATUS_PAGE_NUMBER_MASK 0xFF -#define LP_OPTIONS (NAND_NO_READRDY | NAND_NO_AUTOINCR) +#define LP_OPTIONS 0 struct nand_ctlr { u32 command; /* offset 00h */ diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 858e322..ddfe7e7 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -743,7 +743,7 @@ static void onenand_release_device(struct mtd_info *mtd) } /** - * onenand_transfer_auto_oob - [Internal] oob auto-placement transfer + * onenand_transfer_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param buf destination address * @param column oob offset to read from @@ -807,7 +807,7 @@ static int onenand_recover_lsb(struct mtd_info *mtd, loff_t addr, int status) return status; /* check if we failed due to uncorrectable error */ - if (status != -EBADMSG && status != ONENAND_BBT_READ_ECC_ERROR) + if (!mtd_is_eccerr(status) && status != ONENAND_BBT_READ_ECC_ERROR) return status; /* check if address lies in MLC region */ @@ -847,7 +847,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_read_ops_nolock: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -914,7 +914,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, thisooblen = oobsize - oobcolumn; thisooblen = min_t(int, thisooblen, ooblen - oobread); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, oobbuf, oobcolumn, thisooblen); else this->read_bufferram(mtd, 0, ONENAND_SPARERAM, oobbuf, oobcolumn, thisooblen); @@ -929,7 +929,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, if (unlikely(ret)) ret = onenand_recover_lsb(mtd, from, ret); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } @@ -950,7 +950,7 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from, /* Now wait for load */ ret = this->wait(mtd, FL_READING); onenand_update_bufferram(mtd, from, !ret); - if (ret == -EBADMSG) + if (mtd_is_eccerr(ret)) ret = 0; } } @@ -987,7 +987,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, struct mtd_ecc_stats stats; int read = 0, thislen, column, oobsize; size_t len = ops->ooblen; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; u_char *buf = ops->oobbuf; int ret = 0, readcmd; @@ -998,7 +998,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, /* Initialize return length value */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1041,7 +1041,7 @@ static int onenand_read_oob_nolock(struct mtd_info *mtd, loff_t from, break; } - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_transfer_auto_oob(mtd, buf, column, thislen); else this->read_bufferram(mtd, 0, ONENAND_SPARERAM, buf, column, thislen); @@ -1115,10 +1115,10 @@ int onenand_read_oob(struct mtd_info *mtd, loff_t from, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -1337,7 +1337,7 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr, #define NOTALIGNED(x) ((x & (this->subpagesize - 1)) != 0) /** - * onenand_fill_auto_oob - [Internal] oob auto-placement transfer + * onenand_fill_auto_oob - [INTERN] oob auto-placement transfer * @param mtd MTD device structure * @param oob_buf oob buffer * @param buf source address @@ -1404,19 +1404,13 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, ops->retlen = 0; ops->oobretlen = 0; - /* Do not allow writes past end of device */ - if (unlikely((to + len) > mtd->size)) { - printk(KERN_ERR "onenand_write_ops_nolock: Attempt write to past end of device\n"); - return -EINVAL; - } - /* Reject writes, which are not page aligned */ if (unlikely(NOTALIGNED(to) || NOTALIGNED(len))) { printk(KERN_ERR "onenand_write_ops_nolock: Attempt to write not page aligned data\n"); return -EINVAL; } - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1450,7 +1444,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (ops->mode == MTD_OOB_AUTO) + if (ops->mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, oob, oobcolumn, thisooblen); else memcpy(oobbuf + oobcolumn, oob, thisooblen); @@ -1502,7 +1496,7 @@ static int onenand_write_ops_nolock(struct mtd_info *mtd, loff_t to, } /** - * onenand_write_oob_nolock - [Internal] OneNAND write out-of-band + * onenand_write_oob_nolock - [INTERN] OneNAND write out-of-band * @param mtd MTD device structure * @param to offset to write to * @param len number of bytes to write @@ -1521,7 +1515,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, u_char *oobbuf; size_t len = ops->ooblen; const u_char *buf = ops->oobbuf; - mtd_oob_mode_t mode = ops->mode; + unsigned int mode = ops->mode; to += ops->ooboffs; @@ -1530,7 +1524,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, /* Initialize retlen, in case of early exit */ ops->oobretlen = 0; - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) oobsize = this->ecclayout->oobavail; else oobsize = mtd->oobsize; @@ -1571,7 +1565,7 @@ static int onenand_write_oob_nolock(struct mtd_info *mtd, loff_t to, /* We send data to spare ram with oobsize * to prevent byte access */ memset(oobbuf, 0xff, mtd->oobsize); - if (mode == MTD_OOB_AUTO) + if (mode == MTD_OPS_AUTO_OOB) onenand_fill_auto_oob(mtd, oobbuf, buf, column, thislen); else memcpy(oobbuf + column, buf, thislen); @@ -1661,10 +1655,10 @@ int onenand_write_oob(struct mtd_info *mtd, loff_t to, int ret; switch (ops->mode) { - case MTD_OOB_PLACE: - case MTD_OOB_AUTO: + case MTD_OPS_PLACE_OOB: + case MTD_OPS_AUTO_OOB: break; - case MTD_OOB_RAW: + case MTD_OPS_RAW: /* Not implemented yet */ default: return -EINVAL; @@ -1720,13 +1714,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) MTDDEBUG(MTD_DEBUG_LEVEL3, "onenand_erase: start = 0x%08x, len = %i\n", (unsigned int) addr, len); - /* Do not allow erase past end of device */ - if (unlikely((len + addr) > mtd->size)) { - MTDDEBUG(MTD_DEBUG_LEVEL0, "onenand_erase:" - "Erase past end of device\n"); - return -EINVAL; - } - if (FLEXONENAND(this)) { /* Find the eraseregion of this address */ i = flexonenand_region(mtd, addr); @@ -1762,8 +1749,6 @@ int onenand_erase(struct mtd_info *mtd, struct erase_info *instr) return -EINVAL; } - instr->fail_addr = 0xffffffff; - /* Grab the lock and see if the device is available */ onenand_get_device(mtd, FL_ERASING); @@ -1889,7 +1874,7 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) struct bbm_info *bbm = this->bbm; u_char buf[2] = {0, 0}; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooblen = 2, .oobbuf = buf, .ooboffs = 0, @@ -1915,7 +1900,6 @@ static int onenand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) */ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) { - struct onenand_chip *this = mtd->priv; int ret; ret = onenand_block_isbad(mtd, ofs); @@ -1926,7 +1910,7 @@ int onenand_block_markbad(struct mtd_info *mtd, loff_t ofs) return ret; } - ret = this->block_markbad(mtd, ofs); + ret = mtd_block_markbad(mtd, ofs); return ret; } @@ -2386,7 +2370,7 @@ static int flexonenand_check_blocks_erased(struct mtd_info *mtd, int i, ret; int block; struct mtd_oob_ops ops = { - .mode = MTD_OOB_PLACE, + .mode = MTD_OPS_PLACE_OOB, .ooboffs = 0, .ooblen = mtd->oobsize, .datbuf = NULL, @@ -2645,14 +2629,14 @@ int onenand_probe(struct mtd_info *mtd) mtd->size = this->chipsize; mtd->flags = MTD_CAP_NANDFLASH; - mtd->erase = onenand_erase; - mtd->read = onenand_read; - mtd->write = onenand_write; - mtd->read_oob = onenand_read_oob; - mtd->write_oob = onenand_write_oob; - mtd->sync = onenand_sync; - mtd->block_isbad = onenand_block_isbad; - mtd->block_markbad = onenand_block_markbad; + mtd->_erase = onenand_erase; + mtd->_read = onenand_read; + mtd->_write = onenand_write; + mtd->_read_oob = onenand_read_oob; + mtd->_write_oob = onenand_write_oob; + mtd->_sync = onenand_sync; + mtd->_block_isbad = onenand_block_isbad; + mtd->_block_markbad = onenand_block_markbad; return 0; } diff --git a/drivers/mtd/onenand/onenand_bbt.c b/drivers/mtd/onenand/onenand_bbt.c index 9d5da54..0267c2c 100644 --- a/drivers/mtd/onenand/onenand_bbt.c +++ b/drivers/mtd/onenand/onenand_bbt.c @@ -87,7 +87,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t * buf, startblock = 0; from = 0; - ops.mode = MTD_OOB_PLACE; + ops.mode = MTD_OPS_PLACE_OOB; ops.ooblen = readlen; ops.oobbuf = buf; ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0; @@ -200,10 +200,8 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd) len = this->chipsize >> (this->erase_shift + 2); /* Allocate memory (2bit per block) */ bbm->bbt = malloc(len); - if (!bbm->bbt) { - printk(KERN_ERR "onenand_scan_bbt: Out of memory\n"); + if (!bbm->bbt) return -ENOMEM; - } /* Clear the memory bad block table */ memset(bbm->bbt, 0x00, len); diff --git a/drivers/mtd/spi/spansion.c b/drivers/mtd/spi/spansion.c index dad30b5..3ec2151 100644 --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@ -90,18 +90,32 @@ static const struct spansion_spi_flash_params spansion_spi_flash_table[] = { .name = "S25FL032P", }, { + .idcode1 = 0x0216, + .idcode2 = 0x4d00, + .pages_per_sector = 256, + .nr_sectors = 128, + .name = "S25FL064P", + }, + { .idcode1 = 0x2018, .idcode2 = 0x4d01, .pages_per_sector = 256, .nr_sectors = 256, - .name = "S25FL129P_64K/S25FL128S", + .name = "S25FL129P_64K/S25FL128S_64K", }, { .idcode1 = 0x0219, .idcode2 = 0x4d01, .pages_per_sector = 256, .nr_sectors = 512, - .name = "S25FL256S", + .name = "S25FL256S_64K", + }, + { + .idcode1 = 0x0220, + .idcode2 = 0x4d01, + .pages_per_sector = 256, + .nr_sectors = 1024, + .name = "S25FL512S_64K", }, }; diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c index 6507aa3..6a6fe37 100644 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -68,17 +68,60 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len); } -int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, - size_t len, const void *buf) +int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) { - unsigned long page_addr, byte_addr, page_size; - size_t chunk_len, actual; + struct spi_slave *spi = flash->spi; + unsigned long timebase; int ret; - u8 cmd[4]; + u8 status; + u8 check_status = 0x0; + u8 poll_bit = STATUS_WIP; + u8 cmd = flash->poll_cmd; - page_size = flash->page_size; - page_addr = offset / page_size; - byte_addr = offset % page_size; + if (cmd == CMD_FLAG_STATUS) { + poll_bit = STATUS_PEC; + check_status = poll_bit; + } + + ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); + if (ret) { + debug("SF: fail to read %s status register\n", + cmd == CMD_READ_STATUS ? "read" : "flag"); + return ret; + } + + timebase = get_timer(0); + do { + WATCHDOG_RESET(); + + ret = spi_xfer(spi, 8, NULL, &status, 0); + if (ret) + return -1; + + if ((status & poll_bit) == check_status) + break; + + } while (get_timer(timebase) < timeout); + + spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); + + if ((status & poll_bit) == check_status) + return 0; + + /* Timed out */ + debug("SF: time out!\n"); + return -1; +} + +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, const void *buf, size_t buf_len) +{ + struct spi_slave *spi = flash->spi; + unsigned long timeout = SPI_FLASH_PROG_TIMEOUT; + int ret; + + if (buf == NULL) + timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT; ret = spi_claim_bus(flash->spi); if (ret) { @@ -86,48 +129,122 @@ int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, return ret; } + ret = spi_flash_cmd_write_enable(flash); + if (ret < 0) { + debug("SF: enabling write failed\n"); + return ret; + } + + ret = spi_flash_cmd_write(spi, cmd, cmd_len, buf, buf_len); + if (ret < 0) { + debug("SF: write cmd failed\n"); + return ret; + } + + ret = spi_flash_cmd_wait_ready(flash, timeout); + if (ret < 0) { + debug("SF: write %s timed out\n", + timeout == SPI_FLASH_PROG_TIMEOUT ? + "program" : "page erase"); + return ret; + } + + spi_release_bus(spi); + + return ret; +} + +int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +{ + u32 erase_size; + u8 cmd[4]; + int ret = -1; + + erase_size = flash->sector_size; + if (offset % erase_size || len % erase_size) { + debug("SF: Erase offset/length not multiple of erase size\n"); + return -1; + } + + if (erase_size == 4096) + cmd[0] = CMD_ERASE_4K; + else + cmd[0] = CMD_ERASE_64K; + + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + spi_flash_addr(offset, cmd); + + debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], + cmd[2], cmd[3], offset); + + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0); + if (ret < 0) { + debug("SF: erase failed\n"); + break; + } + + offset += erase_size; + len -= erase_size; + } + + return ret; +} + +int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset, + size_t len, const void *buf) +{ + unsigned long byte_addr, page_size; + size_t chunk_len, actual; + u8 cmd[4]; + int ret = -1; + + page_size = flash->page_size; + cmd[0] = CMD_PAGE_PROGRAM; for (actual = 0; actual < len; actual += chunk_len) { +#ifdef CONFIG_SPI_FLASH_BAR + u8 bank_sel; + + bank_sel = offset / SPI_FLASH_16MB_BOUN; + + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + byte_addr = offset % page_size; chunk_len = min(len - actual, page_size - byte_addr); if (flash->spi->max_write_size) chunk_len = min(chunk_len, flash->spi->max_write_size); - cmd[1] = page_addr >> 8; - cmd[2] = page_addr; - cmd[3] = byte_addr; + spi_flash_addr(offset, cmd); debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n", buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len); - ret = spi_flash_cmd_write_enable(flash); - if (ret < 0) { - debug("SF: enabling write failed\n"); - break; - } - - ret = spi_flash_cmd_write(flash->spi, cmd, 4, - buf + actual, chunk_len); + ret = spi_flash_write_common(flash, cmd, sizeof(cmd), + buf + actual, chunk_len); if (ret < 0) { debug("SF: write failed\n"); break; } - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret) - break; - - byte_addr += chunk_len; - if (byte_addr == page_size) { - page_addr++; - byte_addr = 0; - } + offset += chunk_len; } - debug("SF: program %s %zu bytes @ %#x\n", - ret ? "failure" : "success", len, offset); - - spi_release_bus(flash->spi); return ret; } @@ -137,8 +254,18 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, struct spi_slave *spi = flash->spi; int ret; - spi_claim_bus(spi); + ret = spi_claim_bus(flash->spi); + if (ret) { + debug("SF: unable to claim SPI bus\n"); + return ret; + } + ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len); + if (ret < 0) { + debug("SF: read cmd failed\n"); + return ret; + } + spi_release_bus(spi); return ret; @@ -147,140 +274,125 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset, size_t len, void *data) { - u8 cmd[5]; + u8 cmd[5], bank_sel = 0; + u32 remain_len, read_len; + int ret = -1; /* Handle memory-mapped SPI */ - if (flash->memory_map) + if (flash->memory_map) { memcpy(data, flash->memory_map + offset, len); + return 0; + } cmd[0] = CMD_READ_ARRAY_FAST; - spi_flash_addr(offset, cmd); cmd[4] = 0x00; - return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len); -} - -int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, - u8 cmd, u8 poll_bit) -{ - struct spi_slave *spi = flash->spi; - unsigned long timebase; - int ret; - u8 status; + while (len) { +#ifdef CONFIG_SPI_FLASH_BAR + bank_sel = offset / SPI_FLASH_16MB_BOUN; - ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN); - if (ret) { - debug("SF: Failed to send command %02x: %d\n", cmd, ret); - return ret; - } - - timebase = get_timer(0); - do { - WATCHDOG_RESET(); + ret = spi_flash_cmd_bankaddr_write(flash, bank_sel); + if (ret) { + debug("SF: fail to set bank%d\n", bank_sel); + return ret; + } +#endif + remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1) - offset); + if (len < remain_len) + read_len = len; + else + read_len = remain_len; - ret = spi_xfer(spi, 8, NULL, &status, 0); - if (ret) - return -1; + spi_flash_addr(offset, cmd); - if ((status & poll_bit) == 0) + ret = spi_flash_read_common(flash, cmd, sizeof(cmd), + data, read_len); + if (ret < 0) { + debug("SF: read failed\n"); break; + } - } while (get_timer(timebase) < timeout); - - spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END); - - if ((status & poll_bit) == 0) - return 0; - - /* Timed out */ - debug("SF: time out!\n"); - return -1; -} + offset += read_len; + len -= read_len; + data += read_len; + } -int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout) -{ - return spi_flash_cmd_poll_bit(flash, timeout, - CMD_READ_STATUS, STATUS_WIP); + return ret; } -int spi_flash_cmd_erase(struct spi_flash *flash, u32 offset, size_t len) +int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) { - u32 start, end, erase_size; + u8 cmd; int ret; - u8 cmd[4]; - - erase_size = flash->sector_size; - if (offset % erase_size || len % erase_size) { - debug("SF: Erase offset/length not multiple of erase size\n"); - return -1; - } - ret = spi_claim_bus(flash->spi); - if (ret) { - debug("SF: Unable to claim SPI bus\n"); + cmd = CMD_WRITE_STATUS; + ret = spi_flash_write_common(flash, &cmd, 1, &sr, 1); + if (ret < 0) { + debug("SF: fail to write status register\n"); return ret; } - if (erase_size == 4096) - cmd[0] = CMD_ERASE_4K; - else - cmd[0] = CMD_ERASE_64K; - start = offset; - end = start + len; - - while (offset < end) { - spi_flash_addr(offset, cmd); - offset += erase_size; - - debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1], - cmd[2], cmd[3], offset); - - ret = spi_flash_cmd_write_enable(flash); - if (ret) - goto out; - - ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0); - if (ret) - goto out; - - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT); - if (ret) - goto out; - } - - debug("SF: Successfully erased %zu bytes @ %#x\n", len, start); - - out: - spi_release_bus(flash->spi); - return ret; + return 0; } -int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr) +#ifdef CONFIG_SPI_FLASH_BAR +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel) { u8 cmd; int ret; - ret = spi_flash_cmd_write_enable(flash); + if (flash->bank_curr == bank_sel) { + debug("SF: not require to enable bank%d\n", bank_sel); + return 0; + } + + cmd = flash->bank_write_cmd; + ret = spi_flash_write_common(flash, &cmd, 1, &bank_sel, 1); if (ret < 0) { - debug("SF: enabling write failed\n"); + debug("SF: fail to write bank register\n"); return ret; } + flash->bank_curr = bank_sel; - cmd = CMD_WRITE_STATUS; - ret = spi_flash_cmd_write(flash->spi, &cmd, 1, &sr, 1); - if (ret) { - debug("SF: fail to write status register\n"); - return ret; + return 0; +} + +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0) +{ + u8 cmd; + u8 curr_bank = 0; + + /* discover bank cmds */ + switch (idcode0) { + case SPI_FLASH_SPANSION_IDCODE0: + flash->bank_read_cmd = CMD_BANKADDR_BRRD; + flash->bank_write_cmd = CMD_BANKADDR_BRWR; + break; + case SPI_FLASH_STMICRO_IDCODE0: + case SPI_FLASH_WINBOND_IDCODE0: + flash->bank_read_cmd = CMD_EXTNADDR_RDEAR; + flash->bank_write_cmd = CMD_EXTNADDR_WREAR; + break; + default: + printf("SF: Unsupported bank commands %02x\n", idcode0); + return -1; } - ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT); - if (ret < 0) { - debug("SF: write status register timed out\n"); - return ret; + /* read the bank reg - on which bank the flash is in currently */ + cmd = flash->bank_read_cmd; + if (flash->size > SPI_FLASH_16MB_BOUN) { + if (spi_flash_read_common(flash, &cmd, 1, &curr_bank, 1)) { + debug("SF: fail to read bank addr register\n"); + return -1; + } + flash->bank_curr = curr_bank; + } else { + flash->bank_curr = curr_bank; } return 0; } +#endif #ifdef CONFIG_OF_CONTROL int spi_flash_decode_fdt(const void *blob, struct spi_flash *flash) @@ -429,6 +541,13 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, goto err_manufacturer_probe; } +#ifdef CONFIG_SPI_FLASH_BAR + /* Configure the BAR - disover bank cmds and read current bank */ + ret = spi_flash_bank_config(flash, *idp); + if (ret < 0) + goto err_manufacturer_probe; +#endif + #ifdef CONFIG_OF_CONTROL if (spi_flash_decode_fdt(gd->fdt_blob, flash)) { debug("SF: FDT decode error\n"); @@ -441,6 +560,12 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, if (flash->memory_map) printf(", mapped at %p", flash->memory_map); puts("\n"); +#ifndef CONFIG_SPI_FLASH_BAR + if (flash->size > SPI_FLASH_16MB_BOUN) { + puts("SF: Warning - Only lower 16MiB accessible,"); + puts(" Full access #define CONFIG_SPI_FLASH_BAR\n"); + } +#endif spi_release_bus(spi); @@ -471,6 +596,7 @@ void *spi_flash_do_alloc(int offset, int size, struct spi_slave *spi, /* Set up some basic fields - caller will sort out sizes */ flash->spi = spi; flash->name = name; + flash->poll_cmd = CMD_READ_STATUS; flash->read = spi_flash_cmd_read_fast; flash->write = spi_flash_cmd_write_multi; diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h index e0afbc3..af1afa9 100644 --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -22,14 +22,31 @@ #define CMD_PAGE_PROGRAM 0x02 #define CMD_WRITE_DISABLE 0x04 #define CMD_READ_STATUS 0x05 +#define CMD_FLAG_STATUS 0x70 #define CMD_WRITE_ENABLE 0x06 #define CMD_ERASE_4K 0x20 #define CMD_ERASE_32K 0x52 #define CMD_ERASE_64K 0xd8 #define CMD_ERASE_CHIP 0xc7 +#define SPI_FLASH_16MB_BOUN 0x1000000 + +/* Manufacture ID's */ +#define SPI_FLASH_SPANSION_IDCODE0 0x01 +#define SPI_FLASH_STMICRO_IDCODE0 0x20 +#define SPI_FLASH_WINBOND_IDCODE0 0xef + +#ifdef CONFIG_SPI_FLASH_BAR +/* Bank addr access commands */ +# define CMD_BANKADDR_BRWR 0x17 +# define CMD_BANKADDR_BRRD 0x16 +# define CMD_EXTNADDR_WREAR 0xC5 +# define CMD_EXTNADDR_RDEAR 0xC8 +#endif + /* Common status */ #define STATUS_WIP 0x01 +#define STATUS_PEC 0x80 /* Send a single-byte command to the device and read the response */ int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len); @@ -77,16 +94,30 @@ static inline int spi_flash_cmd_write_disable(struct spi_flash *flash) /* Program the status register. */ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr); +#ifdef CONFIG_SPI_FLASH_BAR +/* Program the bank address register */ +int spi_flash_cmd_bankaddr_write(struct spi_flash *flash, u8 bank_sel); + +/* Configure the BAR - discover the bank cmds */ +int spi_flash_bank_config(struct spi_flash *flash, u8 idcode0); +#endif + /* * Same as spi_flash_cmd_read() except it also claims/releases the SPI * bus. Used as common part of the ->read() operation. */ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, void *data, size_t data_len); - -/* Send a command to the device and wait for some bit to clear itself. */ -int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout, - u8 cmd, u8 poll_bit); +/* + * Used for spi_flash write operation + * - SPI claim + * - spi_flash_cmd_write_enable + * - spi_flash_cmd_write + * - spi_flash_cmd_wait_ready + * - SPI release + */ +int spi_flash_write_common(struct spi_flash *flash, const u8 *cmd, + size_t cmd_len, const void *buf, size_t buf_len); /* * Send the read status command to the device and wait for the wip diff --git a/drivers/mtd/spi/stmicro.c b/drivers/mtd/spi/stmicro.c index 2a9972b..7e41ee1 100644 --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@ -140,6 +140,30 @@ static const struct stmicro_spi_flash_params stmicro_spi_flash_table[] = { .nr_sectors = 512, .name = "N25Q256A", }, + { + .id = 0xba20, + .pages_per_sector = 256, + .nr_sectors = 1024, + .name = "N25Q512", + }, + { + .id = 0xbb20, + .pages_per_sector = 256, + .nr_sectors = 1024, + .name = "N25Q512A", + }, + { + .id = 0xba21, + .pages_per_sector = 256, + .nr_sectors = 2048, + .name = "N25Q1024", + }, + { + .id = 0xbb21, + .pages_per_sector = 256, + .nr_sectors = 2048, + .name = "N25Q1024A", + }, }; struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) @@ -186,5 +210,9 @@ struct spi_flash *spi_flash_probe_stmicro(struct spi_slave *spi, u8 * idcode) flash->sector_size = 256 * params->pages_per_sector; flash->size = flash->sector_size * params->nr_sectors; + /* for >= 512MiB flashes, use flag status instead of read_status */ + if (flash->size >= 0x4000000) + flash->poll_cmd = CMD_FLAG_STATUS; + return flash; } diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c index 2716209..c399bf1 100644 --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@ -18,6 +18,21 @@ struct winbond_spi_flash_params { static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { { + .id = 0x2014, + .nr_blocks = 16, + .name = "W25P80", + }, + { + .id = 0x2015, + .nr_blocks = 32, + .name = "W25P16", + }, + { + .id = 0x2016, + .nr_blocks = 64, + .name = "W25P32", + }, + { .id = 0x3013, .nr_blocks = 8, .name = "W25X40", @@ -40,42 +55,57 @@ static const struct winbond_spi_flash_params winbond_spi_flash_table[] = { { .id = 0x4014, .nr_blocks = 16, - .name = "W25Q80BL", + .name = "W25Q80BL/W25Q80BV", }, { .id = 0x4015, .nr_blocks = 32, - .name = "W25Q16", + .name = "W25Q16CL/W25Q16DV", }, { .id = 0x4016, .nr_blocks = 64, - .name = "W25Q32", + .name = "W25Q32BV/W25Q32FV_SPI", }, { .id = 0x4017, .nr_blocks = 128, - .name = "W25Q64", + .name = "W25Q64CV/W25Q64FV_SPI", }, { .id = 0x4018, .nr_blocks = 256, - .name = "W25Q128", + .name = "W25Q128BV/W25Q128FV_SPI", + }, + { + .id = 0x4019, + .nr_blocks = 512, + .name = "W25Q256", }, { .id = 0x5014, - .nr_blocks = 128, - .name = "W25Q80", + .nr_blocks = 16, + .name = "W25Q80BW", + }, + { + .id = 0x6015, + .nr_blocks = 32, + .name = "W25Q16DW", }, { .id = 0x6016, - .nr_blocks = 512, - .name = "W25Q32DW", + .nr_blocks = 64, + .name = "W25Q32DW/W25Q32FV_QPI", }, { .id = 0x6017, .nr_blocks = 128, - .name = "W25Q64DW", + .name = "W25Q64DW/W25Q64FV_QPI", + }, + { + .id = 0x6018, + .nr_blocks = 256, + .name = "W25Q128FW/W25Q128FV_QPI", }, }; @@ -104,7 +134,7 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode) } flash->page_size = 256; - flash->sector_size = 4096; + flash->sector_size = (idcode[1] == 0x20) ? 65536 : 4096; flash->size = 4096 * 16 * params->nr_blocks; return flash; diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index a708162..2588822 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -539,7 +539,7 @@ static int io_init(struct ubi_device *ubi) ubi->peb_count = mtd_div_by_eb(ubi->mtd->size, ubi->mtd); ubi->flash_size = ubi->mtd->size; - if (ubi->mtd->block_isbad && ubi->mtd->block_markbad) + if (mtd_can_have_bb(ubi->mtd)) ubi->bad_allowed = 1; ubi->min_io_size = ubi->mtd->writesize; diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c index d523c94..d2d3c9c 100644 --- a/drivers/mtd/ubi/eba.c +++ b/drivers/mtd/ubi/eba.c @@ -460,7 +460,7 @@ retry: if (err == UBI_IO_BITFLIPS) { scrub = 1; err = 0; - } else if (err == -EBADMSG) { + } else if (mtd_is_eccerr(err)) { if (vol->vol_type == UBI_DYNAMIC_VOLUME) goto out_unlock; scrub = 1; diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c index 8423894..05de9ae 100644 --- a/drivers/mtd/ubi/io.c +++ b/drivers/mtd/ubi/io.c @@ -154,7 +154,7 @@ int ubi_io_read(const struct ubi_device *ubi, void *buf, int pnum, int offset, addr = (loff_t)pnum * ubi->peb_size + offset; retry: - err = ubi->mtd->read(ubi->mtd, addr, len, &read, buf); + err = mtd_read(ubi->mtd, addr, len, &read, buf); if (err) { if (err == -EUCLEAN) { /* @@ -268,7 +268,7 @@ int ubi_io_write(struct ubi_device *ubi, const void *buf, int pnum, int offset, } addr = (loff_t)pnum * ubi->peb_size + offset; - err = ubi->mtd->write(ubi->mtd, addr, len, &written, buf); + err = mtd_write(ubi->mtd, addr, len, &written, buf); if (err) { ubi_err("error %d while writing %d bytes to PEB %d:%d, written" " %zd bytes", err, len, pnum, offset, written); @@ -318,7 +318,7 @@ retry: ei.callback = erase_callback; ei.priv = (unsigned long)&wq; - err = ubi->mtd->erase(ubi->mtd, &ei); + err = mtd_erase(ubi->mtd, &ei); if (err) { if (retries++ < UBI_IO_RETRIES) { dbg_io("error %d while erasing PEB %d, retry", @@ -516,7 +516,7 @@ int ubi_io_is_bad(const struct ubi_device *ubi, int pnum) if (ubi->bad_allowed) { int ret; - ret = mtd->block_isbad(mtd, (loff_t)pnum * ubi->peb_size); + ret = mtd_block_isbad(mtd, (loff_t)pnum * ubi->peb_size); if (ret < 0) ubi_err("error %d while checking if PEB %d is bad", ret, pnum); @@ -551,7 +551,7 @@ int ubi_io_mark_bad(const struct ubi_device *ubi, int pnum) if (!ubi->bad_allowed) return 0; - err = mtd->block_markbad(mtd, (loff_t)pnum * ubi->peb_size); + err = mtd_block_markbad(mtd, (loff_t)pnum * ubi->peb_size); if (err) ubi_err("cannot mark PEB %d bad, error %d", pnum, err); return err; @@ -1242,7 +1242,7 @@ static int paranoid_check_all_ff(struct ubi_device *ubi, int pnum, int offset, loff_t addr = (loff_t)pnum * ubi->peb_size + offset; mutex_lock(&ubi->dbg_buf_mutex); - err = ubi->mtd->read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); + err = mtd_read(ubi->mtd, addr, len, &read, ubi->dbg_peb_buf); if (err && err != -EUCLEAN) { ubi_err("error %d while reading %d bytes from PEB %d:%d, " "read %zd bytes", err, len, pnum, offset, read); diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index 423d479..e553188 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -349,7 +349,7 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset, return 0; err = ubi_eba_read_leb(ubi, vol, lnum, buf, offset, len, check); - if (err && err == -EBADMSG && vol->vol_type == UBI_STATIC_VOLUME) { + if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) { ubi_warn("mark volume %d as corrupted", vol_id); vol->corrupted = 1; } diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c index a6410bf..e8660d9 100644 --- a/drivers/mtd/ubi/misc.c +++ b/drivers/mtd/ubi/misc.c @@ -82,7 +82,7 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id) err = ubi_eba_read_leb(ubi, vol, i, buf, 0, size, 1); if (err) { - if (err == -EBADMSG) + if (mtd_is_eccerr(err)) err = 1; break; } diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index f679f06..29d2320 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -388,7 +388,7 @@ static struct ubi_vtbl_record *process_lvol(struct ubi_device *ubi, err = ubi_io_read_data(ubi, leb[seb->lnum], seb->pnum, 0, ubi->vtbl_size); - if (err == UBI_IO_BITFLIPS || err == -EBADMSG) + if (err == UBI_IO_BITFLIPS || mtd_is_eccerr(err)) /* * Scrub the PEB later. Note, -EBADMSG indicates an * uncorrectable ECC error, but we have our own CRC and diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 786a656..9cf2983 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -46,10 +46,12 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o +COBJS-$(CONFIG_FTMAC110) += ftmac110.o COBJS-$(CONFIG_FTMAC100) += ftmac100.o COBJS-$(CONFIG_GRETH) += greth.o COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o +COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o COBJS-$(CONFIG_LAN91C96) += lan91c96.o COBJS-$(CONFIG_MACB) += macb.o COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o @@ -68,6 +70,7 @@ COBJS-$(CONFIG_RTL8169) += rtl8169.o COBJS-$(CONFIG_SH_ETHER) += sh_eth.o COBJS-$(CONFIG_SMC91111) += smc91111.o COBJS-$(CONFIG_SMC911X) += smc911x.o +COBJS-$(CONFIG_SUNXI_WEMAC) += sunxi_wemac.o COBJS-$(CONFIG_DRIVER_TI_EMAC) += davinci_emac.o COBJS-$(CONFIG_TSEC_ENET) += tsec.o fsl_mdio.o COBJS-$(CONFIG_DRIVER_TI_CPSW) += cpsw.o diff --git a/drivers/net/designware.c b/drivers/net/designware.c index bf21a08..46f6601 100644 --- a/drivers/net/designware.c +++ b/drivers/net/designware.c @@ -113,7 +113,9 @@ static int mac_reset(struct eth_device *dev) int timeout = CONFIG_MACRESET_TIMEOUT; writel(DMAMAC_SRST, &dma_p->busmode); - writel(MII_PORTSELECT, &mac_p->conf); + + if (priv->interface != PHY_INTERFACE_MODE_RGMII) + writel(MII_PORTSELECT, &mac_p->conf); start = get_timer(0); while (get_timer(start) < timeout) { diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c index 69ba57d..2dbb328 100644 --- a/drivers/net/ftgmac100.c +++ b/drivers/net/ftgmac100.c @@ -27,11 +27,13 @@ #include <malloc.h> #include <net.h> #include <asm/io.h> +#include <asm/dma-mapping.h> #include <linux/mii.h> #include "ftgmac100.h" #define ETH_ZLEN 60 +#define CFG_XBUF_SIZE 1536 /* RBSR - hw default init value is also 0x640 */ #define RBSR_DEFAULT_VALUE 0x640 @@ -40,8 +42,10 @@ #define PKTBUFSTX 4 /* must be power of 2 */ struct ftgmac100_data { - struct ftgmac100_txdes txdes[PKTBUFSTX]; - struct ftgmac100_rxdes rxdes[PKTBUFSRX]; + ulong txdes_dma; + struct ftgmac100_txdes *txdes; + ulong rxdes_dma; + struct ftgmac100_rxdes *rxdes; int tx_index; int rx_index; int phy_addr; @@ -375,13 +379,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd) { struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; struct ftgmac100_data *priv = dev->priv; - struct ftgmac100_txdes *txdes = priv->txdes; - struct ftgmac100_rxdes *rxdes = priv->rxdes; + struct ftgmac100_txdes *txdes; + struct ftgmac100_rxdes *rxdes; unsigned int maccr; + void *buf; int i; debug("%s()\n", __func__); + if (!priv->txdes) { + txdes = dma_alloc_coherent( + sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma); + if (!txdes) + panic("ftgmac100: out of memory\n"); + memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX); + priv->txdes = txdes; + } + txdes = priv->txdes; + + if (!priv->rxdes) { + rxdes = dma_alloc_coherent( + sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma); + if (!rxdes) + panic("ftgmac100: out of memory\n"); + memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX); + priv->rxdes = rxdes; + } + rxdes = priv->rxdes; + /* set the ethernet address */ ftgmac100_set_mac_from_env(dev); @@ -397,21 +422,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd) for (i = 0; i < PKTBUFSTX; i++) { /* TXBUF_BADR */ - txdes[i].txdes3 = 0; + if (!txdes[i].txdes2) { + buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE); + if (!buf) + panic("ftgmac100: out of memory\n"); + txdes[i].txdes3 = virt_to_phys(buf); + txdes[i].txdes2 = (uint)buf; + } txdes[i].txdes1 = 0; } for (i = 0; i < PKTBUFSRX; i++) { /* RXBUF_BADR */ - rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i]; + if (!rxdes[i].rxdes2) { + buf = NetRxPackets[i]; + rxdes[i].rxdes3 = virt_to_phys(buf); + rxdes[i].rxdes2 = (uint)buf; + } rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; } /* transmit ring */ - writel((unsigned int)txdes, &ftgmac100->txr_badr); + writel(priv->txdes_dma, &ftgmac100->txr_badr); /* receive ring */ - writel((unsigned int)rxdes, &ftgmac100->rxr_badr); + writel(priv->rxdes_dma, &ftgmac100->rxr_badr); /* poll receive descriptor automatically */ writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc); @@ -466,8 +501,11 @@ static int ftgmac100_recv(struct eth_device *dev) debug("%s(): RX buffer %d, %x received\n", __func__, priv->rx_index, rxlen); + /* invalidate d-cache */ + dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE); + /* pass the packet up to the protocol layers. */ - NetReceive((void *)curr_des->rxdes3, rxlen); + NetReceive((void *)curr_des->rxdes2, rxlen); /* release buffer to DMA */ curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY; @@ -485,7 +523,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length) struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase; struct ftgmac100_data *priv = dev->priv; struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index]; - int start; if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { debug("%s(): no TX descriptor available\n", __func__); @@ -496,8 +533,8 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length) length = (length < ETH_ZLEN) ? ETH_ZLEN : length; - /* initiate a transmit sequence */ - curr_des->txdes3 = (unsigned int)packet; /* TXBUF_BADR */ + memcpy((void *)curr_des->txdes2, (void *)packet, length); + dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE); /* only one descriptor on TXBUF */ curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR; @@ -509,15 +546,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length) /* start transmit */ writel(1, &ftgmac100->txpd); - /* wait for transfer to succeed */ - start = get_timer(0); - while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) { - if (get_timer(0) >= 5) { - debug("%s(): timed out\n", __func__); - return -1; - } - } - debug("%s(): packet sent\n", __func__); priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX; diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c new file mode 100644 index 0000000..579dcc7 --- /dev/null +++ b/drivers/net/ftmac110.c @@ -0,0 +1,473 @@ +/* + * Faraday 10/100Mbps Ethernet Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <net.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/dma-mapping.h> + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#include <miiphy.h> +#endif + +#include "ftmac110.h" + +#define CFG_RXDES_NUM 8 +#define CFG_TXDES_NUM 2 +#define CFG_XBUF_SIZE 1536 + +#define CFG_MDIORD_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */ +#define CFG_MDIOWR_TIMEOUT (CONFIG_SYS_HZ >> 1) /* 500 ms */ +#define CFG_LINKUP_TIMEOUT (CONFIG_SYS_HZ << 2) /* 4 sec */ + +/* + * FTMAC110 DMA design issue + * + * Its DMA engine has a weird restriction that its Rx DMA engine + * accepts only 16-bits aligned address, 32-bits aligned is not + * acceptable. However this restriction does not apply to Tx DMA. + * + * Conclusion: + * (1) Tx DMA Buffer Address: + * 1 bytes aligned: Invalid + * 2 bytes aligned: O.K + * 4 bytes aligned: O.K (-> u-boot ZeroCopy is possible) + * (2) Rx DMA Buffer Address: + * 1 bytes aligned: Invalid + * 2 bytes aligned: O.K + * 4 bytes aligned: Invalid + */ + +struct ftmac110_chip { + void __iomem *regs; + uint32_t imr; + uint32_t maccr; + uint32_t lnkup; + uint32_t phy_addr; + + struct ftmac110_rxd *rxd; + ulong rxd_dma; + uint32_t rxd_idx; + + struct ftmac110_txd *txd; + ulong txd_dma; + uint32_t txd_idx; +}; + +static int ftmac110_reset(struct eth_device *dev); + +static uint16_t mdio_read(struct eth_device *dev, + uint8_t phyaddr, uint8_t phyreg) +{ + struct ftmac110_chip *chip = dev->priv; + struct ftmac110_regs __iomem *regs = chip->regs; + uint32_t tmp, ts; + uint16_t ret = 0xffff; + + tmp = PHYCR_READ + | (phyaddr << PHYCR_ADDR_SHIFT) + | (phyreg << PHYCR_REG_SHIFT); + + writel(tmp, ®s->phycr); + + for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) { + tmp = readl(®s->phycr); + if (tmp & PHYCR_READ) + continue; + break; + } + + if (tmp & PHYCR_READ) + printf("ftmac110: mdio read timeout\n"); + else + ret = (uint16_t)(tmp & 0xffff); + + return ret; +} + +static void mdio_write(struct eth_device *dev, + uint8_t phyaddr, uint8_t phyreg, uint16_t phydata) +{ + struct ftmac110_chip *chip = dev->priv; + struct ftmac110_regs __iomem *regs = chip->regs; + uint32_t tmp, ts; + + tmp = PHYCR_WRITE + | (phyaddr << PHYCR_ADDR_SHIFT) + | (phyreg << PHYCR_REG_SHIFT); + + writel(phydata, ®s->phydr); + writel(tmp, ®s->phycr); + + for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) { + if (readl(®s->phycr) & PHYCR_WRITE) + continue; + break; + } + + if (readl(®s->phycr) & PHYCR_WRITE) + printf("ftmac110: mdio write timeout\n"); +} + +static uint32_t ftmac110_phyqry(struct eth_device *dev) +{ + ulong ts; + uint32_t maccr; + uint16_t pa, tmp, bmsr, bmcr; + struct ftmac110_chip *chip = dev->priv; + + /* Default = 100Mbps Full */ + maccr = MACCR_100M | MACCR_FD; + + /* 1. find the phy device */ + for (pa = 0; pa < 32; ++pa) { + tmp = mdio_read(dev, pa, MII_PHYSID1); + if (tmp == 0xFFFF || tmp == 0x0000) + continue; + chip->phy_addr = pa; + break; + } + if (pa >= 32) { + puts("ftmac110: phy device not found!\n"); + goto exit; + } + + /* 2. wait until link-up & auto-negotiation complete */ + chip->lnkup = 0; + bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR); + ts = get_timer(0); + do { + bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR); + chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0; + if (!chip->lnkup) + continue; + if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE)) + break; + } while (get_timer(ts) < CFG_LINKUP_TIMEOUT); + if (!chip->lnkup) { + puts("ftmac110: link down\n"); + goto exit; + } + if (!(bmcr & BMCR_ANENABLE)) + puts("ftmac110: auto negotiation disabled\n"); + else if (!(bmsr & BMSR_ANEGCOMPLETE)) + puts("ftmac110: auto negotiation timeout\n"); + + /* 3. derive MACCR */ + if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) { + tmp = mdio_read(dev, chip->phy_addr, MII_ADVERTISE); + tmp &= mdio_read(dev, chip->phy_addr, MII_LPA); + if (tmp & LPA_100FULL) /* 100Mbps full-duplex */ + maccr = MACCR_100M | MACCR_FD; + else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */ + maccr = MACCR_100M; + else if (tmp & LPA_10FULL) /* 10Mbps full-duplex */ + maccr = MACCR_FD; + else if (tmp & LPA_10HALF) /* 10Mbps half-duplex */ + maccr = 0; + } else { + if (bmcr & BMCR_SPEED100) + maccr = MACCR_100M; + else + maccr = 0; + if (bmcr & BMCR_FULLDPLX) + maccr |= MACCR_FD; + } + +exit: + printf("ftmac110: %d Mbps, %s\n", + (maccr & MACCR_100M) ? 100 : 10, + (maccr & MACCR_FD) ? "Full" : "half"); + return maccr; +} + +static int ftmac110_reset(struct eth_device *dev) +{ + uint8_t *a; + uint32_t i, maccr; + struct ftmac110_chip *chip = dev->priv; + struct ftmac110_regs __iomem *regs = chip->regs; + + /* 1. MAC reset */ + writel(MACCR_RESET, ®s->maccr); + for (i = get_timer(0); get_timer(i) < 1000; ) { + if (readl(®s->maccr) & MACCR_RESET) + continue; + break; + } + if (readl(®s->maccr) & MACCR_RESET) { + printf("ftmac110: reset failed\n"); + return -ENXIO; + } + + /* 1-1. Init tx ring */ + for (i = 0; i < CFG_TXDES_NUM; ++i) { + /* owned by SW */ + chip->txd[i].ct[0] = 0; + } + chip->txd_idx = 0; + + /* 1-2. Init rx ring */ + for (i = 0; i < CFG_RXDES_NUM; ++i) { + /* owned by HW */ + chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); + } + chip->rxd_idx = 0; + + /* 2. PHY status query */ + maccr = ftmac110_phyqry(dev); + + /* 3. Fix up the MACCR value */ + chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT + | MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN; + + /* 4. MAC address setup */ + a = dev->enetaddr; + writel(a[1] | (a[0] << 8), ®s->mac[0]); + writel(a[5] | (a[4] << 8) | (a[3] << 16) + | (a[2] << 24), ®s->mac[1]); + + /* 5. MAC registers setup */ + writel(chip->rxd_dma, ®s->rxba); + writel(chip->txd_dma, ®s->txba); + /* interrupt at each tx/rx */ + writel(ITC_DEFAULT, ®s->itc); + /* no tx pool, rx poll = 1 normal cycle */ + writel(APTC_DEFAULT, ®s->aptc); + /* rx threshold = [6/8 fifo, 2/8 fifo] */ + writel(DBLAC_DEFAULT, ®s->dblac); + /* disable & clear all interrupt status */ + chip->imr = 0; + writel(ISR_ALL, ®s->isr); + writel(chip->imr, ®s->imr); + /* enable mac */ + writel(chip->maccr, ®s->maccr); + + return 0; +} + +static int ftmac110_probe(struct eth_device *dev, bd_t *bis) +{ + debug("ftmac110: probe\n"); + + if (ftmac110_reset(dev)) + return -1; + + return 0; +} + +static void ftmac110_halt(struct eth_device *dev) +{ + struct ftmac110_chip *chip = dev->priv; + struct ftmac110_regs __iomem *regs = chip->regs; + + writel(0, ®s->imr); + writel(0, ®s->maccr); + + debug("ftmac110: halt\n"); +} + +static int ftmac110_send(struct eth_device *dev, void *pkt, int len) +{ + struct ftmac110_chip *chip = dev->priv; + struct ftmac110_regs __iomem *regs = chip->regs; + struct ftmac110_txd *des; + + if (!chip->lnkup) + return 0; + + if (len <= 0 || len > CFG_XBUF_SIZE) { + printf("ftmac110: bad tx pkt len(%d)\n", len); + return 0; + } + + len = max(60, len); + + des = &chip->txd[chip->txd_idx]; + if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) { + /* kick-off Tx DMA */ + writel(0xffffffff, ®s->txpd); + printf("ftmac110: out of txd\n"); + return 0; + } + + memcpy(des->vbuf, (void *)pkt, len); + dma_map_single(des->vbuf, len, DMA_TO_DEVICE); + + /* update len, fts and lts */ + des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END); + des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len) + | FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS); + + /* set owner bit and clear others */ + des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER); + + /* kick-off Tx DMA */ + writel(0xffffffff, ®s->txpd); + + chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM; + + return len; +} + +static int ftmac110_recv(struct eth_device *dev) +{ + struct ftmac110_chip *chip = dev->priv; + struct ftmac110_rxd *des; + uint32_t ct0, len, rlen = 0; + uint8_t *buf; + + if (!chip->lnkup) + return 0; + + do { + des = &chip->rxd[chip->rxd_idx]; + ct0 = le32_to_cpu(des->ct[0]); + if (ct0 & FTMAC110_RXCT0_OWNER) + break; + + len = FTMAC110_RXCT0_LEN(ct0); + buf = des->vbuf; + + if (ct0 & FTMAC110_RXCT0_ERRMASK) { + printf("ftmac110: rx error\n"); + } else { + dma_map_single(buf, len, DMA_FROM_DEVICE); + NetReceive(buf, len); + rlen += len; + } + + /* owned by hardware */ + des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); + + chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM; + } while (0); + + return rlen; +} + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + +static int ftmac110_mdio_read( + const char *devname, uint8_t addr, uint8_t reg, uint16_t *value) +{ + int ret = 0; + struct eth_device *dev; + + dev = eth_get_dev_by_name(devname); + if (dev == NULL) { + printf("%s: no such device\n", devname); + ret = -1; + } else { + *value = mdio_read(dev, addr, reg); + } + + return ret; +} + +static int ftmac110_mdio_write( + const char *devname, uint8_t addr, uint8_t reg, uint16_t value) +{ + int ret = 0; + struct eth_device *dev; + + dev = eth_get_dev_by_name(devname); + if (dev == NULL) { + printf("%s: no such device\n", devname); + ret = -1; + } else { + mdio_write(dev, addr, reg, value); + } + + return ret; +} + +#endif /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */ + +int ftmac110_initialize(bd_t *bis) +{ + int i, card_nr = 0; + struct eth_device *dev; + struct ftmac110_chip *chip; + + dev = malloc(sizeof(*dev) + sizeof(*chip)); + if (dev == NULL) { + panic("ftmac110: out of memory 1\n"); + return -1; + } + chip = (struct ftmac110_chip *)(dev + 1); + memset(dev, 0, sizeof(*dev) + sizeof(*chip)); + + sprintf(dev->name, "FTMAC110#%d", card_nr); + + dev->iobase = CONFIG_FTMAC110_BASE; + chip->regs = (void __iomem *)dev->iobase; + dev->priv = chip; + dev->init = ftmac110_probe; + dev->halt = ftmac110_halt; + dev->send = ftmac110_send; + dev->recv = ftmac110_recv; + + if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr)) + eth_random_enetaddr(dev->enetaddr); + + /* allocate tx descriptors (it must be 16 bytes aligned) */ + chip->txd = dma_alloc_coherent( + sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma); + if (!chip->txd) + panic("ftmac110: out of memory 3\n"); + memset(chip->txd, 0, + sizeof(struct ftmac110_txd) * CFG_TXDES_NUM); + for (i = 0; i < CFG_TXDES_NUM; ++i) { + void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE); + if (!va) + panic("ftmac110: out of memory 4\n"); + chip->txd[i].vbuf = va; + chip->txd[i].buf = cpu_to_le32(virt_to_phys(va)); + chip->txd[i].ct[1] = 0; + chip->txd[i].ct[0] = 0; /* owned by SW */ + } + chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END); + chip->txd_idx = 0; + + /* allocate rx descriptors (it must be 16 bytes aligned) */ + chip->rxd = dma_alloc_coherent( + sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma); + if (!chip->rxd) + panic("ftmac110: out of memory 4\n"); + memset((void *)chip->rxd, 0, + sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM); + for (i = 0; i < CFG_RXDES_NUM; ++i) { + void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2); + if (!va) + panic("ftmac110: out of memory 5\n"); + /* it needs to be exactly 2 bytes aligned */ + va = ((uint8_t *)va + 2); + chip->rxd[i].vbuf = va; + chip->rxd[i].buf = cpu_to_le32(virt_to_phys(va)); + chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE); + chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER); + } + chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END); + chip->rxd_idx = 0; + + eth_register(dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write); +#endif + + card_nr++; + + return card_nr; +} diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h new file mode 100644 index 0000000..5b2d23b --- /dev/null +++ b/drivers/net/ftmac110.h @@ -0,0 +1,177 @@ +/* + * Faraday 10/100Mbps Ethernet Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#ifndef _FTMAC110_H +#define _FTMAC110_H + +struct ftmac110_regs { + uint32_t isr; /* 0x00: Interrups Status Register */ + uint32_t imr; /* 0x04: Interrupt Mask Register */ + uint32_t mac[2]; /* 0x08: MAC Address */ + uint32_t mht[2]; /* 0x10: Multicast Hash Table Register */ + uint32_t txpd; /* 0x18: Tx Poll Demand Register */ + uint32_t rxpd; /* 0x1c: Rx Poll Demand Register */ + uint32_t txba; /* 0x20: Tx Ring Base Address Register */ + uint32_t rxba; /* 0x24: Rx Ring Base Address Register */ + uint32_t itc; /* 0x28: Interrupt Timer Control Register */ + uint32_t aptc; /* 0x2C: Automatic Polling Timer Control Register */ + uint32_t dblac; /* 0x30: DMA Burst Length&Arbitration Control */ + uint32_t revr; /* 0x34: Revision Register */ + uint32_t fear; /* 0x38: Feature Register */ + uint32_t rsvd[19]; + uint32_t maccr; /* 0x88: MAC Control Register */ + uint32_t macsr; /* 0x8C: MAC Status Register */ + uint32_t phycr; /* 0x90: PHY Control Register */ + uint32_t phydr; /* 0x94: PHY Data Register */ + uint32_t fcr; /* 0x98: Flow Control Register */ + uint32_t bpr; /* 0x9C: Back Pressure Register */ +}; + +/* + * Interrupt status/mask register(ISR/IMR) bits + */ +#define ISR_ALL 0x3ff +#define ISR_PHYSTCHG (1 << 9) /* phy status change */ +#define ISR_AHBERR (1 << 8) /* bus error */ +#define ISR_RXLOST (1 << 7) /* rx lost */ +#define ISR_RXFIFO (1 << 6) /* rx to fifo */ +#define ISR_TXLOST (1 << 5) /* tx lost */ +#define ISR_TXOK (1 << 4) /* tx to ethernet */ +#define ISR_NOTXBUF (1 << 3) /* out of tx buffer */ +#define ISR_TXFIFO (1 << 2) /* tx to fifo */ +#define ISR_NORXBUF (1 << 1) /* out of rx buffer */ +#define ISR_RXOK (1 << 0) /* rx to buffer */ + +/* + * MACCR control bits + */ +#define MACCR_100M (1 << 18) /* 100Mbps mode */ +#define MACCR_RXBCST (1 << 17) /* rx broadcast packet */ +#define MACCR_RXMCST (1 << 16) /* rx multicast packet */ +#define MACCR_FD (1 << 15) /* full duplex */ +#define MACCR_CRCAPD (1 << 14) /* tx crc append */ +#define MACCR_RXALL (1 << 12) /* rx all packets */ +#define MACCR_RXFTL (1 << 11) /* rx packet even it's > 1518 byte */ +#define MACCR_RXRUNT (1 << 10) /* rx packet even it's < 64 byte */ +#define MACCR_RXMCSTHT (1 << 9) /* rx multicast hash table */ +#define MACCR_RXEN (1 << 8) /* rx enable */ +#define MACCR_RXINHDTX (1 << 6) /* rx in half duplex tx */ +#define MACCR_TXEN (1 << 5) /* tx enable */ +#define MACCR_CRCDIS (1 << 4) /* tx packet even it's crc error */ +#define MACCR_LOOPBACK (1 << 3) /* loop-back */ +#define MACCR_RESET (1 << 2) /* reset */ +#define MACCR_RXDMAEN (1 << 1) /* rx dma enable */ +#define MACCR_TXDMAEN (1 << 0) /* tx dma enable */ + +/* + * PHYCR control bits + */ +#define PHYCR_READ (1 << 26) +#define PHYCR_WRITE (1 << 27) +#define PHYCR_REG_SHIFT 21 +#define PHYCR_ADDR_SHIFT 16 + +/* + * ITC control bits + */ + +/* Tx Cycle Length */ +#define ITC_TX_CYCLONG (1 << 15) /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define ITC_TX_CYCNORM (0 << 15) /* 100Mbps=5.12us; 10Mbps=51.2us */ +/* Tx Threshold: Aggregate n interrupts as 1 interrupt */ +#define ITC_TX_THR(n) (((n) & 0x7) << 12) +/* Tx Interrupt Timeout = n * Tx Cycle */ +#define ITC_TX_ITMO(n) (((n) & 0xf) << 8) +/* Rx Cycle Length */ +#define ITC_RX_CYCLONG (1 << 7) /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define ITC_RX_CYCNORM (0 << 7) /* 100Mbps=5.12us; 10Mbps=51.2us */ +/* Rx Threshold: Aggregate n interrupts as 1 interrupt */ +#define ITC_RX_THR(n) (((n) & 0x7) << 4) +/* Rx Interrupt Timeout = n * Rx Cycle */ +#define ITC_RX_ITMO(n) (((n) & 0xf) << 0) + +#define ITC_DEFAULT \ + (ITC_TX_THR(1) | ITC_TX_ITMO(0) | ITC_RX_THR(1) | ITC_RX_ITMO(0)) + +/* + * APTC contrl bits + */ + +/* Tx Cycle Length */ +#define APTC_TX_CYCLONG (1 << 12) /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define APTC_TX_CYCNORM (0 << 12) /* 100Mbps=5.12us; 10Mbps=51.2us */ +/* Tx Poll Timeout = n * Tx Cycle, 0=No auto polling */ +#define APTC_TX_PTMO(n) (((n) & 0xf) << 8) +/* Rx Cycle Length */ +#define APTC_RX_CYCLONG (1 << 4) /* 100Mbps=81.92us; 10Mbps=819.2us */ +#define APTC_RX_CYCNORM (0 << 4) /* 100Mbps=5.12us; 10Mbps=51.2us */ +/* Rx Poll Timeout = n * Rx Cycle, 0=No auto polling */ +#define APTC_RX_PTMO(n) (((n) & 0xf) << 0) + +#define APTC_DEFAULT (APTC_TX_PTMO(0) | APTC_RX_PTMO(1)) + +/* + * DBLAC contrl bits + */ +#define DBLAC_BURST_MAX_ANY (0 << 14) /* un-limited */ +#define DBLAC_BURST_MAX_32X4 (2 << 14) /* max = 32 x 4 bytes */ +#define DBLAC_BURST_MAX_64X4 (3 << 14) /* max = 64 x 4 bytes */ +#define DBLAC_RXTHR_EN (1 << 9) /* enable rx threshold arbitration */ +#define DBLAC_RXTHR_HIGH(n) (((n) & 0x7) << 6) /* upper bound = n/8 fifo */ +#define DBLAC_RXTHR_LOW(n) (((n) & 0x7) << 3) /* lower bound = n/8 fifo */ +#define DBLAC_BURST_CAP16 (1 << 2) /* support burst 16 */ +#define DBLAC_BURST_CAP8 (1 << 1) /* support burst 8 */ +#define DBLAC_BURST_CAP4 (1 << 0) /* support burst 4 */ + +#define DBLAC_DEFAULT \ + (DBLAC_RXTHR_EN | DBLAC_RXTHR_HIGH(6) | DBLAC_RXTHR_LOW(2)) + +/* + * descriptor structure + */ +struct ftmac110_rxd { + uint32_t ct[2]; + uint32_t buf; + void *vbuf; /* reserved */ +}; + +#define FTMAC110_RXCT0_OWNER BIT_MASK(31) /* owner: 1=HW, 0=SW */ +#define FTMAC110_RXCT0_FRS BIT_MASK(29) /* first pkt desc */ +#define FTMAC110_RXCT0_LRS BIT_MASK(28) /* last pkt desc */ +#define FTMAC110_RXCT0_ODDNB BIT_MASK(22) /* odd nibble */ +#define FTMAC110_RXCT0_RUNT BIT_MASK(21) /* runt pkt */ +#define FTMAC110_RXCT0_FTL BIT_MASK(20) /* frame too long */ +#define FTMAC110_RXCT0_CRC BIT_MASK(19) /* pkt crc error */ +#define FTMAC110_RXCT0_ERR BIT_MASK(18) /* bus error */ +#define FTMAC110_RXCT0_ERRMASK (0x1f << 18) /* all errors */ +#define FTMAC110_RXCT0_BCST BIT_MASK(17) /* Bcst pkt */ +#define FTMAC110_RXCT0_MCST BIT_MASK(16) /* Mcst pkt */ +#define FTMAC110_RXCT0_LEN(x) ((x) & 0x7ff) + +#define FTMAC110_RXCT1_END BIT_MASK(31) +#define FTMAC110_RXCT1_BUFSZ(x) ((x) & 0x7ff) + +struct ftmac110_txd { + uint32_t ct[2]; + uint32_t buf; + void *vbuf; /* reserved */ +}; + +#define FTMAC110_TXCT0_OWNER BIT_MASK(31) /* owner: 1=HW, 0=SW */ +#define FTMAC110_TXCT0_COL 0x00000003 /* collision */ + +#define FTMAC110_TXCT1_END BIT_MASK(31) /* end of ring */ +#define FTMAC110_TXCT1_TXIC BIT_MASK(30) /* tx done interrupt */ +#define FTMAC110_TXCT1_TX2FIC BIT_MASK(29) /* tx fifo interrupt */ +#define FTMAC110_TXCT1_FTS BIT_MASK(28) /* first pkt desc */ +#define FTMAC110_TXCT1_LTS BIT_MASK(27) /* last pkt desc */ +#define FTMAC110_TXCT1_LEN(x) ((x) & 0x7ff) + +#endif /* FTMAC110_H */ diff --git a/drivers/net/ks8851_mll.c b/drivers/net/ks8851_mll.c new file mode 100644 index 0000000..b02d59a --- /dev/null +++ b/drivers/net/ks8851_mll.c @@ -0,0 +1,645 @@ +/* + * Micrel KS8851_MLL 16bit Network driver + * Copyright (c) 2011 Roberto Cerati <roberto.cerati@bticino.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <asm/io.h> +#include <common.h> +#include <command.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> + +#include "ks8851_mll.h" + +#define DRIVERNAME "ks8851_mll" + +#define MAX_RECV_FRAMES 32 +#define MAX_BUF_SIZE 2048 +#define TX_BUF_SIZE 2000 +#define RX_BUF_SIZE 2000 + +static const struct chip_id chip_ids[] = { + {CIDER_ID, "KSZ8851"}, + {0, NULL}, +}; + +/* + * union ks_tx_hdr - tx header data + * @txb: The header as bytes + * @txw: The header as 16bit, little-endian words + * + * A dual representation of the tx header data to allow + * access to individual bytes, and to allow 16bit accesses + * with 16bit alignment. + */ +union ks_tx_hdr { + u8 txb[4]; + __le16 txw[2]; +}; + +/* + * struct ks_net - KS8851 driver private data + * @net_device : The network device we're bound to + * @txh : temporaly buffer to save status/length. + * @frame_head_info : frame header information for multi-pkt rx. + * @statelock : Lock on this structure for tx list. + * @msg_enable : The message flags controlling driver output (see ethtool). + * @frame_cnt : number of frames received. + * @bus_width : i/o bus width. + * @irq : irq number assigned to this device. + * @rc_rxqcr : Cached copy of KS_RXQCR. + * @rc_txcr : Cached copy of KS_TXCR. + * @rc_ier : Cached copy of KS_IER. + * @sharedbus : Multipex(addr and data bus) mode indicator. + * @cmd_reg_cache : command register cached. + * @cmd_reg_cache_int : command register cached. Used in the irq handler. + * @promiscuous : promiscuous mode indicator. + * @all_mcast : mutlicast indicator. + * @mcast_lst_size : size of multicast list. + * @mcast_lst : multicast list. + * @mcast_bits : multicast enabed. + * @mac_addr : MAC address assigned to this device. + * @fid : frame id. + * @extra_byte : number of extra byte prepended rx pkt. + * @enabled : indicator this device works. + */ + +/* Receive multiplex framer header info */ +struct type_frame_head { + u16 sts; /* Frame status */ + u16 len; /* Byte count */ +} fr_h_i[MAX_RECV_FRAMES]; + +struct ks_net { + struct net_device *netdev; + union ks_tx_hdr txh; + struct type_frame_head *frame_head_info; + u32 msg_enable; + u32 frame_cnt; + int bus_width; + int irq; + u16 rc_rxqcr; + u16 rc_txcr; + u16 rc_ier; + u16 sharedbus; + u16 cmd_reg_cache; + u16 cmd_reg_cache_int; + u16 promiscuous; + u16 all_mcast; + u16 mcast_lst_size; + u8 mcast_lst[MAX_MCAST_LST][MAC_ADDR_LEN]; + u8 mcast_bits[HW_MCAST_SIZE]; + u8 mac_addr[6]; + u8 fid; + u8 extra_byte; + u8 enabled; +} ks_str, *ks; + +#define BE3 0x8000 /* Byte Enable 3 */ +#define BE2 0x4000 /* Byte Enable 2 */ +#define BE1 0x2000 /* Byte Enable 1 */ +#define BE0 0x1000 /* Byte Enable 0 */ + +static u8 ks_rdreg8(struct eth_device *dev, u16 offset) +{ + u8 shift_bit = offset & 0x03; + u8 shift_data = (offset & 1) << 3; + + writew(offset | (BE0 << shift_bit), dev->iobase + 2); + + return (u8)(readw(dev->iobase) >> shift_data); +} + +static u16 ks_rdreg16(struct eth_device *dev, u16 offset) +{ + writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2); + + return readw(dev->iobase); +} + +static void ks_wrreg8(struct eth_device *dev, u16 offset, u8 val) +{ + u8 shift_bit = (offset & 0x03); + u16 value_write = (u16)(val << ((offset & 1) << 3)); + + writew(offset | (BE0 << shift_bit), dev->iobase + 2); + writew(value_write, dev->iobase); +} + +static void ks_wrreg16(struct eth_device *dev, u16 offset, u16 val) +{ + writew(offset | ((BE1 | BE0) << (offset & 0x02)), dev->iobase + 2); + writew(val, dev->iobase); +} + +/* + * ks_inblk - read a block of data from QMU. This is called after sudo DMA mode + * enabled. + * @ks: The chip state + * @wptr: buffer address to save data + * @len: length in byte to read + */ +static inline void ks_inblk(struct eth_device *dev, u16 *wptr, u32 len) +{ + len >>= 1; + + while (len--) + *wptr++ = readw(dev->iobase); +} + +/* + * ks_outblk - write data to QMU. This is called after sudo DMA mode enabled. + * @ks: The chip information + * @wptr: buffer address + * @len: length in byte to write + */ +static inline void ks_outblk(struct eth_device *dev, u16 *wptr, u32 len) +{ + len >>= 1; + + while (len--) + writew(*wptr++, dev->iobase); +} + +static void ks_enable_int(struct eth_device *dev) +{ + ks_wrreg16(dev, KS_IER, ks->rc_ier); +} + +static void ks_set_powermode(struct eth_device *dev, unsigned pwrmode) +{ + unsigned pmecr; + + ks_rdreg16(dev, KS_GRR); + pmecr = ks_rdreg16(dev, KS_PMECR); + pmecr &= ~PMECR_PM_MASK; + pmecr |= pwrmode; + + ks_wrreg16(dev, KS_PMECR, pmecr); +} + +/* + * ks_read_config - read chip configuration of bus width. + * @ks: The chip information + */ +static void ks_read_config(struct eth_device *dev) +{ + u16 reg_data = 0; + + /* Regardless of bus width, 8 bit read should always work. */ + reg_data = ks_rdreg8(dev, KS_CCR) & 0x00FF; + reg_data |= ks_rdreg8(dev, KS_CCR + 1) << 8; + + /* addr/data bus are multiplexed */ + ks->sharedbus = (reg_data & CCR_SHARED) == CCR_SHARED; + + /* + * There are garbage data when reading data from QMU, + * depending on bus-width. + */ + if (reg_data & CCR_8BIT) { + ks->bus_width = ENUM_BUS_8BIT; + ks->extra_byte = 1; + } else if (reg_data & CCR_16BIT) { + ks->bus_width = ENUM_BUS_16BIT; + ks->extra_byte = 2; + } else { + ks->bus_width = ENUM_BUS_32BIT; + ks->extra_byte = 4; + } +} + +/* + * ks_soft_reset - issue one of the soft reset to the device + * @ks: The device state. + * @op: The bit(s) to set in the GRR + * + * Issue the relevant soft-reset command to the device's GRR register + * specified by @op. + * + * Note, the delays are in there as a caution to ensure that the reset + * has time to take effect and then complete. Since the datasheet does + * not currently specify the exact sequence, we have chosen something + * that seems to work with our device. + */ +static void ks_soft_reset(struct eth_device *dev, unsigned op) +{ + /* Disable interrupt first */ + ks_wrreg16(dev, KS_IER, 0x0000); + ks_wrreg16(dev, KS_GRR, op); + mdelay(10); /* wait a short time to effect reset */ + ks_wrreg16(dev, KS_GRR, 0); + mdelay(1); /* wait for condition to clear */ +} + +void ks_enable_qmu(struct eth_device *dev) +{ + u16 w; + + w = ks_rdreg16(dev, KS_TXCR); + + /* Enables QMU Transmit (TXCR). */ + ks_wrreg16(dev, KS_TXCR, w | TXCR_TXE); + + /* Enable RX Frame Count Threshold and Auto-Dequeue RXQ Frame */ + w = ks_rdreg16(dev, KS_RXQCR); + ks_wrreg16(dev, KS_RXQCR, w | RXQCR_RXFCTE); + + /* Enables QMU Receive (RXCR1). */ + w = ks_rdreg16(dev, KS_RXCR1); + ks_wrreg16(dev, KS_RXCR1, w | RXCR1_RXE); +} + +static void ks_disable_qmu(struct eth_device *dev) +{ + u16 w; + + w = ks_rdreg16(dev, KS_TXCR); + + /* Disables QMU Transmit (TXCR). */ + w &= ~TXCR_TXE; + ks_wrreg16(dev, KS_TXCR, w); + + /* Disables QMU Receive (RXCR1). */ + w = ks_rdreg16(dev, KS_RXCR1); + w &= ~RXCR1_RXE; + ks_wrreg16(dev, KS_RXCR1, w); +} + +static inline void ks_read_qmu(struct eth_device *dev, u16 *buf, u32 len) +{ + u32 r = ks->extra_byte & 0x1; + u32 w = ks->extra_byte - r; + + /* 1. set sudo DMA mode */ + ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + + /* + * 2. read prepend data + * + * read 4 + extra bytes and discard them. + * extra bytes for dummy, 2 for status, 2 for len + */ + + if (r) + ks_rdreg8(dev, 0); + + ks_inblk(dev, buf, w + 2 + 2); + + /* 3. read pkt data */ + ks_inblk(dev, buf, ALIGN(len, 4)); + + /* 4. reset sudo DMA Mode */ + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff); +} + +static void ks_rcv(struct eth_device *dev, uchar **pv_data) +{ + struct type_frame_head *frame_hdr = ks->frame_head_info; + int i; + + ks->frame_cnt = ks_rdreg16(dev, KS_RXFCTR) >> 8; + + /* read all header information */ + for (i = 0; i < ks->frame_cnt; i++) { + /* Checking Received packet status */ + frame_hdr->sts = ks_rdreg16(dev, KS_RXFHSR); + /* Get packet len from hardware */ + frame_hdr->len = ks_rdreg16(dev, KS_RXFHBCR); + frame_hdr++; + } + + frame_hdr = ks->frame_head_info; + while (ks->frame_cnt--) { + if ((frame_hdr->sts & RXFSHR_RXFV) && + (frame_hdr->len < RX_BUF_SIZE) && + frame_hdr->len) { + /* read data block including CRC 4 bytes */ + ks_read_qmu(dev, (u16 *)(*pv_data), frame_hdr->len); + + /* NetRxPackets buffer size is ok (*pv_data pointer) */ + NetReceive(*pv_data, frame_hdr->len); + pv_data++; + } else { + ks_wrreg16(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_RRXEF)); + printf(DRIVERNAME ": bad packet\n"); + } + frame_hdr++; + } +} + +/* + * ks_read_selftest - read the selftest memory info. + * @ks: The device state + * + * Read and check the TX/RX memory selftest information. + */ +static int ks_read_selftest(struct eth_device *dev) +{ + u16 both_done = MBIR_TXMBF | MBIR_RXMBF; + u16 mbir; + int ret = 0; + + mbir = ks_rdreg16(dev, KS_MBIR); + + if ((mbir & both_done) != both_done) { + printf(DRIVERNAME ": Memory selftest not finished\n"); + return 0; + } + + if (mbir & MBIR_TXMBFA) { + printf(DRIVERNAME ": TX memory selftest fails\n"); + ret |= 1; + } + + if (mbir & MBIR_RXMBFA) { + printf(DRIVERNAME ": RX memory selftest fails\n"); + ret |= 2; + } + + debug(DRIVERNAME ": the selftest passes\n"); + + return ret; +} + +static void ks_setup(struct eth_device *dev) +{ + u16 w; + + /* Setup Transmit Frame Data Pointer Auto-Increment (TXFDPR) */ + ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); + + /* Setup Receive Frame Data Pointer Auto-Increment */ + ks_wrreg16(dev, KS_RXFDPR, RXFDPR_RXFPAI); + + /* Setup Receive Frame Threshold - 1 frame (RXFCTFC) */ + ks_wrreg16(dev, KS_RXFCTR, 1 & RXFCTR_THRESHOLD_MASK); + + /* Setup RxQ Command Control (RXQCR) */ + ks->rc_rxqcr = RXQCR_CMD_CNTL; + ks_wrreg16(dev, KS_RXQCR, ks->rc_rxqcr); + + /* + * set the force mode to half duplex, default is full duplex + * because if the auto-negotiation fails, most switch uses + * half-duplex. + */ + w = ks_rdreg16(dev, KS_P1MBCR); + w &= ~P1MBCR_FORCE_FDX; + ks_wrreg16(dev, KS_P1MBCR, w); + + w = TXCR_TXFCE | TXCR_TXPE | TXCR_TXCRC | TXCR_TCGIP; + ks_wrreg16(dev, KS_TXCR, w); + + w = RXCR1_RXFCE | RXCR1_RXBE | RXCR1_RXUE | RXCR1_RXME | RXCR1_RXIPFCC; + + /* Normal mode */ + w |= RXCR1_RXPAFMA; + + ks_wrreg16(dev, KS_RXCR1, w); +} + +static void ks_setup_int(struct eth_device *dev) +{ + ks->rc_ier = 0x00; + + /* Clear the interrupts status of the hardware. */ + ks_wrreg16(dev, KS_ISR, 0xffff); + + /* Enables the interrupts of the hardware. */ + ks->rc_ier = (IRQ_LCI | IRQ_TXI | IRQ_RXI); +} + +static int ks8851_mll_detect_chip(struct eth_device *dev) +{ + unsigned short val, i; + + ks_read_config(dev); + + val = ks_rdreg16(dev, KS_CIDER); + + if (val == 0xffff) { + /* Special case -- no chip present */ + printf(DRIVERNAME ": is chip mounted ?\n"); + return -1; + } else if ((val & 0xfff0) != CIDER_ID) { + printf(DRIVERNAME ": Invalid chip id 0x%04x\n", val); + return -1; + } + + debug("Read back KS8851 id 0x%x\n", val); + + /* only one entry in the table */ + val &= 0xfff0; + for (i = 0; chip_ids[i].id != 0; i++) { + if (chip_ids[i].id == val) + break; + } + if (!chip_ids[i].id) { + printf(DRIVERNAME ": Unknown chip ID %04x\n", val); + return -1; + } + + dev->priv = (void *)&chip_ids[i]; + + return 0; +} + +static void ks8851_mll_reset(struct eth_device *dev) +{ + /* wake up powermode to normal mode */ + ks_set_powermode(dev, PMECR_PM_NORMAL); + mdelay(1); /* wait for normal mode to take effect */ + + /* Disable interrupt and reset */ + ks_soft_reset(dev, GRR_GSR); + + /* turn off the IRQs and ack any outstanding */ + ks_wrreg16(dev, KS_IER, 0x0000); + ks_wrreg16(dev, KS_ISR, 0xffff); + + /* shutdown RX/TX QMU */ + ks_disable_qmu(dev); +} + +static void ks8851_mll_phy_configure(struct eth_device *dev) +{ + u16 data; + + ks_setup(dev); + ks_setup_int(dev); + + /* Probing the phy */ + data = ks_rdreg16(dev, KS_OBCR); + ks_wrreg16(dev, KS_OBCR, data | OBCR_ODS_16MA); + + debug(DRIVERNAME ": phy initialized\n"); +} + +static void ks8851_mll_enable(struct eth_device *dev) +{ + ks_wrreg16(dev, KS_ISR, 0xffff); + ks_enable_int(dev); + ks_enable_qmu(dev); +} + +static int ks8851_mll_init(struct eth_device *dev, bd_t *bd) +{ + struct chip_id *id = dev->priv; + + debug(DRIVERNAME ": detected %s controller\n", id->name); + + if (ks_read_selftest(dev)) { + printf(DRIVERNAME ": Selftest failed\n"); + return -1; + } + + ks8851_mll_reset(dev); + + /* Configure the PHY, initialize the link state */ + ks8851_mll_phy_configure(dev); + + /* static allocation of private informations */ + ks->frame_head_info = fr_h_i; + + /* Turn on Tx + Rx */ + ks8851_mll_enable(dev); + + return 0; +} + +static void ks_write_qmu(struct eth_device *dev, u8 *pdata, u16 len) +{ + /* start header at txb[0] to align txw entries */ + ks->txh.txw[0] = 0; + ks->txh.txw[1] = cpu_to_le16(len); + + /* 1. set sudo-DMA mode */ + ks_wrreg16(dev, KS_TXFDPR, TXFDPR_TXFPAI); + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr | RXQCR_SDA) & 0xff); + /* 2. write status/lenth info */ + ks_outblk(dev, ks->txh.txw, 4); + /* 3. write pkt data */ + ks_outblk(dev, (u16 *)pdata, ALIGN(len, 4)); + /* 4. reset sudo-DMA mode */ + ks_wrreg8(dev, KS_RXQCR, (ks->rc_rxqcr & ~RXQCR_SDA) & 0xff); + /* 5. Enqueue Tx(move the pkt from TX buffer into TXQ) */ + ks_wrreg16(dev, KS_TXQCR, TXQCR_METFE); + /* 6. wait until TXQCR_METFE is auto-cleared */ + do { } while (ks_rdreg16(dev, KS_TXQCR) & TXQCR_METFE); +} + +static int ks8851_mll_send(struct eth_device *dev, void *packet, int length) +{ + u8 *data = (u8 *)packet; + u16 tmplen = (u16)length; + u16 retv; + + /* + * Extra space are required: + * 4 byte for alignment, 4 for status/length, 4 for CRC + */ + retv = ks_rdreg16(dev, KS_TXMIR) & 0x1fff; + if (retv >= tmplen + 12) { + ks_write_qmu(dev, data, tmplen); + return 0; + } else { + printf(DRIVERNAME ": failed to send packet: No buffer\n"); + return -1; + } +} + +static void ks8851_mll_halt(struct eth_device *dev) +{ + ks8851_mll_reset(dev); +} + +/* + * Maximum receive ring size; that is, the number of packets + * we can buffer before overflow happens. Basically, this just + * needs to be enough to prevent a packet being discarded while + * we are processing the previous one. + */ +static int ks8851_mll_recv(struct eth_device *dev) +{ + u16 status; + + status = ks_rdreg16(dev, KS_ISR); + + ks_wrreg16(dev, KS_ISR, status); + + if ((status & IRQ_RXI)) + ks_rcv(dev, (uchar **)NetRxPackets); + + if ((status & IRQ_LDI)) { + u16 pmecr = ks_rdreg16(dev, KS_PMECR); + pmecr &= ~PMECR_WKEVT_MASK; + ks_wrreg16(dev, KS_PMECR, pmecr | PMECR_WKEVT_LINK); + } + + return 0; +} + +static int ks8851_mll_write_hwaddr(struct eth_device *dev) +{ + u16 addrl, addrm, addrh; + + addrh = (dev->enetaddr[0] << 8) | dev->enetaddr[1]; + addrm = (dev->enetaddr[2] << 8) | dev->enetaddr[3]; + addrl = (dev->enetaddr[4] << 8) | dev->enetaddr[5]; + + ks_wrreg16(dev, KS_MARH, addrh); + ks_wrreg16(dev, KS_MARM, addrm); + ks_wrreg16(dev, KS_MARL, addrl); + + return 0; +} + +int ks8851_mll_initialize(u8 dev_num, int base_addr) +{ + struct eth_device *dev; + + dev = malloc(sizeof(*dev)); + if (!dev) { + printf("Error: Failed to allocate memory\n"); + return -1; + } + memset(dev, 0, sizeof(*dev)); + + dev->iobase = base_addr; + + ks = &ks_str; + + /* Try to detect chip. Will fail if not present. */ + if (ks8851_mll_detect_chip(dev)) { + free(dev); + return -1; + } + + dev->init = ks8851_mll_init; + dev->halt = ks8851_mll_halt; + dev->send = ks8851_mll_send; + dev->recv = ks8851_mll_recv; + dev->write_hwaddr = ks8851_mll_write_hwaddr; + sprintf(dev->name, "%s-%hu", DRIVERNAME, dev_num); + + eth_register(dev); + + return 0; +} diff --git a/drivers/net/ks8851_mll.h b/drivers/net/ks8851_mll.h new file mode 100644 index 0000000..7f90ae4 --- /dev/null +++ b/drivers/net/ks8851_mll.h @@ -0,0 +1,357 @@ +/* + * drivers/net/ks8851_mll.c + * + * Supports: + * KS8851 16bit MLL chip from Micrel Inc. + * + * Copyright (c) 2009 Micrel Inc. + * + * modified by + * (c) 2011 Bticino s.p.a, Roberto Cerati <roberto.cerati@bticino.it> + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _KS8851_MLL_H_ +#define _KS8851_MLL_H_ + +#include <linux/types.h> + +#define KS_CCR 0x08 +#define CCR_EEPROM (1 << 9) +#define CCR_SPI (1 << 8) +#define CCR_8BIT (1 << 7) +#define CCR_16BIT (1 << 6) +#define CCR_32BIT (1 << 5) +#define CCR_SHARED (1 << 4) +#define CCR_32PIN (1 << 0) + +/* MAC address registers */ +#define KS_MARL 0x10 +#define KS_MARM 0x12 +#define KS_MARH 0x14 + +#define KS_OBCR 0x20 +#define OBCR_ODS_16MA (1 << 6) + +#define KS_EEPCR 0x22 +#define EEPCR_EESA (1 << 4) +#define EEPCR_EESB (1 << 3) +#define EEPCR_EEDO (1 << 2) +#define EEPCR_EESCK (1 << 1) +#define EEPCR_EECS (1 << 0) + +#define KS_MBIR 0x24 +#define MBIR_TXMBF (1 << 12) +#define MBIR_TXMBFA (1 << 11) +#define MBIR_RXMBF (1 << 4) +#define MBIR_RXMBFA (1 << 3) + +#define KS_GRR 0x26 +#define GRR_QMU (1 << 1) +#define GRR_GSR (1 << 0) + +#define KS_WFCR 0x2A +#define WFCR_MPRXE (1 << 7) +#define WFCR_WF3E (1 << 3) +#define WFCR_WF2E (1 << 2) +#define WFCR_WF1E (1 << 1) +#define WFCR_WF0E (1 << 0) + +#define KS_WF0CRC0 0x30 +#define KS_WF0CRC1 0x32 +#define KS_WF0BM0 0x34 +#define KS_WF0BM1 0x36 +#define KS_WF0BM2 0x38 +#define KS_WF0BM3 0x3A + +#define KS_WF1CRC0 0x40 +#define KS_WF1CRC1 0x42 +#define KS_WF1BM0 0x44 +#define KS_WF1BM1 0x46 +#define KS_WF1BM2 0x48 +#define KS_WF1BM3 0x4A + +#define KS_WF2CRC0 0x50 +#define KS_WF2CRC1 0x52 +#define KS_WF2BM0 0x54 +#define KS_WF2BM1 0x56 +#define KS_WF2BM2 0x58 +#define KS_WF2BM3 0x5A + +#define KS_WF3CRC0 0x60 +#define KS_WF3CRC1 0x62 +#define KS_WF3BM0 0x64 +#define KS_WF3BM1 0x66 +#define KS_WF3BM2 0x68 +#define KS_WF3BM3 0x6A + +#define KS_TXCR 0x70 +#define TXCR_TCGICMP (1 << 8) +#define TXCR_TCGUDP (1 << 7) +#define TXCR_TCGTCP (1 << 6) +#define TXCR_TCGIP (1 << 5) +#define TXCR_FTXQ (1 << 4) +#define TXCR_TXFCE (1 << 3) +#define TXCR_TXPE (1 << 2) +#define TXCR_TXCRC (1 << 1) +#define TXCR_TXE (1 << 0) + +#define KS_TXSR 0x72 +#define TXSR_TXLC (1 << 13) +#define TXSR_TXMC (1 << 12) +#define TXSR_TXFID_MASK (0x3f << 0) +#define TXSR_TXFID_SHIFT (0) +#define TXSR_TXFID_GET(_v) (((_v) >> 0) & 0x3f) + + +#define KS_RXCR1 0x74 +#define RXCR1_FRXQ (1 << 15) +#define RXCR1_RXUDPFCC (1 << 14) +#define RXCR1_RXTCPFCC (1 << 13) +#define RXCR1_RXIPFCC (1 << 12) +#define RXCR1_RXPAFMA (1 << 11) +#define RXCR1_RXFCE (1 << 10) +#define RXCR1_RXEFE (1 << 9) +#define RXCR1_RXMAFMA (1 << 8) +#define RXCR1_RXBE (1 << 7) +#define RXCR1_RXME (1 << 6) +#define RXCR1_RXUE (1 << 5) +#define RXCR1_RXAE (1 << 4) +#define RXCR1_RXINVF (1 << 1) +#define RXCR1_RXE (1 << 0) +#define RXCR1_FILTER_MASK (RXCR1_RXINVF | RXCR1_RXAE | \ + RXCR1_RXMAFMA | RXCR1_RXPAFMA) + +#define KS_RXCR2 0x76 +#define RXCR2_SRDBL_MASK (0x7 << 5) +#define RXCR2_SRDBL_SHIFT (5) +#define RXCR2_SRDBL_4B (0x0 << 5) +#define RXCR2_SRDBL_8B (0x1 << 5) +#define RXCR2_SRDBL_16B (0x2 << 5) +#define RXCR2_SRDBL_32B (0x3 << 5) +/* #define RXCR2_SRDBL_FRAME (0x4 << 5) */ +#define RXCR2_IUFFP (1 << 4) +#define RXCR2_RXIUFCEZ (1 << 3) +#define RXCR2_UDPLFE (1 << 2) +#define RXCR2_RXICMPFCC (1 << 1) +#define RXCR2_RXSAF (1 << 0) + +#define KS_TXMIR 0x78 + +#define KS_RXFHSR 0x7C +#define RXFSHR_RXFV (1 << 15) +#define RXFSHR_RXICMPFCS (1 << 13) +#define RXFSHR_RXIPFCS (1 << 12) +#define RXFSHR_RXTCPFCS (1 << 11) +#define RXFSHR_RXUDPFCS (1 << 10) +#define RXFSHR_RXBF (1 << 7) +#define RXFSHR_RXMF (1 << 6) +#define RXFSHR_RXUF (1 << 5) +#define RXFSHR_RXMR (1 << 4) +#define RXFSHR_RXFT (1 << 3) +#define RXFSHR_RXFTL (1 << 2) +#define RXFSHR_RXRF (1 << 1) +#define RXFSHR_RXCE (1 << 0) +#define RXFSHR_ERR (RXFSHR_RXCE | RXFSHR_RXRF |\ + RXFSHR_RXFTL | RXFSHR_RXMR |\ + RXFSHR_RXICMPFCS | RXFSHR_RXIPFCS |\ + RXFSHR_RXTCPFCS) +#define KS_RXFHBCR 0x7E +#define RXFHBCR_CNT_MASK 0x0FFF + +#define KS_TXQCR 0x80 +#define TXQCR_AETFE (1 << 2) +#define TXQCR_TXQMAM (1 << 1) +#define TXQCR_METFE (1 << 0) + +#define KS_RXQCR 0x82 +#define RXQCR_RXDTTS (1 << 12) +#define RXQCR_RXDBCTS (1 << 11) +#define RXQCR_RXFCTS (1 << 10) +#define RXQCR_RXIPHTOE (1 << 9) +#define RXQCR_RXDTTE (1 << 7) +#define RXQCR_RXDBCTE (1 << 6) +#define RXQCR_RXFCTE (1 << 5) +#define RXQCR_ADRFE (1 << 4) +#define RXQCR_SDA (1 << 3) +#define RXQCR_RRXEF (1 << 0) +#define RXQCR_CMD_CNTL (RXQCR_RXFCTE|RXQCR_ADRFE) + +#define KS_TXFDPR 0x84 +#define TXFDPR_TXFPAI (1 << 14) +#define TXFDPR_TXFP_MASK (0x7ff << 0) +#define TXFDPR_TXFP_SHIFT (0) + +#define KS_RXFDPR 0x86 +#define RXFDPR_RXFPAI (1 << 14) + +#define KS_RXDTTR 0x8C +#define KS_RXDBCTR 0x8E + +#define KS_IER 0x90 +#define KS_ISR 0x92 +#define IRQ_LCI (1 << 15) +#define IRQ_TXI (1 << 14) +#define IRQ_RXI (1 << 13) +#define IRQ_RXOI (1 << 11) +#define IRQ_TXPSI (1 << 9) +#define IRQ_RXPSI (1 << 8) +#define IRQ_TXSAI (1 << 6) +#define IRQ_RXWFDI (1 << 5) +#define IRQ_RXMPDI (1 << 4) +#define IRQ_LDI (1 << 3) +#define IRQ_EDI (1 << 2) +#define IRQ_SPIBEI (1 << 1) +#define IRQ_DEDI (1 << 0) + +#define KS_RXFCTR 0x9C +#define RXFCTR_THRESHOLD_MASK 0x00FF + +#define KS_RXFC 0x9D +#define RXFCTR_RXFC_MASK (0xff << 8) +#define RXFCTR_RXFC_SHIFT (8) +#define RXFCTR_RXFC_GET(_v) (((_v) >> 8) & 0xff) +#define RXFCTR_RXFCT_MASK (0xff << 0) +#define RXFCTR_RXFCT_SHIFT (0) + +#define KS_TXNTFSR 0x9E + +#define KS_MAHTR0 0xA0 +#define KS_MAHTR1 0xA2 +#define KS_MAHTR2 0xA4 +#define KS_MAHTR3 0xA6 + +#define KS_FCLWR 0xB0 +#define KS_FCHWR 0xB2 +#define KS_FCOWR 0xB4 + +#define KS_CIDER 0xC0 +#define CIDER_ID 0x8870 +#define CIDER_REV_MASK (0x7 << 1) +#define CIDER_REV_SHIFT (1) +#define CIDER_REV_GET(_v) (((_v) >> 1) & 0x7) + +#define KS_CGCR 0xC6 +#define KS_IACR 0xC8 +#define IACR_RDEN (1 << 12) +#define IACR_TSEL_MASK (0x3 << 10) +#define IACR_TSEL_SHIFT (10) +#define IACR_TSEL_MIB (0x3 << 10) +#define IACR_ADDR_MASK (0x1f << 0) +#define IACR_ADDR_SHIFT (0) + +#define KS_IADLR 0xD0 +#define KS_IAHDR 0xD2 + +#define KS_PMECR 0xD4 +#define PMECR_PME_DELAY (1 << 14) +#define PMECR_PME_POL (1 << 12) +#define PMECR_WOL_WAKEUP (1 << 11) +#define PMECR_WOL_MAGICPKT (1 << 10) +#define PMECR_WOL_LINKUP (1 << 9) +#define PMECR_WOL_ENERGY (1 << 8) +#define PMECR_AUTO_WAKE_EN (1 << 7) +#define PMECR_WAKEUP_NORMAL (1 << 6) +#define PMECR_WKEVT_MASK (0xf << 2) +#define PMECR_WKEVT_SHIFT (2) +#define PMECR_WKEVT_GET(_v) (((_v) >> 2) & 0xf) +#define PMECR_WKEVT_ENERGY (0x1 << 2) +#define PMECR_WKEVT_LINK (0x2 << 2) +#define PMECR_WKEVT_MAGICPKT (0x4 << 2) +#define PMECR_WKEVT_FRAME (0x8 << 2) +#define PMECR_PM_MASK (0x3 << 0) +#define PMECR_PM_SHIFT (0) +#define PMECR_PM_NORMAL (0x0 << 0) +#define PMECR_PM_ENERGY (0x1 << 0) +#define PMECR_PM_SOFTDOWN (0x2 << 0) +#define PMECR_PM_POWERSAVE (0x3 << 0) + +/* Standard MII PHY data */ +#define KS_P1MBCR 0xE4 +#define P1MBCR_FORCE_FDX (1 << 8) + +#define KS_P1MBSR 0xE6 +#define P1MBSR_AN_COMPLETE (1 << 5) +#define P1MBSR_AN_CAPABLE (1 << 3) +#define P1MBSR_LINK_UP (1 << 2) + +#define KS_PHY1ILR 0xE8 +#define KS_PHY1IHR 0xEA +#define KS_P1ANAR 0xEC +#define KS_P1ANLPR 0xEE + +#define KS_P1SCLMD 0xF4 +#define P1SCLMD_LEDOFF (1 << 15) +#define P1SCLMD_TXIDS (1 << 14) +#define P1SCLMD_RESTARTAN (1 << 13) +#define P1SCLMD_DISAUTOMDIX (1 << 10) +#define P1SCLMD_FORCEMDIX (1 << 9) +#define P1SCLMD_AUTONEGEN (1 << 7) +#define P1SCLMD_FORCE100 (1 << 6) +#define P1SCLMD_FORCEFDX (1 << 5) +#define P1SCLMD_ADV_FLOW (1 << 4) +#define P1SCLMD_ADV_100BT_FDX (1 << 3) +#define P1SCLMD_ADV_100BT_HDX (1 << 2) +#define P1SCLMD_ADV_10BT_FDX (1 << 1) +#define P1SCLMD_ADV_10BT_HDX (1 << 0) + +#define KS_P1CR 0xF6 +#define P1CR_HP_MDIX (1 << 15) +#define P1CR_REV_POL (1 << 13) +#define P1CR_OP_100M (1 << 10) +#define P1CR_OP_FDX (1 << 9) +#define P1CR_OP_MDI (1 << 7) +#define P1CR_AN_DONE (1 << 6) +#define P1CR_LINK_GOOD (1 << 5) +#define P1CR_PNTR_FLOW (1 << 4) +#define P1CR_PNTR_100BT_FDX (1 << 3) +#define P1CR_PNTR_100BT_HDX (1 << 2) +#define P1CR_PNTR_10BT_FDX (1 << 1) +#define P1CR_PNTR_10BT_HDX (1 << 0) + +/* TX Frame control */ +#define TXFR_TXIC (1 << 15) +#define TXFR_TXFID_MASK (0x3f << 0) +#define TXFR_TXFID_SHIFT (0) + +#define KS_P1SR 0xF8 +#define P1SR_HP_MDIX (1 << 15) +#define P1SR_REV_POL (1 << 13) +#define P1SR_OP_100M (1 << 10) +#define P1SR_OP_FDX (1 << 9) +#define P1SR_OP_MDI (1 << 7) +#define P1SR_AN_DONE (1 << 6) +#define P1SR_LINK_GOOD (1 << 5) +#define P1SR_PNTR_FLOW (1 << 4) +#define P1SR_PNTR_100BT_FDX (1 << 3) +#define P1SR_PNTR_100BT_HDX (1 << 2) +#define P1SR_PNTR_10BT_FDX (1 << 1) +#define P1SR_PNTR_10BT_HDX (1 << 0) + +#define ENUM_BUS_NONE 0 +#define ENUM_BUS_8BIT 1 +#define ENUM_BUS_16BIT 2 +#define ENUM_BUS_32BIT 3 + +#define MAX_MCAST_LST 32 +#define HW_MCAST_SIZE 8 +#define MAC_ADDR_LEN 6 + +/* Chip ID values */ +struct chip_id { + u16 id; + char *name; +}; + +#endif diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 8bacbda..b7802a2 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -103,9 +103,15 @@ struct macb_device { const struct device *dev; struct eth_device netdev; unsigned short phy_addr; + struct mii_dev *bus; }; #define to_macb(_nd) container_of(_nd, struct macb_device, netdev) +static int macb_is_gem(struct macb_device *macb) +{ + return MACB_BFEXT(IDNUM, macb_readl(macb, MID)) == 0x2; +} + static void macb_mdio_write(struct macb_device *macb, u8 reg, u16 value) { unsigned long netctl; @@ -163,7 +169,12 @@ static u16 macb_mdio_read(struct macb_device *macb, u8 reg) return MACB_BFEXT(DATA, frame); } -#if defined(CONFIG_CMD_MII) +void __weak arch_get_mdio_control(const char *name) +{ + return; +} + +#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) { @@ -173,6 +184,7 @@ int macb_miiphy_read(const char *devname, u8 phy_adr, u8 reg, u16 *value) if ( macb->phy_addr != phy_adr ) return -1; + arch_get_mdio_control(devname); *value = macb_mdio_read(macb, reg); return 0; @@ -186,6 +198,7 @@ int macb_miiphy_write(const char *devname, u8 phy_adr, u8 reg, u16 value) if ( macb->phy_addr != phy_adr ) return -1; + arch_get_mdio_control(devname); macb_mdio_write(macb, reg, value); return 0; @@ -372,11 +385,15 @@ static int macb_phy_find(struct macb_device *macb) static int macb_phy_init(struct macb_device *macb) { struct eth_device *netdev = &macb->netdev; +#ifdef CONFIG_PHYLIB + struct phy_device *phydev; +#endif u32 ncfgr; u16 phy_id, status, adv, lpa; int media, speed, duplex; int i; + arch_get_mdio_control(netdev->name); #ifdef CONFIG_MACB_SEARCH_PHY /* Auto-detect phy_addr */ if (!macb_phy_find(macb)) { @@ -391,6 +408,13 @@ static int macb_phy_init(struct macb_device *macb) return 0; } +#ifdef CONFIG_PHYLIB + phydev->bus = macb->bus; + phydev->dev = netdev; + phydev->addr = macb->phy_addr; + phy_config(phydev); +#endif + status = macb_mdio_read(macb, MII_BMSR); if (!(status & BMSR_LSTATUS)) { /* Try to re-negotiate if we don't have link already. */ @@ -408,28 +432,64 @@ static int macb_phy_init(struct macb_device *macb) printf("%s: link down (status: 0x%04x)\n", netdev->name, status); return 0; - } else { - adv = macb_mdio_read(macb, MII_ADVERTISE); - lpa = macb_mdio_read(macb, MII_LPA); - media = mii_nway_result(lpa & adv); - speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) - ? 1 : 0); - duplex = (media & ADVERTISE_FULL) ? 1 : 0; - printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", - netdev->name, - speed ? "100" : "10", - duplex ? "full" : "half", - lpa); - - ncfgr = macb_readl(macb, NCFGR); - ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); - if (speed) - ncfgr |= MACB_BIT(SPD); - if (duplex) - ncfgr |= MACB_BIT(FD); - macb_writel(macb, NCFGR, ncfgr); - return 1; } + + /* First check for GMAC */ + if (macb_is_gem(macb)) { + lpa = macb_mdio_read(macb, MII_STAT1000); + if (lpa & (1 << 11)) { + speed = 1000; + duplex = 1; + } else { + if (lpa & (1 << 10)) { + speed = 1000; + duplex = 1; + } else { + speed = 0; + } + } + + if (speed == 1000) { + printf("%s: link up, %dMbps %s-duplex (lpa: 0x%04x)\n", + netdev->name, + speed, + duplex ? "full" : "half", + lpa); + + ncfgr = macb_readl(macb, NCFGR); + ncfgr &= ~(GEM_BIT(GBE) | MACB_BIT(SPD) | MACB_BIT(FD)); + if (speed) + ncfgr |= GEM_BIT(GBE); + if (duplex) + ncfgr |= MACB_BIT(FD); + macb_writel(macb, NCFGR, ncfgr); + + return 1; + } + } + + /* fall back for EMAC checking */ + adv = macb_mdio_read(macb, MII_ADVERTISE); + lpa = macb_mdio_read(macb, MII_LPA); + media = mii_nway_result(lpa & adv); + speed = (media & (ADVERTISE_100FULL | ADVERTISE_100HALF) + ? 1 : 0); + duplex = (media & ADVERTISE_FULL) ? 1 : 0; + printf("%s: link up, %sMbps %s-duplex (lpa: 0x%04x)\n", + netdev->name, + speed ? "100" : "10", + duplex ? "full" : "half", + lpa); + + ncfgr = macb_readl(macb, NCFGR); + ncfgr &= ~(MACB_BIT(SPD) | MACB_BIT(FD)); + if (speed) + ncfgr |= MACB_BIT(SPD); + if (duplex) + ncfgr |= MACB_BIT(FD); + macb_writel(macb, NCFGR, ncfgr); + + return 1; } static int macb_init(struct eth_device *netdev, bd_t *bd) @@ -464,26 +524,28 @@ static int macb_init(struct eth_device *netdev, bd_t *bd) macb_writel(macb, RBQP, macb->rx_ring_dma); macb_writel(macb, TBQP, macb->tx_ring_dma); + if (macb_is_gem(macb)) { +#ifdef CONFIG_RGMII + gem_writel(macb, UR, GEM_BIT(RGMII)); +#else + gem_writel(macb, UR, 0); +#endif + } else { /* choose RMII or MII mode. This depends on the board */ #ifdef CONFIG_RMII -#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ - defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \ - defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \ - defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5) +#ifdef CONFIG_AT91FAMILY macb_writel(macb, USRIO, MACB_BIT(RMII) | MACB_BIT(CLKEN)); #else macb_writel(macb, USRIO, 0); #endif #else -#if defined(CONFIG_AT91CAP9) || defined(CONFIG_AT91SAM9260) || \ - defined(CONFIG_AT91SAM9263) || defined(CONFIG_AT91SAM9G20) || \ - defined(CONFIG_AT91SAM9G45) || defined(CONFIG_AT91SAM9M10G45) || \ - defined(CONFIG_AT91SAM9XE) || defined(CONFIG_AT91SAM9X5) +#ifdef CONFIG_AT91FAMILY macb_writel(macb, USRIO, MACB_BIT(CLKEN)); #else macb_writel(macb, USRIO, MACB_BIT(MII)); #endif #endif /* CONFIG_RMII */ + } if (!macb_phy_init(macb)) return -1; @@ -527,11 +589,48 @@ static int macb_write_hwaddr(struct eth_device *dev) return 0; } +static u32 macb_mdc_clk_div(int id, struct macb_device *macb) +{ + u32 config; + unsigned long macb_hz = get_macb_pclk_rate(id); + + if (macb_hz < 20000000) + config = MACB_BF(CLK, MACB_CLK_DIV8); + else if (macb_hz < 40000000) + config = MACB_BF(CLK, MACB_CLK_DIV16); + else if (macb_hz < 80000000) + config = MACB_BF(CLK, MACB_CLK_DIV32); + else + config = MACB_BF(CLK, MACB_CLK_DIV64); + + return config; +} + +static u32 gem_mdc_clk_div(int id, struct macb_device *macb) +{ + u32 config; + unsigned long macb_hz = get_macb_pclk_rate(id); + + if (macb_hz < 20000000) + config = GEM_BF(CLK, GEM_CLK_DIV8); + else if (macb_hz < 40000000) + config = GEM_BF(CLK, GEM_CLK_DIV16); + else if (macb_hz < 80000000) + config = GEM_BF(CLK, GEM_CLK_DIV32); + else if (macb_hz < 120000000) + config = GEM_BF(CLK, GEM_CLK_DIV48); + else if (macb_hz < 160000000) + config = GEM_BF(CLK, GEM_CLK_DIV64); + else + config = GEM_BF(CLK, GEM_CLK_DIV96); + + return config; +} + int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) { struct macb_device *macb; struct eth_device *netdev; - unsigned long macb_hz; u32 ncfgr; macb = malloc(sizeof(struct macb_device)); @@ -555,7 +654,11 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) macb->regs = regs; macb->phy_addr = phy_addr; - sprintf(netdev->name, "macb%d", id); + if (macb_is_gem(macb)) + sprintf(netdev->name, "gmac%d", id); + else + sprintf(netdev->name, "macb%d", id); + netdev->init = macb_init; netdev->halt = macb_halt; netdev->send = macb_send; @@ -566,22 +669,20 @@ int macb_eth_initialize(int id, void *regs, unsigned int phy_addr) * Do some basic initialization so that we at least can talk * to the PHY */ - macb_hz = get_macb_pclk_rate(id); - if (macb_hz < 20000000) - ncfgr = MACB_BF(CLK, MACB_CLK_DIV8); - else if (macb_hz < 40000000) - ncfgr = MACB_BF(CLK, MACB_CLK_DIV16); - else if (macb_hz < 80000000) - ncfgr = MACB_BF(CLK, MACB_CLK_DIV32); - else - ncfgr = MACB_BF(CLK, MACB_CLK_DIV64); + if (macb_is_gem(macb)) { + ncfgr = gem_mdc_clk_div(id, macb); + ncfgr |= GEM_BF(DBW, 1); + } else { + ncfgr = macb_mdc_clk_div(id, macb); + } macb_writel(macb, NCFGR, ncfgr); eth_register(netdev); -#if defined(CONFIG_CMD_MII) +#if defined(CONFIG_CMD_MII) || defined(CONFIG_PHYLIB) miiphy_register(netdev->name, macb_miiphy_read, macb_miiphy_write); + macb->bus = miiphy_get_dev_by_name(netdev->name); #endif return 0; } diff --git a/drivers/net/macb.h b/drivers/net/macb.h index f92a20c..68eef00 100644 --- a/drivers/net/macb.h +++ b/drivers/net/macb.h @@ -26,6 +26,7 @@ #define MACB_NCR 0x0000 #define MACB_NCFGR 0x0004 #define MACB_NSR 0x0008 +#define GEM_UR 0x000c #define MACB_TSR 0x0014 #define MACB_RBQP 0x0018 #define MACB_TBQP 0x001c @@ -71,6 +72,7 @@ #define MACB_TPQ 0x00bc #define MACB_USRIO 0x00c0 #define MACB_WOL 0x00c4 +#define MACB_MID 0x00fc /* Bitfields in NCR */ #define MACB_LB_OFFSET 0 @@ -138,6 +140,13 @@ #define MACB_IRXFCS_OFFSET 19 #define MACB_IRXFCS_SIZE 1 +#define GEM_GBE_OFFSET 10 +#define GEM_GBE_SIZE 1 +#define GEM_CLK_OFFSET 18 +#define GEM_CLK_SIZE 3 +#define GEM_DBW_OFFSET 21 +#define GEM_DBW_SIZE 2 + /* Bitfields in NSR */ #define MACB_NSR_LINK_OFFSET 0 #define MACB_NSR_LINK_SIZE 1 @@ -146,6 +155,10 @@ #define MACB_IDLE_OFFSET 2 #define MACB_IDLE_SIZE 1 +/* Bitfields in UR */ +#define GEM_RGMII_OFFSET 0 +#define GEM_RGMII_SIZE 1 + /* Bitfields in TSR */ #define MACB_UBR_OFFSET 0 #define MACB_UBR_SIZE 1 @@ -240,12 +253,25 @@ #define MACB_WOL_MTI_OFFSET 19 #define MACB_WOL_MTI_SIZE 1 +/* Bitfields in MID */ +#define MACB_IDNUM_OFFSET 16 +#define MACB_IDNUM_SIZE 16 + +/* Bitfields in DCFG1 */ /* Constants for CLK */ #define MACB_CLK_DIV8 0 #define MACB_CLK_DIV16 1 #define MACB_CLK_DIV32 2 #define MACB_CLK_DIV64 3 +/* GEM specific constants for CLK */ +#define GEM_CLK_DIV8 0 +#define GEM_CLK_DIV16 1 +#define GEM_CLK_DIV32 2 +#define GEM_CLK_DIV48 3 +#define GEM_CLK_DIV64 4 +#define GEM_CLK_DIV96 5 + /* Constants for MAN register */ #define MACB_MAN_SOF 1 #define MACB_MAN_WRITE 1 @@ -255,21 +281,38 @@ /* Bit manipulation macros */ #define MACB_BIT(name) \ (1 << MACB_##name##_OFFSET) -#define MACB_BF(name,value) \ +#define MACB_BF(name, value) \ (((value) & ((1 << MACB_##name##_SIZE) - 1)) \ << MACB_##name##_OFFSET) -#define MACB_BFEXT(name,value)\ +#define MACB_BFEXT(name, value)\ (((value) >> MACB_##name##_OFFSET) \ & ((1 << MACB_##name##_SIZE) - 1)) -#define MACB_BFINS(name,value,old) \ +#define MACB_BFINS(name, value, old) \ (((old) & ~(((1 << MACB_##name##_SIZE) - 1) \ << MACB_##name##_OFFSET)) \ - | MACB_BF(name,value)) + | MACB_BF(name, value)) + +#define GEM_BIT(name) \ + (1 << GEM_##name##_OFFSET) +#define GEM_BF(name, value) \ + (((value) & ((1 << GEM_##name##_SIZE) - 1)) \ + << GEM_##name##_OFFSET) +#define GEM_BFEXT(name, value)\ + (((value) >> GEM_##name##_OFFSET) \ + & ((1 << GEM_##name##_SIZE) - 1)) +#define GEM_BFINS(name, value, old) \ + (((old) & ~(((1 << GEM_##name##_SIZE) - 1) \ + << GEM_##name##_OFFSET)) \ + | GEM_BF(name, value)) /* Register access macros */ -#define macb_readl(port,reg) \ +#define macb_readl(port, reg) \ readl((port)->regs + MACB_##reg) -#define macb_writel(port,reg,value) \ +#define macb_writel(port, reg, value) \ writel((value), (port)->regs + MACB_##reg) +#define gem_readl(port, reg) \ + readl((port)->regs + GEM_##reg) +#define gem_writel(port, reg, value) \ + writel((value), (port)->regs + GEM_##reg) #endif /* __DRIVERS_MACB_H__ */ diff --git a/drivers/net/mvgbe.c b/drivers/net/mvgbe.c index 47bf27c..319fe8a 100644 --- a/drivers/net/mvgbe.c +++ b/drivers/net/mvgbe.c @@ -43,6 +43,8 @@ #include <asm/arch/kirkwood.h> #elif defined(CONFIG_ORION5X) #include <asm/arch/orion5x.h> +#elif defined(CONFIG_DOVE) +#include <asm/arch/dove.h> #endif #include "mvgbe.h" @@ -52,7 +54,7 @@ DECLARE_GLOBAL_DATA_PTR; #define MV_PHY_ADR_REQUEST 0xee #define MVGBE_SMI_REG (((struct mvgbe_registers *)MVGBE0_BASE)->smi) -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#if defined(CONFIG_PHYLIB) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII) /* * smi_reg_read - miiphy_read callback function. * @@ -184,6 +186,25 @@ static int smi_reg_write(const char *devname, u8 phy_adr, u8 reg_ofs, u16 data) } #endif +#if defined(CONFIG_PHYLIB) +int mvgbe_phy_read(struct mii_dev *bus, int phy_addr, int dev_addr, + int reg_addr) +{ + u16 data; + int ret; + ret = smi_reg_read(bus->name, phy_addr, reg_addr, &data); + if (ret) + return ret; + return data; +} + +int mvgbe_phy_write(struct mii_dev *bus, int phy_addr, int dev_addr, + int reg_addr, u16 data) +{ + return smi_reg_write(bus->name, phy_addr, reg_addr, data); +} +#endif + /* Stop and checks all queues */ static void stop_queue(u32 * qreg) { @@ -467,8 +488,9 @@ static int mvgbe_init(struct eth_device *dev) /* Enable port Rx. */ MVGBE_REG_WR(regs->rqc, (1 << RXUQ)); -#if (defined (CONFIG_MII) || defined (CONFIG_CMD_MII)) \ - && defined (CONFIG_SYS_FAULT_ECHO_LINK_DOWN) +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && \ + !defined(CONFIG_PHYLIB) && \ + defined(CONFIG_SYS_FAULT_ECHO_LINK_DOWN) /* Wait up to 5s for the link status */ for (i = 0; i < 5; i++) { u16 phyadr; @@ -647,6 +669,45 @@ static int mvgbe_recv(struct eth_device *dev) return 0; } +#if defined(CONFIG_PHYLIB) +int mvgbe_phylib_init(struct eth_device *dev, int phyid) +{ + struct mii_dev *bus; + struct phy_device *phydev; + int ret; + + bus = mdio_alloc(); + if (!bus) { + printf("mdio_alloc failed\n"); + return -ENOMEM; + } + bus->read = mvgbe_phy_read; + bus->write = mvgbe_phy_write; + sprintf(bus->name, dev->name); + + ret = mdio_register(bus); + if (ret) { + printf("mdio_register failed\n"); + free(bus); + return -ENOMEM; + } + + /* Set phy address of the port */ + mvgbe_phy_write(bus, MV_PHY_ADR_REQUEST, 0, MV_PHY_ADR_REQUEST, phyid); + + phydev = phy_connect(bus, phyid, dev, PHY_INTERFACE_MODE_RGMII); + if (!phydev) { + printf("phy_connect failed\n"); + return -ENODEV; + } + + phy_config(phydev); + phy_startup(phydev); + + return 0; +} +#endif + int mvgbe_initialize(bd_t *bis) { struct mvgbe_device *dmvgbe; @@ -729,7 +790,9 @@ error1: eth_register(dev); -#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +#if defined(CONFIG_PHYLIB) + mvgbe_phylib_init(dev, PHY_BASE_ADR + devnum); +#elif defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register(dev->name, smi_reg_read, smi_reg_write); /* Set phy address of the port */ miiphy_write(dev->name, MV_PHY_ADR_REQUEST, diff --git a/drivers/net/mvgbe.h b/drivers/net/mvgbe.h index d8a5429..7f5d98f 100644 --- a/drivers/net/mvgbe.h +++ b/drivers/net/mvgbe.h @@ -308,10 +308,17 @@ #define EBAR_TARGET_GUNIT 0x00000007 /* Window attrib */ +#if defined(CONFIG_DOVE) +#define EBAR_DRAM_CS0 0x00000000 +#define EBAR_DRAM_CS1 0x00000000 +#define EBAR_DRAM_CS2 0x00000000 +#define EBAR_DRAM_CS3 0x00000000 +#else #define EBAR_DRAM_CS0 0x00000E00 #define EBAR_DRAM_CS1 0x00000D00 #define EBAR_DRAM_CS2 0x00000B00 #define EBAR_DRAM_CS3 0x00000700 +#endif /* DRAM Target interface */ #define EBAR_DRAM_NO_CACHE_COHERENCY 0x00000000 diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index af5f4b8..695873e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -35,6 +35,7 @@ COBJS-$(CONFIG_PHY_ATHEROS) += atheros.o COBJS-$(CONFIG_PHY_BROADCOM) += broadcom.o COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o +COBJS-$(CONFIG_PHY_ICPLUS) += icplus.o COBJS-$(CONFIG_PHY_LXT) += lxt.o COBJS-$(CONFIG_PHY_MARVELL) += marvell.o COBJS-$(CONFIG_PHY_MICREL) += micrel.o diff --git a/drivers/net/phy/atheros.c b/drivers/net/phy/atheros.c index 9b3808b..09d4879 100644 --- a/drivers/net/phy/atheros.c +++ b/drivers/net/phy/atheros.c @@ -16,7 +16,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * - * Copyright 2011 Freescale Semiconductor, Inc. + * Copyright 2011, 2013 Freescale Semiconductor, Inc. * author Andy Fleming * */ @@ -30,6 +30,27 @@ static int ar8021_config(struct phy_device *phydev) return 0; } +static int ar8035_config(struct phy_device *phydev) +{ + int regval; + + phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x0007); + phy_write(phydev, MDIO_DEVAD_NONE, 0xe, 0x8016); + phy_write(phydev, MDIO_DEVAD_NONE, 0xd, 0x4007); + regval = phy_read(phydev, MDIO_DEVAD_NONE, 0xe); + phy_write(phydev, MDIO_DEVAD_NONE, 0xe, (regval|0x0018)); + + phy_write(phydev, MDIO_DEVAD_NONE, 0x1d, 0x05); + regval = phy_read(phydev, MDIO_DEVAD_NONE, 0x1e); + phy_write(phydev, MDIO_DEVAD_NONE, 0x1e, (regval|0x0100)); + + genphy_config_aneg(phydev); + + phy_reset(phydev); + + return 0; +} + static struct phy_driver AR8021_driver = { .name = "AR8021", .uid = 0x4dd040, @@ -40,9 +61,31 @@ static struct phy_driver AR8021_driver = { .shutdown = genphy_shutdown, }; +static struct phy_driver AR8031_driver = { + .name = "AR8031", + .uid = 0x4dd074, + .mask = 0xfffff0, + .features = PHY_GBIT_FEATURES, + .config = genphy_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + +static struct phy_driver AR8035_driver = { + .name = "AR8035", + .uid = 0x4dd072, + .mask = 0x4fffff, + .features = PHY_GBIT_FEATURES, + .config = ar8035_config, + .startup = genphy_startup, + .shutdown = genphy_shutdown, +}; + int phy_atheros_init(void) { phy_register(&AR8021_driver); + phy_register(&AR8031_driver); + phy_register(&AR8035_driver); return 0; } diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c new file mode 100644 index 0000000..dd5c592 --- /dev/null +++ b/drivers/net/phy/icplus.c @@ -0,0 +1,94 @@ +/* + * ICPlus PHY drivers + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Copyright (c) 2007 Freescale Semiconductor, Inc. + * + */ +#include <phy.h> + +/* IP101A/G - IP1001 */ +#define IP10XX_SPEC_CTRL_STATUS 16 /* Spec. Control Register */ +#define IP1001_SPEC_CTRL_STATUS_2 20 /* IP1001 Spec. Control Reg 2 */ +#define IP1001_PHASE_SEL_MASK 3 /* IP1001 RX/TXPHASE_SEL */ +#define IP1001_APS_ON 11 /* IP1001 APS Mode bit */ +#define IP101A_G_APS_ON 2 /* IP101A/G APS Mode bit */ +#define IP101A_G_IRQ_CONF_STATUS 0x11 /* Conf Info IRQ & Status Reg */ +#define IP101A_G_IRQ_PIN_USED (1<<15) /* INTR pin used */ +#define IP101A_G_IRQ_DEFAULT IP101A_G_IRQ_PIN_USED + +static int ip1001_config(struct phy_device *phydev) +{ + int c; + + /* Enable Auto Power Saving mode */ + c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2); + if (c < 0) + return c; + c |= IP1001_APS_ON; + c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c); + if (c < 0) + return c; + + /* INTR pin used: speed/link/duplex will cause an interrupt */ + c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS, + IP101A_G_IRQ_DEFAULT); + if (c < 0) + return c; + + if (phydev->interface == PHY_INTERFACE_MODE_RGMII) { + /* + * Additional delay (2ns) used to adjust RX clock phase + * at RGMII interface + */ + c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS); + if (c < 0) + return c; + + c |= IP1001_PHASE_SEL_MASK; + c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS, + c); + if (c < 0) + return c; + } + + return 0; +} + +static int ip1001_startup(struct phy_device *phydev) +{ + genphy_update_link(phydev); + genphy_parse_link(phydev); + + return 0; +} +static struct phy_driver IP1001_driver = { + .name = "ICPlus IP1001", + .uid = 0x02430d90, + .mask = 0x0ffffff0, + .features = PHY_GBIT_FEATURES, + .config = &ip1001_config, + .startup = &ip1001_startup, + .shutdown = &genphy_shutdown, +}; + +int phy_icplus_init(void) +{ + phy_register(&IP1001_driver); + + return 0; +} diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index 46801c7..8397e32 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -89,6 +89,12 @@ #define MIIM_88E1149_PHY_PAGE 29 +/* 88E1310 PHY defines */ +#define MIIM_88E1310_PHY_LED_CTRL 16 +#define MIIM_88E1310_PHY_IRQ_EN 18 +#define MIIM_88E1310_PHY_RGMII_CTRL 21 +#define MIIM_88E1310_PHY_PAGE 22 + /* Marvell 88E1011S */ static int m88e1011s_config(struct phy_device *phydev) { @@ -394,6 +400,37 @@ static int m88e1149_config(struct phy_device *phydev) return 0; } +/* Marvell 88E1310 */ +static int m88e1310_config(struct phy_device *phydev) +{ + u16 reg; + + /* LED link and activity */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL); + reg = (reg & ~0xf) | 0x1; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_LED_CTRL, reg); + + /* Set LED2/INT to INT mode, low active */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0003); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN); + reg = (reg & 0x77ff) | 0x0880; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_IRQ_EN, reg); + + /* Set RGMII delay */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0002); + reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL); + reg |= 0x0030; + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_RGMII_CTRL, reg); + + /* Ensure to return to page 0 */ + phy_write(phydev, MDIO_DEVAD_NONE, MIIM_88E1310_PHY_PAGE, 0x0000); + + genphy_config_aneg(phydev); + phy_reset(phydev); + + return 0; +} static struct phy_driver M88E1011S_driver = { .name = "Marvell 88E1011S", @@ -475,8 +512,19 @@ static struct phy_driver M88E1518_driver = { .shutdown = &genphy_shutdown, }; +static struct phy_driver M88E1310_driver = { + .name = "Marvell 88E1310", + .uid = 0x01410e90, + .mask = 0xffffff0, + .features = PHY_GBIT_FEATURES, + .config = &m88e1310_config, + .startup = &m88e1011s_startup, + .shutdown = &genphy_shutdown, +}; + int phy_marvell_init(void) { + phy_register(&M88E1310_driver); phy_register(&M88E1149S_driver); phy_register(&M88E1145_driver); phy_register(&M88E1121R_driver); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 30f3264..aa9cbcf 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -18,6 +18,7 @@ * * Copyright 2010-2011 Freescale Semiconductor, Inc. * author Andy Fleming + * (C) 2012 NetModule AG, David Andrey, added KSZ9031 * */ #include <config.h> @@ -52,16 +53,46 @@ static struct phy_driver KS8721_driver = { }; #endif + +/** + * KSZ9021 - KSZ9031 common + */ + +#define MII_KSZ90xx_PHY_CTL 0x1f +#define MIIM_KSZ90xx_PHYCTL_1000 (1 << 6) +#define MIIM_KSZ90xx_PHYCTL_100 (1 << 5) +#define MIIM_KSZ90xx_PHYCTL_10 (1 << 4) +#define MIIM_KSZ90xx_PHYCTL_DUPLEX (1 << 3) + +static int ksz90xx_startup(struct phy_device *phydev) +{ + unsigned phy_ctl; + genphy_update_link(phydev); + phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ90xx_PHY_CTL); + + if (phy_ctl & MIIM_KSZ90xx_PHYCTL_DUPLEX) + phydev->duplex = DUPLEX_FULL; + else + phydev->duplex = DUPLEX_HALF; + + if (phy_ctl & MIIM_KSZ90xx_PHYCTL_1000) + phydev->speed = SPEED_1000; + else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_100) + phydev->speed = SPEED_100; + else if (phy_ctl & MIIM_KSZ90xx_PHYCTL_10) + phydev->speed = SPEED_10; + return 0; +} #ifdef CONFIG_PHY_MICREL_KSZ9021 -/* ksz9021 PHY Registers */ + +/* + * KSZ9021 + */ + +/* PHY Registers */ #define MII_KSZ9021_EXTENDED_CTRL 0x0b #define MII_KSZ9021_EXTENDED_DATAW 0x0c #define MII_KSZ9021_EXTENDED_DATAR 0x0d -#define MII_KSZ9021_PHY_CTL 0x1f -#define MIIM_KSZ9021_PHYCTL_1000 (1 << 6) -#define MIIM_KSZ9021_PHYCTL_100 (1 << 5) -#define MIIM_KSZ9021_PHYCTL_10 (1 << 4) -#define MIIM_KSZ9021_PHYCTL_DUPLEX (1 << 3) #define CTRL1000_PREFER_MASTER (1 << 10) #define CTRL1000_CONFIG_MASTER (1 << 11) @@ -106,37 +137,64 @@ static int ksz9021_config(struct phy_device *phydev) return 0; } -static int ksz9021_startup(struct phy_device *phydev) -{ - unsigned phy_ctl; - genphy_update_link(phydev); - phy_ctl = phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9021_PHY_CTL); - - if (phy_ctl & MIIM_KSZ9021_PHYCTL_DUPLEX) - phydev->duplex = DUPLEX_FULL; - else - phydev->duplex = DUPLEX_HALF; - - if (phy_ctl & MIIM_KSZ9021_PHYCTL_1000) - phydev->speed = SPEED_1000; - else if (phy_ctl & MIIM_KSZ9021_PHYCTL_100) - phydev->speed = SPEED_100; - else if (phy_ctl & MIIM_KSZ9021_PHYCTL_10) - phydev->speed = SPEED_10; - return 0; -} - static struct phy_driver ksz9021_driver = { .name = "Micrel ksz9021", .uid = 0x221610, .mask = 0xfffff0, .features = PHY_GBIT_FEATURES, .config = &ksz9021_config, - .startup = &ksz9021_startup, + .startup = &ksz90xx_startup, .shutdown = &genphy_shutdown, }; #endif +/** + * KSZ9031 + */ +/* PHY Registers */ +#define MII_KSZ9031_MMD_ACCES_CTRL 0x0d +#define MII_KSZ9031_MMD_REG_DATA 0x0e + +/* Accessors to extended registers*/ +int ksz9031_phy_extended_write(struct phy_device *phydev, + int devaddr, int regnum, u16 mode, u16 val) +{ + /*select register addr for mmd*/ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, devaddr); + /*select register for mmd*/ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_REG_DATA, regnum); + /*setup mode*/ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, (mode | devaddr)); + /*write the value*/ + return phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_REG_DATA, val); +} + +int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, + int regnum, u16 mode) +{ + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, devaddr); + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_REG_DATA, regnum); + phy_write(phydev, MDIO_DEVAD_NONE, + MII_KSZ9031_MMD_ACCES_CTRL, (devaddr | mode)); + return phy_read(phydev, MDIO_DEVAD_NONE, MII_KSZ9031_MMD_REG_DATA); +} + +static struct phy_driver ksz9031_driver = { + .name = "Micrel ksz9031", + .uid = 0x221620, + .mask = 0xfffffe, + .features = PHY_GBIT_FEATURES, + .config = &genphy_config, + .startup = &ksz90xx_startup, + .shutdown = &genphy_shutdown, +}; + int phy_micrel_init(void) { phy_register(&KSZ804_driver); @@ -145,5 +203,6 @@ int phy_micrel_init(void) #else phy_register(&KS8721_driver); #endif + phy_register(&ksz9031_driver); return 0; } diff --git a/drivers/net/phy/natsemi.c b/drivers/net/phy/natsemi.c index ea60ac1..6dc7ed5 100644 --- a/drivers/net/phy/natsemi.c +++ b/drivers/net/phy/natsemi.c @@ -22,6 +22,42 @@ */ #include <phy.h> +/* NatSemi DP83630 */ + +#define DP83630_PHY_PAGESEL_REG 0x13 +#define DP83630_PHY_PTP_COC_REG 0x14 +#define DP83630_PHY_PTP_CLKOUT_EN (1<<15) +#define DP83630_PHY_RBR_REG 0x17 + +static int dp83630_config(struct phy_device *phydev) +{ + int ptp_coc_reg; + + phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET); + phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0x6); + ptp_coc_reg = phy_read(phydev, MDIO_DEVAD_NONE, + DP83630_PHY_PTP_COC_REG); + ptp_coc_reg &= ~DP83630_PHY_PTP_CLKOUT_EN; + phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PTP_COC_REG, + ptp_coc_reg); + phy_write(phydev, MDIO_DEVAD_NONE, DP83630_PHY_PAGESEL_REG, 0); + + genphy_config_aneg(phydev); + + return 0; +} + +static struct phy_driver DP83630_driver = { + .name = "NatSemi DP83630", + .uid = 0x20005ce1, + .mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .config = &dp83630_config, + .startup = &genphy_startup, + .shutdown = &genphy_shutdown, +}; + + /* DP83865 Link and Auto-Neg Status Register */ #define MIIM_DP83865_LANR 0x11 #define MIIM_DP83865_SPD_MASK 0x0018 @@ -90,6 +126,7 @@ static struct phy_driver DP83865_driver = { int phy_natsemi_init(void) { + phy_register(&DP83630_driver); phy_register(&DP83865_driver); return 0; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index f8c5481..7c0eaec 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -75,6 +75,10 @@ static int genphy_config_advert(struct phy_device *phydev) adv |= ADVERTISE_PAUSE_CAP; if (advertise & ADVERTISED_Asym_Pause) adv |= ADVERTISE_PAUSE_ASYM; + if (advertise & ADVERTISED_1000baseX_Half) + adv |= ADVERTISE_1000XHALF; + if (advertise & ADVERTISED_1000baseX_Full) + adv |= ADVERTISE_1000XFULL; if (adv != oldadv) { err = phy_write(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE, adv); @@ -280,7 +284,7 @@ int genphy_update_link(struct phy_device *phydev) * * Stolen from Linux's mii.c and phy_device.c */ -static int genphy_parse_link(struct phy_device *phydev) +int genphy_parse_link(struct phy_device *phydev) { int mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR); @@ -288,6 +292,7 @@ static int genphy_parse_link(struct phy_device *phydev) if (mii_reg & BMSR_ANEGCAPABLE) { u32 lpa = 0; u32 gblpa = 0; + u32 estatus = 0; /* Check for gigabit capability */ if (mii_reg & BMSR_ERCAP) { @@ -327,6 +332,18 @@ static int genphy_parse_link(struct phy_device *phydev) } else if (lpa & LPA_10FULL) phydev->duplex = DUPLEX_FULL; + + if (mii_reg & BMSR_ESTATEN) + estatus = phy_read(phydev, MDIO_DEVAD_NONE, + MII_ESTATUS); + + if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_XHALF | + ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) { + phydev->speed = SPEED_1000; + if (estatus & (ESTATUS_1000_XFULL | ESTATUS_1000_TFULL)) + phydev->duplex = DUPLEX_FULL; + } + } else { u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR); @@ -384,6 +401,10 @@ int genphy_config(struct phy_device *phydev) features |= SUPPORTED_1000baseT_Full; if (val & ESTATUS_1000_THALF) features |= SUPPORTED_1000baseT_Half; + if (val & ESTATUS_1000_XFULL) + features |= SUPPORTED_1000baseX_Full; + if (val & ESTATUS_1000_XHALF) + features |= SUPPORTED_1000baseX_Full; } phydev->supported = features; @@ -433,6 +454,9 @@ int phy_init(void) #ifdef CONFIG_PHY_ET1011C phy_et1011c_init(); #endif +#ifdef CONFIG_PHY_ICPLUS + phy_icplus_init(); +#endif #ifdef CONFIG_PHY_LXT phy_lxt_init(); #endif diff --git a/drivers/net/sunxi_wemac.c b/drivers/net/sunxi_wemac.c new file mode 100644 index 0000000..1db3529 --- /dev/null +++ b/drivers/net/sunxi_wemac.c @@ -0,0 +1,533 @@ +/* + * sunxi_wemac.c -- Allwinner A10 ethernet driver + * + * (C) Copyright 2012, Stefan Roese <sr@denx.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT 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 <common.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> +#include <linux/err.h> +#include <asm/io.h> +#include <asm/arch/clock.h> +#include <asm/arch/gpio.h> + +/* EMAC register */ +struct wemac_regs { + u32 ctl; /* 0x00 */ + u32 tx_mode; /* 0x04 */ + u32 tx_flow; /* 0x08 */ + u32 tx_ctl0; /* 0x0c */ + u32 tx_ctl1; /* 0x10 */ + u32 tx_ins; /* 0x14 */ + u32 tx_pl0; /* 0x18 */ + u32 tx_pl1; /* 0x1c */ + u32 tx_sta; /* 0x20 */ + u32 tx_io_data; /* 0x24 */ + u32 tx_io_data1; /* 0x28 */ + u32 tx_tsvl0; /* 0x2c */ + u32 tx_tsvh0; /* 0x30 */ + u32 tx_tsvl1; /* 0x34 */ + u32 tx_tsvh1; /* 0x38 */ + u32 rx_ctl; /* 0x3c */ + u32 rx_hash0; /* 0x40 */ + u32 rx_hash1; /* 0x44 */ + u32 rx_sta; /* 0x48 */ + u32 rx_io_data; /* 0x4c */ + u32 rx_fbc; /* 0x50 */ + u32 int_ctl; /* 0x54 */ + u32 int_sta; /* 0x58 */ + u32 mac_ctl0; /* 0x5c */ + u32 mac_ctl1; /* 0x60 */ + u32 mac_ipgt; /* 0x64 */ + u32 mac_ipgr; /* 0x68 */ + u32 mac_clrt; /* 0x6c */ + u32 mac_maxf; /* 0x70 */ + u32 mac_supp; /* 0x74 */ + u32 mac_test; /* 0x78 */ + u32 mac_mcfg; /* 0x7c */ + u32 mac_mcmd; /* 0x80 */ + u32 mac_madr; /* 0x84 */ + u32 mac_mwtd; /* 0x88 */ + u32 mac_mrdd; /* 0x8c */ + u32 mac_mind; /* 0x90 */ + u32 mac_ssrr; /* 0x94 */ + u32 mac_a0; /* 0x98 */ + u32 mac_a1; /* 0x9c */ +}; + +/* SRAMC register */ +struct sunxi_sramc_regs { + u32 ctrl0; + u32 ctrl1; +}; + +/* 0: Disable 1: Aborted frame enable(default) */ +#define EMAC_TX_AB_M (0x1 << 0) +/* 0: CPU 1: DMA(default) */ +#define EMAC_TX_TM (0x1 << 1) + +#define EMAC_TX_SETUP (0) + +/* 0: DRQ asserted 1: DRQ automatically(default) */ +#define EMAC_RX_DRQ_MODE (0x1 << 1) +/* 0: CPU 1: DMA(default) */ +#define EMAC_RX_TM (0x1 << 2) +/* 0: Normal(default) 1: Pass all Frames */ +#define EMAC_RX_PA (0x1 << 4) +/* 0: Normal(default) 1: Pass Control Frames */ +#define EMAC_RX_PCF (0x1 << 5) +/* 0: Normal(default) 1: Pass Frames with CRC Error */ +#define EMAC_RX_PCRCE (0x1 << 6) +/* 0: Normal(default) 1: Pass Frames with Length Error */ +#define EMAC_RX_PLE (0x1 << 7) +/* 0: Normal 1: Pass Frames length out of range(default) */ +#define EMAC_RX_POR (0x1 << 8) +/* 0: Not accept 1: Accept unicast Packets(default) */ +#define EMAC_RX_UCAD (0x1 << 16) +/* 0: Normal(default) 1: DA Filtering */ +#define EMAC_RX_DAF (0x1 << 17) +/* 0: Not accept 1: Accept multicast Packets(default) */ +#define EMAC_RX_MCO (0x1 << 20) +/* 0: Disable(default) 1: Enable Hash filter */ +#define EMAC_RX_MHF (0x1 << 21) +/* 0: Not accept 1: Accept Broadcast Packets(default) */ +#define EMAC_RX_BCO (0x1 << 22) +/* 0: Disable(default) 1: Enable SA Filtering */ +#define EMAC_RX_SAF (0x1 << 24) +/* 0: Normal(default) 1: Inverse Filtering */ +#define EMAC_RX_SAIF (0x1 << 25) + +#define EMAC_RX_SETUP (EMAC_RX_POR | EMAC_RX_UCAD | EMAC_RX_DAF | \ + EMAC_RX_MCO | EMAC_RX_BCO) + +/* 0: Disable 1: Enable Receive Flow Control(default) */ +#define EMAC_MAC_CTL0_RFC (0x1 << 2) +/* 0: Disable 1: Enable Transmit Flow Control(default) */ +#define EMAC_MAC_CTL0_TFC (0x1 << 3) + +#define EMAC_MAC_CTL0_SETUP (EMAC_MAC_CTL0_RFC | EMAC_MAC_CTL0_TFC) + +/* 0: Disable 1: Enable MAC Frame Length Checking(default) */ +#define EMAC_MAC_CTL1_FLC (0x1 << 1) +/* 0: Disable(default) 1: Enable Huge Frame */ +#define EMAC_MAC_CTL1_HF (0x1 << 2) +/* 0: Disable(default) 1: Enable MAC Delayed CRC */ +#define EMAC_MAC_CTL1_DCRC (0x1 << 3) +/* 0: Disable 1: Enable MAC CRC(default) */ +#define EMAC_MAC_CTL1_CRC (0x1 << 4) +/* 0: Disable 1: Enable MAC PAD Short frames(default) */ +#define EMAC_MAC_CTL1_PC (0x1 << 5) +/* 0: Disable(default) 1: Enable MAC PAD Short frames and append CRC */ +#define EMAC_MAC_CTL1_VC (0x1 << 6) +/* 0: Disable(default) 1: Enable MAC auto detect Short frames */ +#define EMAC_MAC_CTL1_ADP (0x1 << 7) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_PRE (0x1 << 8) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_LPE (0x1 << 9) +/* 0: Disable(default) 1: Enable no back off */ +#define EMAC_MAC_CTL1_NB (0x1 << 12) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_BNB (0x1 << 13) +/* 0: Disable(default) 1: Enable */ +#define EMAC_MAC_CTL1_ED (0x1 << 14) + +#define EMAC_MAC_CTL1_SETUP (EMAC_MAC_CTL1_FLC | EMAC_MAC_CTL1_CRC | \ + EMAC_MAC_CTL1_PC) + +#define EMAC_MAC_IPGT 0x15 + +#define EMAC_MAC_NBTB_IPG1 0xC +#define EMAC_MAC_NBTB_IPG2 0x12 + +#define EMAC_MAC_CW 0x37 +#define EMAC_MAC_RM 0xF + +#define EMAC_MAC_MFL 0x0600 + +/* Receive status */ +#define EMAC_CRCERR (1 << 4) +#define EMAC_LENERR (3 << 5) + +#define DMA_CPU_TRRESHOLD 2000 + +struct wemac_eth_dev { + u32 speed; + u32 duplex; + u32 phy_configured; + int link_printed; +}; + +struct wemac_rxhdr { + s16 rx_len; + u16 rx_status; +}; + +static void wemac_inblk_32bit(void *reg, void *data, int count) +{ + int cnt = (count + 3) >> 2; + + if (cnt) { + u32 *buf = data; + + do { + u32 x = readl(reg); + *buf++ = x; + } while (--cnt); + } +} + +static void wemac_outblk_32bit(void *reg, void *data, int count) +{ + int cnt = (count + 3) >> 2; + + if (cnt) { + const u32 *buf = data; + + do { + writel(*buf++, reg); + } while (--cnt); + } +} + +/* + * Read a word from phyxcer + */ +static int wemac_phy_read(const char *devname, unsigned char addr, + unsigned char reg, unsigned short *value) +{ + struct eth_device *dev = eth_get_dev_by_name(devname); + struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + + /* issue the phy address and reg */ + writel(addr << 8 | reg, ®s->mac_madr); + + /* pull up the phy io line */ + writel(0x1, ®s->mac_mcmd); + + /* Wait read complete */ + mdelay(1); + + /* push down the phy io line */ + writel(0x0, ®s->mac_mcmd); + + /* and write data */ + *value = readl(®s->mac_mrdd); + + return 0; +} + +/* + * Write a word to phyxcer + */ +static int wemac_phy_write(const char *devname, unsigned char addr, + unsigned char reg, unsigned short value) +{ + struct eth_device *dev = eth_get_dev_by_name(devname); + struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + + /* issue the phy address and reg */ + writel(addr << 8 | reg, ®s->mac_madr); + + /* pull up the phy io line */ + writel(0x1, ®s->mac_mcmd); + + /* Wait write complete */ + mdelay(1); + + /* push down the phy io line */ + writel(0x0, ®s->mac_mcmd); + + /* and write data */ + writel(value, ®s->mac_mwtd); + + return 0; +} + +static void emac_setup(struct eth_device *dev) +{ + struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + u32 reg_val; + u16 phy_val; + u32 duplex_flag; + + /* Set up TX */ + writel(EMAC_TX_SETUP, ®s->tx_mode); + + /* Set up RX */ + writel(EMAC_RX_SETUP, ®s->rx_ctl); + + /* Set MAC */ + /* Set MAC CTL0 */ + writel(EMAC_MAC_CTL0_SETUP, ®s->mac_ctl0); + + /* Set MAC CTL1 */ + wemac_phy_read(dev->name, 1, 0, &phy_val); + debug("PHY SETUP, reg 0 value: %x\n", phy_val); + duplex_flag = !!(phy_val & (1 << 8)); + + reg_val = 0; + if (duplex_flag) + reg_val = (0x1 << 0); + writel(EMAC_MAC_CTL1_SETUP | reg_val, ®s->mac_ctl1); + + /* Set up IPGT */ + writel(EMAC_MAC_IPGT, ®s->mac_ipgt); + + /* Set up IPGR */ + writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), ®s->mac_ipgr); + + /* Set up Collison window */ + writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), ®s->mac_clrt); + + /* Set up Max Frame Length */ + writel(EMAC_MAC_MFL, ®s->mac_maxf); +} + +static void wemac_reset(struct eth_device *dev) +{ + struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + + debug("resetting device\n"); + + /* RESET device */ + writel(0, ®s->ctl); + udelay(200); + + writel(1, ®s->ctl); + udelay(200); +} + +static int sunxi_wemac_eth_init(struct eth_device *dev, bd_t *bd) +{ + struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + struct wemac_eth_dev *priv = dev->priv; + u16 phy_reg; + + /* Init EMAC */ + + /* Flush RX FIFO */ + setbits_le32(®s->rx_ctl, 0x8); + udelay(1); + + /* Init MAC */ + + /* Soft reset MAC */ + clrbits_le32(®s->mac_ctl0, 1 << 15); + + /* Set MII clock */ + clrsetbits_le32(®s->mac_mcfg, 0xf << 2, 0xd << 2); + + /* Clear RX counter */ + writel(0x0, ®s->rx_fbc); + udelay(1); + + /* Set up EMAC */ + emac_setup(dev); + + writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 | + dev->enetaddr[2], ®s->mac_a1); + writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 | + dev->enetaddr[5], ®s->mac_a0); + + mdelay(1); + + wemac_reset(dev); + + /* PHY POWER UP */ + wemac_phy_read(dev->name, 1, 0, &phy_reg); + wemac_phy_write(dev->name, 1, 0, phy_reg & (~(1 << 11))); + mdelay(1); + + wemac_phy_read(dev->name, 1, 0, &phy_reg); + + priv->speed = miiphy_speed(dev->name, 0); + priv->duplex = miiphy_duplex(dev->name, 0); + + /* Print link status only once */ + if (!priv->link_printed) { + printf("ENET Speed is %d Mbps - %s duplex connection\n", + priv->speed, (priv->duplex == HALF) ? "HALF" : "FULL"); + priv->link_printed = 1; + } + + /* Set EMAC SPEED depend on PHY */ + clrsetbits_le32(®s->mac_supp, 1 << 8, + ((phy_reg & (1 << 13)) >> 13) << 8); + + /* Set duplex depend on phy */ + clrsetbits_le32(®s->mac_ctl1, 1 << 0, + ((phy_reg & (1 << 8)) >> 8) << 0); + + /* Enable RX/TX */ + setbits_le32(®s->ctl, 0x7); + + return 0; +} + +static void sunxi_wemac_eth_halt(struct eth_device *dev) +{ + /* Nothing to do here */ +} + +static int sunxi_wemac_eth_recv(struct eth_device *dev) +{ + struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + struct wemac_rxhdr rxhdr; + u32 rxcount; + u32 reg_val; + int rx_len; + int rx_status; + int good_packet; + + /* Check packet ready or not */ + + /* + * Race warning: The first packet might arrive with + * the interrupts disabled, but the second will fix + */ + rxcount = readl(®s->rx_fbc); + if (!rxcount) { + /* Had one stuck? */ + rxcount = readl(®s->rx_fbc); + if (!rxcount) + return 0; + } + + reg_val = readl(®s->rx_io_data); + if (reg_val != 0x0143414d) { + /* Disable RX */ + clrbits_le32(®s->ctl, 1 << 2); + + /* Flush RX FIFO */ + setbits_le32(®s->rx_ctl, 1 << 3); + while (readl(®s->rx_ctl) & (1 << 3)) + ; + + /* Enable RX */ + setbits_le32(®s->ctl, 1 << 2); + + return 0; + } + + /* + * A packet ready now + * Get status/length + */ + good_packet = 1; + + wemac_inblk_32bit(®s->rx_io_data, &rxhdr, sizeof(rxhdr)); + + rx_len = rxhdr.rx_len; + rx_status = rxhdr.rx_status; + + /* Packet Status check */ + if (rx_len < 0x40) { + good_packet = 0; + debug("RX: Bad Packet (runt)\n"); + } + + /* rx_status is identical to RSR register. */ + if (0 & rx_status & (EMAC_CRCERR | EMAC_LENERR)) { + good_packet = 0; + if (rx_status & EMAC_CRCERR) + printf("crc error\n"); + if (rx_status & EMAC_LENERR) + printf("length error\n"); + } + + /* Move data from WEMAC */ + if (good_packet) { + if (rx_len > DMA_CPU_TRRESHOLD) { + printf("Received packet is too big (len=%d)\n", rx_len); + } else { + wemac_inblk_32bit((void *)®s->rx_io_data, + NetRxPackets[0], rx_len); + + /* Pass to upper layer */ + NetReceive(NetRxPackets[0], rx_len); + return rx_len; + } + } + + return 0; +} + +static int sunxi_wemac_eth_send(struct eth_device *dev, void *packet, int len) +{ + struct wemac_regs *regs = (struct wemac_regs *)dev->iobase; + + /* Select channel 0 */ + writel(0, ®s->tx_ins); + + /* Write packet */ + wemac_outblk_32bit((void *)®s->tx_io_data, packet, len); + + /* Set TX len */ + writel(len, ®s->tx_pl0); + + /* Start translate from fifo to phy */ + setbits_le32(®s->tx_ctl0, 1); + + return 0; +} + +int sunxi_wemac_initialize(void) +{ + struct sunxi_ccm_reg *const ccm = + (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + struct sunxi_sramc_regs *sram = + (struct sunxi_sramc_regs *)SUNXI_SRAMC_BASE; + struct eth_device *dev; + struct wemac_eth_dev *priv; + int pin; + + dev = malloc(sizeof(*dev)); + if (dev == NULL) + return -ENOMEM; + + priv = (struct wemac_eth_dev *)malloc(sizeof(struct wemac_eth_dev)); + if (!priv) { + free(dev); + return -ENOMEM; + } + + memset(dev, 0, sizeof(*dev)); + memset(priv, 0, sizeof(struct wemac_eth_dev)); + + /* Map SRAM to EMAC */ + setbits_le32(&sram->ctrl1, 0x5 << 2); + + /* Configure pin mux settings for MII Ethernet */ + for (pin = SUNXI_GPA(0); pin <= SUNXI_GPA(17); pin++) + sunxi_gpio_set_cfgpin(pin, 2); + + /* Set up clock gating */ + setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_EMAC); + + dev->iobase = SUNXI_EMAC_BASE; + dev->priv = priv; + dev->init = sunxi_wemac_eth_init; + dev->halt = sunxi_wemac_eth_halt; + dev->send = sunxi_wemac_eth_send; + dev->recv = sunxi_wemac_eth_recv; + strcpy(dev->name, "wemac"); + + eth_register(dev); + + miiphy_register(dev->name, wemac_phy_read, wemac_phy_write); + + return 0; +} diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 1ae35d3..1499944 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -26,7 +26,8 @@ include $(TOPDIR)/config.mk LIB := $(obj)libpci.o COBJS-$(CONFIG_FSL_PCI_INIT) += fsl_pci_init.o -COBJS-$(CONFIG_PCI) += pci.o pci_auto.o pci_indirect.o +COBJS-$(CONFIG_PCI) += pci.o pci_auto.o +COBJS-$(CONFIG_PCI_INDIRECT_BRIDGE) += pci_indirect.o COBJS-$(CONFIG_FTPCI100) += pci_ftpci100.o COBJS-$(CONFIG_IXP_PCI) += pci_ixp.o COBJS-$(CONFIG_SH4_PCI) += pci_sh4.o diff --git a/drivers/pci/fsl_pci_init.c b/drivers/pci/fsl_pci_init.c index 77ac1f7..621c899 100644 --- a/drivers/pci/fsl_pci_init.c +++ b/drivers/pci/fsl_pci_init.c @@ -211,7 +211,7 @@ static int fsl_pci_setup_inbound_windows(struct pci_controller *hose, return 1; } -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER static void fsl_pcie_boot_master(pit_t *pi) { /* configure inbound window for slave's u-boot image */ @@ -388,7 +388,7 @@ void fsl_pci_init(struct pci_controller *hose, struct fsl_pci_info *pci_info) /* see if we are a PCIe or PCI controller */ pci_hose_read_config_byte(hose, dev, FSL_PCIE_CAP_ID, &pcie_cap); -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER /* boot from PCIE --master */ char *s = getenv("bootmaster"); char pcie[6]; @@ -624,7 +624,7 @@ int fsl_pci_init_port(struct fsl_pci_info *pci_info, if (fsl_is_pci_agent(hose)) { fsl_pci_config_unlock(hose); hose->last_busno = hose->first_busno; -#ifdef CONFIG_SYS_FSL_SRIO_PCIE_BOOT_MASTER +#ifdef CONFIG_SRIO_PCIE_BOOT_MASTER } else { /* boot from PCIE --master releases slave's core 0 */ char *s = getenv("bootmaster"); diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c index daa8003..a19cec5 100644 --- a/drivers/serial/serial.c +++ b/drivers/serial/serial.c @@ -37,7 +37,6 @@ static struct serial_device *serial_current; * Table with supported baudrates (defined in config_xyz.h) */ static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; -#define N_BAUDRATES (sizeof(baudrate_table) / sizeof(baudrate_table[0])) /** * serial_null() - Void registration routine of a serial driver @@ -74,11 +73,11 @@ static int on_baudrate(const char *name, const char *value, enum env_op op, if (gd->baudrate == baudrate) return 0; - for (i = 0; i < N_BAUDRATES; ++i) { + for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) { if (baudrate == baudrate_table[i]) break; } - if (i == N_BAUDRATES) { + if (i == ARRAY_SIZE(baudrate_table)) { if ((flags & H_FORCE) == 0) printf("## Baudrate %d bps not supported\n", baudrate); diff --git a/drivers/spi/armada100_spi.c b/drivers/spi/armada100_spi.c index afdbe05..b237c7c 100644 --- a/drivers/spi/armada100_spi.c +++ b/drivers/spi/armada100_spi.c @@ -182,15 +182,8 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, goto done; } - if (dout) - pss->tx = dout; - else - pss->tx = NULL; - - if (din) - pss->rx = din; - else - pss->rx = NULL; + pss->tx = dout; + pss->rx = din; if (flags & SPI_XFER_BEGIN) { spi_cs_activate(slave); diff --git a/drivers/spi/cf_qspi.c b/drivers/spi/cf_qspi.c index a37ac4e..06bcf91 100644 --- a/drivers/spi/cf_qspi.c +++ b/drivers/spi/cf_qspi.c @@ -171,7 +171,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, volatile qspi_t *qspi = dev->regs; u8 *txbuf = (u8 *)dout; u8 *rxbuf = (u8 *)din; - u32 count = ((bitlen / 8) + (bitlen % 8 ? 1 : 0)); + u32 count = DIV_ROUND_UP(bitlen, 8); u32 n, i = 0; /* Sanitize arguments */ diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c index 607e1cd..7a25a35 100644 --- a/drivers/spi/exynos_spi.c +++ b/drivers/spi/exynos_spi.c @@ -51,6 +51,7 @@ struct exynos_spi_slave { unsigned int mode; enum periph_id periph_id; /* Peripheral ID for this device */ unsigned int fifo_size; + int skip_preamble; }; static struct spi_bus *spi_get_bus(unsigned dev_index) @@ -105,6 +106,8 @@ struct spi_slave *spi_setup_slave(unsigned int busnum, unsigned int cs, else spi_slave->fifo_size = 256; + spi_slave->skip_preamble = 0; + spi_slave->freq = bus->frequency; if (max_hz) spi_slave->freq = min(max_hz, spi_slave->freq); @@ -217,17 +220,23 @@ static void spi_request_bytes(struct exynos_spi *regs, int count) writel(count | SPI_PACKET_CNT_EN, ®s->pkt_cnt); } -static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, - void **dinp, void const **doutp) +static int spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, + void **dinp, void const **doutp, unsigned long flags) { struct exynos_spi *regs = spi_slave->regs; uchar *rxp = *dinp; const uchar *txp = *doutp; int rx_lvl, tx_lvl; uint out_bytes, in_bytes; + int toread; + unsigned start = get_timer(0); + int stopping; out_bytes = in_bytes = todo; + stopping = spi_slave->skip_preamble && (flags & SPI_XFER_END) && + !(spi_slave->mode & SPI_SLAVE); + /* * If there's something to send, do a software reset and set a * transaction size. @@ -238,6 +247,8 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, * Bytes are transmitted/received in pairs. Wait to receive all the * data because then transmission will be done as well. */ + toread = in_bytes; + while (in_bytes) { int temp; @@ -248,15 +259,43 @@ static void spi_rx_tx(struct exynos_spi_slave *spi_slave, int todo, writel(temp, ®s->tx_data); out_bytes--; } - if (rx_lvl > 0 && in_bytes) { + if (rx_lvl > 0) { temp = readl(®s->rx_data); - if (rxp) - *rxp++ = temp; - in_bytes--; + if (spi_slave->skip_preamble) { + if (temp == SPI_PREAMBLE_END_BYTE) { + spi_slave->skip_preamble = 0; + stopping = 0; + } + } else { + if (rxp || stopping) + *rxp++ = temp; + in_bytes--; + } + toread--; + } else if (!toread) { + /* + * We have run out of input data, but haven't read + * enough bytes after the preamble yet. Read some more, + * and make sure that we transmit dummy bytes too, to + * keep things going. + */ + assert(!out_bytes); + out_bytes = in_bytes; + toread = in_bytes; + txp = NULL; + spi_request_bytes(regs, toread); + } + if (spi_slave->skip_preamble && get_timer(start) > 100) { + printf("SPI timeout: in_bytes=%d, out_bytes=%d, ", + in_bytes, out_bytes); + return -1; } } + *dinp = rxp; *doutp = txp; + + return 0; } /** @@ -276,6 +315,7 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, struct exynos_spi_slave *spi_slave = to_exynos_spi(slave); int upto, todo; int bytelen; + int ret = 0; /* spi core configured to do 8 bit transfers */ if (bitlen % 8) { @@ -289,16 +329,24 @@ int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, /* Exynos SPI limits each transfer to 65535 bytes */ bytelen = bitlen / 8; - for (upto = 0; upto < bytelen; upto += todo) { + for (upto = 0; !ret && upto < bytelen; upto += todo) { todo = min(bytelen - upto, (1 << 16) - 1); - spi_rx_tx(spi_slave, todo, &din, &dout); + ret = spi_rx_tx(spi_slave, todo, &din, &dout, flags); + if (ret) + break; } /* Stop the transaction, if necessary. */ - if ((flags & SPI_XFER_END)) + if ((flags & SPI_XFER_END) && !(spi_slave->mode & SPI_SLAVE)) { spi_cs_deactivate(slave); + if (spi_slave->skip_preamble) { + assert(!spi_slave->skip_preamble); + debug("Failed to complete premable transaction\n"); + ret = -1; + } + } - return 0; + return ret; } /** @@ -325,6 +373,7 @@ void spi_cs_activate(struct spi_slave *slave) clrbits_le32(&spi_slave->regs->cs_reg, SPI_SLAVE_SIG_INACT); debug("Activate CS, bus %d\n", spi_slave->slave.bus); + spi_slave->skip_preamble = spi_slave->mode & SPI_PREAMBLE; } /** @@ -416,6 +465,28 @@ static int process_nodes(const void *blob, int node_list[], int count) } #endif +/** + * Set up a new SPI slave for an fdt node + * + * @param blob Device tree blob + * @param node SPI peripheral node to use + * @return 0 if ok, -1 on error + */ +struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, + unsigned int cs, unsigned int max_hz, unsigned int mode) +{ + struct spi_bus *bus; + unsigned int i; + + for (i = 0, bus = spi_bus; i < bus_count; i++, bus++) { + if (bus->node == node) + return spi_setup_slave(i, cs, max_hz, mode); + } + + debug("%s: Failed to find bus node %d\n", __func__, node); + return NULL; +} + /* Sadly there is no error return from this function */ void spi_init(void) { diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c index 0eca776..9c68d7d 100644 --- a/drivers/spi/mxc_spi.c +++ b/drivers/spi/mxc_spi.c @@ -218,7 +218,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, const u8 *dout, u8 *din, unsigned long flags) { struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave); - int nbytes = (bitlen + 7) / 8; + int nbytes = DIV_ROUND_UP(bitlen, 8); u32 data, cnt, i; struct cspi_regs *regs = (struct cspi_regs *)mxcs->base; @@ -288,7 +288,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, /* Transfer completed, clear any pending request */ reg_write(®s->stat, MXC_CSPICTRL_TC | MXC_CSPICTRL_RXOVF); - nbytes = (bitlen + 7) / 8; + nbytes = DIV_ROUND_UP(bitlen, 8); cnt = nbytes % 32; @@ -324,7 +324,7 @@ int spi_xchg_single(struct spi_slave *slave, unsigned int bitlen, int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout, void *din, unsigned long flags) { - int n_bytes = (bitlen + 7) / 8; + int n_bytes = DIV_ROUND_UP(bitlen, 8); int n_bits; int ret; u32 blk_size; diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c index b11a0a1..4d2af48 100644 --- a/drivers/spi/tegra114_spi.c +++ b/drivers/spi/tegra114_spi.c @@ -152,13 +152,11 @@ struct spi_slave *tegra114_spi_setup_slave(unsigned int bus, unsigned int cs, return NULL; } - spi = malloc(sizeof(struct tegra_spi_slave)); + spi = spi_alloc_slave(struct tegra_spi_slave, bus, cs); if (!spi) { printf("SPI error: malloc of SPI structure failed\n"); return NULL; } - spi->slave.bus = bus; - spi->slave.cs = cs; spi->ctrl = &spi_ctrls[bus]; if (!spi->ctrl) { printf("SPI error: could not find controller for bus %d\n", diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c index 9322ce7..7c3a3fc 100644 --- a/drivers/spi/tegra20_sflash.c +++ b/drivers/spi/tegra20_sflash.c @@ -132,8 +132,6 @@ struct spi_slave *tegra20_spi_setup_slave(unsigned int bus, unsigned int cs, printf("SPI error: malloc of SPI structure failed\n"); return NULL; } - spi->slave.bus = bus; - spi->slave.cs = cs; spi->ctrl = &spi_ctrls[bus]; if (!spi->ctrl) { printf("SPI error: could not find controller for bus %d\n", diff --git a/drivers/tpm/Makefile b/drivers/tpm/Makefile index e8c159c..913dd9c 100644 --- a/drivers/tpm/Makefile +++ b/drivers/tpm/Makefile @@ -25,9 +25,10 @@ LIB := $(obj)libtpm.o $(shell mkdir -p $(obj)slb9635_i2c) -COBJS-$(CONFIG_GENERIC_LPC_TPM) = generic_lpc_tpm.o -COBJS-$(CONFIG_INFINEON_TPM_I2C) += tis_i2c.o slb9635_i2c/tpm.o -COBJS-$(CONFIG_INFINEON_TPM_I2C) += slb9635_i2c/tpm_tis_i2c.o +# TODO: Merge tpm_tis_lpc.c with tpm.c +COBJS-$(CONFIG_TPM_TIS_I2C) += tpm.o +COBJS-$(CONFIG_TPM_TIS_I2C) += tpm_tis_i2c.o +COBJS-$(CONFIG_TPM_TIS_LPC) += tpm_tis_lpc.o COBJS := $(COBJS-y) SRCS := $(COBJS:.o=.c) diff --git a/drivers/tpm/tis_i2c.c b/drivers/tpm/tis_i2c.c index e818fba..22554e1 100644 --- a/drivers/tpm/tis_i2c.c +++ b/drivers/tpm/tis_i2c.c @@ -68,6 +68,10 @@ static int tpm_decode_config(struct tpm *dev) node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM); if (node < 0) { + node = fdtdec_next_compatible(blob, 0, + COMPAT_INFINEON_SLB9645_TPM); + } + if (node < 0) { debug("%s: Node not found\n", __func__); return -1; } diff --git a/drivers/tpm/slb9635_i2c/tpm.c b/drivers/tpm/tpm.c index 496c48e..b657334 100644 --- a/drivers/tpm/slb9635_i2c/tpm.c +++ b/drivers/tpm/tpm.c @@ -32,11 +32,30 @@ * MA 02111-1307 USA */ -#include <malloc.h> -#include "tpm.h" +#include <config.h> +#include <common.h> +#include <compiler.h> +#include <fdtdec.h> +#include <i2c.h> +#include <tpm.h> +#include <asm-generic/errno.h> +#include <linux/types.h> +#include <linux/unaligned/be_byteshift.h> -/* global structure for tpm chip data */ -struct tpm_chip g_chip; +#include "tpm_private.h" + +DECLARE_GLOBAL_DATA_PTR; + +/* TPM configuration */ +struct tpm { + int i2c_bus; + int slave_addr; + char inited; + int old_bus; +} tpm; + +/* Global structure for tpm chip data */ +static struct tpm_chip g_chip; enum tpm_duration { TPM_SHORT = 0, @@ -45,9 +64,18 @@ enum tpm_duration { TPM_UNDEFINED, }; -#define TPM_MAX_ORDINAL 243 -#define TPM_MAX_PROTECTED_ORDINAL 12 -#define TPM_PROTECTED_ORDINAL_MASK 0xFF +/* Extended error numbers from linux (see errno.h) */ +#define ECANCELED 125 /* Operation Canceled */ + +/* Timer frequency. Corresponds to msec timer resolution*/ +#define HZ 1000 + +#define TPM_MAX_ORDINAL 243 +#define TPM_MAX_PROTECTED_ORDINAL 12 +#define TPM_PROTECTED_ORDINAL_MASK 0xFF + +#define TPM_CMD_COUNT_BYTE 2 +#define TPM_CMD_ORDINAL_BYTE 6 /* * Array with one entry per ordinal defining the maximum amount @@ -318,34 +346,31 @@ static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { TPM_MEDIUM, }; -/* - * Returns max number of milliseconds to wait - */ -unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) +/* Returns max number of milliseconds to wait */ +static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, + u32 ordinal) { int duration_idx = TPM_UNDEFINED; int duration = 0; - if (ordinal < TPM_MAX_ORDINAL) + if (ordinal < TPM_MAX_ORDINAL) { duration_idx = tpm_ordinal_duration[ordinal]; - else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < - TPM_MAX_PROTECTED_ORDINAL) - duration_idx = - tpm_protected_ordinal_duration[ordinal & - TPM_PROTECTED_ORDINAL_MASK]; + } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < + TPM_MAX_PROTECTED_ORDINAL) { + duration_idx = tpm_protected_ordinal_duration[ + ordinal & TPM_PROTECTED_ORDINAL_MASK]; + } if (duration_idx != TPM_UNDEFINED) duration = chip->vendor.duration[duration_idx]; + if (duration <= 0) - return 2 * 60 * HZ; /*two minutes timeout*/ + return 2 * 60 * HZ; /* Two minutes timeout */ else return duration; } -#define TPM_CMD_COUNT_BYTE 2 -#define TPM_CMD_ORDINAL_BYTE 6 - -ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) +static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) { ssize_t rc; u32 count, ordinal; @@ -358,18 +383,17 @@ ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE); if (count == 0) { - dev_err(chip->dev, "no data\n"); + error("no data\n"); return -ENODATA; } if (count > bufsiz) { - dev_err(chip->dev, - "invalid count value %x %zx\n", count, bufsiz); + error("invalid count value %x %zx\n", count, bufsiz); return -E2BIG; } rc = chip->vendor.send(chip, (u8 *)buf, count); if (rc < 0) { - dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); + error("tpm_transmit: tpm_send: error %zd\n", rc); goto out; } @@ -379,47 +403,126 @@ ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) start = get_timer(0); stop = tpm_calc_ordinal_duration(chip, ordinal); do { - dbg_printf("waiting for status...\n"); + debug("waiting for status...\n"); u8 status = chip->vendor.status(chip); if ((status & chip->vendor.req_complete_mask) == chip->vendor.req_complete_val) { - dbg_printf("...got it;\n"); + debug("...got it;\n"); goto out_recv; } if ((status == chip->vendor.req_canceled)) { - dev_err(chip->dev, "Operation Canceled\n"); + error("Operation Canceled\n"); rc = -ECANCELED; goto out; } - msleep(TPM_TIMEOUT); + udelay(TPM_TIMEOUT * 1000); } while (get_timer(start) < stop); chip->vendor.cancel(chip); - dev_err(chip->dev, "Operation Timed out\n"); + error("Operation Timed out\n"); rc = -ETIME; goto out; out_recv: - - dbg_printf("out_recv: reading response...\n"); + debug("out_recv: reading response...\n"); rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE); if (rc < 0) - dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); + error("tpm_transmit: tpm_recv: error %zd\n", rc); + out: return rc; } -#define TPM_ERROR_SIZE 10 +static int tpm_open(uint32_t dev_addr) +{ + int rc; + if (g_chip.is_open) + return -EBUSY; + rc = tpm_vendor_init(dev_addr); + if (rc < 0) + g_chip.is_open = 0; + return rc; +} -enum tpm_capabilities { - TPM_CAP_PROP = cpu_to_be32(5), -}; +static void tpm_close(void) +{ + if (g_chip.is_open) { + tpm_vendor_cleanup(&g_chip); + g_chip.is_open = 0; + } +} -enum tpm_sub_capabilities { - TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), - TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), -}; +static int tpm_select(void) +{ + int ret; + + tpm.old_bus = i2c_get_bus_num(); + if (tpm.old_bus != tpm.i2c_bus) { + ret = i2c_set_bus_num(tpm.i2c_bus); + if (ret) { + debug("%s: Fail to set i2c bus %d\n", __func__, + tpm.i2c_bus); + return -1; + } + } + return 0; +} + +static int tpm_deselect(void) +{ + int ret; + + if (tpm.old_bus != i2c_get_bus_num()) { + ret = i2c_set_bus_num(tpm.old_bus); + if (ret) { + debug("%s: Fail to restore i2c bus %d\n", + __func__, tpm.old_bus); + return -1; + } + } + tpm.old_bus = -1; + return 0; +} + +/** + * Decode TPM configuration. + * + * @param dev Returns a configuration of TPM device + * @return 0 if ok, -1 on error + */ +static int tpm_decode_config(struct tpm *dev) +{ +#ifdef CONFIG_OF_CONTROL + const void *blob = gd->fdt_blob; + int node, parent; + int i2c_bus; + + node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM); + if (node < 0) { + node = fdtdec_next_compatible(blob, 0, + COMPAT_INFINEON_SLB9645_TPM); + } + if (node < 0) { + debug("%s: Node not found\n", __func__); + return -1; + } + parent = fdt_parent_offset(blob, node); + if (parent < 0) { + debug("%s: Cannot find node parent\n", __func__); + return -1; + } + i2c_bus = i2c_get_bus_num_fdt(parent); + if (i2c_bus < 0) + return -1; + dev->i2c_bus = i2c_bus; + dev->slave_addr = fdtdec_get_addr(blob, node, "reg"); +#else + dev->i2c_bus = CONFIG_TPM_TIS_I2C_BUS_NUMBER; + dev->slave_addr = CONFIG_TPM_TIS_I2C_SLAVE_ADDRESS; +#endif + return 0; +} struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry) { @@ -433,21 +536,94 @@ struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry) return chip; } -int tpm_open(uint32_t dev_addr) +int tis_init(void) +{ + if (tpm.inited) + return 0; + + if (tpm_decode_config(&tpm)) + return -1; + + if (tpm_select()) + return -1; + + /* + * Probe TPM twice; the first probing might fail because TPM is asleep, + * and the probing can wake up TPM. + */ + if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) { + debug("%s: fail to probe i2c addr 0x%x\n", __func__, + tpm.slave_addr); + return -1; + } + + tpm_deselect(); + + tpm.inited = 1; + + return 0; +} + +int tis_open(void) { int rc; - if (g_chip.is_open) - return -EBUSY; - rc = tpm_vendor_init(dev_addr); - if (rc < 0) - g_chip.is_open = 0; + + if (!tpm.inited) + return -1; + + if (tpm_select()) + return -1; + + rc = tpm_open(tpm.slave_addr); + + tpm_deselect(); + return rc; } -void tpm_close(void) +int tis_close(void) { - if (g_chip.is_open) { - tpm_vendor_cleanup(&g_chip); - g_chip.is_open = 0; + if (!tpm.inited) + return -1; + + if (tpm_select()) + return -1; + + tpm_close(); + + tpm_deselect(); + + return 0; +} + +int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, + uint8_t *recvbuf, size_t *rbuf_len) +{ + int len; + uint8_t buf[4096]; + + if (!tpm.inited) + return -1; + + if (sizeof(buf) < sbuf_size) + return -1; + + memcpy(buf, sendbuf, sbuf_size); + + if (tpm_select()) + return -1; + + len = tpm_transmit(buf, sbuf_size); + + tpm_deselect(); + + if (len < 10) { + *rbuf_len = 0; + return -1; } + + memcpy(recvbuf, buf, len); + *rbuf_len = len; + + return 0; } diff --git a/drivers/tpm/slb9635_i2c/tpm.h b/drivers/tpm/tpm_private.h index 9ddee86..888a074 100644 --- a/drivers/tpm/slb9635_i2c/tpm.h +++ b/drivers/tpm/tpm_private.h @@ -33,12 +33,11 @@ * MA 02111-1307 USA */ -#ifndef _TPM_H_ -#define _TPM_H_ +#ifndef _TPM_PRIVATE_H_ +#define _TPM_PRIVATE_H_ #include <linux/compiler.h> - -#include "compatibility.h" +#include <linux/types.h> enum tpm_timeout { TPM_TIMEOUT = 5, /* msecs */ @@ -47,13 +46,9 @@ enum tpm_timeout { /* Size of external transmit buffer (used in tpm_transmit)*/ #define TPM_BUFSIZE 4096 -/* Index of fields in TPM command buffer */ -#define TPM_CMD_SIZE_BYTE 2 -#define TPM_CMD_ORDINAL_BYTE 6 - /* Index of Count field in TPM response buffer */ -#define TPM_RSP_SIZE_BYTE 2 -#define TPM_RSP_RC_BYTE 6 +#define TPM_RSP_SIZE_BYTE 2 +#define TPM_RSP_RC_BYTE 6 struct tpm_chip; @@ -65,10 +60,10 @@ struct tpm_vendor_specific { int (*recv) (struct tpm_chip *, u8 *, size_t); int (*send) (struct tpm_chip *, u8 *, size_t); void (*cancel) (struct tpm_chip *); - u8(*status) (struct tpm_chip *); + u8(*status) (struct tpm_chip *); int locality; - unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ - unsigned long duration[3]; /* msec */ + unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* msec */ + unsigned long duration[3]; /* msec */ }; struct tpm_chip { @@ -132,30 +127,11 @@ struct tpm_cmd_t { union tpm_cmd_params params; } __packed; +struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *); -/* ---------- Interface for TPM vendor ------------ */ - -extern struct tpm_chip *tpm_register_hardware( - const struct tpm_vendor_specific *); +int tpm_vendor_init(uint32_t dev_addr); -extern int tpm_vendor_init(uint32_t dev_addr); +void tpm_vendor_cleanup(struct tpm_chip *chip); -extern void tpm_vendor_cleanup(struct tpm_chip *chip); - -/* ---------- Interface for TDDL ------------------- */ - -/* - * if dev_addr != 0 - redefines TPM device address - * Returns < 0 on error, 0 on success. - */ -extern int tpm_open(uint32_t dev_addr); - -extern void tpm_close(void); - -/* - * Transmit bufsiz bytes out of buf to TPM and get results back in buf, too. - * Returns < 0 on error, 0 on success. - */ -extern ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz); #endif diff --git a/drivers/tpm/slb9635_i2c/tpm_tis_i2c.c b/drivers/tpm/tpm_tis_i2c.c index 82a41bf..2dd8501 100644 --- a/drivers/tpm/slb9635_i2c/tpm_tis_i2c.c +++ b/drivers/tpm/tpm_tis_i2c.c @@ -37,46 +37,102 @@ */ #include <common.h> +#include <fdtdec.h> +#include <compiler.h> #include <i2c.h> +#include <tpm.h> +#include <asm-generic/errno.h> #include <linux/types.h> +#include <linux/unaligned/be_byteshift.h> -#include "compatibility.h" -#include "tpm.h" +#include "tpm_private.h" + +DECLARE_GLOBAL_DATA_PTR; -/* max. buffer size supported by our tpm */ -#ifdef TPM_BUFSIZE -#undef TPM_BUFSIZE -#endif -#define TPM_BUFSIZE 1260 /* Address of the TPM on the I2C bus */ -#define TPM_I2C_ADDR 0x20 -/* max. number of iterations after i2c NAK */ -#define MAX_COUNT 3 +#define TPM_I2C_ADDR 0x20 + +/* Max buffer size supported by our tpm */ +#define TPM_DEV_BUFSIZE 1260 -#define SLEEP_DURATION 60 /*in usec*/ +/* Max number of iterations after i2c NAK */ +#define MAX_COUNT 3 -/* max. number of iterations after i2c NAK for 'long' commands - * we need this especially for sending TPM_READY, since the cleanup after the +/* + * Max number of iterations after i2c NAK for 'long' commands + * + * We need this especially for sending TPM_READY, since the cleanup after the * transtion to the ready state may take some time, but it is unpredictable * how long it will take. */ -#define MAX_COUNT_LONG 50 +#define MAX_COUNT_LONG 50 + +#define SLEEP_DURATION 60 /* in usec */ +#define SLEEP_DURATION_LONG 210 /* in usec */ -#define SLEEP_DURATION_LONG 210 /* in usec */ +#define TPM_HEADER_SIZE 10 + +/* + * Expected value for DIDVID register + * + * The only device the system knows about at this moment is Infineon slb9635. + */ +#define TPM_TIS_I2C_DID_VID 0x000b15d1L + +enum tis_access { + TPM_ACCESS_VALID = 0x80, + TPM_ACCESS_ACTIVE_LOCALITY = 0x20, + TPM_ACCESS_REQUEST_PENDING = 0x04, + TPM_ACCESS_REQUEST_USE = 0x02, +}; + +enum tis_status { + TPM_STS_VALID = 0x80, + TPM_STS_COMMAND_READY = 0x40, + TPM_STS_GO = 0x20, + TPM_STS_DATA_AVAIL = 0x10, + TPM_STS_DATA_EXPECT = 0x08, +}; + +enum tis_defaults { + TIS_SHORT_TIMEOUT = 750, /* ms */ + TIS_LONG_TIMEOUT = 2000, /* ms */ +}; /* expected value for DIDVID register */ -#define TPM_TIS_I2C_DID_VID 0x000b15d1L +#define TPM_TIS_I2C_DID_VID_9635 0x000b15d1L +#define TPM_TIS_I2C_DID_VID_9645 0x001a15d1L + +enum i2c_chip_type { + SLB9635, + SLB9645, + UNKNOWN, +}; + +static const char * const chip_name[] = { + [SLB9635] = "slb9635tt", + [SLB9645] = "slb9645tt", + [UNKNOWN] = "unknown/fallback to slb9635", +}; + +#define TPM_ACCESS(l) (0x0000 | ((l) << 4)) +#define TPM_STS(l) (0x0001 | ((l) << 4)) +#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) +#define TPM_DID_VID(l) (0x0006 | ((l) << 4)) /* Structure to store I2C TPM specific stuff */ -struct tpm_inf_dev { +struct tpm_dev { uint addr; - u8 buf[TPM_BUFSIZE + sizeof(u8)]; /* max. buffer size + addr */ + u8 buf[TPM_DEV_BUFSIZE + sizeof(u8)]; /* Max buffer size + addr */ + enum i2c_chip_type chip_type; }; -static struct tpm_inf_dev tpm_dev = { +static struct tpm_dev tpm_dev = { .addr = TPM_I2C_ADDR }; +static struct tpm_dev tpm_dev; + /* * iic_tpm_read() - read from TPM register * @addr: register address to read from @@ -91,34 +147,52 @@ static struct tpm_inf_dev tpm_dev = { * * Return -EIO on error, 0 on success. */ -int iic_tpm_read(u8 addr, u8 *buffer, size_t len) +static int iic_tpm_read(u8 addr, u8 *buffer, size_t len) { int rc; int count; - uint myaddr = addr; - /* we have to use uint here, uchar hangs the board */ - - for (count = 0; count < MAX_COUNT; count++) { - rc = i2c_write(tpm_dev.addr, 0, 0, (uchar *)&myaddr, 1); - if (rc == 0) - break; /*success, break to skip sleep*/ - - udelay(SLEEP_DURATION); - } - - if (rc) - return -rc; - - /* After the TPM has successfully received the register address it needs - * some time, thus we're sleeping here again, before retrieving the data - */ - for (count = 0; count < MAX_COUNT; count++) { - udelay(SLEEP_DURATION); - rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len); - if (rc == 0) - break; /*success, break to skip sleep*/ + uint32_t addrbuf = addr; + + if ((tpm_dev.chip_type == SLB9635) || (tpm_dev.chip_type == UNKNOWN)) { + /* slb9635 protocol should work in both cases */ + for (count = 0; count < MAX_COUNT; count++) { + rc = i2c_write(tpm_dev.addr, 0, 0, + (uchar *)&addrbuf, 1); + if (rc == 0) + break; /* Success, break to skip sleep */ + udelay(SLEEP_DURATION); + } + if (rc) + return -rc; + + /* After the TPM has successfully received the register address + * it needs some time, thus we're sleeping here again, before + * retrieving the data + */ + for (count = 0; count < MAX_COUNT; count++) { + udelay(SLEEP_DURATION); + rc = i2c_read(tpm_dev.addr, 0, 0, buffer, len); + if (rc == 0) + break; /* success, break to skip sleep */ + } + } else { + /* + * Use a combined read for newer chips. + * Unfortunately the smbus functions are not suitable due to + * the 32 byte limit of the smbus. + * Retries should usually not be needed, but are kept just to + * be safe on the safe side. + */ + for (count = 0; count < MAX_COUNT; count++) { + rc = i2c_read(tpm_dev.addr, addr, 1, buffer, len); + if (rc == 0) + break; /* break here to skip sleep */ + udelay(SLEEP_DURATION); + } } + /* Take care of 'guard time' */ + udelay(SLEEP_DURATION); if (rc) return -rc; @@ -126,24 +200,24 @@ int iic_tpm_read(u8 addr, u8 *buffer, size_t len) } static int iic_tpm_write_generic(u8 addr, u8 *buffer, size_t len, - unsigned int sleep_time, - u8 max_count) + unsigned int sleep_time, u8 max_count) { int rc = 0; int count; - /* prepare send buffer */ + /* Prepare send buffer */ tpm_dev.buf[0] = addr; memcpy(&(tpm_dev.buf[1]), buffer, len); for (count = 0; count < max_count; count++) { rc = i2c_write(tpm_dev.addr, 0, 0, tpm_dev.buf, len + 1); if (rc == 0) - break; /*success, break to skip sleep*/ - + break; /* Success, break to skip sleep */ udelay(sleep_time); } + /* take care of 'guard time' */ + udelay(SLEEP_DURATION); if (rc) return -rc; @@ -175,42 +249,16 @@ static int iic_tpm_write(u8 addr, u8 *buffer, size_t len) /* * This function is needed especially for the cleanup situation after * sending TPM_READY - * */ + */ static int iic_tpm_write_long(u8 addr, u8 *buffer, size_t len) { return iic_tpm_write_generic(addr, buffer, len, SLEEP_DURATION_LONG, MAX_COUNT_LONG); } -#define TPM_HEADER_SIZE 10 - -enum tis_access { - TPM_ACCESS_VALID = 0x80, - TPM_ACCESS_ACTIVE_LOCALITY = 0x20, - TPM_ACCESS_REQUEST_PENDING = 0x04, - TPM_ACCESS_REQUEST_USE = 0x02, -}; - -enum tis_status { - TPM_STS_VALID = 0x80, - TPM_STS_COMMAND_READY = 0x40, - TPM_STS_GO = 0x20, - TPM_STS_DATA_AVAIL = 0x10, - TPM_STS_DATA_EXPECT = 0x08, -}; - -enum tis_defaults { - TIS_SHORT_TIMEOUT = 750, /* ms */ - TIS_LONG_TIMEOUT = 2000, /* 2 sec */ -}; - -#define TPM_ACCESS(l) (0x0000 | ((l) << 4)) -#define TPM_STS(l) (0x0001 | ((l) << 4)) -#define TPM_DATA_FIFO(l) (0x0005 | ((l) << 4)) -#define TPM_DID_VID(l) (0x0006 | ((l) << 4)) - static int check_locality(struct tpm_chip *chip, int loc) { + const u8 mask = TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID; u8 buf; int rc; @@ -218,8 +266,7 @@ static int check_locality(struct tpm_chip *chip, int loc) if (rc < 0) return rc; - if ((buf & (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) == - (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) { + if ((buf & mask) == mask) { chip->vendor.locality = loc; return loc; } @@ -229,12 +276,13 @@ static int check_locality(struct tpm_chip *chip, int loc) static void release_locality(struct tpm_chip *chip, int loc, int force) { + const u8 mask = TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID; u8 buf; + if (iic_tpm_read(TPM_ACCESS(loc), &buf, 1) < 0) return; - if (force || (buf & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) == - (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) { + if (force || (buf & mask) == mask) { buf = TPM_ACCESS_ACTIVE_LOCALITY; iic_tpm_write(TPM_ACCESS(loc), &buf, 1); } @@ -246,17 +294,17 @@ static int request_locality(struct tpm_chip *chip, int loc) u8 buf = TPM_ACCESS_REQUEST_USE; if (check_locality(chip, loc) >= 0) - return loc; /* we already have the locality */ + return loc; /* We already have the locality */ iic_tpm_write(TPM_ACCESS(loc), &buf, 1); - /* wait for burstcount */ + /* Wait for burstcount */ start = get_timer(0); stop = chip->vendor.timeout_a; do { if (check_locality(chip, loc) >= 0) return loc; - msleep(TPM_TIMEOUT); + udelay(TPM_TIMEOUT * 1000); } while (get_timer(start) < stop); return -1; @@ -264,8 +312,9 @@ static int request_locality(struct tpm_chip *chip, int loc) static u8 tpm_tis_i2c_status(struct tpm_chip *chip) { - /* NOTE: since i2c read may fail, return 0 in this case --> time-out */ + /* NOTE: Since i2c read may fail, return 0 in this case --> time-out */ u8 buf; + if (iic_tpm_read(TPM_STS(chip->vendor.locality), &buf, 1) < 0) return 0; else @@ -274,8 +323,9 @@ static u8 tpm_tis_i2c_status(struct tpm_chip *chip) static void tpm_tis_i2c_ready(struct tpm_chip *chip) { - /* this causes the current command to be aborted */ + /* This causes the current command to be aborted */ u8 buf = TPM_STS_COMMAND_READY; + iic_tpm_write_long(TPM_STS(chip->vendor.locality), &buf, 1); } @@ -283,34 +333,34 @@ static ssize_t get_burstcount(struct tpm_chip *chip) { unsigned long start, stop; ssize_t burstcnt; - u8 buf[3]; + u8 addr, buf[3]; - /* wait for burstcount */ - /* which timeout value, spec has 2 answers (c & d) */ + /* Wait for burstcount */ + /* XXX: Which timeout value? Spec has 2 answers (c & d) */ start = get_timer(0); stop = chip->vendor.timeout_d; do { /* Note: STS is little endian */ - if (iic_tpm_read(TPM_STS(chip->vendor.locality) + 1, buf, 3) - < 0) + addr = TPM_STS(chip->vendor.locality) + 1; + if (iic_tpm_read(addr, buf, 3) < 0) burstcnt = 0; else burstcnt = (buf[2] << 16) + (buf[1] << 8) + buf[0]; if (burstcnt) return burstcnt; - msleep(TPM_TIMEOUT); + udelay(TPM_TIMEOUT * 1000); } while (get_timer(start) < stop); return -EBUSY; } static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, - int *status) + int *status) { unsigned long start, stop; - /* check current status */ + /* Check current status */ *status = tpm_tis_i2c_status(chip); if ((*status & mask) == mask) return 0; @@ -318,11 +368,10 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout, start = get_timer(0); stop = timeout; do { - msleep(TPM_TIMEOUT); + udelay(TPM_TIMEOUT * 1000); *status = tpm_tis_i2c_status(chip); if ((*status & mask) == mask) return 0; - } while (get_timer(start) < stop); return -ETIME; @@ -337,17 +386,16 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) while (size < count) { burstcnt = get_burstcount(chip); - /* burstcount < 0 = tpm is busy */ + /* burstcount < 0 -> tpm is busy */ if (burstcnt < 0) return burstcnt; - /* limit received data to max. left */ + /* Limit received data to max left */ if (burstcnt > (count - size)) burstcnt = count - size; rc = iic_tpm_read(TPM_DATA_FIFO(chip->vendor.locality), - &(buf[size]), - burstcnt); + &(buf[size]), burstcnt); if (rc == 0) size += burstcnt; } @@ -365,10 +413,10 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) goto out; } - /* read first 10 bytes, including tag, paramsize, and result */ + /* Read first 10 bytes, including tag, paramsize, and result */ size = recv_data(chip, buf, TPM_HEADER_SIZE); if (size < TPM_HEADER_SIZE) { - dev_err(chip->dev, "Unable to read header\n"); + error("Unable to read header\n"); goto out; } @@ -379,23 +427,24 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) } size += recv_data(chip, &buf[TPM_HEADER_SIZE], - expected - TPM_HEADER_SIZE); + expected - TPM_HEADER_SIZE); if (size < expected) { - dev_err(chip->dev, "Unable to read remainder of result\n"); + error("Unable to read remainder of result\n"); size = -ETIME; goto out; } wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); - if (status & TPM_STS_DATA_AVAIL) { /* retry? */ - dev_err(chip->dev, "Error left over data\n"); + if (status & TPM_STS_DATA_AVAIL) { /* Retry? */ + error("Error left over data\n"); size = -EIO; goto out; } out: tpm_tis_i2c_ready(chip); - /* The TPM needs some time to clean up here, + /* + * The TPM needs some time to clean up here, * so we sleep rather than keeping the bus busy */ udelay(2000); @@ -409,10 +458,11 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) int rc, status; ssize_t burstcnt; size_t count = 0; + int retry = 0; u8 sts = TPM_STS_GO; - if (len > TPM_BUFSIZE) - return -E2BIG; /* command is too long for our tpm, sorry */ + if (len > TPM_DEV_BUFSIZE) + return -E2BIG; /* Command is too long for our tpm, sorry */ if (request_locality(chip, 0) < 0) return -EBUSY; @@ -420,44 +470,45 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) status = tpm_tis_i2c_status(chip); if ((status & TPM_STS_COMMAND_READY) == 0) { tpm_tis_i2c_ready(chip); - if (wait_for_stat - (chip, TPM_STS_COMMAND_READY, - chip->vendor.timeout_b, &status) < 0) { + if (wait_for_stat(chip, TPM_STS_COMMAND_READY, + chip->vendor.timeout_b, &status) < 0) { rc = -ETIME; goto out_err; } } - while (count < len - 1) { - burstcnt = get_burstcount(chip); + burstcnt = get_burstcount(chip); - /* burstcount < 0 = tpm is busy */ - if (burstcnt < 0) - return burstcnt; + /* burstcount < 0 -> tpm is busy */ + if (burstcnt < 0) + return burstcnt; - if (burstcnt > (len-1-count)) - burstcnt = len-1-count; + while (count < len - 1) { + if (burstcnt > len - 1 - count) + burstcnt = len - 1 - count; -#ifdef CONFIG_TPM_I2C_BURST_LIMITATION - if (burstcnt > CONFIG_TPM_I2C_BURST_LIMITATION) - burstcnt = CONFIG_TPM_I2C_BURST_LIMITATION; -#endif /* CONFIG_TPM_I2C_BURST_LIMITATION */ +#ifdef CONFIG_TPM_TIS_I2C_BURST_LIMITATION + if (retry && burstcnt > CONFIG_TPM_TIS_I2C_BURST_LIMITATION) + burstcnt = CONFIG_TPM_TIS_I2C_BURST_LIMITATION; +#endif /* CONFIG_TPM_TIS_I2C_BURST_LIMITATION */ rc = iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), - &(buf[count]), burstcnt); + &(buf[count]), burstcnt); if (rc == 0) count += burstcnt; - - wait_for_stat(chip, TPM_STS_VALID, - chip->vendor.timeout_c, &status); - - if ((status & TPM_STS_DATA_EXPECT) == 0) { - rc = -EIO; - goto out_err; + else { + retry++; + wait_for_stat(chip, TPM_STS_VALID, + chip->vendor.timeout_c, &status); + + if ((status & TPM_STS_DATA_EXPECT) == 0) { + rc = -EIO; + goto out_err; + } } } - /* write last byte */ + /* Write last byte */ iic_tpm_write(TPM_DATA_FIFO(chip->vendor.locality), &(buf[count]), 1); wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status); if ((status & TPM_STS_DATA_EXPECT) != 0) { @@ -465,13 +516,15 @@ static int tpm_tis_i2c_send(struct tpm_chip *chip, u8 *buf, size_t len) goto out_err; } - /* go and do it */ + /* Go and do it */ iic_tpm_write(TPM_STS(chip->vendor.locality), &sts, 1); return len; + out_err: tpm_tis_i2c_ready(chip); - /* The TPM needs some time to clean up here, + /* + * The TPM needs some time to clean up here, * so we sleep rather than keeping the bus busy */ udelay(2000); @@ -490,12 +543,26 @@ static struct tpm_vendor_specific tpm_tis_i2c = { .req_canceled = TPM_STS_COMMAND_READY, }; -/* initialisation of i2c tpm */ +static enum i2c_chip_type tpm_vendor_chip_type(void) +{ +#ifdef CONFIG_OF_CONTROL + const void *blob = gd->fdt_blob; + + if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9645_TPM) >= 0) + return SLB9645; + + if (fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM) >= 0) + return SLB9635; +#endif + return UNKNOWN; +} +/* Initialisation of i2c tpm */ int tpm_vendor_init(uint32_t dev_addr) { u32 vendor; + u32 expected_did_vid; uint old_addr; int rc = 0; struct tpm_chip *chip; @@ -504,6 +571,8 @@ int tpm_vendor_init(uint32_t dev_addr) if (dev_addr != 0) tpm_dev.addr = dev_addr; + tpm_dev.chip_type = tpm_vendor_chip_type(); + chip = tpm_register_hardware(&tpm_tis_i2c); if (chip < 0) { rc = -ENODEV; @@ -519,26 +588,33 @@ int tpm_vendor_init(uint32_t dev_addr) chip->vendor.timeout_c = TIS_SHORT_TIMEOUT; chip->vendor.timeout_d = TIS_SHORT_TIMEOUT; - if (request_locality(chip, 0) != 0) { + if (request_locality(chip, 0) < 0) { rc = -ENODEV; goto out_err; } - /* read four bytes from DID_VID register */ + /* Read four bytes from DID_VID register */ if (iic_tpm_read(TPM_DID_VID(0), (uchar *)&vendor, 4) < 0) { rc = -EIO; goto out_release; } - /* create DID_VID register value, after swapping to little-endian */ - vendor = be32_to_cpu(vendor); + if (tpm_dev.chip_type == SLB9635) { + vendor = be32_to_cpu(vendor); + expected_did_vid = TPM_TIS_I2C_DID_VID_9635; + } else { + /* device id and byte order has changed for newer i2c tpms */ + expected_did_vid = TPM_TIS_I2C_DID_VID_9645; + } - if (vendor != TPM_TIS_I2C_DID_VID) { + if (tpm_dev.chip_type != UNKNOWN && vendor != expected_did_vid) { + error("Vendor id did not match! ID was %08x\n", vendor); rc = -ENODEV; goto out_release; } - dev_info(dev, "1.2 TPM (device-id 0x%X)\n", vendor >> 16); + debug("1.2 TPM (chip type %s device-id 0x%X)\n", + chip_name[tpm_dev.chip_type], vendor >> 16); /* * A timeout query to TPM can be placed here. diff --git a/drivers/tpm/generic_lpc_tpm.c b/drivers/tpm/tpm_tis_lpc.c index 04ad418..04ad418 100644 --- a/drivers/tpm/generic_lpc_tpm.c +++ b/drivers/tpm/tpm_tis_lpc.c diff --git a/drivers/usb/eth/asix.c b/drivers/usb/eth/asix.c index 75ec8f7..db39bd8 100644 --- a/drivers/usb/eth/asix.c +++ b/drivers/usb/eth/asix.c @@ -407,46 +407,40 @@ static int asix_basic_reset(struct ueth_data *dev) rx_ctl = asix_read_rx_ctl(dev); debug("RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); - return 0; -} - -/* - * Asix callbacks - */ -static int asix_init(struct eth_device *eth, bd_t *bd) -{ - struct ueth_data *dev = (struct ueth_data *)eth->priv; - int timeout = 0; -#define TIMEOUT_RESOLUTION 50 /* ms */ - int link_detected; - - debug("** %s()\n", __func__); - dev->phy_id = asix_get_phy_addr(dev); if (dev->phy_id < 0) debug("Failed to read phy id\n"); - if (asix_sw_reset(dev, AX_SWRESET_PRL) < 0) - goto out_err; - - if (asix_sw_reset(dev, AX_SWRESET_IPRL | AX_SWRESET_PRL) < 0) - goto out_err; - asix_mdio_write(dev, dev->phy_id, MII_BMCR, BMCR_RESET); asix_mdio_write(dev, dev->phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA); mii_nway_restart(dev); if (asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT) < 0) - goto out_err; + return -1; if (asix_write_cmd(dev, AX_CMD_WRITE_IPG0, AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT, AX88772_IPG2_DEFAULT, 0, NULL) < 0) { debug("Write IPG,IPG1,IPG2 failed\n"); - goto out_err; + return -1; } + return 0; +} + +/* + * Asix callbacks + */ +static int asix_init(struct eth_device *eth, bd_t *bd) +{ + struct ueth_data *dev = (struct ueth_data *)eth->priv; + int timeout = 0; +#define TIMEOUT_RESOLUTION 50 /* ms */ + int link_detected; + + debug("** %s()\n", __func__); + if (asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL) < 0) goto out_err; @@ -591,6 +585,7 @@ struct asix_dongle { static const struct asix_dongle const asix_dongles[] = { { 0x05ac, 0x1402, FLAG_TYPE_AX88772 }, /* Apple USB Ethernet Adapter */ { 0x07d1, 0x3c05, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver B1 */ + { 0x2001, 0x1a02, FLAG_TYPE_AX88772 }, /* D-Link DUB-E100 H/W Ver C1 */ /* Cables-to-Go USB Ethernet Adapter */ { 0x0b95, 0x772a, FLAG_TYPE_AX88772 }, { 0x0b95, 0x7720, FLAG_TYPE_AX88772 }, /* Trendnet TU2-ET100 V3.0R */ diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index e545b6b..432cf17 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -35,6 +35,7 @@ endif # new USB gadget layer dependencies ifdef CONFIG_USB_GADGET COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o +COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o endif diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 2c5600e..f867793 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -997,7 +997,8 @@ static int composite_bind(struct usb_gadget *gadget) if (status < 0) goto fail; - cdev->desc = *composite->dev; + memcpy(&cdev->desc, composite->dev, + sizeof(struct usb_device_descriptor)); cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; debug("%s: ready\n", composite->name); @@ -1098,4 +1099,5 @@ void usb_composite_unregister(struct usb_composite_driver *driver) if (composite != driver) return; usb_gadget_unregister_driver(&composite_driver); + composite = NULL; } diff --git a/drivers/usb/gadget/f_dfu.c b/drivers/usb/gadget/f_dfu.c index a322ae5..d7ae0c0 100644 --- a/drivers/usb/gadget/f_dfu.c +++ b/drivers/usb/gadget/f_dfu.c @@ -5,6 +5,13 @@ * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com> * Lukasz Majewski <l.majewski@samsung.com> * + * Based on OpenMoko u-boot: drivers/usb/usbdfu.c + * (C) 2007 by OpenMoko, Inc. + * Author: Harald Welte <laforge@openmoko.org> + * + * based on existing SAM7DFU code from OpenPCD: + * (C) Copyright 2006 by Harald Welte <hwelte at hmw-consulting.de> + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -183,6 +190,7 @@ static inline void to_dfu_mode(struct f_dfu *f_dfu) { f_dfu->usb_function.strings = dfu_strings; f_dfu->usb_function.hs_descriptors = f_dfu->function; + f_dfu->dfu_state = DFU_STATE_dfuIDLE; } static inline void to_runtime_mode(struct f_dfu *f_dfu) @@ -233,7 +241,6 @@ static int state_app_idle(struct f_dfu *f_dfu, case USB_REQ_DFU_DETACH: f_dfu->dfu_state = DFU_STATE_appDETACH; to_dfu_mode(f_dfu); - f_dfu->dfu_state = DFU_STATE_dfuIDLE; value = RET_ZLP; break; default: @@ -589,7 +596,7 @@ static int dfu_prepare_function(struct f_dfu *f_dfu, int n) struct usb_interface_descriptor *d; int i = 0; - f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n); + f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n + 1); if (!f_dfu->function) goto enomem; @@ -653,6 +660,8 @@ static int dfu_bind(struct usb_configuration *c, struct usb_function *f) ->iInterface = id; } + to_dfu_mode(f_dfu); + stringtab_dfu.strings = f_dfu->strings; cdev->req->context = f_dfu; diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index c28866f..5b348d7 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -577,9 +577,9 @@ static int fsg_setup(struct usb_function *f, { struct fsg_dev *fsg = fsg_from_func(f); struct usb_request *req = fsg->common->ep0req; - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 w_length = le16_to_cpu(ctrl->wLength); + u16 w_index = get_unaligned_le16(&ctrl->wIndex); + u16 w_value = get_unaligned_le16(&ctrl->wValue); + u16 w_length = get_unaligned_le16(&ctrl->wLength); if (!fsg_is_set(fsg->common)) return -EOPNOTSUPP; @@ -617,7 +617,7 @@ static int fsg_setup(struct usb_function *f, "unknown class-specific control req " "%02x.%02x v%04x i%04x l%u\n", ctrl->bRequestType, ctrl->bRequest, - le16_to_cpu(ctrl->wValue), w_index, w_length); + get_unaligned_le16(&ctrl->wValue), w_index, w_length); return -EOPNOTSUPP; } @@ -2261,7 +2261,8 @@ reset: if (rc) goto reset; fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize); + common->bulk_out_maxpacket = + le16_to_cpu(get_unaligned(&d->wMaxPacketSize)); clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); /* Allocate the requests */ diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c new file mode 100644 index 0000000..d003331 --- /dev/null +++ b/drivers/usb/gadget/fotg210.c @@ -0,0 +1,948 @@ +/* + * Faraday USB 2.0 OTG Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include <common.h> +#include <command.h> +#include <config.h> +#include <net.h> +#include <malloc.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <linux/types.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> + +#include <usb/fotg210.h> + +#define CFG_NUM_ENDPOINTS 4 +#define CFG_EP0_MAX_PACKET_SIZE 64 +#define CFG_EPX_MAX_PACKET_SIZE 512 + +#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */ + +struct fotg210_chip; + +struct fotg210_ep { + struct usb_ep ep; + + uint maxpacket; + uint id; + uint stopped; + + struct list_head queue; + struct fotg210_chip *chip; + const struct usb_endpoint_descriptor *desc; +}; + +struct fotg210_request { + struct usb_request req; + struct list_head queue; + struct fotg210_ep *ep; +}; + +struct fotg210_chip { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct fotg210_regs *regs; + uint8_t irq; + uint16_t addr; + int pullup; + enum usb_device_state state; + struct fotg210_ep ep[1 + CFG_NUM_ENDPOINTS]; +}; + +static struct usb_endpoint_descriptor ep0_desc = { + .bLength = sizeof(struct usb_endpoint_descriptor), + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, +}; + +static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in) +{ + return (id < 0) ? 0 : ((id & 0x03) + 1); +} + +static inline int ep_to_fifo(struct fotg210_chip *chip, int id) +{ + return (id <= 0) ? -1 : ((id - 1) & 0x03); +} + +static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr) +{ + int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK; + struct fotg210_regs *regs = chip->regs; + + if (ep_addr & USB_DIR_IN) { + /* reset endpoint */ + setbits_le32(®s->iep[ep - 1], IEP_RESET); + mdelay(1); + clrbits_le32(®s->iep[ep - 1], IEP_RESET); + /* clear endpoint stall */ + clrbits_le32(®s->iep[ep - 1], IEP_STALL); + } else { + /* reset endpoint */ + setbits_le32(®s->oep[ep - 1], OEP_RESET); + mdelay(1); + clrbits_le32(®s->oep[ep - 1], OEP_RESET); + /* clear endpoint stall */ + clrbits_le32(®s->oep[ep - 1], OEP_STALL); + } + + return 0; +} + +static int fotg210_reset(struct fotg210_chip *chip) +{ + struct fotg210_regs *regs = chip->regs; + uint32_t i; + + chip->state = USB_STATE_POWERED; + + /* chip enable */ + writel(DEVCTRL_EN, ®s->dev_ctrl); + + /* device address reset */ + chip->addr = 0; + writel(0, ®s->dev_addr); + + /* set idle counter to 7ms */ + writel(7, ®s->idle); + + /* disable all interrupts */ + writel(IMR_MASK, ®s->imr); + writel(GIMR_MASK, ®s->gimr); + writel(GIMR0_MASK, ®s->gimr0); + writel(GIMR1_MASK, ®s->gimr1); + writel(GIMR2_MASK, ®s->gimr2); + + /* clear interrupts */ + writel(ISR_MASK, ®s->isr); + writel(0, ®s->gisr); + writel(0, ®s->gisr0); + writel(0, ®s->gisr1); + writel(0, ®s->gisr2); + + /* chip reset */ + setbits_le32(®s->dev_ctrl, DEVCTRL_RESET); + mdelay(10); + if (readl(®s->dev_ctrl) & DEVCTRL_RESET) { + printf("fotg210: chip reset failed\n"); + return -1; + } + + /* CX FIFO reset */ + setbits_le32(®s->cxfifo, CXFIFO_CXFIFOCLR); + mdelay(10); + if (readl(®s->cxfifo) & CXFIFO_CXFIFOCLR) { + printf("fotg210: ep0 fifo reset failed\n"); + return -1; + } + + /* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */ + writel(EPMAP14_DEFAULT, ®s->epmap14); + writel(EPMAP58_DEFAULT, ®s->epmap58); + writel(FIFOMAP_DEFAULT, ®s->fifomap); + writel(0, ®s->fifocfg); + for (i = 0; i < 8; ++i) { + writel(CFG_EPX_MAX_PACKET_SIZE, ®s->iep[i]); + writel(CFG_EPX_MAX_PACKET_SIZE, ®s->oep[i]); + } + + /* FIFO reset */ + for (i = 0; i < 4; ++i) { + writel(FIFOCSR_RESET, ®s->fifocsr[i]); + mdelay(10); + if (readl(®s->fifocsr[i]) & FIFOCSR_RESET) { + printf("fotg210: fifo%d reset failed\n", i); + return -1; + } + } + + /* enable only device interrupt and triggered at level-high */ + writel(IMR_IRQLH | IMR_HOST | IMR_OTG, ®s->imr); + writel(ISR_MASK, ®s->isr); + /* disable EP0 IN/OUT interrupt */ + writel(GIMR0_CXOUT | GIMR0_CXIN, ®s->gimr0); + /* disable EPX IN+SPK+OUT interrupts */ + writel(GIMR1_MASK, ®s->gimr1); + /* disable wakeup+idle+dma+zlp interrupts */ + writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN + | GIMR2_ZLPRX | GIMR2_ZLPTX, ®s->gimr2); + /* enable all group interrupt */ + writel(0, ®s->gimr); + + /* suspend delay = 3 ms */ + writel(3, ®s->idle); + + /* turn-on device interrupts */ + setbits_le32(®s->dev_ctrl, DEVCTRL_GIRQ_EN); + + return 0; +} + +static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask) +{ + struct fotg210_regs *regs = chip->regs; + int ret = -1; + ulong ts; + + for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { + if ((readl(®s->cxfifo) & mask) != mask) + continue; + ret = 0; + break; + } + + if (ret) + printf("fotg210: cx/ep0 timeout\n"); + + return ret; +} + +static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req) +{ + struct fotg210_chip *chip = ep->chip; + struct fotg210_regs *regs = chip->regs; + uint32_t tmp, ts; + uint8_t *buf = req->req.buf + req->req.actual; + uint32_t len = req->req.length - req->req.actual; + int fifo = ep_to_fifo(chip, ep->id); + int ret = -EBUSY; + + /* 1. init dma buffer */ + if (len > ep->maxpacket) + len = ep->maxpacket; + + /* 2. wait for dma ready (hardware) */ + for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { + if (!(readl(®s->dma_ctrl) & DMACTRL_START)) { + ret = 0; + break; + } + } + if (ret) { + printf("fotg210: dma busy\n"); + req->req.status = ret; + return ret; + } + + /* 3. DMA target setup */ + if (ep->desc->bEndpointAddress & USB_DIR_IN) + flush_dcache_range((ulong)buf, (ulong)buf + len); + else + invalidate_dcache_range((ulong)buf, (ulong)buf + len); + + writel(virt_to_phys(buf), ®s->dma_addr); + + if (ep->desc->bEndpointAddress & USB_DIR_IN) { + if (ep->id == 0) { + /* Wait until cx/ep0 fifo empty */ + fotg210_cxwait(chip, CXFIFO_CXFIFOE); + writel(DMAFIFO_CX, ®s->dma_fifo); + } else { + /* Wait until epx fifo empty */ + fotg210_cxwait(chip, CXFIFO_FIFOE(fifo)); + writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); + } + writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, ®s->dma_ctrl); + } else { + uint32_t blen; + + if (ep->id == 0) { + writel(DMAFIFO_CX, ®s->dma_fifo); + do { + blen = CXFIFO_BYTES(readl(®s->cxfifo)); + } while (blen < len); + } else { + writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); + blen = FIFOCSR_BYTES(readl(®s->fifocsr[fifo])); + } + len = (len < blen) ? len : blen; + writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, ®s->dma_ctrl); + } + + /* 4. DMA start */ + setbits_le32(®s->dma_ctrl, DMACTRL_START); + + /* 5. DMA wait */ + ret = -EBUSY; + for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { + tmp = readl(®s->gisr2); + /* DMA complete */ + if (tmp & GISR2_DMAFIN) { + ret = 0; + break; + } + /* DMA error */ + if (tmp & GISR2_DMAERR) { + printf("fotg210: dma error\n"); + break; + } + /* resume, suspend, reset */ + if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) { + printf("fotg210: dma reset by host\n"); + break; + } + } + + /* 7. DMA target reset */ + if (ret) + writel(DMACTRL_ABORT | DMACTRL_CLRFF, ®s->dma_ctrl); + + writel(0, ®s->gisr2); + writel(0, ®s->dma_fifo); + + req->req.status = ret; + if (!ret) + req->req.actual += len; + else + printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret); + + return len; +} + +/* + * result of setup packet + */ +#define CX_IDLE 0 +#define CX_FINISH 1 +#define CX_STALL 2 + +static void fotg210_setup(struct fotg210_chip *chip) +{ + int id, ret = CX_IDLE; + uint32_t tmp[2]; + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp; + struct fotg210_regs *regs = chip->regs; + + /* + * If this is the first Cx 8 byte command, + * we can now query USB mode (high/full speed; USB 2.0/USB 1.0) + */ + if (chip->state == USB_STATE_POWERED) { + chip->state = USB_STATE_DEFAULT; + if (readl(®s->otgcsr) & OTGCSR_DEV_B) { + /* Mini-B */ + if (readl(®s->dev_ctrl) & DEVCTRL_HS) { + puts("fotg210: HS\n"); + chip->gadget.speed = USB_SPEED_HIGH; + /* SOF mask timer = 1100 ticks */ + writel(SOFMTR_TMR(1100), ®s->sof_mtr); + } else { + puts("fotg210: FS\n"); + chip->gadget.speed = USB_SPEED_FULL; + /* SOF mask timer = 10000 ticks */ + writel(SOFMTR_TMR(10000), ®s->sof_mtr); + } + } else { + printf("fotg210: mini-A?\n"); + } + } + + /* switch data port to ep0 */ + writel(DMAFIFO_CX, ®s->dma_fifo); + /* fetch 8 bytes setup packet */ + tmp[0] = readl(®s->ep0_data); + tmp[1] = readl(®s->ep0_data); + /* release data port */ + writel(0, ®s->dma_fifo); + + if (req->bRequestType & USB_DIR_IN) + ep0_desc.bEndpointAddress = USB_DIR_IN; + else + ep0_desc.bEndpointAddress = USB_DIR_OUT; + + ret = CX_IDLE; + + if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { + switch (req->bRequest) { + case USB_REQ_SET_CONFIGURATION: + debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF); + if (!(req->wValue & 0x00FF)) { + chip->state = USB_STATE_ADDRESS; + writel(chip->addr, ®s->dev_addr); + } else { + chip->state = USB_STATE_CONFIGURED; + writel(chip->addr | DEVADDR_CONF, + ®s->dev_addr); + } + ret = CX_IDLE; + break; + + case USB_REQ_SET_ADDRESS: + debug("fotg210: set_addr(0x%04X)\n", req->wValue); + chip->state = USB_STATE_ADDRESS; + chip->addr = req->wValue & DEVADDR_ADDR_MASK; + ret = CX_FINISH; + writel(chip->addr, ®s->dev_addr); + break; + + case USB_REQ_CLEAR_FEATURE: + debug("fotg210: clr_feature(%d, %d)\n", + req->bRequestType & 0x03, req->wValue); + switch (req->wValue) { + case 0: /* [Endpoint] halt */ + ep_reset(chip, req->wIndex); + ret = CX_FINISH; + break; + case 1: /* [Device] remote wake-up */ + case 2: /* [Device] test mode */ + default: + ret = CX_STALL; + break; + } + break; + + case USB_REQ_SET_FEATURE: + debug("fotg210: set_feature(%d, %d)\n", + req->wValue, req->wIndex & 0xf); + switch (req->wValue) { + case 0: /* Endpoint Halt */ + id = req->wIndex & 0xf; + setbits_le32(®s->iep[id - 1], IEP_STALL); + setbits_le32(®s->oep[id - 1], OEP_STALL); + ret = CX_FINISH; + break; + case 1: /* Remote Wakeup */ + case 2: /* Test Mode */ + default: + ret = CX_STALL; + break; + } + break; + + case USB_REQ_GET_STATUS: + debug("fotg210: get_status\n"); + ret = CX_STALL; + break; + + case USB_REQ_SET_DESCRIPTOR: + debug("fotg210: set_descriptor\n"); + ret = CX_STALL; + break; + + case USB_REQ_SYNCH_FRAME: + debug("fotg210: sync frame\n"); + ret = CX_STALL; + break; + } + } /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */ + + if (ret == CX_IDLE && chip->driver->setup) { + if (chip->driver->setup(&chip->gadget, req) < 0) + ret = CX_STALL; + else + ret = CX_FINISH; + } + + switch (ret) { + case CX_FINISH: + setbits_le32(®s->cxfifo, CXFIFO_CXFIN); + break; + + case CX_STALL: + setbits_le32(®s->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN); + printf("fotg210: cx_stall!\n"); + break; + + case CX_IDLE: + debug("fotg210: cx_idle?\n"); + default: + break; + } +} + +/* + * fifo - FIFO id + * zlp - zero length packet + */ +static void fotg210_recv(struct fotg210_chip *chip, int ep_id) +{ + struct fotg210_regs *regs = chip->regs; + struct fotg210_ep *ep = chip->ep + ep_id; + struct fotg210_request *req; + int len; + + if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) { + printf("fotg210: ep%d recv, invalid!\n", ep->id); + return; + } + + if (list_empty(&ep->queue)) { + printf("fotg210: ep%d recv, drop!\n", ep->id); + return; + } + + req = list_first_entry(&ep->queue, struct fotg210_request, queue); + len = fotg210_dma(ep, req); + if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) { + list_del_init(&req->queue); + if (req->req.complete) + req->req.complete(&ep->ep, &req->req); + } + + if (ep->id > 0 && list_empty(&ep->queue)) { + setbits_le32(®s->gimr1, + GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); + } +} + +/* + * USB Gadget Layer + */ +static int fotg210_ep_enable( + struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) +{ + struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); + struct fotg210_chip *chip = ep->chip; + struct fotg210_regs *regs = chip->regs; + int id = ep_to_fifo(chip, ep->id); + int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0; + + if (!_ep || !desc + || desc->bDescriptorType != USB_DT_ENDPOINT + || le16_to_cpu(desc->wMaxPacketSize) == 0) { + printf("fotg210: bad ep or descriptor\n"); + return -EINVAL; + } + + ep->desc = desc; + ep->stopped = 0; + + if (in) + setbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_IN)); + + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_CONTROL: + return -EINVAL; + + case USB_ENDPOINT_XFER_ISOC: + setbits_le32(®s->fifocfg, + FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC)); + break; + + case USB_ENDPOINT_XFER_BULK: + setbits_le32(®s->fifocfg, + FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK)); + break; + + case USB_ENDPOINT_XFER_INT: + setbits_le32(®s->fifocfg, + FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR)); + break; + } + + return 0; +} + +static int fotg210_ep_disable(struct usb_ep *_ep) +{ + struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); + struct fotg210_chip *chip = ep->chip; + struct fotg210_regs *regs = chip->regs; + int id = ep_to_fifo(chip, ep->id); + + ep->desc = NULL; + ep->stopped = 1; + + clrbits_le32(®s->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK)); + clrbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK)); + + return 0; +} + +static struct usb_request *fotg210_ep_alloc_request( + struct usb_ep *_ep, gfp_t gfp_flags) +{ + struct fotg210_request *req = malloc(sizeof(*req)); + + if (req) { + memset(req, 0, sizeof(*req)); + INIT_LIST_HEAD(&req->queue); + } + return &req->req; +} + +static void fotg210_ep_free_request( + struct usb_ep *_ep, struct usb_request *_req) +{ + struct fotg210_request *req; + + req = container_of(_req, struct fotg210_request, req); + free(req); +} + +static int fotg210_ep_queue( + struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) +{ + struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); + struct fotg210_chip *chip = ep->chip; + struct fotg210_regs *regs = chip->regs; + struct fotg210_request *req; + + req = container_of(_req, struct fotg210_request, req); + if (!_req || !_req->complete || !_req->buf + || !list_empty(&req->queue)) { + printf("fotg210: invalid request to ep%d\n", ep->id); + return -EINVAL; + } + + if (!chip || chip->state == USB_STATE_SUSPENDED) { + printf("fotg210: request while chip suspended\n"); + return -EINVAL; + } + + req->req.actual = 0; + req->req.status = -EINPROGRESS; + + if (req->req.length == 0) { + req->req.status = 0; + if (req->req.complete) + req->req.complete(&ep->ep, &req->req); + return 0; + } + + if (ep->id == 0) { + do { + int len = fotg210_dma(ep, req); + if (len < ep->ep.maxpacket) + break; + if (ep->desc->bEndpointAddress & USB_DIR_IN) + udelay(100); + } while (req->req.length > req->req.actual); + } else { + if (ep->desc->bEndpointAddress & USB_DIR_IN) { + do { + int len = fotg210_dma(ep, req); + if (len < ep->ep.maxpacket) + break; + } while (req->req.length > req->req.actual); + } else { + list_add_tail(&req->queue, &ep->queue); + clrbits_le32(®s->gimr1, + GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); + } + } + + if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) { + if (req->req.complete) + req->req.complete(&ep->ep, &req->req); + } + + return 0; +} + +static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); + struct fotg210_request *req; + + /* 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; + + /* remove the request */ + list_del_init(&req->queue); + + /* update status & invoke complete callback */ + if (req->req.status == -EINPROGRESS) { + req->req.status = -ECONNRESET; + if (req->req.complete) + req->req.complete(_ep, &req->req); + } + + return 0; +} + +static int fotg210_ep_halt(struct usb_ep *_ep, int halt) +{ + struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); + struct fotg210_chip *chip = ep->chip; + struct fotg210_regs *regs = chip->regs; + int ret = -1; + + debug("fotg210: ep%d halt=%d\n", ep->id, halt); + + /* Endpoint STALL */ + if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) { + if (halt) { + /* wait until all ep fifo empty */ + fotg210_cxwait(chip, 0xf00); + /* stall */ + if (ep->desc->bEndpointAddress & USB_DIR_IN) { + setbits_le32(®s->iep[ep->id - 1], + IEP_STALL); + } else { + setbits_le32(®s->oep[ep->id - 1], + OEP_STALL); + } + } else { + if (ep->desc->bEndpointAddress & USB_DIR_IN) { + clrbits_le32(®s->iep[ep->id - 1], + IEP_STALL); + } else { + clrbits_le32(®s->oep[ep->id - 1], + OEP_STALL); + } + } + ret = 0; + } + + return ret; +} + +/* + * activate/deactivate link with host. + */ +static void pullup(struct fotg210_chip *chip, int is_on) +{ + struct fotg210_regs *regs = chip->regs; + + if (is_on) { + if (!chip->pullup) { + chip->state = USB_STATE_POWERED; + chip->pullup = 1; + /* enable the chip */ + setbits_le32(®s->dev_ctrl, DEVCTRL_EN); + /* clear unplug bit (BIT0) */ + clrbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); + } + } else { + chip->state = USB_STATE_NOTATTACHED; + chip->pullup = 0; + chip->addr = 0; + writel(chip->addr, ®s->dev_addr); + /* set unplug bit (BIT0) */ + setbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); + /* disable the chip */ + clrbits_le32(®s->dev_ctrl, DEVCTRL_EN); + } +} + +static int fotg210_pullup(struct usb_gadget *_gadget, int is_on) +{ + struct fotg210_chip *chip; + + chip = container_of(_gadget, struct fotg210_chip, gadget); + + debug("fotg210: pullup=%d\n", is_on); + + pullup(chip, is_on); + + return 0; +} + +static int fotg210_get_frame(struct usb_gadget *_gadget) +{ + struct fotg210_chip *chip; + struct fotg210_regs *regs; + + chip = container_of(_gadget, struct fotg210_chip, gadget); + regs = chip->regs; + + return SOFFNR_FNR(readl(®s->sof_fnr)); +} + +static struct usb_gadget_ops fotg210_gadget_ops = { + .get_frame = fotg210_get_frame, + .pullup = fotg210_pullup, +}; + +static struct usb_ep_ops fotg210_ep_ops = { + .enable = fotg210_ep_enable, + .disable = fotg210_ep_disable, + .queue = fotg210_ep_queue, + .dequeue = fotg210_ep_dequeue, + .set_halt = fotg210_ep_halt, + .alloc_request = fotg210_ep_alloc_request, + .free_request = fotg210_ep_free_request, +}; + +static struct fotg210_chip controller = { + .regs = (void __iomem *)CONFIG_FOTG210_BASE, + .gadget = { + .name = "fotg210_udc", + .ops = &fotg210_gadget_ops, + .ep0 = &controller.ep[0].ep, + .speed = USB_SPEED_UNKNOWN, + .is_dualspeed = 1, + .is_otg = 0, + .is_a_peripheral = 0, + .b_hnp_enable = 0, + .a_hnp_support = 0, + .a_alt_hnp_support = 0, + }, + .ep[0] = { + .id = 0, + .ep = { + .name = "ep0", + .ops = &fotg210_ep_ops, + }, + .desc = &ep0_desc, + .chip = &controller, + .maxpacket = CFG_EP0_MAX_PACKET_SIZE, + }, + .ep[1] = { + .id = 1, + .ep = { + .name = "ep1", + .ops = &fotg210_ep_ops, + }, + .chip = &controller, + .maxpacket = CFG_EPX_MAX_PACKET_SIZE, + }, + .ep[2] = { + .id = 2, + .ep = { + .name = "ep2", + .ops = &fotg210_ep_ops, + }, + .chip = &controller, + .maxpacket = CFG_EPX_MAX_PACKET_SIZE, + }, + .ep[3] = { + .id = 3, + .ep = { + .name = "ep3", + .ops = &fotg210_ep_ops, + }, + .chip = &controller, + .maxpacket = CFG_EPX_MAX_PACKET_SIZE, + }, + .ep[4] = { + .id = 4, + .ep = { + .name = "ep4", + .ops = &fotg210_ep_ops, + }, + .chip = &controller, + .maxpacket = CFG_EPX_MAX_PACKET_SIZE, + }, +}; + +int usb_gadget_handle_interrupts(void) +{ + struct fotg210_chip *chip = &controller; + struct fotg210_regs *regs = chip->regs; + uint32_t id, st, isr, gisr; + + isr = readl(®s->isr) & (~readl(®s->imr)); + gisr = readl(®s->gisr) & (~readl(®s->gimr)); + if (!(isr & ISR_DEV) || !gisr) + return 0; + + writel(ISR_DEV, ®s->isr); + + /* CX interrupts */ + if (gisr & GISR_GRP0) { + st = readl(®s->gisr0); + writel(0, ®s->gisr0); + + if (st & GISR0_CXERR) + printf("fotg210: cmd error\n"); + + if (st & GISR0_CXABORT) + printf("fotg210: cmd abort\n"); + + if (st & GISR0_CXSETUP) /* setup */ + fotg210_setup(chip); + else if (st & GISR0_CXEND) /* command finish */ + setbits_le32(®s->cxfifo, CXFIFO_CXFIN); + } + + /* FIFO interrupts */ + if (gisr & GISR_GRP1) { + st = readl(®s->gisr1); + for (id = 0; id < 4; ++id) { + if (st & GISR1_RX_FIFO(id)) + fotg210_recv(chip, fifo_to_ep(chip, id, 0)); + } + } + + /* Device Status Interrupts */ + if (gisr & GISR_GRP2) { + st = readl(®s->gisr2); + writel(0, ®s->gisr2); + + if (st & GISR2_RESET) + printf("fotg210: reset by host\n"); + else if (st & GISR2_SUSPEND) + printf("fotg210: suspend/removed\n"); + else if (st & GISR2_RESUME) + printf("fotg210: resume\n"); + + /* Errors */ + if (st & GISR2_ISOCERR) + printf("fotg210: iso error\n"); + if (st & GISR2_ISOCABT) + printf("fotg210: iso abort\n"); + if (st & GISR2_DMAERR) + printf("fotg210: dma error\n"); + } + + return 0; +} + +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + int i, ret = 0; + struct fotg210_chip *chip = &controller; + + if (!driver || !driver->bind || !driver->setup) { + puts("fotg210: bad parameter.\n"); + return -EINVAL; + } + + INIT_LIST_HEAD(&chip->gadget.ep_list); + for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) { + struct fotg210_ep *ep = chip->ep + i; + + ep->ep.maxpacket = ep->maxpacket; + INIT_LIST_HEAD(&ep->queue); + + if (ep->id == 0) { + ep->stopped = 0; + } else { + ep->stopped = 1; + list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list); + } + } + + if (fotg210_reset(chip)) { + puts("fotg210: reset failed.\n"); + return -EINVAL; + } + + ret = driver->bind(&chip->gadget); + if (ret) { + debug("fotg210: driver->bind() returned %d\n", ret); + return ret; + } + chip->driver = driver; + + return ret; +} + +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct fotg210_chip *chip = &controller; + + driver->unbind(&chip->gadget); + chip->driver = NULL; + + pullup(chip, 0); + + return 0; +} diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c index cc3f344..8a3777b 100644 --- a/drivers/usb/gadget/g_dnl.c +++ b/drivers/usb/gadget/g_dnl.c @@ -125,6 +125,12 @@ static int g_dnl_config_register(struct usb_composite_dev *cdev) return usb_add_config(cdev, &config); } +__weak +int g_dnl_bind_fixup(struct usb_device_descriptor *dev) +{ + return 0; +} + static int g_dnl_bind(struct usb_composite_dev *cdev) { struct usb_gadget *gadget = cdev->gadget; @@ -147,6 +153,7 @@ static int g_dnl_bind(struct usb_composite_dev *cdev) g_dnl_string_defs[1].id = id; device_desc.iProduct = id; + g_dnl_bind_fixup(&device_desc); ret = g_dnl_config_register(cdev); if (ret) goto error; diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index e570142..f038747 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -150,6 +150,12 @@ #define gadget_is_mv(g) 0 #endif +#ifdef CONFIG_USB_GADGET_FOTG210 +#define gadget_is_fotg210(g) (!strcmp("fotg210_udc", (g)->name)) +#else +#define gadget_is_fotg210(g) 0 +#endif + /* * CONFIG_USB_GADGET_SX2 * CONFIG_USB_GADGET_AU1X00 @@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x20; else if (gadget_is_mv(gadget)) return 0x21; + else if (gadget_is_fotg210(gadget)) + return 0x22; return -ENOENT; } diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 9ce98f0..085503d 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -314,7 +314,8 @@ static int pxa25x_ep_enable(struct usb_ep *_ep, if (!_ep || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress - || ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) { + || ep->fifo_size < + le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))) { printf("%s, bad ep or descriptor\n", __func__); return -EINVAL; } @@ -329,9 +330,9 @@ static int pxa25x_ep_enable(struct usb_ep *_ep, /* hardware _could_ do smaller, but driver doesn't */ if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && le16_to_cpu(desc->wMaxPacketSize) + && le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)) != BULK_FIFO_SIZE) - || !desc->wMaxPacketSize) { + || !get_unaligned(&desc->wMaxPacketSize)) { printf("%s, bad %s maxpacket\n", __func__, _ep->name); return -ERANGE; } @@ -345,7 +346,7 @@ static int pxa25x_ep_enable(struct usb_ep *_ep, ep->desc = desc; ep->stopped = 0; ep->pio_irqs = 0; - ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); + ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); /* flush fifo (mostly for OUT buffers) */ pxa25x_ep_fifo_flush(_ep); @@ -485,7 +486,7 @@ write_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) { unsigned max; - max = le16_to_cpu(ep->desc->wMaxPacketSize); + max = le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize)); do { unsigned count; int is_last, is_short; @@ -766,7 +767,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) */ if (unlikely(ep->bmAttributes == USB_ENDPOINT_XFER_ISOC && req->req.length > - le16_to_cpu(ep->desc->wMaxPacketSize))) + le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize)))) return -EMSGSIZE; debug_cond(NOISY, "%s queue req %p, len %d buf %p\n", diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c index 71cc0f2..598923d 100644 --- a/drivers/usb/gadget/pxa27x_udc.c +++ b/drivers/usb/gadget/pxa27x_udc.c @@ -151,7 +151,7 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint) struct urb *urb = endpoint->rcv_urb; int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; u32 *data32 = (u32 *) urb->buffer; - unsigned int i, n, is_short ; + unsigned int i, n; usbdbg("read urb on ep %d", ep_num); #if defined(USBDDBG) && defined(USBDPARANOIA) @@ -165,9 +165,8 @@ static int udc_read_urb(struct usb_endpoint_instance *endpoint) n = readl(UDCBCN(ep_num)) & 0x3ff; else /* zlp */ n = 0; - is_short = n != endpoint->rcv_packetSize; - usbdbg("n %d%s", n, is_short ? "-s" : ""); + usbdbg("n %d%s", n, n != endpoint->rcv_packetSize ? "-s" : ""); for (i = 0; i < n; i += 4) data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num)); @@ -402,16 +401,13 @@ static void udc_handle_ep(struct usb_endpoint_instance *endpoint) static void udc_state_changed(void) { - int config, interface, alternate; writel(readl(UDCCR) | UDCCR_SMAC, UDCCR); - config = (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S; - interface = (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S; - alternate = (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S; - usbdbg("New UDC settings are: conf %d - inter %d - alter %d", - config, interface, alternate); + (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S, + (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S, + (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S); usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); writel(UDCISR1_IRCC, UDCISR1); diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 87a5970..98f2a10 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o else COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o endif +COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c new file mode 100644 index 0000000..86add36 --- /dev/null +++ b/drivers/usb/host/ehci-faraday.c @@ -0,0 +1,148 @@ +/* + * Faraday USB 2.0 EHCI Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#include <common.h> +#include <asm/io.h> +#include <usb.h> +#include <usb/fusbh200.h> +#include <usb/fotg210.h> + +#include "ehci.h" + +#ifndef CONFIG_USB_EHCI_BASE_LIST +#define CONFIG_USB_EHCI_BASE_LIST { CONFIG_USB_EHCI_BASE } +#endif + +union ehci_faraday_regs { + struct fusbh200_regs usb; + struct fotg210_regs otg; +}; + +static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs) +{ + return !readl(®s->usb.easstr); +} + +/* + * Create the appropriate control structures to manage + * a new EHCI host controller. + */ +int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr, + struct ehci_hcor **ret_hcor) +{ + struct ehci_hccr *hccr; + struct ehci_hcor *hcor; + union ehci_faraday_regs *regs; + uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST; + + if (index < 0 || index >= ARRAY_SIZE(base_list)) + return -1; + regs = (void __iomem *)base_list[index]; + hccr = (struct ehci_hccr *)®s->usb.hccr; + hcor = (struct ehci_hcor *)®s->usb.hcor; + + if (ehci_is_fotg2xx(regs)) { + /* A-device bus reset */ + /* ... Power off A-device */ + setbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSDROP); + /* ... Drop vbus and bus traffic */ + clrbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSREQ); + mdelay(1); + /* ... Power on A-device */ + clrbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSDROP); + /* ... Drive vbus and bus traffic */ + setbits_le32(®s->otg.otgcsr, OTGCSR_A_BUSREQ); + mdelay(1); + /* Disable OTG & DEV interrupts, triggered at level-high */ + writel(IMR_IRQLH | IMR_OTG | IMR_DEV, ®s->otg.imr); + /* Clear all interrupt status */ + writel(ISR_HOST | ISR_OTG | ISR_DEV, ®s->otg.isr); + } else { + /* Interrupt=level-high */ + setbits_le32(®s->usb.bmcsr, BMCSR_IRQLH); + /* VBUS on */ + clrbits_le32(®s->usb.bmcsr, BMCSR_VBUS_OFF); + /* Disable all interrupts */ + writel(0x00, ®s->usb.bmier); + writel(0x1f, ®s->usb.bmisr); + } + + *ret_hccr = hccr; + *ret_hcor = hcor; + + return 0; +} + +/* + * Destroy the appropriate control structures corresponding + * the the EHCI host controller. + */ +int ehci_hcd_stop(int index) +{ + return 0; +} + +/* + * This ehci_set_usbmode() overrides the weak function + * in "ehci-hcd.c". + */ +void ehci_set_usbmode(int index) +{ + /* nothing needs to be done */ +} + +/* + * This ehci_get_port_speed() overrides the weak function + * in "ehci-hcd.c". + */ +int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg) +{ + int spd, ret = PORTSC_PSPD_HS; + union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10); + + if (ehci_is_fotg2xx(regs)) + spd = OTGCSR_SPD(readl(®s->otg.otgcsr)); + else + spd = BMCSR_SPD(readl(®s->usb.bmcsr)); + + switch (spd) { + case 0: /* full speed */ + ret = PORTSC_PSPD_FS; + break; + case 1: /* low speed */ + ret = PORTSC_PSPD_LS; + break; + case 2: /* high speed */ + ret = PORTSC_PSPD_HS; + break; + default: + printf("ehci-faraday: invalid device speed\n"); + break; + } + + return ret; +} + +/* + * This ehci_get_portsc_register() overrides the weak function + * in "ehci-hcd.c". + */ +uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port) +{ + /* Faraday EHCI has one and only one portsc register */ + if (port) { + /* Printing the message would cause a scan failure! */ + debug("The request port(%d) is not configured\n", port); + return NULL; + } + + /* Faraday EHCI PORTSC register offset is 0x20 from hcor */ + return (uint32_t *)((uint8_t *)hcor + 0x20); +} diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index e0f3e4b..706cf0c 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -589,10 +589,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer, dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token); } else { dev->act_len = 0; +#ifndef CONFIG_USB_EHCI_FARADAY debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n", dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts), ehci_readl(&ctrl->hcor->or_portsc[0]), ehci_readl(&ctrl->hcor->or_portsc[1])); +#endif } free(qtd); @@ -603,6 +605,17 @@ fail: return -1; } +__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port) +{ + if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { + /* Printing the message would cause a scan failure! */ + debug("The request port(%u) is not configured\n", port); + return NULL; + } + + return (uint32_t *)&hcor->or_portsc[port]; +} + int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *req) @@ -616,11 +629,6 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, int port = le16_to_cpu(req->index) & 0xff; struct ehci_ctrl *ctrl = dev->controller; - if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { - printf("The request port(%d) is not configured\n", port - 1); - return -1; - } - status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1]; srclen = 0; debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n", @@ -631,6 +639,19 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, typeReq = req->request | req->requesttype << 8; switch (typeReq) { + case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8): + case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): + case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): + status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1); + if (!status_reg) + return -1; + break; + default: + status_reg = NULL; + break; + } + + switch (typeReq) { case DeviceRequest | USB_REQ_GET_DESCRIPTOR: switch (le16_to_cpu(req->value) >> 8) { case USB_DT_DEVICE: @@ -809,21 +830,23 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, break; case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): reg = ehci_readl(status_reg); + reg &= ~EHCI_PS_CLEAR; switch (le16_to_cpu(req->value)) { case USB_PORT_FEAT_ENABLE: reg &= ~EHCI_PS_PE; break; case USB_PORT_FEAT_C_ENABLE: - reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_PE; + reg |= EHCI_PS_PE; break; case USB_PORT_FEAT_POWER: if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) - reg = reg & ~(EHCI_PS_CLEAR | EHCI_PS_PP); + reg &= ~EHCI_PS_PP; + break; case USB_PORT_FEAT_C_CONNECTION: - reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_CSC; + reg |= EHCI_PS_CSC; break; case USB_PORT_FEAT_OVER_CURRENT: - reg = (reg & ~EHCI_PS_CLEAR) | EHCI_PS_OCC; + reg |= EHCI_PS_OCC; break; case USB_PORT_FEAT_C_RESET: ctrl->portreset &= ~(1 << port); @@ -903,6 +926,9 @@ int usb_lowlevel_init(int index, void **controller) qh_list->qh_overlay.qt_token = cpu_to_hc32(QT_TOKEN_STATUS(QT_TOKEN_STATUS_HALTED)); + flush_dcache_range((uint32_t)qh_list, + ALIGN_END_ADDR(struct QH, qh_list, 1)); + /* Set async. queue head pointer. */ ehci_writel(&ehcic[index].hcor->or_asynclistaddr, (uint32_t)qh_list); @@ -916,6 +942,9 @@ int usb_lowlevel_init(int index, void **controller) periodic->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE); periodic->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE); + flush_dcache_range((uint32_t)periodic, + ALIGN_END_ADDR(struct QH, periodic, 1)); + /* * Step 2: Setup frame-list: Every microframe, USB tries the same list. * In particular, device specifications on polling frequency @@ -933,6 +962,10 @@ int usb_lowlevel_init(int index, void **controller) | QH_LINK_TYPE_QH; } + flush_dcache_range((uint32_t)ehcic[index].periodic_list, + ALIGN_END_ADDR(uint32_t, ehcic[index].periodic_list, + 1024)); + /* Set periodic list base address */ ehci_writel(&ehcic[index].hcor->or_periodiclistbase, (uint32_t)ehcic[index].periodic_list); @@ -959,10 +992,13 @@ int usb_lowlevel_init(int index, void **controller) cmd |= CMD_RUN; ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd); +#ifndef CONFIG_USB_EHCI_FARADAY /* take control over the ports */ cmd = ehci_readl(&ehcic[index].hcor->or_configflag); cmd |= FLAG_CF; ehci_writel(&ehcic[index].hcor->or_configflag, cmd); +#endif + /* unblock posted write */ cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd); mdelay(5); @@ -1144,6 +1180,16 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, *buf = buffer + i * elementsize; } + flush_dcache_range((uint32_t)buffer, + ALIGN_END_ADDR(char, buffer, + queuesize * elementsize)); + flush_dcache_range((uint32_t)result->first, + ALIGN_END_ADDR(struct QH, result->first, + queuesize)); + flush_dcache_range((uint32_t)result->tds, + ALIGN_END_ADDR(struct qTD, result->tds, + queuesize)); + if (disable_periodic(ctrl) < 0) { debug("FATAL: periodic should never fail, but did"); goto fail3; @@ -1154,6 +1200,11 @@ create_int_queue(struct usb_device *dev, unsigned long pipe, int queuesize, result->last->qh_link = list->qh_link; list->qh_link = (uint32_t)result->first | QH_LINK_TYPE_QH; + flush_dcache_range((uint32_t)result->last, + ALIGN_END_ADDR(struct QH, result->last, 1)); + flush_dcache_range((uint32_t)list, + ALIGN_END_ADDR(struct QH, list, 1)); + if (enable_periodic(ctrl) < 0) { debug("FATAL: periodic should never fail, but did"); goto fail3; @@ -1184,6 +1235,8 @@ void *poll_int_queue(struct usb_device *dev, struct int_queue *queue) return NULL; } /* still active */ + invalidate_dcache_range((uint32_t)cur, + ALIGN_END_ADDR(struct QH, cur, 1)); if (cur->qh_overlay.qt_token & 0x80) { debug("Exit poll_int_queue with no completed intr transfer. " "token is %x\n", cur->qh_overlay.qt_token); @@ -1290,6 +1343,9 @@ submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, return -EINVAL; } + invalidate_dcache_range((uint32_t)buffer, + ALIGN_END_ADDR(char, buffer, length)); + ret = destroy_int_queue(dev, queue); if (ret < 0) return ret; diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c index 15d2ec0..c240032 100644 --- a/drivers/usb/musb-new/musb_uboot.c +++ b/drivers/usb/musb-new/musb_uboot.c @@ -1,4 +1,5 @@ #include <common.h> +#include <watchdog.h> #include <asm/errno.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -164,6 +165,7 @@ static struct musb *gadget; int usb_gadget_handle_interrupts(void) { + WATCHDOG_RESET(); if (!gadget || !gadget->isr) return -EINVAL; diff --git a/drivers/usb/musb/musb_hcd.c b/drivers/usb/musb/musb_hcd.c index 60e03a4..7bb91e5 100644 --- a/drivers/usb/musb/musb_hcd.c +++ b/drivers/usb/musb/musb_hcd.c @@ -1105,8 +1105,7 @@ int usb_lowlevel_init(int index, void **controller) /* Configure all the endpoint FIFO's and start usb controller */ musbr = musb_cfg.regs; - musb_configure_ep(&epinfo[0], - sizeof(epinfo) / sizeof(struct musb_epinfo)); + musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); musb_start(); /* diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c index e0b4217..e8a2ce0 100644 --- a/drivers/usb/musb/musb_udc.c +++ b/drivers/usb/musb/musb_udc.c @@ -894,8 +894,7 @@ void udc_setup_ep(struct usb_device_instance *device, unsigned int id, epinfo[id * 2].epsize = endpoint->rcv_packetSize; } - musb_configure_ep(&epinfo[0], - sizeof(epinfo) / sizeof(struct musb_epinfo)); + musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo)); } else { if (debug_level > 0) serial_printf("ERROR : %s endpoint request %d " diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c index 0793f07..e384b71 100644 --- a/drivers/video/cfb_console.c +++ b/drivers/video/cfb_console.c @@ -181,6 +181,8 @@ */ #include <video_fb.h> +#include <splash.h> + /* * some Macros */ @@ -220,11 +222,7 @@ #if defined(CONFIG_CMD_BMP) || defined(CONFIG_SPLASH_SCREEN) #include <watchdog.h> #include <bmp_layout.h> - -#ifdef CONFIG_SPLASH_SCREEN_ALIGN -#define BMP_ALIGN_CENTER 0x7FFF -#endif - +#include <splash.h> #endif /* @@ -572,8 +570,6 @@ static void video_drawchars(int xx, int yy, unsigned char *s, int count) SWAP32((video_font_draw_table32 [bits & 15][3] & eorx) ^ bgx); } - if (cfb_do_flush_cache) - flush_cache((ulong)dest0, 32); dest0 += VIDEO_FONT_WIDTH * VIDEO_PIXEL_SIZE; s++; } @@ -642,8 +638,6 @@ static void video_invertchar(int xx, int yy) for (x = firstx; x < lastx; x++) { u8 *dest = (u8 *)(video_fb_address) + x + y; *dest = ~*dest; - if (cfb_do_flush_cache) - flush_cache((ulong)dest, 4); } } } @@ -687,6 +681,8 @@ void console_cursor(int state) } cursor_state = state; } + if (cfb_do_flush_cache) + flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); } #endif @@ -739,8 +735,6 @@ static void console_clear_line(int line, int begin, int end) memsetl(offset + i * VIDEO_LINE_LEN, size, bgx); } #endif - if (cfb_do_flush_cache) - flush_cache((ulong)CONSOLE_ROW_FIRST, CONSOLE_SIZE); } static void console_scrollup(void) @@ -1146,6 +1140,8 @@ void video_putc(const char c) #else parse_putc(c); #endif + if (cfb_do_flush_cache) + flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); } void video_puts(const char *s) @@ -1799,6 +1795,8 @@ int video_display_bitmap(ulong bmp_image, int x, int y) } #endif + if (cfb_do_flush_cache) + flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); return (0); } #endif @@ -1974,31 +1972,14 @@ static void *video_logo(void) __maybe_unused ulong addr; __maybe_unused char *s; -#ifdef CONFIG_SPLASH_SCREEN_ALIGN - s = getenv("splashpos"); - if (s != NULL) { - if (s[0] == 'm') - video_logo_xpos = BMP_ALIGN_CENTER; - else - video_logo_xpos = simple_strtol(s, NULL, 0); - - s = strchr(s + 1, ','); - if (s != NULL) { - if (s[1] == 'm') - video_logo_ypos = BMP_ALIGN_CENTER; - else - video_logo_ypos = simple_strtol(s + 1, NULL, 0); - } - } -#endif /* CONFIG_SPLASH_SCREEN_ALIGN */ + splash_get_pos(&video_logo_xpos, &video_logo_ypos); #ifdef CONFIG_SPLASH_SCREEN s = getenv("splashimage"); if (s != NULL) { - + splash_screen_prepare(); addr = simple_strtoul(s, NULL, 16); - if (video_display_bitmap(addr, video_logo_xpos, video_logo_ypos) == 0) { @@ -2209,6 +2190,9 @@ static int video_init(void) console_col = 0; console_row = 0; + if (cfb_do_flush_cache) + flush_cache(VIDEO_FB_ADRS, VIDEO_SIZE); + return 0; } diff --git a/drivers/video/s6e8ax0.c b/drivers/video/s6e8ax0.c index 176c518..f6db694 100644 --- a/drivers/video/s6e8ax0.c +++ b/drivers/video/s6e8ax0.c @@ -29,7 +29,7 @@ static void s6e8ax0_panel_cond(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; int reverse = dsim_dev->dsim_lcd_dev->reverse_panel; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xf8, 0x3d, 0x35, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x4c, 0x6e, 0x10, 0x27, 0x7d, 0x3f, 0x10, 0x00, 0x00, 0x20, 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, @@ -37,7 +37,7 @@ static void s6e8ax0_panel_cond(struct mipi_dsim_device *dsim_dev) 0xff, 0xff, 0xc8 }; - const unsigned char data_to_send_reverse[] = { + static const unsigned char data_to_send_reverse[] = { 0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, 0x3c, 0x7d, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, 0x02, 0x08, 0x08, @@ -58,7 +58,7 @@ static void s6e8ax0_panel_cond(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_display_cond(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xf2, 0x80, 0x03, 0x0d }; @@ -71,7 +71,7 @@ static void s6e8ax0_gamma_cond(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; /* 7500K 2.2 Set : 30cd */ - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xfa, 0x01, 0x60, 0x10, 0x60, 0xf5, 0x00, 0xff, 0xad, 0xaf, 0xba, 0xc3, 0xd8, 0xc5, 0x9f, 0xc6, 0x9e, 0xc1, 0xdc, 0xc0, 0x00, 0x61, 0x00, 0x5a, 0x00, 0x74, @@ -92,7 +92,7 @@ static void s6e8ax0_gamma_update(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_etc_source_control(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xf6, 0x00, 0x02, 0x00 }; @@ -104,7 +104,7 @@ static void s6e8ax0_etc_source_control(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_etc_pentile_control(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0, 0x00 }; @@ -117,7 +117,7 @@ static void s6e8ax0_etc_pentile_control(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_etc_mipi_control1(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xe1, 0x10, 0x1c, 0x17, 0x08, 0x1d }; @@ -129,7 +129,7 @@ static void s6e8ax0_etc_mipi_control1(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_etc_mipi_control2(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xe2, 0xed, 0x07, 0xc3, 0x13, 0x0d, 0x03 }; @@ -141,7 +141,7 @@ static void s6e8ax0_etc_mipi_control2(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_etc_power_control(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x19, 0x33, 0x02 }; @@ -159,7 +159,7 @@ static void s6e8ax0_etc_mipi_control3(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_etc_mipi_control4(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xe4, 0x00, 0x00, 0x14, 0x80, 0x00, 0x00, 0x00 }; @@ -170,7 +170,7 @@ static void s6e8ax0_etc_mipi_control4(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_elvss_set(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xb1, 0x04, 0x00 }; @@ -198,7 +198,7 @@ static void s6e8ax0_sleep_out(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_apply_level1_key(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xf0, 0x5a, 0x5a }; @@ -209,7 +209,7 @@ static void s6e8ax0_apply_level1_key(struct mipi_dsim_device *dsim_dev) static void s6e8ax0_apply_mtp_key(struct mipi_dsim_device *dsim_dev) { struct mipi_dsim_master_ops *ops = dsim_dev->master_ops; - const unsigned char data_to_send[] = { + static const unsigned char data_to_send[] = { 0xf1, 0x5a, 0x5a }; diff --git a/examples/standalone/mem_to_mem_idma2intr.c b/examples/standalone/mem_to_mem_idma2intr.c index e466c90..215dc22 100644 --- a/examples/standalone/mem_to_mem_idma2intr.c +++ b/examples/standalone/mem_to_mem_idma2intr.c @@ -309,7 +309,8 @@ int idma_init (void) memaddr = dpalloc (sizeof (pram_idma_t), 64); - *(volatile ushort *) &immap->im_dprambase[PROFF_IDMA2_BASE] = memaddr; + *(volatile u16 *)&immap->im_dprambase16 + [PROFF_IDMA2_BASE / sizeof(u16)] = memaddr; piptr = (volatile pram_idma_t *) ((uint) (immap) + memaddr); piptr->pi_resv1 = 0; /* manual says: clear it */ diff --git a/fs/yaffs2/yaffs_mtdif.c b/fs/yaffs2/yaffs_mtdif.c index db49052..6fcba04 100644 --- a/fs/yaffs2/yaffs_mtdif.c +++ b/fs/yaffs2/yaffs_mtdif.c @@ -70,22 +70,22 @@ int nandmtd_WriteChunkToNAND(struct yaffs_dev *dev, int chunkInNAND, u8 spareAsBytes[8]; /* OOB */ if (data && !spare) - retval = mtd->write(mtd, addr, dev->data_bytes_per_chunk, + retval = mtd_write(mtd, addr, dev->data_bytes_per_chunk, &dummy, data); else if (spare) { if (dev->param.use_nand_ecc) { translate_spare2oob(spare, spareAsBytes); - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = 8; /* temp hack */ } else { - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooblen = YAFFS_BYTES_PER_SPARE; } ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen; ops.datbuf = (u8 *)data; ops.ooboffs = 0; ops.oobbuf = spareAsBytes; - retval = mtd->write_oob(mtd, addr, &ops); + retval = mtd_write_oob(mtd, addr, &ops); } if (retval == 0) @@ -106,21 +106,21 @@ int nandmtd_ReadChunkFromNAND(struct yaffs_dev *dev, int chunkInNAND, u8 *data, u8 spareAsBytes[8]; /* OOB */ if (data && !spare) - retval = mtd->read(mtd, addr, dev->data_bytes_per_chunk, + retval = mtd_read(mtd, addr, dev->data_bytes_per_chunk, &dummy, data); else if (spare) { if (dev->param.use_nand_ecc) { - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = 8; /* temp hack */ } else { - ops.mode = MTD_OOB_RAW; + ops.mode = MTD_OPS_RAW; ops.ooblen = YAFFS_BYTES_PER_SPARE; } ops.len = data ? dev->data_bytes_per_chunk : ops.ooblen; ops.datbuf = data; ops.ooboffs = 0; ops.oobbuf = spareAsBytes; - retval = mtd->read_oob(mtd, addr, &ops); + retval = mtd_read_oob(mtd, addr, &ops); if (dev->param.use_nand_ecc) translate_oob2spare(spare, spareAsBytes); } @@ -151,7 +151,7 @@ int nandmtd_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber) /* Todo finish off the ei if required */ - retval = mtd->erase(mtd, &ei); + retval = mtd_erase(mtd, &ei); if (retval == 0) return YAFFS_OK; diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c index 8135bcc..234cb70 100644 --- a/fs/yaffs2/yaffs_mtdif2.c +++ b/fs/yaffs2/yaffs_mtdif2.c @@ -77,13 +77,13 @@ int nandmtd2_write_chunk_tags(struct yaffs_dev *dev, int nand_chunk, yaffs_pack_tags2(&pt, tags, !dev->param.no_tags_ecc); } - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = (dev->param.inband_tags) ? 0 : packed_tags_size; ops.len = dev->param.total_bytes_per_chunk; ops.ooboffs = 0; ops.datbuf = (u8 *) data; ops.oobbuf = (dev->param.inband_tags) ? NULL : packed_tags_ptr; - retval = mtd->write_oob(mtd, addr, &ops); + retval = mtd_write_oob(mtd, addr, &ops); if (retval == 0) return YAFFS_OK; @@ -121,16 +121,16 @@ int nandmtd2_read_chunk_tags(struct yaffs_dev *dev, int nand_chunk, } if (dev->param.inband_tags || (data && !tags)) - retval = mtd->read(mtd, addr, dev->param.total_bytes_per_chunk, + retval = mtd_read(mtd, addr, dev->param.total_bytes_per_chunk, &dummy, data); else if (tags) { - ops.mode = MTD_OOB_AUTO; + ops.mode = MTD_OPS_AUTO_OOB; ops.ooblen = packed_tags_size; ops.len = data ? dev->data_bytes_per_chunk : packed_tags_size; ops.ooboffs = 0; ops.datbuf = data; ops.oobbuf = local_spare; - retval = mtd->read_oob(mtd, addr, &ops); + retval = mtd_read_oob(mtd, addr, &ops); } if (dev->param.inband_tags) { @@ -179,7 +179,7 @@ int nandmtd2_MarkNANDBlockBad(struct yaffs_dev *dev, int blockNo) "nandmtd2_MarkNANDBlockBad %d", blockNo); retval = - mtd->block_markbad(mtd, + mtd_block_markbad(mtd, blockNo * dev->param.chunks_per_block * dev->data_bytes_per_chunk); @@ -198,7 +198,7 @@ int nandmtd2_QueryNANDBlock(struct yaffs_dev *dev, int blockNo, yaffs_trace(YAFFS_TRACE_MTD, "nandmtd2_QueryNANDBlock %d", blockNo); retval = - mtd->block_isbad(mtd, + mtd_block_isbad(mtd, blockNo * dev->param.chunks_per_block * dev->data_bytes_per_chunk); diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h index 5416f46..8cfc3fa 100644 --- a/include/asm-generic/global_data.h +++ b/include/asm-generic/global_data.h @@ -68,9 +68,6 @@ typedef struct global_data { unsigned long env_addr; /* Address of Environment struct */ unsigned long env_valid; /* Checksum of Environment valid? */ - /* TODO: is this the same as relocaddr, or something else? */ - unsigned long dest_addr; /* Post-relocation address of U-Boot */ - unsigned long dest_addr_sp; unsigned long ram_top; /* Top address of RAM used by U-Boot */ unsigned long relocaddr; /* Start address of U-Boot in RAM */ @@ -85,6 +82,9 @@ typedef struct global_data { unsigned long fdt_size; /* Space reserved for relocated FDT */ void **jt; /* jump table */ char env_buf[32]; /* buffer for getenv() before reloc. */ +#ifdef CONFIG_TRACE + void *trace_buff; /* The trace buffer */ +#endif struct arch_global_data arch; /* architecture-specific data */ } gd_t; #endif diff --git a/include/bootstage.h b/include/bootstage.h index 6dc0422..ef07a87 100644 --- a/include/bootstage.h +++ b/include/bootstage.h @@ -37,6 +37,24 @@ enum bootstage_flags { BOOTSTAGEF_ALLOC = 1 << 1, /* Allocate an id */ }; +/* bootstate sub-IDs used for kernel and ramdisk ranges */ +enum { + BOOTSTAGE_SUB_FORMAT, + BOOTSTAGE_SUB_FORMAT_OK, + BOOTSTAGE_SUB_NO_UNIT_NAME, + BOOTSTAGE_SUB_UNIT_NAME, + BOOTSTAGE_SUB_SUBNODE, + + BOOTSTAGE_SUB_CHECK, + BOOTSTAGE_SUB_HASH = 5, + BOOTSTAGE_SUB_CHECK_ARCH = 5, + BOOTSTAGE_SUB_CHECK_ALL, + BOOTSTAGE_SUB_GET_DATA, + BOOTSTAGE_SUB_CHECK_ALL_OK = 7, + BOOTSTAGE_SUB_GET_DATA_OK, + BOOTSTAGE_SUB_LOAD, +}; + /* * A list of boot stages that we know about. Each of these indicates the * state that we are at, and the action that we are about to perform. For @@ -137,43 +155,24 @@ enum bootstage_id { BOOTSTAGE_ID_NET_DONE_ERR, BOOTSTAGE_ID_NET_DONE, + BOOTSTAGE_ID_FIT_FDT_START = 90, /* * Boot stages related to loading a FIT image. Some of these are a * bit wonky. */ - BOOTSTAGE_ID_FIT_FORMAT = 100, - BOOTSTAGE_ID_FIT_NO_UNIT_NAME, - BOOTSTAGE_ID_FIT_UNIT_NAME, - BOOTSTAGE_ID_FIT_CONFIG, - BOOTSTAGE_ID_FIT_CHECK_SUBIMAGE, - BOOTSTAGE_ID_FIT_CHECK_HASH = 104, - - BOOTSTAGE_ID_FIT_CHECK_ARCH, - BOOTSTAGE_ID_FIT_CHECK_KERNEL, - BOOTSTAGE_ID_FIT_CHECKED, - - BOOTSTAGE_ID_FIT_KERNEL_INFO_ERR = 107, - BOOTSTAGE_ID_FIT_KERNEL_INFO, + BOOTSTAGE_ID_FIT_KERNEL_START = 100, + + BOOTSTAGE_ID_FIT_CONFIG = 110, BOOTSTAGE_ID_FIT_TYPE, + BOOTSTAGE_ID_FIT_KERNEL_INFO, BOOTSTAGE_ID_FIT_COMPRESSION, BOOTSTAGE_ID_FIT_OS, BOOTSTAGE_ID_FIT_LOADADDR, BOOTSTAGE_ID_OVERWRITTEN, - BOOTSTAGE_ID_FIT_RD_FORMAT = 120, - BOOTSTAGE_ID_FIT_RD_FORMAT_OK, - BOOTSTAGE_ID_FIT_RD_NO_UNIT_NAME, - BOOTSTAGE_ID_FIT_RD_UNIT_NAME, - BOOTSTAGE_ID_FIT_RD_SUBNODE, - - BOOTSTAGE_ID_FIT_RD_CHECK, - BOOTSTAGE_ID_FIT_RD_HASH = 125, - BOOTSTAGE_ID_FIT_RD_CHECK_ALL, - BOOTSTAGE_ID_FIT_RD_GET_DATA, - BOOTSTAGE_ID_FIT_RD_CHECK_ALL_OK = 127, - BOOTSTAGE_ID_FIT_RD_GET_DATA_OK, - BOOTSTAGE_ID_FIT_RD_LOAD, + /* Next 10 IDs used by BOOTSTAGE_SUB_... */ + BOOTSTAGE_ID_FIT_RD_START = 120, /* Ramdisk stages */ BOOTSTAGE_ID_IDE_FIT_READ = 140, BOOTSTAGE_ID_IDE_FIT_READ_OK, diff --git a/include/command.h b/include/command.h index 65692fd..9e05ddc 100644 --- a/include/command.h +++ b/include/command.h @@ -110,6 +110,8 @@ static inline int bootm_maybe_autostart(cmd_tbl_t *cmdtp, const char *cmd) } #endif +extern int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); + extern int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc, char *const argv[]); diff --git a/include/common.h b/include/common.h index e682bd8..e5220cf 100644 --- a/include/common.h +++ b/include/common.h @@ -310,9 +310,6 @@ int readline_into_buffer(const char *const prompt, char *buffer, int parse_line (char *, char *[]); void init_cmd_timeout(void); void reset_cmd_timeout(void); -#ifdef CONFIG_MENU -int abortboot(int bootdelay); -#endif extern char console_buffer[]; /* arch/$(ARCH)/lib/board.c */ @@ -753,6 +750,10 @@ void irq_install_handler(int, interrupt_handler_t *, void *); void irq_free_handler (int); void reset_timer (void); ulong get_timer (ulong base); + +/* Return value of monotonic microsecond timer */ +unsigned long timer_get_us(void); + void enable_interrupts (void); int disable_interrupts (void); diff --git a/include/commproc.h b/include/commproc.h index 7ca28c8..6959905 100644 --- a/include/commproc.h +++ b/include/commproc.h @@ -127,6 +127,7 @@ typedef struct cpm_buf_desc { */ #define PROFF_SCC1 ((uint)0x0000) #define PROFF_IIC ((uint)0x0080) +#define PROFF_REVNUM ((uint)0x00b0) #define PROFF_SCC2 ((uint)0x0100) #define PROFF_SPI ((uint)0x0180) #define PROFF_SCC3 ((uint)0x0200) diff --git a/include/configs/A3000.h b/include/configs/A3000.h index b85244a..d506a55 100644 --- a/include/configs/A3000.h +++ b/include/configs/A3000.h @@ -96,6 +96,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP #define CONFIG_PCI_SCAN_SHOW /* print pci devices @ startup */ diff --git a/include/configs/APC405.h b/include/configs/APC405.h index 9a65cbc..1e39229 100644 --- a/include/configs/APC405.h +++ b/include/configs/APC405.h @@ -218,6 +218,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/AR405.h b/include/configs/AR405.h index 9994476..7337f53 100644 --- a/include/configs/AR405.h +++ b/include/configs/AR405.h @@ -157,6 +157,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/ASH405.h b/include/configs/ASH405.h index 09aa763..35c3773 100644 --- a/include/configs/ASH405.h +++ b/include/configs/ASH405.h @@ -172,6 +172,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_HOST /* select pci host function */ #undef CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/B4860QDS.h b/include/configs/B4860QDS.h index 1c9d08e..a823f9f 100644 --- a/include/configs/B4860QDS.h +++ b/include/configs/B4860QDS.h @@ -34,6 +34,15 @@ #define CONFIG_RESET_VECTOR_ADDRESS 0xfffffffc #endif +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE +/* Set 1M boot space */ +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR (CONFIG_SYS_TEXT_BASE & 0xfff00000) +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS \ + (0x300000000ull | CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR) +#define CONFIG_RESET_VECTOR_ADDRESS 0xfffffffc +#define CONFIG_SYS_NO_FLASH +#endif + /* High Level Configuration Options */ #define CONFIG_BOOKE #define CONFIG_E500 /* BOOKE e500 family */ @@ -63,6 +72,7 @@ #define CONFIG_SYS_SRIO #define CONFIG_SRIO1 /* SRIO port 1 */ #define CONFIG_SRIO2 /* SRIO port 2 */ +#define CONFIG_SRIO_PCIE_BOOT_MASTER #endif #define CONFIG_FSL_LAW /* Use common FSL init code */ @@ -84,14 +94,15 @@ #define CONFIG_ENV_OVERWRITE #ifdef CONFIG_SYS_NO_FLASH +#if !defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) && !defined(CONFIG_RAMBOOT_PBL) #define CONFIG_ENV_IS_NOWHERE +#endif #else #define CONFIG_FLASH_CFI_DRIVER #define CONFIG_SYS_FLASH_CFI #define CONFIG_SYS_FLASH_USE_BUFFER_WRITE #endif -#ifndef CONFIG_SYS_NO_FLASH #if defined(CONFIG_SPIFLASH) #define CONFIG_SYS_EXTRA_ENV_RELOC #define CONFIG_ENV_IS_IN_SPI_FLASH @@ -113,16 +124,18 @@ #define CONFIG_ENV_IS_IN_NAND #define CONFIG_ENV_SIZE CONFIG_SYS_NAND_BLOCK_SIZE #define CONFIG_ENV_OFFSET (5 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +#define CONFIG_ENV_IS_IN_REMOTE +#define CONFIG_ENV_ADDR 0xffe20000 +#define CONFIG_ENV_SIZE 0x2000 +#elif defined(CONFIG_ENV_IS_NOWHERE) +#define CONFIG_ENV_SIZE 0x2000 #else #define CONFIG_ENV_IS_IN_FLASH #define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE) #define CONFIG_ENV_SIZE 0x2000 #define CONFIG_ENV_SECT_SIZE 0x20000 /* 128K (one sector) */ #endif -#else /* CONFIG_SYS_NO_FLASH */ -#define CONFIG_ENV_SIZE 0x2000 -#define CONFIG_ENV_SECT_SIZE 0x20000 /* 128K (one sector) */ -#endif #ifndef __ASSEMBLY__ unsigned long get_board_sys_clk(void); @@ -223,7 +236,7 @@ unsigned long get_board_ddr_clk(void); /* NOR Flash Timing Params */ #define CONFIG_SYS_NOR_CSOR CSOR_NOR_ADM_SHIFT(4) #define CONFIG_SYS_NOR_FTIM0 (FTIM0_NOR_TACSE(0x01) | \ - FTIM0_NOR_TEADC(0x01) | \ + FTIM0_NOR_TEADC(0x04) | \ FTIM0_NOR_TEAHC(0x20)) #define CONFIG_SYS_NOR_FTIM1 (FTIM1_NOR_TACO(0x35) | \ FTIM1_NOR_TRAD_NOR(0x1A) |\ @@ -600,6 +613,16 @@ unsigned long get_board_ddr_clk(void); #elif defined(CONFIG_NAND) #define CONFIG_SYS_QE_FMAN_FW_IN_NAND #define CONFIG_SYS_QE_FMAN_FW_ADDR (6 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +/* + * Slave has no ucode locally, it can fetch this from remote. When implementing + * in two corenet boards, slave's ucode could be stored in master's memory + * space, the address can be mapped from slave TLB->slave LAW-> + * slave SRIO or PCIE outbound window->master inbound window-> + * master LAW->the ucode address in master's memory space. + */ +#define CONFIG_SYS_QE_FMAN_FW_IN_REMOTE +#define CONFIG_SYS_QE_FMAN_FW_ADDR 0xFFE00000 #else #define CONFIG_SYS_QE_FMAN_FW_IN_NOR #define CONFIG_SYS_QE_FMAN_FW_ADDR 0xEFF40000 @@ -620,6 +643,7 @@ unsigned long get_board_ddr_clk(void); #endif #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_NET_MULTI #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_E1000 diff --git a/include/configs/BSC9131RDB.h b/include/configs/BSC9131RDB.h index fd076e0..b5911c6 100644 --- a/include/configs/BSC9131RDB.h +++ b/include/configs/BSC9131RDB.h @@ -40,10 +40,34 @@ #define CONFIG_RESET_VECTOR_ADDRESS 0x1107fffc #endif -#ifndef CONFIG_SYS_MONITOR_BASE -#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */ +#ifdef CONFIG_NAND +#define CONFIG_SPL +#define CONFIG_SPL_INIT_MINIMAL +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_NAND_SUPPORT +#define CONFIG_SPL_NAND_MINIMAL +#define CONFIG_SPL_FLUSH_IMAGE +#define CONFIG_SPL_TARGET "u-boot-with-spl.bin" + +#define CONFIG_SYS_TEXT_BASE 0x00201000 +#define CONFIG_SPL_TEXT_BASE 0xFFFFE000 +#define CONFIG_SPL_MAX_SIZE 8192 +#define CONFIG_SPL_RELOC_TEXT_BASE 0x00100000 +#define CONFIG_SPL_RELOC_STACK 0x00100000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE ((512 << 10) - 0x2000) +#define CONFIG_SYS_NAND_U_BOOT_DST (0x00200000 - CONFIG_SPL_MAX_SIZE) +#define CONFIG_SYS_NAND_U_BOOT_START 0x00200000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0 +#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds" #endif +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MONITOR_BASE CONFIG_SPL_TEXT_BASE +#else +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */ +#endif + + /* High Level Configuration Options */ #define CONFIG_BOOKE /* BOOKE */ #define CONFIG_E500 /* BOOKE e500 family */ @@ -55,7 +79,11 @@ #define CONFIG_ENV_OVERWRITE #define CONFIG_DDR_CLK_FREQ 66666666 /* DDRCLK on 9131 RDB */ +#if defined(CONFIG_SYS_CLK_100) +#define CONFIG_SYS_CLK_FREQ 100000000 /* SYSCLK for 9131 RDB */ +#else #define CONFIG_SYS_CLK_FREQ 66666666 /* SYSCLK for 9131 RDB */ +#endif #define CONFIG_HWCONFIG /* @@ -125,16 +153,21 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_IMMR CONFIG_SYS_CCSRBAR /* PQII uses */ /* CONFIG_SYS_IMMR */ +/* DSP CCSRBAR */ +#define CONFIG_SYS_FSL_DSP_CCSRBAR CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT +#define CONFIG_SYS_FSL_DSP_CCSRBAR_PHYS CONFIG_SYS_FSL_DSP_CCSRBAR_DEFAULT /* * Memory map * * 0x0000_0000 0x3FFF_FFFF DDR 1G cacheable * 0x8800_0000 0x8810_0000 IFC internal SRAM 1M + * 0xB000_0000 0xB0FF_FFFF DSP core M2 memory 16M * 0xC100_0000 0xC13F_FFFF MAPLE-2F 4M * 0xC1F0_0000 0xC1F3_FFFF PA L2 SRAM Region 0 256K * 0xC1F8_0000 0xC1F9_FFFF PA L2 SRAM Region 1 128K * 0xFED0_0000 0xFED0_3FFF SEC Secured RAM 16K + * 0xFF60_0000 0xFF6F_FFFF DSP CCSR 1M * 0xFF70_0000 0xFF7F_FFFF PA CCSR 1M * 0xFF80_0000 0xFFFF_FFFF Boot Page & NAND flash buffer 8M * @@ -214,6 +247,9 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_NS16550_SERIAL #define CONFIG_SYS_NS16550_REG_SIZE 1 #define CONFIG_SYS_NS16550_CLK get_bus_freq(0) +#ifdef CONFIG_SPL_BUILD +#define CONFIG_NS16550_MIN_FUNCTIONS +#endif #define CONFIG_SYS_CONSOLE_IS_IN_ENV /* determine from environment */ @@ -295,7 +331,6 @@ extern unsigned long get_sdram_size(void); /* * Environment */ -#if defined(CONFIG_SYS_RAMBOOT) #if defined(CONFIG_RAMBOOT_SPIFLASH) #define CONFIG_ENV_IS_IN_SPI_FLASH #define CONFIG_ENV_SPI_BUS 0 @@ -305,15 +340,16 @@ extern unsigned long get_sdram_size(void); #define CONFIG_ENV_OFFSET 0x100000 /* 1MB */ #define CONFIG_ENV_SECT_SIZE 0x10000 #define CONFIG_ENV_SIZE 0x2000 -#else -#define CONFIG_ENV_IS_NOWHERE /* Store ENV in memory only */ -#define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - 0x1000) -#define CONFIG_ENV_SIZE 0x2000 -#endif -#else -#define CONFIG_ENV_IS_NOWHERE 1 /* Store ENV in memory only */ +#elif defined(CONFIG_NAND) +#define CONFIG_ENV_IS_IN_NAND +#define CONFIG_SYS_EXTRA_ENV_RELOC +#define CONFIG_ENV_SIZE CONFIG_SYS_NAND_BLOCK_SIZE +#define CONFIG_ENV_OFFSET ((512 * 1024) + CONFIG_SYS_NAND_BLOCK_SIZE) +#define CONFIG_ENV_RANGE (3 * CONFIG_ENV_SIZE) +#elif defined(CONFIG_SYS_RAMBOOT) +#define CONFIG_ENV_IS_NOWHERE /* Store ENV in memory only */ #define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - 0x1000) -#define CONFIG_ENV_SIZE 0x400 +#define CONFIG_ENV_SIZE 0x2000 #endif #define CONFIG_LOADS_ECHO /* echo on for serial download */ @@ -406,7 +442,9 @@ extern unsigned long get_sdram_size(void); "fdtfile=bsc9131rdb.dtb\0" \ "bdev=sda1\0" \ "hwconfig=usb1:dr_mode=host,phy_type=ulpi\0" \ - "othbootargs=ramdisk_size=600000 \0" \ + "bootm_size=0x37000000\0" \ + "othbootargs=ramdisk_size=600000 " \ + "default_hugepagesz=256m hugepagesz=256m hugepages=1\0" \ "usbext2boot=setenv bootargs root=/dev/ram rw " \ "console=$consoledev,$baudrate $othbootargs; " \ "usb start;" \ diff --git a/include/configs/BSC9132QDS.h b/include/configs/BSC9132QDS.h index 431c686..3aa4443 100644 --- a/include/configs/BSC9132QDS.h +++ b/include/configs/BSC9132QDS.h @@ -49,6 +49,27 @@ #define CONFIG_RESET_VECTOR_ADDRESS 0x1107fffc #endif +#ifdef CONFIG_NAND +#define CONFIG_SPL +#define CONFIG_SPL_INIT_MINIMAL +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_NAND_SUPPORT +#define CONFIG_SPL_NAND_MINIMAL +#define CONFIG_SPL_FLUSH_IMAGE +#define CONFIG_SPL_TARGET "u-boot-with-spl.bin" + +#define CONFIG_SYS_TEXT_BASE 0x00201000 +#define CONFIG_SPL_TEXT_BASE 0xFFFFE000 +#define CONFIG_SPL_MAX_SIZE 8192 +#define CONFIG_SPL_RELOC_TEXT_BASE 0x00100000 +#define CONFIG_SPL_RELOC_STACK 0x00100000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE ((512 << 10) - 0x2000) +#define CONFIG_SYS_NAND_U_BOOT_DST (0x00200000 - CONFIG_SPL_MAX_SIZE) +#define CONFIG_SYS_NAND_U_BOOT_START 0x00200000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0 +#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds" +#endif + #ifndef CONFIG_SYS_TEXT_BASE #define CONFIG_SYS_TEXT_BASE 0x8ff80000 #endif @@ -57,11 +78,12 @@ #define CONFIG_RESET_VECTOR_ADDRESS 0x8ffffffc #endif -#ifndef CONFIG_SYS_MONITOR_BASE -#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MONITOR_BASE CONFIG_SPL_TEXT_BASE +#else +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */ #endif - /* High Level Configuration Options */ #define CONFIG_BOOKE /* BOOKE */ #define CONFIG_E500 /* BOOKE e500 family */ @@ -73,6 +95,7 @@ #if defined(CONFIG_PCI) #define CONFIG_PCIE1 /* PCIE controler 1 (slot 1) */ #define CONFIG_FSL_PCI_INIT /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT /* enable 64-bit PCI resources */ @@ -221,6 +244,10 @@ combinations. this should be removed later * IFC Definitions */ /* NOR Flash on IFC */ + +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_NO_FLASH +#endif #define CONFIG_SYS_FLASH_BASE 0x88000000 #define CONFIG_SYS_MAX_FLASH_SECT 1024 /* Max number of sector: 32M */ @@ -301,7 +328,9 @@ combinations. this should be removed later #define CONFIG_SYS_NAND_BLOCK_SIZE (128 * 1024) +#ifndef CONFIG_SPL_BUILD #define CONFIG_FSL_QIXIS +#endif #ifdef CONFIG_FSL_QIXIS #define CONFIG_SYS_FPGA_BASE 0xffb00000 #define CONFIG_SYS_I2C_FPGA_ADDR 0x66 @@ -337,6 +366,22 @@ combinations. this should be removed later #endif /* Set up IFC registers for boot location NOR/NAND */ +#if defined(CONFIG_NAND) +#define CONFIG_SYS_CSPR0 CONFIG_SYS_NAND_CSPR +#define CONFIG_SYS_AMASK0 CONFIG_SYS_NAND_AMASK +#define CONFIG_SYS_CSOR0 CONFIG_SYS_NAND_CSOR +#define CONFIG_SYS_CS0_FTIM0 CONFIG_SYS_NAND_FTIM0 +#define CONFIG_SYS_CS0_FTIM1 CONFIG_SYS_NAND_FTIM1 +#define CONFIG_SYS_CS0_FTIM2 CONFIG_SYS_NAND_FTIM2 +#define CONFIG_SYS_CS0_FTIM3 CONFIG_SYS_NAND_FTIM3 +#define CONFIG_SYS_CSPR1 CONFIG_SYS_NOR_CSPR +#define CONFIG_SYS_AMASK1 CONFIG_SYS_NOR_AMASK +#define CONFIG_SYS_CSOR1 CONFIG_SYS_NOR_CSOR +#define CONFIG_SYS_CS1_FTIM0 CONFIG_SYS_NOR_FTIM0 +#define CONFIG_SYS_CS1_FTIM1 CONFIG_SYS_NOR_FTIM1 +#define CONFIG_SYS_CS1_FTIM2 CONFIG_SYS_NOR_FTIM2 +#define CONFIG_SYS_CS1_FTIM3 CONFIG_SYS_NOR_FTIM3 +#else #define CONFIG_SYS_CSPR0 CONFIG_SYS_NOR_CSPR #define CONFIG_SYS_AMASK0 CONFIG_SYS_NOR_AMASK #define CONFIG_SYS_CSOR0 CONFIG_SYS_NOR_CSOR @@ -351,6 +396,7 @@ combinations. this should be removed later #define CONFIG_SYS_CS1_FTIM1 CONFIG_SYS_NAND_FTIM1 #define CONFIG_SYS_CS1_FTIM2 CONFIG_SYS_NAND_FTIM2 #define CONFIG_SYS_CS1_FTIM3 CONFIG_SYS_NAND_FTIM3 +#endif #define CONFIG_BOARD_EARLY_INIT_F /* Call board_pre_init */ #define CONFIG_BOARD_EARLY_INIT_R @@ -373,6 +419,9 @@ combinations. this should be removed later #define CONFIG_SYS_NS16550_SERIAL #define CONFIG_SYS_NS16550_REG_SIZE 1 #define CONFIG_SYS_NS16550_CLK get_bus_freq(0) +#ifdef CONFIG_SPL_BUILD +#define CONFIG_NS16550_MIN_FUNCTIONS +#endif #define CONFIG_SERIAL_MULTI 1 /* Enable both serial ports */ #define CONFIG_SYS_CONSOLE_IS_IN_ENV /* determine from environment */ @@ -502,7 +551,6 @@ combinations. this should be removed later /* * Environment */ -#if defined(CONFIG_SYS_RAMBOOT) #if defined(CONFIG_RAMBOOT_SDCARD) #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SYS_MMC_ENV_DEV 0 @@ -516,11 +564,15 @@ combinations. this should be removed later #define CONFIG_ENV_OFFSET 0x100000 /* 1MB */ #define CONFIG_ENV_SECT_SIZE 0x10000 #define CONFIG_ENV_SIZE 0x2000 -#else +#elif defined(CONFIG_NAND) +#define CONFIG_ENV_IS_IN_NAND +#define CONFIG_ENV_SIZE CONFIG_SYS_NAND_BLOCK_SIZE +#define CONFIG_ENV_OFFSET ((512 * 1024) + CONFIG_SYS_NAND_BLOCK_SIZE) +#define CONFIG_ENV_RANGE (3 * CONFIG_ENV_SIZE) +#elif defined(CONFIG_SYS_RAMBOOT) #define CONFIG_ENV_IS_NOWHERE /* Store ENV in memory only */ #define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - 0x1000) #define CONFIG_ENV_SIZE 0x2000 -#endif #else #define CONFIG_ENV_IS_IN_FLASH #if CONFIG_SYS_MONITOR_BASE > 0xfff80000 diff --git a/include/configs/CATcenter.h b/include/configs/CATcenter.h index 1e3a564..7017f8c 100644 --- a/include/configs/CATcenter.h +++ b/include/configs/CATcenter.h @@ -327,6 +327,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #undef CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/CPC45.h b/include/configs/CPC45.h index e102c36..c7904a1 100644 --- a/include/configs/CPC45.h +++ b/include/configs/CPC45.h @@ -450,6 +450,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_SYS_EARLY_PCI_INIT #undef CONFIG_PCI_PNP #undef CONFIG_PCI_SCAN_SHOW diff --git a/include/configs/CPCI2DP.h b/include/configs/CPCI2DP.h index 11cf58b..bbd93ac 100644 --- a/include/configs/CPCI2DP.h +++ b/include/configs/CPCI2DP.h @@ -146,6 +146,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/CPCI405.h b/include/configs/CPCI405.h index e3e5ebc..36476e0 100644 --- a/include/configs/CPCI405.h +++ b/include/configs/CPCI405.h @@ -155,6 +155,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/CPCI4052.h b/include/configs/CPCI4052.h index c4fff48..4c12c85 100644 --- a/include/configs/CPCI4052.h +++ b/include/configs/CPCI4052.h @@ -176,6 +176,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/CPCI405AB.h b/include/configs/CPCI405AB.h index 9122cbd..96b6c0a 100644 --- a/include/configs/CPCI405AB.h +++ b/include/configs/CPCI405AB.h @@ -173,6 +173,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/CPCI405DT.h b/include/configs/CPCI405DT.h index f778af7..c4cc5fd 100644 --- a/include/configs/CPCI405DT.h +++ b/include/configs/CPCI405DT.h @@ -177,6 +177,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/CPCIISER4.h b/include/configs/CPCIISER4.h index 35daed0..78c66c7 100644 --- a/include/configs/CPCIISER4.h +++ b/include/configs/CPCIISER4.h @@ -140,6 +140,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/CPU87.h b/include/configs/CPU87.h index aa5ce29..3e9c21c 100644 --- a/include/configs/CPU87.h +++ b/include/configs/CPU87.h @@ -192,6 +192,7 @@ #define CONFIG_CMD_I2C #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_CMD_PCI #endif diff --git a/include/configs/CU824.h b/include/configs/CU824.h index a3ceed1..6632196 100644 --- a/include/configs/CU824.h +++ b/include/configs/CU824.h @@ -288,6 +288,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP diff --git a/include/configs/DU440.h b/include/configs/DU440.h index bbe2713..4970ea6 100644 --- a/include/configs/DU440.h +++ b/include/configs/DU440.h @@ -357,6 +357,7 @@ int du440_phy_addr(int devnum); * PCI stuff */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do (not) pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE*/ diff --git a/include/configs/ELPPC.h b/include/configs/ELPPC.h index 220372c..d10f4c1 100644 --- a/include/configs/ELPPC.h +++ b/include/configs/ELPPC.h @@ -242,6 +242,7 @@ * PCI stuff */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* pci plug-and-play */ #define CONFIG_PCI_HOST PCI_HOST_AUTO #undef CONFIG_PCI_SCAN_SHOW diff --git a/include/configs/G2000.h b/include/configs/G2000.h index 08ba840..b6769ae 100644 --- a/include/configs/G2000.h +++ b/include/configs/G2000.h @@ -216,6 +216,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_HOST /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/HH405.h b/include/configs/HH405.h index 444413d..d65377f 100644 --- a/include/configs/HH405.h +++ b/include/configs/HH405.h @@ -231,6 +231,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_HOST /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/HIDDEN_DRAGON.h b/include/configs/HIDDEN_DRAGON.h index a62ef63..dbad1fd 100644 --- a/include/configs/HIDDEN_DRAGON.h +++ b/include/configs/HIDDEN_DRAGON.h @@ -93,6 +93,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP diff --git a/include/configs/HWW1U1A.h b/include/configs/HWW1U1A.h index 791763a..2b72a33 100644 --- a/include/configs/HWW1U1A.h +++ b/include/configs/HWW1U1A.h @@ -188,6 +188,7 @@ #define CONFIG_PCI_PNP /* Scan PCI busses */ #define CONFIG_CMD_PCI /* Enable the "pci" command */ #define CONFIG_FSL_PCI_INIT /* Common FreeScale PCI initialization */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET /* We have PCI-E reset errata */ #define CONFIG_SYS_PCI_64BIT /* PCI resources are 64-bit */ #define CONFIG_PCI_SCAN_SHOW /* Display PCI scan during boot */ diff --git a/include/configs/JSE.h b/include/configs/JSE.h index e0a0d8e..6ce789d 100644 --- a/include/configs/JSE.h +++ b/include/configs/JSE.h @@ -226,6 +226,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #undef CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/KAREF.h b/include/configs/KAREF.h index 546e28b..8d5e8ff 100644 --- a/include/configs/KAREF.h +++ b/include/configs/KAREF.h @@ -268,6 +268,7 @@ *----------------------------------------------------------------------*/ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices */ #define CONFIG_SYS_PCI_TARGBASE (CONFIG_SYS_PCI_MEMBASE) diff --git a/include/configs/MERGERBOX.h b/include/configs/MERGERBOX.h index 30fb6c2..2496639 100644 --- a/include/configs/MERGERBOX.h +++ b/include/configs/MERGERBOX.h @@ -36,6 +36,7 @@ #define CONFIG_SYS_TEXT_BASE 0xFC000000 #define CONFIG_PCI 1 +#define CONFIG_PCI_INDIRECT_BRIDGE 1 #define CONFIG_MASK_AER_AO #define CONFIG_DISPLAY_AER_FULL diff --git a/include/configs/METROBOX.h b/include/configs/METROBOX.h index 286f869..d1ef559 100644 --- a/include/configs/METROBOX.h +++ b/include/configs/METROBOX.h @@ -333,6 +333,7 @@ *----------------------------------------------------------------------*/ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices */ #define CONFIG_SYS_PCI_TARGBASE (CONFIG_SYS_PCI_MEMBASE) diff --git a/include/configs/MIP405.h b/include/configs/MIP405.h index 979495a..0d023ab 100644 --- a/include/configs/MIP405.h +++ b/include/configs/MIP405.h @@ -206,6 +206,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* configure as pci-host */ #define CONFIG_PCI_PNP /* pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/MOUSSE.h b/include/configs/MOUSSE.h index 1391ce5..b3dbd6f 100644 --- a/include/configs/MOUSSE.h +++ b/include/configs/MOUSSE.h @@ -330,6 +330,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP diff --git a/include/configs/MPC8260ADS.h b/include/configs/MPC8260ADS.h index c4c41c7..c312b77 100644 --- a/include/configs/MPC8260ADS.h +++ b/include/configs/MPC8260ADS.h @@ -195,6 +195,7 @@ /*PCI*/ #if CONFIG_ADSTYPE >= CONFIG_SYS_PQ2FADS #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP #define CONFIG_PCI_BOOTDELAY 0 #define CONFIG_PCI_SCAN_SHOW diff --git a/include/configs/MPC8266ADS.h b/include/configs/MPC8266ADS.h index 0474140..c5aa586 100644 --- a/include/configs/MPC8266ADS.h +++ b/include/configs/MPC8266ADS.h @@ -137,6 +137,7 @@ /* PCI */ #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP #define CONFIG_PCI_BOOTDELAY 0 #undef CONFIG_PCI_SCAN_SHOW diff --git a/include/configs/MPC8308RDB.h b/include/configs/MPC8308RDB.h index 95a1885..f10555c 100644 --- a/include/configs/MPC8308RDB.h +++ b/include/configs/MPC8308RDB.h @@ -402,6 +402,7 @@ #define CONFIG_SYS_SCCR_PCIEXP1CM 1 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCIE #define CONFIG_PCI_PNP /* do pci plug-and-play */ diff --git a/include/configs/MPC8313ERDB.h b/include/configs/MPC8313ERDB.h index c28dfe0..1d753e7 100644 --- a/include/configs/MPC8313ERDB.h +++ b/include/configs/MPC8313ERDB.h @@ -76,6 +76,7 @@ #endif #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_FSL_ELBC 1 #define CONFIG_MISC_INIT_R diff --git a/include/configs/MPC8315ERDB.h b/include/configs/MPC8315ERDB.h index 767b976..ee806c4 100644 --- a/include/configs/MPC8315ERDB.h +++ b/include/configs/MPC8315ERDB.h @@ -405,6 +405,7 @@ #define CONFIG_SYS_PCIE2_IO_SIZE 0x00800000 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCIE #define CONFIG_PCI_PNP /* do pci plug-and-play */ diff --git a/include/configs/MPC8323ERDB.h b/include/configs/MPC8323ERDB.h index 8d5ed0f..ac4c253 100644 --- a/include/configs/MPC8323ERDB.h +++ b/include/configs/MPC8323ERDB.h @@ -264,6 +264,7 @@ #define CONFIG_SYS_PCI1_IO_SIZE 0x04000000 /* 64M */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_SKIP_HOST_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ diff --git a/include/configs/MPC832XEMDS.h b/include/configs/MPC832XEMDS.h index f592d3a..7c31f47 100644 --- a/include/configs/MPC832XEMDS.h +++ b/include/configs/MPC832XEMDS.h @@ -360,6 +360,7 @@ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_83XX_PCI_STREAMING diff --git a/include/configs/MPC8349EMDS.h b/include/configs/MPC8349EMDS.h index e5529c7..212089c 100644 --- a/include/configs/MPC8349EMDS.h +++ b/include/configs/MPC8349EMDS.h @@ -666,6 +666,7 @@ /* PCI @ 0x80000000 */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_IBAT1L (CONFIG_SYS_PCI1_MEM_BASE \ | BATL_PP_RW \ | BATL_MEMCOHERENCE) diff --git a/include/configs/MPC8349ITX.h b/include/configs/MPC8349ITX.h index 2c3f1f6..1130b59 100644 --- a/include/configs/MPC8349ITX.h +++ b/include/configs/MPC8349ITX.h @@ -393,6 +393,7 @@ boards, we say we have two, but don't display a message if we find only one. */ * PCI */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_MPC83XX_PCI2 diff --git a/include/configs/MPC8360EMDS.h b/include/configs/MPC8360EMDS.h index a1fbd5e..a71ac2b 100644 --- a/include/configs/MPC8360EMDS.h +++ b/include/configs/MPC8360EMDS.h @@ -458,6 +458,7 @@ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_83XX_PCI_STREAMING diff --git a/include/configs/MPC8360ERDK.h b/include/configs/MPC8360ERDK.h index fc00952..fcca542 100644 --- a/include/configs/MPC8360ERDK.h +++ b/include/configs/MPC8360ERDK.h @@ -314,6 +314,7 @@ #define CONFIG_SYS_PCI1_IO_SIZE 0x100000 /* 1M */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ diff --git a/include/configs/MPC837XEMDS.h b/include/configs/MPC837XEMDS.h index 8243661..480468f 100644 --- a/include/configs/MPC837XEMDS.h +++ b/include/configs/MPC837XEMDS.h @@ -395,6 +395,7 @@ #define CONFIG_SYS_PCIE2_IO_SIZE 0x00800000 #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #ifndef __ASSEMBLY__ extern int board_pci_host_broken(void); #endif diff --git a/include/configs/MPC837XERDB.h b/include/configs/MPC837XERDB.h index 9ad7e3a..d5c9d05 100644 --- a/include/configs/MPC837XERDB.h +++ b/include/configs/MPC837XERDB.h @@ -421,6 +421,7 @@ #define CONFIG_SYS_PCIE2_IO_SIZE 0x00800000 #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ #undef CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ diff --git a/include/configs/MPC8536DS.h b/include/configs/MPC8536DS.h index bcd77b6..cc2b7c3 100644 --- a/include/configs/MPC8536DS.h +++ b/include/configs/MPC8536DS.h @@ -84,6 +84,7 @@ #define CONFIG_PCIE2 1 /* PCIE controler 2 (slot 2) */ #define CONFIG_PCIE3 1 /* PCIE controler 3 (ULI bridge) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ diff --git a/include/configs/MPC8540ADS.h b/include/configs/MPC8540ADS.h index a0fe15e..6cb00ee 100644 --- a/include/configs/MPC8540ADS.h +++ b/include/configs/MPC8540ADS.h @@ -52,6 +52,7 @@ #endif #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE diff --git a/include/configs/MPC8541CDS.h b/include/configs/MPC8541CDS.h index a6bea15..d0e6ca6 100644 --- a/include/configs/MPC8541CDS.h +++ b/include/configs/MPC8541CDS.h @@ -40,6 +40,7 @@ #define CONFIG_SYS_TEXT_BASE 0xfff80000 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE diff --git a/include/configs/MPC8544DS.h b/include/configs/MPC8544DS.h index d5f3c5f..09d0835 100644 --- a/include/configs/MPC8544DS.h +++ b/include/configs/MPC8544DS.h @@ -44,6 +44,7 @@ #define CONFIG_PCIE2 1 /* PCIE controler 2 (slot 2) */ #define CONFIG_PCIE3 1 /* PCIE controler 3 (ULI bridge) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ diff --git a/include/configs/MPC8548CDS.h b/include/configs/MPC8548CDS.h index 0e22cc7..d070f6a 100644 --- a/include/configs/MPC8548CDS.h +++ b/include/configs/MPC8548CDS.h @@ -52,6 +52,7 @@ #define CONFIG_PCIE1 /* PCIE controler 1 (slot 1) */ #undef CONFIG_PCI2 #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ diff --git a/include/configs/MPC8555CDS.h b/include/configs/MPC8555CDS.h index 266cb54..483556b 100644 --- a/include/configs/MPC8555CDS.h +++ b/include/configs/MPC8555CDS.h @@ -40,6 +40,7 @@ #define CONFIG_SYS_TEXT_BASE 0xfff80000 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #define CONFIG_ENV_OVERWRITE diff --git a/include/configs/MPC8560ADS.h b/include/configs/MPC8560ADS.h index 35d15f4..525e88f 100644 --- a/include/configs/MPC8560ADS.h +++ b/include/configs/MPC8560ADS.h @@ -49,6 +49,7 @@ #define CONFIG_SYS_TEXT_BASE 0xfff80000 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_TSEC_ENET /* tsec ethernet support */ #undef CONFIG_ETHER_ON_FCC /* cpm FCC ethernet support */ diff --git a/include/configs/MPC8568MDS.h b/include/configs/MPC8568MDS.h index 5d69fb6..f1bfdcb 100644 --- a/include/configs/MPC8568MDS.h +++ b/include/configs/MPC8568MDS.h @@ -42,6 +42,7 @@ #define CONFIG_PCI1 1 /* PCI controller */ #define CONFIG_PCIE1 1 /* PCIE controller */ #define CONFIG_FSL_PCI_INIT 1 /* use common fsl pci init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_TSEC_ENET /* tsec ethernet support */ diff --git a/include/configs/MPC8569MDS.h b/include/configs/MPC8569MDS.h index acd3276..c54755f 100644 --- a/include/configs/MPC8569MDS.h +++ b/include/configs/MPC8569MDS.h @@ -41,6 +41,7 @@ #define CONFIG_PCI 1 /* Disable PCI/PCIE */ #define CONFIG_PCIE1 1 /* PCIE controller */ #define CONFIG_FSL_PCI_INIT 1 /* use common fsl pci init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_QE /* Enable QE */ diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h index d233365..25303c4 100644 --- a/include/configs/MPC8572DS.h +++ b/include/configs/MPC8572DS.h @@ -71,6 +71,7 @@ #define CONFIG_PCIE2 1 /* PCIE controler 2 (slot 2) */ #define CONFIG_PCIE3 1 /* PCIE controler 3 (ULI bridge) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ diff --git a/include/configs/MPC8610HPCD.h b/include/configs/MPC8610HPCD.h index c619827..f791e76 100644 --- a/include/configs/MPC8610HPCD.h +++ b/include/configs/MPC8610HPCD.h @@ -51,6 +51,7 @@ #define CONFIG_PCIE1 1 /* PCIe 1 connected to ULI bridge */ #define CONFIG_PCIE2 1 /* PCIe 2 connected to slot */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_FSL_LAW 1 /* Use common FSL init code */ diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h index 2643097..4a3ca01 100644 --- a/include/configs/MPC8641HPCN.h +++ b/include/configs/MPC8641HPCN.h @@ -510,6 +510,7 @@ extern unsigned long get_board_sys_clk(unsigned long dummy); * BAT2 Rapidio Memory */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_DBAT2L (BAT_PHYS_ADDR(CONFIG_SYS_PCIE1_MEM_PHYS_LOW, \ CONFIG_SYS_PCIE1_MEM_PHYS_HIGH) \ | BATL_PP_RW | BATL_CACHEINHIBIT \ diff --git a/include/configs/MUSENKI.h b/include/configs/MUSENKI.h index 84a167d..8b04151 100644 --- a/include/configs/MUSENKI.h +++ b/include/configs/MUSENKI.h @@ -87,6 +87,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP diff --git a/include/configs/MVBLM7.h b/include/configs/MVBLM7.h index a9c00ac..afd4c03 100644 --- a/include/configs/MVBLM7.h +++ b/include/configs/MVBLM7.h @@ -42,6 +42,7 @@ #define CONFIG_SYS_IMMR 0xE0000000 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_SKIP_HOST_BRIDGE #define CONFIG_HARD_I2C #define CONFIG_TSEC_ENET diff --git a/include/configs/MVBLUE.h b/include/configs/MVBLUE.h index 52d1729..21f286e 100644 --- a/include/configs/MVBLUE.h +++ b/include/configs/MVBLUE.h @@ -154,6 +154,7 @@ */ #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP #define CONFIG_PCI_SCAN_SHOW diff --git a/include/configs/OCRTC.h b/include/configs/OCRTC.h index 47110af..4a93417 100644 --- a/include/configs/OCRTC.h +++ b/include/configs/OCRTC.h @@ -136,6 +136,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/ORSG.h b/include/configs/ORSG.h index 9f754c2..cd1f425 100644 --- a/include/configs/ORSG.h +++ b/include/configs/ORSG.h @@ -134,6 +134,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_ADAPTER /* select pci adapter */ #undef CONFIG_PCI_PNP /* no pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/P1010RDB.h b/include/configs/P1010RDB.h index 437ee6e..7b28a27 100644 --- a/include/configs/P1010RDB.h +++ b/include/configs/P1010RDB.h @@ -31,10 +31,10 @@ #define CONFIG_PHYS_64BIT #endif -#ifdef CONFIG_P1010RDB #define CONFIG_P1010 +#define CONFIG_E500 /* BOOKE e500 family */ +#include <asm/config_mpc85xx.h> #define CONFIG_NAND_FSL_IFC -#endif #ifdef CONFIG_SDCARD #define CONFIG_RAMBOOT_SDCARD @@ -48,15 +48,25 @@ #define CONFIG_RESET_VECTOR_ADDRESS 0x1107fffc #endif -#ifdef CONFIG_NAND /* NAND Boot */ -#define CONFIG_RAMBOOT_NAND -#define CONFIG_NAND_U_BOOT -#define CONFIG_SYS_TEXT_BASE_SPL 0xff800000 -#ifdef CONFIG_NAND_SPL -#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE_SPL -#else -#define CONFIG_SYS_TEXT_BASE 0x11001000 -#endif /* CONFIG_NAND_SPL */ +#ifdef CONFIG_NAND +#define CONFIG_SPL +#define CONFIG_SPL_INIT_MINIMAL +#define CONFIG_SPL_SERIAL_SUPPORT +#define CONFIG_SPL_NAND_SUPPORT +#define CONFIG_SPL_NAND_MINIMAL +#define CONFIG_SPL_FLUSH_IMAGE +#define CONFIG_SPL_TARGET "u-boot-with-spl.bin" + +#define CONFIG_SYS_TEXT_BASE 0x00201000 +#define CONFIG_SPL_TEXT_BASE 0xFFFFE000 +#define CONFIG_SPL_MAX_SIZE 8192 +#define CONFIG_SPL_RELOC_TEXT_BASE 0x00100000 +#define CONFIG_SPL_RELOC_STACK 0x00100000 +#define CONFIG_SYS_NAND_U_BOOT_SIZE ((512 << 10) - 0x2000) +#define CONFIG_SYS_NAND_U_BOOT_DST (0x00200000 - CONFIG_SPL_MAX_SIZE) +#define CONFIG_SYS_NAND_U_BOOT_START 0x00200000 +#define CONFIG_SYS_NAND_U_BOOT_OFFS 0 +#define CONFIG_SYS_LDSCRIPT "arch/powerpc/cpu/mpc85xx/u-boot-nand.lds" #endif @@ -74,8 +84,10 @@ #define CONFIG_RESET_VECTOR_ADDRESS 0xeffffffc #endif -#ifndef CONFIG_SYS_MONITOR_BASE -#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_MONITOR_BASE CONFIG_SPL_TEXT_BASE +#else +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */ #endif /* High Level Configuration Options */ @@ -90,6 +102,7 @@ #define CONFIG_PCIE1 /* PCIE controler 1 (slot 1) */ #define CONFIG_PCIE2 /* PCIE controler 2 (slot 2) */ #define CONFIG_FSL_PCI_INIT /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT /* enable 64-bit PCI resources */ @@ -241,7 +254,7 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_CCSRBAR_PHYS_LOW CONFIG_SYS_CCSRBAR /* Don't relocate CCSRBAR while in NAND_SPL */ -#ifdef CONFIG_NAND_SPL +#ifdef CONFIG_SPL_BUILD #define CONFIG_SYS_CCSR_DO_NOT_RELOCATE #endif @@ -267,6 +280,10 @@ extern unsigned long get_sdram_size(void); * IFC Definitions */ /* NOR Flash on IFC */ +#ifdef CONFIG_SPL_BUILD +#define CONFIG_SYS_NO_FLASH +#endif + #define CONFIG_SYS_FLASH_BASE 0xee000000 #define CONFIG_SYS_MAX_FLASH_SECT 256 /* 32M */ @@ -352,7 +369,7 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_NAND_DDR_LAW 11 /* Set up IFC registers for boot location NOR/NAND */ -#if defined(CONFIG_NAND_U_BOOT) || defined(CONFIG_NAND_SECBOOT) +#if defined(CONFIG_NAND) || defined(CONFIG_NAND_SECBOOT) #define CONFIG_SYS_CSPR0 CONFIG_SYS_NAND_CSPR #define CONFIG_SYS_AMASK0 CONFIG_SYS_NAND_AMASK #define CONFIG_SYS_CSOR0 CONFIG_SYS_NAND_CSOR @@ -384,15 +401,6 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_CS1_FTIM3 CONFIG_SYS_NAND_FTIM3 #endif -/* NAND boot: 8K NAND loader config */ -#define CONFIG_SYS_NAND_SPL_SIZE 0x2000 -#define CONFIG_SYS_NAND_U_BOOT_SIZE (512 << 10) -#define CONFIG_SYS_NAND_U_BOOT_DST (0x11000000 - CONFIG_SYS_NAND_SPL_SIZE) -#define CONFIG_SYS_NAND_U_BOOT_START 0x11000000 -#define CONFIG_SYS_NAND_U_BOOT_OFFS (0) -#define CONFIG_SYS_NAND_U_BOOT_RELOC 0x10000 -#define CONFIG_SYS_NAND_U_BOOT_RELOC_SP (CONFIG_SYS_NAND_U_BOOT_RELOC + 0x10000) - /* CPLD on IFC */ #define CONFIG_SYS_CPLD_BASE 0xffb00000 @@ -420,14 +428,20 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_CS3_FTIM3 0x0 #endif /* CONFIG_SDCARD */ -#if defined(CONFIG_RAMBOOT_SDCARD) || defined(CONFIG_RAMBOOT_SPIFLASH) || \ - defined(CONFIG_RAMBOOT_NAND) +#if defined(CONFIG_RAMBOOT_SDCARD) || defined(CONFIG_RAMBOOT_SPIFLASH) #define CONFIG_SYS_RAMBOOT #define CONFIG_SYS_EXTRA_ENV_RELOC #else #undef CONFIG_SYS_RAMBOOT #endif +#ifdef CONFIG_SYS_FSL_ERRATUM_IFC_A003399 +#if !defined(CONFIG_SPL) && !defined(CONFIG_SYS_RAMBOOT)\ + && !defined(CONFIG_SECURE_BOOT) +#define CONFIG_A003399_NOR_WORKAROUND +#endif +#endif + #define CONFIG_BOARD_EARLY_INIT_F /* Call board_pre_init */ #define CONFIG_BOARD_EARLY_INIT_R @@ -449,7 +463,7 @@ extern unsigned long get_sdram_size(void); #define CONFIG_SYS_NS16550_SERIAL #define CONFIG_SYS_NS16550_REG_SIZE 1 #define CONFIG_SYS_NS16550_CLK get_bus_freq(0) -#ifdef CONFIG_NAND_SPL +#ifdef CONFIG_SPL_BUILD #define CONFIG_NS16550_MIN_FUNCTIONS #endif @@ -504,7 +518,7 @@ extern unsigned long get_sdram_size(void); * SPI interface will not be available in case of NAND boot SPI CS0 will be * used for SLIC */ -#if !defined(CONFIG_NAND_U_BOOT) || !defined(CONFIG_NAND_SECBOOT) +#if !defined(CONFIG_NAND) || !defined(CONFIG_NAND_SECBOOT) /* eSPI - Enhanced SPI */ #define CONFIG_FSL_ESPI #define CONFIG_SPI_FLASH @@ -599,7 +613,6 @@ extern unsigned long get_sdram_size(void); /* * Environment */ -#if defined(CONFIG_SYS_RAMBOOT) #if defined(CONFIG_RAMBOOT_SDCARD) #define CONFIG_ENV_IS_IN_MMC #define CONFIG_FSL_FIXED_MMC_LOCATION @@ -614,16 +627,15 @@ extern unsigned long get_sdram_size(void); #define CONFIG_ENV_OFFSET 0x100000 /* 1MB */ #define CONFIG_ENV_SECT_SIZE 0x10000 #define CONFIG_ENV_SIZE 0x2000 -#elif defined(CONFIG_NAND_U_BOOT) +#elif defined(CONFIG_NAND) #define CONFIG_ENV_IS_IN_NAND #define CONFIG_ENV_SIZE CONFIG_SYS_NAND_BLOCK_SIZE -#define CONFIG_ENV_OFFSET CONFIG_SYS_NAND_U_BOOT_SIZE +#define CONFIG_ENV_OFFSET ((512 * 1024) + CONFIG_SYS_NAND_BLOCK_SIZE) #define CONFIG_ENV_RANGE (3 * CONFIG_ENV_SIZE) -#else +#elif defined(CONFIG_SYS_RAMBOOT) #define CONFIG_ENV_IS_NOWHERE /* Store ENV in memory only */ #define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - 0x1000) #define CONFIG_ENV_SIZE 0x2000 -#endif #else #define CONFIG_ENV_IS_IN_FLASH #if CONFIG_SYS_MONITOR_BASE > 0xfff80000 diff --git a/include/configs/P1022DS.h b/include/configs/P1022DS.h index 8b13b10..9c27182 100644 --- a/include/configs/P1022DS.h +++ b/include/configs/P1022DS.h @@ -316,7 +316,6 @@ #define CONFIG_SYS_HUSH_PARSER /* Video */ -#define CONFIG_FSL_DIU_FB #ifdef CONFIG_FSL_DIU_FB #define CONFIG_SYS_DIU_ADDR (CONFIG_SYS_CCSRBAR + 0x10000) @@ -336,7 +335,6 @@ #endif #ifndef CONFIG_FSL_DIU_FB -#define CONFIG_ATI #endif #ifdef CONFIG_ATI @@ -458,6 +456,7 @@ #define CONFIG_SYS_PCIE3_IO_SIZE 0x00010000 /* 64k */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_E1000 /* Define e1000 pci Ethernet card */ diff --git a/include/configs/P1023RDB.h b/include/configs/P1023RDB.h new file mode 100644 index 0000000..fee8040 --- /dev/null +++ b/include/configs/P1023RDB.h @@ -0,0 +1,401 @@ +/* + * Copyright 2013 Freescale Semiconductor, Inc. + * + * Authors: Roy Zang <tie-fei.zang@freescale.com> + * Chunhe Lan <Chunhe.Lan@freescale.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __CONFIG_H +#define __CONFIG_H + +#ifndef CONFIG_SYS_TEXT_BASE +#define CONFIG_SYS_TEXT_BASE 0xeff80000 +#endif + +#ifndef CONFIG_SYS_MONITOR_BASE +#define CONFIG_SYS_MONITOR_BASE CONFIG_SYS_TEXT_BASE /* start of monitor */ +#endif + +#ifndef CONFIG_RESET_VECTOR_ADDRESS +#define CONFIG_RESET_VECTOR_ADDRESS 0xeffffffc +#endif + +/* High Level Configuration Options */ +#define CONFIG_BOOKE /* BOOKE */ +#define CONFIG_E500 /* BOOKE e500 family */ +#define CONFIG_MPC85xx +#define CONFIG_P1023 +#define CONFIG_MP /* support multiple processors */ + +#define CONFIG_FSL_ELBC /* Has Enhanced localbus controller */ +#define CONFIG_PCI /* Enable PCI/PCIE */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ +#define CONFIG_PCIE1 /* PCIE controler 1 (slot 1) */ +#define CONFIG_PCIE2 /* PCIE controler 2 (slot 2) */ +#define CONFIG_PCIE3 /* PCIE controler 3 (slot 3) */ +#define CONFIG_FSL_PCI_INIT /* Use common FSL init code */ +#define CONFIG_FSL_PCIE_RESET /* need PCIe reset errata */ +#define CONFIG_SYS_PCI_64BIT /* enable 64-bit PCI resources */ +#define CONFIG_FSL_LAW /* Use common FSL init code */ + +#ifndef __ASSEMBLY__ +extern unsigned long get_clock_freq(void); +#endif + +#define CONFIG_SYS_CLK_FREQ 66666666 +#define CONFIG_DDR_CLK_FREQ CONFIG_SYS_CLK_FREQ + +/* + * These can be toggled for performance analysis, otherwise use default. + */ +#define CONFIG_L2_CACHE /* toggle L2 cache */ +#define CONFIG_BTB /* toggle branch predition */ +#define CONFIG_HWCONFIG + +#define CONFIG_ENABLE_36BIT_PHYS + +#define CONFIG_SYS_MEMTEST_START 0x01000000 /* memtest works on */ +#define CONFIG_SYS_MEMTEST_END 0x02000000 + +#define CONFIG_PANIC_HANG /* do not reset board on panic */ + +/* Implement conversion of addresses in the LBC */ +#define CONFIG_SYS_LBC_LBCR 0x00000000 +#define CONFIG_SYS_LBC_LCRR LCRR_CLKDIV_8 + +/* DDR Setup */ +#define CONFIG_VERY_BIG_RAM +#define CONFIG_SYS_DDR_SDRAM_BASE 0x00000000 +#define CONFIG_SYS_SDRAM_BASE CONFIG_SYS_DDR_SDRAM_BASE + +#define CONFIG_DIMM_SLOTS_PER_CTLR 1 +#define CONFIG_CHIP_SELECTS_PER_CTRL 1 + +#define CONFIG_DDR_SPD +#define CONFIG_FSL_DDR3 +#define CONFIG_FSL_DDR_INTERACTIVE +#define CONFIG_SYS_SDRAM_SIZE 512u /* DDR is 512M */ +#define CONFIG_SYS_SPD_BUS_NUM 0 +#define SPD_EEPROM_ADDRESS 0x50 +#define CONFIG_SYS_DDR_RAW_TIMING + +/* + * Memory map + * + * 0x0000_0000 0x1fff_ffff DDR 512M cacheable + * 0x8000_0000 0xbfff_ffff PCI Express Mem 1G non-cacheable + * 0xc000_0000 0xdfff_ffff PCI 512M non-cacheable + * 0xe100_0000 0xe3ff_ffff PCI IO range 4M non-cacheable + * 0xff00_0000 0xff3f_ffff DPAA_QBMAN 4M cacheable + * 0xff60_0000 0xff7f_ffff CCSR 2M non-cacheable + * 0xffd0_0000 0xffd0_3fff L1 for stack 16K cacheable TLB0 + * + * Localbus non-cacheable + * + * 0xec00_0000 0xefff_ffff NOR flash 64M non-cacheable + * 0xffa0_0000 0xffaf_ffff NAND 1M non-cacheable + */ + +/* + * Local Bus Definitions + */ +#define CONFIG_SYS_FLASH_BASE 0xec000000 /* start of FLASH 64M */ +#define CONFIG_SYS_FLASH_BASE_PHYS CONFIG_SYS_FLASH_BASE + +#define CONFIG_FLASH_BR_PRELIM (BR_PHYS_ADDR(CONFIG_SYS_FLASH_BASE_PHYS) \ + | BR_PS_16 | BR_V) +#define CONFIG_FLASH_OR_PRELIM 0xfc000ff7 + +#define CONFIG_FLASH_CFI_DRIVER +#define CONFIG_SYS_FLASH_CFI +#define CONFIG_SYS_FLASH_EMPTY_INFO +#define CONFIG_SYS_MAX_FLASH_BANKS 1 /* number of banks */ +#define CONFIG_SYS_MAX_FLASH_SECT 512 /* sectors per device */ +#define CONFIG_SYS_FLASH_ERASE_TOUT 60000 /* Flash Erase Timeout (ms) */ +#define CONFIG_SYS_FLASH_WRITE_TOUT 500 /* Flash Write Timeout (ms) */ + +#define CONFIG_BOARD_EARLY_INIT_F /* call board_early_init_f function */ +#define CONFIG_BOARD_EARLY_INIT_R /* call board_early_init_r function */ + +#define CONFIG_SYS_INIT_RAM_LOCK +#define CONFIG_SYS_INIT_RAM_ADDR 0xffd00000 /* Initial L1 address */ +#define CONFIG_SYS_INIT_RAM_SIZE 0x00004000/* Size of used area in RAM */ +#define CONFIG_SYS_GBL_DATA_OFFSET (CONFIG_SYS_INIT_RAM_SIZE - \ + GENERATED_GBL_DATA_SIZE) +#define CONFIG_SYS_INIT_SP_OFFSET CONFIG_SYS_GBL_DATA_OFFSET + +#define CONFIG_SYS_MONITOR_LEN (512 * 1024) /* Reserve 512 kB for Mon */ +#define CONFIG_SYS_MALLOC_LEN (6 * 1024 * 1024) /* Reserved for malloc */ + +#define CONFIG_SYS_NAND_BASE 0xffa00000 +#define CONFIG_SYS_NAND_BASE_PHYS CONFIG_SYS_NAND_BASE + +#define CONFIG_SYS_NAND_BASE_LIST { CONFIG_SYS_NAND_BASE } +#define CONFIG_SYS_MAX_NAND_DEVICE 1 +#define CONFIG_MTD_NAND_VERIFY_WRITE +#define CONFIG_CMD_NAND +#define CONFIG_NAND_FSL_ELBC +#define CONFIG_SYS_NAND_BLOCK_SIZE (128 * 1024) + +/* NAND flash config */ +#define CONFIG_SYS_NAND_BR_PRELIM (BR_PHYS_ADDR(CONFIG_SYS_NAND_BASE_PHYS) \ + | (2<<BR_DECC_SHIFT) /* Use HW ECC */ \ + | BR_PS_8 /* Port Size = 8bit */ \ + | BR_MS_FCM /* MSEL = FCM */ \ + | BR_V) /* valid */ +#define CONFIG_SYS_NAND_OR_PRELIM (OR_AM_256KB /* length 256K */ \ + | OR_FCM_PGS \ + | OR_FCM_CSCT \ + | OR_FCM_CST \ + | OR_FCM_CHT \ + | OR_FCM_SCY_1 \ + | OR_FCM_TRLX \ + | OR_FCM_EHTR) + +#define CONFIG_SYS_BR0_PRELIM CONFIG_FLASH_BR_PRELIM /* NOR Base Address */ +#define CONFIG_SYS_OR0_PRELIM CONFIG_FLASH_OR_PRELIM /* NOR Options */ +#define CONFIG_SYS_BR1_PRELIM CONFIG_SYS_NAND_BR_PRELIM +#define CONFIG_SYS_OR1_PRELIM CONFIG_SYS_NAND_OR_PRELIM /* NAND Options */ + +/* Serial Port */ +#define CONFIG_CONS_INDEX 1 +#undef CONFIG_SERIAL_SOFTWARE_FIFO +#define CONFIG_SYS_NS16550 +#define CONFIG_SYS_NS16550_SERIAL +#define CONFIG_SYS_NS16550_REG_SIZE 1 +#define CONFIG_SYS_NS16550_CLK get_bus_freq(0) + +#define CONFIG_SYS_BAUDRATE_TABLE \ + {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200} + +#define CONFIG_SYS_NS16550_COM1 (CONFIG_SYS_CCSRBAR + 0x4500) +#define CONFIG_SYS_NS16550_COM2 (CONFIG_SYS_CCSRBAR + 0x4600) + +/* Use the HUSH parser */ +#define CONFIG_SYS_HUSH_PARSER + +/* + * Pass open firmware flat tree + */ +#define CONFIG_OF_LIBFDT +#define CONFIG_OF_BOARD_SETUP +#define CONFIG_OF_STDOUT_VIA_ALIAS + +/* new uImage format support */ +#define CONFIG_FIT +#define CONFIG_FIT_VERBOSE /* enable fit_format_{error,warning}() */ + +/* I2C */ +#define CONFIG_FSL_I2C /* Use FSL common I2C driver */ +#define CONFIG_HARD_I2C /* I2C with hardware support */ +#define CONFIG_I2C_MULTI_BUS +#define CONFIG_SYS_I2C_SPEED 400000 /* I2C speed and slave address */ +#define CONFIG_SYS_I2C_SLAVE 0x7F +#define CONFIG_SYS_I2C_OFFSET 0x3000 +#define CONFIG_SYS_I2C2_OFFSET 0x3100 + +/* + * I2C2 EEPROM + */ +#define CONFIG_ID_EEPROM +#ifdef CONFIG_ID_EEPROM +#define CONFIG_SYS_I2C_EEPROM_NXID +#endif +#define CONFIG_SYS_I2C_EEPROM_ADDR 0x50 +#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 +#define CONFIG_SYS_EEPROM_BUS_NUM 0 + +#define CONFIG_CMD_I2C + +/* + * General PCI + * Memory space is mapped 1-1, but I/O space must start from 0. + */ + +/* controller 3, Slot 1, tgtid 3, Base address b000 */ +#define CONFIG_SYS_PCIE3_NAME "Slot 3" +#define CONFIG_SYS_PCIE3_MEM_VIRT 0x80000000 +#define CONFIG_SYS_PCIE3_MEM_BUS 0x80000000 +#define CONFIG_SYS_PCIE3_MEM_PHYS 0x80000000 +#define CONFIG_SYS_PCIE3_MEM_SIZE 0x20000000 /* 512M */ +#define CONFIG_SYS_PCIE3_IO_VIRT 0xffc00000 +#define CONFIG_SYS_PCIE3_IO_BUS 0x00000000 +#define CONFIG_SYS_PCIE3_IO_PHYS 0xffc00000 +#define CONFIG_SYS_PCIE3_IO_SIZE 0x00010000 /* 64k */ + +/* controller 2, direct to uli, tgtid 2, Base address 9000 */ +#define CONFIG_SYS_PCIE2_NAME "Slot 2" +#define CONFIG_SYS_PCIE2_MEM_VIRT 0xa0000000 +#define CONFIG_SYS_PCIE2_MEM_BUS 0xa0000000 +#define CONFIG_SYS_PCIE2_MEM_PHYS 0xa0000000 +#define CONFIG_SYS_PCIE2_MEM_SIZE 0x20000000 /* 512M */ +#define CONFIG_SYS_PCIE2_IO_VIRT 0xffc10000 +#define CONFIG_SYS_PCIE2_IO_BUS 0x00000000 +#define CONFIG_SYS_PCIE2_IO_PHYS 0xffc10000 +#define CONFIG_SYS_PCIE2_IO_SIZE 0x00010000 /* 64k */ + +/* controller 1, Slot 2, tgtid 1, Base address a000 */ +#define CONFIG_SYS_PCIE1_NAME "Slot 1" +#define CONFIG_SYS_PCIE1_MEM_VIRT 0xc0000000 +#define CONFIG_SYS_PCIE1_MEM_BUS 0xc0000000 +#define CONFIG_SYS_PCIE1_MEM_PHYS 0xc0000000 +#define CONFIG_SYS_PCIE1_MEM_SIZE 0x20000000 /* 512M */ +#define CONFIG_SYS_PCIE1_IO_VIRT 0xffc20000 +#define CONFIG_SYS_PCIE1_IO_BUS 0x00000000 +#define CONFIG_SYS_PCIE1_IO_PHYS 0xffc20000 +#define CONFIG_SYS_PCIE1_IO_SIZE 0x00010000 /* 64k */ + +#if defined(CONFIG_PCI) +#define CONFIG_E1000 /* Defind e1000 pci Ethernet card */ +#define CONFIG_PCI_PNP /* do pci plug-and-play */ +#define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ +#endif /* CONFIG_PCI */ + +/* + * Environment + */ +#define CONFIG_ENV_OVERWRITE + +#define CONFIG_ENV_IS_IN_FLASH +#if CONFIG_SYS_MONITOR_BASE > 0xfff80000 +#define CONFIG_ENV_ADDR 0xfff80000 +#else +#define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE) +#endif +#define CONFIG_ENV_SIZE 0x2000 +#define CONFIG_ENV_SECT_SIZE 0x20000 /* 128K (one sector) */ + +#define CONFIG_LOADS_ECHO /* echo on for serial download */ +#define CONFIG_SYS_LOADS_BAUD_CHANGE /* allow baudrate change */ + +/* + * Command line configuration. + */ +#include <config_cmd_default.h> + +#define CONFIG_CMD_IRQ +#define CONFIG_CMD_PING +#define CONFIG_CMD_MII +#define CONFIG_CMD_SETEXPR +#define CONFIG_CMD_REGINFO + +#if defined(CONFIG_PCI) +#define CONFIG_CMD_PCI +#define CONFIG_CMD_NET +#endif + +/* + * USB + */ +#define CONFIG_HAS_FSL_DR_USB +#ifdef CONFIG_HAS_FSL_DR_USB +#define CONFIG_USB_EHCI + +#ifdef CONFIG_USB_EHCI +#define CONFIG_CMD_USB +#define CONFIG_EHCI_HCD_INIT_AFTER_RESET +#define CONFIG_USB_EHCI_FSL +#define CONFIG_USB_STORAGE +#define CONFIG_CMD_FAT +#define CONFIG_CMD_EXT2 +#define CONFIG_CMD_FAT +#define CONFIG_DOS_PARTITION +#endif +#endif + +/* + * Miscellaneous configurable options + */ +#define CONFIG_SYS_LONGHELP /* undef to save memory */ +#define CONFIG_CMDLINE_EDITING /* Command-line editing */ +#define CONFIG_SYS_LOAD_ADDR 0x2000000 /* default load address */ +#define CONFIG_SYS_PROMPT "=> " /* Monitor Command Prompt */ +#if defined(CONFIG_CMD_KGDB) +#define CONFIG_SYS_CBSIZE 1024 /* Console I/O Buffer Size */ +#else +#define CONFIG_SYS_CBSIZE 256 /* Console I/O Buffer Size */ +#endif +/* Print Buffer Size */ +#define CONFIG_SYS_PBSIZE (CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT)+16) +#define CONFIG_SYS_MAXARGS 16 /* max number of command args */ +/* Boot Argument Buffer Size */ +#define CONFIG_SYS_BARGSIZE CONFIG_SYS_CBSIZE +#define CONFIG_SYS_HZ 1000 /* decrementer freq: 1ms ticks */ + +/* + * For booting Linux, the board info and command line data + * have to be in the first 64 MB of memory, since this is + * the maximum mapped by the Linux kernel during initialization. + */ +#define CONFIG_SYS_BOOTMAPSZ (64 << 20) /* Initial Memory map for Linux*/ +#define CONFIG_SYS_BOOTM_LEN (64 << 20) /* Increase max gunzip size */ + +/* + * Environment Configuration + */ +#define CONFIG_BOOTFILE "uImage" +#define CONFIG_UBOOTPATH (u-boot.bin) /* U-Boot image on TFTP server */ + +/* default location for tftp and bootm */ +#define CONFIG_LOADADDR 1000000 + +#define CONFIG_BOOTDELAY -1 /* -1 disables auto-boot */ + +#define CONFIG_BAUDRATE 115200 + +/* Qman/Bman */ +#define CONFIG_SYS_DPAA_QBMAN /* support Q/Bman */ +#define CONFIG_SYS_QMAN_MEM_BASE 0xff000000 +#define CONFIG_SYS_QMAN_MEM_PHYS CONFIG_SYS_QMAN_MEM_BASE +#define CONFIG_SYS_QMAN_MEM_SIZE 0x00200000 +#define CONFIG_SYS_BMAN_MEM_BASE 0xff200000 +#define CONFIG_SYS_BMAN_MEM_PHYS CONFIG_SYS_BMAN_MEM_BASE +#define CONFIG_SYS_BMAN_MEM_SIZE 0x00200000 + +/* For FM */ +#define CONFIG_SYS_DPAA_FMAN +#define CONFIG_PHY_GIGE /* Include GbE speed/duplex detection */ + +#ifdef CONFIG_SYS_DPAA_FMAN +#define CONFIG_FMAN_ENET +#define CONFIG_PHY_ATHEROS +#endif + +/* Default address of microcode for the Linux Fman driver */ +/* QE microcode/firmware address */ +#define CONFIG_SYS_QE_FMAN_FW_IN_NOR +#define CONFIG_SYS_QE_FMAN_FW_ADDR 0xeff40000 +#define CONFIG_SYS_QE_FMAN_FW_LENGTH 0x10000 +#define CONFIG_SYS_FDT_PAD (0x3000 + CONFIG_SYS_QE_FMAN_FW_LENGTH) + +#ifdef CONFIG_FMAN_ENET +#define CONFIG_SYS_FM1_DTSEC1_PHY_ADDR 0x1 +#define CONFIG_SYS_FM1_DTSEC2_PHY_ADDR 0x2 + +#define CONFIG_SYS_TBIPA_VALUE 8 +#define CONFIG_MII /* MII PHY management */ +#define CONFIG_ETHPRIME "FM1@DTSEC1" +#endif + +#define CONFIG_EXTRA_ENV_SETTINGS \ + "hwconfig=usb1:dr_mode=host,phy_type=ulpi\0" + +#endif /* __CONFIG_H */ diff --git a/include/configs/P1023RDS.h b/include/configs/P1023RDS.h index 878bd5f..4943d7c 100644 --- a/include/configs/P1023RDS.h +++ b/include/configs/P1023RDS.h @@ -73,6 +73,7 @@ #define CONFIG_PCIE2 /* PCIE controler 2 (slot 2) */ #define CONFIG_PCIE3 /* PCIE controler 3 (slot 3) */ #define CONFIG_FSL_PCI_INIT /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT /* enable 64-bit PCI resources */ #define CONFIG_FSL_LAW /* Use common FSL init code */ diff --git a/include/configs/P1_P2_RDB.h b/include/configs/P1_P2_RDB.h index a57d9dd..6ce4cbe 100644 --- a/include/configs/P1_P2_RDB.h +++ b/include/configs/P1_P2_RDB.h @@ -94,6 +94,7 @@ #define CONFIG_PCIE1 1 /* PCIE controler 1 (slot 1) */ #define CONFIG_PCIE2 1 /* PCIE controler 2 (slot 2) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #endif /* #if defined(CONFIG_PCI) */ diff --git a/include/configs/P2020COME.h b/include/configs/P2020COME.h index c75f86c..05a75d8 100644 --- a/include/configs/P2020COME.h +++ b/include/configs/P2020COME.h @@ -58,6 +58,7 @@ #define CONFIG_PCIE3 1 /* PCIE controller 3 (slot 3) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #endif /* #if defined(CONFIG_PCI) */ diff --git a/include/configs/P2020DS.h b/include/configs/P2020DS.h index a975ee1..229117c 100644 --- a/include/configs/P2020DS.h +++ b/include/configs/P2020DS.h @@ -73,6 +73,7 @@ #define CONFIG_PCIE2 1 /* PCIE controler 2 (slot 2) */ #define CONFIG_PCIE3 1 /* PCIE controler 3 (ULI bridge) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ diff --git a/include/configs/P2041RDB.h b/include/configs/P2041RDB.h index bbc53ce..4ea8717 100644 --- a/include/configs/P2041RDB.h +++ b/include/configs/P2041RDB.h @@ -77,6 +77,7 @@ #define CONFIG_SYS_SRIO #define CONFIG_SRIO1 /* SRIO port 1 */ #define CONFIG_SRIO2 /* SRIO port 2 */ +#define CONFIG_SRIO_PCIE_BOOT_MASTER #define CONFIG_SYS_DPAA_RMAN /* RMan */ #define CONFIG_FSL_LAW /* Use common FSL init code */ @@ -560,6 +561,7 @@ unsigned long get_board_sys_clk(unsigned long dummy); #endif #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_E1000 diff --git a/include/configs/P3041DS.h b/include/configs/P3041DS.h index ce8f9b0..dd2b9c3 100644 --- a/include/configs/P3041DS.h +++ b/include/configs/P3041DS.h @@ -40,7 +40,7 @@ #define CONFIG_SYS_SRIO #define CONFIG_SRIO1 /* SRIO port 1 */ #define CONFIG_SRIO2 /* SRIO port 2 */ - +#define CONFIG_SRIO_PCIE_BOOT_MASTER #define CONFIG_ICS307_REFCLK_HZ 25000000 /* ICS307 ref clk freq */ #include "corenet_ds.h" diff --git a/include/configs/P4080DS.h b/include/configs/P4080DS.h index 53979dd..48acee4 100644 --- a/include/configs/P4080DS.h +++ b/include/configs/P4080DS.h @@ -36,7 +36,7 @@ #define CONFIG_SYS_SRIO #define CONFIG_SRIO1 /* SRIO port 1 */ #define CONFIG_SRIO2 /* SRIO port 2 */ - +#define CONFIG_SRIO_PCIE_BOOT_MASTER #define CONFIG_ICS307_REFCLK_HZ 33333000 /* ICS307 ref clk freq */ #include "corenet_ds.h" diff --git a/include/configs/P5020DS.h b/include/configs/P5020DS.h index 778230d..d1e27c4 100644 --- a/include/configs/P5020DS.h +++ b/include/configs/P5020DS.h @@ -41,7 +41,7 @@ #define CONFIG_SYS_SRIO #define CONFIG_SRIO1 /* SRIO port 1 */ #define CONFIG_SRIO2 /* SRIO port 2 */ - +#define CONFIG_SRIO_PCIE_BOOT_MASTER #define CONFIG_ICS307_REFCLK_HZ 25000000 /* ICS307 ref clk freq */ #include "corenet_ds.h" diff --git a/include/configs/PCI405.h b/include/configs/PCI405.h index 119819e..c3cacef 100644 --- a/include/configs/PCI405.h +++ b/include/configs/PCI405.h @@ -141,6 +141,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_ADAPTER /* select pci host function */ #undef CONFIG_PCI_PNP /* no pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/PIP405.h b/include/configs/PIP405.h index 713ea12..3757af0 100644 --- a/include/configs/PIP405.h +++ b/include/configs/PIP405.h @@ -199,6 +199,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* configure as pci-host */ #define CONFIG_PCI_PNP /* pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/PLU405.h b/include/configs/PLU405.h index 1ee0c48..1745eb3 100644 --- a/include/configs/PLU405.h +++ b/include/configs/PLU405.h @@ -192,6 +192,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/PM826.h b/include/configs/PM826.h index fbcf8e5..faadfe4 100644 --- a/include/configs/PM826.h +++ b/include/configs/PM826.h @@ -176,6 +176,7 @@ #define CONFIG_CMD_SNTP #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_CMD_PCI #endif diff --git a/include/configs/PM828.h b/include/configs/PM828.h index c37aafd..f563fbe 100644 --- a/include/configs/PM828.h +++ b/include/configs/PM828.h @@ -176,6 +176,7 @@ #define CONFIG_CMD_SNTP #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_CMD_PCI #endif diff --git a/include/configs/PMC405.h b/include/configs/PMC405.h index 8235b85..d97acec 100644 --- a/include/configs/PMC405.h +++ b/include/configs/PMC405.h @@ -163,6 +163,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/PMC405DE.h b/include/configs/PMC405DE.h index 992443a..a427551 100644 --- a/include/configs/PMC405DE.h +++ b/include/configs/PMC405DE.h @@ -142,6 +142,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* do (not) pci plug-and-play */ diff --git a/include/configs/PMC440.h b/include/configs/PMC440.h index 3837b8f..40c1827 100644 --- a/include/configs/PMC440.h +++ b/include/configs/PMC440.h @@ -419,6 +419,7 @@ *----------------------------------------------------------------------*/ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do (not) pci plug-and-play */ #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 0 /* to avoid problems with PNP */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ diff --git a/include/configs/PN62.h b/include/configs/PN62.h index 93876b1..e2f96aa 100644 --- a/include/configs/PN62.h +++ b/include/configs/PN62.h @@ -122,6 +122,7 @@ * PCI stuff */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* we need Plug 'n Play */ #if 0 #define CONFIG_PCI_SCAN_SHOW /* show PCI auto-scan at boot */ diff --git a/include/configs/PPChameleonEVB.h b/include/configs/PPChameleonEVB.h index 27a12b3..210bc30 100644 --- a/include/configs/PPChameleonEVB.h +++ b/include/configs/PPChameleonEVB.h @@ -324,6 +324,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #undef CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/SIMPC8313.h b/include/configs/SIMPC8313.h index c0ffb33..318c4c5 100644 --- a/include/configs/SIMPC8313.h +++ b/include/configs/SIMPC8313.h @@ -52,6 +52,7 @@ #endif #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_FSL_ELBC 1 #define CONFIG_MISC_INIT_R diff --git a/include/configs/Sandpoint8240.h b/include/configs/Sandpoint8240.h index f54fcb3..fa456ed 100644 --- a/include/configs/Sandpoint8240.h +++ b/include/configs/Sandpoint8240.h @@ -127,6 +127,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP diff --git a/include/configs/Sandpoint8245.h b/include/configs/Sandpoint8245.h index 84e4891..cdc51a5 100644 --- a/include/configs/Sandpoint8245.h +++ b/include/configs/Sandpoint8245.h @@ -95,6 +95,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP diff --git a/include/configs/TQM8272.h b/include/configs/TQM8272.h index be977f1..3b3f9e6 100644 --- a/include/configs/TQM8272.h +++ b/include/configs/TQM8272.h @@ -443,6 +443,7 @@ #define CONFIG_PCI #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_BOARD_EARLY_INIT_F 1 /* Call board_early_init_f */ #define CONFIG_PCI_PNP #define CONFIG_EEPRO100 diff --git a/include/configs/TQM834x.h b/include/configs/TQM834x.h index 0738423..966a6e3 100644 --- a/include/configs/TQM834x.h +++ b/include/configs/TQM834x.h @@ -442,6 +442,7 @@ /* PCI */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_IBAT3L (CONFIG_SYS_PCI1_MEM_BASE \ | BATL_PP_RW \ | BATL_MEMCOHERENCE) diff --git a/include/configs/VOH405.h b/include/configs/VOH405.h index f1032f0..8f0c4b6 100644 --- a/include/configs/VOH405.h +++ b/include/configs/VOH405.h @@ -181,6 +181,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_HOST /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/W7OLMC.h b/include/configs/W7OLMC.h index 462b155..710812f 100644 --- a/include/configs/W7OLMC.h +++ b/include/configs/W7OLMC.h @@ -154,6 +154,7 @@ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/W7OLMG.h b/include/configs/W7OLMG.h index f28f3e4..f88dfe4 100644 --- a/include/configs/W7OLMG.h +++ b/include/configs/W7OLMG.h @@ -161,6 +161,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_AUTO /* select pci host function */ #define CONFIG_PCI_PNP /* pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/WUH405.h b/include/configs/WUH405.h index 5def36a..0c78aca 100644 --- a/include/configs/WUH405.h +++ b/include/configs/WUH405.h @@ -169,6 +169,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_HOST /* select pci host function */ #undef CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/a3m071.h b/include/configs/a3m071.h index e9af825..8f29229 100644 --- a/include/configs/a3m071.h +++ b/include/configs/a3m071.h @@ -426,6 +426,7 @@ #define CONFIG_SPL_BSS_MAX_SIZE (64 << 10) #define CONFIG_SPL_OS_BOOT +#define CONFIG_SPL_ENV_SUPPORT /* Place patched DT blob (fdt) at this address */ #define CONFIG_SYS_SPL_ARGS_ADDR 0x01800000 diff --git a/include/configs/ac14xx.h b/include/configs/ac14xx.h index 7cb10fb..381bcdd 100644 --- a/include/configs/ac14xx.h +++ b/include/configs/ac14xx.h @@ -72,7 +72,7 @@ #define CONFIG_SYS_MAX_RAM_SIZE 0x20000000 /* - * DDR Controller Configuration XXX TODO + * DDR Controller Configuration * * SYS_CFG: * [31:31] MDDRC Soft Reset: Diabled @@ -265,7 +265,6 @@ /* * CS related parameters - * TODO document these */ /* CS0 Flash */ #define CONFIG_SYS_CS0_CFG 0x00031110 @@ -331,8 +330,6 @@ #endif #define CONFIG_BAUDRATE 115200 /* ... at 115200 bps */ -#define CONFIG_SYS_BAUDRATE_TABLE \ - {300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 115200} #define CONSOLE_FIFO_TX_SIZE FIFOC_PSC3_TX_SIZE #define CONSOLE_FIFO_TX_ADDR FIFOC_PSC3_TX_ADDR @@ -497,30 +494,26 @@ #define CONFIG_ENV_OVERWRITE #define CONFIG_TIMESTAMP -#define CONFIG_HOSTNAME ac14xx -#define CONFIG_BOOTFILE "ac14xx/uImage" -#define CONFIG_ROOTPATH "/opt/eldk/ppc_6xx" - /* default load addr for tftp and bootm */ #define CONFIG_LOADADDR 400000 #define CONFIG_BOOTDELAY 2 /* -1 disables auto-boot */ -/* XXX TODO need to specify the builtin environment */ +/* the builtin environment and standard greeting */ #define CONFIG_PREBOOT "echo;" \ "echo Type \\\"run flash_nfs\\\" to mount root filesystem over NFS;" \ "echo" #define CONFIG_EXTRA_ENV_SETTINGS_DEVEL \ - "muster_nr=00\0" \ + "muster_nr=-00\0" \ "fromram=run ramargs addip addtty; " \ - "tftp ${fdt_addr_r} k6m2/ac14xx.dtb-${muster_nr}; " \ - "tftp ${kernel_addr_r} k6m2/uImage-${muster_nr}; " \ - "tftp ${ramdisk_addr_r} k6m2/uFS-${muster_nr}; " \ + "tftp ${fdt_addr_r} ac14xx/ac14xx.dtb${muster_nr}; " \ + "tftp ${kernel_addr_r} ac14xx/uImage${muster_nr}; " \ + "tftp ${ramdisk_addr_r} ac14xx/uFS${muster_nr}; " \ "bootm ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r}\0" \ "fromnfs=run nfsargs addip addtty; " \ - "tftp ${fdt_addr_r} k6m2/ac14xx.dtb-${muster_nr}; " \ - "tftp ${kernel_addr_r} k6m2/uImage-${muster_nr}; " \ + "tftp ${fdt_addr_r} ac14xx/ac14xx.dtb${muster_nr}; " \ + "tftp ${kernel_addr_r} ac14xx/uImage${muster_nr}; " \ "bootm ${kernel_addr_r} - ${fdt_addr_r}\0" \ "fromflash=run nfsargs addip addtty; " \ "bootm fc020000 - fc000000\0" \ @@ -548,12 +541,11 @@ "u-boot=ac14xx/u-boot.bin\0" \ "bootfile=ac14xx/uImage\0" \ "fdtfile=ac14xx/ac14xx.dtb\0" \ - "rootpath=/opt/eldk/ppc_6xx\n" \ "netdev=eth0\0" \ "consdev=ttyPSC0\0" \ "hostname=ac14xx\0" \ "nfsargs=setenv bootargs root=/dev/nfs rw " \ - "nfsroot=${serverip}:${rootpath}-${muster_nr}\0" \ + "nfsroot=${serverip}:${rootpath}${muster_nr}\0" \ "ramargs=setenv bootargs root=/dev/ram rw\0" \ "addip=setenv bootargs ${bootargs} " \ "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}" \ @@ -583,6 +575,8 @@ #define CONFIG_BOOTCOMMAND "run production" +#define CONFIG_ARP_TIMEOUT 200UL + #define CONFIG_FIT 1 #define CONFIG_OF_LIBFDT 1 #define CONFIG_OF_BOARD_SETUP 1 diff --git a/include/configs/adp-ag102.h b/include/configs/adp-ag102.h index eea44db..a6e1849 100644 --- a/include/configs/adp-ag102.h +++ b/include/configs/adp-ag102.h @@ -143,6 +143,7 @@ */ #define CONFIG_PCI #define CONFIG_FTPCI100 +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_FTPCI100_MEM_BASE 0xa0000000 #define CONFIG_FTPCI100_IO_SIZE FTPCI100_BASE_IO_SIZE(256) /* 256M */ #define CONFIG_FTPCI100_MEM_SIZE FTPCI100_MEM_SIZE(128) /* 128M */ diff --git a/include/configs/alpr.h b/include/configs/alpr.h index 0d53e51..d93d5e2 100644 --- a/include/configs/alpr.h +++ b/include/configs/alpr.h @@ -287,6 +287,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE */ diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h index 7cc3ef2..c5a6d4b 100644 --- a/include/configs/am335x_evm.h +++ b/include/configs/am335x_evm.h @@ -145,7 +145,7 @@ "if test $board_name = A33515BB; then " \ "setenv fdtfile am335x-evm.dtb; fi; " \ "if test $board_name = A335X_SK; then " \ - "setenv fdtfile am335x-evmsk.dtb; fi " \ + "setenv fdtfile am335x-evmsk.dtb; fi; " \ "if test $fdtfile = undefined; then " \ "echo WARNING: Could not determine device tree to use; fi; \0" #endif @@ -307,22 +307,44 @@ #define CONFIG_SPL #define CONFIG_SPL_FRAMEWORK /* - * Place the image at the start of the ROM defined image space and leave - * space for SRAM scratch entries (see arch/arm/include/omap_common.h). + * Place the image at the start of the ROM defined image space. * We limit our size to the ROM-defined downloaded image area, and use the * rest of the space for stack. */ -#define CONFIG_SPL_TEXT_BASE 0x402F0500 +#define CONFIG_SPL_TEXT_BASE 0x402F0400 #define CONFIG_SPL_MAX_SIZE (0x4030C000 - CONFIG_SPL_TEXT_BASE) #define CONFIG_SPL_STACK CONFIG_SYS_INIT_SP_ADDR -#define CONFIG_SPL_BSS_START_ADDR 0x80000000 +#define CONFIG_SPL_OS_BOOT + +#define CONFIG_SPL_BSS_START_ADDR 0x80a00000 #define CONFIG_SPL_BSS_MAX_SIZE 0x80000 /* 512 KB */ #define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 0x300 /* address 0x60000 */ #define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS 0x200 /* 256 KB */ #define CONFIG_SYS_MMC_SD_FAT_BOOT_PARTITION 1 #define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME "u-boot.img" + +#ifdef CONFIG_SPL_OS_BOOT +/* fat */ +#define CONFIG_SPL_FAT_LOAD_KERNEL_NAME "uImage" +#define CONFIG_SPL_FAT_LOAD_ARGS_NAME "args" +#define CONFIG_SYS_SPL_ARGS_ADDR (PHYS_DRAM_1 + 0x100) + +/* raw mmc */ +#define CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR 0x500 /* address 0xa0000 */ +#define CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR 0x8 /* address 0x1000 */ +#define CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS 8 /* 4KB */ + +/* nand */ +#define CONFIG_CMD_SPL_NAND_OFS 0x240000 /* end of u-boot */ +#define CONFIG_SYS_NAND_SPL_KERNEL_OFFS 0x280000 +#define CONFIG_CMD_SPL_WRITE_SIZE 0x1000 + +/* spl export command */ +#define CONFIG_CMD_SPL +#endif + #define CONFIG_SPL_MMC_SUPPORT #define CONFIG_SPL_FAT_SUPPORT #define CONFIG_SPL_I2C_SUPPORT @@ -334,6 +356,7 @@ #define CONFIG_SPL_GPIO_SUPPORT #define CONFIG_SPL_YMODEM_SUPPORT #define CONFIG_SPL_NET_SUPPORT +#define CONFIG_SPL_ENV_SUPPORT #define CONFIG_SPL_NET_VCI_STRING "AM335x U-Boot SPL" #define CONFIG_SPL_ETH_SUPPORT #define CONFIG_SPL_SPI_SUPPORT @@ -380,7 +403,7 @@ * other needs. */ #define CONFIG_SYS_TEXT_BASE 0x80800000 -#define CONFIG_SYS_SPL_MALLOC_START 0x80208000 +#define CONFIG_SYS_SPL_MALLOC_START 0x80a08000 #define CONFIG_SYS_SPL_MALLOC_SIZE 0x100000 /* Since SPL did pll and ddr initialization for us, @@ -476,7 +499,8 @@ #define MTDPARTS_DEFAULT "mtdparts=omap2-nand.0:128k(SPL)," \ "128k(SPL.backup1)," \ "128k(SPL.backup2)," \ - "128k(SPL.backup3),1920k(u-boot)," \ + "128k(SPL.backup3),1792k(u-boot)," \ + "128k(u-boot-spl-os)," \ "128k(u-boot-env),5m(kernel),-(rootfs)" #define CONFIG_NAND_OMAP_GPMC #define GPMC_NAND_ECC_LP_x16_LAYOUT 1 diff --git a/include/configs/aria.h b/include/configs/aria.h index 5318aaf..bd81053 100644 --- a/include/configs/aria.h +++ b/include/configs/aria.h @@ -350,6 +350,7 @@ * PCI */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_PCI_MEM_BASE 0xA0000000 #define CONFIG_SYS_PCI_MEM_PHYS CONFIG_SYS_PCI_MEM_BASE diff --git a/include/configs/at91sam9n12ek.h b/include/configs/at91sam9n12ek.h index 8d2673d..b4b1c31 100644 --- a/include/configs/at91sam9n12ek.h +++ b/include/configs/at91sam9n12ek.h @@ -167,6 +167,10 @@ #define CONFIG_DOS_PARTITION #endif +/* Ethernet */ +#define CONFIG_KS8851_MLL +#define CONFIG_KS8851_MLL_BASEADDR 0x30000000 /* use NCS2 */ + #define CONFIG_SYS_LOAD_ADDR 0x22000000 /* load address */ #define CONFIG_SYS_MEMTEST_START CONFIG_SYS_SDRAM_BASE diff --git a/include/configs/atc.h b/include/configs/atc.h index 538a167..57c4b33 100644 --- a/include/configs/atc.h +++ b/include/configs/atc.h @@ -263,6 +263,7 @@ #endif #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP #define CONFIG_SYS_PCI_MSTR_IO_BUS 0x00000000 /* PCI base */ diff --git a/include/configs/bamboo.h b/include/configs/bamboo.h index 506a558..d36984d 100644 --- a/include/configs/bamboo.h +++ b/include/configs/bamboo.h @@ -293,6 +293,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP /* do (not) pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE*/ diff --git a/include/configs/beaver.h b/include/configs/beaver.h index 165de13..628d5d3 100644 --- a/include/configs/beaver.h +++ b/include/configs/beaver.h @@ -56,7 +56,7 @@ /* Environment in eMMC, at the end of 2nd "boot sector" */ #define CONFIG_ENV_IS_IN_MMC -#define CONFIG_ENV_OFFSET ((1024 * 1024) - CONFIG_ENV_SIZE) +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_SYS_MMC_ENV_PART 2 diff --git a/include/configs/bubinga.h b/include/configs/bubinga.h index da67ae3..35a473a 100644 --- a/include/configs/bubinga.h +++ b/include/configs/bubinga.h @@ -153,6 +153,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/canyonlands.h b/include/configs/canyonlands.h index acb127c..92106d7 100644 --- a/include/configs/canyonlands.h +++ b/include/configs/canyonlands.h @@ -496,6 +496,7 @@ *----------------------------------------------------------------------*/ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/configs/cardhu.h b/include/configs/cardhu.h index fd46083..142d20b 100644 --- a/include/configs/cardhu.h +++ b/include/configs/cardhu.h @@ -55,7 +55,7 @@ /* Environment in eMMC, at the end of 2nd "boot sector" */ #define CONFIG_ENV_IS_IN_MMC -#define CONFIG_ENV_OFFSET ((512 * 1024) - CONFIG_ENV_SIZE) +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_SYS_MMC_ENV_PART 2 diff --git a/include/configs/cm_t35.h b/include/configs/cm_t35.h index c6e357a..b258da9 100644 --- a/include/configs/cm_t35.h +++ b/include/configs/cm_t35.h @@ -339,6 +339,5 @@ #define CONFIG_SPLASH_SCREEN #define CONFIG_CMD_BMP #define CONFIG_BMP_16BPP -#define CONFIG_SPLASH_SCREEN_PREPARE #endif /* __CONFIG_H */ diff --git a/include/configs/coreboot.h b/include/configs/coreboot.h index be04a75..288ef8d 100644 --- a/include/configs/coreboot.h +++ b/include/configs/coreboot.h @@ -90,7 +90,8 @@ #endif /* Generic TPM interfaced through LPC bus */ -#define CONFIG_GENERIC_LPC_TPM +#define CONFIG_TPM +#define CONFIG_TPM_TIS_LPC #define CONFIG_TPM_TIS_BASE_ADDRESS 0xfed40000 /*----------------------------------------------------------------------- @@ -167,6 +168,13 @@ */ #include <config_cmd_default.h> +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE (16 << 20) +#define CONFIG_TRACE_EARLY_SIZE (8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR 0x01400000 + #define CONFIG_CMD_BDI #define CONFIG_CMD_BOOTD #define CONFIG_CMD_CONSOLE diff --git a/include/configs/corenet_ds.h b/include/configs/corenet_ds.h index 2e2d439..66c7b4f 100644 --- a/include/configs/corenet_ds.h +++ b/include/configs/corenet_ds.h @@ -564,6 +564,7 @@ #endif #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_E1000 diff --git a/include/configs/csb272.h b/include/configs/csb272.h index f21fa64..eec087c 100644 --- a/include/configs/csb272.h +++ b/include/configs/csb272.h @@ -204,6 +204,7 @@ * */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define PCI_HOST_ADAPTER 0 /* configure ar pci adapter */ #define PCI_HOST_FORCE 1 /* configure as pci host */ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ diff --git a/include/configs/csb472.h b/include/configs/csb472.h index aed5fa6..f6a456c 100644 --- a/include/configs/csb472.h +++ b/include/configs/csb472.h @@ -203,6 +203,7 @@ * */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define PCI_HOST_ADAPTER 0 /* configure ar pci adapter */ #define PCI_HOST_FORCE 1 /* configure as pci host */ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ diff --git a/include/configs/dalmore.h b/include/configs/dalmore.h index 2723843..b6e0161 100644 --- a/include/configs/dalmore.h +++ b/include/configs/dalmore.h @@ -60,7 +60,7 @@ #define CONFIG_ENV_IS_IN_MMC #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_SYS_MMC_ENV_PART 2 -#define CONFIG_ENV_OFFSET ((4096 * 1024) - CONFIG_ENV_SIZE) +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) #define MACH_TYPE_DALMORE 4304 /* not yet in mach-types.h */ diff --git a/include/configs/debris.h b/include/configs/debris.h index 32aa4e5..c40fbd9 100644 --- a/include/configs/debris.h +++ b/include/configs/debris.h @@ -172,6 +172,7 @@ *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP #define CONFIG_EEPRO100 diff --git a/include/configs/devkit8000.h b/include/configs/devkit8000.h index 788227d..3b74d7c 100644 --- a/include/configs/devkit8000.h +++ b/include/configs/devkit8000.h @@ -360,6 +360,14 @@ #define CONFIG_CMD_SPL_NAND_OFS (CONFIG_SYS_NAND_SPL_KERNEL_OFFS+\ 0x400000) #define CONFIG_SYS_NAND_SPL_KERNEL_OFFS 0x280000 + +#define CONFIG_SPL_FAT_LOAD_KERNEL_NAME "uImage" +#define CONFIG_SPL_FAT_LOAD_ARGS_NAME "args" + +#define CONFIG_SYS_MMCSD_RAW_MODE_KERNEL_SECTOR 0x500 /* address 0xa0000 */ +#define CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR 0x8 /* address 0x1000 */ +#define CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTORS 8 /* 4KB */ + #define CONFIG_SYS_SPL_ARGS_ADDR (PHYS_SDRAM_1 + 0x100) #endif /* __CONFIG_H */ diff --git a/include/configs/eXalion.h b/include/configs/eXalion.h index 3238ac7..a6a0f8b 100644 --- a/include/configs/eXalion.h +++ b/include/configs/eXalion.h @@ -180,6 +180,7 @@ * PCI stuff */ #define CONFIG_PCI 1 /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP diff --git a/include/configs/ebony.h b/include/configs/ebony.h index d6b6551..b05ba08 100644 --- a/include/configs/ebony.h +++ b/include/configs/ebony.h @@ -177,6 +177,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE */ diff --git a/include/configs/ep82xxm.h b/include/configs/ep82xxm.h index 8d78921..7393f28 100644 --- a/include/configs/ep82xxm.h +++ b/include/configs/ep82xxm.h @@ -254,6 +254,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_PCI_BOOTDELAY 0 diff --git a/include/configs/exynos5250-dt.h b/include/configs/exynos5250-dt.h index b32d1bd..582c584 100644 --- a/include/configs/exynos5250-dt.h +++ b/include/configs/exynos5250-dt.h @@ -43,6 +43,14 @@ #define CONFIG_OF_CONTROL #define CONFIG_OF_SEPARATE +/* Allow tracing to be enabled */ +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE (16 << 20) +#define CONFIG_TRACE_EARLY_SIZE (8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR 0x50000000 + /* Keep L2 Cache Disabled */ #define CONFIG_SYS_DCACHE_OFF @@ -82,11 +90,19 @@ #define EXYNOS5_DEFAULT_UART_OFFSET 0x010000 #define CONFIG_SILENT_CONSOLE +/* Enable keyboard */ +#define CONFIG_CROS_EC /* CROS_EC protocol */ +#define CONFIG_CROS_EC_SPI /* Support CROS_EC over SPI */ +#define CONFIG_CROS_EC_I2C /* Support CROS_EC over I2C */ +#define CONFIG_CROS_EC_KEYB /* CROS_EC keyboard input */ +#define CONFIG_CMD_CROS_EC +#define CONFIG_KEYBOARD + /* Console configuration */ #define CONFIG_CONSOLE_MUX #define CONFIG_SYS_CONSOLE_IS_IN_ENV #define EXYNOS_DEVICE_SETTINGS \ - "stdin=serial\0" \ + "stdin=serial,cros-ec-keyb\0" \ "stdout=serial,lcd\0" \ "stderr=serial,lcd\0" @@ -146,9 +162,9 @@ /* TPM */ #define CONFIG_TPM #define CONFIG_CMD_TPM -#define CONFIG_INFINEON_TPM_I2C -#define CONFIG_INFINEON_TPM_I2C_BUS 3 -#define CONFIG_INFINEON_TPM_I2C_ADDR 0x20 +#define CONFIG_TPM_TIS_I2C +#define CONFIG_TPM_TIS_I2C_BUS_NUMBER 3 +#define CONFIG_TPM_TIS_I2C_SLAVE_ADDR 0x20 /* MMC SPL */ #define CONFIG_SPL diff --git a/include/configs/gdppc440etx.h b/include/configs/gdppc440etx.h index 9efbb8e..7b8bac4 100644 --- a/include/configs/gdppc440etx.h +++ b/include/configs/gdppc440etx.h @@ -178,6 +178,7 @@ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP /* do (not) pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup*/ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to \ diff --git a/include/configs/icon.h b/include/configs/icon.h index 2fac0ef..c2da4ce 100644 --- a/include/configs/icon.h +++ b/include/configs/icon.h @@ -234,6 +234,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/configs/igep0033.h b/include/configs/igep0033.h index afbd549..12f28f8 100644 --- a/include/configs/igep0033.h +++ b/include/configs/igep0033.h @@ -215,12 +215,11 @@ #define CONFIG_SPL #define CONFIG_SPL_FRAMEWORK /* - * Place the image at the start of the ROM defined image space and leave - * space for SRAM scratch entries (see arch/arm/include/omap_common.h). + * Place the image at the start of the ROM defined image space. * We limit our size to the ROM-defined downloaded image area, and use the * rest of the space for stack. */ -#define CONFIG_SPL_TEXT_BASE 0x402F0500 +#define CONFIG_SPL_TEXT_BASE 0x402F0400 #define CONFIG_SPL_MAX_SIZE (0x4030C000 - CONFIG_SPL_TEXT_BASE) #define CONFIG_SPL_STACK CONFIG_SYS_INIT_SP_ADDR diff --git a/include/configs/intip.h b/include/configs/intip.h index 33364a8..ed96b1b 100644 --- a/include/configs/intip.h +++ b/include/configs/intip.h @@ -316,6 +316,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/configs/katmai.h b/include/configs/katmai.h index 3ed8dc7..c6f712c 100644 --- a/include/configs/katmai.h +++ b/include/configs/katmai.h @@ -238,6 +238,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP 1 /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW 1 /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/configs/kilauea.h b/include/configs/kilauea.h index d505a41..aec4a58 100644 --- a/include/configs/kilauea.h +++ b/include/configs/kilauea.h @@ -483,6 +483,7 @@ * PCI stuff *----------------------------------------------------------------------*/ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP 1 /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW 1 /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/configs/korat.h b/include/configs/korat.h index b919aec..d7c1f85 100644 --- a/include/configs/korat.h +++ b/include/configs/korat.h @@ -355,6 +355,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 0 /* to avoid problems with PNP */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ diff --git a/include/configs/kvme080.h b/include/configs/kvme080.h index e49dc28..87a5056 100644 --- a/include/configs/kvme080.h +++ b/include/configs/kvme080.h @@ -169,6 +169,7 @@ #define CONFIG_SYS_NS16550_CLK 14745600 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP #define CONFIG_EEPRO100 diff --git a/include/configs/linkstation.h b/include/configs/linkstation.h index eec7961..20f0a18 100644 --- a/include/configs/linkstation.h +++ b/include/configs/linkstation.h @@ -185,6 +185,7 @@ * PCI stuff */ #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE /* Verified: CONFIG_PCI_PNP doesn't work */ #undef CONFIG_PCI_PNP #define CONFIG_PCI_SCAN_SHOW diff --git a/include/configs/luan.h b/include/configs/luan.h index 3b4761b..f0e568a 100644 --- a/include/configs/luan.h +++ b/include/configs/luan.h @@ -178,6 +178,7 @@ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do (not) pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ diff --git a/include/configs/makalu.h b/include/configs/makalu.h index 6c1b136..f71f28b 100644 --- a/include/configs/makalu.h +++ b/include/configs/makalu.h @@ -276,6 +276,7 @@ * PCI stuff *----------------------------------------------------------------------*/ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP 1 /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW 1 /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/configs/mpc5121ads.h b/include/configs/mpc5121ads.h index 64ce52d..6f003aa 100644 --- a/include/configs/mpc5121ads.h +++ b/include/configs/mpc5121ads.h @@ -336,6 +336,7 @@ * PCI */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE /* * General PCI diff --git a/include/configs/mpc8308_p1m.h b/include/configs/mpc8308_p1m.h index aa681f0..3c7a85e 100644 --- a/include/configs/mpc8308_p1m.h +++ b/include/configs/mpc8308_p1m.h @@ -353,6 +353,7 @@ #define CONFIG_SYS_SCCR_PCIEXP1CM 1 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCIE #define CONFIG_PCI_PNP /* do pci plug-and-play */ diff --git a/include/configs/ocotea.h b/include/configs/ocotea.h index d0fe9da..3e64c74 100644 --- a/include/configs/ocotea.h +++ b/include/configs/ocotea.h @@ -197,6 +197,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE */ diff --git a/include/configs/p1_p2_rdb_pc.h b/include/configs/p1_p2_rdb_pc.h index 7ed634b..2fa5372 100644 --- a/include/configs/p1_p2_rdb_pc.h +++ b/include/configs/p1_p2_rdb_pc.h @@ -217,6 +217,7 @@ #define CONFIG_PCIE1 /* PCIE controler 1 (slot 1) */ #define CONFIG_PCIE2 /* PCIE controler 2 (slot 2) */ #define CONFIG_FSL_PCI_INIT /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_FSL_PCIE_RESET /* need PCIe reset errata */ #define CONFIG_SYS_PCI_64BIT /* enable 64-bit PCI resources */ diff --git a/include/configs/p3p440.h b/include/configs/p3p440.h index d7b1ca2..a19de07 100644 --- a/include/configs/p3p440.h +++ b/include/configs/p3p440.h @@ -241,6 +241,7 @@ *----------------------------------------------------------------------*/ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE */ diff --git a/include/configs/paz00.h b/include/configs/paz00.h index eac1ef9..9e2686a 100644 --- a/include/configs/paz00.h +++ b/include/configs/paz00.h @@ -46,7 +46,7 @@ /* Environment in eMMC, at the end of 2nd "boot sector" */ #define CONFIG_ENV_IS_IN_MMC -#define CONFIG_ENV_OFFSET ((1024 * 1024) - CONFIG_ENV_SIZE) +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_SYS_MMC_ENV_PART 2 diff --git a/include/configs/pcm051.h b/include/configs/pcm051.h index 3480302..9b16c47 100644 --- a/include/configs/pcm051.h +++ b/include/configs/pcm051.h @@ -205,12 +205,11 @@ #define CONFIG_SPL #define CONFIG_SPL_FRAMEWORK /* - * Place the image at the start of the ROM defined image space and leave - * space for SRAM scratch entries (see arch/arm/include/omap_common.h). + * Place the image at the start of the ROM defined image space. * We limit our size to the ROM-defined downloaded image area, and use the * rest of the space for stack. */ -#define CONFIG_SPL_TEXT_BASE 0x402F0500 +#define CONFIG_SPL_TEXT_BASE 0x402F0400 #define CONFIG_SPL_MAX_SIZE (0x4030C000 - CONFIG_SPL_TEXT_BASE) #define CONFIG_SPL_STACK CONFIG_SYS_INIT_SP_ADDR @@ -232,6 +231,7 @@ #define CONFIG_SPL_GPIO_SUPPORT #define CONFIG_SPL_YMODEM_SUPPORT #define CONFIG_SPL_NET_SUPPORT +#define CONFIG_SPL_ENV_SUPPORT #define CONFIG_SPL_NET_VCI_STRING "pcm051 U-Boot SPL" #define CONFIG_SPL_ETH_SUPPORT #define CONFIG_SPL_SPI_SUPPORT diff --git a/include/configs/pcs440ep.h b/include/configs/pcs440ep.h index 351ff5a..1897619 100644 --- a/include/configs/pcs440ep.h +++ b/include/configs/pcs440ep.h @@ -317,6 +317,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP /* do (not) pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE*/ diff --git a/include/configs/pm9263.h b/include/configs/pm9263.h index b60a9ad..6f6ddfa 100644 --- a/include/configs/pm9263.h +++ b/include/configs/pm9263.h @@ -355,7 +355,7 @@ #define CONFIG_BOOTCOMMAND "run flashboot" #define CONFIG_ROOTPATH "/ronetix/rootfs" -#define CONFIG_AUTOBOOT_PROMPT "autoboot in %d seconds\n" +#define CONFIG_AUTOBOOT_PROMPT "autoboot in %d seconds\n", bootdelay #define CONFIG_CON_ROT "fbcon=rotate:3 " #define CONFIG_BOOTARGS "root=/dev/mtdblock4 rootfstype=jffs2 "\ diff --git a/include/configs/ppmc7xx.h b/include/configs/ppmc7xx.h index 5cd6609..3f9fdd4 100644 --- a/include/configs/ppmc7xx.h +++ b/include/configs/ppmc7xx.h @@ -118,6 +118,7 @@ */ #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI_PNP #undef CONFIG_PCI_SCAN_SHOW @@ -233,7 +234,7 @@ #define CONFIG_SYS_FLASH_ERASE_TOUT 250000 #define CONFIG_SYS_FLASH_WRITE_TOUT 5000 #define CONFIG_SYS_MAX_FLASH_BANKS 1 -#define CONFIG_SYS_MAX_FLASH_SECT 19 +#define CONFIG_SYS_MAX_FLASH_SECT 128 /* diff --git a/include/configs/rpi_b.h b/include/configs/rpi_b.h index c18b35b..216c6cb 100644 --- a/include/configs/rpi_b.h +++ b/include/configs/rpi_b.h @@ -61,6 +61,7 @@ #define CONFIG_BCM2835_GPIO /* LCD */ #define CONFIG_LCD +#define CONFIG_LCD_DT_SIMPLEFB #define LCD_BPP LCD_COLOR16 /* * Prevent allocation of RAM for FB; the real FB address is queried @@ -175,6 +176,7 @@ /* Device tree support for bootm/bootz */ #define CONFIG_OF_LIBFDT +#define CONFIG_OF_BOARD_SETUP /* ATAGs support for bootm/bootz */ #define CONFIG_SETUP_MEMORY_TAGS #define CONFIG_CMDLINE_TAG diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 788207d..98dd083 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -22,6 +22,19 @@ #ifndef __CONFIG_H #define __CONFIG_H +#ifdef FTRACE +#define CONFIG_TRACE +#define CONFIG_CMD_TRACE +#define CONFIG_TRACE_BUFFER_SIZE (16 << 20) +#define CONFIG_TRACE_EARLY_SIZE (8 << 20) +#define CONFIG_TRACE_EARLY +#define CONFIG_TRACE_EARLY_ADDR 0x00100000 + +#endif + +#define CONFIG_BOOTSTAGE +#define CONFIG_BOOTSTAGE_REPORT + /* Number of bits in a C 'long' on this architecture */ #define CONFIG_SANDBOX_BITS_PER_LONG 64 @@ -30,6 +43,8 @@ #define CONFIG_OF_LIBFDT #define CONFIG_LMB #define CONFIG_FIT +#define CONFIG_FIT_SIGNATURE +#define CONFIG_RSA #define CONFIG_CMD_FDT #define CONFIG_FS_FAT diff --git a/include/configs/sbc405.h b/include/configs/sbc405.h index 5abcda3..6e53bc2 100644 --- a/include/configs/sbc405.h +++ b/include/configs/sbc405.h @@ -183,6 +183,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/sbc8349.h b/include/configs/sbc8349.h index 478d0d8..fdc1b95 100644 --- a/include/configs/sbc8349.h +++ b/include/configs/sbc8349.h @@ -573,6 +573,7 @@ /* PCI @ 0x80000000 */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_IBAT1L (CONFIG_SYS_PCI1_MEM_BASE \ | BATL_PP_RW \ | BATL_MEMCOHERENCE) diff --git a/include/configs/sbc8548.h b/include/configs/sbc8548.h index 2209ddf..148ade3 100644 --- a/include/configs/sbc8548.h +++ b/include/configs/sbc8548.h @@ -33,6 +33,7 @@ * Top level Makefile configuration choices */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_PCI1 #endif diff --git a/include/configs/sbc8641d.h b/include/configs/sbc8641d.h index 9040ec6..0e2d17d 100644 --- a/include/configs/sbc8641d.h +++ b/include/configs/sbc8641d.h @@ -64,6 +64,7 @@ #define CONFIG_PCIE1 1 /* PCIE controler 1 (slot 1) */ #define CONFIG_PCIE2 1 /* PCIE controler 2 (slot 2) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_FSL_LAW 1 /* Use common FSL init code */ #define CONFIG_TSEC_ENET /* tsec ethernet support */ diff --git a/include/configs/sc3.h b/include/configs/sc3.h index fb74608..9dec21d 100644 --- a/include/configs/sc3.h +++ b/include/configs/sc3.h @@ -269,6 +269,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/seaboard.h b/include/configs/seaboard.h index f66173e..f0da1fc 100644 --- a/include/configs/seaboard.h +++ b/include/configs/seaboard.h @@ -72,7 +72,7 @@ /* Environment in eMMC, at the end of 2nd "boot sector" */ #define CONFIG_ENV_IS_IN_MMC -#define CONFIG_ENV_OFFSET ((512 * 1024) - CONFIG_ENV_SIZE) +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_SYS_MMC_ENV_PART 2 diff --git a/include/configs/sequoia.h b/include/configs/sequoia.h index dd5d7cd..11fce53 100644 --- a/include/configs/sequoia.h +++ b/include/configs/sequoia.h @@ -363,6 +363,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_SYS_PCI_CACHE_LINE_SIZE 0 /* to avoid problems with PNP */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ diff --git a/include/configs/socrates.h b/include/configs/socrates.h index 25f15f2..7a0b481 100644 --- a/include/configs/socrates.h +++ b/include/configs/socrates.h @@ -48,6 +48,7 @@ #define CONFIG_SYS_TEXT_BASE 0xfff80000 #define CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_TSEC_ENET /* tsec ethernet support */ diff --git a/include/configs/stxssa.h b/include/configs/stxssa.h index c1a90a7..96d7128 100644 --- a/include/configs/stxssa.h +++ b/include/configs/stxssa.h @@ -46,6 +46,7 @@ #define CONFIG_SYS_TEXT_BASE 0xFFF80000 #define CONFIG_PCI /* PCI ethernet support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_TSEC_ENET /* tsec ethernet support*/ #undef CONFIG_ETHER_ON_FCC /* cpm FCC ethernet support */ #define CONFIG_ENV_OVERWRITE diff --git a/include/configs/t3corp.h b/include/configs/t3corp.h index 2a731a6..ff2189c 100644 --- a/include/configs/t3corp.h +++ b/include/configs/t3corp.h @@ -376,6 +376,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/configs/t4qds.h b/include/configs/t4qds.h index fa1dcc3..92b2179 100644 --- a/include/configs/t4qds.h +++ b/include/configs/t4qds.h @@ -33,6 +33,15 @@ #define CONFIG_PBLRCW_CONFIG $(SRCTREE)/board/freescale/t4qds/t4_rcw.cfg #endif +#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE +/* Set 1M boot space */ +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR (CONFIG_SYS_TEXT_BASE & 0xfff00000) +#define CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS \ + (0x300000000ull | CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR) +#define CONFIG_RESET_VECTOR_ADDRESS 0xfffffffc +#define CONFIG_SYS_NO_FLASH +#endif + #define CONFIG_CMD_REGINFO /* High Level Configuration Options */ @@ -65,20 +74,22 @@ #define CONFIG_SYS_SRIO #define CONFIG_SRIO1 /* SRIO port 1 */ #define CONFIG_SRIO2 /* SRIO port 2 */ +#define CONFIG_SRIO_PCIE_BOOT_MASTER #define CONFIG_FSL_LAW /* Use common FSL init code */ #define CONFIG_ENV_OVERWRITE #ifdef CONFIG_SYS_NO_FLASH +#if !defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) && !defined(CONFIG_RAMBOOT_PBL) #define CONFIG_ENV_IS_NOWHERE +#endif #else #define CONFIG_FLASH_CFI_DRIVER #define CONFIG_SYS_FLASH_CFI #define CONFIG_SYS_FLASH_USE_BUFFER_WRITE #endif -#ifndef CONFIG_SYS_NO_FLASH #if defined(CONFIG_SPIFLASH) #define CONFIG_SYS_EXTRA_ENV_RELOC #define CONFIG_ENV_IS_IN_SPI_FLASH @@ -100,18 +111,18 @@ #define CONFIG_ENV_IS_IN_NAND #define CONFIG_ENV_SIZE CONFIG_SYS_NAND_BLOCK_SIZE #define CONFIG_ENV_OFFSET (5 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +#define CONFIG_ENV_IS_IN_REMOTE +#define CONFIG_ENV_ADDR 0xffe20000 +#define CONFIG_ENV_SIZE 0x2000 +#elif defined(CONFIG_ENV_IS_NOWHERE) +#define CONFIG_ENV_SIZE 0x2000 #else #define CONFIG_ENV_IS_IN_FLASH #define CONFIG_ENV_ADDR (CONFIG_SYS_MONITOR_BASE - CONFIG_ENV_SECT_SIZE) #define CONFIG_ENV_SIZE 0x2000 #define CONFIG_ENV_SECT_SIZE 0x20000 /* 128K (one sector) */ #endif -#else /* CONFIG_SYS_NO_FLASH */ -#define CONFIG_ENV_SIZE 0x2000 -#define CONFIG_ENV_SECT_SIZE 0x20000 /* 128K (one sector) */ -#endif - - #define CONFIG_SYS_CLK_FREQ get_board_sys_clk() #define CONFIG_DDR_CLK_FREQ get_board_ddr_clk() @@ -633,6 +644,16 @@ unsigned long get_board_ddr_clk(void); #elif defined(CONFIG_NAND) #define CONFIG_SYS_QE_FMAN_FW_IN_NAND #define CONFIG_SYS_QE_FMAN_FW_ADDR (6 * CONFIG_SYS_NAND_BLOCK_SIZE) +#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE) +/* + * Slave has no ucode locally, it can fetch this from remote. When implementing + * in two corenet boards, slave's ucode could be stored in master's memory + * space, the address can be mapped from slave TLB->slave LAW-> + * slave SRIO or PCIE outbound window->master inbound window-> + * master LAW->the ucode address in master's memory space. + */ +#define CONFIG_SYS_QE_FMAN_FW_IN_REMOTE +#define CONFIG_SYS_QE_FMAN_FW_ADDR 0xFFE00000 #else #define CONFIG_SYS_QE_FMAN_FW_IN_NOR #define CONFIG_SYS_QE_FMAN_FW_ADDR 0xEFF40000 @@ -657,6 +678,7 @@ unsigned long get_board_ddr_clk(void); #endif #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_NET_MULTI #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_E1000 diff --git a/include/configs/taihu.h b/include/configs/taihu.h index a3738b7..a43c3da 100644 --- a/include/configs/taihu.h +++ b/include/configs/taihu.h @@ -171,6 +171,7 @@ unsigned char spi_read(void); #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/taishan.h b/include/configs/taishan.h index 3046081..c9f1a9f 100644 --- a/include/configs/taishan.h +++ b/include/configs/taishan.h @@ -192,6 +192,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_EEPRO100 1 /* include PCI EEPRO100 */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ diff --git a/include/configs/utx8245.h b/include/configs/utx8245.h index 66568c8..60d1503 100644 --- a/include/configs/utx8245.h +++ b/include/configs/utx8245.h @@ -139,6 +139,7 @@ protect on ${u-boot_startaddr} ${u-boot_endaddr}" *----------------------------------------------------------------------- */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP #define CONFIG_PCI_SCAN_SHOW #define CONFIG_EEPRO100 diff --git a/include/configs/ve8313.h b/include/configs/ve8313.h index d3b8379..7b1130a 100644 --- a/include/configs/ve8313.h +++ b/include/configs/ve8313.h @@ -43,6 +43,7 @@ #endif #define CONFIG_PCI 1 +#define CONFIG_PCI_INDIRECT_BRIDGE 1 #define CONFIG_FSL_ELBC 1 #define CONFIG_BOARD_EARLY_INIT_F 1 diff --git a/include/configs/ventana.h b/include/configs/ventana.h index 64e7875..05e682c 100644 --- a/include/configs/ventana.h +++ b/include/configs/ventana.h @@ -53,7 +53,7 @@ /* Environment in eMMC, at the end of 2nd "boot sector" */ #define CONFIG_ENV_IS_IN_MMC -#define CONFIG_ENV_OFFSET ((1024 * 1024) - CONFIG_ENV_SIZE) +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_SYS_MMC_ENV_PART 2 diff --git a/include/configs/vme8349.h b/include/configs/vme8349.h index 61e02e6..f97de54 100644 --- a/include/configs/vme8349.h +++ b/include/configs/vme8349.h @@ -489,6 +489,7 @@ /* PCI @ 0x80000000 */ #ifdef CONFIG_PCI +#define CONFIG_PCI_INDIRECT_BRIDGE #define CONFIG_SYS_IBAT1L (CONFIG_SYS_PCI1_MEM_BASE | BATL_PP_RW | \ BATL_MEMCOHERENCE) #define CONFIG_SYS_IBAT1U (CONFIG_SYS_PCI1_MEM_BASE | BATU_BL_256M | \ diff --git a/include/configs/walnut.h b/include/configs/walnut.h index d10f748..219f276 100644 --- a/include/configs/walnut.h +++ b/include/configs/walnut.h @@ -112,6 +112,7 @@ #define PCI_HOST_AUTO 2 /* detected via arbiter enable */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_HOST PCI_HOST_FORCE /* select pci host function */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ /* resource configuration */ diff --git a/include/configs/whistler.h b/include/configs/whistler.h index 9542c7e..994edec 100644 --- a/include/configs/whistler.h +++ b/include/configs/whistler.h @@ -61,12 +61,12 @@ /* * Environment in eMMC, at the end of 2nd "boot sector". Note: This assumes - * the user plugged the standard 8MB MoviNAND card into J29/HSMMC/POP. If + * the user plugged the standard 8GB MoviNAND card into J29/HSMMC/POP. If * they didn't, the boot sector layout may be different. However, use of that * particular card is standard practice as far as I know. */ #define CONFIG_ENV_IS_IN_MMC -#define CONFIG_ENV_OFFSET ((512 * 1024) - CONFIG_ENV_SIZE) +#define CONFIG_ENV_OFFSET (-CONFIG_ENV_SIZE) #define CONFIG_SYS_MMC_ENV_DEV 0 #define CONFIG_SYS_MMC_ENV_PART 2 diff --git a/include/configs/xpedite1000.h b/include/configs/xpedite1000.h index 506d646..1f48cc5 100644 --- a/include/configs/xpedite1000.h +++ b/include/configs/xpedite1000.h @@ -167,6 +167,7 @@ extern void out32(unsigned int, unsigned long); */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE */ diff --git a/include/configs/xpedite517x.h b/include/configs/xpedite517x.h index 1851a00..f28f443 100644 --- a/include/configs/xpedite517x.h +++ b/include/configs/xpedite517x.h @@ -49,6 +49,7 @@ #define CONFIG_PCIE1 1 /* PCIE controler 1 */ #define CONFIG_PCIE2 1 /* PCIE controler 2 */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_FSL_LAW 1 /* Use common FSL init code */ diff --git a/include/configs/xpedite520x.h b/include/configs/xpedite520x.h index ff99481..3034a3c 100644 --- a/include/configs/xpedite520x.h +++ b/include/configs/xpedite520x.h @@ -48,6 +48,7 @@ #define CONFIG_PCI_SCAN_SHOW 1 /* show pci devices on startup */ #define CONFIG_PCI1 1 /* PCI controller 1 */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_FSL_LAW 1 /* Use common FSL init code */ diff --git a/include/configs/xpedite537x.h b/include/configs/xpedite537x.h index 46f1c90..43359a2 100644 --- a/include/configs/xpedite537x.h +++ b/include/configs/xpedite537x.h @@ -49,6 +49,7 @@ #define CONFIG_PCIE1 1 /* PCIE controler 1 */ #define CONFIG_PCIE2 1 /* PCIE controler 2 */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_FSL_LAW 1 /* Use common FSL init code */ diff --git a/include/configs/xpedite550x.h b/include/configs/xpedite550x.h index 2acf6c8..a171085 100644 --- a/include/configs/xpedite550x.h +++ b/include/configs/xpedite550x.h @@ -48,6 +48,7 @@ #define CONFIG_PCI_SCAN_SHOW 1 /* show pci devices on startup */ #define CONFIG_PCIE1 1 /* PCIE controler 1 (PEX8112 or XMC) */ #define CONFIG_FSL_PCI_INIT 1 /* Use common FSL init code */ +#define CONFIG_PCI_INDIRECT_BRIDGE 1 /* indirect PCI bridge support */ #define CONFIG_SYS_PCI_64BIT 1 /* enable 64-bit PCI resources */ #define CONFIG_FSL_PCIE_RESET 1 /* need PCIe reset errata */ #define CONFIG_FSL_LAW 1 /* Use common FSL init code */ diff --git a/include/configs/yosemite.h b/include/configs/yosemite.h index 0cbef6f..cde0df1 100644 --- a/include/configs/yosemite.h +++ b/include/configs/yosemite.h @@ -222,6 +222,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #undef CONFIG_PCI_PNP /* do (not) pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW /* show pci devices on startup */ #define CONFIG_SYS_PCI_TARGBASE 0x80000000 /* PCIaddr mapped to CONFIG_SYS_PCI_MEMBASE*/ diff --git a/include/configs/yucca.h b/include/configs/yucca.h index fb684b5..3282d37 100644 --- a/include/configs/yucca.h +++ b/include/configs/yucca.h @@ -199,6 +199,7 @@ */ /* General PCI */ #define CONFIG_PCI /* include pci support */ +#define CONFIG_PCI_INDIRECT_BRIDGE /* indirect PCI bridge support */ #define CONFIG_PCI_PNP 1 /* do pci plug-and-play */ #define CONFIG_PCI_SCAN_SHOW 1 /* show pci devices on startup */ #define CONFIG_PCI_CONFIG_HOST_BRIDGE diff --git a/include/cros_ec.h b/include/cros_ec.h new file mode 100644 index 0000000..335d5b4 --- /dev/null +++ b/include/cros_ec.h @@ -0,0 +1,449 @@ +/* + * Chromium OS cros_ec driver + * + * Copyright (c) 2012 The Chromium OS Authors. + * 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 _CROS_EC_H +#define _CROS_EC_H + +#include <linux/compiler.h> +#include <ec_commands.h> +#include <fdtdec.h> +#include <cros_ec_message.h> + +/* Which interface is the device on? */ +enum cros_ec_interface_t { + CROS_EC_IF_NONE, + CROS_EC_IF_SPI, + CROS_EC_IF_I2C, + CROS_EC_IF_LPC, /* Intel Low Pin Count interface */ +}; + +/* Our configuration information */ +struct cros_ec_dev { + enum cros_ec_interface_t interface; + struct spi_slave *spi; /* Our SPI slave, if using SPI */ + int node; /* Our node */ + int parent_node; /* Our parent node (interface) */ + unsigned int cs; /* Our chip select */ + unsigned int addr; /* Device address (for I2C) */ + unsigned int bus_num; /* Bus number (for I2C) */ + unsigned int max_frequency; /* Maximum interface frequency */ + struct fdt_gpio_state ec_int; /* GPIO used as EC interrupt line */ + int cmd_version_is_supported; /* Device supports command versions */ + int optimise_flash_write; /* Don't write erased flash blocks */ + + /* + * These two buffers will always be dword-aligned and include enough + * space for up to 7 word-alignment bytes also, so we can ensure that + * the body of the message is always dword-aligned (64-bit). + * + * We use this alignment to keep ARM and x86 happy. Probably word + * alignment would be OK, there might be a small performance advantage + * to using dword. + */ + uint8_t din[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))] + __aligned(sizeof(int64_t)); + uint8_t dout[ALIGN(MSG_BYTES + sizeof(int64_t), sizeof(int64_t))] + __aligned(sizeof(int64_t)); +}; + +/* + * Hard-code the number of columns we happen to know we have right now. It + * would be more correct to call cros_ec_info() at startup and determine the + * actual number of keyboard cols from there. + */ +#define CROS_EC_KEYSCAN_COLS 13 + +/* Information returned by a key scan */ +struct mbkp_keyscan { + uint8_t data[CROS_EC_KEYSCAN_COLS]; +}; + +/** + * Read the ID of the CROS-EC device + * + * The ID is a string identifying the CROS-EC device. + * + * @param dev CROS-EC device + * @param id Place to put the ID + * @param maxlen Maximum length of the ID field + * @return 0 if ok, -1 on error + */ +int cros_ec_read_id(struct cros_ec_dev *dev, char *id, int maxlen); + +/** + * Read a keyboard scan from the CROS-EC device + * + * Send a message requesting a keyboard scan and return the result + * + * @param dev CROS-EC device + * @param scan Place to put the scan results + * @return 0 if ok, -1 on error + */ +int cros_ec_scan_keyboard(struct cros_ec_dev *dev, struct mbkp_keyscan *scan); + +/** + * Read which image is currently running on the CROS-EC device. + * + * @param dev CROS-EC device + * @param image Destination for image identifier + * @return 0 if ok, <0 on error + */ +int cros_ec_read_current_image(struct cros_ec_dev *dev, + enum ec_current_image *image); + +/** + * Read the hash of the CROS-EC device firmware. + * + * @param dev CROS-EC device + * @param hash Destination for hash information + * @return 0 if ok, <0 on error + */ +int cros_ec_read_hash(struct cros_ec_dev *dev, + struct ec_response_vboot_hash *hash); + +/** + * Send a reboot command to the CROS-EC device. + * + * Note that some reboot commands (such as EC_REBOOT_COLD) also reboot the AP. + * + * @param dev CROS-EC device + * @param cmd Reboot command + * @param flags Flags for reboot command (EC_REBOOT_FLAG_*) + * @return 0 if ok, <0 on error + */ +int cros_ec_reboot(struct cros_ec_dev *dev, enum ec_reboot_cmd cmd, + uint8_t flags); + +/** + * Check if the CROS-EC device has an interrupt pending. + * + * Read the status of the external interrupt connected to the CROS-EC device. + * If no external interrupt is configured, this always returns 1. + * + * @param dev CROS-EC device + * @return 0 if no interrupt is pending + */ +int cros_ec_interrupt_pending(struct cros_ec_dev *dev); + +enum { + CROS_EC_OK, + CROS_EC_ERR = 1, + CROS_EC_ERR_FDT_DECODE, + CROS_EC_ERR_CHECK_VERSION, + CROS_EC_ERR_READ_ID, + CROS_EC_ERR_DEV_INIT, +}; + +/** + * Set up the Chromium OS matrix keyboard protocol + * + * @param blob Device tree blob containing setup information + * @param cros_ecp Returns pointer to the cros_ec device, or NULL if none + * @return 0 if we got an cros_ec device and all is well (or no cros_ec is + * expected), -ve if we should have an cros_ec device but failed to find + * one, or init failed (-CROS_EC_ERR_...). + */ +int cros_ec_init(const void *blob, struct cros_ec_dev **cros_ecp); + +/** + * Read information about the keyboard matrix + * + * @param dev CROS-EC device + * @param info Place to put the info structure + */ +int cros_ec_info(struct cros_ec_dev *dev, + struct ec_response_cros_ec_info *info); + +/** + * Read the host event flags + * + * @param dev CROS-EC device + * @param events_ptr Destination for event flags. Not changed on error. + * @return 0 if ok, <0 on error + */ +int cros_ec_get_host_events(struct cros_ec_dev *dev, uint32_t *events_ptr); + +/** + * Clear the specified host event flags + * + * @param dev CROS-EC device + * @param events Event flags to clear + * @return 0 if ok, <0 on error + */ +int cros_ec_clear_host_events(struct cros_ec_dev *dev, uint32_t events); + +/** + * Get/set flash protection + * + * @param dev CROS-EC device + * @param set_mask Mask of flags to set; if 0, just retrieves existing + * protection state without changing it. + * @param set_flags New flag values; only bits in set_mask are applied; + * ignored if set_mask=0. + * @param prot Destination for updated protection state from EC. + * @return 0 if ok, <0 on error + */ +int cros_ec_flash_protect(struct cros_ec_dev *dev, + uint32_t set_mask, uint32_t set_flags, + struct ec_response_flash_protect *resp); + + +/** + * Run internal tests on the cros_ec interface. + * + * @param dev CROS-EC device + * @return 0 if ok, <0 if the test failed + */ +int cros_ec_test(struct cros_ec_dev *dev); + +/** + * Update the EC RW copy. + * + * @param dev CROS-EC device + * @param image the content to write + * @param imafge_size content length + * @return 0 if ok, <0 if the test failed + */ +int cros_ec_flash_update_rw(struct cros_ec_dev *dev, + const uint8_t *image, int image_size); + +/** + * Return a pointer to the board's CROS-EC device + * + * This should be implemented by board files. + * + * @return pointer to CROS-EC device, or NULL if none is available + */ +struct cros_ec_dev *board_get_cros_ec_dev(void); + + +/* Internal interfaces */ +int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob); +int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob); +int cros_ec_lpc_init(struct cros_ec_dev *dev, const void *blob); + +/** + * Read information from the fdt for the i2c cros_ec interface + * + * @param dev CROS-EC device + * @param blob Device tree blob + * @return 0 if ok, -1 if we failed to read all required information + */ +int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob); + +/** + * Read information from the fdt for the spi cros_ec interface + * + * @param dev CROS-EC device + * @param blob Device tree blob + * @return 0 if ok, -1 if we failed to read all required information + */ +int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob); + +/** + * Check whether the LPC interface supports new-style commands. + * + * LPC has its own way of doing this, which involves checking LPC values + * visible to the host. Do this, and update dev->cmd_version_is_supported + * accordingly. + * + * @param dev CROS-EC device to check + */ +int cros_ec_lpc_check_version(struct cros_ec_dev *dev); + +/** + * Send a command to an I2C CROS-EC device and return the reply. + * + * This rather complicated function deals with sending both old-style and + * new-style commands. The old ones have just a command byte and arguments. + * The new ones have version, command, arg-len, [args], chksum so are 3 bytes + * longer. + * + * The device's internal input/output buffers are used. + * + * @param dev CROS-EC device + * @param cmd Command to send (EC_CMD_...) + * @param cmd_version Version of command to send (EC_VER_...) + * @param dout Output data (may be NULL If dout_len=0) + * @param dout_len Size of output data in bytes + * @param dinp Returns pointer to response data + * @param din_len Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len); + +/** + * Send a command to a LPC CROS-EC device and return the reply. + * + * The device's internal input/output buffers are used. + * + * @param dev CROS-EC device + * @param cmd Command to send (EC_CMD_...) + * @param cmd_version Version of command to send (EC_VER_...) + * @param dout Output data (may be NULL If dout_len=0) + * @param dout_len Size of output data in bytes + * @param dinp Returns pointer to response data + * @param din_len Maximum size of response in bytes + * @return number of bytes in response, or -1 on error + */ +int cros_ec_lpc_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len); + +int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version, + const uint8_t *dout, int dout_len, + uint8_t **dinp, int din_len); + +/** + * Dump a block of data for a command. + * + * @param name Name for data (e.g. 'in', 'out') + * @param cmd Command number associated with data, or -1 for none + * @param data Data block to dump + * @param len Length of data block to dump + */ +void cros_ec_dump_data(const char *name, int cmd, const uint8_t *data, int len); + +/** + * Calculate a simple 8-bit checksum of a data block + * + * @param data Data block to checksum + * @param size Size of data block in bytes + * @return checksum value (0 to 255) + */ +int cros_ec_calc_checksum(const uint8_t *data, int size); + +/** + * Decode a flash region parameter + * + * @param argc Number of params remaining + * @param argv List of remaining parameters + * @return flash region (EC_FLASH_REGION_...) or -1 on error + */ +int cros_ec_decode_region(int argc, char * const argv[]); + +int cros_ec_flash_erase(struct cros_ec_dev *dev, uint32_t offset, + uint32_t size); + +/** + * Read data from the flash + * + * Read an arbitrary amount of data from the EC flash, by repeatedly reading + * small blocks. + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to read for a particular region. + * + * @param dev CROS-EC device + * @param data Pointer to data buffer to read into + * @param offset Offset within flash to read from + * @param size Number of bytes to read + * @return 0 if ok, -1 on error + */ +int cros_ec_flash_read(struct cros_ec_dev *dev, uint8_t *data, uint32_t offset, + uint32_t size); + +/** + * Write data to the flash + * + * Write an arbitrary amount of data to the EC flash, by repeatedly writing + * small blocks. + * + * The offset starts at 0. You can obtain the region information from + * cros_ec_flash_offset() to find out where to write for a particular region. + * + * Attempting to write to the region where the EC is currently running from + * will result in an error. + * + * @param dev CROS-EC device + * @param data Pointer to data buffer to write + * @param offset Offset within flash to write to. + * @param size Number of bytes to write + * @return 0 if ok, -1 on error + */ +int cros_ec_flash_write(struct cros_ec_dev *dev, const uint8_t *data, + uint32_t offset, uint32_t size); + +/** + * Obtain position and size of a flash region + * + * @param dev CROS-EC device + * @param region Flash region to query + * @param offset Returns offset of flash region in EC flash + * @param size Returns size of flash region + * @return 0 if ok, -1 on error + */ +int cros_ec_flash_offset(struct cros_ec_dev *dev, enum ec_flash_region region, + uint32_t *offset, uint32_t *size); + +/** + * Read/write VbNvContext from/to a CROS-EC device. + * + * @param dev CROS-EC device + * @param block Buffer of VbNvContext to be read/write + * @return 0 if ok, -1 on error + */ +int cros_ec_read_vbnvcontext(struct cros_ec_dev *dev, uint8_t *block); +int cros_ec_write_vbnvcontext(struct cros_ec_dev *dev, const uint8_t *block); + +/** + * Read the version information for the EC images + * + * @param dev CROS-EC device + * @param versionp This is set to point to the version information + * @return 0 if ok, -1 on error + */ +int cros_ec_read_version(struct cros_ec_dev *dev, + struct ec_response_get_version **versionp); + +/** + * Read the build information for the EC + * + * @param dev CROS-EC device + * @param versionp This is set to point to the build string + * @return 0 if ok, -1 on error + */ +int cros_ec_read_build_info(struct cros_ec_dev *dev, char **strp); + +/** + * Switch on/off a LDO / FET. + * + * @param dev CROS-EC device + * @param index index of the LDO/FET to switch + * @param state new state of the LDO/FET : EC_LDO_STATE_ON|OFF + * @return 0 if ok, -1 on error + */ +int cros_ec_set_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t state); + +/** + * Read back a LDO / FET current state. + * + * @param dev CROS-EC device + * @param index index of the LDO/FET to switch + * @param state current state of the LDO/FET : EC_LDO_STATE_ON|OFF + * @return 0 if ok, -1 on error + */ +int cros_ec_get_ldo(struct cros_ec_dev *dev, uint8_t index, uint8_t *state); +#endif diff --git a/include/cros_ec_message.h b/include/cros_ec_message.h new file mode 100644 index 0000000..a2421c7 --- /dev/null +++ b/include/cros_ec_message.h @@ -0,0 +1,44 @@ +/* + * Chromium OS Matrix Keyboard Message Protocol definitions + * + * Copyright (c) 2012 The Chromium OS Authors. + * 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 _CROS_MESSAGE_H +#define _CROS_MESSAGE_H + +/* + * Command interface between EC and AP, for LPC, I2C and SPI interfaces. + * + * This is copied from the Chromium OS Open Source Embedded Controller code. + */ +enum { + /* The header byte, which follows the preamble */ + MSG_HEADER = 0xec, + + MSG_HEADER_BYTES = 3, + MSG_TRAILER_BYTES = 2, + MSG_PROTO_BYTES = MSG_HEADER_BYTES + MSG_TRAILER_BYTES, + + /* Max length of messages */ + MSG_BYTES = EC_HOST_PARAM_SIZE + MSG_PROTO_BYTES, +}; + +#endif diff --git a/include/dfu.h b/include/dfu.h index a107f4b..124653c 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -68,7 +68,9 @@ static inline unsigned int get_mmc_blk_size(int dev) #define DFU_NAME_SIZE 32 #define DFU_CMD_BUF_SIZE 128 -#define DFU_DATA_BUF_SIZE (1024*1024*8) /* 8 MiB */ +#ifndef CONFIG_SYS_DFU_DATA_BUF_SIZE +#define CONFIG_SYS_DFU_DATA_BUF_SIZE (1024*1024*8) /* 8 MiB */ +#endif #ifndef CONFIG_SYS_DFU_MAX_FILE_SIZE #define CONFIG_SYS_DFU_MAX_FILE_SIZE (4 << 20) /* 4 MiB */ #endif diff --git a/include/ec_commands.h b/include/ec_commands.h new file mode 100644 index 0000000..12811cc --- /dev/null +++ b/include/ec_commands.h @@ -0,0 +1,1440 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Host communication command constants for Chrome EC */ + +#ifndef __CROS_EC_COMMANDS_H +#define __CROS_EC_COMMANDS_H + +/* + * Protocol overview + * + * request: CMD [ P0 P1 P2 ... Pn S ] + * response: ERR [ P0 P1 P2 ... Pn S ] + * + * where the bytes are defined as follow : + * - CMD is the command code. (defined by EC_CMD_ constants) + * - ERR is the error code. (defined by EC_RES_ constants) + * - Px is the optional payload. + * it is not sent if the error code is not success. + * (defined by ec_params_ and ec_response_ structures) + * - S is the checksum which is the sum of all payload bytes. + * + * On LPC, CMD and ERR are sent/received at EC_LPC_ADDR_KERNEL|USER_CMD + * and the payloads are sent/received at EC_LPC_ADDR_KERNEL|USER_PARAM. + * On I2C, all bytes are sent serially in the same message. + */ + +/* Current version of this protocol */ +#define EC_PROTO_VERSION 0x00000002 + +/* Command version mask */ +#define EC_VER_MASK(version) (1UL << (version)) + +/* I/O addresses for ACPI commands */ +#define EC_LPC_ADDR_ACPI_DATA 0x62 +#define EC_LPC_ADDR_ACPI_CMD 0x66 + +/* I/O addresses for host command */ +#define EC_LPC_ADDR_HOST_DATA 0x200 +#define EC_LPC_ADDR_HOST_CMD 0x204 + +/* I/O addresses for host command args and params */ +#define EC_LPC_ADDR_HOST_ARGS 0x800 +#define EC_LPC_ADDR_HOST_PARAM 0x804 +#define EC_HOST_PARAM_SIZE 0x0fc /* Size of param area in bytes */ + +/* I/O addresses for host command params, old interface */ +#define EC_LPC_ADDR_OLD_PARAM 0x880 +#define EC_OLD_PARAM_SIZE 0x080 /* Size of param area in bytes */ + +/* EC command register bit functions */ +#define EC_LPC_CMDR_DATA (1 << 0) /* Data ready for host to read */ +#define EC_LPC_CMDR_PENDING (1 << 1) /* Write pending to EC */ +#define EC_LPC_CMDR_BUSY (1 << 2) /* EC is busy processing a command */ +#define EC_LPC_CMDR_CMD (1 << 3) /* Last host write was a command */ +#define EC_LPC_CMDR_ACPI_BRST (1 << 4) /* Burst mode (not used) */ +#define EC_LPC_CMDR_SCI (1 << 5) /* SCI event is pending */ +#define EC_LPC_CMDR_SMI (1 << 6) /* SMI event is pending */ + +#define EC_LPC_ADDR_MEMMAP 0x900 +#define EC_MEMMAP_SIZE 255 /* ACPI IO buffer max is 255 bytes */ +#define EC_MEMMAP_TEXT_MAX 8 /* Size of a string in the memory map */ + +/* The offset address of each type of data in mapped memory. */ +#define EC_MEMMAP_TEMP_SENSOR 0x00 /* Temp sensors */ +#define EC_MEMMAP_FAN 0x10 /* Fan speeds */ +#define EC_MEMMAP_TEMP_SENSOR_B 0x18 /* Temp sensors (second set) */ +#define EC_MEMMAP_ID 0x20 /* 'E' 'C' */ +#define EC_MEMMAP_ID_VERSION 0x22 /* Version of data in 0x20 - 0x2f */ +#define EC_MEMMAP_THERMAL_VERSION 0x23 /* Version of data in 0x00 - 0x1f */ +#define EC_MEMMAP_BATTERY_VERSION 0x24 /* Version of data in 0x40 - 0x7f */ +#define EC_MEMMAP_SWITCHES_VERSION 0x25 /* Version of data in 0x30 - 0x33 */ +#define EC_MEMMAP_EVENTS_VERSION 0x26 /* Version of data in 0x34 - 0x3f */ +#define EC_MEMMAP_HOST_CMD_FLAGS 0x27 /* Host command interface flags */ +#define EC_MEMMAP_SWITCHES 0x30 +#define EC_MEMMAP_HOST_EVENTS 0x34 +#define EC_MEMMAP_BATT_VOLT 0x40 /* Battery Present Voltage */ +#define EC_MEMMAP_BATT_RATE 0x44 /* Battery Present Rate */ +#define EC_MEMMAP_BATT_CAP 0x48 /* Battery Remaining Capacity */ +#define EC_MEMMAP_BATT_FLAG 0x4c /* Battery State, defined below */ +#define EC_MEMMAP_BATT_DCAP 0x50 /* Battery Design Capacity */ +#define EC_MEMMAP_BATT_DVLT 0x54 /* Battery Design Voltage */ +#define EC_MEMMAP_BATT_LFCC 0x58 /* Battery Last Full Charge Capacity */ +#define EC_MEMMAP_BATT_CCNT 0x5c /* Battery Cycle Count */ +#define EC_MEMMAP_BATT_MFGR 0x60 /* Battery Manufacturer String */ +#define EC_MEMMAP_BATT_MODEL 0x68 /* Battery Model Number String */ +#define EC_MEMMAP_BATT_SERIAL 0x70 /* Battery Serial Number String */ +#define EC_MEMMAP_BATT_TYPE 0x78 /* Battery Type String */ + +/* Number of temp sensors at EC_MEMMAP_TEMP_SENSOR */ +#define EC_TEMP_SENSOR_ENTRIES 16 +/* + * Number of temp sensors at EC_MEMMAP_TEMP_SENSOR_B. + * + * Valid only if EC_MEMMAP_THERMAL_VERSION returns >= 2. + */ +#define EC_TEMP_SENSOR_B_ENTRIES 8 +#define EC_TEMP_SENSOR_NOT_PRESENT 0xff +#define EC_TEMP_SENSOR_ERROR 0xfe +#define EC_TEMP_SENSOR_NOT_POWERED 0xfd +#define EC_TEMP_SENSOR_NOT_CALIBRATED 0xfc +/* + * The offset of temperature value stored in mapped memory. This allows + * reporting a temperature range of 200K to 454K = -73C to 181C. + */ +#define EC_TEMP_SENSOR_OFFSET 200 + +#define EC_FAN_SPEED_ENTRIES 4 /* Number of fans at EC_MEMMAP_FAN */ +#define EC_FAN_SPEED_NOT_PRESENT 0xffff /* Entry not present */ +#define EC_FAN_SPEED_STALLED 0xfffe /* Fan stalled */ + +/* Battery bit flags at EC_MEMMAP_BATT_FLAG. */ +#define EC_BATT_FLAG_AC_PRESENT 0x01 +#define EC_BATT_FLAG_BATT_PRESENT 0x02 +#define EC_BATT_FLAG_DISCHARGING 0x04 +#define EC_BATT_FLAG_CHARGING 0x08 +#define EC_BATT_FLAG_LEVEL_CRITICAL 0x10 + +/* Switch flags at EC_MEMMAP_SWITCHES */ +#define EC_SWITCH_LID_OPEN 0x01 +#define EC_SWITCH_POWER_BUTTON_PRESSED 0x02 +#define EC_SWITCH_WRITE_PROTECT_DISABLED 0x04 +/* Recovery requested via keyboard */ +#define EC_SWITCH_KEYBOARD_RECOVERY 0x08 +/* Recovery requested via dedicated signal (from servo board) */ +#define EC_SWITCH_DEDICATED_RECOVERY 0x10 +/* Was fake developer mode switch; now unused. Remove in next refactor. */ +#define EC_SWITCH_IGNORE0 0x20 + +/* Host command interface flags */ +/* Host command interface supports LPC args (LPC interface only) */ +#define EC_HOST_CMD_FLAG_LPC_ARGS_SUPPORTED 0x01 + +/* Wireless switch flags */ +#define EC_WIRELESS_SWITCH_WLAN 0x01 +#define EC_WIRELESS_SWITCH_BLUETOOTH 0x02 + +/* + * This header file is used in coreboot both in C and ACPI code. The ACPI code + * is pre-processed to handle constants but the ASL compiler is unable to + * handle actual C code so keep it separate. + */ +#ifndef __ACPI__ + +/* + * Define __packed if someone hasn't beat us to it. Linux kernel style + * checking prefers __packed over __attribute__((packed)). + */ +#ifndef __packed +#define __packed __attribute__((packed)) +#endif + +/* LPC command status byte masks */ +/* EC has written a byte in the data register and host hasn't read it yet */ +#define EC_LPC_STATUS_TO_HOST 0x01 +/* Host has written a command/data byte and the EC hasn't read it yet */ +#define EC_LPC_STATUS_FROM_HOST 0x02 +/* EC is processing a command */ +#define EC_LPC_STATUS_PROCESSING 0x04 +/* Last write to EC was a command, not data */ +#define EC_LPC_STATUS_LAST_CMD 0x08 +/* EC is in burst mode. Unsupported by Chrome EC, so this bit is never set */ +#define EC_LPC_STATUS_BURST_MODE 0x10 +/* SCI event is pending (requesting SCI query) */ +#define EC_LPC_STATUS_SCI_PENDING 0x20 +/* SMI event is pending (requesting SMI query) */ +#define EC_LPC_STATUS_SMI_PENDING 0x40 +/* (reserved) */ +#define EC_LPC_STATUS_RESERVED 0x80 + +/* + * EC is busy. This covers both the EC processing a command, and the host has + * written a new command but the EC hasn't picked it up yet. + */ +#define EC_LPC_STATUS_BUSY_MASK \ + (EC_LPC_STATUS_FROM_HOST | EC_LPC_STATUS_PROCESSING) + +/* Host command response codes */ +enum ec_status { + EC_RES_SUCCESS = 0, + EC_RES_INVALID_COMMAND = 1, + EC_RES_ERROR = 2, + EC_RES_INVALID_PARAM = 3, + EC_RES_ACCESS_DENIED = 4, + EC_RES_INVALID_RESPONSE = 5, + EC_RES_INVALID_VERSION = 6, + EC_RES_INVALID_CHECKSUM = 7, + EC_RES_IN_PROGRESS = 8, /* Accepted, command in progress */ + EC_RES_UNAVAILABLE = 9, /* No response available */ + EC_RES_TIMEOUT = 10, /* We got a timeout */ + EC_RES_OVERFLOW = 11, /* Table / data overflow */ +}; + +/* + * Host event codes. Note these are 1-based, not 0-based, because ACPI query + * EC command uses code 0 to mean "no event pending". We explicitly specify + * each value in the enum listing so they won't change if we delete/insert an + * item or rearrange the list (it needs to be stable across platforms, not + * just within a single compiled instance). + */ +enum host_event_code { + EC_HOST_EVENT_LID_CLOSED = 1, + EC_HOST_EVENT_LID_OPEN = 2, + EC_HOST_EVENT_POWER_BUTTON = 3, + EC_HOST_EVENT_AC_CONNECTED = 4, + EC_HOST_EVENT_AC_DISCONNECTED = 5, + EC_HOST_EVENT_BATTERY_LOW = 6, + EC_HOST_EVENT_BATTERY_CRITICAL = 7, + EC_HOST_EVENT_BATTERY = 8, + EC_HOST_EVENT_THERMAL_THRESHOLD = 9, + EC_HOST_EVENT_THERMAL_OVERLOAD = 10, + EC_HOST_EVENT_THERMAL = 11, + EC_HOST_EVENT_USB_CHARGER = 12, + EC_HOST_EVENT_KEY_PRESSED = 13, + /* + * EC has finished initializing the host interface. The host can check + * for this event following sending a EC_CMD_REBOOT_EC command to + * determine when the EC is ready to accept subsequent commands. + */ + EC_HOST_EVENT_INTERFACE_READY = 14, + /* Keyboard recovery combo has been pressed */ + EC_HOST_EVENT_KEYBOARD_RECOVERY = 15, + + /* Shutdown due to thermal overload */ + EC_HOST_EVENT_THERMAL_SHUTDOWN = 16, + /* Shutdown due to battery level too low */ + EC_HOST_EVENT_BATTERY_SHUTDOWN = 17, + + /* + * The high bit of the event mask is not used as a host event code. If + * it reads back as set, then the entire event mask should be + * considered invalid by the host. This can happen when reading the + * raw event status via EC_MEMMAP_HOST_EVENTS but the LPC interface is + * not initialized on the EC, or improperly configured on the host. + */ + EC_HOST_EVENT_INVALID = 32 +}; +/* Host event mask */ +#define EC_HOST_EVENT_MASK(event_code) (1UL << ((event_code) - 1)) + +/* Arguments at EC_LPC_ADDR_HOST_ARGS */ +struct ec_lpc_host_args { + uint8_t flags; + uint8_t command_version; + uint8_t data_size; + /* + * Checksum; sum of command + flags + command_version + data_size + + * all params/response data bytes. + */ + uint8_t checksum; +} __packed; + +/* Flags for ec_lpc_host_args.flags */ +/* + * Args are from host. Data area at EC_LPC_ADDR_HOST_PARAM contains command + * params. + * + * If EC gets a command and this flag is not set, this is an old-style command. + * Command version is 0 and params from host are at EC_LPC_ADDR_OLD_PARAM with + * unknown length. EC must respond with an old-style response (that is, + * withouth setting EC_HOST_ARGS_FLAG_TO_HOST). + */ +#define EC_HOST_ARGS_FLAG_FROM_HOST 0x01 +/* + * Args are from EC. Data area at EC_LPC_ADDR_HOST_PARAM contains response. + * + * If EC responds to a command and this flag is not set, this is an old-style + * response. Command version is 0 and response data from EC is at + * EC_LPC_ADDR_OLD_PARAM with unknown length. + */ +#define EC_HOST_ARGS_FLAG_TO_HOST 0x02 + +/* + * Notes on commands: + * + * Each command is an 8-byte command value. Commands which take params or + * return response data specify structs for that data. If no struct is + * specified, the command does not input or output data, respectively. + * Parameter/response length is implicit in the structs. Some underlying + * communication protocols (I2C, SPI) may add length or checksum headers, but + * those are implementation-dependent and not defined here. + */ + +/*****************************************************************************/ +/* General / test commands */ + +/* + * Get protocol version, used to deal with non-backward compatible protocol + * changes. + */ +#define EC_CMD_PROTO_VERSION 0x00 + +struct ec_response_proto_version { + uint32_t version; +} __packed; + +/* + * Hello. This is a simple command to test the EC is responsive to + * commands. + */ +#define EC_CMD_HELLO 0x01 + +struct ec_params_hello { + uint32_t in_data; /* Pass anything here */ +} __packed; + +struct ec_response_hello { + uint32_t out_data; /* Output will be in_data + 0x01020304 */ +} __packed; + +/* Get version number */ +#define EC_CMD_GET_VERSION 0x02 + +enum ec_current_image { + EC_IMAGE_UNKNOWN = 0, + EC_IMAGE_RO, + EC_IMAGE_RW +}; + +struct ec_response_get_version { + /* Null-terminated version strings for RO, RW */ + char version_string_ro[32]; + char version_string_rw[32]; + char reserved[32]; /* Was previously RW-B string */ + uint32_t current_image; /* One of ec_current_image */ +} __packed; + +/* Read test */ +#define EC_CMD_READ_TEST 0x03 + +struct ec_params_read_test { + uint32_t offset; /* Starting value for read buffer */ + uint32_t size; /* Size to read in bytes */ +} __packed; + +struct ec_response_read_test { + uint32_t data[32]; +} __packed; + +/* + * Get build information + * + * Response is null-terminated string. + */ +#define EC_CMD_GET_BUILD_INFO 0x04 + +/* Get chip info */ +#define EC_CMD_GET_CHIP_INFO 0x05 + +struct ec_response_get_chip_info { + /* Null-terminated strings */ + char vendor[32]; + char name[32]; + char revision[32]; /* Mask version */ +} __packed; + +/* Get board HW version */ +#define EC_CMD_GET_BOARD_VERSION 0x06 + +struct ec_response_board_version { + uint16_t board_version; /* A monotonously incrementing number. */ +} __packed; + +/* + * Read memory-mapped data. + * + * This is an alternate interface to memory-mapped data for bus protocols + * which don't support direct-mapped memory - I2C, SPI, etc. + * + * Response is params.size bytes of data. + */ +#define EC_CMD_READ_MEMMAP 0x07 + +struct ec_params_read_memmap { + uint8_t offset; /* Offset in memmap (EC_MEMMAP_*) */ + uint8_t size; /* Size to read in bytes */ +} __packed; + +/* Read versions supported for a command */ +#define EC_CMD_GET_CMD_VERSIONS 0x08 + +struct ec_params_get_cmd_versions { + uint8_t cmd; /* Command to check */ +} __packed; + +struct ec_response_get_cmd_versions { + /* + * Mask of supported versions; use EC_VER_MASK() to compare with a + * desired version. + */ + uint32_t version_mask; +} __packed; + +/* + * Check EC communcations status (busy). This is needed on i2c/spi but not + * on lpc since it has its own out-of-band busy indicator. + * + * lpc must read the status from the command register. Attempting this on + * lpc will overwrite the args/parameter space and corrupt its data. + */ +#define EC_CMD_GET_COMMS_STATUS 0x09 + +/* Avoid using ec_status which is for return values */ +enum ec_comms_status { + EC_COMMS_STATUS_PROCESSING = 1 << 0, /* Processing cmd */ +}; + +struct ec_response_get_comms_status { + uint32_t flags; /* Mask of enum ec_comms_status */ +} __packed; + + +/*****************************************************************************/ +/* Flash commands */ + +/* Get flash info */ +#define EC_CMD_FLASH_INFO 0x10 + +struct ec_response_flash_info { + /* Usable flash size, in bytes */ + uint32_t flash_size; + /* + * Write block size. Write offset and size must be a multiple + * of this. + */ + uint32_t write_block_size; + /* + * Erase block size. Erase offset and size must be a multiple + * of this. + */ + uint32_t erase_block_size; + /* + * Protection block size. Protection offset and size must be a + * multiple of this. + */ + uint32_t protect_block_size; +} __packed; + +/* + * Read flash + * + * Response is params.size bytes of data. + */ +#define EC_CMD_FLASH_READ 0x11 + +struct ec_params_flash_read { + uint32_t offset; /* Byte offset to read */ + uint32_t size; /* Size to read in bytes */ +} __packed; + +/* Write flash */ +#define EC_CMD_FLASH_WRITE 0x12 + +struct ec_params_flash_write { + uint32_t offset; /* Byte offset to write */ + uint32_t size; /* Size to write in bytes */ + /* + * Data to write. Could really use EC_PARAM_SIZE - 8, but tidiest to + * use a power of 2 so writes stay aligned. + */ + uint8_t data[64]; +} __packed; + +/* Erase flash */ +#define EC_CMD_FLASH_ERASE 0x13 + +struct ec_params_flash_erase { + uint32_t offset; /* Byte offset to erase */ + uint32_t size; /* Size to erase in bytes */ +} __packed; + +/* + * Get/set flash protection. + * + * If mask!=0, sets/clear the requested bits of flags. Depending on the + * firmware write protect GPIO, not all flags will take effect immediately; + * some flags require a subsequent hard reset to take effect. Check the + * returned flags bits to see what actually happened. + * + * If mask=0, simply returns the current flags state. + */ +#define EC_CMD_FLASH_PROTECT 0x15 +#define EC_VER_FLASH_PROTECT 1 /* Command version 1 */ + +/* Flags for flash protection */ +/* RO flash code protected when the EC boots */ +#define EC_FLASH_PROTECT_RO_AT_BOOT (1 << 0) +/* + * RO flash code protected now. If this bit is set, at-boot status cannot + * be changed. + */ +#define EC_FLASH_PROTECT_RO_NOW (1 << 1) +/* Entire flash code protected now, until reboot. */ +#define EC_FLASH_PROTECT_ALL_NOW (1 << 2) +/* Flash write protect GPIO is asserted now */ +#define EC_FLASH_PROTECT_GPIO_ASSERTED (1 << 3) +/* Error - at least one bank of flash is stuck locked, and cannot be unlocked */ +#define EC_FLASH_PROTECT_ERROR_STUCK (1 << 4) +/* + * Error - flash protection is in inconsistent state. At least one bank of + * flash which should be protected is not protected. Usually fixed by + * re-requesting the desired flags, or by a hard reset if that fails. + */ +#define EC_FLASH_PROTECT_ERROR_INCONSISTENT (1 << 5) +/* Entile flash code protected when the EC boots */ +#define EC_FLASH_PROTECT_ALL_AT_BOOT (1 << 6) + +struct ec_params_flash_protect { + uint32_t mask; /* Bits in flags to apply */ + uint32_t flags; /* New flags to apply */ +} __packed; + +struct ec_response_flash_protect { + /* Current value of flash protect flags */ + uint32_t flags; + /* + * Flags which are valid on this platform. This allows the caller + * to distinguish between flags which aren't set vs. flags which can't + * be set on this platform. + */ + uint32_t valid_flags; + /* Flags which can be changed given the current protection state */ + uint32_t writable_flags; +} __packed; + +/* + * Note: commands 0x14 - 0x19 version 0 were old commands to get/set flash + * write protect. These commands may be reused with version > 0. + */ + +/* Get the region offset/size */ +#define EC_CMD_FLASH_REGION_INFO 0x16 +#define EC_VER_FLASH_REGION_INFO 1 + +enum ec_flash_region { + /* Region which holds read-only EC image */ + EC_FLASH_REGION_RO, + /* Region which holds rewritable EC image */ + EC_FLASH_REGION_RW, + /* + * Region which should be write-protected in the factory (a superset of + * EC_FLASH_REGION_RO) + */ + EC_FLASH_REGION_WP_RO, +}; + +struct ec_params_flash_region_info { + uint32_t region; /* enum ec_flash_region */ +} __packed; + +struct ec_response_flash_region_info { + uint32_t offset; + uint32_t size; +} __packed; + +/* Read/write VbNvContext */ +#define EC_CMD_VBNV_CONTEXT 0x17 +#define EC_VER_VBNV_CONTEXT 1 +#define EC_VBNV_BLOCK_SIZE 16 + +enum ec_vbnvcontext_op { + EC_VBNV_CONTEXT_OP_READ, + EC_VBNV_CONTEXT_OP_WRITE, +}; + +struct ec_params_vbnvcontext { + uint32_t op; + uint8_t block[EC_VBNV_BLOCK_SIZE]; +} __packed; + +struct ec_response_vbnvcontext { + uint8_t block[EC_VBNV_BLOCK_SIZE]; +} __packed; + +/*****************************************************************************/ +/* PWM commands */ + +/* Get fan target RPM */ +#define EC_CMD_PWM_GET_FAN_TARGET_RPM 0x20 + +struct ec_response_pwm_get_fan_rpm { + uint32_t rpm; +} __packed; + +/* Set target fan RPM */ +#define EC_CMD_PWM_SET_FAN_TARGET_RPM 0x21 + +struct ec_params_pwm_set_fan_target_rpm { + uint32_t rpm; +} __packed; + +/* Get keyboard backlight */ +#define EC_CMD_PWM_GET_KEYBOARD_BACKLIGHT 0x22 + +struct ec_response_pwm_get_keyboard_backlight { + uint8_t percent; + uint8_t enabled; +} __packed; + +/* Set keyboard backlight */ +#define EC_CMD_PWM_SET_KEYBOARD_BACKLIGHT 0x23 + +struct ec_params_pwm_set_keyboard_backlight { + uint8_t percent; +} __packed; + +/* Set target fan PWM duty cycle */ +#define EC_CMD_PWM_SET_FAN_DUTY 0x24 + +struct ec_params_pwm_set_fan_duty { + uint32_t percent; +} __packed; + +/*****************************************************************************/ +/* + * Lightbar commands. This looks worse than it is. Since we only use one HOST + * command to say "talk to the lightbar", we put the "and tell it to do X" part + * into a subcommand. We'll make separate structs for subcommands with + * different input args, so that we know how much to expect. + */ +#define EC_CMD_LIGHTBAR_CMD 0x28 + +struct rgb_s { + uint8_t r, g, b; +}; + +#define LB_BATTERY_LEVELS 4 +/* List of tweakable parameters. NOTE: It's __packed so it can be sent in a + * host command, but the alignment is the same regardless. Keep it that way. + */ +struct lightbar_params { + /* Timing */ + int google_ramp_up; + int google_ramp_down; + int s3s0_ramp_up; + int s0_tick_delay[2]; /* AC=0/1 */ + int s0a_tick_delay[2]; /* AC=0/1 */ + int s0s3_ramp_down; + int s3_sleep_for; + int s3_ramp_up; + int s3_ramp_down; + + /* Oscillation */ + uint8_t new_s0; + uint8_t osc_min[2]; /* AC=0/1 */ + uint8_t osc_max[2]; /* AC=0/1 */ + uint8_t w_ofs[2]; /* AC=0/1 */ + + /* Brightness limits based on the backlight and AC. */ + uint8_t bright_bl_off_fixed[2]; /* AC=0/1 */ + uint8_t bright_bl_on_min[2]; /* AC=0/1 */ + uint8_t bright_bl_on_max[2]; /* AC=0/1 */ + + /* Battery level thresholds */ + uint8_t battery_threshold[LB_BATTERY_LEVELS - 1]; + + /* Map [AC][battery_level] to color index */ + uint8_t s0_idx[2][LB_BATTERY_LEVELS]; /* AP is running */ + uint8_t s3_idx[2][LB_BATTERY_LEVELS]; /* AP is sleeping */ + + /* Color palette */ + struct rgb_s color[8]; /* 0-3 are Google colors */ +} __packed; + +struct ec_params_lightbar { + uint8_t cmd; /* Command (see enum lightbar_command) */ + union { + struct { + /* no args */ + } dump, off, on, init, get_seq, get_params; + + struct num { + uint8_t num; + } brightness, seq, demo; + + struct reg { + uint8_t ctrl, reg, value; + } reg; + + struct rgb { + uint8_t led, red, green, blue; + } rgb; + + struct lightbar_params set_params; + }; +} __packed; + +struct ec_response_lightbar { + union { + struct dump { + struct { + uint8_t reg; + uint8_t ic0; + uint8_t ic1; + } vals[23]; + } dump; + + struct get_seq { + uint8_t num; + } get_seq; + + struct lightbar_params get_params; + + struct { + /* no return params */ + } off, on, init, brightness, seq, reg, rgb, demo, set_params; + }; +} __packed; + +/* Lightbar commands */ +enum lightbar_command { + LIGHTBAR_CMD_DUMP = 0, + LIGHTBAR_CMD_OFF = 1, + LIGHTBAR_CMD_ON = 2, + LIGHTBAR_CMD_INIT = 3, + LIGHTBAR_CMD_BRIGHTNESS = 4, + LIGHTBAR_CMD_SEQ = 5, + LIGHTBAR_CMD_REG = 6, + LIGHTBAR_CMD_RGB = 7, + LIGHTBAR_CMD_GET_SEQ = 8, + LIGHTBAR_CMD_DEMO = 9, + LIGHTBAR_CMD_GET_PARAMS = 10, + LIGHTBAR_CMD_SET_PARAMS = 11, + LIGHTBAR_NUM_CMDS +}; + +/*****************************************************************************/ +/* Verified boot commands */ + +/* + * Note: command code 0x29 version 0 was VBOOT_CMD in Link EVT; it may be + * reused for other purposes with version > 0. + */ + +/* Verified boot hash command */ +#define EC_CMD_VBOOT_HASH 0x2A + +struct ec_params_vboot_hash { + uint8_t cmd; /* enum ec_vboot_hash_cmd */ + uint8_t hash_type; /* enum ec_vboot_hash_type */ + uint8_t nonce_size; /* Nonce size; may be 0 */ + uint8_t reserved0; /* Reserved; set 0 */ + uint32_t offset; /* Offset in flash to hash */ + uint32_t size; /* Number of bytes to hash */ + uint8_t nonce_data[64]; /* Nonce data; ignored if nonce_size=0 */ +} __packed; + +struct ec_response_vboot_hash { + uint8_t status; /* enum ec_vboot_hash_status */ + uint8_t hash_type; /* enum ec_vboot_hash_type */ + uint8_t digest_size; /* Size of hash digest in bytes */ + uint8_t reserved0; /* Ignore; will be 0 */ + uint32_t offset; /* Offset in flash which was hashed */ + uint32_t size; /* Number of bytes hashed */ + uint8_t hash_digest[64]; /* Hash digest data */ +} __packed; + +enum ec_vboot_hash_cmd { + EC_VBOOT_HASH_GET = 0, /* Get current hash status */ + EC_VBOOT_HASH_ABORT = 1, /* Abort calculating current hash */ + EC_VBOOT_HASH_START = 2, /* Start computing a new hash */ + EC_VBOOT_HASH_RECALC = 3, /* Synchronously compute a new hash */ +}; + +enum ec_vboot_hash_type { + EC_VBOOT_HASH_TYPE_SHA256 = 0, /* SHA-256 */ +}; + +enum ec_vboot_hash_status { + EC_VBOOT_HASH_STATUS_NONE = 0, /* No hash (not started, or aborted) */ + EC_VBOOT_HASH_STATUS_DONE = 1, /* Finished computing a hash */ + EC_VBOOT_HASH_STATUS_BUSY = 2, /* Busy computing a hash */ +}; + +/* + * Special values for offset for EC_VBOOT_HASH_START and EC_VBOOT_HASH_RECALC. + * If one of these is specified, the EC will automatically update offset and + * size to the correct values for the specified image (RO or RW). + */ +#define EC_VBOOT_HASH_OFFSET_RO 0xfffffffe +#define EC_VBOOT_HASH_OFFSET_RW 0xfffffffd + +/*****************************************************************************/ +/* USB charging control commands */ + +/* Set USB port charging mode */ +#define EC_CMD_USB_CHARGE_SET_MODE 0x30 + +struct ec_params_usb_charge_set_mode { + uint8_t usb_port_id; + uint8_t mode; +} __packed; + +/*****************************************************************************/ +/* Persistent storage for host */ + +/* Maximum bytes that can be read/written in a single command */ +#define EC_PSTORE_SIZE_MAX 64 + +/* Get persistent storage info */ +#define EC_CMD_PSTORE_INFO 0x40 + +struct ec_response_pstore_info { + /* Persistent storage size, in bytes */ + uint32_t pstore_size; + /* Access size; read/write offset and size must be a multiple of this */ + uint32_t access_size; +} __packed; + +/* + * Read persistent storage + * + * Response is params.size bytes of data. + */ +#define EC_CMD_PSTORE_READ 0x41 + +struct ec_params_pstore_read { + uint32_t offset; /* Byte offset to read */ + uint32_t size; /* Size to read in bytes */ +} __packed; + +/* Write persistent storage */ +#define EC_CMD_PSTORE_WRITE 0x42 + +struct ec_params_pstore_write { + uint32_t offset; /* Byte offset to write */ + uint32_t size; /* Size to write in bytes */ + uint8_t data[EC_PSTORE_SIZE_MAX]; +} __packed; + +/*****************************************************************************/ +/* Real-time clock */ + +/* RTC params and response structures */ +struct ec_params_rtc { + uint32_t time; +} __packed; + +struct ec_response_rtc { + uint32_t time; +} __packed; + +/* These use ec_response_rtc */ +#define EC_CMD_RTC_GET_VALUE 0x44 +#define EC_CMD_RTC_GET_ALARM 0x45 + +/* These all use ec_params_rtc */ +#define EC_CMD_RTC_SET_VALUE 0x46 +#define EC_CMD_RTC_SET_ALARM 0x47 + +/*****************************************************************************/ +/* Port80 log access */ + +/* Get last port80 code from previous boot */ +#define EC_CMD_PORT80_LAST_BOOT 0x48 + +struct ec_response_port80_last_boot { + uint16_t code; +} __packed; + +/*****************************************************************************/ +/* Thermal engine commands */ + +/* Set thershold value */ +#define EC_CMD_THERMAL_SET_THRESHOLD 0x50 + +struct ec_params_thermal_set_threshold { + uint8_t sensor_type; + uint8_t threshold_id; + uint16_t value; +} __packed; + +/* Get threshold value */ +#define EC_CMD_THERMAL_GET_THRESHOLD 0x51 + +struct ec_params_thermal_get_threshold { + uint8_t sensor_type; + uint8_t threshold_id; +} __packed; + +struct ec_response_thermal_get_threshold { + uint16_t value; +} __packed; + +/* Toggle automatic fan control */ +#define EC_CMD_THERMAL_AUTO_FAN_CTRL 0x52 + +/* Get TMP006 calibration data */ +#define EC_CMD_TMP006_GET_CALIBRATION 0x53 + +struct ec_params_tmp006_get_calibration { + uint8_t index; +} __packed; + +struct ec_response_tmp006_get_calibration { + float s0; + float b0; + float b1; + float b2; +} __packed; + +/* Set TMP006 calibration data */ +#define EC_CMD_TMP006_SET_CALIBRATION 0x54 + +struct ec_params_tmp006_set_calibration { + uint8_t index; + uint8_t reserved[3]; /* Reserved; set 0 */ + float s0; + float b0; + float b1; + float b2; +} __packed; + +/*****************************************************************************/ +/* CROS_EC - Matrix KeyBoard Protocol */ + +/* + * Read key state + * + * Returns raw data for keyboard cols; see ec_response_cros_ec_info.cols for + * expected response size. + */ +#define EC_CMD_CROS_EC_STATE 0x60 + +/* Provide information about the matrix : number of rows and columns */ +#define EC_CMD_CROS_EC_INFO 0x61 + +struct ec_response_cros_ec_info { + uint32_t rows; + uint32_t cols; + uint8_t switches; +} __packed; + +/* Simulate key press */ +#define EC_CMD_CROS_EC_SIMULATE_KEY 0x62 + +struct ec_params_cros_ec_simulate_key { + uint8_t col; + uint8_t row; + uint8_t pressed; +} __packed; + +/* Configure keyboard scanning */ +#define EC_CMD_CROS_EC_SET_CONFIG 0x64 +#define EC_CMD_CROS_EC_GET_CONFIG 0x65 + +/* flags */ +enum cros_ec_config_flags { + EC_CROS_EC_FLAGS_ENABLE = 1, /* Enable keyboard scanning */ +}; + +enum cros_ec_config_valid { + EC_CROS_EC_VALID_SCAN_PERIOD = 1 << 0, + EC_CROS_EC_VALID_POLL_TIMEOUT = 1 << 1, + EC_CROS_EC_VALID_MIN_POST_SCAN_DELAY = 1 << 3, + EC_CROS_EC_VALID_OUTPUT_SETTLE = 1 << 4, + EC_CROS_EC_VALID_DEBOUNCE_DOWN = 1 << 5, + EC_CROS_EC_VALID_DEBOUNCE_UP = 1 << 6, + EC_CROS_EC_VALID_FIFO_MAX_DEPTH = 1 << 7, +}; + +/* Configuration for our key scanning algorithm */ +struct ec_cros_ec_config { + uint32_t valid_mask; /* valid fields */ + uint8_t flags; /* some flags (enum cros_ec_config_flags) */ + uint8_t valid_flags; /* which flags are valid */ + uint16_t scan_period_us; /* period between start of scans */ + /* revert to interrupt mode after no activity for this long */ + uint32_t poll_timeout_us; + /* + * minimum post-scan relax time. Once we finish a scan we check + * the time until we are due to start the next one. If this time is + * shorter this field, we use this instead. + */ + uint16_t min_post_scan_delay_us; + /* delay between setting up output and waiting for it to settle */ + uint16_t output_settle_us; + uint16_t debounce_down_us; /* time for debounce on key down */ + uint16_t debounce_up_us; /* time for debounce on key up */ + /* maximum depth to allow for fifo (0 = no keyscan output) */ + uint8_t fifo_max_depth; +} __packed; + +struct ec_params_cros_ec_set_config { + struct ec_cros_ec_config config; +} __packed; + +struct ec_response_cros_ec_get_config { + struct ec_cros_ec_config config; +} __packed; + +/* Run the key scan emulation */ +#define EC_CMD_KEYSCAN_SEQ_CTRL 0x66 + +enum ec_keyscan_seq_cmd { + EC_KEYSCAN_SEQ_STATUS = 0, /* Get status information */ + EC_KEYSCAN_SEQ_CLEAR = 1, /* Clear sequence */ + EC_KEYSCAN_SEQ_ADD = 2, /* Add item to sequence */ + EC_KEYSCAN_SEQ_START = 3, /* Start running sequence */ + EC_KEYSCAN_SEQ_COLLECT = 4, /* Collect sequence summary data */ +}; + +enum ec_collect_flags { + /* + * Indicates this scan was processed by the EC. Due to timing, some + * scans may be skipped. + */ + EC_KEYSCAN_SEQ_FLAG_DONE = 1 << 0, +}; + +struct ec_collect_item { + uint8_t flags; /* some flags (enum ec_collect_flags) */ +}; + +struct ec_params_keyscan_seq_ctrl { + uint8_t cmd; /* Command to send (enum ec_keyscan_seq_cmd) */ + union { + struct { + uint8_t active; /* still active */ + uint8_t num_items; /* number of items */ + /* Current item being presented */ + uint8_t cur_item; + } status; + struct { + /* + * Absolute time for this scan, measured from the + * start of the sequence. + */ + uint32_t time_us; + uint8_t scan[0]; /* keyscan data */ + } add; + struct { + uint8_t start_item; /* First item to return */ + uint8_t num_items; /* Number of items to return */ + } collect; + }; +} __packed; + +struct ec_result_keyscan_seq_ctrl { + union { + struct { + uint8_t num_items; /* Number of items */ + /* Data for each item */ + struct ec_collect_item item[0]; + } collect; + }; +} __packed; + +/*****************************************************************************/ +/* Temperature sensor commands */ + +/* Read temperature sensor info */ +#define EC_CMD_TEMP_SENSOR_GET_INFO 0x70 + +struct ec_params_temp_sensor_get_info { + uint8_t id; +} __packed; + +struct ec_response_temp_sensor_get_info { + char sensor_name[32]; + uint8_t sensor_type; +} __packed; + +/*****************************************************************************/ + +/* + * Note: host commands 0x80 - 0x87 are reserved to avoid conflict with ACPI + * commands accidentally sent to the wrong interface. See the ACPI section + * below. + */ + +/*****************************************************************************/ +/* Host event commands */ + +/* + * Host event mask params and response structures, shared by all of the host + * event commands below. + */ +struct ec_params_host_event_mask { + uint32_t mask; +} __packed; + +struct ec_response_host_event_mask { + uint32_t mask; +} __packed; + +/* These all use ec_response_host_event_mask */ +#define EC_CMD_HOST_EVENT_GET_B 0x87 +#define EC_CMD_HOST_EVENT_GET_SMI_MASK 0x88 +#define EC_CMD_HOST_EVENT_GET_SCI_MASK 0x89 +#define EC_CMD_HOST_EVENT_GET_WAKE_MASK 0x8d + +/* These all use ec_params_host_event_mask */ +#define EC_CMD_HOST_EVENT_SET_SMI_MASK 0x8a +#define EC_CMD_HOST_EVENT_SET_SCI_MASK 0x8b +#define EC_CMD_HOST_EVENT_CLEAR 0x8c +#define EC_CMD_HOST_EVENT_SET_WAKE_MASK 0x8e +#define EC_CMD_HOST_EVENT_CLEAR_B 0x8f + +/*****************************************************************************/ +/* Switch commands */ + +/* Enable/disable LCD backlight */ +#define EC_CMD_SWITCH_ENABLE_BKLIGHT 0x90 + +struct ec_params_switch_enable_backlight { + uint8_t enabled; +} __packed; + +/* Enable/disable WLAN/Bluetooth */ +#define EC_CMD_SWITCH_ENABLE_WIRELESS 0x91 + +struct ec_params_switch_enable_wireless { + uint8_t enabled; +} __packed; + +/*****************************************************************************/ +/* GPIO commands. Only available on EC if write protect has been disabled. */ + +/* Set GPIO output value */ +#define EC_CMD_GPIO_SET 0x92 + +struct ec_params_gpio_set { + char name[32]; + uint8_t val; +} __packed; + +/* Get GPIO value */ +#define EC_CMD_GPIO_GET 0x93 + +struct ec_params_gpio_get { + char name[32]; +} __packed; +struct ec_response_gpio_get { + uint8_t val; +} __packed; + +/*****************************************************************************/ +/* I2C commands. Only available when flash write protect is unlocked. */ + +/* Read I2C bus */ +#define EC_CMD_I2C_READ 0x94 + +struct ec_params_i2c_read { + uint16_t addr; + uint8_t read_size; /* Either 8 or 16. */ + uint8_t port; + uint8_t offset; +} __packed; +struct ec_response_i2c_read { + uint16_t data; +} __packed; + +/* Write I2C bus */ +#define EC_CMD_I2C_WRITE 0x95 + +struct ec_params_i2c_write { + uint16_t data; + uint16_t addr; + uint8_t write_size; /* Either 8 or 16. */ + uint8_t port; + uint8_t offset; +} __packed; + +/*****************************************************************************/ +/* Charge state commands. Only available when flash write protect unlocked. */ + +/* Force charge state machine to stop in idle mode */ +#define EC_CMD_CHARGE_FORCE_IDLE 0x96 + +struct ec_params_force_idle { + uint8_t enabled; +} __packed; + +/*****************************************************************************/ +/* Console commands. Only available when flash write protect is unlocked. */ + +/* Snapshot console output buffer for use by EC_CMD_CONSOLE_READ. */ +#define EC_CMD_CONSOLE_SNAPSHOT 0x97 + +/* + * Read next chunk of data from saved snapshot. + * + * Response is null-terminated string. Empty string, if there is no more + * remaining output. + */ +#define EC_CMD_CONSOLE_READ 0x98 + +/*****************************************************************************/ + +/* + * Cut off battery power output if the battery supports. + * + * For unsupported battery, just don't implement this command and lets EC + * return EC_RES_INVALID_COMMAND. + */ +#define EC_CMD_BATTERY_CUT_OFF 0x99 + +/*****************************************************************************/ +/* USB port mux control. */ + +/* + * Switch USB mux or return to automatic switching. + */ +#define EC_CMD_USB_MUX 0x9a + +struct ec_params_usb_mux { + uint8_t mux; +} __packed; + +/*****************************************************************************/ +/* LDOs / FETs control. */ + +enum ec_ldo_state { + EC_LDO_STATE_OFF = 0, /* the LDO / FET is shut down */ + EC_LDO_STATE_ON = 1, /* the LDO / FET is ON / providing power */ +}; + +/* + * Switch on/off a LDO. + */ +#define EC_CMD_LDO_SET 0x9b + +struct ec_params_ldo_set { + uint8_t index; + uint8_t state; +} __packed; + +/* + * Get LDO state. + */ +#define EC_CMD_LDO_GET 0x9c + +struct ec_params_ldo_get { + uint8_t index; +} __packed; + +struct ec_response_ldo_get { + uint8_t state; +} __packed; + +/*****************************************************************************/ +/* Temporary debug commands. TODO: remove this crosbug.com/p/13849 */ + +/* + * Dump charge state machine context. + * + * Response is a binary dump of charge state machine context. + */ +#define EC_CMD_CHARGE_DUMP 0xa0 + +/* + * Set maximum battery charging current. + */ +#define EC_CMD_CHARGE_CURRENT_LIMIT 0xa1 + +struct ec_params_current_limit { + uint32_t limit; +} __packed; + +/*****************************************************************************/ +/* Smart battery pass-through */ + +/* Get / Set 16-bit smart battery registers */ +#define EC_CMD_SB_READ_WORD 0xb0 +#define EC_CMD_SB_WRITE_WORD 0xb1 + +/* Get / Set string smart battery parameters + * formatted as SMBUS "block". + */ +#define EC_CMD_SB_READ_BLOCK 0xb2 +#define EC_CMD_SB_WRITE_BLOCK 0xb3 + +struct ec_params_sb_rd { + uint8_t reg; +} __packed; + +struct ec_response_sb_rd_word { + uint16_t value; +} __packed; + +struct ec_params_sb_wr_word { + uint8_t reg; + uint16_t value; +} __packed; + +struct ec_response_sb_rd_block { + uint8_t data[32]; +} __packed; + +struct ec_params_sb_wr_block { + uint8_t reg; + uint16_t data[32]; +} __packed; + +/*****************************************************************************/ +/* System commands */ + +/* + * TODO: this is a confusing name, since it doesn't necessarily reboot the EC. + * Rename to "set image" or something similar. + */ +#define EC_CMD_REBOOT_EC 0xd2 + +/* Command */ +enum ec_reboot_cmd { + EC_REBOOT_CANCEL = 0, /* Cancel a pending reboot */ + EC_REBOOT_JUMP_RO = 1, /* Jump to RO without rebooting */ + EC_REBOOT_JUMP_RW = 2, /* Jump to RW without rebooting */ + /* (command 3 was jump to RW-B) */ + EC_REBOOT_COLD = 4, /* Cold-reboot */ + EC_REBOOT_DISABLE_JUMP = 5, /* Disable jump until next reboot */ + EC_REBOOT_HIBERNATE = 6 /* Hibernate EC */ +}; + +/* Flags for ec_params_reboot_ec.reboot_flags */ +#define EC_REBOOT_FLAG_RESERVED0 (1 << 0) /* Was recovery request */ +#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1) /* Reboot after AP shutdown */ + +struct ec_params_reboot_ec { + uint8_t cmd; /* enum ec_reboot_cmd */ + uint8_t flags; /* See EC_REBOOT_FLAG_* */ +} __packed; + +/* + * Get information on last EC panic. + * + * Returns variable-length platform-dependent panic information. See panic.h + * for details. + */ +#define EC_CMD_GET_PANIC_INFO 0xd3 + +/*****************************************************************************/ +/* + * ACPI commands + * + * These are valid ONLY on the ACPI command/data port. + */ + +/* + * ACPI Read Embedded Controller + * + * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). + * + * Use the following sequence: + * + * - Write EC_CMD_ACPI_READ to EC_LPC_ADDR_ACPI_CMD + * - Wait for EC_LPC_CMDR_PENDING bit to clear + * - Write address to EC_LPC_ADDR_ACPI_DATA + * - Wait for EC_LPC_CMDR_DATA bit to set + * - Read value from EC_LPC_ADDR_ACPI_DATA + */ +#define EC_CMD_ACPI_READ 0x80 + +/* + * ACPI Write Embedded Controller + * + * This reads from ACPI memory space on the EC (EC_ACPI_MEM_*). + * + * Use the following sequence: + * + * - Write EC_CMD_ACPI_WRITE to EC_LPC_ADDR_ACPI_CMD + * - Wait for EC_LPC_CMDR_PENDING bit to clear + * - Write address to EC_LPC_ADDR_ACPI_DATA + * - Wait for EC_LPC_CMDR_PENDING bit to clear + * - Write value to EC_LPC_ADDR_ACPI_DATA + */ +#define EC_CMD_ACPI_WRITE 0x81 + +/* + * ACPI Query Embedded Controller + * + * This clears the lowest-order bit in the currently pending host events, and + * sets the result code to the 1-based index of the bit (event 0x00000001 = 1, + * event 0x80000000 = 32), or 0 if no event was pending. + */ +#define EC_CMD_ACPI_QUERY_EVENT 0x84 + +/* Valid addresses in ACPI memory space, for read/write commands */ +/* Memory space version; set to EC_ACPI_MEM_VERSION_CURRENT */ +#define EC_ACPI_MEM_VERSION 0x00 +/* + * Test location; writing value here updates test compliment byte to (0xff - + * value). + */ +#define EC_ACPI_MEM_TEST 0x01 +/* Test compliment; writes here are ignored. */ +#define EC_ACPI_MEM_TEST_COMPLIMENT 0x02 +/* Keyboard backlight brightness percent (0 - 100) */ +#define EC_ACPI_MEM_KEYBOARD_BACKLIGHT 0x03 + +/* Current version of ACPI memory address space */ +#define EC_ACPI_MEM_VERSION_CURRENT 1 + + +/*****************************************************************************/ +/* + * Special commands + * + * These do not follow the normal rules for commands. See each command for + * details. + */ + +/* + * Reboot NOW + * + * This command will work even when the EC LPC interface is busy, because the + * reboot command is processed at interrupt level. Note that when the EC + * reboots, the host will reboot too, so there is no response to this command. + * + * Use EC_CMD_REBOOT_EC to reboot the EC more politely. + */ +#define EC_CMD_REBOOT 0xd1 /* Think "die" */ + +/* + * Resend last response (not supported on LPC). + * + * Returns EC_RES_UNAVAILABLE if there is no response available - for example, + * there was no previous command, or the previous command's response was too + * big to save. + */ +#define EC_CMD_RESEND_RESPONSE 0xdb + +/* + * This header byte on a command indicate version 0. Any header byte less + * than this means that we are talking to an old EC which doesn't support + * versioning. In that case, we assume version 0. + * + * Header bytes greater than this indicate a later version. For example, + * EC_CMD_VERSION0 + 1 means we are using version 1. + * + * The old EC interface must not use commands 0dc or higher. + */ +#define EC_CMD_VERSION0 0xdc + +#endif /* !__ACPI__ */ + +#endif /* __CROS_EC_COMMANDS_H */ diff --git a/include/environment.h b/include/environment.h index 4c6a37b..460ccb4 100644 --- a/include/environment.h +++ b/include/environment.h @@ -75,6 +75,12 @@ # endif #endif /* CONFIG_ENV_IS_IN_FLASH */ +#if defined(CONFIG_ENV_IS_IN_MMC) +# ifdef CONFIG_ENV_OFFSET_REDUND +# define CONFIG_SYS_REDUNDAND_ENVIRONMENT +# endif +#endif + #if defined(CONFIG_ENV_IS_IN_NAND) # if defined(CONFIG_ENV_OFFSET_OOB) # ifdef CONFIG_ENV_OFFSET_REDUND diff --git a/include/fdtdec.h b/include/fdtdec.h index 818ddde..bdefda4 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -86,6 +86,8 @@ enum fdt_compat_id { COMPAT_SAMSUNG_EXYNOS5_SOUND, /* Exynos Sound */ COMPAT_WOLFSON_WM8994_CODEC, /* Wolfson WM8994 Sound Codec */ COMPAT_SAMSUNG_EXYNOS_SPI, /* Exynos SPI */ + COMPAT_GOOGLE_CROS_EC, /* Google CROS_EC Protocol */ + COMPAT_GOOGLE_CROS_EC_KEYB, /* Google CROS_EC Keyboard */ COMPAT_SAMSUNG_EXYNOS_EHCI, /* Exynos EHCI controller */ COMPAT_SAMSUNG_EXYNOS_USB_PHY, /* Exynos phy controller for usb2.0 */ COMPAT_SAMSUNG_EXYNOS_TMU, /* Exynos TMU */ @@ -97,6 +99,7 @@ enum fdt_compat_id { COMPAT_GENERIC_SPI_FLASH, /* Generic SPI Flash chip */ COMPAT_MAXIM_98095_CODEC, /* MAX98095 Codec */ COMPAT_INFINEON_SLB9635_TPM, /* Infineon SLB9635 TPM */ + COMPAT_INFINEON_SLB9645_TPM, /* Infineon SLB9645 TPM */ COMPAT_COUNT, }; diff --git a/include/g_dnl.h b/include/g_dnl.h index f47395f..f8affd8 100644 --- a/include/g_dnl.h +++ b/include/g_dnl.h @@ -23,7 +23,7 @@ #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> - +int g_dnl_bind_fixup(struct usb_device_descriptor *); int g_dnl_register(const char *s); void g_dnl_unregister(void); diff --git a/include/ide.h b/include/ide.h index afea85c..f691a74 100644 --- a/include/ide.h +++ b/include/ide.h @@ -54,8 +54,9 @@ typedef ulong lbaint_t; */ void ide_init(void); -ulong ide_read(int device, ulong blknr, lbaint_t blkcnt, void *buffer); -ulong ide_write(int device, ulong blknr, lbaint_t blkcnt, const void *buffer); +ulong ide_read(int device, lbaint_t blknr, lbaint_t blkcnt, void *buffer); +ulong ide_write(int device, lbaint_t blknr, lbaint_t blkcnt, + const void *buffer); #ifdef CONFIG_IDE_PREINIT int ide_preinit(void); diff --git a/include/image.h b/include/image.h index b8cc523..7b0108f 100644 --- a/include/image.h +++ b/include/image.h @@ -320,13 +320,16 @@ typedef struct bootm_headers { int verify; /* getenv("verify")[0] != 'n' */ #define BOOTM_STATE_START (0x00000001) -#define BOOTM_STATE_LOADOS (0x00000002) -#define BOOTM_STATE_RAMDISK (0x00000004) -#define BOOTM_STATE_FDT (0x00000008) -#define BOOTM_STATE_OS_CMDLINE (0x00000010) -#define BOOTM_STATE_OS_BD_T (0x00000020) -#define BOOTM_STATE_OS_PREP (0x00000040) -#define BOOTM_STATE_OS_GO (0x00000080) +#define BOOTM_STATE_FINDOS (0x00000002) +#define BOOTM_STATE_FINDOTHER (0x00000004) +#define BOOTM_STATE_LOADOS (0x00000008) +#define BOOTM_STATE_RAMDISK (0x00000010) +#define BOOTM_STATE_FDT (0x00000020) +#define BOOTM_STATE_OS_CMDLINE (0x00000040) +#define BOOTM_STATE_OS_BD_T (0x00000080) +#define BOOTM_STATE_OS_PREP (0x00000100) +#define BOOTM_STATE_OS_FAKE_GO (0x00000200) /* 'Almost' run the OS */ +#define BOOTM_STATE_OS_GO (0x00000400) int state; #ifdef CONFIG_LMB @@ -402,6 +405,13 @@ void genimg_print_size(uint32_t size); #endif void genimg_print_time(time_t timestamp); +/* What to do with a image load address ('load = <> 'in the FIT) */ +enum fit_load_op { + FIT_LOAD_IGNORED, /* Ignore load address */ + FIT_LOAD_OPTIONAL, /* Can be provided, but optional */ + FIT_LOAD_REQUIRED, /* Must be provided */ +}; + #ifndef USE_HOSTCC /* Image format types, returned by _get_format() routine */ #define IMAGE_FORMAT_INVALID 0x00 @@ -415,8 +425,72 @@ ulong genimg_get_image(ulong img_addr); int boot_get_ramdisk(int argc, char * const argv[], bootm_headers_t *images, uint8_t arch, ulong *rd_start, ulong *rd_end); -int boot_get_fdt(int flag, int argc, char * const argv[], - bootm_headers_t *images, char **of_flat_tree, ulong *of_size); +/** + * fit_image_load() - load an image from a FIT + * + * This deals with all aspects of loading an image from a FIT, including + * selecting the right image based on configuration, verifying it, printing + * out progress messages, checking the type/arch/os and optionally copying it + * to the right load address. + * + * @param images Boot images structure + * @param prop_name Property name to look up (FIT_..._PROP) + * @param addr Address of FIT in memory + * @param fit_unamep On entry this is the requested image name + * (e.g. "kernel@1") or NULL to use the default. On exit + * points to the selected image name + * @param fit_uname_configp On entry this is the requested configuration + * name (e.g. "conf@1") or NULL to use the default. On + * exit points to the selected configuration name. + * @param arch Expected architecture (IH_ARCH_...) + * @param image_type Required image type (IH_TYPE_...). If this is + * IH_TYPE_KERNEL then we allow IH_TYPE_KERNEL_NOLOAD + * also. + * @param bootstage_id ID of starting bootstage to use for progress updates. + * This will be added to the BOOTSTAGE_SUB values when + * calling bootstage_mark() + * @param load_op Decribes what to do with the load address + * @param datap Returns address of loaded image + * @param lenp Returns length of loaded image + */ +int fit_image_load(bootm_headers_t *images, const char *prop_name, ulong addr, + const char **fit_unamep, const char **fit_uname_configp, + int arch, int image_type, int bootstage_id, + enum fit_load_op load_op, ulong *datap, ulong *lenp); + +/** + * fit_get_node_from_config() - Look up an image a FIT by type + * + * This looks in the selected conf@ node (images->fit_uname_cfg) for a + * particular image type (e.g. "kernel") and then finds the image that is + * referred to. + * + * For example, for something like: + * + * images { + * kernel@1 { + * ... + * }; + * }; + * configurations { + * conf@1 { + * kernel = "kernel@1"; + * }; + * }; + * + * the function will return the node offset of the kernel@1 node, assuming + * that conf@1 is the chosen configuration. + * + * @param images Boot images structure + * @param prop_name Property name to look up (FIT_..._PROP) + * @param addr Address of FIT in memory + */ +int fit_get_node_from_config(bootm_headers_t *images, const char *prop_name, + ulong addr); + +int boot_get_fdt(int flag, int argc, char * const argv[], uint8_t arch, + bootm_headers_t *images, + char **of_flat_tree, ulong *of_size); void boot_fdt_add_mem_rsv_regions(struct lmb *lmb, void *fdt_blob); int boot_relocate_fdt(struct lmb *lmb, char **of_flat_tree, ulong *of_size); @@ -589,6 +663,17 @@ int image_setup_libfdt(bootm_headers_t *images, void *blob, */ int image_setup_linux(bootm_headers_t *images); +/** + * bootz_setup() - Extract stat and size of a Linux xImage + * + * @image: Address of image + * @start: Returns start address of image + * @end : Returns end address of image + * @return 0 if OK, 1 if the image was not recognised + */ +int bootz_setup(ulong image, ulong *start, ulong *end); + + /*******************************************************************/ /* New uImage format specific code (prefixed with fit_) */ /*******************************************************************/ @@ -597,11 +682,12 @@ int image_setup_linux(bootm_headers_t *images); #define FIT_IMAGES_PATH "/images" #define FIT_CONFS_PATH "/configurations" -/* hash node */ +/* hash/signature node */ #define FIT_HASH_NODENAME "hash" #define FIT_ALGO_PROP "algo" #define FIT_VALUE_PROP "value" #define FIT_IGNORE_PROP "uboot-ignore" +#define FIT_SIG_NODENAME "signature" /* image node */ #define FIT_DATA_PROP "data" @@ -689,14 +775,29 @@ int fit_image_hash_get_value(const void *fit, int noffset, uint8_t **value, int fit_set_timestamp(void *fit, int noffset, time_t timestamp); /** - * fit_add_verification_data() - Calculate and add hashes to FIT + * fit_add_verification_data() - add verification data to FIT image nodes * - * @fit: Fit image to process - * @return 0 if ok, <0 for error + * @keydir: Directory containing keys + * @kwydest: FDT blob to write public key information to + * @fit: Pointer to the FIT format image header + * @comment: Comment to add to signature nodes + * @require_keys: Mark all keys as 'required' + * + * Adds hash values for all component images in the FIT blob. + * Hashes are calculated for all component images which have hash subnodes + * with algorithm property set to one of the supported hash algorithms. + * + * Also add signatures if signature nodes are present. + * + * returns + * 0, on success + * libfdt error code, on failure */ -int fit_add_verification_data(void *fit); +int fit_add_verification_data(const char *keydir, void *keydest, void *fit, + const char *comment, int require_keys); int fit_image_verify(const void *fit, int noffset); +int fit_config_verify(const void *fit, int conf_noffset); int fit_all_image_verify(const void *fit); int fit_image_check_os(const void *fit, int noffset, uint8_t os); int fit_image_check_arch(const void *fit, int noffset, uint8_t arch); @@ -706,9 +807,6 @@ int fit_check_format(const void *fit); int fit_conf_find_compat(const void *fit, const void *fdt); int fit_conf_get_node(const void *fit, const char *conf_uname); -int fit_conf_get_kernel_node(const void *fit, int noffset); -int fit_conf_get_ramdisk_node(const void *fit, int noffset); -int fit_conf_get_fdt_node(const void *fit, int noffset); /** * fit_conf_get_prop_node() - Get node refered to by a configuration @@ -732,12 +830,170 @@ int fit_check_ramdisk(const void *fit, int os_noffset, int calculate_hash(const void *data, int data_len, const char *algo, uint8_t *value, int *value_len); -#ifndef USE_HOSTCC +/* + * At present we only support signing on the host, and verification on the + * device + */ +#if defined(CONFIG_FIT_SIGNATURE) +# ifdef USE_HOSTCC +# define IMAGE_ENABLE_SIGN 1 +# define IMAGE_ENABLE_VERIFY 0 +#else +# define IMAGE_ENABLE_SIGN 0 +# define IMAGE_ENABLE_VERIFY 1 +# endif +#else +# define IMAGE_ENABLE_SIGN 0 +# define IMAGE_ENABLE_VERIFY 0 +#endif + +#ifdef USE_HOSTCC +# define gd_fdt_blob() NULL +#else +# define gd_fdt_blob() (gd->fdt_blob) +#endif + +#ifdef CONFIG_FIT_BEST_MATCH +#define IMAGE_ENABLE_BEST_MATCH 1 +#else +#define IMAGE_ENABLE_BEST_MATCH 0 +#endif + +/* Information passed to the signing routines */ +struct image_sign_info { + const char *keydir; /* Directory conaining keys */ + const char *keyname; /* Name of key to use */ + void *fit; /* Pointer to FIT blob */ + int node_offset; /* Offset of signature node */ + struct image_sig_algo *algo; /* Algorithm information */ + const void *fdt_blob; /* FDT containing public keys */ + int required_keynode; /* Node offset of key to use: -1=any */ + const char *require_keys; /* Value for 'required' property */ +}; + +/* A part of an image, used for hashing */ +struct image_region { + const void *data; + int size; +}; + +struct image_sig_algo { + const char *name; /* Name of algorithm */ + + /** + * sign() - calculate and return signature for given input data + * + * @info: Specifies key and FIT information + * @data: Pointer to the input data + * @data_len: Data length + * @sigp: Set to an allocated buffer holding the signature + * @sig_len: Set to length of the calculated hash + * + * This computes input data signature according to selected algorithm. + * Resulting signature value is placed in an allocated buffer, the + * pointer is returned as *sigp. The length of the calculated + * signature is returned via the sig_len pointer argument. The caller + * should free *sigp. + * + * @return: 0, on success, -ve on error + */ + int (*sign)(struct image_sign_info *info, + const struct image_region region[], + int region_count, uint8_t **sigp, uint *sig_len); + + /** + * add_verify_data() - Add verification information to FDT + * + * Add public key information to the FDT node, suitable for + * verification at run-time. The information added depends on the + * algorithm being used. + * + * @info: Specifies key and FIT information + * @keydest: Destination FDT blob for public key data + * @return: 0, on success, -ve on error + */ + int (*add_verify_data)(struct image_sign_info *info, void *keydest); + + /** + * verify() - Verify a signature against some data + * + * @info: Specifies key and FIT information + * @data: Pointer to the input data + * @data_len: Data length + * @sig: Signature + * @sig_len: Number of bytes in signature + * @return 0 if verified, -ve on error + */ + int (*verify)(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t *sig, uint sig_len); +}; + +/** + * image_get_sig_algo() - Look up a signature algortihm + * + * @param name Name of algorithm + * @return pointer to algorithm information, or NULL if not found + */ +struct image_sig_algo *image_get_sig_algo(const char *name); + +/** + * fit_image_verify_required_sigs() - Verify signatures marked as 'required' + * + * @fit: FIT to check + * @image_noffset: Offset of image node to check + * @data: Image data to check + * @size: Size of image data + * @sig_blob: FDT containing public keys + * @no_sigsp: Returns 1 if no signatures were required, and + * therefore nothing was checked. The caller may wish + * to fall back to other mechanisms, or refuse to + * boot. + * @return 0 if all verified ok, <0 on error + */ +int fit_image_verify_required_sigs(const void *fit, int image_noffset, + const char *data, size_t size, const void *sig_blob, + int *no_sigsp); + +/** + * fit_image_check_sig() - Check a single image signature node + * + * @fit: FIT to check + * @noffset: Offset of signature node to check + * @data: Image data to check + * @size: Size of image data + * @required_keynode: Offset in the control FDT of the required key node, + * if any. If this is given, then the image wil not + * pass verification unless that key is used. If this is + * -1 then any signature will do. + * @err_msgp: In the event of an error, this will be pointed to a + * help error string to display to the user. + * @return 0 if all verified ok, <0 on error + */ +int fit_image_check_sig(const void *fit, int noffset, const void *data, + size_t size, int required_keynode, char **err_msgp); + +/** + * fit_region_make_list() - Make a list of regions to hash + * + * Given a list of FIT regions (offset, size) provided by libfdt, create + * a list of regions (void *, size) for use by the signature creationg + * and verification code. + * + * @fit: FIT image to process + * @fdt_regions: Regions as returned by libfdt + * @count: Number of regions returned by libfdt + * @region: Place to put list of regions (NULL to allocate it) + * @return pointer to list of regions, or NULL if out of memory + */ +struct image_region *fit_region_make_list(const void *fit, + struct fdt_region *fdt_regions, int count, + struct image_region *region); + static inline int fit_image_check_target_arch(const void *fdt, int node) { return fit_image_check_arch(fdt, node, IH_ARCH_DEFAULT); } -#endif /* USE_HOSTCC */ #ifdef CONFIG_FIT_VERBOSE #define fit_unsupported(msg) printf("! %s:%d " \ diff --git a/include/lcd.h b/include/lcd.h index c6e7fc5..8718a01 100644 --- a/include/lcd.h +++ b/include/lcd.h @@ -37,7 +37,6 @@ extern struct vidinfo panel_info; void lcd_ctrl_init(void *lcdbase); void lcd_enable(void); -int board_splash_screen_prepare(void); /* setcolreg used in 8bpp/16bpp; initcolregs used in monochrome */ void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue); @@ -46,7 +45,8 @@ void lcd_initcolregs(void); int lcd_getfgcolor(void); /* gunzip_bmp used if CONFIG_VIDEO_BMP_GZIP */ -struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp); +struct bmp_image *gunzip_bmp(unsigned long addr, unsigned long *lenp, + void **alloc_addr); int bmp_display(ulong addr, int x, int y); /** @@ -324,6 +324,9 @@ void lcd_show_board_info(void); /* Return the size of the LCD frame buffer, and the line length */ int lcd_get_size(int *line_length); +int lcd_dt_simplefb_add_node(void *blob); +int lcd_dt_simplefb_enable_existing_node(void *blob); + /************************************************************************/ /* ** BITMAP DISPLAY SUPPORT */ /************************************************************************/ diff --git a/include/libfdt.h b/include/libfdt.h index c5ec2ac..765d84f 100644 --- a/include/libfdt.h +++ b/include/libfdt.h @@ -1511,4 +1511,68 @@ int fdt_del_node(void *fdt, int nodeoffset); const char *fdt_strerror(int errval); +struct fdt_region { + int offset; + int size; +}; + +/** + * fdt_find_regions() - find regions in device tree + * + * Given a list of nodes to include and properties to exclude, find + * the regions of the device tree which describe those included parts. + * + * The intent is to get a list of regions which will be invariant provided + * those parts are invariant. For example, if you request a list of regions + * for all nodes but exclude the property "data", then you will get the + * same region contents regardless of any change to "data" properties. + * + * This function can be used to produce a byte-stream to send to a hashing + * function to verify that critical parts of the FDT have not changed. + * + * Nodes which are given in 'inc' are included in the region list, as + * are the names of the immediate subnodes nodes (but not the properties + * or subnodes of those subnodes). + * + * For eaxample "/" means to include the root node, all root properties + * and the FDT_BEGIN_NODE and FDT_END_NODE of all subnodes of /. The latter + * ensures that we capture the names of the subnodes. In a hashing situation + * it prevents the root node from changing at all Any change to non-excluded + * properties, names of subnodes or number of subnodes would be detected. + * + * When used with FITs this provides the ability to hash and sign parts of + * the FIT based on different configurations in the FIT. Then it is + * impossible to change anything about that configuration (include images + * attached to the configuration), but it may be possible to add new + * configurations, new images or new signatures within the existing + * framework. + * + * Adding new properties to a device tree may result in the string table + * being extended (if the new property names are different from those + * already added). This function can optionally include a region for + * the string table so that this can be part of the hash too. + * + * The device tree header is not included in the list. + * + * @fdt: Device tree to check + * @inc: List of node paths to included + * @inc_count: Number of node paths in list + * @exc_prop: List of properties names to exclude + * @exc_prop_count: Number of properties in exclude list + * @region: Returns list of regions + * @max_region: Maximum length of region list + * @path: Pointer to a temporary string for the function to use for + * building path names + * @path_len: Length of path, must be large enough to hold the longest + * path in the tree + * @add_string_tab: 1 to add a region for the string table + * @return number of regions in list. If this is >max_regions then the + * region array was exhausted. You should increase max_regions and try + * the call again. + */ +int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, + char * const exc_prop[], int exc_prop_count, + struct fdt_region region[], int max_regions, + char *path, int path_len, int add_string_tab); + #endif /* _LIBFDT_H */ diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index fcb20fe..f6dbdb0 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -580,6 +580,8 @@ enum ethtool_sfeatures_retval_bits { #define SUPPORTED_10000baseKX4_Full (1 << 18) #define SUPPORTED_10000baseKR_Full (1 << 19) #define SUPPORTED_10000baseR_FEC (1 << 20) +#define SUPPORTED_1000baseX_Half (1 << 21) +#define SUPPORTED_1000baseX_Full (1 << 22) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1 << 0) @@ -603,6 +605,8 @@ enum ethtool_sfeatures_retval_bits { #define ADVERTISED_10000baseKX4_Full (1 << 18) #define ADVERTISED_10000baseKR_Full (1 << 19) #define ADVERTISED_10000baseR_FEC (1 << 20) +#define ADVERTISED_1000baseX_Half (1 << 21) +#define ADVERTISED_1000baseX_Full (1 << 22) /* The following are all involved in forcing a particular link * mode for the device for setting things. When getting the diff --git a/include/linux/mii.h b/include/linux/mii.h index 8b92692..66b83d8 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -115,6 +115,8 @@ #define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */ #define EXPANSION_RESV 0xffe0 /* Unused... */ +#define ESTATUS_1000_XFULL 0x8000 /* Can do 1000BX Full */ +#define ESTATUS_1000_XHALF 0x4000 /* Can do 1000BX Half */ #define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ #define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ diff --git a/include/linux/mtd/bbm.h b/include/linux/mtd/bbm.h index 8cbcdae..71292b1 100644 --- a/include/linux/mtd/bbm.h +++ b/include/linux/mtd/bbm.h @@ -81,32 +81,53 @@ struct nand_bbt_descr { #define NAND_BBT_LASTBLOCK 0x00000010 /* The bbt is at the given page, else we must scan for the bbt */ #define NAND_BBT_ABSPAGE 0x00000020 -/* The bbt is at the given page, else we must scan for the bbt */ -#define NAND_BBT_SEARCH 0x00000040 /* bbt is stored per chip on multichip devices */ #define NAND_BBT_PERCHIP 0x00000080 /* bbt has a version counter at offset veroffs */ #define NAND_BBT_VERSION 0x00000100 /* Create a bbt if none exists */ #define NAND_BBT_CREATE 0x00000200 +/* + * Create an empty BBT with no vendor information. Vendor's information may be + * unavailable, for example, if the NAND controller has a different data and OOB + * layout or if this information is already purged. Must be used in conjunction + * with NAND_BBT_CREATE. + */ +#define NAND_BBT_CREATE_EMPTY 0x00000400 /* Search good / bad pattern through all pages of a block */ -#define NAND_BBT_SCANALLPAGES 0x00000400 +#define NAND_BBT_SCANALLPAGES 0x00000800 /* Scan block empty during good / bad block scan */ -#define NAND_BBT_SCANEMPTY 0x00000800 +#define NAND_BBT_SCANEMPTY 0x00001000 /* Write bbt if neccecary */ -#define NAND_BBT_WRITE 0x00001000 +#define NAND_BBT_WRITE 0x00002000 /* Read and write back block contents when writing bbt */ -#define NAND_BBT_SAVECONTENT 0x00002000 +#define NAND_BBT_SAVECONTENT 0x00004000 /* Search good / bad pattern on the first and the second page */ -#define NAND_BBT_SCAN2NDPAGE 0x00004000 +#define NAND_BBT_SCAN2NDPAGE 0x00008000 /* Search good / bad pattern on the last page of the eraseblock */ -#define NAND_BBT_SCANLASTPAGE 0x00008000 -/* Chip stores bad block marker on BOTH 1st and 6th bytes of OOB */ -#define NAND_BBT_SCANBYTE1AND6 0x00100000 -/* The nand_bbt_descr was created dynamicaly and must be freed */ -#define NAND_BBT_DYNAMICSTRUCT 0x00200000 -/* The bad block table does not OOB for marker */ -#define NAND_BBT_NO_OOB 0x00400000 +#define NAND_BBT_SCANLASTPAGE 0x00010000 +/* + * Use a flash based bad block table. By default, OOB identifier is saved in + * OOB area. This option is passed to the default bad block table function. + */ +#define NAND_BBT_USE_FLASH 0x00020000 +/* + * Do not store flash based bad block table marker in the OOB area; store it + * in-band. + */ +#define NAND_BBT_NO_OOB 0x00040000 +/* + * Do not write new bad block markers to OOB; useful, e.g., when ECC covers + * entire spare area. Must be used with NAND_BBT_USE_FLASH. + */ +#define NAND_BBT_NO_OOB_BBM 0x00080000 + +/* + * Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr + * was allocated dynamicaly and must be freed in nand_release(). Has no meaning + * in nand_chip.bbt_options. + */ +#define NAND_BBT_DYNAMICSTRUCT 0x80000000 /* The maximum number of blocks to scan for a bbt */ #define NAND_BBT_SCAN_MAXBLOCKS 4 diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 141c960..6f44abd 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -9,7 +9,8 @@ #include <linux/types.h> #include <div64.h> -#include <linux/mtd/mtd-abi.h> +#include <mtd/mtd-abi.h> +#include <asm/errno.h> #define MTD_CHAR_MAJOR 90 #define MTD_BLOCK_MAJOR 31 @@ -65,22 +66,6 @@ struct mtd_erase_region_info { unsigned long *lockmap; /* If keeping bitmap of locks */ }; -/* - * oob operation modes - * - * MTD_OOB_PLACE: oob data are placed at the given offset - * MTD_OOB_AUTO: oob data are automatically placed at the free areas - * which are defined by the ecclayout - * MTD_OOB_RAW: mode to read raw data+oob in one chunk. The oob data - * is inserted into the data. Thats a raw image of the - * flash contents. - */ -typedef enum { - MTD_OOB_PLACE, - MTD_OOB_AUTO, - MTD_OOB_RAW, -} mtd_oob_mode_t; - /** * struct mtd_oob_ops - oob operation operands * @mode: operation mode @@ -92,7 +77,7 @@ typedef enum { * @ooblen: number of oob bytes to write/read * @oobretlen: number of oob bytes written/read * @ooboffs: offset of oob data in the oob area (only relevant when - * mode = MTD_OOB_PLACE) + * mode = MTD_OPS_PLACE_OOB or MTD_OPS_RAW) * @datbuf: data buffer - if NULL only oob data are read/written * @oobbuf: oob data buffer * @@ -101,7 +86,7 @@ typedef enum { * OOB area. */ struct mtd_oob_ops { - mtd_oob_mode_t mode; + unsigned int mode; size_t len; size_t retlen; size_t ooblen; @@ -133,13 +118,25 @@ struct mtd_info { u_int32_t oobsize; /* Amount of OOB data per block (e.g. 16) */ u_int32_t oobavail; /* Available OOB bytes per block */ + /* + * read ops return -EUCLEAN if max number of bitflips corrected on any + * one region comprising an ecc step equals or exceeds this value. + * Settable by driver, else defaults to ecc_strength. User can override + * in sysfs. N.B. The meaning of the -EUCLEAN return code has changed; + * see Documentation/ABI/testing/sysfs-class-mtd for more detail. + */ + unsigned int bitflip_threshold; + /* Kernel-only stuff starts here. */ const char *name; int index; - /* ecc layout structure pointer - read only ! */ + /* ECC layout structure pointer - read only! */ struct nand_ecclayout *ecclayout; + /* max number of correctible bit errors per ecc step */ + unsigned int ecc_strength; + /* Data for variable erase regions. If numeraseregions is zero, * it means that the whole device has erasesize as given above. */ @@ -147,25 +144,17 @@ struct mtd_info { struct mtd_erase_region_info *eraseregions; /* - * Erase is an asynchronous operation. Device drivers are supposed - * to call instr->callback() whenever the operation completes, even - * if it completes with a failure. - * Callers are supposed to pass a callback function and wait for it - * to be called before writing to the block. + * Do not call via these pointers, use corresponding mtd_*() + * wrappers instead. */ - int (*erase) (struct mtd_info *mtd, struct erase_info *instr); - - /* This stuff for eXecute-In-Place */ - /* phys is optional and may be set to NULL */ - int (*point) (struct mtd_info *mtd, loff_t from, size_t len, + int (*_erase) (struct mtd_info *mtd, struct erase_info *instr); + int (*_point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, void **virt, phys_addr_t *phys); - - /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ - void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len); - - - int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); + void (*_unpoint) (struct mtd_info *mtd, loff_t from, size_t len); + int (*_read) (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); + int (*_write) (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf); /* In blackbox flight recorder like scenarios we want to make successful writes in interrupt context. panic_write() is only intended to be @@ -174,24 +163,35 @@ struct mtd_info { longer, this function can break locks and delay to ensure the write succeeds (but not sleep). */ - int (*panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); + int (*_panic_write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - int (*read_oob) (struct mtd_info *mtd, loff_t from, + int (*_read_oob) (struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); - int (*write_oob) (struct mtd_info *mtd, loff_t to, + int (*_write_oob) (struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops); - + int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, + size_t len); + int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf); + int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, + size_t len); + int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf); + int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, u_char *buf); + int (*_lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, + size_t len); + void (*_sync) (struct mtd_info *mtd); + int (*_lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); + int (*_unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); + int (*_block_isbad) (struct mtd_info *mtd, loff_t ofs); + int (*_block_markbad) (struct mtd_info *mtd, loff_t ofs); /* - * Methods to access the protection register area, present in some - * flash devices. The user data is one time programmable but the - * factory data is read only. + * If the driver is something smart, like UBI, it may need to maintain + * its own reference counting. The below functions are only for driver. */ - int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); - int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); - int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); + int (*_get_device) (struct mtd_info *mtd); + void (*_put_device) (struct mtd_info *mtd); /* XXX U-BOOT XXX */ #if 0 @@ -201,18 +201,6 @@ struct mtd_info { */ int (*writev) (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen); #endif - - /* Sync */ - void (*sync) (struct mtd_info *mtd); - - /* Chip-supported device locking */ - int (*lock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); - int (*unlock) (struct mtd_info *mtd, loff_t ofs, uint64_t len); - - /* Bad block management functions */ - int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); - int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); - /* XXX U-BOOT XXX */ #if 0 struct notifier_block reboot_notifier; /* default mode before reboot */ @@ -227,15 +215,59 @@ struct mtd_info { struct module *owner; int usecount; - - /* If the driver is something smart, like UBI, it may need to maintain - * its own reference counting. The below functions are only for driver. - * The driver may register its callbacks. These callbacks are not - * supposed to be called by MTD users */ - int (*get_device) (struct mtd_info *mtd); - void (*put_device) (struct mtd_info *mtd); }; +int mtd_erase(struct mtd_info *mtd, struct erase_info *instr); +int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, + u_char *buf); +int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, + const u_char *buf); +int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, + const u_char *buf); + +int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); + +static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to, + struct mtd_oob_ops *ops) +{ + ops->retlen = ops->oobretlen = 0; + if (!mtd->_write_oob) + return -EOPNOTSUPP; + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + return mtd->_write_oob(mtd, to, ops); +} + +int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf, + size_t len); +int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf, + size_t len); +int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, u_char *buf); +int mtd_lock_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len); + +/* XXX U-BOOT XXX */ +#if 0 +int mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, + unsigned long count, loff_t to, size_t *retlen); +#endif + +static inline void mtd_sync(struct mtd_info *mtd) +{ + if (mtd->_sync) + mtd->_sync(mtd); +} + +int mtd_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +int mtd_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len); +int mtd_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len); +int mtd_block_isbad(struct mtd_info *mtd, loff_t ofs); +int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs); + static inline uint32_t mtd_div_by_eb(uint64_t sz, struct mtd_info *mtd) { do_div(sz, mtd->erasesize); @@ -247,6 +279,16 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd) return do_div(sz, mtd->erasesize); } +static inline int mtd_has_oob(const struct mtd_info *mtd) +{ + return mtd->_read_oob && mtd->_write_oob; +} + +static inline int mtd_can_have_bb(const struct mtd_info *mtd) +{ + return !!mtd->_block_isbad; +} + /* Kernel-side ioctl definitions */ extern int add_mtd_device(struct mtd_info *mtd); @@ -269,12 +311,6 @@ struct mtd_notifier { extern void register_mtd_user (struct mtd_notifier *new); extern int unregister_mtd_user (struct mtd_notifier *old); - -int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs, - unsigned long count, loff_t to, size_t *retlen); - -int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, - unsigned long count, loff_t from, size_t *retlen); #endif #ifdef CONFIG_MTD_PARTITIONS @@ -296,17 +332,34 @@ static inline void mtd_erase_callback(struct erase_info *instr) #define MTD_DEBUG_LEVEL3 (3) /* Noisy */ #ifdef CONFIG_MTD_DEBUG +#define pr_debug(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args) #define MTDDEBUG(n, args...) \ do { \ if (n <= CONFIG_MTD_DEBUG_VERBOSE) \ printk(KERN_INFO args); \ } while(0) #else /* CONFIG_MTD_DEBUG */ +#define pr_debug(args...) #define MTDDEBUG(n, args...) \ do { \ if (0) \ printk(KERN_INFO args); \ } while(0) #endif /* CONFIG_MTD_DEBUG */ +#define pr_info(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args) +#define pr_warn(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args) +#define pr_err(args...) MTDDEBUG(MTD_DEBUG_LEVEL0, args) + +static inline int mtd_is_bitflip(int err) { + return err == -EUCLEAN; +} + +static inline int mtd_is_eccerr(int err) { + return err == -EBADMSG; +} + +static inline int mtd_is_bitflip_or_eccerr(int err) { + return mtd_is_bitflip(err) || mtd_is_eccerr(err); +} #endif /* __MTD_MTD_H__ */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 98bf255..2055584 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -46,7 +46,7 @@ extern void nand_wait_ready(struct mtd_info *mtd); * is supported now. If you add a chip with bigger oobsize/page * adjust this accordingly. */ -#define NAND_MAX_OOBSIZE 576 +#define NAND_MAX_OOBSIZE 640 #define NAND_MAX_PAGESIZE 8192 /* @@ -82,6 +82,8 @@ extern void nand_wait_ready(struct mtd_info *mtd); #define NAND_CMD_READID 0x90 #define NAND_CMD_ERASE2 0xd0 #define NAND_CMD_PARAM 0xec +#define NAND_CMD_GET_FEATURES 0xee +#define NAND_CMD_SET_FEATURES 0xef #define NAND_CMD_RESET 0xff #define NAND_CMD_LOCK 0x2a @@ -142,7 +144,7 @@ typedef enum { #define NAND_ECC_READ 0 /* Reset Hardware ECC for write */ #define NAND_ECC_WRITE 1 -/* Enable Hardware ECC before syndrom is read back from flash */ +/* Enable Hardware ECC before syndrome is read back from flash */ #define NAND_ECC_READSYN 2 /* Bit mask for flags passed to do_nand_read_ecc */ @@ -153,9 +155,7 @@ typedef enum { * Option constants for bizarre disfunctionality and real * features. */ -/* Chip can not auto increment pages */ -#define NAND_NO_AUTOINCR 0x00000001 -/* Buswitdh is 16 bit */ +/* Buswidth is 16 bit */ #define NAND_BUSWIDTH_16 0x00000002 /* Device supports partial programming without padding */ #define NAND_NO_PADDING 0x00000004 @@ -179,12 +179,6 @@ typedef enum { * This happens with the Renesas AG-AND chips, possibly others. */ #define BBT_AUTO_REFRESH 0x00000080 -/* - * Chip does not require ready check on read. true - * for all large page devices, as they do not support - * autoincrement. - */ -#define NAND_NO_READRDY 0x00000100 /* Chip does not allow subpage writes */ #define NAND_NO_SUBPAGE_WRITE 0x00000200 @@ -202,34 +196,21 @@ typedef enum { (NAND_NO_PADDING | NAND_CACHEPRG | NAND_COPYBACK) /* Macros to identify the above */ -#define NAND_CANAUTOINCR(chip) (!(chip->options & NAND_NO_AUTOINCR)) #define NAND_MUST_PAD(chip) (!(chip->options & NAND_NO_PADDING)) #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) #define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK)) #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ)) /* Non chip related options */ -/* - * Use a flash based bad block table. OOB identifier is saved in OOB area. - * This option is passed to the default bad block table function. - */ -#define NAND_USE_FLASH_BBT 0x00010000 /* This option skips the bbt scan during initialization. */ -#define NAND_SKIP_BBTSCAN 0x00020000 +#define NAND_SKIP_BBTSCAN 0x00010000 /* * This option is defined if the board driver allocates its own buffers * (e.g. because it needs them DMA-coherent). */ -#define NAND_OWN_BUFFERS 0x00040000 +#define NAND_OWN_BUFFERS 0x00020000 /* Chip may not exist, so silence any errors in scan */ -#define NAND_SCAN_SILENT_NODEV 0x00080000 -/* - * If passed additionally to NAND_USE_FLASH_BBT then BBT code will not touch - * the OOB area. - */ -#define NAND_USE_FLASH_BBT_NO_OOB 0x00800000 -/* Create an empty BBT with no vendor information if the BBT is available */ -#define NAND_CREATE_EMPTY_BBT 0x01000000 +#define NAND_SCAN_SILENT_NODEV 0x00040000 /* Options set by nand scan */ /* bbt has already been read */ @@ -244,6 +225,21 @@ typedef enum { /* Keep gcc happy */ struct nand_chip; +/* ONFI timing mode, used in both asynchronous and synchronous mode */ +#define ONFI_TIMING_MODE_0 (1 << 0) +#define ONFI_TIMING_MODE_1 (1 << 1) +#define ONFI_TIMING_MODE_2 (1 << 2) +#define ONFI_TIMING_MODE_3 (1 << 3) +#define ONFI_TIMING_MODE_4 (1 << 4) +#define ONFI_TIMING_MODE_5 (1 << 5) +#define ONFI_TIMING_MODE_UNKNOWN (1 << 6) + +/* ONFI feature address */ +#define ONFI_FEATURE_ADDR_TIMING_MODE 0x1 + +/* ONFI subfeature parameters length */ +#define ONFI_SUBFEATURE_PARAM_LEN 4 + struct nand_onfi_params { /* rev info and features block */ /* 'O' 'N' 'F' 'I' */ @@ -326,27 +322,32 @@ struct nand_hw_control { }; /** - * struct nand_ecc_ctrl - Control structure for ecc - * @mode: ecc mode - * @steps: number of ecc steps per page - * @size: data bytes per ecc step - * @bytes: ecc bytes per step - * @total: total number of ecc bytes per page - * @prepad: padding information for syndrome based ecc generators - * @postpad: padding information for syndrome based ecc generators + * struct nand_ecc_ctrl - Control structure for ECC + * @mode: ECC mode + * @steps: number of ECC steps per page + * @size: data bytes per ECC step + * @bytes: ECC bytes per step + * @strength: max number of correctible bits per ECC step + * @total: total number of ECC bytes per page + * @prepad: padding information for syndrome based ECC generators + * @postpad: padding information for syndrome based ECC generators * @layout: ECC layout control struct pointer - * @priv: pointer to private ecc control data - * @hwctl: function to control hardware ecc generator. Must only + * @priv: pointer to private ECC control data + * @hwctl: function to control hardware ECC generator. Must only * be provided if an hardware ECC is available - * @calculate: function for ecc calculation or readback from ecc hardware - * @correct: function for ecc correction, matching to ecc generator (sw/hw) + * @calculate: function for ECC calculation or readback from ECC hardware + * @correct: function for ECC correction, matching to ECC generator (sw/hw) * @read_page_raw: function to read a raw page without ECC * @write_page_raw: function to write a raw page without ECC - * @read_page: function to read a page according to the ecc generator - * requirements. - * @read_subpage: function to read parts of the page covered by ECC. - * @write_page: function to write a page according to the ecc generator + * @read_page: function to read a page according to the ECC generator + * requirements; returns maximum number of bitflips corrected in + * any single ECC step, 0 if bitflips uncorrectable, -EIO hw error + * @read_subpage: function to read parts of the page covered by ECC; + * returns same as read_page() + * @write_page: function to write a page according to the ECC generator * requirements. + * @write_oob_raw: function to write chip OOB data without ECC + * @read_oob_raw: function to read chip OOB data without ECC * @read_oob: function to read chip OOB data * @write_oob: function to write chip OOB data */ @@ -356,6 +357,7 @@ struct nand_ecc_ctrl { int size; int bytes; int total; + int strength; int prepad; int postpad; struct nand_ecclayout *layout; @@ -366,25 +368,28 @@ struct nand_ecc_ctrl { int (*correct)(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc); int (*read_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page); - void (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf); + uint8_t *buf, int oob_required, int page); + int (*write_page_raw)(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required); int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip, - uint8_t *buf, int page); + uint8_t *buf, int oob_required, int page); int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip, uint32_t offs, uint32_t len, uint8_t *buf); - void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf); - int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page, - int sndcmd); + int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, + const uint8_t *buf, int oob_required); + int (*write_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, + int page); + int (*read_oob_raw)(struct mtd_info *mtd, struct nand_chip *chip, + int page); + int (*read_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page); int (*write_oob)(struct mtd_info *mtd, struct nand_chip *chip, int page); }; /** * struct nand_buffers - buffer structure for read/write - * @ecccalc: buffer for calculated ecc - * @ecccode: buffer for ecc read from flash + * @ecccalc: buffer for calculated ECC + * @ecccode: buffer for ECC read from flash * @databuf: buffer for data - dynamically sized * * Do not change the order of buffers. databuf and oobrbuf must be in @@ -418,7 +423,7 @@ struct nand_buffers { * mtd->oobsize, mtd->writesize and so on. * @id_data contains the 8 bytes values of NAND_CMD_READID. * Return with the bus width. - * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accesing + * @dev_ready: [BOARDSPECIFIC] hardwarespecific function for accessing * device ready/busy line. If set to NULL no access to * ready/busy is available and the ready/busy information * is read from the chip status register. @@ -426,17 +431,17 @@ struct nand_buffers { * commands to the chip. * @waitfunc: [REPLACEABLE] hardwarespecific function for wait on * ready. - * @ecc: [BOARDSPECIFIC] ecc control ctructure + * @ecc: [BOARDSPECIFIC] ECC control structure * @buffers: buffer structure for read/write * @hwcontrol: platform-specific hardware control structure - * @ops: oob operation operands * @erase_cmd: [INTERN] erase command write function, selectable due * to AND support. * @scan_bbt: [REPLACEABLE] function to scan bad block table * @chip_delay: [BOARDSPECIFIC] chip dependent delay for transferring * data from array to read regs (tR). * @state: [INTERN] the current state of the NAND device - * @oob_poi: poison value buffer + * @oob_poi: "poison value buffer," used for laying out OOB data + * before writing * @page_shift: [INTERN] number of address bits in a page (column * address bits). * @phys_erase_shift: [INTERN] number of address bits in a physical eraseblock @@ -445,10 +450,14 @@ struct nand_buffers { * @options: [BOARDSPECIFIC] various chip options. They can partly * be set to inform nand_scan about special functionality. * See the defines for further explanation. + * @bbt_options: [INTERN] bad block specific options. All options used + * here must come from bbm.h. By default, these options + * will be copied to the appropriate nand_bbt_descr's. * @badblockpos: [INTERN] position of the bad block marker in the oob * area. - * @badblockbits: [INTERN] number of bits to left-shift the bad block - * number + * @badblockbits: [INTERN] minimum number of set bits in a good block's + * bad block marker position; i.e., BBM == 11110111b is + * not bad when badblockbits == 7 * @cellinfo: [INTERN] MLC/multichip data from chip ident * @numchips: [INTERN] number of physical chips * @chipsize: [INTERN] the size of one chip for multichip arrays @@ -460,7 +469,9 @@ struct nand_buffers { * non 0 if ONFI supported. * @onfi_params: [INTERN] holds the ONFI page parameter when ONFI is * supported, 0 otherwise. - * @ecclayout: [REPLACEABLE] the default ecc placement scheme + * @onfi_set_features [REPLACEABLE] set the features for ONFI nand + * @onfi_get_features [REPLACEABLE] get the features for ONFI nand + * @ecclayout: [REPLACEABLE] the default ECC placement scheme * @bbt: [INTERN] bad block table pointer * @bbt_td: [REPLACEABLE] bad block table descriptor for flash * lookup. @@ -468,9 +479,9 @@ struct nand_buffers { * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial * bad block scan. * @controller: [REPLACEABLE] a pointer to a hardware controller - * structure which is shared among multiple independend + * structure which is shared among multiple independent * devices. - * @priv: [OPTIONAL] pointer to private chip date + * @priv: [OPTIONAL] pointer to private chip data * @errstat: [OPTIONAL] hardware specific function to perform * additional error status checks (determine if errors are * correctable). @@ -501,10 +512,16 @@ struct nand_chip { int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip, - const uint8_t *buf, int page, int cached, int raw); + const uint8_t *buf, int oob_required, int page, + int cached, int raw); + int (*onfi_set_features)(struct mtd_info *mtd, struct nand_chip *chip, + int feature_addr, uint8_t *subfeature_para); + int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip, + int feature_addr, uint8_t *subfeature_para); int chip_delay; unsigned int options; + unsigned int bbt_options; int page_shift; int phys_erase_shift; @@ -534,8 +551,6 @@ struct nand_chip { struct nand_buffers *buffers; struct nand_hw_control hwcontrol; - struct mtd_oob_ops ops; - uint8_t *bbt; struct nand_bbt_descr *bbt_td; struct nand_bbt_descr *bbt_md; @@ -557,6 +572,8 @@ struct nand_chip { #define NAND_MFR_HYNIX 0xad #define NAND_MFR_MICRON 0x2c #define NAND_MFR_AMD 0x01 +#define NAND_MFR_MACRONIX 0xc2 +#define NAND_MFR_EON 0x92 /** * struct nand_flash_dev - NAND Flash Device ID Structure @@ -615,9 +632,9 @@ extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len, * @partitions: mtd partition list * @chip_delay: R/B delay value in us * @options: Option flags, e.g. 16bit buswidth - * @ecclayout: ecc layout info structure + * @bbt_options: BBT option flags, e.g. NAND_BBT_USE_FLASH + * @ecclayout: ECC layout info structure * @part_probe_types: NULL-terminated array of probe types - * @priv: hardware controller specific settings */ struct platform_nand_chip { int nr_chips; @@ -627,8 +644,8 @@ struct platform_nand_chip { struct nand_ecclayout *ecclayout; int chip_delay; unsigned int options; + unsigned int bbt_options; const char **part_probe_types; - void *priv; }; /* Keep gcc happy */ @@ -650,6 +667,7 @@ struct platform_nand_ctrl { int (*dev_ready)(struct mtd_info *mtd); void (*select_chip)(struct mtd_info *mtd, int chip); void (*cmd_ctrl)(struct mtd_info *mtd, int dat, unsigned int ctrl); + unsigned char (*read_byte)(struct mtd_info *mtd); void *priv; }; @@ -679,4 +697,23 @@ void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len); void nand_read_buf16(struct mtd_info *mtd, uint8_t *buf, int len); uint8_t nand_read_byte(struct mtd_info *mtd); +/* return the supported asynchronous timing mode. */ + +#ifdef CONFIG_SYS_NAND_ONFI_DETECTION +static inline int onfi_get_async_timing_mode(struct nand_chip *chip) +{ + if (!chip->onfi_version) + return ONFI_TIMING_MODE_UNKNOWN; + return le16_to_cpu(chip->onfi_params.async_timing_mode); +} + +/* return the supported synchronous timing mode. */ +static inline int onfi_get_sync_timing_mode(struct nand_chip *chip) +{ + if (!chip->onfi_version) + return ONFI_TIMING_MODE_UNKNOWN; + return le16_to_cpu(chip->onfi_params.src_sync_timing_mode); +} +#endif + #endif /* __LINUX_MTD_NAND_H */ diff --git a/include/linux/string.h b/include/linux/string.h index e9b134d..8e44855 100644 --- a/include/linux/string.h +++ b/include/linux/string.h @@ -85,6 +85,9 @@ extern int memcmp(const void *,const void *,__kernel_size_t); #ifndef __HAVE_ARCH_MEMCHR extern void * memchr(const void *,int,__kernel_size_t); #endif +#ifndef __HAVE_ARCH_MEMCHR_INV +void *memchr_inv(const void *, int, size_t); +#endif #ifdef __cplusplus } diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index d1d732c..bd48704 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h @@ -35,6 +35,7 @@ #include <linux/types.h> /* __u8 etc */ #include <asm/byteorder.h> /* le16_to_cpu */ +#include <asm/unaligned.h> /* get_unaligned() */ /*-------------------------------------------------------------------------*/ @@ -596,7 +597,7 @@ static inline int usb_endpoint_is_isoc_out( */ static inline int usb_endpoint_maxp(const struct usb_endpoint_descriptor *epd) { - return __le16_to_cpu(epd->wMaxPacketSize); + return __le16_to_cpu(get_unaligned(&epd->wMaxPacketSize)); } static inline int usb_endpoint_interrupt_type( diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 53cb095..4f76f88 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -331,7 +331,7 @@ struct usb_composite_dev { /* private: */ /* internals */ unsigned int suspended:1; - struct usb_device_descriptor desc; + struct usb_device_descriptor __aligned(CONFIG_SYS_CACHELINE_SIZE) desc; struct list_head configs; struct usb_composite_driver *driver; u8 next_string_id; diff --git a/include/micrel.h b/include/micrel.h index 25e8a46..e1c62d8 100644 --- a/include/micrel.h +++ b/include/micrel.h @@ -8,9 +8,20 @@ #define MII_KSZ9021_EXT_RGMII_RX_DATA_SKEW 0x105 #define MII_KSZ9021_EXT_RGMII_TX_DATA_SKEW 0x106 #define MII_KSZ9021_EXT_ANALOG_TEST 0x107 +/* Register operations */ +#define MII_KSZ9031_MOD_REG 0x0000 +/* Data operations */ +#define MII_KSZ9031_MOD_DATA_NO_POST_INC 0x4000 +#define MII_KSZ9031_MOD_DATA_POST_INC_RW 0x8000 +#define MII_KSZ9031_MOD_DATA_POST_INC_W 0xC000 struct phy_device; int ksz9021_phy_extended_write(struct phy_device *phydev, int regnum, u16 val); int ksz9021_phy_extended_read(struct phy_device *phydev, int regnum); +int ksz9031_phy_extended_write(struct phy_device *phydev, int devaddr, + int regnum, u16 mode, u16 val); +int ksz9031_phy_extended_read(struct phy_device *phydev, int devaddr, + int regnum, u16 mode); + #endif diff --git a/include/mmc.h b/include/mmc.h index f88f672..583c30e 100644 --- a/include/mmc.h +++ b/include/mmc.h @@ -163,7 +163,9 @@ /* * EXT_CSD fields */ +#define EXT_CSD_GP_SIZE_MULT 143 /* R/W */ #define EXT_CSD_PARTITIONING_SUPPORT 160 /* RO */ +#define EXT_CSD_RPMB_MULT 168 /* RO */ #define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */ #define EXT_CSD_BOOT_BUS_WIDTH 177 #define EXT_CSD_PART_CONF 179 /* R/W */ @@ -172,6 +174,7 @@ #define EXT_CSD_REV 192 /* RO */ #define EXT_CSD_CARD_TYPE 196 /* RO */ #define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */ +#define EXT_CSD_HC_WP_GRP_SIZE 221 /* RO */ #define EXT_CSD_HC_ERASE_GRP_SIZE 224 /* RO */ #define EXT_CSD_BOOT_MULT 226 /* RO */ @@ -284,6 +287,10 @@ struct mmc { uint write_bl_len; uint erase_grp_size; u64 capacity; + u64 capacity_user; + u64 capacity_boot; + u64 capacity_rpmb; + u64 capacity_gp[4]; block_dev_desc_t block_dev; int (*send_cmd)(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data); diff --git a/include/linux/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index 8bdd231..d51c1ab 100644 --- a/include/linux/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -24,6 +24,25 @@ struct mtd_oob_buf { unsigned char __user *ptr; }; +/* + * MTD operation modes + * + * @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default) + * @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas + * which are defined by the internal ecclayout + * @MTD_OPS_RAW: data are transferred as-is, with no error correction; + * this mode implies %MTD_OPS_PLACE_OOB + * + * These modes can be passed to ioctl(MEMWRITE) and are also used internally. + * See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs. + * %MTD_FILE_MODE_RAW. + */ +enum { + MTD_OPS_PLACE_OOB = 0, + MTD_OPS_AUTO_OOB = 1, + MTD_OPS_RAW = 2, +}; + #define MTD_ABSENT 0 #define MTD_RAM 1 #define MTD_ROM 2 @@ -82,24 +101,42 @@ struct otp_info { uint32_t locked; }; +/* Get basic MTD characteristics info (better to use sysfs) */ #define MEMGETINFO _IOR('M', 1, struct mtd_info_user) +/* Erase segment of MTD */ #define MEMERASE _IOW('M', 2, struct erase_info_user) +/* Write out-of-band data from MTD */ #define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) +/* Read out-of-band data from MTD */ #define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf) +/* Lock a chip (for MTD that supports it) */ #define MEMLOCK _IOW('M', 5, struct erase_info_user) +/* Unlock a chip (for MTD that supports it) */ #define MEMUNLOCK _IOW('M', 6, struct erase_info_user) +/* Get the number of different erase regions */ #define MEMGETREGIONCOUNT _IOR('M', 7, int) +/* Get information about the erase region for a specific index */ #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) +/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */ #define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) #define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo) +/* Check if an eraseblock is bad */ #define MEMGETBADBLOCK _IOW('M', 11, loff_t) +/* Mark an eraseblock as bad */ #define MEMSETBADBLOCK _IOW('M', 12, loff_t) +/* Set OTP (One-Time Programmable) mode (factory vs. user) */ #define OTPSELECT _IOR('M', 13, int) +/* Get number of OTP (One-Time Programmable) regions */ #define OTPGETREGIONCOUNT _IOW('M', 14, int) +/* Get all OTP (One-Time Programmable) info about MTD */ #define OTPGETREGIONINFO _IOW('M', 15, struct otp_info) +/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */ #define OTPLOCK _IOR('M', 16, struct otp_info) +/* Get ECC layout (deprecated) */ #define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout) +/* Get statistics about corrected/uncorrected errors */ #define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats) +/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */ #define MTDFILEMODE _IO('M', 19) /* @@ -146,7 +183,21 @@ struct mtd_ecc_stats { }; /* - * Read/write file modes for access to MTD + * MTD file modes - for read/write access to MTD + * + * @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled + * @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode + * @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode + * @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled + * + * These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained + * separately for each open file descriptor. + * + * Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW - + * raw access to the flash, without error correction or autoplacement schemes. + * Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode + * (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is + * used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)). */ enum mtd_file_modes { MTD_MODE_NORMAL = MTD_OTP_OFF, diff --git a/include/nand.h b/include/nand.h index f0f3bf9..228d871 100644 --- a/include/nand.h +++ b/include/nand.h @@ -31,7 +31,8 @@ * at the same time, so do it here. When all drivers are * converted, this will go away. */ -#if defined(CONFIG_NAND_FSL_ELBC) || defined(CONFIG_NAND_ATMEL) +#if defined(CONFIG_NAND_FSL_ELBC) || defined(CONFIG_NAND_ATMEL)\ + || defined(CONFIG_NAND_FSL_IFC) #define CONFIG_SYS_NAND_SELF_INIT #endif @@ -55,17 +56,17 @@ extern nand_info_t nand_info[]; static inline int nand_read(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf) { - return info->read(info, ofs, *len, (size_t *)len, buf); + return mtd_read(info, ofs, *len, (size_t *)len, buf); } static inline int nand_write(nand_info_t *info, loff_t ofs, size_t *len, u_char *buf) { - return info->write(info, ofs, *len, (size_t *)len, buf); + return mtd_write(info, ofs, *len, (size_t *)len, buf); } static inline int nand_block_isbad(nand_info_t *info, loff_t ofs) { - return info->block_isbad(info, ofs); + return mtd_block_isbad(info, ofs); } static inline int nand_erase(nand_info_t *info, loff_t off, size_t size) @@ -77,7 +78,7 @@ static inline int nand_erase(nand_info_t *info, loff_t off, size_t size) instr.len = size; instr.callback = 0; - return info->erase(info, &instr); + return mtd_erase(info, &instr); } @@ -124,6 +125,8 @@ struct nand_erase_options { /* Don't include skipped bad blocks in size to be erased */ int spread; + /* maximum size that actual may be in order to not exceed the buf */ + loff_t lim; }; typedef struct nand_erase_options nand_erase_options_t; diff --git a/include/net.h b/include/net.h index 970d4d1..7673470 100644 --- a/include/net.h +++ b/include/net.h @@ -39,7 +39,7 @@ #define PKTALIGN ARCH_DMA_MINALIGN /* IPv4 addresses are always 32 bits in size */ -typedef u32 IPaddr_t; +typedef __be32 IPaddr_t; /** @@ -695,6 +695,9 @@ extern void copy_filename(char *dst, const char *src, int size); /* get a random source port */ extern unsigned int random_port(void); +/* Update U-Boot over TFTP */ +extern int update_tftp(ulong addr); + /**********************************************************************/ #endif /* __NET_H__ */ diff --git a/include/netdev.h b/include/netdev.h index df454b5..917d874 100644 --- a/include/netdev.h +++ b/include/netdev.h @@ -67,10 +67,12 @@ int fecmxc_initialize(bd_t *bis); int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr); int ftgmac100_initialize(bd_t *bits); int ftmac100_initialize(bd_t *bits); +int ftmac110_initialize(bd_t *bits); int greth_initialize(bd_t *bis); void gt6426x_eth_initialize(bd_t *bis); int inca_switch_initialize(bd_t *bis); int ks8695_eth_initialize(void); +int ks8851_mll_initialize(u8 dev_num, int base_addr); int lan91c96_initialize(u8 dev_num, int base_addr); int macb_eth_initialize(int id, void *regs, unsigned int phy_addr); int mcdmafec_initialize(bd_t *bis); @@ -93,6 +95,7 @@ int sh_eth_initialize(bd_t *bis); int skge_initialize(bd_t *bis); int smc91111_initialize(u8 dev_num, int base_addr); int smc911x_initialize(u8 dev_num, int base_addr); +int sunxi_wemac_initialize(bd_t *bis); int tsi108_eth_initialize(bd_t *bis); int uec_standard_init(bd_t *bis); int uli526x_initialize(bd_t *bis); diff --git a/include/part.h b/include/part.h index f7c7cc5..35c1c5b 100644 --- a/include/part.h +++ b/include/part.h @@ -43,15 +43,15 @@ typedef struct block_dev_desc { char product[20+1]; /* IDE Serial no, SCSI product */ char revision[8+1]; /* firmware revision */ unsigned long (*block_read)(int dev, - unsigned long start, + lbaint_t start, lbaint_t blkcnt, void *buffer); unsigned long (*block_write)(int dev, - unsigned long start, + lbaint_t start, lbaint_t blkcnt, const void *buffer); unsigned long (*block_erase)(int dev, - unsigned long start, + lbaint_t start, lbaint_t blkcnt); void *priv; /* driver private struct pointer */ }block_dev_desc_t; diff --git a/include/pci.h b/include/pci.h index 15f583f..98ba151 100644 --- a/include/pci.h +++ b/include/pci.h @@ -462,7 +462,7 @@ struct pci_region { #define PCI_REGION_SYS_MEMORY 0x00000100 /* System memory */ #define PCI_REGION_RO 0x00000200 /* Read-only memory */ -extern __inline__ void pci_set_region(struct pci_region *reg, +static inline void pci_set_region(struct pci_region *reg, pci_addr_t bus_start, phys_addr_t phys_start, pci_size_t size, @@ -548,7 +548,7 @@ struct pci_controller { void *priv_data; }; -extern __inline__ void pci_set_ops(struct pci_controller *hose, +static inline void pci_set_ops(struct pci_controller *hose, int (*read_byte)(struct pci_controller*, pci_dev_t, int where, u8 *), int (*read_word)(struct pci_controller*, @@ -569,7 +569,9 @@ extern __inline__ void pci_set_ops(struct pci_controller *hose, hose->write_dword = write_dword; } +#ifdef CONFIG_PCI_INDIRECT_BRIDGE extern void pci_setup_indirect(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data); +#endif extern phys_addr_t pci_hose_bus_to_phys(struct pci_controller* hose, pci_addr_t addr, unsigned long flags); diff --git a/include/phy.h b/include/phy.h index 75bf3b4..dbf3274 100644 --- a/include/phy.h +++ b/include/phy.h @@ -214,6 +214,7 @@ int phy_register(struct phy_driver *drv); int genphy_config_aneg(struct phy_device *phydev); int genphy_restart_aneg(struct phy_device *phydev); int genphy_update_link(struct phy_device *phydev); +int genphy_parse_link(struct phy_device *phydev); int genphy_config(struct phy_device *phydev); int genphy_startup(struct phy_device *phydev); int genphy_shutdown(struct phy_device *phydev); diff --git a/include/rsa.h b/include/rsa.h new file mode 100644 index 0000000..a5dd676 --- /dev/null +++ b/include/rsa.h @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * (C) Copyright 2008 Semihalf + * + * (C) Copyright 2000-2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef _RSA_H +#define _RSA_H + +#include <errno.h> +#include <image.h> + +#if IMAGE_ENABLE_SIGN +/** + * sign() - calculate and return signature for given input data + * + * @info: Specifies key and FIT information + * @data: Pointer to the input data + * @data_len: Data length + * @sigp: Set to an allocated buffer holding the signature + * @sig_len: Set to length of the calculated hash + * + * This computes input data signature according to selected algorithm. + * Resulting signature value is placed in an allocated buffer, the + * pointer is returned as *sigp. The length of the calculated + * signature is returned via the sig_len pointer argument. The caller + * should free *sigp. + * + * @return: 0, on success, -ve on error + */ +int rsa_sign(struct image_sign_info *info, + const struct image_region region[], + int region_count, uint8_t **sigp, uint *sig_len); + +/** + * add_verify_data() - Add verification information to FDT + * + * Add public key information to the FDT node, suitable for + * verification at run-time. The information added depends on the + * algorithm being used. + * + * @info: Specifies key and FIT information + * @keydest: Destination FDT blob for public key data + * @return: 0, on success, -ve on error +*/ +int rsa_add_verify_data(struct image_sign_info *info, void *keydest); +#else +static inline int rsa_sign(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t **sigp, uint *sig_len) +{ + return -ENXIO; +} + +static inline int rsa_add_verify_data(struct image_sign_info *info, + void *keydest) +{ + return -ENXIO; +} +#endif + +#if IMAGE_ENABLE_VERIFY +/** + * rsa_verify() - Verify a signature against some data + * + * Verify a RSA PKCS1.5 signature against an expected hash. + * + * @info: Specifies key and FIT information + * @data: Pointer to the input data + * @data_len: Data length + * @sig: Signature + * @sig_len: Number of bytes in signature + * @return 0 if verified, -ve on error + */ +int rsa_verify(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t *sig, uint sig_len); +#else +static inline int rsa_verify(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t *sig, uint sig_len) +{ + return -ENXIO; +} +#endif + +#endif diff --git a/include/spi.h b/include/spi.h index 3fe2e1e..e8e6544 100644 --- a/include/spi.h +++ b/include/spi.h @@ -37,11 +37,16 @@ #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ #define SPI_3WIRE 0x10 /* SI/SO signals shared */ #define SPI_LOOP 0x20 /* loopback mode */ +#define SPI_SLAVE 0x40 /* slave mode */ +#define SPI_PREAMBLE 0x80 /* Skip preamble bytes */ /* SPI transfer flags */ #define SPI_XFER_BEGIN 0x01 /* Assert CS before transfer */ #define SPI_XFER_END 0x02 /* Deassert CS after transfer */ +/* Header byte that marks the start of the message */ +#define SPI_PREAMBLE_END_BYTE 0xec + /*----------------------------------------------------------------------- * Representation of a SPI slave, i.e. what we're communicating with. * @@ -242,4 +247,20 @@ static inline int spi_w8r8(struct spi_slave *slave, unsigned char byte) return ret < 0 ? ret : din[1]; } +/** + * Set up a SPI slave for a particular device tree node + * + * This calls spi_setup_slave() with the correct bus number. Call + * spi_free_slave() to free it later. + * + * @param blob Device tree blob + * @param node SPI peripheral node to use + * @param cs Chip select to use + * @param max_hz Maximum SCK rate in Hz (0 for default) + * @param mode Clock polarity, clock phase and other parameters + * @return pointer to new spi_slave structure + */ +struct spi_slave *spi_setup_slave_fdt(const void *blob, int node, + unsigned int cs, unsigned int max_hz, unsigned int mode); + #endif /* _SPI_H_ */ diff --git a/include/spi_flash.h b/include/spi_flash.h index 3b6a44e..e80785f 100644 --- a/include/spi_flash.h +++ b/include/spi_flash.h @@ -38,6 +38,16 @@ struct spi_flash { u32 page_size; /* Erase (sector) size */ u32 sector_size; +#ifdef CONFIG_SPI_FLASH_BAR + /* Bank read cmd */ + u8 bank_read_cmd; + /* Bank write cmd */ + u8 bank_write_cmd; + /* Current flash bank */ + u8 bank_curr; +#endif + /* Poll cmd - for flash erase/program */ + u8 poll_cmd; void *memory_map; /* Address of read-only SPI flash access */ int (*read)(struct spi_flash *flash, u32 offset, diff --git a/include/splash.h b/include/splash.h new file mode 100644 index 0000000..89ee7b2 --- /dev/null +++ b/include/splash.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2013, Boundary Devices <info@boundarydevices.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., http://www.fsf.org/about/contact/ + */ + +#ifndef _SPLASH_H_ +#define _SPLASH_H_ + + +int splash_screen_prepare(void); + +#ifdef CONFIG_SPLASH_SCREEN_ALIGN +void splash_get_pos(int *x, int *y); +#else +static inline void splash_get_pos(int *x, int *y) { } +#endif + +#define BMP_ALIGN_CENTER 0x7FFF + +#endif diff --git a/include/trace.h b/include/trace.h new file mode 100644 index 0000000..8082466 --- /dev/null +++ b/include/trace.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 __TRACE_H +#define __TRACE_H + +enum { + /* + * This affects the granularity of our trace. We can bin function + * entry points into groups on the basis that functions typically + * have a minimum size, so entry points can't appear any closer + * than this to each other. + * + * The value here assumes a minimum instruction size of 4 bytes, + * or that instructions are 2 bytes but there are at least 2 of + * them in every function. + * + * Increasing this value reduces the number of functions we can + * resolve, but reduces the size of the uintptr_t array used for + * our function list, which is the length of the code divided by + * this value. + */ + FUNC_SITE_SIZE = 4, /* distance between function sites */ +}; + +enum trace_chunk_type { + TRACE_CHUNK_FUNCS, + TRACE_CHUNK_CALLS, +}; + +/* A trace record for a function, as written to the profile output file */ +struct trace_output_func { + uint32_t offset; /* Function offset into code */ + uint32_t call_count; /* Number of times called */ +}; + +/* A header at the start of the trace output buffer */ +struct trace_output_hdr { + enum trace_chunk_type type; /* Record type */ + uint32_t rec_count; /* Number of records */ +}; + +/* Print statistics about traced function calls */ +void trace_print_stats(void); + +/** + * Dump a list of functions and call counts into a buffer + * + * Each record in the buffer is a struct trace_func_stats. The 'needed' + * parameter returns the number of bytes needed to complete the operation, + * which may be more than buff_size if your buffer is too small. + * + * @param buff Buffer in which to place data, or NULL to count size + * @param buff_size Size of buffer + * @param needed Returns number of bytes used / needed + * @return 0 if ok, -1 on error (buffer exhausted) + */ +int trace_list_functions(void *buff, int buff_size, unsigned *needed); + +/* Flags for ftrace_record */ +enum ftrace_flags { + FUNCF_EXIT = 0UL << 30, + FUNCF_ENTRY = 1UL << 30, + FUNCF_TEXTBASE = 2UL << 30, + + FUNCF_TIMESTAMP_MASK = 0x3fffffff, +}; + +#define TRACE_CALL_TYPE(call) ((call)->flags & 0xc0000000UL) + +/* Information about a single function entry/exit */ +struct trace_call { + uint32_t func; /* Function offset */ + uint32_t caller; /* Caller function offset */ + uint32_t flags; /* Flags and timestamp */ +}; + +int trace_list_calls(void *buff, int buff_size, unsigned int *needed); + +/** + * Turn function tracing on and off + * + * Don't enable trace if it has not been initialised. + * + * @param enabled 1 to enable trace, 0 to disable + */ +void trace_set_enabled(int enabled); + +#ifdef CONFIG_TRACE_EARLY +int trace_early_init(void); +#else +static inline int trace_early_init(void) +{ + return 0; +} +#endif + +/** + * Init the trace system + * + * This should be called after relocation with a suitably large buffer + * (typically as large as the U-Boot text area) + * + * @param buff Pointer to trace buffer + * @param buff_size Size of trace buffer + */ +int trace_init(void *buff, size_t buff_size); + +#endif diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h new file mode 100644 index 0000000..2d2d243 --- /dev/null +++ b/include/usb/fotg210.h @@ -0,0 +1,364 @@ +/* + * Faraday USB 2.0 OTG Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#ifndef _FOTG210_H +#define _FOTG210_H + +struct fotg210_regs { + /* USB Host Controller */ + struct { + uint32_t data[4]; + } hccr; /* 0x00 - 0x0f: hccr */ + struct { + uint32_t data[9]; + } hcor; /* 0x10 - 0x33: hcor */ + uint32_t rsvd1[3]; + uint32_t miscr; /* 0x40: Miscellaneous Register */ + uint32_t rsvd2[15]; + /* USB OTG Controller */ + uint32_t otgcsr;/* 0x80: OTG Control Status Register */ + uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */ + uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */ + uint32_t rsvd3[13]; + uint32_t isr; /* 0xC0: Global Interrupt Status Register */ + uint32_t imr; /* 0xC4: Global Interrupt Mask Register */ + uint32_t rsvd4[14]; + /* USB Device Controller */ + uint32_t dev_ctrl;/* 0x100: Device Control Register */ + uint32_t dev_addr;/* 0x104: Device Address Register */ + uint32_t dev_test;/* 0x108: Device Test Register */ + uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */ + uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */ + uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */ + uint32_t rsvd5[2]; + uint32_t cxfifo;/* 0x120: CX FIFO Register */ + uint32_t idle; /* 0x124: IDLE Counter Register */ + uint32_t rsvd6[2]; + uint32_t gimr; /* 0x130: Group Interrupt Mask Register */ + uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */ + uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */ + uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */ + uint32_t gisr; /* 0x140: Group Interrupt Status Register */ + uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */ + uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */ + uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */ + uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */ + uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */ + uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */ + uint32_t rsvd7[1]; + uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */ + uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */ + uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */ + uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */ + uint32_t fifomap;/* 0x1a8: FIFO Map Register */ + uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */ + uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */ + uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */ + uint32_t rsvd8[1]; + uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */ + uint32_t dma_addr; /* 0x1cc: DMA Address Register */ + uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */ +}; + +/* Miscellaneous Register */ +#define MISCR_SUSPEND (1 << 6) /* Put transceiver in suspend mode */ +#define MISCR_EOF2(x) (((x) & 0x3) << 4) /* EOF 2 Timing */ +#define MISCR_EOF1(x) (((x) & 0x3) << 2) /* EOF 1 Timing */ +#define MISCR_ASST(x) (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */ + +/* OTG Control Status Register */ +#define OTGCSR_SPD_HIGH (2 << 22) /* Speed of the attached device (host) */ +#define OTGCSR_SPD_LOW (1 << 22) +#define OTGCSR_SPD_FULL (0 << 22) +#define OTGCSR_SPD_MASK (3 << 22) +#define OTGCSR_SPD_SHIFT 22 +#define OTGCSR_SPD(x) (((x) >> 22) & 0x03) +#define OTGCSR_DEV_A (0 << 21) /* Acts as A-device */ +#define OTGCSR_DEV_B (1 << 21) /* Acts as B-device */ +#define OTGCSR_ROLE_H (0 << 20) /* Acts as Host */ +#define OTGCSR_ROLE_D (1 << 20) /* Acts as Device */ +#define OTGCSR_A_VBUS_VLD (1 << 19) /* A-device VBUS Valid */ +#define OTGCSR_A_SESS_VLD (1 << 18) /* A-device Session Valid */ +#define OTGCSR_B_SESS_VLD (1 << 17) /* B-device Session Valid */ +#define OTGCSR_B_SESS_END (1 << 16) /* B-device Session End */ +#define OTGCSR_HFT_LONG (1 << 11) /* HDISCON noise filter = 270 us*/ +#define OTGCSR_HFT (0 << 11) /* HDISCON noise filter = 135 us*/ +#define OTGCSR_VFT_LONG (1 << 10) /* VBUS noise filter = 472 us*/ +#define OTGCSR_VFT (0 << 10) /* VBUS noise filter = 135 us*/ +#define OTGCSR_IDFT_LONG (1 << 9) /* ID noise filter = 4 ms*/ +#define OTGCSR_IDFT (0 << 9) /* ID noise filter = 3 ms*/ +#define OTGCSR_A_SRPR_VBUS (0 << 8) /* A-device: SRP responds to VBUS */ +#define OTGCSR_A_SRPR_DATA (1 << 8) /* A-device: SRP responds to DATA-LINE */ +#define OTGCSR_A_SRP_EN (1 << 7) /* A-device SRP detection enabled */ +#define OTGCSR_A_HNP (1 << 6) /* Set role=A-device with HNP enabled */ +#define OTGCSR_A_BUSDROP (1 << 5) /* A-device drop bus (power-down) */ +#define OTGCSR_A_BUSREQ (1 << 4) /* A-device request bus */ +#define OTGCSR_B_VBUS_DISC (1 << 2) /* B-device discharges VBUS */ +#define OTGCSR_B_HNP (1 << 1) /* B-device enable HNP */ +#define OTGCSR_B_BUSREQ (1 << 0) /* B-device request bus */ + +/* OTG Interrupt Status Register */ +#define OTGISR_APRM (1 << 12) /* Mini-A plug removed */ +#define OTGISR_BPRM (1 << 11) /* Mini-B plug removed */ +#define OTGISR_OVD (1 << 10) /* over-current detected */ +#define OTGISR_IDCHG (1 << 9) /* ID(A/B) changed */ +#define OTGISR_RLCHG (1 << 8) /* Role(Host/Device) changed */ +#define OTGISR_BSESSEND (1 << 6) /* B-device Session End */ +#define OTGISR_AVBUSERR (1 << 5) /* A-device VBUS Error */ +#define OTGISR_ASRP (1 << 4) /* A-device SRP detected */ +#define OTGISR_BSRP (1 << 0) /* B-device SRP complete */ + +/* OTG Interrupt Enable Register */ +#define OTGIER_APRM (1 << 12) /* Mini-A plug removed */ +#define OTGIER_BPRM (1 << 11) /* Mini-B plug removed */ +#define OTGIER_OVD (1 << 10) /* over-current detected */ +#define OTGIER_IDCHG (1 << 9) /* ID(A/B) changed */ +#define OTGIER_RLCHG (1 << 8) /* Role(Host/Device) changed */ +#define OTGIER_BSESSEND (1 << 6) /* B-device Session End */ +#define OTGIER_AVBUSERR (1 << 5) /* A-device VBUS Error */ +#define OTGIER_ASRP (1 << 4) /* A-device SRP detected */ +#define OTGIER_BSRP (1 << 0) /* B-device SRP complete */ + +/* Global Interrupt Status Register (W1C) */ +#define ISR_HOST (1 << 2) /* USB Host interrupt */ +#define ISR_OTG (1 << 1) /* USB OTG interrupt */ +#define ISR_DEV (1 << 0) /* USB Device interrupt */ +#define ISR_MASK 0x07 + +/* Global Interrupt Mask Register */ +#define IMR_IRQLH (1 << 3) /* Interrupt triggered at level-high */ +#define IMR_IRQLL (0 << 3) /* Interrupt triggered at level-low */ +#define IMR_HOST (1 << 2) /* USB Host interrupt */ +#define IMR_OTG (1 << 1) /* USB OTG interrupt */ +#define IMR_DEV (1 << 0) /* USB Device interrupt */ +#define IMR_MASK 0x0f + +/* Device Control Register */ +#define DEVCTRL_FS_FORCED (1 << 9) /* Forced to be Full-Speed Mode */ +#define DEVCTRL_HS (1 << 6) /* High Speed Mode */ +#define DEVCTRL_FS (0 << 6) /* Full Speed Mode */ +#define DEVCTRL_EN (1 << 5) /* Chip Enable */ +#define DEVCTRL_RESET (1 << 4) /* Chip Software Reset */ +#define DEVCTRL_SUSPEND (1 << 3) /* Enter Suspend Mode */ +#define DEVCTRL_GIRQ_EN (1 << 2) /* Global Interrupt Enabled */ +#define DEVCTRL_HALFSPD (1 << 1) /* Half speed mode for FPGA test */ +#define DEVCTRL_RWAKEUP (1 << 0) /* Enable remote wake-up */ + +/* Device Address Register */ +#define DEVADDR_CONF (1 << 7) /* SET_CONFIGURATION has been executed */ +#define DEVADDR_ADDR(x) ((x) & 0x7f) +#define DEVADDR_ADDR_MASK 0x7f + +/* Device Test Register */ +#define DEVTEST_NOSOF (1 << 6) /* Do not generate SOF */ +#define DEVTEST_TST_MODE (1 << 5) /* Enter Test Mode */ +#define DEVTEST_TST_NOTS (1 << 4) /* Do not toggle sequence */ +#define DEVTEST_TST_NOCRC (1 << 3) /* Do not append CRC */ +#define DEVTEST_TST_CLREA (1 << 2) /* Clear External Side Address */ +#define DEVTEST_TST_CXLP (1 << 1) /* EP0 loopback test */ +#define DEVTEST_TST_CLRFF (1 << 0) /* Clear FIFO */ + +/* SOF Frame Number Register */ +#define SOFFNR_UFN(x) (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */ +#define SOFFNR_FNR(x) ((x) & 0x7ff) /* SOF Frame Number */ + +/* SOF Mask Timer Register */ +#define SOFMTR_TMR(x) ((x) & 0xffff) + +/* PHY Test Mode Selector Register */ +#define PHYTMSR_TST_PKT (1 << 4) /* Packet send test */ +#define PHYTMSR_TST_SE0NAK (1 << 3) /* High-Speed quiescent state */ +#define PHYTMSR_TST_KSTA (1 << 2) /* High-Speed K state */ +#define PHYTMSR_TST_JSTA (1 << 1) /* High-Speed J state */ +#define PHYTMSR_UNPLUG (1 << 0) /* Enable soft-detachment */ + +/* CX FIFO Register */ +#define CXFIFO_BYTES(x) (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */ +#define CXFIFO_FIFOE(x) (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */ +#define CXFIFO_FIFOE_FIFO0 (1 << 8) +#define CXFIFO_FIFOE_FIFO1 (1 << 9) +#define CXFIFO_FIFOE_FIFO2 (1 << 10) +#define CXFIFO_FIFOE_FIFO3 (1 << 11) +#define CXFIFO_FIFOE_MASK (0x0f << 8) +#define CXFIFO_CXFIFOE (1 << 5) /* CX FIFO empty */ +#define CXFIFO_CXFIFOF (1 << 4) /* CX FIFO full */ +#define CXFIFO_CXFIFOCLR (1 << 3) /* CX FIFO clear */ +#define CXFIFO_CXSTALL (1 << 2) /* CX Stall */ +#define CXFIFO_TSTPKTFIN (1 << 1) /* Test packet data transfer finished */ +#define CXFIFO_CXFIN (1 << 0) /* CX data transfer finished */ + +/* IDLE Counter Register */ +#define IDLE_MS(x) ((x) & 0x07) /* PHY suspend delay = x ms */ + +/* Group Interrupt Mask(Disable) Register */ +#define GIMR_GRP2 (1 << 2) /* Disable interrupt group 2 */ +#define GIMR_GRP1 (1 << 1) /* Disable interrupt group 1 */ +#define GIMR_GRP0 (1 << 0) /* Disable interrupt group 0 */ +#define GIMR_MASK 0x07 + +/* Group Interrupt Mask(Disable) Register 0 (CX) */ +#define GIMR0_CXABORT (1 << 5) /* CX command abort interrupt */ +#define GIMR0_CXERR (1 << 4) /* CX command error interrupt */ +#define GIMR0_CXEND (1 << 3) /* CX command end interrupt */ +#define GIMR0_CXOUT (1 << 2) /* EP0-OUT packet interrupt */ +#define GIMR0_CXIN (1 << 1) /* EP0-IN packet interrupt */ +#define GIMR0_CXSETUP (1 << 0) /* EP0-SETUP packet interrupt */ +#define GIMR0_MASK 0x3f + +/* Group Interrupt Mask(Disable) Register 1 (FIFO) */ +#define GIMR1_FIFO_IN(x) (1 << (((x) & 3) + 16)) /* FIFOx IN */ +#define GIMR1_FIFO_TX(x) GIMR1_FIFO_IN(x) +#define GIMR1_FIFO_OUT(x) (1 << (((x) & 3) * 2)) /* FIFOx OUT */ +#define GIMR1_FIFO_SPK(x) (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */ +#define GIMR1_FIFO_RX(x) (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x)) +#define GIMR1_MASK 0xf00ff + +/* Group Interrupt Mask(Disable) Register 2 (Device) */ +#define GIMR2_WAKEUP (1 << 10) /* Device waked up */ +#define GIMR2_IDLE (1 << 9) /* Device idle */ +#define GIMR2_DMAERR (1 << 8) /* DMA error */ +#define GIMR2_DMAFIN (1 << 7) /* DMA finished */ +#define GIMR2_ZLPRX (1 << 6) /* Zero-Length-Packet Rx Interrupt */ +#define GIMR2_ZLPTX (1 << 5) /* Zero-Length-Packet Tx Interrupt */ +#define GIMR2_ISOCABT (1 << 4) /* ISOC Abort Interrupt */ +#define GIMR2_ISOCERR (1 << 3) /* ISOC Error Interrupt */ +#define GIMR2_RESUME (1 << 2) /* Resume state change Interrupt */ +#define GIMR2_SUSPEND (1 << 1) /* Suspend state change Interrupt */ +#define GIMR2_RESET (1 << 0) /* Reset Interrupt */ +#define GIMR2_MASK 0x7ff + +/* Group Interrupt Status Register */ +#define GISR_GRP2 (1 << 2) /* Interrupt group 2 */ +#define GISR_GRP1 (1 << 1) /* Interrupt group 1 */ +#define GISR_GRP0 (1 << 0) /* Interrupt group 0 */ + +/* Group Interrupt Status Register 0 (CX) */ +#define GISR0_CXABORT (1 << 5) /* CX command abort interrupt */ +#define GISR0_CXERR (1 << 4) /* CX command error interrupt */ +#define GISR0_CXEND (1 << 3) /* CX command end interrupt */ +#define GISR0_CXOUT (1 << 2) /* EP0-OUT packet interrupt */ +#define GISR0_CXIN (1 << 1) /* EP0-IN packet interrupt */ +#define GISR0_CXSETUP (1 << 0) /* EP0-SETUP packet interrupt */ + +/* Group Interrupt Status Register 1 (FIFO) */ +#define GISR1_IN_FIFO(x) (1 << (((x) & 0x03) + 16)) /* FIFOx IN */ +#define GISR1_OUT_FIFO(x) (1 << (((x) & 0x03) * 2)) /* FIFOx OUT */ +#define GISR1_SPK_FIFO(x) (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */ +#define GISR1_RX_FIFO(x) (3 << (((x) & 0x03) * 2)) /* FIFOx OUT/SPK */ + +/* Group Interrupt Status Register 2 (Device) */ +#define GISR2_WAKEUP (1 << 10) /* Device waked up */ +#define GISR2_IDLE (1 << 9) /* Device idle */ +#define GISR2_DMAERR (1 << 8) /* DMA error */ +#define GISR2_DMAFIN (1 << 7) /* DMA finished */ +#define GISR2_ZLPRX (1 << 6) /* Zero-Length-Packet Rx Interrupt */ +#define GISR2_ZLPTX (1 << 5) /* Zero-Length-Packet Tx Interrupt */ +#define GISR2_ISOCABT (1 << 4) /* ISOC Abort Interrupt */ +#define GISR2_ISOCERR (1 << 3) /* ISOC Error Interrupt */ +#define GISR2_RESUME (1 << 2) /* Resume state change Interrupt */ +#define GISR2_SUSPEND (1 << 1) /* Suspend state change Interrupt */ +#define GISR2_RESET (1 << 0) /* Reset Interrupt */ + +/* Receive Zero-Length-Packet Register */ +#define RXZLP_EP(x) (1 << ((x) - 1)) /* EPx ZLP rx interrupt */ + +/* Transfer Zero-Length-Packet Register */ +#define TXZLP_EP(x) (1 << ((x) - 1)) /* EPx ZLP tx interrupt */ + +/* ISOC Error/Abort Status Register */ +#define ISOEASR_EP(x) (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */ + +/* IN Endpoint Register */ +#define IEP_SENDZLP (1 << 15) /* Send Zero-Length-Packet */ +#define IEP_TNRHB(x) (((x) & 0x03) << 13) \ + /* Transaction Number for High-Bandwidth EP(ISOC) */ +#define IEP_RESET (1 << 12) /* Reset Toggle Sequence */ +#define IEP_STALL (1 << 11) /* Stall */ +#define IEP_MAXPS(x) ((x) & 0x7ff) /* Max. packet size */ + +/* OUT Endpoint Register */ +#define OEP_RESET (1 << 12) /* Reset Toggle Sequence */ +#define OEP_STALL (1 << 11) /* Stall */ +#define OEP_MAXPS(x) ((x) & 0x7ff) /* Max. packet size */ + +/* Endpoint Map Register (EP1 ~ EP4) */ +#define EPMAP14_SET_IN(ep, fifo) \ + ((fifo) & 3) << (((ep) - 1) << 3 + 0) +#define EPMAP14_SET_OUT(ep, fifo) \ + ((fifo) & 3) << (((ep) - 1) << 3 + 4) +#define EPMAP14_SET(ep, in, out) \ + do { \ + EPMAP14_SET_IN(ep, in); \ + EPMAP14_SET_OUT(ep, out); \ + } while (0) + +#define EPMAP14_DEFAULT 0x33221100 /* EP1->FIFO0, EP2->FIFO1... */ + +/* Endpoint Map Register (EP5 ~ EP8) */ +#define EPMAP58_SET_IN(ep, fifo) \ + ((fifo) & 3) << (((ep) - 5) << 3 + 0) +#define EPMAP58_SET_OUT(ep, fifo) \ + ((fifo) & 3) << (((ep) - 5) << 3 + 4) +#define EPMAP58_SET(ep, in, out) \ + do { \ + EPMAP58_SET_IN(ep, in); \ + EPMAP58_SET_OUT(ep, out); \ + } while (0) + +#define EPMAP58_DEFAULT 0x00000000 /* All EPx->FIFO0 */ + +/* FIFO Map Register */ +#define FIFOMAP_BIDIR (2 << 4) +#define FIFOMAP_IN (1 << 4) +#define FIFOMAP_OUT (0 << 4) +#define FIFOMAP_DIR_MASK 0x30 +#define FIFOMAP_EP(x) ((x) & 0x0f) +#define FIFOMAP_EP_MASK 0x0f +#define FIFOMAP_CFG_MASK 0x3f +#define FIFOMAP_DEFAULT 0x04030201 /* FIFO0->EP1, FIFO1->EP2... */ +#define FIFOMAP(fifo, cfg) (((cfg) & 0x3f) << (((fifo) & 3) << 3)) + +/* FIFO Configuration Register */ +#define FIFOCFG_EN (1 << 5) +#define FIFOCFG_BLKSZ_1024 (1 << 4) +#define FIFOCFG_BLKSZ_512 (0 << 4) +#define FIFOCFG_3BLK (2 << 2) +#define FIFOCFG_2BLK (1 << 2) +#define FIFOCFG_1BLK (0 << 2) +#define FIFOCFG_NBLK_MASK 3 +#define FIFOCFG_NBLK_SHIFT 2 +#define FIFOCFG_INTR (3 << 0) +#define FIFOCFG_BULK (2 << 0) +#define FIFOCFG_ISOC (1 << 0) +#define FIFOCFG_RSVD (0 << 0) /* Reserved */ +#define FIFOCFG_TYPE_MASK 3 +#define FIFOCFG_TYPE_SHIFT 0 +#define FIFOCFG_CFG_MASK 0x3f +#define FIFOCFG(fifo, cfg) (((cfg) & 0x3f) << (((fifo) & 3) << 3)) + +/* FIFO Control Status Register */ +#define FIFOCSR_RESET (1 << 12) /* FIFO Reset */ +#define FIFOCSR_BYTES(x) ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */ + +/* DMA Target FIFO Register */ +#define DMAFIFO_CX (1 << 4) /* DMA FIFO = CX FIFO */ +#define DMAFIFO_FIFO(x) (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */ + +/* DMA Control Register */ +#define DMACTRL_LEN(x) (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */ +#define DMACTRL_LEN_SHIFT 8 +#define DMACTRL_CLRFF (1 << 4) /* Clear FIFO upon DMA abort */ +#define DMACTRL_ABORT (1 << 3) /* DMA abort */ +#define DMACTRL_IO2IO (1 << 2) /* IO to IO */ +#define DMACTRL_FIFO2MEM (0 << 1) /* FIFO to Memory */ +#define DMACTRL_MEM2FIFO (1 << 1) /* Memory to FIFO */ +#define DMACTRL_START (1 << 0) /* DMA start */ + +#endif diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h new file mode 100644 index 0000000..8a9c488 --- /dev/null +++ b/include/usb/fusbh200.h @@ -0,0 +1,61 @@ +/* + * Faraday USB 2.0 EHCI Controller + * + * (C) Copyright 2010 Faraday Technology + * Dante Su <dantesu@faraday-tech.com> + * + * This file is released under the terms of GPL v2 and any later version. + * See the file COPYING in the root directory of the source tree for details. + */ + +#ifndef _FUSBH200_H +#define _FUSBH200_H + +struct fusbh200_regs { + struct { + uint32_t data[4]; + } hccr; /* 0x00 - 0x0f: hccr */ + struct { + uint32_t data[9]; + } hcor; /* 0x10 - 0x33: hcor */ + uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */ + uint32_t rsvd[2]; + uint32_t bmcsr; /* 0x40: Bus Monitor Control Status Register */ + uint32_t bmisr; /* 0x44: Bus Monitor Interrupt Status Register */ + uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */ +}; + +/* EOF & Async. Schedule Sleep Timer Register */ +#define EASSTR_RUNNING (1 << 6) /* Put transceiver in running/resume mode */ +#define EASSTR_SUSPEND (0 << 6) /* Put transceiver in suspend mode */ +#define EASSTR_EOF2(x) (((x) & 0x3) << 4) /* EOF 2 Timing */ +#define EASSTR_EOF1(x) (((x) & 0x3) << 2) /* EOF 1 Timing */ +#define EASSTR_ASST(x) (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */ + +/* Bus Monitor Control Status Register */ +#define BMCSR_SPD_HIGH (2 << 9) /* Speed of the attached device */ +#define BMCSR_SPD_LOW (1 << 9) +#define BMCSR_SPD_FULL (0 << 9) +#define BMCSR_SPD_MASK (3 << 9) +#define BMCSR_SPD_SHIFT 9 +#define BMCSR_SPD(x) ((x >> 9) & 0x03) +#define BMCSR_VBUS (1 << 8) /* VBUS Valid */ +#define BMCSR_VBUS_OFF (1 << 4) /* VBUS Off */ +#define BMCSR_VBUS_ON (0 << 4) /* VBUS On */ +#define BMCSR_IRQLH (1 << 3) /* IRQ triggered at level-high */ +#define BMCSR_IRQLL (0 << 3) /* IRQ triggered at level-low */ +#define BMCSR_HALFSPD (1 << 2) /* Half speed mode for FPGA test */ +#define BMCSR_HFT_LONG (1 << 1) /* HDISCON noise filter = 270 us*/ +#define BMCSR_HFT (0 << 1) /* HDISCON noise filter = 135 us*/ +#define BMCSR_VFT_LONG (1 << 1) /* VBUS noise filter = 472 us*/ +#define BMCSR_VFT (0 << 1) /* VBUS noise filter = 135 us*/ + +/* Bus Monitor Interrupt Status Register */ +/* Bus Monitor Interrupt Enable Register */ +#define BMISR_DMAERR (1 << 4) /* DMA error */ +#define BMISR_DMA (1 << 3) /* DMA complete */ +#define BMISR_DEVRM (1 << 2) /* device removed */ +#define BMISR_OVD (1 << 1) /* over-current detected */ +#define BMISR_VBUSERR (1 << 0) /* VBUS error */ + +#endif diff --git a/include/vsprintf.h b/include/vsprintf.h index 651077c..6568854 100644 --- a/include/vsprintf.h +++ b/include/vsprintf.h @@ -178,4 +178,15 @@ int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vscnprintf(buf, size, fmt, args...) vsprintf(buf, fmt, ##args) #endif /* CONFIG_SYS_VSNPRINTF */ +/** + * print_grouped_ull() - print a value with digits grouped by ',' + * + * This prints a value with grouped digits, like 12,345,678 to make it easier + * to read. + * + * @val: Value to print + * @digits: Number of digiits to print + */ +void print_grouped_ull(unsigned long long int_val, int digits); + #endif diff --git a/lib/Makefile b/lib/Makefile index 5d58609..f5a8819 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -26,7 +26,6 @@ include $(TOPDIR)/config.mk LIB = $(obj)libgeneric.o ifndef CONFIG_SPL_BUILD -COBJS-$(CONFIG_ADDR_MAP) += addr_map.o COBJS-$(CONFIG_AES) += aes.o COBJS-$(CONFIG_BZIP2) += bzlib.o COBJS-$(CONFIG_BZIP2) += bzlib_crctable.o @@ -36,13 +35,10 @@ COBJS-$(CONFIG_BZIP2) += bzlib_huffman.o COBJS-$(CONFIG_USB_TTY) += circbuf.o COBJS-y += crc7.o COBJS-y += crc16.o -COBJS-y += display_options.o -COBJS-y += errno.o COBJS-$(CONFIG_OF_CONTROL) += fdtdec.o COBJS-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o COBJS-$(CONFIG_GZIP) += gunzip.o COBJS-$(CONFIG_GZIP_COMPRESSED) += gzip.o -COBJS-y += hashtable.o COBJS-y += initcall.o COBJS-$(CONFIG_LMB) += lmb.o COBJS-y += ldiv.o @@ -60,14 +56,12 @@ endif ifdef CONFIG_SPL_BUILD COBJS-$(CONFIG_SPL_YMODEM_SUPPORT) += crc16.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += crc32.o -ifneq ($(CONFIG_SPL_SPI_FLASH_SUPPORT)$(CONFIG_SPL_NET_SUPPORT),) -COBJS-y += display_options.o -endif -COBJS-$(CONFIG_SPL_NET_SUPPORT) += errno.o -COBJS-$(CONFIG_SPL_NET_SUPPORT) += hashtable.o COBJS-$(CONFIG_SPL_NET_SUPPORT) += net_utils.o endif +COBJS-$(CONFIG_ADDR_MAP) += addr_map.o +COBJS-y += hashtable.o +COBJS-y += errno.o +COBJS-y += display_options.o COBJS-$(CONFIG_BCH) += bch.o COBJS-y += crc32.o COBJS-y += ctype.o @@ -77,6 +71,7 @@ COBJS-y += linux_string.o COBJS-$(CONFIG_REGEX) += slre.o COBJS-y += string.o COBJS-y += time.o +COBJS-$(CONFIG_TRACE) += trace.o COBJS-$(CONFIG_BOOTP_PXE) += uuid.o COBJS-y += vsprintf.o COBJS-$(CONFIG_RANDOM_MACADDR) += rand.o diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 24ccd0a..1b3c810 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -59,6 +59,8 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"), COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"), COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"), + COMPAT(GOOGLE_CROS_EC, "google,cros-ec"), + COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"), COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"), COMPAT(SAMSUNG_EXYNOS_USB_PHY, "samsung,exynos-usb-phy"), COMPAT(SAMSUNG_EXYNOS_TMU, "samsung,exynos-tmu"), @@ -70,6 +72,7 @@ static const char * const compat_names[COMPAT_COUNT] = { COMPAT(GENERIC_SPI_FLASH, "spi-flash"), COMPAT(MAXIM_98095_CODEC, "maxim,max98095-codec"), COMPAT(INFINEON_SLB9635_TPM, "infineon,slb9635-tpm"), + COMPAT(INFINEON_SLB9645_TPM, "infineon,slb9645-tpm"), }; const char *fdtdec_get_compatible(enum fdt_compat_id id) diff --git a/lib/libfdt/fdt_wip.c b/lib/libfdt/fdt_wip.c index 63e67b7..b9e3c4a 100644 --- a/lib/libfdt/fdt_wip.c +++ b/lib/libfdt/fdt_wip.c @@ -120,3 +120,132 @@ int fdt_nop_node(void *fdt, int nodeoffset) endoffset - nodeoffset); return 0; } + +#define FDT_MAX_DEPTH 32 + +static int str_in_list(const char *str, char * const list[], int count) +{ + int i; + + for (i = 0; i < count; i++) + if (!strcmp(list[i], str)) + return 1; + + return 0; +} + +int fdt_find_regions(const void *fdt, char * const inc[], int inc_count, + char * const exc_prop[], int exc_prop_count, + struct fdt_region region[], int max_regions, + char *path, int path_len, int add_string_tab) +{ + int stack[FDT_MAX_DEPTH]; + char *end; + int nextoffset = 0; + uint32_t tag; + int count = 0; + int start = -1; + int depth = -1; + int want = 0; + int base = fdt_off_dt_struct(fdt); + + end = path; + *end = '\0'; + do { + const struct fdt_property *prop; + const char *name; + const char *str; + int include = 0; + int stop_at = 0; + int offset; + int len; + + offset = nextoffset; + tag = fdt_next_tag(fdt, offset, &nextoffset); + stop_at = nextoffset; + + switch (tag) { + case FDT_PROP: + include = want >= 2; + stop_at = offset; + prop = fdt_get_property_by_offset(fdt, offset, NULL); + str = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); + if (str_in_list(str, exc_prop, exc_prop_count)) + include = 0; + break; + + case FDT_NOP: + include = want >= 2; + stop_at = offset; + break; + + case FDT_BEGIN_NODE: + depth++; + if (depth == FDT_MAX_DEPTH) + return -FDT_ERR_BADSTRUCTURE; + name = fdt_get_name(fdt, offset, &len); + if (end - path + 2 + len >= path_len) + return -FDT_ERR_NOSPACE; + if (end != path + 1) + *end++ = '/'; + strcpy(end, name); + end += len; + stack[depth] = want; + if (want == 1) + stop_at = offset; + if (str_in_list(path, inc, inc_count)) + want = 2; + else if (want) + want--; + else + stop_at = offset; + include = want; + break; + + case FDT_END_NODE: + include = want; + want = stack[depth--]; + while (end > path && *--end != '/') + ; + *end = '\0'; + break; + + case FDT_END: + include = 1; + break; + } + + if (include && start == -1) { + /* Should we merge with previous? */ + if (count && count <= max_regions && + offset == region[count - 1].offset + + region[count - 1].size - base) + start = region[--count].offset - base; + else + start = offset; + } + + if (!include && start != -1) { + if (count < max_regions) { + region[count].offset = base + start; + region[count].size = stop_at - start; + } + count++; + start = -1; + } + } while (tag != FDT_END); + + if (nextoffset != fdt_size_dt_struct(fdt)) + return -FDT_ERR_BADLAYOUT; + + /* Add a region for the END tag and the string table */ + if (count < max_regions) { + region[count].offset = base + start; + region[count].size = nextoffset - start; + if (add_string_tab) + region[count].size += fdt_size_dt_strings(fdt); + } + count++; + + return count; +} diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile new file mode 100644 index 0000000..9eb3e40 --- /dev/null +++ b/lib/rsa/Makefile @@ -0,0 +1,48 @@ +# +# Copyright (c) 2013, Google Inc. +# +# (C) Copyright 2000-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)librsa.o + +ifdef CONFIG_FIT_SIGNATURE +COBJS-$(CONFIG_RSA) += rsa-verify.o +endif + +COBJS := $(sort $(COBJS-y)) +SRCS := $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(call cmd_link_o_target, $(OBJS)) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c new file mode 100644 index 0000000..e30d8ca --- /dev/null +++ b/lib/rsa/rsa-sign.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public 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 "mkimage.h" +#include <stdio.h> +#include <string.h> +#include <image.h> +#include <time.h> +#include <openssl/rsa.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/ssl.h> +#include <openssl/evp.h> + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L +#define HAVE_ERR_REMOVE_THREAD_STATE +#endif + +static int rsa_err(const char *msg) +{ + unsigned long sslErr = ERR_get_error(); + + fprintf(stderr, "%s", msg); + fprintf(stderr, ": %s\n", + ERR_error_string(sslErr, 0)); + + return -1; +} + +/** + * rsa_get_pub_key() - read a public key from a .crt file + * + * @keydir: Directory containins the key + * @name Name of key file (will have a .crt extension) + * @rsap Returns RSA object, or NULL on failure + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) + */ +static int rsa_get_pub_key(const char *keydir, const char *name, RSA **rsap) +{ + char path[1024]; + EVP_PKEY *key; + X509 *cert; + RSA *rsa; + FILE *f; + int ret; + + *rsap = NULL; + snprintf(path, sizeof(path), "%s/%s.crt", keydir, name); + f = fopen(path, "r"); + if (!f) { + fprintf(stderr, "Couldn't open RSA certificate: '%s': %s\n", + path, strerror(errno)); + return -EACCES; + } + + /* Read the certificate */ + cert = NULL; + if (!PEM_read_X509(f, &cert, NULL, NULL)) { + rsa_err("Couldn't read certificate"); + ret = -EINVAL; + goto err_cert; + } + + /* Get the public key from the certificate. */ + key = X509_get_pubkey(cert); + if (!key) { + rsa_err("Couldn't read public key\n"); + ret = -EINVAL; + goto err_pubkey; + } + + /* Convert to a RSA_style key. */ + rsa = EVP_PKEY_get1_RSA(key); + if (!rsa) { + rsa_err("Couldn't convert to a RSA style key"); + goto err_rsa; + } + fclose(f); + EVP_PKEY_free(key); + X509_free(cert); + *rsap = rsa; + + return 0; + +err_rsa: + EVP_PKEY_free(key); +err_pubkey: + X509_free(cert); +err_cert: + fclose(f); + return ret; +} + +/** + * rsa_get_priv_key() - read a private key from a .key file + * + * @keydir: Directory containins the key + * @name Name of key file (will have a .key extension) + * @rsap Returns RSA object, or NULL on failure + * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL) + */ +static int rsa_get_priv_key(const char *keydir, const char *name, RSA **rsap) +{ + char path[1024]; + RSA *rsa; + FILE *f; + + *rsap = NULL; + snprintf(path, sizeof(path), "%s/%s.key", keydir, name); + f = fopen(path, "r"); + if (!f) { + fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n", + path, strerror(errno)); + return -ENOENT; + } + + rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path); + if (!rsa) { + rsa_err("Failure reading private key"); + fclose(f); + return -EPROTO; + } + fclose(f); + *rsap = rsa; + + return 0; +} + +static int rsa_init(void) +{ + int ret; + + ret = SSL_library_init(); + if (!ret) { + fprintf(stderr, "Failure to init SSL library\n"); + return -1; + } + SSL_load_error_strings(); + + OpenSSL_add_all_algorithms(); + OpenSSL_add_all_digests(); + OpenSSL_add_all_ciphers(); + + return 0; +} + +static void rsa_remove(void) +{ + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); +#ifdef HAVE_ERR_REMOVE_THREAD_STATE + ERR_remove_thread_state(NULL); +#else + ERR_remove_state(0); +#endif + EVP_cleanup(); +} + +static int rsa_sign_with_key(RSA *rsa, const struct image_region region[], + int region_count, uint8_t **sigp, uint *sig_size) +{ + EVP_PKEY *key; + EVP_MD_CTX *context; + int size, ret = 0; + uint8_t *sig; + int i; + + key = EVP_PKEY_new(); + if (!key) + return rsa_err("EVP_PKEY object creation failed"); + + if (!EVP_PKEY_set1_RSA(key, rsa)) { + ret = rsa_err("EVP key setup failed"); + goto err_set; + } + + size = EVP_PKEY_size(key); + sig = malloc(size); + if (!sig) { + fprintf(stderr, "Out of memory for signature (%d bytes)\n", + size); + ret = -ENOMEM; + goto err_alloc; + } + + context = EVP_MD_CTX_create(); + if (!context) { + ret = rsa_err("EVP context creation failed"); + goto err_create; + } + EVP_MD_CTX_init(context); + if (!EVP_SignInit(context, EVP_sha1())) { + ret = rsa_err("Signer setup failed"); + goto err_sign; + } + + for (i = 0; i < region_count; i++) { + if (!EVP_SignUpdate(context, region[i].data, region[i].size)) { + ret = rsa_err("Signing data failed"); + goto err_sign; + } + } + + if (!EVP_SignFinal(context, sig, sig_size, key)) { + ret = rsa_err("Could not obtain signature"); + goto err_sign; + } + EVP_MD_CTX_cleanup(context); + EVP_MD_CTX_destroy(context); + EVP_PKEY_free(key); + + debug("Got signature: %d bytes, expected %d\n", *sig_size, size); + *sigp = sig; + *sig_size = size; + + return 0; + +err_sign: + EVP_MD_CTX_destroy(context); +err_create: + free(sig); +err_alloc: +err_set: + EVP_PKEY_free(key); + return ret; +} + +int rsa_sign(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t **sigp, uint *sig_len) +{ + RSA *rsa; + int ret; + + ret = rsa_init(); + if (ret) + return ret; + + ret = rsa_get_priv_key(info->keydir, info->keyname, &rsa); + if (ret) + goto err_priv; + ret = rsa_sign_with_key(rsa, region, region_count, sigp, sig_len); + if (ret) + goto err_sign; + + RSA_free(rsa); + rsa_remove(); + + return ret; + +err_sign: + RSA_free(rsa); +err_priv: + rsa_remove(); + return ret; +} + +/* + * rsa_get_params(): - Get the important parameters of an RSA public key + */ +int rsa_get_params(RSA *key, uint32_t *n0_invp, BIGNUM **modulusp, + BIGNUM **r_squaredp) +{ + BIGNUM *big1, *big2, *big32, *big2_32; + BIGNUM *n, *r, *r_squared, *tmp; + BN_CTX *bn_ctx = BN_CTX_new(); + int ret = 0; + + /* Initialize BIGNUMs */ + big1 = BN_new(); + big2 = BN_new(); + big32 = BN_new(); + r = BN_new(); + r_squared = BN_new(); + tmp = BN_new(); + big2_32 = BN_new(); + n = BN_new(); + if (!big1 || !big2 || !big32 || !r || !r_squared || !tmp || !big2_32 || + !n) { + fprintf(stderr, "Out of memory (bignum)\n"); + return -ENOMEM; + } + + if (!BN_copy(n, key->n) || !BN_set_word(big1, 1L) || + !BN_set_word(big2, 2L) || !BN_set_word(big32, 32L)) + ret = -1; + + /* big2_32 = 2^32 */ + if (!BN_exp(big2_32, big2, big32, bn_ctx)) + ret = -1; + + /* Calculate n0_inv = -1 / n[0] mod 2^32 */ + if (!BN_mod_inverse(tmp, n, big2_32, bn_ctx) || + !BN_sub(tmp, big2_32, tmp)) + ret = -1; + *n0_invp = BN_get_word(tmp); + + /* Calculate R = 2^(# of key bits) */ + if (!BN_set_word(tmp, BN_num_bits(n)) || + !BN_exp(r, big2, tmp, bn_ctx)) + ret = -1; + + /* Calculate r_squared = R^2 mod n */ + if (!BN_copy(r_squared, r) || + !BN_mul(tmp, r_squared, r, bn_ctx) || + !BN_mod(r_squared, tmp, n, bn_ctx)) + ret = -1; + + *modulusp = n; + *r_squaredp = r_squared; + + BN_free(big1); + BN_free(big2); + BN_free(big32); + BN_free(r); + BN_free(tmp); + BN_free(big2_32); + if (ret) { + fprintf(stderr, "Bignum operations failed\n"); + return -ENOMEM; + } + + return ret; +} + +static int fdt_add_bignum(void *blob, int noffset, const char *prop_name, + BIGNUM *num, int num_bits) +{ + int nwords = num_bits / 32; + int size; + uint32_t *buf, *ptr; + BIGNUM *tmp, *big2, *big32, *big2_32; + BN_CTX *ctx; + int ret; + + tmp = BN_new(); + big2 = BN_new(); + big32 = BN_new(); + big2_32 = BN_new(); + if (!tmp || !big2 || !big32 || !big2_32) { + fprintf(stderr, "Out of memory (bignum)\n"); + return -ENOMEM; + } + ctx = BN_CTX_new(); + if (!tmp) { + fprintf(stderr, "Out of memory (bignum context)\n"); + return -ENOMEM; + } + BN_set_word(big2, 2L); + BN_set_word(big32, 32L); + BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ + + size = nwords * sizeof(uint32_t); + buf = malloc(size); + if (!buf) { + fprintf(stderr, "Out of memory (%d bytes)\n", size); + return -ENOMEM; + } + + /* Write out modulus as big endian array of integers */ + for (ptr = buf + nwords - 1; ptr >= buf; ptr--) { + BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ + *ptr = cpu_to_fdt32(BN_get_word(tmp)); + BN_rshift(num, num, 32); /* N = N/B */ + } + + ret = fdt_setprop(blob, noffset, prop_name, buf, size); + if (ret) { + fprintf(stderr, "Failed to write public key to FIT\n"); + return -ENOSPC; + } + free(buf); + BN_free(tmp); + BN_free(big2); + BN_free(big32); + BN_free(big2_32); + + return ret; +} + +int rsa_add_verify_data(struct image_sign_info *info, void *keydest) +{ + BIGNUM *modulus, *r_squared; + uint32_t n0_inv; + int parent, node; + char name[100]; + int ret; + int bits; + RSA *rsa; + + debug("%s: Getting verification data\n", __func__); + ret = rsa_get_pub_key(info->keydir, info->keyname, &rsa); + if (ret) + return ret; + ret = rsa_get_params(rsa, &n0_inv, &modulus, &r_squared); + if (ret) + return ret; + bits = BN_num_bits(modulus); + parent = fdt_subnode_offset(keydest, 0, FIT_SIG_NODENAME); + if (parent == -FDT_ERR_NOTFOUND) { + parent = fdt_add_subnode(keydest, 0, FIT_SIG_NODENAME); + if (parent < 0) { + fprintf(stderr, "Couldn't create signature node: %s\n", + fdt_strerror(parent)); + return -EINVAL; + } + } + + /* Either create or overwrite the named key node */ + snprintf(name, sizeof(name), "key-%s", info->keyname); + node = fdt_subnode_offset(keydest, parent, name); + if (node == -FDT_ERR_NOTFOUND) { + node = fdt_add_subnode(keydest, parent, name); + if (node < 0) { + fprintf(stderr, "Could not create key subnode: %s\n", + fdt_strerror(node)); + return -EINVAL; + } + } else if (node < 0) { + fprintf(stderr, "Cannot select keys parent: %s\n", + fdt_strerror(node)); + return -ENOSPC; + } + + ret = fdt_setprop_string(keydest, node, "key-name-hint", + info->keyname); + ret |= fdt_setprop_u32(keydest, node, "rsa,num-bits", bits); + ret |= fdt_setprop_u32(keydest, node, "rsa,n0-inverse", n0_inv); + ret |= fdt_add_bignum(keydest, node, "rsa,modulus", modulus, bits); + ret |= fdt_add_bignum(keydest, node, "rsa,r-squared", r_squared, bits); + ret |= fdt_setprop_string(keydest, node, FIT_ALGO_PROP, + info->algo->name); + if (info->require_keys) { + fdt_setprop_string(keydest, node, "required", + info->require_keys); + } + BN_free(modulus); + BN_free(r_squared); + if (ret) + return -EIO; + + return 0; +} diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c new file mode 100644 index 0000000..6a02689 --- /dev/null +++ b/lib/rsa/rsa-verify.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2013, Google Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <fdtdec.h> +#include <rsa.h> +#include <sha1.h> +#include <asm/byteorder.h> +#include <asm/errno.h> +#include <asm/unaligned.h> + +/** + * struct rsa_public_key - holder for a public key + * + * An RSA public key consists of a modulus (typically called N), the inverse + * and R^2, where R is 2^(# key bits). + */ +struct rsa_public_key { + uint len; /* Length of modulus[] in number of uint32_t */ + uint32_t n0inv; /* -1 / modulus[0] mod 2^32 */ + uint32_t *modulus; /* modulus as little endian array */ + uint32_t *rr; /* R^2 as little endian array */ +}; + +#define UINT64_MULT32(v, multby) (((uint64_t)(v)) * ((uint32_t)(multby))) + +#define RSA2048_BYTES (2048 / 8) + +/* This is the minimum/maximum key size we support, in bits */ +#define RSA_MIN_KEY_BITS 2048 +#define RSA_MAX_KEY_BITS 2048 + +/* This is the maximum signature length that we support, in bits */ +#define RSA_MAX_SIG_BITS 2048 + +static const uint8_t padding_sha1_rsa2048[RSA2048_BYTES - SHA1_SUM_LEN] = { + 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30, + 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, + 0x05, 0x00, 0x04, 0x14 +}; + +/** + * subtract_modulus() - subtract modulus from the given value + * + * @key: Key containing modulus to subtract + * @num: Number to subtract modulus from, as little endian word array + */ +static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[]) +{ + int64_t acc = 0; + uint i; + + for (i = 0; i < key->len; i++) { + acc += (uint64_t)num[i] - key->modulus[i]; + num[i] = (uint32_t)acc; + acc >>= 32; + } +} + +/** + * greater_equal_modulus() - check if a value is >= modulus + * + * @key: Key containing modulus to check + * @num: Number to check against modulus, as little endian word array + * @return 0 if num < modulus, 1 if num >= modulus + */ +static int greater_equal_modulus(const struct rsa_public_key *key, + uint32_t num[]) +{ + uint32_t i; + + for (i = key->len - 1; i >= 0; i--) { + if (num[i] < key->modulus[i]) + return 0; + if (num[i] > key->modulus[i]) + return 1; + } + + return 1; /* equal */ +} + +/** + * montgomery_mul_add_step() - Perform montgomery multiply-add step + * + * Operation: montgomery result[] += a * b[] / n0inv % modulus + * + * @key: RSA key + * @result: Place to put result, as little endian word array + * @a: Multiplier + * @b: Multiplicand, as little endian word array + */ +static void montgomery_mul_add_step(const struct rsa_public_key *key, + uint32_t result[], const uint32_t a, const uint32_t b[]) +{ + uint64_t acc_a, acc_b; + uint32_t d0; + uint i; + + acc_a = (uint64_t)a * b[0] + result[0]; + d0 = (uint32_t)acc_a * key->n0inv; + acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a; + for (i = 1; i < key->len; i++) { + acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i]; + acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] + + (uint32_t)acc_a; + result[i - 1] = (uint32_t)acc_b; + } + + acc_a = (acc_a >> 32) + (acc_b >> 32); + + result[i - 1] = (uint32_t)acc_a; + + if (acc_a >> 32) + subtract_modulus(key, result); +} + +/** + * montgomery_mul() - Perform montgomery mutitply + * + * Operation: montgomery result[] = a[] * b[] / n0inv % modulus + * + * @key: RSA key + * @result: Place to put result, as little endian word array + * @a: Multiplier, as little endian word array + * @b: Multiplicand, as little endian word array + */ +static void montgomery_mul(const struct rsa_public_key *key, + uint32_t result[], uint32_t a[], const uint32_t b[]) +{ + uint i; + + for (i = 0; i < key->len; ++i) + result[i] = 0; + for (i = 0; i < key->len; ++i) + montgomery_mul_add_step(key, result, a[i], b); +} + +/** + * pow_mod() - in-place public exponentiation + * + * @key: RSA key + * @inout: Big-endian word array containing value and result + */ +static int pow_mod(const struct rsa_public_key *key, uint32_t *inout) +{ + uint32_t *result, *ptr; + uint i; + + /* Sanity check for stack size - key->len is in 32-bit words */ + if (key->len > RSA_MAX_KEY_BITS / 32) { + debug("RSA key words %u exceeds maximum %d\n", key->len, + RSA_MAX_KEY_BITS / 32); + return -EINVAL; + } + + uint32_t val[key->len], acc[key->len], tmp[key->len]; + result = tmp; /* Re-use location. */ + + /* Convert from big endian byte array to little endian word array. */ + for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--) + val[i] = get_unaligned_be32(ptr); + + montgomery_mul(key, acc, val, key->rr); /* axx = a * RR / R mod M */ + for (i = 0; i < 16; i += 2) { + montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod M */ + montgomery_mul(key, acc, tmp, tmp); /* acc = tmp^2 / R mod M */ + } + montgomery_mul(key, result, acc, val); /* result = XX * a / R mod M */ + + /* Make sure result < mod; result is at most 1x mod too large. */ + if (greater_equal_modulus(key, result)) + subtract_modulus(key, result); + + /* Convert to bigendian byte array */ + for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++) + put_unaligned_be32(result[i], ptr); + + return 0; +} + +static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig, + const uint32_t sig_len, const uint8_t *hash) +{ + const uint8_t *padding; + int pad_len; + int ret; + + if (!key || !sig || !hash) + return -EIO; + + if (sig_len != (key->len * sizeof(uint32_t))) { + debug("Signature is of incorrect length %d\n", sig_len); + return -EINVAL; + } + + /* Sanity check for stack size */ + if (sig_len > RSA_MAX_SIG_BITS / 8) { + debug("Signature length %u exceeds maximum %d\n", sig_len, + RSA_MAX_SIG_BITS / 8); + return -EINVAL; + } + + uint32_t buf[sig_len / sizeof(uint32_t)]; + + memcpy(buf, sig, sig_len); + + ret = pow_mod(key, buf); + if (ret) + return ret; + + /* Determine padding to use depending on the signature type. */ + padding = padding_sha1_rsa2048; + pad_len = RSA2048_BYTES - SHA1_SUM_LEN; + + /* Check pkcs1.5 padding bytes. */ + if (memcmp(buf, padding, pad_len)) { + debug("In RSAVerify(): Padding check failed!\n"); + return -EINVAL; + } + + /* Check hash. */ + if (memcmp((uint8_t *)buf + pad_len, hash, sig_len - pad_len)) { + debug("In RSAVerify(): Hash check failed!\n"); + return -EACCES; + } + + return 0; +} + +static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len) +{ + int i; + + for (i = 0; i < len; i++) + dst[i] = fdt32_to_cpu(src[len - 1 - i]); +} + +static int rsa_verify_with_keynode(struct image_sign_info *info, + const void *hash, uint8_t *sig, uint sig_len, int node) +{ + const void *blob = info->fdt_blob; + struct rsa_public_key key; + const void *modulus, *rr; + int ret; + + if (node < 0) { + debug("%s: Skipping invalid node", __func__); + return -EBADF; + } + if (!fdt_getprop(blob, node, "rsa,n0-inverse", NULL)) { + debug("%s: Missing rsa,n0-inverse", __func__); + return -EFAULT; + } + key.len = fdtdec_get_int(blob, node, "rsa,num-bits", 0); + key.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0); + modulus = fdt_getprop(blob, node, "rsa,modulus", NULL); + rr = fdt_getprop(blob, node, "rsa,r-squared", NULL); + if (!key.len || !modulus || !rr) { + debug("%s: Missing RSA key info", __func__); + return -EFAULT; + } + + /* Sanity check for stack size */ + if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) { + debug("RSA key bits %u outside allowed range %d..%d\n", + key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS); + return -EFAULT; + } + key.len /= sizeof(uint32_t) * 8; + uint32_t key1[key.len], key2[key.len]; + + key.modulus = key1; + key.rr = key2; + rsa_convert_big_endian(key.modulus, modulus, key.len); + rsa_convert_big_endian(key.rr, rr, key.len); + if (!key.modulus || !key.rr) { + debug("%s: Out of memory", __func__); + return -ENOMEM; + } + + debug("key length %d\n", key.len); + ret = rsa_verify_key(&key, sig, sig_len, hash); + if (ret) { + printf("%s: RSA failed to verify: %d\n", __func__, ret); + return ret; + } + + return 0; +} + +int rsa_verify(struct image_sign_info *info, + const struct image_region region[], int region_count, + uint8_t *sig, uint sig_len) +{ + const void *blob = info->fdt_blob; + uint8_t hash[SHA1_SUM_LEN]; + int ndepth, noffset; + int sig_node, node; + char name[100]; + sha1_context ctx; + int ret, i; + + sig_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME); + if (sig_node < 0) { + debug("%s: No signature node found\n", __func__); + return -ENOENT; + } + + sha1_starts(&ctx); + for (i = 0; i < region_count; i++) + sha1_update(&ctx, region[i].data, region[i].size); + sha1_finish(&ctx, hash); + + /* See if we must use a particular key */ + if (info->required_keynode != -1) { + ret = rsa_verify_with_keynode(info, hash, sig, sig_len, + info->required_keynode); + if (!ret) + return ret; + } + + /* Look for a key that matches our hint */ + snprintf(name, sizeof(name), "key-%s", info->keyname); + node = fdt_subnode_offset(blob, sig_node, name); + ret = rsa_verify_with_keynode(info, hash, sig, sig_len, node); + if (!ret) + return ret; + + /* No luck, so try each of the keys in turn */ + for (ndepth = 0, noffset = fdt_next_node(info->fit, sig_node, &ndepth); + (noffset >= 0) && (ndepth > 0); + noffset = fdt_next_node(info->fit, noffset, &ndepth)) { + if (ndepth == 1 && noffset != node) { + ret = rsa_verify_with_keynode(info, hash, sig, sig_len, + noffset); + if (!ret) + break; + } + } + + return ret; +} diff --git a/lib/string.c b/lib/string.c index 09dfae0..3a82efa 100644 --- a/lib/string.c +++ b/lib/string.c @@ -617,3 +617,62 @@ void *memchr(const void *s, int c, size_t n) } #endif +#ifndef __HAVE_ARCH_MEMCHR_INV +static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) +{ + while (bytes) { + if (*start != value) + return (void *)start; + start++; + bytes--; + } + return NULL; +} +/** + * memchr_inv - Find an unmatching character in an area of memory. + * @start: The memory area + * @c: Find a character other than c + * @bytes: The size of the area. + * + * returns the address of the first character other than @c, or %NULL + * if the whole buffer contains just @c. + */ +void *memchr_inv(const void *start, int c, size_t bytes) +{ + u8 value = c; + u64 value64; + unsigned int words, prefix; + + if (bytes <= 16) + return check_bytes8(start, value, bytes); + + value64 = value; + value64 |= value64 << 8; + value64 |= value64 << 16; + value64 |= value64 << 32; + + prefix = (unsigned long)start % 8; + if (prefix) { + u8 *r; + + prefix = 8 - prefix; + r = check_bytes8(start, value, prefix); + if (r) + return r; + start += prefix; + bytes -= prefix; + } + + words = bytes / 8; + + while (words) { + if (*(u64 *)start != value64) + return check_bytes8(start, value, 8); + start += 8; + words--; + } + + return check_bytes8(start, value, bytes % 8); +} +#endif + diff --git a/lib/trace.c b/lib/trace.c new file mode 100644 index 0000000..e7455bc --- /dev/null +++ b/lib/trace.c @@ -0,0 +1,379 @@ +/* + * Copyright (c) 2012 The Chromium OS Authors. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <trace.h> +#include <asm/io.h> +#include <asm/sections.h> + +DECLARE_GLOBAL_DATA_PTR; + +static char trace_enabled __attribute__((section(".data"))); +static char trace_inited __attribute__((section(".data"))); + +/* The header block at the start of the trace memory area */ +struct trace_hdr { + int func_count; /* Total number of function call sites */ + u64 call_count; /* Total number of tracked function calls */ + u64 untracked_count; /* Total number of untracked function calls */ + int funcs_used; /* Total number of functions used */ + + /* + * Call count for each function. This is indexed by the word offset + * of the function from gd->relocaddr + */ + uintptr_t *call_accum; + + /* Function trace list */ + struct trace_call *ftrace; /* The function call records */ + ulong ftrace_size; /* Num. of ftrace records we have space for */ + ulong ftrace_count; /* Num. of ftrace records written */ + ulong ftrace_too_deep_count; /* Functions that were too deep */ + + int depth; + int depth_limit; + int max_depth; +}; + +static struct trace_hdr *hdr; /* Pointer to start of trace buffer */ + +static inline uintptr_t __attribute__((no_instrument_function)) + func_ptr_to_num(void *func_ptr) +{ + uintptr_t offset = (uintptr_t)func_ptr; + +#ifdef CONFIG_SANDBOX + offset -= (uintptr_t)&_init; +#else + if (gd->flags & GD_FLG_RELOC) + offset -= gd->relocaddr; + else + offset -= CONFIG_SYS_TEXT_BASE; +#endif + return offset / FUNC_SITE_SIZE; +} + +static void __attribute__((no_instrument_function)) add_ftrace(void *func_ptr, + void *caller, ulong flags) +{ + if (hdr->depth > hdr->depth_limit) { + hdr->ftrace_too_deep_count++; + return; + } + if (hdr->ftrace_count < hdr->ftrace_size) { + struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; + + rec->func = func_ptr_to_num(func_ptr); + rec->caller = func_ptr_to_num(caller); + rec->flags = flags | (timer_get_us() & FUNCF_TIMESTAMP_MASK); + } + hdr->ftrace_count++; +} + +static void __attribute__((no_instrument_function)) add_textbase(void) +{ + if (hdr->ftrace_count < hdr->ftrace_size) { + struct trace_call *rec = &hdr->ftrace[hdr->ftrace_count]; + + rec->func = CONFIG_SYS_TEXT_BASE; + rec->caller = 0; + rec->flags = FUNCF_TEXTBASE; + } + hdr->ftrace_count++; +} + +/** + * This is called on every function entry + * + * We add to our tally for this function and add to the list of called + * functions. + * + * @param func_ptr Pointer to function being entered + * @param caller Pointer to function which called this function + */ +void __attribute__((no_instrument_function)) __cyg_profile_func_enter( + void *func_ptr, void *caller) +{ + if (trace_enabled) { + int func; + + add_ftrace(func_ptr, caller, FUNCF_ENTRY); + func = func_ptr_to_num(func_ptr); + if (func < hdr->func_count) { + hdr->call_accum[func]++; + hdr->call_count++; + } else { + hdr->untracked_count++; + } + hdr->depth++; + if (hdr->depth > hdr->depth_limit) + hdr->max_depth = hdr->depth; + } +} + +/** + * This is called on every function exit + * + * We do nothing here. + * + * @param func_ptr Pointer to function being entered + * @param caller Pointer to function which called this function + */ +void __attribute__((no_instrument_function)) __cyg_profile_func_exit( + void *func_ptr, void *caller) +{ + if (trace_enabled) { + add_ftrace(func_ptr, caller, FUNCF_EXIT); + hdr->depth--; + } +} + +/** + * Produce a list of called functions + * + * The information is written into the supplied buffer - a header followed + * by a list of function records. + * + * @param buff Buffer to place list into + * @param buff_size Size of buffer + * @param needed Returns size of buffer needed, which may be + * greater than buff_size if we ran out of space. + * @return 0 if ok, -1 if space was exhausted + */ +int trace_list_functions(void *buff, int buff_size, unsigned int *needed) +{ + struct trace_output_hdr *output_hdr = NULL; + void *end, *ptr = buff; + int func; + int upto; + + end = buff ? buff + buff_size : NULL; + + /* Place some header information */ + if (ptr + sizeof(struct trace_output_hdr) < end) + output_hdr = ptr; + ptr += sizeof(struct trace_output_hdr); + + /* Add information about each function */ + for (func = upto = 0; func < hdr->func_count; func++) { + int calls = hdr->call_accum[func]; + + if (!calls) + continue; + + if (ptr + sizeof(struct trace_output_func) < end) { + struct trace_output_func *stats = ptr; + + stats->offset = func * FUNC_SITE_SIZE; + stats->call_count = calls; + upto++; + } + ptr += sizeof(struct trace_output_func); + } + + /* Update the header */ + if (output_hdr) { + output_hdr->rec_count = upto; + output_hdr->type = TRACE_CHUNK_FUNCS; + } + + /* Work out how must of the buffer we used */ + *needed = ptr - buff; + if (ptr > end) + return -1; + return 0; +} + +int trace_list_calls(void *buff, int buff_size, unsigned *needed) +{ + struct trace_output_hdr *output_hdr = NULL; + void *end, *ptr = buff; + int rec, upto; + int count; + + end = buff ? buff + buff_size : NULL; + + /* Place some header information */ + if (ptr + sizeof(struct trace_output_hdr) < end) + output_hdr = ptr; + ptr += sizeof(struct trace_output_hdr); + + /* Add information about each call */ + count = hdr->ftrace_count; + if (count > hdr->ftrace_size) + count = hdr->ftrace_size; + for (rec = upto = 0; rec < count; rec++) { + if (ptr + sizeof(struct trace_call) < end) { + struct trace_call *call = &hdr->ftrace[rec]; + struct trace_call *out = ptr; + + out->func = call->func * FUNC_SITE_SIZE; + out->caller = call->caller * FUNC_SITE_SIZE; + out->flags = call->flags; + upto++; + } + ptr += sizeof(struct trace_call); + } + + /* Update the header */ + if (output_hdr) { + output_hdr->rec_count = upto; + output_hdr->type = TRACE_CHUNK_CALLS; + } + + /* Work out how must of the buffer we used */ + *needed = ptr - buff; + if (ptr > end) + return -1; + return 0; +} + +/* Print basic information about tracing */ +void trace_print_stats(void) +{ + ulong count; + +#ifndef FTRACE + puts("Warning: make U-Boot with FTRACE to enable function instrumenting.\n"); + puts("You will likely get zeroed data here\n"); +#endif + if (!trace_inited) { + printf("Trace is disabled\n"); + return; + } + print_grouped_ull(hdr->func_count, 10); + puts(" function sites\n"); + print_grouped_ull(hdr->call_count, 10); + puts(" function calls\n"); + print_grouped_ull(hdr->untracked_count, 10); + puts(" untracked function calls\n"); + count = min(hdr->ftrace_count, hdr->ftrace_size); + print_grouped_ull(count, 10); + puts(" traced function calls"); + if (hdr->ftrace_count > hdr->ftrace_size) { + printf(" (%lu dropped due to overflow)", + hdr->ftrace_count - hdr->ftrace_size); + } + puts("\n"); + printf("%15d maximum observed call depth\n", hdr->max_depth); + printf("%15d call depth limit\n", hdr->depth_limit); + print_grouped_ull(hdr->ftrace_too_deep_count, 10); + puts(" calls not traced due to depth\n"); +} + +void __attribute__((no_instrument_function)) trace_set_enabled(int enabled) +{ + trace_enabled = enabled != 0; +} + +/** + * Init the tracing system ready for used, and enable it + * + * @param buff Pointer to trace buffer + * @param buff_size Size of trace buffer + */ +int __attribute__((no_instrument_function)) trace_init(void *buff, + size_t buff_size) +{ + ulong func_count = gd->mon_len / FUNC_SITE_SIZE; + size_t needed; + int was_disabled = !trace_enabled; + + if (!was_disabled) { +#ifdef CONFIG_TRACE_EARLY + char *end; + ulong used; + + /* + * Copy over the early trace data if we have it. Disable + * tracing while we are doing this. + */ + trace_enabled = 0; + hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, + CONFIG_TRACE_EARLY_SIZE); + end = (char *)&hdr->ftrace[hdr->ftrace_count]; + used = end - (char *)hdr; + printf("trace: copying %08lx bytes of early data from %x to %08lx\n", + used, CONFIG_TRACE_EARLY_ADDR, + (ulong)map_to_sysmem(buff)); + memcpy(buff, hdr, used); +#else + puts("trace: already enabled\n"); + return -1; +#endif + } + hdr = (struct trace_hdr *)buff; + needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); + if (needed > buff_size) { + printf("trace: buffer size %zd bytes: at least %zd needed\n", + buff_size, needed); + return -1; + } + + if (was_disabled) + memset(hdr, '\0', needed); + hdr->func_count = func_count; + hdr->call_accum = (uintptr_t *)(hdr + 1); + + /* Use any remaining space for the timed function trace */ + hdr->ftrace = (struct trace_call *)(buff + needed); + hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); + add_textbase(); + + puts("trace: enabled\n"); + hdr->depth_limit = 15; + trace_enabled = 1; + trace_inited = 1; + return 0; +} + +#ifdef CONFIG_TRACE_EARLY +int __attribute__((no_instrument_function)) trace_early_init(void) +{ + ulong func_count = gd->mon_len / FUNC_SITE_SIZE; + size_t buff_size = CONFIG_TRACE_EARLY_SIZE; + size_t needed; + + /* We can ignore additional calls to this function */ + if (trace_enabled) + return 0; + + hdr = map_sysmem(CONFIG_TRACE_EARLY_ADDR, CONFIG_TRACE_EARLY_SIZE); + needed = sizeof(*hdr) + func_count * sizeof(uintptr_t); + if (needed > buff_size) { + printf("trace: buffer size is %zd bytes, at least %zd needed\n", + buff_size, needed); + return -1; + } + + memset(hdr, '\0', needed); + hdr->call_accum = (uintptr_t *)(hdr + 1); + hdr->func_count = func_count; + + /* Use any remaining space for the timed function trace */ + hdr->ftrace = (struct trace_call *)((char *)hdr + needed); + hdr->ftrace_size = (buff_size - needed) / sizeof(*hdr->ftrace); + add_textbase(); + hdr->depth_limit = 200; + printf("trace: early enable at %08x\n", CONFIG_TRACE_EARLY_ADDR); + + trace_enabled = 1; + return 0; +} +#endif diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 533a96b..82e5c13 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -870,3 +870,19 @@ char *simple_itoa(ulong i) } while (i > 0); return p + 1; } + +/* We don't seem to have %'d in U-Boot */ +void print_grouped_ull(unsigned long long int_val, int digits) +{ + char str[21], *s; + int grab = 3; + + digits = (digits + 2) / 3; + sprintf(str, "%*llu", digits * 3, int_val); + for (s = str; *s; s += grab) { + if (s != str) + putc(s[-1] != ' ' ? ',' : ' '); + printf("%.*s", grab, s); + grab = 3; + } +} diff --git a/nand_spl/board/freescale/p1010rdb/Makefile b/nand_spl/board/freescale/p1010rdb/Makefile deleted file mode 100644 index f7bdf92..0000000 --- a/nand_spl/board/freescale/p1010rdb/Makefile +++ /dev/null @@ -1,142 +0,0 @@ -# -# (C) Copyright 2007 -# Stefan Roese, DENX Software Engineering, sr@denx.de. -# -# Copyright 2011 Freescale Semiconductor, Inc. -# -# See file CREDITS for list of people who contributed to this -# project. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, -# MA 02111-1307 USA -# - -NAND_SPL := y -CONFIG_SYS_TEXT_BASE_SPL := 0xff800000 -PAD_TO := 0xff802000 - -include $(TOPDIR)/config.mk - -nandobj := $(OBJTREE)/nand_spl/ - -LDSCRIPT= $(TOPDIR)/$(CPUDIR)/u-boot-nand_spl.lds -LDFLAGS := -T $(nandobj)u-boot-nand_spl.lds -Ttext $(CONFIG_SYS_TEXT_BASE_SPL) $(LDFLAGS) \ - $(LDFLAGS_FINAL) -AFLAGS += -DCONFIG_NAND_SPL -CFLAGS += -DCONFIG_NAND_SPL - -SOBJS = start.o resetvec.o ticks.o -COBJS = cache.o cpu_init_early.o spl_minimal.o fsl_law.o law.o \ - nand_boot.o nand_boot_fsl_ifc.o ns16550.o tlb.o tlb_table.o - -SRCS := $(addprefix $(obj),$(SOBJS:.o=.S) $(COBJS:.o=.c)) -OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) -__OBJS := $(SOBJS) $(COBJS) -LNDIR := $(nandobj)board/$(BOARDDIR) - -ALL = $(nandobj)u-boot-spl $(nandobj)u-boot-spl.bin $(nandobj)u-boot-spl-16k.bin - -all: $(obj).depend $(ALL) - -$(nandobj)u-boot-spl-16k.bin: $(nandobj)u-boot-spl - $(OBJCOPY) ${OBJCFLAGS} --pad-to=$(PAD_TO) -O binary $< $@ - -$(nandobj)u-boot-spl.bin: $(nandobj)u-boot-spl - $(OBJCOPY) ${OBJCFLAGS} -O binary $< $@ - -$(nandobj)u-boot-spl: $(OBJS) $(nandobj)u-boot-nand_spl.lds - cd $(LNDIR) && $(LD) $(LDFLAGS) $(__OBJS) $(PLATFORM_LIBS) \ - -Map $(nandobj)u-boot-spl.map \ - -o $(nandobj)u-boot-spl - -$(nandobj)u-boot-nand_spl.lds: $(LDSCRIPT) - $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -I$(nandobj)board/$(BOARDDIR) \ - -ansi -D__ASSEMBLY__ -P - <$< >$@ - -# create symbolic links for common files - -$(obj)cache.c: - @rm -f $(obj)cache.c - ln -sf $(SRCTREE)/arch/powerpc/lib/cache.c $(obj)cache.c - -$(obj)cpu_init_early.c: - @rm -f $(obj)cpu_init_early.c - ln -sf $(SRCTREE)/$(CPUDIR)/cpu_init_early.c $(obj)cpu_init_early.c - -$(obj)spl_minimal.c: - @rm -f $(obj)spl_minimal.c - ln -sf $(SRCTREE)/$(CPUDIR)/spl_minimal.c $(obj)spl_minimal.c - -$(obj)fsl_law.c: - @rm -f $(obj)fsl_law.c - ln -sf $(SRCTREE)/arch/powerpc/cpu/mpc8xxx/law.c $(obj)fsl_law.c - -$(obj)law.c: - @rm -f $(obj)law.c - ln -sf $(SRCTREE)/board/$(BOARDDIR)/law.c $(obj)law.c - -$(obj)nand_boot_fsl_ifc.c: - @rm -f $(obj)nand_boot_fsl_ifc.c - ln -sf $(SRCTREE)/nand_spl/nand_boot_fsl_ifc.c \ - $(obj)nand_boot_fsl_ifc.c - -$(obj)ns16550.c: - @rm -f $(obj)ns16550.c - ln -sf $(SRCTREE)/drivers/serial/ns16550.c $(obj)ns16550.c - -$(obj)resetvec.S: - @rm -f $(obj)resetvec.S - ln -s $(SRCTREE)/$(CPUDIR)/resetvec.S $(obj)resetvec.S - -$(obj)fixed_ivor.S: - @rm -f $(obj)fixed_ivor.S - ln -sf $(SRCTREE)/$(CPUDIR)/fixed_ivor.S $(obj)fixed_ivor.S - -$(obj)start.S: $(obj)fixed_ivor.S - @rm -f $(obj)start.S - ln -sf $(SRCTREE)/$(CPUDIR)/start.S $(obj)start.S - -$(obj)ticks.S: - @rm -f $(obj)ticks.S - ln -sf $(SRCTREE)/arch/powerpc/lib/ticks.S $(obj)ticks.S - -$(obj)tlb.c: - @rm -f $(obj)tlb.c - ln -sf $(SRCTREE)/$(CPUDIR)/tlb.c $(obj)tlb.c - -$(obj)tlb_table.c: - @rm -f $(obj)tlb_table.c - ln -sf $(SRCTREE)/board/$(BOARDDIR)/tlb.c $(obj)tlb_table.c - -ifneq ($(OBJTREE), $(SRCTREE)) -$(obj)nand_boot.c: - @rm -f $(obj)nand_boot.c - ln -s $(SRCTREE)/nand_spl/board/$(BOARDDIR)/nand_boot.c $(obj)nand_boot.c -endif - -######################################################################### - -$(obj)%.o: $(obj)%.S - $(CC) $(AFLAGS) -c -o $@ $< - -$(obj)%.o: $(obj)%.c - $(CC) $(CFLAGS) -c -o $@ $< - -# defines $(obj).depend target -include $(SRCTREE)/rules.mk - -sinclude $(obj).depend - -######################################################################### diff --git a/net/link_local.c b/net/link_local.c index 1ba796e..4152fae 100644 --- a/net/link_local.c +++ b/net/link_local.c @@ -206,6 +206,7 @@ void link_local_receive_arp(struct arp_hdr *arp, int len) { int source_ip_conflict; int target_ip_conflict; + IPaddr_t null_ip = 0; if (state == DISABLED) return; @@ -267,10 +268,18 @@ void link_local_receive_arp(struct arp_hdr *arp, int len) ) { source_ip_conflict = 1; } - if (arp->ar_op == htons(ARPOP_REQUEST) - && memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 - && memcmp(&arp->ar_tha, NetOurEther, ARP_HLEN) != 0 - ) { + + /* + * According to RFC 3927, section 2.2.1: + * Check if packet is an ARP probe by checking for a null source IP + * then check that target IP is equal to ours and source hw addr + * is not equal to ours. This condition should cause a conflict only + * during probe. + */ + if (arp->ar_op == htons(ARPOP_REQUEST) && + memcmp(&arp->ar_spa, &null_ip, ARP_PLEN) == 0 && + memcmp(&arp->ar_tpa, &ip, ARP_PLEN) == 0 && + memcmp(&arp->ar_sha, NetOurEther, ARP_HLEN) != 0) { target_ip_conflict = 1; } @@ -271,7 +271,8 @@ static void NetInitLoop(void) #endif env_changed_id = env_id; } - memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); + if (eth_get_dev()) + memcpy(NetOurEther, eth_get_dev()->enetaddr, 6); return; } @@ -37,10 +37,14 @@ # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT #endif +#define NFS_RPC_ERR 1 +#define NFS_RPC_DROP 124 + static int fs_mounted; static unsigned long rpc_id; static int nfs_offset = -1; static int nfs_len; +static ulong nfs_timeout = NFS_TIMEOUT; static char dirfh[NFS_FHSIZE]; /* file handle of directory */ static char filefh[NFS_FHSIZE]; /* file handle of kernel image */ @@ -399,8 +403,10 @@ rpc_lookup_reply(int prog, uchar *pkt, unsigned len) debug("%s\n", __func__); - if (ntohl(rpc_pkt.u.reply.id) != rpc_id) - return -1; + if (ntohl(rpc_pkt.u.reply.id) > rpc_id) + return -NFS_RPC_ERR; + else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) + return -NFS_RPC_DROP; if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || @@ -428,8 +434,10 @@ nfs_mount_reply(uchar *pkt, unsigned len) memcpy((unsigned char *)&rpc_pkt, pkt, len); - if (ntohl(rpc_pkt.u.reply.id) != rpc_id) - return -1; + if (ntohl(rpc_pkt.u.reply.id) > rpc_id) + return -NFS_RPC_ERR; + else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) + return -NFS_RPC_DROP; if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || @@ -452,8 +460,10 @@ nfs_umountall_reply(uchar *pkt, unsigned len) memcpy((unsigned char *)&rpc_pkt, pkt, len); - if (ntohl(rpc_pkt.u.reply.id) != rpc_id) - return -1; + if (ntohl(rpc_pkt.u.reply.id) > rpc_id) + return -NFS_RPC_ERR; + else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) + return -NFS_RPC_DROP; if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || @@ -475,8 +485,10 @@ nfs_lookup_reply(uchar *pkt, unsigned len) memcpy((unsigned char *)&rpc_pkt, pkt, len); - if (ntohl(rpc_pkt.u.reply.id) != rpc_id) - return -1; + if (ntohl(rpc_pkt.u.reply.id) > rpc_id) + return -NFS_RPC_ERR; + else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) + return -NFS_RPC_DROP; if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || @@ -499,8 +511,10 @@ nfs_readlink_reply(uchar *pkt, unsigned len) memcpy((unsigned char *)&rpc_pkt, pkt, len); - if (ntohl(rpc_pkt.u.reply.id) != rpc_id) - return -1; + if (ntohl(rpc_pkt.u.reply.id) > rpc_id) + return -NFS_RPC_ERR; + else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) + return -NFS_RPC_DROP; if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || @@ -534,8 +548,10 @@ nfs_read_reply(uchar *pkt, unsigned len) memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply)); - if (ntohl(rpc_pkt.u.reply.id) != rpc_id) - return -1; + if (ntohl(rpc_pkt.u.reply.id) > rpc_id) + return -NFS_RPC_ERR; + else if (ntohl(rpc_pkt.u.reply.id) < rpc_id) + return -NFS_RPC_DROP; if (rpc_pkt.u.reply.rstatus || rpc_pkt.u.reply.verifier || @@ -574,7 +590,8 @@ NfsTimeout(void) NetStartAgain(); } else { puts("T "); - NetSetTimeout(NFS_TIMEOUT, NfsTimeout); + NetSetTimeout(nfs_timeout + NFS_TIMEOUT * NfsTimeoutCount, + NfsTimeout); NfsSend(); } } @@ -583,6 +600,7 @@ static void NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) { int rlen; + int reply; debug("%s\n", __func__); @@ -591,19 +609,24 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) switch (NfsState) { case STATE_PRCLOOKUP_PROG_MOUNT_REQ: - rpc_lookup_reply(PROG_MOUNT, pkt, len); + if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP) + break; NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ; NfsSend(); break; case STATE_PRCLOOKUP_PROG_NFS_REQ: - rpc_lookup_reply(PROG_NFS, pkt, len); + if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP) + break; NfsState = STATE_MOUNT_REQ; NfsSend(); break; case STATE_MOUNT_REQ: - if (nfs_mount_reply(pkt, len)) { + reply = nfs_mount_reply(pkt, len); + if (reply == -NFS_RPC_DROP) + break; + else if (reply == -NFS_RPC_ERR) { puts("*** ERROR: Cannot mount\n"); /* just to be sure... */ NfsState = STATE_UMOUNT_REQ; @@ -615,7 +638,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) break; case STATE_UMOUNT_REQ: - if (nfs_umountall_reply(pkt, len)) { + reply = nfs_umountall_reply(pkt, len); + if (reply == -NFS_RPC_DROP) + break; + else if (reply == -NFS_RPC_ERR) { puts("*** ERROR: Cannot umount\n"); net_set_state(NETLOOP_FAIL); } else { @@ -625,7 +651,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) break; case STATE_LOOKUP_REQ: - if (nfs_lookup_reply(pkt, len)) { + reply = nfs_lookup_reply(pkt, len); + if (reply == -NFS_RPC_DROP) + break; + else if (reply == -NFS_RPC_ERR) { puts("*** ERROR: File lookup fail\n"); NfsState = STATE_UMOUNT_REQ; NfsSend(); @@ -638,7 +667,10 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) break; case STATE_READLINK_REQ: - if (nfs_readlink_reply(pkt, len)) { + reply = nfs_readlink_reply(pkt, len); + if (reply == -NFS_RPC_DROP) + break; + else if (reply == -NFS_RPC_ERR) { puts("*** ERROR: Symlink fail\n"); NfsState = STATE_UMOUNT_REQ; NfsSend(); @@ -654,7 +686,7 @@ NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) case STATE_READ_REQ: rlen = nfs_read_reply(pkt, len); - NetSetTimeout(NFS_TIMEOUT, NfsTimeout); + NetSetTimeout(nfs_timeout, NfsTimeout); if (rlen > 0) { nfs_offset += rlen; NfsSend(); @@ -738,7 +770,7 @@ NfsStart(void) printf("\nLoad address: 0x%lx\n" "Loading: *\b", load_addr); - NetSetTimeout(NFS_TIMEOUT, NfsTimeout); + NetSetTimeout(nfs_timeout, NfsTimeout); net_set_udp_handler(NfsHandler); NfsTimeoutCount = 0; @@ -446,8 +446,8 @@ static void TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len) { - ushort proto; - ushort *s; + __be16 proto; + __be16 *s; int i; if (dest != TftpOurPort) { @@ -465,7 +465,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, return; len -= 2; /* warning: don't use increment (++) in ntohs() macros!! */ - s = (ushort *)pkt; + s = (__be16 *)pkt; proto = *s++; pkt = (uchar *)s; switch (ntohs(proto)) { @@ -556,7 +556,7 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, if (len < 2) return; len -= 2; - TftpBlock = ntohs(*(ushort *)pkt); + TftpBlock = ntohs(*(__be16 *)pkt); update_block_number(); @@ -644,9 +644,9 @@ TftpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, case TFTP_ERROR: printf("\nTFTP error: '%s' (%d)\n", - pkt + 2, ntohs(*(ushort *)pkt)); + pkt + 2, ntohs(*(__be16 *)pkt)); - switch (ntohs(*(ushort *)pkt)) { + switch (ntohs(*(__be16 *)pkt)) { case TFTP_ERR_FILE_NOT_FOUND: case TFTP_ERR_ACCESS_DENIED: puts("Not retrying...\n"); diff --git a/test/image/test-fit.py b/test/image/test-fit.py new file mode 100755 index 0000000..aad9f59 --- /dev/null +++ b/test/image/test-fit.py @@ -0,0 +1,423 @@ +#!/usr/bin/python +# +# Copyright (c) 2013, Google Inc. +# +# Sanity check of the FIT handling in U-Boot +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# +# To run this: +# +# make O=sandbox sandbox_config +# make O=sandbox +# ./test/image/test-fit.py -u sandbox/u-boot + +import doctest +from optparse import OptionParser +import os +import shutil +import struct +import sys +import tempfile + +# The 'command' library in patman is convenient for running commands +base_path = os.path.dirname(sys.argv[0]) +patman = os.path.join(base_path, '../../tools/patman') +sys.path.append(patman) + +import command + +# Define a base ITS which we can adjust using % and a dictionary +base_its = ''' +/dts-v1/; + +/ { + description = "Chrome OS kernel image with one or more FDT blobs"; + #address-cells = <1>; + + images { + kernel@1 { + data = /incbin/("%(kernel)s"); + type = "kernel"; + arch = "sandbox"; + os = "linux"; + compression = "none"; + load = <0x40000>; + entry = <0x8>; + }; + fdt@1 { + description = "snow"; + data = /incbin/("u-boot.dtb"); + type = "flat_dt"; + arch = "sandbox"; + %(fdt_load)s + compression = "none"; + signature@1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + }; + }; + ramdisk@1 { + description = "snow"; + data = /incbin/("%(ramdisk)s"); + type = "ramdisk"; + arch = "sandbox"; + os = "linux"; + %(ramdisk_load)s + compression = "none"; + }; + }; + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + %(ramdisk_config)s + }; + }; +}; +''' + +# Define a base FDT - currently we don't use anything in this +base_fdt = ''' +/dts-v1/; + +/ { + model = "Sandbox Verified Boot Test"; + compatible = "sandbox"; + +}; +''' + +# This is the U-Boot script that is run for each test. First load the fit, +# then do the 'bootm' command, then save out memory from the places where +# we expect 'bootm' to write things. Then quit. +base_script = ''' +sb load host 0 %(fit_addr)x %(fit)s +fdt addr %(fit_addr)x +bootm start %(fit_addr)x +bootm loados +sb save host 0 %(kernel_out)s %(kernel_addr)x %(kernel_size)x +sb save host 0 %(fdt_out)s %(fdt_addr)x %(fdt_size)x +sb save host 0 %(ramdisk_out)s %(ramdisk_addr)x %(ramdisk_size)x +reset +''' + +def make_fname(leaf): + """Make a temporary filename + + Args: + leaf: Leaf name of file to create (within temporary directory) + Return: + Temporary filename + """ + global base_dir + + return os.path.join(base_dir, leaf) + +def filesize(fname): + """Get the size of a file + + Args: + fname: Filename to check + Return: + Size of file in bytes + """ + return os.stat(fname).st_size + +def read_file(fname): + """Read the contents of a file + + Args: + fname: Filename to read + Returns: + Contents of file as a string + """ + with open(fname, 'r') as fd: + return fd.read() + +def make_dtb(): + """Make a sample .dts file and compile it to a .dtb + + Returns: + Filename of .dtb file created + """ + src = make_fname('u-boot.dts') + dtb = make_fname('u-boot.dtb') + with open(src, 'w') as fd: + print >>fd, base_fdt + command.Output('dtc', src, '-O', 'dtb', '-o', dtb) + return dtb + +def make_its(params): + """Make a sample .its file with parameters embedded + + Args: + params: Dictionary containing parameters to embed in the %() strings + Returns: + Filename of .its file created + """ + its = make_fname('test.its') + with open(its, 'w') as fd: + print >>fd, base_its % params + return its + +def make_fit(mkimage, params): + """Make a sample .fit file ready for loading + + This creates a .its script with the selected parameters and uses mkimage to + turn this into a .fit image. + + Args: + mkimage: Filename of 'mkimage' utility + params: Dictionary containing parameters to embed in the %() strings + Return: + Filename of .fit file created + """ + fit = make_fname('test.fit') + its = make_its(params) + command.Output(mkimage, '-f', its, fit) + with open(make_fname('u-boot.dts'), 'w') as fd: + print >>fd, base_fdt + return fit + +def make_kernel(): + """Make a sample kernel with test data + + Returns: + Filename of kernel created + """ + fname = make_fname('test-kernel.bin') + data = '' + for i in range(100): + data += 'this kernel %d is unlikely to boot\n' % i + with open(fname, 'w') as fd: + print >>fd, data + return fname + +def make_ramdisk(): + """Make a sample ramdisk with test data + + Returns: + Filename of ramdisk created + """ + fname = make_fname('test-ramdisk.bin') + data = '' + for i in range(100): + data += 'ramdisk %d was seldom used in the middle ages\n' % i + with open(fname, 'w') as fd: + print >>fd, data + return fname + +def find_matching(text, match): + """Find a match in a line of text, and return the unmatched line portion + + This is used to extract a part of a line from some text. The match string + is used to locate the line - we use the first line that contains that + match text. + + Once we find a match, we discard the match string itself from the line, + and return what remains. + + TODO: If this function becomes more generally useful, we could change it + to use regex and return groups. + + Args: + text: Text to check (each line separated by \n) + match: String to search for + Return: + String containing unmatched portion of line + Exceptions: + ValueError: If match is not found + + >>> find_matching('first line:10\\nsecond_line:20', 'first line:') + '10' + >>> find_matching('first line:10\\nsecond_line:20', 'second linex') + Traceback (most recent call last): + ... + ValueError: Test aborted + >>> find_matching('first line:10\\nsecond_line:20', 'second_line:') + '20' + """ + for line in text.splitlines(): + pos = line.find(match) + if pos != -1: + return line[:pos] + line[pos + len(match):] + + print "Expected '%s' but not found in output:" + print text + raise ValueError('Test aborted') + +def set_test(name): + """Set the name of the current test and print a message + + Args: + name: Name of test + """ + global test_name + + test_name = name + print name + +def fail(msg, stdout): + """Raise an error with a helpful failure message + + Args: + msg: Message to display + """ + print stdout + raise ValueError("Test '%s' failed: %s" % (test_name, msg)) + +def run_fit_test(mkimage, u_boot): + """Basic sanity check of FIT loading in U-Boot + + TODO: Almost everything: + - hash algorithms - invalid hash/contents should be detected + - signature algorithms - invalid sig/contents should be detected + - compression + - checking that errors are detected like: + - image overwriting + - missing images + - invalid configurations + - incorrect os/arch/type fields + - empty data + - images too large/small + - invalid FDT (e.g. putting a random binary in instead) + - default configuration selection + - bootm command line parameters should have desired effect + - run code coverage to make sure we are testing all the code + """ + global test_name + + # Set up invariant files + control_dtb = make_dtb() + kernel = make_kernel() + ramdisk = make_ramdisk() + kernel_out = make_fname('kernel-out.bin') + fdt_out = make_fname('fdt-out.dtb') + ramdisk_out = make_fname('ramdisk-out.bin') + + # Set up basic parameters with default values + params = { + 'fit_addr' : 0x1000, + + 'kernel' : kernel, + 'kernel_out' : kernel_out, + 'kernel_addr' : 0x40000, + 'kernel_size' : filesize(kernel), + + 'fdt_out' : fdt_out, + 'fdt_addr' : 0x80000, + 'fdt_size' : filesize(control_dtb), + 'fdt_load' : '', + + 'ramdisk' : ramdisk, + 'ramdisk_out' : ramdisk_out, + 'ramdisk_addr' : 0xc0000, + 'ramdisk_size' : filesize(ramdisk), + 'ramdisk_load' : '', + 'ramdisk_config' : '', + } + + # Make a basic FIT and a script to load it + fit = make_fit(mkimage, params) + params['fit'] = fit + cmd = base_script % params + + # First check that we can load a kernel + # We could perhaps reduce duplication with some loss of readability + set_test('Kernel load') + stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd) + if read_file(kernel) != read_file(kernel_out): + fail('Kernel not loaded', stdout) + if read_file(control_dtb) == read_file(fdt_out): + fail('FDT loaded but should be ignored', stdout) + if read_file(ramdisk) == read_file(ramdisk_out): + fail('Ramdisk loaded but should not be', stdout) + + # Find out the offset in the FIT where U-Boot has found the FDT + line = find_matching(stdout, 'Booting using the fdt blob at ') + fit_offset = int(line, 16) - params['fit_addr'] + fdt_magic = struct.pack('>L', 0xd00dfeed) + data = read_file(fit) + + # Now find where it actually is in the FIT (skip the first word) + real_fit_offset = data.find(fdt_magic, 4) + if fit_offset != real_fit_offset: + fail('U-Boot loaded FDT from offset %#x, FDT is actually at %#x' % + (fit_offset, real_fit_offset), stdout) + + # Now a kernel and an FDT + set_test('Kernel + FDT load') + params['fdt_load'] = 'load = <%#x>;' % params['fdt_addr'] + fit = make_fit(mkimage, params) + stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd) + if read_file(kernel) != read_file(kernel_out): + fail('Kernel not loaded', stdout) + if read_file(control_dtb) != read_file(fdt_out): + fail('FDT not loaded', stdout) + if read_file(ramdisk) == read_file(ramdisk_out): + fail('Ramdisk loaded but should not be', stdout) + + # Try a ramdisk + set_test('Kernel + FDT + Ramdisk load') + params['ramdisk_config'] = 'ramdisk = "ramdisk@1";' + params['ramdisk_load'] = 'load = <%#x>;' % params['ramdisk_addr'] + fit = make_fit(mkimage, params) + stdout = command.Output(u_boot, '-d', control_dtb, '-c', cmd) + if read_file(ramdisk) != read_file(ramdisk_out): + fail('Ramdisk not loaded', stdout) + +def run_tests(): + """Parse options, run the FIT tests and print the result""" + global base_path, base_dir + + # Work in a temporary directory + base_dir = tempfile.mkdtemp() + parser = OptionParser() + parser.add_option('-u', '--u-boot', + default=os.path.join(base_path, 'u-boot'), + help='Select U-Boot sandbox binary') + parser.add_option('-k', '--keep', action='store_true', + help="Don't delete temporary directory even when tests pass") + parser.add_option('-t', '--selftest', action='store_true', + help='Run internal self tests') + (options, args) = parser.parse_args() + + # Find the path to U-Boot, and assume mkimage is in its tools/mkimage dir + base_path = os.path.dirname(options.u_boot) + mkimage = os.path.join(base_path, 'tools/mkimage') + + # There are a few doctests - handle these here + if options.selftest: + doctest.testmod() + return + + title = 'FIT Tests' + print title, '\n', '=' * len(title) + + run_fit_test(mkimage, options.u_boot) + + print '\nTests passed' + print 'Caveat: this is only a sanity check - test coverage is poor' + + # Remove the tempoerary directory unless we are asked to keep it + if options.keep: + print "Output files are in '%s'" % base_dir + else: + shutil.rmtree(base_dir) + +run_tests() diff --git a/test/trace/test-trace.sh b/test/trace/test-trace.sh new file mode 100755 index 0000000..696a396 --- /dev/null +++ b/test/trace/test-trace.sh @@ -0,0 +1,89 @@ +# Copyright (c) 2013 The Chromium OS Authors. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# Simple test script for tracing with sandbox + +OUTPUT_DIR=sandbox +TRACE_OPT="FTRACE=1" + +fail() { + echo "Test failed: $1" + if [ -n ${tmp} ]; then + rm ${tmp} + fi + exit 1 +} + +build_uboot() { + echo "Build sandbox" + OPTS="O=${OUTPUT_DIR} ${TRACE_OPT}" + NUM_CPUS=$(grep -c processor /proc/cpuinfo) + make ${OPTS} sandbox_config + make ${OPTS} -s -j${NUM_CPUS} +} + +run_trace() { + echo "Run trace" + ./${OUTPUT_DIR}/u-boot <<END + trace stats + hash sha256 0 10000 + trace pause + trace stats + hash sha256 0 10000 + trace stats + trace resume + hash sha256 0 10000 + trace pause + trace stats + reset +END +} + +check_results() { + echo "Check results" + + # Expect sha256 to run 3 times, so we see the string 6 times + if [ $(grep -c sha256 ${tmp}) -ne 6 ]; then + fail "sha256 error" + fi + + # 4 sets of results (output of 'trace stats') + if [ $(grep -c "traced function calls" ${tmp}) -ne 4 ]; then + fail "trace output error" + fi + + # Check trace counts. We expect to see an increase in the number of + # traced function calls between each 'trace stats' command, except + # between calls 2 and 3, where tracing is paused. + # This code gets the sign of the difference between each number and + # its predecessor. + counts="$(tr -d , <${tmp} | awk '/traced function calls/ { diff = $1 - upto; upto = $1; printf "%d ", diff < 0 ? -1 : (diff > 0 ? 1 : 0)}')" + + if [ "${counts}" != "1 1 0 1 " ]; then + fail "trace collection error: ${counts}" + fi +} + +echo "Simple trace test / sanity check using sandbox" +echo +tmp="$(tempfile)" +build_uboot +run_trace >${tmp} +check_results ${tmp} +rm ${tmp} +echo "Test passed" diff --git a/test/vboot/.gitignore b/test/vboot/.gitignore new file mode 100644 index 0000000..4631242 --- /dev/null +++ b/test/vboot/.gitignore @@ -0,0 +1,3 @@ +/*.dtb +/test.fit +/dev-keys diff --git a/test/vboot/sandbox-kernel.dts b/test/vboot/sandbox-kernel.dts new file mode 100644 index 0000000..a1e853c --- /dev/null +++ b/test/vboot/sandbox-kernel.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + model = "Sandbox Verified Boot Test"; + compatible = "sandbox"; + +}; diff --git a/test/vboot/sandbox-u-boot.dts b/test/vboot/sandbox-u-boot.dts new file mode 100644 index 0000000..a1e853c --- /dev/null +++ b/test/vboot/sandbox-u-boot.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { + model = "Sandbox Verified Boot Test"; + compatible = "sandbox"; + +}; diff --git a/test/vboot/sign-configs.its b/test/vboot/sign-configs.its new file mode 100644 index 0000000..db2ed79 --- /dev/null +++ b/test/vboot/sign-configs.its @@ -0,0 +1,45 @@ +/dts-v1/; + +/ { + description = "Chrome OS kernel image with one or more FDT blobs"; + #address-cells = <1>; + + images { + kernel@1 { + data = /incbin/("test-kernel.bin"); + type = "kernel_noload"; + arch = "sandbox"; + os = "linux"; + compression = "none"; + load = <0x4>; + entry = <0x8>; + kernel-version = <1>; + hash@1 { + algo = "sha1"; + }; + }; + fdt@1 { + description = "snow"; + data = /incbin/("sandbox-kernel.dtb"); + type = "flat_dt"; + arch = "sandbox"; + compression = "none"; + fdt-version = <1>; + hash@1 { + algo = "sha1"; + }; + }; + }; + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + signature@1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + sign-images = "fdt", "kernel"; + }; + }; + }; +}; diff --git a/test/vboot/sign-images.its b/test/vboot/sign-images.its new file mode 100644 index 0000000..f69326a --- /dev/null +++ b/test/vboot/sign-images.its @@ -0,0 +1,42 @@ +/dts-v1/; + +/ { + description = "Chrome OS kernel image with one or more FDT blobs"; + #address-cells = <1>; + + images { + kernel@1 { + data = /incbin/("test-kernel.bin"); + type = "kernel_noload"; + arch = "sandbox"; + os = "linux"; + compression = "none"; + load = <0x4>; + entry = <0x8>; + kernel-version = <1>; + signature@1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + }; + }; + fdt@1 { + description = "snow"; + data = /incbin/("sandbox-kernel.dtb"); + type = "flat_dt"; + arch = "sandbox"; + compression = "none"; + fdt-version = <1>; + signature@1 { + algo = "sha1,rsa2048"; + key-name-hint = "dev"; + }; + }; + }; + configurations { + default = "conf@1"; + conf@1 { + kernel = "kernel@1"; + fdt = "fdt@1"; + }; + }; +}; diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh new file mode 100755 index 0000000..c3cfade --- /dev/null +++ b/test/vboot/vboot_test.sh @@ -0,0 +1,126 @@ +#!/bin/sh +# +# Copyright (c) 2013, Google Inc. +# +# Simple Verified Boot Test Script +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA + +set -e + +# Run U-Boot and report the result +# Args: +# $1: Test message +run_uboot() { + echo -n "Test Verified Boot Run: $1: " + ${uboot} -d sandbox-u-boot.dtb >${tmp} -c ' +sb load host 0 100 test.fit; +fdt addr 100; +bootm 100; +reset' + if ! grep -q "$2" ${tmp}; then + echo + echo "Verified boot key check failed, output follows:" + cat ${tmp} + false + else + echo "OK" + fi +} + +echo "Simple Verified Boot Test" +echo "=========================" +echo +echo "Please see doc/uImage.FIT/verified-boot.txt for more information" +echo + +err=0 +tmp=/tmp/vboot_test.$$ + +dir=$(dirname $0) + +if [ -z ${O} ]; then + O=. +fi +O=$(readlink -f ${O}) + +dtc="-I dts -O dtb -p 2000" +uboot="${O}/u-boot" +mkimage="${O}/tools/mkimage" +keys="${dir}/dev-keys" +echo ${mkimage} -D "${dtc}" + +echo "Build keys" +mkdir -p ${keys} + +# Create an RSA key pair +openssl genrsa -F4 -out ${keys}/dev.key 2048 2>/dev/null + +# Create a certificate containing the public key +openssl req -batch -new -x509 -key ${keys}/dev.key -out ${keys}/dev.crt + +pushd ${dir} >/dev/null + +# Compile our device tree files for kernel and U-Boot (CONFIG_OF_CONTROL) +dtc -p 0x1000 sandbox-kernel.dts -O dtb -o sandbox-kernel.dtb +dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb + +# Create a number kernel image with zeroes +head -c 5000 /dev/zero >test-kernel.bin + +# Build the FIT, but don't sign anything yet +echo Build FIT with signed images +${mkimage} -D "${dtc}" -f sign-images.its test.fit >${tmp} + +run_uboot "unsigned signatures:" "dev-" + +# Sign images with our dev keys +echo Sign images +${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp} + +run_uboot "signed images" "dev+" + + +# Create a fresh .dtb without the public keys +dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb + +echo Build FIT with signed configuration +${mkimage} -D "${dtc}" -f sign-configs.its test.fit >${tmp} + +run_uboot "unsigned config" "sha1+ OK" + +# Sign images with our dev keys +echo Sign images +${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp} + +run_uboot "signed config" "dev+" + +# Increment the first byte of the signature, which should cause failure +sig=$(fdtget -t bx test.fit /configurations/conf@1/signature@1 value) +newbyte=$(printf %x $((0x${sig:0:2} + 1))) +sig="${newbyte} ${sig:2}" +fdtput -t bx test.fit /configurations/conf@1/signature@1 value ${sig} + +run_uboot "signed config with bad hash" "Bad Data Hash" + +popd >/dev/null + +echo +if ${ok}; then + echo "Test passed" +else + echo "Test failed" +fi diff --git a/tools/.gitignore b/tools/.gitignore index 9bce719..a7fee26 100644 --- a/tools/.gitignore +++ b/tools/.gitignore @@ -9,6 +9,7 @@ /mxsboot /ncb /ncp +/proftool /ubsha1 /xway-swap-bytes /*.exe diff --git a/tools/Makefile b/tools/Makefile index 4630f03..46159b2 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -74,11 +74,13 @@ BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX) BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX) BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX) BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX) +BIN_FILES-y += proftool(SFX) # Source files which exist outside the tools directory EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o EXT_OBJ_FILES-y += common/image.o EXT_OBJ_FILES-$(CONFIG_FIT) += common/image-fit.o +EXT_OBJ_FILES-y += common/image-sig.o EXT_OBJ_FILES-y += lib/crc32.o EXT_OBJ_FILES-y += lib/md5.o EXT_OBJ_FILES-y += lib/sha1.o @@ -87,6 +89,7 @@ EXT_OBJ_FILES-y += lib/sha1.o OBJ_FILES-$(CONFIG_LCD_LOGO) += bmp_logo.o OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o NOPED_OBJ_FILES-y += default_image.o +NOPED_OBJ_FILES-y += proftool.o OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o NOPED_OBJ_FILES-y += fit_image.o OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o @@ -122,6 +125,9 @@ LIBFDT_OBJ_FILES-y += fdt_rw.o LIBFDT_OBJ_FILES-y += fdt_strerror.o LIBFDT_OBJ_FILES-y += fdt_wip.o +# RSA objects +RSA_OBJ_FILES-$(CONFIG_FIT_SIGNATURE) += rsa-sign.o + # Generated LCD/video logo LOGO_H = $(OBJTREE)/include/bmp_logo.h LOGO_DATA_H = $(OBJTREE)/include/bmp_logo_data.h @@ -149,8 +155,14 @@ endif # !LOGO_BMP HOSTSRCS += $(addprefix $(SRCTREE)/,$(EXT_OBJ_FILES-y:.o=.c)) HOSTSRCS += $(addprefix $(SRCTREE)/tools/,$(OBJ_FILES-y:.o=.c)) HOSTSRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c)) +HOSTSRCS += $(addprefix $(SRCTREE)/lib/rsa/,$(RSA_OBJ_FILES-y:.o=.c)) BINS := $(addprefix $(obj),$(sort $(BIN_FILES-y))) LIBFDT_OBJS := $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y)) +RSA_OBJS := $(addprefix $(obj),$(RSA_OBJ_FILES-y)) + +# We cannot check CONFIG_FIT_SIGNATURE here since it is not set on the host +FIT_SIG_OBJ_FILES := image-sig.o +FIT_SIG_OBJS := $(addprefix $(obj),$(FIT_SIG_OBJ_FILES)) HOSTOBJS := $(addprefix $(obj),$(OBJ_FILES-y)) NOPEDOBJS := $(addprefix $(obj),$(NOPED_OBJ_FILES-y)) @@ -180,6 +192,10 @@ $(obj)bmp_logo$(SFX): $(obj)bmp_logo.o $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTSTRIP) $@ +$(obj)proftool(SFX): $(obj)proftool.o + $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ + $(HOSTSTRIP) $@ + $(obj)envcrc$(SFX): $(obj)crc32.o $(obj)env_embedded.o $(obj)envcrc.o $(obj)sha1.o $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ @@ -207,6 +223,7 @@ $(obj)mkimage$(SFX): $(obj)aisimage.o \ $(obj)image-fit.o \ $(obj)image.o \ $(obj)image-host.o \ + $(FIT_SIG_OBJS) \ $(obj)imximage.o \ $(obj)kwbimage.o \ $(obj)pblimage.o \ @@ -216,8 +233,9 @@ $(obj)mkimage$(SFX): $(obj)aisimage.o \ $(obj)omapimage.o \ $(obj)sha1.o \ $(obj)ublimage.o \ - $(LIBFDT_OBJS) - $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ + $(LIBFDT_OBJS) \ + $(RSA_OBJS) + $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS) $(HOSTSTRIP) $@ $(obj)mk$(BOARD)spl$(SFX): $(obj)mkexynosspl.o @@ -253,6 +271,9 @@ $(obj)%.o: $(SRCTREE)/lib/%.c $(obj)%.o: $(SRCTREE)/lib/libfdt/%.c $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $< +$(obj)%.o: $(SRCTREE)/lib/rsa/%.c + $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $< + subdirs: ifeq ($(TOOLSUBDIRS),) @: diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index 9f23901..896e2bc 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -273,6 +273,7 @@ our $logFunctions = qr{(?x: WARN(?:_RATELIMIT|_ONCE|)| panic| debug| + printf| MODULE_[A-Z_]+ )}; diff --git a/tools/fit_image.c b/tools/fit_image.c index cc123dd..281c2bd 100644 --- a/tools/fit_image.c +++ b/tools/fit_image.c @@ -105,9 +105,11 @@ static int fit_handle_file (struct mkimage_params *params) { char tmpfile[MKIMAGE_MAX_TMPFILE_LEN]; char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN]; - int tfd; + int tfd, destfd = 0; + void *dest_blob = NULL; struct stat sbuf; void *ptr; + off_t destfd_size = 0; /* Flattened Image Tree (FIT) format handling */ debug ("FIT format handling\n"); @@ -122,29 +124,44 @@ static int fit_handle_file (struct mkimage_params *params) } sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX); - /* dtc -I dts -O dtb -p 500 datafile > tmpfile */ - sprintf (cmd, "%s %s %s > %s", - MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); - debug ("Trying to execute \"%s\"\n", cmd); + /* We either compile the source file, or use the existing FIT image */ + if (params->datafile) { + /* dtc -I dts -O dtb -p 500 datafile > tmpfile */ + snprintf(cmd, sizeof(cmd), "%s %s %s > %s", + MKIMAGE_DTC, params->dtc, params->datafile, tmpfile); + debug("Trying to execute \"%s\"\n", cmd); + } else { + snprintf(cmd, sizeof(cmd), "cp %s %s", + params->imagefile, tmpfile); + } if (system (cmd) == -1) { fprintf (stderr, "%s: system(%s) failed: %s\n", params->cmdname, cmd, strerror(errno)); goto err_system; } + if (params->keydest) { + destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf); + if (destfd < 0) + goto err_keydest; + destfd_size = sbuf.st_size; + } + tfd = mmap_fdt(params, tmpfile, &ptr, &sbuf); if (tfd < 0) goto err_mmap; /* set hashes for images in the blob */ - if (fit_add_verification_data(ptr)) { - fprintf (stderr, "%s Can't add hashes to FIT blob", - params->cmdname); + if (fit_add_verification_data(params->keydir, + dest_blob, ptr, params->comment, + params->require_keys)) { + fprintf(stderr, "%s Can't add hashes to FIT blob\n", + params->cmdname); goto err_add_hashes; } - /* add a timestamp at offset 0 i.e., root */ - if (fit_set_timestamp (ptr, 0, sbuf.st_mtime)) { + /* for first image creation, add a timestamp at offset 0 i.e., root */ + if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) { fprintf (stderr, "%s: Can't add image timestamp\n", params->cmdname); goto err_add_timestamp; @@ -153,6 +170,10 @@ static int fit_handle_file (struct mkimage_params *params) munmap ((void *)ptr, sbuf.st_size); close (tfd); + if (dest_blob) { + munmap(dest_blob, destfd_size); + close(destfd); + } if (rename (tmpfile, params->imagefile) == -1) { fprintf (stderr, "%s: Can't rename %s to %s: %s\n", @@ -168,6 +189,9 @@ err_add_timestamp: err_add_hashes: munmap(ptr, sbuf.st_size); err_mmap: + if (dest_blob) + munmap(dest_blob, destfd_size); +err_keydest: err_system: unlink(tmpfile); return -1; diff --git a/tools/image-host.c b/tools/image-host.c index d944d0f..932384b 100644 --- a/tools/image-host.c +++ b/tools/image-host.c @@ -26,12 +26,8 @@ */ #include "mkimage.h" -#include <bootstage.h> #include <image.h> -#include <sha1.h> -#include <time.h> -#include <u-boot/crc.h> -#include <u-boot/md5.h> +#include <version.h> /** * fit_set_hash_value - set hash value in requested has node @@ -108,9 +104,165 @@ static int fit_image_process_hash(void *fit, const char *image_name, } /** - * fit_image_add_verification_data() - calculate/set hash data for image node + * fit_image_write_sig() - write the signature to a FIT * - * This adds hash values for a component image node. + * This writes the signature and signer data to the FIT. + * + * @fit: pointer to the FIT format image header + * @noffset: hash node offset + * @value: signature value to be set + * @value_len: signature value length + * @comment: Text comment to write (NULL for none) + * + * returns + * 0, on success + * -FDT_ERR_..., on failure + */ +static int fit_image_write_sig(void *fit, int noffset, uint8_t *value, + int value_len, const char *comment, const char *region_prop, + int region_proplen) +{ + int string_size; + int ret; + + /* + * Get the current string size, before we update the FIT and add + * more + */ + string_size = fdt_size_dt_strings(fit); + + ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len); + if (!ret) { + ret = fdt_setprop_string(fit, noffset, "signer-name", + "mkimage"); + } + if (!ret) { + ret = fdt_setprop_string(fit, noffset, "signer-version", + PLAIN_VERSION); + } + if (comment && !ret) + ret = fdt_setprop_string(fit, noffset, "comment", comment); + if (!ret) + ret = fit_set_timestamp(fit, noffset, time(NULL)); + if (region_prop && !ret) { + uint32_t strdata[2]; + + ret = fdt_setprop(fit, noffset, "hashed-nodes", + region_prop, region_proplen); + strdata[0] = 0; + strdata[1] = cpu_to_fdt32(string_size); + if (!ret) { + ret = fdt_setprop(fit, noffset, "hashed-strings", + strdata, sizeof(strdata)); + } + } + + return ret; +} + +static int fit_image_setup_sig(struct image_sign_info *info, + const char *keydir, void *fit, const char *image_name, + int noffset, const char *require_keys) +{ + const char *node_name; + char *algo_name; + + node_name = fit_get_name(fit, noffset, NULL); + if (fit_image_hash_get_algo(fit, noffset, &algo_name)) { + printf("Can't get algo property for '%s' signature node in '%s' image node\n", + node_name, image_name); + return -1; + } + + memset(info, '\0', sizeof(*info)); + info->keydir = keydir; + info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + info->fit = fit; + info->node_offset = noffset; + info->algo = image_get_sig_algo(algo_name); + info->require_keys = require_keys; + if (!info->algo) { + printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n", + algo_name, node_name, image_name); + return -1; + } + + return 0; +} + +/** + * fit_image_process_sig- Process a single subnode of the images/ node + * + * Check each subnode and process accordingly. For signature nodes we + * generate a signed hash of the supplised data and store it in the node. + * + * @keydir: Directory containing keys to use for signing + * @keydest: Destination FDT blob to write public keys into + * @fit: pointer to the FIT format image header + * @image_name: name of image being processes (used to display errors) + * @noffset: subnode offset + * @data: data to process + * @size: size of data in bytes + * @comment: Comment to add to signature nodes + * @require_keys: Mark all keys as 'required' + * @return 0 if ok, -1 on error + */ +static int fit_image_process_sig(const char *keydir, void *keydest, + void *fit, const char *image_name, + int noffset, const void *data, size_t size, + const char *comment, int require_keys) +{ + struct image_sign_info info; + struct image_region region; + const char *node_name; + uint8_t *value; + uint value_len; + int ret; + + if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset, + require_keys ? "image" : NULL)) + return -1; + + node_name = fit_get_name(fit, noffset, NULL); + region.data = data; + region.size = size; + ret = info.algo->sign(&info, ®ion, 1, &value, &value_len); + if (ret) { + printf("Failed to sign '%s' signature node in '%s' image node: %d\n", + node_name, image_name, ret); + + /* We allow keys to be missing */ + if (ret == -ENOENT) + return 0; + return -1; + } + + ret = fit_image_write_sig(fit, noffset, value, value_len, comment, + NULL, 0); + if (ret) { + printf("Can't write signature for '%s' signature node in '%s' image node: %s\n", + node_name, image_name, fdt_strerror(ret)); + return -1; + } + free(value); + + /* Get keyname again, as FDT has changed and invalidated our pointer */ + info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + + /* Write the public key into the supplied FDT file */ + if (keydest && info.algo->add_verify_data(&info, keydest)) { + printf("Failed to add verification data for '%s' signature node in '%s' image node\n", + node_name, image_name); + return -1; + } + + return 0; +} + +/** + * fit_image_add_verification_data() - calculate/set verig. data for image node + * + * This adds hash and signature values for an component image node. * * All existing hash subnodes are checked, if algorithm property is set to * one of the supported hash algorithms, hash value is computed and @@ -133,11 +285,17 @@ static int fit_image_process_hash(void *fit, const char *image_name, * * For signature details, please see doc/uImage.FIT/signature.txt * + * @keydir Directory containing *.key and *.crt files (or NULL) + * @keydest FDT Blob to write public keys into (NULL if none) * @fit: Pointer to the FIT format image header * @image_noffset: Requested component image node + * @comment: Comment to add to signature nodes + * @require_keys: Mark all keys as 'required' * @return: 0 on success, <0 on failure */ -int fit_image_add_verification_data(void *fit, int image_noffset) +int fit_image_add_verification_data(const char *keydir, void *keydest, + void *fit, int image_noffset, const char *comment, + int require_keys) { const char *image_name; const void *data; @@ -169,6 +327,12 @@ int fit_image_add_verification_data(void *fit, int image_noffset) strlen(FIT_HASH_NODENAME))) { ret = fit_image_process_hash(fit, image_name, noffset, data, size); + } else if (IMAGE_ENABLE_SIGN && keydir && + !strncmp(node_name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_image_process_sig(keydir, keydest, + fit, image_name, noffset, data, size, + comment, require_keys); } if (ret) return -1; @@ -177,9 +341,326 @@ int fit_image_add_verification_data(void *fit, int image_noffset) return 0; } -int fit_add_verification_data(void *fit) +struct strlist { + int count; + char **strings; +}; + +static void strlist_init(struct strlist *list) +{ + memset(list, '\0', sizeof(*list)); +} + +static void strlist_free(struct strlist *list) +{ + int i; + + for (i = 0; i < list->count; i++) + free(list->strings[i]); + free(list->strings); +} + +static int strlist_add(struct strlist *list, const char *str) +{ + char *dup; + + dup = strdup(str); + list->strings = realloc(list->strings, + (list->count + 1) * sizeof(char *)); + if (!list || !str) + return -1; + list->strings[list->count++] = dup; + + return 0; +} + +static const char *fit_config_get_image_list(void *fit, int noffset, + int *lenp, int *allow_missingp) +{ + static const char default_list[] = FIT_KERNEL_PROP "\0" + FIT_FDT_PROP; + const char *prop; + + /* If there is an "image" property, use that */ + prop = fdt_getprop(fit, noffset, "sign-images", lenp); + if (prop) { + *allow_missingp = 0; + return *lenp ? prop : NULL; + } + + /* Default image list */ + *allow_missingp = 1; + *lenp = sizeof(default_list); + + return default_list; +} + +static int fit_config_get_hash_list(void *fit, int conf_noffset, + int sig_offset, struct strlist *node_inc) +{ + int allow_missing; + const char *prop, *iname, *end; + const char *conf_name, *sig_name; + char name[200], path[200]; + int image_count; + int ret, len; + + conf_name = fit_get_name(fit, conf_noffset, NULL); + sig_name = fit_get_name(fit, sig_offset, NULL); + + /* + * Build a list of nodes we need to hash. We always need the root + * node and the configuration. + */ + strlist_init(node_inc); + snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name); + if (strlist_add(node_inc, "/") || + strlist_add(node_inc, name)) + goto err_mem; + + /* Get a list of images that we intend to sign */ + prop = fit_config_get_image_list(fit, conf_noffset, &len, + &allow_missing); + if (!prop) + return 0; + + /* Locate the images */ + end = prop + len; + image_count = 0; + for (iname = prop; iname < end; iname += strlen(iname) + 1) { + int noffset; + int image_noffset; + int hash_count; + + image_noffset = fit_conf_get_prop_node(fit, conf_noffset, + iname); + if (image_noffset < 0) { + printf("Failed to find image '%s' in configuration '%s/%s'\n", + iname, conf_name, sig_name); + if (allow_missing) + continue; + + return -ENOENT; + } + + ret = fdt_get_path(fit, image_noffset, path, sizeof(path)); + if (ret < 0) + goto err_path; + if (strlist_add(node_inc, path)) + goto err_mem; + + snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, + conf_name); + + /* Add all this image's hashes */ + hash_count = 0; + for (noffset = fdt_first_subnode(fit, image_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + const char *name = fit_get_name(fit, noffset, NULL); + + if (strncmp(name, FIT_HASH_NODENAME, + strlen(FIT_HASH_NODENAME))) + continue; + ret = fdt_get_path(fit, noffset, path, sizeof(path)); + if (ret < 0) + goto err_path; + if (strlist_add(node_inc, path)) + goto err_mem; + hash_count++; + } + + if (!hash_count) { + printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n", + conf_name, sig_name, iname); + return -ENOMSG; + } + + image_count++; + } + + if (!image_count) { + printf("Failed to find any images for configuration '%s/%s'\n", + conf_name, sig_name); + return -ENOMSG; + } + + return 0; + +err_mem: + printf("Out of memory processing configuration '%s/%s'\n", conf_name, + sig_name); + return -ENOMEM; + +err_path: + printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n", + iname, conf_name, sig_name, fdt_strerror(ret)); + return -ENOENT; +} + +static int fit_config_get_data(void *fit, int conf_noffset, int noffset, + struct image_region **regionp, int *region_countp, + char **region_propp, int *region_proplen) { - int images_noffset; + char * const exc_prop[] = {"data"}; + struct strlist node_inc; + struct image_region *region; + struct fdt_region fdt_regions[100]; + const char *conf_name, *sig_name; + char path[200]; + int count, i; + char *region_prop; + int ret, len; + + conf_name = fit_get_name(fit, conf_noffset, NULL); + sig_name = fit_get_name(fit, conf_noffset, NULL); + debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name); + + /* Get a list of nodes we want to hash */ + ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc); + if (ret) + return ret; + + /* Get a list of regions to hash */ + count = fdt_find_regions(fit, node_inc.strings, node_inc.count, + exc_prop, ARRAY_SIZE(exc_prop), + fdt_regions, ARRAY_SIZE(fdt_regions), + path, sizeof(path), 1); + if (count < 0) { + printf("Failed to hash configuration '%s/%s': %s\n", conf_name, + sig_name, fdt_strerror(ret)); + return -EIO; + } + if (count == 0) { + printf("No data to hash for configuration '%s/%s': %s\n", + conf_name, sig_name, fdt_strerror(ret)); + return -EINVAL; + } + + /* Build our list of data blocks */ + region = fit_region_make_list(fit, fdt_regions, count, NULL); + if (!region) { + printf("Out of memory hashing configuration '%s/%s'\n", + conf_name, sig_name); + return -ENOMEM; + } + + /* Create a list of all hashed properties */ + debug("Hash nodes:\n"); + for (i = len = 0; i < node_inc.count; i++) { + debug(" %s\n", node_inc.strings[i]); + len += strlen(node_inc.strings[i]) + 1; + } + region_prop = malloc(len); + if (!region_prop) { + printf("Out of memory setting up regions for configuration '%s/%s'\n", + conf_name, sig_name); + return -ENOMEM; + } + for (i = len = 0; i < node_inc.count; + len += strlen(node_inc.strings[i]) + 1, i++) + strcpy(region_prop + len, node_inc.strings[i]); + strlist_free(&node_inc); + + *region_countp = count; + *regionp = region; + *region_propp = region_prop; + *region_proplen = len; + + return 0; +} + +static int fit_config_process_sig(const char *keydir, void *keydest, + void *fit, const char *conf_name, int conf_noffset, + int noffset, const char *comment, int require_keys) +{ + struct image_sign_info info; + const char *node_name; + struct image_region *region; + char *region_prop; + int region_proplen; + int region_count; + uint8_t *value; + uint value_len; + int ret; + + node_name = fit_get_name(fit, noffset, NULL); + if (fit_config_get_data(fit, conf_noffset, noffset, ®ion, + ®ion_count, ®ion_prop, ®ion_proplen)) + return -1; + + if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset, + require_keys ? "conf" : NULL)) + return -1; + + ret = info.algo->sign(&info, region, region_count, &value, &value_len); + free(region); + if (ret) { + printf("Failed to sign '%s' signature node in '%s' conf node\n", + node_name, conf_name); + + /* We allow keys to be missing */ + if (ret == -ENOENT) + return 0; + return -1; + } + + if (fit_image_write_sig(fit, noffset, value, value_len, comment, + region_prop, region_proplen)) { + printf("Can't write signature for '%s' signature node in '%s' conf node\n", + node_name, conf_name); + return -1; + } + free(value); + free(region_prop); + + /* Get keyname again, as FDT has changed and invalidated our pointer */ + info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL); + + /* Write the public key into the supplied FDT file */ + if (keydest && info.algo->add_verify_data(&info, keydest)) { + printf("Failed to add verification data for '%s' signature node in '%s' image node\n", + node_name, conf_name); + return -1; + } + + return 0; +} + +static int fit_config_add_verification_data(const char *keydir, void *keydest, + void *fit, int conf_noffset, const char *comment, + int require_keys) +{ + const char *conf_name; + int noffset; + + conf_name = fit_get_name(fit, conf_noffset, NULL); + + /* Process all hash subnodes of the configuration node */ + for (noffset = fdt_first_subnode(fit, conf_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + const char *node_name; + int ret = 0; + + node_name = fit_get_name(fit, noffset, NULL); + if (!strncmp(node_name, FIT_SIG_NODENAME, + strlen(FIT_SIG_NODENAME))) { + ret = fit_config_process_sig(keydir, keydest, + fit, conf_name, conf_noffset, noffset, comment, + require_keys); + } + if (ret) + return ret; + } + + return 0; +} + +int fit_add_verification_data(const char *keydir, void *keydest, void *fit, + const char *comment, int require_keys) +{ + int images_noffset, confs_noffset; int noffset; int ret; @@ -199,7 +680,31 @@ int fit_add_verification_data(void *fit) * Direct child node of the images parent node, * i.e. component image node. */ - ret = fit_image_add_verification_data(fit, noffset); + ret = fit_image_add_verification_data(keydir, keydest, + fit, noffset, comment, require_keys); + if (ret) + return ret; + } + + /* If there are no keys, we can't sign configurations */ + if (!IMAGE_ENABLE_SIGN || !keydir) + return 0; + + /* Find configurations parent node offset */ + confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH); + if (confs_noffset < 0) { + printf("Can't find images parent node '%s' (%s)\n", + FIT_IMAGES_PATH, fdt_strerror(confs_noffset)); + return -ENOENT; + } + + /* Process its subnodes, print out component images details */ + for (noffset = fdt_first_subnode(fit, confs_noffset); + noffset >= 0; + noffset = fdt_next_subnode(fit, noffset)) { + ret = fit_config_add_verification_data(keydir, keydest, + fit, noffset, comment, + require_keys); if (ret) return ret; } diff --git a/tools/mkimage.c b/tools/mkimage.c index e43b09f..d312844 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -183,6 +183,11 @@ main (int argc, char **argv) genimg_get_arch_id (*++argv)) < 0) usage (); goto NXTARG; + case 'c': + if (--argc <= 0) + usage(); + params.comment = *++argv; + goto NXTARG; case 'C': if ((--argc <= 0) || (params.comp = @@ -240,19 +245,34 @@ main (int argc, char **argv) case 'f': if (--argc <= 0) usage (); + params.datafile = *++argv; + /* no break */ + case 'F': /* * The flattened image tree (FIT) format * requires a flattened device tree image type */ params.type = IH_TYPE_FLATDT; - params.datafile = *++argv; params.fflag = 1; goto NXTARG; + case 'k': + if (--argc <= 0) + usage(); + params.keydir = *++argv; + goto NXTARG; + case 'K': + if (--argc <= 0) + usage(); + params.keydest = *++argv; + goto NXTARG; case 'n': if (--argc <= 0) usage (); params.imagename = *++argv; goto NXTARG; + case 'r': + params.require_keys = 1; + break; case 'R': if (--argc <= 0) usage(); @@ -623,8 +643,20 @@ usage () " -d ==> use image data from 'datafile'\n" " -x ==> set XIP (execute in place)\n", params.cmdname); - fprintf (stderr, " %s [-D dtc_options] -f fit-image.its fit-image\n", + fprintf(stderr, " %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n", params.cmdname); + fprintf(stderr, " -D => set options for device tree compiler\n" + " -f => input filename for FIT source\n"); +#ifdef CONFIG_FIT_SIGNATURE + fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n" + " -k => set directory containing private keys\n" + " -K => write public keys to this .dtb file\n" + " -c => add comment in signature node\n" + " -F => re-sign existing FIT image\n" + " -r => mark keys used as 'required' in dtb\n"); +#else + fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n"); +#endif fprintf (stderr, " %s -V ==> print version information and exit\n", params.cmdname); diff --git a/tools/mkimage.h b/tools/mkimage.h index e07a615..1d9984e 100644 --- a/tools/mkimage.h +++ b/tools/mkimage.h @@ -44,12 +44,24 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +static inline void *map_sysmem(ulong paddr, unsigned long len) +{ + return (void *)(uintptr_t)paddr; +} + +static inline ulong map_to_sysmem(void *ptr) +{ + return (ulong)(uintptr_t)ptr; +} + #define MKIMAGE_TMPFILE_SUFFIX ".tmp" #define MKIMAGE_MAX_TMPFILE_LEN 256 #define MKIMAGE_DEFAULT_DTC_OPTIONS "-I dts -O dtb -p 500" #define MKIMAGE_MAX_DTC_CMDLINE_LEN 512 #define MKIMAGE_DTC "dtc" /* assume dtc is in $PATH */ +#define IH_ARCH_DEFAULT IH_ARCH_INVALID + /* * This structure defines all such variables those are initialized by * mkimage main core and need to be referred by image type specific @@ -75,6 +87,10 @@ struct mkimage_params { char *datafile; char *imagefile; char *cmdname; + const char *keydir; /* Directory holding private keys */ + const char *keydest; /* Destination .dtb for public key */ + const char *comment; /* Comment to add to signature node */ + int require_keys; /* 1 to mark signing keys as 'required' */ }; /* diff --git a/tools/pblimage.c b/tools/pblimage.c index 508a747..5f39dc5 100644 --- a/tools/pblimage.c +++ b/tools/pblimage.c @@ -26,18 +26,14 @@ #include "pblimage.h" /* - * The PBL can load up to 64 bytes at a time, so we split the U-Boot - * image into 64 byte chunks. PBL needs a command for each piece, of - * the form "81xxxxxx", where "xxxxxx" is the offset. SYS_TEXT_BASE - * is 0xFFF80000 for PBL boot, and PBL only cares about low 24-bit, - * so it starts from 0x81F80000. + * Initialize to an invalid value. */ -static uint32_t next_pbl_cmd = 0x81F80000; +static uint32_t next_pbl_cmd = 0x82000000; /* * need to store all bytes in memory for calculating crc32, then write the * bytes to image file for PBL boot. */ -static unsigned char mem_buf[600000]; +static unsigned char mem_buf[1000000]; static unsigned char *pmem_buf = mem_buf; static int pbl_size; static char *fname = "Unknown"; @@ -52,6 +48,27 @@ static union #define ENDIANNESS ((char)endian_test.l) +/* + * The PBL can load up to 64 bytes at a time, so we split the U-Boot + * image into 64 byte chunks. PBL needs a command for each piece, of + * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the + * start offset by subtracting the size of the u-boot image from the + * top of the allowable 24-bit range. + */ +static void init_next_pbl_cmd(FILE *fp_uboot) +{ + struct stat st; + int fd = fileno(fp_uboot); + + if (fstat(fd, &st) == -1) { + printf("Error: Could not determine u-boot image size. %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + + next_pbl_cmd = 0x82000000 - st.st_size; +} + static void generate_pbl_cmd(void) { uint32_t val = next_pbl_cmd; @@ -80,6 +97,7 @@ static void pbl_fget(size_t size, FILE *stream) /* load split u-boot with PBI command 81xxxxxx. */ static void load_uboot(FILE *fp_uboot) { + init_next_pbl_cmd(fp_uboot); while (next_pbl_cmd < 0x82000000) { generate_pbl_cmd(); pbl_fget(64, fp_uboot); diff --git a/tools/proftool.c b/tools/proftool.c new file mode 100644 index 0000000..aa05e77 --- /dev/null +++ b/tools/proftool.c @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* Decode and dump U-Boot profiling information */ + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <regex.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/param.h> + +#include <compiler.h> +#include <trace.h> + +#define MAX_LINE_LEN 500 + +enum { + FUNCF_TRACE = 1 << 0, /* Include this function in trace */ +}; + +struct func_info { + unsigned long offset; + const char *name; + unsigned long code_size; + unsigned long call_count; + unsigned flags; + /* the section this function is in */ + struct objsection_info *objsection; +}; + +enum trace_line_type { + TRACE_LINE_INCLUDE, + TRACE_LINE_EXCLUDE, +}; + +struct trace_configline_info { + struct trace_configline_info *next; + enum trace_line_type type; + const char *name; /* identifier name / wildcard */ + regex_t regex; /* Regex to use if name starts with / */ +}; + +/* The contents of the trace config file */ +struct trace_configline_info *trace_config_head; + +struct func_info *func_list; +int func_count; +struct trace_call *call_list; +int call_count; +int verbose; /* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */ +unsigned long text_offset; /* text address of first function */ + +static void outf(int level, const char *fmt, ...) + __attribute__ ((format (__printf__, 2, 3))); +#define error(fmt, b...) outf(0, fmt, ##b) +#define warn(fmt, b...) outf(1, fmt, ##b) +#define notice(fmt, b...) outf(2, fmt, ##b) +#define info(fmt, b...) outf(3, fmt, ##b) +#define debug(fmt, b...) outf(4, fmt, ##b) + + +static void outf(int level, const char *fmt, ...) +{ + if (verbose >= level) { + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + } +} + +static void usage(void) +{ + fprintf(stderr, + "Usage: proftool -cds -v3 <cmd> <profdata>\n" + "\n" + "Commands\n" + " dump-ftrace\t\tDump out textual data in ftrace format\n" + "\n" + "Options:\n" + " -m <map>\tSpecify Systen.map file\n" + " -t <trace>\tSpecific trace data file (from U-Boot)\n" + " -v <0-4>\tSpecify verbosity\n"); + exit(EXIT_FAILURE); +} + +static int h_cmp_offset(const void *v1, const void *v2) +{ + const struct func_info *f1 = v1, *f2 = v2; + + return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE); +} + +static int read_system_map(FILE *fin) +{ + unsigned long offset, start = 0; + struct func_info *func; + char buff[MAX_LINE_LEN]; + char symtype; + char symname[MAX_LINE_LEN + 1]; + int linenum; + int alloced; + + for (linenum = 1, alloced = func_count = 0;; linenum++) { + int fields = 0; + + if (fgets(buff, sizeof(buff), fin)) + fields = sscanf(buff, "%lx %c %100s\n", &offset, + &symtype, symname); + if (fields == 2) { + continue; + } else if (feof(fin)) { + break; + } else if (fields < 2) { + error("Map file line %d: invalid format\n", linenum); + return 1; + } + + /* Must be a text symbol */ + symtype = tolower(symtype); + if (symtype != 't' && symtype != 'w') + continue; + + if (func_count == alloced) { + alloced += 256; + func_list = realloc(func_list, + sizeof(struct func_info) * alloced); + assert(func_list); + } + if (!func_count) + start = offset; + + func = &func_list[func_count++]; + memset(func, '\0', sizeof(*func)); + func->offset = offset - start; + func->name = strdup(symname); + func->flags = FUNCF_TRACE; /* trace by default */ + + /* Update previous function's code size */ + if (func_count > 1) + func[-1].code_size = func->offset - func[-1].offset; + } + notice("%d functions found in map file\n", func_count); + text_offset = start; + return 0; +} + +static int read_data(FILE *fin, void *buff, int size) +{ + int err; + + err = fread(buff, 1, size, fin); + if (!err) + return 1; + if (err != size) { + error("Cannot read profile file at pos %ld\n", ftell(fin)); + return -1; + } + return 0; +} + +static struct func_info *find_func_by_offset(uint32_t offset) +{ + struct func_info key, *found; + + key.offset = offset; + found = bsearch(&key, func_list, func_count, sizeof(struct func_info), + h_cmp_offset); + + return found; +} + +/* This finds the function which contains the given offset */ +static struct func_info *find_caller_by_offset(uint32_t offset) +{ + int low; /* least function that could be a match */ + int high; /* greated function that could be a match */ + struct func_info key; + + low = 0; + high = func_count - 1; + key.offset = offset; + while (high > low + 1) { + int mid = (low + high) / 2; + int result; + + result = h_cmp_offset(&key, &func_list[mid]); + if (result > 0) + low = mid; + else if (result < 0) + high = mid; + else + return &func_list[mid]; + } + + return low >= 0 ? &func_list[low] : NULL; +} + +static int read_calls(FILE *fin, int count) +{ + struct trace_call *call_data; + int i; + + notice("call count: %d\n", count); + call_list = (struct trace_call *)calloc(count, sizeof(*call_data)); + if (!call_list) { + error("Cannot allocate call_list\n"); + return -1; + } + call_count = count; + + call_data = call_list; + for (i = 0; i < count; i++, call_data++) { + if (read_data(fin, call_data, sizeof(*call_data))) + return 1; + } + return 0; +} + +static int read_profile(FILE *fin, int *not_found) +{ + struct trace_output_hdr hdr; + + *not_found = 0; + while (!feof(fin)) { + int err; + + err = read_data(fin, &hdr, sizeof(hdr)); + if (err == 1) + break; /* EOF */ + else if (err) + return 1; + + switch (hdr.type) { + case TRACE_CHUNK_FUNCS: + /* Ignored at present */ + break; + + case TRACE_CHUNK_CALLS: + if (read_calls(fin, hdr.rec_count)) + return 1; + break; + } + } + return 0; +} + +static int read_map_file(const char *fname) +{ + FILE *fmap; + int err = 0; + + fmap = fopen(fname, "r"); + if (!fmap) { + error("Cannot open map file '%s'\n", fname); + return 1; + } + if (fmap) { + err = read_system_map(fmap); + fclose(fmap); + } + return err; +} + +static int read_profile_file(const char *fname) +{ + int not_found = INT_MAX; + FILE *fprof; + int err; + + fprof = fopen(fname, "rb"); + if (!fprof) { + error("Cannot open profile data file '%s'\n", + fname); + return 1; + } else { + err = read_profile(fprof, ¬_found); + fclose(fprof); + if (err) + return err; + + if (not_found) { + warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n", + not_found); + return 1; + } + } + return 0; +} + +static int regex_report_error(regex_t *regex, int err, const char *op, + const char *name) +{ + char buf[200]; + + regerror(err, regex, buf, sizeof(buf)); + error("Regex error '%s' in %s '%s'\n", buf, op, name); + return -1; +} + +static void check_trace_config_line(struct trace_configline_info *item) +{ + struct func_info *func, *end; + int err; + + debug("Checking trace config line '%s'\n", item->name); + for (func = func_list, end = func + func_count; func < end; func++) { + err = regexec(&item->regex, func->name, 0, NULL, 0); + debug(" - regex '%s', string '%s': %d\n", item->name, + func->name, err); + if (err == REG_NOMATCH) + continue; + + if (err) { + regex_report_error(&item->regex, err, "match", + item->name); + break; + } + + /* It matches, so perform the action */ + switch (item->type) { + case TRACE_LINE_INCLUDE: + info(" include %s at %lx\n", func->name, + text_offset + func->offset); + func->flags |= FUNCF_TRACE; + break; + + case TRACE_LINE_EXCLUDE: + info(" exclude %s at %lx\n", func->name, + text_offset + func->offset); + func->flags &= ~FUNCF_TRACE; + break; + } + } +} + +static void check_trace_config(void) +{ + struct trace_configline_info *line; + + for (line = trace_config_head; line; line = line->next) + check_trace_config_line(line); +} + +/** + * Check the functions to see if they each have an objsection. If not, then + * the linker must have eliminated them. + */ +static void check_functions(void) +{ + struct func_info *func, *end; + unsigned long removed_code_size = 0; + int not_found = 0; + + /* Look for missing functions */ + for (func = func_list, end = func + func_count; func < end; func++) { + if (!func->objsection) { + removed_code_size += func->code_size; + not_found++; + } + } + + /* Figure out what functions we want to trace */ + check_trace_config(); + + warn("%d functions removed by linker, %ld code size\n", + not_found, removed_code_size); +} + +static int read_trace_config(FILE *fin) +{ + char buff[200]; + int linenum = 0; + struct trace_configline_info **tailp = &trace_config_head; + + while (fgets(buff, sizeof(buff), fin)) { + int len = strlen(buff); + struct trace_configline_info *line; + char *saveptr; + char *s, *tok; + int err; + + linenum++; + if (len && buff[len - 1] == '\n') + buff[len - 1] = '\0'; + + /* skip blank lines and comments */ + for (s = buff; *s == ' ' || *s == '\t'; s++) + ; + if (!*s || *s == '#') + continue; + + line = (struct trace_configline_info *)calloc(1, + sizeof(*line)); + if (!line) { + error("Cannot allocate config line\n"); + return -1; + } + + tok = strtok_r(s, " \t", &saveptr); + if (!tok) { + error("Invalid trace config data on line %d\n", + linenum); + return -1; + } + if (0 == strcmp(tok, "include-func")) { + line->type = TRACE_LINE_INCLUDE; + } else if (0 == strcmp(tok, "exclude-func")) { + line->type = TRACE_LINE_EXCLUDE; + } else { + error("Unknown command in trace config data line %d\n", + linenum); + return -1; + } + + tok = strtok_r(NULL, " \t", &saveptr); + if (!tok) { + error("Missing pattern in trace config data line %d\n", + linenum); + return -1; + } + + err = regcomp(&line->regex, tok, REG_NOSUB); + if (err) { + free(line); + return regex_report_error(&line->regex, err, "compile", + tok); + } + + /* link this new one to the end of the list */ + line->name = strdup(tok); + line->next = NULL; + *tailp = line; + tailp = &line->next; + } + + if (!feof(fin)) { + error("Cannot read from trace config file at position %ld\n", + ftell(fin)); + return -1; + } + return 0; +} + +static int read_trace_config_file(const char *fname) +{ + FILE *fin; + int err; + + fin = fopen(fname, "r"); + if (!fin) { + error("Cannot open trace_config file '%s'\n", fname); + return -1; + } + err = read_trace_config(fin); + fclose(fin); + return err; +} + +static void out_func(ulong func_offset, int is_caller, const char *suffix) +{ + struct func_info *func; + + func = (is_caller ? find_caller_by_offset : find_func_by_offset) + (func_offset); + + if (func) + printf("%s%s", func->name, suffix); + else + printf("%lx%s", func_offset, suffix); +} + +/* + * # tracer: function + * # + * # TASK-PID CPU# TIMESTAMP FUNCTION + * # | | | | | + * # bash-4251 [01] 10152.583854: path_put <-path_walk + * # bash-4251 [01] 10152.583855: dput <-path_put + * # bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput + */ +static int make_ftrace(void) +{ + struct trace_call *call; + int missing_count = 0, skip_count = 0; + int i; + + printf("# tracer: ftrace\n" + "#\n" + "# TASK-PID CPU# TIMESTAMP FUNCTION\n" + "# | | | | |\n"); + for (i = 0, call = call_list; i < call_count; i++, call++) { + struct func_info *func = find_func_by_offset(call->func); + ulong time = call->flags & FUNCF_TIMESTAMP_MASK; + + if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY && + TRACE_CALL_TYPE(call) != FUNCF_EXIT) + continue; + if (!func) { + warn("Cannot find function at %lx\n", + text_offset + call->func); + missing_count++; + continue; + } + + if (!(func->flags & FUNCF_TRACE)) { + debug("Funcion '%s' is excluded from trace\n", + func->name); + skip_count++; + continue; + } + + printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1, + time / 1000000, time % 1000000); + + out_func(call->func, 0, " <- "); + out_func(call->caller, 1, "\n"); + } + info("ftrace: %d functions not found, %d excluded\n", missing_count, + skip_count); + + return 0; +} + +static int prof_tool(int argc, char * const argv[], + const char *prof_fname, const char *map_fname, + const char *trace_config_fname) +{ + int err = 0; + + if (read_map_file(map_fname)) + return -1; + if (prof_fname && read_profile_file(prof_fname)) + return -1; + if (trace_config_fname && read_trace_config_file(trace_config_fname)) + return -1; + + check_functions(); + + for (; argc; argc--, argv++) { + const char *cmd = *argv; + + if (0 == strcmp(cmd, "dump-ftrace")) + err = make_ftrace(); + else + warn("Unknown command '%s'\n", cmd); + } + + return err; +} + +int main(int argc, char *argv[]) +{ + const char *map_fname = "System.map"; + const char *prof_fname = NULL; + const char *trace_config_fname = NULL; + int opt; + + verbose = 2; + while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) { + switch (opt) { + case 'm': + map_fname = optarg; + break; + + case 'p': + prof_fname = optarg; + break; + + case 't': + trace_config_fname = optarg; + break; + + case 'v': + verbose = atoi(optarg); + break; + + default: + usage(); + } + } + argc -= optind; argv += optind; + if (argc < 1) + usage(); + + debug("Debug enabled\n"); + return prof_tool(argc, argv, prof_fname, map_fname, + trace_config_fname); +} |