diff options
Diffstat (limited to 'board/evb64260')
29 files changed, 7872 insertions, 0 deletions
diff --git a/board/evb64260/64260.h b/board/evb64260/64260.h new file mode 100755 index 0000000..d106ced --- /dev/null +++ b/board/evb64260/64260.h @@ -0,0 +1,31 @@ +#ifndef __64260_H__ +#define __64260_H__ + +/* CPU Configuration bits */ +#define CPU_CONF_ADDR_MISS_EN (1 << 8) +#define CPU_CONF_AACK_DELAY (1 << 11) +#define CPU_CONF_ENDIANESS (1 << 12) +#define CPU_CONF_PIPELINE (1 << 13) +#define CPU_CONF_TA_DELAY (1 << 15) +#define CPU_CONF_RD_OOO (1 << 16) +#define CPU_CONF_STOP_RETRY (1 << 17) +#define CPU_CONF_MULTI_DECODE (1 << 18) +#define CPU_CONF_DP_VALID (1 << 19) +#define CPU_CONF_PERR_PROP (1 << 22) +#define CPU_CONF_FAST_CLK (1 << 23) +#define CPU_CONF_AACK_DELAY_2 (1 << 25) +#define CPU_CONF_AP_VALID (1 << 26) +#define CPU_CONF_REMAP_WR_DIS (1 << 27) +#define CPU_CONF_CONF_SB_DIS (1 << 28) +#define CPU_CONF_IO_SB_DIS (1 << 29) +#define CPU_CONF_CLK_SYNC (1 << 30) + +/* CPU Master Control bits */ +#define CPU_MAST_CTL_ARB_EN (1 << 8) +#define CPU_MAST_CTL_MASK_BR_1 (1 << 9) +#define CPU_MAST_CTL_M_WR_TRIG (1 << 10) +#define CPU_MAST_CTL_M_RD_TRIG (1 << 11) +#define CPU_MAST_CTL_CLEAN_BLK (1 << 12) +#define CPU_MAST_CTL_FLUSH_BLK (1 << 13) + +#endif /* __64260_H__ */ diff --git a/board/evb64260/Makefile b/board/evb64260/Makefile new file mode 100755 index 0000000..c493d6c --- /dev/null +++ b/board/evb64260/Makefile @@ -0,0 +1,44 @@ +# +# (C) Copyright 2001 +# Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 $(TOPDIR)/config.mk + +LIB = lib$(BOARD).a + +SOBJS = misc.o +OBJS = $(BOARD).o flash.o serial.o memory.o pci.o \ + eth.o eth_addrtbl.o mpsc.o i2c.o \ + sdram_init.o zuma_pbb.o intel_flash.o zuma_pbb_mbox.o + + +$(LIB): .depend $(OBJS) $(SOBJS) + $(AR) crv $@ $(OBJS) $(SOBJS) + +######################################################################### + +.depend: Makefile $(SOBJS:.o=.S) $(OBJS:.o=.c) + $(CC) -M $(CFLAGS) $(SOBJS:.o=.S) $(OBJS:.o=.c) > $@ + +sinclude .depend + +######################################################################### diff --git a/board/evb64260/bootseq.txt b/board/evb64260/bootseq.txt new file mode 100755 index 0000000..391d49a --- /dev/null +++ b/board/evb64260/bootseq.txt @@ -0,0 +1,94 @@ +(cpu/mpc7xxx/start.S) + +start: + b boot_cold + +start_warm: + b boot_warm + + +boot_cold: +boot_warm: + clear bats + init l2 (if enabled) + init altivec (if enabled) + invalidate l2 (if enabled) + setup bats (from defines in config_EVB) + enable_addr_trans: (if MMU enabled) + enable MSR_IR and MSR_DR + jump to in_flash + +in_flash: + enable l1 dcache + gal_low_init: (board/evb64260/sdram_init.S) + config SDRAM (CFG, TIMING, DECODE) + init scratch regs (810 + 814) + + detect DIMM0 (bank 0 only) + config SDRAM_PARA0 to 256/512Mbit + bl sdram_op_mode + detect bank0 width + write scratch reg 810 + config SDRAM_PARA0 with results + config SDRAM_PARA1 with results + + detect DIMM1 (bank 2 only) + config SDRAM_PARA2 to 256/512Mbit + detect bank2 width + write scratch reg 814 + config SDRAM_PARA2 with results + config SDRAM_PARA3 with results + + setup device bus timings/width + setup boot device timings/width + + setup CPU_CONF (0x0) + setup cpu master control register 0x160 + setup PCI0 TIMEOUT + setup PCI1 TIMEOUT + setup PCI0 BAR + setup PCI1 BAR + + setup MPP control 0-3 + setup GPP level control + setup Serial ports multiplex + + setup stack pointer (r1) + setup GOT + call cpu_init_f + debug leds + board_init_f: (common/board.c) + board_early_init_f: + remap gt regs? + map PCI mem/io + map device space + clear out interupts + init_timebase + env_init + serial_init + console_init_f + display_options + initdram: (board/evb64260/evb64260.c) + detect memory + for each bank: + dram_size() + setup PCI slave memory mappings + setup SCS + setup monitor + alloc board info struct + init bd struct + relocate_code: (cpu/mpc7xxx/start.S) + copy,got,clearbss + board_init_r(bd, dest_addr) (common/board.c) + setup bd function pointers + trap_init + flash_init: (board/evb64260/flash.c) + setup bd flash info + cpu_init_r: (cpu/mpc7xxx/cpu_init.c) + nothing + mem_malloc_init + malloc_bin_reloc + spi_init (r or f)??? (CFG_ENV_IS_IN_EEPROM) + env_relocated + misc_init_r(bd): (board/evb64260/evb64260.c) + mpsc_init2 diff --git a/board/evb64260/config.mk b/board/evb64260/config.mk new file mode 100755 index 0000000..0646a3e --- /dev/null +++ b/board/evb64260/config.mk @@ -0,0 +1,28 @@ +# +# (C) Copyright 2001 +# Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 +# + +# +# EVB64260 boards +# + +TEXT_BASE = 0xfff00000 diff --git a/board/evb64260/ecctest.c b/board/evb64260/ecctest.c new file mode 100755 index 0000000..5d3679a --- /dev/null +++ b/board/evb64260/ecctest.c @@ -0,0 +1,111 @@ +indent: Standard input:27: Warning:old style assignment ambiguity in "=*". Assuming "= *" + +#ifdef ECC_TEST +static inline void ecc_off (void) +{ + *(volatile int *) (INTERNAL_REG_BASE_ADDR + 0x4b4) &= ~0x00200000; +} + +static inline void ecc_on (void) +{ + *(volatile int *) (INTERNAL_REG_BASE_ADDR + 0x4b4) |= 0x00200000; +} + +static int putshex (const char *buf, int len) +{ + int i; + + for (i = 0; i < len; i++) { + printf ("%02x", buf[i]); + } + return 0; +} + +static int char_memcpy (void *d, const void *s, int len) +{ + int i; + char *cd = d; + const char *cs = s; + + for (i = 0; i < len; i++) { + *(cd++) = *(cs++); + } + return 0; +} + +static int memory_test (char *buf) +{ + const char src[][16] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, + {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, + {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08}, + {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10}, + {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, + {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}, + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}, + {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, + {0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa}, + {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + }; + const int foo[] = { 0 }; + int i, j, a; + + printf ("\ntest @ %d %p\n", foo[0], buf); + for (i = 0; i < 12; i++) { + for (a = 0; a < 8; a++) { + const char *s = src[i] + a; + int align = (unsigned) (s) & 0x7; + + /* ecc_off(); */ + memcpy (buf, s, 8); + /* ecc_on(); */ + putshex (s, 8); + if (memcmp (buf, s, 8)) { + putc ('\n'); + putshex (buf, 8); + printf (" [FAIL] (%p) align=%d\n", s, align); + for (j = 0; j < 8; j++) { + s[j] == buf[j] ? puts (" ") : + printf ("%02x", + (s[j]) ^ (buf[j])); + } + putc ('\n'); + } else { + printf (" [PASS] (%p) align=%d\n", s, align); + } + /* ecc_off(); */ + char_memcpy (buf, s, 8); + /* ecc_on(); */ + putshex (s, 8); + if (memcmp (buf, s, 8)) { + putc ('\n'); + putshex (buf, 8); + printf (" [FAIL] (%p) align=%d\n", s, align); + for (j = 0; j < 8; j++) { + s[j] == buf[j] ? puts (" ") : + printf ("%02x", + (s[j]) ^ (buf[j])); + } + putc ('\n'); + } else { + printf (" [PASS] (%p) align=%d\n", s, align); + } + } + } + + return 0; +} +#endif diff --git a/board/evb64260/eth.c b/board/evb64260/eth.c new file mode 100755 index 0000000..eafa48b --- /dev/null +++ b/board/evb64260/eth.c @@ -0,0 +1,807 @@ +/************************************************************************** +Etherboot - BOOTP/TFTP Bootstrap Program +Skeleton NIC driver for Etherboot +***************************************************************************/ + +/* + * 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, or (at + * your option) any later version. + */ + +/* + * This file is a modified version from the Galileo polled mode + * network driver for the ethernet contained within the GT64260 + * chip. It has been modified to fit into the U-Boot framework, from + * the original (etherboot) setup. Also, additional cleanup and features + * were added. + * + * - Josh Huber <huber@mclx.com> + */ + +#include <common.h> +#include <malloc.h> +#include <galileo/gt64260R.h> +#include <galileo/core.h> +#include <asm/cache.h> +#include <miiphy.h> +#include <net.h> + +#include "eth.h" +#include "eth_addrtbl.h" + +#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) + +#define GT6426x_ETH_BUF_SIZE 1536 + +/* if you like verbose output, turn this on! */ +#undef DEBUG + +/* Restart autoneg if we detect link is up on phy init. */ + +/* + * The GT doc's say that after Rst is deasserted, and the PHY + * reports autoneg complete, it runs through its autoneg + * procedures. This doesn't seem to be the case for MII + * PHY's. To work around this check for link up && autoneg + * complete when initilizing the port. If they are both set, + * then restart PHY autoneg. Of course, it may be something + * completly different. + */ +#ifdef CONFIG_ETHER_PORT_MII +# define RESTART_AUTONEG +#endif + +/* do this if you dont want to use snooping */ +#define USE_SOFTWARE_CACHE_MANAGEMENT + +#ifdef USE_SOFTWARE_CACHE_MANAGEMENT +#define FLUSH_DCACHE(a,b) if(dcache_status()){clean_dcache_range((u32)(a),(u32)(b));} +#define FLUSH_AND_INVALIDATE_DCACHE(a,b) if(dcache_status()){flush_dcache_range((u32)(a),(u32)(b));} +#define INVALIDATE_DCACHE(a,b) if(dcache_status()){invalidate_dcache_range((u32)(a),(u32)(b));} +#else +/* bummer - w/o flush, nothing works, even with snooping - FIXME */ +/* #define FLUSH_DCACHE(a,b) */ +#define FLUSH_DCACHE(a,b) if(dcache_status()){clean_dcache_range((u32)(a),(u32)(b));} +#define FLUSH_AND_INVALIDATE_DCACHE(a,b) +#define INVALIDATE_DCACHE(a,b) +#endif +struct eth_dev_s { + eth0_tx_desc_single *eth_tx_desc; + eth0_rx_desc_single *eth_rx_desc; + char *eth_tx_buffer; + char *eth_rx_buffer[NR]; + int tdn, rdn; + int dev; + unsigned int reg_base; +}; + + +#ifdef CONFIG_INTEL_LXT97X +/* for intel LXT972 */ +static const char ether_port_phy_addr[3]={0,1,2}; +#else +static const char ether_port_phy_addr[3]={4,5,6}; +#endif + +/* MII PHY access routines are common for all i/f, use gal_ent0 */ +#define GT6426x_MII_DEVNAME "gal_enet0" + +int gt6426x_miiphy_read(char *devname, unsigned char phy, + unsigned char reg, unsigned short *val); + +static inline unsigned short +miiphy_read_ret(unsigned short phy, unsigned short reg) +{ + unsigned short val; + gt6426x_miiphy_read(GT6426x_MII_DEVNAME,phy,reg,&val); + return val; +} + + +/************************************************************************** +RESET - Reset adapter +***************************************************************************/ +void +gt6426x_eth_reset(void *v) +{ + /* we should do something here... + struct eth_device *wp = (struct eth_device *)v; + struct eth_dev_s *p = wp->priv; + */ + + printf ("RESET\n"); + /* put the card in its initial state */ +} + +static void gt6426x_handle_SMI(struct eth_dev_s *p, unsigned int icr) +{ +#ifdef DEBUG + printf("SMI interrupt: "); + + if(icr&0x20000000) { + printf("SMI done\n"); + } +#endif + + if(icr&0x10000000) { + unsigned int psr; + psr=GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + p->reg_base); +#ifdef DEBUG + printf("PHY state change:\n" + " GT:%s:%s:%s:%s\n", + psr&1?"100":" 10", + psr&8?" Link":"nLink", + psr&2?"FD":"HD", + psr&4?" FC":"nFC"); + +#ifdef CONFIG_INTEL_LXT97X /* non-standard mii reg (intel lxt972a) */ + { + unsigned short mii_11; + mii_11=miiphy_read_ret(ether_port_phy_addr[p->dev],0x11); + + printf(" mii:%s:%s:%s:%s %s:%s %s\n", + mii_11&(1<<14)?"100":" 10", + mii_11&(1<<10)?" Link":"nLink", + mii_11&(1<<9)?"FD":"HD", + mii_11&(1<<4)?" FC":"nFC", + + mii_11&(1<<7)?"ANc":"ANnc", + mii_11&(1<<8)?"AN":"Manual", + "" + ); + } +#endif /* CONFIG_INTEL_LXT97X */ +#endif /* DEBUG */ + } +} + +static int +gt6426x_eth_receive(struct eth_dev_s *p,unsigned int icr) +{ + int eth_len=0; + char *eth_data; + + eth0_rx_desc_single *rx=&p->eth_rx_desc[(p->rdn)]; + + INVALIDATE_DCACHE((unsigned int)rx,(unsigned int)(rx+1)); + + if (rx->command_status & 0x80000000) { + return 0; /* No packet received */ + } + + eth_len = (unsigned int) + (rx->buff_size_byte_count) & 0x0000ffff; + eth_data = (char *) p->eth_rx_buffer[p->rdn]; + +#ifdef DEBUG + if (eth_len) { + printf ("%s: Recived %d byte Packet @ 0x%p\n", + __FUNCTION__, eth_len, eth_data); + } +#endif + /* + * packet is now in: + * eth0_rx_buffer[RDN_ETH0]; + */ + + /* let the upper layer handle the packet */ + NetReceive ((uchar *)eth_data, eth_len); + + rx->buff_size_byte_count = GT6426x_ETH_BUF_SIZE<<16; + + + /* GT96100 Owner */ + rx->command_status = 0x80000000; + + FLUSH_DCACHE((unsigned int)rx,(unsigned int)(rx+1)); + + p->rdn ++; + if (p->rdn == NR) {p->rdn = 0;} + + sync(); + + /* Start Rx*/ + GT_REG_WRITE (ETHERNET0_SDMA_COMMAND_REGISTER + p->reg_base, 0x00000080); + +#ifdef DEBUG + { + int i; + for (i=0;i<12;i++) { + printf(" %02x", eth_data[i]); + } + } + printf(": %d bytes\n", eth_len); +#endif + INVALIDATE_DCACHE((unsigned int)eth_data, + (unsigned int)eth_data+eth_len); + return eth_len; +} + +/************************************************************************** +POLL - look for an rx frame, handle other conditions +***************************************************************************/ +int +gt6426x_eth_poll(void *v) +{ + struct eth_device *wp = (struct eth_device *)v; + struct eth_dev_s *p = wp->priv; + unsigned int icr=GTREGREAD(ETHERNET0_INTERRUPT_CAUSE_REGISTER + p->reg_base); + + if(icr) { + GT_REG_WRITE(ETHERNET0_INTERRUPT_CAUSE_REGISTER +p->reg_base, 0); +#ifdef DEBUG + printf("poll got ICR %08x\n", icr); +#endif + /* SMI done or PHY state change*/ + if(icr&0x30000000) gt6426x_handle_SMI(p, icr); + } + /* always process. We aren't using RX interrupts */ + return gt6426x_eth_receive(p, icr); +} + +/************************************************************************** +TRANSMIT - Transmit a frame +***************************************************************************/ +int +gt6426x_eth_transmit(void *v, volatile char *p, unsigned int s) +{ + struct eth_device *wp = (struct eth_device *)v; + struct eth_dev_s *dev = (struct eth_dev_s *)wp->priv; +#ifdef DEBUG + unsigned int old_command_stat,old_psr; +#endif + eth0_tx_desc_single *tx=&dev->eth_tx_desc[dev->tdn]; + + /* wait for tx to be ready */ + INVALIDATE_DCACHE((unsigned int)tx,(unsigned int)(tx+1)); + while (tx->command_status & 0x80000000) { + int i; + for(i=0;i<1000;i++); + INVALIDATE_DCACHE((unsigned int)tx,(unsigned int)(tx+1)); + } + + GT_REG_WRITE (ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0 + dev->reg_base, + (unsigned int)tx); + +#ifdef DEBUG + printf("copying to tx_buffer [%p], length %x, desc = %p\n", + dev->eth_tx_buffer, s, dev->eth_tx_desc); +#endif + memcpy(dev->eth_tx_buffer, (char *) p, s); + + tx->buff_pointer = (uchar *)dev->eth_tx_buffer; + tx->bytecount_reserved = ((__u16)s) << 16; + + /* 31 - own + * 22 - gencrc + * 18:16 - pad, last, first */ + tx->command_status = (1<<31) | (1<<22) | (7<<16); +#if 0 + /* FEr #18 */ + tx->next_desc = NULL; +#else + tx->next_desc = + (struct eth0_tx_desc_struct *) + &dev->eth_tx_desc[(dev->tdn+1)%NT].bytecount_reserved; + + /* cpu owned */ + dev->eth_tx_desc[(dev->tdn+1)%NT].command_status = (7<<16); /* pad, last, first */ +#endif + +#ifdef DEBUG + old_command_stat=tx->command_status, + old_psr=GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + dev->reg_base); +#endif + + FLUSH_DCACHE((unsigned int)tx, + (unsigned int)&dev->eth_tx_desc[(dev->tdn+2)%NT]); + + FLUSH_DCACHE((unsigned int)dev->eth_tx_buffer,(unsigned int)dev->eth_tx_buffer+s); + + GT_REG_WRITE(ETHERNET0_SDMA_COMMAND_REGISTER + dev->reg_base, 0x01000000); + +#ifdef DEBUG + { + unsigned int command_stat=0; + printf("cmd_stat: %08x PSR: %08x\n", old_command_stat, old_psr); + /* wait for tx to be ready */ + do { + unsigned int psr=GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + dev->reg_base); + command_stat=tx->command_status; + if(command_stat!=old_command_stat || psr !=old_psr) { + printf("cmd_stat: %08x PSR: %08x\n", command_stat, psr); + old_command_stat = command_stat; + old_psr = psr; + } + /* gt6426x_eth0_poll(); */ + } while (command_stat & 0x80000000); + + printf("sent %d byte frame\n", s); + + if((command_stat & (3<<15)) == 3) { + printf("frame had error (stat=%08x)\n", command_stat); + } + } +#endif + return 0; +} + +/************************************************************************** +DISABLE - Turn off ethernet interface +***************************************************************************/ +void +gt6426x_eth_disable(void *v) +{ + struct eth_device *wp = (struct eth_device *)v; + struct eth_dev_s *p = (struct eth_dev_s *)wp->priv; + + GT_REG_WRITE(ETHERNET0_SDMA_COMMAND_REGISTER + p->reg_base, 0x80008000); +} + +/************************************************************************** +MII utilities - write: write to an MII register via SMI +***************************************************************************/ +int +gt6426x_miiphy_write(char *devname, unsigned char phy, + unsigned char reg, unsigned short data) +{ + unsigned int temp= (reg<<21) | (phy<<16) | data; + + while(GTREGREAD(ETHERNET_SMI_REGISTER) & (1<<28)); /* wait for !Busy */ + + GT_REG_WRITE(ETHERNET_SMI_REGISTER, temp); + return 0; +} + +/************************************************************************** +MII utilities - read: read from an MII register via SMI +***************************************************************************/ +int +gt6426x_miiphy_read(char *devname, unsigned char phy, + unsigned char reg, unsigned short *val) +{ + unsigned int temp= (reg<<21) | (phy<<16) | 1<<26; + + while(GTREGREAD(ETHERNET_SMI_REGISTER) & (1<<28)); /* wait for !Busy */ + + GT_REG_WRITE(ETHERNET_SMI_REGISTER, temp); + + while(1) { + temp=GTREGREAD(ETHERNET_SMI_REGISTER); + if(temp & (1<<27)) break; /* wait for ReadValid */ + } + *val = temp & 0xffff; + + return 0; +} + +#ifdef DEBUG +/************************************************************************** +MII utilities - dump mii registers +***************************************************************************/ +static void +gt6426x_dump_mii(bd_t *bis, unsigned short phy) +{ + printf("mii reg 0 - 3: %04x %04x %04x %04x\n", + miiphy_read_ret(phy, 0x0), + miiphy_read_ret(phy, 0x1), + miiphy_read_ret(phy, 0x2), + miiphy_read_ret(phy, 0x3) + ); + printf(" 4 - 7: %04x %04x %04x %04x\n", + miiphy_read_ret(phy, 0x4), + miiphy_read_ret(phy, 0x5), + miiphy_read_ret(phy, 0x6), + miiphy_read_ret(phy, 0x7) + ); + printf(" 8: %04x\n", + miiphy_read_ret(phy, 0x8) + ); + printf(" 16-19: %04x %04x %04x %04x\n", + miiphy_read_ret(phy, 0x10), + miiphy_read_ret(phy, 0x11), + miiphy_read_ret(phy, 0x12), + miiphy_read_ret(phy, 0x13) + ); + printf(" 20,30: %04x %04x\n", + miiphy_read_ret(phy, 20), + miiphy_read_ret(phy, 30) + ); +} +#endif + +#ifdef RESTART_AUTONEG + +/* If link is up && autoneg compleate, and if + * GT and PHY disagree about link capabilitys, + * restart autoneg - something screwy with FD/HD + * unless we do this. */ +static void +check_phy_state(struct eth_dev_s *p) +{ + int bmsr = miiphy_read_ret(ether_port_phy_addr[p->dev], PHY_BMSR); + int psr = GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + p->reg_base); + + if ((psr & 1<<3) && (bmsr & PHY_BMSR_LS)) { + int nego = miiphy_read_ret(ether_port_phy_addr[p->dev], PHY_ANAR) & + miiphy_read_ret(ether_port_phy_addr[p->dev], PHY_ANLPAR); + int want; + + if (nego & PHY_ANLPAR_TXFD) { + want = 0x3; + printf("MII: 100Base-TX, Full Duplex\n"); + } else if (nego & PHY_ANLPAR_TX) { + want = 0x1; + printf("MII: 100Base-TX, Half Duplex\n"); + } else if (nego & PHY_ANLPAR_10FD) { + want = 0x2; + printf("MII: 10Base-T, Full Duplex\n"); + } else if (nego & PHY_ANLPAR_10) { + want = 0x0; + printf("MII: 10Base-T, Half Duplex\n"); + } else { + printf("MII: Unknown link-foo! %x\n", nego); + return; + } + + if ((psr & 0x3) != want) { + printf("MII: GT thinks %x, PHY thinks %x, restarting autoneg..\n", + psr & 0x3, want); + miiphy_write(GT6426x_MII_DEVNAME,ether_port_phy_addr[p->dev],0, + miiphy_read_ret(ether_port_phy_addr[p->dev],0) | (1<<9)); + udelay(10000); /* the EVB's GT takes a while to notice phy + went down and up */ + } + } +} +#endif + +/************************************************************************** +PROBE - Look for an adapter, this routine's visible to the outside +***************************************************************************/ +int +gt6426x_eth_probe(void *v, bd_t *bis) +{ + struct eth_device *wp = (struct eth_device *)v; + struct eth_dev_s *p = (struct eth_dev_s *)wp->priv; + int dev = p->dev; + unsigned int reg_base = p->reg_base; + unsigned long temp; + int i; + + if (( dev < 0 ) || ( dev >= GAL_ETH_DEVS )) + { /* This should never happen */ + printf("%s: Invalid device %d\n", __FUNCTION__, dev ); + return 0; + } + +#ifdef DEBUG + printf ("%s: initializing %s\n", __FUNCTION__, wp->name ); + printf ("\nCOMM_CONTROL = %08x , COMM_CONF = %08x\n", + GTREGREAD(COMM_UNIT_ARBITER_CONTROL), + GTREGREAD(COMM_UNIT_ARBITER_CONFIGURATION_REGISTER)); +#endif + + /* clear MIB counters */ + for(i=0;i<255; i++) + temp=GTREGREAD(ETHERNET0_MIB_COUNTER_BASE + reg_base +i); + +#ifdef CONFIG_INTEL_LXT97X + /* for intel LXT972 */ + + /* led 1: 0x1=txact + led 2: 0xc=link/rxact + led 3: 0x2=rxact (N/C) + strch: 0,2=30 ms, enable */ + miiphy_write(GT6426x_MII_DEVNAME,ether_port_phy_addr[p->dev], 20, 0x1c22); + + /* 2.7ns port rise time */ + /*miiphy_write(ether_port_phy_addr[p->dev], 30, 0x0<<10); */ +#else + /* already set up in mpsc.c */ + /*GT_REG_WRITE(MAIN_ROUTING_REGISTER, 0x7ffe38); / b400 */ + + /* already set up in sdram_init.S... */ + /* MPSC0, MPSC1, RMII */ + /*GT_REG_WRITE(SERIAL_PORT_MULTIPLEX, 0x1102); / f010 */ +#endif + GT_REG_WRITE(ETHERNET_PHY_ADDRESS_REGISTER, + ether_port_phy_addr[0] | + (ether_port_phy_addr[1]<<5) | + (ether_port_phy_addr[2]<<10)); /* 2000 */ + + /* 13:12 - 10: 4x64bit burst (cache line size = 32 bytes) + * 9 - 1: RIFB - interrupt on frame boundaries only + * 6:7 - 00: big endian rx and tx + * 5:2 - 1111: 15 retries */ + GT_REG_WRITE(ETHERNET0_SDMA_CONFIGURATION_REGISTER + reg_base, + (2<<12) | (1<<9) | (0xf<<2) ); /* 2440 */ + +#ifndef USE_SOFTWARE_CACHE_MANAGEMENT + /* enable rx/tx desc/buffer cache snoop */ + GT_REG_READ(ETHERNET_0_ADDRESS_CONTROL_LOW + dev*0x20, + &temp); /* f200 */ + temp|= (1<<6)| (1<<14)| (1<<22)| (1<<30); + GT_REG_WRITE(ETHERNET_0_ADDRESS_CONTROL_LOW + dev*0x20, + temp); +#endif + + /* 31 28 27 24 23 20 19 16 + * 0000 0000 0000 0000 [0004] + * 15 12 11 8 7 4 3 0 + * 1000 1101 0000 0000 [4d00] + * 20 - 0=MII 1=RMII + * 19 - 0=speed autoneg + * 15:14 - framesize 1536 (GT6426x_ETH_BUF_SIZE) + * 11 - no force link pass + * 10 - 1=disable fctl autoneg + * 8 - override prio ?? */ + temp = 0x00004d00; +#ifndef CONFIG_ETHER_PORT_MII + temp |= (1<<20); /* RMII */ +#endif + /* set En */ + GT_REG_WRITE(ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER + reg_base, + temp); /* 2408 */ + + /* hardcode E1 also? */ + /* -- according to dox, this is safer due to extra pulldowns? */ + if (dev<2) { + GT_REG_WRITE(ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER + (dev+1) * 0x400, + temp); /* 2408 */ + } + + /* wake up MAC */ /* 2400 */ + GT_REG_READ(ETHERNET0_PORT_CONFIGURATION_REGISTER + reg_base, &temp); + temp |= (1<<7); /* enable port */ +#ifdef CONFIG_GT_USE_MAC_HASH_TABLE + temp |= (1<<12); /* hash size 1/2k */ +#else + temp |= 1; /* promisc */ +#endif + GT_REG_WRITE(ETHERNET0_PORT_CONFIGURATION_REGISTER + reg_base, temp); + /* 2400 */ + +#ifdef RESTART_AUTONEG + check_phy_state(p); +#endif + + printf("%s: Waiting for link up..\n", wp->name); + temp = 10 * 1000; + /* wait for link back up */ + while(!(GTREGREAD(ETHERNET0_PORT_STATUS_REGISTER + reg_base) & 8) + && (--temp > 0)){ + udelay(1000); /* wait 1 ms */ + } + if ( temp == 0) { + printf("%s: Failed!\n", wp->name); + return (0); + } + + printf("%s: OK!\n", wp->name); + + p->tdn = 0; + p->rdn = 0; + p->eth_tx_desc[p->tdn].command_status = 0; + + /* Initialize Rx Side */ + for (temp = 0; temp < NR; temp++) { + p->eth_rx_desc[temp].buff_pointer = (uchar *)p->eth_rx_buffer[temp]; + p->eth_rx_desc[temp].buff_size_byte_count = GT6426x_ETH_BUF_SIZE<<16; + + /* GT96100 Owner */ + p->eth_rx_desc[temp].command_status = 0x80000000; + p->eth_rx_desc[temp].next_desc = + (struct eth0_rx_desc_struct *) + &p->eth_rx_desc[(temp+1)%NR].buff_size_byte_count; + } + + FLUSH_DCACHE((unsigned int)&p->eth_tx_desc[0], + (unsigned int)&p->eth_tx_desc[NR]); + FLUSH_DCACHE((unsigned int)&p->eth_rx_desc[0], + (unsigned int)&p->eth_rx_desc[NR]); + + GT_REG_WRITE(ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0 + reg_base, + (unsigned int) p->eth_tx_desc); + GT_REG_WRITE(ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0 + reg_base, + (unsigned int) p->eth_rx_desc); + GT_REG_WRITE(ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0 + reg_base, + (unsigned int) p->eth_rx_desc); + +#ifdef DEBUG + printf ("\nRx descriptor pointer is %08x %08x\n", + GTREGREAD(ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0 + reg_base), + GTREGREAD(ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0 + reg_base)); + printf ("\n\n%08x %08x\n", + (unsigned int)p->eth_rx_desc,p->eth_rx_desc[0].command_status); + + printf ("Descriptor dump:\n"); + printf ("cmd status: %08x\n",p->eth_rx_desc[0].command_status); + printf ("byte_count: %08x\n",p->eth_rx_desc[0].buff_size_byte_count); + printf ("buff_ptr: %08x\n",(unsigned int)p->eth_rx_desc[0].buff_pointer); + printf ("next_desc: %08x\n\n",(unsigned int)p->eth_rx_desc[0].next_desc); + printf ("%08x\n",*(unsigned int *) ((unsigned int)p->eth_rx_desc + 0x0)); + printf ("%08x\n",*(unsigned int *) ((unsigned int)p->eth_rx_desc + 0x4)); + printf ("%08x\n",*(unsigned int *) ((unsigned int)p->eth_rx_desc + 0x8)); + printf ("%08x\n\n", + *(unsigned int *) ((unsigned int)p->eth_rx_desc + 0xc)); +#endif + +#ifdef DEBUG + gt6426x_dump_mii(bis,ether_port_phy_addr[p->dev]); +#endif + +#ifdef CONFIG_GT_USE_MAC_HASH_TABLE + { + unsigned int hashtable_base; + u8 *b = (u8 *)(wp->enetaddr); + u32 macH, macL; + + /* twist the MAC up into the way the discovery wants it */ + macH= (b[0]<<8) | b[1]; + macL= (b[2]<<24) | (b[3]<<16) | (b[4]<<8) | b[5]; + + /* mode 0, size 0x800 */ + hashtable_base =initAddressTable(dev,0,1); + + if(!hashtable_base) { + printf("initAddressTable failed\n"); + return 0; + } + + addAddressTableEntry(dev, macH, macL, 1, 0); + GT_REG_WRITE(ETHERNET0_HASH_TABLE_POINTER_REGISTER + reg_base, + hashtable_base); + } +#endif + + /* Start Rx*/ + GT_REG_WRITE(ETHERNET0_SDMA_COMMAND_REGISTER + reg_base, 0x00000080); + printf("%s: gt6426x eth device %d init success \n", wp->name, dev ); + return 1; +} + +/* enter all the galileo ethernet devs into MULTI-BOOT */ +void +gt6426x_eth_initialize(bd_t *bis) +{ + struct eth_device *dev; + struct eth_dev_s *p; + int devnum, x, temp; + char *s, *e, buf[64]; + +#ifdef DEBUG + printf( "\n%s\n", __FUNCTION ); +#endif + + for (devnum = 0; devnum < GAL_ETH_DEVS; devnum++) { + dev = calloc(sizeof(*dev), 1); + if (!dev) { + printf( "%s: gal_enet%d allocation failure, %s\n", + __FUNCTION__, devnum, "eth_device structure"); + return; + } + + /* must be less than NAMESIZE (16) */ + sprintf(dev->name, "gal_enet%d", devnum); + +#ifdef DEBUG + printf( "Initializing %s\n", dev->name ); +#endif + + /* Extract the MAC address from the environment */ + switch (devnum) + { + case 0: s = "ethaddr"; break; +#if (GAL_ETH_DEVS > 1) + case 1: s = "eth1addr"; break; +#endif +#if (GAL_ETH_DEVS > 2) + case 2: s = "eth2addr"; break; +#endif + default: /* this should never happen */ + printf( "%s: Invalid device number %d\n", + __FUNCTION__, devnum ); + return; + } + + temp = getenv_r (s, buf, sizeof(buf)); + s = (temp > 0) ? buf : NULL; + +#ifdef DEBUG + printf ("Setting MAC %d to %s\n", devnum, s ); +#endif + for (x = 0; x < 6; ++x) { + dev->enetaddr[x] = s ? simple_strtoul(s, &e, 16) : 0; + if (s) + s = (*e) ? e+1 : e; + } + + dev->init = (void*)gt6426x_eth_probe; + dev->halt = (void*)gt6426x_eth_reset; + dev->send = (void*)gt6426x_eth_transmit; + dev->recv = (void*)gt6426x_eth_poll; + + p = calloc( sizeof(*p), 1 ); + dev->priv = (void*)p; + if (!p) + { + printf( "%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, "Private Device Structure"); + free(dev); + return; + } + + p->dev = devnum; + p->tdn=0; + p->rdn=0; + p->reg_base = devnum * ETHERNET_PORTS_DIFFERENCE_OFFSETS; + + p->eth_tx_desc = + (eth0_tx_desc_single *) + (((unsigned int) malloc(sizeof (eth0_tx_desc_single) * + (NT+1)) & 0xfffffff0) + 0x10); + if (!p) + { + printf( "%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, "Tx Descriptor"); + free(dev); + return; + } + + p->eth_rx_desc = + (eth0_rx_desc_single *) + (((unsigned int) malloc(sizeof (eth0_rx_desc_single) * + (NR+1)) & 0xfffffff0) + 0x10); + if (!p->eth_rx_desc) + { + printf( "%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, "Rx Descriptor"); + free(dev); + free(p); + return; + } + + p->eth_tx_buffer = + (char *) (((unsigned int) malloc(GT6426x_ETH_BUF_SIZE) & 0xfffffff0) + 0x10); + if (!p->eth_tx_buffer) + { + printf( "%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, "Tx Bufffer"); + free(dev); + free(p); + free(p->eth_rx_desc); + return; + } + + for (temp = 0 ; temp < NR ; temp ++) { + p->eth_rx_buffer[temp] = + (char *) + (((unsigned int) malloc(GT6426x_ETH_BUF_SIZE) & 0xfffffff0) + 0x10); + if (!p->eth_rx_buffer[temp]) + { + printf( "%s: %s allocation failure, %s\n", + __FUNCTION__, dev->name, "Rx Buffers"); + free(dev); + free(p); + free(p->eth_tx_buffer); + free(p->eth_rx_desc); + free(p->eth_tx_desc); + while (temp >= 0) + free(p->eth_rx_buffer[--temp]); + return; + } + } + + + eth_register(dev); +#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) + miiphy_register(dev->name, + gt6426x_miiphy_read, gt6426x_miiphy_write); +#endif + } + +} +#endif /* CFG_CMD_NET && CONFIG_NET_MULTI */ diff --git a/board/evb64260/eth.h b/board/evb64260/eth.h new file mode 100755 index 0000000..beb6db1 --- /dev/null +++ b/board/evb64260/eth.h @@ -0,0 +1,75 @@ +/* + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 + */ + +/* + * eth.h - header file for the polled mode GT ethernet driver + */ + +#ifndef __GT6426x_ETH_H__ +#define __GT6426x_ETH_H__ + +#include <asm/types.h> +#include <asm/io.h> +#include <asm/byteorder.h> +#include <common.h> + +typedef struct eth0_tx_desc_struct { + volatile __u32 bytecount_reserved; + volatile __u32 command_status; + volatile struct eth0_tx_desc_struct * next_desc; + /* Note - the following will not work for 64 bit addressing */ + volatile unsigned char * buff_pointer; +} __attribute__ ((packed)) eth0_tx_desc_single; + +typedef struct eth0_rx_desc_struct { + volatile __u32 buff_size_byte_count; + volatile __u32 command_status; + volatile struct eth0_rx_desc_struct * next_desc; + volatile unsigned char * buff_pointer; +} __attribute__ ((packed)) eth0_rx_desc_single; + +#define NT 20 /* Number of Transmit buffers */ +#define NR 20 /* Number of Receive buffers */ +#define MAX_BUFF_SIZE (1536+2*CACHE_LINE_SIZE) /* 1600 */ +#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400 + +unsigned long TDN_ETH0 , RDN_ETH0; /* Rx/Tx current Descriptor Number*/ +unsigned int EVB64260_ETH0_irq; + +#define CLOSED 0 +#define OPENED 1 + +#define PORT_ETH0 0 + +extern eth0_tx_desc_single *eth0_tx_desc; +extern eth0_rx_desc_single *eth0_rx_desc; +extern char *eth0_tx_buffer; +extern char *eth0_rx_buffer[NR]; +extern char *eth_data; + +extern int gt6426x_eth_poll(void *v); +extern int gt6426x_eth_transmit(void *v, volatile char *p, unsigned int s); +extern void gt6426x_eth_disable(void *v); +extern int gt6426x_eth_probe(void *v, bd_t *bis); + +#endif /* __GT64260x_ETH_H__ */ diff --git a/board/evb64260/eth_addrtbl.c b/board/evb64260/eth_addrtbl.c new file mode 100755 index 0000000..e8ef0e3 --- /dev/null +++ b/board/evb64260/eth_addrtbl.c @@ -0,0 +1,221 @@ +#include <common.h> +#include <malloc.h> +#include <galileo/gt64260R.h> +#include <galileo/core.h> +#include <asm/cache.h> +#include "eth.h" +#include "eth_addrtbl.h" + +#define TRUE 1 +#define FALSE 0 + +#define PRINTF printf + +#ifdef CONFIG_GT_USE_MAC_HASH_TABLE + +static u32 addressTableHashMode[GAL_ETH_DEVS] = { 0, }; +static u32 addressTableHashSize[GAL_ETH_DEVS] = { 0, }; +static addrTblEntry *addressTableBase[GAL_ETH_DEVS] = { 0, }; +static void *realAddrTableBase[GAL_ETH_DEVS] = { 0, }; + +static const u32 hashLength[2] = { + (0x8000), /* 8K * 4 entries */ + (0x8000 / 16), /* 512 * 4 entries */ +}; + +/* Initialize the address table for a port, if needed */ +unsigned int initAddressTable (u32 port, u32 hashMode, u32 hashSizeSelector) +{ + unsigned int tableBase; + + if (port < 0 || port >= GAL_ETH_DEVS) { + printf ("%s: Invalid port number %d\n", __FUNCTION__, port); + return 0; + } + + if (hashMode > 1) { + printf ("%s: Invalid Hash Mode %d\n", __FUNCTION__, port); + return 0; + } + + if (realAddrTableBase[port] && + (addressTableHashSize[port] != hashSizeSelector)) { + /* we have been here before, + * but now we want a different sized table + */ + free (realAddrTableBase[port]); + realAddrTableBase[port] = 0; + addressTableBase[port] = 0; + + } + + tableBase = (unsigned int) addressTableBase[port]; + /* we get called for every probe, so only do this once */ + if (!tableBase) { + int bytes = + hashLength[hashSizeSelector] * sizeof (addrTblEntry); + + realAddrTableBase[port] = + malloc (bytes + 64); + tableBase = (unsigned int)realAddrTableBase; + + if (!tableBase) { + printf ("%s: alloc memory failed \n", __FUNCTION__); + return 0; + } + + /* align to octal byte */ + if (tableBase & 63) + tableBase = (tableBase + 63) & ~63; + + addressTableHashMode[port] = hashMode; + addressTableHashSize[port] = hashSizeSelector; + addressTableBase[port] = (addrTblEntry *) tableBase; + + memset ((void *) tableBase, 0, bytes); + } + + return tableBase; +} + +/* + * ---------------------------------------------------------------------------- + * This function will calculate the hash function of the address. + * depends on the hash mode and hash size. + * Inputs + * macH - the 2 most significant bytes of the MAC address. + * macL - the 4 least significant bytes of the MAC address. + * hashMode - hash mode 0 or hash mode 1. + * hashSizeSelector - indicates number of hash table entries (0=0x8000,1=0x800) + * Outputs + * return the calculated entry. + */ +u32 hashTableFunction (u32 macH, u32 macL, u32 HashSize, u32 hash_mode) +{ + u32 hashResult; + u32 addrH; + u32 addrL; + u32 addr0; + u32 addr1; + u32 addr2; + u32 addr3; + u32 addrHSwapped; + u32 addrLSwapped; + + + addrH = NIBBLE_SWAPPING_16_BIT (macH); + addrL = NIBBLE_SWAPPING_32_BIT (macL); + + addrHSwapped = FLIP_4_BITS (addrH & 0xf) + + ((FLIP_4_BITS ((addrH >> 4) & 0xf)) << 4) + + ((FLIP_4_BITS ((addrH >> 8) & 0xf)) << 8) + + ((FLIP_4_BITS ((addrH >> 12) & 0xf)) << 12); + + addrLSwapped = FLIP_4_BITS (addrL & 0xf) + + ((FLIP_4_BITS ((addrL >> 4) & 0xf)) << 4) + + ((FLIP_4_BITS ((addrL >> 8) & 0xf)) << 8) + + ((FLIP_4_BITS ((addrL >> 12) & 0xf)) << 12) + + ((FLIP_4_BITS ((addrL >> 16) & 0xf)) << 16) + + ((FLIP_4_BITS ((addrL >> 20) & 0xf)) << 20) + + ((FLIP_4_BITS ((addrL >> 24) & 0xf)) << 24) + + ((FLIP_4_BITS ((addrL >> 28) & 0xf)) << 28); + + addrH = addrHSwapped; + addrL = addrLSwapped; + + if (hash_mode == 0) { + addr0 = (addrL >> 2) & 0x03f; + addr1 = (addrL & 0x003) | ((addrL >> 8) & 0x7f) << 2; + addr2 = (addrL >> 15) & 0x1ff; + addr3 = ((addrL >> 24) & 0x0ff) | ((addrH & 1) << 8); + } else { + addr0 = FLIP_6_BITS (addrL & 0x03f); + addr1 = FLIP_9_BITS (((addrL >> 6) & 0x1ff)); + addr2 = FLIP_9_BITS ((addrL >> 15) & 0x1ff); + addr3 = FLIP_9_BITS ((((addrL >> 24) & 0x0ff) | + ((addrH & 0x1) << 8))); + } + + hashResult = (addr0 << 9) | (addr1 ^ addr2 ^ addr3); + + if (HashSize == _8K_TABLE) { + hashResult = hashResult & 0xffff; + } else { + hashResult = hashResult & 0x07ff; + } + + return (hashResult); +} + + +/* + * ---------------------------------------------------------------------------- + * This function will add an entry to the address table. + * depends on the hash mode and hash size that was initialized. + * Inputs + * port - ETHERNET port number. + * macH - the 2 most significant bytes of the MAC address. + * macL - the 4 least significant bytes of the MAC address. + * skip - if 1, skip this address. + * rd - the RD field in the address table. + * Outputs + * address table entry is added. + * TRUE if success. + * FALSE if table full + */ +int addAddressTableEntry (u32 port, u32 macH, u32 macL, u32 rd, u32 skip) +{ + addrTblEntry *entry; + u32 newHi; + u32 newLo; + u32 i; + + newLo = (((macH >> 4) & 0xf) << 15) + | (((macH >> 0) & 0xf) << 11) + | (((macH >> 12) & 0xf) << 7) + | (((macH >> 8) & 0xf) << 3) + | (((macL >> 20) & 0x1) << 31) + | (((macL >> 16) & 0xf) << 27) + | (((macL >> 28) & 0xf) << 23) + | (((macL >> 24) & 0xf) << 19) + | (skip << SKIP_BIT) | (rd << 2) | VALID; + + newHi = (((macL >> 4) & 0xf) << 15) + | (((macL >> 0) & 0xf) << 11) + | (((macL >> 12) & 0xf) << 7) + | (((macL >> 8) & 0xf) << 3) + | (((macL >> 21) & 0x7) << 0); + + /* + * Pick the appropriate table, start scanning for free/reusable + * entries at the index obtained by hashing the specified MAC address + */ + entry = addressTableBase[port]; + entry += hashTableFunction (macH, macL, addressTableHashSize[port], + addressTableHashMode[port]); + for (i = 0; i < HOP_NUMBER; i++, entry++) { + if (!(entry->lo & VALID) /*|| (entry->lo & SKIP) */ ) { + break; + } else { /* if same address put in same position */ + if (((entry->lo & 0xfffffff8) == (newLo & 0xfffffff8)) + && (entry->hi == newHi)) { + break; + } + } + } + + if (i == HOP_NUMBER) { + PRINTF ("addGT64260addressTableEntry: table section is full\n"); + return (FALSE); + } + + /* + * Update the selected entry + */ + entry->hi = newHi; + entry->lo = newLo; + DCACHE_FLUSH_N_SYNC ((u32) entry, MAC_ENTRY_SIZE); + return (TRUE); +} + +#endif /* CONFIG_GT_USE_MAC_HASH_TABLE */ diff --git a/board/evb64260/eth_addrtbl.h b/board/evb64260/eth_addrtbl.h new file mode 100755 index 0000000..5a62c67 --- /dev/null +++ b/board/evb64260/eth_addrtbl.h @@ -0,0 +1,83 @@ +#ifndef _ADDRESS_TABLE_H +#define _ADDRESS_TABLE_H 1 + +/* + * ---------------------------------------------------------------------------- + * addressTable.h - this file has all the declarations of the address table + */ + +#define _8K_TABLE 0 +#define ADDRESS_TABLE_ALIGNMENT 8 +#define HASH_DEFAULT_MODE 14 +#define HASH_MODE 13 +#define HASH_SIZE 12 +#define HOP_NUMBER 12 +#define MAC_ADDRESS_STRING_SIZE 12 +#define MAC_ENTRY_SIZE sizeof(addrTblEntry) +#define MAX_NUMBER_OF_ADDRESSES_TO_STORE 1000 +#define PROMISCUOUS_MODE 0 +#define SKIP 1<<1 +#define SKIP_BIT 1 +#define VALID 1 + +/* + * ---------------------------------------------------------------------------- + * XXX_MIKE - potential sign-extension bugs lurk here... + */ +#define NIBBLE_SWAPPING_32_BIT(X) ( (((X) & 0xf0f0f0f0) >> 4) \ + | (((X) & 0x0f0f0f0f) << 4) ) + +#define NIBBLE_SWAPPING_16_BIT(X) ( (((X) & 0x0000f0f0) >> 4) \ + | (((X) & 0x00000f0f) << 4) ) + +#define FLIP_4_BITS(X) ( (((X) & 0x01) << 3) | (((X) & 0x002) << 1) \ + | (((X) & 0x04) >> 1) | (((X) & 0x008) >> 3) ) + +#define FLIP_6_BITS(X) ( (((X) & 0x01) << 5) | (((X) & 0x020) >> 5) \ + | (((X) & 0x02) << 3) | (((X) & 0x010) >> 3) \ + | (((X) & 0x04) << 1) | (((X) & 0x008) >> 1) ) + +#define FLIP_9_BITS(X) ( (((X) & 0x01) << 8) | (((X) & 0x100) >> 8) \ + | (((X) & 0x02) << 6) | (((X) & 0x080) >> 6) \ + | (((X) & 0x04) << 4) | (((X) & 0x040) >> 4) \ + | ((X) & 0x10) | (((X) & 0x08) << 2) | (((X) & 0x020) >> 2) ) + +/* + * V: value we're operating on + * O: offset of rightmost bit in field + * W: width of field to shift + * S: distance to shift left + */ +#define MASK( fieldWidth ) ((1 << (fieldWidth)) - 1) +#define leftShiftedBitfield( V,O,W,S) (((V) & (MASK(W) << (O))) << (S)) +#define rightShiftedBitfield(V,O,W,S) (((u32)((V) & (MASK(W) << (O)))) >> (S)) + + +/* + * Push to main memory all cache lines associated with + * the specified range of virtual memory addresses + * + * A: Address of first byte in range to flush + * N: Number of bytes to flush + * Note - flush_dcache_range() does a "sync", does NOT invalidate + */ +#define DCACHE_FLUSH_N_SYNC( A, N ) flush_dcache_range( (A), ((A)+(N)) ) + + +typedef struct addressTableEntryStruct { + u32 hi; + u32 lo; +} addrTblEntry; + +u32 +uncachedPages( u32 pages ); +u32 +hashTableFunction( u32 macH, u32 macL, u32 HashSize, u32 hash_mode ); + +unsigned int +initAddressTable( u32 port, u32 hashMode, u32 hashSize ); + +int +addAddressTableEntry( u32 port, u32 macH, u32 macL, u32 rd, u32 skip ); + +#endif /* #ifndef _ADDRESS_TABLE_H */ diff --git a/board/evb64260/evb64260.c b/board/evb64260/evb64260.c new file mode 100755 index 0000000..6a9d164 --- /dev/null +++ b/board/evb64260/evb64260.c @@ -0,0 +1,444 @@ +/* + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 + */ + +/* + * evb64260.c - main board support/init for the Galileo Eval board. + */ + +#include <common.h> +#include <74xx_7xx.h> +#include <galileo/memory.h> +#include <galileo/pci.h> +#include <galileo/gt64260R.h> +#include <net.h> + +#include <asm/io.h> +#include "eth.h" +#include "mpsc.h" +#include "i2c.h" +#include "64260.h" +#ifdef CONFIG_ZUMA_V2 +extern void zuma_mbox_init(void); +#endif + +#undef DEBUG +#define MAP_PCI + +#ifdef DEBUG +#define DP(x) x +#else +#define DP(x) +#endif + +/* ------------------------------------------------------------------------- */ + +/* this is the current GT register space location */ +/* it starts at CFG_DFL_GT_REGS but moves later to CFG_GT_REGS */ + +/* Unfortunately, we cant change it while we are in flash, so we initialize it + * to the "final" value. This means that any debug_led calls before + * board_early_init_f wont work right (like in cpu_init_f). + * See also my_remap_gt_regs below. (NTL) + */ + +unsigned int INTERNAL_REG_BASE_ADDR = CFG_GT_REGS; + +/* ------------------------------------------------------------------------- */ + +/* + * This is a version of the GT register space remapping function that + * doesn't touch globals (meaning, it's ok to run from flash.) + * + * Unfortunately, this has the side effect that a writable + * INTERNAL_REG_BASE_ADDR is impossible. Oh well. + */ + +void +my_remap_gt_regs(u32 cur_loc, u32 new_loc) +{ + u32 temp; + + /* check and see if it's already moved */ + temp = in_le32((u32 *)(new_loc + INTERNAL_SPACE_DECODE)); + if ((temp & 0xffff) == new_loc >> 20) + return; + + temp = (in_le32((u32 *)(cur_loc + INTERNAL_SPACE_DECODE)) & + 0xffff0000) | (new_loc >> 20); + + out_le32((u32 *)(cur_loc + INTERNAL_SPACE_DECODE), temp); + + while (GTREGREAD(INTERNAL_SPACE_DECODE) != temp); +} + +static void +gt_pci_config(void) +{ + /* move PCI stuff out of the way - NTL */ + /* map PCI Host 0 */ + pciMapSpace(PCI_HOST0, PCI_REGION0, CFG_PCI0_0_MEM_SPACE, + CFG_PCI0_0_MEM_SPACE, CFG_PCI0_MEM_SIZE); + + pciMapSpace(PCI_HOST0, PCI_REGION1, 0, 0, 0); + pciMapSpace(PCI_HOST0, PCI_REGION2, 0, 0, 0); + pciMapSpace(PCI_HOST0, PCI_REGION3, 0, 0, 0); + + pciMapSpace(PCI_HOST0, PCI_IO, CFG_PCI0_IO_SPACE_PCI, + CFG_PCI0_IO_SPACE, CFG_PCI0_IO_SIZE); + + /* map PCI Host 1 */ + pciMapSpace(PCI_HOST1, PCI_REGION0, CFG_PCI1_0_MEM_SPACE, + CFG_PCI1_0_MEM_SPACE, CFG_PCI1_MEM_SIZE); + + pciMapSpace(PCI_HOST1, PCI_REGION1, 0, 0, 0); + pciMapSpace(PCI_HOST1, PCI_REGION2, 0, 0, 0); + pciMapSpace(PCI_HOST1, PCI_REGION3, 0, 0, 0); + + pciMapSpace(PCI_HOST1, PCI_IO, CFG_PCI1_IO_SPACE_PCI, + CFG_PCI1_IO_SPACE, CFG_PCI1_IO_SIZE); + + /* PCI interface settings */ + GT_REG_WRITE(PCI_0TIMEOUT_RETRY, 0xffff); + GT_REG_WRITE(PCI_1TIMEOUT_RETRY, 0xffff); + GT_REG_WRITE(PCI_0BASE_ADDRESS_REGISTERS_ENABLE, 0xfffff80e); + GT_REG_WRITE(PCI_1BASE_ADDRESS_REGISTERS_ENABLE, 0xfffff80e); + + +} + +/* Setup CPU interface paramaters */ +static void +gt_cpu_config(void) +{ + cpu_t cpu = get_cpu_type(); + ulong tmp; + + /* cpu configuration register */ + tmp = GTREGREAD(CPU_CONFIGURATION); + + /* set the AACK delay bit + * see Res#14 */ + tmp |= CPU_CONF_AACK_DELAY; + tmp &= ~CPU_CONF_AACK_DELAY_2; /* New RGF */ + + /* Galileo claims this is necessary for all busses >= 100 MHz */ + tmp |= CPU_CONF_FAST_CLK; + + if (cpu == CPU_750CX) { + tmp &= ~CPU_CONF_DP_VALID; /* Safer, needed for CXe. RGF */ + tmp &= ~CPU_CONF_AP_VALID; + } else { + tmp |= CPU_CONF_DP_VALID; + tmp |= CPU_CONF_AP_VALID; + } + + /* this only works with the MPX bus */ + tmp &= ~CPU_CONF_RD_OOO; /* Safer RGF */ + tmp |= CPU_CONF_PIPELINE; + tmp |= CPU_CONF_TA_DELAY; + + GT_REG_WRITE(CPU_CONFIGURATION, tmp); + + /* CPU master control register */ + tmp = GTREGREAD(CPU_MASTER_CONTROL); + + tmp |= CPU_MAST_CTL_ARB_EN; + + if ((cpu == CPU_7400) || + (cpu == CPU_7410) || + (cpu == CPU_7450)) { + + tmp |= CPU_MAST_CTL_CLEAN_BLK; + tmp |= CPU_MAST_CTL_FLUSH_BLK; + + } else { + /* cleanblock must be cleared for CPUs + * that do not support this command + * see Res#1 */ + tmp &= ~CPU_MAST_CTL_CLEAN_BLK; + tmp &= ~CPU_MAST_CTL_FLUSH_BLK; + } + GT_REG_WRITE(CPU_MASTER_CONTROL, tmp); +} + +/* + * board_early_init_f. + * + * set up gal. device mappings, etc. + */ +int board_early_init_f (void) +{ + uchar sram_boot = 0; + + /* + * set up the GT the way the kernel wants it + * the call to move the GT register space will obviously + * fail if it has already been done, but we're going to assume + * that if it's not at the power-on location, it's where we put + * it last time. (huber) + */ + my_remap_gt_regs(CFG_DFL_GT_REGS, CFG_GT_REGS); + + gt_pci_config(); + + /* mask all external interrupt sources */ + GT_REG_WRITE(CPU_INTERRUPT_MASK_REGISTER_LOW, 0); + GT_REG_WRITE(CPU_INTERRUPT_MASK_REGISTER_HIGH, 0); + GT_REG_WRITE(PCI_0INTERRUPT_CAUSE_MASK_REGISTER_LOW, 0); + GT_REG_WRITE(PCI_0INTERRUPT_CAUSE_MASK_REGISTER_HIGH, 0); + GT_REG_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_LOW, 0); + GT_REG_WRITE(PCI_1INTERRUPT_CAUSE_MASK_REGISTER_HIGH, 0); + GT_REG_WRITE(CPU_INT_0_MASK, 0); + GT_REG_WRITE(CPU_INT_1_MASK, 0); + GT_REG_WRITE(CPU_INT_2_MASK, 0); + GT_REG_WRITE(CPU_INT_3_MASK, 0); + + /* now, onto the configuration */ + GT_REG_WRITE(SDRAM_CONFIGURATION, CFG_SDRAM_CONFIG); + + /* ----- DEVICE BUS SETTINGS ------ */ + + /* + * EVB + * 0 - SRAM + * 1 - RTC + * 2 - UART + * 3 - Flash + * boot - BootCS + * + * Zuma + * 0 - Flash + * boot - BootCS + */ + + /* + * the dual 7450 module requires burst access to the boot + * device, so the serial rom copies the boot device to the + * on-board sram on the eval board, and updates the correct + * registers to boot from the sram. (device0) + */ +#if defined(CONFIG_ZUMA_V2) || defined(CONFIG_P3G4) + /* Zuma has no SRAM */ + sram_boot = 0; +#else + if (memoryGetDeviceBaseAddress(DEVICE0) && 0xfff00000 == CFG_MONITOR_BASE) + sram_boot = 1; +#endif + + if (!sram_boot) + memoryMapDeviceSpace(DEVICE0, CFG_DEV0_SPACE, CFG_DEV0_SIZE); + + memoryMapDeviceSpace(DEVICE1, CFG_DEV1_SPACE, CFG_DEV1_SIZE); + memoryMapDeviceSpace(DEVICE2, CFG_DEV2_SPACE, CFG_DEV2_SIZE); + memoryMapDeviceSpace(DEVICE3, CFG_DEV3_SPACE, CFG_DEV3_SIZE); + + /* configure device timing */ +#ifdef CFG_DEV0_PAR + if (!sram_boot) + GT_REG_WRITE(DEVICE_BANK0PARAMETERS, CFG_DEV0_PAR); +#endif + +#ifdef CFG_DEV1_PAR + GT_REG_WRITE(DEVICE_BANK1PARAMETERS, CFG_DEV1_PAR); +#endif +#ifdef CFG_DEV2_PAR + GT_REG_WRITE(DEVICE_BANK2PARAMETERS, CFG_DEV2_PAR); +#endif + +#ifdef CONFIG_EVB64260 +#ifdef CFG_32BIT_BOOT_PAR + /* detect if we are booting from the 32 bit flash */ + if (GTREGREAD(DEVICE_BOOT_BANK_PARAMETERS) & (0x3 << 20)) { + /* 32 bit boot flash */ + GT_REG_WRITE(DEVICE_BANK3PARAMETERS, CFG_8BIT_BOOT_PAR); + GT_REG_WRITE(DEVICE_BOOT_BANK_PARAMETERS, CFG_32BIT_BOOT_PAR); + } else { + /* 8 bit boot flash */ + GT_REG_WRITE(DEVICE_BANK3PARAMETERS, CFG_32BIT_BOOT_PAR); + GT_REG_WRITE(DEVICE_BOOT_BANK_PARAMETERS, CFG_8BIT_BOOT_PAR); + } +#else + /* 8 bit boot flash only */ + GT_REG_WRITE(DEVICE_BOOT_BANK_PARAMETERS, CFG_8BIT_BOOT_PAR); +#endif +#else /* CONFIG_EVB64260 not defined */ + /* We are booting from 16-bit flash. + */ + GT_REG_WRITE(DEVICE_BOOT_BANK_PARAMETERS, CFG_16BIT_BOOT_PAR); +#endif + + gt_cpu_config(); + + /* MPP setup */ + GT_REG_WRITE(MPP_CONTROL0, CFG_MPP_CONTROL_0); + GT_REG_WRITE(MPP_CONTROL1, CFG_MPP_CONTROL_1); + GT_REG_WRITE(MPP_CONTROL2, CFG_MPP_CONTROL_2); + GT_REG_WRITE(MPP_CONTROL3, CFG_MPP_CONTROL_3); + + GT_REG_WRITE(GPP_LEVEL_CONTROL, CFG_GPP_LEVEL_CONTROL); + GT_REG_WRITE(SERIAL_PORT_MULTIPLEX, CFG_SERIAL_PORT_MUX); + + return 0; +} + +/* various things to do after relocation */ + +int misc_init_r (void) +{ + icache_enable(); +#ifdef CFG_L2 + l2cache_enable(); +#endif + +#ifdef CONFIG_MPSC + mpsc_init2(); +#endif + +#ifdef CONFIG_ZUMA_V2 + zuma_mbox_init(); +#endif + return (0); +} + +void +after_reloc(ulong dest_addr) +{ + DECLARE_GLOBAL_DATA_PTR; + + /* check to see if we booted from the sram. If so, move things + * back to the way they should be. (we're running from main + * memory at this point now */ + + if (memoryGetDeviceBaseAddress(DEVICE0) == CFG_MONITOR_BASE) { + memoryMapDeviceSpace(DEVICE0, CFG_DEV0_SPACE, CFG_DEV0_SIZE); + memoryMapDeviceSpace(BOOT_DEVICE, CFG_FLASH_BASE, _1M); + } + + /* now, jump to the main U-Boot board init code */ + board_init_r ((gd_t *)gd, dest_addr); + + /* NOTREACHED */ +} + +/* ------------------------------------------------------------------------- */ + +/* + * Check Board Identity: + */ + +int +checkboard (void) +{ + puts ("Board: " CFG_BOARD_NAME "\n"); + return (0); +} + +/* utility functions */ +void +debug_led(int led, int mode) +{ +#if !defined(CONFIG_ZUMA_V2) && !defined(CONFIG_P3G4) + volatile int *addr = NULL; + int dummy; + + if (mode == 1) { + switch (led) { + case 0: + addr = (int *)((unsigned int)CFG_DEV1_SPACE | 0x08000); + break; + + case 1: + addr = (int *)((unsigned int)CFG_DEV1_SPACE | 0x0c000); + break; + + case 2: + addr = (int *)((unsigned int)CFG_DEV1_SPACE | 0x10000); + break; + } + } else if (mode == 0) { + switch (led) { + case 0: + addr = (int *)((unsigned int)CFG_DEV1_SPACE | 0x14000); + break; + + case 1: + addr = (int *)((unsigned int)CFG_DEV1_SPACE | 0x18000); + break; + + case 2: + addr = (int *)((unsigned int)CFG_DEV1_SPACE | 0x1c000); + break; + } + } + WRITE_CHAR(addr, 0); + dummy = *addr; +#endif /* CONFIG_ZUMA_V2 */ +} + +void +display_mem_map(void) +{ + int i,j; + unsigned int base,size,width; + /* SDRAM */ + printf("SDRAM\n"); + for(i=0;i<=BANK3;i++) { + base = memoryGetBankBaseAddress(i); + size = memoryGetBankSize(i); + if(size !=0) + { + printf("BANK%d: base - 0x%08x\tsize - %dM bytes\n",i,base,size>>20); + } + } + + /* CPU's PCI windows */ + for(i=0;i<=PCI_HOST1;i++) { + printf("\nCPU's PCI %d windows\n", i); + base=pciGetSpaceBase(i,PCI_IO); + size=pciGetSpaceSize(i,PCI_IO); + printf(" IO: base - 0x%08x\tsize - %dM bytes\n",base,size>>20); + for(j=0;j<=PCI_REGION3;j++) { + base = pciGetSpaceBase(i,j); + size = pciGetSpaceSize(i,j); + printf("MEMORY %d: base - 0x%08x\tsize - %dM bytes\n",j,base, + size>>20); + } + } + + /* Devices */ + printf("\nDEVICES\n"); + for(i=0;i<=DEVICE3;i++) { + base = memoryGetDeviceBaseAddress(i); + size = memoryGetDeviceSize(i); + width= memoryGetDeviceWidth(i) * 8; + printf("DEV %d: base - 0x%08x\tsize - %dM bytes\twidth - %d bits\n", + i, base, size>>20, width); + } + + /* Bootrom */ + base = memoryGetDeviceBaseAddress(BOOT_DEVICE); /* Boot */ + size = memoryGetDeviceSize(BOOT_DEVICE); + width= memoryGetDeviceWidth(BOOT_DEVICE) * 8; + printf(" BOOT: base - 0x%08x\tsize - %dM bytes\twidth - %d bits\n", + base, size>>20, width); +} diff --git a/board/evb64260/flash.c b/board/evb64260/flash.c new file mode 100755 index 0000000..6ab23dc --- /dev/null +++ b/board/evb64260/flash.c @@ -0,0 +1,854 @@ +/* + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 + */ + +/* + * flash.c - flash support for the 512k, 8bit boot flash on the GEVB + * most of this file was based on the existing U-Boot + * flash drivers. + */ + +#include <common.h> +#include <mpc8xx.h> +#include <galileo/gt64260R.h> +#include <galileo/memory.h> +#include "intel_flash.h" + +#define FLASH_ROM 0xFFFD /* unknown flash type */ +#define FLASH_RAM 0xFFFE /* unknown flash type */ +#define FLASH_MAN_UNKNOWN 0xFFFF0000 + +/* #define DEBUG */ +/* #define FLASH_ID_OVERRIDE */ /* Hack to set type to 040B if ROM emulator is installed. + * Can be used to program a ROM in circuit if a programmer + * is not available by swapping the rom out. */ + +/* Intel flash commands */ +int flash_erase_intel(flash_info_t *info, int s_first, int s_last); +int write_word_intel(bank_addr_t addr, bank_word_t value); + +flash_info_t flash_info[CFG_MAX_FLASH_BANKS]; /* info for FLASH chips */ + +/*----------------------------------------------------------------------- + * Functions + */ +static ulong flash_get_size (int portwidth, vu_long *addr, flash_info_t *info); +static int write_word (flash_info_t *info, ulong dest, ulong data); +static void flash_get_offsets (ulong base, flash_info_t *info); +static flash_info_t *flash_get_info(ulong base); + +/*----------------------------------------------------------------------- + */ + +unsigned long +flash_init (void) +{ + unsigned int i; + unsigned long size_b0 = 0, size_b1 = 0; + unsigned long base, flash_size; + + /* Init: no FLASHes known */ + for (i=0; i<CFG_MAX_FLASH_BANKS; ++i) { + flash_info[i].flash_id = FLASH_UNKNOWN; + } + + /* the boot flash */ + base = CFG_FLASH_BASE; +#ifndef CFG_BOOT_FLASH_WIDTH +#define CFG_BOOT_FLASH_WIDTH 1 +#endif + size_b0 = flash_get_size(CFG_BOOT_FLASH_WIDTH, (vu_long *)base, + &flash_info[0]); + +#ifndef CONFIG_P3G4 + printf("["); + print_size (size_b0, ""); + printf("@%08lX] ", base); +#endif + + if (flash_info[0].flash_id == FLASH_UNKNOWN) { + printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n", + base, size_b0, size_b0<<20); + } + + base = memoryGetDeviceBaseAddress(CFG_EXTRA_FLASH_DEVICE); + for(i=1;i<CFG_MAX_FLASH_BANKS;i++) { + unsigned long size = flash_get_size(CFG_EXTRA_FLASH_WIDTH, (vu_long *)base, &flash_info[i]); + +#ifndef CONFIG_P3G4 + printf("["); + print_size (size, ""); + printf("@%08lX] ", base); +#endif + + if (flash_info[i].flash_id == FLASH_UNKNOWN) { + if(i==1) { + printf ("## Unknown FLASH at %08lx: Size = 0x%08lx = %ld MB\n", + base, size_b1, size_b1<<20); + } + break; + } + size_b1+=size; + base+=size; + } + +#if CFG_MONITOR_BASE >= CFG_FLASH_BASE + /* monitor protection ON by default */ + flash_protect(FLAG_PROTECT_SET, + CFG_MONITOR_BASE, + CFG_MONITOR_BASE + monitor_flash_len - 1, + flash_get_info(CFG_MONITOR_BASE)); +#endif + +#ifdef CFG_ENV_IS_IN_FLASH + /* ENV protection ON by default */ + flash_protect(FLAG_PROTECT_SET, + CFG_ENV_ADDR, + CFG_ENV_ADDR + CFG_ENV_SIZE - 1, + flash_get_info(CFG_ENV_ADDR)); +#endif + + flash_size = size_b0 + size_b1; + return flash_size; +} + +/*----------------------------------------------------------------------- + */ +static void +flash_get_offsets (ulong base, flash_info_t *info) +{ + int i; + int sector_size; + + if(!info->sector_count) return; + + /* set up sector start address table */ + switch(info->flash_id & FLASH_TYPEMASK) { + case FLASH_AM040: + case FLASH_28F128J3A: + case FLASH_28F640J3A: + case FLASH_RAM: + /* this chip has uniformly spaced sectors */ + sector_size=info->size/info->sector_count; + for (i = 0; i < info->sector_count; i++) + info->start[i] = base + (i * sector_size); + break; + default: + if (info->flash_id & FLASH_BTYPE) { + /* set sector offsets for bottom boot block type */ + info->start[0] = base + 0x00000000; + info->start[1] = base + 0x00008000; + info->start[2] = base + 0x0000C000; + info->start[3] = base + 0x00010000; + for (i = 4; i < info->sector_count; i++) { + info->start[i] = base + (i * 0x00020000) - 0x00060000; + } + } else { + /* set sector offsets for top boot block type */ + i = info->sector_count - 1; + info->start[i--] = base + info->size - 0x00008000; + info->start[i--] = base + info->size - 0x0000C000; + info->start[i--] = base + info->size - 0x00010000; + for (; i >= 0; i--) { + info->start[i] = base + i * 0x00020000; + } + } + } +} + +/*----------------------------------------------------------------------- + */ + +static flash_info_t *flash_get_info(ulong base) +{ + int i; + flash_info_t * info; + + for (i = 0; i < CFG_MAX_FLASH_BANKS; i ++) { + info = & flash_info[i]; + if (info->start[0] <= base && base <= info->start[0] + info->size - 1) + break; + } + + return i == CFG_MAX_FLASH_BANKS ? 0 : info; +} + +/*----------------------------------------------------------------------- + */ +void +flash_print_info (flash_info_t *info) +{ + int i; + + if (info->flash_id == FLASH_UNKNOWN) { + printf ("missing or unknown FLASH type\n"); + return; + } + + switch (info->flash_id & FLASH_VENDMASK) { + case FLASH_MAN_AMD: printf ("AMD "); break; + case FLASH_MAN_FUJ: printf ("FUJITSU "); break; + case FLASH_MAN_INTEL: printf ("INTEL "); break; + default: printf ("Unknown Vendor "); break; + } + + switch (info->flash_id & FLASH_TYPEMASK) { + case FLASH_AM040: + printf ("AM29LV040B (4 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM400B: + printf ("AM29LV400B (4 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM400T: + printf ("AM29LV400T (4 Mbit, top boot sector)\n"); + break; + case FLASH_AM800B: + printf ("AM29LV800B (8 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM800T: + printf ("AM29LV800T (8 Mbit, top boot sector)\n"); + break; + case FLASH_AM160B: + printf ("AM29LV160B (16 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM160T: + printf ("AM29LV160T (16 Mbit, top boot sector)\n"); + break; + case FLASH_AM320B: + printf ("AM29LV320B (32 Mbit, bottom boot sect)\n"); + break; + case FLASH_AM320T: + printf ("AM29LV320T (32 Mbit, top boot sector)\n"); + break; + case FLASH_28F640J3A: + printf ("28F640J3A (64 Mbit)\n"); + break; + case FLASH_28F128J3A: + printf ("28F128J3A (128 Mbit)\n"); + break; + case FLASH_ROM: + printf ("ROM\n"); + break; + case FLASH_RAM: + printf ("RAM\n"); + break; + default: + printf ("Unknown Chip Type\n"); + break; + } + + puts (" Size: "); + print_size (info->size, ""); + printf (" in %d Sectors\n", info->sector_count); + + printf (" Sector Start Addresses:"); + for (i=0; i<info->sector_count; ++i) { + if ((i % 5) == 0) + printf ("\n "); + printf (" %08lX%s", + info->start[i], + info->protect[i] ? " (RO)" : " " + ); + } + printf ("\n"); + return; +} + +/*----------------------------------------------------------------------- + */ + + +/*----------------------------------------------------------------------- + */ + +/* + * The following code cannot be run from FLASH! + */ + +static inline void flash_cmd(int width, volatile unsigned char *addr, int offset, unsigned char cmd) +{ + /* supports 1x8, 1x16, and 2x16 */ + /* 2x8 and 4x8 are not supported */ + if(width==4) { + /* assuming chips are in 16 bit mode */ + /* 2x16 */ + unsigned long cmd32=(cmd<<16)|cmd; + *(volatile unsigned long *)(addr+offset*2)=cmd32; + } else if (width == 2) { + /* 1x16 */ + *(volatile unsigned short *)((unsigned short*)addr+offset)=cmd; + } else { + /* 1x8 */ + *(volatile unsigned char *)(addr+offset)=cmd; + } +} + +static ulong +flash_get_size (int portwidth, vu_long *addr, flash_info_t *info) +{ + short i; + volatile unsigned char *caddr = (unsigned char *)addr; + volatile unsigned short *saddr = (unsigned short *)addr; + volatile unsigned long *laddr = (unsigned long *)addr; + char old[2], save; + ulong id, manu, base = (ulong)addr; + + info->portwidth=portwidth; + + save = *caddr; + + flash_cmd(portwidth,caddr,0,0xf0); + flash_cmd(portwidth,caddr,0,0xf0); + + udelay(10); + + old[0] = caddr[0]; + old[1] = caddr[1]; + + + if(old[0]!=0xf0) { + flash_cmd(portwidth,caddr,0,0xf0); + flash_cmd(portwidth,caddr,0,0xf0); + + udelay(10); + + if(*caddr==0xf0) { + /* this area is ROM */ + *caddr=save; +#ifndef FLASH_ID_OVERRIDE + info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN; + info->sector_count = 8; + info->size = 0x80000; +#else + info->flash_id = FLASH_MAN_AMD + FLASH_AM040; + info->sector_count = 8; + info->size = 0x80000; + info->chipwidth=1; +#endif + flash_get_offsets(base, info); + return info->size; + } + } else { + *caddr=0; + + udelay(10); + + if(*caddr==0) { + /* this area is RAM */ + *caddr=save; + info->flash_id = FLASH_RAM + FLASH_MAN_UNKNOWN; + info->sector_count = 8; + info->size = 0x80000; + flash_get_offsets(base, info); + return info->size; + } + flash_cmd(portwidth,caddr,0,0xf0); + + udelay(10); + } + + /* Write auto select command: read Manufacturer ID */ + flash_cmd(portwidth,caddr,0x555,0xAA); + flash_cmd(portwidth,caddr,0x2AA,0x55); + flash_cmd(portwidth,caddr,0x555,0x90); + + udelay(10); + + if ((caddr[0] == old[0]) && + (caddr[1] == old[1])) { + + /* this area is ROM */ +#ifndef FLASH_ID_OVERRIDE + info->flash_id = FLASH_ROM + FLASH_MAN_UNKNOWN; + info->sector_count = 8; + info->size = 0x80000; +#else + info->flash_id = FLASH_MAN_AMD + FLASH_AM040; + info->sector_count = 8; + info->size = 0x80000; + info->chipwidth=1; +#endif + flash_get_offsets(base, info); + return info->size; +#ifdef DEBUG + } else { + printf("%px%d: %02x:%02x -> %02x:%02x\n", + caddr, portwidth, old[0], old[1], + caddr[0], caddr[1]); +#endif + } + + switch(portwidth) { + case 1: + manu = caddr[0]; + manu |= manu<<16; + id = caddr[1]; + break; + case 2: + manu = saddr[0]; + manu |= manu<<16; + id = saddr[1]; + id |= id<<16; + break; + case 4: + manu = laddr[0]; + id = laddr[1]; + break; + default: + id = manu = -1; + break; + } + +#ifdef DEBUG + printf("\n%08lx:%08lx:%08lx\n", base, manu, id); + printf("%08lx %08lx %08lx %08lx\n", + laddr[0],laddr[1],laddr[2],laddr[3]); +#endif + + switch (manu) { + case AMD_MANUFACT: + info->flash_id = FLASH_MAN_AMD; + break; + case FUJ_MANUFACT: + info->flash_id = FLASH_MAN_FUJ; + break; + case INTEL_MANUFACT: + info->flash_id = FLASH_MAN_INTEL; + break; + default: + printf("Unknown Mfr [%08lx]:%08lx\n", manu, id); + info->flash_id = FLASH_UNKNOWN; + info->sector_count = 0; + info->size = 0; + return (0); /* no or unknown flash */ + } + + switch (id) { + case AMD_ID_LV400T: + info->flash_id += FLASH_AM400T; + info->sector_count = 11; + info->size = 0x00100000; + info->chipwidth=1; + break; /* => 1 MB */ + + case AMD_ID_LV400B: + info->flash_id += FLASH_AM400B; + info->sector_count = 11; + info->size = 0x00100000; + info->chipwidth=1; + break; /* => 1 MB */ + + case AMD_ID_LV800T: + info->flash_id += FLASH_AM800T; + info->sector_count = 19; + info->size = 0x00200000; + info->chipwidth=1; + break; /* => 2 MB */ + + case AMD_ID_LV800B: + info->flash_id += FLASH_AM800B; + info->sector_count = 19; + info->size = 0x00200000; + info->chipwidth=1; + break; /* => 2 MB */ + + case AMD_ID_LV160T: + info->flash_id += FLASH_AM160T; + info->sector_count = 35; + info->size = 0x00400000; + info->chipwidth=1; + break; /* => 4 MB */ + + case AMD_ID_LV160B: + info->flash_id += FLASH_AM160B; + info->sector_count = 35; + info->size = 0x00400000; + info->chipwidth=1; + break; /* => 4 MB */ +#if 0 /* enable when device IDs are available */ + case AMD_ID_LV320T: + info->flash_id += FLASH_AM320T; + info->sector_count = 67; + info->size = 0x00800000; + break; /* => 8 MB */ + + case AMD_ID_LV320B: + info->flash_id += FLASH_AM320B; + info->sector_count = 67; + info->size = 0x00800000; + break; /* => 8 MB */ +#endif + case AMD_ID_LV040B: + info->flash_id += FLASH_AM040; + info->sector_count = 8; + info->size = 0x80000; + info->chipwidth=1; + break; + + case INTEL_ID_28F640J3A: + info->flash_id += FLASH_28F640J3A; + info->sector_count = 64; + info->size = 128*1024 * 64; /* 128kbytes x 64 blocks */ + info->chipwidth=2; + if(portwidth==4) info->size*=2; /* 2x16 */ + break; + + case INTEL_ID_28F128J3A: + info->flash_id += FLASH_28F128J3A; + info->sector_count = 128; + info->size = 128*1024 * 128; /* 128kbytes x 128 blocks */ + info->chipwidth=2; + if(portwidth==4) info->size*=2; /* 2x16 */ + break; + + default: + printf("Unknown id %lx:[%lx]\n", manu, id); + info->flash_id = FLASH_UNKNOWN; + info->chipwidth=1; + return (0); /* => no or unknown flash */ + + } + + flash_get_offsets(base, info); + +#if 0 + /* set up sector start address table */ + if (info->flash_id & FLASH_AM040) { + /* this chip has uniformly spaced sectors */ + for (i = 0; i < info->sector_count; i++) + info->start[i] = base + (i * 0x00010000); + + } else if (info->flash_id & FLASH_BTYPE) { + /* set sector offsets for bottom boot block type */ + info->start[0] = base + 0x00000000; + info->start[1] = base + 0x00008000; + info->start[2] = base + 0x0000C000; + info->start[3] = base + 0x00010000; + for (i = 4; i < info->sector_count; i++) { + info->start[i] = base + (i * 0x00020000) - 0x00060000; + } + } else { + /* set sector offsets for top boot block type */ + i = info->sector_count - 1; + info->start[i--] = base + info->size - 0x00008000; + info->start[i--] = base + info->size - 0x0000C000; + info->start[i--] = base + info->size - 0x00010000; + for (; i >= 0; i--) { + info->start[i] = base + i * 0x00020000; + } + } +#endif + + /* check for protected sectors */ + for (i = 0; i < info->sector_count; i++) { + /* read sector protection at sector address, (A7 .. A0)=0x02 */ + /* D0 = 1 if protected */ + caddr = (volatile unsigned char *)(info->start[i]); + saddr = (volatile unsigned short *)(info->start[i]); + laddr = (volatile unsigned long *)(info->start[i]); + if(portwidth==1) + info->protect[i] = caddr[2] & 1; + else if(portwidth==2) + info->protect[i] = saddr[2] & 1; + else + info->protect[i] = laddr[2] & 1; + } + + /* + * Prevent writes to uninitialized FLASH. + */ + if (info->flash_id != FLASH_UNKNOWN) { + caddr = (volatile unsigned char *)info->start[0]; + + flash_cmd(portwidth,caddr,0,0xF0); /* reset bank */ + } + + return (info->size); +} + +/* TODO: 2x16 unsupported */ +int +flash_erase (flash_info_t *info, int s_first, int s_last) +{ + volatile unsigned char *addr = (uchar *)(info->start[0]); + int flag, prot, sect, l_sect; + ulong start, now, last; + + /* TODO: 2x16 unsupported */ + if(info->portwidth==4) return 1; + + if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 1; + if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) { + for (sect = s_first; sect<=s_last; sect++) { + int sector_size=info->size/info->sector_count; + addr = (uchar *)(info->start[sect]); + memset((void *)addr, 0, sector_size); + } + return 0; + } + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf ("- missing\n"); + } else { + printf ("- no sectors to erase\n"); + } + return 1; + } + + if ((info->flash_id&FLASH_VENDMASK) == FLASH_MAN_INTEL) { + return flash_erase_intel(info, + (unsigned short)s_first, + (unsigned short)s_last); + } + +#if 0 + if ((info->flash_id == FLASH_UNKNOWN) || + (info->flash_id > FLASH_AMD_COMP)) { + printf ("Can't erase unknown flash type %08lx - aborted\n", + info->flash_id); + return 1; + } +#endif + + 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"); + } + + l_sect = -1; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + flash_cmd(info->portwidth,addr,0x555,0xAA); + flash_cmd(info->portwidth,addr,0x2AA,0x55); + flash_cmd(info->portwidth,addr,0x555,0x80); + flash_cmd(info->portwidth,addr,0x555,0xAA); + flash_cmd(info->portwidth,addr,0x2AA,0x55); + + /* Start erase on unprotected sectors */ + for (sect = s_first; sect<=s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + addr = (uchar *)(info->start[sect]); + flash_cmd(info->portwidth,addr,0,0x30); + l_sect = sect; + } + } + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + /* wait at least 80us - let's wait 1 ms */ + udelay (1000); + + /* + * We wait for the last triggered sector + */ + if (l_sect < 0) + goto DONE; + + start = get_timer (0); + last = start; + addr = (volatile unsigned char *)(info->start[l_sect]); + /* broken for 2x16: TODO */ + while ((addr[0] & 0x80) != 0x80) { + if ((now = get_timer(start)) > CFG_FLASH_ERASE_TOUT) { + printf ("Timeout\n"); + return 1; + } + /* show that we're waiting */ + if ((now - last) > 1000) { /* every second */ + putc ('.'); + last = now; + } + } + +DONE: + /* reset to read mode */ + addr = (volatile unsigned char *)info->start[0]; + flash_cmd(info->portwidth,addr,0,0xf0); + flash_cmd(info->portwidth,addr,0,0xf0); + + printf (" done\n"); + return 0; +} + +/*----------------------------------------------------------------------- + * Copy memory to flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ + +/* broken for 2x16: TODO */ +int +write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt) +{ + ulong cp, wp, data; + int i, l, rc; + + if(info->portwidth==4) return 1; + + if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 0; + if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) { + memcpy((void *)addr, src, cnt); + return 0; + } + + wp = (addr & ~3); /* get lower word aligned address */ + + /* + * handle unaligned start bytes + */ + if ((l = addr - wp) != 0) { + data = 0; + for (i=0, cp=wp; i<l; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + for (; i<4 && cnt>0; ++i) { + data = (data << 8) | *src++; + --cnt; + ++cp; + } + for (; cnt==0 && i<4; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + wp += 4; + } + + /* + * handle word aligned part + */ + while (cnt >= 4) { + data = 0; + for (i=0; i<4; ++i) { + data = (data << 8) | *src++; + } + if ((rc = write_word(info, wp, data)) != 0) { + return (rc); + } + wp += 4; + cnt -= 4; + } + + if (cnt == 0) { + return (0); + } + + /* + * handle unaligned tail bytes + */ + data = 0; + for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) { + data = (data << 8) | *src++; + --cnt; + } + for (; i<4; ++i, ++cp) { + data = (data << 8) | (*(uchar *)cp); + } + + return (write_word(info, wp, data)); +} + +/*----------------------------------------------------------------------- + * Write a word to Flash, returns: + * 0 - OK + * 1 - write timeout + * 2 - Flash not erased + */ +/* broken for 2x16: TODO */ +static int +write_word (flash_info_t *info, ulong dest, ulong data) +{ + volatile unsigned char *addr = (uchar *)(info->start[0]); + ulong start; + int flag, i; + + if(info->portwidth==4) return 1; + + if((info->flash_id & FLASH_TYPEMASK) == FLASH_ROM) return 1; + if((info->flash_id & FLASH_TYPEMASK) == FLASH_RAM) { + *(unsigned long *)dest=data; + return 0; + } + if ((info->flash_id & FLASH_VENDMASK) == FLASH_MAN_INTEL) { + unsigned short low = data & 0xffff; + unsigned short hi = (data >> 16) & 0xffff; + int ret = write_word_intel((bank_addr_t)dest, hi); + + if (!ret) ret = write_word_intel((bank_addr_t)(dest+2), low); + + return ret; + } + + /* Check if Flash is (sufficiently) erased */ + if ((*((vu_long *)dest) & data) != data) { + return (2); + } + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + /* first, perform an unlock bypass command to speed up flash writes */ + addr[0x555] = 0xAA; + addr[0x2AA] = 0x55; + addr[0x555] = 0x20; + + /* write each byte out */ + for (i = 0; i < 4; i++) { + char *data_ch = (char *)&data; + addr[0] = 0xA0; + *(((char *)dest)+i) = data_ch[i]; + udelay(10); /* XXX */ + } + + /* we're done, now do an unlock bypass reset */ + addr[0] = 0x90; + addr[0] = 0x00; + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + /* data polling for D7 */ + start = get_timer (0); + while ((*((vu_long *)dest) & 0x00800080) != (data & 0x00800080)) { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + return (1); + } + } + return (0); +} diff --git a/board/evb64260/i2c.c b/board/evb64260/i2c.c new file mode 100755 index 0000000..c62b647 --- /dev/null +++ b/board/evb64260/i2c.c @@ -0,0 +1,315 @@ +#include <common.h> +#include <mpc8xx.h> +#include <malloc.h> +#include <galileo/gt64260R.h> +#include <galileo/core.h> + +#define MAX_I2C_RETRYS 10 +#define I2C_DELAY 1000 /* Should be at least the # of MHz of Tclk */ +#undef DEBUG_I2C + +#ifdef DEBUG_I2C +#define DP(x) x +#else +#define DP(x) +#endif + +/* Assuming that there is only one master on the bus (us) */ + +static void +i2c_init(int speed, int slaveaddr) +{ + unsigned int n, m, freq, margin, power; + unsigned int actualFreq, actualN=0, actualM=0; + unsigned int control, status; + unsigned int minMargin = 0xffffffff; + unsigned int tclk = 125000000; + + DP(puts("i2c_init\n")); + + for(n = 0 ; n < 8 ; n++) + { + for(m = 0 ; m < 16 ; m++) + { + power = 2<<n; /* power = 2^(n+1) */ + freq = tclk/(10*(m+1)*power); + if (speed > freq) + margin = speed - freq; + else + margin = freq - speed; + if(margin < minMargin) + { + minMargin = margin; + actualFreq = freq; + actualN = n; + actualM = m; + } + } + } + + DP(puts("setup i2c bus\n")); + + /* Setup bus */ + + GT_REG_WRITE(I2C_SOFT_RESET, 0); + + DP(puts("udelay...\n")); + + udelay(I2C_DELAY); + + DP(puts("set baudrate\n")); + + GT_REG_WRITE(I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN); + GT_REG_WRITE(I2C_CONTROL, (0x1 << 2) | (0x1 << 6)); + + udelay(I2C_DELAY * 10); + + DP(puts("read control, baudrate\n")); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + GT_REG_READ(I2C_CONTROL, &control); +} + +static uchar +i2c_start(void) +{ + unsigned int control, status; + int count = 0; + + DP(puts("i2c_start\n")); + + /* Set the start bit */ + + GT_REG_READ(I2C_CONTROL, &control); + control |= (0x1 << 5); + GT_REG_WRITE(I2C_CONTROL, control); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + + count = 0; + while ((status & 0xff) != 0x08) { + udelay(I2C_DELAY); + if (count > 20) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return (status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + + return (0); +} + +static uchar +i2c_select_device(uchar dev_addr, uchar read, int ten_bit) +{ + unsigned int status, data, bits = 7; + int count = 0; + + DP(puts("i2c_select_device\n")); + + /* Output slave address */ + + if (ten_bit) { + bits = 10; + } + + data = (dev_addr << 1); + /* set the read bit */ + data |= read; + GT_REG_WRITE(I2C_DATA, data); + /* assert the address */ + RESET_REG_BITS(I2C_CONTROL, BIT3); + + udelay(I2C_DELAY); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count = 0; + while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) { + udelay(I2C_DELAY); + if (count > 20) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return(status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + + if (bits == 10) { + printf("10 bit I2C addressing not yet implemented\n"); + return (0xff); + } + + return (0); +} + +static uchar +i2c_get_data(uchar* return_data, int len) { + + unsigned int data, status = 0; + int count = 0; + + DP(puts("i2c_get_data\n")); + + while (len) { + + /* Get and return the data */ + + RESET_REG_BITS(I2C_CONTROL, (0x1 << 3)); + + udelay(I2C_DELAY * 5); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + while ((status & 0xff) != 0x50) { + udelay(I2C_DELAY); + if(count > 2) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return 0; + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + GT_REG_READ(I2C_DATA, &data); + len--; + *return_data = (uchar)data; + return_data++; + } + RESET_REG_BITS(I2C_CONTROL, BIT2|BIT3); + while ((status & 0xff) != 0x58) { + udelay(I2C_DELAY); + if(count > 200) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return (status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /* stop */ + + return (0); +} + +static uchar +i2c_write_data(unsigned int data, int len) +{ + unsigned int status; + int count = 0; + + DP(puts("i2c_write_data\n")); + + if (len > 4) + return -1; + + while (len) { + /* Set and assert the data */ + + GT_REG_WRITE(I2C_DATA, (unsigned int)data); + RESET_REG_BITS(I2C_CONTROL, (0x1 << 3)); + + udelay(I2C_DELAY); + + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + while ((status & 0xff) != 0x28) { + udelay(I2C_DELAY); + if(count > 20) { + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); /*stop*/ + return (status); + } + GT_REG_READ(I2C_STATUS_BAUDE_RATE, &status); + count++; + } + len--; + } + GT_REG_WRITE(I2C_CONTROL, (0x1 << 3) | (0x1 << 4)); + GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); + + udelay(I2C_DELAY * 10); + + return (0); +} + +static uchar +i2c_set_dev_offset(uchar dev_addr, unsigned int offset, int ten_bit) +{ + uchar status; + + DP(puts("i2c_set_dev_offset\n")); + + status = i2c_select_device(dev_addr, 0, ten_bit); + if (status) { +#ifdef DEBUG_I2C + printf("Failed to select device setting offset: 0x%02x\n", + status); +#endif + return status; + } + + status = i2c_write_data(offset, 1); + if (status) { +#ifdef DEBUG_I2C + printf("Failed to write data: 0x%02x\n", status); +#endif + return status; + } + + return (0); +} + +uchar +i2c_read(uchar dev_addr, unsigned int offset, int len, uchar* data, + int ten_bit) +{ + uchar status = 0; + unsigned int i2cFreq = 400000; + + DP(puts("i2c_read\n")); + + i2c_init(i2cFreq,0); + + status = i2c_start(); + + if (status) { +#ifdef DEBUG_I2C + printf("Transaction start failed: 0x%02x\n", status); +#endif + return status; + } + + status = i2c_set_dev_offset(dev_addr, 0, 0); + if (status) { +#ifdef DEBUG_I2C + printf("Failed to set offset: 0x%02x\n", status); +#endif + return status; + } + + i2c_init(i2cFreq,0); + + status = i2c_start(); + if (status) { +#ifdef DEBUG_I2C + printf("Transaction restart failed: 0x%02x\n", status); +#endif + return status; + } + + status = i2c_select_device(dev_addr, 1, ten_bit); + if (status) { +#ifdef DEBUG_I2C + printf("Address not acknowledged: 0x%02x\n", status); +#endif + return status; + } + + status = i2c_get_data(data, len); + if (status) { +#ifdef DEBUG_I2C + printf("Data not recieved: 0x%02x\n", status); +#endif + return status; + } + + return 0; +} diff --git a/board/evb64260/i2c.h b/board/evb64260/i2c.h new file mode 100755 index 0000000..9c21992 --- /dev/null +++ b/board/evb64260/i2c.h @@ -0,0 +1,7 @@ +#ifndef __I2C_H__ +#define __I2C_H__ + +/* function declarations */ +uchar i2c_read(uchar, unsigned int, int, uchar*, int); + +#endif diff --git a/board/evb64260/intel_flash.c b/board/evb64260/intel_flash.c new file mode 100755 index 0000000..ed6a2a0 --- /dev/null +++ b/board/evb64260/intel_flash.c @@ -0,0 +1,277 @@ +/* + * (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 + * + * Hacked for the Hymod board by Murray.Jensen@cmst.csiro.au, 20-Oct-00 + */ + +#include <common.h> +#include <mpc8xx.h> +#include <galileo/gt64260R.h> +#include <galileo/memory.h> +#include "intel_flash.h" + + +/*----------------------------------------------------------------------- + * Protection Flags: + */ +#define FLAG_PROTECT_SET 0x01 +#define FLAG_PROTECT_CLEAR 0x02 + +static void +bank_reset(flash_info_t *info, int sect) +{ + bank_addr_t addrw, eaddrw; + + addrw = (bank_addr_t)info->start[sect]; + eaddrw = BANK_ADDR_NEXT_WORD(addrw); + + while (addrw < eaddrw) { +#ifdef FLASH_DEBUG + printf(" writing reset cmd to addr 0x%08lx\n", + (unsigned long)addrw); +#endif + *addrw = BANK_CMD_RST; + addrw++; + } +} + +static void +bank_erase_init(flash_info_t *info, int sect) +{ + bank_addr_t addrw, saddrw, eaddrw; + int flag; + +#ifdef FLASH_DEBUG + printf("0x%08x BANK_CMD_PROG\n", BANK_CMD_PROG); + printf("0x%08x BANK_CMD_ERASE1\n", BANK_CMD_ERASE1); + printf("0x%08x BANK_CMD_ERASE2\n", BANK_CMD_ERASE2); + printf("0x%08x BANK_CMD_CLR_STAT\n", BANK_CMD_CLR_STAT); + printf("0x%08x BANK_CMD_RST\n", BANK_CMD_RST); + printf("0x%08x BANK_STAT_RDY\n", BANK_STAT_RDY); + printf("0x%08x BANK_STAT_ERR\n", BANK_STAT_ERR); +#endif + + saddrw = (bank_addr_t)info->start[sect]; + eaddrw = BANK_ADDR_NEXT_WORD(saddrw); + +#ifdef FLASH_DEBUG + printf("erasing sector %d, start addr = 0x%08lx " + "(bank next word addr = 0x%08lx)\n", sect, + (unsigned long)saddrw, (unsigned long)eaddrw); +#endif + + /* Disable intrs which might cause a timeout here */ + flag = disable_interrupts(); + + for (addrw = saddrw; addrw < eaddrw; addrw++) { +#ifdef FLASH_DEBUG + printf(" writing erase cmd to addr 0x%08lx\n", + (unsigned long)addrw); +#endif + *addrw = BANK_CMD_ERASE1; + *addrw = BANK_CMD_ERASE2; + } + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); +} + +static int +bank_erase_poll(flash_info_t *info, int sect) +{ + bank_addr_t addrw, saddrw, eaddrw; + int sectdone, haderr; + + saddrw = (bank_addr_t)info->start[sect]; + eaddrw = BANK_ADDR_NEXT_WORD(saddrw); + + sectdone = 1; + haderr = 0; + + for (addrw = saddrw; addrw < eaddrw; addrw++) { + bank_word_t stat = *addrw; + +#ifdef FLASH_DEBUG + printf(" checking status at addr " + "0x%08x [0x%08x]\n", + (unsigned long)addrw, stat); +#endif + if ((stat & BANK_STAT_RDY) != BANK_STAT_RDY) + sectdone = 0; + else if ((stat & BANK_STAT_ERR) != 0) { + printf(" failed on sector %d " + "(stat = 0x%08x) at " + "address 0x%p\n", + sect, stat, addrw); + *addrw = BANK_CMD_CLR_STAT; + haderr = 1; + } + } + + if (haderr) + return (-1); + else + return (sectdone); +} + +int +write_word_intel(bank_addr_t addr, bank_word_t value) +{ + bank_word_t stat; + ulong start; + int flag, retval; + + /* Disable interrupts which might cause a timeout here */ + flag = disable_interrupts(); + + *addr = BANK_CMD_PROG; + + *addr = value; + + /* re-enable interrupts if necessary */ + if (flag) + enable_interrupts(); + + retval = 0; + + /* data polling for D7 */ + start = get_timer (0); + do { + if (get_timer(start) > CFG_FLASH_WRITE_TOUT) { + retval = 1; + goto done; + } + stat = *addr; + } while ((stat & BANK_STAT_RDY) != BANK_STAT_RDY); + + if ((stat & BANK_STAT_ERR) != 0) { + printf("flash program failed (stat = 0x%08lx) " + "at address 0x%08lx\n", (ulong)stat, (ulong)addr); + *addr = BANK_CMD_CLR_STAT; + retval = 3; + } + +done: + /* reset to read mode */ + *addr = BANK_CMD_RST; + + return (retval); +} + +/*----------------------------------------------------------------------- + */ + +int +flash_erase_intel(flash_info_t *info, int s_first, int s_last) +{ + int prot, sect, haderr; + ulong start, now, last; + +#ifdef FLASH_DEBUG + printf("\nflash_erase: erase %d sectors (%d to %d incl.) from\n" + " Bank # %d: ", s_last - s_first + 1, s_first, s_last, + (info - flash_info) + 1); + flash_print_info(info); +#endif + + if ((s_first < 0) || (s_first > s_last)) { + if (info->flash_id == FLASH_UNKNOWN) { + printf ("- missing\n"); + } else { + printf ("- no sectors to erase\n"); + } + return 1; + } + + prot = 0; + for (sect=s_first; sect<=s_last; ++sect) { + if (info->protect[sect]) { + prot++; + } + } + + if (prot) { + printf("- Warning: %d protected sector%s will not be erased!\n", + prot, (prot > 1 ? "s" : "")); + } + + start = get_timer (0); + last = 0; + haderr = 0; + + for (sect = s_first; sect <= s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + ulong estart; + int sectdone; + + bank_erase_init(info, sect); + + /* wait at least 80us - let's wait 1 ms */ + udelay (1000); + + estart = get_timer(start); + + do { + now = get_timer(start); + + if (now - estart > CFG_FLASH_ERASE_TOUT) { + printf ("Timeout (sect %d)\n", sect); + haderr = 1; + break; + } + +#ifndef FLASH_DEBUG + /* show that we're waiting */ + if ((now - last) > 1000) { /* every second */ + putc ('.'); + last = now; + } +#endif + + sectdone = bank_erase_poll(info, sect); + + if (sectdone < 0) { + haderr = 1; + break; + } + + } while (!sectdone); + + if (haderr) + break; + } + } + + if (haderr > 0) + printf (" failed\n"); + else + printf (" done\n"); + + /* reset to read mode */ + for (sect = s_first; sect <= s_last; sect++) { + if (info->protect[sect] == 0) { /* not protected */ + bank_reset(info, sect); + } + } + return haderr; +} diff --git a/board/evb64260/intel_flash.h b/board/evb64260/intel_flash.h new file mode 100755 index 0000000..dc2aa00 --- /dev/null +++ b/board/evb64260/intel_flash.h @@ -0,0 +1,160 @@ +/*************** DEFINES for Intel StrataFlash FLASH chip ********************/ + +/* + * acceptable chips types are: + * + * 28F320J5, 28F640J5, 28F320J3A, 28F640J3A and 28F128J3A + */ + +/* register addresses, valid only following an CHIP_CMD_RD_ID command */ +#define CHIP_ADDR_REG_MAN 0x000000 /* manufacturer's id */ +#define CHIP_ADDR_REG_DEV 0x000001 /* device id */ +#define CHIP_ADDR_REG_CFGM 0x000003 /* master lock config */ +#define CHIP_ADDR_REG_CFG(b) (((b)<<16)|2) /* lock config for block b */ + +/* Commands */ +#define CHIP_CMD_RST 0xFF /* reset flash */ +#define CHIP_CMD_RD_ID 0x90 /* read the id and lock bits */ +#define CHIP_CMD_RD_QUERY 0x98 /* read device capabilities */ +#define CHIP_CMD_RD_STAT 0x70 /* read the status register */ +#define CHIP_CMD_CLR_STAT 0x50 /* clear the staus register */ +#define CHIP_CMD_WR_BUF 0xE8 /* clear the staus register */ +#define CHIP_CMD_PROG 0x40 /* program word command */ +#define CHIP_CMD_ERASE1 0x20 /* 1st word for block erase */ +#define CHIP_CMD_ERASE2 0xD0 /* 2nd word for block erase */ +#define CHIP_CMD_ERASE_SUSP 0xB0 /* suspend block erase */ +#define CHIP_CMD_LOCK 0x60 /* 1st word for all lock cmds */ +#define CHIP_CMD_SET_LOCK_BLK 0x01 /* 2nd wrd set block lock bit */ +#define CHIP_CMD_SET_LOCK_MSTR 0xF1 /* 2nd wrd set master lck bit */ +#define CHIP_CMD_CLR_LOCK_BLK 0xD0 /* 2nd wrd clear blk lck bit */ + +/* status register bits */ +#define CHIP_STAT_DPS 0x02 /* Device Protect Status */ +#define CHIP_STAT_VPPS 0x08 /* VPP Status */ +#define CHIP_STAT_PSLBS 0x10 /* Program+Set Lock Bit Stat */ +#define CHIP_STAT_ECLBS 0x20 /* Erase+Clr Lock Bit Stat */ +#define CHIP_STAT_ESS 0x40 /* Erase Suspend Status */ +#define CHIP_STAT_RDY 0x80 /* WSM Mach Status, 1=rdy */ + +#define CHIP_STAT_ERR (CHIP_STAT_VPPS | CHIP_STAT_DPS | \ + CHIP_STAT_ECLBS | CHIP_STAT_PSLBS) + +/* ID and Lock Configuration */ +#define CHIP_RD_ID_LOCK 0x01 /* Bit 0 of each byte */ +#define CHIP_RD_ID_MAN 0x89 /* Manufacturer code = 0x89 */ +#define CHIP_RD_ID_DEV CFG_FLASH_ID + +/* dimensions */ +#define CHIP_WIDTH 2 /* chips are in 16 bit mode */ +#define CHIP_WSHIFT 1 /* (log2 of CHIP_WIDTH) */ +#define CHIP_NBLOCKS 128 +#define CHIP_BLKSZ (128 * 1024) /* of 128Kbytes each */ +#define CHIP_SIZE (CHIP_BLKSZ * CHIP_NBLOCKS) + +/********************** DEFINES for Hymod Flash ******************************/ + +/* + * The hymod board has 2 x 28F320J5 chips running in + * 16 bit mode, for a 32 bit wide bank. + */ + +typedef unsigned short bank_word_t; /* 8/16/32/64bit unsigned int */ +typedef volatile bank_word_t *bank_addr_t; +typedef unsigned long bank_size_t; /* want this big - >= 32 bit */ + +#define BANK_CHIP_WIDTH 1 /* each bank is 1 chip wide */ +#define BANK_CHIP_WSHIFT 0 /* (log2 of BANK_CHIP_WIDTH) */ + +#define BANK_WIDTH (CHIP_WIDTH * BANK_CHIP_WIDTH) +#define BANK_WSHIFT (CHIP_WSHIFT + BANK_CHIP_WSHIFT) +#define BANK_NBLOCKS CHIP_NBLOCKS +#define BANK_BLKSZ (CHIP_BLKSZ * BANK_CHIP_WIDTH) +#define BANK_SIZE (CHIP_SIZE * BANK_CHIP_WIDTH) + +#define MAX_BANKS 1 /* only one bank possible */ + +/* align bank addresses and sizes to bank word boundaries */ +#define BANK_ADDR_WORD_ALIGN(a) ((bank_addr_t)((bank_size_t)(a) \ + & ~(BANK_WIDTH - 1))) +#define BANK_SIZE_WORD_ALIGN(s) ((bank_size_t)BANK_ADDR_WORD_ALIGN( \ + (bank_size_t)(s) + (BANK_WIDTH - 1))) + +/* align bank addresses and sizes to bank block boundaries */ +#define BANK_ADDR_BLK_ALIGN(a) ((bank_addr_t)((bank_size_t)(a) \ + & ~(BANK_BLKSZ - 1))) +#define BANK_SIZE_BLK_ALIGN(s) ((bank_size_t)BANK_ADDR_BLK_ALIGN( \ + (bank_size_t)(s) + (BANK_BLKSZ - 1))) + +/* align bank addresses and sizes to bank boundaries */ +#define BANK_ADDR_BANK_ALIGN(a) ((bank_addr_t)((bank_size_t)(a) \ + & ~(BANK_SIZE - 1))) +#define BANK_SIZE_BANK_ALIGN(s) ((bank_size_t)BANK_ADDR_BANK_ALIGN( \ + (bank_size_t)(s) + (BANK_SIZE - 1))) + +/* add an offset to a bank address */ +#define BANK_ADDR_OFFSET(a, o) (bank_addr_t)((bank_size_t)(a) + \ + (bank_size_t)(o)) + +/* get base address of bank b, given flash base address a */ +#define BANK_ADDR_BASE(a, b) BANK_ADDR_OFFSET(BANK_ADDR_BANK_ALIGN(a), \ + (bank_size_t)(b) * BANK_SIZE) + +/* adjust a bank address to start of next word, block or bank */ +#define BANK_ADDR_NEXT_WORD(a) BANK_ADDR_OFFSET(BANK_ADDR_WORD_ALIGN(a), \ + BANK_WIDTH) +#define BANK_ADDR_NEXT_BLK(a) BANK_ADDR_OFFSET(BANK_ADDR_BLK_ALIGN(a), \ + BANK_BLKSZ) +#define BANK_ADDR_NEXT_BANK(a) BANK_ADDR_OFFSET(BANK_ADDR_BANK_ALIGN(a), \ + BANK_SIZE) + +/* get bank address of chip register r given a bank base address a */ +#define BANK_ADDR_REG(a, r) BANK_ADDR_OFFSET(BANK_ADDR_BANK_ALIGN(a), \ + ((bank_size_t)(r) << BANK_WSHIFT)) + +/* make a bank address for each chip register address */ + +#define BANK_ADDR_REG_MAN(a) BANK_ADDR_REG((a), CHIP_ADDR_REG_MAN) +#define BANK_ADDR_REG_DEV(a) BANK_ADDR_REG((a), CHIP_ADDR_REG_DEV) +#define BANK_ADDR_REG_CFGM(a) BANK_ADDR_REG((a), CHIP_ADDR_REG_CFGM) +#define BANK_ADDR_REG_CFG(b,a) BANK_ADDR_REG((a), CHIP_ADDR_REG_CFG(b)) + +/* + * replicate a chip cmd/stat/rd value into each byte position within a word + * so that multiple chips are accessed in a single word i/o operation + * + * this must be as wide as the bank_word_t type, and take into account the + * chip width and bank layout + */ + +#define BANK_FILL_WORD(o) ((bank_word_t)(o)) + +/* make a bank word value for each chip cmd/stat/rd value */ + +/* Commands */ +#define BANK_CMD_RST BANK_FILL_WORD(CHIP_CMD_RST) +#define BANK_CMD_RD_ID BANK_FILL_WORD(CHIP_CMD_RD_ID) +#define BANK_CMD_RD_STAT BANK_FILL_WORD(CHIP_CMD_RD_STAT) +#define BANK_CMD_CLR_STAT BANK_FILL_WORD(CHIP_CMD_CLR_STAT) +#define BANK_CMD_ERASE1 BANK_FILL_WORD(CHIP_CMD_ERASE1) +#define BANK_CMD_ERASE2 BANK_FILL_WORD(CHIP_CMD_ERASE2) +#define BANK_CMD_PROG BANK_FILL_WORD(CHIP_CMD_PROG) +#define BANK_CMD_LOCK BANK_FILL_WORD(CHIP_CMD_LOCK) +#define BANK_CMD_SET_LOCK_BLK BANK_FILL_WORD(CHIP_CMD_SET_LOCK_BLK) +#define BANK_CMD_SET_LOCK_MSTR BANK_FILL_WORD(CHIP_CMD_SET_LOCK_MSTR) +#define BANK_CMD_CLR_LOCK_BLK BANK_FILL_WORD(CHIP_CMD_CLR_LOCK_BLK) + +/* status register bits */ +#define BANK_STAT_DPS BANK_FILL_WORD(CHIP_STAT_DPS) +#define BANK_STAT_PSS BANK_FILL_WORD(CHIP_STAT_PSS) +#define BANK_STAT_VPPS BANK_FILL_WORD(CHIP_STAT_VPPS) +#define BANK_STAT_PSLBS BANK_FILL_WORD(CHIP_STAT_PSLBS) +#define BANK_STAT_ECLBS BANK_FILL_WORD(CHIP_STAT_ECLBS) +#define BANK_STAT_ESS BANK_FILL_WORD(CHIP_STAT_ESS) +#define BANK_STAT_RDY BANK_FILL_WORD(CHIP_STAT_RDY) + +#define BANK_STAT_ERR BANK_FILL_WORD(CHIP_STAT_ERR) + +/* ID and Lock Configuration */ +#define BANK_RD_ID_LOCK BANK_FILL_WORD(CHIP_RD_ID_LOCK) +#define BANK_RD_ID_MAN BANK_FILL_WORD(CHIP_RD_ID_MAN) +#define BANK_RD_ID_DEV BANK_FILL_WORD(CHIP_RD_ID_DEV) diff --git a/board/evb64260/local.h b/board/evb64260/local.h new file mode 100755 index 0000000..3d9b443 --- /dev/null +++ b/board/evb64260/local.h @@ -0,0 +1,62 @@ +/* + * include/local.h - local configuration options, board specific + */ + +#ifndef __LOCAL_H +#define __LOCAL_H + +/* + * High Level Configuration Options + * (easy to change) + */ + +/* This tells U-Boot that the config options are compiled in */ +/* #undef ENV_IS_EMBEDDED */ +/* Don't touch this! U-Boot figures this out based on other + * magic. */ + +/* Uncomment and define any of the below options */ + +/* #define CONFIG_750CX */ /* The 750CX doesn't support as many things in L2CR */ + /* Note: If you defined CONFIG_EVB64260_750CX this */ + /* gets defined automatically. */ + +/* These want string arguments */ +/* #define CONFIG_BOOTARGS */ +/* #define CONFIG_BOOTCOMMAND */ +/* #define CONFIG_RAMBOOTCOMMAND */ +/* #define CONFIG_NFSBOOTCOMMAND */ +/* #define CFG_AUTOLOAD */ +/* #define CONFIG_PREBOOT */ + +/* These don't */ + +/* #define CONFIG_BOOTDELAY */ +/* #define CONFIG_BAUDRATE */ +/* #define CONFIG_LOADS_ECHO */ +/* #define CONFIG_ETHADDR */ +/* #define CONFIG_ETH2ADDR */ +/* #define CONFIG_ETH3ADDR */ +/* #define CONFIG_IPADDR */ +/* #define CONFIG_SERVERIP */ +/* #define CONFIG_ROOTPATH */ +/* #define CONFIG_GATEWAYIP */ +/* #define CONFIG_NETMASK */ +/* #define CONFIG_HOSTNAME */ +/* #define CONFIG_BOOTFILE */ +/* #define CONFIG_LOADADDR */ + +/* these hardware addresses are pretty bogus, please change them to + suit your needs */ + +/* first ethernet */ +#define CONFIG_ETHADDR 00:11:22:33:44:55 + +/* next two ethernet hwaddrs */ +#define CONFIG_HAS_ETH1 +#define CONFIG_ETH1ADDR 00:11:22:33:44:66 +#define CONFIG_HAS_ETH2 +#define CONFIG_ETH2ADDR 00:11:22:33:44:77 + +#define CONFIG_ENV_OVERWRITE +#endif /* __CONFIG_H */ diff --git a/board/evb64260/memory.c b/board/evb64260/memory.c new file mode 100755 index 0000000..e339854 --- /dev/null +++ b/board/evb64260/memory.c @@ -0,0 +1,457 @@ +/* Memory.c - Memory mappings and remapping functions */ + +/* Copyright - Galileo technology. */ + +/* modified by Josh Huber to clean some things up, and + * fit it into the U-Boot framework */ + +#include <galileo/core.h> +#include <galileo/memory.h> + +/******************************************************************** +* memoryGetBankBaseAddress - Gets the base address of a memory bank +* - If the memory bank size is 0 then this base address has no meaning!!! +* +* +* INPUTS: MEMORY_BANK bank - The bank we ask for its base Address. +* OUTPUT: N/A +* RETURNS: Memory bank base address. +*********************************************************************/ +static unsigned long memoryGetBankRegOffset(MEMORY_BANK bank) +{ + switch (bank) + { + case BANK0: + return SCS_0_LOW_DECODE_ADDRESS; + case BANK1: + return SCS_1_LOW_DECODE_ADDRESS; + case BANK2: + return SCS_2_LOW_DECODE_ADDRESS; + case BANK3: + return SCS_3_LOW_DECODE_ADDRESS; + } + return SCS_0_LOW_DECODE_ADDRESS; /* default value */ +} + +unsigned int memoryGetBankBaseAddress(MEMORY_BANK bank) +{ + unsigned int base; + unsigned int regOffset=memoryGetBankRegOffset(bank); + + GT_REG_READ(regOffset,&base); + base = base << 20; + return base; +} + +/******************************************************************** +* memoryGetDeviceBaseAddress - Gets the base address of a device. +* - If the device size is 0 then this base address has no meaning!!! +* +* +* INPUT: DEVICE device - The device we ask for its base address. +* OUTPUT: N/A +* RETURNS: Device base address. +*********************************************************************/ +static unsigned int memoryGetDeviceRegOffset(DEVICE device) +{ + switch (device) + { + case DEVICE0: + return CS_0_LOW_DECODE_ADDRESS; + case DEVICE1: + return CS_1_LOW_DECODE_ADDRESS; + case DEVICE2: + return CS_2_LOW_DECODE_ADDRESS; + case DEVICE3: + return CS_3_LOW_DECODE_ADDRESS; + case BOOT_DEVICE: + return BOOTCS_LOW_DECODE_ADDRESS; + } + return CS_0_LOW_DECODE_ADDRESS; /* default value */ +} + +unsigned int memoryGetDeviceBaseAddress(DEVICE device) +{ + unsigned int regBase; + unsigned int regEnd; + unsigned int regOffset=memoryGetDeviceRegOffset(device); + + GT_REG_READ(regOffset, ®Base); + GT_REG_READ(regOffset+8, ®End); + + if(regEnd<=regBase) return 0xffffffff; /* ERROR !!! */ + + regBase = regBase << 20; + return regBase; +} + +/******************************************************************** +* memoryGetBankSize - Returns the size of a memory bank. +* +* +* INPUT: MEMORY_BANK bank - The bank we ask for its size. +* OUTPUT: N/A +* RETURNS: Memory bank size. +*********************************************************************/ +unsigned int memoryGetBankSize(MEMORY_BANK bank) +{ + unsigned int size,base; + unsigned int highValue; + unsigned int highAddress=memoryGetBankRegOffset(bank)+8; + + base = memoryGetBankBaseAddress(bank); + GT_REG_READ(highAddress,&highValue); + highValue = (highValue + 1) << 20; + if(base > highValue) + size=0; + else + size = highValue - base; + return size; +} + +/******************************************************************** +* memoryGetDeviceSize - Returns the size of a device memory space +* +* +* INPUT: DEVICE device - The device we ask for its base address. +* OUTPUT: N/A +* RETURNS: Size of a device memory space. +*********************************************************************/ +unsigned int memoryGetDeviceSize(DEVICE device) +{ + unsigned int size,base; + unsigned int highValue; + unsigned int highAddress=memoryGetDeviceRegOffset(device)+8; + + base = memoryGetDeviceBaseAddress(device); + GT_REG_READ(highAddress,&highValue); + if (highValue == 0xfff) + { + size = (~base) + 1; /* what the heck is this? */ + return size; + } + else + highValue = (highValue + 1) << 20; + + if(base > highValue) + size=0; + else + size = highValue - base; + return size; +} + +/******************************************************************** +* memoryGetDeviceWidth - A device can be with: 1,2,4 or 8 Bytes data width. +* The width is determine in registers: 'Device Parameters' +* registers (0x45c, 0x460, 0x464, 0x468, 0x46c - for each device. +* at bits: [21:20]. +* +* INPUT: DEVICE device - Device number +* OUTPUT: N/A +* RETURNS: Device width in Bytes (1,2,4 or 8), 0 if error had occurred. +*********************************************************************/ +unsigned int memoryGetDeviceWidth(DEVICE device) +{ + unsigned int width; + unsigned int regValue; + + GT_REG_READ(DEVICE_BANK0PARAMETERS + device*4,®Value); + width = (regValue & 0x00300000) >> 20; + switch (width) + { + case 0: + return 1; + case 1: + return 2; + case 2: + return 4; + case 3: + return 8; + default: + return 0; + } +} + +bool memoryMapBank(MEMORY_BANK bank, unsigned int bankBase,unsigned int bankLength) +{ + unsigned int low=0xfff; + unsigned int high=0x0; + unsigned int regOffset=memoryGetBankRegOffset(bank); + + if(bankLength!=0) { + low = (bankBase >> 20) & 0xffff; + high=((bankBase+bankLength)>>20)-1; + } + +#ifdef DEBUG + { + unsigned int oldLow, oldHigh; + GT_REG_READ(regOffset,&oldLow); + GT_REG_READ(regOffset+8,&oldHigh); + + printf("b%d %x-%x->%x-%x\n", bank, oldLow, oldHigh, low, high); + } +#endif + + GT_REG_WRITE(regOffset,low); + GT_REG_WRITE(regOffset+8,high); + + return true; +} +bool memoryMapDeviceSpace(DEVICE device, unsigned int deviceBase,unsigned int deviceLength) +{ + /* TODO: what are appropriate "unmapped" values? */ + unsigned int low=0xfff; + unsigned int high=0x0; + unsigned int regOffset=memoryGetDeviceRegOffset(device); + + if(deviceLength != 0) { + low=deviceBase>>20; + high=((deviceBase+deviceLength)>>20)-1; + } else { + /* big problems in here... */ + /* this will HANG */ + } + + GT_REG_WRITE(regOffset,low); + GT_REG_WRITE(regOffset+8,high); + + return true; +} + + +/******************************************************************** +* memoryMapInternalRegistersSpace - Sets new base address for the internals +* registers. +* +* INPUTS: unsigned int internalRegBase - The new base address. +* RETURNS: true on success, false on failure +*********************************************************************/ +bool memoryMapInternalRegistersSpace(unsigned int internalRegBase) +{ + unsigned int currentValue; + unsigned int internalValue = internalRegBase; + + internalRegBase = (internalRegBase >> 20); + GT_REG_READ(INTERNAL_SPACE_DECODE,¤tValue); + internalRegBase = (currentValue & 0xffff0000) | internalRegBase; + GT_REG_WRITE(INTERNAL_SPACE_DECODE,internalRegBase); + INTERNAL_REG_BASE_ADDR = internalValue; + return true; +} + +/******************************************************************** +* memoryGetInternalRegistersSpace - Gets internal registers Base Address. +* +* INPUTS: unsigned int internalRegBase - The new base address. +* RETURNS: true on success, false on failure +*********************************************************************/ +unsigned int memoryGetInternalRegistersSpace(void) +{ + return INTERNAL_REG_BASE_ADDR; +} + +/******************************************************************** +* memorySetProtectRegion - This function modifys one of the 8 regions with +* one of the three protection mode. +* - Be advised to check the spec before modifying them. +* +* +* Inputs: CPU_PROTECT_REGION - one of the eight regions. +* CPU_ACCESS - general access. +* CPU_WRITE - read only access. +* CPU_CACHE_PROTECT - chache access. +* we defining CPU because there is another protect from the pci SIDE. +* Returns: false if one of the parameters is wrong and true else +*********************************************************************/ +bool memorySetProtectRegion(MEMORY_PROTECT_REGION region, + MEMORY_ACCESS memAccess, + MEMORY_ACCESS_WRITE memWrite, + MEMORY_CACHE_PROTECT cacheProtection, + unsigned int baseAddress, + unsigned int regionLength) +{ + unsigned int protectHigh = baseAddress + regionLength; + + if(regionLength == 0) /* closing the region */ + { + GT_REG_WRITE(CPU_LOW_PROTECT_ADDRESS_0 + 0x10*region,0x0000ffff); + GT_REG_WRITE(CPU_HIGH_PROTECT_ADDRESS_0 + 0x10*region,0); + return true; + } + baseAddress = (baseAddress & 0xfff00000) >> 20; + baseAddress = baseAddress | memAccess << 16 | memWrite << 17 + | cacheProtection << 18; + GT_REG_WRITE(CPU_LOW_PROTECT_ADDRESS_0 + 0x10*region,baseAddress); + protectHigh = (protectHigh & 0xfff00000) >> 20; + GT_REG_WRITE(CPU_HIGH_PROTECT_ADDRESS_0 + 0x10*region,protectHigh - 1); + return true; +} + +/******************************************************************** +* memorySetRegionSnoopMode - This function modifys one of the 4 regions which +* supports Cache Coherency. +* +* +* Inputs: SNOOP_REGION region - One of the four regions. +* SNOOP_TYPE snoopType - There is four optional Types: +* 1. No Snoop. +* 2. Snoop to WT region. +* 3. Snoop to WB region. +* 4. Snoop & Invalidate to WB region. +* unsigned int baseAddress - Base Address of this region. +* unsigned int topAddress - Top Address of this region. +* Returns: false if one of the parameters is wrong and true else +*********************************************************************/ +bool memorySetRegionSnoopMode(MEMORY_SNOOP_REGION region, + MEMORY_SNOOP_TYPE snoopType, + unsigned int baseAddress, + unsigned int regionLength) +{ + unsigned int snoopXbaseAddress; + unsigned int snoopXtopAddress; + unsigned int data; + unsigned int snoopHigh = baseAddress + regionLength; + + if( (region > MEM_SNOOP_REGION3) || (snoopType > MEM_SNOOP_WB) ) + return false; + snoopXbaseAddress = SNOOP_BASE_ADDRESS_0 + 0x10 * region; + snoopXtopAddress = SNOOP_TOP_ADDRESS_0 + 0x10 * region; + if(regionLength == 0) /* closing the region */ + { + GT_REG_WRITE(snoopXbaseAddress,0x0000ffff); + GT_REG_WRITE(snoopXtopAddress,0); + return true; + } + baseAddress = baseAddress & 0xffff0000; + data = (baseAddress >> 16) | snoopType << 16; + GT_REG_WRITE(snoopXbaseAddress,data); + snoopHigh = (snoopHigh & 0xfff00000) >> 20; + GT_REG_WRITE(snoopXtopAddress,snoopHigh - 1); + return true; +} + +/******************************************************************** +* memoryRemapAddress - This fubction used for address remapping. +* +* +* Inputs: regOffset: remap register +* remapValue : +* Returns: false if one of the parameters is erroneous,true otherwise. +*********************************************************************/ +bool memoryRemapAddress(unsigned int remapReg, unsigned int remapValue) +{ + unsigned int valueForReg; + valueForReg = (remapValue & 0xfff00000) >> 20; + GT_REG_WRITE(remapReg, valueForReg); + return true; +} + +/******************************************************************** +* memoryGetDeviceParam - This function used for getting device parameters from +* DEVICE BANK PARAMETERS REGISTER +* +* +* Inputs: - deviceParam: STRUCT with paramiters for DEVICE BANK +* PARAMETERS REGISTER +* - deviceNum : number of device +* Returns: false if one of the parameters is erroneous,true otherwise. +*********************************************************************/ +bool memoryGetDeviceParam(DEVICE_PARAM *deviceParam, DEVICE deviceNum) +{ + unsigned int valueOfReg; + unsigned int calcData; + + GT_REG_READ(DEVICE_BANK0PARAMETERS + 4 * deviceNum, &valueOfReg); + calcData = (0x7 & valueOfReg) + ((0x400000 & valueOfReg) >> 19); + deviceParam -> turnOff = calcData; /* Turn Off */ + + calcData = ((0x78 & valueOfReg) >> 3) + ((0x800000 & valueOfReg) >> 19); + deviceParam -> acc2First = calcData; /* Access To First */ + + calcData = ((0x780 & valueOfReg) >> 7) + ((0x1000000 & valueOfReg) >> 20); + deviceParam -> acc2Next = calcData; /* Access To Next */ + + calcData = ((0x3800 & valueOfReg) >> 11) + ((0x2000000 & valueOfReg) >> 22); + deviceParam -> ale2Wr = calcData; /* Ale To Write */ + + calcData = ((0x1c000 & valueOfReg) >> 14) + ((0x4000000 & valueOfReg) >> 23); + deviceParam -> wrLow = calcData; /* Write Active */ + + calcData = ((0xe0000 & valueOfReg) >> 17) + ((0x8000000 & valueOfReg) >> 24); + deviceParam -> wrHigh = calcData; /* Write High */ + + calcData = ((0x300000 & valueOfReg) >> 20); + switch (calcData) + { + case 0: + deviceParam -> deviceWidth = 1; /* one Byte - 8-bit */ + break; + case 1: + deviceParam -> deviceWidth = 2; /* two Bytes - 16-bit */ + break; + case 2: + deviceParam -> deviceWidth = 4; /* four Bytes - 32-bit */ + break; + case 3: + deviceParam -> deviceWidth = 8; /* eight Bytes - 64-bit */ + break; + default: + deviceParam -> deviceWidth = 1; + break; + } + return true; +} + +/******************************************************************** +* memorySetDeviceParam - This function used for setting device parameters to +* DEVICE BANK PARAMETERS REGISTER +* +* +* Inputs: - deviceParam: STRUCT for store paramiters from DEVICE BANK +* PARAMETERS REGISTER +* - deviceNum : number of device +* Returns: false if one of the parameters is erroneous,true otherwise. +*********************************************************************/ +bool memorySetDeviceParam(DEVICE_PARAM *deviceParam, DEVICE deviceNum) +{ + unsigned int valueForReg; + + if((deviceParam -> turnOff >= 0xf) || (deviceParam -> acc2First >= 0x1f) || + (deviceParam -> acc2Next >= 0x1f) || (deviceParam -> ale2Wr >= 0xf) || + (deviceParam -> wrLow >= 0xf) || (deviceParam -> wrHigh >= 0xf)) + return false; + valueForReg = (((deviceParam -> turnOff) & 0x7) | + (((deviceParam -> turnOff) & 0x8) << 19) | + (((deviceParam -> acc2First) & 0xf) << 3) | + (((deviceParam -> acc2First) & 0x10) << 19) | + (((deviceParam -> acc2Next) & 0xf) << 7) | + (((deviceParam -> acc2Next) & 0x10) << 20) | + (((deviceParam -> ale2Wr) & 0x7) << 11) | + (((deviceParam -> ale2Wr) & 0xf) << 22) | + (((deviceParam -> wrLow) & 0x7) << 14) | + (((deviceParam -> wrLow) & 0xf) << 23) | + (((deviceParam -> wrHigh) & 0x7) << 17) | + (((deviceParam -> wrHigh) & 0xf) << 24)); + /* insert the device width: */ + switch(deviceParam->deviceWidth) + { + case 1: + valueForReg = valueForReg | _8BIT; + break; + case 2: + valueForReg = valueForReg | _16BIT; + break; + case 4: + valueForReg = valueForReg | _32BIT; + break; + case 8: + valueForReg = valueForReg | _64BIT; + break; + default: + valueForReg = valueForReg | _8BIT; + break; + } + GT_REG_WRITE(DEVICE_BANK0PARAMETERS + 4 * deviceNum, valueForReg); + return true; +} diff --git a/board/evb64260/misc.S b/board/evb64260/misc.S new file mode 100755 index 0000000..438dea6 --- /dev/null +++ b/board/evb64260/misc.S @@ -0,0 +1,182 @@ +#include <config.h> +#include <74xx_7xx.h> +#include <version.h> + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#include <galileo/gt64260R.h> + +#ifdef CONFIG_ECC + /* Galileo specific asm code for initializing ECC */ + .globl board_relocate_rom +board_relocate_rom: + mflr r7 + /* update the location of the GT registers */ + lis r11, CFG_GT_REGS@h + /* if we're using ECC, we must use the DMA engine to copy ourselves */ + bl start_idma_transfer_0 + bl wait_for_idma_0 + bl stop_idma_engine_0 + + mtlr r7 + blr + + .globl board_init_ecc +board_init_ecc: + mflr r7 + /* NOTE: r10 still contains the location we've been relocated to + * which happens to be TOP_OF_RAM - CFG_MONITOR_LEN */ + + /* now that we're running from ram, init the rest of main memory + * for ECC use */ + lis r8, CFG_MONITOR_LEN@h + ori r8, r8, CFG_MONITOR_LEN@l + + divw r3, r10, r8 + + /* set up the counter, and init the starting address */ + mtctr r3 + li r12, 0 + + /* bytes per transfer */ + mr r5, r8 +about_to_init_ecc: +1: mr r3, r12 + mr r4, r12 + bl start_idma_transfer_0 + bl wait_for_idma_0 + bl stop_idma_engine_0 + add r12, r12, r8 + bdnz 1b + + mtlr r7 + blr + + /* r3: dest addr + * r4: source addr + * r5: byte count + * r11: gt regbase + * trashes: r6, r5 + */ +start_idma_transfer_0: + /* set the byte count, including the OWN bit */ + mr r6, r11 + ori r6, r6, CHANNEL0_DMA_BYTE_COUNT + stwbrx r5, 0, (r6) + + /* set the source address */ + mr r6, r11 + ori r6, r6, CHANNEL0_DMA_SOURCE_ADDRESS + stwbrx r4, 0, (r6) + + /* set the dest address */ + mr r6, r11 + ori r6, r6, CHANNEL0_DMA_DESTINATION_ADDRESS + stwbrx r3, 0, (r6) + + /* set the next record pointer */ + li r5, 0 + mr r6, r11 + ori r6, r6, CHANNEL0NEXT_RECORD_POINTER + stwbrx r5, 0, (r6) + + /* set the low control register */ + /* bit 9 is NON chained mode, bit 31 is new style descriptors. + bit 12 is channel enable */ + ori r5, r5, (1 << 12) | (1 << 12) | (1 << 11) + /* 15 shifted by 16 (oris) == bit 31 */ + oris r5, r5, (1 << 15) + mr r6, r11 + ori r6, r6, CHANNEL0CONTROL + stwbrx r5, 0, (r6) + + blr + + /* this waits for the bytecount to return to zero, indicating + * that the trasfer is complete */ +wait_for_idma_0: + mr r5, r11 + lis r6, 0xff + ori r6, r6, 0xffff + ori r5, r5, CHANNEL0_DMA_BYTE_COUNT +1: lwbrx r4, 0, (r5) + and. r4, r4, r6 + bne 1b + + blr + + /* this turns off channel 0 of the idma engine */ +stop_idma_engine_0: + /* shut off the DMA engine */ + li r5, 0 + mr r6, r11 + ori r6, r6, CHANNEL0CONTROL + stwbrx r5, 0, (r6) + + blr +#endif + +#ifdef CFG_BOARD_ASM_INIT + /* NOTE: trashes r3-r7 */ + .globl board_asm_init +board_asm_init: + /* just move the GT registers to where they belong */ + lis r3, CFG_DFL_GT_REGS@h + ori r3, r3, CFG_DFL_GT_REGS@l + lis r4, CFG_GT_REGS@h + ori r4, r4, CFG_GT_REGS@l + li r5, INTERNAL_SPACE_DECODE + + /* test to see if we've already moved */ + lwbrx r6, r5, r4 + andi. r6, r6, 0xffff + rlwinm r7, r4, 12, 16, 31 + cmp cr0, r7, r6 + beqlr + + /* nope, have to move the registers */ + lwbrx r6, r5, r3 + andis. r6, r6, 0xffff + or r6, r6, r7 + stwbrx r6, r5, r3 + + /* now, poll for the change */ +1: lwbrx r7, r5, r4 + cmp cr0, r7, r6 + bne 1b + + /* done! */ + blr +#endif + +/* For use of the debug LEDs */ + .global led_on0 +led_on0: + xor r18, r18, r18 + lis r18, 0x1c80 + ori r18, r18, 0x8000 + stw r18, 0x0(r18) + sync + blr + + .global led_on1 +led_on1: + xor r18, r18, r18 + lis r18, 0x1c80 + ori r18, r18, 0xc000 + stw r18, 0x0(r18) + sync + blr + + .global led_on2 +led_on2: + xor r18, r18, r18 + lis r18, 0x1c81 + ori r18, r18, 0x0000 + stw r18, 0x0(r18) + sync + blr diff --git a/board/evb64260/mpsc.c b/board/evb64260/mpsc.c new file mode 100755 index 0000000..ee623ca --- /dev/null +++ b/board/evb64260/mpsc.c @@ -0,0 +1,868 @@ +/* + * (C) Copyright 2001 + * John Clemens <clemens@mclx.com>, Mission Critical Linux, 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 + */ + +/* + * mpsc.c - driver for console over the MPSC. + */ + +#include <common.h> +#include <config.h> +#include <asm/cache.h> + +#include <malloc.h> +#include "mpsc.h" + +int (*mpsc_putchar)(char ch) = mpsc_putchar_early; + +static volatile unsigned int *rx_desc_base=NULL; +static unsigned int rx_desc_index=0; +static volatile unsigned int *tx_desc_base=NULL; +static unsigned int tx_desc_index=0; + +/* local function declarations */ +static int galmpsc_connect(int channel, int connect); +static int galmpsc_route_serial(int channel, int connect); +static int galmpsc_route_rx_clock(int channel, int brg); +static int galmpsc_route_tx_clock(int channel, int brg); +static int galmpsc_write_config_regs(int mpsc, int mode); +static int galmpsc_config_channel_regs(int mpsc); +static int galmpsc_set_char_length(int mpsc, int value); +static int galmpsc_set_stop_bit_length(int mpsc, int value); +static int galmpsc_set_parity(int mpsc, int value); +static int galmpsc_enter_hunt(int mpsc); +static int galmpsc_set_brkcnt(int mpsc, int value); +static int galmpsc_set_tcschar(int mpsc, int value); +static int galmpsc_set_snoop(int mpsc, int value); +static int galmpsc_shutdown(int mpsc); + +static int galsdma_set_RFT(int channel); +static int galsdma_set_SFM(int channel); +static int galsdma_set_rxle(int channel); +static int galsdma_set_txle(int channel); +static int galsdma_set_burstsize(int channel, unsigned int value); +static int galsdma_set_RC(int channel, unsigned int value); + +static int galbrg_set_CDV(int channel, int value); +static int galbrg_enable(int channel); +static int galbrg_disable(int channel); +static int galbrg_set_clksrc(int channel, int value); +static int galbrg_set_CUV(int channel, int value); + +static void galsdma_enable_rx(void); + +/* static int galbrg_reset(int channel); */ + +#define SOFTWARE_CACHE_MANAGEMENT + +#ifdef SOFTWARE_CACHE_MANAGEMENT +#define FLUSH_DCACHE(a,b) if(dcache_status()){clean_dcache_range((u32)(a),(u32)(b));} +#define FLUSH_AND_INVALIDATE_DCACHE(a,b) if(dcache_status()){flush_dcache_range((u32)(a),(u32)(b));} +#define INVALIDATE_DCACHE(a,b) if(dcache_status()){invalidate_dcache_range((u32)(a),(u32)(b));} +#else +#define FLUSH_DCACHE(a,b) +#define FLUSH_AND_INVALIDATE_DCACHE(a,b) +#define INVALIDATE_DCACHE(a,b) +#endif + + +/* GT64240A errata: cant read MPSC/BRG registers... so make mirrors in ram for read/modify write */ +#define MIRROR_HACK ((struct _tag_mirror_hack *)&(gd->mirror_hack)) + +#define GT_REG_WRITE_MIRROR_G(a,d) {MIRROR_HACK->a ## _M = d; GT_REG_WRITE(a,d);} +#define GTREGREAD_MIRROR_G(a) (MIRROR_HACK->a ## _M) + +#define GT_REG_WRITE_MIRROR(a,i,g,d) {MIRROR_HACK->a ## _M[i] = d; GT_REG_WRITE(a + (i*g),d);} +#define GTREGREAD_MIRROR(a,i,g) (MIRROR_HACK->a ## _M[i]) + +/* make sure this isn't bigger than 16 long words (u-boot.h) */ +struct _tag_mirror_hack { + unsigned GALMPSC_PROTOCONF_REG_M[2]; /* 8008 */ + unsigned GALMPSC_CHANNELREG_1_M[2]; /* 800c */ + unsigned GALMPSC_CHANNELREG_2_M[2]; /* 8010 */ + unsigned GALBRG_0_CONFREG_M[2]; /* b200 */ + + unsigned GALMPSC_ROUTING_REGISTER_M; /* b400 */ + unsigned GALMPSC_RxC_ROUTE_M; /* b404 */ + unsigned GALMPSC_TxC_ROUTE_M; /* b408 */ + + unsigned int baudrate; /* current baudrate, for tsc delay calc */ +}; + +/* static struct _tag_mirror_hack *mh = NULL; */ + +/* special function for running out of flash. doesn't modify any + * global variables [josh] */ +int +mpsc_putchar_early(char ch) +{ + DECLARE_GLOBAL_DATA_PTR; + int mpsc=CHANNEL; + int temp=GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); + galmpsc_set_tcschar(mpsc,ch); + GT_REG_WRITE(GALMPSC_CHANNELREG_2+(mpsc*GALMPSC_REG_GAP), temp|0x200); + +#define MAGIC_FACTOR (10*1000000) + + udelay(MAGIC_FACTOR / MIRROR_HACK->baudrate); + return 0; +} + +/* This is used after relocation, see serial.c and mpsc_init2 */ +static int +mpsc_putchar_sdma(char ch) +{ + volatile unsigned int *p; + unsigned int temp; + + + /* align the descriptor */ + p = tx_desc_base; + memset((void *)p, 0, 8 * sizeof(unsigned int)); + + /* fill one 64 bit buffer */ + /* word swap, pad with 0 */ + p[4] = 0; /* x */ + p[5] = (unsigned int)ch; /* x */ + + /* CHANGED completely according to GT64260A dox - NTL */ + p[0] = 0x00010001; /* 0 */ + p[1] = DESC_OWNER | DESC_FIRST | DESC_LAST; /* 4 */ + p[2] = 0; /* 8 */ + p[3] = (unsigned int)&p[4]; /* c */ + +#if 0 + p[9] = DESC_FIRST | DESC_LAST; + p[10] = (unsigned int)&p[0]; + p[11] = (unsigned int)&p[12]; +#endif + + FLUSH_DCACHE(&p[0], &p[8]); + + GT_REG_WRITE(GALSDMA_0_CUR_TX_PTR+(CHANNEL*GALSDMA_REG_DIFF), + (unsigned int)&p[0]); + GT_REG_WRITE(GALSDMA_0_FIR_TX_PTR+(CHANNEL*GALSDMA_REG_DIFF), + (unsigned int)&p[0]); + + temp = GTREGREAD(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF)); + temp |= (TX_DEMAND | TX_STOP); + GT_REG_WRITE(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF), temp); + + INVALIDATE_DCACHE(&p[1], &p[2]); + + while(p[1] & DESC_OWNER) { + udelay(100); + INVALIDATE_DCACHE(&p[1], &p[2]); + } + + return 0; +} + +char +mpsc_getchar(void) +{ + DECLARE_GLOBAL_DATA_PTR; + static unsigned int done = 0; + volatile char ch; + unsigned int len=0, idx=0, temp; + + volatile unsigned int *p; + + + do { + p=&rx_desc_base[rx_desc_index*8]; + + INVALIDATE_DCACHE(&p[0], &p[1]); + /* Wait for character */ + while (p[1] & DESC_OWNER){ + udelay(100); + INVALIDATE_DCACHE(&p[0], &p[1]); + } + + /* Handle error case */ + if (p[1] & (1<<15)) { + printf("oops, error: %08x\n", p[1]); + + temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,CHANNEL,GALMPSC_REG_GAP); + temp |= (1 << 23); + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2, CHANNEL,GALMPSC_REG_GAP, temp); + + /* Can't poll on abort bit, so we just wait. */ + udelay(100); + + galsdma_enable_rx(); + } + + /* Number of bytes left in this descriptor */ + len = p[0] & 0xffff; + + if (len) { + /* Where to look */ + idx = 5; + if (done > 3) idx = 4; + if (done > 7) idx = 7; + if (done > 11) idx = 6; + + INVALIDATE_DCACHE(&p[idx], &p[idx+1]); + ch = p[idx] & 0xff; + done++; + } + + if (done < len) { + /* this descriptor has more bytes still + * shift down the char we just read, and leave the + * buffer in place for the next time around + */ + p[idx] = p[idx] >> 8; + FLUSH_DCACHE(&p[idx], &p[idx+1]); + } + + if (done == len) { + /* nothing left in this descriptor. + * go to next one + */ + p[1] = DESC_OWNER | DESC_FIRST | DESC_LAST; + p[0] = 0x00100000; + FLUSH_DCACHE(&p[0], &p[1]); + /* Next descriptor */ + rx_desc_index = (rx_desc_index + 1) % RX_DESC; + done = 0; + } + } while (len==0); /* galileo bug.. len might be zero */ + + return ch; +} + +int +mpsc_test_char(void) +{ + volatile unsigned int *p=&rx_desc_base[rx_desc_index*8]; + + INVALIDATE_DCACHE(&p[1], &p[2]); + + if (p[1] & DESC_OWNER) return 0; + else return 1; +} + +int +mpsc_init(int baud) +{ + DECLARE_GLOBAL_DATA_PTR; + + memset(MIRROR_HACK, 0, sizeof(struct _tag_mirror_hack)); + MIRROR_HACK->GALMPSC_ROUTING_REGISTER_M=0x3fffffff; + + /* BRG CONFIG */ + galbrg_set_baudrate(CHANNEL, baud); +#if defined(CONFIG_ZUMA_V2) || defined(CONFIG_P3G4) + galbrg_set_clksrc(CHANNEL,0x8); /* connect TCLK -> BRG */ +#else + galbrg_set_clksrc(CHANNEL,0); +#endif + galbrg_set_CUV(CHANNEL, 0); + galbrg_enable(CHANNEL); + + /* Set up clock routing */ + galmpsc_connect(CHANNEL, GALMPSC_CONNECT); + galmpsc_route_serial(CHANNEL, GALMPSC_CONNECT); + galmpsc_route_rx_clock(CHANNEL, CHANNEL); + galmpsc_route_tx_clock(CHANNEL, CHANNEL); + + /* reset MPSC state */ + galmpsc_shutdown(CHANNEL); + + /* SDMA CONFIG */ + galsdma_set_burstsize(CHANNEL, L1_CACHE_BYTES/8); /* in 64 bit words (8 bytes) */ + galsdma_set_txle(CHANNEL); + galsdma_set_rxle(CHANNEL); + galsdma_set_RC(CHANNEL, 0xf); + galsdma_set_SFM(CHANNEL); + galsdma_set_RFT(CHANNEL); + + /* MPSC CONFIG */ + galmpsc_write_config_regs(CHANNEL, GALMPSC_UART); + galmpsc_config_channel_regs(CHANNEL); + galmpsc_set_char_length(CHANNEL, GALMPSC_CHAR_LENGTH_8); /* 8 */ + galmpsc_set_parity(CHANNEL, GALMPSC_PARITY_NONE); /* N */ + galmpsc_set_stop_bit_length(CHANNEL, GALMPSC_STOP_BITS_1); /* 1 */ + + /* COMM_MPSC CONFIG */ +#ifdef SOFTWARE_CACHE_MANAGEMENT + galmpsc_set_snoop(CHANNEL, 0); /* disable snoop */ +#else + galmpsc_set_snoop(CHANNEL, 1); /* enable snoop */ +#endif + + return 0; +} + +void +mpsc_init2(void) +{ + int i; + + mpsc_putchar = mpsc_putchar_sdma; + + /* RX descriptors */ + rx_desc_base = (unsigned int *)malloc(((RX_DESC+1)*8) * + sizeof(unsigned int)); + + /* align descriptors */ + rx_desc_base = (unsigned int *) + (((unsigned int)rx_desc_base+32) & 0xFFFFFFF0); + + rx_desc_index = 0; + + memset((void *)rx_desc_base, 0, (RX_DESC*8)*sizeof(unsigned int)); + + for (i = 0; i < RX_DESC; i++) { + rx_desc_base[i*8 + 3] = (unsigned int)&rx_desc_base[i*8 + 4]; /* Buffer */ + rx_desc_base[i*8 + 2] = (unsigned int)&rx_desc_base[(i+1)*8]; /* Next descriptor */ + rx_desc_base[i*8 + 1] = DESC_OWNER | DESC_FIRST | DESC_LAST; /* Command & control */ + rx_desc_base[i*8] = 0x00100000; + } + rx_desc_base[(i-1)*8 + 2] = (unsigned int)&rx_desc_base[0]; + + FLUSH_DCACHE(&rx_desc_base[0], &rx_desc_base[RX_DESC*8]); + GT_REG_WRITE(GALSDMA_0_CUR_RX_PTR+(CHANNEL*GALSDMA_REG_DIFF), + (unsigned int)&rx_desc_base[0]); + + /* TX descriptors */ + tx_desc_base = (unsigned int *)malloc(((TX_DESC+1)*8) * + sizeof(unsigned int)); + + /* align descriptors */ + tx_desc_base = (unsigned int *) + (((unsigned int)tx_desc_base+32) & 0xFFFFFFF0); + + tx_desc_index = -1; + + memset((void *)tx_desc_base, 0, (TX_DESC*8)*sizeof(unsigned int)); + + for (i = 0; i < TX_DESC; i++) { + tx_desc_base[i*8 + 5] = (unsigned int)0x23232323; + tx_desc_base[i*8 + 4] = (unsigned int)0x23232323; + tx_desc_base[i*8 + 3] = (unsigned int)&tx_desc_base[i*8 + 4]; + tx_desc_base[i*8 + 2] = (unsigned int)&tx_desc_base[(i+1)*8]; + tx_desc_base[i*8 + 1] = DESC_OWNER | DESC_FIRST | DESC_LAST; + + /* set sbytecnt and shadow byte cnt to 1 */ + tx_desc_base[i*8] = 0x00010001; + } + tx_desc_base[(i-1)*8 + 2] = (unsigned int)&tx_desc_base[0]; + + FLUSH_DCACHE(&tx_desc_base[0], &tx_desc_base[TX_DESC*8]); + + udelay(100); + + galsdma_enable_rx(); + + return; +} + +int +galbrg_set_baudrate(int channel, int rate) +{ + DECLARE_GLOBAL_DATA_PTR; + int clock; + + galbrg_disable(channel); + +#if defined(CONFIG_ZUMA_V2) || defined(CONFIG_P3G4) + /* from tclk */ + clock = (CFG_BUS_HZ/(16*rate)) - 1; +#else + clock = (3686400/(16*rate)) - 1; +#endif + + galbrg_set_CDV(channel, clock); + + galbrg_enable(channel); + + MIRROR_HACK->baudrate = rate; + + return 0; +} + +/* ------------------------------------------------------------------ */ + +/* Below are all the private functions that no one else needs */ + +static int +galbrg_set_CDV(int channel, int value) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP); + temp &= 0xFFFF0000; + temp |= (value & 0x0000FFFF); + GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG,channel,GALBRG_REG_GAP, temp); + + return 0; +} + +static int +galbrg_enable(int channel) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP); + temp |= 0x00010000; + GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP,temp); + + return 0; +} + +static int +galbrg_disable(int channel) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP); + temp &= 0xFFFEFFFF; + GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG, channel, GALBRG_REG_GAP,temp); + + return 0; +} + +static int +galbrg_set_clksrc(int channel, int value) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALBRG_0_CONFREG,channel, GALBRG_REG_GAP); + temp &= 0xFF83FFFF; + temp |= (value << 18); + GT_REG_WRITE_MIRROR(GALBRG_0_CONFREG,channel, GALBRG_REG_GAP,temp); + + return 0; +} + +static int +galbrg_set_CUV(int channel, int value) +{ + GT_REG_WRITE(GALBRG_0_BTREG + (channel * GALBRG_REG_GAP), value); + + return 0; +} + +#if 0 +static int +galbrg_reset(int channel) +{ + unsigned int temp; + + temp = GTREGREAD(GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP)); + temp |= 0x20000; + GT_REG_WRITE(GALBRG_0_CONFREG + (channel * GALBRG_REG_GAP), temp); + + return 0; +} +#endif + +static int +galsdma_set_RFT(int channel) +{ + unsigned int temp; + + temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); + temp |= 0x00000001; + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); + + return 0; +} + +static int +galsdma_set_SFM(int channel) +{ + unsigned int temp; + + temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); + temp |= 0x00000002; + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); + + return 0; +} + +static int +galsdma_set_rxle(int channel) +{ + unsigned int temp; + + temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); + temp |= 0x00000040; + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); + + return 0; +} + +static int +galsdma_set_txle(int channel) +{ + unsigned int temp; + + temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); + temp |= 0x00000080; + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); + + return 0; +} + +static int +galsdma_set_RC(int channel, unsigned int value) +{ + unsigned int temp; + + temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); + temp &= ~0x0000003c; + temp |= (value << 2); + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), temp); + + return 0; +} + +static int +galsdma_set_burstsize(int channel, unsigned int value) +{ + unsigned int temp; + + temp = GTREGREAD(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF)); + temp &= 0xFFFFCFFF; + switch (value) { + case 8: + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), + (temp | (0x3 << 12))); + break; + + case 4: + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), + (temp | (0x2 << 12))); + break; + + case 2: + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), + (temp | (0x1 << 12))); + break; + + case 1: + GT_REG_WRITE(GALSDMA_0_CONF_REG+(channel*GALSDMA_REG_DIFF), + (temp | (0x0 << 12))); + break; + + default: + return -1; + break; + } + + return 0; +} + +static int +galmpsc_connect(int channel, int connect) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR_G(GALMPSC_ROUTING_REGISTER); + + if ((channel == 0) && connect) + temp &= ~0x00000007; + else if ((channel == 1) && connect) + temp &= ~(0x00000007 << 6); + else if ((channel == 0) && !connect) + temp |= 0x00000007; + else + temp |= (0x00000007 << 6); + + /* Just in case... */ + temp &= 0x3fffffff; + + GT_REG_WRITE_MIRROR_G(GALMPSC_ROUTING_REGISTER, temp); + + return 0; +} + +static int +galmpsc_route_serial(int channel, int connect) +{ + unsigned int temp; + + temp = GTREGREAD(GALMPSC_SERIAL_MULTIPLEX); + + if ((channel == 0) && connect) + temp |= 0x00000100; + else if ((channel == 1) && connect) + temp |= 0x00001000; + else if ((channel == 0) && !connect) + temp &= ~0x00000100; + else + temp &= ~0x00001000; + + GT_REG_WRITE(GALMPSC_SERIAL_MULTIPLEX,temp); + + return 0; +} + +static int +galmpsc_route_rx_clock(int channel, int brg) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR_G(GALMPSC_RxC_ROUTE); + + if (channel == 0) + temp |= brg; + else + temp |= (brg << 8); + + GT_REG_WRITE_MIRROR_G(GALMPSC_RxC_ROUTE,temp); + + return 0; +} + +static int +galmpsc_route_tx_clock(int channel, int brg) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR_G(GALMPSC_TxC_ROUTE); + + if (channel == 0) + temp |= brg; + else + temp |= (brg << 8); + + GT_REG_WRITE_MIRROR_G(GALMPSC_TxC_ROUTE,temp); + + return 0; +} + +static int +galmpsc_write_config_regs(int mpsc, int mode) +{ + if (mode == GALMPSC_UART) { + /* Main config reg Low (Null modem, Enable Tx/Rx, UART mode) */ + GT_REG_WRITE(GALMPSC_MCONF_LOW + (mpsc*GALMPSC_REG_GAP), + 0x000004c4); + + /* Main config reg High (32x Rx/Tx clock mode, width=8bits */ + GT_REG_WRITE(GALMPSC_MCONF_HIGH +(mpsc*GALMPSC_REG_GAP), + 0x024003f8); + /* 22 2222 1111 */ + /* 54 3210 9876 */ + /* 0000 0010 0000 0000 */ + /* 1 */ + /* 098 7654 3210 */ + /* 0000 0011 1111 1000 */ + } else + return -1; + + return 0; +} + +static int +galmpsc_config_channel_regs(int mpsc) +{ + DECLARE_GLOBAL_DATA_PTR; + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP, 0); + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP, 0); + GT_REG_WRITE(GALMPSC_CHANNELREG_3+(mpsc*GALMPSC_REG_GAP), 1); + GT_REG_WRITE(GALMPSC_CHANNELREG_4+(mpsc*GALMPSC_REG_GAP), 0); + GT_REG_WRITE(GALMPSC_CHANNELREG_5+(mpsc*GALMPSC_REG_GAP), 0); + GT_REG_WRITE(GALMPSC_CHANNELREG_6+(mpsc*GALMPSC_REG_GAP), 0); + GT_REG_WRITE(GALMPSC_CHANNELREG_7+(mpsc*GALMPSC_REG_GAP), 0); + GT_REG_WRITE(GALMPSC_CHANNELREG_8+(mpsc*GALMPSC_REG_GAP), 0); + GT_REG_WRITE(GALMPSC_CHANNELREG_9+(mpsc*GALMPSC_REG_GAP), 0); + GT_REG_WRITE(GALMPSC_CHANNELREG_10+(mpsc*GALMPSC_REG_GAP), 0); + + galmpsc_set_brkcnt(mpsc, 0x3); + galmpsc_set_tcschar(mpsc, 0xab); + + return 0; +} + +static int +galmpsc_set_brkcnt(int mpsc, int value) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP); + temp &= 0x0000FFFF; + temp |= (value << 16); + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP, temp); + + return 0; +} + +static int +galmpsc_set_tcschar(int mpsc, int value) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP); + temp &= 0xFFFF0000; + temp |= value; + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_1,mpsc,GALMPSC_REG_GAP, temp); + + return 0; +} + +static int +galmpsc_set_char_length(int mpsc, int value) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP); + temp &= 0xFFFFCFFF; + temp |= (value << 12); + GT_REG_WRITE_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP, temp); + + return 0; +} + +static int +galmpsc_set_stop_bit_length(int mpsc, int value) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP); + temp |= (value << 14); + GT_REG_WRITE_MIRROR(GALMPSC_PROTOCONF_REG,mpsc,GALMPSC_REG_GAP,temp); + + return 0; +} + +static int +galmpsc_set_parity(int mpsc, int value) +{ + DECLARE_GLOBAL_DATA_PTR; + unsigned int temp; + + temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); + if (value != -1) { + temp &= 0xFFF3FFF3; + temp |= ((value << 18) | (value << 2)); + temp |= ((value << 17) | (value << 1)); + } else { + temp &= 0xFFF1FFF1; + } + + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP, temp); + + return 0; +} + +static int +galmpsc_enter_hunt(int mpsc) +{ + DECLARE_GLOBAL_DATA_PTR; + int temp; + + temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); + temp |= 0x80000000; + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP, temp); + + /* Should Poll on Enter Hunt bit, but the register is write-only */ + /* errata suggests pausing 100 system cycles */ + udelay(100); + + return 0; +} + + +static int +galmpsc_shutdown(int mpsc) +{ + DECLARE_GLOBAL_DATA_PTR; +#if 0 + unsigned int temp; + + /* cause RX abort (clears RX) */ + temp = GTREGREAD_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP); + temp |= MPSC_RX_ABORT | MPSC_TX_ABORT; + temp &= ~MPSC_ENTER_HUNT; + GT_REG_WRITE_MIRROR(GALMPSC_CHANNELREG_2,mpsc,GALMPSC_REG_GAP,temp); +#endif + + GT_REG_WRITE(GALSDMA_0_COM_REG + CHANNEL * GALSDMA_REG_DIFF, 0); + GT_REG_WRITE(GALSDMA_0_COM_REG + CHANNEL * GALSDMA_REG_DIFF, + SDMA_TX_ABORT | SDMA_RX_ABORT); + + /* shut down the MPSC */ + GT_REG_WRITE(GALMPSC_MCONF_LOW, 0); + GT_REG_WRITE(GALMPSC_MCONF_HIGH, 0); + GT_REG_WRITE_MIRROR(GALMPSC_PROTOCONF_REG, mpsc, GALMPSC_REG_GAP,0); + + udelay(100); + + /* shut down the sdma engines. */ + /* reset config to default */ + GT_REG_WRITE(GALSDMA_0_CONF_REG + CHANNEL * GALSDMA_REG_DIFF, + 0x000000fc); + + udelay(100); + + /* clear the SDMA current and first TX and RX pointers */ + GT_REG_WRITE(GALSDMA_0_CUR_RX_PTR + CHANNEL * GALSDMA_REG_DIFF, 0); + GT_REG_WRITE(GALSDMA_0_CUR_TX_PTR + CHANNEL * GALSDMA_REG_DIFF, 0); + GT_REG_WRITE(GALSDMA_0_FIR_TX_PTR + CHANNEL * GALSDMA_REG_DIFF, 0); + + udelay(100); + + return 0; +} + +static void +galsdma_enable_rx(void) +{ + int temp; + + /* Enable RX processing */ + temp = GTREGREAD(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF)); + temp |= RX_ENABLE; + GT_REG_WRITE(GALSDMA_0_COM_REG+(CHANNEL*GALSDMA_REG_DIFF), temp); + + galmpsc_enter_hunt(CHANNEL); +} + +static int +galmpsc_set_snoop(int mpsc, int value) +{ + int reg = mpsc ? MPSC_1_ADDRESS_CONTROL_LOW : MPSC_0_ADDRESS_CONTROL_LOW; + int temp=GTREGREAD(reg); + if(value) + temp |= (1<< 6) | (1<<14) | (1<<22) | (1<<30); + else + temp &= ~((1<< 6) | (1<<14) | (1<<22) | (1<<30)); + GT_REG_WRITE(reg, temp); + return 0; +} diff --git a/board/evb64260/mpsc.h b/board/evb64260/mpsc.h new file mode 100755 index 0000000..54b642a --- /dev/null +++ b/board/evb64260/mpsc.h @@ -0,0 +1,142 @@ +/* + * (C) Copyright 2001 + * John Clemens <clemens@mclx.com>, Mission Critical Linux, 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 + */ + +/* + * mpsc.h - header file for MPSC in uart mode (console driver) + */ + +#ifndef __MPSC_H__ +#define __MPSC_H__ + +/* include actual Galileo defines */ +#include <galileo/gt64260R.h> + +/* driver related defines */ + +int mpsc_init(int baud); +void mpsc_init2(void); +char mpsc_getchar(void); +int mpsc_test_char(void); +int galbrg_set_baudrate(int channel, int rate); + +int mpsc_putchar_early(char ch); +extern int (*mpsc_putchar)(char ch); + +#define CHANNEL CONFIG_MPSC_PORT + +#define TX_DESC 5 +#define RX_DESC 20 + +#define DESC_FIRST 0x00010000 +#define DESC_LAST 0x00020000 +#define DESC_OWNER 0x80000000 + +#define TX_DEMAND 0x00800000 +#define TX_STOP 0x00010000 +#define RX_ENABLE 0x00000080 + +#define SDMA_RX_ABORT (1 << 15) +#define SDMA_TX_ABORT (1 << 31) +#define MPSC_TX_ABORT (1 << 7) +#define MPSC_RX_ABORT (1 << 23) +#define MPSC_ENTER_HUNT (1 << 31) + +/* MPSC defines */ + +#define GALMPSC_CONNECT 0x1 +#define GALMPSC_DISCONNECT 0x0 + +#define GALMPSC_UART 0x1 + +#define GALMPSC_STOP_BITS_1 0x0 +#define GALMPSC_STOP_BITS_2 0x1 +#define GALMPSC_CHAR_LENGTH_8 0x3 +#define GALMPSC_CHAR_LENGTH_7 0x2 + +#define GALMPSC_PARITY_ODD 0x0 +#define GALMPSC_PARITY_EVEN 0x2 +#define GALMPSC_PARITY_MARK 0x3 +#define GALMPSC_PARITY_SPACE 0x1 +#define GALMPSC_PARITY_NONE -1 + +#define GALMPSC_SERIAL_MULTIPLEX SERIAL_PORT_MULTIPLEX /* 0xf010 */ +#define GALMPSC_ROUTING_REGISTER MAIN_ROUTING_REGISTER /* 0xb400 */ +#define GALMPSC_RxC_ROUTE RECEIVE_CLOCK_ROUTING_REGISTER /* 0xb404 */ +#define GALMPSC_TxC_ROUTE TRANSMIT_CLOCK_ROUTING_REGISTER /* 0xb408 */ +#define GALMPSC_MCONF_LOW MPSC0_MAIN_CONFIGURATION_LOW /* 0x8000 */ +#define GALMPSC_MCONF_HIGH MPSC0_MAIN_CONFIGURATION_HIGH /* 0x8004 */ +#define GALMPSC_PROTOCONF_REG MPSC0_PROTOCOL_CONFIGURATION /* 0x8008 */ + +#define GALMPSC_REG_GAP 0x1000 + +#define GALMPSC_MCONF_CHREG_BASE CHANNEL0_REGISTER1 /* 0x800c */ +#define GALMPSC_CHANNELREG_1 CHANNEL0_REGISTER1 /* 0x800c */ +#define GALMPSC_CHANNELREG_2 CHANNEL0_REGISTER2 /* 0x8010 */ +#define GALMPSC_CHANNELREG_3 CHANNEL0_REGISTER3 /* 0x8014 */ +#define GALMPSC_CHANNELREG_4 CHANNEL0_REGISTER4 /* 0x8018 */ +#define GALMPSC_CHANNELREG_5 CHANNEL0_REGISTER5 /* 0x801c */ +#define GALMPSC_CHANNELREG_6 CHANNEL0_REGISTER6 /* 0x8020 */ +#define GALMPSC_CHANNELREG_7 CHANNEL0_REGISTER7 /* 0x8024 */ +#define GALMPSC_CHANNELREG_8 CHANNEL0_REGISTER8 /* 0x8028 */ +#define GALMPSC_CHANNELREG_9 CHANNEL0_REGISTER9 /* 0x802c */ +#define GALMPSC_CHANNELREG_10 CHANNEL0_REGISTER10 /* 0x8030 */ +#define GALMPSC_CHANNELREG_11 CHANNEL0_REGISTER11 /* 0x8034 */ + +#define GALSDMA_COMMAND_FIRST (1 << 16) +#define GALSDMA_COMMAND_LAST (1 << 17) +#define GALSDMA_COMMAND_ENABLEINT (1 << 23) +#define GALSDMA_COMMAND_AUTO (1 << 30) +#define GALSDMA_COMMAND_OWNER (1 << 31) + +#define GALSDMA_RX 0 +#define GALSDMA_TX 1 + +/* CHANNEL2 should be CHANNEL1, according to documentation, + * but to work with the current GTREGS file... + */ +#define GALSDMA_0_CONF_REG CHANNEL0_CONFIGURATION_REGISTER /* 0x4000 */ +#define GALSDMA_1_CONF_REG CHANNEL2_CONFIGURATION_REGISTER /* 0x6000 */ +#define GALSDMA_0_COM_REG CHANNEL0_COMMAND_REGISTER /* 0x4008 */ +#define GALSDMA_1_COM_REG CHANNEL2_COMMAND_REGISTER /* 0x6008 */ +#define GALSDMA_0_CUR_RX_PTR CHANNEL0_CURRENT_RX_DESCRIPTOR_POINTER /* 0x4810 */ +#define GALSDMA_0_CUR_TX_PTR CHANNEL0_CURRENT_TX_DESCRIPTOR_POINTER /* 0x4c10 */ +#define GALSDMA_0_FIR_TX_PTR CHANNEL0_FIRST_TX_DESCRIPTOR_POINTER /* 0x4c14 */ +#define GALSDMA_1_CUR_RX_PTR CHANNEL2_CURRENT_RX_DESCRIPTOR_POINTER /* 0x6810 */ +#define GALSDMA_1_CUR_TX_PTR CHANNEL2_CURRENT_TX_DESCRIPTOR_POINTER /* 0x6c10 */ +#define GALSDMA_1_FIR_TX_PTR CHANNEL2_FIRST_TX_DESCRIPTOR_POINTER /* 0x6c14 */ +#define GALSDMA_REG_DIFF 0x2000 + +/* WRONG in gt64260R.h */ +#define GALSDMA_INT_CAUSE 0xb800 /* SDMA_CAUSE */ +#define GALSDMA_INT_MASK 0xb880 /* SDMA_MASK */ + +#define GALSDMA_MODE_UART 0 +#define GALSDMA_MODE_BISYNC 1 +#define GALSDMA_MODE_HDLC 2 +#define GALSDMA_MODE_TRANSPARENT 3 + +#define GALBRG_0_CONFREG BRG0_CONFIGURATION_REGISTER /* 0xb200 */ +#define GALBRG_REG_GAP 0x0008 +#define GALBRG_0_BTREG BRG0_BAUDE_TUNING_REGISTER /* 0xb204 */ + +#endif /* __MPSC_H__ */ diff --git a/board/evb64260/pci.c b/board/evb64260/pci.c new file mode 100755 index 0000000..59b9acb --- /dev/null +++ b/board/evb64260/pci.c @@ -0,0 +1,760 @@ +/* PCI.c - PCI functions */ + +/* Copyright - Galileo technology. */ + +#include <common.h> +#include <pci.h> + +#include <galileo/pci.h> + +static const unsigned char pci_irq_swizzle[2][PCI_MAX_DEVICES] = { +#ifdef CONFIG_ZUMA_V2 + {0, 0, 0, 0, 0, 0, 0, 29,[8 ... PCI_MAX_DEVICES - 1] = 0}, + {0, 0, 0, 0, 0, 0, 0, 28,[8 ... PCI_MAX_DEVICES - 1] = 0} +#else /* EVB??? This is a guess */ + {0, 0, 0, 0, 0, 0, 0, 27, 27,[9 ... PCI_MAX_DEVICES - 1] = 0}, + {0, 0, 0, 0, 0, 0, 0, 29, 29,[9 ... PCI_MAX_DEVICES - 1] = 0} +#endif +}; + +static const unsigned int pci_p2p_configuration_reg[] = { + PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION +}; + +static const unsigned int pci_configuration_address[] = { + PCI_0CONFIGURATION_ADDRESS, PCI_1CONFIGURATION_ADDRESS +}; + +static const unsigned int pci_configuration_data[] = { + PCI_0CONFIGURATION_DATA_VIRTUAL_REGISTER, + PCI_1CONFIGURATION_DATA_VIRTUAL_REGISTER +}; + +static const unsigned int pci_error_cause_reg[] = { + PCI_0ERROR_CAUSE, PCI_1ERROR_CAUSE +}; + +static const unsigned int pci_arbiter_control[] = { + PCI_0ARBITER_CONTROL, PCI_1ARBITER_CONTROL +}; + +static const unsigned int pci_snoop_control_base_0_low[] = { + PCI_0SNOOP_CONTROL_BASE_0_LOW, PCI_1SNOOP_CONTROL_BASE_0_LOW +}; +static const unsigned int pci_snoop_control_top_0[] = { + PCI_0SNOOP_CONTROL_TOP_0, PCI_1SNOOP_CONTROL_TOP_0 +}; + +static const unsigned int pci_access_control_base_0_low[] = { + PCI_0ACCESS_CONTROL_BASE_0_LOW, PCI_1ACCESS_CONTROL_BASE_0_LOW +}; +static const unsigned int pci_access_control_top_0[] = { + PCI_0ACCESS_CONTROL_TOP_0, PCI_1ACCESS_CONTROL_TOP_0 +}; + +static const unsigned int pci_scs_bank_size[2][4] = { + {PCI_0SCS_0_BANK_SIZE, PCI_0SCS_1_BANK_SIZE, + PCI_0SCS_2_BANK_SIZE, PCI_0SCS_3_BANK_SIZE}, + {PCI_1SCS_0_BANK_SIZE, PCI_1SCS_1_BANK_SIZE, + PCI_1SCS_2_BANK_SIZE, PCI_1SCS_3_BANK_SIZE} +}; + +static const unsigned int pci_p2p_configuration[] = { + PCI_0P2P_CONFIGURATION, PCI_1P2P_CONFIGURATION +}; + +static unsigned int local_buses[] = { 0, 0 }; + +/******************************************************************** +* pciWriteConfigReg - Write to a PCI configuration register +* - Make sure the GT is configured as a master before writing +* to another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* +* +* Inputs: unsigned int regOffset: The register offset as it apears in the GT spec +* (or any other PCI device spec) +* pciDevNum: The device number needs to be addressed. +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ +void pciWriteConfigReg (PCI_HOST host, unsigned int regOffset, + unsigned int pciDevNum, unsigned int data) +{ + volatile unsigned int DataForAddrReg; + unsigned int functionNum; + unsigned int busNum = PCI_BUS (pciDevNum); + unsigned int addr; + + if (pciDevNum > 32) /* illegal device Number */ + return; + if (pciDevNum == SELF) { /* configure our configuration space. */ + pciDevNum = + (GTREGREAD (pci_p2p_configuration_reg[host]) >> 24) & + 0x1f; + busNum = GTREGREAD (pci_p2p_configuration_reg[host]) & + 0xff0000; + } + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xfc; + DataForAddrReg = + (regOffset | pciDevNum | functionNum | busNum) | BIT31; + GT_REG_WRITE (pci_configuration_address[host], DataForAddrReg); + GT_REG_READ (pci_configuration_address[host], &addr); + if (addr != DataForAddrReg) + return; + GT_REG_WRITE (pci_configuration_data[host], data); +} + +/******************************************************************** +* pciReadConfigReg - Read from a PCI0 configuration register +* - Make sure the GT is configured as a master before reading +* from another device on the PCI. +* - The function takes care of Big/Little endian conversion. +* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI +* spec) +* pciDevNum: The device number needs to be addressed. +* RETURNS: data , if the data == 0xffffffff check the master abort bit in the +* cause register to make sure the data is valid +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|00| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ +unsigned int pciReadConfigReg (PCI_HOST host, unsigned int regOffset, + unsigned int pciDevNum) +{ + volatile unsigned int DataForAddrReg; + unsigned int data; + unsigned int functionNum; + unsigned int busNum = PCI_BUS (pciDevNum); + + if (pciDevNum > 32) /* illegal device Number */ + return 0xffffffff; + if (pciDevNum == SELF) { /* configure our configuration space. */ + pciDevNum = + (GTREGREAD (pci_p2p_configuration_reg[host]) >> 24) & + 0x1f; + busNum = GTREGREAD (pci_p2p_configuration_reg[host]) & + 0xff0000; + } + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xfc; + DataForAddrReg = + (regOffset | pciDevNum | functionNum | busNum) | BIT31; + GT_REG_WRITE (pci_configuration_address[host], DataForAddrReg); + GT_REG_READ (pci_configuration_address[host], &data); + if (data != DataForAddrReg) + return 0xffffffff; + GT_REG_READ (pci_configuration_data[host], &data); + return data; +} + +/******************************************************************** +* pciOverBridgeWriteConfigReg - Write to a PCI configuration register where +* the agent is placed on another Bus. For more +* information read P2P in the PCI spec. +* +* Inputs: unsigned int regOffset - The register offset as it apears in the +* GT spec (or any other PCI device spec). +* unsigned int pciDevNum - The device number needs to be addressed. +* unsigned int busNum - On which bus does the Target agent connect +* to. +* unsigned int data - data to be written. +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|01| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +* The configuration Address is configure as type-I (bits[1:0] = '01') due to +* PCI spec referring to P2P. +* +*********************************************************************/ +void pciOverBridgeWriteConfigReg (PCI_HOST host, + unsigned int regOffset, + unsigned int pciDevNum, + unsigned int busNum, unsigned int data) +{ + unsigned int DataForReg; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xff; + busNum = busNum << 16; + if (pciDevNum == SELF) { /* This board */ + DataForReg = (regOffset | pciDevNum | functionNum) | BIT0; + } else { + DataForReg = (regOffset | pciDevNum | functionNum | busNum) | + BIT31 | BIT0; + } + GT_REG_WRITE (pci_configuration_address[host], DataForReg); + if (pciDevNum == SELF) { /* This board */ + GT_REG_WRITE (pci_configuration_data[host], data); + } else { /* configuration Transaction over the pci. */ + + /* The PCI is working in LE Mode So it swap the Data. */ + GT_REG_WRITE (pci_configuration_data[host], WORD_SWAP (data)); + } +} + + +/******************************************************************** +* pciOverBridgeReadConfigReg - Read from a PCIn configuration register where +* the agent target locate on another PCI bus. +* - Make sure the GT is configured as a master +* before reading from another device on the PCI. +* - The function takes care of Big/Little endian +* conversion. +* INPUTS: regOffset: The register offset as it apears in the GT spec (or PCI +* spec). (configuration register offset.) +* pciDevNum: The device number needs to be addressed. +* busNum: the Bus number where the agent is place. +* RETURNS: data , if the data == 0xffffffff check the master abort bit in the +* cause register to make sure the data is valid +* +* Configuration Address 0xCF8: +* +* 31 30 24 23 16 15 11 10 8 7 2 0 <=bit Number +* |congif|Reserved| Bus |Device|Function|Register|01| +* |Enable| |Number|Number| Number | Number | | <=field Name +* +*********************************************************************/ +unsigned int pciOverBridgeReadConfigReg (PCI_HOST host, + unsigned int regOffset, + unsigned int pciDevNum, + unsigned int busNum) +{ + unsigned int DataForReg; + unsigned int data; + unsigned int functionNum; + + functionNum = regOffset & 0x00000700; + pciDevNum = pciDevNum << 11; + regOffset = regOffset & 0xff; + busNum = busNum << 16; + if (pciDevNum == SELF) { /* This board */ + DataForReg = (regOffset | pciDevNum | functionNum) | BIT31; + } else { /* agent on another bus */ + + DataForReg = (regOffset | pciDevNum | functionNum | busNum) | + BIT0 | BIT31; + } + GT_REG_WRITE (pci_configuration_address[host], DataForReg); + if (pciDevNum == SELF) { /* This board */ + GT_REG_READ (pci_configuration_data[host], &data); + return data; + } else { /* The PCI is working in LE Mode So it swap the Data. */ + + GT_REG_READ (pci_configuration_data[host], &data); + return WORD_SWAP (data); + } +} + +/******************************************************************** +* pciGetRegOffset - Gets the register offset for this region config. +* +* INPUT: Bus, Region - The bus and region we ask for its base address. +* OUTPUT: N/A +* RETURNS: PCI register base address +*********************************************************************/ +static unsigned int pciGetRegOffset (PCI_HOST host, PCI_REGION region) +{ + switch (host) { + case PCI_HOST0: + switch (region) { + case PCI_IO: + return PCI_0I_O_LOW_DECODE_ADDRESS; + case PCI_REGION0: + return PCI_0MEMORY0_LOW_DECODE_ADDRESS; + case PCI_REGION1: + return PCI_0MEMORY1_LOW_DECODE_ADDRESS; + case PCI_REGION2: + return PCI_0MEMORY2_LOW_DECODE_ADDRESS; + case PCI_REGION3: + return PCI_0MEMORY3_LOW_DECODE_ADDRESS; + } + case PCI_HOST1: + switch (region) { + case PCI_IO: + return PCI_1I_O_LOW_DECODE_ADDRESS; + case PCI_REGION0: + return PCI_1MEMORY0_LOW_DECODE_ADDRESS; + case PCI_REGION1: + return PCI_1MEMORY1_LOW_DECODE_ADDRESS; + case PCI_REGION2: + return PCI_1MEMORY2_LOW_DECODE_ADDRESS; + case PCI_REGION3: + return PCI_1MEMORY3_LOW_DECODE_ADDRESS; + } + } + return PCI_0MEMORY0_LOW_DECODE_ADDRESS; +} + +static unsigned int pciGetRemapOffset (PCI_HOST host, PCI_REGION region) +{ + switch (host) { + case PCI_HOST0: + switch (region) { + case PCI_IO: + return PCI_0I_O_ADDRESS_REMAP; + case PCI_REGION0: + return PCI_0MEMORY0_ADDRESS_REMAP; + case PCI_REGION1: + return PCI_0MEMORY1_ADDRESS_REMAP; + case PCI_REGION2: + return PCI_0MEMORY2_ADDRESS_REMAP; + case PCI_REGION3: + return PCI_0MEMORY3_ADDRESS_REMAP; + } + case PCI_HOST1: + switch (region) { + case PCI_IO: + return PCI_1I_O_ADDRESS_REMAP; + case PCI_REGION0: + return PCI_1MEMORY0_ADDRESS_REMAP; + case PCI_REGION1: + return PCI_1MEMORY1_ADDRESS_REMAP; + case PCI_REGION2: + return PCI_1MEMORY2_ADDRESS_REMAP; + case PCI_REGION3: + return PCI_1MEMORY3_ADDRESS_REMAP; + } + } + return PCI_0MEMORY0_ADDRESS_REMAP; +} + +bool pciMapSpace (PCI_HOST host, PCI_REGION region, unsigned int remapBase, + unsigned int bankBase, unsigned int bankLength) +{ + unsigned int low = 0xfff; + unsigned int high = 0x0; + unsigned int regOffset = pciGetRegOffset (host, region); + unsigned int remapOffset = pciGetRemapOffset (host, region); + + if (bankLength != 0) { + low = (bankBase >> 20) & 0xfff; + high = ((bankBase + bankLength) >> 20) - 1; + } + + GT_REG_WRITE (regOffset, low | (1 << 24)); /* no swapping */ + GT_REG_WRITE (regOffset + 8, high); + + if (bankLength != 0) { /* must do AFTER writing maps */ + GT_REG_WRITE (remapOffset, remapBase >> 20); /* sorry, 32 bits only. + dont support upper 32 + in this driver */ + } + return true; +} + +unsigned int pciGetSpaceBase (PCI_HOST host, PCI_REGION region) +{ + unsigned int low; + unsigned int regOffset = pciGetRegOffset (host, region); + + GT_REG_READ (regOffset, &low); + return (low & 0xfff) << 20; +} + +unsigned int pciGetSpaceSize (PCI_HOST host, PCI_REGION region) +{ + unsigned int low, high; + unsigned int regOffset = pciGetRegOffset (host, region); + + GT_REG_READ (regOffset, &low); + GT_REG_READ (regOffset + 8, &high); + high &= 0xfff; + low &= 0xfff; + if (high <= low) + return 0; + return (high + 1 - low) << 20; +} + +/******************************************************************** +* pciMapMemoryBank - Maps PCI_host memory bank "bank" for the slave. +* +* Inputs: base and size of PCI SCS +*********************************************************************/ +void pciMapMemoryBank (PCI_HOST host, MEMORY_BANK bank, + unsigned int pciDramBase, unsigned int pciDramSize) +{ + pciDramBase = pciDramBase & 0xfffff000; + pciDramBase = pciDramBase | (pciReadConfigReg (host, + PCI_SCS_0_BASE_ADDRESS + + 4 * bank, + SELF) & 0x00000fff); + pciWriteConfigReg (host, PCI_SCS_0_BASE_ADDRESS + 4 * bank, SELF, + pciDramBase); + if (pciDramSize == 0) + pciDramSize++; + GT_REG_WRITE (pci_scs_bank_size[host][bank], pciDramSize - 1); +} + + +/******************************************************************** +* pciSetRegionFeatures - This function modifys one of the 8 regions with +* feature bits given as an input. +* - Be advised to check the spec before modifying them. +* Inputs: PCI_PROTECT_REGION region - one of the eight regions. +* unsigned int features - See file: pci.h there are defintion for those +* region features. +* unsigned int baseAddress - The region base Address. +* unsigned int topAddress - The region top Address. +* Returns: false if one of the parameters is erroneous true otherwise. +*********************************************************************/ +bool pciSetRegionFeatures (PCI_HOST host, PCI_ACCESS_REGIONS region, + unsigned int features, unsigned int baseAddress, + unsigned int regionLength) +{ + unsigned int accessLow; + unsigned int accessHigh; + unsigned int accessTop = baseAddress + regionLength; + + if (regionLength == 0) { /* close the region. */ + pciDisableAccessRegion (host, region); + return true; + } + /* base Address is store is bits [11:0] */ + accessLow = (baseAddress & 0xfff00000) >> 20; + /* All the features are update according to the defines in pci.h (to be on + the safe side we disable bits: [11:0] */ + accessLow = accessLow | (features & 0xfffff000); + /* write to the Low Access Region register */ + GT_REG_WRITE (pci_access_control_base_0_low[host] + 0x10 * region, + accessLow); + + accessHigh = (accessTop & 0xfff00000) >> 20; + + /* write to the High Access Region register */ + GT_REG_WRITE (pci_access_control_top_0[host] + 0x10 * region, + accessHigh - 1); + return true; +} + +/******************************************************************** +* pciDisableAccessRegion - Disable The given Region by writing MAX size +* to its low Address and MIN size to its high Address. +* +* Inputs: PCI_ACCESS_REGIONS region - The region we to be Disabled. +* Returns: N/A. +*********************************************************************/ +void pciDisableAccessRegion (PCI_HOST host, PCI_ACCESS_REGIONS region) +{ + /* writing back the registers default values. */ + GT_REG_WRITE (pci_access_control_base_0_low[host] + 0x10 * region, + 0x01001fff); + GT_REG_WRITE (pci_access_control_top_0[host] + 0x10 * region, 0); +} + +/******************************************************************** +* pciArbiterEnable - Enables PCI-0`s Arbitration mechanism. +* +* Inputs: N/A +* Returns: true. +*********************************************************************/ +bool pciArbiterEnable (PCI_HOST host) +{ + unsigned int regData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + GT_REG_WRITE (pci_arbiter_control[host], regData | BIT31); + return true; +} + +/******************************************************************** +* pciArbiterDisable - Disable PCI-0`s Arbitration mechanism. +* +* Inputs: N/A +* Returns: true +*********************************************************************/ +bool pciArbiterDisable (PCI_HOST host) +{ + unsigned int regData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + GT_REG_WRITE (pci_arbiter_control[host], regData & 0x7fffffff); + return true; +} + +/******************************************************************** +* pciParkingDisable - Park on last option disable, with this function you can +* disable the park on last mechanism for each agent. +* disabling this option for all agents results parking +* on the internal master. +* +* Inputs: PCI_AGENT_PARK internalAgent - parking Disable for internal agent. +* PCI_AGENT_PARK externalAgent0 - parking Disable for external#0 agent. +* PCI_AGENT_PARK externalAgent1 - parking Disable for external#1 agent. +* PCI_AGENT_PARK externalAgent2 - parking Disable for external#2 agent. +* PCI_AGENT_PARK externalAgent3 - parking Disable for external#3 agent. +* PCI_AGENT_PARK externalAgent4 - parking Disable for external#4 agent. +* PCI_AGENT_PARK externalAgent5 - parking Disable for external#5 agent. +* Returns: true +*********************************************************************/ +bool pciParkingDisable (PCI_HOST host, PCI_AGENT_PARK internalAgent, + PCI_AGENT_PARK externalAgent0, + PCI_AGENT_PARK externalAgent1, + PCI_AGENT_PARK externalAgent2, + PCI_AGENT_PARK externalAgent3, + PCI_AGENT_PARK externalAgent4, + PCI_AGENT_PARK externalAgent5) +{ + unsigned int regData; + unsigned int writeData; + + GT_REG_READ (pci_arbiter_control[host], ®Data); + writeData = (internalAgent << 14) + (externalAgent0 << 15) + + (externalAgent1 << 16) + (externalAgent2 << 17) + + (externalAgent3 << 18) + (externalAgent4 << 19) + + (externalAgent5 << 20); + regData = (regData & ~(0x7f << 14)) | writeData; + GT_REG_WRITE (pci_arbiter_control[host], regData); + return true; +} + +/******************************************************************** +* pciSetRegionSnoopMode - This function modifys one of the 4 regions which +* supports Cache Coherency in the PCI_n interface. +* Inputs: region - One of the four regions. +* snoopType - There is four optional Types: +* 1. No Snoop. +* 2. Snoop to WT region. +* 3. Snoop to WB region. +* 4. Snoop & Invalidate to WB region. +* baseAddress - Base Address of this region. +* regionLength - Region length. +* Returns: false if one of the parameters is wrong otherwise return true. +*********************************************************************/ +bool pciSetRegionSnoopMode (PCI_HOST host, PCI_SNOOP_REGION region, + PCI_SNOOP_TYPE snoopType, + unsigned int baseAddress, + unsigned int regionLength) +{ + unsigned int snoopXbaseAddress; + unsigned int snoopXtopAddress; + unsigned int data; + unsigned int snoopHigh = baseAddress + regionLength; + + if ((region > PCI_SNOOP_REGION3) || (snoopType > PCI_SNOOP_WB)) + return false; + snoopXbaseAddress = + pci_snoop_control_base_0_low[host] + 0x10 * region; + snoopXtopAddress = pci_snoop_control_top_0[host] + 0x10 * region; + if (regionLength == 0) { /* closing the region */ + GT_REG_WRITE (snoopXbaseAddress, 0x0000ffff); + GT_REG_WRITE (snoopXtopAddress, 0); + return true; + } + baseAddress = baseAddress & 0xfff00000; /* Granularity of 1MByte */ + data = (baseAddress >> 20) | snoopType << 12; + GT_REG_WRITE (snoopXbaseAddress, data); + snoopHigh = (snoopHigh & 0xfff00000) >> 20; + GT_REG_WRITE (snoopXtopAddress, snoopHigh - 1); + return true; +} + +/* + * + */ + +static int gt_read_config_dword (struct pci_controller *hose, + pci_dev_t dev, int offset, u32 * value) +{ + int bus = PCI_BUS (dev); + + if ((bus == local_buses[0]) || (bus == local_buses[1])) { + *value = pciReadConfigReg ((PCI_HOST) hose->cfg_addr, offset, + PCI_DEV (dev)); + } else { + *value = pciOverBridgeReadConfigReg ((PCI_HOST) hose-> + cfg_addr, offset, + PCI_DEV (dev), bus); + } + return 0; +} + +static int gt_write_config_dword (struct pci_controller *hose, + pci_dev_t dev, int offset, u32 value) +{ + int bus = PCI_BUS (dev); + + if ((bus == local_buses[0]) || (bus == local_buses[1])) { + pciWriteConfigReg ((PCI_HOST) hose->cfg_addr, offset, + PCI_DEV (dev), value); + } else { + pciOverBridgeWriteConfigReg ((PCI_HOST) hose->cfg_addr, + offset, PCI_DEV (dev), value, + bus); + } + return 0; +} + +/* + * + */ + +static void gt_setup_ide (struct pci_controller *hose, + pci_dev_t dev, struct pci_config_table *entry) +{ + static const int ide_bar[] = { 8, 4, 8, 4, 0, 0 }; + u32 bar_response, bar_value; + int bar; + + for (bar = 0; bar < 6; bar++) { + pci_write_config_dword (dev, PCI_BASE_ADDRESS_0 + bar * 4, + 0x0); + pci_read_config_dword (dev, PCI_BASE_ADDRESS_0 + bar * 4, + &bar_response); + + pciauto_region_allocate (bar_response & + PCI_BASE_ADDRESS_SPACE_IO ? hose-> + pci_io : hose->pci_mem, ide_bar[bar], + &bar_value); + + pci_write_config_dword (dev, PCI_BASE_ADDRESS_0 + bar * 4, + bar_value); + } +} + +#ifndef CONFIG_P3G4 +static void gt_fixup_irq (struct pci_controller *hose, pci_dev_t dev) +{ + unsigned char pin, irq; + + pci_read_config_byte (dev, PCI_INTERRUPT_PIN, &pin); + + if (pin == 1) { /* only allow INT A */ + irq = pci_irq_swizzle[(PCI_HOST) hose-> + cfg_addr][PCI_DEV (dev)]; + if (irq) + pci_write_config_byte (dev, PCI_INTERRUPT_LINE, irq); + } +} +#endif + +struct pci_config_table gt_config_table[] = { + {PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE, + PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, gt_setup_ide}, + + {} +}; + +struct pci_controller pci0_hose = { +#ifndef CONFIG_P3G4 + fixup_irq:gt_fixup_irq, +#endif + config_table:gt_config_table, +}; + +struct pci_controller pci1_hose = { +#ifndef CONFIG_P3G4 + fixup_irq:gt_fixup_irq, +#endif + config_table:gt_config_table, +}; + +void pci_init_board (void) +{ + unsigned int command; + + pci0_hose.first_busno = 0; + pci0_hose.last_busno = 0xff; + local_buses[0] = pci0_hose.first_busno; + /* PCI memory space */ + pci_set_region (pci0_hose.regions + 0, + CFG_PCI0_0_MEM_SPACE, + CFG_PCI0_0_MEM_SPACE, + CFG_PCI0_MEM_SIZE, PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region (pci0_hose.regions + 1, + CFG_PCI0_IO_SPACE_PCI, + CFG_PCI0_IO_SPACE, CFG_PCI0_IO_SIZE, PCI_REGION_IO); + + pci_set_ops (&pci0_hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + gt_read_config_dword, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + gt_write_config_dword); + + pci0_hose.region_count = 2; + + pci0_hose.cfg_addr = (unsigned int *) PCI_HOST0; + + pci_register_hose (&pci0_hose); + +#ifndef CONFIG_P3G4 + pciArbiterEnable (PCI_HOST0); + pciParkingDisable (PCI_HOST0, 1, 1, 1, 1, 1, 1, 1); +#endif + + command = pciReadConfigReg (PCI_HOST0, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MASTER; + pciWriteConfigReg (PCI_HOST0, PCI_COMMAND, SELF, command); + + pci0_hose.last_busno = pci_hose_scan (&pci0_hose); + + command = pciReadConfigReg (PCI_HOST0, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MEMORY; + pciWriteConfigReg (PCI_HOST0, PCI_COMMAND, SELF, command); + + pci1_hose.first_busno = pci0_hose.last_busno + 1; + pci1_hose.last_busno = 0xff; + pci1_hose.current_busno = pci0_hose.current_busno; + local_buses[1] = pci1_hose.first_busno; + + /* PCI memory space */ + pci_set_region (pci1_hose.regions + 0, + CFG_PCI1_0_MEM_SPACE, + CFG_PCI1_0_MEM_SPACE, + CFG_PCI1_MEM_SIZE, PCI_REGION_MEM); + + /* PCI I/O space */ + pci_set_region (pci1_hose.regions + 1, + CFG_PCI1_IO_SPACE_PCI, + CFG_PCI1_IO_SPACE, CFG_PCI1_IO_SIZE, PCI_REGION_IO); + + pci_set_ops (&pci1_hose, + pci_hose_read_config_byte_via_dword, + pci_hose_read_config_word_via_dword, + gt_read_config_dword, + pci_hose_write_config_byte_via_dword, + pci_hose_write_config_word_via_dword, + gt_write_config_dword); + + pci1_hose.region_count = 2; + + pci1_hose.cfg_addr = (unsigned int *) PCI_HOST1; + + pci_register_hose (&pci1_hose); + +#ifndef CONFIG_P3G4 + pciArbiterEnable (PCI_HOST1); + pciParkingDisable (PCI_HOST1, 1, 1, 1, 1, 1, 1, 1); +#endif + + command = pciReadConfigReg (PCI_HOST1, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MASTER; + pciWriteConfigReg (PCI_HOST1, PCI_COMMAND, SELF, command); + + pci1_hose.last_busno = pci_hose_scan (&pci1_hose); + + command = pciReadConfigReg (PCI_HOST1, PCI_COMMAND, SELF); + command |= PCI_COMMAND_MEMORY; + pciWriteConfigReg (PCI_HOST1, PCI_COMMAND, SELF, command); +} diff --git a/board/evb64260/sdram_init.c b/board/evb64260/sdram_init.c new file mode 100755 index 0000000..8d63c6f --- /dev/null +++ b/board/evb64260/sdram_init.c @@ -0,0 +1,662 @@ +/* + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 + */ + +/* sdram_init.c - automatic memory sizing */ + +#include <common.h> +#include <74xx_7xx.h> +#include <galileo/memory.h> +#include <galileo/pci.h> +#include <galileo/gt64260R.h> +#include <net.h> + +#include "eth.h" +#include "mpsc.h" +#include "i2c.h" +#include "64260.h" + +/* #define DEBUG */ +#define MAP_PCI + +#ifdef DEBUG +#define DP(x) x +#else +#define DP(x) +#endif + +#define GB (1 << 30) + +/* structure to store the relevant information about an sdram bank */ +typedef struct sdram_info { + uchar drb_size; + uchar registered, ecc; + uchar tpar; + uchar tras_clocks; + uchar burst_len; + uchar banks, slot; + int size; /* detected size, not from I2C but from dram_size() */ +} sdram_info_t; + +#ifdef DEBUG +void dump_dimm_info (struct sdram_info *d) +{ + static const char *ecc_legend[] = { "", " Parity", " ECC" }; + + printf ("dimm%s %sDRAM: %dMibytes:\n", + ecc_legend[d->ecc], + d->registered ? "R" : "", (d->size >> 20)); + printf (" drb=%d tpar=%d tras=%d burstlen=%d banks=%d slot=%d\n", + d->drb_size, d->tpar, d->tras_clocks, d->burst_len, + d->banks, d->slot); +} +#endif + +static int +memory_map_bank (unsigned int bankNo, + unsigned int bankBase, unsigned int bankLength) +{ +#ifdef DEBUG + if (bankLength > 0) { + printf ("mapping bank %d at %08x - %08x\n", + bankNo, bankBase, bankBase + bankLength - 1); + } else { + printf ("unmapping bank %d\n", bankNo); + } +#endif + + memoryMapBank (bankNo, bankBase, bankLength); + + return 0; +} + +#ifdef MAP_PCI +static int +memory_map_bank_pci (unsigned int bankNo, + unsigned int bankBase, unsigned int bankLength) +{ + PCI_HOST host; + + for (host = PCI_HOST0; host <= PCI_HOST1; host++) { + const int features = + PREFETCH_ENABLE | + DELAYED_READ_ENABLE | + AGGRESSIVE_PREFETCH | + READ_LINE_AGGRESSIVE_PREFETCH | + READ_MULTI_AGGRESSIVE_PREFETCH | + MAX_BURST_4 | PCI_NO_SWAP; + + pciMapMemoryBank (host, bankNo, bankBase, bankLength); + + pciSetRegionSnoopMode (host, bankNo, PCI_SNOOP_WB, bankBase, + bankLength); + + pciSetRegionFeatures (host, bankNo, features, bankBase, + bankLength); + } + return 0; +} +#endif + +/* ------------------------------------------------------------------------- */ + +/* much of this code is based on (or is) the code in the pip405 port */ +/* thanks go to the authors of said port - Josh */ + + +/* + * translate ns.ns/10 coding of SPD timing values + * into 10 ps unit values + */ +static inline unsigned short NS10to10PS (unsigned char spd_byte) +{ + unsigned short ns, ns10; + + /* isolate upper nibble */ + ns = (spd_byte >> 4) & 0x0F; + /* isolate lower nibble */ + ns10 = (spd_byte & 0x0F); + + return (ns * 100 + ns10 * 10); +} + +/* + * translate ns coding of SPD timing values + * into 10 ps unit values + */ +static inline unsigned short NSto10PS (unsigned char spd_byte) +{ + return (spd_byte * 100); +} + +#ifdef CONFIG_ZUMA_V2 +static int check_dimm (uchar slot, sdram_info_t * info) +{ + /* assume 2 dimms, 2 banks each 256M - we dont have an + * dimm i2c so rely on the detection routines later */ + + memset (info, 0, sizeof (*info)); + + info->slot = slot; + info->banks = 2; /* Detect later */ + info->registered = 0; + info->drb_size = 32; /* 16 - 256MBit, 32 - 512MBit + but doesn't matter, both do same + thing in setup_sdram() */ + info->tpar = 3; + info->tras_clocks = 5; + info->burst_len = 4; +#ifdef CONFIG_ECC + info->ecc = 0; /* Detect later */ +#endif /* CONFIG_ECC */ + return 0; +} + +#elif defined(CONFIG_P3G4) + +static int check_dimm (uchar slot, sdram_info_t * info) +{ + memset (info, 0, sizeof (*info)); + + if (slot) + return 0; + + info->slot = slot; + info->banks = 1; + info->registered = 0; + info->drb_size = 4; + info->tpar = 3; + info->tras_clocks = 6; + info->burst_len = 4; +#ifdef CONFIG_ECC + info->ecc = 2; +#endif + return 0; +} + +#else /* ! CONFIG_ZUMA_V2 && ! CONFIG_P3G4 */ + +/* This code reads the SPD chip on the sdram and populates + * the array which is passed in with the relevant information */ +static int check_dimm (uchar slot, sdram_info_t * info) +{ + DECLARE_GLOBAL_DATA_PTR; + uchar addr = slot == 0 ? DIMM0_I2C_ADDR : DIMM1_I2C_ADDR; + int ret; + uchar rows, cols, sdram_banks, supp_cal, width, cal_val; + ulong tmemclk; + uchar trp_clocks, trcd_clocks; + uchar data[128]; + + get_clocks (); + + tmemclk = 1000000000 / (gd->bus_clk / 100); /* in 10 ps units */ + +#ifdef CONFIG_EVB64260_750CX + if (0 != slot) { + printf ("check_dimm: The EVB-64260-750CX only has 1 DIMM,"); + printf (" called with slot=%d insetad!\n", slot); + return 0; + } +#endif + DP (puts ("before i2c read\n")); + + ret = i2c_read (addr, 0, 128, data, 0); + + DP (puts ("after i2c read\n")); + + /* zero all the values */ + memset (info, 0, sizeof (*info)); + + if (ret) { + DP (printf ("No DIMM in slot %d [err = %x]\n", slot, ret)); + return 0; + } + + /* first, do some sanity checks */ + if (data[2] != 0x4) { + printf ("Not SDRAM in slot %d\n", slot); + return 0; + } + + /* get various information */ + rows = data[3]; + cols = data[4]; + info->banks = data[5]; + sdram_banks = data[17]; + width = data[13] & 0x7f; + + DP (printf + ("sdram_banks: %d, banks: %d\n", sdram_banks, info->banks)); + + /* check if the memory is registered */ + if (data[21] & (BIT1 | BIT4)) + info->registered = 1; + +#ifdef CONFIG_ECC + /* check for ECC/parity [0 = none, 1 = parity, 2 = ecc] */ + info->ecc = (data[11] & 2) >> 1; +#endif + + /* bit 1 is CL2, bit 2 is CL3 */ + supp_cal = (data[18] & 0x6) >> 1; + + /* compute the relevant clock values */ + trp_clocks = (NSto10PS (data[27]) + (tmemclk - 1)) / tmemclk; + trcd_clocks = (NSto10PS (data[29]) + (tmemclk - 1)) / tmemclk; + info->tras_clocks = (NSto10PS (data[30]) + (tmemclk - 1)) / tmemclk; + + DP (printf ("trp = %d\ntrcd_clocks = %d\ntras_clocks = %d\n", + trp_clocks, trcd_clocks, info->tras_clocks)); + + /* try a CAS latency of 3 first... */ + cal_val = 0; + if (supp_cal & 3) { + if (NS10to10PS (data[9]) <= tmemclk) + cal_val = 3; + } + + /* then 2... */ + if (supp_cal & 2) { + if (NS10to10PS (data[23]) <= tmemclk) + cal_val = 2; + } + + DP (printf ("cal_val = %d\n", cal_val)); + + /* bummer, did't work... */ + if (cal_val == 0) { + DP (printf ("Couldn't find a good CAS latency\n")); + return 0; + } + + /* get the largest delay -- these values need to all be the same + * see Res#6 */ + info->tpar = cal_val; + if (trp_clocks > info->tpar) + info->tpar = trp_clocks; + if (trcd_clocks > info->tpar) + info->tpar = trcd_clocks; + + DP (printf ("tpar set to: %d\n", info->tpar)); + +#ifdef CFG_BROKEN_CL2 + if (info->tpar == 2) { + info->tpar = 3; + DP (printf ("tpar fixed-up to: %d\n", info->tpar)); + } +#endif + /* compute the module DRB size */ + info->drb_size = + (((1 << (rows + cols)) * sdram_banks) * width) / _16M; + + DP (printf ("drb_size set to: %d\n", info->drb_size)); + + /* find the burst len */ + info->burst_len = data[16] & 0xf; + if ((info->burst_len & 8) == 8) { + info->burst_len = 1; + } else if ((info->burst_len & 4) == 4) { + info->burst_len = 0; + } else { + return 0; + } + + info->slot = slot; + return 0; +} +#endif /* ! CONFIG_ZUMA_V2 */ + +static int setup_sdram_common (sdram_info_t info[2]) +{ + ulong tmp; + int tpar = 2, tras_clocks = 5, registered = 1, ecc = 2; + + if (!info[0].banks && !info[1].banks) + return 0; + + if (info[0].banks) { + if (info[0].tpar > tpar) + tpar = info[0].tpar; + if (info[0].tras_clocks > tras_clocks) + tras_clocks = info[0].tras_clocks; + if (!info[0].registered) + registered = 0; + if (info[0].ecc != 2) + ecc = 0; + } + + if (info[1].banks) { + if (info[1].tpar > tpar) + tpar = info[1].tpar; + if (info[1].tras_clocks > tras_clocks) + tras_clocks = info[1].tras_clocks; + if (!info[1].registered) + registered = 0; + if (info[1].ecc != 2) + ecc = 0; + } + + /* SDRAM configuration */ + tmp = GTREGREAD (SDRAM_CONFIGURATION); + + /* Turn on physical interleave if both DIMMs + * have even numbers of banks. */ + if ((info[0].banks == 0 || info[0].banks == 2) && + (info[1].banks == 0 || info[1].banks == 2)) { + /* physical interleave on */ + tmp &= ~(1 << 15); + } else { + /* physical interleave off */ + tmp |= (1 << 15); + } + + tmp |= (registered << 17); + + /* Use buffer 1 to return read data to the CPU + * See Res #12 */ + tmp |= (1 << 26); + + GT_REG_WRITE (SDRAM_CONFIGURATION, tmp); + DP (printf ("SDRAM config: %08x\n", GTREGREAD (SDRAM_CONFIGURATION))); + + /* SDRAM timing */ + tmp = (((tpar == 3) ? 2 : 1) | + (((tpar == 3) ? 2 : 1) << 2) | + (((tpar == 3) ? 2 : 1) << 4) | (tras_clocks << 8)); + +#ifdef CONFIG_ECC + /* Setup ECC */ + if (ecc == 2) + tmp |= 1 << 13; +#endif /* CONFIG_ECC */ + + GT_REG_WRITE (SDRAM_TIMING, tmp); + DP (printf ("SDRAM timing: %08x (%d,%d,%d,%d)\n", + GTREGREAD (SDRAM_TIMING), tpar, tpar, tpar, tras_clocks)); + + /* SDRAM address decode register */ + /* program this with the default value */ + GT_REG_WRITE (SDRAM_ADDRESS_DECODE, 0x2); + DP (printf ("SDRAM decode: %08x\n", + GTREGREAD (SDRAM_ADDRESS_DECODE))); + + return 0; +} + +/* sets up the GT properly with information passed in */ +static int setup_sdram (sdram_info_t * info) +{ + ulong tmp, check; + ulong *addr = 0; + int i; + + /* sanity checking */ + if (!info->banks) + return 0; + + /* ---------------------------- */ + /* Program the GT with the discovered data */ + + /* bank parameters */ + tmp = (0xf << 16); /* leave all virt bank pages open */ + + DP (printf ("drb_size: %d\n", info->drb_size)); + switch (info->drb_size) { + case 1: + tmp |= (1 << 14); + break; + case 4: + case 8: + tmp |= (2 << 14); + break; + case 16: + case 32: + tmp |= (3 << 14); + break; + default: + printf ("Error in dram size calculation\n"); + return 1; + } + + /* SDRAM bank parameters */ + /* the param registers for slot 1 (banks 2+3) are offset by 0x8 */ + GT_REG_WRITE (SDRAM_BANK0PARAMETERS + (info->slot * 0x8), tmp); + GT_REG_WRITE (SDRAM_BANK1PARAMETERS + (info->slot * 0x8), tmp); + DP (printf + ("SDRAM bankparam slot %d (bank %d+%d): %08lx\n", info->slot, + info->slot * 2, (info->slot * 2) + 1, tmp)); + + /* set the SDRAM configuration for each bank */ + for (i = info->slot * 2; i < ((info->slot * 2) + info->banks); i++) { + DP (printf ("*** Running a MRS cycle for bank %d ***\n", i)); + + /* map the bank */ + memory_map_bank (i, 0, GB / 4); + + /* set SDRAM mode */ + GT_REG_WRITE (SDRAM_OPERATION_MODE, 0x3); + check = GTREGREAD (SDRAM_OPERATION_MODE); + + /* dummy write */ + *addr = 0; + + /* wait for the command to complete */ + while ((GTREGREAD (SDRAM_OPERATION_MODE) & (1 << 31)) == 0); + + /* switch back to normal operation mode */ + GT_REG_WRITE (SDRAM_OPERATION_MODE, 0); + check = GTREGREAD (SDRAM_OPERATION_MODE); + + /* unmap the bank */ + memory_map_bank (i, 0, 0); + DP (printf ("*** MRS cycle for bank %d done ***\n", i)); + } + + return 0; +} + +/* + * Check memory range for valid RAM. A simple memory test determines + * the actually available RAM size between addresses `base' and + * `base + maxsize'. Some (not all) hardware errors are detected: + * - short between address lines + * - short between data lines + */ +static long int dram_size (long int *base, long int maxsize) +{ + volatile long int *addr, *b = base; + long int cnt, val, save1, save2; + +#define STARTVAL (1<<20) /* start test at 1M */ + for (cnt = STARTVAL / sizeof (long); cnt < maxsize / sizeof (long); + cnt <<= 1) { + addr = base + cnt; /* pointer arith! */ + + save1 = *addr; /* save contents of addr */ + save2 = *b; /* save contents of base */ + + *addr = cnt; /* write cnt to addr */ + *b = 0; /* put null at base */ + + /* check at base address */ + if ((*b) != 0) { + *addr = save1; /* restore *addr */ + *b = save2; /* restore *b */ + return (0); + } + val = *addr; /* read *addr */ + + *addr = save1; + *b = save2; + + if (val != cnt) { + /* fix boundary condition.. STARTVAL means zero */ + if (cnt == STARTVAL / sizeof (long)) + cnt = 0; + return (cnt * sizeof (long)); + } + } + return maxsize; +} + +/* ------------------------------------------------------------------------- */ + +/* U-Boot interface function to SDRAM init - this is where all the + * controlling logic happens */ +long int initdram (int board_type) +{ + ulong checkbank[4] = {[0 ... 3] = 0 }; + int bank_no; + ulong total; + int nhr; + sdram_info_t dimm_info[2]; + + + /* first, use the SPD to get info about the SDRAM */ + + /* check the NHR bit and skip mem init if it's already done */ + nhr = get_hid0 () & (1 << 16); + + if (nhr) { + printf ("Skipping SDRAM setup due to NHR bit being set\n"); + } else { + /* DIMM0 */ + check_dimm (0, &dimm_info[0]); + + /* DIMM1 */ +#ifndef CONFIG_EVB64260_750CX /* EVB64260_750CX has only 1 DIMM */ + check_dimm (1, &dimm_info[1]); +#else /* CONFIG_EVB64260_750CX */ + memset (&dimm_info[1], 0, sizeof (sdram_info_t)); +#endif + + /* unmap all banks */ + memory_map_bank (0, 0, 0); + memory_map_bank (1, 0, 0); + memory_map_bank (2, 0, 0); + memory_map_bank (3, 0, 0); + + /* Now, program the GT with the correct values */ + if (setup_sdram_common (dimm_info)) { + printf ("Setup common failed.\n"); + } + + if (setup_sdram (&dimm_info[0])) { + printf ("Setup for DIMM1 failed.\n"); + } + + if (setup_sdram (&dimm_info[1])) { + printf ("Setup for DIMM2 failed.\n"); + } + + /* set the NHR bit */ + set_hid0 (get_hid0 () | (1 << 16)); + } + /* next, size the SDRAM banks */ + + total = 0; + if (dimm_info[0].banks > 0) + checkbank[0] = 1; + if (dimm_info[0].banks > 1) + checkbank[1] = 1; + if (dimm_info[0].banks > 2) + printf ("Error, SPD claims DIMM1 has >2 banks\n"); + + if (dimm_info[1].banks > 0) + checkbank[2] = 1; + if (dimm_info[1].banks > 1) + checkbank[3] = 1; + if (dimm_info[1].banks > 2) + printf ("Error, SPD claims DIMM2 has >2 banks\n"); + + /* Generic dram sizer: works even if we don't have i2c DIMMs, + * as long as the timing settings are more or less correct */ + + /* + * pass 1: size all the banks, using first bat (0-256M) + * limitation: we only support 256M per bank due to + * us only having 1 BAT for all DRAM + */ + for (bank_no = 0; bank_no < CFG_DRAM_BANKS; bank_no++) { + /* skip over banks that are not populated */ + if (!checkbank[bank_no]) + continue; + + DP (printf ("checking bank %d\n", bank_no)); + + memory_map_bank (bank_no, 0, GB / 4); + checkbank[bank_no] = dram_size (NULL, GB / 4); + memory_map_bank (bank_no, 0, 0); + + DP (printf ("bank %d %08lx\n", bank_no, checkbank[bank_no])); + } + + /* + * pass 2: contiguously map each bank into physical address + * space. + */ + dimm_info[0].banks = dimm_info[1].banks = 0; + for (bank_no = 0; bank_no < CFG_DRAM_BANKS; bank_no++) { + if (!checkbank[bank_no]) + continue; + + dimm_info[bank_no / 2].banks++; + dimm_info[bank_no / 2].size += checkbank[bank_no]; + + memory_map_bank (bank_no, total, checkbank[bank_no]); +#ifdef MAP_PCI + memory_map_bank_pci (bank_no, total, checkbank[bank_no]); +#endif + total += checkbank[bank_no]; + } + +#ifdef CONFIG_ECC +#ifdef CONFIG_ZUMA_V2 + /* + * We always enable ECC when bank 2 and 3 are unpopulated + * If we 2 or 3 are populated, we CAN'T support ECC. + * (Zuma boards only support ECC in banks 0 and 1; assume that + * in that configuration, ECC chips are mounted, even for stacked + * chips) + */ + if (checkbank[2] == 0 && checkbank[3] == 0) { + dimm_info[0].ecc = 2; + GT_REG_WRITE (SDRAM_TIMING, + GTREGREAD (SDRAM_TIMING) | (1 << 13)); + /* TODO: do we have to run MRS cycles again? */ + } +#endif /* CONFIG_ZUMA_V2 */ + + if (GTREGREAD (SDRAM_TIMING) & (1 << 13)) { + puts ("[ECC] "); + } +#endif /* CONFIG_ECC */ + +#ifdef DEBUG + dump_dimm_info (&dimm_info[0]); + dump_dimm_info (&dimm_info[1]); +#endif + /* TODO: return at MOST 256M? */ + /* return total > GB/4 ? GB/4 : total; */ + return total; +} diff --git a/board/evb64260/serial.c b/board/evb64260/serial.c new file mode 100755 index 0000000..d9c7a15 --- /dev/null +++ b/board/evb64260/serial.c @@ -0,0 +1,191 @@ +/* + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 + */ + +/* + * serial.c - serial support for the gal ev board + */ + +/* supports both the 16650 duart and the MPSC */ + +#include <common.h> +#include <command.h> +#include <galileo/memory.h> + +#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2) +#include <ns16550.h> +#endif + +#include "serial.h" + +#include "mpsc.h" + +#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2) +const NS16550_t COM_PORTS[] = { (NS16550_t) CFG_NS16550_COM1, + (NS16550_t) CFG_NS16550_COM2 }; +#endif + +#ifdef CONFIG_MPSC + +int serial_init (void) +{ + DECLARE_GLOBAL_DATA_PTR; + +#if (defined CFG_INIT_CHAN1) || (defined CFG_INIT_CHAN2) + int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate; +#endif + + mpsc_init(gd->baudrate); + + /* init the DUART chans so that KGDB in the kernel can use them */ +#ifdef CFG_INIT_CHAN1 + NS16550_reinit(COM_PORTS[0], clock_divisor); +#endif +#ifdef CFG_INIT_CHAN2 + NS16550_reinit(COM_PORTS[1], clock_divisor); +#endif + return (0); +} + +void +serial_putc(const char c) +{ + if (c == '\n') + mpsc_putchar('\r'); + + mpsc_putchar(c); +} + +int +serial_getc(void) +{ + return mpsc_getchar(); +} + +int +serial_tstc(void) +{ + return mpsc_test_char(); +} + +void +serial_setbrg (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + galbrg_set_baudrate(CONFIG_MPSC_PORT, gd->baudrate); +} + +#else /* ! CONFIG_MPSC */ + +int serial_init (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate; + +#ifdef CFG_INIT_CHAN1 + (void)NS16550_init(COM_PORTS[0], clock_divisor); +#endif +#ifdef CFG_INIT_CHAN2 + (void)NS16550_init(COM_PORTS[1], clock_divisor); +#endif + + return (0); +} + +void +serial_putc(const char c) +{ + if (c == '\n') + NS16550_putc(COM_PORTS[CFG_DUART_CHAN], '\r'); + + NS16550_putc(COM_PORTS[CFG_DUART_CHAN], c); +} + +int +serial_getc(void) +{ + return NS16550_getc(COM_PORTS[CFG_DUART_CHAN]); +} + +int +serial_tstc(void) +{ + return NS16550_tstc(COM_PORTS[CFG_DUART_CHAN]); +} + +void +serial_setbrg (void) +{ + DECLARE_GLOBAL_DATA_PTR; + + int clock_divisor = CFG_NS16550_CLK / 16 / gd->baudrate; + +#ifdef CFG_INIT_CHAN1 + NS16550_reinit(COM_PORTS[0], clock_divisor); +#endif +#ifdef CFG_INIT_CHAN2 + NS16550_reinit(COM_PORTS[1], clock_divisor); +#endif +} + +#endif /* CONFIG_MPSC */ + +void +serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +void +kgdb_serial_init(void) +{ +} + +void +putDebugChar (int c) +{ + serial_putc (c); +} + +void +putDebugStr (const char *str) +{ + serial_puts (str); +} + +int +getDebugChar (void) +{ + return serial_getc(); +} + +void +kgdb_interruptible (int yes) +{ + return; +} +#endif /* CFG_CMD_KGDB */ diff --git a/board/evb64260/serial.h b/board/evb64260/serial.h new file mode 100755 index 0000000..bac9253 --- /dev/null +++ b/board/evb64260/serial.h @@ -0,0 +1,63 @@ +/* serial.h - mostly useful for DUART serial_init in serial.c */ + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#if 0 + +#define B230400 1 +#define B115200 2 +#define B57600 4 +#define B38400 82 +#define B19200 163 +#define B9600 24 +#define B4800 651 +#define B2400 1302 +#define B1200 2604 +#define B600 5208 +#define B300 10417 +#define B150 20833 +#define B110 28409 +#define BDEFAULT B115200 + + /* this stuff is important to initialize + the DUART channels */ + +#define Scale 0x01L /* distance between port addresses */ +#define COM1 0x000003f8 /* Keyboard */ +#define COM2 0x000002f8 /* Host */ + + +/* Port Definitions relative to base COM port addresses */ +#define DataIn (0x00*Scale) /* data input port */ +#define DataOut (0x00*Scale) /* data output port */ +#define BaudLsb (0x00*Scale) /* baud rate divisor least significant byte */ +#define BaudMsb (0x01*Scale) /* baud rate divisor most significant byte */ +#define Ier (0x01*Scale) /* interrupt enable register */ +#define Iir (0x02*Scale) /* interrupt identification register */ +#define Lcr (0x03*Scale) /* line control register */ +#define Mcr (0x04*Scale) /* modem control register */ +#define Lsr (0x05*Scale) /* line status register */ +#define Msr (0x06*Scale) /* modem status register */ + +/* Bit Definitions for above ports */ +#define LcrDlab 0x80 /* b7: enable baud rate divisor registers */ +#define LcrDflt 0x03 /* b6-0: no parity, 1 stop, 8 data */ + +#define McrRts 0x02 /* b1: request to send (I am ready to xmit) */ +#define McrDtr 0x01 /* b0: data terminal ready (I am alive ready to rcv) */ +#define McrDflt (McrRts|McrDtr) + +#define LsrTxD 0x6000 /* b5: transmit holding register empty (i.e. xmit OK!)*/ + /* b6: transmitter empty */ +#define LsrRxD 0x0100 /* b0: received data ready (i.e. got a byte!) */ + +#define MsrRi 0x0040 /* b6: ring indicator (other guy is ready to rcv) */ +#define MsrDsr 0x0020 /* b5: data set ready (other guy is alive ready to rcv */ +#define MsrCts 0x0010 /* b4: clear to send (other guy is ready to rcv) */ + +#define IerRda 0xf /* b0: Enable received data available interrupt */ + +#endif + +#endif /* __SERIAL_H__ */ diff --git a/board/evb64260/u-boot.lds b/board/evb64260/u-boot.lds new file mode 100755 index 0000000..d89eb6c --- /dev/null +++ b/board/evb64260/u-boot.lds @@ -0,0 +1,138 @@ +/* + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, 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 + */ + +/* + * u-boot.lds - linker script for U-Boot on the Galileo Eval Board. + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/74xx_7xx/start.o (.text) + +/* store the environment in a seperate sector in the boot flash */ +/* . = env_offset; */ +/* common/environment.o(.text) */ + + *(.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 : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/board/evb64260/zuma_pbb.c b/board/evb64260/zuma_pbb.c new file mode 100755 index 0000000..d64025a --- /dev/null +++ b/board/evb64260/zuma_pbb.c @@ -0,0 +1,220 @@ +#include <common.h> +#include <malloc.h> + +#if (CONFIG_COMMANDS & CFG_CMD_BSP) +#include <command.h> +#endif + +#include <pci.h> +#include <galileo/pci.h> +#include "zuma_pbb.h" + +#undef DEBUG + +#define PAT_LO 0x00010203 +#define PAT_HI 0x04050607 + +static PBB_DMA_REG_MAP *zuma_pbb_reg = NULL; +static char test_buf1[2048]; +static char test_buf2[2048]; +void zuma_init_pbb(void); +int zuma_mbox_init(void); +int zuma_test_dma(int cmd, int size); + +int zuma_test_dma (int cmd, int size) +{ + static const char *const test_legend[] = { + "write", "verify", + "copy", "compare", + "write inc", "verify inc" + }; + register int i, j; + unsigned int p1 = ((unsigned int) test_buf1 + 0xff) & (~0xff); + unsigned int p2 = ((unsigned int) test_buf2 + 0xff) & (~0xff); + volatile unsigned int *ps = (unsigned int *) p1; + volatile unsigned int *pd = (unsigned int *) p2; + unsigned int funct, pat_lo = PAT_LO, pat_hi = PAT_HI; + DMA_INT_STATUS stat; + int ret = 0; + + if (!zuma_pbb_reg) { + printf ("not initted\n"); + return -1; + } + + if (cmd < 0 || cmd > 5) { + printf ("inv cmd %d\n", cmd); + return -1; + } + + if (cmd == 2 || cmd == 3) { + /* not implemented */ + return 0; + } + + if (size <= 0 || size > 1024) + size = 1024; + + size &= (~7); /* throw away bottom 3 bits */ + + p1 = ((unsigned int) test_buf1 + 0xff) & (~0xff); + p2 = ((unsigned int) test_buf2 + 0xff) & (~0xff); + + memset ((void *) p1, 0, size); + memset ((void *) p2, 0, size); + + for (i = 0; i < size / 4; i += 2) { + ps[i] = pat_lo; + ps[i + 1] = pat_hi; + if (cmd == 4 || cmd == 5) { + unsigned char *pl = (unsigned char *) &pat_lo; + unsigned char *ph = (unsigned char *) &pat_hi; + + for (j = 0; j < 4; j++) { + pl[j] += 8; + ph[j] += 8; + } + } + } + + funct = (1 << 31) | (cmd << 24) | (size); + + zuma_pbb_reg->int_mask.pci_bits.chan0 = + EOF_RX_FLAG | EOF_TX_FLAG | EOB_TX_FLAG; + + zuma_pbb_reg->debug_57 = PAT_LO; /* patl */ + zuma_pbb_reg->debug_58 = PAT_HI; /* path */ + + zuma_pbb_reg->debug_54 = cpu_to_le32 (p1); /* src 0x01b0 */ + zuma_pbb_reg->debug_55 = cpu_to_le32 (p2); /* dst 0x01b8 */ + zuma_pbb_reg->debug_56 = cpu_to_le32 (funct); /* func, 0x01c0 */ + + /* give DMA time to chew on things.. dont use DRAM or PCI */ + /* if you can avoid it. */ + do { + for (i = 0; i < 1000 * 10; i++); + } while (le32_to_cpu (zuma_pbb_reg->debug_56) & (1 << 31)); + + stat.word = zuma_pbb_reg->status.word; + zuma_pbb_reg->int_mask.word = 0; + + printf ("stat: %08x (%x)\n", stat.word, stat.pci_bits.chan0); + + printf ("func: %08x\n", le32_to_cpu (zuma_pbb_reg->debug_56)); + printf ("src @%08x: %08x %08x %08x %08x\n", p1, ps[0], ps[1], ps[2], + ps[3]); + printf ("dst @%08x: %08x %08x %08x %08x\n", p2, pd[0], pd[1], pd[2], + pd[3]); + printf ("func: %08x\n", le32_to_cpu (zuma_pbb_reg->debug_56)); + + + if (cmd == 0 || cmd == 4) { + /* this is a write */ + if (!(stat.pci_bits.chan0 & EOF_RX_FLAG) || /* not done */ + (memcmp ((void *) ps, (void *) pd, size) != 0)) { /* cmp error */ + for (i = 0; i < size / 4; i += 2) { + if ((ps[i] != pd[i]) || (ps[i + 1] != pd[i + 1])) { + printf ("s @%p:%08x %08x\n", &ps[i], ps[i], ps[i + 1]); + printf ("d @%p:%08x %08x\n", &pd[i], pd[i], pd[i + 1]); + } + } + ret = -1; + } + } else { + /* this is a verify */ + if (!(stat.pci_bits.chan0 & EOF_TX_FLAG) || /* not done */ + (stat.pci_bits.chan0 & EOB_TX_FLAG)) { /* cmp error */ + printf ("%08x: %08x %08x\n", + le32_to_cpu (zuma_pbb_reg->debug_63), + zuma_pbb_reg->debug_61, zuma_pbb_reg->debug_62); + ret = -1; + } + } + + printf ("%s cmd %d, %d bytes: %s!\n", test_legend[cmd], cmd, size, + (ret == 0) ? "PASSED" : "FAILED"); + return 0; +} + +void zuma_init_pbb (void) +{ + unsigned int iobase; + pci_dev_t dev = + pci_find_device (VENDOR_ID_ZUMA, DEVICE_ID_ZUMA_PBB, 0); + + if (dev == -1) { + printf ("no zuma pbb\n"); + return; + } + + pci_read_config_dword (dev, PCI_BASE_ADDRESS_0, &iobase); + + zuma_pbb_reg = + (PBB_DMA_REG_MAP *) (iobase & PCI_BASE_ADDRESS_MEM_MASK); + + if (!zuma_pbb_reg) { + printf ("zuma pbb bar none! (hah hah, get it?)\n"); + return; + } + + zuma_pbb_reg->int_mask.word = 0; + + printf ("pbb @ %p v%d.%d, timestamp %08x\n", zuma_pbb_reg, + zuma_pbb_reg->version.pci_bits.rev_major, + zuma_pbb_reg->version.pci_bits.rev_minor, + zuma_pbb_reg->timestamp); + +} + +#if (CONFIG_COMMANDS & CFG_CMD_BSP) + +static int last_cmd = 4; /* write increment */ +static int last_size = 64; + +int +do_zuma_init_pbb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + zuma_init_pbb (); + return 0; +} + +int +do_zuma_test_dma (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + if (argc > 1) { + last_cmd = simple_strtoul (argv[1], NULL, 10); + } + if (argc > 2) { + last_size = simple_strtoul (argv[2], NULL, 10); + } + zuma_test_dma (last_cmd, last_size); + return 0; +} + +int +do_zuma_init_mbox (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) +{ + zuma_mbox_init (); + return 0; +} + +U_BOOT_CMD( + zinit, 1, 0, do_zuma_init_pbb, + "zinit - init zuma pbb\n", + "\n" + " - init zuma pbb\n" +); +U_BOOT_CMD( + zdtest, 3, 1, do_zuma_test_dma, + "zdtest - run dma test\n", + "[cmd [count]]\n" + " - run dma cmd (w=0,v=1,cp=2,cmp=3,wi=4,vi=5), count bytes\n" +); +U_BOOT_CMD( + zminit, 1, 0, do_zuma_init_mbox, + "zminit - init zuma mbox\n", + "\n" + " - init zuma mbox\n" +); + +#endif /* CFG_CMD_BSP */ diff --git a/board/evb64260/zuma_pbb.h b/board/evb64260/zuma_pbb.h new file mode 100755 index 0000000..300b2fe --- /dev/null +++ b/board/evb64260/zuma_pbb.h @@ -0,0 +1,346 @@ +#ifndef ZUMA_PBB_H +#define ZUMA_PBB_H + +#define MAX_NUM_BUFFER_PER_RING 32 + +#ifdef __BIG_ENDIAN +#define cpu_bits _be_s_bits /* use with le32_to_cpu only */ +#define pci_bits _be_bits /* may contain swapped bytes, + but dont need le32_to_cpu */ +#endif + +#ifdef __LITTLE_ENDIAN +#define cpu_bits _le_bits +#define pci_bits _le_bits +#endif + +#define VENDOR_ID_ZUMA 0x1172 +#define DEVICE_ID_ZUMA_PBB 0x0004 + +#define RXDBP(chan) (&sip->rx_desc[chan].base) /* ch*8 */ +#define RXDP(chan) (&sip->rx_desc[chan].current) /* ch*8 + 4 */ +#define TXDBP(chan) (&sip->tx_desc[chan].base) /* ch*8 + 64 */ +#define TXDP(chan) (&sip->tx_desc[chan].current) /* ch*8 + 68 */ + +#define PBB_DMA_OWN_BIT 0x80000000 +#define PBB_DMA_LAST_BIT 0x40000000 + +#define EOF_RX_FLAG 1 /* bit 0 */ +#define EOB_RX_FLAG 2 /* bit 1 */ +#define EOF_TX_FLAG 4 /* bit 2 */ +#define EOB_TX_FLAG 8 /* bit 3 */ + +#define TX_MODE(m) (((m)&7) << 16) + +#define RX_DESC(i) (cs->rx_desc[i]) +#define TX_DESC(i) (cs->tx_desc[i]) + +#define RX_CONTROL(i) (RX_DESC(i).control.word) +#define RX_CONTROL_SIZE(i) (RX_DESC(i).control.rx.size) +#define TX_CONTROL(i) (TX_DESC(i).control.word) + +#define RX_DATA_P(i) (&RX_DESC(i).ptr) +#define TX_DATA_P(i) (&TX_DESC(i).ptr) + +typedef volatile unsigned char V8; +typedef volatile unsigned short V16; +typedef volatile unsigned int V32; + +/* RAM descriptor layout */ +typedef struct _tag_dma_descriptor { + V32 ptr; + union { + struct { + V32 owner:1; + V32 last:1; + V32 reserved0: 10; + V32 tx_mode: 4; + + V32 reserved1: 5; + V32 size: 11; + } tx; + struct { + V32 owner:1; + V32 last:1; + V32 reserved0: 14; + + V32 reserved1: 5; + V32 size: 11; + } rx; + V32 word; + } control; +} DMA_DESCRIPTOR; + +/* + * NOTE: DO NOT USE structure to write non-word values... all registers + * MUST be written 4 bytes at a time in SI version 0. + * Non-word writes will result in "unaccessed" bytes written as zero. + * + * Byte reads are allowed. + * + * V32 pads are because the registers are spaced every 8 bytes (64 bits) + * + */ + +/* NOTE!!! 4 dwords */ +typedef struct _tag_dma_descriptor_ring { + DMA_DESCRIPTOR *base; + V32 pad1; /* skip high dword */ + volatile DMA_DESCRIPTOR *current; + V32 pad3; /* skip high dword */ +} DMA_DESCRIPTOR_RING; + +/* 1 dword */ +typedef union _tag_dma_generic { + struct { /* byte 3 2 1 0 */ + V32 chan7:4; /* bits 31-28 */ + V32 chan6:4; /* bits 27-24 */ + V32 chan5:4; /* bits 23-20 */ + V32 chan4:4; /* bits 19-16 */ + V32 chan3:4; /* bits 15-12 */ + V32 chan2:4; /* bits 11-8 */ + V32 chan1:4; /* bits 7-4 */ + V32 chan0:4; /* bits 3-0 */ + } _be_s_bits; + struct { /* byte 0 1 2 3 */ + V32 chan1:4; /* bits 7-4 */ + V32 chan0:4; /* bits 3-0 */ + V32 chan3:4; /* bits 15-12 */ + V32 chan2:4; /* bits 11-8 */ + V32 chan5:4; /* bits 23-20 */ + V32 chan4:4; /* bits 19-16 */ + V32 chan7:4; /* bits 31-28 */ + V32 chan6:4; /* bits 27-24 */ + } _be_bits; + struct { /* byte 0 1 2 3 */ + V32 chan0:4; /* bits 0-3 */ + V32 chan1:4; /* bits 4-7 */ + V32 chan2:4; /* bits 8-11 */ + V32 chan3:4; /* bits 12-15 */ + V32 chan4:4; /* bits 16-19 */ + V32 chan5:4; /* bits 20-23 */ + V32 chan6:4; /* bits 24-27 */ + V32 chan7:4; /* bits 28-31 */ + } _le_bits; + V8 byte[4]; + V32 word; +} DMA_RXTX_ENABLE, DMA_RX_DELETE, + DMA_INT_STATUS, DMA_INT_MASK, + DMA_RX_LEVEL_STATUS, DMA_RX_LEVEL_INT_MASK; + +/* 1 dword */ +typedef union _tag_dma_rx_timer{ + struct { + V32 res0:8; /* bits 32-24 */ + V32 res1:7; /* bits 23-17 */ + V32 enable:1; /* bit 16 */ + V32 value:16; /* bits 15-0 */ + } _be_s_bits; + struct { + /* crosses byte boundary. must use swap. */ + V32 s_value:16; /* bits 7-0,15-8 */ + V32 enable:1; /* bit 16 */ + V32 res1:7; /* bits 23-17 */ + V32 res0:8; /* bits 32-24 */ + } _be_bits; + struct { + V32 value:16; /* bits 0-15 */ + V32 enable:1; /* bit 16 */ + V32 res1:7; /* bits 17-23 */ + V32 res0:8; /* bits 24-32 */ + } _le_bits; + V8 byte[4]; + V32 word; +} DMA_RX_TIMER; + +/* NOTE!!!: 2 dwords */ +typedef struct _tag_dma_desc_level{ + union { + struct { + V32 res1:8; /* bits 31-24 */ + V32 res0:7; /* bits 23-17 */ + V32 write:1; /* bit 16 */ + V32 thresh:8; /* bits 15-8 */ + V32 level:8; /* bits 7-0 */ + } _be_s_bits; + struct { + V32 level:8; /* bits 7-0 */ + V32 thresh:8; /* bits 15-8 */ + V32 res0:7; /* bits 30-17 */ + V32 write:1; /* bit 16 */ + V32 res1:8; /* bits 31-24 */ + } _be_bits; + struct { + V32 level:8; /* bits 0-7 */ + V32 thresh:8; /* bits 8-15 */ + V32 write:1; /* bit 16 */ + V32 res0:7; /* bit 17-30 */ + V32 res1:8; /* bits 24-31 */ + } _le_bits; + V8 byte[4]; + V32 word; + } desc; + V32 pad1; +} DMA_DESC_LEVEL; + +typedef struct _tag_pbb_dma_reg_map { + /* 0-15 (0x000-0x078) */ + DMA_DESCRIPTOR_RING rx_desc[8]; /* 4 dwords each, 128 bytes tot. */ + + /* 16-31 (0x080-0x0f8) */ + DMA_DESCRIPTOR_RING tx_desc[8]; /* 4 dwords each, 128 bytes tot. */ + + /* 32/33 (0x100/0x108) */ + V32 reserved_32; + V32 pad_32; + V32 reserved_33; + V32 pad_33; + + /* 34 (0x110) */ + DMA_RXTX_ENABLE rxtx_enable; + V32 pad_34; + + /* 35 (0x118) */ + DMA_RX_DELETE rx_delete; + V32 pad_35; + + /* 36-38 (0x120-0x130) */ + DMA_INT_STATUS status; + V32 pad_36; + DMA_INT_STATUS last_status; + V32 pad_37; + DMA_INT_MASK int_mask; + V32 pad_38; + + /* 39/40 (0x138/0x140) */ + union { + /* NOTE!! 4 dwords */ + struct { + V32 channel_3:8; + V32 channel_2:8; + V32 channel_1:8; + V32 channel_0:8; + V32 pad1; + V32 channel_7:8; + V32 channel_6:8; + V32 channel_5:8; + V32 channel_4:8; + V32 pad3; + } _be_s_bits; + struct { + V32 channel_0:8; + V32 channel_1:8; + V32 channel_2:8; + V32 channel_3:8; + V32 pad1; + V32 channel_4:8; + V32 channel_5:8; + V32 channel_6:8; + V32 channel_7:8; + V32 pad3; + } _be_bits, _le_bits; + V8 byte[16]; + V32 word[4]; + } rx_size; + + /* 41/42 (0x148/0x150) */ + V32 reserved_41; + V32 pad_41; + V32 reserved_42; + V32 pad_42; + + /* 43/44 (0x158/0x160) */ + DMA_RX_LEVEL_STATUS rx_level_status; + V32 pad_43; + DMA_RX_LEVEL_INT_MASK rx_level_int_mask; + V32 pad_44; + + /* 45 (0x168) */ + DMA_RX_TIMER rx_timer; + V32 pad_45; + + /* 46 (0x170) */ + V32 reserved_46; + V32 pad_46; + + /* 47 (0x178) */ + V32 mbox_status; + V32 pad_47; + + /* 48/49 (0x180/0x188) */ + V32 mbox_out; + V32 pad_48; + V32 mbox_in; + V32 pad_49; + + /* 50 (0x190) */ + V32 config; + V32 pad_50; + + /* 51/52 (0x198/0x1a0) */ + V32 c2a_ctr; + V32 pad_51; + V32 a2c_ctr; + V32 pad_52; + + /* 53 (0x1a8) */ + union { + struct { + V32 rev_major:8; /* bits 31-24 */ + V32 rev_minor:8; /* bits 23-16 */ + V32 reserved:16; /* bits 15-0 */ + } _be_s_bits; + struct { + V32 s_reserved:16; /* bits 7-0, 15-8 */ + V32 rev_minor:8; /* bits 23-16 */ + V32 rev_major:8; /* bits 31-24 */ + } _be_bits; + struct { + V32 reserved:16; /* bits 0-15 */ + V32 rev_minor:8; /* bits 16-23 */ + V32 rev_major:8; /* bits 24-31 */ + } _le_bits; + V8 byte[4]; + V32 word; + } version; + V32 pad_53; + + /* 54-59 (0x1b0-0x1d8) */ + V32 debug_54; + V32 pad_54; + V32 debug_55; + V32 pad_55; + V32 debug_56; + V32 pad_56; + V32 debug_57; + V32 pad_57; + V32 debug_58; + V32 pad_58; + V32 debug_59; + V32 pad_59; + + /* 60 (0x1e0) */ + V32 timestamp; + V32 pad_60; + + /* 61-63 (0x1e8-0x1f8) */ + V32 debug_61; + V32 pad_61; + V32 debug_62; + V32 pad_62; + V32 debug_63; + V32 pad_63; + + /* 64-71 (0x200 - 0x238) */ + DMA_DESC_LEVEL rx_desc_level[8]; /* 2 dwords each, 32 bytes tot. */ + + /* 72-98 (0x240 - 0x2f8) */ + /* reserved */ + + /* 96-127 (0x300 - 0x3f8) */ + /* mirrors (0x100 - 0x1f8) */ + +} PBB_DMA_REG_MAP; + + +#endif /* ZUMA_PBB_H */ diff --git a/board/evb64260/zuma_pbb_mbox.c b/board/evb64260/zuma_pbb_mbox.c new file mode 100755 index 0000000..2b9a469 --- /dev/null +++ b/board/evb64260/zuma_pbb_mbox.c @@ -0,0 +1,187 @@ +#include <common.h> +#include <galileo/pci.h> +#include <net.h> +#include <pci.h> + +#include "zuma_pbb.h" +#include "zuma_pbb_mbox.h" + + +struct _zuma_mbox_dev zuma_mbox_dev; + + +static int zuma_mbox_write(struct _zuma_mbox_dev *dev, unsigned int data) +{ + unsigned int status, count = 0, i; + + status = (volatile int)le32_to_cpu(dev->sip->mbox_status); + + while((status & OUT_PENDING) && count < 1000) { + count++; + for(i=0;i<1000;i++); + status = (volatile int)le32_to_cpu(dev->sip->mbox_status); + } + if(count < 1000) { + /* if SET it means msg pending */ + /* printf("mbox real write %08x\n",data); */ + dev->sip->mbox_out = cpu_to_le32(data); + return 4; + } + + printf("mbox tx timeout\n"); + return 0; +} + +static int zuma_mbox_read(struct _zuma_mbox_dev *dev, unsigned int *data) +{ + unsigned int status, count = 0, i; + + status = (volatile int)le32_to_cpu(dev->sip->mbox_status); + + while(!(status & IN_VALID) && count < 1000) { + count++; + for(i=0;i<1000;i++); + status = (volatile int)le32_to_cpu(dev->sip->mbox_status); + } + if(count < 1000) { + /* if SET it means msg pending */ + *data=le32_to_cpu(dev->sip->mbox_in); + /*printf("mbox real read %08x\n", *data); */ + return 4; + } + printf("mbox rx timeout\n"); + return 0; +} + +static int zuma_mbox_do_one_mailbox(unsigned int out, unsigned int *in) +{ + int ret; + ret=zuma_mbox_write(&zuma_mbox_dev,out); + /*printf("write 0x%08x (%d bytes)\n", out, ret); */ + if(ret!=4) return -1; + ret=zuma_mbox_read(&zuma_mbox_dev,in); + /*printf("read 0x%08x (%d bytes)\n", *in, ret); */ + if(ret!=4) return -1; + return 0; +} + + +#define RET_IF_FAILED(x) if ((x) == -1) return -1 + +static int zuma_mbox_do_all_mailbox(void) +{ + unsigned int data_in; + unsigned short sdata_in; + + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_START, &data_in)); + + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_MACL, &data_in)); + memcpy(zuma_acc_mac+2,&data_in,4); + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_MACH, &data_in)); + sdata_in=data_in&0xffff; + memcpy(zuma_acc_mac,&sdata_in,2); + + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_IP, &data_in)); + zuma_ip=data_in; + + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_SLOT, &data_in)); + zuma_slot_bac=data_in>>3; + + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_BAUD, &data_in)); + zuma_console_baud = data_in & 0xffff; + zuma_debug_baud = data_in >> 16; + + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_ENG_PRV_MACL, &data_in)); + memcpy(zuma_prv_mac+2,&data_in,4); + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_ENG_PRV_MACH, &data_in)); + sdata_in=data_in&0xffff; + memcpy(zuma_prv_mac,&sdata_in,2); + + RET_IF_FAILED(zuma_mbox_do_one_mailbox(ZUMA_MBOXMSG_DONE, &data_in)); + + return 0; +} + + +static void +zuma_mbox_dump(void) +{ + printf("ACC MAC=%04x%08x\n",*(unsigned short *)(&zuma_acc_mac),*(unsigned int *)((char *)&zuma_acc_mac+2)); + printf("PRV MAC=%04x%08x\n",*(unsigned short *)(&zuma_prv_mac),*(unsigned int *)((char *)&zuma_prv_mac+2)); + printf("slot:bac=%d:%d\n",(zuma_slot_bac>>2)&0xf, zuma_slot_bac & 0x3); + printf("BAUD1=%d BAUD2=%d\n",zuma_console_baud,zuma_debug_baud); +} + + +static void +zuma_mbox_setenv(void) +{ + char *data, buf[32]; + unsigned char save = 0; + + data = getenv("baudrate"); + + if(!data || (zuma_console_baud != simple_strtoul(data, NULL, 10))) { + sprintf(buf, "%6d", zuma_console_baud); + setenv("baudrate", buf); + save=1; + printf("baudrate doesn't match from mbox\n"); + } + + ip_to_string(zuma_ip, buf); + setenv("ipaddr", buf); + + sprintf(buf,"%02x:%02x:%02x:%02x:%02x:%02x", + zuma_prv_mac[0], + zuma_prv_mac[1], + zuma_prv_mac[2], + zuma_prv_mac[3], + zuma_prv_mac[4], + zuma_prv_mac[5]); + setenv("ethaddr", buf); + + sprintf(buf,"%02x",zuma_slot_bac); + setenv("bacslot", buf); + + if(save) + saveenv(); +} + +/** + * zuma_mbox_init: + */ + +int zuma_mbox_init(void) +{ + unsigned int iobase; + memset(&zuma_mbox_dev, 0, sizeof(struct _zuma_mbox_dev)); + + zuma_mbox_dev.dev = pci_find_device(VENDOR_ID_ZUMA, DEVICE_ID_ZUMA_PBB, 0); + + if(zuma_mbox_dev.dev == -1) { + printf("no zuma pbb\n"); + return -1; + } + + pci_read_config_dword(zuma_mbox_dev.dev, PCI_BASE_ADDRESS_0, &iobase); + + zuma_mbox_dev.sip = (PBB_DMA_REG_MAP *) (iobase & PCI_BASE_ADDRESS_MEM_MASK); + + zuma_mbox_dev.sip->int_mask.word=0; + + printf("pbb @ %p v%d.%d, timestamp %08x\n", zuma_mbox_dev.sip, + zuma_mbox_dev.sip->version.pci_bits.rev_major, + zuma_mbox_dev.sip->version.pci_bits.rev_minor, + zuma_mbox_dev.sip->timestamp); + + if (zuma_mbox_do_all_mailbox() == -1) { + printf("mailbox failed.. no ACC?\n"); + return -1; + } + + zuma_mbox_dump(); + + zuma_mbox_setenv(); + + return 0; +} diff --git a/board/evb64260/zuma_pbb_mbox.h b/board/evb64260/zuma_pbb_mbox.h new file mode 100755 index 0000000..b4a4c0c --- /dev/null +++ b/board/evb64260/zuma_pbb_mbox.h @@ -0,0 +1,43 @@ +#define IN_VALID 1 +#define OUT_PENDING 2 + +enum { + ZUMA_MBOXMSG_DONE, + ZUMA_MBOXMSG_MACL, + ZUMA_MBOXMSG_MACH, + ZUMA_MBOXMSG_IP, + ZUMA_MBOXMSG_SLOT, + ZUMA_MBOXMSG_RESET, + ZUMA_MBOXMSG_BAUD, + ZUMA_MBOXMSG_START, + ZUMA_MBOXMSG_ENG_PRV_MACL, + ZUMA_MBOXMSG_ENG_PRV_MACH, + + MBOXMSG_LAST +}; + +struct zuma_mailbox_info { + unsigned char acc_mac[6]; + unsigned char prv_mac[6]; + unsigned int ip; + unsigned int slot_bac; + unsigned int console_baud; + unsigned int debug_baud; +}; + +struct _zuma_mbox_dev { + pci_dev_t dev; + PBB_DMA_REG_MAP *sip; + struct zuma_mailbox_info mailbox; +}; + +#define zuma_prv_mac zuma_mbox_dev.mailbox.prv_mac +#define zuma_acc_mac zuma_mbox_dev.mailbox.acc_mac +#define zuma_ip zuma_mbox_dev.mailbox.ip +#define zuma_slot_bac zuma_mbox_dev.mailbox.slot_bac +#define zuma_console_baud zuma_mbox_dev.mailbox.console_baud +#define zuma_debug_baud zuma_mbox_dev.mailbox.debug_baud + + +extern struct _zuma_mbox_dev zuma_mbox_dev; +extern int zuma_mbox_init (void); |