summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.checkpatch.conf3
-rw-r--r--Makefile10
-rw-r--r--README173
-rw-r--r--arch/arm/cpu/armv7/s5p-common/timer.c2
-rw-r--r--arch/arm/dts/exynos5250.dtsi3
-rw-r--r--arch/arm/include/asm/arch-am33xx/omap.h2
-rw-r--r--arch/arm/include/asm/arch-exynos/cpu.h10
-rw-r--r--arch/arm/include/asm/arch-omap4/omap.h1
-rw-r--r--arch/arm/include/asm/arch-omap5/omap.h1
-rw-r--r--arch/arm/include/asm/omap_common.h1
-rw-r--r--arch/arm/lib/bootm.c41
-rw-r--r--arch/avr32/lib/bootm.c9
-rw-r--r--arch/blackfin/lib/boot.c2
-rw-r--r--arch/m68k/cpu/mcf5445x/speed.c10
-rw-r--r--arch/m68k/include/asm/m5235.h2
-rw-r--r--arch/m68k/lib/board.c4
-rw-r--r--arch/m68k/lib/bootm.c6
-rw-r--r--arch/microblaze/lib/bootm.c10
-rw-r--r--arch/mips/include/asm/errno.h144
-rw-r--r--arch/mips/include/asm/io.h26
-rw-r--r--arch/nds32/lib/bootm.c6
-rw-r--r--arch/nios2/lib/bootm.c10
-rw-r--r--arch/openrisc/lib/bootm.c10
-rw-r--r--arch/powerpc/cpu/mpc8260/commproc.c2
-rw-r--r--arch/powerpc/cpu/mpc8260/cpu.c2
-rw-r--r--arch/powerpc/cpu/mpc8260/i2c.c8
-rw-r--r--arch/powerpc/cpu/mpc8260/serial_smc.c4
-rw-r--r--arch/powerpc/cpu/mpc8260/spi.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/Makefile1
-rw-r--r--arch/powerpc/cpu/mpc85xx/cmd_errata.c3
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu.c10
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu_init.c5
-rw-r--r--arch/powerpc/cpu/mpc85xx/cpu_init_early.c10
-rw-r--r--arch/powerpc/cpu/mpc85xx/fdt.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8536_serdes.c4
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8544_serdes.c4
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8548_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8568_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8569_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/mpc8572_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1010_serdes.c4
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1021_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1022_serdes.c4
-rw-r--r--arch/powerpc/cpu/mpc85xx/p1023_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p2020_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p2041_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p3041_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p4080_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p5020_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/p5040_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/start.S2
-rw-r--r--arch/powerpc/cpu/mpc85xx/t1040_serdes.c2
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot-spl.lds18
-rw-r--r--arch/powerpc/cpu/mpc85xx/u-boot.lds8
-rw-r--r--arch/powerpc/cpu/mpc86xx/cpu.c2
-rw-r--r--arch/powerpc/cpu/mpc86xx/mpc8610_serdes.c4
-rw-r--r--arch/powerpc/cpu/mpc86xx/mpc8641_serdes.c4
-rw-r--r--arch/powerpc/cpu/mpc8xx/cpu.c12
-rw-r--r--arch/powerpc/cpu/mpc8xxx/fsl_ifc.c60
-rw-r--r--arch/powerpc/cpu/mpc8xxx/srio.c4
-rw-r--r--arch/powerpc/include/asm/8xx_immap.h7
-rw-r--r--arch/powerpc/include/asm/config_mpc85xx.h13
-rw-r--r--arch/powerpc/include/asm/fsl_ifc.h95
-rw-r--r--arch/powerpc/include/asm/fsl_law.h5
-rw-r--r--arch/powerpc/include/asm/immap_8260.h19
-rw-r--r--arch/powerpc/include/asm/immap_85xx.h4
-rw-r--r--arch/powerpc/lib/bootm.c5
-rw-r--r--arch/sandbox/cpu/cpu.c2
-rw-r--r--arch/sandbox/cpu/os.c2
-rw-r--r--arch/sh/lib/bootm.c6
-rw-r--r--arch/sparc/lib/bootm.c6
-rw-r--r--arch/x86/include/asm/global_data.h2
-rw-r--r--arch/x86/include/asm/msr.h3
-rw-r--r--arch/x86/include/asm/u-boot-x86.h2
-rw-r--r--arch/x86/lib/bootm.c4
-rw-r--r--arch/x86/lib/gcc.c4
-rw-r--r--arch/x86/lib/tsc_timer.c6
-rw-r--r--board/ait/cam_enc_4xx/cam_enc_4xx.c12
-rw-r--r--board/atmel/at91sam9n12ek/at91sam9n12ek.c36
-rw-r--r--board/compulab/cm_t35/cm_t35.c2
-rw-r--r--board/eltec/elppc/misc.c11
-rw-r--r--board/freescale/b4860qds/tlb.c19
-rw-r--r--board/freescale/bsc9131rdb/Makefile16
-rw-r--r--board/freescale/bsc9131rdb/README18
-rw-r--r--board/freescale/bsc9131rdb/law.c4
-rw-r--r--board/freescale/bsc9131rdb/spl_minimal.c118
-rw-r--r--board/freescale/bsc9131rdb/tlb.c17
-rw-r--r--board/freescale/bsc9132qds/Makefile17
-rw-r--r--board/freescale/bsc9132qds/bsc9132qds.c4
-rw-r--r--board/freescale/bsc9132qds/law.c6
-rw-r--r--board/freescale/bsc9132qds/spl_minimal.c130
-rw-r--r--board/freescale/bsc9132qds/tlb.c27
-rw-r--r--board/freescale/common/Makefile10
-rw-r--r--board/freescale/common/pixis.c2
-rw-r--r--board/freescale/p1010rdb/Makefile16
-rw-r--r--board/freescale/p1010rdb/spl_minimal.c (renamed from nand_spl/board/freescale/p1010rdb/nand_boot.c)20
-rw-r--r--board/freescale/p1010rdb/tlb.c13
-rw-r--r--board/freescale/p1023rdb/Makefile33
-rw-r--r--board/freescale/p1023rdb/ddr.c105
-rw-r--r--board/freescale/p1023rdb/law.c (renamed from drivers/tpm/slb9635_i2c/compatibility.h)37
-rw-r--r--board/freescale/p1023rdb/p1023rdb.c161
-rw-r--r--board/freescale/p1023rdb/tlb.c115
-rw-r--r--board/freescale/t4qds/tlb.c19
-rw-r--r--board/ifm/ac14xx/ac14xx.c50
-rw-r--r--board/raspberrypi/rpi_b/rpi_b.c14
-rw-r--r--board/samsung/dts/exynos5250-snow.dts81
-rw-r--r--board/samsung/smdk5250/exynos5-dt.c45
-rw-r--r--board/ti/am335x/board.c9
-rw-r--r--boards.cfg8
-rw-r--r--common/Makefile47
-rw-r--r--common/board_f.c124
-rw-r--r--common/board_r.c23
-rw-r--r--common/bootstage.c26
-rw-r--r--common/cmd_bmp.c45
-rw-r--r--common/cmd_bootm.c831
-rw-r--r--common/cmd_elf.c6
-rw-r--r--common/cmd_fitupd.c3
-rw-r--r--common/cmd_ide.c14
-rw-r--r--common/cmd_immap.c2
-rw-r--r--common/cmd_mem.c2
-rw-r--r--common/cmd_nand.c46
-rw-r--r--common/cmd_onenand.c30
-rw-r--r--common/cmd_pxe.c221
-rw-r--r--common/cmd_sf.c34
-rw-r--r--common/cmd_trace.c133
-rw-r--r--common/env_mmc.c12
-rw-r--r--common/env_onenand.c6
-rw-r--r--common/fdt_support.c3
-rw-r--r--common/image-fdt.c222
-rw-r--r--common/image-fit.c397
-rw-r--r--common/image-sig.c422
-rw-r--r--common/image.c146
-rw-r--r--common/lcd.c122
-rw-r--r--common/main.c296
-rw-r--r--common/spl/spl_mmc.c91
-rw-r--r--common/splash.c56
-rw-r--r--common/usb_hub.c15
-rw-r--r--common/usb_kbd.c10
-rw-r--r--common/usb_storage.c8
-rw-r--r--config.mk16
-rw-r--r--disk/part_efi.c11
-rw-r--r--doc/README.SPL2
-rw-r--r--doc/README.plan918
-rw-r--r--doc/README.splashprepare8
-rw-r--r--doc/README.srio-pcie-boot-corenet34
-rw-r--r--doc/README.trace361
-rw-r--r--doc/device-tree-bindings/input/cros-ec-keyb.txt79
-rw-r--r--doc/device-tree-bindings/misc/cros-ec.txt38
-rw-r--r--doc/device-tree-bindings/video/simple-framebuffer.txt25
-rw-r--r--doc/mkimage.173
-rw-r--r--doc/uImage.FIT/sign-configs.its45
-rw-r--r--doc/uImage.FIT/sign-images.its42
-rw-r--r--doc/uImage.FIT/signature.txt382
-rw-r--r--doc/uImage.FIT/verified-boot.txt104
-rw-r--r--drivers/dfu/dfu.c52
-rw-r--r--drivers/dfu/dfu_mmc.c2
-rw-r--r--drivers/dfu/dfu_nand.c18
-rw-r--r--drivers/hwmon/lm63.c3
-rw-r--r--drivers/input/Makefile1
-rw-r--r--drivers/input/cros_ec_keyb.c261
-rw-r--r--drivers/input/key_matrix.c68
-rw-r--r--drivers/misc/Makefile4
-rw-r--r--drivers/misc/cros_ec.c1304
-rw-r--r--drivers/misc/cros_ec_i2c.c199
-rw-r--r--drivers/misc/cros_ec_lpc.c283
-rw-r--r--drivers/misc/cros_ec_spi.c161
-rw-r--r--drivers/mmc/fsl_esdhc.c9
-rw-r--r--drivers/mmc/mmc.c93
-rw-r--r--drivers/mmc/sdhci.c6
-rw-r--r--drivers/mtd/Makefile4
-rw-r--r--drivers/mtd/cfi_flash.c7
-rw-r--r--drivers/mtd/cfi_mtd.c12
-rw-r--r--drivers/mtd/mtdconcat.c98
-rw-r--r--drivers/mtd/mtdcore.c191
-rw-r--r--drivers/mtd/mtdpart.c158
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/atmel_nand.c17
-rw-r--r--drivers/mtd/nand/bfin_nand.c2
-rw-r--r--drivers/mtd/nand/davinci_nand.c4
-rw-r--r--drivers/mtd/nand/diskonchip.c13
-rw-r--r--drivers/mtd/nand/docg4.c26
-rw-r--r--drivers/mtd/nand/docg4_spl.c15
-rw-r--r--drivers/mtd/nand/fsl_elbc_nand.c56
-rw-r--r--drivers/mtd/nand/fsl_ifc_nand.c62
-rw-r--r--drivers/mtd/nand/fsl_ifc_spl.c (renamed from nand_spl/nand_boot_fsl_ifc.c)37
-rw-r--r--drivers/mtd/nand/fsmc_nand.c5
-rw-r--r--drivers/mtd/nand/jz4740_nand.c3
-rw-r--r--drivers/mtd/nand/mpc5121_nfc.c2
-rw-r--r--drivers/mtd/nand/mxc_nand.c25
-rw-r--r--drivers/mtd/nand/mxs_nand.c34
-rw-r--r--drivers/mtd/nand/nand_base.c1658
-rw-r--r--drivers/mtd/nand/nand_bbt.c822
-rw-r--r--drivers/mtd/nand/nand_ids.c14
-rw-r--r--drivers/mtd/nand/nand_util.c30
-rw-r--r--drivers/mtd/nand/ndfc.c1
-rw-r--r--drivers/mtd/nand/nomadik.c1
-rw-r--r--drivers/mtd/nand/omap_gpmc.c8
-rw-r--r--drivers/mtd/nand/s3c2410_nand.c5
-rw-r--r--drivers/mtd/nand/tegra_nand.c27
-rw-r--r--drivers/mtd/nand/tegra_nand.h2
-rw-r--r--drivers/mtd/onenand/onenand_base.c82
-rw-r--r--drivers/mtd/onenand/onenand_bbt.c6
-rw-r--r--drivers/mtd/spi/spansion.c18
-rw-r--r--drivers/mtd/spi/spi_flash.c386
-rw-r--r--drivers/mtd/spi/spi_flash_internal.h39
-rw-r--r--drivers/mtd/spi/stmicro.c28
-rw-r--r--drivers/mtd/spi/winbond.c52
-rw-r--r--drivers/mtd/ubi/build.c2
-rw-r--r--drivers/mtd/ubi/eba.c2
-rw-r--r--drivers/mtd/ubi/io.c12
-rw-r--r--drivers/mtd/ubi/kapi.c2
-rw-r--r--drivers/mtd/ubi/misc.c2
-rw-r--r--drivers/mtd/ubi/vtbl.c2
-rw-r--r--drivers/net/Makefile3
-rw-r--r--drivers/net/designware.c4
-rw-r--r--drivers/net/ftgmac100.c70
-rw-r--r--drivers/net/ftmac110.c473
-rw-r--r--drivers/net/ftmac110.h177
-rw-r--r--drivers/net/ks8851_mll.c645
-rw-r--r--drivers/net/ks8851_mll.h357
-rw-r--r--drivers/net/macb.c185
-rw-r--r--drivers/net/macb.h55
-rw-r--r--drivers/net/mvgbe.c71
-rw-r--r--drivers/net/mvgbe.h7
-rw-r--r--drivers/net/phy/Makefile1
-rw-r--r--drivers/net/phy/atheros.c45
-rw-r--r--drivers/net/phy/icplus.c94
-rw-r--r--drivers/net/phy/marvell.c48
-rw-r--r--drivers/net/phy/micrel.c113
-rw-r--r--drivers/net/phy/natsemi.c37
-rw-r--r--drivers/net/phy/phy.c26
-rw-r--r--drivers/net/sunxi_wemac.c533
-rw-r--r--drivers/pci/Makefile3
-rw-r--r--drivers/pci/fsl_pci_init.c6
-rw-r--r--drivers/serial/serial.c5
-rw-r--r--drivers/spi/armada100_spi.c11
-rw-r--r--drivers/spi/cf_qspi.c2
-rw-r--r--drivers/spi/exynos_spi.c91
-rw-r--r--drivers/spi/mxc_spi.c6
-rw-r--r--drivers/spi/tegra114_spi.c4
-rw-r--r--drivers/spi/tegra20_sflash.c2
-rw-r--r--drivers/tpm/Makefile7
-rw-r--r--drivers/tpm/tis_i2c.c4
-rw-r--r--drivers/tpm/tpm.c (renamed from drivers/tpm/slb9635_i2c/tpm.c)280
-rw-r--r--drivers/tpm/tpm_private.h (renamed from drivers/tpm/slb9635_i2c/tpm.h)46
-rw-r--r--drivers/tpm/tpm_tis_i2c.c (renamed from drivers/tpm/slb9635_i2c/tpm_tis_i2c.c)354
-rw-r--r--drivers/tpm/tpm_tis_lpc.c (renamed from drivers/tpm/generic_lpc_tpm.c)0
-rw-r--r--drivers/usb/eth/asix.c41
-rw-r--r--drivers/usb/gadget/Makefile1
-rw-r--r--drivers/usb/gadget/composite.c4
-rw-r--r--drivers/usb/gadget/f_dfu.c13
-rw-r--r--drivers/usb/gadget/f_mass_storage.c11
-rw-r--r--drivers/usb/gadget/fotg210.c948
-rw-r--r--drivers/usb/gadget/g_dnl.c7
-rw-r--r--drivers/usb/gadget/gadget_chips.h8
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c13
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c14
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-faraday.c148
-rw-r--r--drivers/usb/host/ehci-hcd.c74
-rw-r--r--drivers/usb/musb-new/musb_uboot.c2
-rw-r--r--drivers/usb/musb/musb_hcd.c3
-rw-r--r--drivers/usb/musb/musb_udc.c3
-rw-r--r--drivers/video/cfb_console.c44
-rw-r--r--drivers/video/s6e8ax0.c26
-rw-r--r--examples/standalone/mem_to_mem_idma2intr.c3
-rw-r--r--fs/yaffs2/yaffs_mtdif.c18
-rw-r--r--fs/yaffs2/yaffs_mtdif2.c14
-rw-r--r--include/asm-generic/global_data.h6
-rw-r--r--include/bootstage.h51
-rw-r--r--include/command.h2
-rw-r--r--include/common.h7
-rw-r--r--include/commproc.h1
-rw-r--r--include/configs/A3000.h1
-rw-r--r--include/configs/APC405.h1
-rw-r--r--include/configs/AR405.h1
-rw-r--r--include/configs/ASH405.h1
-rw-r--r--include/configs/B4860QDS.h36
-rw-r--r--include/configs/BSC9131RDB.h62
-rw-r--r--include/configs/BSC9132QDS.h64
-rw-r--r--include/configs/CATcenter.h1
-rw-r--r--include/configs/CPC45.h1
-rw-r--r--include/configs/CPCI2DP.h1
-rw-r--r--include/configs/CPCI405.h1
-rw-r--r--include/configs/CPCI4052.h1
-rw-r--r--include/configs/CPCI405AB.h1
-rw-r--r--include/configs/CPCI405DT.h1
-rw-r--r--include/configs/CPCIISER4.h1
-rw-r--r--include/configs/CPU87.h1
-rw-r--r--include/configs/CU824.h1
-rw-r--r--include/configs/DU440.h1
-rw-r--r--include/configs/ELPPC.h1
-rw-r--r--include/configs/G2000.h1
-rw-r--r--include/configs/HH405.h1
-rw-r--r--include/configs/HIDDEN_DRAGON.h1
-rw-r--r--include/configs/HWW1U1A.h1
-rw-r--r--include/configs/JSE.h1
-rw-r--r--include/configs/KAREF.h1
-rw-r--r--include/configs/MERGERBOX.h1
-rw-r--r--include/configs/METROBOX.h1
-rw-r--r--include/configs/MIP405.h1
-rw-r--r--include/configs/MOUSSE.h1
-rw-r--r--include/configs/MPC8260ADS.h1
-rw-r--r--include/configs/MPC8266ADS.h1
-rw-r--r--include/configs/MPC8308RDB.h1
-rw-r--r--include/configs/MPC8313ERDB.h1
-rw-r--r--include/configs/MPC8315ERDB.h1
-rw-r--r--include/configs/MPC8323ERDB.h1
-rw-r--r--include/configs/MPC832XEMDS.h1
-rw-r--r--include/configs/MPC8349EMDS.h1
-rw-r--r--include/configs/MPC8349ITX.h1
-rw-r--r--include/configs/MPC8360EMDS.h1
-rw-r--r--include/configs/MPC8360ERDK.h1
-rw-r--r--include/configs/MPC837XEMDS.h1
-rw-r--r--include/configs/MPC837XERDB.h1
-rw-r--r--include/configs/MPC8536DS.h1
-rw-r--r--include/configs/MPC8540ADS.h1
-rw-r--r--include/configs/MPC8541CDS.h1
-rw-r--r--include/configs/MPC8544DS.h1
-rw-r--r--include/configs/MPC8548CDS.h1
-rw-r--r--include/configs/MPC8555CDS.h1
-rw-r--r--include/configs/MPC8560ADS.h1
-rw-r--r--include/configs/MPC8568MDS.h1
-rw-r--r--include/configs/MPC8569MDS.h1
-rw-r--r--include/configs/MPC8572DS.h1
-rw-r--r--include/configs/MPC8610HPCD.h1
-rw-r--r--include/configs/MPC8641HPCN.h1
-rw-r--r--include/configs/MUSENKI.h1
-rw-r--r--include/configs/MVBLM7.h1
-rw-r--r--include/configs/MVBLUE.h1
-rw-r--r--include/configs/OCRTC.h1
-rw-r--r--include/configs/ORSG.h1
-rw-r--r--include/configs/P1010RDB.h78
-rw-r--r--include/configs/P1022DS.h3
-rw-r--r--include/configs/P1023RDB.h401
-rw-r--r--include/configs/P1023RDS.h1
-rw-r--r--include/configs/P1_P2_RDB.h1
-rw-r--r--include/configs/P2020COME.h1
-rw-r--r--include/configs/P2020DS.h1
-rw-r--r--include/configs/P2041RDB.h2
-rw-r--r--include/configs/P3041DS.h2
-rw-r--r--include/configs/P4080DS.h2
-rw-r--r--include/configs/P5020DS.h2
-rw-r--r--include/configs/PCI405.h1
-rw-r--r--include/configs/PIP405.h1
-rw-r--r--include/configs/PLU405.h1
-rw-r--r--include/configs/PM826.h1
-rw-r--r--include/configs/PM828.h1
-rw-r--r--include/configs/PMC405.h1
-rw-r--r--include/configs/PMC405DE.h1
-rw-r--r--include/configs/PMC440.h1
-rw-r--r--include/configs/PN62.h1
-rw-r--r--include/configs/PPChameleonEVB.h1
-rw-r--r--include/configs/SIMPC8313.h1
-rw-r--r--include/configs/Sandpoint8240.h1
-rw-r--r--include/configs/Sandpoint8245.h1
-rw-r--r--include/configs/TQM8272.h1
-rw-r--r--include/configs/TQM834x.h1
-rw-r--r--include/configs/VOH405.h1
-rw-r--r--include/configs/W7OLMC.h1
-rw-r--r--include/configs/W7OLMG.h1
-rw-r--r--include/configs/WUH405.h1
-rw-r--r--include/configs/a3m071.h1
-rw-r--r--include/configs/ac14xx.h28
-rw-r--r--include/configs/adp-ag102.h1
-rw-r--r--include/configs/alpr.h1
-rw-r--r--include/configs/am335x_evm.h38
-rw-r--r--include/configs/aria.h1
-rw-r--r--include/configs/at91sam9n12ek.h4
-rw-r--r--include/configs/atc.h1
-rw-r--r--include/configs/bamboo.h1
-rw-r--r--include/configs/beaver.h2
-rw-r--r--include/configs/bubinga.h1
-rw-r--r--include/configs/canyonlands.h1
-rw-r--r--include/configs/cardhu.h2
-rw-r--r--include/configs/cm_t35.h1
-rw-r--r--include/configs/coreboot.h10
-rw-r--r--include/configs/corenet_ds.h1
-rw-r--r--include/configs/csb272.h1
-rw-r--r--include/configs/csb472.h1
-rw-r--r--include/configs/dalmore.h2
-rw-r--r--include/configs/debris.h1
-rw-r--r--include/configs/devkit8000.h8
-rw-r--r--include/configs/eXalion.h1
-rw-r--r--include/configs/ebony.h1
-rw-r--r--include/configs/ep82xxm.h1
-rw-r--r--include/configs/exynos5250-dt.h24
-rw-r--r--include/configs/gdppc440etx.h1
-rw-r--r--include/configs/icon.h1
-rw-r--r--include/configs/igep0033.h5
-rw-r--r--include/configs/intip.h1
-rw-r--r--include/configs/katmai.h1
-rw-r--r--include/configs/kilauea.h1
-rw-r--r--include/configs/korat.h1
-rw-r--r--include/configs/kvme080.h1
-rw-r--r--include/configs/linkstation.h1
-rw-r--r--include/configs/luan.h1
-rw-r--r--include/configs/makalu.h1
-rw-r--r--include/configs/mpc5121ads.h1
-rw-r--r--include/configs/mpc8308_p1m.h1
-rw-r--r--include/configs/ocotea.h1
-rw-r--r--include/configs/p1_p2_rdb_pc.h1
-rw-r--r--include/configs/p3p440.h1
-rw-r--r--include/configs/paz00.h2
-rw-r--r--include/configs/pcm051.h6
-rw-r--r--include/configs/pcs440ep.h1
-rw-r--r--include/configs/pm9263.h2
-rw-r--r--include/configs/ppmc7xx.h3
-rw-r--r--include/configs/rpi_b.h2
-rw-r--r--include/configs/sandbox.h15
-rw-r--r--include/configs/sbc405.h1
-rw-r--r--include/configs/sbc8349.h1
-rw-r--r--include/configs/sbc8548.h1
-rw-r--r--include/configs/sbc8641d.h1
-rw-r--r--include/configs/sc3.h1
-rw-r--r--include/configs/seaboard.h2
-rw-r--r--include/configs/sequoia.h1
-rw-r--r--include/configs/socrates.h1
-rw-r--r--include/configs/stxssa.h1
-rw-r--r--include/configs/t3corp.h1
-rw-r--r--include/configs/t4qds.h36
-rw-r--r--include/configs/taihu.h1
-rw-r--r--include/configs/taishan.h1
-rw-r--r--include/configs/utx8245.h1
-rw-r--r--include/configs/ve8313.h1
-rw-r--r--include/configs/ventana.h2
-rw-r--r--include/configs/vme8349.h1
-rw-r--r--include/configs/walnut.h1
-rw-r--r--include/configs/whistler.h4
-rw-r--r--include/configs/xpedite1000.h1
-rw-r--r--include/configs/xpedite517x.h1
-rw-r--r--include/configs/xpedite520x.h1
-rw-r--r--include/configs/xpedite537x.h1
-rw-r--r--include/configs/xpedite550x.h1
-rw-r--r--include/configs/yosemite.h1
-rw-r--r--include/configs/yucca.h1
-rw-r--r--include/cros_ec.h449
-rw-r--r--include/cros_ec_message.h44
-rw-r--r--include/dfu.h4
-rw-r--r--include/ec_commands.h1440
-rw-r--r--include/environment.h6
-rw-r--r--include/fdtdec.h3
-rw-r--r--include/g_dnl.h2
-rw-r--r--include/ide.h5
-rw-r--r--include/image.h294
-rw-r--r--include/lcd.h7
-rw-r--r--include/libfdt.h64
-rw-r--r--include/linux/ethtool.h4
-rw-r--r--include/linux/mii.h2
-rw-r--r--include/linux/mtd/bbm.h49
-rw-r--r--include/linux/mtd/mtd.h203
-rw-r--r--include/linux/mtd/nand.h173
-rw-r--r--include/linux/string.h3
-rw-r--r--include/linux/usb/ch9.h3
-rw-r--r--include/linux/usb/composite.h2
-rw-r--r--include/micrel.h11
-rw-r--r--include/mmc.h7
-rw-r--r--include/mtd/mtd-abi.h (renamed from include/linux/mtd/mtd-abi.h)53
-rw-r--r--include/nand.h13
-rw-r--r--include/net.h5
-rw-r--r--include/netdev.h3
-rw-r--r--include/part.h6
-rw-r--r--include/pci.h6
-rw-r--r--include/phy.h1
-rw-r--r--include/rsa.h108
-rw-r--r--include/spi.h21
-rw-r--r--include/spi_flash.h10
-rw-r--r--include/splash.h36
-rw-r--r--include/trace.h125
-rw-r--r--include/usb/fotg210.h364
-rw-r--r--include/usb/fusbh200.h61
-rw-r--r--include/vsprintf.h11
-rw-r--r--lib/Makefile15
-rw-r--r--lib/fdtdec.c3
-rw-r--r--lib/libfdt/fdt_wip.c129
-rw-r--r--lib/rsa/Makefile48
-rw-r--r--lib/rsa/rsa-sign.c459
-rw-r--r--lib/rsa/rsa-verify.c385
-rw-r--r--lib/string.c59
-rw-r--r--lib/trace.c379
-rw-r--r--lib/vsprintf.c16
-rw-r--r--nand_spl/board/freescale/p1010rdb/Makefile142
-rw-r--r--net/link_local.c17
-rw-r--r--net/net.c3
-rw-r--r--net/nfs.c74
-rw-r--r--net/tftp.c12
-rwxr-xr-xtest/image/test-fit.py423
-rwxr-xr-xtest/trace/test-trace.sh89
-rw-r--r--test/vboot/.gitignore3
-rw-r--r--test/vboot/sandbox-kernel.dts7
-rw-r--r--test/vboot/sandbox-u-boot.dts7
-rw-r--r--test/vboot/sign-configs.its45
-rw-r--r--test/vboot/sign-images.its42
-rwxr-xr-xtest/vboot/vboot_test.sh126
-rw-r--r--tools/.gitignore1
-rw-r--r--tools/Makefile25
-rwxr-xr-xtools/checkpatch.pl1
-rw-r--r--tools/fit_image.c44
-rw-r--r--tools/image-host.c527
-rw-r--r--tools/mkimage.c36
-rw-r--r--tools/mkimage.h16
-rw-r--r--tools/pblimage.c32
-rw-r--r--tools/proftool.c611
503 files changed, 22111 insertions, 4592 deletions
diff --git a/.checkpatch.conf b/.checkpatch.conf
index d88af57129..35167e1201 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
diff --git a/Makefile b/Makefile
index b1e5d5f52e..446c2f8e63 100644
--- a/Makefile
+++ b/Makefile
@@ -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 \
diff --git a/README b/README
index b1b3e1788e..33b5728abc 100644
--- a/README
+++ b/README
@@ -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 4adfaae656..637593c339 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 f98243c7a5..4fff5e3694 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 db15159643..e7576c1106 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 8685c429fe..1ff231bcff 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 66afd92492..9fd00ff2aa 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 817c1ff27f..5e6d82e51f 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 787e614ecb..0dbe81b59c 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 1b6e0ace45..0325d08ca9 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 87f3f9c35d..eedab9d119 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 768a8826b5..5644d589e7 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 aa73e1f025..0276d4d826 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 71a40d33d2..a573f1cf01 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 b2e3068364..efc9fccc1b 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 56b6512be0..cc45167fcd 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 3842709001..c5dfc9ebe8 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 1665a63a81..4c82b503d9 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 3864c804c0..50a882ca5a 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 03f58bf321..65ae1eb715 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 f32be52108..51597ea6fd 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 2c5d9aea99..24ca0a7249 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 22cef3e983..484bd17745 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 f8bc5a9834..22e1a23a2a 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 b720b1fb88..e2341e9c39 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 feba1f63d2..9410e4c3b2 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 dc98ea73f2..01b492e8e4 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 2318064a47..4669883a3c 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 422782ca8f..a7ed87769e 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 6ce483e17a..fbee753903 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 4067f05375..3c8f59cdb3 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 234fde4846..837c034be9 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 288f7b2860..bb95f3d500 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 6dadeb8cab..ec96e81ed5 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 7c490972a5..3483366e6d 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 76288cd568..c9eea15d3c 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 258263739f..49a0290620 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 f480c2609d..7af6aff259 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 2ff5d9a060..fcccb52b68 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 e8a0387ca0..1f7dba0d6f 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 1849c1642c..d6d2696e07 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 e4c9c22100..ed4992053c 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 c8ab5d6f33..0b4ae90c24 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 389ff6bd28..01af333706 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 eec4ffe516..87335c9444 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 fba9ff245f..a36dcd5426 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 87bd795293..94ec445037 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 fba9ff245f..a36dcd5426 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 890b88e4e3..d646e8561c 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 4f0480b768..2657982a45 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 8261e03476..19add9f96c 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 f2b7bffdab..20284ed5a5 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 0503dce5ae..2643563d4d 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 c553415b55..5ed3eb24f2 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 0dc1975bf9..0342e34654 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 3ae9069f1b..21c5ddbfac 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 b6b733d77f..dc33eb3d10 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 56b319f5d4..4e8a4415f5 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 6e6f7dcc3f..90d1065deb 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 40679cb2b0..01129ed4f0 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 1009a31b33..1d46b14230 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 ba41b73cc0..3baf4ccbae 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 90b264d35e..bea1636768 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 4974ae56fc..c7021a7095 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 4052037f56..db70d048f5 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 dd6c98cdb4..d4ad323fe9 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 dd8d495e3f..e9385de2a6 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 d07540776c..541e450bf6 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 57273fa443..4fdc7aab74 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 1a9343c108..9e5fb40df8 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 4fdb08090a..9a2056a70f 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 6030633d10..b459a63ee6 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 22e093427f..709dc8400d 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 2520228b4c..b84e35a9b8 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 4043431eca..497ad75b7a 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 c509801f9e..06889737d1 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 644c445693..80a78221b1 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 8752794c84..3013a42a2e 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 b0b80e5bc9..95098af02f 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 89f1b1d355..4c3656e24d 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 29cc41bfaf..1416f98dc6 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 6f4cb268f1..2e829ad2e2 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 065faa378d..4902b98ba1 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 201c147079..0432780f94 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 0000000000..301115e5e6
--- /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 5b68f4af3c..c05a556a3d 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 267400becb..72b19174bf 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 6e1b55816f..ddc9d0a16a 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 dc2365851b..b4bce99d3d 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 0000000000..62dee52b17
--- /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 0e4545fb12..0ec9a851ab 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 72bb56cac4..37236d072b 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 8d07061c36..fbb709de14 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 4c705b627e..e6563be098 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 3c7bc2bc65..c909e0ee31 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 4256bf4e57..078717a5b9 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 0000000000..45c4f8b7c1
--- /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 0000000000..7ed275ade2
--- /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 62dc9fa964..331662cfc6 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 0000000000..918398bd85
--- /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 0000000000..3417c0f019
--- /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 92c01cf95c..a138d5a9e6 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 74425912d6..dc2aff0993 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 6b3e095ba8..16d442aa62 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 fdc047a142..dca3386cf2 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 813150586f..aacf43eaa4 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 fb98df0f84..fdbe26cde1 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
/*
diff --git a/boards.cfg b/boards.cfg
index 1458289abf..dd2cd98424 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -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 3ba4316263..53c92ef62e 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 81edbdf8e4..ab4242a77e 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 fd1fd319b6..f7a036e32f 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 c5c69961ac..94a32a9971 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 5a52edde31..a7c5fbd269 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 15f4599d45..2694c664a4 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 ab9c7e332d..f741f6b83f 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 7a3789e3ed..618ff7c8d6 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 78b4aa70ba..59e95dfa12 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 fdf9489b2e..bb15795e22 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 6df00b15d3..77eafa0b89 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 e9d3d3c1bf..886212aa07 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 a0d25e5521..06cc140567 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 2dbd49cbd6..1fb75d8ae9 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 0a17782d66..19b0dc9f43 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 0000000000..ec3137a8a2
--- /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 9ca098fa67..5d3a769db0 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 faa903d2f0..e8bde37266 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 416100e394..9a6f6b7d8b 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 158c9cfbf5..203404afb4 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 254feecaad..e28dd05474 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, &timestamp))
+ 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 0000000000..5d907cfc42
--- /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, &region, 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 e91c89e1c5..327006e5aa 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 edae835fb0..50ea4d6cac 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 953ef296b1..56da214b26 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 7efdcb88b7..170fa3871a 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 0000000000..18885f1bfe
--- /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 0d79ec3ea8..774ba6387a 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 b962849920..3174b5e1bf 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 457970f770..4599d03c3a 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;
diff --git a/config.mk b/config.mk
index ddf350e8e9..81c2584216 100644
--- a/config.mk
+++ b/config.mk
@@ -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 5986589708..fb5e9f0477 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 4e1cb28800..ac9a2137c8 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 0000000000..2d3d0e0cf6
--- /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 0000000000..61b4ec53ec
--- /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 cd7e7ee9b3..2b1f76b8d0 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 0000000000..b535c06566
--- /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 0000000000..3118276078
--- /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 0000000000..07ea7cdeac
--- /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 0000000000..3ea4605831
--- /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 39652c82d0..14374da88a 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 0000000000..3c17f040de
--- /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 0000000000..f69326a39b
--- /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 0000000000..bc9f3fa6e1
--- /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 0000000000..3c83fbc2c1
--- /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 6af6890d09..05217526be 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 e2f3978400..e7ee0770c2 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 7dc89b2f2b..07dee89815 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 f3adf64859..bb8e644cd9 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 0805e86678..4331190def 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 0000000000..c197308221
--- /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 946a186a1f..c900e45d15 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 5d869b47ad..5fbff8ab6b 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 0000000000..6e774d921b
--- /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,
+ &params, 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,
+ &params, 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,
+ &params, 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,
+ &params, 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, &region_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 0000000000..b0060ac197
--- /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 0000000000..cf0435b8dd
--- /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 0000000000..e15c83341c
--- /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 861f4b9d6c..973b19f337 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(&regs->irqsigen, 0);
+
/* Send the command */
esdhc_write32(&regs->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(&regs->xfertyp, xfertyp);
#endif
- /* Mask all irqs */
- esdhc_write32(&regs->irqsigen, 0);
-
/* Wait for the command to complete */
while (!(esdhc_read32(&regs->irqstat) & (IRQSTAT_CC | IRQSTAT_CTOE)))
;
irqstat = esdhc_read32(&regs->irqstat);
- esdhc_write32(&regs->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 a492bbb41f..73f7195792 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 1eaea04ad1..c5631bff67 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 543c845ff0..99f39fc752 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 25f875202c..25a5710758 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 8d74fa9412..bbb71a19e7 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 e6d938417d..31e4289b16 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 3a81adaf60..49c08145a7 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 cbfc6796c7..9dfe7bbc9a 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 8821704911..bb81e84113 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 994dd9f095..3bfbaf8ac9 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 c7ddbb21d8..7e755e8965 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 e8506ddd9b..90f59857fd 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 edf3a099ba..4cd741ebbb 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 7dd9953bed..09f01c80d3 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 95e856c213..734cbeb7ca 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 834a8a6498..0fa776ae91 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 b13d8a9303..439822c5a2 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 44972c5c09..8537c4c6f5 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 7a61d88cc5..fab2aebc31 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 3ec34f3c9b..9421e5661b 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 e6b7a70661..e53f341dcf 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 eeba521942..ac435f2050 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 398e4ddc15..866cabd276 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 a2d06be99f..9e05cef417 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 74a7061b05..8ef58451d5 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 39535497f8..f856778b5e 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 4727f9c989..1d22b5240d 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 213d2c945a..94b90332d6 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 b76f4cbb5e..dc8e513739 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 bc1bcad3ba..5d088227ea 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 e1a459b009..1187b9fee4 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 4d94cc6f56..6afbec61ee 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 7e74be75f8..622b869808 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 858e322743..ddfe7e7c75 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 9d5da54708..0267c2c5c9 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 dad30b54c5..3ec2151b3a 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 6507aa34bb..6a6fe37e0e 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 e0afbc3d87..af1afa96c9 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 2a9972bd4e..7e41ee1321 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 27162091c5..c399bf14d1 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 a708162e43..25888220df 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 d523c94b12..d2d3c9c580 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 8423894000..05de9aeb6e 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 423d479152..e553188797 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 a6410bfb6b..e8660d9970 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 f679f06494..29d2320010 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 786a6567a5..9cf2983d18 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 bf21a08bdf..46f6601fa3 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 69ba57d3d0..2dbb328b88 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 0000000000..579dcc72fa
--- /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, &regs->phycr);
+
+ for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
+ tmp = readl(&regs->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, &regs->phydr);
+ writel(tmp, &regs->phycr);
+
+ for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
+ if (readl(&regs->phycr) & PHYCR_WRITE)
+ continue;
+ break;
+ }
+
+ if (readl(&regs->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, &regs->maccr);
+ for (i = get_timer(0); get_timer(i) < 1000; ) {
+ if (readl(&regs->maccr) & MACCR_RESET)
+ continue;
+ break;
+ }
+ if (readl(&regs->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), &regs->mac[0]);
+ writel(a[5] | (a[4] << 8) | (a[3] << 16)
+ | (a[2] << 24), &regs->mac[1]);
+
+ /* 5. MAC registers setup */
+ writel(chip->rxd_dma, &regs->rxba);
+ writel(chip->txd_dma, &regs->txba);
+ /* interrupt at each tx/rx */
+ writel(ITC_DEFAULT, &regs->itc);
+ /* no tx pool, rx poll = 1 normal cycle */
+ writel(APTC_DEFAULT, &regs->aptc);
+ /* rx threshold = [6/8 fifo, 2/8 fifo] */
+ writel(DBLAC_DEFAULT, &regs->dblac);
+ /* disable & clear all interrupt status */
+ chip->imr = 0;
+ writel(ISR_ALL, &regs->isr);
+ writel(chip->imr, &regs->imr);
+ /* enable mac */
+ writel(chip->maccr, &regs->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, &regs->imr);
+ writel(0, &regs->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, &regs->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, &regs->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 0000000000..5b2d23b0d2
--- /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 0000000000..b02d59a1b3
--- /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 0000000000..7f90ae4e59
--- /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 8bacbda719..b7802a2fed 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 f92a20c701..68eef00c03 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 47bf27c8ba..319fe8aba9 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 d8a5429de4..7f5d98ff5e 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 af5f4b848c..695873eaa4 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 9b3808bfa9..09d487971f 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 0000000000..dd5c59259d
--- /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 46801c7919..8397e32e1a 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 30f3264897..aa9cbcfffc 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 ea60ac1b0e..6dc7ed5059 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 f8c5481477..7c0eaec513 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 0000000000..1db3529c27
--- /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, &regs->mac_madr);
+
+ /* pull up the phy io line */
+ writel(0x1, &regs->mac_mcmd);
+
+ /* Wait read complete */
+ mdelay(1);
+
+ /* push down the phy io line */
+ writel(0x0, &regs->mac_mcmd);
+
+ /* and write data */
+ *value = readl(&regs->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, &regs->mac_madr);
+
+ /* pull up the phy io line */
+ writel(0x1, &regs->mac_mcmd);
+
+ /* Wait write complete */
+ mdelay(1);
+
+ /* push down the phy io line */
+ writel(0x0, &regs->mac_mcmd);
+
+ /* and write data */
+ writel(value, &regs->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, &regs->tx_mode);
+
+ /* Set up RX */
+ writel(EMAC_RX_SETUP, &regs->rx_ctl);
+
+ /* Set MAC */
+ /* Set MAC CTL0 */
+ writel(EMAC_MAC_CTL0_SETUP, &regs->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, &regs->mac_ctl1);
+
+ /* Set up IPGT */
+ writel(EMAC_MAC_IPGT, &regs->mac_ipgt);
+
+ /* Set up IPGR */
+ writel(EMAC_MAC_NBTB_IPG2 | (EMAC_MAC_NBTB_IPG1 << 8), &regs->mac_ipgr);
+
+ /* Set up Collison window */
+ writel(EMAC_MAC_RM | (EMAC_MAC_CW << 8), &regs->mac_clrt);
+
+ /* Set up Max Frame Length */
+ writel(EMAC_MAC_MFL, &regs->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, &regs->ctl);
+ udelay(200);
+
+ writel(1, &regs->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(&regs->rx_ctl, 0x8);
+ udelay(1);
+
+ /* Init MAC */
+
+ /* Soft reset MAC */
+ clrbits_le32(&regs->mac_ctl0, 1 << 15);
+
+ /* Set MII clock */
+ clrsetbits_le32(&regs->mac_mcfg, 0xf << 2, 0xd << 2);
+
+ /* Clear RX counter */
+ writel(0x0, &regs->rx_fbc);
+ udelay(1);
+
+ /* Set up EMAC */
+ emac_setup(dev);
+
+ writel(dev->enetaddr[0] << 16 | dev->enetaddr[1] << 8 |
+ dev->enetaddr[2], &regs->mac_a1);
+ writel(dev->enetaddr[3] << 16 | dev->enetaddr[4] << 8 |
+ dev->enetaddr[5], &regs->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(&regs->mac_supp, 1 << 8,
+ ((phy_reg & (1 << 13)) >> 13) << 8);
+
+ /* Set duplex depend on phy */
+ clrsetbits_le32(&regs->mac_ctl1, 1 << 0,
+ ((phy_reg & (1 << 8)) >> 8) << 0);
+
+ /* Enable RX/TX */
+ setbits_le32(&regs->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(&regs->rx_fbc);
+ if (!rxcount) {
+ /* Had one stuck? */
+ rxcount = readl(&regs->rx_fbc);
+ if (!rxcount)
+ return 0;
+ }
+
+ reg_val = readl(&regs->rx_io_data);
+ if (reg_val != 0x0143414d) {
+ /* Disable RX */
+ clrbits_le32(&regs->ctl, 1 << 2);
+
+ /* Flush RX FIFO */
+ setbits_le32(&regs->rx_ctl, 1 << 3);
+ while (readl(&regs->rx_ctl) & (1 << 3))
+ ;
+
+ /* Enable RX */
+ setbits_le32(&regs->ctl, 1 << 2);
+
+ return 0;
+ }
+
+ /*
+ * A packet ready now
+ * Get status/length
+ */
+ good_packet = 1;
+
+ wemac_inblk_32bit(&regs->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 *)&regs->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, &regs->tx_ins);
+
+ /* Write packet */
+ wemac_outblk_32bit((void *)&regs->tx_io_data, packet, len);
+
+ /* Set TX len */
+ writel(len, &regs->tx_pl0);
+
+ /* Start translate from fifo to phy */
+ setbits_le32(&regs->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 1ae35d360b..14999447b1 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 77ac1f7c7b..621c899120 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 daa80038a7..a19cec5ace 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 afdbe0508c..b237c7c0fe 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 a37ac4e526..06bcf91a4a 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 607e1cdec2..7a25a35aa0 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, &regs->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, &regs->tx_data);
out_bytes--;
}
- if (rx_lvl > 0 && in_bytes) {
+ if (rx_lvl > 0) {
temp = readl(&regs->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 0eca7767e0..9c68d7d29f 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(&regs->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 b11a0a1ff7..4d2af483d7 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 9322ce7f64..7c3a3fc35b 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 e8c159c0f3..913dd9c862 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 e818fbaf54..22554e1456 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 496c48e8cf..b657334195 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 9ddee865df..888a074d35 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 82a41bf5b2..2dd8501f92 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 04ad418973..04ad418973 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 75ec8f7881..db39bd86f5 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 e545b6be6b..432cf178cf 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 2c5600ed52..f8677931b4 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 a322ae5eb8..d7ae0c0c6a 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 c28866f7d3..5b348d7a6e 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 0000000000..d003331bae
--- /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(&regs->iep[ep - 1], IEP_RESET);
+ mdelay(1);
+ clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+ /* clear endpoint stall */
+ clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+ } else {
+ /* reset endpoint */
+ setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+ mdelay(1);
+ clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+ /* clear endpoint stall */
+ clrbits_le32(&regs->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, &regs->dev_ctrl);
+
+ /* device address reset */
+ chip->addr = 0;
+ writel(0, &regs->dev_addr);
+
+ /* set idle counter to 7ms */
+ writel(7, &regs->idle);
+
+ /* disable all interrupts */
+ writel(IMR_MASK, &regs->imr);
+ writel(GIMR_MASK, &regs->gimr);
+ writel(GIMR0_MASK, &regs->gimr0);
+ writel(GIMR1_MASK, &regs->gimr1);
+ writel(GIMR2_MASK, &regs->gimr2);
+
+ /* clear interrupts */
+ writel(ISR_MASK, &regs->isr);
+ writel(0, &regs->gisr);
+ writel(0, &regs->gisr0);
+ writel(0, &regs->gisr1);
+ writel(0, &regs->gisr2);
+
+ /* chip reset */
+ setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+ mdelay(10);
+ if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+ printf("fotg210: chip reset failed\n");
+ return -1;
+ }
+
+ /* CX FIFO reset */
+ setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+ mdelay(10);
+ if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+ printf("fotg210: ep0 fifo reset failed\n");
+ return -1;
+ }
+
+ /* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+ writel(EPMAP14_DEFAULT, &regs->epmap14);
+ writel(EPMAP58_DEFAULT, &regs->epmap58);
+ writel(FIFOMAP_DEFAULT, &regs->fifomap);
+ writel(0, &regs->fifocfg);
+ for (i = 0; i < 8; ++i) {
+ writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+ writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+ }
+
+ /* FIFO reset */
+ for (i = 0; i < 4; ++i) {
+ writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+ mdelay(10);
+ if (readl(&regs->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, &regs->imr);
+ writel(ISR_MASK, &regs->isr);
+ /* disable EP0 IN/OUT interrupt */
+ writel(GIMR0_CXOUT | GIMR0_CXIN, &regs->gimr0);
+ /* disable EPX IN+SPK+OUT interrupts */
+ writel(GIMR1_MASK, &regs->gimr1);
+ /* disable wakeup+idle+dma+zlp interrupts */
+ writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN
+ | GIMR2_ZLPRX | GIMR2_ZLPTX, &regs->gimr2);
+ /* enable all group interrupt */
+ writel(0, &regs->gimr);
+
+ /* suspend delay = 3 ms */
+ writel(3, &regs->idle);
+
+ /* turn-on device interrupts */
+ setbits_le32(&regs->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(&regs->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(&regs->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), &regs->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, &regs->dma_fifo);
+ } else {
+ /* Wait until epx fifo empty */
+ fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+ writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+ }
+ writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+ } else {
+ uint32_t blen;
+
+ if (ep->id == 0) {
+ writel(DMAFIFO_CX, &regs->dma_fifo);
+ do {
+ blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+ } while (blen < len);
+ } else {
+ writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+ blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+ }
+ len = (len < blen) ? len : blen;
+ writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+ }
+
+ /* 4. DMA start */
+ setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+ /* 5. DMA wait */
+ ret = -EBUSY;
+ for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+ tmp = readl(&regs->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, &regs->dma_ctrl);
+
+ writel(0, &regs->gisr2);
+ writel(0, &regs->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(&regs->otgcsr) & OTGCSR_DEV_B) {
+ /* Mini-B */
+ if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+ puts("fotg210: HS\n");
+ chip->gadget.speed = USB_SPEED_HIGH;
+ /* SOF mask timer = 1100 ticks */
+ writel(SOFMTR_TMR(1100), &regs->sof_mtr);
+ } else {
+ puts("fotg210: FS\n");
+ chip->gadget.speed = USB_SPEED_FULL;
+ /* SOF mask timer = 10000 ticks */
+ writel(SOFMTR_TMR(10000), &regs->sof_mtr);
+ }
+ } else {
+ printf("fotg210: mini-A?\n");
+ }
+ }
+
+ /* switch data port to ep0 */
+ writel(DMAFIFO_CX, &regs->dma_fifo);
+ /* fetch 8 bytes setup packet */
+ tmp[0] = readl(&regs->ep0_data);
+ tmp[1] = readl(&regs->ep0_data);
+ /* release data port */
+ writel(0, &regs->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, &regs->dev_addr);
+ } else {
+ chip->state = USB_STATE_CONFIGURED;
+ writel(chip->addr | DEVADDR_CONF,
+ &regs->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, &regs->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(&regs->iep[id - 1], IEP_STALL);
+ setbits_le32(&regs->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(&regs->cxfifo, CXFIFO_CXFIN);
+ break;
+
+ case CX_STALL:
+ setbits_le32(&regs->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(&regs->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(&regs->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(&regs->fifocfg,
+ FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+ break;
+
+ case USB_ENDPOINT_XFER_BULK:
+ setbits_le32(&regs->fifocfg,
+ FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+ break;
+
+ case USB_ENDPOINT_XFER_INT:
+ setbits_le32(&regs->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(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+ clrbits_le32(&regs->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(&regs->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(&regs->iep[ep->id - 1],
+ IEP_STALL);
+ } else {
+ setbits_le32(&regs->oep[ep->id - 1],
+ OEP_STALL);
+ }
+ } else {
+ if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+ clrbits_le32(&regs->iep[ep->id - 1],
+ IEP_STALL);
+ } else {
+ clrbits_le32(&regs->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(&regs->dev_ctrl, DEVCTRL_EN);
+ /* clear unplug bit (BIT0) */
+ clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+ }
+ } else {
+ chip->state = USB_STATE_NOTATTACHED;
+ chip->pullup = 0;
+ chip->addr = 0;
+ writel(chip->addr, &regs->dev_addr);
+ /* set unplug bit (BIT0) */
+ setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+ /* disable the chip */
+ clrbits_le32(&regs->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(&regs->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(&regs->isr) & (~readl(&regs->imr));
+ gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+ if (!(isr & ISR_DEV) || !gisr)
+ return 0;
+
+ writel(ISR_DEV, &regs->isr);
+
+ /* CX interrupts */
+ if (gisr & GISR_GRP0) {
+ st = readl(&regs->gisr0);
+ writel(0, &regs->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(&regs->cxfifo, CXFIFO_CXFIN);
+ }
+
+ /* FIFO interrupts */
+ if (gisr & GISR_GRP1) {
+ st = readl(&regs->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(&regs->gisr2);
+ writel(0, &regs->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 cc3f3449c9..8a3777b6e0 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 e5701422fa..f038747e63 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 9ce98f0768..085503dbe8 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 71cc0f2a05..598923dfc8 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 87a59704db..98f2a104b7 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 0000000000..86add36ce1
--- /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(&regs->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 *)&regs->usb.hccr;
+ hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+ if (ehci_is_fotg2xx(regs)) {
+ /* A-device bus reset */
+ /* ... Power off A-device */
+ setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+ /* ... Drop vbus and bus traffic */
+ clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+ mdelay(1);
+ /* ... Power on A-device */
+ clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+ /* ... Drive vbus and bus traffic */
+ setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+ mdelay(1);
+ /* Disable OTG & DEV interrupts, triggered at level-high */
+ writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+ /* Clear all interrupt status */
+ writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+ } else {
+ /* Interrupt=level-high */
+ setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+ /* VBUS on */
+ clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+ /* Disable all interrupts */
+ writel(0x00, &regs->usb.bmier);
+ writel(0x1f, &regs->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(&regs->otg.otgcsr));
+ else
+ spd = BMCSR_SPD(readl(&regs->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 e0f3e4b6c7..706cf0cb7d 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 15d2ec0078..c2400328a3 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 60e03a4bf7..7bb91e5abf 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 e0b4217dc3..e8a2ce0419 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 0793f07f24..e384b71401 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 176c5187af..f6db694266 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 e466c904a7..215dc22033 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 db49052b38..6fcba047f9 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 8135bcc0fe..234cb706df 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 5416f468b0..8cfc3fa775 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 6dc0422bac..ef07a87e8d 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 65692fd2a6..9e05ddc132 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 e682bd8237..e5220cf671 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 7ca28c8369..6959905efe 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 b85244a89a..d506a558c0 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 9a65cbced0..1e392290d7 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 99944766dd..7337f5374b 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 09aa763c11..35c37731cb 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 1c9d08e256..a823f9f3a7 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 fd076e09a2..b5911c6945 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 431c686967..3aa44435a2 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 1e3a5640eb..7017f8c19b 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 e102c365c4..c7904a1880 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 11cf58b146..bbd93ac502 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 e3e5ebc53c..36476e0135 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 c4fff486d8..4c12c85c2b 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 9122cbd877..96b6c0ab66 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 f778af7e36..c4cc5fd737 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 35daed05ef..78c66c76a7 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 aa5ce29585..3e9c21cc9d 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 a3ceed17f1..6632196ad9 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 bbe271303a..4970ea657b 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 220372ccd8..d10f4c18a7 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 08ba8404bf..b6769ae68d 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 444413d8d6..d65377f580 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 a62ef6364b..dbad1fd6af 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 791763aaaf..2b72a33487 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 e0a0d8e46b..6ce789d7fa 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 546e28b8fa..8d5e8ff653 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 30fb6c2ffd..2496639512 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 286f8690a8..d1ef559cf4 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 979495a72c..0d023ab9fb 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 1391ce517d..b3dbd6fae5 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 c4c41c77de..c312b7781d 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 0474140fb3..c5aa58650e 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 95a1885ace..f10555ce01 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 c28dfe0068..1d753e76b9 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 767b9763e4..ee806c4403 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 8d5ed0f7ab..ac4c253968 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 f592d3a3a4..7c31f47953 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 e5529c7007..212089c238 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 2c3f1f62a6..1130b59a21 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 a1fbd5e4a4..a71ac2bd35 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 fc0095281a..fcca5424e3 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 82436618be..480468f2d7 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 9ad7e3a90f..d5c9d059eb 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 bcd77b608f..cc2b7c332b 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 a0fe15e86e..6cb00ee664 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 a6bea153d7..d0e6ca65bf 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 d5f3c5f56f..09d0835c61 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 0e22cc7e14..d070f6adc3 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 266cb54c92..483556b31b 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 35d15f4271..525e88fa1b 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 5d69fb66d9..f1bfdcbd2c 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 acd3276e98..c54755fab8 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 d233365b7d..25303c4f65 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 c61982745f..f791e7682e 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 264309772a..4a3ca017e8 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 84a167d2a7..8b0415158a 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 a9c00acc9a..afd4c0356d 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 52d172925b..21f286e0fb 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 47110aff24..4a93417655 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 9f754c2a81..cd1f4254ad 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 437ee6ee6b..7b28a27bc0 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 8b13b107e2..9c27182dc7 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 0000000000..fee8040e2d
--- /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 878bd5fa5e..4943d7c8fe 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 a57d9dd26e..6ce4cbef9c 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 c75f86cb84..05a75d8a76 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 a975ee10ed..229117c18d 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 bbc53ceafd..4ea8717368 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 ce8f9b0b2e..dd2b9c34e4 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 53979dddf2..48acee4993 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 778230d335..d1e27c42d4 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 119819e371..c3cacefed8 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 713ea12ee5..3757af07a0 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 1ee0c48fa1..1745eb39fc 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 fbcf8e5e22..faadfe43c1 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 c37aafdd47..f563fbe335 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 8235b857d3..d97acecc44 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 992443a8e2..a427551281 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 3837b8f139..40c18274f9 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 93876b1317..e2f96aa4ac 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 27a12b310b..210bc30ca8 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 c0ffb33129..318c4c5d51 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 f54fcb33e5..fa456ed79f 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 84e4891dc9..cdc51a5016 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 be977f1d76..3b3f9e6302 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 07384234c9..966a6e3da9 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 f1032f0f3f..8f0c4b6241 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 462b155a30..710812fc9f 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 f28f3e4f9a..f88dfe4cde 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 5def36ad0c..0c78acac80 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 e9af825663..8f29229cdc 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 7cb10fb01e..381bcdda0d 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 eea44db356..a6e184961f 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 0d53e51b9d..d93d5e204f 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 7cc3ef24ac..c5a6d4b315 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 5318aaf99c..bd81053875 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 8d2673dacb..b4b1c31960 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 538a167528..57c4b33f1c 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 506a558f14..d36984df2d 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 165de13753..628d5d3db1 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 da67ae3b5a..35a473a429 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 acb127c1d1..92106d762d 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 fd46083581..142d20b5c5 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 c6e357a8ce..b258da9e92 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 be04a7548a..288ef8df74 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 2e2d439678..66c7b4f95f 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 f21fa648b1..eec087c0dc 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 aed5fa6a45..f6a456c18f 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 2723843439..b6e01617c8 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 32aa4e5065..c40fbd9f8d 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 788227d79d..3b74d7c31c 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 3238ac7327..a6a0f8bb58 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 d6b655122a..b05ba08afd 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 8d78921f6b..7393f289a7 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 b32d1bdb98..582c584ae6 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 9efbb8e34c..7b8bac48ec 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 2fac0efe13..c2da4cec9a 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 afbd549997..12f28f82a8 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 33364a843e..ed96b1b3c4 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 3ed8dc7f3e..c6f712c937 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 d505a41de4..aec4a584ef 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 b919aec359..d7c1f8508b 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 e49dc28776..87a5056afd 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 eec79619c1..20f0a18f86 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 3b4761bd08..f0e568af83 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 6c1b136659..f71f28bb87 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 64ce52dee7..6f003aa03f 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 aa681f0628..3c7a85e359 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 d0fe9dadfb..3e64c7405b 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 7ed634b701..2fa537291b 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 d7b1ca203a..a19de079b6 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 eac1ef9e02..9e2686ac44 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 348030227d..9b16c47820 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 351ff5a22b..1897619058 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 b60a9ade15..6f6ddfa20e 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 5cd660927a..3f9fdd444d 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 c18b35b057..216c6cb70b 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 788207d007..98dd083302 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 5abcda3c36..6e53bc2ee2 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 478d0d8f9d..fdc1b95e23 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 2209ddf823..148ade3568 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 9040ec6095..0e2d17deb5 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 fb74608bb9..9dec21de6e 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 f66173e0f2..f0da1fcf1f 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 dd5d7cd260..11fce53c02 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 25f15f2c35..7a0b481931 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 c1a90a7047..96d7128d0a 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 2a731a637b..ff2189c2fb 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 fa1dcc3528..92b2179ca7 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 a3738b7b1d..a43c3da4a0 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 3046081c52..c9f1a9fa24 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 66568c8d00..60d1503bc3 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 d3b8379186..7b1130a48e 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 64e78751af..05e682c4e9 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 61e02e6077..f97de5490b 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 d10f74843d..219f276a4c 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 9542c7e213..994edecaab 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 506d646fec..1f48cc5772 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 1851a00c16..f28f443fe9 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 ff99481b2f..3034a3c9a9 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 46f1c903f1..43359a2eef 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 2acf6c80a5..a171085354 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 0cbef6f85f..cde0df1a08 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 fb684b5e10..3282d378d7 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 0000000000..335d5b4e63
--- /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 0000000000..a2421c7ba4
--- /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 a107f4b13e..124653c816 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 0000000000..12811cc070
--- /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 4c6a37b112..460ccb42af 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 818ddde369..bdefda4958 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 f47395f35d..f8affd8d91 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 afea85cdc2..f691a74ab4 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 b8cc5236a8..7b0108f320 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 c6e7fc5216..8718a01902 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 c5ec2acfd8..765d84f5e4 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 fcb20fe108..f6dbdb096d 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 8b92692146..66b83d83de 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 8cbcdae114..71292b1a86 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 141c96024c..6f44abdc16 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 98bf255bb2..2055584374 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 e9b134d142..8e44855712 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 d1d732c283..bd48704c87 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 53cb095507..4f76f88d67 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 25e8a4624b..e1c62d83cb 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 f88f672f11..583c30e270 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 8bdd23112b..d51c1abd18 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 f0f3bf94b5..228d87127c 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 970d4d1fab..7673470046 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 df454b50c3..917d8746fb 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 f7c7cc59fc..35c1c5b5f5 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 15f583f069..98ba151f90 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 75bf3b4728..dbf32740bb 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 0000000000..a5dd676b6b
--- /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 3fe2e1eab2..e8e654467f 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 3b6a44edce..e80785f55e 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 0000000000..89ee7b22ec
--- /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 0000000000..8082466f54
--- /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 0000000000..2d2d2431ba
--- /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 0000000000..8a9c488cb5
--- /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 651077ca4d..6568854fbe 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 5d586098dd..f5a8819f39 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 24ccd0af11..1b3c810588 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 63e67b78c8..b9e3c4a742 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 0000000000..9eb3e40f56
--- /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 0000000000..e30d8ca847
--- /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 0000000000..6a0268919d
--- /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 09dfae03c2..3a82efab61 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 0000000000..e7455bcfe6
--- /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 533a96b85e..82e5c13653 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 f7bdf9207d..0000000000
--- 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 1ba796ebdf..4152fae5ba 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;
}
diff --git a/net/net.c b/net/net.c
index df94789de9..7663b9cd6c 100644
--- a/net/net.c
+++ b/net/net.c
@@ -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;
}
diff --git a/net/nfs.c b/net/nfs.c
index 7f2393f606..381b75f1c5 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -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;
diff --git a/net/tftp.c b/net/tftp.c
index 09790eb7cf..6d333d559c 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -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 0000000000..aad9f59019
--- /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 0000000000..696a39675b
--- /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 0000000000..4631242709
--- /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 0000000000..a1e853c9ca
--- /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 0000000000..a1e853c9ca
--- /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 0000000000..db2ed79355
--- /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 0000000000..f69326a39b
--- /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 0000000000..c3cfadeb1b
--- /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 9bce719478..a7fee26cdd 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 4630f03dc5..46159b23d6 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 9f23901872..896e2bc985 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 cc123dd37a..281c2bda13 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 d944d0ff4e..932384beab 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, &region, 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, &region,
+ &region_count, &region_prop, &region_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 e43b09f766..d312844e9c 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 e07a6157eb..1d9984e1a3 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 508a747a3f..5f39dc5bbf 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 0000000000..aa05e77ece
--- /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, &not_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);
+}