diff options
Diffstat (limited to 'board')
-rw-r--r-- | board/cmc_pu2/Makefile | 2 | ||||
-rw-r--r-- | board/cmc_pu2/cmc_pu2.c | 23 | ||||
-rw-r--r-- | board/cmc_pu2/load_sernum_ethaddr.c | 122 | ||||
-rw-r--r-- | board/esd/cpci5200/config.mk | 44 | ||||
-rw-r--r-- | board/esd/cpci5200/cpci5200.c | 295 | ||||
-rw-r--r-- | board/esd/cpci5200/mt46v16m16-75.h | 37 | ||||
-rw-r--r-- | board/esd/cpci5200/strataflash.c | 804 | ||||
-rw-r--r-- | board/esd/cpci5200/u-boot.lds | 122 | ||||
-rw-r--r-- | board/esd/pf5200/Makefile | 53 | ||||
-rw-r--r-- | board/esd/pf5200/config.mk | 44 | ||||
-rw-r--r-- | board/esd/pf5200/flash.c | 461 | ||||
-rw-r--r-- | board/esd/pf5200/mt46v16m16-75.h | 37 | ||||
-rw-r--r-- | board/esd/pf5200/pf5200.c | 370 | ||||
-rw-r--r-- | board/esd/pf5200/u-boot.lds | 122 | ||||
-rw-r--r-- | board/o2dnt/Makefile | 47 | ||||
-rw-r--r-- | board/o2dnt/config.mk | 27 | ||||
-rw-r--r-- | board/o2dnt/flash.c | 587 | ||||
-rw-r--r-- | board/o2dnt/o2dnt.c | 182 | ||||
-rw-r--r-- | board/o2dnt/u-boot.lds | 122 | ||||
-rw-r--r-- | board/tqm5200/Makefile | 2 | ||||
-rwxr-xr-x | board/tqm5200/cmd_stk52xx.c | 1221 | ||||
-rw-r--r-- | board/tqm5200/tqm5200.c | 50 |
22 files changed, 4758 insertions, 16 deletions
diff --git a/board/cmc_pu2/Makefile b/board/cmc_pu2/Makefile index ba433d5..7703a4a 100644 --- a/board/cmc_pu2/Makefile +++ b/board/cmc_pu2/Makefile @@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk LIB = lib$(BOARD).a -OBJS := cmc_pu2.o at45.o dm9161.o flash.o +OBJS := cmc_pu2.o at45.o dm9161.o flash.o load_sernum_ethaddr.o $(LIB): $(OBJS) $(SOBJS) $(AR) crv $@ $(OBJS) $(SOBJS) diff --git a/board/cmc_pu2/cmc_pu2.c b/board/cmc_pu2/cmc_pu2.c index 8e0f6d3..b5e5e28 100644 --- a/board/cmc_pu2/cmc_pu2.c +++ b/board/cmc_pu2/cmc_pu2.c @@ -35,8 +35,9 @@ /* * Miscelaneous platform dependent initialisations */ -#define CMC_BASIC 1 +#define CMC_HP_BASIC 1 #define CMC_PU2 2 +#define CMC_BASIC 4 int hw_detect (void); @@ -74,14 +75,14 @@ int board_init (void) /* * On CMC-PU2 board configure PB3-PB6 to input without pull ups to * clear the duo LEDs (the external pull downs assure a proper - * signal). On CMC-BASIC set PB3-PB6 to output and drive it - * high, to configure current meassurement on AINx. + * signal). On CMC-BASIC and CMC-HP-BASIC set PB3-PB6 to output and + * drive it high, to configure current measurement on AINx. */ if (hw_detect() & CMC_PU2) { piob->PIO_ODR = AT91C_PIO_PB3 | AT91C_PIO_PB4 | AT91C_PIO_PB5 | AT91C_PIO_PB6; } - else if (hw_detect() & CMC_BASIC) { + else if ((hw_detect() & CMC_BASIC) || (hw_detect() & CMC_HP_BASIC)) { piob->PIO_SODR = AT91C_PIO_PB3 | AT91C_PIO_PB4 | AT91C_PIO_PB5 | AT91C_PIO_PB6; piob->PIO_OER = AT91C_PIO_PB3 | AT91C_PIO_PB4 | @@ -119,6 +120,8 @@ int checkboard (void) puts ("Board: CMC-PU2 (Rittal GmbH)\n"); else if (hw_detect() & CMC_BASIC) puts ("Board: CMC-BASIC (Rittal GmbH)\n"); + else if (hw_detect() & CMC_HP_BASIC) + puts ("Board: CMC-HP-BASIC (Rittal GmbH)\n"); else puts ("Board: unknown\n"); return 0; @@ -136,6 +139,16 @@ int hw_detect (void) pio->PIO_PPUDR = AT91C_PIO_PB12; pio->PIO_PER = AT91C_PIO_PB12; + /* configure PB13 as input without pull up */ + pio->PIO_ODR = AT91C_PIO_PB13; + pio->PIO_PPUDR = AT91C_PIO_PB13; + pio->PIO_PER = AT91C_PIO_PB13; + /* read board identification pin */ - return ((pio->PIO_PDSR & AT91C_PIO_PB12) ? CMC_PU2 : CMC_BASIC); + if (pio->PIO_PDSR & AT91C_PIO_PB12) + return ((pio->PIO_PDSR & AT91C_PIO_PB13) + ? CMC_PU2 : 0); + else + return ((pio->PIO_PDSR & AT91C_PIO_PB13) + ? CMC_HP_BASIC : CMC_BASIC); } diff --git a/board/cmc_pu2/load_sernum_ethaddr.c b/board/cmc_pu2/load_sernum_ethaddr.c new file mode 100644 index 0000000..94aa30d --- /dev/null +++ b/board/cmc_pu2/load_sernum_ethaddr.c @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2000, 2001, 2002 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2005 + * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* #define DEBUG */ + +#include <common.h> + +#define I2C_CHIP 0x50 /* I2C bus address of onboard EEPROM */ +#define I2C_ALEN 1 /* length of EEPROM addresses in bytes */ +#define I2C_OFFSET 0x0 /* start address of manufacturere data block + * in EEPROM */ + +/* 64 Byte manufacturer data block in EEPROM */ +struct manufacturer_data { + unsigned int serial_number; /* serial number (0...999999) */ + unsigned short hardware; /* hardware version (e.g. V1.02) */ + unsigned short manuf_date; /* manufacture date (e.g. 25/02) */ + unsigned char name[20]; /* device name (in CHIP.INI) */ + unsigned char macadr[6]; /* MAC address */ + signed char a_kal[4]; /* calibration value for U */ + signed char i_kal[4]; /* calibration value for I */ + unsigned char reserve[18]; /* reserved */ + unsigned short save_nr; /* save count */ + unsigned short chksum; /* checksum */ +}; + + +int i2c_read (unsigned char chip, unsigned int addr, int alen, + unsigned char *buffer, int len); + +/*----------------------------------------------------------------------- + * Process manufacturer data block in EEPROM: + * + * If we boot on a system fresh from factory, check if the manufacturer data + * in the EEPROM is valid and save some information it contains. + * + * CMC manufacturer data is defined as follows: + * + * - located in the onboard EEPROM + * - starts at offset 0x0 + * - size 0x00000040 + * + * Internal structure: see struct definition + */ + +void load_sernum_ethaddr (void) +{ + struct manufacturer_data data; + unsigned char serial [9]; + unsigned char ethaddr[18]; + unsigned short chksum; + unsigned char *p; + unsigned short i, is, id; + +#if !defined(CONFIG_HARD_I2C) && !defined(CONFIG_SOFT_I2C) +#error you must define some I2C support (CONFIG_HARD_I2C or CONFIG_SOFT_I2C) +#endif + if (i2c_read(I2C_CHIP, I2C_OFFSET, I2C_ALEN, (unsigned char *)&data, + sizeof(data)) != 0) { + puts ("Error reading manufacturer data from EEPROM\n"); + return; + } + + /* check if manufacturer data block is valid */ + p = (unsigned char *)&data; + chksum = 0; + for (i = 0; i < (sizeof(data) - sizeof(data.chksum)); i++) + chksum += *p++; + + debug ("checksum of manufacturer data block: %#.4x\n", chksum); + + if (chksum != data.chksum) { + puts ("Error: manufacturer data block has invalid checksum\n"); + return; + } + + /* copy MAC address */ + is = 0; + id = 0; + for (i = 0; i < 6; i++) { + sprintf (ðaddr[id], "%02x", data.macadr[is++]); + id += 2; + if (is < 6) + ethaddr[id++] = ':'; + } + ethaddr[id] = '\0'; /* just to be sure */ + + /* copy serial number */ + sprintf (serial, "%d", data.serial_number); + + /* set serial# and ethaddr if not yet defined */ + if (getenv("serial#") == NULL) { + setenv ("serial#", serial); + } + + if (getenv("ethaddr") == NULL) { + setenv ("ethaddr", ethaddr); + } +} diff --git a/board/esd/cpci5200/config.mk b/board/esd/cpci5200/config.mk new file mode 100644 index 0000000..07b5de1 --- /dev/null +++ b/board/esd/cpci5200/config.mk @@ -0,0 +1,44 @@ +# +# (C) Copyright 2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# +# IceCube board: +# +# Valid values for TEXT_BASE are: +# +# 0xFFF00000 boot high (standard configuration) +# 0xFF000000 boot low for 16 MiB boards +# 0xFF800000 boot low for 8 MiB boards +# 0x00100000 boot from RAM (for testing only) +# + +sinclude $(TOPDIR)/board/$(BOARDDIR)/config.tmp + +ifndef TEXT_BASE +## Standard: boot high +TEXT_BASE = 0xFFF00000 +## For testing: boot from RAM +# TEXT_BASE = 0x00100000 +endif + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR)/board diff --git a/board/esd/cpci5200/cpci5200.c b/board/esd/cpci5200/cpci5200.c new file mode 100644 index 0000000..01c4171 --- /dev/null +++ b/board/esd/cpci5200/cpci5200.c @@ -0,0 +1,295 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * cpci5200.c - main board support/init for the esd cpci5200. + */ + +#include <common.h> +#include <mpc5xxx.h> +#include <pci.h> +#include <command.h> + +#include "mt46v16m16-75.h" + +void init_ata_reset(void); + +static void sdram_start(int hi_addr) +{ + long hi_addr_bit = hi_addr ? 0x01000000 : 0; + + /* unlock mode register */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000000 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* set mode register: extended mode */ + *(vu_long *) MPC5XXX_SDRAM_MODE = SDRAM_EMODE; + __asm__ volatile ("sync"); + + /* set mode register: reset DLL */ + *(vu_long *) MPC5XXX_SDRAM_MODE = SDRAM_MODE | 0x04000000; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* auto refresh */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000004 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* set mode register */ + *(vu_long *) MPC5XXX_SDRAM_MODE = SDRAM_MODE; + __asm__ volatile ("sync"); + + /* normal operation */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | hi_addr_bit; + __asm__ volatile ("sync"); +} + +/* + * ATTENTION: Although partially referenced initdram does NOT make real use + * use of CFG_SDRAM_BASE. The code does not work if CFG_SDRAM_BASE + * is something else than 0x00000000. + */ + +long int initdram(int board_type) +{ + ulong dramsize = 0; + ulong test1, test2; + + /* setup SDRAM chip selects */ + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = 0x0000001e; /* 2G at 0x0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = 0x80000000; /* disabled */ + __asm__ volatile ("sync"); + + /* setup config registers */ + *(vu_long *) MPC5XXX_SDRAM_CONFIG1 = SDRAM_CONFIG1; + *(vu_long *) MPC5XXX_SDRAM_CONFIG2 = SDRAM_CONFIG2; + __asm__ volatile ("sync"); + + /* set tap delay */ + *(vu_long *) MPC5XXX_CDM_PORCFG = SDRAM_TAPDELAY; + __asm__ volatile ("sync"); + + /* find RAM size using SDRAM CS0 only */ + sdram_start(0); + test1 = get_ram_size((ulong *) CFG_SDRAM_BASE, 0x80000000); + sdram_start(1); + test2 = get_ram_size((ulong *) CFG_SDRAM_BASE, 0x80000000); + + if (test1 > test2) { + sdram_start(0); + dramsize = test1; + } else { + dramsize = test2; + } + + /* memory smaller than 1MB is impossible */ + if (dramsize < (1 << 20)) { + dramsize = 0; + } + + /* set SDRAM CS0 size according to the amount of RAM found */ + if (dramsize > 0) { + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = + 0x13 + __builtin_ffs(dramsize >> 20) - 1; + /* let SDRAM CS1 start right after CS0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = dramsize + 0x0000001e; /* 2G */ + } else { +#if 0 + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ + /* let SDRAM CS1 start right after CS0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = dramsize + 0x0000001e; /* 2G */ +#else + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = + 0x13 + __builtin_ffs(0x08000000 >> 20) - 1; + /* let SDRAM CS1 start right after CS0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = 0x08000000 + 0x0000001e; /* 2G */ +#endif + } + +#if 0 + /* find RAM size using SDRAM CS1 only */ + sdram_start(0); + get_ram_size((ulong *) (CFG_SDRAM_BASE + dramsize), 0x80000000); + sdram_start(1); + get_ram_size((ulong *) (CFG_SDRAM_BASE + dramsize), 0x80000000); + sdram_start(0); +#endif + /* set SDRAM CS1 size according to the amount of RAM found */ + + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = dramsize; /* disabled */ + + init_ata_reset(); + return (dramsize); +} + +int checkboard(void) +{ + puts("Board: esd CPCI5200 (cpci5200)\n"); + return 0; +} + +void flash_preinit(void) +{ + /* + * Now, when we are in RAM, enable flash write + * access for detection process. + * Note that CS_BOOT cannot be cleared when + * executing in flash. + */ + *(vu_long *) MPC5XXX_BOOTCS_CFG &= ~0x1; /* clear RO */ +} + +void flash_afterinit(ulong size) +{ + if (size == 0x02000000) { + /* adjust mapping */ + *(vu_long *) MPC5XXX_BOOTCS_START = + *(vu_long *) MPC5XXX_CS0_START = + START_REG(CFG_BOOTCS_START | size); + *(vu_long *) MPC5XXX_BOOTCS_STOP = + *(vu_long *) MPC5XXX_CS0_STOP = + STOP_REG(CFG_BOOTCS_START | size, size); + } +} + +#ifdef CONFIG_PCI +static struct pci_controller hose; + +extern void pci_mpc5xxx_init(struct pci_controller *); + +void pci_init_board(void + ) { + pci_mpc5xxx_init(&hose); +} +#endif + +#if defined (CFG_CMD_IDE) && defined (CONFIG_IDE_RESET) + +#define GPIO_PSC1_4 0x01000000UL + +void init_ide_reset(void) +{ + debug("init_ide_reset\n"); + + /* Configure PSC1_4 as GPIO output for ATA reset */ + *(vu_long *) MPC5XXX_WU_GPIO_ENABLE |= GPIO_PSC1_4; + *(vu_long *) MPC5XXX_WU_GPIO_DIR |= GPIO_PSC1_4; +} + +void ide_set_reset(int idereset) +{ + debug("ide_reset(%d)\n", idereset); + + if (idereset) { + *(vu_long *) MPC5XXX_WU_GPIO_DATA &= ~GPIO_PSC1_4; + } else { + *(vu_long *) MPC5XXX_WU_GPIO_DATA |= GPIO_PSC1_4; + } +} +#endif /* defined (CFG_CMD_IDE) && defined (CONFIG_IDE_RESET) */ + +#define MPC5XXX_SIMPLEIO_GPIO_ENABLE (MPC5XXX_GPIO + 0x0004) +#define MPC5XXX_SIMPLEIO_GPIO_DIR (MPC5XXX_GPIO + 0x000C) +#define MPC5XXX_SIMPLEIO_GPIO_DATA_OUTPUT (MPC5XXX_GPIO + 0x0010) +#define MPC5XXX_SIMPLEIO_GPIO_DATA_INPUT (MPC5XXX_GPIO + 0x0014) + +#define MPC5XXX_INTERRUPT_GPIO_ENABLE (MPC5XXX_GPIO + 0x0020) +#define MPC5XXX_INTERRUPT_GPIO_DIR (MPC5XXX_GPIO + 0x0028) +#define MPC5XXX_INTERRUPT_GPIO_DATA_OUTPUT (MPC5XXX_GPIO + 0x002C) +#define MPC5XXX_INTERRUPT_GPIO_STATUS (MPC5XXX_GPIO + 0x003C) + +#define GPIO_WU6 0x40000000UL +#define GPIO_USB0 0x00010000UL +#define GPIO_USB9 0x08000000UL +#define GPIO_USB9S 0x00080000UL + +void init_ata_reset(void) +{ + debug("init_ata_reset\n"); + + /* Configure GPIO_WU6 as GPIO output for ATA reset */ + *(vu_long *) MPC5XXX_WU_GPIO_DATA |= GPIO_WU6; + *(vu_long *) MPC5XXX_WU_GPIO_ENABLE |= GPIO_WU6; + *(vu_long *) MPC5XXX_WU_GPIO_DIR |= GPIO_WU6; + __asm__ volatile ("sync"); + + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_DATA_OUTPUT &= ~GPIO_USB0; + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_ENABLE |= GPIO_USB0; + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_DIR |= GPIO_USB0; + __asm__ volatile ("sync"); + + *(vu_long *) MPC5XXX_INTERRUPT_GPIO_DATA_OUTPUT &= ~GPIO_USB9; + *(vu_long *) MPC5XXX_INTERRUPT_GPIO_ENABLE &= ~GPIO_USB9; + __asm__ volatile ("sync"); + + if ((*(vu_long *) MPC5XXX_INTERRUPT_GPIO_STATUS & GPIO_USB9S) == 0) { + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_DATA_OUTPUT |= GPIO_USB0; + __asm__ volatile ("sync"); + } +} + +int do_writepci(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + unsigned int addr; + unsigned int size; + int i; + volatile unsigned long *ptr; + + addr = simple_strtol(argv[1], NULL, 16); + size = simple_strtol(argv[2], NULL, 16); + + printf("\nWriting at addr %08x, size %08x.\n", addr, size); + + while (1) { + ptr = (volatile unsigned long *)addr; + for (i = 0; i < (size >> 2); i++) { + *ptr++ = i; + } + + /* Abort if ctrl-c was pressed */ + if (ctrlc()) { + puts("\nAbort\n"); + return 0; + } + putc('.'); + } + return 0; +} + +U_BOOT_CMD(writepci, 3, 1, do_writepci, + "writepci- Write some data to pcibus\n", + "<addr> <size>\n" " - Write some data to pcibus.\n"); diff --git a/board/esd/cpci5200/mt46v16m16-75.h b/board/esd/cpci5200/mt46v16m16-75.h new file mode 100644 index 0000000..22d0a55 --- /dev/null +++ b/board/esd/cpci5200/mt46v16m16-75.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define SDRAM_DDR 1 /* is DDR */ + +#if defined(CONFIG_MPC5200) +/* Settings for XLB = 132 MHz */ +#define SDRAM_MODE 0x018D0000 +#define SDRAM_EMODE 0x40090000 +#define SDRAM_CONTROL 0x705f0f00 +#define SDRAM_CONFIG1 0x73722930 +#define SDRAM_CONFIG2 0x47770000 +#define SDRAM_TAPDELAY 0x10000000 + +#else +#error CONFIG_MPC5200 not defined +#endif diff --git a/board/esd/cpci5200/strataflash.c b/board/esd/cpci5200/strataflash.c new file mode 100644 index 0000000..d76af02 --- /dev/null +++ b/board/esd/cpci5200/strataflash.c @@ -0,0 +1,804 @@ +/* + * (C) Copyright 2002 + * Brad Kemp, Seranoa Networks, Brad.Kemp@seranoa.com + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <asm/processor.h> +#include <asm/cache.h> + +#undef DEBUG_FLASH +/* + * This file implements a Common Flash Interface (CFI) driver for U-Boot. + * The width of the port and the width of the chips are determined at initialization. + * These widths are used to calculate the address for access CFI data structures. + * It has been tested on an Intel Strataflash implementation. + * + * References + * JEDEC Standard JESD68 - Common Flash Interface (CFI) + * JEDEC Standard JEP137-A Common Flash Interface (CFI) ID Codes + * Intel Application Note 646 Common Flash Interface (CFI) and Command Sets + * Intel 290667-008 3 Volt Intel StrataFlash Memory datasheet + * + * TODO + * Use Primary Extended Query table (PRI) and Alternate Algorithm Query Table (ALT) to determine if protection is available + * Add support for other command sets Use the PRI and ALT to determine command set + * Verify erase and program timeouts. + */ + +#define FLASH_CMD_CFI 0x98 +#define FLASH_CMD_READ_ID 0x90 +#define FLASH_CMD_RESET 0xff +#define FLASH_CMD_BLOCK_ERASE 0x20 +#define FLASH_CMD_ERASE_CONFIRM 0xD0 +#define FLASH_CMD_WRITE 0x40 +#define FLASH_CMD_PROTECT 0x60 +#define FLASH_CMD_PROTECT_SET 0x01 +#define FLASH_CMD_PROTECT_CLEAR 0xD0 +#define FLASH_CMD_CLEAR_STATUS 0x50 +#define FLASH_CMD_WRITE_TO_BUFFER 0xE8 +#define FLASH_CMD_WRITE_BUFFER_CONFIRM 0xD0 + +#define FLASH_STATUS_DONE 0x80 +#define FLASH_STATUS_ESS 0x40 +#define FLASH_STATUS_ECLBS 0x20 +#define FLASH_STATUS_PSLBS 0x10 +#define FLASH_STATUS_VPENS 0x08 +#define FLASH_STATUS_PSS 0x04 +#define FLASH_STATUS_DPS 0x02 +#define FLASH_STATUS_R 0x01 +#define FLASH_STATUS_PROTECT 0x01 + +#define FLASH_OFFSET_CFI 0x55 +#define FLASH_OFFSET_CFI_RESP 0x10 +#define FLASH_OFFSET_WTOUT 0x1F +#define FLASH_OFFSET_WBTOUT 0x20 +#define FLASH_OFFSET_ETOUT 0x21 +#define FLASH_OFFSET_CETOUT 0x22 +#define FLASH_OFFSET_WMAX_TOUT 0x23 +#define FLASH_OFFSET_WBMAX_TOUT 0x24 +#define FLASH_OFFSET_EMAX_TOUT 0x25 +#define FLASH_OFFSET_CEMAX_TOUT 0x26 +#define FLASH_OFFSET_SIZE 0x27 +#define FLASH_OFFSET_INTERFACE 0x28 +#define FLASH_OFFSET_BUFFER_SIZE 0x2A +#define FLASH_OFFSET_NUM_ERASE_REGIONS 0x2C +#define FLASH_OFFSET_ERASE_REGIONS 0x2D +#define FLASH_OFFSET_PROTECT 0x02 +#define FLASH_OFFSET_USER_PROTECTION 0x85 +#define FLASH_OFFSET_INTEL_PROTECTION 0x81 + +#define FLASH_MAN_CFI 0x01000000 + +typedef union { + unsigned char c; + unsigned short w; + unsigned long l; +} cfiword_t; + +typedef union { + unsigned char *cp; + unsigned short *wp; + unsigned long *lp; +} cfiptr_t; + +#define NUM_ERASE_REGIONS 4 + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +/*----------------------------------------------------------------------- + * Functions + */ + +static void flash_add_byte(flash_info_t * info, cfiword_t * cword, uchar c); +static void flash_make_cmd(flash_info_t * info, uchar cmd, void *cmdbuf); +static void flash_write_cmd(flash_info_t * info, int sect, uchar offset, + uchar cmd); +static int flash_isequal(flash_info_t * info, int sect, uchar offset, + uchar cmd); +static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd); +static int flash_detect_cfi(flash_info_t * info); +static ulong flash_get_size(ulong base, int banknum); +static int flash_write_cfiword(flash_info_t * info, ulong dest, + cfiword_t cword); +static int flash_full_status_check(flash_info_t * info, ulong sector, + ulong tout, char *prompt); +#ifdef CFG_FLASH_USE_BUFFER_WRITE +static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, + int len); +#endif +/*----------------------------------------------------------------------- + * create an address based on the offset and the port width + */ +inline uchar *flash_make_addr(flash_info_t * info, int sect, int offset) +{ + return ((uchar *) (info->start[sect] + (offset * info->portwidth))); +} + +/*----------------------------------------------------------------------- + * read a character at a port width address + */ +inline uchar flash_read_uchar(flash_info_t * info, uchar offset) +{ + uchar *cp; + cp = flash_make_addr(info, 0, offset); + return (cp[info->portwidth - 1]); +} + +/*----------------------------------------------------------------------- + * read a short word by swapping for ppc format. + */ +ushort flash_read_ushort(flash_info_t * info, int sect, uchar offset) +{ + uchar *addr; + + addr = flash_make_addr(info, sect, offset); + return ((addr[(2 * info->portwidth) - 1] << 8) | + addr[info->portwidth - 1]); + +} + +/*----------------------------------------------------------------------- + * read a long word by picking the least significant byte of each maiximum + * port size word. Swap for ppc format. + */ +ulong flash_read_long(flash_info_t * info, int sect, uchar offset) +{ + uchar *addr; + + addr = flash_make_addr(info, sect, offset); + return ((addr[(2 * info->portwidth) - 1] << 24) | + (addr[(info->portwidth) - 1] << 16) | + (addr[(4 * info->portwidth) - 1] << 8) | + addr[(3 * info->portwidth) - 1]); + +} + +/*----------------------------------------------------------------------- + */ +unsigned long flash_init(void) +{ + unsigned long size; + int i; + unsigned long address; + + /* The flash is positioned back to back, with the demultiplexing of the chip + * based on the A24 address line. + * + */ + + address = CFG_FLASH_BASE; + size = 0; + + /* Init: no FLASHes known */ + for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { + flash_info[i].flash_id = FLASH_UNKNOWN; + size += flash_info[i].size = flash_get_size(address, i); + address += CFG_FLASH_INCREMENT; + if (flash_info[i].flash_id == FLASH_UNKNOWN) { + printf + ("## Unknown FLASH on Bank %d - Size = 0x%08lx = %ld MB\n", + i, flash_info[0].size, flash_info[i].size << 20); + } + } + +#if 0 /* test-only */ + /* Monitor protection ON by default */ +#if (CFG_MONITOR_BASE >= CFG_FLASH_BASE) + for (i = 0; + flash_info[0].start[i] < CFG_MONITOR_BASE + monitor_flash_len - 1; + i++) + (void)flash_real_protect(&flash_info[0], i, 1); +#endif +#endif + + return (size); +} + +/*----------------------------------------------------------------------- + */ +int flash_erase(flash_info_t * info, int s_first, int s_last) +{ + int rcode = 0; + int prot; + int sect; + + if (info->flash_id != FLASH_MAN_CFI) { + printf("Can't erase unknown flash type - aborted\n"); + return 1; + } + if ((s_first < 0) || (s_first > s_last)) { + printf("- no sectors to erase\n"); + return 1; + } + + prot = 0; + for (sect = s_first; sect <= s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + if (prot) { + printf("- Warning: %d protected sectors will not be erased!\n", + prot); + } else { + printf("\n"); + } + + for (sect = s_first; sect <= s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + flash_write_cmd(info, sect, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sect, 0, FLASH_CMD_BLOCK_ERASE); + flash_write_cmd(info, sect, 0, FLASH_CMD_ERASE_CONFIRM); + + if (flash_full_status_check + (info, sect, info->erase_blk_tout, "erase")) { + rcode = 1; + } else + printf("."); + } + } + printf(" done\n"); + return rcode; +} + +/*----------------------------------------------------------------------- + */ +void flash_print_info(flash_info_t * info) +{ + int i; + + if (info->flash_id != FLASH_MAN_CFI) { + printf("missing or unknown FLASH type\n"); + return; + } + + printf("CFI conformant FLASH (%d x %d)", + (info->portwidth << 3), (info->chipwidth << 3)); + printf(" Size: %ld MB in %d Sectors\n", + info->size >> 20, info->sector_count); + printf + (" Erase timeout %ld ms, write timeout %ld ms, buffer write timeout %ld ms, buffer size %d\n", + info->erase_blk_tout, info->write_tout, info->buffer_write_tout, + info->buffer_size); + + printf(" Sector Start Addresses:"); + for (i = 0; i < info->sector_count; ++i) { + if ((i % 5) == 0) + printf("\n"); + printf(" %08lX%5s", + info->start[i], info->protect[i] ? " (RO)" : " "); + } + printf("\n"); + return; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + ulong wp; + ulong cp; + int aln; + cfiword_t cword; + int i, rc; + + /* get lower aligned address */ + wp = (addr & ~(info->portwidth - 1)); + + /* handle unaligned start */ + if ((aln = addr - wp) != 0) { + cword.l = 0; + cp = wp; + for (i = 0; i < aln; ++i, ++cp) + flash_add_byte(info, &cword, (*(uchar *) cp)); + + for (; (i < info->portwidth) && (cnt > 0); i++) { + flash_add_byte(info, &cword, *src++); + cnt--; + cp++; + } + for (; (cnt == 0) && (i < info->portwidth); ++i, ++cp) + flash_add_byte(info, &cword, (*(uchar *) cp)); + if ((rc = flash_write_cfiword(info, wp, cword)) != 0) + return rc; + wp = cp; + } +#ifdef CFG_FLASH_USE_BUFFER_WRITE + while (cnt >= info->portwidth) { + i = info->buffer_size > cnt ? cnt : info->buffer_size; + if ((rc = flash_write_cfibuffer(info, wp, src, i)) != ERR_OK) + return rc; + wp += i; + src += i; + cnt -= i; + } +#else + /* handle the aligned part */ + while (cnt >= info->portwidth) { + cword.l = 0; + for (i = 0; i < info->portwidth; i++) { + flash_add_byte(info, &cword, *src++); + } + if ((rc = flash_write_cfiword(info, wp, cword)) != 0) + return rc; + wp += info->portwidth; + cnt -= info->portwidth; + } +#endif /* CFG_FLASH_USE_BUFFER_WRITE */ + if (cnt == 0) { + return (0); + } + + /* + * handle unaligned tail bytes + */ + cword.l = 0; + for (i = 0, cp = wp; (i < info->portwidth) && (cnt > 0); ++i, ++cp) { + flash_add_byte(info, &cword, *src++); + --cnt; + } + for (; i < info->portwidth; ++i, ++cp) { + flash_add_byte(info, &cword, (*(uchar *) cp)); + } + + return flash_write_cfiword(info, wp, cword); +} + +/*----------------------------------------------------------------------- + */ +int flash_real_protect(flash_info_t * info, long sector, int prot) +{ + int retcode = 0; + + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT); + if (prot) + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_SET); + else + flash_write_cmd(info, sector, 0, FLASH_CMD_PROTECT_CLEAR); + + if ((retcode = + flash_full_status_check(info, sector, info->erase_blk_tout, + prot ? "protect" : "unprotect")) == 0) { + + info->protect[sector] = prot; + /* Intel's unprotect unprotects all locking */ + if (prot == 0) { + int i; + for (i = 0; i < info->sector_count; i++) { + if (info->protect[i]) + flash_real_protect(info, i, 1); + } + } + } + + return retcode; +} + +/*----------------------------------------------------------------------- + * wait for XSR.7 to be set. Time out with an error if it does not. + * This routine does not set the flash to read-array mode. + */ +static int flash_status_check(flash_info_t * info, ulong sector, ulong tout, + char *prompt) +{ + ulong start; + + /* Wait for command completion */ + start = get_timer(0); + while (!flash_isset(info, sector, 0, FLASH_STATUS_DONE)) { + if (get_timer(start) > info->erase_blk_tout) { + printf("Flash %s timeout at address %lx\n", prompt, + info->start[sector]); + flash_write_cmd(info, sector, 0, FLASH_CMD_RESET); + return ERR_TIMOUT; + } + } + return ERR_OK; +} + +/*----------------------------------------------------------------------- + * Wait for XSR.7 to be set, if it times out print an error, otherwise do a full status check. + * This routine sets the flash to read-array mode. + */ +static int flash_full_status_check(flash_info_t * info, ulong sector, + ulong tout, char *prompt) +{ + int retcode; + retcode = flash_status_check(info, sector, tout, prompt); + if ((retcode == ERR_OK) + && !flash_isequal(info, sector, 0, FLASH_STATUS_DONE)) { + retcode = ERR_INVAL; + printf("Flash %s error at address %lx\n", prompt, + info->start[sector]); + if (flash_isset + (info, sector, 0, + FLASH_STATUS_ECLBS | FLASH_STATUS_PSLBS)) { + printf("Command Sequence Error.\n"); + } else if (flash_isset(info, sector, 0, FLASH_STATUS_ECLBS)) { + printf("Block Erase Error.\n"); + retcode = ERR_NOT_ERASED; + } else if (flash_isset(info, sector, 0, FLASH_STATUS_PSLBS)) { + printf("Locking Error\n"); + } + if (flash_isset(info, sector, 0, FLASH_STATUS_DPS)) { + printf("Block locked.\n"); + retcode = ERR_PROTECTED; + } + if (flash_isset(info, sector, 0, FLASH_STATUS_VPENS)) + printf("Vpp Low Error.\n"); + } + flash_write_cmd(info, sector, 0, FLASH_CMD_RESET); + return retcode; +} + +/*----------------------------------------------------------------------- + */ +static void flash_add_byte(flash_info_t * info, cfiword_t * cword, uchar c) +{ + switch (info->portwidth) { + case FLASH_CFI_8BIT: + cword->c = c; + break; + case FLASH_CFI_16BIT: + cword->w = (cword->w << 8) | c; + break; + case FLASH_CFI_32BIT: + cword->l = (cword->l << 8) | c; + } +} + +/*----------------------------------------------------------------------- + * make a proper sized command based on the port and chip widths + */ +static void flash_make_cmd(flash_info_t * info, uchar cmd, void *cmdbuf) +{ + int i; + uchar *cp = (uchar *) cmdbuf; + for (i = 0; i < info->portwidth; i++) + *cp++ = ((i + 1) % info->chipwidth) ? '\0' : cmd; +} + +/* + * Write a proper sized command to the correct address + */ +static void flash_write_cmd(flash_info_t * info, int sect, uchar offset, + uchar cmd) +{ + + volatile cfiptr_t addr; + cfiword_t cword; + addr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch (info->portwidth) { + case FLASH_CFI_8BIT: + *addr.cp = cword.c; + break; + case FLASH_CFI_16BIT: + *addr.wp = cword.w; + break; + case FLASH_CFI_32BIT: + *addr.lp = cword.l; + break; + } +} + +/*----------------------------------------------------------------------- + */ +static int flash_isequal(flash_info_t * info, int sect, uchar offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + cptr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch (info->portwidth) { + case FLASH_CFI_8BIT: + retval = (cptr.cp[0] == cword.c); + break; + case FLASH_CFI_16BIT: + retval = (cptr.wp[0] == cword.w); + break; + case FLASH_CFI_32BIT: + retval = (cptr.lp[0] == cword.l); + break; + default: + retval = 0; + break; + } + return retval; +} + +/*----------------------------------------------------------------------- + */ +static int flash_isset(flash_info_t * info, int sect, uchar offset, uchar cmd) +{ + cfiptr_t cptr; + cfiword_t cword; + int retval; + cptr.cp = flash_make_addr(info, sect, offset); + flash_make_cmd(info, cmd, &cword); + switch (info->portwidth) { + case FLASH_CFI_8BIT: + retval = ((cptr.cp[0] & cword.c) == cword.c); + break; + case FLASH_CFI_16BIT: + retval = ((cptr.wp[0] & cword.w) == cword.w); + break; + case FLASH_CFI_32BIT: + retval = ((cptr.lp[0] & cword.l) == cword.l); + break; + default: + retval = 0; + break; + } + return retval; +} + +/*----------------------------------------------------------------------- + * detect if flash is compatible with the Common Flash Interface (CFI) + * http://www.jedec.org/download/search/jesd68.pdf + * + */ +static int flash_detect_cfi(flash_info_t * info) +{ + + for (info->portwidth = FLASH_CFI_8BIT; + info->portwidth <= FLASH_CFI_32BIT; info->portwidth <<= 1) { + for (info->chipwidth = FLASH_CFI_BY8; + info->chipwidth <= info->portwidth; + info->chipwidth <<= 1) { + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); + flash_write_cmd(info, 0, FLASH_OFFSET_CFI, + FLASH_CMD_CFI); + if (flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP, 'Q') + && flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 1, + 'R') + && flash_isequal(info, 0, FLASH_OFFSET_CFI_RESP + 2, + 'Y')) + return 1; + } + } + return 0; +} + +/* + * The following code cannot be run from FLASH! + * + */ +static ulong flash_get_size(ulong base, int banknum) +{ + flash_info_t *info = &flash_info[banknum]; + int i, j; + int sect_cnt; + unsigned long sector; + unsigned long tmp; + int size_ratio = 0; + uchar num_erase_regions; + int erase_region_size; + int erase_region_count; + + info->start[0] = base; +#if 0 + invalidate_dcache_range(base, base + 0x400); +#endif + if (flash_detect_cfi(info)) { + + size_ratio = info->portwidth / info->chipwidth; + num_erase_regions = + flash_read_uchar(info, FLASH_OFFSET_NUM_ERASE_REGIONS); + + sect_cnt = 0; + sector = base; + for (i = 0; i < num_erase_regions; i++) { + if (i > NUM_ERASE_REGIONS) { + printf("%d erase regions found, only %d used\n", + num_erase_regions, NUM_ERASE_REGIONS); + break; + } + tmp = + flash_read_long(info, 0, + FLASH_OFFSET_ERASE_REGIONS); + erase_region_size = + (tmp & 0xffff) ? ((tmp & 0xffff) * 256) : 128; + tmp >>= 16; + erase_region_count = (tmp & 0xffff) + 1; + for (j = 0; j < erase_region_count; j++) { + info->start[sect_cnt] = sector; + sector += (erase_region_size * size_ratio); + info->protect[sect_cnt] = + flash_isset(info, sect_cnt, + FLASH_OFFSET_PROTECT, + FLASH_STATUS_PROTECT); + sect_cnt++; + } + } + + info->sector_count = sect_cnt; + /* multiply the size by the number of chips */ + info->size = + (1 << flash_read_uchar(info, FLASH_OFFSET_SIZE)) * + size_ratio; + info->buffer_size = + (1 << flash_read_ushort(info, 0, FLASH_OFFSET_BUFFER_SIZE)); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_ETOUT); + info->erase_blk_tout = + (tmp * + (1 << flash_read_uchar(info, FLASH_OFFSET_EMAX_TOUT))); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WBTOUT); + info->buffer_write_tout = + (tmp * + (1 << flash_read_uchar(info, FLASH_OFFSET_WBMAX_TOUT))); + tmp = 1 << flash_read_uchar(info, FLASH_OFFSET_WTOUT); + info->write_tout = + (tmp * + (1 << flash_read_uchar(info, FLASH_OFFSET_WMAX_TOUT))) / + 1000; + info->flash_id = FLASH_MAN_CFI; + } + + flash_write_cmd(info, 0, 0, FLASH_CMD_RESET); +#ifdef DEBUG_FLASH + printf("portwidth=%d chipwidth=%d\n", info->portwidth, info->chipwidth); /* test-only */ +#endif +#ifdef DEBUG_FLASH + printf("found %d erase regions\n", num_erase_regions); +#endif +#ifdef DEBUG_FLASH + printf("size=%08x sectors=%08x \n", info->size, info->sector_count); +#endif + return (info->size); +} + +/*----------------------------------------------------------------------- + */ +static int flash_write_cfiword(flash_info_t * info, ulong dest, cfiword_t cword) +{ + + cfiptr_t ctladdr; + cfiptr_t cptr; + int flag; + + ctladdr.cp = flash_make_addr(info, 0, 0); + cptr.cp = (uchar *) dest; + + /* Check if Flash is (sufficiently) erased */ + switch (info->portwidth) { + case FLASH_CFI_8BIT: + flag = ((cptr.cp[0] & cword.c) == cword.c); + break; + case FLASH_CFI_16BIT: + flag = ((cptr.wp[0] & cword.w) == cword.w); + break; + case FLASH_CFI_32BIT: + flag = ((cptr.lp[0] & cword.l) == cword.l); + break; + default: + return 2; + } + if (!flag) + return 2; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + flash_write_cmd(info, 0, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, 0, 0, FLASH_CMD_WRITE); + + switch (info->portwidth) { + case FLASH_CFI_8BIT: + cptr.cp[0] = cword.c; + break; + case FLASH_CFI_16BIT: + cptr.wp[0] = cword.w; + break; + case FLASH_CFI_32BIT: + cptr.lp[0] = cword.l; + break; + } + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + return flash_full_status_check(info, 0, info->write_tout, "write"); +} + +#ifdef CFG_FLASH_USE_BUFFER_WRITE + +/* loop through the sectors from the highest address + * when the passed address is greater or equal to the sector address + * we have a match + */ +static int find_sector(flash_info_t * info, ulong addr) +{ + int sector; + for (sector = info->sector_count - 1; sector >= 0; sector--) { + if (addr >= info->start[sector]) + break; + } + return sector; +} + +static int flash_write_cfibuffer(flash_info_t * info, ulong dest, uchar * cp, + int len) +{ + + int sector; + int cnt; + int retcode; + volatile cfiptr_t src; + volatile cfiptr_t dst; + + src.cp = cp; + dst.cp = (uchar *) dest; + sector = find_sector(info, dest); + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + flash_write_cmd(info, sector, 0, FLASH_CMD_WRITE_TO_BUFFER); + if ((retcode = flash_status_check(info, sector, info->buffer_write_tout, + "write to buffer")) == ERR_OK) { + switch (info->portwidth) { + case FLASH_CFI_8BIT: + cnt = len; + break; + case FLASH_CFI_16BIT: + cnt = len >> 1; + break; + case FLASH_CFI_32BIT: + cnt = len >> 2; + break; + default: + return ERR_INVAL; + break; + } + flash_write_cmd(info, sector, 0, (uchar) cnt - 1); + while (cnt-- > 0) { + switch (info->portwidth) { + case FLASH_CFI_8BIT: + *dst.cp++ = *src.cp++; + break; + case FLASH_CFI_16BIT: + *dst.wp++ = *src.wp++; + break; + case FLASH_CFI_32BIT: + *dst.lp++ = *src.lp++; + break; + default: + return ERR_INVAL; + break; + } + } + flash_write_cmd(info, sector, 0, + FLASH_CMD_WRITE_BUFFER_CONFIRM); + retcode = + flash_full_status_check(info, sector, + info->buffer_write_tout, + "buffer write"); + } + flash_write_cmd(info, sector, 0, FLASH_CMD_CLEAR_STATUS); + return retcode; +} +#endif /* CFG_USE_FLASH_BUFFER_WRITE */ diff --git a/board/esd/cpci5200/u-boot.lds b/board/esd/cpci5200/u-boot.lds new file mode 100644 index 0000000..d999dd1 --- /dev/null +++ b/board/esd/cpci5200/u-boot.lds @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/mpc5xxx/start.o (.text) + *(.text) + *(.fixup) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/board/esd/pf5200/Makefile b/board/esd/pf5200/Makefile new file mode 100644 index 0000000..603bbe2 --- /dev/null +++ b/board/esd/pf5200/Makefile @@ -0,0 +1,53 @@ + +# +# (C) Copyright 2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +# Objects for Xilinx JTAG programming (CPLD) +# CPLD = ../common/xilinx_jtag/lenval.o \ +# ../common/xilinx_jtag/micro.o \ +# ../common/xilinx_jtag/ports.o + +# OBJS = $(BOARD).o flash.o $(CPLD) +OBJS = $(BOARD).o flash.o + +$(LIB): $(OBJS) $(SOBJS) + $(AR) crv $@ $(OBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +-include .depend + +######################################################################### diff --git a/board/esd/pf5200/config.mk b/board/esd/pf5200/config.mk new file mode 100644 index 0000000..07b5de1 --- /dev/null +++ b/board/esd/pf5200/config.mk @@ -0,0 +1,44 @@ +# +# (C) Copyright 2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# +# IceCube board: +# +# Valid values for TEXT_BASE are: +# +# 0xFFF00000 boot high (standard configuration) +# 0xFF000000 boot low for 16 MiB boards +# 0xFF800000 boot low for 8 MiB boards +# 0x00100000 boot from RAM (for testing only) +# + +sinclude $(TOPDIR)/board/$(BOARDDIR)/config.tmp + +ifndef TEXT_BASE +## Standard: boot high +TEXT_BASE = 0xFFF00000 +## For testing: boot from RAM +# TEXT_BASE = 0x00100000 +endif + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR)/board diff --git a/board/esd/pf5200/flash.c b/board/esd/pf5200/flash.c new file mode 100644 index 0000000..bfbd090 --- /dev/null +++ b/board/esd/pf5200/flash.c @@ -0,0 +1,461 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +typedef unsigned short FLASH_PORT_WIDTH; +typedef volatile unsigned short FLASH_PORT_WIDTHV; + +#define FLASH_ID_MASK 0x00FF + +#define FPW FLASH_PORT_WIDTH +#define FPWV FLASH_PORT_WIDTHV + +#define FLASH_CYCLE1 0x0555 +#define FLASH_CYCLE2 0x0aaa +#define FLASH_ID1 0x00 +#define FLASH_ID2 0x01 +#define FLASH_ID3 0x0E +#define FLASH_ID4 0x0F + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size(FPWV * addr, flash_info_t * info); +static void flash_reset(flash_info_t * info); +static int write_word_amd(flash_info_t * info, FPWV * dest, FPW data); +static flash_info_t *flash_get_info(ulong base); + +/*----------------------------------------------------------------------- + * flash_init() + * + * sets up flash_info and returns size of FLASH (bytes) + */ +unsigned long flash_init(void) +{ + unsigned long size = 0; + int i = 0; + extern void flash_preinit(void); + extern void flash_afterinit(uint, ulong, ulong); + + ulong flashbase = CFG_FLASH_BASE; + + flash_preinit(); + + /* There is only ONE FLASH device */ + memset(&flash_info[i], 0, sizeof(flash_info_t)); + flash_info[i].size = flash_get_size((FPW *) flashbase, &flash_info[i]); + size += flash_info[i].size; + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + /* monitor protection ON by default */ + flash_protect(FLAG_PROTECT_SET, CFG_MONITOR_BASE, + CFG_MONITOR_BASE + monitor_flash_len - 1, + flash_get_info(CFG_MONITOR_BASE)); +#endif + +#ifdef CFG_ENV_IS_IN_FLASH + /* ENV protection ON by default */ + flash_protect(FLAG_PROTECT_SET, CFG_ENV_ADDR, + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, + flash_get_info(CFG_ENV_ADDR)); +#endif + + flash_afterinit(i, flash_info[i].start[0], flash_info[i].size); + return size ? size : 1; +} + +/*----------------------------------------------------------------------- + */ +static void flash_reset(flash_info_t * info) { + FPWV *base = (FPWV *) (info->start[0]); + + /* Put FLASH back in read mode */ + if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { + *base = (FPW) 0x00FF00FF; /* Intel Read Mode */ + } else if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_AMD) { + *base = (FPW) 0x00F000F0; /* AMD Read Mode */ + } +} + +/*----------------------------------------------------------------------- + */ + +static flash_info_t *flash_get_info(ulong base) { + int i; + flash_info_t *info; + + for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { + info = &flash_info[i]; + if ((info->size) && (info->start[0] <= base) + && (base <= info->start[0] + info->size - 1)) { + break; + } + } + return (i == CFG_MAX_FLASH_BANKS ? 0 : info); +} + +/*----------------------------------------------------------------------- + */ + +void flash_print_info(flash_info_t * info) { + int i; + uchar *fmt; + + if (info->flash_id == FLASH_UNKNOWN) { + printf("missing or unknown FLASH type\n"); + return; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_AMD: + printf("AMD "); + break; + default: + printf("Unknown Vendor "); + break; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_AMLV256U: + fmt = "29LV256M (256 Mbit)\n"; + break; + default: + fmt = "Unknown Chip Type\n"; + break; + } + + printf(fmt); + printf(" Size: %ld MB in %d Sectors\n", info->size >> 20, + info->sector_count); + printf(" Sector Start Addresses:"); + + for (i = 0; i < info->sector_count; ++i) { + ulong size; + int erased; + ulong *flash = (unsigned long *)info->start[i]; + + if ((i % 5) == 0) { + printf("\n "); + } + + /* + * Check if whole sector is erased + */ + size = + (i != + (info->sector_count - 1)) ? (info->start[i + 1] - + info->start[i]) >> 2 : (info-> + start + [0] + + info-> + size - + info-> + start + [i]) + >> 2; + + for (flash = (unsigned long *)info->start[i], erased = 1; + (flash != (unsigned long *)info->start[i] + size) + && erased; flash++) { + erased = *flash == ~0x0UL; + } + printf(" %08lX %s %s", info->start[i], erased ? "E" : " ", + info->protect[i] ? "(RO)" : " "); + } + + printf("\n"); +} + +/*----------------------------------------------------------------------- + */ + +/* + * The following code cannot be run from FLASH! + */ + +ulong flash_get_size(FPWV * addr, flash_info_t * info) { + int i; + + /* Write auto select command: read Manufacturer ID */ + /* Write auto select command sequence and test FLASH answer */ + addr[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* for AMD, Intel ignores this */ + addr[FLASH_CYCLE2] = (FPW) 0x00550055; /* for AMD, Intel ignores this */ + addr[FLASH_CYCLE1] = (FPW) 0x00900090; /* selects Intel or AMD */ + + /* The manufacturer codes are only 1 byte, so just use 1 byte. */ + /* This works for any bus width and any FLASH device width. */ + udelay(100); + switch (addr[FLASH_ID1] & 0x00ff) { + case (uchar) AMD_MANUFACT: + info->flash_id = FLASH_MAN_AMD; + break; + default: + printf("unknown vendor=%x ", addr[FLASH_ID1] & 0xff); + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + break; + } + + /* Check 16 bits or 32 bits of ID so work on 32 or 16 bit bus. */ + if (info->flash_id != FLASH_UNKNOWN) { + switch ((FPW) addr[FLASH_ID2]) { + case (FPW) AMD_ID_MIRROR: + /* MIRROR BIT FLASH, read more ID bytes */ + if ((FPW) addr[FLASH_ID3] == (FPW) AMD_ID_LV256U_2 + && (FPW) addr[FLASH_ID4] == (FPW) AMD_ID_LV256U_3) { + /* attention: only the first 16 MB will be used in u-boot */ + info->flash_id += FLASH_AMLV256U; + info->sector_count = 512; + info->size = 0x02000000; + for (i = 0; i < info->sector_count; i++) { + info->start[i] = + (ulong) addr + 0x10000 * i; + } + break; + } + /* fall thru to here ! */ + default: + printf("unknown AMD device=%x %x %x", + (FPW) addr[FLASH_ID2], (FPW) addr[FLASH_ID3], + (FPW) addr[FLASH_ID4]); + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0x800000; + break; + } + + /* Put FLASH back in read mode */ + flash_reset(info); + } + return (info->size); +} + +/*----------------------------------------------------------------------- + */ + +int flash_erase(flash_info_t * info, int s_first, int s_last) { + FPWV *addr; + int flag, prot, sect; + int intel = (info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL; + ulong start, now, last; + int rcode = 0; + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf("- missing\n"); + } else { + printf("- no sectors to erase\n"); + } + return 1; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_AMLV256U: + break; + case FLASH_UNKNOWN: + default: + printf("Can't erase unknown flash type %08lx - aborted\n", + info->flash_id); + return 1; + } + + prot = 0; + for (sect = s_first; sect <= s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + + if (prot) { + printf("- Warning: %d protected sectors will not be erased!\n", + prot); + } else { + printf("\n"); + } + + last = get_timer(0); + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect <= s_last && rcode == 0; sect++) { + if (info->protect[sect] != 0) { /* protected, skip it */ + continue; + } + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + addr = (FPWV *) (info->start[sect]); + if (intel) { + *addr = (FPW) 0x00500050; /* clear status register */ + *addr = (FPW) 0x00200020; /* erase setup */ + *addr = (FPW) 0x00D000D0; /* erase confirm */ + } else { + /* must be AMD style if not Intel */ + FPWV *base; /* first address in bank */ + + base = (FPWV *) (info->start[0]); + base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ + base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ + base[FLASH_CYCLE1] = (FPW) 0x00800080; /* erase mode */ + base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ + base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ + *addr = (FPW) 0x00300030; /* erase sector */ + } + + /* re-enable interrupts if necessary */ + if (flag) { + enable_interrupts(); + } + start = get_timer(0); + + /* wait at least 50us for AMD, 80us for Intel. */ + /* Let's wait 1 ms. */ + udelay(1000); + + while ((*addr & (FPW) 0x00800080) != (FPW) 0x00800080) { + if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { + printf("Timeout\n"); + if (intel) { + /* suspend erase */ + *addr = (FPW) 0x00B000B0; + } + flash_reset(info); /* reset to read mode */ + rcode = 1; /* failed */ + break; + } + /* show that we're waiting */ + if ((get_timer(last)) > CFG_HZ) { + /* every second */ + putc('.'); + last = get_timer(0); + } + } + /* show that we're waiting */ + if ((get_timer(last)) > CFG_HZ) { + /* every second */ + putc('.'); + last = get_timer(0); + } + flash_reset(info); /* reset to read mode */ + } + printf(" done\n"); + return (rcode); +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */ + int bytes; /* number of bytes to program in current word */ + int left; /* number of bytes left to program */ + int i, res; + + for (left = cnt, res = 0; + left > 0 && res == 0; + addr += sizeof(data), left -= sizeof(data) - bytes) { + + bytes = addr & (sizeof(data) - 1); + addr &= ~(sizeof(data) - 1); + + /* combine source and destination data so can program + * an entire word of 16 or 32 bits + */ + for (i = 0; i < sizeof(data); i++) { + data <<= 8; + if (i < bytes || i - bytes >= left) + data += *((uchar *) addr + i); + else + data += *src++; + } + + /* write one word to the flash */ + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_AMD: + res = write_word_amd(info, (FPWV *) addr, data); + break; + default: + /* unknown flash type, error! */ + printf("missing or unknown FLASH type\n"); + res = 1; /* not really a timeout, but gives error */ + break; + } + } + return (res); +} + +/*----------------------------------------------------------------------- + * Write a word to Flash for AMD FLASH + * A word is 16 or 32 bits, whichever the bus width of the flash bank + * (not an individual chip) is. + * + * returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_word_amd(flash_info_t * info, FPWV * dest, FPW data) { + ulong start; + int flag; + int res = 0; /* result, assume success */ + FPWV *base; /* first address in flash bank */ + + /* Check if Flash is (sufficiently) erased */ + if ((*dest & data) != data) { + return (2); + } + + base = (FPWV *) (info->start[0]); + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + base[FLASH_CYCLE1] = (FPW) 0x00AA00AA; /* unlock */ + base[FLASH_CYCLE2] = (FPW) 0x00550055; /* unlock */ + base[FLASH_CYCLE1] = (FPW) 0x00A000A0; /* selects program mode */ + + *dest = data; /* start programming the data */ + + /* re-enable interrupts if necessary */ + if (flag) { + enable_interrupts(); + } + start = get_timer(0); + + /* data polling for D7 */ + while (res == 0 + && (*dest & (FPW) 0x00800080) != (data & (FPW) 0x00800080)) { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + *dest = (FPW) 0x00F000F0; /* reset bank */ + res = 1; + } + } + return (res); +} diff --git a/board/esd/pf5200/mt46v16m16-75.h b/board/esd/pf5200/mt46v16m16-75.h new file mode 100644 index 0000000..22d0a55 --- /dev/null +++ b/board/esd/pf5200/mt46v16m16-75.h @@ -0,0 +1,37 @@ +/* + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#define SDRAM_DDR 1 /* is DDR */ + +#if defined(CONFIG_MPC5200) +/* Settings for XLB = 132 MHz */ +#define SDRAM_MODE 0x018D0000 +#define SDRAM_EMODE 0x40090000 +#define SDRAM_CONTROL 0x705f0f00 +#define SDRAM_CONFIG1 0x73722930 +#define SDRAM_CONFIG2 0x47770000 +#define SDRAM_TAPDELAY 0x10000000 + +#else +#error CONFIG_MPC5200 not defined +#endif diff --git a/board/esd/pf5200/pf5200.c b/board/esd/pf5200/pf5200.c new file mode 100644 index 0000000..fa71c79 --- /dev/null +++ b/board/esd/pf5200/pf5200.c @@ -0,0 +1,370 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * pf5200.c - main board support/init for the esd pf5200. + */ + +#include <common.h> +#include <mpc5xxx.h> +#include <pci.h> +#include <command.h> + +#include "mt46v16m16-75.h" + +void init_power_switch(void); + +static void sdram_start(int hi_addr) +{ + long hi_addr_bit = hi_addr ? 0x01000000 : 0; + + /* unlock mode register */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000000 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* set mode register: extended mode */ + *(vu_long *) MPC5XXX_SDRAM_MODE = SDRAM_EMODE; + __asm__ volatile ("sync"); + + /* set mode register: reset DLL */ + *(vu_long *) MPC5XXX_SDRAM_MODE = SDRAM_MODE | 0x04000000; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* auto refresh */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = + SDRAM_CONTROL | 0x80000004 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* set mode register */ + *(vu_long *) MPC5XXX_SDRAM_MODE = SDRAM_MODE; + __asm__ volatile ("sync"); + + /* normal operation */ + *(vu_long *) MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | hi_addr_bit; + __asm__ volatile ("sync"); +} + +/* + * ATTENTION: Although partially referenced initdram does NOT make real use + * use of CFG_SDRAM_BASE. The code does not work if CFG_SDRAM_BASE + * is something else than 0x00000000. + */ + +long int initdram(int board_type) +{ + ulong dramsize = 0; + ulong test1, test2; + + /* setup SDRAM chip selects */ + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = 0x0000001e; /* 2G at 0x0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = 0x80000000; /* disabled */ + __asm__ volatile ("sync"); + + /* setup config registers */ + *(vu_long *) MPC5XXX_SDRAM_CONFIG1 = SDRAM_CONFIG1; + *(vu_long *) MPC5XXX_SDRAM_CONFIG2 = SDRAM_CONFIG2; + __asm__ volatile ("sync"); + + /* set tap delay */ + *(vu_long *) MPC5XXX_CDM_PORCFG = SDRAM_TAPDELAY; + __asm__ volatile ("sync"); + + /* find RAM size using SDRAM CS0 only */ + sdram_start(0); + test1 = get_ram_size((ulong *) CFG_SDRAM_BASE, 0x80000000); + sdram_start(1); + test2 = get_ram_size((ulong *) CFG_SDRAM_BASE, 0x80000000); + + if (test1 > test2) { + sdram_start(0); + dramsize = test1; + } else { + dramsize = test2; + } + + /* memory smaller than 1MB is impossible */ + if (dramsize < (1 << 20)) { + dramsize = 0; + } + + /* set SDRAM CS0 size according to the amount of RAM found */ + if (dramsize > 0) { + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = + 0x13 + __builtin_ffs(dramsize >> 20) - 1; + /* let SDRAM CS1 start right after CS0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = dramsize + 0x0000001e; /* 2G */ + } else { +#if 0 + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ + /* let SDRAM CS1 start right after CS0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = dramsize + 0x0000001e; /* 2G */ +#else + *(vu_long *) MPC5XXX_SDRAM_CS0CFG = + 0x13 + __builtin_ffs(0x08000000 >> 20) - 1; + /* let SDRAM CS1 start right after CS0 */ + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = 0x08000000 + 0x0000001e; /* 2G */ +#endif + } + +#if 0 + /* find RAM size using SDRAM CS1 only */ + sdram_start(0); + get_ram_size((ulong *) (CFG_SDRAM_BASE + dramsize), 0x80000000); + sdram_start(1); + get_ram_size((ulong *) (CFG_SDRAM_BASE + dramsize), 0x80000000); + sdram_start(0); +#endif + /* set SDRAM CS1 size according to the amount of RAM found */ + + *(vu_long *) MPC5XXX_SDRAM_CS1CFG = dramsize; /* disabled */ + + init_power_switch(); + return (dramsize); +} + +int checkboard(void) +{ + puts("Board: esd ParaFinder (pf5200)\n"); + return 0; +} + +void flash_preinit(void) +{ + /* + * Now, when we are in RAM, enable flash write + * access for detection process. + * Note that CS_BOOT cannot be cleared when + * executing in flash. + */ + *(vu_long *) MPC5XXX_BOOTCS_CFG &= ~0x1; /* clear RO */ +} + +void flash_afterinit(ulong size) +{ + if (size == 0x02000000) { + /* adjust mapping */ + *(vu_long *) MPC5XXX_BOOTCS_START = + *(vu_long *) MPC5XXX_CS0_START = + START_REG(CFG_BOOTCS_START | size); + *(vu_long *) MPC5XXX_BOOTCS_STOP = + *(vu_long *) MPC5XXX_CS0_STOP = + STOP_REG(CFG_BOOTCS_START | size, size); + } +} + +#ifdef CONFIG_PCI +static struct pci_controller hose; + +extern void pci_mpc5xxx_init(struct pci_controller *); + +void pci_init_board(void + ) { + pci_mpc5xxx_init(&hose); +} +#endif + +#if defined (CFG_CMD_IDE) && defined (CONFIG_IDE_RESET) + +#define GPIO_PSC1_4 0x01000000UL + +void init_ide_reset(void) +{ + debug("init_ide_reset\n"); + + /* Configure PSC1_4 as GPIO output for ATA reset */ + *(vu_long *) MPC5XXX_WU_GPIO_ENABLE |= GPIO_PSC1_4; + *(vu_long *) MPC5XXX_WU_GPIO_DIR |= GPIO_PSC1_4; +} + +void ide_set_reset(int idereset) +{ + debug("ide_reset(%d)\n", idereset); + + if (idereset) { + *(vu_long *) MPC5XXX_WU_GPIO_DATA &= ~GPIO_PSC1_4; + } else { + *(vu_long *) MPC5XXX_WU_GPIO_DATA |= GPIO_PSC1_4; + } +} +#endif /* defined (CFG_CMD_IDE) && defined (CONFIG_IDE_RESET) */ + +#define MPC5XXX_SIMPLEIO_GPIO_ENABLE (MPC5XXX_GPIO + 0x0004) +#define MPC5XXX_SIMPLEIO_GPIO_DIR (MPC5XXX_GPIO + 0x000C) +#define MPC5XXX_SIMPLEIO_GPIO_DATA_OUTPUT (MPC5XXX_GPIO + 0x0010) +#define MPC5XXX_SIMPLEIO_GPIO_DATA_INPUT (MPC5XXX_GPIO + 0x0014) + +#define MPC5XXX_INTERRUPT_GPIO_ENABLE (MPC5XXX_GPIO + 0x0020) +#define MPC5XXX_INTERRUPT_GPIO_DIR (MPC5XXX_GPIO + 0x0028) +#define MPC5XXX_INTERRUPT_GPIO_DATA_OUTPUT (MPC5XXX_GPIO + 0x002C) +#define MPC5XXX_INTERRUPT_GPIO_STATUS (MPC5XXX_GPIO + 0x003C) + +#define GPIO_WU6 0x40000000UL +#define GPIO_USB0 0x00010000UL +#define GPIO_USB9 0x08000000UL +#define GPIO_USB9S 0x00080000UL + +void init_power_switch(void) +{ + debug("init_power_switch\n"); + + /* Configure GPIO_WU6 as GPIO output for ATA reset */ + *(vu_long *) MPC5XXX_WU_GPIO_DATA |= GPIO_WU6; + *(vu_long *) MPC5XXX_WU_GPIO_ENABLE |= GPIO_WU6; + *(vu_long *) MPC5XXX_WU_GPIO_DIR |= GPIO_WU6; + __asm__ volatile ("sync"); + + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_DATA_OUTPUT &= ~GPIO_USB0; + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_ENABLE |= GPIO_USB0; + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_DIR |= GPIO_USB0; + __asm__ volatile ("sync"); + + *(vu_long *) MPC5XXX_INTERRUPT_GPIO_DATA_OUTPUT &= ~GPIO_USB9; + *(vu_long *) MPC5XXX_INTERRUPT_GPIO_ENABLE &= ~GPIO_USB9; + __asm__ volatile ("sync"); + + if ((*(vu_long *) MPC5XXX_INTERRUPT_GPIO_STATUS & GPIO_USB9S) == 0) { + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_DATA_OUTPUT |= GPIO_USB0; + __asm__ volatile ("sync"); + } + *(vu_char *) CFG_CS1_START = 0x02; /* Red Power LED on */ + __asm__ volatile ("sync"); + + *(vu_char *) (CFG_CS1_START + 1) = 0x02; /* Disable driver for KB11 */ + __asm__ volatile ("sync"); +} + +void power_set_reset(int power) +{ + debug("ide_set_reset(%d)\n", power); + + if (power) { + *(vu_long *) MPC5XXX_WU_GPIO_DATA &= ~GPIO_WU6; + *(vu_long *) MPC5XXX_INTERRUPT_GPIO_DATA_OUTPUT &= ~GPIO_USB9; + } else { + *(vu_long *) MPC5XXX_WU_GPIO_DATA |= GPIO_WU6; + if ((*(vu_long *) MPC5XXX_INTERRUPT_GPIO_STATUS & GPIO_USB9S) == + 0) { + *(vu_long *) MPC5XXX_SIMPLEIO_GPIO_DATA_OUTPUT |= + GPIO_USB0; + } + + } +} + +int do_poweroff(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + power_set_reset(1); + return (0); +} + +U_BOOT_CMD(poweroff, 1, 1, do_poweroff, "poweroff- Switch off power\n", NULL); + +int phypower(int flag) +{ + u32 addr; + vu_long *reg; + int status; + pci_dev_t dev; + + dev = PCI_BDF(0, 0x18, 0); + status = pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &addr); + if (status == 0) { + reg = (vu_long *) (addr + 0x00000040); + *reg |= 0x40000000; + __asm__ volatile ("sync"); + + reg = (vu_long *) (addr + 0x001000c); + *reg |= 0x20000000; + __asm__ volatile ("sync"); + + reg = (vu_long *) (addr + 0x0010004); + if (flag != 0) { + *reg &= ~0x20000000; + } else { + *reg |= 0x20000000; + } + __asm__ volatile ("sync"); + } + return (status); +} + +int do_phypower(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int status; + + if (argv[1][0] == '0') { + status = phypower(0); + } else { + status = phypower(1); + } + return (0); +} + +U_BOOT_CMD(phypower, 2, 2, do_phypower, + "phypower- Switch power of ethernet phy\n", NULL); + +int do_writepci(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + unsigned int addr; + unsigned int size; + int i; + volatile unsigned long *ptr; + + addr = simple_strtol(argv[1], NULL, 16); + size = simple_strtol(argv[2], NULL, 16); + + printf("\nWriting at addr %08x, size %08x.\n", addr, size); + + while (1) { + ptr = (volatile unsigned long *)addr; + for (i = 0; i < (size >> 2); i++) { + *ptr++ = i; + } + + /* Abort if ctrl-c was pressed */ + if (ctrlc()) { + puts("\nAbort\n"); + return 0; + } + putc('.'); + } + return 0; +} + +U_BOOT_CMD(writepci, 3, 1, do_writepci, + "writepci- Write some data to pcibus\n", + "<addr> <size>\n" " - Write some data to pcibus.\n"); diff --git a/board/esd/pf5200/u-boot.lds b/board/esd/pf5200/u-boot.lds new file mode 100644 index 0000000..d999dd1 --- /dev/null +++ b/board/esd/pf5200/u-boot.lds @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/mpc5xxx/start.o (.text) + *(.text) + *(.fixup) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/board/o2dnt/Makefile b/board/o2dnt/Makefile new file mode 100644 index 0000000..2eb4366 --- /dev/null +++ b/board/o2dnt/Makefile @@ -0,0 +1,47 @@ + +# +# (C) Copyright 2005 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +OBJS := $(BOARD).o flash.o + +$(LIB): $(OBJS) $(SOBJS) + $(AR) crv $@ $(OBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CPPFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +-include .depend + +######################################################################### diff --git a/board/o2dnt/config.mk b/board/o2dnt/config.mk new file mode 100644 index 0000000..b873376 --- /dev/null +++ b/board/o2dnt/config.mk @@ -0,0 +1,27 @@ +# +# (C) Copyright 2005 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +# boot low for 16 MiB boards +TEXT_BASE = 0xFF000000 + +PLATFORM_CPPFLAGS += -DTEXT_BASE=$(TEXT_BASE) -I$(TOPDIR)/board diff --git a/board/o2dnt/flash.c b/board/o2dnt/flash.c new file mode 100644 index 0000000..dbb49f7 --- /dev/null +++ b/board/o2dnt/flash.c @@ -0,0 +1,587 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * flash_real_protect() routine based on boards/alaska/flash.c + * (C) Copyright 2001 + * Kyle Harris, Nexus Technologies, Inc. kharris@nexus-tech.net + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +/* Intel-compatible flash commands */ +#define INTEL_ERASE 0x20 +#define INTEL_PROGRAM 0x40 +#define INTEL_CLEAR 0x50 +#define INTEL_LOCKBIT 0x60 +#define INTEL_PROTECT 0x01 +#define INTEL_STATUS 0x70 +#define INTEL_READID 0x90 +#define INTEL_READID 0x90 +#define INTEL_SUSPEND 0xB0 +#define INTEL_CONFIRM 0xD0 +#define INTEL_RESET 0xFF + +/* Intel-compatible flash status bits */ +#define INTEL_FINISHED 0x80 +#define INTEL_OK 0x80 + +typedef unsigned char FLASH_PORT_WIDTH; +typedef volatile unsigned char FLASH_PORT_WIDTHV; +#define FPW FLASH_PORT_WIDTH +#define FPWV FLASH_PORT_WIDTHV +#define FLASH_ID_MASK 0xFF + +#define ORMASK(size) ((-size) & OR_AM_MSK) + +#define FLASH_CYCLE1 0x0555 +#define FLASH_CYCLE2 0x02aa + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size(FPWV *addr, flash_info_t *info); +static void flash_reset(flash_info_t *info); +static flash_info_t *flash_get_info(ulong base); +static int write_data (flash_info_t *info, FPWV *dest, FPW data); /* O2D */ +static void flash_sync_real_protect (flash_info_t * info); +static unsigned char intel_sector_protected (flash_info_t *info, ushort sector); + +/*----------------------------------------------------------------------- + * flash_init() + * + * sets up flash_info and returns size of FLASH (bytes) + */ +unsigned long flash_init (void) +{ + unsigned long size = 0; + int i; + extern void flash_preinit(void); + extern void flash_afterinit(ulong); + + flash_preinit(); + + /* Init: no FLASHes known */ + for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { + memset(&flash_info[i], 0, sizeof(flash_info_t)); + flash_info[i].flash_id = FLASH_UNKNOWN; + } + + /* Query flash chip */ + flash_info[0].size = + flash_get_size((FPW *)CFG_FLASH_BASE, &flash_info[0]); + size += flash_info[0].size; + + /* get the h/w and s/w protection status in sync */ + flash_sync_real_protect(&flash_info[0]); + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + /* monitor protection ON by default */ + flash_protect(FLAG_PROTECT_SET, + CFG_MONITOR_BASE, + CFG_MONITOR_BASE+monitor_flash_len-1, + flash_get_info(CFG_MONITOR_BASE)); +#endif + +#ifdef CFG_ENV_IS_IN_FLASH + /* ENV protection ON by default */ + flash_protect(FLAG_PROTECT_SET, + CFG_ENV_ADDR, + CFG_ENV_ADDR+CFG_ENV_SIZE-1, + flash_get_info(CFG_ENV_ADDR)); +#endif + + + flash_afterinit(size); + return (size ? size : 1); +} + +/*----------------------------------------------------------------------- + */ +static void flash_reset(flash_info_t *info) +{ + FPWV *base = (FPWV *)(info->start[0]); + + /* Put FLASH back in read mode */ + if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) + *base = (FPW) INTEL_RESET; /* Intel Read Mode */ +} + +/*----------------------------------------------------------------------- + */ + +static flash_info_t *flash_get_info(ulong base) +{ + int i; + flash_info_t * info; + + for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) { + info = & flash_info[i]; + if (info->size && + info->start[0] <= base && + base <= info->start[0] + info->size - 1) + break; + } + + return (i == CFG_MAX_FLASH_BANKS ? 0 : info); +} + +/*----------------------------------------------------------------------- + */ + +void flash_print_info (flash_info_t *info) +{ + int i; + uchar *boottype; + uchar *bootletter; + uchar *fmt; + uchar botbootletter[] = "B"; + uchar topbootletter[] = "T"; + uchar botboottype[] = "bottom boot sector"; + uchar topboottype[] = "top boot sector"; + + if (info->flash_id == FLASH_UNKNOWN) { + printf ("missing or unknown FLASH type\n"); + return; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_INTEL: + printf ("INTEL "); + break; + default: + printf ("Unknown Vendor "); + break; + } + + /* check for top or bottom boot, if it applies */ + if (info->flash_id & FLASH_BTYPE) { + boottype = botboottype; + bootletter = botbootletter; + } else { + boottype = topboottype; + bootletter = topbootletter; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_28F128J3A: + fmt = "28F128J3 (128 Mbit, uniform sectors)\n"; + break; + default: + fmt = "Unknown Chip Type\n"; + break; + } + + printf (fmt, bootletter, boottype); + printf (" Size: %ld MB in %d Sectors\n", + info->size >> 20, + info->sector_count); + + printf (" Sector Start Addresses:"); + for (i=0; i<info->sector_count; ++i) { + if ((i % 5) == 0) + printf ("\n "); + + printf (" %08lX%s", info->start[i], + info->protect[i] ? " (RO)" : " "); + } + printf ("\n"); +} + +/*----------------------------------------------------------------------- + */ + +/* + * The following code cannot be run from FLASH! + */ +ulong flash_get_size (FPWV *addr, flash_info_t *info) +{ + int i; + + /* Write auto select command: read Manufacturer ID */ + /* Write auto select command sequence and test FLASH answer */ + addr[FLASH_CYCLE1] = (FPW) INTEL_READID; /* selects Intel or AMD */ + + /* The manufacturer codes are only 1 byte, so just use 1 byte. + * This works for any bus width and any FLASH device width. + */ + udelay(100); + switch (addr[0] & 0xff) { + case (uchar)INTEL_MANUFACT: + info->flash_id = FLASH_MAN_INTEL; + break; + default: + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + break; + } + + /* Strataflash is configurable to 8/16bit Bus, + * but the Query-Structure is Word-orientated */ + if (info->flash_id != FLASH_UNKNOWN) { + switch ((FPW)addr[2]) { + case (FPW)INTEL_ID_28F128J3: + info->flash_id += FLASH_28F128J3A; + info->sector_count = 128; + info->size = 0x01000000; + for( i = 0; i < info->sector_count; i++ ) + info->start[i] = (ulong)addr + (i * 0x20000); + break; /* => Intel Strataflash 16MB */ + default: + printf("Flash_id != %xd\n", (FPW)addr[2]); + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + return (0); /* => no or unknown flash */ + } + } + + /* Put FLASH back in read mode */ + flash_reset(info); + + return (info->size); +} + +/*----------------------------------------------------------------------- + */ + +int flash_erase (flash_info_t *info, int s_first, int s_last) +{ + FPWV *addr; + int flag, prot, sect; + ulong start, now, last; + int rcode = 0; + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf ("- missing\n"); + } else { + printf ("- no sectors to erase\n"); + } + return 1; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_28F128J3A: + break; + case FLASH_UNKNOWN: + default: + printf ("Can't erase unknown flash type %08lx - aborted\n", + info->flash_id); + return 1; + } + + prot = 0; + for (sect = s_first; sect <= s_last; ++sect) + if (info->protect[sect]) + prot++; + + if (prot) + printf ("- Warning: %d protected sectors will not be erased!", + prot); + + printf ("\n"); + last = get_timer(0); + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect <= s_last && rcode == 0; sect++) { + + if (info->protect[sect] != 0) /* protected, skip it */ + continue; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + addr = (FPWV *)(info->start[sect]); + *addr = (FPW) INTEL_CLEAR; /* clear status register */ + *addr = (FPW) INTEL_ERASE; /* erase setup */ + *addr = (FPW) INTEL_CONFIRM; /* erase confirm */ + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + start = get_timer(0); + + /* wait at least 80us for Intel - let's wait 1 ms */ + udelay (1000); + + while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) { + if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { + printf ("Timeout\n"); + *addr = (FPW) INTEL_SUSPEND;/* suspend erase */ + flash_reset(info); /* reset to read mode */ + rcode = 1; /* failed */ + break; + } + + /* show that we're waiting */ + if ((get_timer(last)) > CFG_HZ) { /* every second */ + putc ('.'); + last = get_timer(0); + } + } + + flash_reset(info); /* reset to read mode */ + } + + printf (" done\n"); + return rcode; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + FPW data = 0; /* 16 or 32 bit word, matches flash bus width on MPC8XX */ + int bytes; /* number of bytes to program in current word */ + int left; /* number of bytes left to program */ + int i, res; + + for (left = cnt, res = 0; + left > 0 && res == 0; + addr += sizeof(data), left -= sizeof(data) - bytes) { + + bytes = addr & (sizeof(data) - 1); + addr &= ~(sizeof(data) - 1); + + /* combine source and destination data so can program + * an entire word of 16 or 32 bits */ + for (i = 0; i < sizeof(data); i++) { + data <<= 8; + if (i < bytes || i - bytes >= left ) + data += *((uchar *)addr + i); + else + data += *src++; + } + + /* write one word to the flash */ + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_INTEL: + res = write_data(info, (FPWV *)addr, data); + break; + default: + /* unknown flash type, error! */ + printf ("missing or unknown FLASH type\n"); + res = 1; /* not really a timeout, but gives error */ + break; + } + } + + return (res); +} + +/*----------------------------------------------------------------------- + * Write a word or halfword to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +static int write_data (flash_info_t *info, FPWV *dest, FPW data) +{ + FPWV *addr = dest; + ulong status; + ulong start; + int flag; + + /* Check if Flash is (sufficiently) erased */ + if ((*addr & data) != data) { + printf ("not erased at %08lx (%lx)\n", (ulong) addr, *addr); + return (2); + } + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts (); + + *addr = (FPW) INTEL_PROGRAM; /* write setup */ + *addr = data; + + /* arm simple, non interrupt dependent timer */ + start = get_timer(0); + + /* wait while polling the status register */ + while (((status = *addr) & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + *addr = (FPW) INTEL_RESET; /* restore read mode */ + return (1); + } + } + + *addr = (FPW) INTEL_RESET; /* restore read mode */ + if (flag) + enable_interrupts(); + + return (0); +} + + +/*----------------------------------------------------------------------- + * Set/Clear sector's lock bit, returns: + * 0 - OK + * 1 - Error (timeout, voltage problems, etc.) + */ +int flash_real_protect (flash_info_t * info, long sector, int prot) +{ + ulong start; + int i; + int rc = 0; + FPWV *addr = (FPWV *) (info->start[sector]); + int flag = disable_interrupts (); + + *addr = INTEL_CLEAR; /* Clear status register */ + if (prot) { /* Set sector lock bit */ + *addr = INTEL_LOCKBIT; /* Sector lock bit */ + *addr = INTEL_PROTECT; /* set */ + } else { /* Clear sector lock bit */ + *addr = INTEL_LOCKBIT; /* All sectors lock bits */ + *addr = INTEL_CONFIRM; /* clear */ + } + + start = get_timer (0); + + while ((*addr & INTEL_FINISHED) != INTEL_FINISHED) { + if (get_timer (start) > CFG_FLASH_UNLOCK_TOUT) { + printf ("Flash lock bit operation timed out\n"); + rc = 1; + break; + } + } + + if (*addr != INTEL_OK) { + printf ("Flash lock bit operation failed at %08X, CSR=%08X\n", + (uint) addr, (uint) * addr); + rc = 1; + } + + if (!rc) + info->protect[sector] = prot; + + /* + * Clear lock bit command clears all sectors lock bits, so + * we have to restore lock bits of protected sectors. + */ + if (!prot) { + for (i = 0; i < info->sector_count; i++) { + if (info->protect[i]) { + start = get_timer (0); + addr = (FPWV *) (info->start[i]); + *addr = INTEL_LOCKBIT; /* Sector lock bit */ + *addr = INTEL_PROTECT; /* set */ + while ((*addr & INTEL_FINISHED) != + INTEL_FINISHED) { + if (get_timer (start) > + CFG_FLASH_UNLOCK_TOUT) { + printf ("Flash lock bit operation timed out\n"); + rc = 1; + break; + } + } + } + } + } + + if (flag) + enable_interrupts (); + + *addr = INTEL_RESET; /* Reset to read array mode */ + + return rc; +} + + +/* + * This function gets the u-boot flash sector protection status + * (flash_info_t.protect[]) in sync with the sector protection + * status stored in hardware. + */ +static void flash_sync_real_protect (flash_info_t * info) +{ + int i; + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_28F128J3A: + for (i = 0; i < info->sector_count; ++i) { + info->protect[i] = intel_sector_protected(info, i); + } + break; + default: + /* no h/w protect support */ + break; + } +} + + +/* + * checks if "sector" in bank "info" is protected. Should work on intel + * strata flash chips 28FxxxJ3x in 8-bit mode. + * Returns 1 if sector is protected (or timed-out while trying to read + * protection status), 0 if it is not. + */ +static unsigned char intel_sector_protected (flash_info_t *info, ushort sector) +{ + FPWV *addr; + FPWV *lock_conf_addr; + ulong start; + unsigned char ret; + + /* + * first, wait for the WSM to be finished. The rationale for + * waiting for the WSM to become idle for at most + * CFG_FLASH_ERASE_TOUT is as follows. The WSM can be busy + * because of: (1) erase, (2) program or (3) lock bit + * configuration. So we just wait for the longest timeout of + * the (1)-(3), i.e. the erase timeout. + */ + + /* wait at least 35ns (W12) before issuing Read Status Register */ + udelay(1); + addr = (FPWV *) info->start[sector]; + *addr = (FPW) INTEL_STATUS; + + start = get_timer (0); + while ((*addr & (FPW) INTEL_FINISHED) != (FPW) INTEL_FINISHED) { + if (get_timer (start) > CFG_FLASH_ERASE_TOUT) { + *addr = (FPW) INTEL_RESET; /* restore read mode */ + printf("WSM busy too long, can't get prot status\n"); + return 1; + } + } + + /* issue the Read Identifier Codes command */ + *addr = (FPW) INTEL_READID; + + /* wait at least 35ns (W12) before reading */ + udelay(1); + + /* Intel example code uses offset of 4 for 8-bit flash */ + lock_conf_addr = (FPWV *) info->start[sector] + 4; + ret = (*lock_conf_addr & (FPW) INTEL_PROTECT) ? 1 : 0; + + /* put flash back in read mode */ + *addr = (FPW) INTEL_RESET; + + return ret; +} diff --git a/board/o2dnt/o2dnt.c b/board/o2dnt/o2dnt.c new file mode 100644 index 0000000..8c6f5db --- /dev/null +++ b/board/o2dnt/o2dnt.c @@ -0,0 +1,182 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2004 + * Mark Jonas, Freescale Semiconductor, mark.jonas@motorola.com. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <mpc5xxx.h> +#include <pci.h> + +#define SDRAM_MODE 0x00CD0000 +#define SDRAM_CONTROL 0x504F0000 +#define SDRAM_CONFIG1 0xD2322800 +#define SDRAM_CONFIG2 0x8AD70000 + +static void sdram_start (int hi_addr) +{ + long hi_addr_bit = hi_addr ? 0x01000000 : 0; + + /* unlock mode register */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000000 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* precharge all banks */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000002 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* auto refresh */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | 0x80000004 | hi_addr_bit; + __asm__ volatile ("sync"); + + /* set mode register */ + *(vu_long *)MPC5XXX_SDRAM_MODE = SDRAM_MODE; + __asm__ volatile ("sync"); + + /* normal operation */ + *(vu_long *)MPC5XXX_SDRAM_CTRL = SDRAM_CONTROL | hi_addr_bit; + __asm__ volatile ("sync"); +} + +/* + * ATTENTION: Although partially referenced initdram does NOT make real use + * use of CFG_SDRAM_BASE. The code does not work if CFG_SDRAM_BASE + * is something else than 0x00000000. + */ +long int initdram (int board_type) +{ + ulong dramsize = 0; + ulong dramsize2 = 0; + ulong test1, test2; + + /* setup SDRAM chip selects */ + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x0000001e;/* 2G at 0x0 */ + *(vu_long *)MPC5XXX_SDRAM_CS1CFG = 0x80000000;/* disabled */ + __asm__ volatile ("sync"); + + /* setup config registers */ + *(vu_long *)MPC5XXX_SDRAM_CONFIG1 = SDRAM_CONFIG1; + *(vu_long *)MPC5XXX_SDRAM_CONFIG2 = SDRAM_CONFIG2; + __asm__ volatile ("sync"); + + /* find RAM size using SDRAM CS0 only */ + sdram_start(0); + test1 = get_ram_size((ulong *)CFG_SDRAM_BASE, 0x80000000); + sdram_start(1); + test2 = get_ram_size((ulong *)CFG_SDRAM_BASE, 0x80000000); + if (test1 > test2) { + sdram_start(0); + dramsize = test1; + } else { + dramsize = test2; + } + + /* memory smaller than 1MB is impossible */ + if (dramsize < (1 << 20)) { + dramsize = 0; + } + + /* set SDRAM CS0 size according to the amount of RAM found */ + if (dramsize > 0) + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0x13 + __builtin_ffs(dramsize >> 20) - 1; + else + *(vu_long *)MPC5XXX_SDRAM_CS0CFG = 0; /* disabled */ + + /* let SDRAM CS1 start right after CS0 */ + *(vu_long *)MPC5XXX_SDRAM_CS1CFG = dramsize + 0x0000001e;/* 2G */ + + /* find RAM size using SDRAM CS1 only */ + if (!dramsize) + sdram_start(0); + + test2 = test1 = get_ram_size((ulong *)(CFG_SDRAM_BASE + dramsize), 0x80000000); + + if (!dramsize) { + sdram_start(1); + test2 = get_ram_size((ulong *)(CFG_SDRAM_BASE + dramsize), 0x80000000); + } + + if (test1 > test2) { + sdram_start(0); + dramsize2 = test1; + } else { + dramsize2 = test2; + } + + /* memory smaller than 1MB is impossible */ + if (dramsize2 < (1 << 20)) + dramsize2 = 0; + + /* set SDRAM CS1 size according to the amount of RAM found */ + if (dramsize2 > 0) { + *(vu_long *)MPC5XXX_SDRAM_CS1CFG = dramsize + | (0x13 + __builtin_ffs(dramsize2 >> 20) - 1); + } else { + *(vu_long *)MPC5XXX_SDRAM_CS1CFG = dramsize; /* disabled */ + } + + return dramsize + dramsize2; +} + +int checkboard (void) +{ + puts ("Board: O2DNT\n"); + return 0; +} + +void flash_preinit(void) +{ + /* + * Now, when we are in RAM, enable flash write + * access for detection process. + * Note that CS_BOOT cannot be cleared when + * executing in flash. + */ + *(vu_long *)MPC5XXX_BOOTCS_CFG &= ~0x1; /* clear RO */ +} + +void flash_afterinit(ulong size) +{ + if (size == 0x800000) { /* adjust mapping */ + *(vu_long *)MPC5XXX_BOOTCS_START = *(vu_long *)MPC5XXX_CS0_START = + START_REG(CFG_BOOTCS_START | size); + + *(vu_long *)MPC5XXX_BOOTCS_STOP = *(vu_long *)MPC5XXX_CS0_STOP = + STOP_REG(CFG_BOOTCS_START | size, size); + } +} + +#ifdef CONFIG_PCI +static struct pci_controller hose; + +extern void pci_mpc5xxx_init(struct pci_controller *); + +void pci_init_board(void) +{ + pci_mpc5xxx_init(&hose); +} +#endif diff --git a/board/o2dnt/u-boot.lds b/board/o2dnt/u-boot.lds new file mode 100644 index 0000000..7c52b04 --- /dev/null +++ b/board/o2dnt/u-boot.lds @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2005 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/mpc5xxx/start.o (.text) + *(.text) + *(.fixup) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/board/tqm5200/Makefile b/board/tqm5200/Makefile index 50ef578..c234332 100644 --- a/board/tqm5200/Makefile +++ b/board/tqm5200/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = lib$(BOARD).a #OBJS := $(BOARD).o flash.o -OBJS := $(BOARD).o +OBJS := $(BOARD).o cmd_stk52xx.o $(LIB): $(OBJS) $(SOBJS) $(AR) crv $@ $(OBJS) diff --git a/board/tqm5200/cmd_stk52xx.c b/board/tqm5200/cmd_stk52xx.c new file mode 100755 index 0000000..c30e9df --- /dev/null +++ b/board/tqm5200/cmd_stk52xx.c @@ -0,0 +1,1221 @@ +/* + * (C) Copyright 2005 + * Martin Krause, TQ-Systems GmbH, martin.krause@tqs.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * SKT52XX specific functions + */ +/*#define DEBUG*/ + +#include <common.h> +#include <command.h> + +#if (CONFIG_COMMANDS & CFG_CMD_BSP) + +#define DEFAULT_VOL 45 +#define DEFAULT_FREQ 500 +#define DEFAULT_DURATION 200 +#define LEFT 1 +#define RIGHT 2 +#define LEFT_RIGHT 3 +#define BL_OFF 0 +#define BL_ON 1 + +#define SM501_GPIO_CTRL_LOW 0x00000008UL +#define SM501_GPIO_CTRL_HIGH 0x0000000CUL +#define SM501_POWER_MODE0_GATE 0x00000040UL +#define SM501_POWER_MODE1_GATE 0x00000048UL +#define POWER_MODE_GATE_GPIO_PWM_I2C 0x00000040UL +#define SM501_GPIO_DATA_LOW 0x00010000UL +#define SM501_GPIO_DATA_HIGH 0x00010004UL +#define SM501_GPIO_DATA_DIR_LOW 0x00010008UL +#define SM501_GPIO_DATA_DIR_HIGH 0x0001000CUL +#define SM501_PANEL_DISPLAY_CONTROL 0x00080000UL + +static int i2s_squarewave(unsigned long duration, unsigned int freq, + unsigned int channel); +static int i2s_sawtooth(unsigned long duration, unsigned int freq, + unsigned int channel); +static void spi_init(void); +static int spi_transmit(unsigned char data); +static void pcm1772_write_reg(unsigned char addr, unsigned char data); +static void set_attenuation(unsigned char attenuation); + +#ifdef CONFIG_STK52XX +static void spi_init(void) +{ + struct mpc5xxx_spi *spi = (struct mpc5xxx_spi*)MPC5XXX_SPI; + struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio*)MPC5XXX_GPIO; + + /* PSC3 as SPI and GPIOs */ + gpio->port_config &= 0xFFFFF0FF; + gpio->port_config |= 0x00000800; + /* + * Its important to use the correct order when initializing the + * registers + */ + spi->ddr = 0x0F; /* set all SPI pins as output */ + spi->pdr = 0x08; /* set SS high */ + spi->cr1 = 0x50; /* SPI is master, SS is general purpose output */ + spi->cr2 = 0x00; /* normal operation */ + spi->brr = 0xFF; /* baud rate: IPB clock / 2048 */ +} + +static int spi_transmit(unsigned char data) +{ + int dummy; + struct mpc5xxx_spi *spi = (struct mpc5xxx_spi*)MPC5XXX_SPI; + + spi->dr = data; + /* wait for SPI transmission completed */ + while(!(spi->sr & 0x80)) + { + if (spi->sr & 0x40) /* if write collision occured */ + { + /* do dummy read to clear status register */ + dummy = spi->dr; + printf ("SPI write collision\n"); + return -1; + } + } + return (spi->dr); +} + +static void pcm1772_write_reg(unsigned char addr, unsigned char data) +{ + struct mpc5xxx_spi *spi = (struct mpc5xxx_spi*)MPC5XXX_SPI; + + spi->pdr = 0x00; /* Set SS low */ + spi_transmit(addr); + spi_transmit(data); + /* wait some time to meet MS# hold time of PCM1772 */ + udelay (1); + spi->pdr = 0x08; /* set SS high */ +} + +static void set_attenuation(unsigned char attenuation) +{ + pcm1772_write_reg(0x01, attenuation); /* left channel */ + debug ("PCM1772 attenuation left set to %d.\n", attenuation); + pcm1772_write_reg(0x02, attenuation); /* right channel */ + debug ("PCM1772 attenuation right set to %d.\n", attenuation); +} + +void amplifier_init(void) +{ + static int init_done = 0; + int i; + struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio*)MPC5XXX_GPIO; + + /* Do this only once, because of the long time delay */ + if (!init_done) { + /* configure PCM1772 audio format as I2S */ + pcm1772_write_reg(0x03, 0x01); + /* enable audio amplifier */ + gpio->sint_gpioe |= 0x02; /* PSC3_5 as GPIO */ + gpio->sint_ode &= ~0x02; /* PSC3_5 is not open Drain */ + gpio->sint_dvo &= ~0x02; /* PSC3_5 is LOW */ + gpio->sint_ddr |= 0x02; /* PSC3_5 as output */ + /* + * wait some time to allow amplifier to recover from shutdown + * mode. + */ + for(i = 0; i < 350; i++) + udelay(1000); + /* + * The used amplifier (LM4867) has a so called "pop and click" + * elmination filter. The input signal of the amplifier must + * exceed a certain level once after power up to activate the + * generation of the output signal. This is achieved by + * sending a low frequent (nearly inaudible) sawtooth with a + * sufficient signal level. + */ + set_attenuation(50); + i2s_sawtooth (200, 5, LEFT_RIGHT); + init_done = 1; + } +} + +static void i2s_init(void) +{ + unsigned long i; + struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2;; + struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio*)MPC5XXX_GPIO; + + gpio->port_config |= 0x00000070; /* PSC2 ports as Codec with MCLK */ + psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); + psc->sicr = 0x22E00000; /* 16 bit data; I2S */ + + *(vu_long *)(CFG_MBAR + 0x22C) = 0x805d; /* PSC2 CDM MCLK config; MCLK + * 5.617 MHz */ + *(vu_long *)(CFG_MBAR + 0x214) |= 0x00000040; /* CDM clock enable + * register */ + psc->ccr = 0x1F03; /* 16 bit data width; 5.617MHz MCLK */ + psc->ctur = 0x0F; /* 16 bit frame width */ + + for(i=0;i<128;i++) + { + psc->psc_buffer_32 = 0; /* clear tx fifo */ + } +} + +static int i2s_play_wave(unsigned long addr, unsigned long len) +{ + unsigned long i; + unsigned char *wave_file = (char *)addr + 44; /* quick'n dirty: skip + * wav header*/ + unsigned char swapped[4]; + struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2; + + /* + * play wave file in memory; bytes/words are be swapped + */ + psc->command = (PSC_RX_ENABLE | PSC_TX_ENABLE); + + for(i = 0;i < (len / 4); i++) { + swapped[3]=*wave_file++; + swapped[2]=*wave_file++; + swapped[1]=*wave_file++; + swapped[0]=*wave_file++; + psc->psc_buffer_32 = *((unsigned long*)swapped); + while (psc->tfnum > 400) { + if(ctrlc()) + return 0; + } + } + while (psc->tfnum > 0); /* wait for fifo empty */ + udelay (100); + psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); + return 0; +} + +static int i2s_sawtooth(unsigned long duration, unsigned int freq, + unsigned int channel) +{ + long i,j; + unsigned long data; + struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2; + + psc->command = (PSC_RX_ENABLE | PSC_TX_ENABLE); + + /* + * Generate sawtooth. Start with middle level up to highest level. Then + * go to lowest level and back to middle level. + */ + for(j = 0; j < ((duration * freq) / 1000); j++) { + for(i = 0; i <= 0x7FFF; i += (0x7FFF/(44100/(freq*4)))) { + data = (i & 0xFFFF); + /* data format: right data left data) */ + if (channel == LEFT_RIGHT) + data |= (data<<16); + if (channel == RIGHT) + data = (data<<16); + psc->psc_buffer_32 = data; + while (psc->tfnum > 400); + } + for(i = 0x7FFF; i >= -0x7FFF; i -= (0xFFFF/(44100/(freq*2)))) { + data = (i & 0xFFFF); + /* data format: right data left data) */ + if (channel == LEFT_RIGHT) + data |= (data<<16); + if (channel == RIGHT) + data = (data<<16); + psc->psc_buffer_32 = data; + while (psc->tfnum > 400); + } + for(i = -0x7FFF; i <= 0; i += (0x7FFF/(44100/(freq*4)))) { + data = (i & 0xFFFF); + /* data format: right data left data) */ + if (channel == LEFT_RIGHT) + data |= (data<<16); + if (channel == RIGHT) + data = (data<<16); + psc->psc_buffer_32 = data; + while (psc->tfnum > 400); + } + } + while (psc->tfnum > 0); /* wait for fifo empty */ + udelay (100); + psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); + + return 0; +} + +static int i2s_squarewave(unsigned long duration, unsigned int freq, + unsigned int channel) +{ + long i,j; + unsigned long data; + struct mpc5xxx_psc *psc = (struct mpc5xxx_psc*)MPC5XXX_PSC2; + + psc->command = (PSC_RX_ENABLE | PSC_TX_ENABLE); + + /* + * Generate sqarewave. Start with high level, duty cycle 1:1. + */ + for(j = 0; j < ((duration * freq) / 1000); j++) { + for(i = 0; i < (44100/(freq*2)); i ++) { + data = 0x7FFF; + /* data format: right data left data) */ + if (channel == LEFT_RIGHT) + data |= (data<<16); + if (channel == RIGHT) + data = (data<<16); + psc->psc_buffer_32 = data; + while (psc->tfnum > 400); + } + for(i = 0; i < (44100/(freq*2)); i ++) { + data = 0x8000; + /* data format: right data left data) */ + if (channel == LEFT_RIGHT) + data |= (data<<16); + if (channel == RIGHT) + data = (data<<16); + psc->psc_buffer_32 = data; + while (psc->tfnum > 400); + } + } + while (psc->tfnum > 0); /* wait for fifo empty */ + udelay (100); + psc->command = (PSC_RX_DISABLE | PSC_TX_DISABLE); + + return 0; +} + +static int cmd_sound(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + unsigned long reg, val, duration; + unsigned char *tmp; + unsigned int freq, channel; + unsigned char volume; + int rcode = 1; + +#ifdef CONFIG_STK52XX_REV100 + printf ("Revision 100 of STK52XX not supported!\n"); + return 1; +#endif + spi_init(); + i2s_init(); + amplifier_init(); + + if ((tmp = getenv ("volume")) != NULL) { + volume = simple_strtoul (tmp, NULL, 10); + } else { + volume = DEFAULT_VOL; + } + set_attenuation(volume); + + switch (argc) { + case 0: + case 1: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 2: + if (strncmp(argv[1],"saw",3) == 0) { + printf ("Play sawtooth\n"); + rcode = i2s_sawtooth (DEFAULT_DURATION, DEFAULT_FREQ, + LEFT_RIGHT); + return rcode; + } else if (strncmp(argv[1],"squ",3) == 0) { + printf ("Play squarewave\n"); + rcode = i2s_squarewave (DEFAULT_DURATION, DEFAULT_FREQ, + LEFT_RIGHT); + return rcode; + } + + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 3: + if (strncmp(argv[1],"saw",3) == 0) { + duration = simple_strtoul(argv[2], NULL, 10); + printf ("Play sawtooth\n"); + rcode = i2s_sawtooth (duration, DEFAULT_FREQ, + LEFT_RIGHT); + return rcode; + } else if (strncmp(argv[1],"squ",3) == 0) { + duration = simple_strtoul(argv[2], NULL, 10); + printf ("Play squarewave\n"); + rcode = i2s_squarewave (duration, DEFAULT_FREQ, + LEFT_RIGHT); + return rcode; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 4: + if (strncmp(argv[1],"saw",3) == 0) { + duration = simple_strtoul(argv[2], NULL, 10); + freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); + printf ("Play sawtooth\n"); + rcode = i2s_sawtooth (duration, freq, + LEFT_RIGHT); + return rcode; + } else if (strncmp(argv[1],"squ",3) == 0) { + duration = simple_strtoul(argv[2], NULL, 10); + freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); + printf ("Play squarewave\n"); + rcode = i2s_squarewave (duration, freq, + LEFT_RIGHT); + return rcode; + } else if (strcmp(argv[1],"pcm1772") == 0) { + reg = simple_strtoul(argv[2], NULL, 10); + val = simple_strtoul(argv[3], NULL, 10); + printf("Set PCM1772 %lu. %lu\n", reg, val); + pcm1772_write_reg((uchar)reg, (uchar)val); + return 0; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + case 5: + if (strncmp(argv[1],"saw",3) == 0) { + duration = simple_strtoul(argv[2], NULL, 10); + freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); + if (strncmp(argv[4],"l",1) == 0) + channel = LEFT; + else if (strncmp(argv[4],"r",1) == 0) + channel = RIGHT; + else + channel = LEFT_RIGHT; + printf ("Play squarewave\n"); + rcode = i2s_sawtooth (duration, freq, + channel); + return rcode; + } else if (strncmp(argv[1],"squ",3) == 0) { + duration = simple_strtoul(argv[2], NULL, 10); + freq = (unsigned int)simple_strtoul(argv[3], NULL, 10); + if (strncmp(argv[4],"l",1) == 0) + channel = LEFT; + else if (strncmp(argv[4],"r",1) == 0) + channel = RIGHT; + else + channel = LEFT_RIGHT; + printf ("Play squarewave\n"); + rcode = i2s_squarewave (duration, freq, + channel); + return rcode; + } + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + printf ("Usage:\nsound cmd [arg1] [arg2] ...\n"); + return 1; +} + +static int cmd_wav(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + unsigned long length, addr; + unsigned char volume; + int rcode = 1; + char *tmp; + +#ifdef CONFIG_STK52XX_REV100 + printf ("Revision 100 of STK52XX not supported!\n"); + return 1; +#endif + spi_init(); + i2s_init(); + amplifier_init(); + + switch (argc) { + + case 3: + length = simple_strtoul(argv[2], NULL, 16); + addr = simple_strtoul(argv[1], NULL, 16); + break; + + case 2: + if ((tmp = getenv ("filesize")) != NULL) { + length = simple_strtoul (tmp, NULL, 16); + } else { + puts ("No filesize provided\n"); + return 1; + } + addr = simple_strtoul(argv[1], NULL, 16); + + case 1: + if ((tmp = getenv ("filesize")) != NULL) { + length = simple_strtoul (tmp, NULL, 16); + } else { + puts ("No filesize provided\n"); + return 1; + } + if ((tmp = getenv ("loadaddr")) != NULL) { + addr = simple_strtoul (tmp, NULL, 16); + } else { + puts ("No loadaddr provided\n"); + return 1; + } + break; + + default: + printf("Usage:\nwav <addr> <length[s]\n"); + return 1; + break; + } + + if ((tmp = getenv ("volume")) != NULL) { + volume = simple_strtoul (tmp, NULL, 10); + } else { + volume = DEFAULT_VOL; + } + set_attenuation(volume); + + printf("Play wave file at %#p with length %#x\n", addr, length); + rcode = i2s_play_wave(addr, length); + + return rcode; +} + +static int cmd_beep(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + unsigned char volume; + unsigned int channel; + int rcode; + char *tmp; + +#ifdef CONFIG_STK52XX_REV100 + printf ("Revision 100 of STK52XX not supported!\n"); + return 1; +#endif + spi_init(); + i2s_init(); + amplifier_init(); + + switch (argc) { + case 0: + case 1: + channel = LEFT_RIGHT; + break; + case 2: + if (strncmp(argv[1],"l",1) == 0) + channel = LEFT; + else if (strncmp(argv[1],"r",1) == 0) + channel = RIGHT; + else + channel = LEFT_RIGHT; + break; + default: + printf ("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if ((tmp = getenv ("volume")) != NULL) { + volume = simple_strtoul (tmp, NULL, 10); + } else { + volume = DEFAULT_VOL; + } + set_attenuation(volume); + + printf("Beep on "); + if (channel == LEFT) + printf ("left "); + else if (channel == RIGHT) + printf ("right "); + else + printf ("left and right "); + printf ("channel\n"); + + rcode = i2s_squarewave (DEFAULT_DURATION, DEFAULT_FREQ, channel); + + return rcode; +} + +void led_init(void) +{ + struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO; + struct mpc5xxx_gpt_0_7 *gpt = (struct mpc5xxx_gpt_0_7 *)MPC5XXX_GPT; + + /* configure PSC3 for SPI and GPIO */ + gpio->port_config &= ~(0x00000F00); + gpio->port_config |= 0x00000800; + + gpio->simple_gpioe &= ~(0x00000F00); + gpio->simple_gpioe |= 0x00000F00; + + gpio->simple_ddr &= ~(0x00000F00); + gpio->simple_ddr |= 0x00000F00; + + /* configure timer 4-7 for simple GPIO output */ + gpt->gpt4.emsr |= 0x00000024; + gpt->gpt5.emsr |= 0x00000024; + gpt->gpt6.emsr |= 0x00000024; + gpt->gpt7.emsr |= 0x00000024; + + + /* enable SM501 GPIO control (in both power modes) */ + *(vu_long *) (SM501_MMIO_BASE+SM501_POWER_MODE0_GATE) |= + POWER_MODE_GATE_GPIO_PWM_I2C; + *(vu_long *) (SM501_MMIO_BASE+SM501_POWER_MODE1_GATE) |= + POWER_MODE_GATE_GPIO_PWM_I2C; + + /* configure SM501 gpio pins 24-27 as output */ + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_CTRL_LOW) &= ~(0xF << 24); + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_DIR_LOW) |= (0xF << 24); + + /* configure SM501 gpio pins 48-51 as output */ + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_DIR_HIGH) |= (0xF << 16); +} + +/* + * return 1 if led number unknown + * return 0 else + */ +int do_led(char *argv[]) +{ + struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO; + struct mpc5xxx_gpt_0_7 *gpt = (struct mpc5xxx_gpt_0_7 *)MPC5XXX_GPT; + + switch (simple_strtoul(argv[2], NULL, 10)) { + + case 0: + if (strcmp (argv[3], "on") == 0) { + gpio->simple_dvo |= (1 << 8); + } else { + gpio->simple_dvo &= ~(1 << 8); + } + break; + + case 1: + if (strcmp (argv[3], "on") == 0) { + gpio->simple_dvo |= (1 << 9); + } else { + gpio->simple_dvo &= ~(1 << 9); + } + break; + + case 2: + if (strcmp (argv[3], "on") == 0) { + gpio->simple_dvo |= (1 << 10); + } else { + gpio->simple_dvo &= ~(1 << 10); + } + break; + + case 3: + if (strcmp (argv[3], "on") == 0) { + gpio->simple_dvo |= (1 << 11); + } else { + gpio->simple_dvo &= ~(1 << 11); + } + break; + + case 4: + if (strcmp (argv[3], "on") == 0) { + gpt->gpt4.emsr |= (1 << 4); + } else { + gpt->gpt4.emsr &= ~(1 << 4); + } + break; + + case 5: + if (strcmp (argv[3], "on") == 0) { + gpt->gpt5.emsr |= (1 << 4); + } else { + gpt->gpt5.emsr &= ~(1 << 4); + } + break; + + case 6: + if (strcmp (argv[3], "on") == 0) { + gpt->gpt6.emsr |= (1 << 4); + } else { + gpt->gpt6.emsr &= ~(1 << 4); + } + break; + + case 7: + if (strcmp (argv[3], "on") == 0) { + gpt->gpt7.emsr |= (1 << 4); + } else { + gpt->gpt7.emsr &= ~(1 << 4); + } + break; + + case 24: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= + (0x1 << 24); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= + ~(0x1 << 24); + } + break; + + case 25: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= + (0x1 << 25); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= + ~(0x1 << 25); + } + break; + + case 26: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= + (0x1 << 26); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= + ~(0x1 << 26); + } + break; + + case 27: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) |= + (0x1 << 27); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_LOW) &= + ~(0x1 << 27); + } + break; + + case 48: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= + (0x1 << 16); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= + ~(0x1 << 16); + } + break; + + case 49: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= + (0x1 << 17); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= + ~(0x1 << 17); + } + break; + + case 50: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= + (0x1 << 18); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= + ~(0x1 << 18); + } + break; + + case 51: + if (strcmp (argv[3], "on") == 0) { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) |= + (0x1 << 19); + } else { + *(vu_long *) (SM501_MMIO_BASE+SM501_GPIO_DATA_HIGH) &= + ~(0x1 << 19); + } + break; + + default: + printf ("%s: invalid led number %s\n", __FUNCTION__, argv[2]); + return 1; + } + + return 0; +} + +/* + * return 1 on CAN initialization failure + * return 0 if no failure + */ +int can_init(void) +{ + static int init_done = 0; + int i; + struct mpc5xxx_mscan *can1 = + (struct mpc5xxx_mscan *)(CFG_MBAR + 0x0900); + struct mpc5xxx_mscan *can2 = + (struct mpc5xxx_mscan *)(CFG_MBAR + 0x0980); + + /* GPIO configuration of the CAN pins is done in TQM5200.h */ + + if (!init_done) { + /* init CAN 1 */ + can1->canctl1 |= 0x80; /* CAN enable */ + udelay(100); + + i = 0; + can1->canctl0 |= 0x02; /* sleep mode */ + /* wait until sleep mode reached */ + while (!(can1->canctl1 & 0x02)) { + udelay(10); + i++; + if (i == 10) { + printf ("%s: CAN1 initialize error, " + "can not enter sleep mode!\n", + __FUNCTION__); + return 1; + } + } + i = 0; + can1->canctl0 = 0x01; /* enter init mode */ + /* wait until init mode reached */ + while (!(can1->canctl1 & 0x01)) { + udelay(10); + i++; + if (i == 10) { + printf ("%s: CAN1 initialize error, " + "can not enter init mode!\n", + __FUNCTION__); + return 1; + } + } + can1->canctl1 = 0x80; + can1->canctl1 |= 0x40; + can1->canbtr0 = 0x0F; + can1->canbtr1 = 0x7F; + can1->canidac &= ~(0x30); + can1->canidar1 = 0x00; + can1->canidar3 = 0x00; + can1->canidar5 = 0x00; + can1->canidar7 = 0x00; + can1->canidmr0 = 0xFF; + can1->canidmr1 = 0xFF; + can1->canidmr2 = 0xFF; + can1->canidmr3 = 0xFF; + can1->canidmr4 = 0xFF; + can1->canidmr5 = 0xFF; + can1->canidmr6 = 0xFF; + can1->canidmr7 = 0xFF; + + i = 0; + can1->canctl0 &= ~(0x01); /* leave init mode */ + can1->canctl0 &= ~(0x02); + /* wait until init and sleep mode left */ + while ((can1->canctl1 & 0x01) || (can1->canctl1 & 0x02)) { + udelay(10); + i++; + if (i == 10) { + printf ("%s: CAN1 initialize error, " + "can not leave init/sleep mode!\n", + __FUNCTION__); + return 1; + } + } + + /* init CAN 2 */ + can2->canctl1 |= 0x80; /* CAN enable */ + udelay(100); + + i = 0; + can2->canctl0 |= 0x02; /* sleep mode */ + /* wait until sleep mode reached */ + while (!(can2->canctl1 & 0x02)) { + udelay(10); + i++; + if (i == 10) { + printf ("%s: CAN2 initialize error, " + "can not enter sleep mode!\n", + __FUNCTION__); + return 1; + } + } + i = 0; + can2->canctl0 = 0x01; /* enter init mode */ + /* wait until init mode reached */ + while (!(can2->canctl1 & 0x01)) { + udelay(10); + i++; + if (i == 10) { + printf ("%s: CAN2 initialize error, " + "can not enter init mode!\n", + __FUNCTION__); + return 1; + } + } + can2->canctl1 = 0x80; + can2->canctl1 |= 0x40; + can2->canbtr0 = 0x0F; + can2->canbtr1 = 0x7F; + can2->canidac &= ~(0x30); + can2->canidar1 = 0x00; + can2->canidar3 = 0x00; + can2->canidar5 = 0x00; + can2->canidar7 = 0x00; + can2->canidmr0 = 0xFF; + can2->canidmr1 = 0xFF; + can2->canidmr2 = 0xFF; + can2->canidmr3 = 0xFF; + can2->canidmr4 = 0xFF; + can2->canidmr5 = 0xFF; + can2->canidmr6 = 0xFF; + can2->canidmr7 = 0xFF; + can2->canctl0 &= ~(0x01); /* leave init mode */ + can2->canctl0 &= ~(0x02); + + i = 0; + /* wait until init mode left */ + while ((can2->canctl1 & 0x01) || (can2->canctl1 & 0x02)) { + udelay(10); + i++; + if (i == 10) { + printf ("%s: CAN2 initialize error, " + "can not leave init/sleep mode!\n", + __FUNCTION__); + return 1; + } + } + init_done = 1; + } + return 0; +} + +/* + * return 1 on CAN failure + * return 0 if no failure + */ +int do_can(char *argv[]) +{ + int i; + struct mpc5xxx_mscan *can1 = + (struct mpc5xxx_mscan *)(CFG_MBAR + 0x0900); + struct mpc5xxx_mscan *can2 = + (struct mpc5xxx_mscan *)(CFG_MBAR + 0x0980); + + /* send a message on CAN1 */ + can1->cantbsel = 0x01; + can1->cantxfg.idr[0] = 0x55; + can1->cantxfg.idr[1] = 0x00; + can1->cantxfg.idr[1] &= ~0x8; + can1->cantxfg.idr[1] &= ~0x10; + can1->cantxfg.dsr[0] = 0xCC; + can1->cantxfg.dlr = 1; + can1->cantxfg.tbpr = 0; + can1->cantflg = 0x01; + + i = 0; + while ((can1->cantflg & 0x01) == 0) { + i++; + if (i == 10) { + printf ("%s: CAN1 send timeout, " + "can not send message!\n", + __FUNCTION__); + return 1; + } + udelay(1000); + } + udelay(1000); + + i = 0; + while (!(can2->canrflg & 0x01)) { + i++; + if (i == 10) { + printf ("%s: CAN2 receive timeout, " + "no message received!\n", + __FUNCTION__); + return 1; + } + udelay(1000); + } + + if (can2->canrxfg.dsr[0] != 0xCC) { + printf ("%s: CAN2 receive error, " + "data mismatch!\n", + __FUNCTION__); + return 1; + } + + /* send a message on CAN2 */ + can2->cantbsel = 0x01; + can2->cantxfg.idr[0] = 0x55; + can2->cantxfg.idr[1] = 0x00; + can2->cantxfg.idr[1] &= ~0x8; + can2->cantxfg.idr[1] &= ~0x10; + can2->cantxfg.dsr[0] = 0xCC; + can2->cantxfg.dlr = 1; + can2->cantxfg.tbpr = 0; + can2->cantflg = 0x01; + + i = 0; + while ((can2->cantflg & 0x01) == 0) { + i++; + if (i == 10) { + printf ("%s: CAN2 send error, " + "can not send message!\n", + __FUNCTION__); + return 1; + } + udelay(1000); + } + udelay(1000); + + i = 0; + while (!(can1->canrflg & 0x01)) { + i++; + if (i == 10) { + printf ("%s: CAN1 receive timeout, " + "no message received!\n", + __FUNCTION__); + return 1; + } + udelay(1000); + } + + if (can1->canrxfg.dsr[0] != 0xCC) { + printf ("%s: CAN1 receive error 0x%02x\n", + __FUNCTION__, (can1->canrxfg.dsr[0])); + return 1; + } + + return 0; +} + +/* + * return 1 if rs232 port unknown + * return 2 on txd/rxd failure (only rs232 2) + * return 3 on rts/cts failure + * return 0 if no failure + */ +int do_rs232(char *argv[]) +{ + int error_status = 0; + struct mpc5xxx_gpio *gpio = (struct mpc5xxx_gpio *)MPC5XXX_GPIO; + struct mpc5xxx_psc *psc1 = (struct mpc5xxx_psc *)MPC5XXX_PSC1; + + switch (simple_strtoul(argv[2], NULL, 10)) { + + case 1: + /* check RTS <-> CTS loop */ + /* set rts to 0 */ + psc1->op1 |= 0x01; + + /* wait some time before requesting status */ + udelay(10); + + /* check status at cts */ + if ((psc1->ip & 0x01) != 0) { + error_status = 3; + printf ("%s: failure at rs232_1, cts status is %d " + "(should be 0)\n", + __FUNCTION__, (psc1->ip & 0x01)); + } + + /* set rts to 1 */ + psc1->op0 |= 0x01; + + /* wait some time before requesting status */ + udelay(10); + + /* check status at cts */ + if ((psc1->ip & 0x01) != 1) { + error_status = 3; + printf ("%s: failure at rs232_1, cts status is %d " + "(should be 1)\n", + __FUNCTION__, (psc1->ip & 0x01)); + } + + break; + + case 2: + /* set PSC3_0, PSC3_2 as output and PSC3_1, PSC3_3 as input */ + gpio->simple_ddr &= ~(0x00000F00); + gpio->simple_ddr |= 0x00000500; + + /* check TXD <-> RXD loop */ + /* set TXD to 1 */ + gpio->simple_dvo |= (1 << 8); + + /* wait some time before requesting status */ + udelay(10); + + if ((gpio->simple_ival & 0x00000200) != 0x00000200) { + error_status = 2; + printf ("%s: failure at rs232_2, rxd status is %d " + "(should be 1)\n", + __FUNCTION__, + (gpio->simple_ival & 0x00000200) >> 9); + } + + /* set TXD to 0 */ + gpio->simple_dvo &= ~(1 << 8); + + /* wait some time before requesting status */ + udelay(10); + + if ((gpio->simple_ival & 0x00000200) != 0x00000000) { + error_status = 2; + printf ("%s: failure at rs232_2, rxd status is %d " + "(should be 0)\n", + __FUNCTION__, + (gpio->simple_ival & 0x00000200) >> 9); + } + + /* check RTS <-> CTS loop */ + /* set RTS to 1 */ + gpio->simple_dvo |= (1 << 10); + + /* wait some time before requesting status */ + udelay(10); + + if ((gpio->simple_ival & 0x00000800) != 0x00000800) { + error_status = 3; + printf ("%s: failure at rs232_2, cts status is %d " + "(should be 1)\n", + __FUNCTION__, + (gpio->simple_ival & 0x00000800) >> 11); + } + + /* set RTS to 0 */ + gpio->simple_dvo &= ~(1 << 10); + + /* wait some time before requesting status */ + udelay(10); + + if ((gpio->simple_ival & 0x00000800) != 0x00000000) { + error_status = 3; + printf ("%s: failure at rs232_2, cts status is %d " + "(should be 0)\n", + __FUNCTION__, + (gpio->simple_ival & 0x00000800) >> 11); + } + + /* set PSC3_0, PSC3_1, PSC3_2 and PSC3_3 as output */ + gpio->simple_ddr &= ~(0x00000F00); + gpio->simple_ddr |= 0x00000F00; + break; + + default: + printf ("%s: invalid rs232 number %s\n", __FUNCTION__, argv[2]); + error_status = 1; + break; + } + + return error_status; +} + +static void sm501_backlight (unsigned int state) +{ + if (state == BL_ON) { + *(vu_long *)(SM501_MMIO_BASE+SM501_PANEL_DISPLAY_CONTROL) |= + (1 << 26) | (1 << 27); + } else if (state == BL_OFF) + *(vu_long *)(SM501_MMIO_BASE+SM501_PANEL_DISPLAY_CONTROL) &= + ~((1 << 26) | (1 << 27)); +} + +int cmd_fkt(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + int rcode; + +#ifdef CONFIG_STK52XX_REV100 + printf ("Revision 100 of STK52XX not supported!\n"); + return 1; +#endif + led_init(); + can_init(); + + switch (argc) { + + case 0: + case 1: + break; + + case 2: + if (strncmp (argv[1], "can", 3) == 0) { + rcode = do_can (argv); + if (rcode == 0) + printf ("OK\n"); + else + printf ("Error\n"); + return rcode; + } + break; + + case 3: + if (strncmp (argv[1], "rs232", 3) == 0) { + rcode = do_rs232 (argv); + if (rcode == 0) + printf ("OK\n"); + else + printf ("Error\n"); + return rcode; + } else if (strncmp (argv[1], "backlight", 4) == 0) { + if (strncmp (argv[2], "on", 2) == 0) { + sm501_backlight (BL_ON); + return 0; + } + else if (strncmp (argv[2], "off", 3) == 0) { + sm501_backlight (BL_OFF); + return 0; + } + } + break; + + case 4: + if (strcmp (argv[1], "led") == 0) { + return (do_led (argv)); + } + break; + + default: + break; + } + + printf ("Usage:\nfkt cmd [arg1] [arg2] ...\n"); + return 1; +} + + +U_BOOT_CMD( + sound , 5, 1, cmd_sound, + "sound - Sound sub-system\n", + "saw [duration] [freq] [channel]\n" + " - generate sawtooth for 'duration' ms with frequency 'freq'\n" + " on left \"l\" or right \"r\" channel\n" + "sound square [duration] [freq] [channel]\n" + " - generate squarewave for 'duration' ms with frequency 'freq'\n" + " on left \"l\" or right \"r\" channel\n" + "pcm1772 reg val\n" +); + +U_BOOT_CMD( + wav , 3, 1, cmd_wav, + "wav - play wav file\n", + "[addr] [bytes]\n" + " - play wav file at address 'addr' with length 'bytes'\n" +); + +U_BOOT_CMD( + beep , 2, 1, cmd_beep, + "beep - play short beep\n", + "[channel]\n" + " - play short beep on \"l\"eft or \"r\"ight channel\n" +); + +U_BOOT_CMD( + fkt , 4, 1, cmd_fkt, + "fkt - Function test routines\n", + "led number on/off\n" + " - 'number's like printed on SKT52XX board\n" + "fkt can\n" + " - loopback plug for X83 required\n" + "fkt rs232 number\n" + " - loopback plug(s) for X2 required\n" + "fkt backlight on/off\n" + " - switch backlight on or off\n" +); +#endif /* CONFIG_STK52XX */ +#endif /* CFG_CMD_BSP */ diff --git a/board/tqm5200/tqm5200.c b/board/tqm5200/tqm5200.c index 90275ec..dbd78d5 100644 --- a/board/tqm5200/tqm5200.c +++ b/board/tqm5200/tqm5200.c @@ -425,7 +425,7 @@ int last_stage_init (void) * Check for SRAM and SRAM size */ - /* save origianl SRAM content */ + /* save original SRAM content */ save = *(volatile u16 *)CFG_CS2_START; restore = 1; @@ -447,8 +447,7 @@ int last_stage_init (void) *(vu_long *)MPC5XXX_CS2_STOP = 0x0000FFFF; restore = 0; __asm__ volatile ("sync"); - } - else if (*(volatile u16 *)(CFG_CS2_START + (1<<19)) == 0xA5A5) { + } else if (*(volatile u16 *)(CFG_CS2_START + (1<<19)) == 0xA5A5) { /* make sure that we access a mirrored address */ *(volatile u16 *)CFG_CS2_START = 0x1111; __asm__ volatile ("sync"); @@ -461,8 +460,7 @@ int last_stage_init (void) } else puts ("!! possible error in SRAM detection\n"); - } - else { + } else { puts ("SRAM: 1 MB\n"); } /* restore origianl SRAM content */ @@ -497,8 +495,7 @@ int last_stage_init (void) *(vu_long *)MPC5XXX_CS1_STOP = 0x0000FFFF; restore = 0; __asm__ volatile ("sync"); - } - else { + } else { puts ("VGA: SMI501 (Voyager) with 8 MB\n"); } /* restore origianl FB content */ @@ -598,11 +595,46 @@ void video_get_info_str (int line_number, char *info) #endif /* - * Returns SM501 register base address. First thing called in the driver. + * Returns SM501 register base address. First thing called in the + * driver. Checks if SM501 is physically present. */ unsigned int board_video_init (void) { - return SM501_MMIO_BASE; + u16 save, tmp; + int restore, ret; + + /* + * Check for Grafic Controller + */ + + /* save origianl FB content */ + save = *(volatile u16 *)CFG_CS1_START; + restore = 1; + + /* write test pattern to FB memory */ + *(volatile u16 *)CFG_CS1_START = 0xA5A5; + __asm__ volatile ("sync"); + /* + * Put a different pattern on the data lines: otherwise they may float + * long enough to read back what we wrote. + */ + tmp = *(volatile u16 *)CFG_FLASH_BASE; + if (tmp == 0xA5A5) + puts ("!! possible error in grafic controller detection\n"); + + if (*(volatile u16 *)CFG_CS1_START != 0xA5A5) { + /* no grafic controller found */ + restore = 0; + ret = 0; + } else { + ret = SM501_MMIO_BASE; + } + + if (restore) { + *(volatile u16 *)CFG_CS1_START = save; + __asm__ volatile ("sync"); + } + return ret; } /* |