diff --git a/Documentation/boards.dox b/Documentation/boards.dox index dba547f..3eb79b2 100644 --- a/Documentation/boards.dox +++ b/Documentation/boards.dox @@ -20,6 +20,14 @@ @li @subpage a9m2440 @li @subpage a9m2410 @li @subpage eukrea_cpuimx27 +@li @subpage edb9301 +@li @subpage edb9302 +@li @subpage edb9302a +@li @subpage edb9307 +@li @subpage edb9307a +@li @subpage edb9312 +@li @subpage edb9315 +@li @subpage edb9315a Blackfin type: @@ -27,7 +35,7 @@ x86 type: -@li nothing yet +@li @subpage generic_pc coldfire/m68k type: diff --git a/Documentation/commands.dox b/Documentation/commands.dox index 4c14a88..a8850b1 100644 --- a/Documentation/commands.dox +++ b/Documentation/commands.dox @@ -20,5 +20,5 @@ @li @subpage setenv_command @li @subpage sh_command @li @subpage unprotect_command - +@li @subpage linux16_command */ diff --git a/Documentation/developers_manual.dox b/Documentation/developers_manual.dox index 2f7d360..620905e 100644 --- a/Documentation/developers_manual.dox +++ b/Documentation/developers_manual.dox @@ -20,5 +20,6 @@ @li @subpage barebox_simul @li @subpage io_access_functions @li @subpage mcfv4e_MCDlib +@li @subpage x86_runtime */ diff --git a/Documentation/users_manual.dox b/Documentation/users_manual.dox index e4ba9d0..5467bee 100644 --- a/Documentation/users_manual.dox +++ b/Documentation/users_manual.dox @@ -10,5 +10,6 @@ @li @subpage readline_parser @li @subpage command_reference @li @subpage partitions +@li @subpage x86_bootloader */ diff --git a/Doxyfile b/Doxyfile index c9b04b6..94dd6ae 100644 --- a/Doxyfile +++ b/Doxyfile @@ -484,7 +484,8 @@ commands \ common \ board \ - lib + lib \ + scripts/setupmbr # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default diff --git a/Makefile b/Makefile index 5d4f634..5826368 100644 --- a/Makefile +++ b/Makefile @@ -643,7 +643,30 @@ barebox.bin: barebox $(Q)$(OBJCOPY) -O binary barebox barebox.bin +ifdef CONFIG_X86 +ifdef CONFIG_X86_HDBOOT + @echo "-------------------------------------------------" > barebox.S + @echo " * MBR content" >> barebox.S + $(Q)$(OBJDUMP) -j .bootsector -mi8086 -d barebox >> barebox.S + @echo "-------------------------------------------------" >> barebox.S + @echo " * Boot loader content" >> barebox.S + $(Q)$(OBJDUMP) -j .bootstrapping -mi8086 -d barebox >> barebox.S +endif + @echo "-------------------------------------------------" >> barebox.S + @echo " * Regular Text content" >> barebox.S + $(Q)$(OBJDUMP) -j .text -d barebox >> barebox.S + @echo "-------------------------------------------------" >> barebox.S + @echo " * Regular Data content" >> barebox.S + $(Q)$(OBJDUMP) -j .data -d barebox >> barebox.S + @echo "-------------------------------------------------" >> barebox.S + @echo " * Commands content" >> barebox.S + $(Q)$(OBJDUMP) -j .barebox_cmd -d barebox >> barebox.S + @echo "-------------------------------------------------" >> barebox.S + @echo " * Init Calls content" >> barebox.S + $(Q)$(OBJDUMP) -j .barebox_initcalls -d barebox >> barebox.S +else $(Q)$(OBJDUMP) -d barebox > barebox.S +endif # barebox image barebox: $(barebox-lds) $(barebox-head) $(barebox-common) $(kallsyms.o) FORCE diff --git a/arch/architecture.dox b/arch/architecture.dox index 669c028..ea00dcd 100644 --- a/arch/architecture.dox +++ b/arch/architecture.dox @@ -88,6 +88,7 @@ @li @subpage dev_bf_mach @li @subpage dev_ppc_mach @li @subpage dev_m68k_mach +@li @subpage dev_x86_mach */ diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c091a99..9cad224 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -31,6 +31,11 @@ bool "Atmel AT91RM9200" select CPU_ARM920T +config ARCH_EP93XX + bool "Cirrus Logic EP93xx" + select CPU_ARM920T + select GENERIC_GPIO + config ARCH_IMX bool "Freescale iMX-based" select GENERIC_GPIO @@ -51,6 +56,7 @@ source arch/arm/cpu/Kconfig source arch/arm/mach-at91/Kconfig source arch/arm/mach-at91rm9200/Kconfig +source arch/arm/mach-ep93xx/Kconfig source arch/arm/mach-imx/Kconfig source arch/arm/mach-netx/Kconfig source arch/arm/mach-omap/Kconfig diff --git a/arch/arm/Makefile b/arch/arm/Makefile index 47b002f..ede2085 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -39,6 +39,7 @@ # by CONFIG_* macro name. machine-$(CONFIG_ARCH_AT91) := at91 machine-$(CONFIG_ARCH_AT91RM9200) := at91rm9200 +machine-$(CONFIG_ARCH_EP93XX) := ep93xx machine-$(CONFIG_ARCH_IMX) := imx machine-$(CONFIG_ARCH_NETX) := netx machine-$(CONFIG_ARCH_OMAP) := omap @@ -51,6 +52,14 @@ board-$(CONFIG_MACH_AT91SAM9260EK) := at91sam9260ek board-$(CONFIG_MACH_AT91SAM9263EK) := at91sam9263ek board-$(CONFIG_MACH_ECO920) := eco920 +board-$(CONFIG_MACH_EDB9301) := edb93xx +board-$(CONFIG_MACH_EDB9302) := edb93xx +board-$(CONFIG_MACH_EDB9302A) := edb93xx +board-$(CONFIG_MACH_EDB9307) := edb93xx +board-$(CONFIG_MACH_EDB9307A) := edb93xx +board-$(CONFIG_MACH_EDB93012) := edb93xx +board-$(CONFIG_MACH_EDB9315) := edb93xx +board-$(CONFIG_MACH_EDB9315A) := edb93xx board-$(CONFIG_MACH_EUKREA_CPUIMX27) := eukrea_cpuimx27 board-$(CONFIG_MACH_FREESCALE_MX35_3STACK) := freescale-mx35-3-stack board-$(CONFIG_MACH_FREESCALE_MX25_3STACK) := freescale-mx25-3-stack diff --git a/arch/arm/configs/edb93xx_defconfig b/arch/arm/configs/edb93xx_defconfig new file mode 100644 index 0000000..d6b4b19 --- /dev/null +++ b/arch/arm/configs/edb93xx_defconfig @@ -0,0 +1,236 @@ +# +# Automatically generated make config: don't edit +# barebox version: 2009.12.0 +# Fri Jan 8 17:27:15 2010 +# +CONFIG_ARM=y + +# +# System Type +# +# CONFIG_ARCH_AT91 is not set +# CONFIG_ARCH_AT91RM9200 is not set +CONFIG_ARCH_EP93XX=y +# CONFIG_ARCH_IMX is not set +# CONFIG_ARCH_NETX is not set +# CONFIG_ARCH_OMAP is not set +# CONFIG_ARCH_S3C24xx is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +CONFIG_CPU_ARM920T=y +CONFIG_CPU_32v4T=y + +# +# processor features +# +CONFIG_ARCH_TEXT_BASE=0x05700000 +CONFIG_BOARDINFO="Cirrus Logic EDB9301" +CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET=y + +# +# Cirrus EP93xx System-on-Chip +# +CONFIG_ARCH_EP9301=y +# CONFIG_ARCH_EP9302 is not set +# CONFIG_ARCH_EP9307 is not set +# CONFIG_ARCH_EP9312 is not set +# CONFIG_ARCH_EP9315 is not set +CONFIG_MACH_EDB9301=y +CONFIG_EP93XX_SDRAM_NUM_BANKS=4 +CONFIG_EP93XX_SDRAM_BANK0_BASE=0x00000000 +CONFIG_EP93XX_SDRAM_BANK0_SIZE=0x00800000 +CONFIG_EP93XX_SDRAM_BANK1_BASE=0x01000000 +CONFIG_EP93XX_SDRAM_BANK1_SIZE=0x00800000 +CONFIG_EP93XX_SDRAM_BANK2_BASE=0x04000000 +CONFIG_EP93XX_SDRAM_BANK2_SIZE=0x00800000 +CONFIG_EP93XX_SDRAM_BANK3_BASE=0x05000000 +CONFIG_EP93XX_SDRAM_BANK3_SIZE=0x00800000 +CONFIG_AEABI=y + +# +# Arm specific settings +# +CONFIG_CMD_ARM_CPUINFO=y +CONFIG_CMDLINE_TAG=y +CONFIG_SETUP_MEMORY_TAGS=y +# CONFIG_INITRD_TAG is not set +CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y +CONFIG_GREGORIAN_CALENDER=y +CONFIG_HAS_KALLSYMS=y +CONFIG_HAS_MODULES=y +CONFIG_CMD_MEMORY=y +CONFIG_ENV_HANDLING=y +CONFIG_GENERIC_GPIO=y + +# +# General Settings +# +CONFIG_LOCALVERSION_AUTO=y + +# +# memory layout +# +CONFIG_HAVE_CONFIGURABLE_TEXT_BASE=y +CONFIG_TEXT_BASE=0x05700000 +CONFIG_HAVE_CONFIGURABLE_MEMORY_LAYOUT=y +CONFIG_MEMORY_LAYOUT_DEFAULT=y +# CONFIG_MEMORY_LAYOUT_FIXED is not set +CONFIG_STACK_SIZE=0x8000 +CONFIG_MALLOC_SIZE=0x400000 +# CONFIG_BROKEN is not set +# CONFIG_EXPERIMENTAL is not set +CONFIG_MACH_HAS_LOWLEVEL_INIT=y +CONFIG_MACH_DO_LOWLEVEL_INIT=y +CONFIG_PROMPT="barebox:" +CONFIG_BAUDRATE=115200 +CONFIG_LONGHELP=y +CONFIG_CBSIZE=1024 +CONFIG_MAXARGS=16 +CONFIG_SHELL_HUSH=y +# CONFIG_SHELL_SIMPLE is not set +CONFIG_GLOB=y +CONFIG_PROMPT_HUSH_PS2="> " +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_DYNAMIC_CRC_TABLE=y +CONFIG_ERRNO_MESSAGES=y +CONFIG_TIMESTAMP=y +CONFIG_CONSOLE_FULL=y +CONFIG_CONSOLE_ACTIVATE_FIRST=y +# CONFIG_OF_FLAT_TREE is not set +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="board/edb93xx/env" + +# +# Debugging +# +# CONFIG_DEBUG_INFO is not set +# CONFIG_ENABLE_FLASH_NOISE is not set +# CONFIG_ENABLE_PARTITION_NOISE is not set +# CONFIG_ENABLE_DEVICE_NOISE is not set + +# +# Commands +# + +# +# scripting +# +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_READLINE=y +CONFIG_CMD_TRUE=y +CONFIG_CMD_FALSE=y + +# +# file commands +# +CONFIG_CMD_LS=y +CONFIG_CMD_RM=y +CONFIG_CMD_CAT=y +CONFIG_CMD_MKDIR=y +CONFIG_CMD_RMDIR=y +CONFIG_CMD_CP=y +CONFIG_CMD_PWD=y +CONFIG_CMD_CD=y +CONFIG_CMD_MOUNT=y +CONFIG_CMD_UMOUNT=y + +# +# console +# +CONFIG_CMD_CLEAR=y +CONFIG_CMD_ECHO=y + +# +# memory +# +# CONFIG_CMD_LOADB is not set +CONFIG_CMD_MEMINFO=y +CONFIG_CMD_CRC=y +CONFIG_CMD_MTEST=y +# CONFIG_CMD_MTEST_ALTERNATIVE is not set + +# +# flash +# +CONFIG_CMD_FLASH=y + +# +# booting +# +CONFIG_CMD_BOOTM=y +# CONFIG_CMD_BOOTM_ZLIB is not set +# CONFIG_CMD_BOOTM_BZLIB is not set +# CONFIG_CMD_BOOTM_SHOW_TYPE is not set +CONFIG_CMD_BOOTZ=y +CONFIG_CMD_BOOTU=y +CONFIG_CMD_RESET=y +CONFIG_CMD_GO=y +CONFIG_CMD_TIMEOUT=y +CONFIG_CMD_PARTITION=y +CONFIG_CMD_TEST=y +CONFIG_CMD_VERSION=y +CONFIG_CMD_HELP=y +CONFIG_CMD_DEVINFO=y +CONFIG_CMD_GPIO=y +CONFIG_NET=y +CONFIG_NET_DHCP=y +# CONFIG_NET_RARP is not set +# CONFIG_NET_NFS is not set +CONFIG_NET_PING=y +CONFIG_NET_TFTP=y + +# +# Drivers +# + +# +# serial drivers +# +# CONFIG_DRIVER_SERIAL_ARM_DCC is not set +# CONFIG_DRIVER_SERIAL_NS16550 is not set +CONFIG_DRIVER_SERIAL_PL010=y +CONFIG_MIIPHY=y + +# +# Network drivers +# +# CONFIG_DRIVER_NET_SMC911X is not set +# CONFIG_DRIVER_NET_SMC91111 is not set +CONFIG_DRIVER_NET_EP93XX=y + +# +# SPI drivers +# +# CONFIG_SPI is not set +# CONFIG_I2C is not set + +# +# flash drivers +# +CONFIG_DRIVER_CFI=y +# CONFIG_DRIVER_CFI_NEW is not set +CONFIG_DRIVER_CFI_OLD=y +# CONFIG_CFI_BUFFER_WRITE is not set +# CONFIG_NAND is not set +# CONFIG_USB is not set +# CONFIG_USB_GADGET is not set +# CONFIG_VIDEO is not set + +# +# Filesystem support +# +# CONFIG_FS_CRAMFS is not set +CONFIG_FS_RAMFS=y +CONFIG_FS_DEVFS=y +CONFIG_CRC32=y +# CONFIG_GENERIC_FIND_NEXT_BIT is not set diff --git a/arch/arm/configs/freescale_mx35_3stack_defconfig b/arch/arm/configs/freescale_mx35_3stack_defconfig index 1319a69..17a2fdc 100644 --- a/arch/arm/configs/freescale_mx35_3stack_defconfig +++ b/arch/arm/configs/freescale_mx35_3stack_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# barebox version: 2.0.0-rc10 -# Fri Dec 18 11:47:45 2009 +# barebox version: 2009.12.0-pre +# Tue Dec 22 17:43:43 2009 # # CONFIG_BOARD_LINKER_SCRIPT is not set CONFIG_GENERIC_LINKER_SCRIPT=y @@ -43,17 +43,17 @@ # CONFIG_MACH_PCM043 is not set # -# Board specific settings +# Board specific settings # # -# i.MX specific settings +# i.MX specific settings # # CONFIG_IMX_CLKO is not set -# CONFIG_AEABI is not set +CONFIG_AEABI=y # -# Arm specific settings +# Arm specific settings # CONFIG_CMD_ARM_CPUINFO=y CONFIG_CMDLINE_TAG=y @@ -68,12 +68,12 @@ CONFIG_GENERIC_GPIO=y # -# General Settings +# General Settings # CONFIG_LOCALVERSION_AUTO=y # -# memory layout +# memory layout # CONFIG_HAVE_CONFIGURABLE_TEXT_BASE=y CONFIG_TEXT_BASE=0x87F00000 @@ -81,7 +81,7 @@ CONFIG_MEMORY_LAYOUT_DEFAULT=y # CONFIG_MEMORY_LAYOUT_FIXED is not set CONFIG_STACK_SIZE=0x8000 -CONFIG_MALLOC_SIZE=0x400000 +CONFIG_MALLOC_SIZE=0x1000000 # CONFIG_BROKEN is not set # CONFIG_EXPERIMENTAL is not set CONFIG_MACH_HAS_LOWLEVEL_INIT=y @@ -105,10 +105,10 @@ # CONFIG_OF_FLAT_TREE is not set CONFIG_PARTITION=y CONFIG_DEFAULT_ENVIRONMENT=y -CONFIG_DEFAULT_ENVIRONMENT_PATH="board/pcm043/env/" +CONFIG_DEFAULT_ENVIRONMENT_PATH="board/freescale-mx35-3-stack/env/" # -# Debugging +# Debugging # # CONFIG_DEBUG_INFO is not set # CONFIG_ENABLE_FLASH_NOISE is not set @@ -116,11 +116,11 @@ # CONFIG_ENABLE_DEVICE_NOISE is not set # -# Commands +# Commands # # -# scripting +# scripting # CONFIG_CMD_EDIT=y CONFIG_CMD_SLEEP=y @@ -133,7 +133,7 @@ CONFIG_CMD_FALSE=y # -# file commands +# file commands # CONFIG_CMD_LS=y CONFIG_CMD_RM=y @@ -147,13 +147,13 @@ CONFIG_CMD_UMOUNT=y # -# console +# console # CONFIG_CMD_CLEAR=y CONFIG_CMD_ECHO=y # -# memory +# memory # # CONFIG_CMD_LOADB is not set CONFIG_CMD_MEMINFO=y @@ -161,12 +161,12 @@ # CONFIG_CMD_MTEST is not set # -# flash +# flash # CONFIG_CMD_FLASH=y # -# booting +# booting # CONFIG_CMD_BOOTM=y # CONFIG_CMD_BOOTM_ZLIB is not set @@ -182,7 +182,8 @@ CONFIG_CMD_VERSION=y CONFIG_CMD_HELP=y CONFIG_CMD_DEVINFO=y -CONFIG_CMD_GPIO=y +CONFIG_CMD_BMP=y +# CONFIG_CMD_GPIO is not set CONFIG_NET=y CONFIG_NET_DHCP=y # CONFIG_NET_RARP is not set @@ -191,11 +192,11 @@ CONFIG_NET_TFTP=y # -# Drivers +# Drivers # # -# serial drivers +# serial drivers # # CONFIG_DRIVER_SERIAL_ARM_DCC is not set CONFIG_DRIVER_SERIAL_IMX=y @@ -203,39 +204,43 @@ CONFIG_MIIPHY=y # -# Network drivers +# Network drivers # CONFIG_DRIVER_NET_SMC911X=y CONFIG_DRIVER_NET_SMC911X_ADDRESS_SHIFT=0 # CONFIG_DRIVER_NET_SMC91111 is not set -# CONFIG_DRIVER_NET_FEC_IMX is not set +CONFIG_DRIVER_NET_FEC_IMX=y # -# SPI drivers +# SPI drivers # -CONFIG_SPI=y -# CONFIG_DRIVER_SPI_IMX is not set -# CONFIG_DRIVER_SPI_MC13783 is not set +# CONFIG_SPI is not set CONFIG_I2C=y CONFIG_DRIVER_I2C_IMX=y CONFIG_DRIVER_I2C_MC13892=y CONFIG_DRIVER_I2C_MC9SDZ60=y # -# flash drivers +# flash drivers # CONFIG_HAS_CFI=y CONFIG_DRIVER_CFI=y # CONFIG_DRIVER_CFI_NEW is not set CONFIG_DRIVER_CFI_OLD=y CONFIG_CFI_BUFFER_WRITE=y -# CONFIG_NAND is not set +CONFIG_NAND=y +CONFIG_NAND_IMX=y +CONFIG_NAND_IMX_BOOT=y +# CONFIG_MTD_NAND_VERIFY_WRITE is not set +# CONFIG_MTD_NAND_ECC_SMC is not set +CONFIG_MTD_NAND_IDS=y # CONFIG_USB is not set # CONFIG_USB_GADGET is not set -# CONFIG_VIDEO is not set +CONFIG_VIDEO=y +CONFIG_DRIVER_VIDEO_IMX_IPU=y # -# Filesystem support +# Filesystem support # # CONFIG_FS_CRAMFS is not set CONFIG_FS_RAMFS=y diff --git a/arch/arm/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S index c8d1bb9..a5eaefa 100644 --- a/arch/arm/lib/barebox.lds.S +++ b/arch/arm/lib/barebox.lds.S @@ -39,6 +39,11 @@ _stext = .; _text = .; *(.text_entry*) +#ifdef CONFIG_ARCH_EP93XX + /* the EP93xx expects to find the pattern 'CRUS' at 0x1000 */ + . = 0x1000; + LONG(0x53555243) /* 'CRUS' */ +#endif *(.text_bare_init*) *(.text*) } diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig new file mode 100644 index 0000000..ed6e986 --- /dev/null +++ b/arch/arm/mach-ep93xx/Kconfig @@ -0,0 +1,438 @@ +if ARCH_EP93XX + +config EP93XX_SDCE0_PHYS_OFFSET + bool + +config EP93XX_SDCE3_SYNC_PHYS_OFFSET + bool + +comment "Cirrus EP93xx System-on-Chip" + +choice + prompt "Cirrus Logic EP93XX Processor" + +config ARCH_EP9301 + bool "EP9301" + +config ARCH_EP9302 + bool "EP9302" + +config ARCH_EP9307 + bool "EP9307" + +config ARCH_EP9312 + bool "EP9312" + +config ARCH_EP9315 + bool "EP9315" + +endchoice + +# ---------------------------------------------------------- + +if ARCH_EP9301 + +choice + prompt "EP9301 Board Type" + +config MACH_EDB9301 + bool "Cirrus Logic EDB9301" + select EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9301 Evaluation board + +endchoice + +if MACH_EDB9301 + +config BOARDINFO + default "Cirrus Logic EDB9301" + +config ARCH_TEXT_BASE + hex + default 0x05700000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 4 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0x00000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0x01000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK2_BASE + hex + default 0x04000000 + +config EP93XX_SDRAM_BANK2_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK3_BASE + hex + default 0x05000000 + +config EP93XX_SDRAM_BANK3_SIZE + hex + default 0x00800000 + +endif + +endif + +# ---------------------------------------------------------- + +if ARCH_EP9302 + +choice + prompt "EP9302 Board Type" + +config MACH_EDB9302 + bool "Cirrus Logic EDB9302" + select EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9302 Evaluation board + +config MACH_EDB9302A + bool "Cirrus Logic EDB9302A" + select EP93XX_SDCE0_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9302A Evaluation board + +endchoice + +if MACH_EDB9302 + +config BOARDINFO + default "Cirrus Logic EDB9302" + +config ARCH_TEXT_BASE + hex + default 0x05700000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 4 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0x00000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0x01000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK2_BASE + hex + default 0x04000000 + +config EP93XX_SDRAM_BANK2_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK3_BASE + hex + default 0x05000000 + +config EP93XX_SDRAM_BANK3_SIZE + hex + default 0x00800000 + +endif + +if MACH_EDB9302A + +config BOARDINFO + default "Cirrus Logic EDB9302A" + +config ARCH_TEXT_BASE + hex + default 0xc5700000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 4 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0xc0000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0xc1000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK2_BASE + hex + default 0xc4000000 + +config EP93XX_SDRAM_BANK2_SIZE + hex + default 0x00800000 + +config EP93XX_SDRAM_BANK3_BASE + hex + default 0xc5000000 + +config EP93XX_SDRAM_BANK3_SIZE + hex + default 0x00800000 + +endif + +endif + +# ---------------------------------------------------------- + +if ARCH_EP9307 + +choice + prompt "EP9307 Board Type" + +config MACH_EDB9307 + bool "Cirrus Logic EDB9307" + select EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9307 Evaluation board + +config MACH_EDB9307A + bool "Cirrus Logic EDB9307A" + select EP93XX_SDCE0_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9307A Evaluation board + +endchoice + +if MACH_EDB9307 + +config BOARDINFO + default "Cirrus Logic EDB9307" + +config ARCH_TEXT_BASE + hex + default 0x01f00000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 2 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0x00000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x02000000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0x04000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x02000000 + +endif + +if MACH_EDB9307A + +config BOARDINFO + default "Cirrus Logic EDB9307A" + +config ARCH_TEXT_BASE + hex + default 0xc1f00000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 2 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0xc0000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x02000000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0xc4000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x02000000 + +endif + +endif + +# ---------------------------------------------------------- + +if ARCH_EP9312 + +choice + prompt "EP9312 Board Type" + +config MACH_EDB9312 + bool "Cirrus Logic EDB9312" + select EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9312 Evaluation board + +endchoice + +if MACH_EDB9312 + +config BOARDINFO + default "Cirrus Logic EDB9312" + +config ARCH_TEXT_BASE + hex + default 0x01f00000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 2 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0x00000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x02000000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0x04000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x02000000 + +endif + +endif + +# ---------------------------------------------------------- + +if ARCH_EP9315 + +choice + prompt "EP9315 Board Type" + +config MACH_EDB9315 + bool "Cirrus Logic EDB9315" + select EP93XX_SDCE3_SYNC_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9315 Evaluation board + +config MACH_EDB9315A + bool "Cirrus Logic EDB9315A" + select EP93XX_SDCE0_PHYS_OFFSET + select MACH_HAS_LOWLEVEL_INIT + help + Say y here if you are using Cirrus Logic's EDB9315A Evaluation board + +endchoice + +if MACH_EDB9315 + +config BOARDINFO + default "Cirrus Logic EDB9315" + +config ARCH_TEXT_BASE + hex + default 0x01f00000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 2 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0x00000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x02000000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0x04000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x02000000 + +endif + +if MACH_EDB9315A + +config BOARDINFO + default "Cirrus Logic EDB9315A" + +config ARCH_TEXT_BASE + hex + default 0xc1f00000 + +config EP93XX_SDRAM_NUM_BANKS + int + default 2 + +config EP93XX_SDRAM_BANK0_BASE + hex + default 0xc0000000 + +config EP93XX_SDRAM_BANK0_SIZE + hex + default 0x02000000 + +config EP93XX_SDRAM_BANK1_BASE + hex + default 0xc4000000 + +config EP93XX_SDRAM_BANK1_SIZE + hex + default 0x02000000 + +endif + +endif + +endif diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile new file mode 100644 index 0000000..dac6571 --- /dev/null +++ b/arch/arm/mach-ep93xx/Makefile @@ -0,0 +1,3 @@ +obj-y += clocksource.o gpio.o led.o + +obj-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += lowlevel_init.o diff --git a/arch/arm/mach-ep93xx/clocksource.c b/arch/arm/mach-ep93xx/clocksource.c new file mode 100644 index 0000000..2a7d90e --- /dev/null +++ b/arch/arm/mach-ep93xx/clocksource.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#define TIMER_CLKSEL (1 << 3) +#define TIMER_MODE (1 << 6) +#define TIMER_ENABLE (1 << 7) + +#define TIMER_FREQ 508469 + +static uint64_t ep93xx_clocksource_read(void) +{ + struct timer_regs *timer = (struct timer_regs *)TIMER_BASE; + + return 0xffffffff - readl(&timer->timer3.value); +} + +static struct clocksource cs = { + .read = ep93xx_clocksource_read, + .mask = 0xffffffff, + .shift = 10, +}; + +static int clocksource_init(void) +{ + struct timer_regs *timer = (struct timer_regs *)TIMER_BASE; + + /* use timer 3 with 508KHz and free running */ + writel(TIMER_CLKSEL, + &timer->timer3.control); + + /* load timer 3 with max value */ + writel(0xffffffff, &timer->timer3.load); + + /* enable timer 3 with 508KHz and periodic mode */ + writel(TIMER_ENABLE | TIMER_MODE | TIMER_CLKSEL, + &timer->timer3.control); + + cs.mult = clocksource_hz2mult(TIMER_FREQ, cs.shift); + + init_clock(&cs); + + return 0; +} + +core_initcall(clocksource_init); + +/* + * Reset the cpu + */ +void reset_cpu(ulong ignored) +{ + struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; + uint32_t value; + + /* Unlock DeviceCfg and set SWRST */ + writel(0xAA, &syscon->sysswlock); + value = readl(&syscon->devicecfg); + value |= SYSCON_DEVICECFG_SWRST; + writel(value, &syscon->devicecfg); + + /* Unlock DeviceCfg and clear SWRST */ + writel(0xAA, &syscon->sysswlock); + value = readl(&syscon->devicecfg); + value &= ~SYSCON_DEVICECFG_SWRST; + writel(value, &syscon->devicecfg); + + /* Dying... */ + while (1) + ; /* noop */ +} +EXPORT_SYMBOL(reset_cpu); diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c new file mode 100644 index 0000000..5d57434 --- /dev/null +++ b/arch/arm/mach-ep93xx/gpio.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2010 Matthias Kaehlcke + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#define EP93XX_GPIO_NUM_PORTS 8 +#define EP93XX_GPIO_NUM_GPIOS (EP93XX_GPIO_NUM_PORTS * 8) + +struct gpio_port { + uint32_t *dr; + uint32_t *ddr; +}; + +struct gpio_port gpio_ports[EP93XX_GPIO_NUM_PORTS]; + +static int ep93xx_gpio_init(void) +{ + struct gpio_regs *gpio_regs = (struct gpio_regs *)GPIO_BASE; + + gpio_ports[0].dr = &gpio_regs->padr; + gpio_ports[0].ddr = &gpio_regs->paddr; + gpio_ports[1].dr = &gpio_regs->pbdr; + gpio_ports[1].ddr = &gpio_regs->pbddr; + gpio_ports[2].dr = &gpio_regs->pcdr; + gpio_ports[2].ddr = &gpio_regs->pcddr; + gpio_ports[3].dr = &gpio_regs->pddr; + gpio_ports[3].ddr = &gpio_regs->pdddr; + gpio_ports[4].dr = &gpio_regs->pedr; + gpio_ports[4].ddr = &gpio_regs->peddr; + gpio_ports[5].dr = &gpio_regs->pfdr; + gpio_ports[5].ddr = &gpio_regs->pfddr; + gpio_ports[6].dr = &gpio_regs->pgdr; + gpio_ports[6].ddr = &gpio_regs->pgddr; + gpio_ports[7].dr = &gpio_regs->phdr; + gpio_ports[7].ddr = &gpio_regs->phddr; + + return 0; +} + +postcore_initcall(ep93xx_gpio_init); + +static struct gpio_port *gpio_get_port(unsigned gpio) +{ + if (gpio >= EP93XX_GPIO_NUM_GPIOS) + return 0; + + return &gpio_ports[gpio / 8]; +} + +void gpio_set_value(unsigned gpio, int value) +{ + struct gpio_port *port = gpio_get_port(gpio); + const int shift = gpio % 8; + u32 val; + + if (!port) + return; + + val = readl(port->dr); + + if (value) + val |= 1 << shift; + else + val &= ~(1 << shift); + + writel(val, port->dr); +} + +int gpio_direction_input(unsigned gpio) +{ + struct gpio_port *port = gpio_get_port(gpio); + const int shift = gpio % 8; + u32 val; + + if (!port) + return -EINVAL; + + val = readl(port->ddr); + val &= ~(1 << shift); + writel(val, port->ddr); + + return 0; +} + +int gpio_direction_output(unsigned gpio, int value) +{ + struct gpio_port *port = gpio_get_port(gpio); + const int shift = gpio % 8; + u32 val; + + if (!port) + return -EINVAL; + + gpio_set_value(gpio, value); + + val = readl(port->ddr); + val |= 1 << shift; + writel(val, port->ddr); + + return 0; +} + +int gpio_get_value(unsigned gpio) +{ + struct gpio_port *port = gpio_get_port(gpio); + const int shift = gpio % 8; + u32 val; + + if (!port) + return -EINVAL; + + val = readl(port->dr); + + return val & (1 << shift) ? 1 : 0; +} + diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h new file mode 100644 index 0000000..50bb0eb --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h @@ -0,0 +1,600 @@ +/* ----------------------------------------------------------------------------- + * Cirrus Logic EP93xx register definitions. + * + * Copyright (C) 2009 + * Matthias Kaehlcke + * + * Copyright (C) 2006 + * Dominic Rath + * + * Copyright (C) 2004, 2005 + * Cory T. Tusar, Videon Central, Inc., + * + * Based in large part on linux/include/asm-arm/arch-ep93xx/regmap.h, which is + * + * Copyright (C) 2004 Ray Lehtiniemi + * Copyright (C) 2003 Cirrus Logic, Inc + * Copyright (C) 1999 ARM Limited. + * + * 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __ASSEMBLY__ +#include +#endif + +#define EP93XX_AHB_BASE 0x80000000 +#define EP93XX_APB_BASE 0x80800000 + +/* ----------------------------------------------------------------------------- + * 0x80000000 - 0x8000FFFF: DMA + */ +#define DMA_OFFSET 0x000000 +#define DMA_BASE (EP93XX_AHB_BASE | DMA_OFFSET) + +#ifndef __ASSEMBLY__ +struct dma_channel { + uint32_t control; + uint32_t interrupt; + uint32_t ppalloc; + uint32_t status; + uint32_t reserved0; + uint32_t remain; + uint32_t reserved1[2]; + uint32_t maxcnt0; + uint32_t base0; + uint32_t current0; + uint32_t reserved2; + uint32_t maxcnt1; + uint32_t base1; + uint32_t current1; + uint32_t reserved3; +}; + +struct dma_regs { + struct dma_channel m2p_channel_0; + struct dma_channel m2p_channel_1; + struct dma_channel m2p_channel_2; + struct dma_channel m2p_channel_3; + struct dma_channel m2m_channel_0; + struct dma_channel m2m_channel_1; + struct dma_channel reserved0[2]; + struct dma_channel m2p_channel_5; + struct dma_channel m2p_channel_4; + struct dma_channel m2p_channel_7; + struct dma_channel m2p_channel_6; + struct dma_channel m2p_channel_9; + struct dma_channel m2p_channel_8; + uint32_t channel_arbitration; + uint32_t reserved[15]; + uint32_t global_interrupt; +}; +#endif + +/* ----------------------------------------------------------------------------- + * 0x80010000 - 0x8001FFFF: Ethernet MAC + */ +#define MAC_OFFSET 0x010000 +#define MAC_BASE (EP93XX_AHB_BASE | MAC_OFFSET) + +#ifndef __ASSEMBLY__ +struct mac_queue { + uint32_t badd; + union { /* deal with half-word aligned registers */ + uint32_t blen; + union { + uint16_t filler; + uint16_t curlen; + }; + }; + uint32_t curadd; +}; + +struct mac_regs { + uint32_t rxctl; + uint32_t txctl; + uint32_t testctl; + uint32_t reserved0; + uint32_t miicmd; + uint32_t miidata; + uint32_t miists; + uint32_t reserved1; + uint32_t selfctl; + uint32_t inten; + uint32_t intstsp; + uint32_t intstsc; + uint32_t reserved2[2]; + uint32_t diagad; + uint32_t diagdata; + uint32_t gt; + uint32_t fct; + uint32_t fcf; + uint32_t afp; + union { + struct { + uint32_t indad; + uint32_t indad_upper; + }; + uint32_t hashtbl; + }; + uint32_t reserved3[2]; + uint32_t giintsts; + uint32_t giintmsk; + uint32_t giintrosts; + uint32_t giintfrc; + uint32_t txcollcnt; + uint32_t rxmissnct; + uint32_t rxruntcnt; + uint32_t reserved4; + uint32_t bmctl; + uint32_t bmsts; + uint32_t rxbca; + uint32_t reserved5; + struct mac_queue rxdq; + uint32_t rxdqenq; + struct mac_queue rxstsq; + uint32_t rxstsqenq; + struct mac_queue txdq; + uint32_t txdqenq; + struct mac_queue txstsq; + uint32_t reserved6; + uint32_t rxbufthrshld; + uint32_t txbufthrshld; + uint32_t rxststhrshld; + uint32_t txststhrshld; + uint32_t rxdthrshld; + uint32_t txdthrshld; + uint32_t maxfrmlen; + uint32_t maxhdrlen; +}; +#endif + +#define SELFCTL_RWP (1 << 7) +#define SELFCTL_GPO0 (1 << 5) +#define SELFCTL_PUWE (1 << 4) +#define SELFCTL_PDWE (1 << 3) +#define SELFCTL_MIIL (1 << 2) +#define SELFCTL_RESET (1 << 0) + +#define INTSTS_RWI (1 << 30) +#define INTSTS_RXMI (1 << 29) +#define INTSTS_RXBI (1 << 28) +#define INTSTS_RXSQI (1 << 27) +#define INTSTS_TXLEI (1 << 26) +#define INTSTS_ECIE (1 << 25) +#define INTSTS_TXUHI (1 << 24) +#define INTSTS_MOI (1 << 18) +#define INTSTS_TXCOI (1 << 17) +#define INTSTS_RXROI (1 << 16) +#define INTSTS_MIII (1 << 12) +#define INTSTS_PHYI (1 << 11) +#define INTSTS_TI (1 << 10) +#define INTSTS_AHBE (1 << 8) +#define INTSTS_OTHER (1 << 4) +#define INTSTS_TXSQ (1 << 3) +#define INTSTS_RXSQ (1 << 2) + +#define BMCTL_MT (1 << 13) +#define BMCTL_TT (1 << 12) +#define BMCTL_UNH (1 << 11) +#define BMCTL_TXCHR (1 << 10) +#define BMCTL_TXDIS (1 << 9) +#define BMCTL_TXEN (1 << 8) +#define BMCTL_EH2 (1 << 6) +#define BMCTL_EH1 (1 << 5) +#define BMCTL_EEOB (1 << 4) +#define BMCTL_RXCHR (1 << 2) +#define BMCTL_RXDIS (1 << 1) +#define BMCTL_RXEN (1 << 0) + +#define BMSTS_TXACT (1 << 7) +#define BMSTS_TP (1 << 4) +#define BMSTS_RXACT (1 << 3) +#define BMSTS_QID_MASK 0x07 +#define BMSTS_QID_RXDATA 0x00 +#define BMSTS_QID_TXDATA 0x01 +#define BMSTS_QID_RXSTS 0x02 +#define BMSTS_QID_TXSTS 0x03 +#define BMSTS_QID_RXDESC 0x04 +#define BMSTS_QID_TXDESC 0x05 + +#define AFP_MASK 0x07 +#define AFP_IAPRIMARY 0x00 +#define AFP_IASECONDARY1 0x01 +#define AFP_IASECONDARY2 0x02 +#define AFP_IASECONDARY3 0x03 +#define AFP_TX 0x06 +#define AFP_HASH 0x07 + +#define RXCTL_PAUSEA (1 << 20) +#define RXCTL_RXFCE1 (1 << 19) +#define RXCTL_RXFCE0 (1 << 18) +#define RXCTL_BCRC (1 << 17) +#define RXCTL_SRXON (1 << 16) +#define RXCTL_RCRCA (1 << 13) +#define RXCTL_RA (1 << 12) +#define RXCTL_PA (1 << 11) +#define RXCTL_BA (1 << 10) +#define RXCTL_MA (1 << 9) +#define RXCTL_IAHA (1 << 8) +#define RXCTL_IA3 (1 << 3) +#define RXCTL_IA2 (1 << 2) +#define RXCTL_IA1 (1 << 1) +#define RXCTL_IA0 (1 << 0) + +#define TXCTL_DEFDIS (1 << 7) +#define TXCTL_MBE (1 << 6) +#define TXCTL_ICRC (1 << 5) +#define TXCTL_TPD (1 << 4) +#define TXCTL_OCOLL (1 << 3) +#define TXCTL_SP (1 << 2) +#define TXCTL_PB (1 << 1) +#define TXCTL_STXON (1 << 0) + +#define MIICMD_REGAD_MASK (0x001F) +#define MIICMD_PHYAD_MASK (0x03E0) +#define MIICMD_OPCODE_MASK (0xC000) +#define MIICMD_PHYAD_8950 (0x0000) +#define MIICMD_OPCODE_READ (0x8000) +#define MIICMD_OPCODE_WRITE (0x4000) + +#define MIISTS_BUSY (1 << 0) + +/* ----------------------------------------------------------------------------- + * 0x80020000 - 0x8002FFFF: USB OHCI + */ +#define USB_OFFSET 0x020000 +#define USB_BASE (EP93XX_AHB_BASE | USB_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80030000 - 0x8003FFFF: Raster engine + */ +#if (defined(CONFIG_EP9307) || defined(CONFIG_EP9312) || defined(CONFIG_EP9315)) +#define RASTER_OFFSET 0x030000 +#define RASTER_BASE (EP93XX_AHB_BASE | RASTER_OFFSET) +#endif + +/* ----------------------------------------------------------------------------- + * 0x80040000 - 0x8004FFFF: Graphics accelerator + */ +#if defined(CONFIG_EP9315) +#define GFX_OFFSET 0x040000 +#define GFX_BASE (EP93XX_AHB_BASE | GFX_OFFSET) +#endif + +/* ----------------------------------------------------------------------------- + * 0x80050000 - 0x8005FFFF: Reserved + */ + +/* ----------------------------------------------------------------------------- + * 0x80060000 - 0x8006FFFF: SDRAM controller + */ +#define SDRAM_OFFSET 0x060000 +#define SDRAM_BASE (EP93XX_AHB_BASE | SDRAM_OFFSET) + +#ifndef __ASSEMBLY__ +struct sdram_regs { + uint32_t reserved; + uint32_t glconfig; + uint32_t refrshtimr; + uint32_t bootsts; + uint32_t devcfg0; + uint32_t devcfg1; + uint32_t devcfg2; + uint32_t devcfg3; +}; +#endif + +#define SDRAM_DEVCFG_EXTBUSWIDTH (1 << 2) +#define SDRAM_DEVCFG_BANKCOUNT (1 << 3) +#define SDRAM_DEVCFG_SROMLL (1 << 5) +#define SDRAM_DEVCFG_CASLAT_2 0x00010000 +#define SDRAM_DEVCFG_RASTOCAS_2 0x00200000 + +#define GLCONFIG_INIT (1 << 0) +#define GLCONFIG_MRS (1 << 1) +#define GLCONFIG_SMEMBUSY (1 << 5) +#define GLCONFIG_LCR (1 << 6) +#define GLCONFIG_REARBEN (1 << 7) +#define GLCONFIG_CLKSHUTDOWN (1 << 30) +#define GLCONFIG_CKE (1 << 31) + +/* ----------------------------------------------------------------------------- + * 0x80070000 - 0x8007FFFF: Reserved + */ + +/* ----------------------------------------------------------------------------- + * 0x80080000 - 0x8008FFFF: SRAM controller & PCMCIA + */ +#define SMC_OFFSET 0x080000 +#define SMC_BASE (EP93XX_AHB_BASE | SMC_OFFSET) + +#ifndef __ASSEMBLY__ +struct smc_regs { + uint32_t bcr0; + uint32_t bcr1; + uint32_t bcr2; + uint32_t bcr3; + uint32_t reserved0[2]; + uint32_t bcr6; + uint32_t bcr7; +#if defined(CONFIG_EP9315) + uint32_t pcattribute; + uint32_t pccommon; + uint32_t pcio; + uint32_t reserved1[5]; + uint32_t pcmciactrl; +#endif +}; +#endif + +#define SMC_BCR_IDCY_SHIFT 0 +#define SMC_BCR_WST1_SHIFT 5 +#define SMC_BCR_BLE (1 << 10) +#define SMC_BCR_WST2_SHIFT 11 +#define SMC_BCR_MW_SHIFT 28 + +/* ----------------------------------------------------------------------------- + * 0x80090000 - 0x8009FFFF: Boot ROM + */ + +/* ----------------------------------------------------------------------------- + * 0x800A0000 - 0x800AFFFF: IDE interface + */ + +/* ----------------------------------------------------------------------------- + * 0x800B0000 - 0x800BFFFF: VIC1 + */ + +/* ----------------------------------------------------------------------------- + * 0x800C0000 - 0x800CFFFF: VIC2 + */ + +/* ----------------------------------------------------------------------------- + * 0x800D0000 - 0x800FFFFF: Reserved + */ + +/* ----------------------------------------------------------------------------- + * 0x80800000 - 0x8080FFFF: Reserved + */ + +/* ----------------------------------------------------------------------------- + * 0x80810000 - 0x8081FFFF: Timers + */ +#define TIMER_OFFSET 0x010000 +#define TIMER_BASE (EP93XX_APB_BASE | TIMER_OFFSET) + +#ifndef __ASSEMBLY__ +struct timer { + uint32_t load; + uint32_t value; + uint32_t control; + uint32_t clear; +}; + +struct timer4 { + uint32_t value_low; + uint32_t value_high; +}; + +struct timer_regs { + struct timer timer1; + uint32_t reserved0[4]; + struct timer timer2; + uint32_t reserved1[12]; + struct timer4 timer4; + uint32_t reserved2[6]; + struct timer timer3; +}; +#endif + +/* ----------------------------------------------------------------------------- + * 0x80820000 - 0x8082FFFF: I2S + */ +#define I2S_OFFSET 0x020000 +#define I2S_BASE (EP93XX_APB_BASE | I2S_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80830000 - 0x8083FFFF: Security + */ +#define SECURITY_OFFSET 0x030000 +#define SECURITY_BASE (EP93XX_APB_BASE | SECURITY_OFFSET) + +#define EXTENSIONID (SECURITY_BASE + 0x2714) + +/* ----------------------------------------------------------------------------- + * 0x80840000 - 0x8084FFFF: GPIO + */ +#define GPIO_OFFSET 0x040000 +#define GPIO_BASE (EP93XX_APB_BASE | GPIO_OFFSET) + +#ifndef __ASSEMBLY__ +struct gpio_int { + uint32_t inttype1; + uint32_t inttype2; + uint32_t eoi; + uint32_t inten; + uint32_t intsts; + uint32_t rawintsts; + uint32_t db; +}; + +struct gpio_regs { + uint32_t padr; + uint32_t pbdr; + uint32_t pcdr; + uint32_t pddr; + uint32_t paddr; + uint32_t pbddr; + uint32_t pcddr; + uint32_t pdddr; + uint32_t pedr; + uint32_t peddr; + uint32_t reserved0[2]; + uint32_t pfdr; + uint32_t pfddr; + uint32_t pgdr; + uint32_t pgddr; + uint32_t phdr; + uint32_t phddr; + uint32_t reserved1; + uint32_t finttype1; + uint32_t finttype2; + uint32_t reserved2; + struct gpio_int pfint; + uint32_t reserved3[10]; + struct gpio_int paint; + struct gpio_int pbint; + uint32_t eedrive; +}; +#endif + +/* ----------------------------------------------------------------------------- + * 0x80850000 - 0x8087FFFF: Reserved + */ + +/* ----------------------------------------------------------------------------- + * 0x80880000 - 0x8088FFFF: AAC + */ +#define AAC_OFFSET 0x080000 +#define AAC_BASE (EP93XX_APB_BASE | AAC_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80890000 - 0x8089FFFF: Reserved + */ + +/* ----------------------------------------------------------------------------- + * 0x808A0000 - 0x808AFFFF: SPI + */ +#define SPI_OFFSET 0x0A0000 +#define SPI_BASE (EP93XX_APB_BASE | SPI_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x808B0000 - 0x808BFFFF: IrDA + */ +#define IRDA_OFFSET 0x0B0000 +#define IRDA_BASE (EP93XX_APB_BASE | IRDA_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x808C0000 - 0x808CFFFF: UART1 + */ +#define UART1_OFFSET 0x0C0000 +#define UART1_BASE (EP93XX_APB_BASE | UART1_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x808D0000 - 0x808DFFFF: UART2 + */ +#define UART2_OFFSET 0x0D0000 +#define UART2_BASE (EP93XX_APB_BASE | UART2_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x808E0000 - 0x808EFFFF: UART3 + */ +#define UART3_OFFSET 0x0E0000 +#define UART3_BASE (EP93XX_APB_BASE | UART3_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x808F0000 - 0x808FFFFF: Key Matrix + */ +#define KEY_OFFSET 0x0F0000 +#define KEY_BASE (EP93XX_APB_BASE | KEY_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80900000 - 0x8090FFFF: Touchscreen + */ +#define TOUCH_OFFSET 0x900000 +#define TOUCH_BASE (EP93XX_APB_BASE | TOUCH_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80910000 - 0x8091FFFF: Pulse Width Modulation + */ +#define PWM_OFFSET 0x910000 +#define PWM_BASE (EP93XX_APB_BASE | PWM_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80920000 - 0x8092FFFF: Real time clock + */ +#define RTC_OFFSET 0x920000 +#define RTC_BASE (EP93XX_APB_BASE | RTC_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80930000 - 0x8093FFFF: Syscon + */ +#define SYSCON_OFFSET 0x930000 +#define SYSCON_BASE (EP93XX_APB_BASE | SYSCON_OFFSET) + +#ifndef __ASSEMBLY__ +struct syscon_regs { + uint32_t pwrsts; + uint32_t pwrcnt; + uint32_t halt; + uint32_t stby; + uint32_t reserved0[2]; + uint32_t teoi; + uint32_t stfclr; + uint32_t clkset1; + uint32_t clkset2; + uint32_t reserved1[6]; + uint32_t scratch0; + uint32_t scratch1; + uint32_t reserved2[2]; + uint32_t apbwait; + uint32_t bustmstrarb; + uint32_t bootmodeclr; + uint32_t reserved3[9]; + uint32_t devicecfg; + uint32_t vidclkdiv; + uint32_t mirclkdiv; + uint32_t i2sclkdiv; + uint32_t keytchclkdiv; + uint32_t chipid; + uint32_t syscfg; + uint32_t reserved4[8]; + uint32_t sysswlock; +}; +#else +#define SYSCON_SCRATCH0 (SYSCON_BASE + 0x0040) +#endif + +#define SYSCON_PWRCNT_UART_BAUD (1 << 29) + +#define SYSCON_CLKSET_PLL_X2IPD_SHIFT 0 +#define SYSCON_CLKSET_PLL_X2FBD2_SHIFT 5 +#define SYSCON_CLKSET_PLL_X1FBD1_SHIFT 11 +#define SYSCON_CLKSET_PLL_PS_SHIFT 16 +#define SYSCON_CLKSET1_PCLK_DIV_SHIFT 18 +#define SYSCON_CLKSET1_HCLK_DIV_SHIFT 20 +#define SYSCON_CLKSET1_NBYP1 (1 << 23) +#define SYSCON_CLKSET1_FCLK_DIV_SHIFT 25 + +#define SYSCON_CLKSET2_PLL2_EN (1 << 18) +#define SYSCON_CLKSET2_NBYP2 (1 << 19) +#define SYSCON_CLKSET2_USB_DIV_SHIFT 28 + +#define SYSCON_CHIPID_REV_MASK 0xF0000000 +#define SYSCON_DEVICECFG_SWRST (1 << 31) + +/* ----------------------------------------------------------------------------- + * 0x80930000 - 0x8093FFFF: Watchdog Timer + */ +#define WATCHDOG_OFFSET 0x940000 +#define WATCHDOG_BASE (EP93XX_APB_BASE | WATCHDOG_OFFSET) + +/* ----------------------------------------------------------------------------- + * 0x80950000 - 0x9000FFFF: Reserved + */ + diff --git a/arch/arm/mach-ep93xx/include/mach/gpio.h b/arch/arm/mach-ep93xx/include/mach/gpio.h new file mode 100644 index 0000000..a305f27 --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/gpio.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2010 Matthias Kaehlcke + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASM_ARCH_GPIO_H +#define __ASM_ARCH_GPIO_H + +void gpio_set_value(unsigned gpio, int value); +int gpio_get_value(unsigned gpio); +int gpio_direction_output(unsigned gpio, int value); +int gpio_direction_input(unsigned gpio); + +#endif /* __ASM_ARCH_GPIO_H */ + diff --git a/arch/arm/mach-ep93xx/led.c b/arch/arm/mach-ep93xx/led.c new file mode 100644 index 0000000..6d6b902 --- /dev/null +++ b/arch/arm/mach-ep93xx/led.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#define GREEN_LED_POS 0x01 +#define RED_LED_POS 0x02 + +inline void switch_LED_on(uint32_t bit_pos) +{ + register struct gpio_regs *gpio = (struct gpio_regs *)GPIO_BASE; + + writel(readl(&gpio->pedr) | bit_pos, &gpio->pedr); +} + +inline void switch_LED_off(uint32_t bit_pos) +{ + register struct gpio_regs *gpio = (struct gpio_regs *)GPIO_BASE; + + writel(readl(&gpio->pedr) & ~bit_pos, &gpio->pedr); +} + +void red_LED_on(void) +{ + switch_LED_on(RED_LED_POS); +} + +void red_LED_off(void) +{ + switch_LED_off(RED_LED_POS); +} + +void green_LED_on(void) +{ + switch_LED_on(GREEN_LED_POS); +} + +void green_LED_off(void) +{ + switch_LED_off(GREEN_LED_POS); +} diff --git a/arch/arm/mach-ep93xx/led.h b/arch/arm/mach-ep93xx/led.h new file mode 100644 index 0000000..db9512f --- /dev/null +++ b/arch/arm/mach-ep93xx/led.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +extern void red_LED_on(void); +extern void red_LED_off(void); +extern void green_LED_on(void); +extern void green_LED_off(void); diff --git a/arch/arm/mach-ep93xx/lowlevel_init.S b/arch/arm/mach-ep93xx/lowlevel_init.S new file mode 100644 index 0000000..27c2c90 --- /dev/null +++ b/arch/arm/mach-ep93xx/lowlevel_init.S @@ -0,0 +1,64 @@ +/* + * Low-level initialization for EP93xx + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2006 Dominic Rath + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +.globl board_init_lowlevel +board_init_lowlevel: + /* backup return address */ + ldr r1, =SYSCON_SCRATCH0 + str lr, [r1] + + /* Turn on both LEDs */ + bl red_LED_on + bl green_LED_on + + /* Configure flash wait states before we switch to the PLL */ + bl flash_cfg + + /* Set up PLL */ + bl pll_cfg + + /* Turn off the Green LED and leave the Red LED on */ + bl green_LED_off + + /* Setup SDRAM */ + bl sdram_cfg + + /* Turn on Green LED, Turn off the Red LED */ + bl green_LED_on + bl red_LED_off + + /* switch to async mode */ + mrc p15, 0, r0, c1, c0, 0 + orr r0, r0, #0xc0000000 + mcr p15, 0, r0, c1, c0, 0 + + /* restore return address */ + ldr r1, =SYSCON_SCRATCH0 + ldr lr, [r1] + + mov pc, lr diff --git a/arch/arm/mach-imx/include/mach/imx27-regs.h b/arch/arm/mach-imx/include/mach/imx27-regs.h index 33d67d6..6c31ccd 100644 --- a/arch/arm/mach-imx/include/mach/imx27-regs.h +++ b/arch/arm/mach-imx/include/mach/imx27-regs.h @@ -16,6 +16,7 @@ #define IMX_UART2_BASE (0x0b000 + IMX_IO_BASE) #define IMX_UART3_BASE (0x0c000 + IMX_IO_BASE) #define IMX_UART4_BASE (0x0d000 + IMX_IO_BASE) +#define IMX_I2C1_BASE (0x12000 + IMX_IO_BASE) #define IMX_GPIO_BASE (0x15000 + IMX_IO_BASE) #define IMX_TIM4_BASE (0x19000 + IMX_IO_BASE) #define IMX_TIM5_BASE (0x1a000 + IMX_IO_BASE) diff --git a/arch/arm/mach-imx/speed-imx27.c b/arch/arm/mach-imx/speed-imx27.c index deaca1e..cdcd419 100644 --- a/arch/arm/mach-imx/speed-imx27.c +++ b/arch/arm/mach-imx/speed-imx27.c @@ -154,6 +154,11 @@ return imx_get_perclk3(); } +ulong imx_get_i2cclk(void) +{ + return imx_get_ipgclk(); +} + void imx_dump_clocks(void) { uint32_t cid = CID; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig new file mode 100644 index 0000000..6e70760 --- /dev/null +++ b/arch/x86/Kconfig @@ -0,0 +1,67 @@ +# +# +# +config ARCH_TEXT_BASE + hex + default 0x00007c00 if MACH_X86_GENERIC + +config BOARDINFO + default "Generic x86 bootloader" if MACH_X86_GENERIC + +config BOARD_LINKER_SCRIPT + bool + default n + +config GENERIC_LINKER_SCRIPT + bool + default y + depends on !BOARD_LINKER_SCRIPT + +config X86 + bool + select HAS_KALLSYMS + select HAS_MODULES + select HAVE_CONFIGURABLE_MEMORY_LAYOUT + select HAVE_CONFIGURABLE_TEXT_BASE + default y + +choice + prompt "Select your board" + +config MACH_X86_GENERIC + bool "Generic x86" + select X86_BOOTLOADER + help + Say Y here if you want barebox to be your BIOS based bootloader + +endchoice + +choice + prompt "Bring up type" + + config X86_BIOS_BRINGUP + prompt "16 bit BIOS" + bool + help + Barebox will act as a BIOS based bootloader. This includes + some 16 bit real mode code and some restrictions everyone knows + from BIOS based systems. + + config X86_NATIVE_BRINGUP + bool "native" + help + Barebox will act as a native bootloader. This includes all the + required initialization needed to bring up a piece of hardware. + Note: Not implemented yet + +endchoice + +source arch/x86/boot/Kconfig +source arch/x86/mach-i386/Kconfig + +source common/Kconfig +source commands/Kconfig +source net/Kconfig +source drivers/Kconfig +source fs/Kconfig +source lib/Kconfig diff --git a/arch/x86/Makefile b/arch/x86/Makefile new file mode 100644 index 0000000..2e2cb81 --- /dev/null +++ b/arch/x86/Makefile @@ -0,0 +1,50 @@ +CPPFLAGS += -D__X86__ -fno-strict-aliasing + +board-y := x86_generic +machine-y := i386 + +TEXT_BASE = $(CONFIG_TEXT_BASE) + +CPPFLAGS += -march=i386 -DTEXT_BASE=$(TEXT_BASE) -P + +ifndef CONFIG_MODULES +# Add cleanup flags +CPPFLAGS += -fdata-sections -ffunction-sections +LDFLAGS_uboot += -static --gc-sections +endif + +ifeq ($(incdir-y),) +incdir-y := $(machine-y) +endif +INCDIR := arch-$(incdir-y) + +all: $(KBUILD_IMAGE) + + + + + + +ifneq ($(board-y),) +BOARD := board/$(board-y)/ +else +BOARD := +endif + +ifneq ($(machine-y),) +MACH := arch/x86/mach-$(machine-y)/ +else +MACH := +endif + +common-y += $(BOARD) $(MACH) +common-y += arch/x86/lib/ +common-y += arch/x86/boot/ + +# arch/x86/cpu/ + +lds-$(CONFIG_GENERIC_LINKER_SCRIPT) := arch/x86/lib/barebox.lds +lds-$(CONFIG_BOARD_LINKER_SCRIPT) := $(BOARD)/barebox.lds + +CLEAN_FILES += arch/x86/lib/barebox.lds barebox.map barebox.S + diff --git a/arch/x86/boot/Kconfig b/arch/x86/boot/Kconfig new file mode 100644 index 0000000..cdb82e4 --- /dev/null +++ b/arch/x86/boot/Kconfig @@ -0,0 +1,20 @@ +if X86_BIOS_BRINGUP + +menu "BIOS boot source " + +config X86_HDBOOT + bool "HD boot" + help + Add code to boot from harddisk + +config X86_VESA + bool + default y if X86_GENERIC_HAS_VIDEO + +config X86_VGA + bool + default y if X86_GENERIC_HAS_VIDEO + +endmenu + +endif diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile new file mode 100644 index 0000000..b92b475 --- /dev/null +++ b/arch/x86/boot/Makefile @@ -0,0 +1,13 @@ + +CPPFLAGS += -D__I386__ -fno-strict-aliasing -m32 -g -Os -march=i386 \ + -mregparm=3 -fno-strict-aliasing -fomit-frame-pointer -ffreestanding \ + -fno-toplevel-reorder -fno-unit-at-a-time -fno-stack-protector \ + -mpreferred-stack-boundary=2 + +obj-$(CONFIG_X86_HDBOOT) += boot_main.o boot_hdisk.o + +obj-$(CONFIG_X86_BIOS_BRINGUP) += prepare_uboot.o a20.o bioscall.o regs.o tty.o pmjump.o main_entry.o + +obj-$(CONFIG_X86_VESA) += console_vesa.o +obj-$(CONFIG_X86_VGA) += console_vga.o +obj-$(CONFIG_X86_SERIAL) += console_serial.o diff --git a/arch/x86/boot/a20.c b/arch/x86/boot/a20.c new file mode 100644 index 0000000..4b61d91 --- /dev/null +++ b/arch/x86/boot/a20.c @@ -0,0 +1,170 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007-2008 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * Enable A20 gate (return -1 on failure) + */ + +#include +#include +#include "boot.h" + +#define MAX_8042_LOOPS 100000 +#define MAX_8042_FF 32 + +/* be aware of: */ +THIS_IS_REALMODE_CODE + +static int __bootcode empty_8042(void) +{ + u8 status; + int loops = MAX_8042_LOOPS; + int ffs = MAX_8042_FF; + + while (loops--) { + io_delay(); + + status = inb(0x64); + if (status == 0xff) { + /* FF is a plausible, but very unlikely status */ + if (!--ffs) + return -1; /* Assume no KBC present */ + } + if (status & 1) { + /* Read and discard input data */ + io_delay(); + (void)inb(0x60); + } else if (!(status & 2)) { + /* Buffers empty, finished! */ + return 0; + } + } + + return -1; +} + +/* Returns nonzero if the A20 line is enabled. The memory address + used as a test is the int $0x80 vector, which should be safe. */ + +#define A20_TEST_ADDR (4*0x80) +#define A20_TEST_SHORT 32 +#define A20_TEST_LONG 2097152 /* 2^21 */ + +static int __bootcode a20_test(int loops) +{ + int ok = 0; + int saved, ctr; + + set_fs(0x0000); + set_gs(0xffff); + + saved = ctr = rdfs32(A20_TEST_ADDR); + + while (loops--) { + wrfs32(++ctr, A20_TEST_ADDR); + io_delay(); /* Serialize and make delay constant */ + ok = rdgs32(A20_TEST_ADDR+0x10) ^ ctr; + if (ok) + break; + } + + wrfs32(saved, A20_TEST_ADDR); + return ok; +} + +/* Quick test to see if A20 is already enabled */ +static int __bootcode a20_test_short(void) +{ + return a20_test(A20_TEST_SHORT); +} + +/* Longer test that actually waits for A20 to come on line; this + is useful when dealing with the KBC or other slow external circuitry. */ +static int __bootcode a20_test_long(void) +{ + return a20_test(A20_TEST_LONG); +} + +static void __bootcode enable_a20_bios(void) +{ + struct biosregs ireg; + + initregs(&ireg); + ireg.ax = 0x2401; + intcall(0x15, &ireg, NULL); +} + +static void __bootcode enable_a20_kbc(void) +{ + empty_8042(); + + outb(0xd1, 0x64); /* Command write */ + empty_8042(); + + outb(0xdf, 0x60); /* A20 on */ + empty_8042(); + + outb(0xff, 0x64); /* Null command, but UHCI wants it */ + empty_8042(); +} + +static void __bootcode enable_a20_fast(void) +{ + u8 port_a; + + port_a = inb(0x92); /* Configuration port A */ + port_a |= 0x02; /* Enable A20 */ + port_a &= ~0x01; /* Do not reset machine */ + outb(port_a, 0x92); +} + +/* + * Actual routine to enable A20; return 0 on ok, -1 on failure + */ + +#define A20_ENABLE_LOOPS 255 /* Number of times to try */ + +int __bootcode enable_a20(void) +{ + int loops = A20_ENABLE_LOOPS; + int kbc_err; + + while (loops--) { + /* First, check to see if A20 is already enabled + (legacy free, etc.) */ + if (a20_test_short()) + return 0; + + /* Next, try the BIOS (INT 0x15, AX=0x2401) */ + enable_a20_bios(); + if (a20_test_short()) + return 0; + + /* Try enabling A20 through the keyboard controller */ + kbc_err = empty_8042(); + + if (a20_test_short()) + return 0; /* BIOS worked, but with delayed reaction */ + + if (!kbc_err) { + enable_a20_kbc(); + if (a20_test_long()) + return 0; + } + + /* Finally, try enabling the "fast A20 gate" */ + enable_a20_fast(); + if (a20_test_long()) + return 0; + } + + return -1; +} diff --git a/arch/x86/boot/bioscall.S b/arch/x86/boot/bioscall.S new file mode 100644 index 0000000..84d2577 --- /dev/null +++ b/arch/x86/boot/bioscall.S @@ -0,0 +1,99 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2 or (at your + * option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * "Glove box" for BIOS calls. Avoids the constant problems with BIOSes + * touching registers they shouldn't be. + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + .file "bioscall.S" + .code16 + .section .boot.text.intcall, "ax" + + .globl intcall + .type intcall, @function +intcall: + /* Self-modify the INT instruction. Ugly, but works. */ + cmpb %al, 3f + je 1f + movb %al, 3f + jmp 1f /* Synchronize pipeline */ +1: + /* Save state */ + pushfl + pushw %fs + pushw %gs + pushal + + /* Copy input state to stack frame */ + subw $44, %sp + movw %dx, %si + movw %sp, %di + movw $11, %cx + rep; movsd + + /* Pop full state from the stack */ + popal + popw %gs + popw %fs + popw %es + popw %ds + popfl + + /* Actual INT */ + .byte 0xcd /* INT opcode */ +3: .byte 0 + + /* Push full state to the stack */ + pushfl + pushw %ds + pushw %es + pushw %fs + pushw %gs + pushal + + /* Re-establish C environment invariants */ + cld + movzwl %sp, %esp + movw %cs, %ax + movw %ax, %ds + movw %ax, %es + + /* Copy output state from stack frame */ + movw 68(%esp), %di /* Original %cx == 3rd argument */ + andw %di, %di + jz 4f + movw %sp, %si + movw $11, %cx + rep; movsd +4: addw $44, %sp + + /* Restore state and return */ + popal + popw %gs + popw %fs + popfl + retl + .size intcall, .-intcall + +/* ------------------------------------------------------------------------ */ + .code16 + .section .boot.text.die, "ax" + + .globl die + .type die, @function +die: + hlt + jmp die + .size die, .-die + +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ diff --git a/arch/x86/boot/boot.h b/arch/x86/boot/boot.h new file mode 100644 index 0000000..d98b066 --- /dev/null +++ b/arch/x86/boot/boot.h @@ -0,0 +1,193 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/** + * @file + * @brief Main declarations for the real mode code + */ + +#ifndef BOOT_BOOT_H +#define BOOT_BOOT_H + +#define STACK_SIZE 512 /* Minimum number of bytes for stack */ + +/** Carry flag */ +#define X86_EFLAGS_CF 0x00000001 + +/** PE flag */ +#define X86_CR0_PE 0x00000001 + +#ifndef __ASSEMBLY__ + +#include + +/* we are still in real mode here! */ +#define THIS_IS_REALMODE_CODE asm(".code16gcc"); + +struct biosregs { + union { + struct { + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t _esp; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t _fsgs; + uint32_t _dses; + uint32_t eflags; + }; + struct { + uint16_t di, hdi; + uint16_t si, hsi; + uint16_t bp, hbp; + uint16_t _sp, _hsp; + uint16_t bx, hbx; + uint16_t dx, hdx; + uint16_t cx, hcx; + uint16_t ax, hax; + uint16_t gs, fs; + uint16_t es, ds; + uint16_t flags, hflags; + }; + struct { + uint8_t dil, dih, edi2, edi3; + uint8_t sil, sih, esi2, esi3; + uint8_t bpl, bph, ebp2, ebp3; + uint8_t _spl, _sph, _esp2, _esp3; + uint8_t bl, bh, ebx2, ebx3; + uint8_t dl, dh, edx2, edx3; + uint8_t cl, ch, ecx2, ecx3; + uint8_t al, ah, eax2, eax3; + }; + }; +}; + +/* functions in the realmode part */ +extern int enable_a20(void); +extern void initregs(struct biosregs *regs); +extern void intcall(uint8_t int_no, const struct biosregs *ireg, struct biosregs *oreg); +extern void boot_puts(char*); +extern void __attribute__((noreturn)) die(void); +extern void __attribute__((noreturn)) protected_mode_jump(void); + +struct gdt_ptr { + uint16_t len; + uint32_t ptr; +} __attribute__((packed)); + +/* These functions are used to reference data in other segments. */ + +static inline uint16_t ds(void) +{ + uint16_t seg; + asm("movw %%ds,%0" : "=rm" (seg)); + return seg; +} + +static inline void set_fs(uint16_t seg) +{ + asm volatile("movw %0,%%fs" : : "rm" (seg)); +} + +static inline uint16_t fs(void) +{ + uint16_t seg; + asm volatile("movw %%fs,%0" : "=rm" (seg)); + return seg; +} + +static inline void set_gs(uint16_t seg) +{ + asm volatile("movw %0,%%gs" : : "rm" (seg)); +} + +static inline uint16_t gs(void) +{ + uint16_t seg; + asm volatile("movw %%gs,%0" : "=rm" (seg)); + return seg; +} + +typedef unsigned int addr_t; + +static inline uint8_t rdfs8(addr_t addr) +{ + uint8_t v; + asm volatile("movb %%fs:%1,%0" : "=q" (v) : "m" (*(uint8_t *)addr)); + return v; +} +static inline uint16_t rdfs16(addr_t addr) +{ + uint16_t v; + asm volatile("movw %%fs:%1,%0" : "=r" (v) : "m" (*(uint16_t *)addr)); + return v; +} +static inline uint32_t rdfs32(addr_t addr) +{ + uint32_t v; + asm volatile("movl %%fs:%1,%0" : "=r" (v) : "m" (*(uint32_t *)addr)); + return v; +} + +static inline void wrfs8(uint8_t v, addr_t addr) +{ + asm volatile("movb %1,%%fs:%0" : "+m" (*(uint8_t *)addr) : "qi" (v)); +} +static inline void wrfs16(uint16_t v, addr_t addr) +{ + asm volatile("movw %1,%%fs:%0" : "+m" (*(uint16_t *)addr) : "ri" (v)); +} +static inline void wrfs32(uint32_t v, addr_t addr) +{ + asm volatile("movl %1,%%fs:%0" : "+m" (*(uint32_t *)addr) : "ri" (v)); +} + +static inline uint8_t rdgs8(addr_t addr) +{ + uint8_t v; + asm volatile("movb %%gs:%1,%0" : "=q" (v) : "m" (*(uint8_t *)addr)); + return v; +} +static inline uint16_t rdgs16(addr_t addr) +{ + uint16_t v; + asm volatile("movw %%gs:%1,%0" : "=r" (v) : "m" (*(uint16_t *)addr)); + return v; +} +static inline uint32_t rdgs32(addr_t addr) +{ + uint32_t v; + asm volatile("movl %%gs:%1,%0" : "=r" (v) : "m" (*(uint32_t *)addr)); + return v; +} + +static inline void wrgs8(uint8_t v, addr_t addr) +{ + asm volatile("movb %1,%%gs:%0" : "+m" (*(uint8_t *)addr) : "qi" (v)); +} +static inline void wrgs16(uint16_t v, addr_t addr) +{ + asm volatile("movw %1,%%gs:%0" : "+m" (*(uint16_t *)addr) : "ri" (v)); +} +static inline void wrgs32(uint32_t v, addr_t addr) +{ + asm volatile("movl %1,%%gs:%0" : "+m" (*(uint32_t *)addr) : "ri" (v)); +} + +/** use the built in memset function for the real mode code */ +#define memset(d,c,l) __builtin_memset(d,c,l) + +#endif /* __ASSEMBLY__ */ + +#endif /* BOOT_BOOT_H */ diff --git a/arch/x86/boot/boot_hdisk.S b/arch/x86/boot/boot_hdisk.S new file mode 100644 index 0000000..40388e9 --- /dev/null +++ b/arch/x86/boot/boot_hdisk.S @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This code was inspired by the GRUB2 project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Loading the barebox image from a disk drive in LBA mode + */ + +/** + * @fn void real_start(void) + * @brief A very simple and small loader to fetch all required sectors + * from the boot media. + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + .file "boot_hdisk.S" + .code16 + + /* + * These symbols are generated by the linker, because they need a + * special layout. This layout is needed to be able to setup this + * bootloader by patching the binary when it gets stored into the + * master boot record. + */ + .extern indirect_sector_lba + .extern boot_stack + .extern start_pre_uboot + .extern boot_disk + .section .boot_code, "ax" + + .globl real_start + .type real_start, @function + +real_start: + + xorw %ax, %ax /* set up %ds and %ss as offset from 0 */ + movw %ax, %ds + movw %ax, %ss + + /* set up the REAL stack */ + movw $boot_stack, %sp + + sti /* we're safe again */ + + /* save drive reference first thing! */ + movb %dl, boot_disk + pushw %dx + + movw $notification_string, %si + call output_message + + /* + * This boot code only supports LBA. We fail here, if the BIOS + * does not support LBA for the harddisk + */ + + /* check if LBA is supported */ + movb $0x41, %ah + movw $0x55aa, %bx + int $0x13 + + /* + * %dl may have been clobbered by INT 13, AH=41H. + * This happens, for example, with AST BIOS 1.04. + */ + popw %dx + pushw %dx + + /* stop if no LBA support */ + jc no_lba + cmpw $0xaa55, %bx + jne no_lba + andw $1, %cx + jz no_lba + +lba_mode: + /* + * Load the indirect sector. Its content is ready for use, + * provided by the installer + */ + movw $indirect_sector_lba, %si + movb $0x42, %ah + int $0x13 + jc no_lba /* error? Then die */ + + /* + * Now loop through all valid entries in the indirect sector + */ + movw $indirect_area, %si + +load_loop: + /* + * Stop if this "Disk Address Packet Structure" is invalid + * We call it invalid, if the size member is zero. If it is invalid + * we are optimistic and calling the loaded image + */ + movw (%si), %ax + cmpw $0x0000, %ax + je start_main + + /* + * Load this entry + */ + movb $0x42, %ah + int $0x13 + jc no_lba + + addw (%si), %si /* next entry */ + cmpw $indirect_area + 512, %si + jne load_loop + /* + * fall through to start u-boot. + */ +start_main: + movw $jmp_string, %si + call output_message + jmp start_pre_uboot +/* + * die if there is no LBA support + */ +no_lba: movw $chs_string, %si + call output_message + hlt + +/* + * message: write the string pointed to by %si + * + * WARNING: trashes %si, %ax, and %bx + */ + +/* + * Use BIOS "int 10H Function 0Eh" to write character in teletype mode + * %ah = 0xe %al = character + * %bh = page %bl = foreground color (graphics modes) + */ + +1: + movw $0x0001, %bx + movb $0xe, %ah + int $0x10 /* display this char */ + +output_message: + lodsb + cmpb $0, %al + jne 1b /* if not end of string, next char */ + ret + +/* ---------------------------------------------------------------------- */ + + .section .boot_data + +notification_string: .asciz "UBOOT2 " +chs_string: .asciz "CHS " +jmp_string: .asciz "JMP " + +#endif diff --git a/arch/x86/boot/boot_main.S b/arch/x86/boot/boot_main.S new file mode 100644 index 0000000..f3d248a --- /dev/null +++ b/arch/x86/boot/boot_main.S @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This code was inspired by the GRUB2 project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Common boot sector main routine to be entered by the BIOS + */ +/** + * @fn void _start(void) + * + * @brief Fix segment:offset settings of some buggy BIOSs + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + .file "boot_main.S" + .code16 + + .extern real_start + + .section .boot_start, "ax" + .type _start, @function + + /* + * The BIOS loads this code to address 0x00007c00. + * The code should be called with CS:IP 0:0x7c00 (hopefully). + */ + .globl _start +_start: + cli /* we're not safe here! */ + /* + * It seems there are implementations in the wild which call this + * code with CS:IP 0x07C0:0000 instead. We fix it immediately. + */ + ljmp $0, $real_start + + .size _start, .-_start + +#endif diff --git a/arch/x86/boot/main_entry.c b/arch/x86/boot/main_entry.c new file mode 100644 index 0000000..5f199e9 --- /dev/null +++ b/arch/x86/boot/main_entry.c @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Start of the 32 bit flat mode + */ + +#include + +/* These symbols are generated by the linker */ +extern char __bss_start; +extern char __bss_end; + +extern void start_barebox(void); + +/** + * Called plainly from assembler that switches from real to flat mode + * + * @note The C environment isn't initialized yet + */ +void uboot_entry(void) +{ + /* clear the BSS first */ + memset(&__bss_start, 0x00, &__bss_end - &__bss_start); + start_barebox(); +} diff --git a/arch/x86/boot/pmjump.S b/arch/x86/boot/pmjump.S new file mode 100644 index 0000000..d48e198 --- /dev/null +++ b/arch/x86/boot/pmjump.S @@ -0,0 +1,89 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/** + * @file + * @brief The actual transition into protected mode + * + * Note: This function is running in flat and real mode. Due to some + * other restrictions it must running from an address space below 0x10000 + */ + +/** + * @fn void protected_mode_jump(void) + * @brief Switches the first time from real mode to flat mode + */ +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include +#include "boot.h" + + .file "pmjump.S" + .code16 + .section .boot.text.protected_mode_jump, "ax" + + .globl protected_mode_jump + .type protected_mode_jump, @function + +protected_mode_jump: + jmp 1f /* Short jump to serialize on 386/486 */ +1: + + movw $__BOOT_DS, %cx + movw $__BOOT_TSS, %di + + movl %cr0, %edx + orb $X86_CR0_PE, %dl /* enable protected mode */ + movl %edx, %cr0 + + /* Transition to 32-bit flat mode */ + data32 ljmp $__BOOT_CS, $in_pm32 + +/* ------------------------------------------------------------------------ */ + + .section ".text.in_pm32","ax" + .code32 + + .extern uboot_entry + .extern __bss_end + + .type in_pm32, @function +in_pm32: + # Set up data segments for flat 32-bit mode + movl %ecx, %ds + movl %ecx, %es + movl %ecx, %fs + movl %ecx, %gs + movl %ecx, %ss +/* + * Our flat mode code uses its own stack area behind the bss. With this we + * are still able to return to real mode temporarely + */ + movl $__bss_end + 32768, %esp + + # Set up TR to make Intel VT happy + ltr %di + + # Clear registers to allow for future extensions to the + # 32-bit boot protocol + xorl %ecx, %ecx + xorl %edx, %edx + xorl %ebx, %ebx + xorl %ebp, %ebp + xorl %edi, %edi + + # Set up LDTR to make Intel VT happy + lldt %cx + + jmp uboot_entry + + .size protected_mode_jump, .-protected_mode_jump + +#endif diff --git a/arch/x86/boot/prepare_uboot.c b/arch/x86/boot/prepare_uboot.c new file mode 100644 index 0000000..a68aced --- /dev/null +++ b/arch/x86/boot/prepare_uboot.c @@ -0,0 +1,86 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/* + * Prepare the machine for transition to protected mode. + */ +#include +#include +#include +#include "boot.h" + +/* be aware of: */ +THIS_IS_REALMODE_CODE + +/* + * While we are in flat mode, we can't handle interrupts. But we can't + * switch them off for ever in the PIC, because we need them again while + * entering real mode code again and again.... + */ +static void __bootcode realmode_switch_hook(void) +{ + asm volatile("cli"); + outb(0x80, 0x70); /* Disable NMI */ + io_delay(); +} + +/* + * Reset IGNNE# if asserted in the FPU. + */ +static void __bootcode reset_coprocessor(void) +{ + outb(0, 0xf0); + io_delay(); + outb(0, 0xf1); + io_delay(); +} + +/** + * Setup and register the global descriptor table (GDT) + * + * @note This is for the first time only + */ +static void __bootcode setup_gdt(void) +{ + /* Xen HVM incorrectly stores a pointer to the gdt_ptr, instead + of the gdt_ptr contents. Thus, make it static so it will + stay in memory, at least long enough that we switch to the + proper kernel GDT. */ + static struct gdt_ptr __bootdata gdt_ptr; + + gdt_ptr.len = gdt_size - 1; + gdt_ptr.ptr = (uint32_t)&gdt + (ds() << 4); + + asm volatile("lgdtl %0" : : "m" (gdt_ptr)); +} + +static char a20_message[] __bootdata = "A20 gate not responding, unable to boot...\n"; + +/* + * Actual invocation sequence + */ +void __bootcode start_pre_uboot(void) +{ + /* Hook before leaving real mode, also disables interrupts */ + realmode_switch_hook(); + + /* Enable the A20 gate */ + if (enable_a20()) { + boot_puts(a20_message); + die(); + } + + /* Reset coprocessor (IGNNE#) */ + reset_coprocessor(); + + setup_gdt(); + /* Actual transition to protected mode... */ + protected_mode_jump(); +} diff --git a/arch/x86/boot/regs.c b/arch/x86/boot/regs.c new file mode 100644 index 0000000..ddc5155 --- /dev/null +++ b/arch/x86/boot/regs.c @@ -0,0 +1,34 @@ +/* ----------------------------------------------------------------------- + * + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2 or (at your + * option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/** + * @file + * @brief Simple helper function for initializing a register set. + * + * Note that this sets EFLAGS_CF in the input register set; this + * makes it easier to catch functions which do nothing but don't + * explicitly set CF. + */ + +#include +#include "boot.h" + +/* be aware of: */ +THIS_IS_REALMODE_CODE + +void __bootcode initregs(struct biosregs *reg) +{ + memset(reg, 0, sizeof *reg); + reg->eflags |= X86_EFLAGS_CF; + reg->ds = ds(); + reg->es = ds(); + reg->fs = fs(); + reg->gs = gs(); +} diff --git a/arch/x86/boot/tty.c b/arch/x86/boot/tty.c new file mode 100644 index 0000000..a81671b --- /dev/null +++ b/arch/x86/boot/tty.c @@ -0,0 +1,45 @@ +/* -*- linux-c -*- ------------------------------------------------------- * + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright 2007 rPath, Inc. - All Rights Reserved + * Copyright 2009 Intel Corporation; author H. Peter Anvin + * + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2. + * + * ----------------------------------------------------------------------- */ + +/** + * @file + * @brief Very simple screen I/O for the initialization stage + * + * @todo Probably should add very simple serial I/O? + * @attention This is real mode code! + */ + +#include +#include "boot.h" + +/* be aware of: */ +THIS_IS_REALMODE_CODE + +static void __bootcode putchar(int ch) +{ + struct biosregs ireg; + + if (ch == '\n') + putchar('\r'); /* \n -> \r\n */ + + initregs(&ireg); + ireg.bx = 0x0007; + ireg.cx = 0x0001; + ireg.ah = 0x0e; + ireg.al = ch; + intcall(0x10, &ireg, NULL); +} + +void __bootcode boot_puts(char *str) +{ + while (*str) + putchar(*str++); +} diff --git a/arch/x86/configs/generic_defconfig b/arch/x86/configs/generic_defconfig new file mode 100644 index 0000000..091f696 --- /dev/null +++ b/arch/x86/configs/generic_defconfig @@ -0,0 +1,186 @@ +# +# Automatically generated make config: don't edit +# barebox version: 2009.12.0-x86-trunk +# +CONFIG_ARCH_TEXT_BASE=0x00007c00 +CONFIG_BOARDINFO="Generic x86 bootloader" +# CONFIG_BOARD_LINKER_SCRIPT is not set +CONFIG_GENERIC_LINKER_SCRIPT=y +CONFIG_X86=y +CONFIG_MACH_X86_GENERIC=y +CONFIG_X86_BIOS_BRINGUP=y +# CONFIG_X86_NATIVE_BRINGUP is not set + +# +# BIOS boot source +# +CONFIG_X86_HDBOOT=y + +# +# Board specific settings +# +CONFIG_GREGORIAN_CALENDER=y +CONFIG_HAS_KALLSYMS=y +CONFIG_HAS_MODULES=y +CONFIG_CMD_MEMORY=y +CONFIG_ENV_HANDLING=y + +# +# General Settings +# +CONFIG_LOCALVERSION_AUTO=y + +# +# memory layout +# +CONFIG_HAVE_CONFIGURABLE_TEXT_BASE=y +CONFIG_TEXT_BASE=0x00007c00 +CONFIG_HAVE_CONFIGURABLE_MEMORY_LAYOUT=y +CONFIG_MEMORY_LAYOUT_DEFAULT=y +# CONFIG_MEMORY_LAYOUT_FIXED is not set +CONFIG_STACK_SIZE=0x7000 +CONFIG_MALLOC_SIZE=0x400000 +CONFIG_BROKEN=y +CONFIG_EXPERIMENTAL=y +# CONFIG_MODULES is not set +# CONFIG_KALLSYMS is not set +CONFIG_PROMPT="uboot:" +CONFIG_BAUDRATE=115200 +CONFIG_LONGHELP=y +CONFIG_CBSIZE=1024 +CONFIG_MAXARGS=16 +CONFIG_SHELL_HUSH=y +# CONFIG_SHELL_SIMPLE is not set +CONFIG_GLOB=y +CONFIG_PROMPT_HUSH_PS2="> " +CONFIG_CMDLINE_EDITING=y +CONFIG_AUTO_COMPLETE=y +CONFIG_DYNAMIC_CRC_TABLE=y +CONFIG_ERRNO_MESSAGES=y +CONFIG_TIMESTAMP=y +CONFIG_CONSOLE_FULL=y +CONFIG_CONSOLE_ACTIVATE_FIRST=y +# CONFIG_OF_FLAT_TREE is not set +CONFIG_PARTITION=y +CONFIG_DEFAULT_ENVIRONMENT=y +CONFIG_DEFAULT_ENVIRONMENT_PATH="board/x86_generic/env" + +# +# Debugging +# +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_FLASH_NOISE is not set +# CONFIG_ENABLE_PARTITION_NOISE is not set +# CONFIG_ENABLE_DEVICE_NOISE is not set + +# +# Commands +# + +# +# scripting +# +CONFIG_CMD_EDIT=y +CONFIG_CMD_SLEEP=y +CONFIG_CMD_SAVEENV=y +CONFIG_CMD_LOADENV=y +CONFIG_CMD_EXPORT=y +CONFIG_CMD_PRINTENV=y +CONFIG_CMD_READLINE=y +# CONFIG_CMD_TRUE is not set +# CONFIG_CMD_FALSE is not set + +# +# file commands +# +CONFIG_CMD_LS=y +CONFIG_CMD_RM=y +CONFIG_CMD_CAT=y +CONFIG_CMD_MKDIR=y +CONFIG_CMD_RMDIR=y +CONFIG_CMD_CP=y +CONFIG_CMD_PWD=y +CONFIG_CMD_CD=y +CONFIG_CMD_MOUNT=y +CONFIG_CMD_UMOUNT=y + +# +# console +# +CONFIG_CMD_CLEAR=y +CONFIG_CMD_ECHO=y + +# +# memory +# +# CONFIG_CMD_LOADB is not set +# CONFIG_CMD_LOADY is not set +# CONFIG_CMD_LOADS is not set +CONFIG_CMD_MEMINFO=y +# CONFIG_CMD_CRC is not set +# CONFIG_CMD_MTEST is not set + +# +# flash +# +# CONFIG_CMD_FLASH is not set + +# +# booting +# +# CONFIG_CMD_BOOTM is not set +CONFIG_CMD_LINUX16=y +CONFIG_CMD_RESET=y +CONFIG_CMD_GO=y +CONFIG_CMD_TIMEOUT=y +# CONFIG_CMD_PARTITION is not set +CONFIG_CMD_TEST=y +CONFIG_CMD_VERSION=y +CONFIG_CMD_HELP=y +CONFIG_CMD_DEVINFO=y +# CONFIG_NET is not set + +# +# Drivers +# + +# +# serial drivers +# +CONFIG_DRIVER_SERIAL_NS16550=y + +# +# SPI drivers +# +# CONFIG_SPI is not set +# CONFIG_I2C is not set + +# +# flash drivers +# +# CONFIG_DRIVER_CFI is not set +# CONFIG_DRIVER_CFI_OLD is not set +# CONFIG_NAND is not set +CONFIG_ATA=y + +# +# drive types +# +CONFIG_ATA_DISK=y + +# +# interface types +# +CONFIG_ATA_BIOS=y +# CONFIG_USB is not set +# CONFIG_USB_GADGET is not set +# CONFIG_VIDEO is not set + +# +# Filesystem support +# +# CONFIG_FS_CRAMFS is not set +CONFIG_FS_RAMFS=y +CONFIG_FS_DEVFS=y +CONFIG_CRC32=y +# CONFIG_GENERIC_FIND_NEXT_BIT is not set diff --git a/arch/x86/include/asm/barebox.h b/arch/x86/include/asm/barebox.h new file mode 100644 index 0000000..39bea18 --- /dev/null +++ b/arch/x86/include/asm/barebox.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* nothing special yet */ diff --git a/arch/x86/include/asm/barebox.lds.h b/arch/x86/include/asm/barebox.lds.h new file mode 100644 index 0000000..6cbf15f --- /dev/null +++ b/arch/x86/include/asm/barebox.lds.h @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Adapt linker script content in accordance to Kconfig settings + */ + +#define INITCALLS \ + KEEP(*(.initcall.0)) \ + KEEP(*(.initcall.1)) \ + KEEP(*(.initcall.2)) \ + KEEP(*(.initcall.3)) \ + KEEP(*(.initcall.4)) \ + KEEP(*(.initcall.5)) \ + KEEP(*(.initcall.6)) \ + KEEP(*(.initcall.7)) + +#define BAREBOX_CMDS KEEP(*(SORT_BY_NAME(.barebox_cmd*))) + +#define BAREBOX_SYMS KEEP(*(__usymtab)) + +/** + * Area in the MBR of the barebox basic boot code. This offset must be in + * accordance to the 'indirect_sector_lba' label. + */ +#define PATCH_AREA 400 + +/** + * Offset where to store the boot drive number (BIOS number, 1 byte) + */ +#define PATCH_AREA_BOOT_DEV 16 + +/** + * Offset where to store information about the persistant environment storage + * It points to an LBA number (8 bytes) and defines the first sector of this + * storage on disk. + */ +#define PATCH_AREA_PERS_START 20 + +/** + * Offset where to store information about the persistant environment storage + * It points to a short number (2 bytes) and defines the sector count of this + * storage on disk. + */ +#define PATCH_AREA_PERS_SIZE 28 + +/** + * Offset where to store information about the persistant environment storage + * drive number (BIOS number, 1 byte) + */ +#define PATCH_AREA_PERS_DRIVE 30 + +/** + * Mark the persistant environment as not used + */ +#define PATCH_AREA_PERS_SIZE_UNUSED 0x000 + +/** + * Mark a DAPS as unused/invalid + */ +#define MARK_DAPS_INVALID 0x0000 + +/** + * Offset of the partition table in an MBR + */ +#define OFFSET_OF_PARTITION_TABLE 446 + +/** + * Offset of the signature in an MBR + */ +#define OFFSET_OF_SIGNATURE 510 + +/** + * Area where to store indirect sector to loop through. Keep this value + * in accordance to the 'indirect_area' label. Note: . + * + * @attention These addresses are real mode ones (seg:offset) + */ +#define INDIRECT_AREA 0x7A00 +#define INDIRECT_SEGMENT 0x0000 + +/** + * Area where to load sectors from disk to. They should start after the + * MBR area and must be in accordance to the offset of the '.bootstrapping' + * section in the linker file. + * + * @attention The address must be a multiple of 512. + */ +#define LOAD_AREA 0x7e00 +#define LOAD_SEGMENT 0x0000 + +/** + * Size of one sector. + */ +#define SECTOR_SIZE 512 diff --git a/arch/x86/include/asm/bitops.h b/arch/x86/include/asm/bitops.h new file mode 100644 index 0000000..b43afa3 --- /dev/null +++ b/arch/x86/include/asm/bitops.h @@ -0,0 +1,32 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 bit operations + * + * This file is required only to make all sources happy including + * 'linux/bitops.h' + */ + +#ifndef _ASM_X86_BITOPS_H_ +#define _ASM_X86_BITOPS_H_ + +/* nothing special yet */ + +#endif /* _ASM_X86_BITOPS_H_ */ diff --git a/arch/x86/include/asm/byteorder.h b/arch/x86/include/asm/byteorder.h new file mode 100644 index 0000000..51ce8e1 --- /dev/null +++ b/arch/x86/include/asm/byteorder.h @@ -0,0 +1,30 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 endianess declaration + */ + +#ifndef __ASM_X86_BYTEORDER_H +#define __ASM_X86_BYTEORDER_H + +#include +#include + +#endif diff --git a/arch/x86/include/asm/common.h b/arch/x86/include/asm/common.h new file mode 100644 index 0000000..4862680 --- /dev/null +++ b/arch/x86/include/asm/common.h @@ -0,0 +1,29 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 common declarations + */ + +#ifndef _ASM_X86_COMMON_H_ +#define _ASM_X86_COMMON_H_ + +/* Nothing exiting yet */ + +#endif /* _ASM_X86_COMMON_H_ */ diff --git a/arch/x86/include/asm/elf.h b/arch/x86/include/asm/elf.h new file mode 100644 index 0000000..01342d6 --- /dev/null +++ b/arch/x86/include/asm/elf.h @@ -0,0 +1,30 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 specific elf information + * + */ + +#ifndef _ASM_X86_ELF_H +#define _ASM_X86_ELF_H + +#define ELF_CLASS ELFCLASS32 + +#endif /* _ASM_X86_ELF_H */ diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h new file mode 100644 index 0000000..27ea642 --- /dev/null +++ b/arch/x86/include/asm/io.h @@ -0,0 +1,73 @@ +/* + * Mostly stolen from the linux kernel + */ + +/** + * @file + * @brief x86 IO access functions + */ + +#ifndef __ASM_X86_IO_H +#define __ASM_X86_IO_H + +static inline void outb(unsigned char value, int port) +{ + asm volatile("outb %b0, %w1" : : "a"(value), "Nd"(port)); +} + +static inline void outw(unsigned short value, int port) +{ + asm volatile("outw %w0, %w1" : : "a"(value), "Nd"(port)); +} + +static inline void outl(unsigned long value, int port) +{ + asm volatile("outl %0, %w1" : : "a"(value), "Nd"(port)); +} + +static inline unsigned char inb(int port) +{ + unsigned char value; + asm volatile("inb %w1, %b0" : "=a"(value) : "Nd"(port)); + return value; +} + +static inline unsigned short inw(int port) +{ + unsigned short value; + asm volatile("inw %w1, %w0" : "=a"(value) : "Nd"(port)); + return value; +} + +static inline unsigned long inl(int port) +{ + unsigned long value; + asm volatile("inl %w1, %0" : "=a"(value) : "Nd"(port)); + return value; +} + +#define build_mmio_read(name, size, type, reg, barrier) \ + static inline type name(const volatile void *addr) \ + { type ret; asm volatile("mov" size " %1,%0":reg (ret) \ + :"m" (*(volatile type*)addr) barrier); return ret; } + +build_mmio_read(readb, "b", unsigned char, "=q", :"memory") +build_mmio_read(readw, "w", unsigned short, "=r", :"memory") +build_mmio_read(readl, "l", unsigned int, "=r", :"memory") + +#define build_mmio_write(name, size, type, reg, barrier) \ + static inline void name(type val, volatile void *addr) \ + { asm volatile("mov" size " %0,%1": :reg (val), \ + "m" (*(volatile type*)addr) barrier); } + +build_mmio_write(writeb, "b", unsigned char, "q", :"memory") +build_mmio_write(writew, "w", unsigned short, "r", :"memory") +build_mmio_write(writel, "l", unsigned int, "r", :"memory") + +/* do a tiny io delay */ +static inline void io_delay(void) +{ + inb(0x80); +} + +#endif /* __ASM_X86_IO_H */ diff --git a/arch/x86/include/asm/modes.h b/arch/x86/include/asm/modes.h new file mode 100644 index 0000000..8417ddc --- /dev/null +++ b/arch/x86/include/asm/modes.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Declarations to bring some light in the real/protected/flat mode darkness + */ +#ifndef _ASM_X86_MODES_H +#define _ASM_X86_MODES_H + +#ifndef __ASSEMBLY__ + +#include + +extern uint64_t gdt[]; +extern unsigned gdt_size; + +#endif + +/** to simplify GDT entry generation */ +#define GDT_ENTRY(flags, base, limit) \ + ((((base) & 0xff000000ULL) << (56-24)) | \ + (((flags) & 0x0000f0ffULL) << 40) | \ + (((limit) & 0x000f0000ULL) << (48-16)) | \ + (((base) & 0x00ffffffULL) << 16) | \ + (((limit) & 0x0000ffffULL))) + +/** 32 bit barebox text */ +#define GDT_ENTRY_BOOT_CS 2 +#define __BOOT_CS (GDT_ENTRY_BOOT_CS * 8) + +/** 32 bit barebox data */ +#define GDT_ENTRY_BOOT_DS 3 +#define __BOOT_DS (GDT_ENTRY_BOOT_DS * 8) + +/** 16 bit barebox text */ +#define GDT_ENTRY_REAL_CS 4 +#define __REAL_CS (GDT_ENTRY_REAL_CS * 8) + +/** 16 bit barebox data */ +#define GDT_ENTRY_REAL_DS 5 +#define __REAL_DS (GDT_ENTRY_REAL_DS * 8) + +/** Something to make others happy */ +#define GDT_ENTRY_BOOT_TSS 6 +#define __BOOT_TSS (GDT_ENTRY_BOOT_TSS * 8) + +#endif /* _ASM_X86_MODES_H */ diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h new file mode 100644 index 0000000..168e91d --- /dev/null +++ b/arch/x86/include/asm/module.h @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 module support + * + */ + +#ifndef _ASM_X86_MODULE_H_ +#define _ASM_X86_MODULE_H_ + +/** currently nothing special */ +struct mod_arch_specific +{ + int foo; +}; + +#define Elf_Shdr Elf32_Shdr +#define Elf_Ehdr Elf32_Ehdr + +#endif /* _ASM_X86_MODULE_H_ */ diff --git a/arch/x86/include/asm/posix_types.h b/arch/x86/include/asm/posix_types.h new file mode 100644 index 0000000..a22f301 --- /dev/null +++ b/arch/x86/include/asm/posix_types.h @@ -0,0 +1,49 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 posix types + * + * Minimal set to make all the other header files copied from the Linxu kernel happy + */ + +#ifndef _ASM_X86_POSIX_TYPES_H +#define _ASM_X86_POSIX_TYPES_H + +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_dev_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; +typedef long long __kernel_loff_t; + +#endif /* _ASM_X86_POSIX_TYPES_H */ diff --git a/arch/x86/include/asm/segment.h b/arch/x86/include/asm/segment.h new file mode 100644 index 0000000..cb9b3d0 --- /dev/null +++ b/arch/x86/include/asm/segment.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef _ASM_X86_SEGMENT_H +#define _ASM_X86_SEGMENT_H + +#include + +/** + * @file + * @brief To be able to mark functions running in real _and_ flat mode + */ + +/** + * Section for every program code needed to bring barebox from real mode + * to flat mode + */ +#define __bootcode __section(.boot.text) + +/** + * Section for every data needed to bring barebox from real mode + * to flat mode + */ +#define __bootdata __section(.boot.data) + +#endif /* _ASM_X86_SEGMENT_H */ diff --git a/arch/x86/include/asm/string.h b/arch/x86/include/asm/string.h new file mode 100644 index 0000000..5ca2ff1 --- /dev/null +++ b/arch/x86/include/asm/string.h @@ -0,0 +1,31 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 specific string optimizations + * + * Thanks to the Linux kernel here we can add many micro optimized string + * functions. But currently it makes no sense, to do so. + */ +#ifndef __ASM_X86_STRING_H +#define __ASM_X86_STRING_H + +/* nothing special yet */ + +#endif diff --git a/arch/x86/include/asm/syslib.h b/arch/x86/include/asm/syslib.h new file mode 100644 index 0000000..eebe1a9 --- /dev/null +++ b/arch/x86/include/asm/syslib.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +extern unsigned int x86_uart_read(unsigned long, unsigned char); +extern void x86_uart_write(unsigned int, unsigned long, unsigned char); + +#ifdef CONFIG_X86_BIOS_BRINGUP + +extern int bios_disk_rw_int13_extensions(int, int, void*) __attribute__((regparm(3))); +extern uint16_t bios_get_memsize(void); + +#endif + +#ifdef CONFIG_CMD_LINUX16 +extern void bios_start_linux(unsigned) __attribute__((regparm(1))); +#endif diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h new file mode 100644 index 0000000..17c5fd7 --- /dev/null +++ b/arch/x86/include/asm/types.h @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef __ASM_X86_TYPES_H +#define __ASM_X86_TYPES_H + +#ifndef __ASSEMBLY__ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +typedef __signed__ long long __s64; +typedef unsigned long long __u64; + +typedef unsigned char u8; + +typedef unsigned short u16; + +typedef unsigned int u32; + +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_X86_TYPES_H */ diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile new file mode 100644 index 0000000..b67629f --- /dev/null +++ b/arch/x86/lib/Makefile @@ -0,0 +1,9 @@ +extra-$(CONFIG_GENERIC_LINKER_SCRIPT) += barebox.lds +obj-y += memory.o +obj-y += gdt.o + +# needed, when running via a 16 bit BIOS +obj-$(CONFIG_X86_BIOS_BRINGUP) += memory16.o +obj-$(CONFIG_X86_BIOS_BRINGUP) += traveler.o +obj-$(CONFIG_X86_BIOS_BRINGUP) += bios_disk.o +obj-$(CONFIG_CMD_LINUX16) += linux_start.o diff --git a/arch/x86/lib/barebox.lds.S b/arch/x86/lib/barebox.lds.S new file mode 100644 index 0000000..2917d2f --- /dev/null +++ b/arch/x86/lib/barebox.lds.S @@ -0,0 +1,194 @@ +/* + * 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 + * + */ + +#undef i386 +#include + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +MEMORY +{ + mbr(rwx): ORIGIN = TEXT_BASE, LENGTH = 2 * SECTOR_SIZE + barebox (rwx) : ORIGIN = TEXT_BASE + SECTOR_SIZE, LENGTH = (256 * 1024 * 1024) +} + +SECTIONS +{ +#ifdef CONFIG_X86_HDBOOT + + .ramlayout : { + boot_stack = INDIRECT_AREA; + indirect_area = INDIRECT_AREA; + } + /* describing the main boot sector */ + .bootsector : AT (0) { + *(.boot_start) + + . = 0x00b; + /* + * Maybe later on occupied by a "BIOS parameter block". So, + * keep it free from code. + * - BytesPerSector dw@0x000B + * - SectorsPerCluster db@0x000D + * - ReservedSectors dw@0x000E + * - FatCopies db@0x0010 + * - RootDirEntries dw@0x0011 + * - NumSectors dw@0x0013 + * - MediaType db@0x0015 + * - SectorsPerFAT dw@0x0016 + * - SectorsPerTrack dw@0x0018 + * - NumberOfHeads dw@0x001A + * - HiddenSectors dd@0x001C + * - SectorsBig dd@0x0020 + */ + LONG(0); + + . = 0x024; + *(.boot_code) + *(.boot_data) + + /* + * embed one "Disk Address Packet Structure" into the boot sector + * This DAPS points to the 'indirect' sector to give the boot code + * an idea what and where to load. Its content must be adapted + * to the system it should run on, so, this structure must be + * located at a well known offset. + */ + . = PATCH_AREA; + indirect_sector_lba = .; + SHORT(0x0010); /* size of this structure */ + SHORT(0x0001); /* one sector */ + SHORT(indirect_area); /* where to store: offset */ + SHORT(0x0000); /* where to store: segment */ + /* the following values are filled by the installer */ + LONG(0x00000000); /* LBA start lower */ + LONG(0x00000000); /* LBA start upper */ + + /* boot disk number used by upper layers */ + . = PATCH_AREA + PATCH_AREA_BOOT_DEV; + boot_disk = .; + BYTE(0x00); /* boot disk number (provided by the BIOS) + + /* information about the persistant environment storage */ + . = PATCH_AREA + PATCH_AREA_PERS_START; + pers_env_storage = .; + LONG(0x00000000); /* LBA start lower */ + LONG(0x00000000); /* LBA start upper */ + + . = PATCH_AREA + PATCH_AREA_PERS_SIZE; + pers_env_size = .; + SHORT(PATCH_AREA_PERS_SIZE_UNUSED); /* size of this area in sectors */ + + . = PATCH_AREA + PATCH_AREA_PERS_DRIVE; + pers_env_drive = .; + BYTE(0x00); /* used drive */ + + /* partition table area (fixed location) */ + . = OFFSET_OF_PARTITION_TABLE; + /* create an empty one */ + LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); + LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); + LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); + LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); LONG(0x00000000); + + /* boot sector signature */ + . = OFFSET_OF_SIGNATURE; + BYTE(0x55); + BYTE(0xAA); + /* end of the first sector */ + + /* + * The indirect sector starts here + */ + . = SECTOR_SIZE; + BYTE(MARK_DAPS_INVALID); /* mark the first entry invalid */ + BYTE(0x00); + . = SECTOR_SIZE + 496; + BYTE(MARK_DAPS_INVALID); /* mark the last entry invalid */ + BYTE(0x00); + . = SECTOR_SIZE + 508; + LONG(0x00000000); /* LBA start upper */ + } > mbr + + /* some real mode bootstrapping */ + .bootstrapping : AT ( LOADADDR(.bootsector) + SIZEOF(.bootsector) ) { + *(.boot.head) + *(.boot.text*) + *(.boot.rodata*) + *(.boot.data*) + . = ALIGN(4); + } > barebox +#endif + + /* the main barebox part (32 bit) */ + .text : AT ( LOADADDR(.bootstrapping) + SIZEOF(.bootstrapping) ) { + /* do not align here! It may fails with the LOADADDR! */ + _stext = .; + *(.text_entry*) + *(.text_bare_init*) + *(.text*) + . = ALIGN(4); + *(.rodata*) + . = ALIGN(4); + _etext = .; /* End of text and rodata section */ + } > barebox + + .data : AT ( LOADADDR(.text) + SIZEOF(.text) ) { + *(.data*) + . = ALIGN(4); + } > barebox + + .got : AT ( LOADADDR(.data) + SIZEOF (.data) ) { + *(.got*) + . = ALIGN(4); + } > barebox + + .barebox_cmd : AT ( LOADADDR(.got) + SIZEOF (.got) ) { + __barebox_cmd_start = .; + BAREBOX_CMDS + __barebox_cmd_end = .; + . = ALIGN(4); + } > barebox + + .barebox_initcalls : AT ( LOADADDR(.barebox_cmd) + SIZEOF (.barebox_cmd) ) { + __barebox_initcalls_start = .; + INITCALLS + __barebox_initcalls_end = .; + . = ALIGN(4); + } > barebox + + .__usymtab : AT ( LOADADDR(.barebox_initcalls) + SIZEOF (.barebox_initcalls) ) { + __usymtab_start = .; + BAREBOX_SYMS + __usymtab_end = .; + . = ALIGN(4); + } > barebox + + .bss : { + __bss_start = .; + *(.bss*); + *( COMMON ) + __bss_end = .; + _end = .; + } > barebox +} diff --git a/arch/x86/lib/bios_disk.S b/arch/x86/lib/bios_disk.S new file mode 100644 index 0000000..3acd660 --- /dev/null +++ b/arch/x86/lib/bios_disk.S @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * Mostly stolen from the GRUB2 project + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, 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 + * + */ + +/** + * @file + * @brief Do BIOS calls to load or save data from disks + * + * @note These functions are running in flat and real mode. Due to some + * other restrictions these routines must running from an address + * space below 0x10000 + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +/* + * int bios_disk_rw_int13_extensions (int ah, int drive, void *dap) + * + * Call IBM/MS INT13 Extensions (int 13 %ah=AH) for DRIVE. DAP + * is passed for disk address packet. If an error occurs, return + * non-zero, otherwise zero. + */ + .section .boot.text.bios_disk_rw_int13_extensions, "ax" + .code32 + .globl bios_disk_rw_int13_extensions + .type bios_disk_rw_int13_extensions, @function + + .extern prot_to_real + .extern real_to_prot + +bios_disk_rw_int13_extensions: + pushl %ebp + pushl %esi + + /* compute the address of disk_address_packet */ + movw %cx, %si + xorw %cx, %cx + shrl $4, %ecx /* save the segment to cx */ + + movb %al, %dh + call prot_to_real /* enter real mode right now */ + + .code16 + movb %dh, %ah + movw %cx, %ds + int $0x13 /* do the operation */ + movb %ah, %dl /* save return value */ + /* back to protected mode */ + DATA32 call real_to_prot + + .code32 + movb %dl, %al /* return value in %eax */ + + popl %esi + popl %ebp + + ret + +#endif diff --git a/arch/x86/lib/gdt.c b/arch/x86/lib/gdt.c new file mode 100644 index 0000000..a9c4d0e --- /dev/null +++ b/arch/x86/lib/gdt.c @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Definition of the Global Descriptor Table + */ + +#include +#include +#include + +/** + * The 'Global Descriptor Table' used in barebox + * + * Note: This table must reachable by real and flat mode code + */ +uint64_t gdt[] __attribute__((aligned(16))) __bootdata = { + /* CS: code, read/execute, 4 GB, base 0 */ + [GDT_ENTRY_BOOT_CS] = GDT_ENTRY(0xc09b, 0, 0xfffff), + /* DS: data, read/write, 4 GB, base 0 */ + [GDT_ENTRY_BOOT_DS] = GDT_ENTRY(0xc093, 0, 0xfffff), + /* CS: for real mode calls */ + [GDT_ENTRY_REAL_CS] = GDT_ENTRY(0x009E, 0, 0x0ffff), + /* DS: for real mode calls */ + [GDT_ENTRY_REAL_DS] = GDT_ENTRY(0x0092, 0, 0x0ffff), + /* TSS: 32-bit tss, 104 bytes, base 4096 */ + /* We only have a TSS here to keep Intel VT happy; + we don't actually use it for anything. */ + [GDT_ENTRY_BOOT_TSS] = GDT_ENTRY(0x0089, 4096, 103), +}; + +/** + * Size of the GDT must be known to load it + * + * Note: This varibale must reachable by real and flat mode code + */ +unsigned gdt_size __bootdata = sizeof(gdt); diff --git a/arch/x86/lib/linux_start.S b/arch/x86/lib/linux_start.S new file mode 100644 index 0000000..fac2510 --- /dev/null +++ b/arch/x86/lib/linux_start.S @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * Mostly stolen from the GRUB2 project + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, 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 + * + */ + +/** + * @file + * @brief Start the Linux real mode setup code + * + * Note: These functions are running in flat and real mode. Due to some + * other restrictions these routines must running from an address + * space below 0x10000 + */ + +/* + * void bios_start_linux(unsigned segment) + * + */ +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + .section .boot.text.bios_start_linux, "ax" + .code32 + .globl bios_start_linux + .type bios_start_linux, @function + + .extern prot_to_real + +bios_start_linux: + /* 'prot_to_real' eats our eax content */ + movl %eax, %ebx + addl $0x20, %eax + movw %ax, setup_seg + + call prot_to_real + + .code16 + + cli + /* all segment registers are using the same segment */ + movw %bx, %ss + movw %bx, %ds + movw %bx, %es + movw %bx, %fs + movw %bx, %gs + + /* stack for the setup code (end of heap) */ + movw $0x9000, %sp + + /* do an 'ljmp' and never return */ + .byte 0xea + .word 0 +setup_seg: + .word 0 + + .code32 + +#endif diff --git a/arch/x86/lib/memory.c b/arch/x86/lib/memory.c new file mode 100644 index 0000000..9496d22 --- /dev/null +++ b/arch/x86/lib/memory.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This code was inspired by the GRUB2 project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Memory management + */ + +#include +#include +#include +#include +#include + +/** + * Handling of free memory + * + * Topics: + * - areas used by BIOS code + * - The 0xa0000... 0xfffff hole + * - memory above 0x100000 + */ + +static int x86_mem_malloc_init(void) +{ +#ifdef CONFIG_MEMORY_LAYOUT_DEFAULT + unsigned long memory_size; + + memory_size = bios_get_memsize(); + memory_size <<= 10; /* BIOS reports in kiB */ + + /* + * We do not want to conflict with the kernel. So, we keep the + * area from 0x100000 ... 0xFFFFFF free from usage + */ + if (memory_size >= (15 * 1024 * 1024 + MALLOC_SIZE)) + mem_malloc_init((void*)(16 * 1024 * 1024), + (void*)(16 * 1024 * 1024) + MALLOC_SIZE); + else + return -1; +#else + mem_malloc_init((void *)MALLOC_BASE, + (void *)(MALLOC_BASE + MALLOC_SIZE)); +#endif + return 0; +} + +core_initcall(x86_mem_malloc_init); diff --git a/arch/x86/lib/memory16.S b/arch/x86/lib/memory16.S new file mode 100644 index 0000000..01450fa --- /dev/null +++ b/arch/x86/lib/memory16.S @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This code was inspired by the GRUB2 project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Query the memory layout information from the BIOS + * + * Note: This function is running in flat and real mode. Due to some + * other restrictions it must running from an address space below 0x10000 + */ + +/** + * @fn unsigned short bios_get_memsize(void) + * @brief Does a BIOS call "INT 15H, AH=88H" to get extended memory size + * @return Extended memory size in KB + * + * @note This call is limited to 64 MiB. So, if the system provides more than + * 64 MiB of memory, still 64 MiB are reported. + * + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + + .section .boot.text.bios_get_memsize, "ax" + .code32 + .globl bios_get_memsize + .type bios_get_memsize, @function + + .extern prot_to_real + +bios_get_memsize: + + pushl %ebp + + call prot_to_real /* enter real mode */ + .code16 + + movb $0x88, %ah + int $0x15 + + movw %ax, %dx + + DATA32 call real_to_prot + + .code32 + + movw %dx, %ax + + popl %ebp + ret + + .size bios_get_memsize, .-bios_get_memsize + +#endif diff --git a/arch/x86/lib/traveler.S b/arch/x86/lib/traveler.S new file mode 100644 index 0000000..2b6dc85 --- /dev/null +++ b/arch/x86/lib/traveler.S @@ -0,0 +1,183 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * Mostly stolen from the GRUB2 project + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Switch from the flat mode world into the real mode world and vice versa + * + * Note: These functions are *called* and return in a different operating mode + */ + +/** + * @fn void real_to_prot(void) + * @brief Switch from temp. real mode back to flat mode + * + * Called from a 32 bit flat mode segment and returns into a 16 bit segment + */ + +/** + * @fn void prot_to_real(void) + * @brief Switch from flat mode to real mode + * + * Called from a 16 bit real mode segment and returns into a 32 bit segment + */ + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + +#include + + .file "walkyrie.S" + +/* keep the current flat mode stack pointer, while playing in real mode */ + .section .boot.data.protstack + .code32 +protstack: .long 4 +/* temp. store */ +return_addr: .long 4 + + + .section .boot.text.real_to_prot, "ax" + .code16 + .globl real_to_prot + .type real_to_prot, @function + +/* Note: This routine should not change any other standard registers than eax */ +real_to_prot: + /* + * Always disable the interrupts, when returning to flat mode + */ + cli + + /* turn on protected mode */ + movl %cr0, %eax + orl $0x00000001, %eax + movl %eax, %cr0 + + /* jump to relocation, flush prefetch queue, and reload %cs */ + DATA32 ljmp $__BOOT_CS, $return_to_flatmode + +/* ----------------------------------------------------------------------- */ + .section .boot.text.return_to_flatmode, "ax" + .type return_to_flatmode, @function + .code32 + +return_to_flatmode: + /* reload other segment registers */ + movw $__BOOT_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* move the return address from the real mode to the flat mode stack */ + movl (%esp), %eax + movl %eax, return_addr + + /* setup again the flat mode stack */ + movl protstack, %eax + movl %eax, %esp + movl %eax, %ebp + + movl return_addr, %eax + movl %eax, (%esp) + + /* flag we returned happy here */ + xorl %eax, %eax + ret + + .size real_to_prot, .-real_to_prot + +/* ------------------------------------------------------------------------ */ + +/* Note: This routine should not change any other standard registers than eax */ + + .section .boot.text.prot_to_real, "ax" + .globl prot_to_real + .type prot_to_real, @function + .extern boot_stack + .code32 + +prot_to_real: + /* save the protected mode stack */ + movl %esp, %eax + movl %eax, protstack + + /* prepare the real mode stack */ + /* - address to call to the top of this stack */ + movl (%esp), %eax + movl %eax, boot_stack - 4 + + /* - the stack itself */ + movl $boot_stack - 4, %eax + movl %eax, %esp + movl %eax, %ebp + + /* prepare segments limits to 16 bit */ + movw $__REAL_DS, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + + /* at last, also limit the code segment to 16 bit */ + ljmp $__REAL_CS, $return_to_realmode + +/* ----------------------------------------------------------------------- */ + + .section .boot.text.return_to_realmode, "ax" +return_to_realmode: + .code16 + + /* disable protected mode */ + movl %cr0, %eax + andl $(~0x00000001), %eax + movl %eax, %cr0 + + /* + * all the protected mode settings are still cached in the CPU. + * Refresh them by re-loading all registers in realmode + * Start with the CS, continue with the data registers + */ + ljmp $0, $enter_realmode + +enter_realmode: + xorl %eax, %eax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + /* + * back in plain real mode now, we can play again with the BIOS + */ + + /* restore interrupts */ + sti + + /* return on realmode stack! */ + DATA32 ret + + .size prot_to_real, .-prot_to_real + +#endif diff --git a/arch/x86/mach-i386/Kconfig b/arch/x86/mach-i386/Kconfig new file mode 100644 index 0000000..11f6aa6 --- /dev/null +++ b/arch/x86/mach-i386/Kconfig @@ -0,0 +1,29 @@ + +menu "Board specific settings " + +if X86_BOOTLOADER + +config X86_GENERIC_HAS_ISA + bool "ISA support" + help + Say Y here if the target supports a ISA bus + +config X86_GENERIC_HAS_PCI + bool "PCI support" + select HAS_PCI + help + Say Y here if the target supports a PCI bus + +config X86_GENERIC_HAS_VIDEO + bool "video support" + help + Say Y here if the target supports a video output + +config X86_GENERIC_HAS_USB + bool "USB support" + help + Say Y here if the target supports a USB interface + +endif + +endmenu diff --git a/arch/x86/mach-i386/Makefile b/arch/x86/mach-i386/Makefile new file mode 100644 index 0000000..10712e6 --- /dev/null +++ b/arch/x86/mach-i386/Makefile @@ -0,0 +1,5 @@ +obj-y += generic.o +obj-y += reset.o + +# reference clocksource +obj-y += pit_timer.o diff --git a/arch/x86/mach-i386/generic.c b/arch/x86/mach-i386/generic.c new file mode 100644 index 0000000..edeacc4 --- /dev/null +++ b/arch/x86/mach-i386/generic.c @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief x86 Architecture Initialization routines + */ + +#include + +/** to work with the 8250 UART driver implementation we need this function */ +unsigned int x86_uart_read(unsigned long base, unsigned char reg_idx) +{ + return inb(base + reg_idx); +} + +/** to work with the 8250 UART driver implementation we need this function */ +void x86_uart_write(unsigned int val, unsigned long base, unsigned char reg_idx) +{ + outb(val, base + reg_idx); +} diff --git a/arch/x86/mach-i386/pit_timer.c b/arch/x86/mach-i386/pit_timer.c new file mode 100644 index 0000000..b9f805e --- /dev/null +++ b/arch/x86/mach-i386/pit_timer.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Clocksource based on the 'Programmable Interval Timer' PIT (8253) + * + * This timer should be available on almost all PCs. It also should be run + * at a fixed frequency (1193181.8181 Hz) and not modified to use another + * reload value than 0xFFFF. So, it always counts from 0xffff down to 0. + * + * @note: We can't reprogram the PIT, it will be still used by the BIOS. This + * clocksource driver does not touch any PIT settings. + */ + +#include +#include +#include + +/** base address of the PIT in a standard PC */ +#define PIT 0x40 + +static uint64_t pit_clocksource_read(void) +{ + uint16_t val1, val2; + + outb(0x00, PIT + 3); /* latch counter 0 */ + outb(0x00, 0x80); + + val1 = inb(PIT); + outb(0x00, 0x80); + + val2 = inb(PIT); + val2 <<= 8; + + /* note: its a down counter */ + return 0xFFFFU - (val1 | val2); +} + +static struct clocksource cs = { + .read = pit_clocksource_read, + .mask = 0x0000ffff, + .shift = 10, +}; + +static int clocksource_init (void) +{ + cs.mult = clocksource_hz2mult(1193182, cs.shift); + init_clock(&cs); + + return 0; +} + +core_initcall(clocksource_init); diff --git a/arch/x86/mach-i386/reset.c b/arch/x86/mach-i386/reset.c new file mode 100644 index 0000000..a4eb364 --- /dev/null +++ b/arch/x86/mach-i386/reset.c @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Resetting an x86 CPU + */ + +#include + +void reset_cpu(ulong addr) +{ + /** How to reset the machine? */ + while(1) + ; +} +EXPORT_SYMBOL(reset_cpu); diff --git a/arch/x86/mach-x86.dox b/arch/x86/mach-x86.dox new file mode 100644 index 0000000..fc5b85a --- /dev/null +++ b/arch/x86/mach-x86.dox @@ -0,0 +1,128 @@ +/* This document is intended to provide the developer with information + * how to integrate a new CPU (MACH) into this part of the barebox tree + */ + +/** @page x86_runtime barebox on x86 at runtime + +@section mach_x86_memory_layout barebox's memory layout (BIOS based) + +@a barebox uses the following memory layout at runtime when it still depends +on some kind of BIOS function: + +@verbatim + Addresses +------------------------ + + seg:off flat + +xxxx:xxxx 0x01xxxxxx end of barebox's malloc area + . . +xxxx:xxxx 0x01000000 start of barebox's malloc area + . . + . . (used while loading a Linux kernel of type 'bzImage') + . . +xxxx:xxxx 0x00100000 start of extended memory and malloc area + . . + . . (the big hole) + . . +9000:ffff 0x0009ffff end of expected real mode memory + . . + . . (used while loading a Linux kernel of type 'bzImage') + . . +9000:0000 0x00090000 end of used lower real mode memory + . . + . . + . . Flat mode stack (about 32 kiB) + . . bss + . . Data + . . Text +0000:7e00 0x00007e00 Real and flat mode barebox code +0000:7c00 0x00007c00 MBR initial boot loader code +0000:7a00 0x00007a00 location of the indirect sector (while booting only) + below: real mode stack +@endverbatim + +@note The start address of 0x0000:7c000 is a fixed one, defined by the BIOS. +So, for a BIOS based @a barebox this address can't be changed. + +While the @a barebox code is runnung in flat mode, all interrupts are disabled. +But in the CPU only. All other interrupt settings are still valid. This is +required to be able to call real mode code from inside @a barebox flat mode +code. Thats why not the PIC is touched nor the IDT. + +@todo Add some notes about drive numbers used by the BIOS. They may change +if one change orders in the BIOS setup. Drive orders and numbers may be +different at BIOS runtime and Linux runtime! But these numbers are required +at BIOS runtime for booting and the persistant environment storage. + +@attention Currently there is a 4 GiB limit for the disk sizes! + +@section mach_x86_image_layout barebox's image layout + +@a barebox's binary image layout + +@verbatim + Offset Content + + 0x????? + . 32 bit barebox code + . + . 16 bit bootstrap code, BIOS calling code + 0x00400 + 0x003ff + . indirect sector + 0x00200 + 0x001ff + . MBR + 0x00000 +@endverbatim + +The "indirect sector" is a free area in the image where the sector information +gets stored when this image will be written to a boot media. This information +is required to load all parts of the image from the boot media at runtime. + +The image gets installed in two ways onto the boot media, depending on the +need for a persistant storage. + +@subsection mach_x86_drive_layout_wops barebox's boot media layout without persistant storage + +In this case @a barebox's persistant storage is anywhere: + +@verbatim + Sector Content +--------------------------- + X start of first partition + . + ? end of the binary image + . 32 bit barebox code + 2 16 bit bootstrap code, BIOS calling code + 1 indirect sector + 0 MBR, Partition table, boot code +@endverbatim + +@subsection mach_x86_drive_layout_wps barebox's boot media layout with persistant storage + +@a barebox's persistant storage is part of the boot media (more +space required in front of the first partition) and interferes with the +boot loader image itself: + +@verbatim + Sector Content +--------------------------- + X start of first partition + . + n+? end of the binary image + . 32 bit barebox code + n+2 16 bit bootstrap code, BIOS calling code + n+1 indirect sector + n end of persistant environment storage + . + 1 start of persistant environment storage + 0 MBR, Partition table, boot code +@endverbatim + +The information where the persistant storage is located is also stored into +the MBR at specific locations by @p setupmbr. The @a barebox runtime will use +it to load and store all environment relevant data. + +*/ diff --git a/board/edb93xx/Makefile b/board/edb93xx/Makefile new file mode 100644 index 0000000..e19cd7b --- /dev/null +++ b/board/edb93xx/Makefile @@ -0,0 +1,2 @@ + +obj-y += edb93xx.o flash_cfg.o pll_cfg.o sdram_cfg.o diff --git a/board/edb93xx/config.h b/board/edb93xx/config.h new file mode 100644 index 0000000..6ae9a40e --- /dev/null +++ b/board/edb93xx/config.h @@ -0,0 +1,4 @@ +#ifndef __CONFIG_H +#define __CONFIG_H + +#endif /* __CONFIG_H */ diff --git a/board/edb93xx/early_udelay.h b/board/edb93xx/early_udelay.h new file mode 100644 index 0000000..3b26b3f --- /dev/null +++ b/board/edb93xx/early_udelay.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include + +/* delay execution before timers are initialized */ +static inline void early_udelay(uint32_t usecs) +{ + /* loop takes 4 cycles at 5.0ns (fastest case, running at 200MHz) */ + register uint32_t loops = (usecs * 1000) / 20; + + __asm__ volatile ("1:\n" + "subs %0, %1, #1\n" + "bne 1b":"=r" (loops):"0" (loops)); +} diff --git a/board/edb93xx/edb93xx.c b/board/edb93xx/edb93xx.c new file mode 100644 index 0000000..add88e1 --- /dev/null +++ b/board/edb93xx/edb93xx.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "edb93xx.h" + +/* + * Up to 32MiB NOR type flash, connected to + * CS line 6, data width is 16 bit + */ +static struct device_d cfi_dev = { + .name = "cfi_flash", + .map_base = 0x60000000, + .size = EDB93XX_CFI_FLASH_SIZE, +}; + +static struct memory_platform_data ram_dev_pdata0 = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram0_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK0_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK0_SIZE, + .platform_data = &ram_dev_pdata0, +}; + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) +static struct memory_platform_data ram_dev_pdata1 = { + .name = "ram1", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram1_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK1_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK1_SIZE, + .platform_data = &ram_dev_pdata1, +}; +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) +static struct memory_platform_data ram_dev_pdata2 = { + .name = "ram2", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram2_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK2_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK2_SIZE, + .platform_data = &ram_dev_pdata2, +}; +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) +static struct memory_platform_data ram_dev_pdata3 = { + .name = "ram3", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram3_dev = { + .name = "mem", + .map_base = CONFIG_EP93XX_SDRAM_BANK3_BASE, + .size = CONFIG_EP93XX_SDRAM_BANK3_SIZE, + .platform_data = &ram_dev_pdata3, +}; +#endif + +static struct device_d eth_dev = { + .name = "ep93xx_eth", +}; + +static int ep93xx_devices_init(void) +{ + register_device(&cfi_dev); + + /* + * Create partitions that should be + * not touched by any regular user + */ + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); + devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); + + protect_file("/dev/env0", 1); + + register_device(&sdram0_dev); +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + register_device(&sdram1_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + register_device(&sdram2_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + register_device(&sdram3_dev); +#endif + + armlinux_add_dram(&sdram0_dev); +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + armlinux_add_dram(&sdram1_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + armlinux_add_dram(&sdram2_dev); +#endif +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + armlinux_add_dram(&sdram3_dev); +#endif + + register_device(ð_dev); + + armlinux_set_bootparams((void *)CONFIG_EP93XX_SDRAM_BANK0_BASE + 0x100); + + armlinux_set_architecture(MACH_TYPE); + + return 0; +} + +device_initcall(ep93xx_devices_init); + +static struct device_d edb93xx_serial_device = { + .name = "pl010_serial", + .map_base = UART1_BASE, + .size = 4096, +}; + +static int edb93xx_console_init(void) +{ + struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; + + /* + * set UARTBAUD bit to drive UARTs with 14.7456MHz instead of + * 14.7456/2 MHz + */ + uint32_t value = readl(&syscon->pwrcnt); + value |= SYSCON_PWRCNT_UART_BAUD; + writel(value, &syscon->pwrcnt); + + register_device(&edb93xx_serial_device); + + return 0; +} + +console_initcall(edb93xx_console_init); diff --git a/board/edb93xx/edb93xx.dox b/board/edb93xx/edb93xx.dox new file mode 100644 index 0000000..3964d55 --- /dev/null +++ b/board/edb93xx/edb93xx.dox @@ -0,0 +1,108 @@ +/** @page edb9301 Cirrus Logic EDB9301 + +This boards is based on a Cirrus Logic EP9301 CPU. The board is shipped with: + +- 16MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM on CS3 +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec + +*/ + +/** @page edb9302 Cirrus Logic EDB9302 + +This board is based on a Cirrus Logic EP9302 CPU. The board is shipped with: + +- 16MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM on CS3 +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec + +*/ + +/** @page edb9302a Cirrus Logic EDB9302A + +This board is based on a Cirrus Logic EP9302 CPU. The board is shipped with: + +- 16MiB NOR type Flash Memory +- 32MiB synchronous dynamic RAM on CS0 +- 512kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec + +*/ + +/** @page edb9307 Cirrus Logic EDB9307 + +This board is based on a Cirrus Logic EP9307 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS3 +- 512kiB asynchronous SRAM +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9307a Cirrus Logic EDB9307A + +This board is based on a Cirrus Logic EP9307 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS0 +- 512kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9312 Cirrus Logic EDB9312 + +This board is based on a Cirrus Logic EP9312 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS3 +- 512kiB asynchronous SRAM +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9315 Cirrus Logic EDB9315 + +This board is based on a Cirrus Logic EP9315 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS3 +- 512kiB asynchronous SRAM +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ + +/** @page edb9315a Cirrus Logic EDB9315A + +This board is based on a Cirrus Logic EP9315 CPU. The board is shipped with: + +- 32MiB NOR type Flash Memory +- 64MiB synchronous dynamic RAM on CS0 +- 128kiB serial EEPROM +- MII 10/100 Ethernet PHY +- Stereo audio codec +- Real-Time Clock +- IR receiver + +*/ \ No newline at end of file diff --git a/board/edb93xx/edb93xx.h b/board/edb93xx/edb93xx.h new file mode 100644 index 0000000..5e5c6f5 --- /dev/null +++ b/board/edb93xx/edb93xx.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#if defined(CONFIG_MACH_EDB9301) +#define MACH_TYPE MACH_TYPE_EDB9301 +#elif defined(CONFIG_MACH_EDB9302) +#define MACH_TYPE MACH_TYPE_EDB9302 +#elif defined(CONFIG_MACH_EDB9302A) +#define MACH_TYPE MACH_TYPE_EDB9302A +#elif defined(CONFIG_MACH_EDB9307) +#define MACH_TYPE MACH_TYPE_EDB9307 +#elif defined(CONFIG_MACH_EDB9307A) +#define MACH_TYPE MACH_TYPE_EDB9307A +#elif defined(CONFIG_MACH_EDB9312) +#define MACH_TYPE MACH_TYPE_EDB9312 +#elif defined(CONFIG_MACH_EDB9315) +#define MACH_TYPE MACH_TYPE_EDB9315 +#elif defined(CONFIG_MACH_EDB9315A) +#define MACH_TYPE MACH_TYPE_EDB9315A +#endif + +#if defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) || \ + defined(CONFIG_MACH_EDB9302A) +#define EDB93XX_CFI_FLASH_SIZE (16 * 1024 * 1024) +#elif defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) || \ + defined(CONFIG_MACH_EDB9312) || defined(CONFIG_MACH_EDB9315) || \ + defined(CONFIG_MACH_EDB9315A) +#define EDB93XX_CFI_FLASH_SIZE (32 * 1024 * 1024) +#endif diff --git a/board/edb93xx/env/bin/boot b/board/edb93xx/env/bin/boot new file mode 100644 index 0000000..143f3d0 --- /dev/null +++ b/board/edb93xx/env/bin/boot @@ -0,0 +1,48 @@ +#!/bin/sh + +. /env/config + +if [ x${rootfs_boot_media} = xflash ]; +then + rootfs_img=/dev/nor0.rootfs_${active_cfg} + + if [ x${active_cfg} = x1 ]; + then + rootfs_blkdev=/dev/mtdblock4 + cfg_1_ro="ro" + cfg_2_ro="" + else + rootfs_blkdev=/dev/mtdblock6 + cfg_1_ro="" + cfg_2_ro="ro" + fi + + bootargs_rootfs="root=${rootfs_blkdev} rootfstype=squashfs ro" +elif [ x${rootfs_boot_media} = xnet ]; +then + bootargs_rootfs="root=/dev/nfs nfsroot=${eth0.serverip}:/srv/nfs/${board},v3,nolock,tcp ip=${eth0.ipaddr}" +else + echo "ERROR: \$rootfs_boot_media invalid: ${rootfs_boot_media}" + exit 1 +fi + +if [ x${kernel_boot_media} = xflash ]; +then + kernel_img=/dev/nor0.kernel_${active_cfg} +elif [ x${kernel_boot_media} = xnet ]; +then + cd / + tftp ${board}/kernel.img || exit 1 + kernel_img=/kernel.img +else + echo "ERROR: \$kernel_boot_media invalid: ${kernel_boot_media}" + exit 1 +fi + +source /env/bin/set_nor_parts + +bootargs_mtd="mtdparts=physmap-flash.0:${nor_parts}" + +bootargs="${bootargs_common} ${bootargs_mtd} ${bootargs_rootfs}" + +bootm ${kernel_img} \ No newline at end of file diff --git a/board/edb93xx/env/bin/flash_partition b/board/edb93xx/env/bin/flash_partition new file mode 100644 index 0000000..ded40aa --- /dev/null +++ b/board/edb93xx/env/bin/flash_partition @@ -0,0 +1,22 @@ +#!/bin/sh + +if [ $# != 2 ]; +then + echo "Usage: $0 " + exit 1 +fi + +image=$1 +partition=$2 + +echo "Unlocking ${partition}" +unprotect ${partition} + +echo "Erasing ${partition}" +erase ${partition} + +echo "Flashing ${image} to ${partition}" +cp ${image} ${partition} + +echo "Locking ${partition}" +protect ${partition} diff --git a/board/edb93xx/env/bin/init b/board/edb93xx/env/bin/init new file mode 100644 index 0000000..c6b5aed --- /dev/null +++ b/board/edb93xx/env/bin/init @@ -0,0 +1,19 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + +# add partitions to barebox +. /env/bin/set_nor_parts +addpart /dev/nor0 ${nor_parts} + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + exit +fi + +boot \ No newline at end of file diff --git a/board/edb93xx/env/bin/set_nor_parts b/board/edb93xx/env/bin/set_nor_parts new file mode 100644 index 0000000..38321fa --- /dev/null +++ b/board/edb93xx/env/bin/set_nor_parts @@ -0,0 +1,3 @@ +#!/bin/sh + +nor_parts="256k(barebox)ro,128k(env_boot),128k(env_boot.bak),1664k(kernel_1)${cfg_1_ro},6144k(rootfs_1)${cfg_1_ro},1664k(kernel_2)${cfg_2_ro},6144k(rootfs_2)${cfg_2_ro},128k(cfg_app),128k(cfg_app.bak)" \ No newline at end of file diff --git a/board/edb93xx/env/bin/update_kernel b/board/edb93xx/env/bin/update_kernel new file mode 100644 index 0000000..3e4b9b0 --- /dev/null +++ b/board/edb93xx/env/bin/update_kernel @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +if [ $# != 1 ]; +then + echo "Usage: $0 <1/2>" + exit 1 +fi + +partition=/dev/nor0.kernel_$1 + +cd / +tftp ${board}/kernel.img || exit 1 + +flash_partition kernel.img ${partition} diff --git a/board/edb93xx/env/bin/update_rootfs b/board/edb93xx/env/bin/update_rootfs new file mode 100644 index 0000000..52a3699 --- /dev/null +++ b/board/edb93xx/env/bin/update_rootfs @@ -0,0 +1,16 @@ +#!/bin/sh + +. /env/config + +if [ $# != 1 ]; +then + echo "Usage: $0 <1/2>" + exit 1 +fi + +partition=/dev/nor0.rootfs_$1 + +cd / +tftp ${board}/rootfs.img || exit 1 + +flash_partition rootfs.img ${partition} diff --git a/board/edb93xx/env/config b/board/edb93xx/env/config new file mode 100644 index 0000000..47ab209 --- /dev/null +++ b/board/edb93xx/env/config @@ -0,0 +1,16 @@ +#!/bin/sh + +eth0.ipaddr=192.168.0.50 +eth0.netmask=255.255.0.0 +eth0.serverip=192.168.0.8 +eth0.ethaddr=80:81:82:83:84:85 + +board=edb9301 +autoboot_timeout=3 +active_cfg=1 +bootargs_common="console=ttyAM0,115200" + +# valid media: flash/net +kernel_boot_media=flash +rootfs_boot_media=flash + diff --git a/board/edb93xx/flash_cfg.c b/board/edb93xx/flash_cfg.c new file mode 100644 index 0000000..91a6a4e --- /dev/null +++ b/board/edb93xx/flash_cfg.c @@ -0,0 +1,38 @@ +/* + * Flash setup for Cirrus edb93xx boards + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include + +#define SMC_BCR6_VALUE (2 << SMC_BCR_IDCY_SHIFT | 5 << SMC_BCR_WST1_SHIFT | \ + SMC_BCR_BLE | 2 << SMC_BCR_WST2_SHIFT | \ + 1 << SMC_BCR_MW_SHIFT) + +void flash_cfg(void) +{ + struct smc_regs *smc = (struct smc_regs *)SMC_BASE; + + writel(SMC_BCR6_VALUE, &smc->bcr6); +} diff --git a/board/edb93xx/pll_cfg.c b/board/edb93xx/pll_cfg.c new file mode 100644 index 0000000..a687af0 --- /dev/null +++ b/board/edb93xx/pll_cfg.c @@ -0,0 +1,58 @@ +/* + * PLL setup for Cirrus edb93xx boards + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2006 Dominic Rath + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "pll_cfg.h" +#include "early_udelay.h" + +void pll_cfg(void) +{ + struct syscon_regs *syscon = (struct syscon_regs *)SYSCON_BASE; + + /* setup PLL1 */ + writel(CLKSET1_VAL, &syscon->clkset1); + + /* + * flush the pipeline + * writing to CLKSET1 causes the EP93xx to enter standby for between + * 8 ms to 16 ms, until PLL1 stabilizes + */ + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + asm("nop"); + + /* setup PLL2 */ + writel(CLKSET2_VAL, &syscon->clkset2); + + /* + * the user's guide recommends to wait at least 1 ms for PLL2 to + * stabilize + */ + early_udelay(1000); +} diff --git a/board/edb93xx/pll_cfg.h b/board/edb93xx/pll_cfg.h new file mode 100644 index 0000000..9691339 --- /dev/null +++ b/board/edb93xx/pll_cfg.h @@ -0,0 +1,72 @@ +/* + * PLL register values for Cirrus edb93xx boards + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#if defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) || \ + defined(CONFIG_MACH_EDB9302A) +/* + * fclk_div: 2, nbyp1: 1, hclk_div: 5, pclk_div: 2 + * pll1_x1: 294912000.000000, pll1_x2ip: 36864000.000000, + * pll1_x2: 331776000.000000, pll1_out: 331776000.000000 + */ +#define CLKSET1_VAL (7 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ + 8 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ + 19 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ + 1 << SYSCON_CLKSET1_PCLK_DIV_SHIFT | \ + 3 << SYSCON_CLKSET1_HCLK_DIV_SHIFT | \ + SYSCON_CLKSET1_NBYP1 | \ + 1 << SYSCON_CLKSET1_FCLK_DIV_SHIFT) +#elif defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) ||\ + defined CONFIG_MACH_EDB9312 || defined(CONFIG_MACH_EDB9315) ||\ + defined(CONFIG_MACH_EDB9315A) +/* + * fclk_div: 2, nbyp1: 1, hclk_div: 4, pclk_div: 2 + * pll1_x1: 3096576000.000000, pll1_x2ip: 129024000.000000, + * pll1_x2: 3999744000.000000, pll1_out: 1999872000.000000 + */ +#define CLKSET1_VAL (23 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ + 30 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ + 20 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ + 1 << SYSCON_CLKSET1_PCLK_DIV_SHIFT | \ + 2 << SYSCON_CLKSET1_HCLK_DIV_SHIFT | \ + SYSCON_CLKSET1_NBYP1 | \ + 1 << SYSCON_CLKSET1_FCLK_DIV_SHIFT) +#else +#error "Undefined board" +#endif + +/* + * usb_div: 4, nbyp2: 1, pll2_en: 1 + * pll2_x1: 368640000.000000, pll2_x2ip: 15360000.000000, + * pll2_x2: 384000000.000000, pll2_out: 192000000.000000 + */ +#define CLKSET2_VAL (23 << SYSCON_CLKSET_PLL_X2IPD_SHIFT | \ + 24 << SYSCON_CLKSET_PLL_X2FBD2_SHIFT | \ + 24 << SYSCON_CLKSET_PLL_X1FBD1_SHIFT | \ + 1 << SYSCON_CLKSET_PLL_PS_SHIFT | \ + SYSCON_CLKSET2_PLL2_EN | \ + SYSCON_CLKSET2_NBYP2 | \ + 3 << SYSCON_CLKSET2_USB_DIV_SHIFT) diff --git a/board/edb93xx/sdram_cfg.c b/board/edb93xx/sdram_cfg.c new file mode 100644 index 0000000..9f56f72 --- /dev/null +++ b/board/edb93xx/sdram_cfg.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2006 Dominic Rath + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include +#include "sdram_cfg.h" +#include "early_udelay.h" + +#define PROGRAM_MODE_REG(bank) (*(volatile uint32_t *) \ + (SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank | SDRAM_MODE_REG_VAL)) + +#define PRECHARGE_BANK(bank) (*(volatile uint32_t *) \ + (SDRAM_BASE_ADDR | SDRAM_BANK_SEL_##bank)) + +static void force_precharge(void); +static void setup_refresh_timer(void); +static void program_mode_registers(void); + +void sdram_cfg(void) +{ + struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; + + writel(SDRAM_DEVCFG_VAL, &sdram->SDRAM_DEVCFG_REG); + + /* Issue continous NOP commands */ + writel(GLCONFIG_INIT | GLCONFIG_MRS | GLCONFIG_CKE, &sdram->glconfig); + + early_udelay(200); + + force_precharge(); + + setup_refresh_timer(); + + program_mode_registers(); + + /* Select normal operation mode */ + writel(GLCONFIG_CKE, &sdram->glconfig); +} + +static void force_precharge(void) +{ + /* + * Errata most EP93xx revisions say that PRECHARGE ALL isn't always + * issued. + * + * Do a read from each bank to make sure they're precharged + */ + + PRECHARGE_BANK(0); + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + PRECHARGE_BANK(1); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + PRECHARGE_BANK(2); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + PRECHARGE_BANK(3); +#endif +} + +static void setup_refresh_timer(void) +{ + struct sdram_regs *sdram = (struct sdram_regs *)SDRAM_BASE; + + /* Load refresh timer with 10 to issue refresh every 10 cycles */ + writel(0x0a, &sdram->refrshtimr); + + /* + * Wait at least 80 clock cycles to provide 8 refresh cycles + * to all SDRAMs + */ + early_udelay(1); + + /* + * Program refresh timer with normal value + * We need 8192 refresh cycles every 64ms + * at 15ns (HCLK >= 66MHz) per cycle: + * 64ms / 8192 = 7.8125us + * 7.8125us / 15ns = 520 (0x208) + */ + /* + * TODO: redboot uses 0x1e0 for the slowest possible device + * but i don't understand how this value is calculated + */ + writel(0x208, &sdram->refrshtimr); +} + +static void program_mode_registers(void) +{ + PROGRAM_MODE_REG(0); + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 2) + PROGRAM_MODE_REG(1); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS >= 3) + PROGRAM_MODE_REG(2); +#endif + +#if (CONFIG_EP93XX_SDRAM_NUM_BANKS == 4) + PROGRAM_MODE_REG(3); +#endif +} diff --git a/board/edb93xx/sdram_cfg.h b/board/edb93xx/sdram_cfg.h new file mode 100644 index 0000000..7babee8 --- /dev/null +++ b/board/edb93xx/sdram_cfg.h @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2006 Dominic Rath + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include +#include + +#define SDRAM_BASE_ADDR CONFIG_EP93XX_SDRAM_BANK0_BASE + +#ifdef CONFIG_EP93XX_SDCE0_PHYS_OFFSET +#define SDRAM_DEVCFG_REG devcfg0 +#elif defined(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) +#define SDRAM_DEVCFG_REG devcfg3 +#else +#error "SDRAM bank configuration" +#endif + +#if defined(CONFIG_MACH_EDB9301) || defined(CONFIG_MACH_EDB9302) ||\ + defined(CONFIG_MACH_EDB9302A) +/* + * 1x Samsung K4S561632C-TC/L75 4M x 16bit x 4 banks SDRAM + * + * CLK cycle time min: + * @ CAS latency = 3: 7.5ns + * @ CAS latency = 2: 10ns + * We're running at 66MHz (15ns cycle time) external bus speed (HCLK), + * so it's safe to use CAS latency = 2 + * + * RAS-to-CAS delay min: + * 20ns + * At 15ns cycle time, we use RAS-to-CAS delay = 2 + * + * SROMLL = 1: Swap BA[1:0] with A[13:12], making the SDRAM appear + * as four blocks of 8MB size, instead of eight blocks of 4MB size: + * + * EDB9301/EDB9302: + * + * 0x00000000 - 0x007fffff + * 0x01000000 - 0x017fffff + * 0x04000000 - 0x047fffff + * 0x05000000 - 0x057fffff + * + * + * EDB9302a: + * + * 0xc0000000 - 0xc07fffff + * 0xc1000000 - 0xc17fffff + * 0xc4000000 - 0xc47fffff + * 0xc5000000 - 0xc57fffff + * + * BANKCOUNT = 1: This is a device with four banks + */ + +#define SDRAM_DEVCFG_VAL (SDRAM_DEVCFG_BANKCOUNT | \ + SDRAM_DEVCFG_SROMLL | \ + SDRAM_DEVCFG_CASLAT_2 | \ + SDRAM_DEVCFG_RASTOCAS_2 | \ + SDRAM_DEVCFG_EXTBUSWIDTH) + +/* + * 16 bit ext. bus + * + * A[22:09] is output as SYA[13:0] + * CAS latency: 2 + * Burst type: sequential + * Burst length: 8 (required for 16 bit ext. bus) + * SYA[13:0] = 0x0023 + */ +#define SDRAM_MODE_REG_VAL 0x4600 + +#define SDRAM_BANK_SEL_0 0x00000000 /* A[22:21] = b00 */ +#define SDRAM_BANK_SEL_1 0x00200000 /* A[22:21] = b01 */ +#define SDRAM_BANK_SEL_2 0x00400000 /* A[22:21] = b10 */ +#define SDRAM_BANK_SEL_3 0x00600000 /* A[22:21] = b11 */ + +#elif defined(CONFIG_MACH_EDB9307) || defined(CONFIG_MACH_EDB9307A) ||\ + defined CONFIG_MACH_EDB9312 || defined(CONFIG_MACH_EDB9315) ||\ + defined(CONFIG_MACH_EDB9315A) +/* + * 2x Samsung K4S561632C-TC/L75 4M x 16bit x 4 banks SDRAM + * + * CLK cycle time min: + * @ CAS latency = 3: 7.5ns + * @ CAS latency = 2: 10ns + * We're running at 100MHz (10ns cycle time) external bus speed (HCLK), + * so it's safe to use CAS latency = 2 + * + * RAS-to-CAS delay min: + * 20ns + * At 10ns cycle time, we use RAS-to-CAS delay = 2 + * + * EDB9307, EDB9312, EDB9315: + * + * 0x00000000 - 0x01ffffff + * 0x04000000 - 0x05ffffff + * + * + * EDB9307a, EDB9315a: + * + * 0xc0000000 - 0xc1ffffff + * 0xc4000000 - 0xc5ffffff + */ + +#define SDRAM_DEVCFG_VAL (SDRAM_DEVCFG_BANKCOUNT | \ + SDRAM_DEVCFG_SROMLL | \ + SDRAM_DEVCFG_CASLAT_2 | \ + SDRAM_DEVCFG_RASTOCAS_2) + +/* + * 32 bit ext. bus + * + * A[23:10] is output as SYA[13:0] + * CAS latency: 2 + * Burst type: sequential + * Burst length: 4 + * SYA[13:0] = 0x0022 + */ +#define SDRAM_MODE_REG_VAL 0x8800 + +#define SDRAM_BANK_SEL_0 0x00000000 /* A[23:22] = b00 */ +#define SDRAM_BANK_SEL_1 0x00400000 /* A[23:22] = b01 */ +#define SDRAM_BANK_SEL_2 0x00800000 /* A[23:22] = b10 */ +#define SDRAM_BANK_SEL_3 0x00c00000 /* A[23:22] = b11 */ +#endif diff --git a/board/eukrea_cpuimx27/eukrea_cpuimx27.c b/board/eukrea_cpuimx27/eukrea_cpuimx27.c index 6878044..0908dca 100644 --- a/board/eukrea_cpuimx27/eukrea_cpuimx27.c +++ b/board/eukrea_cpuimx27/eukrea_cpuimx27.c @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -42,6 +43,8 @@ #include #include #include +#include +#include static struct device_d cfi_dev = { .name = "cfi_flash", @@ -140,6 +143,17 @@ }; #endif +static struct i2c_board_info i2c_devices[] = { + { + I2C_BOARD_INFO("lp3972", 0x34), + }, +}; + +static struct device_d i2c_dev = { + .name = "i2c-imx", + .map_base = IMX_I2C1_BASE, +}; + #ifdef CONFIG_MMU static void eukrea_cpuimx27_mmu_init(void) { @@ -187,6 +201,8 @@ PD15_AOUT_FEC_COL, PD16_AIN_FEC_TX_ER, PF23_AIN_FEC_TX_EN, + PD17_PF_I2C_DATA, + PD18_PF_I2C_CLK, #ifdef CONFIG_DRIVER_SERIAL_IMX PE12_PF_UART1_TXD, PE13_PF_UART1_RXD, @@ -198,9 +214,9 @@ eukrea_cpuimx27_mmu_init(); /* configure 16 bit nor flash on cs0 */ - CS0U = 0x0000CC03; - CS0L = 0xa0330D01; - CS0A = 0x00220800; + CS0U = 0x00008F03; + CS0L = 0xA0330D01; + CS0A = 0x002208C0; /* initizalize gpios */ for (i = 0; i < ARRAY_SIZE(mode); i++) @@ -213,6 +229,10 @@ register_device(&nand_dev); register_device(&sdram_dev); + PCCR0 |= PCCR0_I2C1_EN; + i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices)); + register_device(&i2c_dev); + devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); protect_file("/dev/env0", 1); @@ -244,9 +264,9 @@ #endif /* configure 8 bit UART on cs3 */ FMCR &= ~0x2; - CS3U = 0x0000DCF6; - CS3L = 0x444A4541; - CS3A = 0x44443302; + CS3U = 0x0000D603; + CS3L = 0x0D1D0D01; + CS3A = 0x00D20000; #ifdef CONFIG_DRIVER_SERIAL_NS16550 register_device(&quad_uart_serial_device); #endif @@ -257,9 +277,18 @@ static int eukrea_cpuimx27_late_init(void) { + struct i2c_client *client; + u8 reg[1]; + console_flush(); register_device(&fec_dev); + client = lp3972_get_client(); + if (!client) + return -ENODEV; + reg[0] = 0xa0; + i2c_write_reg(client, 0x39, reg, sizeof(reg)); + return 0; } diff --git a/board/eukrea_cpuimx27/lowlevel_init.S b/board/eukrea_cpuimx27/lowlevel_init.S index 4622af8..5295a8a 100644 --- a/board/eukrea_cpuimx27/lowlevel_init.S +++ b/board/eukrea_cpuimx27/lowlevel_init.S @@ -8,10 +8,10 @@ #if defined CONFIG_EUKREA_CPUIMX27_SDRAM_256MB #define ROWS0 ESDCTL_ROW14 -#define CFG0 0x00695729 +#define CFG0 0x0029572D #elif defined CONFIG_EUKREA_CPUIMX27_SDRAM_128MB #define ROWS0 ESDCTL_ROW13 -#define CFG0 0x00395B28 +#define CFG0 0x00095728 #endif #define ESDCTL0_VAL (ESDCTL0_SDE | ROWS0 | ESDCTL0_COL10) diff --git a/board/freescale-mx35-3-stack/3stack.c b/board/freescale-mx35-3-stack/3stack.c index e541966..e6fa0f0 100644 --- a/board/freescale-mx35-3-stack/3stack.c +++ b/board/freescale-mx35-3-stack/3stack.c @@ -60,8 +60,8 @@ }; static struct fec_platform_data fec_info = { - .xcv_type = MII100, - .phy_addr = 0x1F, + .xcv_type = MII100, + .phy_addr = 0x1F, }; static struct device_d fec_dev = { @@ -71,8 +71,8 @@ }; static struct memory_platform_data sdram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, + .name = "ram0", + .flags = DEVFS_RDWR, }; static struct device_d sdram_dev = { @@ -157,7 +157,7 @@ reg = readl(IMX_CCM_BASE + CCM_RCSR); /* some fuses provide us vital information about connected hardware */ if (reg & 0x20000000) - nand_info.width = 2; /* bit */ + nand_info.width = 2; /* 16 bit */ else nand_info.width = 1; /* 8 bit */ @@ -167,17 +167,17 @@ register_device(&nand_dev); register_device(&cfi_dev); - switch ( (reg >> 25) & 0x3) { + switch ((reg >> 25) & 0x3) { case 0x01: /* NAND is the source */ devfs_add_partition("nand0", 0x00000, 0x40000, PARTITION_FIXED, "self_raw"); dev_add_bb_dev("self_raw", "self0"); - devfs_add_partition("nand0", 0x40000, 0x20000, PARTITION_FIXED, "env_raw"); + devfs_add_partition("nand0", 0x40000, 0x80000, PARTITION_FIXED, "env_raw"); dev_add_bb_dev("env_raw", "env0"); break; case 0x00: /* NOR is the source */ devfs_add_partition("nor0", 0x00000, 0x40000, PARTITION_FIXED, "self0"); - devfs_add_partition("nor0", 0x40000, 0x20000, PARTITION_FIXED, "env0"); + devfs_add_partition("nor0", 0x40000, 0x80000, PARTITION_FIXED, "env0"); protect_file("/dev/env0", 1); break; } @@ -332,7 +332,7 @@ /* MPR - priority is M4 > M2 > M3 > M5 > M0 > M1 */ #define MAX_PARAM1 0x00302154 - writel(MAX_PARAM1, IMX_MAX_BASE + 0x0); /* for S0 */ + writel(MAX_PARAM1, IMX_MAX_BASE + 0x000); /* for S0 */ writel(MAX_PARAM1, IMX_MAX_BASE + 0x100); /* for S1 */ writel(MAX_PARAM1, IMX_MAX_BASE + 0x200); /* for S2 */ writel(MAX_PARAM1, IMX_MAX_BASE + 0x300); /* for S3 */ @@ -358,74 +358,84 @@ core_initcall(f3s_core_init); -static int f3s_get_rev(struct i2c_client *client) +static int f3s_get_rev(struct mc13892 *mc13892) { - u8 reg[3]; - int rev; + u32 rev; + int err; - i2c_read_reg(client, 0x7, reg, sizeof(reg)); + err = mc13892_reg_read(mc13892, MC13892_REG_IDENTIFICATION, &rev); + if (err) + return err; - rev = reg[0] << 16 | reg [1] << 8 | reg[2]; - dev_info(&client->dev, "revision: 0x%x\n", rev); + dev_info(&mc13892->client->dev, "revision: 0x%x\n", rev); + if (rev == 0x00ffffff) + return -ENODEV; - /* just return '0' or '1' */ - return !!((rev >> 6) & 0x7); + return ((rev >> 6) & 0x7) ? 20 : 10; } -static void f3s_pmic_init_v2(struct i2c_client *client) +static int f3s_pmic_init_v2(struct mc13892 *mc13892) { - u8 reg[3]; + int err = 0; - i2c_read_reg(client, 0x1e, reg, sizeof(reg)); - reg[2] |= 0x03; - i2c_write_reg(client, 0x1e, reg, sizeof(reg)); + err |= mc13892_set_bits(mc13892, MC13892_REG_SETTING_0, 0x03, 0x03); + err |= mc13892_set_bits(mc13892, MC13892_REG_MODE_0, 0x01, 0x01); + if (err) + dev_err(&mc13892->client->dev, + "Init sequence failed, the system might not be working!\n"); - i2c_read_reg(client, 0x20, reg, sizeof(reg)); - reg[2] |= 0x01; - i2c_write_reg(client, 0x20, reg, sizeof(reg)); + return err; } -static void f3s_pmic_init_all(struct i2c_client *client) +static int f3s_pmic_init_all(struct mc9sdz60 *mc9sdz60) { - u8 reg[1]; + int err = 0; - i2c_read_reg(client, 0x20, reg, sizeof(reg)); - reg[0] |= 0x04; - i2c_write_reg(client, 0x20, reg, sizeof(reg)); + err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_INT_FLAG_1, 0x04, 0x04); + err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_GPIO_2, 0x80, 0x00); mdelay(200); + err |= mc9sdz60_set_bits(mc9sdz60, MC9SDZ60_REG_GPIO_2, 0x80, 0x80); - i2c_read_reg(client, 0x1a, reg, sizeof(reg)); - reg[0] &= 0x7f; - i2c_write_reg(client, 0x1a, reg, sizeof(reg)); + if (err) + dev_err(&mc9sdz60->client->dev, + "Init sequence failed, the system might not be working!\n"); - mdelay(200); - - reg[0] |= 0x80; - i2c_write_reg(client, 0x1a, reg, sizeof(reg)); + return err; } static int f3s_pmic_init(void) { - struct i2c_client *client; + struct mc13892 *mc13892; + struct mc9sdz60 *mc9sdz60; int rev; - client = mc13892_get_client(); - if (!client) - return -ENODEV; - - rev = f3s_get_rev(client); - if (rev) { - printf("i.MX35 CPU board version 2.0\n"); - f3s_pmic_init_v2(client); - } else { - printf("i.MX35 CPU board version 1.0\n"); + mc13892 = mc13892_get(); + if (!mc13892) { + printf("FAILED to get mc13892 handle!\n"); + return 0; } - client = mc9sdz60_get_client(); - if (!client) - return -ENODEV; - f3s_pmic_init_all(client); + rev = f3s_get_rev(mc13892); + switch (rev) { + case 10: + break; + case 20: + f3s_pmic_init_v2(mc13892); + break; + default: + printf("FAILED to identify board revision!\n"); + return 0; + } + printf("i.MX35 PDK CPU board version %d.%d\n", rev / 10, rev % 10); + + mc9sdz60 = mc9sdz60_get(); + if (!mc9sdz60) { + printf("FAILED to get mc9sdz60 handle!\n"); + return 0; + } + + f3s_pmic_init_all(mc9sdz60); return 0; } @@ -442,4 +452,3 @@ imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); } #endif - diff --git a/board/freescale-mx35-3-stack/env/bin/_update b/board/freescale-mx35-3-stack/env/bin/_update index fb7cbe8..4f0839f 100644 --- a/board/freescale-mx35-3-stack/env/bin/_update +++ b/board/freescale-mx35-3-stack/env/bin/_update @@ -20,7 +20,7 @@ ping $eth0.serverip if [ $? -ne 0 ] ; then - echo "update aborted" + echo "Server did not reply! Update aborted." exit 1 fi @@ -28,9 +28,12 @@ echo echo "erasing partition $part" +echo erase $part echo echo "flashing $image to $part" echo tftp $image $part + +protect $part diff --git a/board/freescale-mx35-3-stack/env/bin/boot b/board/freescale-mx35-3-stack/env/bin/boot index dfb59aa..fb2fe61 100644 --- a/board/freescale-mx35-3-stack/env/bin/boot +++ b/board/freescale-mx35-3-stack/env/bin/boot @@ -3,43 +3,53 @@ . /env/config if [ x$1 = xnand ]; then - root=nand - kernel=nand + rootfs_loc=nand + kernel_loc=nand +elif [ x$1 = xnor ]; then + rootfs_loc=nor + kernel_loc=nor +elif [ x$1 = xnet ]; then + rootfs_loc=net + kernel_loc=net fi -if [ x$1 = xnet ]; then - root=net - kernel=net -fi - -if [ x$1 = xnor ]; then - root=nor - kernel=nor -fi if [ x$ip = xdhcp ]; then bootargs="$bootargs ip=dhcp" -else +elif [ x$ip != xno ]; then bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" fi -if [ x$root = xnand ]; then - bootargs="$bootargs root=$rootpart_nand rootfstype=jffs2" -elif [ x$root = xnor ]; then - bootargs="$bootargs root=$rootpart_nor rootfstype=jffs2" + +if [ $rootfs_loc != net ]; then + if [ x$rootfs_loc = xnand ]; then + rootfs_mtdblock=$rootfs_mtdblock_nand + else + rootfs_mtdblock=$rootfs_mtdblock_nor + fi + + + if [ $rootfs_type = ubifs ]; then + bootargs="$bootargs root=ubi0:root ubi.mtd=$rootfs_mtdblock" + else + bootargs="$bootargs root=/dev/mtdblock$rootfs_mtdblock" + fi + + bootargs="$bootargs rootfstype=$rootfs_type" else bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp" fi -bootargs="$bootargs mtdparts=physmap-flash.0:$nor_parts;imx_nand:$nand_parts" -if [ $kernel = net ]; then +bootargs="$bootargs mtdparts=\"physmap-flash.0:$nor_parts;mxc_nand:$nand_parts\"" + +if [ $kernel_loc = net ]; then if [ x$ip = xdhcp ]; then dhcp fi - tftp $uimage uImage || exit 1 + tftp $kernel uImage || exit 1 bootm uImage -elif [ $kernel = nor ]; then +elif [ $kernel_loc = nor ]; then bootm /dev/nor0.kernel else bootm /dev/nand0.kernel.bb diff --git a/board/freescale-mx35-3-stack/env/bin/init b/board/freescale-mx35-3-stack/env/bin/init index cdf0f6b..c982f22 100644 --- a/board/freescale-mx35-3-stack/env/bin/init +++ b/board/freescale-mx35-3-stack/env/bin/init @@ -16,12 +16,13 @@ source /env/bin/hush_hack fi -#if [ -z $eth0.ethaddr ]; then -# while [ -z $eth0.ethaddr ]; do -# readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr -# done -# echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" -#fi +if [ -z $eth0.ethaddr ]; then + while [ -z $eth0.ethaddr ]; do + readline "no MAC address set for eth0. please enter the one found on your board: " eth0.ethaddr + done + echo -a /env/config "eth0.ethaddr=$eth0.ethaddr" + saveenv +fi echo echo -n "Hit any key to stop autoboot: " @@ -29,7 +30,7 @@ if [ $? != 0 ]; then echo echo "type update_kernel nand|nor [] to update kernel into flash" - echo "type update_root nand|nor [] to update rootfs into flash" + echo "type update_rootfs nand|nor [] to update rootfs into flash" echo exit fi diff --git a/board/freescale-mx35-3-stack/env/bin/update_kernel b/board/freescale-mx35-3-stack/env/bin/update_kernel index 05c822d..63ad11a 100644 --- a/board/freescale-mx35-3-stack/env/bin/update_kernel +++ b/board/freescale-mx35-3-stack/env/bin/update_kernel @@ -1,8 +1,8 @@ #!/bin/sh . /env/config +image=$kernel -image=$uimage if [ x$1 = xnand ]; then part=/dev/nand0.kernel.bb elif [ x$1 = xnor ]; then diff --git a/board/freescale-mx35-3-stack/env/bin/update_root b/board/freescale-mx35-3-stack/env/bin/update_root deleted file mode 100644 index eaf36eb..0000000 --- a/board/freescale-mx35-3-stack/env/bin/update_root +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -. /env/config - -image=$uimage -if [ x$1 = xnand ]; then - part=/dev/nand0.root.bb -elif [ x$1 = xnor ]; then - part=/dev/nor0.root -else - echo "usage: $0 nor|nand [imagename]" - exit 1 -fi - -. /env/bin/_update $2 - diff --git a/board/freescale-mx35-3-stack/env/bin/update_rootfs b/board/freescale-mx35-3-stack/env/bin/update_rootfs new file mode 100644 index 0000000..53dd2ca --- /dev/null +++ b/board/freescale-mx35-3-stack/env/bin/update_rootfs @@ -0,0 +1,20 @@ +#!/bin/sh + +. /env/config + +if [ $rootfs_type = ubifs ]; then + image=${rootfs}.ubi +else + image=${rootfs}.$rootfs_type +fi + +if [ x$1 = xnand ]; then + part=/dev/nand0.root.bb +elif [ x$1 = xnor ]; then + part=/dev/nor0.root +else + echo "usage: $0 nor|nand [imagename]" + exit 1 +fi + +. /env/bin/_update $2 diff --git a/board/freescale-mx35-3-stack/env/config b/board/freescale-mx35-3-stack/env/config index 9fcb3dc..51195f7 100644 --- a/board/freescale-mx35-3-stack/env/config +++ b/board/freescale-mx35-3-stack/env/config @@ -1,28 +1,35 @@ #!/bin/sh -# can be either 'net', 'nor' or 'nand'' -kernel=net -root=net - -uimage=uImage-pcm038 -jffs2=root-pcm038.jffs2 - -autoboot_timeout=3 - -nfsroot="/ptx/work/octopus/rsc/svn/oselas/bsp/phytec/phyCORE-i.MX27/OSELAS.BSP-Phytec-phyCORE-i.MX27-trunk/root" -bootargs="console=ttymxc0,115200" - -nor_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" -rootpart_nor="/dev/mtdblock3" - -nand_parts="256k(barebox)ro,128k(bareboxenv),1536k(kernel),-(root)" -rootpart_nand="/dev/mtdblock7" - # use 'dhcp' to do dhcp in barebox and in kernel -ip=dhcp +# use 'no' if you don't want to pass the ip from barebox to the kernel +#ip=dhcp # or set your networking parameters here #eth0.ipaddr=a.b.c.d #eth0.netmask=a.b.c.d #eth0.gateway=a.b.c.d #eth0.serverip=a.b.c.d + +# can be either 'net', 'nor' or 'nand'' +kernel_loc=nand +rootfs_loc=nand + +# can be either 'jffs2', or 'ubifs' +rootfs_type=ubifs + +kernel=uImage-mx35-3-stack +rootfs=root-mx35-3-stack +envimage=u-boot-v2-environment-mx35-3-stack + +autoboot_timeout=3 + +nfsroot="/path/to/nfs/root" +bootargs="console=ttymxc0,115200" + +bootargs="$bootargs video=mx3fb:CTP-CLAA070LC0ACW" + +nor_parts="256k(barebox)ro,512k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nor=3 + +nand_parts="256k(barebox)ro,512k(bareboxenv),2M(kernel),-(root)" +rootfs_mtdblock_nand=7 diff --git a/board/freescale-mx35-3-stack/lowlevel_init.S b/board/freescale-mx35-3-stack/lowlevel_init.S index 4e0a102..1680579 100644 --- a/board/freescale-mx35-3-stack/lowlevel_init.S +++ b/board/freescale-mx35-3-stack/lowlevel_init.S @@ -27,9 +27,9 @@ #include #include "board-mx35_3stack.h" -#define CSD0_BASE_ADDR 0x80000000 -#define ESDCTL_BASE_ADDR 0xB8001000 -#define CSD1_BASE_ADDR 0x90000000 +#define CSD0_BASE_ADDR 0x80000000 +#define ESDCTL_BASE_ADDR 0xB8001000 +#define CSD1_BASE_ADDR 0x90000000 #define writel(val, reg) \ ldr r0, =reg; \ @@ -42,84 +42,84 @@ strb r1, [r0]; /* Assuming 24MHz input clock */ -#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) -#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) -#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) +#define MPCTL_PARAM_399 (IMX_PLL_PD(0) | IMX_PLL_MFD(15) | IMX_PLL_MFI(8) | IMX_PLL_MFN(5)) +#define MPCTL_PARAM_532 ((1 << 31) | IMX_PLL_PD(0) | IMX_PLL_MFD(11) | IMX_PLL_MFI(11) | IMX_PLL_MFN(1)) +#define PPCTL_PARAM_300 (IMX_PLL_PD(0) | IMX_PLL_MFD(3) | IMX_PLL_MFI(6) | IMX_PLL_MFN(1)) .section ".text_bare_init","ax" -ARM_PPMRR: .word 0x40000015 -L2CACHE_PARAM: .word 0x00030024 -CCM_CCMR_W: .word 0x003F4208 -CCM_PDR0_W: .word 0x00001000 -MPCTL_PARAM_399_W: .word MPCTL_PARAM_399 -MPCTL_PARAM_532_W: .word MPCTL_PARAM_532 -PPCTL_PARAM_W: .word PPCTL_PARAM_300 -CCM_BASE_ADDR_W: .word IMX_CCM_BASE +ARM_PPMRR: .word 0x40000015 +L2CACHE_PARAM: .word 0x00030024 +CCM_CCMR_W: .word 0x003F4208 +CCM_PDR0_W: .word 0x00001000 +MPCTL_PARAM_399_W: .word MPCTL_PARAM_399 +MPCTL_PARAM_532_W: .word MPCTL_PARAM_532 +PPCTL_PARAM_W: .word PPCTL_PARAM_300 +CCM_BASE_ADDR_W: .word IMX_CCM_BASE .globl board_init_lowlevel board_init_lowlevel: - mov r10, lr + mov r10, lr - mrc 15, 0, r1, c1, c0, 0 + mrc 15, 0, r1, c1, c0, 0 - mrc 15, 0, r0, c1, c0, 1 - orr r0, r0, #7 - mcr 15, 0, r0, c1, c0, 1 + mrc 15, 0, r0, c1, c0, 1 + orr r0, r0, #7 + mcr 15, 0, r0, c1, c0, 1 - orr r1, r1, #(1<<11) /* Flow prediction (Z) */ - orr r1, r1, #(1<<22) /* unaligned accesses */ - orr r1, r1, #(1<<21) /* Low Int Latency */ + orr r1, r1, #(1 << 11) /* Flow prediction (Z) */ + orr r1, r1, #(1 << 22) /* unaligned accesses */ + orr r1, r1, #(1 << 21) /* Low Int Latency */ - mcr 15, 0, r1, c1, c0, 0 + mcr 15, 0, r1, c1, c0, 0 - mov r0, #0 - mcr 15, 0, r0, c15, c2, 4 + mov r0, #0 + mcr 15, 0, r0, c15, c2, 4 /* - * Branch predicition is now enabled. Flush the BTAC to ensure a valid - * starting point. Don't flush BTAC while it is disabled to avoid + * Branch predicition is now enabled. Flush the BTAC to ensure a valid + * starting point. Don't flush BTAC while it is disabled to avoid * ARM1136 erratum 408023. */ - mov r0, #0 - mcr p15, 0, r0, c7, c5, 6 /* flush entire BTAC */ + mov r0, #0 + mcr p15, 0, r0, c7, c5, 6 /* flush entire BTAC */ - mov r0, #0 - mcr 15, 0, r0, c7, c7, 0 /* invalidate I cache and D cache */ - mcr 15, 0, r0, c8, c7, 0 /* invalidate TLBs */ - mcr 15, 0, r0, c7, c10, 4 /* Drain the write buffer */ + mov r0, #0 + mcr 15, 0, r0, c7, c7, 0 /* invalidate I cache and D cache */ + mcr 15, 0, r0, c8, c7, 0 /* invalidate TLBs */ + mcr 15, 0, r0, c7, c10, 4 /* Drain the write buffer */ /* Also setup the Peripheral Port Remap register inside the core */ - ldr r0, ARM_PPMRR /* start from AIPS 2GB region */ - mcr p15, 0, r0, c15, c2, 4 + ldr r0, ARM_PPMRR /* start from AIPS 2GB region */ + mcr p15, 0, r0, c15, c2, 4 /* * End of ARM1136 init */ - ldr r0, CCM_BASE_ADDR_W + ldr r0, CCM_BASE_ADDR_W - ldr r2, CCM_CCMR_W - str r2, [r0, #CCM_CCMR] + ldr r2, CCM_CCMR_W + str r2, [r0, #CCM_CCMR] - ldr r3, MPCTL_PARAM_532_W /* consumer path*/ + ldr r3, MPCTL_PARAM_532_W /* consumer path*/ - /* Set MPLL , arm clock and ahb clock*/ - str r3, [r0, #CCM_MPCTL] + /* Set MPLL, arm clock and ahb clock */ + str r3, [r0, #CCM_MPCTL] - ldr r1, PPCTL_PARAM_W - str r1, [r0, #CCM_PPCTL] + ldr r1, PPCTL_PARAM_W + str r1, [r0, #CCM_PPCTL] - ldr r1, CCM_PDR0_W - str r1, [r0, #CCM_PDR0] + ldr r1, CCM_PDR0_W + str r1, [r0, #CCM_PDR0] - ldr r1, [r0, #CCM_CGR0] - orr r1, r1, #0x00300000 - str r1, [r0, #CCM_CGR0] + ldr r1, [r0, #CCM_CGR0] + orr r1, r1, #0x00300000 + str r1, [r0, #CCM_CGR0] - ldr r1, [r0, #CCM_CGR1] - orr r1, r1, #0x00000C00 - orr r1, r1, #0x00000003 - str r1, [r0, #CCM_CGR1] + ldr r1, [r0, #CCM_CGR1] + orr r1, r1, #0x00000C00 + orr r1, r1, #0x00000003 + str r1, [r0, #CCM_CGR1] /* Skip SDRAM initialization if we run from RAM */ cmp pc, #0x80000000 @@ -130,33 +130,33 @@ mov pc, r10 1: - ldr r0, =ESDCTL_BASE_ADDR - mov r3, #0x2000 - str r3, [r0, #0x0] - str r3, [r0, #0x8] + ldr r0, =ESDCTL_BASE_ADDR + mov r3, #0x2000 + str r3, [r0, #0x0] + str r3, [r0, #0x8] - /* ip(r12) has used to save lr register in upper calling*/ - mov fp, lr + /* ip(r12) has used to save lr register in upper calling */ + mov fp, lr - mov r5, #0x00 - mov r2, #0x00 - mov r1, #CSD0_BASE_ADDR - bl setup_sdram_bank - cmp r3, #0x0 - orreq r5, r5, #1 - eorne r2, r2, #0x1 - blne setup_sdram_bank + mov r5, #0x00 + mov r2, #0x00 + mov r1, #CSD0_BASE_ADDR + bl setup_sdram_bank + cmp r3, #0x0 + orreq r5, r5, #1 + eorne r2, r2, #0x1 + blne setup_sdram_bank - mov lr, fp + mov lr, fp - ldr r3, =ESDCTL_DELAY_LINE5 - str r3, [r0, #0x30] + ldr r3, =ESDCTL_DELAY_LINE5 + str r3, [r0, #0x30] #ifdef CONFIG_NAND_IMX_BOOT - ldr sp, =TEXT_BASE - 4 /* Setup a temporary stack in SDRAM */ + ldr sp, =TEXT_BASE - 4 /* Setup a temporary stack in SDRAM */ - ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ - ldr r2, =IMX_NFC_BASE + 0x800 /* end of NFC SRAM */ + ldr r0, =IMX_NFC_BASE /* start of NFC SRAM */ + ldr r2, =IMX_NFC_BASE + 0x800 /* end of NFC SRAM */ /* skip NAND boot if not running from NFC space */ cmp pc, r0 @@ -165,119 +165,119 @@ bhs ret /* Move ourselves out of NFC SRAM */ - ldr r1, =TEXT_BASE + ldr r1, =TEXT_BASE copy_loop: - ldmia r0!, {r3-r9} /* copy from source address [r0] */ - stmia r1!, {r3-r9} /* copy to target address [r1] */ - cmp r0, r2 /* until source end addreee [r2] */ + ldmia r0!, {r3-r9} /* copy from source address [r0] */ + stmia r1!, {r3-r9} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop - ldr pc, =1f /* Jump to SDRAM */ + ldr pc, =1f /* Jump to SDRAM */ 1: - bl nand_boot /* Load barebox from NAND Flash */ + bl nand_boot /* Load barebox from NAND Flash */ /* rebase the return address */ ldr r1, =IMX_NFC_BASE - TEXT_BASE - sub r10, r10, r1 /* adjust return address from NFC SRAM */ + sub r10, r10, r1 /* adjust return address from NFC SRAM */ ret: #endif /* CONFIG_NAND_IMX_BOOT */ - mov pc, r10 + mov pc, r10 /* * r0: ESDCTL control base, r1: sdram slot base - * r2: DDR type(0:DDR2, 1:MDDR) r3, r4:working base + * r2: DDR type (0: DDR2, 1: MDDR) r3, r4: working base */ setup_sdram_bank: - mov r3, #0xE /*0xA + 0x4*/ - tst r2, #0x1 - orreq r3, r3, #0x300 /*DDR2*/ - str r3, [r0, #0x10] - bic r3, r3, #0x00A - str r3, [r0, #0x10] - beq 2f + mov r3, #0xE /* 0xA + 0x4 */ + tst r2, #0x1 + orreq r3, r3, #0x300 /* DDR2 */ + str r3, [r0, #0x10] + bic r3, r3, #0x00A + str r3, [r0, #0x10] + beq 2f - mov r3, #0x20000 -1: subs r3, r3, #1 - bne 1b + mov r3, #0x20000 +1: subs r3, r3, #1 + bne 1b -2: tst r2, #0x1 - ldreq r3, =ESDCTL_DDR2_CONFIG - ldrne r3, =ESDCTL_MDDR_CONFIG - cmp r1, #CSD1_BASE_ADDR - strlo r3, [r0, #0x4] - strhs r3, [r0, #0xC] +2: tst r2, #0x1 + ldreq r3, =ESDCTL_DDR2_CONFIG + ldrne r3, =ESDCTL_MDDR_CONFIG + cmp r1, #CSD1_BASE_ADDR + strlo r3, [r0, #0x4] + strhs r3, [r0, #0xC] - ldr r3, =ESDCTL_0x92220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, =ESDCTL_PRECHARGE - strb r3, [r1, r4] + ldr r3, =ESDCTL_0x92220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, =ESDCTL_PRECHARGE + strb r3, [r1, r4] - tst r2, #0x1 - bne skip_set_mode + tst r2, #0x1 + bne skip_set_mode - cmp r1, #CSD1_BASE_ADDR - ldr r3, =ESDCTL_0xB2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, =ESDCTL_DDR2_EMR2 - strb r3, [r1, r4] - ldr r4, =ESDCTL_DDR2_EMR3 - strb r3, [r1, r4] - ldr r4, =ESDCTL_DDR2_EN_DLL - strb r3, [r1, r4] - ldr r4, =ESDCTL_DDR2_RESET_DLL - strb r3, [r1, r4] + cmp r1, #CSD1_BASE_ADDR + ldr r3, =ESDCTL_0xB2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, =ESDCTL_DDR2_EMR2 + strb r3, [r1, r4] + ldr r4, =ESDCTL_DDR2_EMR3 + strb r3, [r1, r4] + ldr r4, =ESDCTL_DDR2_EN_DLL + strb r3, [r1, r4] + ldr r4, =ESDCTL_DDR2_RESET_DLL + strb r3, [r1, r4] - ldr r3, =ESDCTL_0x92220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - ldr r4, =ESDCTL_PRECHARGE - strb r3, [r1, r4] + ldr r3, =ESDCTL_0x92220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + ldr r4, =ESDCTL_PRECHARGE + strb r3, [r1, r4] skip_set_mode: - cmp r1, #CSD1_BASE_ADDR - ldr r3, =ESDCTL_0xA2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - mov r3, #0xDA - strb r3, [r1] - strb r3, [r1] + cmp r1, #CSD1_BASE_ADDR + ldr r3, =ESDCTL_0xA2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + mov r3, #0xDA + strb r3, [r1] + strb r3, [r1] - ldr r3, =ESDCTL_0xB2220000 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] - tst r2, #0x1 - ldreq r4, =ESDCTL_DDR2_MR - ldrne r4, =ESDCTL_MDDR_MR - mov r3, #0xDA - strb r3, [r1, r4] - ldreq r4, =ESDCTL_DDR2_OCD_DEFAULT - streqb r3, [r1, r4] - ldreq r4, =ESDCTL_DDR2_EN_DLL - ldrne r4, =ESDCTL_MDDR_EMR - strb r3, [r1, r4] + ldr r3, =ESDCTL_0xB2220000 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] + tst r2, #0x1 + ldreq r4, =ESDCTL_DDR2_MR + ldrne r4, =ESDCTL_MDDR_MR + mov r3, #0xDA + strb r3, [r1, r4] + ldreq r4, =ESDCTL_DDR2_OCD_DEFAULT + streqb r3, [r1, r4] + ldreq r4, =ESDCTL_DDR2_EN_DLL + ldrne r4, =ESDCTL_MDDR_EMR + strb r3, [r1, r4] - cmp r1, #CSD1_BASE_ADDR - ldr r3, =ESDCTL_0x82228080 - strlo r3, [r0, #0x0] - strhs r3, [r0, #0x8] + cmp r1, #CSD1_BASE_ADDR + ldr r3, =ESDCTL_0x82228080 + strlo r3, [r0, #0x0] + strhs r3, [r0, #0x8] - tst r2, #0x1 - moveq r4, #0x20000 - movne r4, #0x200 -1: subs r4, r4, #1 - bne 1b + tst r2, #0x1 + moveq r4, #0x20000 + movne r4, #0x200 +1: subs r4, r4, #1 + bne 1b - str r3, [r1, #0x100] - ldr r4, [r1, #0x100] - cmp r3, r4 - movne r3, #1 - moveq r3, #0 + str r3, [r1, #0x100] + ldr r4, [r1, #0x100] + cmp r3, r4 + movne r3, #1 + moveq r3, #0 - mov pc, lr + mov pc, lr diff --git a/board/x86_generic/Makefile b/board/x86_generic/Makefile new file mode 100644 index 0000000..248240d --- /dev/null +++ b/board/x86_generic/Makefile @@ -0,0 +1 @@ +obj-y += generic_pc.o diff --git a/board/x86_generic/config.h b/board/x86_generic/config.h new file mode 100644 index 0000000..39bea18 --- /dev/null +++ b/board/x86_generic/config.h @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/* nothing special yet */ diff --git a/board/x86_generic/env/bin/boot b/board/x86_generic/env/bin/boot new file mode 100644 index 0000000..fcfffe3 --- /dev/null +++ b/board/x86_generic/env/bin/boot @@ -0,0 +1,37 @@ +#!/bin/sh + +. /env/config + +if [ x$1 = xdisk ]; then + root=disk + kernel=disk +fi + +if [ x$1 = xnet ]; then + root=net + kernel=net +fi + +if [ x$ip = xdhcp ]; then + bootargs="$bootargs ip=dhcp" +else + bootargs="$bootargs ip=$eth0.ipaddr:$eth0.serverip:$eth0.gateway:$eth0.netmask:::" +fi + +if [ x$root = xdisk ]; then + bootargs="$bootargs root=$rootpart_disk rootfstype=$rootpart_fs rw" +else + bootargs="$bootargs root=/dev/nfs nfsroot=$eth0.serverip:$nfsroot,v3,tcp rw" +fi + +if [ $kernel = net ]; then + if [ x$ip = xdhcp ]; then + dhcp + fi + tftp $uimage uImage || exit 1 + bootm uImage +else + bootargs="BOOT_IMAGE=$kernel_device auto $bootargs" + linux16 $kernel_device +fi + diff --git a/board/x86_generic/env/bin/init b/board/x86_generic/env/bin/init new file mode 100644 index 0000000..2924a44 --- /dev/null +++ b/board/x86_generic/env/bin/init @@ -0,0 +1,15 @@ +#!/bin/sh + +PATH=/env/bin +export PATH + +. /env/config + +echo +echo -n "Hit any key to stop autoboot: " +timeout -a $autoboot_timeout +if [ $? != 0 ]; then + exit +fi + +boot diff --git a/board/x86_generic/env/config b/board/x86_generic/env/config new file mode 100644 index 0000000..dd57aad --- /dev/null +++ b/board/x86_generic/env/config @@ -0,0 +1,31 @@ +# +# basic config +# +# boot source: 'disk' or 'net' +kernel=disk +root=disk + +# data for the NFS case +nfsroot="/path/to/nfs_root" + +# data for the disk case +kernel_device=/dev/biosdisk0.1 +rootpart_disk=/dev/sda1 +rootpart_fs=ext2 + +baudrate=115200 +serial=ttyS0 + +# use UART for console +bootargs="console=$serial,$baudrate" + +autoboot_timeout=3 + +# use 'dhcp' to do dhcp in uboot and in kernel +# ip=dhcp +# or set your networking parameters here +# eth0.ipaddr=192.168.3.11 +# eth0.netmask=255.255.255.0 +# eth0.gateway=a.b.c.d +# eth0.serverip=192.168.3.10 +# eth0.ethaddr=aa.bb.cc.dd.ee.ff diff --git a/board/x86_generic/generic_pc.c b/board/x86_generic/generic_pc.c new file mode 100644 index 0000000..bd93bc1 --- /dev/null +++ b/board/x86_generic/generic_pc.c @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Generic PC support to let barebox acting as a boot loader + */ + +#include +#include +#include +#include +#include +#include + +static struct memory_platform_data ram_pdata = { + .name = "ram0", + .flags = DEVFS_RDWR, +}; + +static struct device_d sdram_dev = { + .name = "mem", + .size = 16 * 1024 * 1024, + .map_base = 0, + .platform_data = &ram_pdata, +}; + +static struct device_d bios_disk_dev = { + .name = "biosdrive", + .size = 1, +}; + +/* + * These datas are from the MBR, created by the linker and filled by the + * setup tool while installing barebox on the disk drive + */ +extern uint64_t pers_env_storage; +extern uint16_t pers_env_size; +extern uint8_t pers_env_drive; + +/** + * Persistant environment "not used" marker. + * Note: Must be in accordance to the value the tool "setup_mbr" writes. + */ +#define PATCH_AREA_PERS_SIZE_UNUSED 0x000 + +static int devices_init(void) +{ + int rc; + + sdram_dev.size = bios_get_memsize(); /* extended memory only */ + sdram_dev.size <<= 10; + + register_device(&sdram_dev); + register_device(&bios_disk_dev); + + if (pers_env_size != PATCH_AREA_PERS_SIZE_UNUSED) { + rc = devfs_add_partition("disk0", /* FIXME */ + pers_env_storage * 512, + (unsigned)pers_env_size * 512, + DEVFS_PARTITION_FIXED, "env0"); + printf("Partition: %d\n", rc); + } else + printf("No persistant storage defined\n"); + + return 0; +} +device_initcall(devices_init); + +#ifdef CONFIG_DRIVER_SERIAL_NS16550 + +static struct NS16550_plat serial_plat = { + .clock = 1843200, + .f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR, + .reg_read = x86_uart_read, + .reg_write = x86_uart_write, +}; + +/* we are expecting always one serial interface */ +static struct device_d generic_pc_serial_device = { + .name = "serial_ns16550", + .map_base = 0x3f8, + .size = 8, + .platform_data = (void *)&serial_plat, +}; + +static int pc_console_init(void) +{ + /* Register the serial port */ + return register_device(&generic_pc_serial_device); +} +console_initcall(pc_console_init); + +#endif + +/** @page generic_pc Generic PC based bootloader + +This platform acts as a generic PC based bootloader. It depends on at least +one boot media that is connected locally (no network boot) and can be +handled by the regular BIOS (any kind of hard disks for example). + +The created @a barebox image can be used to boot a standard x86 bzImage +Linux kernel. + +Refer section @ref x86_bootloader_preparations how to do so. + +How to get the binary image: + +Using the default configuration: + +@code +make ARCH=x86 generic_defconfig +@endcode + +Build the binary image: + +@code +make ARCH=x86 CROSS_COMPILE=x86compiler +@endcode + +@note replace the 'x86compiler' with your x86 (cross) compiler. + +*/ diff --git a/commands/Kconfig b/commands/Kconfig index 28896cb..bb264fc 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -219,6 +219,14 @@ compile in the 'bootu' command to start raw (uncompressed) Linux images +config CMD_LINUX16 + tristate + default y if X86 + prompt "linux16" + help + Compile the linux16 command to be able to boot bzImages + via real mode. + config CMD_RESET tristate prompt "reset" diff --git a/commands/Makefile b/commands/Makefile index 1c657dd..b32fa05 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -1,4 +1,5 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o +obj-$(CONFIG_CMD_LINUX16) += linux16.o obj-$(CONFIG_CMD_LOADB) += loadb.o xyzModem.o obj-$(CONFIG_CMD_LOADY) += loadb.o xyzModem.o obj-$(CONFIG_CMD_LOADS) += loads.o diff --git a/commands/linux16.c b/commands/linux16.c new file mode 100644 index 0000000..b15812f --- /dev/null +++ b/commands/linux16.c @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * In parts from the GRUB2 project: + * + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2007,2008 Free Software Foundation, 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 +#include +#include +#include +#include +#include +#include + +/** FIXME */ +#define LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */ + +/** FIXME */ +#define LINUX_FLAG_BIG_KERNEL 0x1 + +/** FIXME */ +#define LINUX_BOOT_LOADER_TYPE 0x72 + +/** FIXME */ +#define LINUX_DEFAULT_SETUP_SECTS 4 + +/** FIXME */ +#define LINUX_MAX_SETUP_SECTS 64 + +/** FIXME */ +#define LINUX_OLD_REAL_MODE_SEGMT 0x9000 + +/** FIXME */ +#define LINUX_OLD_REAL_MODE_ADDR (LINUX_OLD_REAL_MODE_SEGMT << 4) + +/** FIXME */ +#define LINUX_HEAP_END_OFFSET (LINUX_OLD_REAL_MODE_SEGMT - 0x200) + +/** FIXME */ +#define LINUX_FLAG_CAN_USE_HEAP 0x80 + +/** Define kernel command lines's start offset in the setup segment */ +#define LINUX_CL_OFFSET 0x9000 + +/** Define kernel command lines's end offset */ +#define LINUX_CL_END_OFFSET 0x90FF + +/** FIXME */ +#define LINUX_CL_MAGIC 0xA33F + +/** FIXME */ +#define LINUX_SETUP_MOVE_SIZE 0x9100 + +/** Sector size */ +#define DISK_SECTOR_BITS 9 +#define DISK_SECTOR_SIZE 0x200 + +/** Where to load a bzImage */ +#define LINUX_BZIMAGE_ADDR 0x100000 + +struct linux_kernel_header { + /* first sector of the image */ + uint8_t code1[0x0020]; + uint16_t cl_magic; /**< Magic number 0xA33F */ + uint16_t cl_offset; /**< The offset of command line */ + uint8_t code2[0x01F1 - 0x0020 - 2 - 2]; + uint8_t setup_sects; /**< The size of the setup in sectors */ + uint16_t root_flags; /**< If the root is mounted readonly */ + uint16_t syssize; /**< obsolete */ + uint16_t swap_dev; /**< obsolete */ + uint16_t ram_size; /**< obsolete */ + uint16_t vid_mode; /**< Video mode control */ + uint16_t root_dev; /**< Default root device number */ + uint16_t boot_flag; /**< 0xAA55 magic number */ + + /* second sector of the image */ + uint16_t jump; /**< Jump instruction (this is code!) */ + uint32_t header; /**< Magic signature "HdrS" */ + uint16_t version; /**< Boot protocol version supported */ + uint32_t realmode_swtch; /**< Boot loader hook */ + uint16_t start_sys; /**< The load-low segment (obsolete) */ + uint16_t kernel_version; /**< Points to kernel version string */ + uint8_t type_of_loader; /**< Boot loader identifier */ +#define LINUX_LOADER_ID_LILO 0x0 +#define LINUX_LOADER_ID_LOADLIN 0x1 +#define LINUX_LOADER_ID_BOOTSECT 0x2 +#define LINUX_LOADER_ID_SYSLINUX 0x3 +#define LINUX_LOADER_ID_ETHERBOOT 0x4 +#define LINUX_LOADER_ID_ELILO 0x5 +#define LINUX_LOADER_ID_GRUB 0x7 +#define LINUX_LOADER_ID_UBOOT 0x8 +#define LINUX_LOADER_ID_XEN 0x9 +#define LINUX_LOADER_ID_GUJIN 0xa +#define LINUX_LOADER_ID_QEMU 0xb + uint8_t loadflags; /**< Boot protocol option flags */ + uint16_t setup_move_size; /**< Move to high memory size */ + uint32_t code32_start; /**< Boot loader hook */ + uint32_t ramdisk_image; /**< initrd load address */ + uint32_t ramdisk_size; /**< initrd size */ + uint32_t bootsect_kludge; /**< obsolete */ + uint16_t heap_end_ptr; /**< Free memory after setup end */ + uint8_t ext_loader_ver; /**< boot loader's extension of the version number */ + uint8_t ext_loader_type; /**< boot loader's extension of its type */ + char *cmd_line_ptr; /**< Points to the kernel command line */ + uint32_t initrd_addr_max; /**< Highest address for initrd */ +#if 0 + /* for the records only. These members are defined in + * more recent Linux kernels + */ + uint32_t kernel_alignment; /**< Alignment unit required by the kernel */ + uint8_t relocatable_kernel; /** */ + uint8_t min_alignment; /** */ + uint32_t cmdline_size; /** */ + uint32_t hardware_subarch; /** */ + uint64_t hardware_subarch_data; /** */ + uint32_t payload_offset; /** */ + uint32_t payload_length; /** */ + uint64_t setup_data; /** */ + uint64_t pref_address; /** */ + uint32_t init_size; /** */ +#endif +} __attribute__ ((packed)); + +/** + * Load an x86 Linux kernel bzImage and start it + * @param cmdtp FIXME + * @param argc parameter count + * @param argv list of parameter + * + * Loads an x86 bzImage, checks for its integrity, stores the two parts + * (setup = 'real mode code' and kernel = 'protected mode code') to their + * default locations, switches back to real mode and runs the setup code. + */ +static int do_linux16(cmd_tbl_t *cmdtp, int argc, char *argv[]) +{ + struct linux_kernel_header *lh = NULL; + int rc; + unsigned setup_sects; + unsigned real_mode_size; + size_t image_size; + const char *cmdline = getenv("bootargs"); + + if (argc < 2) { + perror("linux16"); + return 1; + } + + lh = read_file(argv[1], &image_size); + if (lh == NULL) { + printf("Cannot read file '%s'\n", argv[1]); + return 1; + } + + if (lh->boot_flag != 0xaa55) { + printf("File '%s' has invalid magic number\n", argv[1]); + rc = 1; + goto on_error; + } + + if (lh->setup_sects > LINUX_MAX_SETUP_SECTS) { + printf("File '%s' contains too many setup sectors\n", argv[1]); + rc = 1; + goto on_error; + } + + setup_sects = lh->setup_sects; + + printf("Found a %d.%d image header\n", lh->version >> 8, lh->version & 0xFF); + + if (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0200) { + /* kernel is recent enough */ + ; + if (!(lh->loadflags & LINUX_FLAG_BIG_KERNEL)) { + printf("Cannot load a classic zImage. Use a bzImage instead\n"); + goto on_error; + } + lh->type_of_loader = LINUX_BOOT_LOADER_TYPE; /* TODO */ + + if (lh->version >= 0x0201) { + lh->heap_end_ptr = LINUX_HEAP_END_OFFSET; + lh->loadflags |= LINUX_FLAG_CAN_USE_HEAP; + } + + if (lh->version >= 0x0202) + lh->cmd_line_ptr = (void*)(LINUX_OLD_REAL_MODE_ADDR + LINUX_CL_OFFSET); /* FIXME */ + else { + lh->cl_magic = LINUX_CL_MAGIC; + lh->cl_offset = LINUX_CL_OFFSET; + lh->setup_move_size = LINUX_SETUP_MOVE_SIZE; + } + } else { + printf("Kernel too old to handle\n"); + rc = 1; + goto on_error; + } + + if (strlen(cmdline) >= (LINUX_CL_END_OFFSET - LINUX_CL_OFFSET)) { + printf("Kernel command line exceeds the available space\n"); + rc = 1; + goto on_error; + } + + /* If SETUP_SECTS is not set, set it to the default. */ + if (setup_sects == 0) { + printf("Fixing setup sector count\n"); + setup_sects = LINUX_DEFAULT_SETUP_SECTS; + } + + if (setup_sects >= 15) { + void *src = lh; + if (lh->kernel_version != 0) + printf("Kernel version: '%s'\n", src + lh->kernel_version + DISK_SECTOR_SIZE); + } + + /* + * Size of the real mode part to handle in a separate way + */ + real_mode_size = (setup_sects << DISK_SECTOR_BITS) + DISK_SECTOR_SIZE; + + /* + * real mode space hole extended memory + * |---------------------------------------------->|----------->|------------------------------> + * 0 0xa0000 0x100000 + * <-1-|----------2-----------><-3- | + * 0x7e00 0x90000 + * <-4--|-5--> |---------6-------------> + * + * 1) real mode stack + * 2) barebox code + * 3) flat mode stack + * 4) realmode stack when starting a Linux kernel + * 5) Kernel's real mode setup code + * 6) compressed kernel image + */ + /* + * Parts of the image we know: + * - real mode part + * - kernel payload + */ + /* + * NOTE: This part is dangerous, as it copies some image content to + * various locations in the main memory. This could overwrite important + * data of the running barebox (hopefully not) + */ + /* copy the real mode part of the image to the 9th segment */ + memcpy((void*)LINUX_OLD_REAL_MODE_ADDR, lh, LINUX_SETUP_MOVE_SIZE); + + /* TODO add 'BOOT_IMAGE=' and 'auto' if no user intervention was done (in front of all other params) */ + /* copy also the command line into this area */ + memcpy((void*)(LINUX_OLD_REAL_MODE_ADDR + LINUX_CL_OFFSET), cmdline, strlen(cmdline) + 1); + printf("Using kernel command line: '%s'\n", cmdline); + + /* copy the compressed image part to its final address the setup code expects it + * Note: The protected mode part starts at offset (setup_sects + 1) * 512 + */ + memcpy((void*)LINUX_BZIMAGE_ADDR, ((void*)lh) + real_mode_size, image_size - real_mode_size); + + /* + * switch back to real mode now and start the real mode part of the + * image at address "(LINUX_OLD_REAL_MODE_ADDR >> 4) + 0x20:0x0000" + * which means "0x9020:0x000" -> 0x90200 + */ + bios_start_linux(LINUX_OLD_REAL_MODE_SEGMT); /* does not return */ + +on_error: + if (lh != NULL) + free(lh); + + return rc; +} + +static const __maybe_unused char cmd_linux16_help[] = +"Usage: linux16 \n" +"Boot a linux kernel via real mode code\n"; + + +BAREBOX_CMD_START(linux16) + .cmd = do_linux16, + .usage = "boot linux kernel", + BAREBOX_CMD_HELP(cmd_linux16_help) +BAREBOX_CMD_END + +/** + * @file + * @brief Boot support for Linux on x86 + */ + +/** + * @page linux16_command linux16: Boot a bzImage kernel on x86 + * + * Usage is: linux16 \ + * + * Boot a linux kernel via real mode code. Only kernel images in the + * @p bzImage format are supported. + */ + +/** + * @page x86_boot_preparation Linux Preparation on x86 + * + * Due to some real mode constraints, starting Linux is somehow tricky. + * Currently only @p bzImages are supported, because @p zImages would + * interfere with the @a barebox runtime. + * Also older load header versions than 2.00 aren't supported. + * + * The memory layout immediately before starting the Linux kernel: + * +@verbatim + real mode space hole extended memory + |---------------------------------------------->|----------->|------------------------------> + 0 0x7e00 0x90000 0xa0000 0x100000 + <-1-|----------2-----------><-3- | + <-4--|-5--> |---------6-------------> +@endverbatim + * + * @li 1 = @a barebox's real mode stack + * @li 2 = @a barebox's code + * @li 3 = @a barebox's flat mode stack + * @li 4 = real mode stack, when starting the Linux kernel + * @li 5 = Kernel's real mode setup code + * @li 6 = compressed kernel image + * + * A more detailed memory layout for kernel's real mode setup code + * +@verbatim + + 0x90000 0x97fff 0x99000 0x990ff + ---|------------------------------------------|----------------|--------------------| + |<-------- max setup code size ----------->|<--heap/stack-->|<-- command line -->| + +@endverbatim + * + * The regular entry point into the setup code is 0x90200 (2nd sector) + * + * To start the kernel, it's own setup code will be called. To do so, it + * must be called in real mode. So, @a barebox switches back to real mode + * a last time and does a jump to the setup code entry point. Now its up to + * the setup code to deflate the kernel, switching to its own protected mode + * setup and starting the kernel itself. + * + * @note This scenario only works, if a BIOS is still present. In this case + * there is no need for @a barebox to forward any system related information + * to the kernel. Everything is detected by kernel's setup code. + * + */ diff --git a/commands/partition.c b/commands/partition.c index 3cb7b61..bc0bbf9 100755 --- a/commands/partition.c +++ b/commands/partition.c @@ -41,8 +41,10 @@ #include #include +#define SIZE_REMAINING ((ulong)-1) + static int mtd_part_do_parse_one(char *devname, const char *partstr, - char **endp, unsigned long offset, + char **endp, unsigned long *offset, off_t devsize, size_t *retsize) { ulong size; @@ -54,12 +56,18 @@ memset(buf, 0, PATH_MAX); if (*partstr == '-') { - size = devsize - offset; + size = SIZE_REMAINING; end = (char *)partstr + 1; } else { size = strtoul_suffix(partstr, &end, 0); } + if (*end == '@') + *offset = strtoul_suffix(end+1, &end, 0); + + if (size == SIZE_REMAINING) + size = devsize - *offset; + partstr = end; if (*partstr == '(') { @@ -76,7 +84,7 @@ end++; } - if (size + offset > devsize) { + if (size + *offset > devsize) { printf("%s: partition end is beyond device\n", buf); return -EINVAL; } @@ -93,7 +101,7 @@ *retsize = size; - ret = devfs_add_partition(devname, offset, size, flags, buf); + ret = devfs_add_partition(devname, *offset, size, flags, buf); if (ret) printf("cannot create %s: %s\n", buf, strerror(-ret)); return ret; @@ -123,7 +131,7 @@ while (1) { size_t size = 0; - if (mtd_part_do_parse_one(devname, endp, &endp, offset, devsize, &size)) + if (mtd_part_do_parse_one(devname, endp, &endp, &offset, devsize, &size)) return 1; offset += size; @@ -146,10 +154,11 @@ "\n" "addpart adds a partition description to a device. The partition description\n" "has the form\n" -"size1(name1)[ro],size2(name2)[ro],...\n" -" is the device name under. Size can be given in decimal or if prefixed\n" -"with 0x in hex. Sizes can have an optional suffix K,M,G. The size of the last\n" -"partition can be specified as '-' for the remaining space of the device.\n" +"size1[@offset1](name1)[ro],size2[@offset2](name2)[ro],...\n" +" is the device name under. Size and offset can be given in decimal\n" +"or - if prefixed with 0x in hex. Both can have an optional suffix K,M,G.\n" +"The size of the last partition can be specified as '-' for the remaining\n" +"space of the device.\n" "This format is the same as used in the Linux kernel for cmdline mtd partitions.\n" "\n" "Note: That this command has to be reworked and will probably change it's API."; @@ -167,12 +176,12 @@ * Adds a partition description to a device. The partition description has the * form * - * size1(name1)[ro],size2(name2)[ro],... + * size1[@offset1](name1)[ro],size2[@offset2](name2)[ro],... * - * \ is the device name under. Sizes can be given in decimal or - if - * prefixed with 0x - in hex. Sizes can have an optional suffix K,M,G. The - * size of the last partition can be specified as '-' for the remaining space - * of the device. + * \ is the device name under. Size and offset can be given in decimal + * or - if prefixed with 0x - in hex. Both can have an optional suffix K,M,G. + * The size of the last partition can be specified as '-' for the remaining + * space of the device. * * @note The format is the same as used in the Linux kernel for cmdline mtd * partitions. diff --git a/drivers/Kconfig b/drivers/Kconfig index 8bab7ac..bf559c4 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -6,6 +6,7 @@ source "drivers/i2c/Kconfig" source "drivers/nor/Kconfig" source "drivers/nand/Kconfig" +source "drivers/ata/Kconfig" source "drivers/usb/Kconfig" source "drivers/video/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 5dc7756..7bae6ff 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -3,6 +3,7 @@ obj-y += nand/ obj-y += nor/ obj-y += usb/ +obj-$(CONFIG_ATA) += ata/ obj-$(CONFIG_SPI) += spi/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_VIDEO) += video/ diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig new file mode 100644 index 0000000..b43c975 --- /dev/null +++ b/drivers/ata/Kconfig @@ -0,0 +1,26 @@ +menuconfig ATA + bool "ATA " + help + Add support for ATA types of drives like harddisks and CDROMs. + +if ATA + +comment "drive types" + +config ATA_DISK + bool "disk drives" + help + Add support for regular disk drives + +comment "interface types" + +config ATA_BIOS + bool "BIOS based" + depends on X86_BIOS_BRINGUP + help + Gain disk drive access via int13 calls to the standard PC-BIOS. + The advantage of this driver is, it still uses user's defined boot + media to work on. Disadvantage is: Due to its 16 bit nature it is + slow. + +endif diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile new file mode 100644 index 0000000..30d15cc --- /dev/null +++ b/drivers/ata/Makefile @@ -0,0 +1,7 @@ +# drive types + +obj-$(CONFIG_ATA_DISK) += disk_drive.o + +# interface types + +obj-$(CONFIG_ATA_BIOS) += bios.o diff --git a/drivers/ata/bios.c b/drivers/ata/bios.c new file mode 100644 index 0000000..51e2425 --- /dev/null +++ b/drivers/ata/bios.c @@ -0,0 +1,291 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * Mostly stolen from the GRUB2 project + * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008 Free Software Foundation, 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 + * + */ + +/** + * @file + * @brief Media communication layer through the standard 16 bit PC-BIOS + * + * This communication driver does all accesses to the boot medium via 16 bit + * real mode calls into the standard BIOS. Due to this method, its possible + * to use all the medias to boot from that are supported by the BIOS. This + * also includes emulated only medias. + * + * To be able to call the real mode BIOS, this driver must switch back to + * real mode for each access. This will slow down the access a little bit, but + * we are a boot loader here, not an operating system... + * + * Note: We need scratch memory for the BIOS communication, because the BIOS + * can only handle memory below 0xA0000. So we must copy all data between + * the flat mode buffers and realmode buffers. + * + * Note: This driver makes no sense on other architectures than x86. + * + * Note: This driver does only support LBA addressing. Currently no CHS! + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Sector count handled in one count + * + * @todo 127 are always possible, some BIOS manufacturer supports up to 255. + * Is it's worth to detect Phoenic's restriction? + */ +#define SECTORS_AT_ONCE 64 + +/** Size of one sector in bytes */ +#define SECTOR_SIZE 512 + +/** Command to read sectors from media */ +#define BIOS_READ_CMD 0 + +/** Command to write sectors to media */ +#define BIOS_WRT_CMD 1 + +/** + * "Disk Address Packet Structure" to be used when calling + * BIOS's int13, function 0x42/0x43 + */ +struct DAPS +{ + uint8_t size; /**< always '16' */ + uint8_t res1; /**< always '0' */ + int8_t count; /**< number of sectors 0...127 */ + uint8_t res2; /**< always '0' */ + uint16_t offset; /**< buffer address: offset */ + uint16_t segment; /**< buffer address: segment */ + uint64_t lba; /**< LBA of the start sector */ +} __attribute__ ((packed)); + +/** + * Collection of data we need to know about the connected drive + */ +struct media_access { + int drive_no; /**< drive number used by the BIOS */ + int is_cdrom; /**< drive is a CDROM e.g. no write support */ +}; + +/** + * Scratch memory for BIOS communication to handle data in chunks of 32 kiB + * + * Note: This variable is located in the .bss segment, assuming it is located + * below 0xA0000. If not, the BIOS is not able to read or store any data + * from/to it. The variable must also aligned to a 16 byte boundary to easify + * linear to segment:offset address conversion. + */ +static uint8_t scratch_buffer[SECTORS_AT_ONCE * SECTOR_SIZE] __attribute__((aligned(16))); + +/** + * Communication buffer for the 16 bit int13 BIOS call + * + * Note: This variable is located in the .bss segment, assuming it is located + * below 0xA0000. If not, the BIOS is not able to read or store any data + * from/to it. The variable must also aligned to a 16 byte boundary to easify + * linear to segment:offset conversion. + */ +static struct DAPS bios_daps __attribute__((aligned(16))); + +/** + * @param media our data we need to do the access + * @param cmd Command to forward to the BIOS + * @param sector_start LBA of the start sector + * @param sector_count Sector count + * @param buffer Buffer to read from or write to (in the low memory area) + * @return 0 on success, anything else on failure + */ +static int biosdisk_bios_call(struct media_access *media, int cmd, uint64_t sector_start, unsigned sector_count, void *buffer) +{ + int rc; + + /* prepare the DAPS for the int13 call */ + bios_daps.size = sizeof(struct DAPS); + bios_daps.res1 = 0; + bios_daps.count = sector_count; /* always less than 128! */ + bios_daps.res2 = 0; + bios_daps.segment = (unsigned long)buffer >> 4; + bios_daps.offset = (unsigned long)buffer - (unsigned long)(bios_daps.segment << 4); + bios_daps.lba = sector_start; + + if (cmd == BIOS_READ_CMD) + rc = bios_disk_rw_int13_extensions(0x42, media->drive_no, &bios_daps); + else if (cmd == BIOS_WRT_CMD) + rc = bios_disk_rw_int13_extensions(0x43, media->drive_no, &bios_daps); + else + return -1; + + return rc; +} + +/** + * Read a chunk of sectors from media + * @param dev our data we need to do the access + * @param sector_start Sector's LBA number to start read from + * @param sector_count Sectors to read + * @param buffer Buffer to read into + * @return 0 on success, anything else on failure + * + * This routine expects the buffer has the correct size to store all data! + */ +static int biosdisk_read(struct device_d *dev, uint64_t sector_start, unsigned sector_count, void *buffer) +{ + int rc; + struct ata_interface *intf = dev->platform_data; + struct media_access *media = intf->priv; + + while (sector_count >= SECTORS_AT_ONCE) { + rc = biosdisk_bios_call(media, BIOS_READ_CMD, sector_start, SECTORS_AT_ONCE, scratch_buffer); + if (rc != 0) + return rc; + __builtin_memcpy(buffer, scratch_buffer, sizeof(scratch_buffer)); + buffer += sizeof(scratch_buffer); + sector_start += SECTORS_AT_ONCE; + sector_count -= SECTORS_AT_ONCE; + }; + + /* Are sectors still remaining? */ + if (sector_count) { + rc = biosdisk_bios_call(media, BIOS_READ_CMD, sector_start, sector_count, scratch_buffer); + __builtin_memcpy(buffer, scratch_buffer, sector_count * SECTOR_SIZE); + } else + rc = 0; + + return rc; +} + +/** + * Write a chunk of sectors to media + * @param dev our data we need to do the access + * @param sector_start Sector's LBA number to start write to + * @param sector_count Sectors to write + * @param buffer Buffer to write from + * @return 0 on success, anything else on failure + * + * This routine expects the buffer has the correct size to read all data! + */ +static int biosdisk_write(struct device_d *dev, uint64_t sector_start, unsigned sector_count, const void *buffer) +{ + int rc; + struct ata_interface *intf = dev->platform_data; + struct media_access *media = intf->priv; + + while (sector_count >= SECTORS_AT_ONCE) { + __builtin_memcpy(scratch_buffer, buffer, sizeof(scratch_buffer)); + rc = biosdisk_bios_call(media, BIOS_WRT_CMD, sector_start, SECTORS_AT_ONCE, scratch_buffer); + if (rc != 0) + return rc; + buffer += sizeof(scratch_buffer); + sector_start += SECTORS_AT_ONCE; + sector_count -= SECTORS_AT_ONCE; + }; + + /* Are sectors still remaining? */ + if (sector_count) { + __builtin_memcpy(scratch_buffer, buffer, sector_count * SECTOR_SIZE); + rc = biosdisk_bios_call(media, BIOS_WRT_CMD, sector_start, sector_count, scratch_buffer); + } else + rc = 0; + + return rc; +} + +/** + * Probe for connected drives and register them + * + * Detecting if a drive is present is done by simply reading its MBR. + * + * FIXME: Relation between BIOS disk numbering scheme and our representation + * here in barebox (and later on in the linux kernel) + */ +static int biosdisk_probe(struct device_d *dev) +{ + int drive, rc; + struct media_access media, *m; + struct device_d *drive_dev; + struct ata_interface *p; + + for (drive = 0x80; drive < 0x90; drive++) { + media.drive_no = drive; + media.is_cdrom = 0; /* don't know yet */ + rc = biosdisk_bios_call(&media, BIOS_READ_CMD, 0, 1, scratch_buffer); + if (rc != 0) + continue; + + printf("BIOSdrive %d seems valid. Registering...\n", media.drive_no); + + drive_dev = xzalloc(sizeof(struct device_d) + sizeof(struct media_access) + sizeof(struct ata_interface)); + if (drive_dev == NULL) { + dev_err(dev, "Out of memory\n"); + return -1; + } + m = (struct media_access*)&drive_dev[1]; + p = (struct ata_interface*)&m[1]; + + m->drive_no = drive; + m->is_cdrom = 0; + + p->write = biosdisk_write; + p->read = biosdisk_read; + p->priv = m; + + strcpy(drive_dev->name, "biosdisk"); + drive_dev->id = drive - 0x80; + drive_dev->size = 1; + drive_dev->map_base = 0; + drive_dev->platform_data = p; + + register_device(drive_dev); + } + + return 0; +} + +static struct driver_d biosdisk_driver = { + .name = "biosdrive", + .probe = biosdisk_probe, +}; + +static int biosdisk_init(void) +{ + /* sanity */ + if (scratch_buffer > (uint8_t*)0x9FFFF) { + printf("BIOS driver: Scratch memory not in real mode area. Cannot continue!\n"); + return -EIO; + } + if (&bios_daps > (struct DAPS*)0x9FFFF) { + printf("BIOS driver: DAPS memory not in real mode area. Cannot continue!\n"); + return -EIO; + } + + register_driver(&biosdisk_driver); + return 0; +} + +device_initcall(biosdisk_init); diff --git a/drivers/ata/disk_drive.c b/drivers/ata/disk_drive.c new file mode 100644 index 0000000..250dada --- /dev/null +++ b/drivers/ata/disk_drive.c @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Generic disk drive support + * + * @todo Support for disks larger than 4 GiB + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Description of one partition table entry (D*S type) + */ +struct partition_entry { + uint8_t boot_indicator; + uint8_t chs_begin[3]; + uint8_t type; + uint8_t chs_end[3]; + uint32_t partition_start; + uint32_t partition_size; +} __attribute__ ((packed)); + +/** one for all */ +#define SECTOR_SIZE 512 + +/** + * Guess the size of the disk, based on the partition table entries + * @param dev device to create partitions for + * @param table partition table + * @return size in sectors + */ +static unsigned long disk_guess_size(struct device_d *dev, struct partition_entry *table) +{ + int part_order[4] = {0, 1, 2, 3}; + unsigned long size = 0; + int i; + + /* TODO order the partitions */ + + for (i = 0; i < 4; i++) { + if (table[part_order[i]].partition_start != 0) { + size += table[part_order[i]].partition_start - size; /* the gap */ + size += table[part_order[i]].partition_size; + } + } +#if 1 +/* limit disk sizes we can't handle due to 32 bit limits */ + if (size > 0x7fffff) { + dev_warn(dev, "Warning: Size limited due to 32 bit contraints\n"); + size = 0x7fffff; + } +#endif + return size; +} + +/** + * Register partitions found on the drive + * @param dev device to create partitions for + * @param table partition table + * @return 0 on success + */ +static int disk_register_partitions(struct device_d *dev, struct partition_entry *table) +{ + int part_order[4] = {0, 1, 2, 3}; + int i, rc; + char drive_name[16], partition_name[19]; + + /* TODO order the partitions */ + + for (i = 0; i < 4; i++) { + sprintf(drive_name, "%s%d", dev->name, dev->id); + sprintf(partition_name, "%s%d.%d", dev->name, dev->id, i); + if (table[part_order[i]].partition_start != 0) { +#if 1 +/* ignore partitions we can't handle due to 32 bit limits */ + if (table[part_order[i]].partition_start > 0x7fffff) + continue; + if (table[part_order[i]].partition_size > 0x7fffff) + continue; +#endif + dev_info(dev, "Registering partition %s to drive %s\n", partition_name, drive_name); + rc = devfs_add_partition(drive_name, + table[part_order[i]].partition_start * SECTOR_SIZE, + table[part_order[i]].partition_size * SECTOR_SIZE, + DEVFS_PARTITION_FIXED, partition_name); + if (rc != 0) + dev_err(dev, "Failed to register partition %s (%d)\n", partition_name, rc); + } + } + + return 0; +} + +/** + * Write some data to a disk + * @param cdev the device to write to + * @param _buf source of data + * @param count byte count to write + * @param offset where to write to disk + * @param flags Ignored + * @return Written bytes or negative value in case of failure + */ +static ssize_t disk_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags) +{ + struct device_d *dev = cdev->dev; + struct ata_interface *intf = dev->platform_data; + int rc; + unsigned sep_count = offset & (SECTOR_SIZE - 1); + ssize_t written = 0; + + /* starting at no sector boundary? */ + if (sep_count != 0) { + uint8_t tmp_buf[SECTOR_SIZE]; + unsigned to_write = min(SECTOR_SIZE - sep_count, count); + + rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf); + if (rc != 0) { + dev_err(dev, "Cannot read data\n"); + return -1; + } + memcpy(&tmp_buf[sep_count], _buf, to_write); + rc = intf->write(dev, offset / SECTOR_SIZE, 1, tmp_buf); + if (rc != 0) { + dev_err(dev, "Cannot write data\n"); + return -1; + } + + _buf += to_write; + offset += to_write; + count -= to_write; + written += to_write; + } + + /* full sector part */ + sep_count = count / SECTOR_SIZE; + if (sep_count) { + rc = intf->write(dev, offset / SECTOR_SIZE, sep_count, _buf); + if (rc != 0) { + dev_err(dev, "Cannot write data\n"); + return -1; + } + _buf += sep_count * SECTOR_SIZE; + offset += sep_count * SECTOR_SIZE; + count -= sep_count * SECTOR_SIZE; + written += sep_count * SECTOR_SIZE; + } + + /* ending at no sector boundary? */ + if (count) { + uint8_t tmp_buf[SECTOR_SIZE]; + + rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf); + if (rc != 0) { + dev_err(dev, "Cannot read data\n"); + return -1; + } + memcpy(tmp_buf, _buf, count); + rc = intf->write(dev, offset / SECTOR_SIZE, 1, tmp_buf); + if (rc != 0) { + dev_err(dev, "Cannot write data\n"); + return -1; + } + written += count; + } + + return written; +} + +/** + * Read some data from a disk + * @param cdev the device to read from + * @param _buf destination of the data + * @param count byte count to read + * @param offset where to read from + * @param flags Ignored + * @return Read bytes or negative value in case of failure + */ +static ssize_t disk_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags) +{ + struct device_d *dev = cdev->dev; + struct ata_interface *intf = dev->platform_data; + int rc; + unsigned sep_count = offset & (SECTOR_SIZE - 1); + ssize_t read = 0; + + /* starting at no sector boundary? */ + if (sep_count != 0) { + uint8_t tmp_buf[SECTOR_SIZE]; + unsigned to_read = min(SECTOR_SIZE - sep_count, count); + + rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf); + if (rc != 0) { + dev_err(dev, "Cannot read data\n"); + return -1; + } + memcpy(_buf, &tmp_buf[sep_count], to_read); + _buf += to_read; + offset += to_read; + count -= to_read; + read += to_read; + } + + /* full sector part */ + sep_count = count / SECTOR_SIZE; + if (sep_count) { + rc = intf->read(dev, offset / SECTOR_SIZE, sep_count, _buf); + if (rc != 0) { + dev_err(dev, "Cannot read data\n"); + return -1; + } + _buf += sep_count * SECTOR_SIZE; + offset += sep_count * SECTOR_SIZE; + count -= sep_count * SECTOR_SIZE; + read += sep_count * SECTOR_SIZE; + } + + /* ending at no sector boundary? */ + if (count) { + uint8_t tmp_buf[SECTOR_SIZE]; + + rc = intf->read(dev, offset / SECTOR_SIZE, 1, tmp_buf); + if (rc != 0) { + dev_err(dev, "Cannot read data\n"); + return -1; + } + memcpy(_buf, tmp_buf, count); + read += count; + } + + return read; +} + +static struct file_operations disk_ops = { + .read = disk_read, + .write = disk_write, + .lseek = dev_lseek_default, +}; + +/** + * Probe the connected disk drive + */ +static int disk_probe(struct device_d *dev) +{ + uint8_t sector[512]; + int rc; + struct ata_interface *intf = dev->platform_data; + struct cdev *disk_cdev; + + rc = intf->read(dev, 0, 1, sector); + if (rc != 0) { + dev_err(dev, "Cannot read MBR of this device\n"); + return -1; + } + + /* It seems a valuable disk. Register it */ + disk_cdev = xzalloc(sizeof(struct cdev)); + if (disk_cdev == NULL) { + dev_err(dev, "Out of memory\n"); + return -ENOMEM; + } + + /* + * BIOS based disks needs special handling. Not the driver can + * enumerate the hardware, the BIOS did it already. To show the user + * the drive ordering must not correspond to the Linux drive order, + * use the 'biosdisk' name instead. + */ +#ifdef CONFIG_ATA_BIOS + if (strcmp(dev->driver->name, "biosdisk") == 0) + disk_cdev->name = asprintf("biosdisk%d", dev->id); + else +#endif + disk_cdev->name = asprintf("disk%d", dev->id); + /** + * @todo we need the size of the drive, else its nearly impossible + * to do anything with it (at least with the generic routines) + */ + disk_cdev->size = 32; /* FIXME */ + disk_cdev->ops = &disk_ops; + disk_cdev->dev = dev; + devfs_create(disk_cdev); + + if ((sector[510] != 0x55) || (sector[511] != 0xAA)) { + dev_info(dev, "No partition table found\n"); + return 0; + } + + /* guess the size of this drive */ + dev->size = disk_guess_size(dev, (struct partition_entry*)§or[446]) * SECTOR_SIZE; + dev_info(dev, "Drive size guessed to %u kiB\n", dev->size / 1024); + disk_cdev->size = dev->size; + + disk_register_partitions(dev, (struct partition_entry*)§or[446]); + + return 0; +} + +#ifdef CONFIG_ATA_BIOS +static struct driver_d biosdisk_driver = { + .name = "biosdisk", + .probe = disk_probe, +}; +#endif + +static struct driver_d disk_driver = { + .name = "disk", + .probe = disk_probe, +}; + +static int disk_init(void) +{ +#ifdef CONFIG_ATA_BIOS + register_driver(&biosdisk_driver); +#endif + register_driver(&disk_driver); + return 0; +} + +device_initcall(disk_init); diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 46723ed..f1b2949 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -13,4 +13,7 @@ config DRIVER_I2C_MC9SDZ60 bool "MC9SDZ60 driver" +config DRIVER_I2C_LP3972 + bool "LP3972 driver" + endif diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 5dd642f..62d030b 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_DRIVER_I2C_MC13892) += mc13892.o obj-$(CONFIG_DRIVER_I2C_MC9SDZ60) += mc9sdz60.o +obj-$(CONFIG_DRIVER_I2C_LP3972) += lp3972.o diff --git a/drivers/i2c/lp3972.c b/drivers/i2c/lp3972.c new file mode 100644 index 0000000..9826699 --- /dev/null +++ b/drivers/i2c/lp3972.c @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2007 Sascha Hauer, Pengutronix + * 2009 Marc Kleine-Budde + * 2009 Eric Benard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include + +#include + +#include + +#define DRIVERNAME "lp3972" + +struct lp_priv { + struct cdev cdev; + struct i2c_client *client; +}; + +#define to_lp_priv(a) container_of(a, struct lp_priv, cdev) + +static struct lp_priv *lp_dev; + +struct i2c_client *lp3972_get_client(void) +{ + if (!lp_dev) + return NULL; + + return lp_dev->client; +} + +static u32 lp_read_reg(struct lp_priv *lp, int reg) +{ + u8 buf; + + i2c_read_reg(lp->client, reg, &buf, sizeof(buf)); + + return buf; +} + +static ssize_t lp_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags) +{ + struct lp_priv *priv = to_lp_priv(cdev); + int i = count; + u8 *buf = _buf; + + while (i) { + *buf = lp_read_reg(priv, offset); + buf++; + i--; + offset++; + } + + return count; +} + +static struct file_operations lp_fops = { + .lseek = dev_lseek_default, + .read = lp_read, +}; + +static int lp_probe(struct device_d *dev) +{ + if (lp_dev) + return -EBUSY; + + lp_dev = xzalloc(sizeof(struct lp_priv)); + lp_dev->cdev.name = DRIVERNAME; + lp_dev->client = to_i2c_client(dev); + lp_dev->cdev.size = 256; + lp_dev->cdev.dev = dev; + lp_dev->cdev.ops = &lp_fops; + + devfs_create(&lp_dev->cdev); + + return 0; +} + +static struct driver_d lp_driver = { + .name = DRIVERNAME, + .probe = lp_probe, +}; + +static int lp_init(void) +{ + register_driver(&lp_driver); + return 0; +} + +device_initcall(lp_init); diff --git a/drivers/i2c/mc13892.c b/drivers/i2c/mc13892.c index 54661d4..67d4232 100644 --- a/drivers/i2c/mc13892.c +++ b/drivers/i2c/mc13892.c @@ -26,47 +26,99 @@ #include #include - -#include +#include #define DRIVERNAME "mc13892" -struct mc_priv { - struct cdev cdev; - struct i2c_client *client; -}; +#define to_mc13892(a) container_of(a, struct mc13892, cdev) -#define to_mc_priv(a) container_of(a, struct mc_priv, cdev) +static struct mc13892 *mc_dev; -static struct mc_priv *mc_dev; - -struct i2c_client *mc13892_get_client(void) +struct mc13892 *mc13892_get(void) { if (!mc_dev) return NULL; - return mc_dev->client; + return mc_dev; } +EXPORT_SYMBOL(mc13892_get); -static u32 mc_read_reg(struct mc_priv *mc, int reg) +int mc13892_reg_read(struct mc13892 *mc13892, enum mc13892_reg reg, u32 *val) { - u32 buf; + u8 buf[3]; + int ret; - i2c_read_reg(mc->client, reg, (u8 *)&buf, sizeof(buf)); + ret = i2c_read_reg(mc13892->client, reg, buf, 3); + *val = buf[0] << 16 | buf[1] << 8 | buf[2] << 0; - return buf; + return ret == 3 ? 0 : ret; } +EXPORT_SYMBOL(mc13892_reg_read) + +int mc13892_reg_write(struct mc13892 *mc13892, enum mc13892_reg reg, u32 val) +{ + u8 buf[] = { + val >> 16, + val >> 8, + val >> 0, + }; + int ret; + + ret = i2c_write_reg(mc13892->client, reg, buf, 3); + + return ret == 3 ? 0 : ret; +} +EXPORT_SYMBOL(mc13892_reg_write) + +int mc13892_set_bits(struct mc13892 *mc13892, enum mc13892_reg reg, u32 mask, u32 val) +{ + u32 tmp; + int err; + + err = mc13892_reg_read(mc13892, reg, &tmp); + tmp = (tmp & ~mask) | val; + + if (!err) + err = mc13892_reg_write(mc13892, reg, tmp); + + return err; +} +EXPORT_SYMBOL(mc13892_set_bits); static ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags) { - struct mc_priv *priv = to_mc_priv(cdev); - int i = count >> 2; + struct mc13892 *priv = to_mc13892(cdev); u32 *buf = _buf; + size_t i = count >> 2; + int err; offset >>= 2; while (i) { - *buf = mc_read_reg(priv, offset); + err = mc13892_reg_read(priv, offset, buf); + if (err) + return (ssize_t)err; + buf++; + i--; + offset++; + } + + return count; +} + +static ssize_t mc_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags) +{ + struct mc13892 *mc13892 = to_mc13892(cdev); + const u32 *buf = _buf; + size_t i = count >> 2; + int err; + + offset >>= 2; + + while (i) { + err = mc13892_reg_write(mc13892, offset, *buf); + if (err) + return (ssize_t)err; buf++; i--; offset++; @@ -78,6 +130,7 @@ static struct file_operations mc_fops = { .lseek = dev_lseek_default, .read = mc_read, + .write = mc_write, }; static int mc_probe(struct device_d *dev) @@ -85,7 +138,7 @@ if (mc_dev) return -EBUSY; - mc_dev = xzalloc(sizeof(struct mc_priv)); + mc_dev = xzalloc(sizeof(struct mc13892)); mc_dev->cdev.name = DRIVERNAME; mc_dev->client = to_i2c_client(dev); mc_dev->cdev.size = 256; diff --git a/drivers/i2c/mc9sdz60.c b/drivers/i2c/mc9sdz60.c index 4b1068d..3580af8 100644 --- a/drivers/i2c/mc9sdz60.c +++ b/drivers/i2c/mc9sdz60.c @@ -26,45 +26,88 @@ #include #include - -#include +#include #define DRIVERNAME "mc9sdz60" -struct mc_priv { - struct cdev cdev; - struct i2c_client *client; -}; +#define to_mc9sdz60(a) container_of(a, struct mc9sdz60, cdev) -#define to_mc_priv(a) container_of(a, struct mc_priv, cdev) +static struct mc9sdz60 *mc_dev; -static struct mc_priv *mc_dev; - -struct i2c_client *mc9sdz60_get_client(void) +struct mc9sdz60 *mc9sdz60_get(void) { if (!mc_dev) return NULL; - return mc_dev->client; + return mc_dev; } +EXPORT_SYMBOL(mc9sdz60_get); -static u32 mc_read_reg(struct mc_priv *mc, int reg) +int mc9sdz60_reg_read(struct mc9sdz60 *mc9sdz60, enum mc9sdz60_reg reg, u8 *val) { - u8 buf; + int ret; - i2c_read_reg(mc->client, reg, &buf, sizeof(buf)); + ret = i2c_read_reg(mc9sdz60->client, reg, val, 1); - return buf; + return ret == 1 ? 0 : ret; } +EXPORT_SYMBOL(mc9sdz60_reg_read) + +int mc9sdz60_reg_write(struct mc9sdz60 *mc9sdz60, enum mc9sdz60_reg reg, u8 val) +{ + int ret; + + ret = i2c_write_reg(mc9sdz60->client, reg, &val, 1); + + return ret == 1 ? 0 : ret; +} +EXPORT_SYMBOL(mc9sdz60_reg_write) + +int mc9sdz60_set_bits(struct mc9sdz60 *mc9sdz60, enum mc9sdz60_reg reg, u8 mask, u8 val) +{ + u8 tmp; + int err; + + err = mc9sdz60_reg_read(mc9sdz60, reg, &tmp); + tmp = (tmp & ~mask) | val; + + if (!err) + err = mc9sdz60_reg_write(mc9sdz60, reg, tmp); + + return err; +} +EXPORT_SYMBOL(mc9sdz60_set_bits); static ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags) { - struct mc_priv *priv = to_mc_priv(cdev); - int i = count; + struct mc9sdz60 *mc9sdz60 = to_mc9sdz60(cdev); u8 *buf = _buf; + size_t i = count; + int err; while (i) { - *buf = mc_read_reg(priv, offset); + err = mc9sdz60_reg_read(mc9sdz60, offset, buf); + if (err) + return (ssize_t)err; + buf++; + i--; + offset++; + } + + return count; +} + +static ssize_t mc_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags) +{ + struct mc9sdz60 *mc9sdz60 = to_mc9sdz60(cdev); + const u8 *buf = _buf; + size_t i = count; + int err; + + while (i) { + err = mc9sdz60_reg_write(mc9sdz60, offset, *buf); + if (err) + return (ssize_t)err; buf++; i--; offset++; @@ -76,6 +119,7 @@ static struct file_operations mc_fops = { .lseek = dev_lseek_default, .read = mc_read, + .write = mc_write, }; static int mc_probe(struct device_d *dev) @@ -83,10 +127,10 @@ if (mc_dev) return -EBUSY; - mc_dev = xzalloc(sizeof(struct mc_priv)); + mc_dev = xzalloc(sizeof(struct mc9sdz60)); mc_dev->cdev.name = DRIVERNAME; mc_dev->client = to_i2c_client(dev); - mc_dev->cdev.size = 256; + mc_dev->cdev.size = 64; /* 35 known registers */ mc_dev->cdev.dev = dev; mc_dev->cdev.ops = &mc_fops; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ed7656e..0955562 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -64,6 +64,11 @@ depends on ARCH_HAS_FEC_IMX select MIIPHY +config DRIVER_NET_EP93XX + bool "EP93xx Ethernet driver" + depends on ARCH_EP93XX + select MIIPHY + config DRIVER_NET_MACB bool "macb Ethernet driver" depends on ARCH_AT91 diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6751920..1b6f104 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o obj-$(CONFIG_DRIVER_NET_FEC_IMX) += fec_imx.o +obj-$(CONFIG_DRIVER_NET_EP93XX) += ep93xx.o obj-$(CONFIG_DRIVER_NET_MACB) += macb.o obj-$(CONFIG_DRIVER_NET_TAP) += tap.o obj-$(CONFIG_MIIPHY) += miiphy.o diff --git a/drivers/net/ep93xx.c b/drivers/net/ep93xx.c new file mode 100644 index 0000000..aa1a005 --- /dev/null +++ b/drivers/net/ep93xx.c @@ -0,0 +1,676 @@ +/* + * Cirrus Logic EP93xx ethernet MAC / MII driver. + * + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2004, 2005 + * Cory T. Tusar, Videon Central, Inc., + * + * Based on the original eth.[ch] Cirrus Logic EP93xx Rev D. Ethernet Driver, + * which is + * + * (C) Copyright 2002 2003 + * Adam Bezanson, Network Audio Technologies, 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., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ep93xx.h" + +static int ep93xx_eth_send_packet(struct eth_device *edev, + void *packet, int length); +static int ep93xx_eth_rcv_packet(struct eth_device *edev); + +static int ep93xx_phy_read(struct miiphy_device *mdev, uint8_t phy_addr, + uint8_t phy_reg, uint16_t *value); +static int ep93xx_phy_write(struct miiphy_device *mdev, uint8_t phy_addr, + uint8_t phy_reg, uint16_t value); + +static inline struct ep93xx_eth_priv *ep93xx_get_priv(struct eth_device *edev) +{ + return (struct ep93xx_eth_priv *)edev->priv; +} + +static inline struct mac_regs *ep93xx_get_regs(struct eth_device *edev) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + + return priv->regs; +} + +#if defined(EP93XX_MAC_DEBUG) +/** + * Dump ep93xx_mac values to the terminal. + */ +inline void dump_dev(struct eth_device *edev) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + int i; + + printf("\ndump_dev()\n"); + printf(" rx_dq.base %08X\n", priv->rx_dq.base); + printf(" rx_dq.current %08X\n", priv->rx_dq.current); + printf(" rx_dq.end %08X\n", priv->rx_dq.end); + printf(" rx_sq.base %08X\n", priv->rx_sq.base); + printf(" rx_sq.current %08X\n", priv->rx_sq.current); + printf(" rx_sq.end %08X\n", priv->rx_sq.end); + + for (i = 0; i < NUMRXDESC; i++) + printf(" rx_buffer[%2.d] %08X\n", i, NetRxPackets[i]); + + printf(" tx_dq.base %08X\n", priv->tx_dq.base); + printf(" tx_dq.current %08X\n", priv->tx_dq.current); + printf(" tx_dq.end %08X\n", priv->tx_dq.end); + printf(" tx_sq.base %08X\n", priv->tx_sq.base); + printf(" tx_sq.current %08X\n", priv->tx_sq.current); + printf(" tx_sq.end %08X\n", priv->tx_sq.end); +} + +/** + * Dump all RX descriptor queue entries to the terminal. + */ +inline void dump_rx_descriptor_queue(struct eth_device *edev) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + int i; + + printf("\ndump_rx_descriptor_queue()\n"); + printf(" descriptor address word1 word2\n"); + for (i = 0; i < NUMRXDESC; i++) { + printf(" [ %08X ] %08X %08X\n", + (priv->rx_dq.base + i), + (priv->rx_dq.base + i)->word1, + (priv->rx_dq.base + i)->word2); + } +} + +/** + * Dump all RX status queue entries to the terminal. + */ +inline void dump_rx_status_queue(void) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + int i; + + printf("\ndump_rx_status_queue()\n"); + printf(" descriptor address word1 word2\n"); + for (i = 0; i < NUMRXDESC; i++) { + printf(" [ %08X ] %08X %08X\n", + (priv->rx_sq.base + i), + (priv->rx_sq.base + i)->word1, + (priv->rx_sq.base + i)->word2); + } +} + +/** + * Dump all TX descriptor queue entries to the terminal. + */ +inline void dump_tx_descriptor_queue(void) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + int i; + + printf("\ndump_tx_descriptor_queue()\n"); + printf(" descriptor address word1 word2\n"); + for (i = 0; i < NUMTXDESC; i++) { + printf(" [ %08X ] %08X %08X\n", + (priv->tx_dq.base + i), + (priv->tx_dq.base + i)->word1, + (priv->tx_dq.base + i)->word2); + } +} + +/** + * Dump all TX status queue entries to the terminal. + */ +inline void dump_tx_status_queue(void) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + int i; + + printf("\ndump_tx_status_queue()\n"); + printf(" descriptor address word1\n"); + for (i = 0; i < NUMTXDESC; i++) { + printf(" [ %08X ] %08X\n", + (priv->rx_sq.base + i), + (priv->rx_sq.base + i)->word1); + } +} +#else +#define dump_dev(x) +#define dump_rx_descriptor_queue() +#define dump_rx_status_queue() +#define dump_tx_descriptor_queue() +#define dump_tx_status_queue() +#endif /* defined(EP93XX_MAC_DEBUG) */ + +/** + * Reset the EP93xx MAC by twiddling the soft reset bit and spinning until + * it's cleared. + */ +static void ep93xx_eth_reset(struct eth_device *edev) +{ + struct mac_regs *regs = ep93xx_get_regs(edev); + uint32_t value; + + pr_debug("+ep93xx_eth_reset\n"); + + value = readl(®s->selfctl); + value |= SELFCTL_RESET; + writel(value, ®s->selfctl); + + while (readl(®s->selfctl) & SELFCTL_RESET) + ; /* noop */ + + pr_debug("-ep93xx_eth_reset\n"); +} + +static int ep93xx_eth_init_dev(struct eth_device *edev) +{ + pr_debug("+ep93xx_eth_init_dev\n"); + + pr_debug("-ep93xx_eth_init_dev\n"); + + return 0; +} + +static int ep93xx_eth_open(struct eth_device *edev) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + struct mac_regs *regs = ep93xx_get_regs(edev); + int i; + + pr_debug("+ep93xx_eth_open\n"); + + ep93xx_eth_reset(edev); + + /* Reset the descriptor queues' current and end address values */ + priv->tx_dq.current = priv->tx_dq.base; + priv->tx_dq.end = (priv->tx_dq.base + NUMTXDESC); + + priv->tx_sq.current = priv->tx_sq.base; + priv->tx_sq.end = (priv->tx_sq.base + NUMTXDESC); + + priv->rx_dq.current = priv->rx_dq.base; + priv->rx_dq.end = (priv->rx_dq.base + NUMRXDESC); + + priv->rx_sq.current = priv->rx_sq.base; + priv->rx_sq.end = (priv->rx_sq.base + NUMRXDESC); + + /* + * Set the transmit descriptor and status queues' base address, + * current address, and length registers. Set the maximum frame + * length and threshold. Enable the transmit descriptor processor. + */ + writel((uint32_t)priv->tx_dq.base, ®s->txdq.badd); + writel((uint32_t)priv->tx_dq.base, ®s->txdq.curadd); + writel(sizeof(struct tx_descriptor) * NUMTXDESC, ®s->txdq.blen); + + writel((uint32_t)priv->tx_sq.base, ®s->txstsq.badd); + writel((uint32_t)priv->tx_sq.base, ®s->txstsq.curadd); + writel(sizeof(struct tx_status) * NUMTXDESC, ®s->txstsq.blen); + + writel(0x00040000, ®s->txdthrshld); + writel(0x00040000, ®s->txststhrshld); + + writel((TXSTARTMAX << 0) | (PKTSIZE_ALIGN << 16), ®s->maxfrmlen); + writel(BMCTL_TXEN, ®s->bmctl); + + /* + * Set the receive descriptor and status queues' base address, + * current address, and length registers. Enable the receive + * descriptor processor. + */ + writel((uint32_t)priv->rx_dq.base, ®s->rxdq.badd); + writel((uint32_t)priv->rx_dq.base, ®s->rxdq.curadd); + writel(sizeof(struct rx_descriptor) * NUMRXDESC, ®s->rxdq.blen); + + writel((uint32_t)priv->rx_sq.base, ®s->rxstsq.badd); + writel((uint32_t)priv->rx_sq.base, ®s->rxstsq.curadd); + writel(sizeof(struct rx_status) * NUMRXDESC, ®s->rxstsq.blen); + + writel(0x00040000, ®s->rxdthrshld); + + writel(BMCTL_RXEN, ®s->bmctl); + + writel(0x00040000, ®s->rxststhrshld); + + /* Wait until the receive descriptor processor is active */ + while (!(readl(®s->bmsts) & BMSTS_RXACT)) + ; /* noop */ + + /* + * Initialize the RX descriptor queue. Clear the TX descriptor queue. + * Clear the RX and TX status queues. Enqueue the RX descriptor and + * status entries to the MAC. + */ + for (i = 0; i < NUMRXDESC; i++) { + /* set buffer address */ + (priv->rx_dq.base + i)->word1 = (uint32_t)NetRxPackets[i]; + + /* set buffer length, clear buffer index and NSOF */ + (priv->rx_dq.base + i)->word2 = PKTSIZE_ALIGN; + } + + memset(priv->tx_dq.base, 0, + (sizeof(struct tx_descriptor) * NUMTXDESC)); + memset(priv->rx_sq.base, 0, + (sizeof(struct rx_status) * NUMRXDESC)); + memset(priv->tx_sq.base, 0, + (sizeof(struct tx_status) * NUMTXDESC)); + + writel(NUMRXDESC, ®s->rxdqenq); + writel(NUMRXDESC, ®s->rxstsqenq); + + /* Turn on RX and TX */ + writel(RXCTL_IA0 | RXCTL_BA | RXCTL_SRXON | + RXCTL_RCRCA | RXCTL_MA, ®s->rxctl); + writel(TXCTL_STXON, ®s->txctl); + + /* Dump data structures if we're debugging */ + dump_dev(); + dump_rx_descriptor_queue(); + dump_rx_status_queue(); + dump_tx_descriptor_queue(); + dump_tx_status_queue(); + + pr_debug("-ep93xx_eth_open\n"); + + return 0; +} + +/** + * Halt EP93xx MAC transmit and receive by clearing the TxCTL and RxCTL + * registers. + */ +static void ep93xx_eth_halt(struct eth_device *edev) +{ + struct mac_regs *regs = ep93xx_get_regs(edev); + + pr_debug("+ep93xx_eth_halt\n"); + + writel(0x00000000, ®s->rxctl); + writel(0x00000000, ®s->txctl); + + pr_debug("-ep93xx_eth_halt\n"); +} + +static int ep93xx_eth_get_ethaddr(struct eth_device *edev, + unsigned char *mac_addr) +{ + struct mac_regs *regs = ep93xx_get_regs(edev); + uint32_t value; + + value = readl(®s->indad); + mac_addr[0] = value & 0xFF; + mac_addr[1] = (value >> 8) & 0xFF; + mac_addr[2] = (value >> 16) & 0xFF; + mac_addr[3] = (value >> 24) & 0xFF; + + value = readl(®s->indad_upper); + mac_addr[4] = value & 0xFF; + mac_addr[5] = (value >> 8) & 0xFF; + + return 0; +} + +static int ep93xx_eth_set_ethaddr(struct eth_device *edev, + unsigned char *mac_addr) +{ + struct mac_regs *regs = ep93xx_get_regs(edev); + + writel(AFP_IAPRIMARY, ®s->afp); + + writel(mac_addr[0] | (mac_addr[1] << 8) | + (mac_addr[2] << 16) | (mac_addr[3] << 24), + ®s->indad); + writel(mac_addr[4] | (mac_addr[5] << 8), ®s->indad_upper); + + return 0; +} + +static int ep93xx_eth_probe(struct device_d *dev) +{ + struct eth_device *edev; + struct ep93xx_eth_priv *priv; + int ret = -1; + + pr_debug("ep93xx_eth_probe()\n"); + + edev = xzalloc(sizeof(struct eth_device) + + sizeof(struct ep93xx_eth_priv)); + dev->type_data = edev; + edev->priv = (struct ep93xx_eth_priv *)(edev + 1); + + priv = edev->priv; + priv->regs = (struct mac_regs *)MAC_BASE; + + edev->init = ep93xx_eth_init_dev; + edev->open = ep93xx_eth_open; + edev->send = ep93xx_eth_send_packet; + edev->recv = ep93xx_eth_rcv_packet; + edev->halt = ep93xx_eth_halt; + edev->get_ethaddr = ep93xx_eth_get_ethaddr; + edev->set_ethaddr = ep93xx_eth_set_ethaddr; + + priv->miiphy.read = ep93xx_phy_read; + priv->miiphy.write = ep93xx_phy_write; + priv->miiphy.address = 0; + priv->miiphy.flags = 0; + + priv->tx_dq.base = calloc(NUMTXDESC, + sizeof(struct tx_descriptor)); + if (priv->tx_dq.base == NULL) { + pr_err("calloc() failed: tx_dq.base"); + goto eth_probe_failed_0; + } + + priv->tx_sq.base = calloc(NUMTXDESC, + sizeof(struct tx_status)); + if (priv->tx_sq.base == NULL) { + pr_err("calloc() failed: tx_sq.base"); + goto eth_probe_failed_1; + } + + priv->rx_dq.base = calloc(NUMRXDESC, + sizeof(struct rx_descriptor)); + if (priv->rx_dq.base == NULL) { + pr_err("calloc() failed: rx_dq.base"); + goto eth_probe_failed_2; + } + + priv->rx_sq.base = calloc(NUMRXDESC, + sizeof(struct rx_status)); + if (priv->rx_sq.base == NULL) { + pr_err("calloc() failed: rx_sq.base"); + goto eth_probe_failed_3; + } + + miiphy_register(&priv->miiphy); + eth_register(edev); + + ret = 0; + + goto eth_probe_done; + +eth_probe_failed_3: + free(priv->rx_dq.base); + /* Fall through */ + +eth_probe_failed_2: + free(priv->tx_sq.base); + /* Fall through */ + +eth_probe_failed_1: + free(priv->tx_dq.base); + /* Fall through */ + +eth_probe_failed_0: + /* Fall through */ + +eth_probe_done: + return ret; +} + +/** + * Copy a frame of data from the MAC into the protocol layer for further + * processing. + */ +static int ep93xx_eth_rcv_packet(struct eth_device *edev) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + struct mac_regs *regs = ep93xx_get_regs(edev); + int ret = -1; + + pr_debug("+ep93xx_eth_rcv_packet\n"); + + if (RX_STATUS_RFP(priv->rx_sq.current)) { + if (RX_STATUS_RWE(priv->rx_sq.current)) { + /* + * We have a good frame. Extract the frame's length + * from the current rx_status_queue entry, and copy + * the frame's data into NetRxPackets[] of the + * protocol stack. We track the total number of + * bytes in the frame (nbytes_frame) which will be + * used when we pass the data off to the protocol + * layer via NetReceive(). + */ + NetReceive((uchar *)priv->rx_dq.current->word1, + RX_STATUS_FRAME_LEN(priv->rx_sq.current)); + pr_debug("reporting %d bytes...\n", + RX_STATUS_FRAME_LEN(priv->rx_sq.current)); + + ret = 0; + + } else { + /* Do we have an erroneous packet? */ + pr_err("packet rx error, status %08X %08X\n", + priv->rx_sq.current->word1, + priv->rx_sq.current->word2); + dump_rx_descriptor_queue(); + dump_rx_status_queue(); + } + + /* + * Clear the associated status queue entry, and + * increment our current pointers to the next RX + * descriptor and status queue entries (making sure + * we wrap properly). + */ + memset((void *)priv->rx_sq.current, 0, + sizeof(struct rx_status)); + + priv->rx_sq.current++; + if (priv->rx_sq.current >= priv->rx_sq.end) + priv->rx_sq.current = priv->rx_sq.base; + + priv->rx_dq.current++; + if (priv->rx_dq.current >= priv->rx_dq.end) + priv->rx_dq.current = priv->rx_dq.base; + + /* + * Finally, return the RX descriptor and status entries + * back to the MAC engine, and loop again, checking for + * more descriptors to process. + */ + writel(1, ®s->rxdqenq); + writel(1, ®s->rxstsqenq); + } else { + ret = 0; + } + + pr_debug("-ep93xx_eth_rcv_packet %d\n", ret); + + return ret; +} + +/** + * Send a block of data via ethernet. + */ +static int ep93xx_eth_send_packet(struct eth_device *edev, + void *packet, int length) +{ + struct ep93xx_eth_priv *priv = ep93xx_get_priv(edev); + struct mac_regs *regs = ep93xx_get_regs(edev); + int ret = -1; + + pr_debug("+ep93xx_eth_send_packet\n"); + + /* + * Initialize the TX descriptor queue with the new packet's info. + * Clear the associated status queue entry. Enqueue the packet + * to the MAC for transmission. + */ + + /* set buffer address */ + priv->tx_dq.current->word1 = (uint32_t)packet; + + /* set buffer length and EOF bit */ + priv->tx_dq.current->word2 = length | TX_DESC_EOF; + + /* clear tx status */ + priv->tx_sq.current->word1 = 0; + + /* enqueue the TX descriptor */ + writel(1, ®s->txdqenq); + + /* wait for the frame to become processed */ + while (!TX_STATUS_TXFP(priv->tx_sq.current)) + ; /* noop */ + + if (!TX_STATUS_TXWE(priv->tx_sq.current)) { + pr_err("packet tx error, status %08X\n", + priv->tx_sq.current->word1); + dump_tx_descriptor_queue(); + dump_tx_status_queue(); + + /* TODO: Add better error handling? */ + goto eth_send_failed_0; + } + + ret = 0; + /* Fall through */ + +eth_send_failed_0: + pr_debug("-ep93xx_eth_send_packet %d\n", ret); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * EP93xx ethernet MII functionality. + */ + +/** + * Maximum MII address we support + */ +#define MII_ADDRESS_MAX (31) + +/** + * Maximum MII register address we support + */ +#define MII_REGISTER_MAX (31) + +/** + * Read a 16-bit value from an MII register. + */ +static int ep93xx_phy_read(struct miiphy_device *mdev, uint8_t phy_addr, + uint8_t phy_reg, uint16_t *value) +{ + struct mac_regs *regs = ep93xx_get_regs(mdev->edev); + int ret = -1; + uint32_t self_ctl; + + pr_debug("+ep93xx_phy_read\n"); + + /* + * Save the current SelfCTL register value. Set MAC to suppress + * preamble bits. Wait for any previous MII command to complete + * before issuing the new command. + */ + self_ctl = readl(®s->selfctl); +#if defined(CONFIG_MII_SUPPRESS_PREAMBLE) /* TODO */ + writel(self_ctl & ~(1 << 8), ®s->selfctl); +#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */ + + while (readl(®s->miists) & MIISTS_BUSY) + ; /* noop */ + + /* + * Issue the MII 'read' command. Wait for the command to complete. + * Read the MII data value. + */ + writel(MIICMD_OPCODE_READ | ((uint32_t)phy_addr << 5) | + (uint32_t)phy_reg, ®s->miicmd); + while (readl(®s->miists) & MIISTS_BUSY) + ; /* noop */ + + *value = (unsigned short)readl(®s->miidata); + + /* Restore the saved SelfCTL value and return. */ + writel(self_ctl, ®s->selfctl); + + ret = 0; + + pr_debug("-ep93xx_phy_read\n"); + + return ret; +} + +/** + * Write a 16-bit value to an MII register. + */ +static int ep93xx_phy_write(struct miiphy_device *mdev, uint8_t phy_addr, + uint8_t phy_reg, uint16_t value) +{ + struct mac_regs *regs = ep93xx_get_regs(mdev->edev); + int ret = -1; + uint32_t self_ctl; + + pr_debug("+ep93xx_phy_write\n"); + + /* + * Save the current SelfCTL register value. Set MAC to suppress + * preamble bits. Wait for any previous MII command to complete + * before issuing the new command. + */ + self_ctl = readl(®s->selfctl); +#if defined(CONFIG_MII_SUPPRESS_PREAMBLE) /* TODO */ + writel(self_ctl & ~(1 << 8), ®s->selfctl); +#endif /* defined(CONFIG_MII_SUPPRESS_PREAMBLE) */ + + while (readl(®s->miists) & MIISTS_BUSY) + ; /* noop */ + + /* Issue the MII 'write' command. Wait for the command to complete. */ + writel((uint32_t)value, ®s->miidata); + writel(MIICMD_OPCODE_WRITE | ((uint32_t)phy_addr << 5) | phy_reg, + ®s->miicmd); + while (readl(®s->miists) & MIISTS_BUSY) + ; /* noop */ + + /* Restore the saved SelfCTL value and return. */ + writel(self_ctl, ®s->selfctl); + + ret = 0; + + pr_debug("-ep93xx_phy_write\n"); + + return ret; +} + +static struct driver_d ep93xx_eth_driver = { + .name = "ep93xx_eth", + .probe = ep93xx_eth_probe, +}; + +static int ep93xx_eth_init(void) +{ + register_driver(&ep93xx_eth_driver); + return 0; +} + +device_initcall(ep93xx_eth_init); diff --git a/drivers/net/ep93xx.h b/drivers/net/ep93xx.h new file mode 100644 index 0000000..ae45c54 --- /dev/null +++ b/drivers/net/ep93xx.h @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2009 Matthias Kaehlcke + * + * Copyright (C) 2004, 2005 + * Cory T. Tusar, Videon Central, Inc., + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#ifndef _ETH_H +#define _ETH_H + +#include + +/** + * #define this to dump device status and queue info during initialization and + * following errors. + */ +#undef EP93XX_MAC_DEBUG + +/** + * Number of descriptor and status entries in our RX queues. + * It must be power of 2 ! + */ +#define NUMRXDESC PKTBUFSRX + +/** + * Number of descriptor and status entries in our TX queues. + */ +#define NUMTXDESC 1 + +/** + * 944 = (1024 - 64) - 16, Fifo size - Minframesize - 16 (Chip FACT) + */ +#define TXSTARTMAX 944 + +/** + * Receive descriptor queue entry + */ +struct rx_descriptor { + uint32_t word1; + uint32_t word2; +} __attribute__((packed)); + +/** + * Receive status queue entry + */ +struct rx_status { + uint32_t word1; + uint32_t word2; +} __attribute__((packed)); + +#define RX_STATUS_RWE(rx_status) ((rx_status->word1 >> 30) & 0x01) +#define RX_STATUS_RFP(rx_status) ((rx_status->word1 >> 31) & 0x01) +#define RX_STATUS_FRAME_LEN(rx_status) (rx_status->word2 & 0xFFFF) + + +/** + * Transmit descriptor queue entry + */ +struct tx_descriptor { + uint32_t word1; + uint32_t word2; +} __attribute__((packed)); + +#define TX_DESC_EOF (1 << 31) + +/** + * Transmit status queue entry + */ +struct tx_status { + uint32_t word1; +} __attribute__((packed)); + +#define TX_STATUS_TXWE(tx_status) (((tx_status)->word1 >> 30) & 0x01) +#define TX_STATUS_TXFP(tx_status) (((tx_status)->word1 >> 31) & 0x01) + +/** + * Transmit descriptor queue + */ +struct tx_descriptor_queue { + struct tx_descriptor *base; + struct tx_descriptor *current; + struct tx_descriptor *end; +}; + +/** + * Transmit status queue + */ +struct tx_status_queue { + struct tx_status *base; + volatile struct tx_status *current; + struct tx_status *end; +}; + +/** + * Receive descriptor queue + */ +struct rx_descriptor_queue { + struct rx_descriptor *base; + struct rx_descriptor *current; + struct rx_descriptor *end; +}; + +/** + * Receive status queue + */ +struct rx_status_queue { + struct rx_status *base; + volatile struct rx_status *current; + struct rx_status *end; +}; + +/** + * EP93xx MAC private data structure + */ +struct ep93xx_eth_priv { + struct mac_regs *regs; + + struct rx_descriptor_queue rx_dq; + struct rx_status_queue rx_sq; + void *rx_buffer[NUMRXDESC]; + + struct tx_descriptor_queue tx_dq; + struct tx_status_queue tx_sq; + + struct miiphy_device miiphy; +}; + +#endif diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b0ff5fa..8a5056b 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -47,6 +47,13 @@ help Say Y here if you are using OMAP extensions to NS16550 +config DRIVER_SERIAL_PL010 + depends on ARCH_EP93XX + default y + bool "ARM AMBA PL010 support" + help + Enable this to get support for AMBA PL010 based serial devices + config DRIVER_SERIAL_S3C24X0 bool "Samsung S3C24X0 serial driver" depends on ARCH_S3C24xx diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 8ab680d..9f203bb 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -3,7 +3,6 @@ # s3c4510b_uart.o # serial_max3100.o # serial_pl010.o -# serial_pl011.o # serial_xuartlite.o obj-$(CONFIG_DRIVER_SERIAL_ARM_DCC) += arm_dcc.o obj-$(CONFIG_DRIVER_SERIAL_IMX) += serial_imx.o @@ -13,4 +12,5 @@ obj-$(CONFIG_DRIVER_SERIAL_MPC5XXX) += serial_mpc5xxx.o obj-$(CONFIG_DRIVER_SERIAL_BLACKFIN) += serial_blackfin.o obj-$(CONFIG_DRIVER_SERIAL_NS16550) += serial_ns16550.o +obj-$(CONFIG_DRIVER_SERIAL_PL010) += serial_pl010.o obj-$(CONFIG_DRIVER_SERIAL_S3C24X0) += serial_s3c24x0.o diff --git a/drivers/serial/serial_pl010.c b/drivers/serial/serial_pl010.c new file mode 100644 index 0000000..1a6366f --- /dev/null +++ b/drivers/serial/serial_pl010.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2010 Matthias Kaehlcke + * + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * (C) Copyright 2004 + * ARM Ltd. + * Philippe Robin, + * + * 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 + */ + +/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ + +#include +#include +#include +#include +#include "serial_pl010.h" + +static int pl010_setbaudrate(struct console_device *cdev, int baudrate) +{ + struct pl010_struct *pl010 = (struct pl010_struct *)cdev->dev->map_base; + unsigned int divisor; + + switch (baudrate) { + case 9600: + divisor = UART_PL010_BAUD_9600; + break; + + case 19200: + divisor = UART_PL010_BAUD_9600; + break; + + case 38400: + divisor = UART_PL010_BAUD_38400; + break; + + case 57600: + divisor = UART_PL010_BAUD_57600; + break; + + case 115200: + divisor = UART_PL010_BAUD_115200; + break; + + default: + divisor = UART_PL010_BAUD_38400; + } + + writel((divisor & 0xf00) >> 8, &pl010->linctrlmid); + writel(divisor & 0xff, &pl010->linctrllow); + + /* high register must always be written */ + writel(readl(&pl010->linctrlhigh), &pl010->linctrlhigh); + + return 0; +} + +static int pl010_init_port(struct console_device *cdev) +{ + struct pl010_struct *pl010 = (struct pl010_struct *)cdev->dev->map_base; + + /* + * First, disable everything. + */ + writel(0x00, &pl010->ctrl); + + /* + * Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled. + */ + writel(UART_PL010_LCRH_WLEN_8 | UART_PL010_LCRH_FEN, + &pl010->linctrlhigh); + + /* + * Finally, enable the UART + */ + writel(UART_PL010_CR_UARTEN, &pl010->ctrl); + + return 0; +} + +static void pl010_putc(struct console_device *cdev, char c) +{ + struct pl010_struct *pl010 = (struct pl010_struct *)cdev->dev->map_base; + + /* Wait until there is space in the FIFO */ + while (readl(&pl010->flag) & UART_PL010_FR_TXFF) + ; /* noop */ + + /* Send the character */ + writel(c, &pl010->data); +} + +static int pl010_getc(struct console_device *cdev) +{ + struct pl010_struct *pl010 = (struct pl010_struct *)cdev->dev->map_base; + unsigned int data; + + /* Wait until there is data in the FIFO */ + while (readl(&pl010->flag) & UART_PL010_FR_RXFE) + ; /* noop */ + + data = readl(&pl010->data); + + /* Check for an error flag */ + if (data & 0xFFFFFF00) { + /* Clear the error */ + writel(0xFFFFFFFF, &pl010->errclr); + return -1; + } + + return (int)data; +} + +static int pl010_tstc(struct console_device *cdev) +{ + struct pl010_struct *pl010 = (struct pl010_struct *)cdev->dev->map_base; + + return !(readl(&pl010->flag) & UART_PL010_FR_RXFE); +} + +static int pl010_probe(struct device_d *dev) +{ + struct console_device *cdev; + + cdev = malloc(sizeof(struct console_device)); + dev->type_data = cdev; + cdev->dev = dev; + cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR; + cdev->tstc = pl010_tstc; + cdev->putc = pl010_putc; + cdev->getc = pl010_getc; + cdev->setbrg = pl010_setbaudrate; + + pl010_init_port(cdev); + + console_register(cdev); + + return 0; +} + +static struct driver_d pl010_driver = { + .name = "pl010_serial", + .probe = pl010_probe, +}; + +static int pl010_init(void) +{ + register_driver(&pl010_driver); + + return 0; +} + +console_initcall(pl010_init); diff --git a/drivers/serial/serial_pl010.h b/drivers/serial/serial_pl010.h new file mode 100644 index 0000000..6124e0e --- /dev/null +++ b/drivers/serial/serial_pl010.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2010 Matthias Kaehlcke + * + * (C) Copyright 2003, 2004 + * ARM Ltd. + * Philippe Robin, + * + * 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 + */ + +struct hldc_struct { + uint32_t ctrl; + uint32_t addmtchval; + uint32_t addmask; + uint32_t rxinfobuf; + uint32_t sts; +}; + +struct pl010_struct { + uint32_t data; + union { + uint32_t rxsts; + uint32_t errclr; + }; + uint32_t linctrlhigh; + uint32_t linctrlmid; + uint32_t linctrllow; + uint32_t ctrl; + uint32_t flag; + union { + uint32_t intid; + uint32_t intclr; + }; + uint32_t not_used0[2]; + uint32_t dmactrl; + uint32_t not_used1[53]; + uint32_t modemctrl; + uint32_t modemsts; + uint32_t not_used2[65]; + struct hldc_struct hldc; +}; + +#define UART_PL010_RSR_OE (1 << 3) +#define UART_PL010_RSR_BE (1 << 2) +#define UART_PL010_RSR_PE (1 << 1) +#define UART_PL010_RSR_FE (1 << 0) + +#define UART_PL010_FR_TXFE (1 << 7) +#define UART_PL010_FR_RXFF (1 << 6) +#define UART_PL010_FR_TXFF (1 << 5) +#define UART_PL010_FR_RXFE (1 << 4) +#define UART_PL010_FR_BUSY (1 << 3) +#define UART_PL010_FR_TMSK (UART_PL010_FR_TXFF + UART_PL010_FR_BUSY) + +#define UART_PL010_CR_LPE (1 << 7) +#define UART_PL010_CR_RTIE (1 << 6) +#define UART_PL010_CR_TIE (1 << 5) +#define UART_PL010_CR_RIE (1 << 4) +#define UART_PL010_CR_MSIE (1 << 3) +#define UART_PL010_CR_IIRLP (1 << 2) +#define UART_PL010_CR_SIREN (1 << 1) +#define UART_PL010_CR_UARTEN (1 << 0) + +#define UART_PL010_LCRH_WLEN_8 (3 << 5) +#define UART_PL010_LCRH_WLEN_7 (2 << 5) +#define UART_PL010_LCRH_WLEN_6 (1 << 5) +#define UART_PL010_LCRH_WLEN_5 (0 << 5) +#define UART_PL010_LCRH_FEN (1 << 4) +#define UART_PL010_LCRH_STP2 (1 << 3) +#define UART_PL010_LCRH_EPS (1 << 2) +#define UART_PL010_LCRH_PEN (1 << 1) +#define UART_PL010_LCRH_BRK (1 << 0) + +#define UART_PL010_BAUD_460800 1 +#define UART_PL010_BAUD_230400 3 +#define UART_PL010_BAUD_115200 7 +#define UART_PL010_BAUD_57600 15 +#define UART_PL010_BAUD_38400 23 +#define UART_PL010_BAUD_19200 47 +#define UART_PL010_BAUD_14400 63 +#define UART_PL010_BAUD_9600 95 +#define UART_PL010_BAUD_4800 191 +#define UART_PL010_BAUD_2400 383 +#define UART_PL010_BAUD_1200 767 diff --git a/include/ata.h b/include/ata.h new file mode 100644 index 0000000..d56399e --- /dev/null +++ b/include/ata.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Declarations to communicate with ATA types of drives + */ + +#include +#include + +/** + * Access functions from drives through the specified interface + */ +struct ata_interface { + /** write a count of sectors from a buffer to the drive */ + int (*write)(struct device_d*, uint64_t, unsigned, const void*); + /** read a count of sectors from the drive into the buffer */ + int (*read)(struct device_d*, uint64_t, unsigned, void*); + /** private interface data */ + void *priv; +}; diff --git a/include/common.h b/include/common.h index 0c49d95..2b40954 100644 --- a/include/common.h +++ b/include/common.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #define pr_info(fmt, arg...) printf(fmt, ##arg) diff --git a/include/i2c/lp3972.h b/include/i2c/lp3972.h new file mode 100644 index 0000000..edb5801 --- /dev/null +++ b/include/i2c/lp3972.h @@ -0,0 +1,7 @@ +#ifndef __ASM_ARCH_LP3972_H +#define __ASM_ARCH_LP3972_H + +extern struct i2c_client *lp3972_get_client(void); + +#endif /* __ASM_ARCH_LP3972_H */ + diff --git a/include/i2c/mc13892.h b/include/i2c/mc13892.h index 2f44f6c..112d05b 100644 --- a/include/i2c/mc13892.h +++ b/include/i2c/mc13892.h @@ -1,7 +1,93 @@ +/* + * Copyright (C) 2009 Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + * Derived from: + * - arch-mxc/pmic_external.h -- contains interface of the PMIC protocol driver + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + */ + #ifndef __ASM_ARCH_MC13892_H #define __ASM_ARCH_MC13892_H -extern struct i2c_client *mc13892_get_client(void); +enum mc13892_reg { + MC13892_REG_INT_STATUS0 = 0x00, + MC13892_REG_INT_MASK0 = 0x01, + MC13892_REG_INT_SENSE0 = 0x02, + MC13892_REG_INT_STATUS1 = 0x03, + MC13892_REG_INT_MASK1 = 0x04, + MC13892_REG_INT_SENSE1 = 0x05, + MC13892_REG_PU_MODE_S = 0x06, + MC13892_REG_IDENTIFICATION = 0x07, + MC13892_REG_UNUSED0 = 0x08, + MC13892_REG_ACC0 = 0x09, + MC13892_REG_ACC1 = 0x0a, + MC13892_REG_UNUSED1 = 0x0b, + MC13892_REG_UNUSED2 = 0x0c, + MC13892_REG_POWER_CTL0 = 0x0d, + MC13892_REG_POWER_CTL1 = 0x0e, + MC13892_REG_POWER_CTL2 = 0x0f, + MC13892_REG_REGEN_ASSIGN = 0x10, + MC13892_REG_UNUSED3 = 0x11, + MC13892_REG_MEM_A = 0x12, + MC13892_REG_MEM_B = 0x13, + MC13892_REG_RTC_TIME = 0x14, + MC13892_REG_RTC_ALARM = 0x15, + MC13892_REG_RTC_DAY = 0x16, + MC13892_REG_RTC_DAY_ALARM = 0x17, + MC13892_REG_SW_0 = 0x18, + MC13892_REG_SW_1 = 0x19, + MC13892_REG_SW_2 = 0x1a, + MC13892_REG_SW_3 = 0x1b, + MC13892_REG_SW_4 = 0x1c, + MC13892_REG_SW_5 = 0x1d, + MC13892_REG_SETTING_0 = 0x1e, + MC13892_REG_SETTING_1 = 0x1f, + MC13892_REG_MODE_0 = 0x20, + MC13892_REG_MODE_1 = 0x21, + MC13892_REG_POWER_MISC = 0x22, + MC13892_REG_UNUSED4 = 0x23, + MC13892_REG_UNUSED5 = 0x24, + MC13892_REG_UNUSED6 = 0x25, + MC13892_REG_UNUSED7 = 0x26, + MC13892_REG_UNUSED8 = 0x27, + MC13892_REG_UNUSED9 = 0x28, + MC13892_REG_UNUSED10 = 0x29, + MC13892_REG_UNUSED11 = 0x2a, + MC13892_REG_ADC0 = 0x2b, + MC13892_REG_ADC1 = 0x2c, + MC13892_REG_ADC2 = 0x2d, + MC13892_REG_ADC3 = 0x2e, + MC13892_REG_ADC4 = 0x2f, + MC13892_REG_CHARGE = 0x30, + MC13892_REG_USB0 = 0x31, + MC13892_REG_USB1 = 0x32, + MC13892_REG_LED_CTL0 = 0x33, + MC13892_REG_LED_CTL1 = 0x34, + MC13892_REG_LED_CTL2 = 0x35, + MC13892_REG_LED_CTL3 = 0x36, + MC13892_REG_UNUSED12 = 0x37, + MC13892_REG_UNUSED13 = 0x38, + MC13892_REG_TRIM0 = 0x39, + MC13892_REG_TRIM1 = 0x3a, + MC13892_REG_TEST0 = 0x3b, + MC13892_REG_TEST1 = 0x3c, + MC13892_REG_TEST2 = 0x3d, + MC13892_REG_TEST3 = 0x3e, + MC13892_REG_TEST4 = 0x3f, +}; + +struct mc13892 { + struct cdev cdev; + struct i2c_client *client; +}; + +extern struct mc13892 *mc13892_get(void); + +extern int mc13892_reg_read(struct mc13892 *mc13892, enum mc13892_reg reg, u32 *val); +extern int mc13892_reg_write(struct mc13892 *mc13892, enum mc13892_reg reg, u32 val); +extern int mc13892_set_bits(struct mc13892 *mc13892, enum mc13892_reg reg, u32 mask, u32 val); #endif /* __ASM_ARCH_MC13892_H */ - diff --git a/include/i2c/mc9sdz60.h b/include/i2c/mc9sdz60.h index 04cfca0..4cc233e 100644 --- a/include/i2c/mc9sdz60.h +++ b/include/i2c/mc9sdz60.h @@ -1,7 +1,64 @@ +/* + * Copyright (C) 2009 Marc Kleine-Budde + * + * This file is released under the GPLv2 + * + * Derived from: + * - mcu_max8660-bus.h -- contains interface of the mc9sdz60 and max8660 + * Copyright 2004-2009 Freescale Semiconductor, Inc. All Rights Reserved. + * + */ + #ifndef __ASM_ARCH_MC9SDZ60_H #define __ASM_ARCH_MC9SDZ60_H -extern struct i2c_client *mc9sdz60_get_client(void); +enum mc9sdz60_reg { + MC9SDZ60_REG_VERSION = 0x00, + MC9SDZ60_REG_SECS = 0x01, + MC9SDZ60_REG_MINS = 0x02, + MC9SDZ60_REG_HRS = 0x03, + MC9SDZ60_REG_DAY = 0x04, + MC9SDZ60_REG_DATE = 0x05, + MC9SDZ60_REG_MONTH = 0x06, + MC9SDZ60_REG_YEAR = 0x07, + MC9SDZ60_REG_ALARM_SECS = 0x08, + MC9SDZ60_REG_ALARM_MINS = 0x09, + MC9SDZ60_REG_ALARM_HRS = 0x0a, + MC9SDZ60_REG_TS_CONTROL = 0x0b, + MC9SDZ60_REG_X_LOW = 0x0c, + MC9SDZ60_REG_Y_LOW = 0x0d, + MC9SDZ60_REG_XY_HIGH = 0x0e, + MC9SDZ60_REG_X_LEFT_LOW = 0x0f, + MC9SDZ60_REG_X_LEFT_HIGH = 0x10, + MC9SDZ60_REG_X_RIGHT = 0x11, + MC9SDZ60_REG_Y_TOP_LOW = 0x12, + MC9SDZ60_REG_Y_TOP_HIGH = 0x13, + MC9SDZ60_REG_Y_BOTTOM = 0x14, + MC9SDZ60_REG_RESET_1 = 0x15, + MC9SDZ60_REG_RESET_2 = 0x16, + MC9SDZ60_REG_POWER_CTL = 0x17, + MC9SDZ60_REG_DELAY_CONFIG = 0x18, + MC9SDZ60_REG_GPIO_1 = 0x19, + MC9SDZ60_REG_GPIO_2 = 0x1a, + MC9SDZ60_REG_KPD_1 = 0x1b, + MC9SDZ60_REG_KPD_2 = 0x1c, + MC9SDZ60_REG_KPD_CONTROL = 0x1d, + MC9SDZ60_REG_INT_ENABLE_1 = 0x1e, + MC9SDZ60_REG_INT_ENABLE_2 = 0x1f, + MC9SDZ60_REG_INT_FLAG_1 = 0x20, + MC9SDZ60_REG_INT_FLAG_2 = 0x21, + MC9SDZ60_REG_DES_FLAG = 0x22, +}; + +struct mc9sdz60 { + struct cdev cdev; + struct i2c_client *client; +}; + +extern struct mc9sdz60 *mc9sdz60_get(void); + +extern int mc9sdz60_reg_read(struct mc9sdz60 *priv, enum mc9sdz60_reg reg, u8 *val); +extern int mc9sdz60_reg_write(struct mc9sdz60 *priv, enum mc9sdz60_reg reg, u8 val); +extern int mc9sdz60_set_bits(struct mc9sdz60 *priv, enum mc9sdz60_reg reg, u8 mask, u8 val); #endif /* __ASM_ARCH_MC9SDZ60_H */ - diff --git a/scripts/Makefile b/scripts/Makefile index c22a8b6..be8e3e0 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -14,5 +14,7 @@ subdir-y += mod +subdir-$(CONFIG_X86) += setupmbr + # Let clean descend into subdirs -subdir- += basic kconfig +subdir- += basic kconfig setupmbr diff --git a/scripts/setupmbr/Makefile b/scripts/setupmbr/Makefile new file mode 100644 index 0000000..8680fed --- /dev/null +++ b/scripts/setupmbr/Makefile @@ -0,0 +1,4 @@ +HOST_EXTRACFLAGS=-I$(srctree) + +hostprogs-y := setupmbr +always := $(hostprogs-y) diff --git a/scripts/setupmbr/arch.h b/scripts/setupmbr/arch.h new file mode 100644 index 0000000..a720dfe --- /dev/null +++ b/scripts/setupmbr/arch.h @@ -0,0 +1,55 @@ + +/* we need the one from the host */ +#include +#include + +/* Byte-orders. */ +#define swap16(x) \ +({ \ + uint16_t _x = (x); \ + (uint16_t) ((_x << 8) | (_x >> 8)); \ +}) + +#define swap32(x) \ +({ \ + uint32_t _x = (x); \ + (uint32_t) ((_x << 24) \ + | ((_x & (uint32_t) 0xFF00UL) << 8) \ + | ((_x & (uint32_t) 0xFF0000UL) >> 8) \ + | (_x >> 24)); \ +}) + +#define swap64(x) \ +({ \ + uint64_t _x = (x); \ + (uint64_t) ((_x << 56) \ + | ((_x & (uint64_t) 0xFF00ULL) << 40) \ + | ((_x & (uint64_t) 0xFF0000ULL) << 24) \ + | ((_x & (uint64_t) 0xFF000000ULL) << 8) \ + | ((_x & (uint64_t) 0xFF00000000ULL) >> 8) \ + | ((_x & (uint64_t) 0xFF0000000000ULL) >> 24) \ + | ((_x & (uint64_t) 0xFF000000000000ULL) >> 40) \ + | (_x >> 56)); \ +}) + +#if __BYTE_ORDER == __BIG_ENDIAN + +/* Our target is a ia32 machine, always little endian */ + +# define host2target_16(x) swap16(x) +# define host2target_32(x) swap32(x) +# define host2target_64(x) swap64(x) +# define target2host_16(x) swap16(x) +# define target2host_32(x) swap32(x) +# define target2host_64(x) swap64(x) + +#else + +# define host2target_16(x) (x) +# define host2target_32(x) (x) +# define host2target_64(x) (x) +# define target2host_16(x) (x) +# define target2host_32(x) (x) +# define target2host_64(x) (x) + +#endif diff --git a/scripts/setupmbr/setupmbr.c b/scripts/setupmbr/setupmbr.c new file mode 100644 index 0000000..01e8c64 --- /dev/null +++ b/scripts/setupmbr/setupmbr.c @@ -0,0 +1,705 @@ +/* + * Copyright (C) 2009 Juergen Beisert, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +/** + * @file + * @brief Write the barebox binary to the MBR and the following disk sectors + * + * Also patch dedicated locations in the image to make it work at runtime + * + * Current restrictions are: + * - only installs into MBR and the sectors after it + * - tested only with QEMU + * - and maybe some others + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* include the info from this barebox release */ +#include "include/linux/utsrelease.h" +#include "arch/x86/include/asm/barebox.lds.h" + +/** define to disable integrity tests and debug messages */ +#define NDEBUG + +/* some infos about our target architecture */ +#include "arch.h" + +/** + * "Disk Address Packet Structure" to be used when calling int13, + * function 0x42 + * + * @note All entries are in target endianess + */ +struct DAPS +{ + uint8_t size; /**< size of this data set, 0 marks it as invalid */ + uint8_t res1; /**< always 0 */ + int8_t count; /**< number of sectors 0...127 to handle */ + uint8_t res2; /**< always 0 */ + uint16_t offset; /**< store address: offset */ + uint16_t segment; /**< store address: segment */ + uint64_t lba; /**< start sector number in LBA */ +} __attribute__ ((packed)); + +/** + * Description of one partition table entry (D*S type) + * + * @note All entries are in target endianess + */ +struct partition_entry { + uint8_t boot_indicator; + uint8_t chs_begin[3]; + uint8_t type; + uint8_t chs_end[3]; + uint32_t partition_start; /* LE */ + uint32_t partition_size; /* LE */ +} __attribute__ ((packed)); + +#ifndef NDEBUG +static void debugout(const struct DAPS *entry, int supress_entry) +{ + if (supress_entry) + printf("DAPS entry: "); + else + printf("DAPS entry % 3u: ", ((unsigned)entry & ( SECTOR_SIZE - 1)) / sizeof(struct DAPS)); + + printf("Size: % 2u, Count: % 3d, Offset: 0x%04hX, Segment: 0x%04hX, LBA: %llu\n", + entry->size, entry->count, + target2host_16(entry->offset), target2host_16(entry->segment), + target2host_64(entry->lba)); +} +#else +# define debugout(x,y) (__ASSERT_VOID_CAST(0)) +#endif + +/** + * Fill *one* DAPS + * @param sector The DAPS to fill + * @param count Sector count + * @param offset Realmode offset in the segment + * @param segment Real mode segment + * @param lba LBA of the first sector to read + * @return 0 on success + */ +static int fill_daps(struct DAPS *sector, unsigned count, unsigned offset, unsigned segment, uint64_t lba) +{ + assert(sector != NULL); + assert(count < 128); + assert(offset < 0x10000); + assert(segment < 0x10000); + + sector->size = sizeof(struct DAPS); + sector->res1 = 0; + sector->count = (int8_t)count; + sector->res2 = 0; + sector->offset = host2target_16(offset); + sector->segment = host2target_16(segment); + sector->lba = host2target_64(lba); + + return 0; +} + +/** + * Mark a DAPS invalid to let the boot loader code stop at this entry. + * @param sector The DAPS to be marked as invalid + * + * Marking as invalid must be done in accordance to the detection method + * the assembler routine in the boot loader uses: + * The current code tests for zero in the first two bytes of the DAPS. + */ +static void invalidate_daps(struct DAPS *sector) +{ + sector->size = MARK_DAPS_INVALID; + sector->res1 = 0; +} + +/** + * Create the indirect sector with the DAPS entries + * @param daps_table Where to store the entries + * @param size Size of the whole image in bytes + * @param pers_sector_count Count of sectors to skip after MBR for the persistant environment storage + * @return 0 on success + * + * This routine calculates the DAPS entries for the case the whole + * barebox images fits into the MBR itself and the sectors after it. + * This means the start of the first partition must keep enough sectors + * unused. + * It also skips 'pers_sector_count' sectors after the MBR for special + * usage if given. + */ +static int barebox_linear_image(struct DAPS *daps_table, off_t size, long pers_sector_count) +{ + unsigned offset = LOAD_AREA, next_offset; + unsigned segment = LOAD_SEGMENT; + unsigned chunk_size, i = 0; + uint64_t lba = 2 + pers_sector_count; + int rc; + + /* + * We can load up to 127 sectors in one chunk. What a bad number... + * So, we will load in chunks of 32 kiB. + */ + + /* at runtime two sectors from the image are already loaded: MBR and indirect */ + size -= 2 * SECTOR_SIZE; + /* and now round up to multiple of sector size */ + size = (size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); + + /* + * The largest image we can load with this method is: + * (SECTOR_SIZE / sizeof(DAPS) - 1) * 32 kiB + * For a 512 byte sector and a 16 byte DAPS: + * (512 / 16 - 1) * 32 kiB = 992 kiB + * Note: '- 1' to consider one entry is required to pad to a 32 kiB boundary + */ + + if (size >= (SECTOR_SIZE / sizeof(struct DAPS) - 1) * 32 * 1024) { + fprintf(stderr, "Image too large to boot. Max size is %zu kiB, image size is %lu kiB\n", + (SECTOR_SIZE / sizeof(struct DAPS) - 1) * 32, size / 1024); + return -1; + } + + if (size > 32 * 1024) { + /* first fill up until the next 32 k boundary */ + next_offset = (offset + 32 * 1024 -1) & ~0x7fff; + chunk_size = next_offset - offset; + if (chunk_size & (SECTOR_SIZE-1)) { + fprintf(stderr, "Unable to pad from %X to %X in multiple of sectors\n", offset, next_offset); + return -1; + } + + rc = fill_daps(&daps_table[i], chunk_size / SECTOR_SIZE, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + + /* calculate values to enter the loop for the other entries */ + size -= chunk_size; + i++; + lba += chunk_size / SECTOR_SIZE; + offset += chunk_size; + if (offset >= 0x10000) { + segment += 4096; + offset = 0; + } + + /* + * Now load the remaining image part in 32 kiB chunks + */ + while (size) { + if (size >= 32 * 1024 ) { + if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) { + fprintf(stderr, "Internal tool error: Too many DAPS entries!\n"); + return -1; + } + rc = fill_daps(&daps_table[i], 64, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + + size -= 32 * 1024; + lba += 64; + offset += 32 * 1024; + if (offset >= 0x10000) { + segment += 4096; + offset = 0; + } + i++; + } else { + if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) { + fprintf(stderr, "Internal tool error: Too many DAPS entries!\n"); + return -1; + } + rc = fill_daps(&daps_table[i], size / SECTOR_SIZE, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + size = 0; /* finished */ + i++; + } + }; + } else { + /* less than 32 kiB. Very small image... */ + rc = fill_daps(&daps_table[i], size / SECTOR_SIZE, offset, segment, lba); + if (rc != 0) + return -1; + debugout(&daps_table[i], 0); + i++; + } + + /* + * Do not mark an entry as invalid if the buffer is full. The + * boot code stops if all entries of a buffer are read. + */ + if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) + return 0; + + /* mark the last DAPS invalid */ + invalidate_daps(&daps_table[i]); + debugout(&daps_table[i], 0); + + return 0; +} + +/** + * Do some simple sanity checks if this sector could be an MBR + * @param sector Sector with data to check + * @param size Size of the buffer + * @return 0 if successfull + */ +static int check_for_valid_mbr(const uint8_t *sector, off_t size) +{ + if (size < SECTOR_SIZE) { + fprintf(stderr, "MBR too small to be valid\n"); + return -1; + } + + if ((sector[OFFSET_OF_SIGNATURE] != 0x55) || + (sector[OFFSET_OF_SIGNATURE + 1] != 0xAA)) { + fprintf(stderr, "No MBR signature found\n"); + return -1; + } + + /* FIXME: try to check if there is a valid partition table */ + return 0; +} + +/** + * Check space between start of the image and the start of the first partition + * @param hd_image HD image to examine + * @param size Size of the barebox image + * @return 0 on success, -1 if the barebox image is too large + */ +static int check_for_space(const void *hd_image, off_t size) +{ + struct partition_entry *partition; + uint8_t *mbr_disk_sector = (uint8_t*)hd_image; + off_t spare_sector_count; + + assert(hd_image != NULL); + assert(size > 0); + + if (check_for_valid_mbr(hd_image, size) != 0) + return -1; + + /* where to read */ + partition = (struct partition_entry*) &mbr_disk_sector[OFFSET_OF_PARTITION_TABLE]; + + /* TODO describes the first entry always the first partition? */ + spare_sector_count = target2host_32(partition->partition_start); + +#ifdef DEBUG + printf("Debug: Required free sectors for barebox prior first partition: %lu, hd image provides: %lu\n", + (size + SECTOR_SIZE - 1) / SECTOR_SIZE, spare_sector_count); +#endif + spare_sector_count *= SECTOR_SIZE; + if (spare_sector_count < size) { + fprintf(stderr, "Not enough space after MBR to store barebox\n"); + fprintf(stderr, "Move begin of the first partition beyond sector %lu\n", (size + SECTOR_SIZE - 1) / SECTOR_SIZE); + return -1; + } + + return 0; +} + +/** + * Setup the persistant environment storage information + * @param patch_area Where to patch + * @param pers_sector_start Start sector of the persistant environment storage + * @param pers_sector_count Count of sectors for the persistant environment storage + * @return 0 on success + */ +static int store_pers_env_info(void *patch_area, uint64_t pers_sector_start, long pers_sector_count) +{ + uint64_t *start_lba = (uint64_t*)(patch_area + PATCH_AREA_PERS_START); + uint16_t *count_lba = (uint16_t*)(patch_area + PATCH_AREA_PERS_SIZE); + + assert(patch_area != NULL); + assert(pers_sector_count >= 0); + + if (pers_sector_count == 0) { + *count_lba = host2target_16(PATCH_AREA_PERS_SIZE_UNUSED); + return 0; + } + + *start_lba = host2target_64(pers_sector_start); + *count_lba = host2target_16(pers_sector_count); + + return 0; +} + +/** + * Prepare the MBR and indirect sector for runtime + * @param fd_barebox barebox image to use + * @param fd_hd Hard disk image to prepare + * @param pers_sector_count Count of sectors to skip after MBR for the persistant environment storage + * @return 0 on success + * + * This routine expects a prepared hard disk image file with a partition table + * in its first sector. This method only is currently supported. + */ +static int barebox_overlay_mbr(int fd_barebox, int fd_hd, long pers_sector_count) +{ + const void *barebox_image; + void *hd_image; + int rc; + struct stat sb; + struct DAPS *embed; /* part of the MBR */ + struct DAPS *indirect; /* sector with indirect DAPS */ + off_t required_size; + + if (fstat(fd_barebox, &sb) == -1) { + perror("fstat"); + return -1; + } + + /* the barebox image won't be touched */ + barebox_image = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd_barebox, 0); + if (barebox_image == MAP_FAILED) { + perror("mmap"); + return -1; + } + + rc = check_for_valid_mbr(barebox_image, sb.st_size); + if (rc != 0) { + fprintf(stderr, "barebox image seems not valid: Bad MBR signature\n"); + goto on_error_hd; + } + + /* + * the persistant environment storage is in front of the main + * barebox image. To handle both, we need more space in front of the + * the first partition. + */ + required_size = sb.st_size + pers_sector_count * SECTOR_SIZE; + + /* the hd image will be modified */ + hd_image = mmap(NULL, required_size, PROT_READ | PROT_WRITE, + MAP_SHARED, fd_hd, 0); + if (hd_image == MAP_FAILED) { + perror("mmap"); + rc = -1; + goto on_error_hd; + } + + /* check for space */ + rc = check_for_space(hd_image, required_size); + if (rc != 0) + goto on_error_space; + + /* embed barebox's boot code into the disk drive image */ + memcpy(hd_image, barebox_image, OFFSET_OF_PARTITION_TABLE); + + /* + * embed the barebox main image into the disk drive image, + * but keep the persistant environment storage untouched + * (if defined), e.g. store the main image behind this special area. + */ + memcpy(hd_image + ((pers_sector_count + 1) * SECTOR_SIZE), + barebox_image + SECTOR_SIZE, sb.st_size - SECTOR_SIZE); + + /* now, prepare this hard disk image for BIOS based booting */ + embed = hd_image + PATCH_AREA; + indirect = hd_image + ((pers_sector_count + 1) * SECTOR_SIZE); + + /* + * Fill the embedded DAPS to let the basic boot code find the + * indirect sector at runtime + */ +#ifdef DEBUG + printf("Debug: Fill in embedded DAPS\n"); +#endif + rc = fill_daps(embed, 1, INDIRECT_AREA, INDIRECT_SEGMENT, + 1 + pers_sector_count); + if (rc != 0) + goto on_error_space; + debugout(embed, 1); + +#ifdef DEBUG + printf("Debug: Fill in indirect sector\n"); +#endif + /* + * fill the indirect sector with the remaining DAPS to load the + * whole barebox image at runtime + */ + rc = barebox_linear_image(indirect, sb.st_size, pers_sector_count); + if (rc != 0) + goto on_error_space; + + /* + * TODO: Replace the fixed LBA starting number by a calculated one, + * to support barebox as a chained loader in a different start + * sector than the MBR + */ + rc = store_pers_env_info(embed, 1, pers_sector_count); + if (rc != 0) + goto on_error_space; + +on_error_space: + munmap(hd_image, required_size); + +on_error_hd: + munmap((void*)barebox_image, sb.st_size); + + return rc; +} + +static void print_usage(const char *pname) +{ + printf("%s: Preparing a hard disk image for boot with barebox on x86.\n", pname); + printf("Usage is\n %s [options] -m -d \n", pname); + printf(" [options] are:\n -s sector count of the persistant environment storage\n"); + printf(" barebox's boot image file\n"); + printf(" HD image to store the barebox image\n"); + printf(" If no '-s ' was given, barebox occupies sectors 0 to n, else sector 0 and x+1 to n\n"); +} + +int main(int argc, char *argv[]) +{ + int rc = 0, c; + char *barebox_image_filename = NULL, *hd_image_filename = NULL; + int fd_barebox_image = 0, fd_hd_image = 0; + long barebox_pers_size = -1; + + if (argc == 1) { + print_usage(argv[0]); + exit(0); + } + + /* handle command line options first */ + while (1) { + c = getopt(argc, argv, "m:d:s:hv"); + if (c == -1) + break; + + switch (c) { + case 's': + barebox_pers_size = strtol(optarg, NULL, 0); + break; + case 'm': + barebox_image_filename = strdup(optarg); + break; + case 'd': + hd_image_filename = strdup(optarg); + break; + case 'h': + print_usage(argv[0]); + rc = 0; + goto on_error; + case 'v': + printf("setupmbr for u-boot-v%s\n", UTS_RELEASE); + printf("Send bug reports to 'barebox@lists.infradead.org'\n"); + rc = 0; + goto on_error; + } + } + + if (barebox_image_filename == NULL) { + print_usage(argv[0]); + rc = -1; + goto on_error; + } + + fd_barebox_image = open(barebox_image_filename, O_RDONLY); + if (fd_barebox_image == -1) { + fprintf(stderr, "Cannot open '%s' for reading\n", + barebox_image_filename); + rc = -1; + goto on_error; + } + + fd_hd_image = open(hd_image_filename, O_RDWR); + if (fd_hd_image == -1) { + fprintf(stderr, "Cannot open '%s'\n", hd_image_filename); + rc = -1; + goto on_error; + } + + if (barebox_pers_size < 0) + barebox_pers_size = 0; + + rc = barebox_overlay_mbr(fd_barebox_image, fd_hd_image, barebox_pers_size); + +on_error: + if (fd_barebox_image != -1) + close(fd_barebox_image); + if (fd_hd_image != -1) + close(fd_hd_image); + + if (barebox_image_filename != NULL) + free(barebox_image_filename); + if (hd_image_filename != NULL) + free(hd_image_filename); + + return rc; +} + +/** @page x86_bootloader barebox acting as PC bootloader + +@section x86_bootloader_features Features + +@a barebox can act as a bootloader for PC based systems. In this case a special +binary layout will be created to be able to store it on some media the PC +BIOS can boot from. It can boot Linux kernels stored also on the same boot +media and be configured at runtime, with the possibility to store the changed +configuration on the boot media. + +@section x86_bootloader_restrictions Restrictions + +Due to some BIOS and @a barebox restrictions the boot media must be +prepared in some special way: + +@li @a barebox must be stored in the MBR (Master Boot Record) of the boot media. + Currently its not possible to store and boot it in one of the partition + sectors (to use it as a second stage loader). This is no eternal + restriction. It only needs further effort to add this feature. +@li @a barebox currently cannot run a chained boot loader. Also, this is no + eternal restriction, only further effort needed. +@li @a barebox comes with limited filesystem support. There is currently no + support for the most common and popular filesystems used in the *NIX world. + This restricts locations where to store a kernel and other runtime + information +@li @a barebox must be stored to the first n sectors of the boot media. To ensure + this does not collide with partitions on the boot media, the first + partition must start at a sector behind the ones @a barebox occupies. +@li @a barebox handles its runtime configuration in a special way: It stores it + in a binary way into some reserved sectors ("persistant storage"). + +@section x86_bootloader_preparations Boot Preparations + +To store the @a barebox image to a boot media, it comes with the tool +@p setupmbr in the directory @p scripts/setupmbr/ . To be able to use it on +the boot media of your choice, some preparations are required: + +@subsection x86_bootloader_preparations_partition Keep Sectors free + +Build the @a barebox image and check its size. At least this amount of +sectors must be kept free after the MBR prior the first partition. Do this +simple calulation: + + sectors = (\ + 511) / 512 + +To be able to store the runtime configuration, further free sectors are +required. Its up to you and your requirements, how large this persistant +storage must be. If you need 16 kiB for this purpose, you need to keep +additional 32 sectors free. + +For this example we are reserving 300 sectors for the @a barebox image and +additionaly 32 sectors for the persistant storage. So, the first partition on +the boot media must start at sector 333 or later. + +Run the @p fdisk tool to setup such a partition table: + +@verbatim +[jb@host]~> fdisk /dev/sda +Command (m for help): p + +Disk /dev/sda: 20.7 MB, 212680704 bytes +16 heads, 63 sectors/track, 406 cylinders +Units = cylinders of 1008 * 512 = 516096 bytes + + Device Boot Start End Blocks Id System +@endverbatim + +Change the used units to @p sectors for easier handling. + +@verbatim +Command (m for help): u +Changing display/entry units to sectors + +Command (m for help): p + +Disk /dev/sda: 20.7 MB, 212680704 bytes +16 heads, 63 sectors/track, 406 cylinders, total 409248 sectors +Units = sectors of 1 * 512 = 512 bytes + + Device Boot Start End Blocks Id System +@endverbatim + +Now its possible to create the first partition with the required offset: + +@verbatim +Command (m for help): n +Command action + e extended + p primary partition (1-4) +p +Partition number (1-4): 1 +First sector (63-409247, default 63): 333 +Last sector or +size or +sizeM or +sizeK (333-409247, default 409247): +18M +Command (m for help): p + +Disk /dev/sda: 20.7 MB, 212680704 bytes +16 heads, 63 sectors/track, 406 cylinders, total 409248 sectors +Units = sectors of 1 * 512 = 512 bytes + + Device Boot Start End Blocks Id System +/dev/sda 333 35489 17578+ 83 Linux +@endverbatim + +That's all. Do whatever is required now with the new partition (formatting +and populating the root filesystem for example) to make it useful. + +In the next step, @a barebox gets installed to this boot media: + +@verbatim +[jb@host]~> scripts/setupmbr/setupmbr -s 32 -m ./barebox -d /dev/sda +@endverbatim + +This command writes the @a barebox image file './barebox' onto the device +@p /dev/sda. + +The @p -s option will keep the persistant storage sectors free and untouched +and set flags in the MBR to forward its existance, size and location to +@a barebox at runtime. @p setupmbr also does not change the partition table. + +The @a barebox image gets stored on the boot media like this: + +@verbatim +sector 0 1 33 333 + |---|-------------|--------------- ~~~ ------------|-------------- + MBR persistant barebox first + storage main image partition +@endverbatim + +If the @p -s option is omitted, the "persistant storage" part simply does +not exist: + +@verbatim +sector 0 1 333 + |---|--------------- ~~~ ------------|-------------- + MBR barebox first + main image partition +@endverbatim + +@note The @p setupmbr tool is also working on real image file than on device + nodes only. So, there is no restriction what kind of file will be + modified. +*/