diff options
Diffstat (limited to 'board/bf537-stamp')
-rw-r--r-- | board/bf537-stamp/Makefile | 58 | ||||
-rw-r--r-- | board/bf537-stamp/bf537-stamp.c | 437 | ||||
-rw-r--r-- | board/bf537-stamp/cmd_bf537led.c | 201 | ||||
-rw-r--r-- | board/bf537-stamp/config.mk | 25 | ||||
-rw-r--r-- | board/bf537-stamp/ether_bf537.c | 545 | ||||
-rw-r--r-- | board/bf537-stamp/ether_bf537.h | 110 | ||||
-rw-r--r-- | board/bf537-stamp/flash-defines.h | 123 | ||||
-rw-r--r-- | board/bf537-stamp/flash.c | 403 | ||||
-rw-r--r-- | board/bf537-stamp/nand.c | 106 | ||||
-rw-r--r-- | board/bf537-stamp/post-memory.c | 322 | ||||
-rw-r--r-- | board/bf537-stamp/stm_m25p64.c | 515 | ||||
-rw-r--r-- | board/bf537-stamp/u-boot.lds.S | 190 |
12 files changed, 3035 insertions, 0 deletions
diff --git a/board/bf537-stamp/Makefile b/board/bf537-stamp/Makefile new file mode 100644 index 0000000..e488844 --- /dev/null +++ b/board/bf537-stamp/Makefile @@ -0,0 +1,58 @@ +# +# U-boot - Makefile +# +# Copyright (c) 2005-2007 Analog Device Inc. +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(BOARD).a + +COBJS := $(BOARD).o flash.o ether_bf537.o post-memory.o stm_m25p64.o cmd_bf537led.o nand.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) $(SOBJS) u-boot.lds + $(AR) $(ARFLAGS) $@ $(OBJS) $(SOBJS) + +u-boot.lds: u-boot.lds.S + $(CPP) $(CPPFLAGS) -P -Ubfin $^ > $@.tmp + mv -f $@.tmp $@ + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak .depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/bf537-stamp/bf537-stamp.c b/board/bf537-stamp/bf537-stamp.c new file mode 100644 index 0000000..cc4e998 --- /dev/null +++ b/board/bf537-stamp/bf537-stamp.c @@ -0,0 +1,437 @@ +/* + * U-boot - BF537.c + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * 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> +#include <config.h> +#include <command.h> +#include <asm/blackfin.h> +#include <asm/io.h> +#include "ether_bf537.h" + +#define POST_WORD_ADDR 0xFF903FFC + +/* + * the bootldr command loads an address, checks to see if there + * is a Boot stream that the on-chip BOOTROM can understand, + * and loads it via the BOOTROM Callback. It is possible + * to also add booting from SPI, or TWI, but this function does + * not currently support that. + */ +int do_bootldr(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + ulong addr, entry; + ulong *data; + + /* Get the address */ + if (argc < 2) { + addr = load_addr; + } else { + addr = simple_strtoul(argv[1], NULL, 16); + } + + /* Check if it is a LDR file */ + data = (ulong *) addr; + if (*data == 0xFF800060 || *data == 0xFF800040 || *data == 0xFF800020) { + /* We want to boot from FLASH or SDRAM */ + entry = _BOOTROM_BOOT_DXE_FLASH; + printf("## Booting ldr image at 0x%08lx ...\n", addr); + if (icache_status()) + icache_disable(); + if (dcache_status()) + dcache_disable(); + + __asm__("R7=%[a];\n" "P0=%[b];\n" "JUMP (P0);\n": + :[a] "d"(addr),[b] "a"(entry) + :"R7", "P0"); + + } else { + printf("## No ldr image at address 0x%08lx\n", addr); + } + + return 0; +} + +U_BOOT_CMD(bootldr, 2, 0, do_bootldr, + "bootldr - boot ldr image from memory\n", + "[addr]\n - boot ldr image stored in memory\n"); + +int checkboard(void) +{ +#if (BFIN_CPU == ADSP_BF534) + printf("CPU: ADSP BF534 Rev.: 0.%d\n", *pCHIPID >> 28); +#elif (BFIN_CPU == ADSP_BF536) + printf("CPU: ADSP BF536 Rev.: 0.%d\n", *pCHIPID >> 28); +#else + printf("CPU: ADSP BF537 Rev.: 0.%d\n", *pCHIPID >> 28); +#endif + printf("Board: ADI BF537 stamp board\n"); + printf(" Support: http://blackfin.uclinux.org/\n"); + return 0; +} + +#if defined(CONFIG_BFIN_IDE) + +void cf_outb(unsigned char val, volatile unsigned char *addr) +{ + *(addr) = val; + sync(); +} + +unsigned char cf_inb(volatile unsigned char *addr) +{ + volatile unsigned char c; + + c = *(addr); + sync(); + + return c; +} + +void cf_insw(unsigned short *sect_buf, unsigned short *addr, int words) +{ + int i; + + for (i = 0; i < words; i++) + *(sect_buf + i) = *(addr); + sync(); +} + +void cf_outsw(unsigned short *addr, unsigned short *sect_buf, int words) +{ + int i; + + for (i = 0; i < words; i++) + *(addr) = *(sect_buf + i); + sync(); +} +#endif /* CONFIG_BFIN_IDE */ + +long int initdram(int board_type) +{ + DECLARE_GLOBAL_DATA_PTR; +#ifdef DEBUG + int brate; + char *tmp = getenv("baudrate"); + brate = simple_strtoul(tmp, NULL, 16); + printf("Serial Port initialized with Baud rate = %x\n", brate); + printf("SDRAM attributes:\n"); + printf("tRCD %d SCLK Cycles,tRP %d SCLK Cycles,tRAS %d SCLK Cycles" + "tWR %d SCLK Cycles,CAS Latency %d SCLK cycles \n", + 3, 3, 6, 2, 3); + printf("SDRAM Begin: 0x%x\n", CFG_SDRAM_BASE); + printf("Bank size = %d MB\n", CFG_MAX_RAM_SIZE >> 20); +#endif + gd->bd->bi_memstart = CFG_SDRAM_BASE; + gd->bd->bi_memsize = CFG_MAX_RAM_SIZE; + return CFG_MAX_RAM_SIZE; +} + +#if defined(CONFIG_MISC_INIT_R) +/* miscellaneous platform dependent initialisations */ +int misc_init_r(void) +{ +#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT) + char nid[32]; + unsigned char *pMACaddr = (unsigned char *)0x203F0000; + u8 SrcAddr[6] = { 0x02, 0x80, 0xAD, 0x20, 0x31, 0xB8 }; + +#if (CONFIG_COMMANDS & CFG_CMD_NET) + /* The 0xFF check here is to make sure we don't use the address + * in flash if it's simply been erased (aka all 0xFF values) */ + if (getenv("ethaddr") == NULL && is_valid_ether_addr(pMACaddr)) { + sprintf(nid, "%02x:%02x:%02x:%02x:%02x:%02x", + pMACaddr[0], pMACaddr[1], + pMACaddr[2], pMACaddr[3], pMACaddr[4], pMACaddr[5]); + setenv("ethaddr", nid); + } + if (getenv("ethaddr")) { + SetupMacAddr(SrcAddr); + } +#endif /* CONFIG_COMMANDS & CFG_CMD_NET */ +#endif /* BFIN_BOOT_MODE == BF537_BYPASS_BOOT */ + +#if defined(CONFIG_BFIN_IDE) +#if defined(CONFIG_BFIN_TRUE_IDE) + /* Enable ATASEL when in True IDE mode */ + printf("Using CF True IDE Mode\n"); + cf_outb(0, (unsigned char *)CONFIG_CF_ATASEL_ENA); + udelay(1000); +#elif defined(CONFIG_BFIN_CF_IDE) + /* Disable ATASEL when we're in Common Memory Mode */ + printf("Using CF Common Memory Mode\n"); + cf_outb(0, (unsigned char *)CONFIG_CF_ATASEL_DIS); + udelay(1000); +#elif defined(CONFIG_BFIN_HDD_IDE) + printf("Using HDD IDE Mode\n"); +#endif + ide_init(); +#endif /* CONFIG_BFIN_IDE */ + return 0; +} +#endif /* CONFIG_MISC_INIT_R */ + +#ifdef CONFIG_POST +#if (BFIN_BOOT_MODE != BF537_BYPASS_BOOT) +/* Using sw10-PF5 as the hotkey */ +int post_hotkeys_pressed(void) +{ + return 0; +} +#else +/* Using sw10-PF5 as the hotkey */ +int post_hotkeys_pressed(void) +{ + int delay = 3; + int i; + unsigned short value; + + *pPORTF_FER &= ~PF5; + *pPORTFIO_DIR &= ~PF5; + *pPORTFIO_INEN |= PF5; + + printf("########Press SW10 to enter Memory POST########: %2d ", delay); + while (delay--) { + for (i = 0; i < 100; i++) { + value = *pPORTFIO & PF5; + if (value != 0) { + break; + } + udelay(10000); + } + printf("\b\b\b%2d ", delay); + } + printf("\b\b\b 0"); + printf("\n"); + if (value == 0) + return 0; + else { + printf("Hotkey has been pressed, Enter POST . . . . . .\n"); + return 1; + } +} +#endif +#endif + +#if defined(CONFIG_POST) || defined(CONFIG_LOGBUFFER) +void post_word_store(ulong a) +{ + volatile ulong *save_addr = (volatile ulong *)POST_WORD_ADDR; + *save_addr = a; +} + +ulong post_word_load(void) +{ + volatile ulong *save_addr = (volatile ulong *)POST_WORD_ADDR; + return *save_addr; +} +#endif + +#ifdef CONFIG_POST +int uart_post_test(int flags) +{ + return 0; +} + +#define BLOCK_SIZE 0x10000 +#define VERIFY_ADDR 0x2000000 +extern int erase_block_flash(int); +extern int write_data(long lStart, long lCount, uchar * pnData); +int flash_post_test(int flags) +{ + unsigned short *pbuf, *temp; + int offset, n, i; + int value = 0; + int result = 0; + printf("\n"); + pbuf = (unsigned short *)VERIFY_ADDR; + temp = pbuf; + for (n = FLASH_START_POST_BLOCK; n < FLASH_END_POST_BLOCK; n++) { + offset = (n - 7) * BLOCK_SIZE; + printf("--------Erase block:%2d..", n); + erase_block_flash(n); + printf("OK\r"); + printf("--------Program block:%2d...", n); + write_data(CFG_FLASH_BASE + offset, BLOCK_SIZE, pbuf); + printf("OK\r"); + printf("--------Verify block:%2d...", n); + for (i = 0; i < BLOCK_SIZE; i += 2) { + if (*(unsigned short *)(CFG_FLASH_BASE + offset + i) != + *temp++) { + value = 1; + result = 1; + } + } + if (value) + printf("failed\n"); + else + printf("OK %3d%%\r", + (int)( + (n + 1 - + FLASH_START_POST_BLOCK) * + 100 / (FLASH_END_POST_BLOCK - + FLASH_START_POST_BLOCK))); + + temp = pbuf; + value = 0; + } + printf("\n"); + if (result) + return -1; + else + return 0; +} + +/**************************************************** + * LED1 ---- PF6 LED2 ---- PF7 * + * LED3 ---- PF8 LED4 ---- PF9 * + * LED5 ---- PF10 LED6 ---- PF11 * + ****************************************************/ +int led_post_test(int flags) +{ + *pPORTF_FER &= ~(PF6 | PF7 | PF8 | PF9 | PF10 | PF11); + *pPORTFIO_DIR |= PF6 | PF7 | PF8 | PF9 | PF10 | PF11; + *pPORTFIO_INEN &= ~(PF6 | PF7 | PF8 | PF9 | PF10 | PF11); + *pPORTFIO &= ~(PF6 | PF7 | PF8 | PF9 | PF10 | PF11); + udelay(1000000); + printf("LED1 on"); + *pPORTFIO |= PF6; + udelay(1000000); + printf("\b\b\b\b\b\b\b"); + printf("LED2 on"); + *pPORTFIO |= PF7; + udelay(1000000); + printf("\b\b\b\b\b\b\b"); + printf("LED3 on"); + *pPORTFIO |= PF8; + udelay(1000000); + printf("\b\b\b\b\b\b\b"); + printf("LED4 on"); + *pPORTFIO |= PF9; + udelay(1000000); + printf("\b\b\b\b\b\b\b"); + printf("LED5 on"); + *pPORTFIO |= PF10; + udelay(1000000); + printf("\b\b\b\b\b\b\b"); + printf("lED6 on"); + *pPORTFIO |= PF11; + printf("\b\b\b\b\b\b\b "); + return 0; +} + +/************************************************ + * SW10 ---- PF5 SW11 ---- PF4 * + * SW12 ---- PF3 SW13 ---- PF2 * + ************************************************/ +int button_post_test(int flags) +{ + int i, delay = 5; + unsigned short value = 0; + int result = 0; + + *pPORTF_FER &= ~(PF5 | PF4 | PF3 | PF2); + *pPORTFIO_DIR &= ~(PF5 | PF4 | PF3 | PF2); + *pPORTFIO_INEN |= (PF5 | PF4 | PF3 | PF2); + + printf("\n--------Press SW10: %2d ", delay); + while (delay--) { + for (i = 0; i < 100; i++) { + value = *pPORTFIO & PF5; + if (value != 0) { + break; + } + udelay(10000); + } + printf("\b\b\b%2d ", delay); + } + if (value != 0) + printf("\b\bOK"); + else { + result = -1; + printf("\b\bfailed"); + } + + delay = 5; + printf("\n--------Press SW11: %2d ", delay); + while (delay--) { + for (i = 0; i < 100; i++) { + value = *pPORTFIO & PF4; + if (value != 0) { + break; + } + udelay(10000); + } + printf("\b\b\b%2d ", delay); + } + if (value != 0) + printf("\b\bOK"); + else { + result = -1; + printf("\b\bfailed"); + } + + delay = 5; + printf("\n--------Press SW12: %2d ", delay); + while (delay--) { + for (i = 0; i < 100; i++) { + value = *pPORTFIO & PF3; + if (value != 0) { + break; + } + udelay(10000); + } + printf("\b\b\b%2d ", delay); + } + if (value != 0) + printf("\b\bOK"); + else { + result = -1; + printf("\b\bfailed"); + } + + delay = 5; + printf("\n--------Press SW13: %2d ", delay); + while (delay--) { + for (i = 0; i < 100; i++) { + value = *pPORTFIO & PF2; + if (value != 0) { + break; + } + udelay(10000); + } + printf("\b\b\b%2d ", delay); + } + if (value != 0) + printf("\b\bOK"); + else { + result = -1; + printf("\b\bfailed"); + } + printf("\n"); + return result; +} +#endif diff --git a/board/bf537-stamp/cmd_bf537led.c b/board/bf537-stamp/cmd_bf537led.c new file mode 100644 index 0000000..fa650f2 --- /dev/null +++ b/board/bf537-stamp/cmd_bf537led.c @@ -0,0 +1,201 @@ +/* + * U-boot - cmd_bf537led.c + * + * Copyright (C) 2006 Aaron Gage, Ocean Optics Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ +#include <common.h> +#include <config.h> +#include <command.h> +#include <asm/blackfin.h> +#include <asm-blackfin/string.h> +#ifdef CONFIG_BF537_STAMP_LEDCMD + +/* Define the command usage in a reusable way */ +#define USAGE_LONG \ + "led <number> <action>\n" \ + " <number> - Index (0-5) of LED to change, or \"all\"\n" \ + " <action> - Must be one of:\n" \ + " on off toggle\n" + +/* Number of LEDs supported by the board */ +#define NUMBER_LEDS 6 +/* The BF537 stamp has 6 LEDs. This mask indicates that all should be lit. */ +#define LED_ALL_MASK 0x003F + +void show_cmd_usage(void); +void set_led_state(int index, int state); +void configure_GPIO_to_output(int index); + +/* Map of LEDs according to their GPIO ports. This can be rearranged or + * otherwise changed to account for different GPIO configurations. + */ +int led_ports[] = { PF6, PF7, PF8, PF9, PF10, PF11 }; + +#define ACTION_TOGGLE -1 +#define ACTION_OFF 0 +#define ACTION_ON 1 + +#define LED_STATE_OFF 0 +#define LED_STATE_ON 1 + +/* This is a trivial atoi implementation since we don't have one available */ +int atoi(char *string) +{ + int length; + int retval = 0; + int i; + int sign = 1; + + length = strlen(string); + for (i = 0; i < length; i++) { + if (0 == i && string[0] == '-') { + sign = -1; + continue; + } + if (string[i] > '9' || string[i] < '0') { + break; + } + retval *= 10; + retval += string[i] - '0'; + } + retval *= sign; + return retval; +} + +int do_bf537led(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + int led_mask = 0; + int led_current_state = 0; + int action = ACTION_OFF; + int temp; + + if (3 != argc) { + /* Not enough arguments, so just show usage information */ + show_cmd_usage(); + return 1; + } + + if (strcmp(argv[1], "all") == 0) { + led_mask = LED_ALL_MASK; + } else { + temp = atoi(argv[1]); + if (temp < 0 || temp >= NUMBER_LEDS) { + printf("Invalid LED number [%s]\n", argv[1]); + show_cmd_usage(); + return 2; + } + led_mask |= (1 << temp); + } + + if (strcmp(argv[2], "off") == 0) { + action = ACTION_OFF; + } else if (strcmp(argv[2], "on") == 0) { + action = ACTION_ON; + } else if (strcmp(argv[2], "toggle") == 0) { + action = ACTION_TOGGLE; + } else { + printf("Invalid action [%s]\n", argv[2]); + show_cmd_usage(); + return 3; + } + + for (temp = 0; temp < NUMBER_LEDS; temp++) { + if ((led_mask & (1 << temp)) > 0) { + /* + * It is possible that the user has wired one of PF6-PF11 to + * something other than an LED, so this will only change a pin + * to output if the user has indicated a state change. This may + * happen a lot, but this way is safer than just setting all pins + * to output. + */ + configure_GPIO_to_output(temp); + + led_current_state = + ((*pPORTFIO & led_ports[temp]) > + 0) ? LED_STATE_ON : LED_STATE_OFF; + /* + printf("LED state for index %d (%x) is %d\n", temp, led_ports[temp], + led_current_state); + printf("*pPORTFIO is %x\n", *pPORTFIO); + */ + if (ACTION_ON == action + || (ACTION_TOGGLE == action + && 0 == led_current_state)) { + printf("Turning LED %d on\n", temp); + set_led_state(temp, LED_STATE_ON); + } else { + printf("Turning LED %d off\n", temp); + set_led_state(temp, LED_STATE_OFF); + } + } + } + + return 0; +} + +/* + * The GPIO pins that go to the LEDs on the BF537 stamp must be configured + * as output. This function simply configures them that way. This could + * be done to all of the GPIO lines at once, but if a user is using a + * custom board, this will try to be nice and only change the GPIO lines + * that the user specifically names. + */ +void configure_GPIO_to_output(int index) +{ + int port; + + port = led_ports[index]; + + /* Clear the Port F Function Enable Register */ + *pPORTF_FER &= ~port; + /* Set the Port F I/O direction register */ + *pPORTFIO_DIR |= port; + /* Clear the Port F I/O Input Enable Register */ + *pPORTFIO_INEN &= ~port; +} + +/* Enforce the given state on the GPIO line for the indicated LED */ +void set_led_state(int index, int state) +{ + int port; + + port = led_ports[index]; + + if (LED_STATE_OFF == state) { + /* Clear the bit to turn off the LED */ + *pPORTFIO &= ~port; + } else { + /* Set the bit to turn on the LED */ + *pPORTFIO |= port; + } +} + +/* Display usage information */ +void show_cmd_usage() +{ + printf("Usage:\n%s", USAGE_LONG); +} + +/* Register information for u-boot to find this command */ +U_BOOT_CMD(led, 3, 1, do_bf537led, + "led- Control BF537 stamp LEDs\n", USAGE_LONG); + +#endif diff --git a/board/bf537-stamp/config.mk b/board/bf537-stamp/config.mk new file mode 100644 index 0000000..a623c3d --- /dev/null +++ b/board/bf537-stamp/config.mk @@ -0,0 +1,25 @@ +# +# (C) Copyright 2001 +# 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 +# +# TEXT_BASE should be defined as the MAX_SDRAM Address - 256k bytes +# 256k is defined as CFG_MONITOR_LEN in ./include/configs/<board>.h +TEXT_BASE = 0x03FC0000 diff --git a/board/bf537-stamp/ether_bf537.c b/board/bf537-stamp/ether_bf537.c new file mode 100644 index 0000000..f00837a --- /dev/null +++ b/board/bf537-stamp/ether_bf537.c @@ -0,0 +1,545 @@ +/* + * ADI Blackfin 537 MAC Ethernet + * + * Copyright (c) 2005 Analog Device, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <config.h> +#include <asm/blackfin.h> +#include <net.h> +#include <command.h> +#include <malloc.h> +#include "ether_bf537.h" + +#ifdef CONFIG_POST +#include <post.h> +#endif + +#undef DEBUG_ETHERNET + +#ifdef DEBUG_ETHERNET +#define DEBUGF(fmt,args...) printf(fmt,##args) +#else +#define DEBUGF(fmt,args...) +#endif + +#if (CONFIG_COMMANDS & CFG_CMD_NET) + +#define RXBUF_BASE_ADDR 0xFF900000 +#define TXBUF_BASE_ADDR 0xFF800000 +#define TX_BUF_CNT 1 + +#define TOUT_LOOP 1000000 + +ADI_ETHER_BUFFER *txbuf[TX_BUF_CNT]; +ADI_ETHER_BUFFER *rxbuf[PKTBUFSRX]; +static u16 txIdx; /* index of the current RX buffer */ +static u16 rxIdx; /* index of the current TX buffer */ + +u8 SrcAddr[6]; +u16 PHYregs[NO_PHY_REGS]; /* u16 PHYADDR; */ + +/* DMAx_CONFIG values at DMA Restart */ +const ADI_DMA_CONFIG_REG rxdmacfg = { 1, 1, 2, 0, 0, 0, 0, 5, 7 }; + +#if 0 + rxdmacfg.b_DMA_EN = 1; /* enabled */ + rxdmacfg.b_WNR = 1; /* write to memory */ + rxdmacfg.b_WDSIZE = 2; /* wordsize is 32 bits */ + rxdmacfg.b_DMA2D = 0; /* N/A */ + rxdmacfg.b_RESTART= 0; /* N/A */ + rxdmacfg.b_DI_SEL = 0; /* N/A */ + rxdmacfg.b_DI_EN = 0; /* no interrupt */ + rxdmacfg.b_NDSIZE = 5; /* 5 half words is desc size. */ + rxdmacfg.b_FLOW = 7; /* large desc flow */ +#endif + +const ADI_DMA_CONFIG_REG txdmacfg = { 1, 0, 2, 0, 0, 0, 0, 5, 7 }; + +#if 0 + txdmacfg.b_DMA_EN = 1; /* enabled */ + txdmacfg.b_WNR = 0; /* read from memory */ + txdmacfg.b_WDSIZE = 2; /* wordsize is 32 bits */ + txdmacfg.b_DMA2D = 0; /* N/A */ + txdmacfg.b_RESTART= 0; /* N/A */ + txdmacfg.b_DI_SEL = 0; /* N/A */ + txdmacfg.b_DI_EN = 0; /* no interrupt */ + txdmacfg.b_NDSIZE = 5; /* 5 half words is desc size. */ + txdmacfg.b_FLOW = 7; /* large desc flow */ +#endif + +ADI_ETHER_BUFFER *SetupRxBuffer(int no); +ADI_ETHER_BUFFER *SetupTxBuffer(int no); + +static int bfin_EMAC_init(struct eth_device *dev, bd_t * bd); +static void bfin_EMAC_halt(struct eth_device *dev); +static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, + int length); +static int bfin_EMAC_recv(struct eth_device *dev); + +int bfin_EMAC_initialize(bd_t * bis) +{ + struct eth_device *dev; + dev = (struct eth_device *)malloc(sizeof(*dev)); + if (dev == NULL) + hang(); + + memset(dev, 0, sizeof(*dev)); + sprintf(dev->name, "BF537 ETHERNET"); + + dev->iobase = 0; + dev->priv = 0; + dev->init = bfin_EMAC_init; + dev->halt = bfin_EMAC_halt; + dev->send = bfin_EMAC_send; + dev->recv = bfin_EMAC_recv; + + eth_register(dev); + + return 1; +} + +static int bfin_EMAC_send(struct eth_device *dev, volatile void *packet, + int length) +{ + int i; + int result = 0; + unsigned int *buf; + buf = (unsigned int *)packet; + + if (length <= 0) { + printf("Ethernet: bad packet size: %d\n", length); + goto out; + } + + if ((*pDMA2_IRQ_STATUS & DMA_ERR) != 0) { + printf("Ethernet: tx DMA error\n"); + goto out; + } + + for (i = 0; (*pDMA2_IRQ_STATUS & DMA_RUN) != 0; i++) { + if (i > TOUT_LOOP) { + puts("Ethernet: tx time out\n"); + goto out; + } + } + txbuf[txIdx]->FrmData->NoBytes = length; + memcpy(txbuf[txIdx]->FrmData->Dest, (void *)packet, length); + txbuf[txIdx]->Dma[0].START_ADDR = (u32) txbuf[txIdx]->FrmData; + *pDMA2_NEXT_DESC_PTR = &txbuf[txIdx]->Dma[0]; + *pDMA2_CONFIG = *(u16 *) (void *)(&txdmacfg); + *pEMAC_OPMODE |= TE; + + for (i = 0; (txbuf[txIdx]->StatusWord & TX_COMP) == 0; i++) { + if (i > TOUT_LOOP) { + puts("Ethernet: tx error\n"); + goto out; + } + } + result = txbuf[txIdx]->StatusWord; + txbuf[txIdx]->StatusWord = 0; + if ((txIdx + 1) >= TX_BUF_CNT) + txIdx = 0; + else + txIdx++; + out: + DEBUGF("BFIN EMAC send: length = %d\n", length); + return result; +} + +static int bfin_EMAC_recv(struct eth_device *dev) +{ + int length = 0; + + for (;;) { + if ((rxbuf[rxIdx]->StatusWord & RX_COMP) == 0) { + length = -1; + break; + } + if ((rxbuf[rxIdx]->StatusWord & RX_DMAO) != 0) { + printf("Ethernet: rx dma overrun\n"); + break; + } + if ((rxbuf[rxIdx]->StatusWord & RX_OK) == 0) { + printf("Ethernet: rx error\n"); + break; + } + length = rxbuf[rxIdx]->StatusWord & 0x000007FF; + if (length <= 4) { + printf("Ethernet: bad frame\n"); + break; + } + NetRxPackets[rxIdx] = + (volatile uchar *)(rxbuf[rxIdx]->FrmData->Dest); + NetReceive(NetRxPackets[rxIdx], length - 4); + *pDMA1_IRQ_STATUS |= DMA_DONE | DMA_ERR; + rxbuf[rxIdx]->StatusWord = 0x00000000; + if ((rxIdx + 1) >= PKTBUFSRX) + rxIdx = 0; + else + rxIdx++; + } + + return length; +} + +/************************************************************** + * + * Ethernet Initialization Routine + * + *************************************************************/ + +static int bfin_EMAC_init(struct eth_device *dev, bd_t * bd) +{ + u32 opmode; + int dat; + int i; + DEBUGF("Eth_init: ......\n"); + + txIdx = 0; + rxIdx = 0; + +/* Initialize System Register */ + if (SetupSystemRegs(&dat) < 0) + return -1; + +/* Initialize EMAC address */ + SetupMacAddr(SrcAddr); + +/* Initialize TX and RX buffer */ + for (i = 0; i < PKTBUFSRX; i++) { + rxbuf[i] = SetupRxBuffer(i); + if (i > 0) { + rxbuf[i - 1]->Dma[1].NEXT_DESC_PTR = + &(rxbuf[i]->Dma[0]); + if (i == (PKTBUFSRX - 1)) + rxbuf[i]->Dma[1].NEXT_DESC_PTR = + &(rxbuf[0]->Dma[0]); + } + } + for (i = 0; i < TX_BUF_CNT; i++) { + txbuf[i] = SetupTxBuffer(i); + if (i > 0) { + txbuf[i - 1]->Dma[1].NEXT_DESC_PTR = + &(txbuf[i]->Dma[0]); + if (i == (TX_BUF_CNT - 1)) + txbuf[i]->Dma[1].NEXT_DESC_PTR = + &(txbuf[0]->Dma[0]); + } + } + + /* Set RX DMA */ + *pDMA1_NEXT_DESC_PTR = &rxbuf[0]->Dma[0]; + *pDMA1_CONFIG = *((u16 *) (void *)&rxbuf[0]->Dma[0].CONFIG); + + /* Wait MII done */ + PollMdcDone(); + + /* We enable only RX here */ + /* ASTP : Enable Automatic Pad Stripping + PR : Promiscuous Mode for test + PSF : Receive frames with total length less than 64 bytes. + FDMODE : Full Duplex Mode + LB : Internal Loopback for test + RE : Receiver Enable */ + if (dat == FDMODE) + opmode = ASTP | FDMODE | PSF; + else + opmode = ASTP | PSF; + opmode |= RE; +#ifdef CONFIG_BFIN_MAC_RMII + opmode |= TE | RMII; +#endif + /* Turn on the EMAC */ + *pEMAC_OPMODE = opmode; + return 0; +} + +static void bfin_EMAC_halt(struct eth_device *dev) +{ + DEBUGF("Eth_halt: ......\n"); + /* Turn off the EMAC */ + *pEMAC_OPMODE = 0x00000000; + /* Turn off the EMAC RX DMA */ + *pDMA1_CONFIG = 0x0000; + *pDMA2_CONFIG = 0x0000; + +} + +void SetupMacAddr(u8 * MACaddr) +{ + char *tmp, *end; + int i; + /* this depends on a little-endian machine */ + tmp = getenv("ethaddr"); + if (tmp) { + for (i = 0; i < 6; i++) { + MACaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0; + if (tmp) + tmp = (*end) ? end + 1 : end; + } + +#ifndef CONFIG_NETCONSOLE + printf("Using MAC Address %02X:%02X:%02X:%02X:%02X:%02X\n", + MACaddr[0], MACaddr[1], + MACaddr[2], MACaddr[3], MACaddr[4], MACaddr[5]); +#endif + *pEMAC_ADDRLO = MACaddr[0] | MACaddr[1] << 8 | + MACaddr[2] << 16 | MACaddr[3] << 24; + *pEMAC_ADDRHI = MACaddr[4] | MACaddr[5] << 8; + } +} + +void PollMdcDone(void) +{ + /* poll the STABUSY bit */ + while (*pEMAC_STAADD & STABUSY) ; +} + +void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data) +{ + PollMdcDone(); + + *pEMAC_STADAT = Data; + + *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | + STAOP | STAIE | STABUSY; +} + +/********************************************************************************* + * Read an off-chip register in a PHY through the MDC/MDIO port * + *********************************************************************************/ +u16 RdPHYReg(u16 PHYAddr, u16 RegAddr) +{ + u16 Data; + + PollMdcDone(); + + *pEMAC_STAADD = SET_PHYAD(PHYAddr) | SET_REGAD(RegAddr) | + STAIE | STABUSY; + + PollMdcDone(); + + Data = (u16) * pEMAC_STADAT; + + PHYregs[RegAddr] = Data; /* save shadow copy */ + + return Data; +} + +void SoftResetPHY(void) +{ + u16 phydat; + /* set the reset bit */ + WrPHYReg(PHYADDR, PHY_MODECTL, PHY_RESET); + /* and clear it again */ + WrPHYReg(PHYADDR, PHY_MODECTL, 0x0000); + do { + /* poll until reset is complete */ + phydat = RdPHYReg(PHYADDR, PHY_MODECTL); + } while ((phydat & PHY_RESET) != 0); +} + +int SetupSystemRegs(int *opmode) +{ + u16 sysctl, phydat; + int count = 0; + /* Enable PHY output */ + *pVR_CTL |= PHYCLKOE; + /* MDC = 2.5 MHz */ + sysctl = SET_MDCDIV(24); + /* Odd word alignment for Receive Frame DMA word */ + /* Configure checksum support and rcve frame word alignment */ + sysctl |= RXDWA | RXCKS; + *pEMAC_SYSCTL = sysctl; + /* auto negotiation on */ + /* full duplex */ + /* 100 Mbps */ + phydat = PHY_ANEG_EN | PHY_DUPLEX | PHY_SPD_SET; + WrPHYReg(PHYADDR, PHY_MODECTL, phydat); + do { + udelay(1000); + phydat = RdPHYReg(PHYADDR, PHY_MODESTAT); + if (count > 3000) { + printf + ("Link is down, please check your network connection\n"); + return -1; + } + count++; + } while (!(phydat & 0x0004)); + + phydat = RdPHYReg(PHYADDR, PHY_ANLPAR); + + if ((phydat & 0x0100) || (phydat & 0x0040)) + *opmode = FDMODE; + else + *opmode = 0; + + *pEMAC_MMC_CTL = RSTC | CROLL; + + /* Initialize the TX DMA channel registers */ + *pDMA2_X_COUNT = 0; + *pDMA2_X_MODIFY = 4; + *pDMA2_Y_COUNT = 0; + *pDMA2_Y_MODIFY = 0; + + /* Initialize the RX DMA channel registers */ + *pDMA1_X_COUNT = 0; + *pDMA1_X_MODIFY = 4; + *pDMA1_Y_COUNT = 0; + *pDMA1_Y_MODIFY = 0; + return 0; +} + +ADI_ETHER_BUFFER *SetupRxBuffer(int no) +{ + ADI_ETHER_FRAME_BUFFER *frmbuf; + ADI_ETHER_BUFFER *buf; + int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ + int total_size = nobytes_buffer + RECV_BUFSIZE; + + buf = (ADI_ETHER_BUFFER *) (RXBUF_BASE_ADDR + no * total_size); + frmbuf = + (ADI_ETHER_FRAME_BUFFER *) (RXBUF_BASE_ADDR + no * total_size + + nobytes_buffer); + + memset(buf, 0x00, nobytes_buffer); + buf->FrmData = frmbuf; + memset(frmbuf, 0xfe, RECV_BUFSIZE); + + /* set up first desc to point to receive frame buffer */ + buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]); + buf->Dma[0].START_ADDR = (u32) buf->FrmData; + buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[0].CONFIG.b_WNR = 1; /* Write to memory */ + buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */ + buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */ + + /* set up second desc to point to status word */ + buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]); + buf->Dma[1].START_ADDR = (u32) & buf->IPHdrChksum; + buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */ + buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */ + buf->Dma[1].CONFIG.b_NDSIZE = 5; /* must be 0 when FLOW is 0 */ + buf->Dma[1].CONFIG.b_FLOW = 7; /* stop */ + + return buf; +} + +ADI_ETHER_BUFFER *SetupTxBuffer(int no) +{ + ADI_ETHER_FRAME_BUFFER *frmbuf; + ADI_ETHER_BUFFER *buf; + int nobytes_buffer = sizeof(ADI_ETHER_BUFFER[2]) / 2; /* ensure a multi. of 4 */ + int total_size = nobytes_buffer + RECV_BUFSIZE; + + buf = (ADI_ETHER_BUFFER *) (TXBUF_BASE_ADDR + no * total_size); + frmbuf = + (ADI_ETHER_FRAME_BUFFER *) (TXBUF_BASE_ADDR + no * total_size + + nobytes_buffer); + + memset(buf, 0x00, nobytes_buffer); + buf->FrmData = frmbuf; + memset(frmbuf, 0x00, RECV_BUFSIZE); + + /* set up first desc to point to receive frame buffer */ + buf->Dma[0].NEXT_DESC_PTR = &(buf->Dma[1]); + buf->Dma[0].START_ADDR = (u32) buf->FrmData; + buf->Dma[0].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[0].CONFIG.b_WNR = 0; /* Read to memory */ + buf->Dma[0].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[0].CONFIG.b_NDSIZE = 5; /* 5 half words is desc size. */ + buf->Dma[0].CONFIG.b_FLOW = 7; /* large desc flow */ + + /* set up second desc to point to status word */ + buf->Dma[1].NEXT_DESC_PTR = &(buf->Dma[0]); + buf->Dma[1].START_ADDR = (u32) & buf->StatusWord; + buf->Dma[1].CONFIG.b_DMA_EN = 1; /* enabled */ + buf->Dma[1].CONFIG.b_WNR = 1; /* Write to memory */ + buf->Dma[1].CONFIG.b_WDSIZE = 2; /* wordsize is 32 bits */ + buf->Dma[1].CONFIG.b_DI_EN = 1; /* enable interrupt */ + buf->Dma[1].CONFIG.b_NDSIZE = 0; /* must be 0 when FLOW is 0 */ + buf->Dma[1].CONFIG.b_FLOW = 0; /* stop */ + + return buf; +} + +#if defined(CONFIG_POST) && defined(CFG_POST_ETHER) +int ether_post_test(int flags) +{ + uchar buf[64]; + int i, value = 0; + int length; + + printf("\n--------"); + bfin_EMAC_init(NULL, NULL); + /* construct the package */ + buf[0] = buf[6] = (unsigned char)(*pEMAC_ADDRLO & 0xFF); + buf[1] = buf[7] = (unsigned char)((*pEMAC_ADDRLO & 0xFF00) >> 8); + buf[2] = buf[8] = (unsigned char)((*pEMAC_ADDRLO & 0xFF0000) >> 16); + buf[3] = buf[9] = (unsigned char)((*pEMAC_ADDRLO & 0xFF000000) >> 24); + buf[4] = buf[10] = (unsigned char)(*pEMAC_ADDRHI & 0xFF); + buf[5] = buf[11] = (unsigned char)((*pEMAC_ADDRHI & 0xFF00) >> 8); + buf[12] = 0x08; /* Type: ARP */ + buf[13] = 0x06; + buf[14] = 0x00; /* Hardware type: Ethernet */ + buf[15] = 0x01; + buf[16] = 0x08; /* Protocal type: IP */ + buf[17] = 0x00; + buf[18] = 0x06; /* Hardware size */ + buf[19] = 0x04; /* Protocol size */ + buf[20] = 0x00; /* Opcode: request */ + buf[21] = 0x01; + + for (i = 0; i < 42; i++) + buf[i + 22] = i; + printf("--------Send 64 bytes......\n"); + bfin_EMAC_send(NULL, (volatile void *)buf, 64); + for (i = 0; i < 100; i++) { + udelay(10000); + if ((rxbuf[rxIdx]->StatusWord & RX_COMP) != 0) { + value = 1; + break; + } + } + if (value == 0) { + printf("--------EMAC can't receive any data\n"); + eth_halt(); + return -1; + } + length = rxbuf[rxIdx]->StatusWord & 0x000007FF - 4; + for (i = 0; i < length; i++) { + if (rxbuf[rxIdx]->FrmData->Dest[i] != buf[i]) { + printf("--------EMAC receive error data!\n"); + eth_halt(); + return -1; + } + } + printf("--------receive %d bytes, matched\n", length); + bfin_EMAC_halt(NULL); + return 0; +} +#endif +#endif /* CFG_CMD_NET */ diff --git a/board/bf537-stamp/ether_bf537.h b/board/bf537-stamp/ether_bf537.h new file mode 100644 index 0000000..64240ba --- /dev/null +++ b/board/bf537-stamp/ether_bf537.h @@ -0,0 +1,110 @@ +#define PHYADDR 0x01 +#define NO_PHY_REGS 0x20 + +#define DEFAULT_PHY_PHYID1 0x0007 +#define DEFAULT_PHY_PHYID2 0xC0A3 +#define PHY_MODECTL 0x00 +#define PHY_MODESTAT 0x01 +#define PHY_PHYID1 0x02 +#define PHY_PHYID2 0x03 +#define PHY_ANAR 0x04 +#define PHY_ANLPAR 0x05 +#define PHY_ANER 0x06 + +#define PHY_RESET 0x8000 +#define PHY_ANEG_EN 0x1000 +#define PHY_DUPLEX 0x0100 +#define PHY_SPD_SET 0x2000 + +#define RECV_BUFSIZE (0x614) + +typedef volatile u32 reg32; +typedef volatile u16 reg16; + +typedef struct ADI_DMA_CONFIG_REG { + u16 b_DMA_EN:1; /* 0 Enabled */ + u16 b_WNR:1; /* 1 Direction */ + u16 b_WDSIZE:2; /* 2:3 Transfer word size */ + u16 b_DMA2D:1; /* 4 DMA mode */ + u16 b_RESTART:1; /* 5 Retain FIFO */ + u16 b_DI_SEL:1; /* 6 Data interrupt timing select */ + u16 b_DI_EN:1; /* 7 Data interrupt enabled */ + u16 b_NDSIZE:4; /* 8:11 Flex descriptor size */ + u16 b_FLOW:3; /* 12:14Flow */ +} ADI_DMA_CONFIG_REG; + +typedef struct adi_ether_frame_buffer { + u16 NoBytes; /* the no. of following bytes */ + u8 Dest[6]; /* destination MAC address */ + u8 Srce[6]; /* source MAC address */ + u16 LTfield; /* length/type field */ + u8 Data[0]; /* payload bytes */ +} ADI_ETHER_FRAME_BUFFER; +/* 16 bytes/struct */ + +typedef struct dma_descriptor { + struct dma_descriptor *NEXT_DESC_PTR; + u32 START_ADDR; + ADI_DMA_CONFIG_REG CONFIG; +} DMA_DESCRIPTOR; +/* 10 bytes/struct in 12 bytes */ + +typedef struct adi_ether_buffer { + DMA_DESCRIPTOR Dma[2]; /* first for the frame, second for the status */ + ADI_ETHER_FRAME_BUFFER *FrmData;/* pointer to data */ + struct adi_ether_buffer *pNext; /* next buffer */ + struct adi_ether_buffer *pPrev; /* prev buffer */ + u16 IPHdrChksum; /* the IP header checksum */ + u16 IPPayloadChksum; /* the IP header and payload checksum */ + volatile u32 StatusWord; /* the frame status word */ +} ADI_ETHER_BUFFER; +/* 40 bytes/struct in 44 bytes */ + +void SetupMacAddr(u8 * MACaddr); + +void PollMdcDone(void); +void WrPHYReg(u16 PHYAddr, u16 RegAddr, u16 Data); +u16 RdPHYReg(u16 PHYAddr, u16 RegAddr); +void SoftResetPHY(void); +void DumpPHYRegs(void); + +int SetupSystemRegs(int *opmode); + +/** + * is_zero_ether_addr - Determine if give Ethernet address is all zeros. + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is all zeroes. + */ +static inline int is_zero_ether_addr(const u8 * addr) +{ + return !(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]); +} + +/** + * is_multicast_ether_addr - Determine if the Ethernet address is a multicast. + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Return true if the address is a multicast address. + * By definition the broadcast address is also a multicast address. + */ +static inline int is_multicast_ether_addr(const u8 * addr) +{ + return (0x01 & addr[0]); +} + +/** + * is_valid_ether_addr - Determine if the given Ethernet address is valid + * @addr: Pointer to a six-byte array containing the Ethernet address + * + * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not + * a multicast address, and is not FF:FF:FF:FF:FF:FF. + * + * Return true if the address is valid. + */ +static inline int is_valid_ether_addr(const u8 * addr) +{ + /* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to + * explicitly check for it here. */ + return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); +} diff --git a/board/bf537-stamp/flash-defines.h b/board/bf537-stamp/flash-defines.h new file mode 100644 index 0000000..f19e171 --- /dev/null +++ b/board/bf537-stamp/flash-defines.h @@ -0,0 +1,123 @@ +/* + * U-boot - flash-defines.h + * + * Copyright (c) 2005 blackfin.uclinux.org + * + * (C) Copyright 2000-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __FLASHDEFINES_H__ +#define __FLASHDEFINES_H__ + +#include <common.h> + +#define V_ULONG(a) (*(volatile unsigned long *)( a )) +#define V_BYTE(a) (*(volatile unsigned char *)( a )) +#define TRUE 0x1 +#define FALSE 0x0 +#define BUFFER_SIZE 0x80000 +#define NO_COMMAND 0 +#define GET_CODES 1 +#define RESET 2 +#define WRITE 3 +#define FILL 4 +#define ERASE_ALL 5 +#define ERASE_SECT 6 +#define READ 7 +#define GET_SECTNUM 8 +#define FLASH_START_L 0x0000 +#define FLASH_START_H 0x2000 +#define FLASH_MAN_ST 2 +#define RESET_VAL 0xF0 + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; + +int get_codes(void); +int poll_toggle_bit(long lOffset); +void reset_flash(void); +int erase_flash(void); +int erase_block_flash(int); +void unlock_flash(long lOffset); +int write_data(long lStart, long lCount, uchar * pnData); +int read_flash(long nOffset, int *pnValue); +int write_flash(long nOffset, int nValue); +void get_sector_number(long lOffset, int *pnSector); +int GetSectorProtectionStatus(flash_info_t * info, int nSector); +int GetOffset(int nBlock); +int AFP_NumSectors = 71; +long AFP_SectorSize2 = 0x10000; +int AFP_SectorSize1 = 0x2000; + +#define NUM_SECTORS 71 + +#define WRITESEQ1 0x0AAA +#define WRITESEQ2 0x0554 +#define WRITESEQ3 0x0AAA +#define WRITESEQ4 0x0AAA +#define WRITESEQ5 0x0554 +#define WRITESEQ6 0x0AAA +#define WRITEDATA1 0xaa +#define WRITEDATA2 0x55 +#define WRITEDATA3 0x80 +#define WRITEDATA4 0xaa +#define WRITEDATA5 0x55 +#define WRITEDATA6 0x10 +#define PriFlashABegin 0 +#define SecFlashABegin 8 +#define SecFlashBBegin 36 +#define PriFlashAOff 0x0 +#define PriFlashBOff 0x100000 +#define SecFlashAOff 0x10000 +#define SecFlashBOff 0x280000 +#define INVALIDLOCNSTART 0x20270000 +#define INVALIDLOCNEND 0x20280000 +#define BlockEraseVal 0x30 +#define UNLOCKDATA1 0xaa +#define UNLOCKDATA2 0x55 +#define UNLOCKDATA3 0xa0 +#define GETCODEDATA1 0xaa +#define GETCODEDATA2 0x55 +#define GETCODEDATA3 0x90 +#define SecFlashASec1Off 0x200000 +#define SecFlashASec2Off 0x204000 +#define SecFlashASec3Off 0x206000 +#define SecFlashASec4Off 0x208000 +#define SecFlashAEndOff 0x210000 +#define SecFlashBSec1Off 0x280000 +#define SecFlashBSec2Off 0x284000 +#define SecFlashBSec3Off 0x286000 +#define SecFlashBSec4Off 0x288000 +#define SecFlashBEndOff 0x290000 + +#define SECT32 32 +#define SECT33 33 +#define SECT34 34 +#define SECT35 35 +#define SECT36 36 +#define SECT37 37 +#define SECT38 38 +#define SECT39 39 + +#define FLASH_SUCCESS 0 +#define FLASH_FAIL -1 + +#endif diff --git a/board/bf537-stamp/flash.c b/board/bf537-stamp/flash.c new file mode 100644 index 0000000..42dcf06 --- /dev/null +++ b/board/bf537-stamp/flash.c @@ -0,0 +1,403 @@ +/* + * U-boot - flash.c Flash driver for PSD4256GV + * + * Copyright (c) 2005 blackfin.uclinux.org + * This file is based on BF533EzFlash.c originally written by Analog Devices, Inc. + * + * (C) Copyright 2000-2004 + * 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 <malloc.h> +#include <config.h> +#include <asm/io.h> +#include "flash-defines.h" + +void flash_reset(void) +{ + reset_flash(); +} + +unsigned long flash_get_size(ulong baseaddr, flash_info_t * info, int bank_flag) +{ + int id = 0, i = 0; + static int FlagDev = 1; + + id = get_codes(); + if (FlagDev) { + FlagDev = 0; + } + info->flash_id = id; + switch (bank_flag) { + case 0: + for (i = PriFlashABegin; i < SecFlashABegin; i++) + info->start[i] = (baseaddr + (i * AFP_SectorSize1)); + for (i = SecFlashABegin; i < NUM_SECTORS; i++) + info->start[i] = + (baseaddr + SecFlashAOff + + ((i - SecFlashABegin) * AFP_SectorSize2)); + info->size = 0x400000; + info->sector_count = NUM_SECTORS; + break; + case 1: + info->start[0] = baseaddr + SecFlashASec1Off; + info->start[1] = baseaddr + SecFlashASec2Off; + info->start[2] = baseaddr + SecFlashASec3Off; + info->start[3] = baseaddr + SecFlashASec4Off; + info->size = 0x10000; + info->sector_count = 4; + break; + case 2: + info->start[0] = baseaddr + SecFlashBSec1Off; + info->start[1] = baseaddr + SecFlashBSec2Off; + info->start[2] = baseaddr + SecFlashBSec3Off; + info->start[3] = baseaddr + SecFlashBSec4Off; + info->size = 0x10000; + info->sector_count = 4; + break; + } + return (info->size); +} + +unsigned long flash_init(void) +{ + unsigned long size_b; + int i; + + size_b = 0; + for (i = 0; i < CFG_MAX_FLASH_BANKS; ++i) { + flash_info[i].flash_id = FLASH_UNKNOWN; + } + + size_b = flash_get_size(CFG_FLASH_BASE, &flash_info[0], 0); + + if (flash_info[0].flash_id == FLASH_UNKNOWN || size_b == 0) { + printf("## Unknown FLASH on Bank 0 - Size = 0x%08lx = %ld MB\n", + size_b, size_b >> 20); + } + + /* flash_protect (int flag, ulong from, ulong to, flash_info_t *info) */ + (void)flash_protect(FLAG_PROTECT_SET, CFG_FLASH_BASE, + (flash_info[0].start[2] - 1), &flash_info[0]); +#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT) + (void)flash_protect(FLAG_PROTECT_SET, 0x203F0000, 0x203FFFFF, + &flash_info[0]); +#endif + + return (size_b); +} + +void flash_print_info(flash_info_t * info) +{ + int i; + + if (info->flash_id == FLASH_UNKNOWN) { + printf("missing or unknown FLASH type\n"); + return; + } + + switch (info->flash_id) { + case (STM_ID_29W320EB & 0xFFFF): + case (STM_ID_29W320DB & 0xFFFF): + printf("ST Microelectronics "); + break; + default: + printf("Unknown Vendor: (0x%08X) ", info->flash_id); + break; + } + 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"); + return; +} + +int flash_erase(flash_info_t * info, int s_first, int s_last) +{ + int cnt = 0, i; + int prot, sect; + + 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"); + + cnt = s_last - s_first + 1; + +#if (BFIN_BOOT_MODE == BF537_BYPASS_BOOT) + printf("Erasing Flash locations, Please Wait\n"); + for (i = s_first; i <= s_last; i++) { + if (info->protect[i] == 0) { /* not protected */ + if (erase_block_flash(i) < 0) { + printf("Error Sector erasing \n"); + return FLASH_FAIL; + } + } + } +#elif (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT) + if (cnt == FLASH_TOT_SECT) { + printf("Erasing flash, Please Wait \n"); + if (erase_flash() < 0) { + printf("Erasing flash failed \n"); + return FLASH_FAIL; + } + } else { + printf("Erasing Flash locations, Please Wait\n"); + for (i = s_first; i <= s_last; i++) { + if (info->protect[i] == 0) { /* not protected */ + if (erase_block_flash(i) < 0) { + printf("Error Sector erasing \n"); + return FLASH_FAIL; + } + } + } + } +#endif + printf("\n"); + return FLASH_SUCCESS; +} + +int write_buff(flash_info_t * info, uchar * src, ulong addr, ulong cnt) +{ + int d; + if (addr % 2) { + read_flash(addr - 1 - CFG_FLASH_BASE, &d); + d = (int)((d & 0x00FF) | (*src++ << 8)); + write_data(addr - 1, 2, (uchar *) & d); + write_data(addr + 1, cnt - 1, src); + } else + write_data(addr, cnt, src); + return FLASH_SUCCESS; +} + +int write_data(long lStart, long lCount, uchar * pnData) +{ + long i = 0; + unsigned long ulOffset = lStart - CFG_FLASH_BASE; + int d; + int nSector = 0; + int flag = 0; + + if (lCount % 2) { + flag = 1; + lCount = lCount - 1; + } + + for (i = 0; i < lCount - 1; i += 2, ulOffset += 2) { + get_sector_number(ulOffset, &nSector); + read_flash(ulOffset, &d); + if (d != 0xffff) { + printf + ("Flash not erased at offset 0x%x Please erase to reprogram \n", + ulOffset); + return FLASH_FAIL; + } + unlock_flash(ulOffset); + d = (int)(pnData[i] | pnData[i + 1] << 8); + write_flash(ulOffset, d); + if (poll_toggle_bit(ulOffset) < 0) { + printf("Error programming the flash \n"); + return FLASH_FAIL; + } + if ((i > 0) && (!(i % AFP_SectorSize2))) + printf("."); + } + if (flag) { + get_sector_number(ulOffset, &nSector); + read_flash(ulOffset, &d); + if (d != 0xffff) { + printf + ("Flash not erased at offset 0x%x Please erase to reprogram \n", + ulOffset); + return FLASH_FAIL; + } + unlock_flash(ulOffset); + d = (int)(pnData[i] | (d & 0xFF00)); + write_flash(ulOffset, d); + if (poll_toggle_bit(ulOffset) < 0) { + printf("Error programming the flash \n"); + return FLASH_FAIL; + } + } + return FLASH_SUCCESS; +} + +int write_flash(long nOffset, int nValue) +{ + long addr; + + addr = (CFG_FLASH_BASE + nOffset); + *(unsigned volatile short *)addr = nValue; + sync(); +#if (BFIN_BOOT_MODE == BF537_SPI_MASTER_BOOT) + if (icache_status()) + udelay(CONFIG_CCLK_HZ / 1000000); +#endif + return FLASH_SUCCESS; +} + +int read_flash(long nOffset, int *pnValue) +{ + unsigned short *pFlashAddr = + (unsigned short *)(CFG_FLASH_BASE + nOffset); + + *pnValue = *pFlashAddr; + + return TRUE; +} + +int poll_toggle_bit(long lOffset) +{ + unsigned int u1, u2; + volatile unsigned long *FB = + (volatile unsigned long *)(CFG_FLASH_BASE + lOffset); + while (1) { + u1 = *(volatile unsigned short *)FB; + u2 = *(volatile unsigned short *)FB; + u1 ^= u2; + if (!(u1 & 0x0040)) + break; + if (!(u2 & 0x0020)) + continue; + else { + u1 = *(volatile unsigned short *)FB; + u2 = *(volatile unsigned short *)FB; + u1 ^= u2; + if (!(u1 & 0x0040)) + break; + else { + reset_flash(); + return FLASH_FAIL; + } + } + } + return FLASH_SUCCESS; +} + +void reset_flash(void) +{ + write_flash(WRITESEQ1, RESET_VAL); + /* Wait for 10 micro seconds */ + udelay(10); +} + +int erase_flash(void) +{ + write_flash(WRITESEQ1, WRITEDATA1); + write_flash(WRITESEQ2, WRITEDATA2); + write_flash(WRITESEQ3, WRITEDATA3); + write_flash(WRITESEQ4, WRITEDATA4); + write_flash(WRITESEQ5, WRITEDATA5); + write_flash(WRITESEQ6, WRITEDATA6); + + if (poll_toggle_bit(0x0000) < 0) + return FLASH_FAIL; + + return FLASH_SUCCESS; +} + +int erase_block_flash(int nBlock) +{ + long ulSectorOff = 0x0; + + if ((nBlock < 0) || (nBlock > AFP_NumSectors)) + return FALSE; + + /* figure out the offset of the block in flash */ + if ((nBlock >= 0) && (nBlock < SecFlashABegin)) + ulSectorOff = nBlock * AFP_SectorSize1; + + else if ((nBlock >= SecFlashABegin) && (nBlock < NUM_SECTORS)) + ulSectorOff = + SecFlashAOff + (nBlock - SecFlashABegin) * AFP_SectorSize2; + /* no such sector */ + else + return FLASH_FAIL; + + write_flash((WRITESEQ1 | ulSectorOff), WRITEDATA1); + write_flash((WRITESEQ2 | ulSectorOff), WRITEDATA2); + write_flash((WRITESEQ3 | ulSectorOff), WRITEDATA3); + write_flash((WRITESEQ4 | ulSectorOff), WRITEDATA4); + write_flash((WRITESEQ5 | ulSectorOff), WRITEDATA5); + + write_flash(ulSectorOff, BlockEraseVal); + + if (poll_toggle_bit(ulSectorOff) < 0) + return FLASH_FAIL; + printf("."); + + return FLASH_SUCCESS; +} + +void unlock_flash(long ulOffset) +{ + unsigned long ulOffsetAddr = ulOffset; + ulOffsetAddr &= 0xFFFF0000; + + write_flash((WRITESEQ1 | ulOffsetAddr), UNLOCKDATA1); + write_flash((WRITESEQ2 | ulOffsetAddr), UNLOCKDATA2); + write_flash((WRITESEQ3 | ulOffsetAddr), UNLOCKDATA3); +} + +int get_codes() +{ + int dev_id = 0; + + write_flash(WRITESEQ1, GETCODEDATA1); + write_flash(WRITESEQ2, GETCODEDATA2); + write_flash(WRITESEQ3, GETCODEDATA3); + + read_flash(0x0402, &dev_id); + dev_id &= 0x0000FFFF; + + reset_flash(); + + return dev_id; +} + +void get_sector_number(long ulOffset, int *pnSector) +{ + int nSector = 0; + long lMainEnd = 0x400000; + long lBootEnd = 0x10000; + + /* sector numbers for the FLASH A boot sectors */ + if (ulOffset < lBootEnd) { + nSector = (int)ulOffset / AFP_SectorSize1; + } + /* sector numbers for the FLASH B boot sectors */ + else if ((ulOffset >= lBootEnd) && (ulOffset < lMainEnd)) { + nSector = ((ulOffset / (AFP_SectorSize2)) + 7); + } + /* if it is a valid sector, set it */ + if ((nSector >= 0) && (nSector < AFP_NumSectors)) + *pnSector = nSector; + +} diff --git a/board/bf537-stamp/nand.c b/board/bf537-stamp/nand.c new file mode 100644 index 0000000..4d6e776 --- /dev/null +++ b/board/bf537-stamp/nand.c @@ -0,0 +1,106 @@ +/* + * (C) Copyright 2006 Aubrey.Li, aubrey.li@analog.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/io.h> + +#if (CONFIG_COMMANDS & CFG_CMD_NAND) + +#include <nand.h> + +#define CONCAT(a,b,c,d) a ## b ## c ## d +#define PORT(a,b) CONCAT(pPORT,a,b,) + +#ifndef CONFIG_NAND_GPIO_PORT +#define CONFIG_NAND_GPIO_PORT F +#endif + +/* + * hardware specific access to control-lines + */ +static void bfin_hwcontrol(struct mtd_info *mtd, int cmd) +{ + register struct nand_chip *this = mtd->priv; + + switch (cmd) { + + case NAND_CTL_SETCLE: + this->IO_ADDR_W = CFG_NAND_BASE + BFIN_NAND_CLE; + break; + case NAND_CTL_CLRCLE: + this->IO_ADDR_W = CFG_NAND_BASE; + break; + + case NAND_CTL_SETALE: + this->IO_ADDR_W = CFG_NAND_BASE + BFIN_NAND_ALE; + break; + case NAND_CTL_CLRALE: + this->IO_ADDR_W = CFG_NAND_BASE; + break; + case NAND_CTL_SETNCE: + case NAND_CTL_CLRNCE: + break; + } + + this->IO_ADDR_R = this->IO_ADDR_W; + + /* Drain the writebuffer */ + sync(); +} + +int bfin_device_ready(struct mtd_info *mtd) +{ + int ret = (*PORT(CONFIG_NAND_GPIO_PORT, IO) & BFIN_NAND_READY) ? 1 : 0; + sync(); + return ret; +} + +/* + * Board-specific NAND initialization. The following members of the + * argument are board-specific (per include/linux/mtd/nand.h): + * - IO_ADDR_R?: address to read the 8 I/O lines of the flash device + * - IO_ADDR_W?: address to write the 8 I/O lines of the flash device + * - hwcontrol: hardwarespecific function for accesing control-lines + * - dev_ready: hardwarespecific function for accesing device ready/busy line + * - enable_hwecc?: function to enable (reset) hardware ecc generator. Must + * only be provided if a hardware ECC is available + * - eccmode: mode of ecc, see defines + * - chip_delay: chip dependent delay for transfering data from array to + * read regs (tR) + * - options: various chip options. They can partly be set to inform + * nand_scan about special functionality. See the defines for further + * explanation + * Members with a "?" were not set in the merged testing-NAND branch, + * so they are not set here either. + */ +void board_nand_init(struct nand_chip *nand) +{ + *PORT(CONFIG_NAND_GPIO_PORT, _FER) &= ~BFIN_NAND_READY; + *PORT(CONFIG_NAND_GPIO_PORT, IO_DIR) &= ~BFIN_NAND_READY; + *PORT(CONFIG_NAND_GPIO_PORT, IO_INEN) |= BFIN_NAND_READY; + + nand->hwcontrol = bfin_hwcontrol; + nand->eccmode = NAND_ECC_SOFT; + nand->dev_ready = bfin_device_ready; + nand->chip_delay = 30; +} +#endif /* (CONFIG_COMMANDS & CFG_CMD_NAND) */ diff --git a/board/bf537-stamp/post-memory.c b/board/bf537-stamp/post-memory.c new file mode 100644 index 0000000..6039350 --- /dev/null +++ b/board/bf537-stamp/post-memory.c @@ -0,0 +1,322 @@ +#include <common.h> +#include <asm/io.h> + +#ifdef CONFIG_POST + +#include <post.h> +#include <watchdog.h> + +#if CONFIG_POST & CFG_POST_MEMORY +#define CLKIN 25000000 +#define PATTERN1 0x5A5A5A5A +#define PATTERN2 0xAAAAAAAA + +#define CCLK_NUM 4 +#define SCLK_NUM 3 + +void post_out_buff(char *buff); +int post_key_pressed(void); +void post_init_pll(int mult, int div); +int post_init_sdram(int sclk); +void post_init_uart(int sclk); + +const int pll[CCLK_NUM][SCLK_NUM][2] = { + {{20, 4}, {20, 5}, {20, 10}}, /* CCLK = 500M */ + {{16, 4}, {16, 5}, {16, 8}}, /* CCLK = 400M */ + {{8, 2}, {8, 4}, {8, 5}}, /* CCLK = 200M */ + {{4, 1}, {4, 2}, {4, 4}} /* CCLK = 100M */ +}; +const char *const log[CCLK_NUM][SCLK_NUM] = { + {"CCLK-500Mhz SCLK-125Mhz: Writing...\0", + "CCLK-500Mhz SCLK-100Mhz: Writing...\0", + "CCLK-500Mhz SCLK- 50Mhz: Writing...\0",}, + {"CCLK-400Mhz SCLK-100Mhz: Writing...\0", + "CCLK-400Mhz SCLK- 80Mhz: Writing...\0", + "CCLK-400Mhz SCLK- 50Mhz: Writing...\0",}, + {"CCLK-200Mhz SCLK-100Mhz: Writing...\0", + "CCLK-200Mhz SCLK- 50Mhz: Writing...\0", + "CCLK-200Mhz SCLK- 40Mhz: Writing...\0",}, + {"CCLK-100Mhz SCLK-100Mhz: Writing...\0", + "CCLK-100Mhz SCLK- 50Mhz: Writing...\0", + "CCLK-100Mhz SCLK- 25Mhz: Writing...\0",}, +}; + +int memory_post_test(int flags) +{ + int addr; + int m, n; + int sclk, sclk_temp; + int ret = 1; + + sclk_temp = CLKIN / 1000000; + sclk_temp = sclk_temp * CONFIG_VCO_MULT; + for (sclk = 0; sclk_temp > 0; sclk++) + sclk_temp -= CONFIG_SCLK_DIV; + sclk = sclk * 1000000; + post_init_uart(sclk); + if (post_key_pressed() == 0) + return 0; + + for (m = 0; m < CCLK_NUM; m++) { + for (n = 0; n < SCLK_NUM; n++) { + /* Calculate the sclk */ + sclk_temp = CLKIN / 1000000; + sclk_temp = sclk_temp * pll[m][n][0]; + for (sclk = 0; sclk_temp > 0; sclk++) + sclk_temp -= pll[m][n][1]; + sclk = sclk * 1000000; + + post_init_pll(pll[m][n][0], pll[m][n][1]); + post_init_sdram(sclk); + post_init_uart(sclk); + post_out_buff("\n\r\0"); + post_out_buff(log[m][n]); + for (addr = 0x0; addr < CFG_MAX_RAM_SIZE; addr += 4) + *(unsigned long *)addr = PATTERN1; + post_out_buff("Reading...\0"); + for (addr = 0x0; addr < CFG_MAX_RAM_SIZE; addr += 4) { + if ((*(unsigned long *)addr) != PATTERN1) { + post_out_buff("Error\n\r\0"); + ret = 0; + } + } + post_out_buff("OK\n\r\0"); + } + } + if (ret) + post_out_buff("memory POST passed\n\r\0"); + else + post_out_buff("memory POST failed\n\r\0"); + + post_out_buff("\n\r\n\r\0"); + return 1; +} + +void post_init_uart(int sclk) +{ + int divisor; + + for (divisor = 0; sclk > 0; divisor++) + sclk -= 57600 * 16; + + *pPORTF_FER = 0x000F; + *pPORTH_FER = 0xFFFF; + + *pUART_GCTL = 0x00; + *pUART_LCR = 0x83; + sync(); + *pUART_DLL = (divisor & 0xFF); + sync(); + *pUART_DLH = ((divisor >> 8) & 0xFF); + sync(); + *pUART_LCR = 0x03; + sync(); + *pUART_GCTL = 0x01; + sync(); +} + +void post_out_buff(char *buff) +{ + + int i = 0; + for (i = 0; i < 0x80000; i++) ; + i = 0; + while ((buff[i] != '\0') && (i != 100)) { + while (!(*pUART_LSR & 0x20)) ; + *pUART_THR = buff[i]; + sync(); + i++; + } + for (i = 0; i < 0x80000; i++) ; +} + +/* Using sw10-PF5 as the hotkey */ +#define KEY_LOOP 0x80000 +#define KEY_DELAY 0x80 +int post_key_pressed(void) +{ + int i, n; + unsigned short value; + + *pPORTF_FER &= ~PF5; + *pPORTFIO_DIR &= ~PF5; + *pPORTFIO_INEN |= PF5; + sync(); + + post_out_buff("########Press SW10 to enter Memory POST########: 3\0"); + for (i = 0; i < KEY_LOOP; i++) { + value = *pPORTFIO & PF5; + if (*pUART0_RBR == 0x0D) { + value = 0; + goto key_pressed; + } + if (value != 0) { + goto key_pressed; + } + for (n = 0; n < KEY_DELAY; n++) + asm("nop"); + } + post_out_buff("\b2\0"); + + for (i = 0; i < KEY_LOOP; i++) { + value = *pPORTFIO & PF5; + if (*pUART0_RBR == 0x0D) { + value = 0; + goto key_pressed; + } + if (value != 0) { + goto key_pressed; + } + for (n = 0; n < KEY_DELAY; n++) + asm("nop"); + } + post_out_buff("\b1\0"); + + for (i = 0; i < KEY_LOOP; i++) { + value = *pPORTFIO & PF5; + if (*pUART0_RBR == 0x0D) { + value = 0; + goto key_pressed; + } + if (value != 0) { + goto key_pressed; + } + for (n = 0; n < KEY_DELAY; n++) + asm("nop"); + } + key_pressed: + post_out_buff("\b0"); + post_out_buff("\n\r\0"); + if (value == 0) + return 0; + post_out_buff("Hotkey has been pressed, Enter POST . . . . . .\n\r\0"); + return 1; +} + +void post_init_pll(int mult, int div) +{ + + *pSIC_IWR = 0x01; + *pPLL_CTL = (mult << 9); + *pPLL_DIV = div; + asm("CLI R2;"); + asm("IDLE;"); + asm("STI R2;"); + while (!(*pPLL_STAT & 0x20)) ; +} + +int post_init_sdram(int sclk) +{ + int SDRAM_tRP, SDRAM_tRP_num, SDRAM_tRAS, SDRAM_tRAS_num, SDRAM_tRCD, + SDRAM_tWR; + int SDRAM_Tref, SDRAM_NRA, SDRAM_CL, SDRAM_SIZE, SDRAM_WIDTH, + mem_SDGCTL, mem_SDBCTL, mem_SDRRC; + + if ((sclk > 119402985)) { + SDRAM_tRP = TRP_2; + SDRAM_tRP_num = 2; + SDRAM_tRAS = TRAS_7; + SDRAM_tRAS_num = 7; + SDRAM_tRCD = TRCD_2; + SDRAM_tWR = TWR_2; + } else if ((sclk > 104477612) && (sclk <= 119402985)) { + SDRAM_tRP = TRP_2; + SDRAM_tRP_num = 2; + SDRAM_tRAS = TRAS_6; + SDRAM_tRAS_num = 6; + SDRAM_tRCD = TRCD_2; + SDRAM_tWR = TWR_2; + } else if ((sclk > 89552239) && (sclk <= 104477612)) { + SDRAM_tRP = TRP_2; + SDRAM_tRP_num = 2; + SDRAM_tRAS = TRAS_5; + SDRAM_tRAS_num = 5; + SDRAM_tRCD = TRCD_2; + SDRAM_tWR = TWR_2; + } else if ((sclk > 74626866) && (sclk <= 89552239)) { + SDRAM_tRP = TRP_2; + SDRAM_tRP_num = 2; + SDRAM_tRAS = TRAS_4; + SDRAM_tRAS_num = 4; + SDRAM_tRCD = TRCD_2; + SDRAM_tWR = TWR_2; + } else if ((sclk > 66666667) && (sclk <= 74626866)) { + SDRAM_tRP = TRP_2; + SDRAM_tRP_num = 2; + SDRAM_tRAS = TRAS_3; + SDRAM_tRAS_num = 3; + SDRAM_tRCD = TRCD_2; + SDRAM_tWR = TWR_2; + } else if ((sclk > 59701493) && (sclk <= 66666667)) { + SDRAM_tRP = TRP_1; + SDRAM_tRP_num = 1; + SDRAM_tRAS = TRAS_4; + SDRAM_tRAS_num = 4; + SDRAM_tRCD = TRCD_1; + SDRAM_tWR = TWR_2; + } else if ((sclk > 44776119) && (sclk <= 59701493)) { + SDRAM_tRP = TRP_1; + SDRAM_tRP_num = 1; + SDRAM_tRAS = TRAS_3; + SDRAM_tRAS_num = 3; + SDRAM_tRCD = TRCD_1; + SDRAM_tWR = TWR_2; + } else if ((sclk > 29850746) && (sclk <= 44776119)) { + SDRAM_tRP = TRP_1; + SDRAM_tRP_num = 1; + SDRAM_tRAS = TRAS_2; + SDRAM_tRAS_num = 2; + SDRAM_tRCD = TRCD_1; + SDRAM_tWR = TWR_2; + } else if (sclk <= 29850746) { + SDRAM_tRP = TRP_1; + SDRAM_tRP_num = 1; + SDRAM_tRAS = TRAS_1; + SDRAM_tRAS_num = 1; + SDRAM_tRCD = TRCD_1; + SDRAM_tWR = TWR_2; + } else { + SDRAM_tRP = TRP_1; + SDRAM_tRP_num = 1; + SDRAM_tRAS = TRAS_1; + SDRAM_tRAS_num = 1; + SDRAM_tRCD = TRCD_1; + SDRAM_tWR = TWR_2; + } + /*SDRAM INFORMATION: */ + SDRAM_Tref = 64; /* Refresh period in milliseconds */ + SDRAM_NRA = 4096; /* Number of row addresses in SDRAM */ + SDRAM_CL = CL_3; /* 2 */ + + SDRAM_SIZE = EBSZ_64; + SDRAM_WIDTH = EBCAW_10; + + mem_SDBCTL = SDRAM_WIDTH | SDRAM_SIZE | EBE; + + /* Equation from section 17 (p17-46) of BF533 HRM */ + mem_SDRRC = + (((CONFIG_SCLK_HZ / 1000) * SDRAM_Tref) / SDRAM_NRA) - + (SDRAM_tRAS_num + SDRAM_tRP_num); + + /* Enable SCLK Out */ + mem_SDGCTL = + (SCTLE | SDRAM_CL | SDRAM_tRAS | SDRAM_tRP | SDRAM_tRCD | SDRAM_tWR + | PSS); + + sync(); + + *pEBIU_SDGCTL |= 0x1000000; + /* Set the SDRAM Refresh Rate control register based on SSCLK value */ + *pEBIU_SDRRC = mem_SDRRC; + + /* SDRAM Memory Bank Control Register */ + *pEBIU_SDBCTL = mem_SDBCTL; + + /* SDRAM Memory Global Control Register */ + *pEBIU_SDGCTL = mem_SDGCTL; + sync(); + return mem_SDRRC; +} + +#endif /* CONFIG_POST & CFG_POST_MEMORY */ +#endif /* CONFIG_POST */ diff --git a/board/bf537-stamp/stm_m25p64.c b/board/bf537-stamp/stm_m25p64.c new file mode 100644 index 0000000..7077e85 --- /dev/null +++ b/board/bf537-stamp/stm_m25p64.c @@ -0,0 +1,515 @@ +/**************************************************************************** + * SPI flash driver for M25P64 + ****************************************************************************/ +#include <common.h> +#include <linux/ctype.h> +#include <asm/io.h> + +#if defined(CONFIG_SPI) + +/* Application definitions */ + +#define NUM_SECTORS 128 /* number of sectors */ +#define SECTOR_SIZE 0x10000 +#define NOP_NUM 1000 + +#define COMMON_SPI_SETTINGS (SPE|MSTR|CPHA|CPOL) /* Settings to the SPI_CTL */ +#define TIMOD01 (0x01) /* stes the SPI to work with core instructions */ + +/* Flash commands */ +#define SPI_WREN (0x06) /*Set Write Enable Latch */ +#define SPI_WRDI (0x04) /*Reset Write Enable Latch */ +#define SPI_RDSR (0x05) /*Read Status Register */ +#define SPI_WRSR (0x01) /*Write Status Register */ +#define SPI_READ (0x03) /*Read data from memory */ +#define SPI_FAST_READ (0x0B) /*Read data from memory */ +#define SPI_PP (0x02) /*Program Data into memory */ +#define SPI_SE (0xD8) /*Erase one sector in memory */ +#define SPI_BE (0xC7) /*Erase all memory */ +#define WIP (0x1) /*Check the write in progress bit of the SPI status register */ +#define WEL (0x2) /*Check the write enable bit of the SPI status register */ + +#define TIMEOUT 350000000 + +typedef enum { + NO_ERR, + POLL_TIMEOUT, + INVALID_SECTOR, + INVALID_BLOCK, +} ERROR_CODE; + +void spi_init_f(void); +void spi_init_r(void); +ssize_t spi_read(uchar *, int, uchar *, int); +ssize_t spi_write(uchar *, int, uchar *, int); + +char ReadStatusRegister(void); +void Wait_For_SPIF(void); +void SetupSPI(const int spi_setting); +void SPI_OFF(void); +void SendSingleCommand(const int iCommand); + +ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector); +ERROR_CODE EraseBlock(int nBlock); +ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData); +ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData); +ERROR_CODE Wait_For_Status(char Statusbit); +ERROR_CODE Wait_For_WEL(void); + +/* + * Function: spi_init_f + * Description: Init SPI-Controller (ROM part) + * return: --- + */ +void spi_init_f(void) +{ +} + +/* + * Function: spi_init_r + * Description: Init SPI-Controller (RAM part) - + * The malloc engine is ready and we can move our buffers to + * normal RAM + * return: --- + */ +void spi_init_r(void) +{ + return; +} + +/* + * Function: spi_write + */ +ssize_t spi_write(uchar * addr, int alen, uchar * buffer, int len) +{ + unsigned long offset; + int start_block, end_block; + int start_byte, end_byte; + ERROR_CODE result = NO_ERR; + uchar temp[SECTOR_SIZE]; + int i, num; + + offset = addr[0] << 16 | addr[1] << 8 | addr[2]; + /* Get the start block number */ + result = GetSectorNumber(offset, &start_block); + if (result == INVALID_SECTOR) { + printf("Invalid sector! "); + return 0; + } + /* Get the end block number */ + result = GetSectorNumber(offset + len - 1, &end_block); + if (result == INVALID_SECTOR) { + printf("Invalid sector! "); + return 0; + } + + for (num = start_block; num <= end_block; num++) { + ReadData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp); + start_byte = num * SECTOR_SIZE; + end_byte = (num + 1) * SECTOR_SIZE - 1; + if (start_byte < offset) + start_byte = offset; + if (end_byte > (offset + len)) + end_byte = (offset + len - 1); + for (i = start_byte; i <= end_byte; i++) + temp[i - num * SECTOR_SIZE] = buffer[i - offset]; + EraseBlock(num); + result = WriteData(num * SECTOR_SIZE, SECTOR_SIZE, (int *)temp); + if (result != NO_ERR) + return 0; + printf("."); + } + return len; +} + +/* + * Function: spi_read + */ +ssize_t spi_read(uchar * addr, int alen, uchar * buffer, int len) +{ + unsigned long offset; + offset = addr[0] << 16 | addr[1] << 8 | addr[2]; + ReadData(offset, len, (int *)buffer); + return len; +} + +void SendSingleCommand(const int iCommand) +{ + unsigned short dummy; + + /* turns on the SPI in single write mode */ + SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); + + /* sends the actual command to the SPI TX register */ + *pSPI_TDBR = iCommand; + sync(); + + /* The SPI status register will be polled to check the SPIF bit */ + Wait_For_SPIF(); + + dummy = *pSPI_RDBR; + + /* The SPI will be turned off */ + SPI_OFF(); + +} + +void SetupSPI(const int spi_setting) +{ + + if (icache_status() || dcache_status()) + udelay(CONFIG_CCLK_HZ / 50000000); + /*sets up the PF10 to be the slave select of the SPI */ + *pPORTF_FER |= (PF10 | PF11 | PF12 | PF13); + *pSPI_FLG = 0xFF02; + *pSPI_BAUD = CONFIG_SPI_BAUD; + *pSPI_CTL = spi_setting; + sync(); + + *pSPI_FLG = 0xFD02; + sync(); +} + +void SPI_OFF(void) +{ + + *pSPI_CTL = 0x0400; /* disable SPI */ + *pSPI_FLG = 0; + *pSPI_BAUD = 0; + sync(); + udelay(CONFIG_CCLK_HZ / 50000000); + +} + +void Wait_For_SPIF(void) +{ + unsigned short dummyread; + while ((*pSPI_STAT & TXS)) ; + while (!(*pSPI_STAT & SPIF)) ; + while (!(*pSPI_STAT & RXS)) ; + /* Read dummy to empty the receive register */ + dummyread = *pSPI_RDBR; +} + +ERROR_CODE Wait_For_WEL(void) +{ + int i; + char status_register = 0; + ERROR_CODE ErrorCode = NO_ERR; + + for (i = 0; i < TIMEOUT; i++) { + status_register = ReadStatusRegister(); + if ((status_register & WEL)) { + ErrorCode = NO_ERR; + break; + } + ErrorCode = POLL_TIMEOUT; /* Time out error */ + }; + + return ErrorCode; +} + +ERROR_CODE Wait_For_Status(char Statusbit) +{ + int i; + char status_register = 0xFF; + ERROR_CODE ErrorCode = NO_ERR; + + for (i = 0; i < TIMEOUT; i++) { + status_register = ReadStatusRegister(); + if (!(status_register & Statusbit)) { + ErrorCode = NO_ERR; + break; + } + ErrorCode = POLL_TIMEOUT; /* Time out error */ + }; + + return ErrorCode; +} + +char ReadStatusRegister(void) +{ + char status_register = 0; + + SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); /* Turn on the SPI */ + + *pSPI_TDBR = SPI_RDSR; /* send instruction to read status register */ + sync(); + Wait_For_SPIF(); /*wait until the instruction has been sent */ + *pSPI_TDBR = 0; /*send dummy to receive the status register */ + sync(); + Wait_For_SPIF(); /*wait until the data has been sent */ + status_register = *pSPI_RDBR; /*read the status register */ + + SPI_OFF(); /* Turn off the SPI */ + + return status_register; +} + +ERROR_CODE GetSectorNumber(unsigned long ulOffset, int *pnSector) +{ + int nSector = 0; + ERROR_CODE ErrorCode = NO_ERR; + + if (ulOffset > (NUM_SECTORS * 0x10000 - 1)) { + ErrorCode = INVALID_SECTOR; + return ErrorCode; + } + + nSector = (int)ulOffset / 0x10000; + *pnSector = nSector; + + return ErrorCode; +} + +ERROR_CODE EraseBlock(int nBlock) +{ + unsigned long ulSectorOff = 0x0, ShiftValue; + ERROR_CODE ErrorCode = NO_ERR; + + /* if the block is invalid just return */ + if ((nBlock < 0) || (nBlock > NUM_SECTORS)) { + ErrorCode = INVALID_BLOCK; + return ErrorCode; + } + /* figure out the offset of the block in flash */ + if ((nBlock >= 0) && (nBlock < NUM_SECTORS)) { + ulSectorOff = (nBlock * SECTOR_SIZE); + + } else { + ErrorCode = INVALID_BLOCK; + return ErrorCode; + } + + /* A write enable instruction must previously have been executed */ + SendSingleCommand(SPI_WREN); + + /* The status register will be polled to check the write enable latch "WREN" */ + ErrorCode = Wait_For_WEL(); + + if (POLL_TIMEOUT == ErrorCode) { + printf("SPI Erase block error\n"); + return ErrorCode; + } else + + /* Turn on the SPI to send single commands */ + SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); + + /* + * Send the erase block command to the flash followed by the 24 address + * to point to the start of a sector + */ + *pSPI_TDBR = SPI_SE; + sync(); + Wait_For_SPIF(); + /* Send the highest byte of the 24 bit address at first */ + ShiftValue = (ulSectorOff >> 16); + *pSPI_TDBR = ShiftValue; + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); + /* Send the middle byte of the 24 bit address at second */ + ShiftValue = (ulSectorOff >> 8); + *pSPI_TDBR = ShiftValue; + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); + /* Send the lowest byte of the 24 bit address finally */ + *pSPI_TDBR = ulSectorOff; + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); + + /* Turns off the SPI */ + SPI_OFF(); + + /* Poll the status register to check the Write in Progress bit */ + /* Sector erase takes time */ + ErrorCode = Wait_For_Status(WIP); + + /* block erase should be complete */ + return ErrorCode; +} + +/* + * ERROR_CODE ReadData() + * Read a value from flash for verify purpose + * Inputs: unsigned long ulStart - holds the SPI start address + * int pnData - pointer to store value read from flash + * long lCount - number of elements to read + */ +ERROR_CODE ReadData(unsigned long ulStart, long lCount, int *pnData) +{ + unsigned long ShiftValue; + char *cnData; + int i; + + /* Pointer cast to be able to increment byte wise */ + + cnData = (char *)pnData; + /* Start SPI interface */ + SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); + +#ifdef CONFIG_SPI_FLASH_FAST_READ + /* Send the read command to SPI device */ + *pSPI_TDBR = SPI_FAST_READ; +#else + /* Send the read command to SPI device */ + *pSPI_TDBR = SPI_READ; +#endif + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); + /* Send the highest byte of the 24 bit address at first */ + ShiftValue = (ulStart >> 16); + /* Send the byte to the SPI device */ + *pSPI_TDBR = ShiftValue; + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); + /* Send the middle byte of the 24 bit address at second */ + ShiftValue = (ulStart >> 8); + /* Send the byte to the SPI device */ + *pSPI_TDBR = ShiftValue; + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); + /* Send the lowest byte of the 24 bit address finally */ + *pSPI_TDBR = ulStart; + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); + +#ifdef CONFIG_SPI_FLASH_FAST_READ + /* Send dummy for FAST_READ */ + *pSPI_TDBR = 0; + sync(); + /* Wait until the instruction has been sent */ + Wait_For_SPIF(); +#endif + + /* After the SPI device address has been placed on the MOSI pin the data can be */ + /* received on the MISO pin. */ + for (i = 0; i < lCount; i++) { + *pSPI_TDBR = 0; + sync(); + while (!(*pSPI_STAT & RXS)) ; + *cnData++ = *pSPI_RDBR; + + if ((i >= SECTOR_SIZE) && (i % SECTOR_SIZE == 0)) + printf("."); + } + + /* Turn off the SPI */ + SPI_OFF(); + + return NO_ERR; +} + +ERROR_CODE WriteFlash(unsigned long ulStartAddr, long lTransferCount, + int *iDataSource, long *lWriteCount) +{ + + unsigned long ulWAddr; + long lWTransferCount = 0; + int i; + char iData; + char *temp = (char *)iDataSource; + ERROR_CODE ErrorCode = NO_ERR; + + /* First, a Write Enable Command must be sent to the SPI. */ + SendSingleCommand(SPI_WREN); + + /* + * Second, the SPI Status Register will be tested whether the + * Write Enable Bit has been set + */ + ErrorCode = Wait_For_WEL(); + if (POLL_TIMEOUT == ErrorCode) { + printf("SPI Write Time Out\n"); + return ErrorCode; + } else + /* Third, the 24 bit address will be shifted out + * the SPI MOSI bytewise. + * Turns the SPI on + */ + SetupSPI((COMMON_SPI_SETTINGS | TIMOD01)); + *pSPI_TDBR = SPI_PP; + sync(); + /*wait until the instruction has been sent */ + Wait_For_SPIF(); + ulWAddr = (ulStartAddr >> 16); + *pSPI_TDBR = ulWAddr; + sync(); + /*wait until the instruction has been sent */ + Wait_For_SPIF(); + ulWAddr = (ulStartAddr >> 8); + *pSPI_TDBR = ulWAddr; + sync(); + /*wait until the instruction has been sent */ + Wait_For_SPIF(); + ulWAddr = ulStartAddr; + *pSPI_TDBR = ulWAddr; + sync(); + /*wait until the instruction has been sent */ + Wait_For_SPIF(); + /* + * Fourth, maximum number of 256 bytes will be taken from the Buffer + * and sent to the SPI device. + */ + for (i = 0; (i < lTransferCount) && (i < 256); i++, lWTransferCount++) { + iData = *temp; + *pSPI_TDBR = iData; + sync(); + /*wait until the instruction has been sent */ + Wait_For_SPIF(); + temp++; + } + + /* Turns the SPI off */ + SPI_OFF(); + + /* + * Sixth, the SPI Write in Progress Bit must be toggled to ensure the + * programming is done before start of next transfer + */ + ErrorCode = Wait_For_Status(WIP); + + if (POLL_TIMEOUT == ErrorCode) { + printf("SPI Program Time out!\n"); + return ErrorCode; + } else + + *lWriteCount = lWTransferCount; + + return ErrorCode; +} + +ERROR_CODE WriteData(unsigned long ulStart, long lCount, int *pnData) +{ + + unsigned long ulWStart = ulStart; + long lWCount = lCount, lWriteCount; + long *pnWriteCount = &lWriteCount; + + ERROR_CODE ErrorCode = NO_ERR; + + while (lWCount != 0) { + ErrorCode = WriteFlash(ulWStart, lWCount, pnData, pnWriteCount); + + /* + * After each function call of WriteFlash the counter + * must be adjusted + */ + lWCount -= *pnWriteCount; + + /* Also, both address pointers must be recalculated. */ + ulWStart += *pnWriteCount; + pnData += *pnWriteCount / 4; + } + + /* return the appropriate error code */ + return ErrorCode; +} + +#endif /* CONFIG_SPI */ diff --git a/board/bf537-stamp/u-boot.lds.S b/board/bf537-stamp/u-boot.lds.S new file mode 100644 index 0000000..3fb2d0c --- /dev/null +++ b/board/bf537-stamp/u-boot.lds.S @@ -0,0 +1,190 @@ +/* + * U-boot - u-boot.lds.S + * + * Copyright (c) 2005-2007 Analog Device Inc. + * + * (C) Copyright 2000-2004 + * 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 <config.h> + +OUTPUT_ARCH(bfin) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +MEMORY + { + ram : ORIGIN = (CFG_MONITOR_BASE), LENGTH = (256 * 1024) + l1_code : ORIGIN = 0xFFA00000, LENGTH = 0xC000 + l1_data : ORIGIN = 0xFF900000, LENGTH = 0x4000 + } + +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; /*0x1000;*/ + .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) } + . = CFG_MONITOR_BASE; + .text : + { + /* WARNING - the following is hand-optimized to fit within */ + /* the sector before the environment sector. If it throws */ + /* an error during compilation remove an object here to get */ + /* it linked after the configuration sector. */ + + cpu/bf537/start.o (.text) + cpu/bf537/start1.o (.text) + cpu/bf537/traps.o (.text) + cpu/bf537/interrupt.o (.text) + cpu/bf537/serial.o (.text) + common/dlmalloc.o (.text) +/* lib_blackfin/bf533_string.o (.text) */ +/* lib_generic/vsprintf.o (.text) */ + lib_generic/crc32.o (.text) +/* lib_generic/zlib.o (.text) */ +/* board/bf537-stamp/bf537-stamp.o (.text) */ + + . = DEFINED(env_offset) ? env_offset : .; + common/environment.o (.text) + + *(EXCLUDE_FILE (board/bf537-stamp/post-memory.o) .text) + *(.fixup) + *(.got1) + } > ram + _etext = .; + PROVIDE (etext = .); + .text_l1 : + { + . = ALIGN(4) ; + _text_l1 = .; + PROVIDE (text_l1 = .); + board/bf537-stamp/post-memory.o (.text) + . = ALIGN(4) ; + _etext_l1 = .; + PROVIDE (etext_l1 = .); + } > l1_code AT > ram + + .rodata : + { + . = ALIGN(4); + *(EXCLUDE_FILE (board/bf537-stamp/post-memory.o) .rodata) + *(EXCLUDE_FILE (board/bf537-stamp/post-memory.o) .rodata1) + *(EXCLUDE_FILE (board/bf537-stamp/post-memory.o) .rodata.str1.4) + *(.eh_frame) + . = ALIGN(4); + } > ram + + . = ALIGN(4); + _erodata = .; + PROVIDE (erodata = .); + .rodata_l1 : + { + . = ALIGN(4) ; + _rodata_l1 = .; + PROVIDE (rodata_l1 = .); + board/bf537-stamp/post-memory.o (.rodata) + board/bf537-stamp/post-memory.o (.rodata1) + board/bf537-stamp/post-memory.o (.rodata.str1.4) + . = ALIGN(4) ; + _erodata_l1 = .; + PROVIDE(erodata_l1 = .); + } > l1_data AT > ram + + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x00FF) & 0xFFFFFF00; + _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 + } > ram + _edata = .; + PROVIDE (edata = .); + + ___u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } > ram + ___u_boot_cmd_end = .; + + + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + + .bss : + { + __bss_start = .; + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } > ram + _end = . ; + PROVIDE (end = .); +} |