diff options
Diffstat (limited to 'board/keymile')
-rw-r--r-- | board/keymile/common/common.c | 523 | ||||
-rw-r--r-- | board/keymile/common/keymile_hdlc_enet.c | 620 | ||||
-rw-r--r-- | board/keymile/common/keymile_hdlc_enet.h | 129 | ||||
-rw-r--r-- | board/keymile/mgcoge/Makefile | 54 | ||||
-rw-r--r-- | board/keymile/mgcoge/config.mk | 24 | ||||
-rw-r--r-- | board/keymile/mgcoge/mgcoge.c | 349 | ||||
-rw-r--r-- | board/keymile/mgcoge/mgcoge_hdlc_enet.c | 276 | ||||
-rw-r--r-- | board/keymile/mgsuvd/Makefile | 48 | ||||
-rw-r--r-- | board/keymile/mgsuvd/config.mk | 28 | ||||
-rw-r--r-- | board/keymile/mgsuvd/mgsuvd.c | 204 | ||||
-rw-r--r-- | board/keymile/mgsuvd/mgsuvd_hdlc_enet.c | 278 | ||||
-rw-r--r-- | board/keymile/mgsuvd/u-boot.lds | 144 |
12 files changed, 2677 insertions, 0 deletions
diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c new file mode 100644 index 0000000..a4cf24c --- /dev/null +++ b/board/keymile/common/common.c @@ -0,0 +1,523 @@ +/* + * (C) Copyright 2008 + * Heiko Schocher, DENX Software Engineering, hs@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 <mpc8260.h> +#include <ioports.h> +#include <malloc.h> +#include <hush.h> + +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) +#include <libfdt.h> +#endif + +#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) +#include <i2c.h> +#endif +#include <asm/io.h> + +extern int i2c_soft_read_pin (void); + +int ivm_calc_crc (unsigned char *buf, int len) +{ + const unsigned short crc_tab[16] = { + 0x0000, 0xCC01, 0xD801, 0x1400, + 0xF001, 0x3C00, 0x2800, 0xE401, + 0xA001, 0x6C00, 0x7800, 0xB401, + 0x5000, 0x9C01, 0x8801, 0x4400}; + + unsigned short crc = 0; /* final result */ + unsigned short r1 = 0; /* temp */ + unsigned char byte = 0; /* input buffer */ + int i; + + /* calculate CRC from array data */ + for (i = 0; i < len; i++) { + byte = buf[i]; + + /* lower 4 bits */ + r1 = crc_tab[crc & 0xF]; + crc = ((crc) >> 4) & 0x0FFF; + crc = crc ^ r1 ^ crc_tab[byte & 0xF]; + + /* upper 4 bits */ + r1 = crc_tab[crc & 0xF]; + crc = (crc >> 4) & 0x0FFF; + crc = crc ^ r1 ^ crc_tab[(byte >> 4) & 0xF]; + } + return crc; +} + +static int ivm_set_value (char *name, char *value) +{ + char tempbuf[256]; + + if (value != NULL) { + sprintf (tempbuf, "%s=%s", name, value); + return set_local_var (tempbuf, 0); + } else { + unset_local_var (name); + } + return 0; +} + +static int ivm_get_value (unsigned char *buf, int len, char *name, int off, + int check) +{ + unsigned short val; + unsigned char valbuf[30]; + + if ((buf[off + 0] != buf[off + 2]) && + (buf[off + 2] != buf[off + 4])) { + printf ("%s Error corrupted %s\n", __FUNCTION__, name); + val = -1; + } else { + val = buf[off + 0] + (buf[off + 1] << 8); + if ((val == 0) && (check == 1)) + val = -1; + } + sprintf ((char *)valbuf, "%x", val); + ivm_set_value (name, (char *)valbuf); + return val; +} + +#define INVENTORYBLOCKSIZE 0x100 +#define INVENTORYDATAADDRESS 0x21 +#define INVENTORYDATASIZE (INVENTORYBLOCKSIZE - INVENTORYDATAADDRESS - 3) + +#define IVM_POS_SHORT_TEXT 0 +#define IVM_POS_MANU_ID 1 +#define IVM_POS_MANU_SERIAL 2 +#define IVM_POS_PART_NUMBER 3 +#define IVM_POS_BUILD_STATE 4 +#define IVM_POS_SUPPLIER_PART_NUMBER 5 +#define IVM_POS_DELIVERY_DATE 6 +#define IVM_POS_SUPPLIER_BUILD_STATE 7 +#define IVM_POS_CUSTOMER_ID 8 +#define IVM_POS_CUSTOMER_PROD_ID 9 +#define IVM_POS_HISTORY 10 +#define IVM_POS_SYMBOL_ONLY 11 + +static char convert_char (char c) +{ + return (c < ' ' || c > '~') ? '.' : c; +} + +static int ivm_findinventorystring (int type, + unsigned char* const string, + unsigned long maxlen, + unsigned char *buf) +{ + int xcode = 0; + unsigned long cr = 0; + unsigned long addr = INVENTORYDATAADDRESS; + unsigned long size = 0; + unsigned long nr = type; + int stop = 0; /* stop on semicolon */ + + memset(string, '\0', maxlen); + switch (type) { + case IVM_POS_SYMBOL_ONLY: + nr = 0; + stop= 1; + break; + default: + nr = type; + stop = 0; + } + + /* Look for the requested number of CR. */ + while ((cr != nr) && (addr < INVENTORYDATASIZE)) { + if ((buf[addr] == '\r')) { + cr++; + } + addr++; + } + + /* the expected number of CR was found until the end of the IVM + * content --> fill string */ + if (addr < INVENTORYDATASIZE) { + /* Copy the IVM string in the corresponding string */ + for (; (buf[addr] != '\r') && + ((buf[addr] != ';') || (!stop)) && + (size < (maxlen - 1) && + (addr < INVENTORYDATASIZE)); addr++) + { + size += sprintf((char *)string + size, "%c", + convert_char (buf[addr])); + } + + /* copy phase is done: check if everything is ok. If not, + * the inventory data is most probably corrupted: tell + * the world there is a problem! */ + if (addr == INVENTORYDATASIZE) { + xcode = -1; + printf ("Error end of string not found\n"); + } else if ((size >= (maxlen - 1)) && + (buf[addr] != '\r')) { + xcode = -1; + printf ("string too long till next CR\n"); + } + } else { + /* some CR are missing... + * the inventory data is most probably corrupted */ + xcode = -1; + printf ("not enough cr found\n"); + } + return xcode; +} + +#define GET_STRING(name, which, len) \ + if (ivm_findinventorystring (which, valbuf, len, buf) == 0) { \ + ivm_set_value (name, (char *)valbuf); \ + } + +static int ivm_check_crc (unsigned char *buf, int block) +{ + unsigned long crc; + unsigned long crceeprom; + + crc = ivm_calc_crc (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2); + crceeprom = (buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 1] + \ + buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN - 2] * 256); + if (crc != crceeprom) { + printf ("Error CRC Block: %d EEprom: calculated: %lx EEprom: %lx\n", + block, crc, crceeprom); + return -1; + } + return 0; +} + +static int ivm_analyze_block2 (unsigned char *buf, int len) +{ + unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; + unsigned long count; + + /* IVM_MacAddress */ + sprintf ((char *)valbuf, "%02X:%02X:%02X:%02X:%02X:%02X", + buf[1], + buf[2], + buf[3], + buf[4], + buf[5], + buf[6]); + ivm_set_value ("IVM_MacAddress", (char *)valbuf); + if (getenv ("ethaddr") == NULL) + setenv ((char *)"ethaddr", (char *)valbuf); + /* IVM_MacCount */ + count = (buf[10] << 24) + + (buf[11] << 16) + + (buf[12] << 8) + + buf[13]; + if (count == 0xffffffff) + count = 1; + sprintf ((char *)valbuf, "%lx", count); + ivm_set_value ("IVM_MacCount", (char *)valbuf); + return 0; +} + +int ivm_analyze_eeprom (unsigned char *buf, int len) +{ + unsigned short val; + unsigned char valbuf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN]; + unsigned char *tmp; + + if (ivm_check_crc (buf, 0) != 0) + return -1; + + ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_BoardId", 0, 1); + val = ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_HWKey", 6, 1); + if (val != 0xffff) { + sprintf ((char *)valbuf, "%x", ((val /100) % 10)); + ivm_set_value ("IVM_HWVariant", (char *)valbuf); + sprintf ((char *)valbuf, "%x", (val % 100)); + ivm_set_value ("IVM_HWVersion", (char *)valbuf); + } + ivm_get_value (buf, CONFIG_SYS_IVM_EEPROM_PAGE_LEN, "IVM_Functions", 12, 0); + + GET_STRING("IVM_Symbol", IVM_POS_SYMBOL_ONLY, 8) + GET_STRING("IVM_DeviceName", IVM_POS_SHORT_TEXT, 64) + tmp = (unsigned char *) getenv("IVM_DeviceName"); + if (tmp) { + int len = strlen ((char *)tmp); + int i = 0; + + while (i < len) { + if (tmp[i] == ';') { + ivm_set_value ("IVM_ShortText", (char *)&tmp[i + 1]); + break; + } + i++; + } + if (i >= len) + ivm_set_value ("IVM_ShortText", NULL); + } else { + ivm_set_value ("IVM_ShortText", NULL); + } + GET_STRING("IVM_ManufacturerID", IVM_POS_MANU_ID, 32) + GET_STRING("IVM_ManufacturerSerialNumber", IVM_POS_MANU_SERIAL, 20) + GET_STRING("IVM_ManufacturerPartNumber", IVM_POS_PART_NUMBER, 32) + GET_STRING("IVM_ManufacturerBuildState", IVM_POS_BUILD_STATE, 32) + GET_STRING("IVM_SupplierPartNumber", IVM_POS_SUPPLIER_PART_NUMBER, 32) + GET_STRING("IVM_DelieveryDate", IVM_POS_DELIVERY_DATE, 32) + GET_STRING("IVM_SupplierBuildState", IVM_POS_SUPPLIER_BUILD_STATE, 32) + GET_STRING("IVM_CustomerID", IVM_POS_CUSTOMER_ID, 32) + GET_STRING("IVM_CustomerProductID", IVM_POS_CUSTOMER_PROD_ID, 32) + + if (ivm_check_crc (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], 2) != 0) + return -2; + ivm_analyze_block2 (&buf[CONFIG_SYS_IVM_EEPROM_PAGE_LEN * 2], CONFIG_SYS_IVM_EEPROM_PAGE_LEN); + + return 0; +} + +int ivm_read_eeprom (void) +{ + I2C_MUX_DEVICE *dev = NULL; + uchar i2c_buffer[CONFIG_SYS_IVM_EEPROM_MAX_LEN]; + uchar *buf; + unsigned dev_addr = CONFIG_SYS_IVM_EEPROM_ADR; + + /* First init the Bus, select the Bus */ +#if defined(CONFIG_SYS_I2C_IVM_BUS) + dev = i2c_mux_ident_muxstring ((uchar *)CONFIG_SYS_I2C_IVM_BUS); +#else + buf = (unsigned char *) getenv ("EEprom_ivm"); + if (buf != NULL) + dev = i2c_mux_ident_muxstring (buf); +#endif + if (dev == NULL) { + printf ("Error couldnt add Bus for IVM\n"); + return -1; + } + i2c_set_bus_num (dev->busid); + + buf = (unsigned char *) getenv ("EEprom_ivm_addr"); + if (buf != NULL) + dev_addr = simple_strtoul ((char *)buf, NULL, 16); + + if (eeprom_read (dev_addr, 0, i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN) != 0) { + printf ("Error reading EEprom\n"); + return -2; + } + + return ivm_analyze_eeprom (i2c_buffer, CONFIG_SYS_IVM_EEPROM_MAX_LEN); +} + +#if defined(CONFIG_SYS_I2C_INIT_BOARD) +#define DELAY_ABORT_SEQ 62 +#define DELAY_HALF_PERIOD (500 / (CONFIG_SYS_I2C_SPEED / 1000)) + +#if defined(CONFIG_MGCOGE) +#define SDA_MASK 0x00010000 +#define SCL_MASK 0x00020000 +static void set_pin (int state, unsigned long mask) +{ + volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3); + + if (state) + iop->pdat |= (mask); + else + iop->pdat &= ~(mask); + + iop->pdir |= (mask); +} + +static int get_pin (unsigned long mask) +{ + volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3); + + iop->pdir &= ~(mask); + return (0 != (iop->pdat & (mask))); +} + +static void set_sda (int state) +{ + set_pin (state, SDA_MASK); +} + +static void set_scl (int state) +{ + set_pin (state, SCL_MASK); +} + +static int get_sda (void) +{ + return get_pin (SDA_MASK); +} + +static int get_scl (void) +{ + return get_pin (SCL_MASK); +} + +#if defined(CONFIG_HARD_I2C) +static void setports (int gpio) +{ + volatile ioport_t *iop = ioport_addr ((immap_t *)CONFIG_SYS_IMMR, 3); + + if (gpio) { + iop->ppar &= ~(SDA_MASK | SCL_MASK); + iop->podr &= ~(SDA_MASK | SCL_MASK); + } else { + iop->ppar |= (SDA_MASK | SCL_MASK); + iop->pdir &= ~(SDA_MASK | SCL_MASK); + iop->podr |= (SDA_MASK | SCL_MASK); + } +} +#endif +#endif + +#if defined(CONFIG_MGSUVD) +static void set_sda (int state) +{ + I2C_SDA(state); +} + +static void set_scl (int state) +{ + I2C_SCL(state); +} + +static int get_sda (void) +{ + return I2C_READ; +} + +static int get_scl (void) +{ + int val; + + *(unsigned short *)(I2C_BASE_DIR) &= ~SCL_CONF; + udelay (1); + val = *(unsigned char *)(I2C_BASE_PORT); + + return ((val & SCL_BIT) == SCL_BIT); +} + +#endif + +static void writeStartSeq (void) +{ + set_sda (1); + udelay (DELAY_HALF_PERIOD); + set_scl (1); + udelay (DELAY_HALF_PERIOD); + set_sda (0); + udelay (DELAY_HALF_PERIOD); + set_scl (0); + udelay (DELAY_HALF_PERIOD); +} + +/* I2C is a synchronous protocol and resets of the processor in the middle + of an access can block the I2C Bus until a powerdown of the full unit is + done. This function toggles the SCL until the SCL and SCA line are + released, but max. 16 times, after this a I2C start-sequence is sent. + This I2C Deblocking mechanism was developed by Keymile in association + with Anatech and Atmel in 1998. + */ +static int i2c_make_abort (void) +{ + int scl_state = 0; + int sda_state = 0; + int i = 0; + int ret = 0; + + if (!get_sda ()) { + ret = -1; + while (i < 16) { + i++; + set_scl (0); + udelay (DELAY_ABORT_SEQ); + set_scl (1); + udelay (DELAY_ABORT_SEQ); + scl_state = get_scl (); + sda_state = get_sda (); + if (scl_state && sda_state) { + ret = 0; + break; + } + } + } + if (ret == 0) { + for (i =0; i < 5; i++) { + writeStartSeq (); + } + } + get_sda (); + return ret; +} + +/** + * i2c_init_board - reset i2c bus. When the board is powercycled during a + * bus transfer it might hang; for details see doc/I2C_Edge_Conditions. + */ +void i2c_init_board(void) +{ +#if defined(CONFIG_HARD_I2C) + volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR ; + volatile i2c8260_t *i2c = (i2c8260_t *)&immap->im_i2c; + + /* disable I2C controller first, otherwhise it thinks we want to */ + /* talk to the slave port... */ + i2c->i2c_i2mod &= ~0x01; + + /* Set the PortPins to GPIO */ + setports (1); +#endif + + /* Now run the AbortSequence() */ + i2c_make_abort (); + +#if defined(CONFIG_HARD_I2C) + /* Set the PortPins back to use for I2C */ + setports (0); +#endif +} +#endif + +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) +int fdt_set_node_and_value (void *blob, + char *nodename, + char *regname, + void *var, + int size) +{ + int ret = 0; + int nodeoffset = 0; + + nodeoffset = fdt_path_offset (blob, nodename); + if (nodeoffset >= 0) { + ret = fdt_setprop (blob, nodeoffset, regname, var, + size); + if (ret < 0) + printf("ft_blob_update(): cannot set %s/%s " + "property err:%s\n", nodename, regname, + fdt_strerror (ret)); + } else { + printf("ft_blob_update(): cannot find %s node " + "err:%s\n", nodename, fdt_strerror (nodeoffset)); + } + return ret; +} +#endif diff --git a/board/keymile/common/keymile_hdlc_enet.c b/board/keymile/common/keymile_hdlc_enet.c new file mode 100644 index 0000000..141371b --- /dev/null +++ b/board/keymile/common/keymile_hdlc_enet.c @@ -0,0 +1,620 @@ +/* + * (C) Copyright 2008 + * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de. + * + * Based in part on cpu/mpc8260/ether_scc.c. + * + * 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 <malloc.h> +#include <net.h> + +#ifdef CONFIG_KEYMILE_HDLC_ENET +#ifdef TEST_IT +#include <command.h> +#endif + +#include "keymile_hdlc_enet.h" + +extern char keymile_slot; /* our slot number in the backplane */ + +/* Allow up to about 50 ms for sending */ +#define TOUT_LOOP 50000 + +/* + * Since, except during initialization, ethact is always HDLC ETHERNET + * while we're in the driver, just use serial_printf() everywhere for + * output. This avoids possible conflicts when netconsole is being + * used. + */ +#define dprintf(fmt, args...) serial_printf(fmt, ##args) + +/* Cannot use the storage from net.c because we allocate larger buffers */ +static volatile uchar MyPktBuf[HDLC_PKTBUFSRX * PKT_MAXBLR_SIZE + PKTALIGN]; +static volatile uchar *MyRxPackets[HDLC_PKTBUFSRX]; /* Receive packet */ + +static unsigned int keymile_rxIdx; /* index of the current RX buffer */ + +static IPaddr_t cachedNumbers[CACHEDNUMBERS]; /* 4 bytes per entry */ +void initCachedNumbers(int); + +/* + * SCC Ethernet Tx and Rx buffer descriptors allocated at the + * immr->udata_bd address on Dual-Port RAM + * Provide for Double Buffering + */ +typedef volatile struct CommonBufferDescriptor { + cbd_t txbd; /* Tx BD */ + cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */ +} RTXBD; + +/* + * This must be extern because it is allocated in DPRAM using CPM-sepcific + * code. + */ +static RTXBD *rtx; + +static int keymile_hdlc_enet_send(struct eth_device *, volatile void *, int); +static int keymile_hdlc_enet_recv(struct eth_device *); +void keymile_hdlc_enet_init_bds(RTXBD *); +extern int keymile_hdlc_enet_init(struct eth_device *, bd_t *); +extern void keymile_hdlc_enet_halt(struct eth_device *); + +/* flags in the buffer descriptor not defined anywhere else */ +#define BD_SC_CT BD_SC_CD +#define BD_SC_CR 0x04 +#define BD_SC_DE 0x80 +#ifndef BD_SC_TC +#define BD_SC_TC ((ushort)0x0400) /* Transmit CRC */ +#endif +#define BD_SC_FIRST BD_SC_TC +#define BD_SC_STATS (BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_CR | BD_SC_CD \ + | BD_SC_OV | BD_SC_DE) + +#if defined(TEST_RX) || defined(TEST_TX) || defined(TEST_IT) +static void hexdump(unsigned char *buf, int len) +{ + int i; + const int bytesPerLine = 32; + + if (len > 4 * bytesPerLine) + len = 4 * bytesPerLine; + dprintf("\t address: %08x\n", (unsigned int)buf); + for (i = 0; i < len; i++) { + if (i % bytesPerLine == 0) + dprintf("%04x: ", (unsigned short)i); + dprintf("%02x ", buf[i]); + if ((i + 1) % bytesPerLine == 0) { + dprintf("\n"); + continue; + } + if ((i + 1) % 8 == 0) + printf(" "); + } + if (len % bytesPerLine) + dprintf("\n"); +} +#endif + +int keymile_hdlc_enet_initialize(bd_t *bis) +{ + struct eth_device *dev; + + dev = (struct eth_device *) malloc(sizeof *dev); + memset(dev, 0, sizeof *dev); +#ifdef TEST_IT + seth = dev; +#endif + + sprintf(dev->name, "HDLC ETHERNET"); + dev->init = keymile_hdlc_enet_init; + dev->halt = keymile_hdlc_enet_halt; + dev->send = keymile_hdlc_enet_send; + dev->recv = keymile_hdlc_enet_recv; + + eth_register(dev); + + return 1; +} + +/* + * This is called from the board-specific driver after rtx is allocated. + */ +void keymile_hdlc_enet_init_bds(RTXBD *board_rtx) +{ + volatile cbd_t *bdp; + int i; + + rtx = board_rtx; + keymile_rxIdx = 0; + /* + * Initialize the buffer descriptors. + */ + bdp = &rtx->txbd; + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp->cbd_sc = BD_SC_WRAP; + + /* + * Setup RX packet buffers, aligned correctly. + * Borrowed from net/net.c. + */ + MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1); + MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN; + for (i = 1; i < HDLC_PKTBUFSRX; i++) + MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE; + + bdp = &rtx->rxbd[0]; + for (i = 0; i < HDLC_PKTBUFSRX; i++) { + bdp->cbd_sc = BD_SC_EMPTY; + /* Leave space at the start for INET header. */ + bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] + + INET_HDR_ALIGN); + bdp++; + } + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; +} + +/* + * This returns the current port number for NETCONSOLE. If nc_port + * in netconsole.c weren't declared static we wouldn't need this. + */ +static short get_netcons_port(void) +{ + char *p; + short nc_port; + + nc_port = 6666; /* default */ + + p = getenv("ncip"); + if (p != NULL) { + p = strchr(p, ':'); + if (p != NULL) + nc_port = simple_strtoul(p + 1, NULL, 10); + } + + return htons(nc_port); +} + +/* + * Read the port numbers from the variables + */ +void initCachedNumbers(int verbose) +{ + char *str; + ushort port; + + /* already in network order */ + cachedNumbers[IP_ADDR] = getenv_IPaddr("ipaddr"); + /* already in network order */ + cachedNumbers[IP_SERVER] = getenv_IPaddr("serverip"); + str = getenv("tftpsrcp"); + if (str != NULL) { + /* avoid doing htons() again and again */ + port = htons((ushort)simple_strtol(str, NULL, 10)); + cachedNumbers[TFTP_SRC_PORT] = port; + } else + /* this can never be a valid port number */ + cachedNumbers[TFTP_SRC_PORT] = (ulong)-1; + str = getenv("tftpdstp"); + if (str != NULL) { + /* avoid doing htons() again and again */ + port = htons((ushort)simple_strtol(str, NULL, 10)); + cachedNumbers[TFTP_DST_PORT] = port; + } else + /* this is the default value */ + cachedNumbers[TFTP_DST_PORT] = htons(WELL_KNOWN_PORT); + /* already in network order */ + cachedNumbers[NETCONS_PORT] = get_netcons_port(); + if (verbose) { + dprintf("\nIP Number Initialization:\n"); + dprintf(" ip address %08lx\n", cachedNumbers[IP_ADDR]); + dprintf(" server ip address %08lx\n", + cachedNumbers[IP_SERVER]); + dprintf(" tftp client port %ld\n", + cachedNumbers[TFTP_SRC_PORT]); + dprintf(" tftp server port %ld\n", + cachedNumbers[TFTP_DST_PORT]); + dprintf(" netcons port %ld\n", + cachedNumbers[NETCONS_PORT]); + dprintf(" slot number (hex) %02x\n", keymile_slot); + } +} + +static void keymile_hdlc_enet_doarp(volatile void *packet, int len) +{ + ARP_t *arp; + IPaddr_t src_ip; /* U-Boot's IP */ + IPaddr_t dest_ip; /* the mgcoge's IP */ + unsigned char *packet_copy = malloc(len); + + /* + * Handling an ARP request means that a new transfer has started. + * Update our cached parameters now. + */ + initCachedNumbers(0); /* may reinit port numbers */ + + /* special handling required for ARP */ + arp = (ARP_t *)(packet + ETHER_HDR_SIZE); + /* + * XXXX + * This is pretty dirty! NetReceive only uses + * a few fields when handling an ARP reply, so + * we only modify those here. This could + * result in catastrophic failure at a later + * time if the handler is modified! + */ + arp->ar_op = htons(ARPOP_REPLY); + /* save his/our IP */ + src_ip = NetReadIP(&arp->ar_data[6]); + dest_ip = NetReadIP(&arp->ar_data[16]); + /* copy target IP to source IP */ + NetCopyIP(&arp->ar_data[6], &dest_ip); + /* copy our IP to the right place */ + NetCopyIP(&arp->ar_data[16], &src_ip); + /* always use 0x7f as the MAC for the coge */ + arp->ar_data[0] = HDLC_UACUA; + /* + * copy the packet + * if NetReceive wants to write to stdout, it may overwrite packet + * especially if stdout is set to nc! + * + * However, if the malloc() above fails then we can still try the + * original packet, rather than causing the transfer to fail. + */ + if (packet_copy != NULL) { + memcpy(packet_copy, (char *)packet, len); + NetReceive(packet_copy, len); + free(packet_copy); + } else + NetReceive(packet, len); +} + +/* + * NOTE all callers ignore the returned value! + * At the moment this only handles ARP Requests, TFTP and NETCONSOLE. + */ +static int keymile_hdlc_enet_send(struct eth_device *dev, volatile void *packet, + int len) +{ + int j; + uint data_addr; + int data_len; + struct icn_hdr header; + struct icn_frame *frame; + Ethernet_t *et; + ARP_t *arp; + IP_t *ip; + + if (len > (MAX_FRAME_LENGTH - sizeof(header))) + return -1; + + frame = NULL; + et = NULL; + arp = NULL; + ip = NULL; + + j = 0; + while ((rtx->txbd.cbd_sc & BD_SC_READY) && (j < TOUT_LOOP)) { + /* will also trigger Wd if needed, but maybe too often */ + udelay(1); + j++; + } + if (j >= TOUT_LOOP) { + dprintf("TX not ready sc %x\n", rtx->txbd.cbd_sc); + return -1; + } + + /* + * First check for an ARP Request since this requires special handling. + */ + if (len >= (ARP_HDR_SIZE + ETHER_HDR_SIZE)) { + et = (Ethernet_t *)packet; + arp = (ARP_t *)(((char *)et) + ETHER_HDR_SIZE); + /* ARP and REQUEST? */ + if (et->et_protlen == PROT_ARP && + arp->ar_op == htons(ARPOP_REQUEST)) { + /* just short-circuit the request on the U-Boot side */ + keymile_hdlc_enet_doarp(packet, len); + return 0; + } + } + + /* + * GJ - I suppose the assumption here that len will always be + * > INET_HDR_SIZE is alright as long as the network stack + * isn't changed. + * Do not send INET header. + */ + data_len = len + sizeof(header) - INET_HDR_SIZE; + frame = (struct icn_frame *) (((char *)packet) + INET_HDR_SIZE - + sizeof(header)); + +#ifdef TEST_TX + printf("frame: %08x, ", frame); + hexdump((unsigned char *)packet, data_len + INET_HDR_SIZE); +#endif + + data_addr = (uint)frame; + if (len >= (IP_HDR_SIZE + ETHER_HDR_SIZE)) + ip = (IP_t *)(packet + ETHER_HDR_SIZE); + /* Is it TFTP? TFTP always uses UDP and the cached dport */ + if (ip != NULL && ip->ip_p == IPPROTO_UDP && ip->udp_dst == + (ushort)cachedNumbers[TFTP_DST_PORT]) { + /* just in case the port wasn't set in the environment */ + if (cachedNumbers[TFTP_SRC_PORT] == (ulong)-1) + cachedNumbers[TFTP_SRC_PORT] = ip->udp_src; + frame->hdr.application = MGS_TFTP; + } + /* + * Is it NETCONSOLE? NETCONSOLE always uses UDP. + */ + else if (ip != NULL && ip->ip_p == IPPROTO_UDP + && ip->udp_dst == (ushort)cachedNumbers[NETCONS_PORT]) { + frame->hdr.application = MGS_NETCONS; + } else { + /* reject unknown packets */ + /* may do some check on frame->hdr.application */ + dprintf("Unknown packet type in %s, rejected\n", + __func__); + return -1; + } + /* + * Could extract the target's slot ID from its MAC here, + * but u-boot only wants to talk to the active server. + * + * avoid setting new source address when moving to another slot + */ + frame->hdr.src_addr = keymile_slot; + frame->hdr.dest_addr = HDLC_UACUA; +#ifdef TEST_TX + { + dprintf("TX: "); + hexdump((unsigned char *)data_addr, data_len); + } +#endif + + flush_cache(data_addr, data_len); + rtx->txbd.cbd_bufaddr = data_addr; + rtx->txbd.cbd_datlen = data_len; + rtx->txbd.cbd_sc |= (BD_SC_READY | BD_SC_TC | BD_SC_LAST | BD_SC_WRAP); + + while ((rtx->txbd.cbd_sc & BD_SC_READY) && (j < TOUT_LOOP)) { + /* will also trigger Wd if needed, but maybe too often */ + udelay(1); + j++; + } + if (j >= TOUT_LOOP) + dprintf("TX timeout\n"); +#ifdef ET_DEBUG + dprintf("cycles: %d status: %x\n", j, rtx->txbd.cbd_sc); +#endif + j = (rtx->txbd.cbd_sc & BD_SC_STATS); /* return only status bits */ + return j; +} + +/* + * During a receive, the RxIdx points to the current incoming buffer. + * When we update through the ring, if the next incoming buffer has + * not been given to the system, we just set the empty indicator, + * effectively tossing the packet. + */ +static int keymile_hdlc_enet_recv(struct eth_device *dev) +{ + int length; + unsigned char app; + struct icn_frame *fp; + Ethernet_t *ep; + IP_t *ip; + + for (;;) { + if (rtx->rxbd[keymile_rxIdx].cbd_sc & BD_SC_EMPTY) { + length = -1; + break; /* nothing received - leave for() loop */ + } + + length = rtx->rxbd[keymile_rxIdx].cbd_datlen; +#ifdef TEST_RX + dprintf("packet %d bytes long\n", length); +#endif + + /* + * BD_SC_BR -> LG bit + * BD_SC_FR -> NO bit + * BD_SC_PR -> AB bit + * BD_SC_NAK -> CR bit + * 0x80 -> DE bit + */ + if (rtx->rxbd[keymile_rxIdx].cbd_sc & BD_SC_STATS) { +#ifdef ET_DEBUG + dprintf("err: %x\n", rtx->rxbd[keymile_rxIdx].cbd_sc); +#endif + } else if (length > MAX_FRAME_LENGTH) { /* can't happen */ +#ifdef ET_DEBUG + dprintf("err: packet too big\n"); +#endif + } else { + fp = (struct icn_frame *)(MyRxPackets[keymile_rxIdx] + + INET_HDR_ALIGN - INET_HDR_SIZE); +#ifdef TEST_RX + dprintf("RX %d: ", keymile_rxIdx); + hexdump((unsigned char *)MyRxPackets[keymile_rxIdx], + INET_HDR_ALIGN + INET_HDR_SIZE + 4); +#endif + /* copy icn header to the beginning */ + memcpy(fp, ((char *)fp + INET_HDR_SIZE), + sizeof(struct icn_hdr)); + app = fp->hdr.application; + if (app == MGS_NETCONS || app == MGS_TFTP) { + struct icn_hdr *ih = &fp->hdr; + unsigned char icn_src_addr = ih->src_addr; + unsigned char icn_dest_addr = ih->dest_addr; + + /* + * expand header by INET_HDR_SIZE + */ + length += INET_HDR_SIZE; + /* initalize header */ + memset((char *)fp->data, 0x00, INET_HDR_SIZE); + ep = (Ethernet_t *)fp->data; + /* set MACs */ + ep->et_dest[0] = icn_dest_addr; + ep->et_src[0] = icn_src_addr; + ep->et_protlen = htons(PROT_IP); + /* set ip stuff */ + ip = (IP_t *)(fp->data + ETHER_HDR_SIZE); + /* set ip addresses */ + ip->ip_src = cachedNumbers[IP_SERVER]; + ip->ip_dst = cachedNumbers[IP_ADDR]; + /* ip length */ + ip->ip_len = htons(length - ETHER_HDR_SIZE - + REMOVE); + /* ip proto */ + ip->ip_p = IPPROTO_UDP; + switch (app) { + case MGS_TFTP: + /* swap src/dst port numbers */ + ip->udp_src = (ushort) + cachedNumbers[TFTP_DST_PORT]; + ip->udp_dst = (ushort) + cachedNumbers[TFTP_SRC_PORT]; + ip->udp_len = ip->ip_len - + IP_HDR_SIZE_NO_UDP; + ip->udp_xsum = 0; + break; + case MGS_NETCONS: + ip->udp_src = (ushort) + cachedNumbers[NETCONS_PORT]; + /* + * in drivers/net/netconsole.c src port + * equals dest port + */ + ip->udp_dst = ip->udp_src; + ip->udp_len = ip->ip_len - + IP_HDR_SIZE_NO_UDP; + ip->udp_xsum = 0; + break; + } + /* ip version */ + ip->ip_hl_v = (0x40) | (0x0f & + (IP_HDR_SIZE_NO_UDP / 4)); + ip->ip_tos = 0; + ip->ip_id = 0; + /* flags, fragment offset */ + ip->ip_off = htons(0x4000); + ip->ip_ttl = 255; /* time to live */ + /* have to fixup the checksum */ + ip->ip_sum = ~NetCksum((uchar *)ip, + IP_HDR_SIZE_NO_UDP / 2); + /* + * Pass the packet up to the protocol layers + * but remove dest_addr, src_addr, application + * and the CRC. + */ +#ifdef TEST_RX + hexdump((unsigned char *)fp->data, + INET_HDR_SIZE + 4); +#endif + NetReceive(fp->data, length - REMOVE); + } else { + /* + * the other application types are not yet + * supported by u-boot. + */ + /* normally drop it */ +#ifdef TEST_NO + /* send it anyway */ + fp = (struct icn_frame *) + (MyRxPackets[keymile_rxIdx] + + INET_HDR_ALIGN); + NetReceive(fp->data, length - REMOVE); +#endif + } + } + + /* Give the buffer back to the SCC. */ + rtx->rxbd[keymile_rxIdx].cbd_datlen = 0; + + /* wrap around buffer index when necessary */ + if ((keymile_rxIdx + 1) >= HDLC_PKTBUFSRX) { + rtx->rxbd[HDLC_PKTBUFSRX - 1].cbd_sc = + (BD_SC_WRAP | BD_SC_EMPTY); + keymile_rxIdx = 0; + } else { + rtx->rxbd[keymile_rxIdx].cbd_sc = BD_SC_EMPTY; + keymile_rxIdx++; + } + } + return length; +} + +#ifdef TEST_IT +/* simple send test routine */ +int hdlc_enet_stest(struct cmd_tbl_s *a, int b, int c, char **d) +{ + unsigned char pkt[2]; + int ret; + + dprintf("enter stest\n"); + /* may have to initialize things */ + if (seth->state != ETH_STATE_ACTIVE) { + /* the bd_t* is not used */ + if (seth->init(seth, NULL) >= 0) + seth->state = ETH_STATE_ACTIVE; + } + pkt[0] = 0xea; + pkt[1] = 0xae; + ret = keymile_hdlc_enet_send(seth, pkt, 2); + dprintf("return from send %x\n", ret); + dprintf("exit stest\n"); + return ret; +} +U_BOOT_CMD( + stest, 1, 1, hdlc_enet_stest, + "stest - simple send test for hdlc_enet\n", + "no arguments\n" +); +/* simple receive test routine */ +int hdlc_enet_rtest(struct cmd_tbl_s *a, int b, int c, char **d) +{ + int ret; + + dprintf("enter rtest\n"); + /* may have to initialize things */ + if (seth->state != ETH_STATE_ACTIVE) { + /* the bd_t* is not used */ + if (seth->init(seth, NULL) >= 0) + seth->state = ETH_STATE_ACTIVE; + } + ret = keymile_hdlc_enet_recv(seth); + dprintf("return from recv %x\n", ret); + dprintf("exit rtest\n"); + return ret; +} +U_BOOT_CMD( + rtest, 1, 1, hdlc_enet_rtest, + "rtest - simple receive test for hdlc_enet\n", + "no arguments\n" +); +#endif + +#endif /* CONFIG_KEYMILE_HDLC_ENET */ diff --git a/board/keymile/common/keymile_hdlc_enet.h b/board/keymile/common/keymile_hdlc_enet.h new file mode 100644 index 0000000..965bd5a --- /dev/null +++ b/board/keymile/common/keymile_hdlc_enet.h @@ -0,0 +1,129 @@ +/* + * (C) Copyright 2008 + * Gary Jennejohn, DENX Software Engineering GmbH, garyj@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 _KEYMILE_HDLC_ENET_H_ +#define _KEYMILE_HDLC_ENET_H_ + +/* Unfortuantely, we have do this to get the flag defines in the cbd_t */ +#ifdef CONFIG_MGSUVD +#include <commproc.h> +#endif +#ifdef CONFIG_MGCOGE +#include <mpc8260.h> +#include <asm/cpm_8260.h> +#endif + +/* + * Defines for the ICN protocol used for communication over HDLC + * on the backplane between MGSUVDs and MGCOGEs. + */ + +/* + * MAC which is reserved for communication (0x00 - 0xff in the last byte, + * which is the slot number) + */ + +/* + * A DLL frame looks like this: + * 8 bit | 8 bit | 8 bit | 8 bit | n * 8 bit| 16 bit| 8 bit + * opening| destination| source | application| data | FCS | closing + * flag | address | address| | | | flag + * (HW) (APP) (APP) (APP) (APP) (HW) (HW) + */ + +/* + * The opening flag, the FCS and the closing flag are set by the hardware so + * they are not reflected in this struct. + */ +struct icn_hdr { + unsigned char dest_addr; + unsigned char src_addr; + unsigned char application; +} __attribute__((packed)); + +#define ICNHDR_LEN (sizeof(struct icn_hdr)) +#define CRC_LEN (sizeof(short)) +/* bytes to remove from packet before sending it upstream */ +#define REMOVE (ICNHDR_LEN + CRC_LEN) + +struct icn_frame { + struct icn_hdr hdr; + unsigned char data[0]; /* a place holder */ +} __attribute__((packed)); + +/* Address field */ +#define HDLC_UUA 0x00 /* Unicast Unit Address */ +#define HDLC_UUA_MASK 0x3f /* the last 6 bits contain the slot number */ +#define SET_HDLC_UUA(x) ((HDLC_UUA | ((x) & HDLC_UUA_MASK))) +#define HDLC_UACUA 0x7f /* Unicast Active Control Unit Address */ +#define HDLC_BCAST 0xff /* broadcast */ + +/* Application field */ +#define MGS_UUSP 0x00 +#define MGS_UREP 0x01 +#define MGS_IUP 0x02 +#define MGS_UTA 0x03 +#define MGS_MDS 0x04 +#define MGS_ITIME 0x05 +/* added by DENX */ +#define MGS_NETCONS 0x06 /* netconsole */ +#define MGS_TFTP 0x07 + +/* Useful defines for buffer sizes, etc. */ +#define HDLC_PKTBUFSRX 32 +#define MAX_FRAME_LENGTH 1500 /* ethernet frame size */ + /* 14 + 28 */ +#define INET_HDR_SIZE (ETHER_HDR_SIZE + IP_HDR_SIZE) +#define INET_HDR_ALIGN (((INET_HDR_SIZE + PKTALIGN - 1) / PKTALIGN) * PKTALIGN) +/* INET_HDR_SIZE is stripped off */ +#define PKT_MAXBLR_SIZE (MAX_FRAME_LENGTH + INET_HDR_ALIGN) + +/* + * It is too slow to read always the port numbers and IP addresses from the + * string variables. + * cachedNumbers is meant to cache it. + * THIS IS ONLY A SPEED IMPROVEMENT! + */ +enum { + IP_ADDR = 0, /* getenv_IPaddr("serverip"); */ + IP_SERVER, /* getenv_IPaddr("ipaddr"); */ + TFTP_SRC_PORT, /* simple_strtol(getenv("tftpsrcp"), NULL, 10); */ + TFTP_DST_PORT, /* simple_strtol(getenv("tftpdstp"), NULL, 10); */ + NETCONS_PORT, /* simple_strtol(getenv("ncip"), NULL, 10); */ + CACHEDNUMBERS +}; + +#define WELL_KNOWN_PORT 69 /* Well known TFTP port # */ + +/* define this to create a test commend (htest) */ +#undef TEST_IT +#ifdef TEST_IT +/* have to save a copy of the eth_device for the test command's use */ +struct eth_device *seth; +#endif +/* define this for outputting of received packets */ +#undef TEST_RX +/* define this for outputting of packets being sent */ +#undef TEST_TX + +#endif /* _KEYMILE_HDLC_ENET_H_ */ diff --git a/board/keymile/mgcoge/Makefile b/board/keymile/mgcoge/Makefile new file mode 100644 index 0000000..2774a70 --- /dev/null +++ b/board/keymile/mgcoge/Makefile @@ -0,0 +1,54 @@ +# +# (C) Copyright 2001-2007 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk +ifneq ($(OBJTREE),$(SRCTREE)) +$(shell mkdir -p $(obj)../common) +endif + +LIB = $(obj)lib$(BOARD).a + +COBJS := $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \ + mgcoge_hdlc_enet.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +clean: + rm -f $(SOBJS) $(OBJS) + +distclean: clean + rm -f $(LIB) core *.bak $(obj).depend + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/keymile/mgcoge/config.mk b/board/keymile/mgcoge/config.mk new file mode 100644 index 0000000..143bc9f --- /dev/null +++ b/board/keymile/mgcoge/config.mk @@ -0,0 +1,24 @@ +# +# (C) Copyright 2007 +# Heiko Schocher, DENX Software Engineering, hs@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 = 0xFE000000 diff --git a/board/keymile/mgcoge/mgcoge.c b/board/keymile/mgcoge/mgcoge.c new file mode 100644 index 0000000..3683417 --- /dev/null +++ b/board/keymile/mgcoge/mgcoge.c @@ -0,0 +1,349 @@ +/* + * (C) Copyright 2007 - 2008 + * Heiko Schocher, DENX Software Engineering, hs@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 <mpc8260.h> +#include <ioports.h> +#include <malloc.h> +#include <asm/io.h> + +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) +#include <libfdt.h> +#endif + +#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C) +#include <i2c.h> +#endif + +extern int ivm_read_eeprom (void); +/* + * I/O Port configuration table + * + * if conf is 1, then that port pin will be configured at boot time + * according to the five values podr/pdir/ppar/psor/pdat for that entry + */ +const iop_conf_t iop_conf_tab[4][32] = { + + /* Port A */ + { /* conf ppar psor pdir podr pdat */ + /* PA31 */ { 0, 0, 0, 0, 0, 0 }, /* PA31 */ + /* PA30 */ { 0, 0, 0, 0, 0, 0 }, /* PA30 */ + /* PA29 */ { 0, 0, 0, 0, 0, 0 }, /* PA29 */ + /* PA28 */ { 0, 0, 0, 0, 0, 0 }, /* PA28 */ + /* PA27 */ { 0, 0, 0, 0, 0, 0 }, /* PA27 */ + /* PA26 */ { 0, 0, 0, 0, 0, 0 }, /* PA26 */ + /* PA25 */ { 0, 0, 0, 0, 0, 0 }, /* PA25 */ + /* PA24 */ { 0, 0, 0, 0, 0, 0 }, /* PA24 */ + /* PA23 */ { 0, 0, 0, 0, 0, 0 }, /* PA23 */ + /* PA22 */ { 0, 0, 0, 0, 0, 0 }, /* PA22 */ + /* PA21 */ { 0, 0, 0, 0, 0, 0 }, /* PA21 */ + /* PA20 */ { 0, 0, 0, 0, 0, 0 }, /* PA20 */ + /* PA19 */ { 0, 0, 0, 0, 0, 0 }, /* PA19 */ + /* PA18 */ { 0, 0, 0, 0, 0, 0 }, /* PA18 */ + /* PA17 */ { 0, 0, 0, 0, 0, 0 }, /* PA17 */ + /* PA16 */ { 0, 0, 0, 0, 0, 0 }, /* PA16 */ + /* PA15 */ { 0, 0, 0, 0, 0, 0 }, /* PA15 */ + /* PA14 */ { 0, 0, 0, 0, 0, 0 }, /* PA14 */ + /* PA13 */ { 0, 0, 0, 0, 0, 0 }, /* PA13 */ + /* PA12 */ { 0, 0, 0, 0, 0, 0 }, /* PA12 */ + /* PA11 */ { 0, 0, 0, 0, 0, 0 }, /* PA11 */ + /* PA10 */ { 0, 0, 0, 0, 0, 0 }, /* PA10 */ + /* PA9 */ { 1, 1, 0, 1, 0, 0 }, /* SMC2 TxD */ + /* PA8 */ { 1, 1, 0, 0, 0, 0 }, /* SMC2 RxD */ + /* PA7 */ { 0, 0, 0, 0, 0, 0 }, /* PA7 */ + /* PA6 */ { 0, 0, 0, 0, 0, 0 }, /* PA6 */ + /* PA5 */ { 0, 0, 0, 0, 0, 0 }, /* PA5 */ + /* PA4 */ { 0, 0, 0, 0, 0, 0 }, /* PA4 */ + /* PA3 */ { 0, 0, 0, 0, 0, 0 }, /* PA3 */ + /* PA2 */ { 0, 0, 0, 0, 0, 0 }, /* PA2 */ + /* PA1 */ { 0, 0, 0, 0, 0, 0 }, /* PA1 */ + /* PA0 */ { 0, 0, 0, 0, 0, 0 } /* PA0 */ + }, + + /* Port B */ + { /* conf ppar psor pdir podr pdat */ + /* PB31 */ { 0, 0, 0, 0, 0, 0 }, /* PB31 */ + /* PB30 */ { 0, 0, 0, 0, 0, 0 }, /* PB30 */ + /* PB29 */ { 0, 0, 0, 0, 0, 0 }, /* PB29 */ + /* PB28 */ { 0, 0, 0, 0, 0, 0 }, /* PB28 */ + /* PB27 */ { 0, 0, 0, 0, 0, 0 }, /* PB27 */ + /* PB26 */ { 0, 0, 0, 0, 0, 0 }, /* PB26 */ + /* PB25 */ { 0, 0, 0, 0, 0, 0 }, /* PB25 */ + /* PB24 */ { 0, 0, 0, 0, 0, 0 }, /* PB24 */ + /* PB23 */ { 0, 0, 0, 0, 0, 0 }, /* PB23 */ + /* PB22 */ { 0, 0, 0, 0, 0, 0 }, /* PB22 */ + /* PB21 */ { 0, 0, 0, 0, 0, 0 }, /* PB21 */ + /* PB20 */ { 0, 0, 0, 0, 0, 0 }, /* PB20 */ + /* PB19 */ { 0, 0, 0, 0, 0, 0 }, /* PB19 */ + /* PB18 */ { 0, 0, 0, 0, 0, 0 }, /* PB18 */ + /* PB17 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB16 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB15 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB14 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB13 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB12 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB11 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB10 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB9 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB8 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB7 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB6 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB5 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB4 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB3 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB2 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB1 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PB0 */ { 0, 0, 0, 0, 0, 0 } /* non-existent */ + }, + + /* Port C */ + { /* conf ppar psor pdir podr pdat */ + /* PC31 */ { 0, 0, 0, 0, 0, 0 }, /* PC31 */ + /* PC30 */ { 0, 0, 0, 0, 0, 0 }, /* PC30 */ + /* PC29 */ { 0, 0, 0, 0, 0, 0 }, /* PC29 */ + /* PC28 */ { 0, 0, 0, 0, 0, 0 }, /* PC28 */ + /* PC27 */ { 0, 0, 0, 0, 0, 0 }, /* PC27 */ + /* PC26 */ { 0, 0, 0, 0, 0, 0 }, /* PC26 */ + /* PC25 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4 RxClk */ + /* PC24 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4 TxClk */ + /* PC23 */ { 0, 0, 0, 0, 0, 0 }, /* PC23 */ + /* PC22 */ { 0, 0, 0, 0, 0, 0 }, /* PC22 */ + /* PC21 */ { 0, 0, 0, 0, 0, 0 }, /* PC21 */ + /* PC20 */ { 0, 0, 0, 0, 0, 0 }, /* PC20 */ + /* PC19 */ { 0, 0, 0, 0, 0, 0 }, /* PC19 */ + /* PC18 */ { 0, 0, 0, 0, 0, 0 }, /* PC18 */ + /* PC17 */ { 0, 0, 0, 0, 0, 0 }, /* PC17 */ + /* PC16 */ { 0, 0, 0, 0, 0, 0 }, /* PC16 */ + /* PC15 */ { 0, 0, 0, 0, 0, 0 }, /* PC15 */ + /* PC14 */ { 0, 0, 0, 0, 0, 0 }, /* PC14 */ + /* PC13 */ { 0, 0, 0, 0, 0, 0 }, /* PC13 */ + /* PC12 */ { 0, 0, 0, 0, 0, 0 }, /* PC12 */ + /* PC11 */ { 0, 0, 0, 0, 0, 0 }, /* PC11 */ + /* PC10 */ { 0, 0, 0, 0, 0, 0 }, /* PC10 */ + /* PC9 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4: CTS */ + /* PC8 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4: CD */ + /* PC7 */ { 0, 0, 0, 0, 0, 0 }, /* PC7 */ + /* PC6 */ { 0, 0, 0, 0, 0, 0 }, /* PC6 */ + /* PC5 */ { 0, 0, 0, 0, 0, 0 }, /* PC5 */ + /* PC4 */ { 0, 0, 0, 0, 0, 0 }, /* PC4 */ + /* PC3 */ { 0, 0, 0, 0, 0, 0 }, /* PC3 */ + /* PC2 */ { 0, 0, 0, 0, 0, 0 }, /* PC2 */ + /* PC1 */ { 0, 0, 0, 0, 0, 0 }, /* PC1 */ + /* PC0 */ { 0, 0, 0, 0, 0, 0 }, /* PC0 */ + }, + + /* Port D */ + { /* conf ppar psor pdir podr pdat */ + /* PD31 */ { 0, 0, 0, 0, 0, 0 }, /* PD31 */ + /* PD30 */ { 0, 0, 0, 0, 0, 0 }, /* PD30 */ + /* PD29 */ { 0, 0, 0, 0, 0, 0 }, /* PD29 */ + /* PD28 */ { 0, 0, 0, 0, 0, 0 }, /* PD28 */ + /* PD27 */ { 0, 0, 0, 0, 0, 0 }, /* PD27 */ + /* PD26 */ { 0, 0, 0, 0, 0, 0 }, /* PD26 */ + /* PD25 */ { 0, 0, 0, 0, 0, 0 }, /* PD25 */ + /* PD24 */ { 0, 0, 0, 0, 0, 0 }, /* PD24 */ + /* PD23 */ { 0, 0, 0, 0, 0, 0 }, /* PD23 */ + /* PD22 */ { 1, 1, 0, 0, 0, 0 }, /* SCC4: RXD */ + /* PD21 */ { 1, 1, 0, 1, 0, 0 }, /* SCC4: TXD */ + /* PD20 */ { 1, 1, 0, 1, 0, 0 }, /* SCC4: RTS */ + /* PD19 */ { 0, 0, 0, 0, 0, 0 }, /* PD19 */ + /* PD18 */ { 0, 0, 0, 0, 0, 0 }, /* PD18 */ + /* PD17 */ { 0, 0, 0, 0, 0, 0 }, /* PD17 */ + /* PD16 */ { 0, 0, 0, 0, 0, 0 }, /* PD16 */ +#if defined(CONFIG_HARD_I2C) + /* PD15 */ { 1, 1, 1, 0, 1, 0 }, /* I2C SDA */ + /* PD14 */ { 1, 1, 1, 0, 1, 0 }, /* I2C SCL */ +#else + /* PD15 */ { 1, 0, 0, 0, 1, 1 }, /* PD15 */ + /* PD14 */ { 1, 0, 0, 1, 1, 1 }, /* PD14 */ +#endif + /* PD13 */ { 0, 0, 0, 0, 0, 0 }, /* PD13 */ + /* PD12 */ { 0, 0, 0, 0, 0, 0 }, /* PD12 */ + /* PD11 */ { 0, 0, 0, 0, 0, 0 }, /* PD11 */ + /* PD10 */ { 0, 0, 0, 0, 0, 0 }, /* PD10 */ + /* PD9 */ { 0, 0, 0, 0, 0, 0 }, /* PD9 */ + /* PD8 */ { 0, 0, 0, 0, 0, 0 }, /* PD8 */ + /* PD7 */ { 0, 0, 0, 0, 0, 0 }, /* PD7 */ + /* PD6 */ { 0, 0, 0, 0, 0, 0 }, /* PD6 */ + /* PD5 */ { 0, 0, 0, 0, 0, 0 }, /* PD5 */ + /* PD4 */ { 0, 0, 0, 0, 0, 0 }, /* PD4 */ + /* PD3 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PD2 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PD1 */ { 0, 0, 0, 0, 0, 0 }, /* non-existent */ + /* PD0 */ { 0, 0, 0, 0, 0, 0 } /* non-existent */ + } +}; + +/* Try SDRAM initialization with P/LSDMR=sdmr and ORx=orx + * + * This routine performs standard 8260 initialization sequence + * and calculates the available memory size. It may be called + * several times to try different SDRAM configurations on both + * 60x and local buses. + */ +static long int try_init (volatile memctl8260_t * memctl, ulong sdmr, + ulong orx, volatile uchar * base) +{ + volatile uchar c = 0xff; + volatile uint *sdmr_ptr; + volatile uint *orx_ptr; + ulong maxsize, size; + int i; + + /* We must be able to test a location outsize the maximum legal size + * to find out THAT we are outside; but this address still has to be + * mapped by the controller. That means, that the initial mapping has + * to be (at least) twice as large as the maximum expected size. + */ + maxsize = (1 + (~orx | 0x7fff))/* / 2*/; + + sdmr_ptr = &memctl->memc_psdmr; + orx_ptr = &memctl->memc_or1; + + *orx_ptr = orx; + + /* + * Quote from 8260 UM (10.4.2 SDRAM Power-On Initialization, 10-35): + * + * "At system reset, initialization software must set up the + * programmable parameters in the memory controller banks registers + * (ORx, BRx, P/LSDMR). After all memory parameters are configured, + * system software should execute the following initialization sequence + * for each SDRAM device. + * + * 1. Issue a PRECHARGE-ALL-BANKS command + * 2. Issue eight CBR REFRESH commands + * 3. Issue a MODE-SET command to initialize the mode register + * + * The initial commands are executed by setting P/LSDMR[OP] and + * accessing the SDRAM with a single-byte transaction." + * + * The appropriate BRx/ORx registers have already been set when we + * get here. The SDRAM can be accessed at the address CONFIG_SYS_SDRAM_BASE. + */ + + *sdmr_ptr = sdmr | PSDMR_OP_PREA; + *base = c; + + *sdmr_ptr = sdmr | PSDMR_OP_CBRR; + for (i = 0; i < 8; i++) + *base = c; + + *sdmr_ptr = sdmr | PSDMR_OP_MRW; + *(base + CONFIG_SYS_MRS_OFFS) = c; /* setting MR on address lines */ + + *sdmr_ptr = sdmr | PSDMR_OP_NORM | PSDMR_RFEN; + *base = c; + + size = get_ram_size ((long *)base, maxsize); + *orx_ptr = orx | ~(size - 1); + + return (size); +} + +phys_size_t initdram (int board_type) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + volatile memctl8260_t *memctl = &immap->im_memctl; + + long psize; + + memctl->memc_psrt = CONFIG_SYS_PSRT; + memctl->memc_mptpr = CONFIG_SYS_MPTPR; + +#ifndef CONFIG_SYS_RAMBOOT + /* 60x SDRAM setup: + */ + psize = try_init (memctl, CONFIG_SYS_PSDMR, CONFIG_SYS_OR1, + (uchar *) CONFIG_SYS_SDRAM_BASE); +#endif /* CONFIG_SYS_RAMBOOT */ + + icache_enable (); + + return (psize); +} + +int checkboard(void) +{ + puts ("Board: mgcoge\n"); + + return 0; +} + +/* + * Early board initalization. + */ +int board_early_init_r (void) +{ + /* setup the UPIOx */ + out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x02), 0xc0); + out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x03), 0x15); + return 0; +} + +int hush_init_var (void) +{ + ivm_read_eeprom (); + return 0; +} + +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) +extern int fdt_set_node_and_value (void *blob, + char *nodename, + char *regname, + void *var, + int size); + +/* + * update "memory" property in the blob + */ +void ft_blob_update (void *blob, bd_t *bd) +{ + ulong memory_data[2] = {0}; + ulong flash_data[8] = {0}; + + memory_data[0] = cpu_to_be32 (bd->bi_memstart); + memory_data[1] = cpu_to_be32 (bd->bi_memsize); + fdt_set_node_and_value (blob, "/memory", "reg", memory_data, + sizeof (memory_data)); + + /* update Flash addr, size */ + flash_data[2] = cpu_to_be32 (CONFIG_SYS_FLASH_BASE); + flash_data[3] = cpu_to_be32 (CONFIG_SYS_FLASH_SIZE); + flash_data[4] = cpu_to_be32 (5); + flash_data[5] = cpu_to_be32 (0); + flash_data[6] = cpu_to_be32 (CONFIG_SYS_FLASH_BASE_1); + flash_data[7] = cpu_to_be32 (CONFIG_SYS_FLASH_SIZE_1); + fdt_set_node_and_value (blob, "/localbus", "ranges", flash_data, + sizeof (flash_data)); + /* MAC addr */ + fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address", + bd->bi_enetaddr, sizeof (u8) * 6); +} + +void ft_board_setup (void *blob, bd_t *bd) +{ + ft_cpu_setup (blob, bd); + ft_blob_update (blob, bd); +} +#endif /* defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) */ diff --git a/board/keymile/mgcoge/mgcoge_hdlc_enet.c b/board/keymile/mgcoge/mgcoge_hdlc_enet.c new file mode 100644 index 0000000..34f04f5 --- /dev/null +++ b/board/keymile/mgcoge/mgcoge_hdlc_enet.c @@ -0,0 +1,276 @@ +/* + * (C) Copyright 2008 + * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de. + * + * Based in part on cpu/mpc8260/ether_scc.c. + * + * 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 <malloc.h> +#include <net.h> + +#ifdef CONFIG_KEYMILE_HDLC_ENET + +#include "../common/keymile_hdlc_enet.h" + +char keymile_slot; /* our slot number in the backplane */ + +/* + * Since, except during initialization, ethact is always HDLC ETHERNET + * while we're in the driver, just use serial_printf() everywhere for + * output. This avoids possible conflicts when netconsole is being + * used. + */ +#define dprintf(fmt, args...) serial_printf(fmt, ##args) + +static int already_inited; + +/* + * SCC Ethernet Tx and Rx buffer descriptors allocated at the + * immr->udata_bd address on Dual-Port RAM + * Provide for Double Buffering + */ +typedef volatile struct CommonBufferDescriptor { + cbd_t txbd; /* Tx BD */ + cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */ +} RTXBD; + +static RTXBD *rtx; + +int keymile_hdlc_enet_init(struct eth_device *, bd_t *); +void keymile_hdlc_enet_halt(struct eth_device *); +extern void keymile_hdlc_enet_init_bds(RTXBD *); +extern void initCachedNumbers(int); + +/* Use SCC1 */ +#define CPM_CR_SCC_PAGE CPM_CR_SCC1_PAGE +#define CPM_CR_SCC_SBLOCK CPM_CR_SCC1_SBLOCK +#define CMXSCR_MASK (CMXSCR_GR1|CMXSCR_SC1|\ + CMXSCR_RS1CS_MSK|CMXSCR_TS1CS_MSK) +#define CMXSCR_VALUE (CMXSCR_RS1CS_CLK11|CMXSCR_TS1CS_CLK11) +#define MGC_PROFF_HDLC PROFF_SCC1 +#define MGC_SCC_HDLC 0 /* Index, not number! */ + +int keymile_hdlc_enet_init(struct eth_device *dev, bd_t *bis) +{ + /* int i; */ + uint dpr; + /* volatile cbd_t *bdp; */ + volatile immap_t *im = (immap_t *)CONFIG_SYS_IMMR; + volatile cpm8260_t *cp = &(im->im_cpm); + volatile scc_t *sccp; + volatile scc_hdlc_t *hpr; + volatile iop8260_t *iop; + + if (already_inited) + return 0; + + hpr = (scc_hdlc_t *)(&im->im_dprambase[MGC_PROFF_HDLC]); + sccp = (scc_t *)(&im->im_scc[MGC_SCC_HDLC]); + iop = &im->im_ioport; + + /* + * Disable receive and transmit just in case. + */ + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + /* + * Avoid exhausting DPRAM, which would cause a panic. + */ + if (rtx == NULL) { + /* dpr is an offset into dpram */ + dpr = m8260_cpm_dpalloc(sizeof(RTXBD), 8); + rtx = (RTXBD *)&im->im_dprambase[dpr]; + } + + /* We need the slot number for addressing. */ + keymile_slot = *(char *)(CONFIG_SYS_SLOT_ID_BASE + + CONFIG_SYS_SLOT_ID_OFF) & CONFIG_SYS_SLOT_ID_MASK; + /* + * Be consistent with the Linux driver and set + * only enetaddr[0]. + * + * Always add 1 to the slot number so that + * there are no problems with an ethaddr which + * is all 0s. This should be acceptable because + * a board should never have a slot number of 255, + * which is the broadcast address. The HDLC addressing + * uses only the slot number. + */ + dev->enetaddr[0] = keymile_slot + 1; +#ifdef TEST_IT + dprintf("slot %d\n", keymile_slot); +#endif + + /* use pd30, pd31 pins for TXD1, RXD1 respectively */ + iop->iop_ppard |= (0x80000000 >> 30) | (0x80000000 >> 31); + iop->iop_pdird |= (0x80000000 >> 30); + iop->iop_psord |= (0x80000000 >> 30); + + /* use pc21 as CLK11 */ + iop->iop_pparc |= (0x80000000 >> 21); + iop->iop_pdirc &= ~(0x80000000 >> 21); + iop->iop_psorc &= ~(0x80000000 >> 21); + + /* use pc15 as CTS1 */ + iop->iop_pparc |= (0x80000000 >> 15); + iop->iop_pdirc &= ~(0x80000000 >> 15); + iop->iop_psorc &= ~(0x80000000 >> 15); + + /* + * SI clock routing + * use CLK11 + * this also connects SCC1 to NMSI + */ + im->im_cpmux.cmx_scr = (im->im_cpmux.cmx_scr & ~CMXSCR_MASK) | + CMXSCR_VALUE; + + /* keymile_rxIdx = 0; */ + + /* + * Initialize function code registers for big-endian. + */ + hpr->sh_genscc.scc_rfcr = CPMFCR_EB; + hpr->sh_genscc.scc_tfcr = CPMFCR_EB; + + /* + * Set maximum bytes per receive buffer. + */ + hpr->sh_genscc.scc_mrblr = MAX_FRAME_LENGTH; + + /* Setup CRC generator values for HDLC */ + hpr->sh_cmask = 0x0000F0B8; + hpr->sh_cpres = 0x0000FFFF; + + /* Initialize all error counters to 0 */ + hpr->sh_disfc = 0; + hpr->sh_crcec = 0; + hpr->sh_abtsc = 0; + hpr->sh_nmarc = 0; + hpr->sh_retrc = 0; + + /* Set maximum frame length size */ + hpr->sh_mflr = MAX_FRAME_LENGTH; + + /* set to 1 for per frame processing change later if needed */ + hpr->sh_rfthr = 1; + + hpr->sh_hmask = 0xff; + + hpr->sh_haddr2 = SET_HDLC_UUA(keymile_slot); + hpr->sh_haddr3 = hpr->sh_haddr2; + hpr->sh_haddr4 = hpr->sh_haddr2; + /* broadcast */ + hpr->sh_haddr1 = HDLC_BCAST; + + hpr->sh_genscc.scc_rbase = (unsigned int) &rtx->rxbd[0]; + hpr->sh_genscc.scc_tbase = (unsigned int) &rtx->txbd; + +#if 0 + /* + * Initialize the buffer descriptors. + */ + bdp = &rtx->txbd; + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp->cbd_sc = BD_SC_WRAP; + + /* + * Setup RX packet buffers, aligned correctly. + * Borrowed from net/net.c. + */ + MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1); + MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN; + for (i = 1; i < HDLC_PKTBUFSRX; i++) + MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE; + + bdp = &rtx->rxbd[0]; + for (i = 0; i < HDLC_PKTBUFSRX; i++) { + bdp->cbd_sc = BD_SC_EMPTY; + /* Leave space at the start for INET header. */ + bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] + + INET_HDR_ALIGN); + bdp++; + } + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; +#else + keymile_hdlc_enet_init_bds(rtx); +#endif + + /* Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cp->cp_cpcr = mk_cr_cmd(CPM_CR_SCC_PAGE, CPM_CR_SCC_SBLOCK, + 0, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + sccp->scc_gsmrl = SCC_GSMRL_MODE_HDLC; + /* CTSS=1 */ + sccp->scc_gsmrh = SCC_GSMRH_CTSS; + /* NOF=0, RTE=1, DRT=0, BUS=1 */ + sccp->scc_psmr = ((0x8000 >> 6) | (0x8000 >> 10)); + +/* loopback for local testing */ +#ifdef GJTEST + dprintf("LOOPBACK!\n"); + sccp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP; +#endif + + /* + * Disable all interrupts and clear all pending + * events. + */ + sccp->scc_sccm = 0; + sccp->scc_scce = 0xffff; + + /* + * And last, enable the transmit and receive processing. + */ + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + dprintf("%s: HDLC ENET Version 0.3 on SCC%d\n", dev->name, + MGC_SCC_HDLC + 1); + + /* + * We may not get an ARP packet because ARP was already done on + * a different interface, so initialize the cached values now. + */ + initCachedNumbers(1); + + already_inited = 1; + + return 0; +} + +void keymile_hdlc_enet_halt(struct eth_device *dev) +{ +#if 0 /* just return, but keep this for reference */ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + + /* maybe should do a graceful stop here? */ + immr->im_scc[MGC_SCC_HDLC].scc_gsmrl &= + ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif +} + +#endif /* CONFIG_MGCOGE_HDLC_ENET */ diff --git a/board/keymile/mgsuvd/Makefile b/board/keymile/mgsuvd/Makefile new file mode 100644 index 0000000..2c5732d --- /dev/null +++ b/board/keymile/mgsuvd/Makefile @@ -0,0 +1,48 @@ +# +# (C) Copyright 2007 +# Heiko Schocher, DENX Software Engineering, hs@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 +ifneq ($(OBJTREE),$(SRCTREE)) +$(shell mkdir -p $(obj)../common) +endif + +LIB = $(obj)lib$(BOARD).a + +COBJS = $(BOARD).o ../common/common.o ../common/keymile_hdlc_enet.o \ + mgsuvd_hdlc_enet.o + +SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS)) +SOBJS := $(addprefix $(obj),$(SOBJS)) + +$(LIB): $(obj).depend $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/board/keymile/mgsuvd/config.mk b/board/keymile/mgsuvd/config.mk new file mode 100644 index 0000000..8625cea --- /dev/null +++ b/board/keymile/mgsuvd/config.mk @@ -0,0 +1,28 @@ +# +# (C) Copyright 2007 +# Heiko Schocher, DENX Software Engineering, hs@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 +# + +# +# mgsvud boards +# + +TEXT_BASE = 0xf0000000 diff --git a/board/keymile/mgsuvd/mgsuvd.c b/board/keymile/mgsuvd/mgsuvd.c new file mode 100644 index 0000000..3726acf --- /dev/null +++ b/board/keymile/mgsuvd/mgsuvd.c @@ -0,0 +1,204 @@ +/* + * (C) Copyright 2007 + * Heiko Schocher, DENX Software Engineering, hs@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 <mpc8xx.h> +#include <asm/io.h> + +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) +#include <libfdt.h> +#endif + +extern int ivm_read_eeprom (void); + +DECLARE_GLOBAL_DATA_PTR; + +const uint sdram_table[] = +{ + 0x0f07fc04, 0x0ffffc04, 0x00bdfc04, 0x0ff77c00, + 0x1ffffc05, 0xfffffc04, 0xfffffc04, 0xfffffc04, + /* 0x08 Burst Read */ + 0x0f07fc04, 0x0ffffc04, 0x00bdfc04, 0x00fffc00, + 0x00fffc00, 0x00fffc00, 0x0ff77c00, 0x1ffffc05, + /* 0x10 Load mode register */ + 0x0ffffc34, 0x0ff57c04, 0x0ffffc04, 0x1ffffc05, + 0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04, + /* 0x18 Single Write */ + 0x0f07fc04, 0x0ffffc00, 0x00bd7c04, 0x0ffffc04, + 0x0ff77c04, 0x1ffffc05, 0xfffffc04, 0xfffffc04, + /* 0x20 Burst Write */ + 0x0f07fc04, 0x0ffffc00, 0x00bd7c00, 0x00fffc00, + 0x00fffc00, 0x00fffc04, 0x0ffffc04, 0x0ff77c04, + 0x1ffffc05, 0xfffffc04, 0xfffffc04, 0xfffffc04, + 0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04, + /* 0x30 Precharge all and Refresh */ + 0x0ff77c04, 0x0ffffc04, 0x0ff5fc84, 0x0ffffc04, + 0x0ffffc04, 0x0ffffc84, 0x1ffffc05, 0xfffffc04, + 0xfffffc04, 0xfffffc04, 0xfffffc04, 0xfffffc04, + /* 0x3C Exception */ + 0x7ffffc04, 0xfffffc07, 0xfffffc04, 0xfffffc04, +}; + +int checkboard (void) +{ + puts ("Board: Keymile mgsuvd\n"); + return (0); +} + +phys_size_t initdram (int board_type) +{ + volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; + volatile memctl8xx_t *memctl = &immap->im_memctl; + long int size; + + upmconfig (UPMB, (uint *) sdram_table, + sizeof (sdram_table) / sizeof (uint)); + + /* + * Preliminary prescaler for refresh (depends on number of + * banks): This value is selected for four cycles every 62.4 us + * with two SDRAM banks or four cycles every 31.2 us with one + * bank. It will be adjusted after memory sizing. + */ + memctl->memc_mptpr = CONFIG_SYS_MPTPR; + + /* + * The following value is used as an address (i.e. opcode) for + * the LOAD MODE REGISTER COMMAND during SDRAM initialisation. If + * the port size is 32bit the SDRAM does NOT "see" the lower two + * address lines, i.e. mar=0x00000088 -> opcode=0x00000022 for + * MICRON SDRAMs: + * -> 0 00 010 0 010 + * | | | | +- Burst Length = 4 + * | | | +----- Burst Type = Sequential + * | | +------- CAS Latency = 2 + * | +----------- Operating Mode = Standard + * +-------------- Write Burst Mode = Programmed Burst Length + */ + memctl->memc_mar = CONFIG_SYS_MAR; + + /* + * Map controller banks 1 to the SDRAM banks 1 at + * preliminary addresses - these have to be modified after the + * SDRAM size has been determined. + */ + memctl->memc_or1 = CONFIG_SYS_OR1_PRELIM; + memctl->memc_br1 = CONFIG_SYS_BR1_PRELIM; + + memctl->memc_mbmr = CONFIG_SYS_MBMR & (~(MBMR_PTBE)); /* no refresh yet */ + + udelay (200); + + /* perform SDRAM initializsation sequence */ + + memctl->memc_mcr = 0x80802830; /* SDRAM bank 0 */ + udelay (1); + memctl->memc_mcr = 0x80802110; /* SDRAM bank 0 - execute twice */ + udelay (1); + + memctl->memc_mbmr |= MBMR_PTBE; /* enable refresh */ + + udelay (1000); + + /* + * Check Bank 0 Memory Size for re-configuration + * + */ + size = get_ram_size(SDRAM_BASE1_PRELIM, SDRAM_MAX_SIZE); + + udelay (1000); + + debug ("SDRAM Bank 0: %ld MB\n", size >> 20); + + return (size); +} + +/* + * Early board initalization. + */ +int board_early_init_r(void) +{ + /* setup the UPIOx */ + out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x02), 0xc0); + out_8((u8 *)(CONFIG_SYS_PIGGY_BASE + 0x03), 0x35); + return 0; +} + +int hush_init_var (void) +{ + ivm_read_eeprom (); + return 0; +} + +#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) +extern int fdt_set_node_and_value (void *blob, + char *nodename, + char *regname, + void *var, + int size); + +/* + * update "memory" property in the blob + */ +void ft_blob_update (void *blob, bd_t *bd) +{ + ulong brg_data[1] = {0}; + ulong memory_data[2] = {0}; + ulong flash_data[4] = {0}; + + memory_data[0] = cpu_to_be32 (bd->bi_memstart); + memory_data[1] = cpu_to_be32 (bd->bi_memsize); + fdt_set_node_and_value (blob, "/memory", "reg", memory_data, + sizeof (memory_data)); + + flash_data[2] = cpu_to_be32 (bd->bi_flashstart); + flash_data[3] = cpu_to_be32 (bd->bi_flashsize); + fdt_set_node_and_value (blob, "/localbus", "ranges", flash_data, + sizeof (flash_data)); + + /* BRG */ + brg_data[0] = cpu_to_be32 (bd->bi_busfreq); + fdt_set_node_and_value (blob, "/soc/cpm", "brg-frequency", brg_data, + sizeof (brg_data)); + + /* MAC adr */ + fdt_set_node_and_value (blob, "/soc/cpm/ethernet", "mac-address", + bd->bi_enetaddr, sizeof (u8) * 6); +} + +void ft_board_setup(void *blob, bd_t *bd) +{ + ft_cpu_setup (blob, bd); + ft_blob_update (blob, bd); +} +#endif /* defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_LIBFDT) */ + +int i2c_soft_read_pin (void) +{ + int val; + + *(unsigned short *)(I2C_BASE_DIR) &= ~SDA_CONF; + udelay(1); + val = *(unsigned char *)(I2C_BASE_PORT); + + return ((val & SDA_BIT) == SDA_BIT); +} diff --git a/board/keymile/mgsuvd/mgsuvd_hdlc_enet.c b/board/keymile/mgsuvd/mgsuvd_hdlc_enet.c new file mode 100644 index 0000000..9b93131 --- /dev/null +++ b/board/keymile/mgsuvd/mgsuvd_hdlc_enet.c @@ -0,0 +1,278 @@ +/* + * (C) Copyright 2008 + * Gary Jennejohn, DENX Software Engineering GmbH, garyj@denx.de. + * + * Based in part on cpu/mpc8xx/scc.c. + * + * 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> /* commproc.h is included here */ +#include <malloc.h> +#include <net.h> + +#ifdef CONFIG_KEYMILE_HDLC_ENET + +#include "../common/keymile_hdlc_enet.h" + +char keymile_slot; /* our slot number in the backplane */ + +/* + * Since, except during initialization, ethact is always HDLC ETHERNET + * while we're in the driver, just use serial_printf() everywhere for + * output. This avoids possible conflicts when netconsole is being + * used. + */ +#define dprintf(fmt, args...) serial_printf(fmt, ##args) + +static int already_inited; + +/* + * SCC Ethernet Tx and Rx buffer descriptors allocated at the + * immr->udata_bd address on Dual-Port RAM + * Provide for Double Buffering + */ +typedef volatile struct CommonBufferDescriptor { + cbd_t txbd; /* Tx BD */ + cbd_t rxbd[HDLC_PKTBUFSRX]; /* Rx BD */ +} RTXBD; + +static RTXBD *rtx; + +int keymile_hdlc_enet_init(struct eth_device *, bd_t *); +void keymile_hdlc_enet_halt(struct eth_device *); +extern void keymile_hdlc_enet_init_bds(RTXBD *); +extern void initCachedNumbers(int); + +/* Use SCC4 */ +#define MGS_CPM_CR_HDLC CPM_CR_CH_SCC4 +#define MGS_PROFF_HDLC PROFF_SCC4 +#define MGS_SCC_HDLC 3 /* Index, not number! */ + +int keymile_hdlc_enet_init(struct eth_device *dev, bd_t *bis) +{ + /* int i; */ + /* volatile cbd_t *bdp; */ + volatile cpm8xx_t *cp; + volatile scc_t *sccp; + volatile hdlc_pram_t *hpr; + volatile iop8xx_t *iop; + + if (already_inited) + return 0; + + cp = (cpm8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_cpm); + hpr = (hdlc_pram_t *)(&cp->cp_dparam[MGS_PROFF_HDLC]); + sccp = (volatile scc_t *)(&cp->cp_scc[MGS_SCC_HDLC]); + iop = (iop8xx_t *)&(((volatile immap_t *)CONFIG_SYS_IMMR)->im_ioport); + + /* + * Disable receive and transmit just in case. + */ + sccp->scc_gsmrl &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); + +#ifndef CONFIG_SYS_ALLOC_DPRAM +#error "CONFIG_SYS_ALLOC_DPRAM must be defined" +#else + /* + * Avoid exhausting DPRAM, which would cause a panic. + * Actually this isn't really necessary, but leave it here + * for safety's sake. + */ + if (rtx == NULL) { + rtx = (RTXBD *) (cp->cp_dpmem + + dpram_alloc_align(sizeof(RTXBD), 8)); + if (rtx == (RTXBD *)CPM_DP_NOSPACE) + return -1; + memset((void *)rtx, 0, sizeof(RTXBD)); + } +#endif /* !CONFIG_SYS_ALLOC_DPRAM */ + + /* We need the slot number for addressing. */ + keymile_slot = *(char *)(CONFIG_SYS_SLOT_ID_BASE + + CONFIG_SYS_SLOT_ID_OFF) & CONFIG_SYS_SLOT_ID_MASK; + /* + * Be consistent with the Linux driver and set + * only enetaddr[0]. + * + * Always add 1 to the slot number so that + * there are no problems with an ethaddr which + * is all 0s. This should be acceptable because + * a board should never have a slot number of 255, + * which is the broadcast address. The HDLC addressing + * uses only the slot number. + */ + dev->enetaddr[0] = keymile_slot + 1; + +#ifdef TEST_IT + dprintf("slot %d\n", keymile_slot); +#endif + + /* use pa8, pa9 pins for TXD4, RXD4 respectively */ + iop->iop_papar |= ((0x8000 >> 8) | (0x8000 >> 9)); + iop->iop_padir &= ~((0x8000 >> 8) | (0x8000 >> 9)); + iop->iop_paodr &= ~((0x8000 >> 8) | (0x8000 >> 9)); + + /* also use pa0 as CLK8 */ + iop->iop_papar |= 0x8000; + iop->iop_padir &= ~0x8000; + iop->iop_paodr &= ~0x8000; + + /* use pc5 as CTS4 */ + iop->iop_pcpar &= ~(0x8000 >> 5); + iop->iop_pcdir &= ~(0x8000 >> 5); + iop->iop_pcso |= (0x8000 >> 5); + + /* + * SI clock routing + * use CLK8 + * this also connects SCC4 to NMSI + */ + cp->cp_sicr = (cp->cp_sicr & ~0xff000000) | 0x3f000000; + + /* keymile_rxIdx = 0; */ + + /* + * Initialize function code registers for big-endian. + */ + hpr->rfcr = SCC_EB; + hpr->tfcr = SCC_EB; + + /* + * Set maximum bytes per receive buffer. + */ + hpr->mrblr = MAX_FRAME_LENGTH; + + /* Setup CRC generator values for HDLC */ + hpr->c_mask = 0x0000F0B8; + hpr->c_pres = 0x0000FFFF; + + /* Initialize all error counters to 0 */ + hpr->disfc = 0; + hpr->crcec = 0; + hpr->abtsc = 0; + hpr->nmarc = 0; + hpr->retrc = 0; + + /* Set maximum frame length size */ + hpr->mflr = MAX_FRAME_LENGTH; + + /* set to 1 for per frame processing change later if needed */ + hpr->rfthr = 1; + + hpr->hmask = 0xff; + + hpr->haddr2 = SET_HDLC_UUA(keymile_slot); + hpr->haddr3 = hpr->haddr2; + hpr->haddr4 = hpr->haddr2; + /* broadcast */ + hpr->haddr1 = HDLC_BCAST; + + hpr->rbase = (unsigned int) &rtx->rxbd[0]; + hpr->tbase = (unsigned int) &rtx->txbd; + +#if 0 + /* + * Initialize the buffer descriptors. + */ + bdp = &rtx->txbd; + bdp->cbd_sc = 0; + bdp->cbd_bufaddr = 0; + bdp->cbd_sc = BD_SC_WRAP; + + /* + * Setup RX packet buffers, aligned correctly. + * Borrowed from net/net.c. + */ + MyRxPackets[0] = &MyPktBuf[0] + (PKTALIGN - 1); + MyRxPackets[0] -= (ulong)MyRxPackets[0] % PKTALIGN; + for (i = 1; i < HDLC_PKTBUFSRX; i++) + MyRxPackets[i] = MyRxPackets[0] + i * PKT_MAXBLR_SIZE; + + bdp = &rtx->rxbd[0]; + for (i = 0; i < HDLC_PKTBUFSRX; i++) { + bdp->cbd_sc = BD_SC_EMPTY; + /* Leave space at the start for INET header. */ + bdp->cbd_bufaddr = (unsigned int)(MyRxPackets[i] + + INET_HDR_ALIGN); + bdp++; + } + bdp--; + bdp->cbd_sc |= BD_SC_WRAP; +#else + keymile_hdlc_enet_init_bds(rtx); +#endif + + /* Let's re-initialize the channel now. We have to do it later + * than the manual describes because we have just now finished + * the BD initialization. + */ + cp->cp_cpcr = mk_cr_cmd(MGS_CPM_CR_HDLC, CPM_CR_INIT_TRX) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + + sccp->scc_gsmrl = SCC_GSMRL_MODE_HDLC; + /* CTSS=1 */ + sccp->scc_gsmrh = SCC_GSMRH_CTSS; + /* NOF=0, RTE=1, DRT=0, BUS=1 */ + sccp->scc_psmr = ((0x8000 >> 6) | (0x8000 >> 10)); + +/* loopback for local testing */ +#ifdef GJTEST + dprintf("LOOPBACK!\n"); + sccp->scc_gsmrl |= SCC_GSMRL_DIAG_LOOP; +#endif + + /* + * Disable all interrupts and clear all pending + * events. + */ + sccp->scc_sccm = 0; + sccp->scc_scce = 0xffff; + + /* + * And last, enable the transmit and receive processing. + */ + sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + + dprintf("%s: HDLC ENET Version 0.3 on SCC%d\n", dev->name, + MGS_SCC_HDLC + 1); + + /* + * We may not get an ARP packet because ARP was already done on + * a different interface, so initialize the cached values now. + */ + initCachedNumbers(1); + + already_inited = 1; + + return 0; +} + +void keymile_hdlc_enet_halt(struct eth_device *dev) +{ +#if 0 /* just return, but keep this for reference */ + volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR; + + /* maybe should do a graceful stop here? */ + immr->im_cpm.cp_scc[MGS_SCC_HDLC].scc_gsmrl &= + ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT); +#endif +} + +#endif /* CONFIG_KEYMILE_HDLC_ENET */ diff --git a/board/keymile/mgsuvd/u-boot.lds b/board/keymile/mgsuvd/u-boot.lds new file mode 100644 index 0000000..5af36c9 --- /dev/null +++ b/board/keymile/mgsuvd/u-boot.lds @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2000 + * 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) +/* 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 : + { + /* WARNING - the following is hand-optimized to fit within */ + /* the sector layout of our flash chips! XXX FIXME XXX */ + + cpu/mpc8xx/start.o (.text) + cpu/mpc8xx/traps.o (.text) + common/dlmalloc.o (.text) + lib_ppc/ppcstring.o (.text) + lib_generic/vsprintf.o (.text) + lib_generic/crc32.o (.text) + lib_generic/zlib.o (.text) + lib_ppc/cache.o (.text) + lib_ppc/time.o (.text) + + . = DEFINED(env_offset) ? env_offset : .; + common/env_embedded.o (.ppcenv) + + *(.text) + *(.fixup) + *(.got1) + } + _etext = .; + PROVIDE (etext = .); + .rodata : + { + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .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 + } + _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(256); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(256); + __init_end = .; + + __bss_start = .; + .bss (NOLOAD) : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + . = ALIGN(4); + } + _end = . ; + PROVIDE (end = .); +} |