From 3d26aca96d709eb5922cce379edefa75b5a93dfa Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 12 Jan 2010 20:30:36 +0100 Subject: [PATCH 01/32] ARM: Add support for EP93xx SoCs Add support for the Cirrus Logic EP93xx platform Signed-off-by: Matthias Kaehlcke Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 5 + arch/arm/Makefile | 9 + arch/arm/lib/barebox.lds.S | 5 + arch/arm/mach-ep93xx/Kconfig | 438 +++++++++++++ arch/arm/mach-ep93xx/Makefile | 3 + arch/arm/mach-ep93xx/clocksource.c | 96 +++ .../mach-ep93xx/include/mach/ep93xx-regs.h | 600 ++++++++++++++++++ arch/arm/mach-ep93xx/led.c | 62 ++ arch/arm/mach-ep93xx/led.h | 26 + arch/arm/mach-ep93xx/lowlevel_init.S | 64 ++ 10 files changed, 1308 insertions(+) create mode 100644 arch/arm/mach-ep93xx/Kconfig create mode 100644 arch/arm/mach-ep93xx/Makefile create mode 100644 arch/arm/mach-ep93xx/clocksource.c create mode 100644 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h create mode 100644 arch/arm/mach-ep93xx/led.c create mode 100644 arch/arm/mach-ep93xx/led.h create mode 100644 arch/arm/mach-ep93xx/lowlevel_init.S diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c091a996a..414a013bf 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -31,6 +31,10 @@ config ARCH_AT91RM9200 bool "Atmel AT91RM9200" select CPU_ARM920T +config ARCH_EP93XX + bool "Cirrus Logic EP93xx" + select CPU_ARM920T + config ARCH_IMX bool "Freescale iMX-based" select GENERIC_GPIO @@ -51,6 +55,7 @@ endchoice 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 47b002f9d..ede20854c 100644 --- a/arch/arm/Makefile +++ b/arch/arm/Makefile @@ -39,6 +39,7 @@ CPPFLAGS += $(CFLAGS_ABI) $(arch-y) $(tune-y) # 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_A9M2440) := a9m2440 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/lib/barebox.lds.S b/arch/arm/lib/barebox.lds.S index c8d1bb9d8..a5eaefa21 100644 --- a/arch/arm/lib/barebox.lds.S +++ b/arch/arm/lib/barebox.lds.S @@ -39,6 +39,11 @@ SECTIONS _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 000000000..ed6e9864c --- /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 000000000..d5786db2b --- /dev/null +++ b/arch/arm/mach-ep93xx/Makefile @@ -0,0 +1,3 @@ +obj-y += clocksource.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 000000000..2a7d90e4e --- /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/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h new file mode 100644 index 000000000..50bb0eb41 --- /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/led.c b/arch/arm/mach-ep93xx/led.c new file mode 100644 index 000000000..6d6b90235 --- /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 000000000..db9512fc3 --- /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 000000000..27c2c90b7 --- /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 From 6f4ed9536d2806e93f402eaf83755ffed542ca30 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 12 Jan 2010 20:30:41 +0100 Subject: [PATCH 02/32] Add EP93xx ethernet driver Added ethernet driver for EP93xx SoCs Signed-off-by: Matthias Kaehlcke Signed-off-by: Sascha Hauer --- drivers/net/Kconfig | 5 + drivers/net/Makefile | 1 + drivers/net/ep93xx.c | 676 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/ep93xx.h | 147 ++++++++++ include/common.h | 1 + 5 files changed, 830 insertions(+) create mode 100644 drivers/net/ep93xx.c create mode 100644 drivers/net/ep93xx.h diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index ed7656ee2..09555622b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -64,6 +64,11 @@ config DRIVER_NET_FEC_IMX 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 675192047..1b6f1046d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_DRIVER_NET_NETX) += netx_eth.o obj-$(CONFIG_DRIVER_NET_AT91_ETHER) += at91_ether.o obj-$(CONFIG_DRIVER_NET_MPC5200) += fec_mpc5200.o 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 000000000..aa1a00536 --- /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 000000000..ae45c54f5 --- /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/include/common.h b/include/common.h index 0c49d9505..2b40954a7 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) From 80bbe0c66e5a36054738c4331f13ba7a5694a448 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 12 Jan 2010 20:30:47 +0100 Subject: [PATCH 03/32] Add support for EP9xx GPIOs Added generic GPIO support for EP93xx SoCs Signed-off-by: Matthias Kaehlcke Signed-off-by: Sascha Hauer --- arch/arm/Kconfig | 1 + arch/arm/mach-ep93xx/Makefile | 2 +- arch/arm/mach-ep93xx/gpio.c | 136 +++++++++++++++++++++++ arch/arm/mach-ep93xx/include/mach/gpio.h | 29 +++++ 4 files changed, 167 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-ep93xx/gpio.c create mode 100644 arch/arm/mach-ep93xx/include/mach/gpio.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 414a013bf..9cad224ce 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -34,6 +34,7 @@ config ARCH_AT91RM9200 config ARCH_EP93XX bool "Cirrus Logic EP93xx" select CPU_ARM920T + select GENERIC_GPIO config ARCH_IMX bool "Freescale iMX-based" diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile index d5786db2b..dac657178 100644 --- a/arch/arm/mach-ep93xx/Makefile +++ b/arch/arm/mach-ep93xx/Makefile @@ -1,3 +1,3 @@ -obj-y += clocksource.o led.o +obj-y += clocksource.o gpio.o led.o obj-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += lowlevel_init.o diff --git a/arch/arm/mach-ep93xx/gpio.c b/arch/arm/mach-ep93xx/gpio.c new file mode 100644 index 000000000..5d5743403 --- /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/gpio.h b/arch/arm/mach-ep93xx/include/mach/gpio.h new file mode 100644 index 000000000..a305f274c --- /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 */ + From f13033d938081deed6dcb62a17ee98925c6140f3 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 12 Jan 2010 20:30:51 +0100 Subject: [PATCH 04/32] Add PrimeCell PL010 serial driver Added driver for ARM PrimeCell PL010 UART Signed-off-by: Matthias Kaehlcke Signed-off-by: Sascha Hauer --- drivers/serial/Kconfig | 7 ++ drivers/serial/Makefile | 2 +- drivers/serial/serial_pl010.c | 172 ++++++++++++++++++++++++++++++++++ drivers/serial/serial_pl010.h | 100 ++++++++++++++++++++ 4 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 drivers/serial/serial_pl010.c create mode 100644 drivers/serial/serial_pl010.h diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index b0ff5fa13..8a5056bc6 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -47,6 +47,13 @@ config DRIVER_SERIAL_NS16550_OMAP_EXTENSIONS 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 8ab680de7..9f203bbc0 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_LINUX_COMSOLE) += linux_console.o 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 000000000..1a6366f63 --- /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 000000000..6124e0e0f --- /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 From 6dff4e13a15cb806d835919de63c10da2f609932 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 12 Jan 2010 20:30:56 +0100 Subject: [PATCH 05/32] Add support for EDB93xx boards Added support for the following Cirrus Logic EDB93xx boards: EDB9301 EDB9302 EDB9302A EDB9307 EDB9307A EDB93012 EDB9315 EDB9315A Signed-off-by: Matthias Kaehlcke Signed-off-by: Sascha Hauer --- Documentation/boards.dox | 8 + arch/arm/configs/edb93xx_defconfig | 236 ++++++++++++++++++++++++++ board/edb93xx/Makefile | 2 + board/edb93xx/config.h | 4 + board/edb93xx/early_udelay.h | 34 ++++ board/edb93xx/edb93xx.c | 172 +++++++++++++++++++ board/edb93xx/edb93xx.dox | 108 ++++++++++++ board/edb93xx/edb93xx.h | 48 ++++++ board/edb93xx/env/bin/boot | 48 ++++++ board/edb93xx/env/bin/flash_partition | 22 +++ board/edb93xx/env/bin/init | 19 +++ board/edb93xx/env/bin/set_nor_parts | 3 + board/edb93xx/env/bin/update_kernel | 16 ++ board/edb93xx/env/bin/update_rootfs | 16 ++ board/edb93xx/env/config | 16 ++ board/edb93xx/flash_cfg.c | 38 +++++ board/edb93xx/pll_cfg.c | 58 +++++++ board/edb93xx/pll_cfg.h | 72 ++++++++ board/edb93xx/sdram_cfg.c | 127 ++++++++++++++ board/edb93xx/sdram_cfg.h | 144 ++++++++++++++++ 20 files changed, 1191 insertions(+) create mode 100644 arch/arm/configs/edb93xx_defconfig create mode 100644 board/edb93xx/Makefile create mode 100644 board/edb93xx/config.h create mode 100644 board/edb93xx/early_udelay.h create mode 100644 board/edb93xx/edb93xx.c create mode 100644 board/edb93xx/edb93xx.dox create mode 100644 board/edb93xx/edb93xx.h create mode 100644 board/edb93xx/env/bin/boot create mode 100644 board/edb93xx/env/bin/flash_partition create mode 100644 board/edb93xx/env/bin/init create mode 100644 board/edb93xx/env/bin/set_nor_parts create mode 100644 board/edb93xx/env/bin/update_kernel create mode 100644 board/edb93xx/env/bin/update_rootfs create mode 100644 board/edb93xx/env/config create mode 100644 board/edb93xx/flash_cfg.c create mode 100644 board/edb93xx/pll_cfg.c create mode 100644 board/edb93xx/pll_cfg.h create mode 100644 board/edb93xx/sdram_cfg.c create mode 100644 board/edb93xx/sdram_cfg.h diff --git a/Documentation/boards.dox b/Documentation/boards.dox index dba547f32..7c7f4d14b 100644 --- a/Documentation/boards.dox +++ b/Documentation/boards.dox @@ -20,6 +20,14 @@ ARM type: @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: diff --git a/arch/arm/configs/edb93xx_defconfig b/arch/arm/configs/edb93xx_defconfig new file mode 100644 index 000000000..d6b4b19f1 --- /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/board/edb93xx/Makefile b/board/edb93xx/Makefile new file mode 100644 index 000000000..e19cd7b4c --- /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 000000000..6ae9a40e1 --- /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 000000000..3b26b3f16 --- /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 000000000..add88e1de --- /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 000000000..3964d5536 --- /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 000000000..5e5c6f518 --- /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 000000000..143f3d018 --- /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 000000000..ded40aa8a --- /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 000000000..c6b5aed27 --- /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 000000000..38321fa8c --- /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 000000000..3e4b9b0b8 --- /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 000000000..52a3699fd --- /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 000000000..47ab209d8 --- /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 000000000..91a6a4ea9 --- /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 000000000..a687af0a0 --- /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 000000000..9691339eb --- /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 000000000..9f56f7272 --- /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 000000000..7babee8d6 --- /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 From 5d591e14ef15f28779a9c5aba08549129a29a550 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:35 +0100 Subject: [PATCH 06/32] Add a tool to activate barebox as a boot loader on x86 architectures To use barebox as a BIOS based bootloader for x86 architectures, the binary must be patched to get it bootstrapped at runtime. The 'setupmbr' tool installs the barebox-binary to the given device node or image file and patch it in accordance to the needed sector information at runtime. Signed-off by: Juergen Beisert Signed-off-by: Sascha Hauer --- Doxyfile | 3 +- scripts/Makefile | 4 +- scripts/setupmbr/Makefile | 4 + scripts/setupmbr/arch.h | 55 +++ scripts/setupmbr/setupmbr.c | 705 ++++++++++++++++++++++++++++++++++++ 5 files changed, 769 insertions(+), 2 deletions(-) create mode 100644 scripts/setupmbr/Makefile create mode 100644 scripts/setupmbr/arch.h create mode 100644 scripts/setupmbr/setupmbr.c diff --git a/Doxyfile b/Doxyfile index c9b04b6d1..94dd6ae0d 100644 --- a/Doxyfile +++ b/Doxyfile @@ -484,7 +484,8 @@ INPUT = Documentation \ 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/scripts/Makefile b/scripts/Makefile index c22a8b6e8..be8e3e056 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -14,5 +14,7 @@ always := $(hostprogs-y) $(hostprogs-m) 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 000000000..8680fedce --- /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 000000000..a720dfe95 --- /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 000000000..01e8c645f --- /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. +*/ From ae2afbb2db231ffda34a269a27581fa516af30e0 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:36 +0100 Subject: [PATCH 07/32] Consider real and protected mode in the dump file On x86 'objdump' does not know which parts of the image are 16 bit code and 32 bit. As the default is 32 bit, it will output garbage from the 16 bit parts (due to 16/32 bit ops are sharing the same opcodes). Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- Makefile | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Makefile b/Makefile index 0c0082990..953f94268 100644 --- a/Makefile +++ b/Makefile @@ -643,7 +643,30 @@ endef 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 From 2dac49cea06c4e0ab4000904e474b675d5e714bd Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:37 +0100 Subject: [PATCH 08/32] Adding x86 usage documentation to the tree Adding x86 usage documentation to the tree Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- Documentation/developers_manual.dox | 1 + Documentation/users_manual.dox | 1 + arch/architecture.dox | 1 + arch/x86/mach-x86.dox | 128 ++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 arch/x86/mach-x86.dox diff --git a/Documentation/developers_manual.dox b/Documentation/developers_manual.dox index 2f7d3605e..620905eaa 100644 --- a/Documentation/developers_manual.dox +++ b/Documentation/developers_manual.dox @@ -20,5 +20,6 @@ This part of the documentation is intended for developers of @a barebox. @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 e4ba9d00e..5467bee47 100644 --- a/Documentation/users_manual.dox +++ b/Documentation/users_manual.dox @@ -10,5 +10,6 @@ work easier. @li @subpage readline_parser @li @subpage command_reference @li @subpage partitions +@li @subpage x86_bootloader */ diff --git a/arch/architecture.dox b/arch/architecture.dox index 669c02843..ea00dcdc8 100644 --- a/arch/architecture.dox +++ b/arch/architecture.dox @@ -88,6 +88,7 @@ TODO @li @subpage dev_bf_mach @li @subpage dev_ppc_mach @li @subpage dev_m68k_mach +@li @subpage dev_x86_mach */ diff --git a/arch/x86/mach-x86.dox b/arch/x86/mach-x86.dox new file mode 100644 index 000000000..fc5b85a08 --- /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. + +*/ From acd2bf6bc0ee81a6a890fe7d07c6db54daacd515 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:38 +0100 Subject: [PATCH 09/32] Adding required architecture header files Add architecture header files. Some of these files are empty, they only must exists to make the build system happy. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- arch/x86/include/asm/barebox.h | 21 ++++++ arch/x86/include/asm/barebox.lds.h | 113 +++++++++++++++++++++++++++++ arch/x86/include/asm/bitops.h | 32 ++++++++ arch/x86/include/asm/byteorder.h | 30 ++++++++ arch/x86/include/asm/common.h | 29 ++++++++ arch/x86/include/asm/elf.h | 30 ++++++++ arch/x86/include/asm/io.h | 73 +++++++++++++++++++ arch/x86/include/asm/modes.h | 65 +++++++++++++++++ arch/x86/include/asm/module.h | 37 ++++++++++ arch/x86/include/asm/posix_types.h | 49 +++++++++++++ arch/x86/include/asm/segment.h | 43 +++++++++++ arch/x86/include/asm/string.h | 31 ++++++++ arch/x86/include/asm/syslib.h | 29 ++++++++ arch/x86/include/asm/types.h | 44 +++++++++++ 14 files changed, 626 insertions(+) create mode 100644 arch/x86/include/asm/barebox.h create mode 100644 arch/x86/include/asm/barebox.lds.h create mode 100644 arch/x86/include/asm/bitops.h create mode 100644 arch/x86/include/asm/byteorder.h create mode 100644 arch/x86/include/asm/common.h create mode 100644 arch/x86/include/asm/elf.h create mode 100644 arch/x86/include/asm/io.h create mode 100644 arch/x86/include/asm/modes.h create mode 100644 arch/x86/include/asm/module.h create mode 100644 arch/x86/include/asm/posix_types.h create mode 100644 arch/x86/include/asm/segment.h create mode 100644 arch/x86/include/asm/string.h create mode 100644 arch/x86/include/asm/syslib.h create mode 100644 arch/x86/include/asm/types.h diff --git a/arch/x86/include/asm/barebox.h b/arch/x86/include/asm/barebox.h new file mode 100644 index 000000000..39bea1844 --- /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 000000000..6cbf15f5c --- /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 000000000..b43afa3f9 --- /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 000000000..51ce8e1d5 --- /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 000000000..4862680e4 --- /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 000000000..01342d6ae --- /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 000000000..27ea64252 --- /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 000000000..8417ddc4b --- /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 000000000..168e91df2 --- /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 000000000..a22f301ae --- /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 000000000..cb9b3d0c5 --- /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 000000000..5ca2ff1af --- /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 000000000..a1316872c --- /dev/null +++ b/arch/x86/include/asm/syslib.h @@ -0,0 +1,29 @@ +/* + * 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 diff --git a/arch/x86/include/asm/types.h b/arch/x86/include/asm/types.h new file mode 100644 index 000000000..17c5fd7b9 --- /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 */ From c7f2adaf7dfd9b752972a5ebf48baf30684106cc Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:39 +0100 Subject: [PATCH 10/32] Bring in the first x86 specific code Add some generic required code to make barebox work on x86. Note: Resetting the CPU is unfinished yet. I need some ideas how to reset this kind of architecture gracefully. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- arch/x86/mach-i386/Kconfig | 29 +++++++++++++++++++++++++++ arch/x86/mach-i386/Makefile | 2 ++ arch/x86/mach-i386/generic.c | 38 ++++++++++++++++++++++++++++++++++++ arch/x86/mach-i386/reset.c | 34 ++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 arch/x86/mach-i386/Kconfig create mode 100644 arch/x86/mach-i386/Makefile create mode 100644 arch/x86/mach-i386/generic.c create mode 100644 arch/x86/mach-i386/reset.c diff --git a/arch/x86/mach-i386/Kconfig b/arch/x86/mach-i386/Kconfig new file mode 100644 index 000000000..11f6aa679 --- /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 000000000..49ed10ff5 --- /dev/null +++ b/arch/x86/mach-i386/Makefile @@ -0,0 +1,2 @@ +obj-y += generic.o +obj-y += reset.o diff --git a/arch/x86/mach-i386/generic.c b/arch/x86/mach-i386/generic.c new file mode 100644 index 000000000..edeacc427 --- /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/reset.c b/arch/x86/mach-i386/reset.c new file mode 100644 index 000000000..a4eb36487 --- /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); From 2bdd75bd02f3d214b285429be72b3a0eab4e9610 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:40 +0100 Subject: [PATCH 11/32] Add some generic functions to make x86 work Add some generic functions to make barebox work on x86. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- arch/x86/lib/Makefile | 7 ++ arch/x86/lib/barebox.lds.S | 194 +++++++++++++++++++++++++++++++++++++ arch/x86/lib/gdt.c | 55 +++++++++++ arch/x86/lib/memory.c | 67 +++++++++++++ arch/x86/lib/memory16.S | 73 ++++++++++++++ arch/x86/lib/traveler.S | 183 ++++++++++++++++++++++++++++++++++ 6 files changed, 579 insertions(+) create mode 100644 arch/x86/lib/Makefile create mode 100644 arch/x86/lib/barebox.lds.S create mode 100644 arch/x86/lib/gdt.c create mode 100644 arch/x86/lib/memory.c create mode 100644 arch/x86/lib/memory16.S create mode 100644 arch/x86/lib/traveler.S diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile new file mode 100644 index 000000000..5d813933d --- /dev/null +++ b/arch/x86/lib/Makefile @@ -0,0 +1,7 @@ +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 diff --git a/arch/x86/lib/barebox.lds.S b/arch/x86/lib/barebox.lds.S new file mode 100644 index 000000000..2917d2fa1 --- /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/gdt.c b/arch/x86/lib/gdt.c new file mode 100644 index 000000000..a9c4d0e9d --- /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/memory.c b/arch/x86/lib/memory.c new file mode 100644 index 000000000..9496d2277 --- /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 000000000..01450fa59 --- /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 000000000..2b6dc85ed --- /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 From 7dcc15e8197e647abc80b1d3298a91edd45a8c2d Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:41 +0100 Subject: [PATCH 12/32] Add functions to be able to boot with BIOSs help These functions are special: They are running in the 16 bit real mode world to bring up barebox on an x86 box. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- arch/x86/boot/Kconfig | 20 ++++ arch/x86/boot/Makefile | 13 +++ arch/x86/boot/a20.c | 170 ++++++++++++++++++++++++++++++ arch/x86/boot/bioscall.S | 99 +++++++++++++++++ arch/x86/boot/boot.h | 193 ++++++++++++++++++++++++++++++++++ arch/x86/boot/boot_hdisk.S | 176 +++++++++++++++++++++++++++++++ arch/x86/boot/boot_main.S | 58 ++++++++++ arch/x86/boot/main_entry.c | 44 ++++++++ arch/x86/boot/pmjump.S | 89 ++++++++++++++++ arch/x86/boot/prepare_uboot.c | 86 +++++++++++++++ arch/x86/boot/regs.c | 34 ++++++ arch/x86/boot/tty.c | 45 ++++++++ 12 files changed, 1027 insertions(+) create mode 100644 arch/x86/boot/Kconfig create mode 100644 arch/x86/boot/Makefile create mode 100644 arch/x86/boot/a20.c create mode 100644 arch/x86/boot/bioscall.S create mode 100644 arch/x86/boot/boot.h create mode 100644 arch/x86/boot/boot_hdisk.S create mode 100644 arch/x86/boot/boot_main.S create mode 100644 arch/x86/boot/main_entry.c create mode 100644 arch/x86/boot/pmjump.S create mode 100644 arch/x86/boot/prepare_uboot.c create mode 100644 arch/x86/boot/regs.c create mode 100644 arch/x86/boot/tty.c diff --git a/arch/x86/boot/Kconfig b/arch/x86/boot/Kconfig new file mode 100644 index 000000000..cdb82e46d --- /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 000000000..b92b4750f --- /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 000000000..4b61d9193 --- /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 000000000..84d2577eb --- /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 000000000..d98b0661c --- /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 000000000..40388e993 --- /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 000000000..f3d248ae5 --- /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 000000000..5f199e985 --- /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 000000000..d48e1983f --- /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 000000000..a68aceddb --- /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 000000000..ddc515518 --- /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 000000000..a81671be3 --- /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++); +} From 46348b5d65ce6911b9d936f684828b2760cf2a14 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:42 +0100 Subject: [PATCH 13/32] Add a generic PC platform This code adds a generic x86 platform, enabling barebox to act as a bootloader like 'GRUB'. Very minimalistic, yet. Supports only a serial console and is tested with QEMU only. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- Documentation/boards.dox | 2 +- arch/x86/configs/generic_defconfig | 186 +++++++++++++++++++++++++++++ board/x86_generic/Makefile | 1 + board/x86_generic/config.h | 21 ++++ board/x86_generic/env/bin/boot | 37 ++++++ board/x86_generic/env/bin/init | 15 +++ board/x86_generic/env/config | 31 +++++ board/x86_generic/generic_pc.c | 140 ++++++++++++++++++++++ 8 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 arch/x86/configs/generic_defconfig create mode 100644 board/x86_generic/Makefile create mode 100644 board/x86_generic/config.h create mode 100644 board/x86_generic/env/bin/boot create mode 100644 board/x86_generic/env/bin/init create mode 100644 board/x86_generic/env/config create mode 100644 board/x86_generic/generic_pc.c diff --git a/Documentation/boards.dox b/Documentation/boards.dox index 7c7f4d14b..3eb79b27b 100644 --- a/Documentation/boards.dox +++ b/Documentation/boards.dox @@ -35,7 +35,7 @@ Blackfin type: x86 type: -@li nothing yet +@li @subpage generic_pc coldfire/m68k type: diff --git a/arch/x86/configs/generic_defconfig b/arch/x86/configs/generic_defconfig new file mode 100644 index 000000000..091f696e3 --- /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/board/x86_generic/Makefile b/board/x86_generic/Makefile new file mode 100644 index 000000000..248240da0 --- /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 000000000..39bea1844 --- /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 000000000..fcfffe319 --- /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 000000000..2924a4449 --- /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 000000000..dd57aad71 --- /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 000000000..bd93bc168 --- /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. + +*/ From c3a99ec501b19372e52a63c9787e7b6f916552a1 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:43 +0100 Subject: [PATCH 14/32] Bring in the time reference for the x86 platforms This code uses the always (hopefully) existing PIT device to get the time reference for barebox. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- arch/x86/mach-i386/Makefile | 3 ++ arch/x86/mach-i386/pit_timer.c | 71 ++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 arch/x86/mach-i386/pit_timer.c diff --git a/arch/x86/mach-i386/Makefile b/arch/x86/mach-i386/Makefile index 49ed10ff5..10712e6a3 100644 --- a/arch/x86/mach-i386/Makefile +++ b/arch/x86/mach-i386/Makefile @@ -1,2 +1,5 @@ obj-y += generic.o obj-y += reset.o + +# reference clocksource +obj-y += pit_timer.o diff --git a/arch/x86/mach-i386/pit_timer.c b/arch/x86/mach-i386/pit_timer.c new file mode 100644 index 000000000..b9f805e61 --- /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); From 2264ac8e652210c1beb9452c56f107955db65492 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:44 +0100 Subject: [PATCH 15/32] Start to add ATA support to barebox Add the basic files, declarations and folders to bring in ATA support. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- drivers/Kconfig | 1 + drivers/Makefile | 1 + drivers/ata/Kconfig | 12 ++++++++++++ drivers/ata/Makefile | 3 +++ include/ata.h | 39 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 56 insertions(+) create mode 100644 drivers/ata/Kconfig create mode 100644 drivers/ata/Makefile create mode 100644 include/ata.h diff --git a/drivers/Kconfig b/drivers/Kconfig index 8bab7ac0b..bf559c405 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -6,6 +6,7 @@ source "drivers/spi/Kconfig" 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 5dc7756aa..7bae6ffcb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -3,6 +3,7 @@ obj-y += serial/ 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 000000000..fcec99a2b --- /dev/null +++ b/drivers/ata/Kconfig @@ -0,0 +1,12 @@ +menuconfig ATA + bool "ATA " + help + Add support for ATA types of drives like harddisks and CDROMs. + +if ATA + +comment "drive types" + +comment "interface types" + +endif diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile new file mode 100644 index 000000000..0048e2415 --- /dev/null +++ b/drivers/ata/Makefile @@ -0,0 +1,3 @@ +# drive types + +# interface types diff --git a/include/ata.h b/include/ata.h new file mode 100644 index 000000000..d56399ea7 --- /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; +}; From bb0d24d5b47b43cf429ecca0d138e99b90435802 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:45 +0100 Subject: [PATCH 16/32] Add the main disk driver This is the generic disk driver. It does not know how to access the drives. Other low level drivers are required for this. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- drivers/ata/Kconfig | 5 + drivers/ata/Makefile | 2 + drivers/ata/disk_drive.c | 346 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 353 insertions(+) create mode 100644 drivers/ata/disk_drive.c diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index fcec99a2b..8e3a075f7 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -7,6 +7,11 @@ if ATA comment "drive types" +config ATA_DISK + bool "disk drives" + help + Add support for regular disk drives + comment "interface types" endif diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile index 0048e2415..90494441b 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -1,3 +1,5 @@ # drive types +obj-$(CONFIG_ATA_DISK) += disk_drive.o + # interface types diff --git a/drivers/ata/disk_drive.c b/drivers/ata/disk_drive.c new file mode 100644 index 000000000..250dadaa2 --- /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); From 835aa6b59948817f094c7e55e530a7e426c79161 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:46 +0100 Subject: [PATCH 17/32] Add a low level disk drive access driver This is a low level disk drive communication driver. It uses the real mode BIOS found on most x86 platforms, to read and write sectors. Used by the generic disk driver. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- arch/x86/lib/Makefile | 1 + arch/x86/lib/bios_disk.S | 77 +++++++++++ drivers/ata/Kconfig | 9 ++ drivers/ata/Makefile | 2 + drivers/ata/bios.c | 291 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 380 insertions(+) create mode 100644 arch/x86/lib/bios_disk.S create mode 100644 drivers/ata/bios.c diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index 5d813933d..013d369ea 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -5,3 +5,4 @@ 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 diff --git a/arch/x86/lib/bios_disk.S b/arch/x86/lib/bios_disk.S new file mode 100644 index 000000000..3acd66047 --- /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/drivers/ata/Kconfig b/drivers/ata/Kconfig index 8e3a075f7..b43c975d3 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -14,4 +14,13 @@ config ATA_DISK 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 index 90494441b..30d15ccb0 100644 --- a/drivers/ata/Makefile +++ b/drivers/ata/Makefile @@ -3,3 +3,5 @@ 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 000000000..51e2425a9 --- /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); From 70810935313bfb073c942f9a96bdd8502a05f6c1 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:47 +0100 Subject: [PATCH 18/32] Add a special command to load and start a bzImage on x86 Other architectures are supporting the uImage format used by barebox's 'bootm' command. x86 does'nt. So, we need a special command to be able to boot the x86 specific bzImage format. Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- Documentation/commands.dox | 2 +- arch/x86/include/asm/syslib.h | 4 + arch/x86/lib/Makefile | 1 + arch/x86/lib/linux_start.S | 75 +++++++ commands/Kconfig | 8 + commands/Makefile | 1 + commands/linux16.c | 363 ++++++++++++++++++++++++++++++++++ 7 files changed, 453 insertions(+), 1 deletion(-) create mode 100644 arch/x86/lib/linux_start.S create mode 100644 commands/linux16.c diff --git a/Documentation/commands.dox b/Documentation/commands.dox index 4c14a8855..a8850b1bb 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/arch/x86/include/asm/syslib.h b/arch/x86/include/asm/syslib.h index a1316872c..eebe1a99c 100644 --- a/arch/x86/include/asm/syslib.h +++ b/arch/x86/include/asm/syslib.h @@ -27,3 +27,7 @@ extern int bios_disk_rw_int13_extensions(int, int, void*) __attribute__((regparm 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/lib/Makefile b/arch/x86/lib/Makefile index 013d369ea..b67629f11 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -6,3 +6,4 @@ obj-y += gdt.o 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/linux_start.S b/arch/x86/lib/linux_start.S new file mode 100644 index 000000000..fac2510d1 --- /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/commands/Kconfig b/commands/Kconfig index 28896cb93..bb264fc17 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -219,6 +219,14 @@ config CMD_BOOTU 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 1c657dd68..b32fa05d3 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 000000000..b15812f1d --- /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. + * + */ From 12769b3b78717476fe7e455cef5e59f903648e42 Mon Sep 17 00:00:00 2001 From: Juergen Beisert Date: Tue, 12 Jan 2010 11:15:48 +0100 Subject: [PATCH 19/32] Add the whole x86 architecture to the build system Signed-off-by: Juergen Beisert Signed-off-by: Sascha Hauer --- arch/x86/Kconfig | 67 +++++++++++++++++++++++++++++++++++++++++++++++ arch/x86/Makefile | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 arch/x86/Kconfig create mode 100644 arch/x86/Makefile diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig new file mode 100644 index 000000000..6e70760f5 --- /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 000000000..2e2cb810d --- /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 + From d8a014ccdf50927c0944f8491527e6965df66b52 Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Fri, 15 Jan 2010 14:44:54 +0100 Subject: [PATCH 20/32] addpart: support @ We claim to be compatible with the kernel's cmdlinepart parser, so support @ like the kernel does. Signed-off-by: Peter Korsgaard Signed-off-by: Sascha Hauer --- commands/partition.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/commands/partition.c b/commands/partition.c index 3cb7b612f..bc0bbf962 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 @@ static int mtd_part_do_parse_one(char *devname, const char *partstr, 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 @@ static int mtd_part_do_parse_one(char *devname, const char *partstr, end++; } - if (size + offset > devsize) { + if (size + *offset > devsize) { printf("%s: partition end is beyond device\n", buf); return -EINVAL; } @@ -93,7 +101,7 @@ static int mtd_part_do_parse_one(char *devname, const char *partstr, *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 @@ static int do_addpart(cmd_tbl_t * cmdtp, int argc, char *argv[]) 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 @@ static const __maybe_unused char cmd_addpart_help[] = "\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 @@ BAREBOX_CMD_END * 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. From e5b873753d50216354443bcf4abf072e879ee062 Mon Sep 17 00:00:00 2001 From: Eric Benard Date: Fri, 15 Jan 2010 11:50:16 +0100 Subject: [PATCH 21/32] eukrea_cpuimx27 : update timings use optimized DDR, NOR & QuadUART timings Signed-off-by: Eric Benard Signed-off-by: Sascha Hauer --- board/eukrea_cpuimx27/eukrea_cpuimx27.c | 12 ++++++------ board/eukrea_cpuimx27/lowlevel_init.S | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/board/eukrea_cpuimx27/eukrea_cpuimx27.c b/board/eukrea_cpuimx27/eukrea_cpuimx27.c index 68780449b..629399f99 100644 --- a/board/eukrea_cpuimx27/eukrea_cpuimx27.c +++ b/board/eukrea_cpuimx27/eukrea_cpuimx27.c @@ -198,9 +198,9 @@ static int eukrea_cpuimx27_devices_init(void) 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++) @@ -244,9 +244,9 @@ static int eukrea_cpuimx27_console_init(void) #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 diff --git a/board/eukrea_cpuimx27/lowlevel_init.S b/board/eukrea_cpuimx27/lowlevel_init.S index 4622af88a..5295a8a22 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) From 21a9d8d87e41743669c2ed3a27b3174ef02c9585 Mon Sep 17 00:00:00 2001 From: Eric Benard Date: Fri, 15 Jan 2010 11:50:17 +0100 Subject: [PATCH 22/32] Add necessary clocks & defines to get I2C support for i.MX27 Signed-off-by: Eric Benard Signed-off-by: Sascha Hauer --- arch/arm/mach-imx/include/mach/imx27-regs.h | 1 + arch/arm/mach-imx/speed-imx27.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/arch/arm/mach-imx/include/mach/imx27-regs.h b/arch/arm/mach-imx/include/mach/imx27-regs.h index 33d67d6f5..6c31ccd91 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 deaca1eb4..cdcd4191f 100644 --- a/arch/arm/mach-imx/speed-imx27.c +++ b/arch/arm/mach-imx/speed-imx27.c @@ -154,6 +154,11 @@ ulong imx_get_lcdclk(void) return imx_get_perclk3(); } +ulong imx_get_i2cclk(void) +{ + return imx_get_ipgclk(); +} + void imx_dump_clocks(void) { uint32_t cid = CID; From f8dc81ba5a291f6649f3e5f759086f4af98e159e Mon Sep 17 00:00:00 2001 From: Eric Benard Date: Fri, 15 Jan 2010 11:50:18 +0100 Subject: [PATCH 23/32] I2C : add NS LP3972 PMIC support Signed-off-by: Eric Benard Signed-off-by: Sascha Hauer --- drivers/i2c/Kconfig | 3 ++ drivers/i2c/Makefile | 1 + drivers/i2c/lp3972.c | 110 +++++++++++++++++++++++++++++++++++++++++++ include/i2c/lp3972.h | 7 +++ 4 files changed, 121 insertions(+) create mode 100644 drivers/i2c/lp3972.c create mode 100644 include/i2c/lp3972.h diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 46723ed84..f1b2949fa 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -13,4 +13,7 @@ config DRIVER_I2C_MC13892 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 5dd642fda..62d030bf0 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_DRIVER_I2C_IMX) += i2c-imx.o 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 000000000..98266990d --- /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/include/i2c/lp3972.h b/include/i2c/lp3972.h new file mode 100644 index 000000000..edb580111 --- /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 */ + From bc31ee222caf142cb6828909606e6def0a213b40 Mon Sep 17 00:00:00 2001 From: Eric Benard Date: Fri, 15 Jan 2010 11:50:19 +0100 Subject: [PATCH 24/32] Eukrea CPUIMX27 : add I2C and LP3972 support This allows to properly setup the voltage on LCD pins at boot. Signed-off-by: Eric Benard Signed-off-by: Sascha Hauer --- board/eukrea_cpuimx27/eukrea_cpuimx27.c | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/board/eukrea_cpuimx27/eukrea_cpuimx27.c b/board/eukrea_cpuimx27/eukrea_cpuimx27.c index 629399f99..0908dca7c 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 @@ static struct device_d quad_uart_serial_device = { }; #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 @@ static int eukrea_cpuimx27_devices_init(void) 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, @@ -213,6 +229,10 @@ static int eukrea_cpuimx27_devices_init(void) 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); @@ -257,9 +277,18 @@ console_initcall(eukrea_cpuimx27_console_init); 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; } From fc268d55844d6a714ab1a6131dc5cc9b8043cca9 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 9 Dec 2009 02:19:33 +0100 Subject: [PATCH 25/32] mc9sdz60: clean up driver interface Export mc9sdz60_reg_read, mc9sdz60_reg_write and mc9sdz60_set_bits function instead of exposing the i2c interface. Signed-off-by: Marc Kleine-Budde --- drivers/i2c/mc9sdz60.c | 84 ++++++++++++++++++++++++++++++++---------- include/i2c/mc9sdz60.h | 61 +++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 22 deletions(-) diff --git a/drivers/i2c/mc9sdz60.c b/drivers/i2c/mc9sdz60.c index 4b1068d17..3580af885 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 ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset 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 @@ static int mc_probe(struct device_d *dev) 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/include/i2c/mc9sdz60.h b/include/i2c/mc9sdz60.h index 04cfca04a..4cc233e05 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 */ - From 23f4449b78851d8a21ca42ecec57f48982f9d0e3 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 9 Dec 2009 02:05:07 +0100 Subject: [PATCH 26/32] mc13892: clean up driver interface Export mc13892_reg_read, mc13892_reg_write and mc13892_set_bits function instead of exposing the i2c interface. Signed-off-by: Marc Kleine-Budde --- drivers/i2c/mc13892.c | 91 ++++++++++++++++++++++++++++++++++--------- include/i2c/mc13892.h | 90 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 160 insertions(+), 21 deletions(-) diff --git a/drivers/i2c/mc13892.c b/drivers/i2c/mc13892.c index 54661d4f5..67d4232a2 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 ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset 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 @@ static int mc_probe(struct device_d *dev) 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/include/i2c/mc13892.h b/include/i2c/mc13892.h index 2f44f6c85..112d05ba6 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 */ - From c23a05d01dd175969847b875d18ccdec1d7e4ee4 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 9 Dec 2009 02:17:56 +0100 Subject: [PATCH 27/32] i.MX35 3stack: adopt board to new mc13892 and mc9sdz60 driver interface Signed-off-by: Marc Kleine-Budde --- board/freescale-mx35-3-stack/3stack.c | 99 +++++++++++++++------------ 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/board/freescale-mx35-3-stack/3stack.c b/board/freescale-mx35-3-stack/3stack.c index e54196617..f67193613 100644 --- a/board/freescale-mx35-3-stack/3stack.c +++ b/board/freescale-mx35-3-stack/3stack.c @@ -157,7 +157,7 @@ static int f3s_devices_init(void) 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 */ @@ -358,74 +358,84 @@ static int f3s_core_init(void) 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 @@ void __bare_init nand_boot(void) imx_nand_load_image((void *)TEXT_BASE, 256 * 1024); } #endif - From 884d875fb8175bf01c8d642b55a5e6c94cf2b692 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Wed, 9 Dec 2009 02:17:05 +0100 Subject: [PATCH 28/32] i.MX35 3stack: clean up indention Signed-off-by: Marc Kleine-Budde --- board/freescale-mx35-3-stack/3stack.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/board/freescale-mx35-3-stack/3stack.c b/board/freescale-mx35-3-stack/3stack.c index f67193613..d87808a4a 100644 --- a/board/freescale-mx35-3-stack/3stack.c +++ b/board/freescale-mx35-3-stack/3stack.c @@ -60,8 +60,8 @@ static struct device_d cfi_dev = { }; 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 device_d fec_dev = { }; static struct memory_platform_data sdram_pdata = { - .name = "ram0", - .flags = DEVFS_RDWR, + .name = "ram0", + .flags = DEVFS_RDWR, }; static struct device_d sdram_dev = { @@ -167,7 +167,7 @@ static int f3s_devices_init(void) 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"); @@ -332,7 +332,7 @@ static int f3s_core_init(void) /* 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 */ From 5f2afc699bf8d94656203d89b7bc1b1047756c1b Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 4 Dec 2009 10:35:00 +0100 Subject: [PATCH 29/32] i.MX35 3stack: clean up indention of lowlevel_init Signed-off-by: Marc Kleine-Budde --- board/freescale-mx35-3-stack/lowlevel_init.S | 318 +++++++++---------- 1 file changed, 159 insertions(+), 159 deletions(-) diff --git a/board/freescale-mx35-3-stack/lowlevel_init.S b/board/freescale-mx35-3-stack/lowlevel_init.S index 4e0a10293..1680579b5 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 @@ board_init_lowlevel: 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 @@ board_init_lowlevel: 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 From 695539fd762b4c258a243d0a64a9f536df5c0b26 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 10 Dec 2009 12:35:26 +0100 Subject: [PATCH 30/32] i.MX35 3stack: increase env partition to hold splash image Signed-off-by: Marc Kleine-Budde --- board/freescale-mx35-3-stack/3stack.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/board/freescale-mx35-3-stack/3stack.c b/board/freescale-mx35-3-stack/3stack.c index d87808a4a..e6fa0f047 100644 --- a/board/freescale-mx35-3-stack/3stack.c +++ b/board/freescale-mx35-3-stack/3stack.c @@ -171,13 +171,13 @@ static int f3s_devices_init(void) 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; } From 860566557a7b8de8518c77988d868ec5f59ac4ac Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Thu, 3 Dec 2009 13:17:54 +0100 Subject: [PATCH 31/32] i.MX35 3stack: update environemnt to support jffs and ubi/ubifs ubifs from nand is default Signed-off-by: Marc Kleine-Budde --- board/freescale-mx35-3-stack/env/bin/_update | 5 +- board/freescale-mx35-3-stack/env/bin/boot | 50 +++++++++++-------- board/freescale-mx35-3-stack/env/bin/init | 15 +++--- .../env/bin/update_kernel | 2 +- .../env/bin/{update_root => update_rootfs} | 8 ++- board/freescale-mx35-3-stack/env/config | 45 ++++++++++------- 6 files changed, 75 insertions(+), 50 deletions(-) rename board/freescale-mx35-3-stack/env/bin/{update_root => update_rootfs} (68%) diff --git a/board/freescale-mx35-3-stack/env/bin/_update b/board/freescale-mx35-3-stack/env/bin/_update index fb7cbe861..4f0839f89 100644 --- a/board/freescale-mx35-3-stack/env/bin/_update +++ b/board/freescale-mx35-3-stack/env/bin/_update @@ -20,7 +20,7 @@ fi ping $eth0.serverip if [ $? -ne 0 ] ; then - echo "update aborted" + echo "Server did not reply! Update aborted." exit 1 fi @@ -28,9 +28,12 @@ unprotect $part echo echo "erasing partition $part" +echo erase $part echo echo "flashing $image to $part" echo tftp $image $part + +protect $part diff --git a/board/freescale-mx35-3-stack/env/bin/boot b/board/freescale-mx35-3-stack/env/bin/boot index dfb59aa69..fb2fe614d 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 cdf0f6b8e..c982f22a8 100644 --- a/board/freescale-mx35-3-stack/env/bin/init +++ b/board/freescale-mx35-3-stack/env/bin/init @@ -16,12 +16,13 @@ if [ -e /dev/nand0 ]; then 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 @@ timeout -a $autoboot_timeout if [ $? != 0 ]; then echo echo "type update_kernel nand|nor [] to update kernel into flash" - echo "type update_root nand|nor [] to update rootfs into flash" + echo "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 05c822d86..63ad11aae 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_rootfs similarity index 68% rename from board/freescale-mx35-3-stack/env/bin/update_root rename to board/freescale-mx35-3-stack/env/bin/update_rootfs index eaf36ebce..53dd2ca57 100644 --- a/board/freescale-mx35-3-stack/env/bin/update_root +++ b/board/freescale-mx35-3-stack/env/bin/update_rootfs @@ -2,7 +2,12 @@ . /env/config -image=$uimage +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 @@ -13,4 +18,3 @@ else fi . /env/bin/_update $2 - diff --git a/board/freescale-mx35-3-stack/env/config b/board/freescale-mx35-3-stack/env/config index 9fcb3dc7b..51195f740 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 From 196333c1e54841f0b33db39353ead2e1062f4300 Mon Sep 17 00:00:00 2001 From: Marc Kleine-Budde Date: Fri, 20 Nov 2009 21:01:08 +0100 Subject: [PATCH 32/32] i.MX35 3stack: update of defconfig Signed-off-by: Marc Kleine-Budde --- .../configs/freescale_mx35_3stack_defconfig | 67 ++++++++++--------- 1 file changed, 36 insertions(+), 31 deletions(-) diff --git a/arch/arm/configs/freescale_mx35_3stack_defconfig b/arch/arm/configs/freescale_mx35_3stack_defconfig index 1319a695e..17a2fdc6d 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_FREESCALE_MX35_3STACK=y # 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_ENV_HANDLING=y 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_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_MALLOC_SIZE=0x1000000 # CONFIG_BROKEN is not set # CONFIG_EXPERIMENTAL is not set CONFIG_MACH_HAS_LOWLEVEL_INIT=y @@ -105,10 +105,10 @@ CONFIG_CONSOLE_ACTIVATE_FIRST=y # 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_DEFAULT_ENVIRONMENT_PATH="board/pcm043/env/" # 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_TRUE=y CONFIG_CMD_FALSE=y # -# file commands +# file commands # CONFIG_CMD_LS=y CONFIG_CMD_RM=y @@ -147,13 +147,13 @@ CONFIG_CMD_MOUNT=y 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_CRC=y # 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_TEST=y 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_PING=y 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_DRIVER_SERIAL_IMX=y 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