diff options
Diffstat (limited to 'cpu')
136 files changed, 9011 insertions, 3186 deletions
diff --git a/cpu/74xx_7xx/kgdb.S b/cpu/74xx_7xx/kgdb.S index e838513..4f23122 100644 --- a/cpu/74xx_7xx/kgdb.S +++ b/cpu/74xx_7xx/kgdb.S @@ -31,7 +31,7 @@ #include <asm/cache.h> #include <asm/mmu.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) /* * cache flushing routines for kgdb @@ -74,4 +74,4 @@ kgdb_flush_cache_range: SYNC blr -#endif /* CFG_CMD_KGDB */ +#endif diff --git a/cpu/74xx_7xx/traps.c b/cpu/74xx_7xx/traps.c index 50c5eeb..b066227 100644 --- a/cpu/74xx_7xx/traps.c +++ b/cpu/74xx_7xx/traps.c @@ -40,7 +40,7 @@ DECLARE_GLOBAL_DATA_PTR; #endif -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif @@ -133,7 +133,7 @@ MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -166,7 +166,7 @@ MachineCheckException(struct pt_regs *regs) void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -181,7 +181,7 @@ ProgramCheckException(struct pt_regs *regs) unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL; int i, j; -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -204,7 +204,7 @@ ProgramCheckException(struct pt_regs *regs) void SoftEmuException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -217,7 +217,7 @@ SoftEmuException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif diff --git a/cpu/arm920t/at91rm9200/Makefile b/cpu/arm920t/at91rm9200/Makefile index 8d4e478..ab4c52c 100644 --- a/cpu/arm920t/at91rm9200/Makefile +++ b/cpu/arm920t/at91rm9200/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).a COBJS = bcm5221.o dm9161.o ether.o i2c.o interrupts.o \ - lxt972.o serial.o usb_ohci.o + lxt972.o serial.o usb.o spi.o SOBJS = lowlevel_init.o SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/arm920t/at91rm9200/bcm5221.c b/cpu/arm920t/at91rm9200/bcm5221.c index 6db1435..b52c615 100644 --- a/cpu/arm920t/at91rm9200/bcm5221.c +++ b/cpu/arm920t/at91rm9200/bcm5221.c @@ -32,7 +32,7 @@ #ifdef CONFIG_DRIVER_ETHER -#if (CONFIG_COMMANDS & CFG_CMD_NET) +#if defined(CONFIG_CMD_NET) /* * Name: @@ -227,6 +227,6 @@ unsigned char bcm5221_AutoNegotiate (AT91PS_EMAC p_mac, int *status) return FALSE; } -#endif /* CONFIG_COMMANDS & CFG_CMD_NET */ +#endif #endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm920t/at91rm9200/dm9161.c b/cpu/arm920t/at91rm9200/dm9161.c index 4b13c23..1beb6e8 100644 --- a/cpu/arm920t/at91rm9200/dm9161.c +++ b/cpu/arm920t/at91rm9200/dm9161.c @@ -27,7 +27,7 @@ #ifdef CONFIG_DRIVER_ETHER -#if (CONFIG_COMMANDS & CFG_CMD_NET) +#if defined(CONFIG_CMD_NET) /* * Name: @@ -95,7 +95,7 @@ UCHAR dm9161_GetLinkSpeed (AT91PS_EMAC p_mac) return TRUE; } - if ((stat1 & DM9161_100BASE_T4_HD) && (stat2 & DM9161_100HDX)) { + if ((stat1 & DM9161_100BASE_TX_HD) && (stat2 & DM9161_100HDX)) { /*set MII for 100BaseTX and Half Duplex */ p_mac->EMAC_CFG = (p_mac->EMAC_CFG & ~(AT91C_EMAC_SPD | AT91C_EMAC_FD)) @@ -140,7 +140,7 @@ UCHAR dm9161_InitPhy (AT91PS_EMAC p_mac) at91rm9200_EmacReadPhy (p_mac, DM9161_MDINTR, &IntValue); /* set FDX, SPD, Link, INTR masks */ IntValue |= (DM9161_FDX_MASK | DM9161_SPD_MASK | - DM9161_LINK_MASK | DM9161_INTR_MASK); + DM9161_LINK_MASK | DM9161_INTR_MASK); at91rm9200_EmacWritePhy (p_mac, DM9161_MDINTR, &IntValue); at91rm9200_EmacDisableMDIO (p_mac); @@ -174,10 +174,11 @@ UCHAR dm9161_AutoNegotiate (AT91PS_EMAC p_mac, int *status) if (!at91rm9200_EmacWritePhy (p_mac, DM9161_BMCR, &value)) return FALSE; - /* Set the Auto_negotiation Advertisement Register */ - /* MII advertising for Next page, 100BaseTxFD and HD, 10BaseTFD and HD, IEEE 802.3 */ + /* Set the Auto_negotiation Advertisement Register */ + /* MII advertising for Next page, 100BaseTxFD and HD, */ + /* 10BaseTFD and HD, IEEE 802.3 */ PhyAnar = DM9161_NP | DM9161_TX_FDX | DM9161_TX_HDX | - DM9161_10_FDX | DM9161_10_HDX | DM9161_AN_IEEE_802_3; + DM9161_10_FDX | DM9161_10_HDX | DM9161_AN_IEEE_802_3; if (!at91rm9200_EmacWritePhy (p_mac, DM9161_ANAR, &PhyAnar)) return FALSE; @@ -220,6 +221,6 @@ UCHAR dm9161_AutoNegotiate (AT91PS_EMAC p_mac, int *status) return FALSE; } -#endif /* CONFIG_COMMANDS & CFG_CMD_NET */ +#endif #endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm920t/at91rm9200/ether.c b/cpu/arm920t/at91rm9200/ether.c index 67008d0..c8f56aa 100644 --- a/cpu/arm920t/at91rm9200/ether.c +++ b/cpu/arm920t/at91rm9200/ether.c @@ -50,7 +50,7 @@ typedef struct { #ifdef CONFIG_DRIVER_ETHER -#if (CONFIG_COMMANDS & CFG_CMD_NET) +#if defined(CONFIG_CMD_NET) /* alignment as per Errata #11 (64 bytes) is insufficient! */ rbf_t rbfdt[RBF_FRAMEMAX] __attribute((aligned(512))); @@ -265,7 +265,7 @@ void eth_halt (void) { }; -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) int at91rm9200_miiphy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short * value) { @@ -284,16 +284,16 @@ int at91rm9200_miiphy_write(char *devname, unsigned char addr, return 0; } -#endif /* defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) */ +#endif int at91rm9200_miiphy_initialize(bd_t *bis) { -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register("at91rm9200phy", at91rm9200_miiphy_read, at91rm9200_miiphy_write); #endif return 0; } -#endif /* CONFIG_COMMANDS & CFG_CMD_NET */ +#endif #endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm920t/at91rm9200/lxt972.c b/cpu/arm920t/at91rm9200/lxt972.c index f12c59c..4edcc9a 100644 --- a/cpu/arm920t/at91rm9200/lxt972.c +++ b/cpu/arm920t/at91rm9200/lxt972.c @@ -33,7 +33,7 @@ #ifdef CONFIG_DRIVER_ETHER -#if (CONFIG_COMMANDS & CFG_CMD_NET) +#if defined(CONFIG_CMD_NET) /* * Name: @@ -186,6 +186,6 @@ UCHAR lxt972_AutoNegotiate (AT91PS_EMAC p_mac, int *status) return (lxt972_GetLinkSpeed (p_mac)); } -#endif /* CONFIG_COMMANDS & CFG_CMD_NET */ +#endif #endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm920t/at91rm9200/spi.c b/cpu/arm920t/at91rm9200/spi.c new file mode 100644 index 0000000..265d185 --- /dev/null +++ b/cpu/arm920t/at91rm9200/spi.c @@ -0,0 +1,151 @@ +/* Driver for ATMEL DataFlash support + * Author : Hamid Ikdoumi (Atmel) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + */ + +#include <config.h> +#include <common.h> +#include <asm/hardware.h> + +#ifdef CONFIG_HAS_DATAFLASH +#include <dataflash.h> + +#define AT91C_SPI_CLK 10000000 /* Max Value = 10MHz to be compliant to + the Continuous Array Read function */ + +/* AC Characteristics */ +/* DLYBS = tCSS = 250ns min and DLYBCT = tCSH = 250ns */ +#define DATAFLASH_TCSS (0xC << 16) +#define DATAFLASH_TCHS (0x1 << 24) + +#define AT91C_TIMEOUT_WRDY 200000 +#define AT91C_SPI_PCS0_SERIAL_DATAFLASH 0xE /* Chip Select 0: NPCS0%1110 */ +#define AT91C_SPI_PCS3_DATAFLASH_CARD 0x7 /* Chip Select 3: NPCS3%0111 */ + +/*-------------------------------------------------------------------*/ +/* SPI DataFlash Init */ +/*-------------------------------------------------------------------*/ +void AT91F_SpiInit(void) +{ + /* Configure PIOs */ + AT91C_BASE_PIOA->PIO_ASR = + AT91C_PA3_NPCS0 | AT91C_PA4_NPCS1 | AT91C_PA1_MOSI | + AT91C_PA5_NPCS2 | AT91C_PA6_NPCS3 | AT91C_PA0_MISO | + AT91C_PA2_SPCK; + AT91C_BASE_PIOA->PIO_PDR = + AT91C_PA3_NPCS0 | AT91C_PA4_NPCS1 | AT91C_PA1_MOSI | + AT91C_PA5_NPCS2 | AT91C_PA6_NPCS3 | AT91C_PA0_MISO | + AT91C_PA2_SPCK; + /* Enable CLock */ + AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SPI; + + /* Reset the SPI */ + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SWRST; + + /* Configure SPI in Master Mode with No CS selected !!! */ + AT91C_BASE_SPI->SPI_MR = + AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS; + + /* Configure CS0 and CS3 */ + *(AT91C_SPI_CSR + 0) = + AT91C_SPI_CPOL | (AT91C_SPI_DLYBS & DATAFLASH_TCSS) | + (AT91C_SPI_DLYBCT & DATAFLASH_TCHS) | + ((AT91C_MASTER_CLOCK / (2*AT91C_SPI_CLK)) << 8); + + *(AT91C_SPI_CSR + 3) = + AT91C_SPI_CPOL | (AT91C_SPI_DLYBS & DATAFLASH_TCSS) | + (AT91C_SPI_DLYBCT & DATAFLASH_TCHS) | + ((AT91C_MASTER_CLOCK / (2*AT91C_SPI_CLK)) << 8); +} + +void AT91F_SpiEnable(int cs) +{ + switch(cs) { + case 0: /* Configure SPI CS0 for Serial DataFlash AT45DBxx */ + AT91C_BASE_SPI->SPI_MR &= 0xFFF0FFFF; + AT91C_BASE_SPI->SPI_MR |= + ((AT91C_SPI_PCS0_SERIAL_DATAFLASH<<16) & + AT91C_SPI_PCS); + break; + case 3: /* Configure SPI CS3 for Serial DataFlash Card */ + /* Set up PIO SDC_TYPE to switch on DataFlash Card */ + /* and not MMC/SDCard */ + AT91C_BASE_PIOB->PIO_PER = + AT91C_PIO_PB7; /* Set in PIO mode */ + AT91C_BASE_PIOB->PIO_OER = + AT91C_PIO_PB7; /* Configure in output */ + /* Clear Output */ + AT91C_BASE_PIOB->PIO_CODR = AT91C_PIO_PB7; + /* Configure PCS */ + AT91C_BASE_SPI->SPI_MR &= 0xFFF0FFFF; + AT91C_BASE_SPI->SPI_MR |= + ((AT91C_SPI_PCS3_DATAFLASH_CARD<<16) & AT91C_SPI_PCS); + break; + } + + /* SPI_Enable */ + AT91C_BASE_SPI->SPI_CR = AT91C_SPI_SPIEN; } + +/*---------------------------------------------------------------------------*/ +/* \fn AT91F_SpiWrite */ +/* \brief Set the PDC registers for a transfert */ +/*---------------------------------------------------------------------------*/ +unsigned int AT91F_SpiWrite ( AT91PS_DataflashDesc pDesc ) +{ + unsigned int timeout; + + pDesc->state = BUSY; + + AT91C_BASE_SPI->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS; + + /* Initialize the Transmit and Receive Pointer */ + AT91C_BASE_SPI->SPI_RPR = (unsigned int)pDesc->rx_cmd_pt ; + AT91C_BASE_SPI->SPI_TPR = (unsigned int)pDesc->tx_cmd_pt ; + + /* Intialize the Transmit and Receive Counters */ + AT91C_BASE_SPI->SPI_RCR = pDesc->rx_cmd_size; + AT91C_BASE_SPI->SPI_TCR = pDesc->tx_cmd_size; + + if ( pDesc->tx_data_size != 0 ) { + /* Initialize the Next Transmit and Next Receive Pointer */ + AT91C_BASE_SPI->SPI_RNPR = (unsigned int)pDesc->rx_data_pt ; + AT91C_BASE_SPI->SPI_TNPR = (unsigned int)pDesc->tx_data_pt ; + + /* Intialize the Next Transmit and Next Receive Counters */ + AT91C_BASE_SPI->SPI_RNCR = pDesc->rx_data_size ; + AT91C_BASE_SPI->SPI_TNCR = pDesc->tx_data_size ; + } + + /* arm simple, non interrupt dependent timer */ + reset_timer_masked(); + timeout = 0; + + AT91C_BASE_SPI->SPI_PTCR = AT91C_PDC_TXTEN + AT91C_PDC_RXTEN; + while(!(AT91C_BASE_SPI->SPI_SR & AT91C_SPI_RXBUFF) && + ((timeout = get_timer_masked() ) < CFG_SPI_WRITE_TOUT)); + AT91C_BASE_SPI->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS; + pDesc->state = IDLE; + + if (timeout >= CFG_SPI_WRITE_TOUT){ + printf("Error Timeout\n\r"); + return DATAFLASH_ERROR; + } + + return DATAFLASH_OK; +} +#endif diff --git a/cpu/arm920t/at91rm9200/usb.c b/cpu/arm920t/at91rm9200/usb.c new file mode 100644 index 0000000..366262e --- /dev/null +++ b/cpu/arm920t/at91rm9200/usb.c @@ -0,0 +1,53 @@ +/* + * (C) Copyright 2006 + * DENX Software Engineering <mk@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) +# ifdef CONFIG_AT91RM9200 + +#include <asm/arch/hardware.h> + +int usb_cpu_init() +{ + /* Enable USB host clock. */ + *AT91C_PMC_SCER = AT91C_PMC_UHP; /* 48MHz clock enabled for UHP */ + *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; /* Peripheral Clock Enable Register */ + return 0; +} + +int usb_cpu_stop() +{ + /* Initialization failed */ + *AT91C_PMC_PCDR = 1 << AT91C_ID_UHP; /* Peripheral Clock Disable Register */ + *AT91C_PMC_SCDR = AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ + return 0; +} + +int usb_cpu_init_fail() +{ + usb_cpu_stop(); +} + +# endif /* CONFIG_AT91RM9200 */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/arm920t/at91rm9200/usb_ohci.c b/cpu/arm920t/at91rm9200/usb_ohci.c deleted file mode 100644 index 5b2c56c..0000000 --- a/cpu/arm920t/at91rm9200/usb_ohci.c +++ /dev/null @@ -1,1635 +0,0 @@ -/* - * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200. - * - * (C) Copyright 2003 - * Gary Jennejohn, DENX Software Engineering <gj@denx.de> - * - * Note: Much of this code has been derived from Linux 2.4 - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2002 David Brownell - * - * Modified for the MP2USB by (C) Copyright 2005 Eric Benard - * ebenard@eukrea.com - based on s3c24x0's driver - * - * 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 - * - */ -/* - * IMPORTANT NOTES - * 1 - you MUST define LITTLEENDIAN in the configuration file for the - * board or this driver will NOT work! - * 2 - this driver is intended for use with USB Mass Storage Devices - * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes! - * 3 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG - * to activate workaround for bug #41 or this driver will NOT work! - */ - -#include <common.h> -/* #include <pci.h> no PCI on the S3C24X0 */ - -#ifdef CONFIG_USB_OHCI - -#include <asm/arch/hardware.h> - -#include <malloc.h> -#include <usb.h> -#include "usb_ohci.h" - -#define OHCI_USE_NPS /* force NoPowerSwitching mode */ -#undef OHCI_VERBOSE_DEBUG /* not always helpful */ - -/* For initializing controller (mask in an HCFS mode too) */ -#define OHCI_CONTROL_INIT \ - (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE - -#define readl(a) (*((vu_long *)(a))) -#define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a)) - -#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) - -#undef DEBUG -#ifdef DEBUG -#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg) -#else -#define dbg(format, arg...) do {} while(0) -#endif /* DEBUG */ -#define err(format, arg...) printf("ERROR: " format "\n", ## arg) -#undef SHOW_INFO -#ifdef SHOW_INFO -#define info(format, arg...) printf("INFO: " format "\n", ## arg) -#else -#define info(format, arg...) do {} while(0) -#endif - -#define m16_swap(x) swap_16(x) -#define m32_swap(x) swap_32(x) - -/* global ohci_t */ -static ohci_t gohci; -/* this must be aligned to a 256 byte boundary */ -struct ohci_hcca ghcca[1]; -/* a pointer to the aligned storage */ -struct ohci_hcca *phcca; -/* this allocates EDs for all possible endpoints */ -struct ohci_device ohci_dev; -/* urb_priv */ -urb_priv_t urb_priv; -/* RHSC flag */ -int got_rhsc; -/* device which was disconnected */ -struct usb_device *devgone; - -/*-------------------------------------------------------------------------*/ - -/* AMD-756 (D2 rev) reports corrupt register contents in some cases. - * The erratum (#4) description is incorrect. AMD's workaround waits - * till some bits (mostly reserved) are clear; ok for all revs. - */ -#define OHCI_QUIRK_AMD756 0xabcd -#define read_roothub(hc, register, mask) ({ \ - u32 temp = readl (&hc->regs->roothub.register); \ - if (hc->flags & OHCI_QUIRK_AMD756) \ - while (temp & mask) \ - temp = readl (&hc->regs->roothub.register); \ - temp; }) - -static u32 roothub_a (struct ohci *hc) - { return read_roothub (hc, a, 0xfc0fe000); } -static inline u32 roothub_b (struct ohci *hc) - { return readl (&hc->regs->roothub.b); } -static inline u32 roothub_status (struct ohci *hc) - { return readl (&hc->regs->roothub.status); } -static u32 roothub_portstatus (struct ohci *hc, int i) - { return read_roothub (hc, portstatus [i], 0xffe0fce0); } - - -/* forward declaration */ -static int hc_interrupt (void); -static void -td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer, - int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval); - -/*-------------------------------------------------------------------------* - * URB support functions - *-------------------------------------------------------------------------*/ - -/* free HCD-private data associated with this URB */ - -static void urb_free_priv (urb_priv_t * urb) -{ - int i; - int last; - struct td * td; - - last = urb->length - 1; - if (last >= 0) { - for (i = 0; i <= last; i++) { - td = urb->td[i]; - if (td) { - td->usb_dev = NULL; - urb->td[i] = NULL; - } - } - } -} - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -static int sohci_get_current_frame_number (struct usb_device * dev); - -/* debug| print the main components of an URB - * small: 0) header + data packets 1) just header */ - -static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer, - int transfer_len, struct devrequest * setup, char * str, int small) -{ - urb_priv_t * purb = &urb_priv; - - dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx", - str, - sohci_get_current_frame_number (dev), - usb_pipedevice (pipe), - usb_pipeendpoint (pipe), - usb_pipeout (pipe)? 'O': 'I', - usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"): - (usb_pipecontrol (pipe)? "CTRL": "BULK"), - purb->actual_length, - transfer_len, dev->status); -#ifdef OHCI_VERBOSE_DEBUG - if (!small) { - int i, len; - - if (usb_pipecontrol (pipe)) { - printf (__FILE__ ": cmd(8):"); - for (i = 0; i < 8 ; i++) - printf (" %02x", ((__u8 *) setup) [i]); - printf ("\n"); - } - if (transfer_len > 0 && buffer) { - printf (__FILE__ ": data(%d/%d):", - purb->actual_length, - transfer_len); - len = usb_pipeout (pipe)? - transfer_len: purb->actual_length; - for (i = 0; i < 16 && i < len; i++) - printf (" %02x", ((__u8 *) buffer) [i]); - printf ("%s\n", i < len? "...": ""); - } - } -#endif -} - -/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/ -void ep_print_int_eds (ohci_t *ohci, char * str) { - int i, j; - __u32 * ed_p; - for (i= 0; i < 32; i++) { - j = 5; - ed_p = &(ohci->hcca->int_table [i]); - if (*ed_p == 0) - continue; - printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i); - while (*ed_p != 0 && j--) { - ed_t *ed = (ed_t *)m32_swap(ed_p); - printf (" ed: %4x;", ed->hwINFO); - ed_p = &ed->hwNextED; - } - printf ("\n"); - } -} - -static void ohci_dump_intr_mask (char *label, __u32 mask) -{ - dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s", - label, - mask, - (mask & OHCI_INTR_MIE) ? " MIE" : "", - (mask & OHCI_INTR_OC) ? " OC" : "", - (mask & OHCI_INTR_RHSC) ? " RHSC" : "", - (mask & OHCI_INTR_FNO) ? " FNO" : "", - (mask & OHCI_INTR_UE) ? " UE" : "", - (mask & OHCI_INTR_RD) ? " RD" : "", - (mask & OHCI_INTR_SF) ? " SF" : "", - (mask & OHCI_INTR_WDH) ? " WDH" : "", - (mask & OHCI_INTR_SO) ? " SO" : "" - ); -} - -static void maybe_print_eds (char *label, __u32 value) -{ - ed_t *edp = (ed_t *)value; - - if (value) { - dbg ("%s %08x", label, value); - dbg ("%08x", edp->hwINFO); - dbg ("%08x", edp->hwTailP); - dbg ("%08x", edp->hwHeadP); - dbg ("%08x", edp->hwNextED); - } -} - -static char * hcfs2string (int state) -{ - switch (state) { - case OHCI_USB_RESET: return "reset"; - case OHCI_USB_RESUME: return "resume"; - case OHCI_USB_OPER: return "operational"; - case OHCI_USB_SUSPEND: return "suspend"; - } - return "?"; -} - -/* dump control and status registers */ -static void ohci_dump_status (ohci_t *controller) -{ - struct ohci_regs *regs = controller->regs; - __u32 temp; - - temp = readl (®s->revision) & 0xff; - if (temp != 0x10) - dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f)); - - temp = readl (®s->control); - dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp, - (temp & OHCI_CTRL_RWE) ? " RWE" : "", - (temp & OHCI_CTRL_RWC) ? " RWC" : "", - (temp & OHCI_CTRL_IR) ? " IR" : "", - hcfs2string (temp & OHCI_CTRL_HCFS), - (temp & OHCI_CTRL_BLE) ? " BLE" : "", - (temp & OHCI_CTRL_CLE) ? " CLE" : "", - (temp & OHCI_CTRL_IE) ? " IE" : "", - (temp & OHCI_CTRL_PLE) ? " PLE" : "", - temp & OHCI_CTRL_CBSR - ); - - temp = readl (®s->cmdstatus); - dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp, - (temp & OHCI_SOC) >> 16, - (temp & OHCI_OCR) ? " OCR" : "", - (temp & OHCI_BLF) ? " BLF" : "", - (temp & OHCI_CLF) ? " CLF" : "", - (temp & OHCI_HCR) ? " HCR" : "" - ); - - ohci_dump_intr_mask ("intrstatus", readl (®s->intrstatus)); - ohci_dump_intr_mask ("intrenable", readl (®s->intrenable)); - - maybe_print_eds ("ed_periodcurrent", readl (®s->ed_periodcurrent)); - - maybe_print_eds ("ed_controlhead", readl (®s->ed_controlhead)); - maybe_print_eds ("ed_controlcurrent", readl (®s->ed_controlcurrent)); - - maybe_print_eds ("ed_bulkhead", readl (®s->ed_bulkhead)); - maybe_print_eds ("ed_bulkcurrent", readl (®s->ed_bulkcurrent)); - - maybe_print_eds ("donehead", readl (®s->donehead)); -} - -static void ohci_dump_roothub (ohci_t *controller, int verbose) -{ - __u32 temp, ndp, i; - - temp = roothub_a (controller); - ndp = (temp & RH_A_NDP); -#ifdef CONFIG_AT91C_PQFP_UHPBUG - ndp = (ndp == 2) ? 1:0; -#endif - if (verbose) { - dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp, - ((temp & RH_A_POTPGT) >> 24) & 0xff, - (temp & RH_A_NOCP) ? " NOCP" : "", - (temp & RH_A_OCPM) ? " OCPM" : "", - (temp & RH_A_DT) ? " DT" : "", - (temp & RH_A_NPS) ? " NPS" : "", - (temp & RH_A_PSM) ? " PSM" : "", - ndp - ); - temp = roothub_b (controller); - dbg ("roothub.b: %08x PPCM=%04x DR=%04x", - temp, - (temp & RH_B_PPCM) >> 16, - (temp & RH_B_DR) - ); - temp = roothub_status (controller); - dbg ("roothub.status: %08x%s%s%s%s%s%s", - temp, - (temp & RH_HS_CRWE) ? " CRWE" : "", - (temp & RH_HS_OCIC) ? " OCIC" : "", - (temp & RH_HS_LPSC) ? " LPSC" : "", - (temp & RH_HS_DRWE) ? " DRWE" : "", - (temp & RH_HS_OCI) ? " OCI" : "", - (temp & RH_HS_LPS) ? " LPS" : "" - ); - } - - for (i = 0; i < ndp; i++) { - temp = roothub_portstatus (controller, i); - dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s", - i, - temp, - (temp & RH_PS_PRSC) ? " PRSC" : "", - (temp & RH_PS_OCIC) ? " OCIC" : "", - (temp & RH_PS_PSSC) ? " PSSC" : "", - (temp & RH_PS_PESC) ? " PESC" : "", - (temp & RH_PS_CSC) ? " CSC" : "", - - (temp & RH_PS_LSDA) ? " LSDA" : "", - (temp & RH_PS_PPS) ? " PPS" : "", - (temp & RH_PS_PRS) ? " PRS" : "", - (temp & RH_PS_POCI) ? " POCI" : "", - (temp & RH_PS_PSS) ? " PSS" : "", - - (temp & RH_PS_PES) ? " PES" : "", - (temp & RH_PS_CCS) ? " CCS" : "" - ); - } -} - -static void ohci_dump (ohci_t *controller, int verbose) -{ - dbg ("OHCI controller usb-%s state", controller->slot_name); - - /* dumps some of the state we know about */ - ohci_dump_status (controller); - if (verbose) - ep_print_int_eds (controller, "hcca"); - dbg ("hcca frame #%04x", controller->hcca->frame_no); - ohci_dump_roothub (controller, 1); -} - - -#endif /* DEBUG */ - -/*-------------------------------------------------------------------------* - * Interface functions (URB) - *-------------------------------------------------------------------------*/ - -/* get a transfer request */ - -int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, int interval) -{ - ohci_t *ohci; - ed_t * ed; - urb_priv_t *purb_priv; - int i, size = 0; - - ohci = &gohci; - - /* when controller's hung, permit only roothub cleanup attempts - * such as powering down ports */ - if (ohci->disabled) { - err("sohci_submit_job: EPIPE"); - return -1; - } - - /* every endpoint has a ed, locate and fill it */ - if (!(ed = ep_add_ed (dev, pipe))) { - err("sohci_submit_job: ENOMEM"); - return -1; - } - - /* for the private part of the URB we need the number of TDs (size) */ - switch (usb_pipetype (pipe)) { - case PIPE_BULK: /* one TD for every 4096 Byte */ - size = (transfer_len - 1) / 4096 + 1; - break; - case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */ - size = (transfer_len == 0)? 2: - (transfer_len - 1) / 4096 + 3; - break; - } - - if (size >= (N_URB_TD - 1)) { - err("need %d TDs, only have %d", size, N_URB_TD); - return -1; - } - purb_priv = &urb_priv; - purb_priv->pipe = pipe; - - /* fill the private part of the URB */ - purb_priv->length = size; - purb_priv->ed = ed; - purb_priv->actual_length = 0; - - /* allocate the TDs */ - /* note that td[0] was allocated in ep_add_ed */ - for (i = 0; i < size; i++) { - purb_priv->td[i] = td_alloc (dev); - if (!purb_priv->td[i]) { - purb_priv->length = i; - urb_free_priv (purb_priv); - err("sohci_submit_job: ENOMEM"); - return -1; - } - } - - if (ed->state == ED_NEW || (ed->state & ED_DEL)) { - urb_free_priv (purb_priv); - err("sohci_submit_job: EINVAL"); - return -1; - } - - /* link the ed into a chain if is not already */ - if (ed->state != ED_OPER) - ep_link (ohci, ed); - - /* fill the TDs and link it to the ed */ - td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef DEBUG -/* tell us the current USB frame number */ - -static int sohci_get_current_frame_number (struct usb_device *usb_dev) -{ - ohci_t *ohci = &gohci; - - return m16_swap (ohci->hcca->frame_no); -} -#endif - -/*-------------------------------------------------------------------------* - * ED handling functions - *-------------------------------------------------------------------------*/ - -/* link an ed into one of the HC chains */ - -static int ep_link (ohci_t *ohci, ed_t *edi) -{ - volatile ed_t *ed = edi; - - ed->state = ED_OPER; - - switch (ed->type) { - case PIPE_CONTROL: - ed->hwNextED = 0; - if (ohci->ed_controltail == NULL) { - writel (ed, &ohci->regs->ed_controlhead); - } else { - ohci->ed_controltail->hwNextED = m32_swap (ed); - } - ed->ed_prev = ohci->ed_controltail; - if (!ohci->ed_controltail && !ohci->ed_rm_list[0] && - !ohci->ed_rm_list[1] && !ohci->sleeping) { - ohci->hc_control |= OHCI_CTRL_CLE; - writel (ohci->hc_control, &ohci->regs->control); - } - ohci->ed_controltail = edi; - break; - - case PIPE_BULK: - ed->hwNextED = 0; - if (ohci->ed_bulktail == NULL) { - writel (ed, &ohci->regs->ed_bulkhead); - } else { - ohci->ed_bulktail->hwNextED = m32_swap (ed); - } - ed->ed_prev = ohci->ed_bulktail; - if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] && - !ohci->ed_rm_list[1] && !ohci->sleeping) { - ohci->hc_control |= OHCI_CTRL_BLE; - writel (ohci->hc_control, &ohci->regs->control); - } - ohci->ed_bulktail = edi; - break; - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* unlink an ed from one of the HC chains. - * just the link to the ed is unlinked. - * the link from the ed still points to another operational ed or 0 - * so the HC can eventually finish the processing of the unlinked ed */ - -static int ep_unlink (ohci_t *ohci, ed_t *ed) -{ - ed->hwINFO |= m32_swap (OHCI_ED_SKIP); - - switch (ed->type) { - case PIPE_CONTROL: - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_CLE; - writel (ohci->hc_control, &ohci->regs->control); - } - writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead); - } else { - ed->ed_prev->hwNextED = ed->hwNextED; - } - if (ohci->ed_controltail == ed) { - ohci->ed_controltail = ed->ed_prev; - } else { - ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev; - } - break; - - case PIPE_BULK: - if (ed->ed_prev == NULL) { - if (!ed->hwNextED) { - ohci->hc_control &= ~OHCI_CTRL_BLE; - writel (ohci->hc_control, &ohci->regs->control); - } - writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead); - } else { - ed->ed_prev->hwNextED = ed->hwNextED; - } - if (ohci->ed_bulktail == ed) { - ohci->ed_bulktail = ed->ed_prev; - } else { - ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev; - } - break; - } - ed->state = ED_UNLINK; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* add/reinit an endpoint; this should be done once at the usb_set_configuration command, - * but the USB stack is a little bit stateless so we do it at every transaction - * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK - * in all other cases the state is left unchanged - * the ed info fields are setted anyway even though most of them should not change */ - -static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe) -{ - td_t *td; - ed_t *ed_ret; - volatile ed_t *ed; - - ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) | - (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))]; - - if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) { - err("ep_add_ed: pending delete"); - /* pending delete request */ - return NULL; - } - - if (ed->state == ED_NEW) { - ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */ - /* dummy td; end of td list for ed */ - td = td_alloc (usb_dev); - ed->hwTailP = m32_swap (td); - ed->hwHeadP = ed->hwTailP; - ed->state = ED_UNLINK; - ed->type = usb_pipetype (pipe); - ohci_dev.ed_cnt++; - } - - ed->hwINFO = m32_swap (usb_pipedevice (pipe) - | usb_pipeendpoint (pipe) << 7 - | (usb_pipeisoc (pipe)? 0x8000: 0) - | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000)) - | usb_pipeslow (pipe) << 13 - | usb_maxpacket (usb_dev, pipe) << 16); - - return ed_ret; -} - -/*-------------------------------------------------------------------------* - * TD handling functions - *-------------------------------------------------------------------------*/ - -/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */ - -static void td_fill (ohci_t *ohci, unsigned int info, - void *data, int len, - struct usb_device *dev, int index, urb_priv_t *urb_priv) -{ - volatile td_t *td, *td_pt; -#ifdef OHCI_FILL_TRACE - int i; -#endif - - if (index > urb_priv->length) { - err("index > length"); - return; - } - /* use this td as the next dummy */ - td_pt = urb_priv->td [index]; - td_pt->hwNextTD = 0; - - /* fill the old dummy TD */ - td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf); - - td->ed = urb_priv->ed; - td->next_dl_td = NULL; - td->index = index; - td->data = (__u32)data; -#ifdef OHCI_FILL_TRACE - if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) { - for (i = 0; i < len; i++) - printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]); - printf("\n"); - } -#endif - if (!len) - data = 0; - - td->hwINFO = m32_swap (info); - td->hwCBP = m32_swap (data); - if (data) - td->hwBE = m32_swap (data + len - 1); - else - td->hwBE = 0; - td->hwNextTD = m32_swap (td_pt); - td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000); - - /* append to queue */ - td->ed->hwTailP = td->hwNextTD; -} - -/*-------------------------------------------------------------------------*/ - -/* prepare all TDs of a transfer */ - -static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval) -{ - ohci_t *ohci = &gohci; - int data_len = transfer_len; - void *data; - int cnt = 0; - __u32 info = 0; - unsigned int toggle = 0; - - /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */ - if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) { - toggle = TD_T_TOGGLE; - } else { - toggle = TD_T_DATA0; - usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1); - } - urb->td_cnt = 0; - if (data_len) - data = buffer; - else - data = 0; - - switch (usb_pipetype (pipe)) { - case PIPE_BULK: - info = usb_pipeout (pipe)? - TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ; - while(data_len > 4096) { - td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb); - data += 4096; data_len -= 4096; cnt++; - } - info = usb_pipeout (pipe)? - TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ; - td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb); - cnt++; - - if (!ohci->sleeping) - writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */ - break; - - case PIPE_CONTROL: - info = TD_CC | TD_DP_SETUP | TD_T_DATA0; - td_fill (ohci, info, setup, 8, dev, cnt++, urb); - if (data_len > 0) { - info = usb_pipeout (pipe)? - TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1; - /* NOTE: mishandles transfers >8K, some >4K */ - td_fill (ohci, info, data, data_len, dev, cnt++, urb); - } - info = usb_pipeout (pipe)? - TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1; - td_fill (ohci, info, data, 0, dev, cnt++, urb); - if (!ohci->sleeping) - writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */ - break; - } - if (urb->length != cnt) - dbg("TD LENGTH %d != CNT %d", urb->length, cnt); -} - -/*-------------------------------------------------------------------------* - * Done List handling functions - *-------------------------------------------------------------------------*/ - - -/* calculate the transfer length and update the urb */ - -static void dl_transfer_length(td_t * td) -{ - __u32 tdINFO, tdBE, tdCBP; - urb_priv_t *lurb_priv = &urb_priv; - - tdINFO = m32_swap (td->hwINFO); - tdBE = m32_swap (td->hwBE); - tdCBP = m32_swap (td->hwCBP); - - - if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL && - ((td->index == 0) || (td->index == lurb_priv->length - 1)))) { - if (tdBE != 0) { - if (td->hwCBP == 0) - lurb_priv->actual_length += tdBE - td->data + 1; - else - lurb_priv->actual_length += tdCBP - td->data; - } - } -} - -/*-------------------------------------------------------------------------*/ - -/* replies to the request have to be on a FIFO basis so - * we reverse the reversed done-list */ - -static td_t * dl_reverse_done_list (ohci_t *ohci) -{ - __u32 td_list_hc; - td_t *td_rev = NULL; - td_t *td_list = NULL; - urb_priv_t *lurb_priv = NULL; - - td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0; - ohci->hcca->done_head = 0; - - while (td_list_hc) { - td_list = (td_t *)td_list_hc; - - if (TD_CC_GET (m32_swap (td_list->hwINFO))) { - lurb_priv = &urb_priv; - dbg(" USB-error/status: %x : %p", - TD_CC_GET (m32_swap (td_list->hwINFO)), td_list); - if (td_list->ed->hwHeadP & m32_swap (0x1)) { - if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) { - td_list->ed->hwHeadP = - (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) | - (td_list->ed->hwHeadP & m32_swap (0x2)); - lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1; - } else - td_list->ed->hwHeadP &= m32_swap (0xfffffff2); - } - } - - td_list->next_dl_td = td_rev; - td_rev = td_list; - td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0; - } - return td_list; -} - -/*-------------------------------------------------------------------------*/ - -/* td done list */ -static int dl_done_list (ohci_t *ohci, td_t *td_list) -{ - td_t *td_list_next = NULL; - ed_t *ed; - int cc = 0; - int stat = 0; - /* urb_t *urb; */ - urb_priv_t *lurb_priv; - __u32 tdINFO, edHeadP, edTailP; - - while (td_list) { - td_list_next = td_list->next_dl_td; - - lurb_priv = &urb_priv; - tdINFO = m32_swap (td_list->hwINFO); - - ed = td_list->ed; - - dl_transfer_length(td_list); - - /* error code of transfer */ - cc = TD_CC_GET (tdINFO); - if (cc != 0) { - dbg("ConditionCode %#x", cc); - stat = cc_to_error[cc]; - } - - if (ed->state != ED_NEW) { - edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0; - edTailP = m32_swap (ed->hwTailP); - - /* unlink eds if they are not busy */ - if ((edHeadP == edTailP) && (ed->state == ED_OPER)) - ep_unlink (ohci, ed); - } - - td_list = td_list_next; - } - return stat; -} - -/*-------------------------------------------------------------------------* - * Virtual Root Hub - *-------------------------------------------------------------------------*/ - -/* Device descriptor */ -static __u8 root_hub_dev_des[] = -{ - 0x12, /* __u8 bLength; */ - 0x01, /* __u8 bDescriptorType; Device */ - 0x10, /* __u16 bcdUSB; v1.1 */ - 0x01, - 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */ - 0x00, /* __u8 bDeviceSubClass; */ - 0x00, /* __u8 bDeviceProtocol; */ - 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */ - 0x00, /* __u16 idVendor; */ - 0x00, - 0x00, /* __u16 idProduct; */ - 0x00, - 0x00, /* __u16 bcdDevice; */ - 0x00, - 0x00, /* __u8 iManufacturer; */ - 0x01, /* __u8 iProduct; */ - 0x00, /* __u8 iSerialNumber; */ - 0x01 /* __u8 bNumConfigurations; */ -}; - - -/* Configuration descriptor */ -static __u8 root_hub_config_des[] = -{ - 0x09, /* __u8 bLength; */ - 0x02, /* __u8 bDescriptorType; Configuration */ - 0x19, /* __u16 wTotalLength; */ - 0x00, - 0x01, /* __u8 bNumInterfaces; */ - 0x01, /* __u8 bConfigurationValue; */ - 0x00, /* __u8 iConfiguration; */ - 0x40, /* __u8 bmAttributes; - Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */ - 0x00, /* __u8 MaxPower; */ - - /* interface */ - 0x09, /* __u8 if_bLength; */ - 0x04, /* __u8 if_bDescriptorType; Interface */ - 0x00, /* __u8 if_bInterfaceNumber; */ - 0x00, /* __u8 if_bAlternateSetting; */ - 0x01, /* __u8 if_bNumEndpoints; */ - 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */ - 0x00, /* __u8 if_bInterfaceSubClass; */ - 0x00, /* __u8 if_bInterfaceProtocol; */ - 0x00, /* __u8 if_iInterface; */ - - /* endpoint */ - 0x07, /* __u8 ep_bLength; */ - 0x05, /* __u8 ep_bDescriptorType; Endpoint */ - 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ - 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */ - 0x00, - 0xff /* __u8 ep_bInterval; 255 ms */ -}; - -static unsigned char root_hub_str_index0[] = -{ - 0x04, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 0x09, /* __u8 lang ID */ - 0x04, /* __u8 lang ID */ -}; - -static unsigned char root_hub_str_index1[] = -{ - 28, /* __u8 bLength; */ - 0x03, /* __u8 bDescriptorType; String-descriptor */ - 'O', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'C', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'I', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'R', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'o', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 't', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - ' ', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'H', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'u', /* __u8 Unicode */ - 0, /* __u8 Unicode */ - 'b', /* __u8 Unicode */ - 0, /* __u8 Unicode */ -}; - -/* Hub class-specific descriptor is constructed dynamically */ - - -/*-------------------------------------------------------------------------*/ - -#define OK(x) len = (x); break -#ifdef DEBUG -#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);} -#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);} -#else -#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status) -#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1]) -#endif -#define RD_RH_STAT roothub_status(&gohci) -#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1) - -/* request to virtual root hub */ - -int rh_check_port_status(ohci_t *controller) -{ - __u32 temp, ndp, i; - int res; - - res = -1; - temp = roothub_a (controller); - ndp = (temp & RH_A_NDP); -#ifdef CONFIG_AT91C_PQFP_UHPBUG - ndp = (ndp == 2) ? 1:0; -#endif - - for (i = 0; i < ndp; i++) { - temp = roothub_portstatus (controller, i); - /* check for a device disconnect */ - if (((temp & (RH_PS_PESC | RH_PS_CSC)) == - (RH_PS_PESC | RH_PS_CSC)) && - ((temp & RH_PS_CCS) == 0)) { - res = i; - break; - } - } - return res; -} - -static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe, - void *buffer, int transfer_len, struct devrequest *cmd) -{ - void * data = buffer; - int leni = transfer_len; - int len = 0; - int stat = 0; - __u32 datab[4]; - __u8 *data_buf = (__u8 *)datab; - __u16 bmRType_bReq; - __u16 wValue; - __u16 wIndex; - __u16 wLength; - -#ifdef DEBUG -urb_priv.actual_length = 0; -pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe)); -#else - wait_ms(1); -#endif - if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) { - info("Root-Hub submit IRQ: NOT implemented"); - return 0; - } - - bmRType_bReq = cmd->requesttype | (cmd->request << 8); - wValue = m16_swap (cmd->value); - wIndex = m16_swap (cmd->index); - wLength = m16_swap (cmd->length); - - info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x", - dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength); - - switch (bmRType_bReq) { - /* Request Destination: - without flags: Device, - RH_INTERFACE: interface, - RH_ENDPOINT: endpoint, - RH_CLASS means HUB here, - RH_OTHER | RH_CLASS almost ever means HUB_PORT here - */ - - case RH_GET_STATUS: - *(__u16 *) data_buf = m16_swap (1); OK (2); - case RH_GET_STATUS | RH_INTERFACE: - *(__u16 *) data_buf = m16_swap (0); OK (2); - case RH_GET_STATUS | RH_ENDPOINT: - *(__u16 *) data_buf = m16_swap (0); OK (2); - case RH_GET_STATUS | RH_CLASS: - *(__u32 *) data_buf = m32_swap ( - RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE)); - OK (4); - case RH_GET_STATUS | RH_OTHER | RH_CLASS: - *(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4); - - case RH_CLEAR_FEATURE | RH_ENDPOINT: - switch (wValue) { - case (RH_ENDPOINT_STALL): OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_CLASS: - switch (wValue) { - case RH_C_HUB_LOCAL_POWER: - OK(0); - case (RH_C_HUB_OVER_CURRENT): - WR_RH_STAT(RH_HS_OCIC); OK (0); - } - break; - - case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_ENABLE): - WR_RH_PORTSTAT (RH_PS_CCS ); OK (0); - case (RH_PORT_SUSPEND): - WR_RH_PORTSTAT (RH_PS_POCI); OK (0); - case (RH_PORT_POWER): - WR_RH_PORTSTAT (RH_PS_LSDA); OK (0); - case (RH_C_PORT_CONNECTION): - WR_RH_PORTSTAT (RH_PS_CSC ); OK (0); - case (RH_C_PORT_ENABLE): - WR_RH_PORTSTAT (RH_PS_PESC); OK (0); - case (RH_C_PORT_SUSPEND): - WR_RH_PORTSTAT (RH_PS_PSSC); OK (0); - case (RH_C_PORT_OVER_CURRENT): - WR_RH_PORTSTAT (RH_PS_OCIC); OK (0); - case (RH_C_PORT_RESET): - WR_RH_PORTSTAT (RH_PS_PRSC); OK (0); - } - break; - - case RH_SET_FEATURE | RH_OTHER | RH_CLASS: - switch (wValue) { - case (RH_PORT_SUSPEND): - WR_RH_PORTSTAT (RH_PS_PSS ); OK (0); - case (RH_PORT_RESET): /* BUG IN HUP CODE *********/ - if (RD_RH_PORTSTAT & RH_PS_CCS) - WR_RH_PORTSTAT (RH_PS_PRS); - OK (0); - case (RH_PORT_POWER): - WR_RH_PORTSTAT (RH_PS_PPS ); OK (0); - case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/ - if (RD_RH_PORTSTAT & RH_PS_CCS) - WR_RH_PORTSTAT (RH_PS_PES ); - OK (0); - } - break; - - case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0); - - case RH_GET_DESCRIPTOR: - switch ((wValue & 0xff00) >> 8) { - case (0x01): /* device descriptor */ - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_dev_des), - wLength)); - data_buf = root_hub_dev_des; OK(len); - case (0x02): /* configuration descriptor */ - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_config_des), - wLength)); - data_buf = root_hub_config_des; OK(len); - case (0x03): /* string descriptors */ - if(wValue==0x0300) { - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_str_index0), - wLength)); - data_buf = root_hub_str_index0; - OK(len); - } - if(wValue==0x0301) { - len = min_t(unsigned int, - leni, - min_t(unsigned int, - sizeof (root_hub_str_index1), - wLength)); - data_buf = root_hub_str_index1; - OK(len); - } - default: - stat = USB_ST_STALLED; - } - break; - - case RH_GET_DESCRIPTOR | RH_CLASS: - { - __u32 temp = roothub_a (&gohci); - - data_buf [0] = 9; /* min length; */ - data_buf [1] = 0x29; - data_buf [2] = temp & RH_A_NDP; -#ifdef CONFIG_AT91C_PQFP_UHPBUG - data_buf [2] = (data_buf [2] == 2) ? 1:0; -#endif - data_buf [3] = 0; - if (temp & RH_A_PSM) /* per-port power switching? */ - data_buf [3] |= 0x1; - if (temp & RH_A_NOCP) /* no overcurrent reporting? */ - data_buf [3] |= 0x10; - else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */ - data_buf [3] |= 0x8; - - /* corresponds to data_buf[4-7] */ - datab [1] = 0; - data_buf [5] = (temp & RH_A_POTPGT) >> 24; - temp = roothub_b (&gohci); - data_buf [7] = temp & RH_B_DR; - if (data_buf [2] < 7) { - data_buf [8] = 0xff; - } else { - data_buf [0] += 2; - data_buf [8] = (temp & RH_B_DR) >> 8; - data_buf [10] = data_buf [9] = 0xff; - } - - len = min_t(unsigned int, leni, - min_t(unsigned int, data_buf [0], wLength)); - OK (len); - } - - case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1); - - case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0); - - default: - dbg ("unsupported root hub command"); - stat = USB_ST_STALLED; - } - -#ifdef DEBUG - ohci_dump_roothub (&gohci, 1); -#else - wait_ms(1); -#endif - - len = min_t(int, len, leni); - if (data != data_buf) - memcpy (data, data_buf, len); - dev->act_len = len; - dev->status = stat; - -#ifdef DEBUG - if (transfer_len) - urb_priv.actual_length = transfer_len; - pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/); -#else - wait_ms(1); -#endif - - return stat; -} - -/*-------------------------------------------------------------------------*/ - -/* common code for handling submit messages - used for all but root hub */ -/* accesses. */ -int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup, int interval) -{ - int stat = 0; - int maxsize = usb_maxpacket(dev, pipe); - int timeout; - - /* device pulled? Shortcut the action. */ - if (devgone == dev) { - dev->status = USB_ST_CRC_ERR; - return 0; - } - -#ifdef DEBUG - urb_priv.actual_length = 0; - pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); -#else - wait_ms(1); -#endif - if (!maxsize) { - err("submit_common_message: pipesize for pipe %lx is zero", - pipe); - return -1; - } - - if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) { - err("sohci_submit_job failed"); - return -1; - } - - wait_ms(10); - /* ohci_dump_status(&gohci); */ - - /* allow more time for a BULK device to react - some are slow */ -#define BULK_TO 5000 /* timeout in milliseconds */ - if (usb_pipetype (pipe) == PIPE_BULK) - timeout = BULK_TO; - else - timeout = 100; - - /* wait for it to complete */ - for (;;) { - /* check whether the controller is done */ - stat = hc_interrupt(); - if (stat < 0) { - stat = USB_ST_CRC_ERR; - break; - } - if (stat >= 0 && stat != 0xff) { - /* 0xff is returned for an SF-interrupt */ - break; - } - if (--timeout) { - wait_ms(1); - } else { - err("CTL:TIMEOUT "); - stat = USB_ST_CRC_ERR; - break; - } - } - /* we got an Root Hub Status Change interrupt */ - if (got_rhsc) { -#ifdef DEBUG - ohci_dump_roothub (&gohci, 1); -#endif - got_rhsc = 0; - /* abuse timeout */ - timeout = rh_check_port_status(&gohci); - if (timeout >= 0) { -#if 0 /* this does nothing useful, but leave it here in case that changes */ - /* the called routine adds 1 to the passed value */ - usb_hub_port_connect_change(gohci.rh.dev, timeout - 1); -#endif - /* - * XXX - * This is potentially dangerous because it assumes - * that only one device is ever plugged in! - */ - devgone = dev; - } - } - - dev->status = stat; - dev->act_len = transfer_len; - -#ifdef DEBUG - pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe)); -#else - wait_ms(1); -#endif - - /* free TDs in urb_priv */ - urb_free_priv (&urb_priv); - return 0; -} - -/* submit routines called from usb.c */ -int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len) -{ - info("submit_bulk_msg"); - return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0); -} - -int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, struct devrequest *setup) -{ - int maxsize = usb_maxpacket(dev, pipe); - - info("submit_control_msg"); -#ifdef DEBUG - urb_priv.actual_length = 0; - pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe)); -#else - wait_ms(1); -#endif - if (!maxsize) { - err("submit_control_message: pipesize for pipe %lx is zero", - pipe); - return -1; - } - if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) { - gohci.rh.dev = dev; - /* root hub - redirect */ - return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len, - setup); - } - - return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0); -} - -int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, - int transfer_len, int interval) -{ - info("submit_int_msg"); - return -1; -} - -/*-------------------------------------------------------------------------* - * HC functions - *-------------------------------------------------------------------------*/ - -/* reset the HC and BUS */ - -static int hc_reset (ohci_t *ohci) -{ - int timeout = 30; - int smm_timeout = 50; /* 0,5 sec */ - - dbg("%s\n", __FUNCTION__); - - if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */ - writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */ - info("USB HC TakeOver from SMM"); - while (readl (&ohci->regs->control) & OHCI_CTRL_IR) { - wait_ms (10); - if (--smm_timeout == 0) { - err("USB HC TakeOver failed!"); - return -1; - } - } - } - - /* Disable HC interrupts */ - writel (OHCI_INTR_MIE, &ohci->regs->intrdisable); - - dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n", - ohci->slot_name, - readl(&ohci->regs->control)); - - /* Reset USB (needed by some controllers) */ - writel (0, &ohci->regs->control); - - /* HC Reset requires max 10 us delay */ - writel (OHCI_HCR, &ohci->regs->cmdstatus); - while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) { - if (--timeout == 0) { - err("USB HC reset timed out!"); - return -1; - } - udelay (1); - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* Start an OHCI controller, set the BUS operational - * enable interrupts - * connect the virtual root hub */ - -static int hc_start (ohci_t * ohci) -{ - __u32 mask; - unsigned int fminterval; - - ohci->disabled = 1; - - /* Tell the controller where the control and bulk lists are - * The lists are empty now. */ - - writel (0, &ohci->regs->ed_controlhead); - writel (0, &ohci->regs->ed_bulkhead); - - writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */ - - fminterval = 0x2edf; - writel ((fminterval * 9) / 10, &ohci->regs->periodicstart); - fminterval |= ((((fminterval - 210) * 6) / 7) << 16); - writel (fminterval, &ohci->regs->fminterval); - writel (0x628, &ohci->regs->lsthresh); - - /* start controller operations */ - ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER; - ohci->disabled = 0; - writel (ohci->hc_control, &ohci->regs->control); - - /* disable all interrupts */ - mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD | - OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC | - OHCI_INTR_OC | OHCI_INTR_MIE); - writel (mask, &ohci->regs->intrdisable); - /* clear all interrupts */ - mask &= ~OHCI_INTR_MIE; - writel (mask, &ohci->regs->intrstatus); - /* Choose the interrupts we care about now - but w/o MIE */ - mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO; - writel (mask, &ohci->regs->intrenable); - -#ifdef OHCI_USE_NPS - /* required for AMD-756 and some Mac platforms */ - writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM, - &ohci->regs->roothub.a); - writel (RH_HS_LPSC, &ohci->regs->roothub.status); -#endif /* OHCI_USE_NPS */ - -#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);}) - /* POTPGT delay is bits 24-31, in 2 ms units. */ - mdelay ((roothub_a (ohci) >> 23) & 0x1fe); - - /* connect the virtual root hub */ - ohci->rh.devnum = 0; - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* an interrupt happens */ - -static int -hc_interrupt (void) -{ - ohci_t *ohci = &gohci; - struct ohci_regs *regs = ohci->regs; - int ints; - int stat = -1; - - if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) { - ints = OHCI_INTR_WDH; - } else { - ints = readl (®s->intrstatus); - } - - /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */ - - if (ints & OHCI_INTR_RHSC) { - got_rhsc = 1; - } - - if (ints & OHCI_INTR_UE) { - ohci->disabled++; - err ("OHCI Unrecoverable Error, controller usb-%s disabled", - ohci->slot_name); - /* e.g. due to PCI Master/Target Abort */ - -#ifdef DEBUG - ohci_dump (ohci, 1); -#else - wait_ms(1); -#endif - /* FIXME: be optimistic, hope that bug won't repeat often. */ - /* Make some non-interrupt context restart the controller. */ - /* Count and limit the retries though; either hardware or */ - /* software errors can go forever... */ - hc_reset (ohci); - return -1; - } - - if (ints & OHCI_INTR_WDH) { - wait_ms(1); - writel (OHCI_INTR_WDH, ®s->intrdisable); - stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci)); - writel (OHCI_INTR_WDH, ®s->intrenable); - } - - if (ints & OHCI_INTR_SO) { - dbg("USB Schedule overrun\n"); - writel (OHCI_INTR_SO, ®s->intrenable); - stat = -1; - } - - /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */ - if (ints & OHCI_INTR_SF) { - unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1; - wait_ms(1); - writel (OHCI_INTR_SF, ®s->intrdisable); - if (ohci->ed_rm_list[frame] != NULL) - writel (OHCI_INTR_SF, ®s->intrenable); - stat = 0xff; - } - - writel (ints, ®s->intrstatus); - return stat; -} - -/*-------------------------------------------------------------------------*/ - -/*-------------------------------------------------------------------------*/ - -/* De-allocate all resources.. */ - -static void hc_release_ohci (ohci_t *ohci) -{ - dbg ("USB HC release ohci usb-%s", ohci->slot_name); - - if (!ohci->disabled) - hc_reset (ohci); -} - -/*-------------------------------------------------------------------------*/ - -/* - * low level initalisation routine, called from usb.c - */ -static char ohci_inited = 0; - -int usb_lowlevel_init(void) -{ - /* - * Enable USB host clock. - */ - *AT91C_PMC_SCER = AT91C_PMC_UHP; /* 48MHz clock enabled for UHP */ - *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; /* Peripheral Clock Enable Register */ - - memset (&gohci, 0, sizeof (ohci_t)); - memset (&urb_priv, 0, sizeof (urb_priv_t)); - - /* align the storage */ - if ((__u32)&ghcca[0] & 0xff) { - err("HCCA not aligned!!"); - return -1; - } - phcca = &ghcca[0]; - info("aligned ghcca %p", phcca); - memset(&ohci_dev, 0, sizeof(struct ohci_device)); - if ((__u32)&ohci_dev.ed[0] & 0x7) { - err("EDs not aligned!!"); - return -1; - } - memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1)); - if ((__u32)gtd & 0x7) { - err("TDs not aligned!!"); - return -1; - } - ptd = gtd; - gohci.hcca = phcca; - memset (phcca, 0, sizeof (struct ohci_hcca)); - - gohci.disabled = 1; - gohci.sleeping = 0; - gohci.irq = -1; - gohci.regs = (struct ohci_regs *)AT91_USB_HOST_BASE; - - gohci.flags = 0; - gohci.slot_name = "at91rm9200"; - - if (hc_reset (&gohci) < 0) { - hc_release_ohci (&gohci); - /* Initialization failed */ - *AT91C_PMC_PCER = AT91C_ID_UHP; - *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ - return -1; - } - - /* FIXME this is a second HC reset; why?? */ -/* writel (gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control); - wait_ms (10);*/ - - if (hc_start (&gohci) < 0) { - err ("can't start usb-%s", gohci.slot_name); - hc_release_ohci (&gohci); - /* Initialization failed */ - *AT91C_PMC_PCER = AT91C_ID_UHP; - *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ - return -1; - } - -#ifdef DEBUG - ohci_dump (&gohci, 1); -#else - wait_ms(1); -#endif - ohci_inited = 1; - return 0; -} - -int usb_lowlevel_stop(void) -{ - /* this gets called really early - before the controller has */ - /* even been initialized! */ - if (!ohci_inited) - return 0; - /* TODO release any interrupts, etc. */ - /* call hc_release_ohci() here ? */ - hc_reset (&gohci); - /* may not want to do this */ - *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; - *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */ - return 0; -} - -#endif /* CONFIG_USB_OHCI */ diff --git a/cpu/arm920t/at91rm9200/usb_ohci.h b/cpu/arm920t/at91rm9200/usb_ohci.h deleted file mode 100644 index ecb4e93..0000000 --- a/cpu/arm920t/at91rm9200/usb_ohci.h +++ /dev/null @@ -1,419 +0,0 @@ -/* - * URB OHCI HCD (Host Controller Driver) for USB. - * - * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> - * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net> - * - * usb-ohci.h - */ - - -static int cc_to_error[16] = { - -/* mapping of the OHCI CC status to error codes */ - /* No Error */ 0, - /* CRC Error */ USB_ST_CRC_ERR, - /* Bit Stuff */ USB_ST_BIT_ERR, - /* Data Togg */ USB_ST_CRC_ERR, - /* Stall */ USB_ST_STALLED, - /* DevNotResp */ -1, - /* PIDCheck */ USB_ST_BIT_ERR, - /* UnExpPID */ USB_ST_BIT_ERR, - /* DataOver */ USB_ST_BUF_ERR, - /* DataUnder */ USB_ST_BUF_ERR, - /* reservd */ -1, - /* reservd */ -1, - /* BufferOver */ USB_ST_BUF_ERR, - /* BuffUnder */ USB_ST_BUF_ERR, - /* Not Access */ -1, - /* Not Access */ -1 -}; - -/* ED States */ - -#define ED_NEW 0x00 -#define ED_UNLINK 0x01 -#define ED_OPER 0x02 -#define ED_DEL 0x04 -#define ED_URB_DEL 0x08 - -/* usb_ohci_ed */ -struct ed { - __u32 hwINFO; - __u32 hwTailP; - __u32 hwHeadP; - __u32 hwNextED; - - struct ed *ed_prev; - __u8 int_period; - __u8 int_branch; - __u8 int_load; - __u8 int_interval; - __u8 state; - __u8 type; - __u16 last_iso; - struct ed *ed_rm_list; - - struct usb_device *usb_dev; - __u32 unused[3]; -} __attribute((aligned(16))); -typedef struct ed ed_t; - - -/* TD info field */ -#define TD_CC 0xf0000000 -#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f) -#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28) -#define TD_EC 0x0C000000 -#define TD_T 0x03000000 -#define TD_T_DATA0 0x02000000 -#define TD_T_DATA1 0x03000000 -#define TD_T_TOGGLE 0x00000000 -#define TD_R 0x00040000 -#define TD_DI 0x00E00000 -#define TD_DI_SET(X) (((X) & 0x07)<< 21) -#define TD_DP 0x00180000 -#define TD_DP_SETUP 0x00000000 -#define TD_DP_IN 0x00100000 -#define TD_DP_OUT 0x00080000 - -#define TD_ISO 0x00010000 -#define TD_DEL 0x00020000 - -/* CC Codes */ -#define TD_CC_NOERROR 0x00 -#define TD_CC_CRC 0x01 -#define TD_CC_BITSTUFFING 0x02 -#define TD_CC_DATATOGGLEM 0x03 -#define TD_CC_STALL 0x04 -#define TD_DEVNOTRESP 0x05 -#define TD_PIDCHECKFAIL 0x06 -#define TD_UNEXPECTEDPID 0x07 -#define TD_DATAOVERRUN 0x08 -#define TD_DATAUNDERRUN 0x09 -#define TD_BUFFEROVERRUN 0x0C -#define TD_BUFFERUNDERRUN 0x0D -#define TD_NOTACCESSED 0x0F - - -#define MAXPSW 1 - -struct td { - __u32 hwINFO; - __u32 hwCBP; /* Current Buffer Pointer */ - __u32 hwNextTD; /* Next TD Pointer */ - __u32 hwBE; /* Memory Buffer End Pointer */ - - __u16 hwPSW[MAXPSW]; - __u8 unused; - __u8 index; - struct ed *ed; - struct td *next_dl_td; - struct usb_device *usb_dev; - int transfer_len; - __u32 data; - - __u32 unused2[2]; -} __attribute((aligned(32))); -typedef struct td td_t; - -#define OHCI_ED_SKIP (1 << 14) - -/* - * The HCCA (Host Controller Communications Area) is a 256 byte - * structure defined in the OHCI spec. that the host controller is - * told the base address of. It must be 256-byte aligned. - */ - -#define NUM_INTS 32 /* part of the OHCI standard */ -struct ohci_hcca { - __u32 int_table[NUM_INTS]; /* Interrupt ED table */ - __u16 frame_no; /* current frame number */ - __u16 pad1; /* set to 0 on each frame_no change */ - __u32 done_head; /* info returned for an interrupt */ - u8 reserved_for_hc[116]; -} __attribute((aligned(256))); - - -/* - * Maximum number of root hub ports. - */ -#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ - -/* - * This is the structure of the OHCI controller's memory mapped I/O - * region. This is Memory Mapped I/O. You must use the readl() and - * writel() macros defined in asm/io.h to access these!! - */ -struct ohci_regs { - /* control and status registers */ - __u32 revision; - __u32 control; - __u32 cmdstatus; - __u32 intrstatus; - __u32 intrenable; - __u32 intrdisable; - /* memory pointers */ - __u32 hcca; - __u32 ed_periodcurrent; - __u32 ed_controlhead; - __u32 ed_controlcurrent; - __u32 ed_bulkhead; - __u32 ed_bulkcurrent; - __u32 donehead; - /* frame counters */ - __u32 fminterval; - __u32 fmremaining; - __u32 fmnumber; - __u32 periodicstart; - __u32 lsthresh; - /* Root hub ports */ - struct ohci_roothub_regs { - __u32 a; - __u32 b; - __u32 status; - __u32 portstatus[MAX_ROOT_PORTS]; - } roothub; -} __attribute((aligned(32))); - - -/* OHCI CONTROL AND STATUS REGISTER MASKS */ - -/* - * HcControl (control) register masks - */ -#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */ -#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */ -#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */ -#define OHCI_CTRL_CLE (1 << 4) /* control list enable */ -#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */ -#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */ -#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */ -#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */ -#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */ - -/* pre-shifted values for HCFS */ -# define OHCI_USB_RESET (0 << 6) -# define OHCI_USB_RESUME (1 << 6) -# define OHCI_USB_OPER (2 << 6) -# define OHCI_USB_SUSPEND (3 << 6) - -/* - * HcCommandStatus (cmdstatus) register masks - */ -#define OHCI_HCR (1 << 0) /* host controller reset */ -#define OHCI_CLF (1 << 1) /* control list filled */ -#define OHCI_BLF (1 << 2) /* bulk list filled */ -#define OHCI_OCR (1 << 3) /* ownership change request */ -#define OHCI_SOC (3 << 16) /* scheduling overrun count */ - -/* - * masks used with interrupt registers: - * HcInterruptStatus (intrstatus) - * HcInterruptEnable (intrenable) - * HcInterruptDisable (intrdisable) - */ -#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */ -#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */ -#define OHCI_INTR_SF (1 << 2) /* start frame */ -#define OHCI_INTR_RD (1 << 3) /* resume detect */ -#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */ -#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */ -#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */ -#define OHCI_INTR_OC (1 << 30) /* ownership change */ -#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */ - - -/* Virtual Root HUB */ -struct virt_root_hub { - int devnum; /* Address of Root Hub endpoint */ - void *dev; /* was urb */ - void *int_addr; - int send; - int interval; -}; - -/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */ - -/* destination of request */ -#define RH_INTERFACE 0x01 -#define RH_ENDPOINT 0x02 -#define RH_OTHER 0x03 - -#define RH_CLASS 0x20 -#define RH_VENDOR 0x40 - -/* Requests: bRequest << 8 | bmRequestType */ -#define RH_GET_STATUS 0x0080 -#define RH_CLEAR_FEATURE 0x0100 -#define RH_SET_FEATURE 0x0300 -#define RH_SET_ADDRESS 0x0500 -#define RH_GET_DESCRIPTOR 0x0680 -#define RH_SET_DESCRIPTOR 0x0700 -#define RH_GET_CONFIGURATION 0x0880 -#define RH_SET_CONFIGURATION 0x0900 -#define RH_GET_STATE 0x0280 -#define RH_GET_INTERFACE 0x0A80 -#define RH_SET_INTERFACE 0x0B00 -#define RH_SYNC_FRAME 0x0C80 -/* Our Vendor Specific Request */ -#define RH_SET_EP 0x2000 - - -/* Hub port features */ -#define RH_PORT_CONNECTION 0x00 -#define RH_PORT_ENABLE 0x01 -#define RH_PORT_SUSPEND 0x02 -#define RH_PORT_OVER_CURRENT 0x03 -#define RH_PORT_RESET 0x04 -#define RH_PORT_POWER 0x08 -#define RH_PORT_LOW_SPEED 0x09 - -#define RH_C_PORT_CONNECTION 0x10 -#define RH_C_PORT_ENABLE 0x11 -#define RH_C_PORT_SUSPEND 0x12 -#define RH_C_PORT_OVER_CURRENT 0x13 -#define RH_C_PORT_RESET 0x14 - -/* Hub features */ -#define RH_C_HUB_LOCAL_POWER 0x00 -#define RH_C_HUB_OVER_CURRENT 0x01 - -#define RH_DEVICE_REMOTE_WAKEUP 0x00 -#define RH_ENDPOINT_STALL 0x01 - -#define RH_ACK 0x01 -#define RH_REQ_ERR -1 -#define RH_NACK 0x00 - - -/* OHCI ROOT HUB REGISTER MASKS */ - -/* roothub.portstatus [i] bits */ -#define RH_PS_CCS 0x00000001 /* current connect status */ -#define RH_PS_PES 0x00000002 /* port enable status*/ -#define RH_PS_PSS 0x00000004 /* port suspend status */ -#define RH_PS_POCI 0x00000008 /* port over current indicator */ -#define RH_PS_PRS 0x00000010 /* port reset status */ -#define RH_PS_PPS 0x00000100 /* port power status */ -#define RH_PS_LSDA 0x00000200 /* low speed device attached */ -#define RH_PS_CSC 0x00010000 /* connect status change */ -#define RH_PS_PESC 0x00020000 /* port enable status change */ -#define RH_PS_PSSC 0x00040000 /* port suspend status change */ -#define RH_PS_OCIC 0x00080000 /* over current indicator change */ -#define RH_PS_PRSC 0x00100000 /* port reset status change */ - -/* roothub.status bits */ -#define RH_HS_LPS 0x00000001 /* local power status */ -#define RH_HS_OCI 0x00000002 /* over current indicator */ -#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */ -#define RH_HS_LPSC 0x00010000 /* local power status change */ -#define RH_HS_OCIC 0x00020000 /* over current indicator change */ -#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */ - -/* roothub.b masks */ -#define RH_B_DR 0x0000ffff /* device removable flags */ -#define RH_B_PPCM 0xffff0000 /* port power control mask */ - -/* roothub.a masks */ -#define RH_A_NDP (0xff << 0) /* number of downstream ports */ -#define RH_A_PSM (1 << 8) /* power switching mode */ -#define RH_A_NPS (1 << 9) /* no power switching */ -#define RH_A_DT (1 << 10) /* device type (mbz) */ -#define RH_A_OCPM (1 << 11) /* over current protection mode */ -#define RH_A_NOCP (1 << 12) /* no over current protection */ -#define RH_A_POTPGT (0xff << 24) /* power on to power good time */ - -/* urb */ -#define N_URB_TD 48 -typedef struct -{ - ed_t *ed; - __u16 length; /* number of tds associated with this request */ - __u16 td_cnt; /* number of tds already serviced */ - int state; - unsigned long pipe; - int actual_length; - td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */ -} urb_priv_t; -#define URB_DEL 1 - -/* - * This is the full ohci controller description - * - * Note how the "proper" USB information is just - * a subset of what the full implementation needs. (Linus) - */ - - -typedef struct ohci { - struct ohci_hcca *hcca; /* hcca */ - /*dma_addr_t hcca_dma;*/ - - int irq; - int disabled; /* e.g. got a UE, we're hung */ - int sleeping; - unsigned long flags; /* for HC bugs */ - - struct ohci_regs *regs; /* OHCI controller's memory */ - - ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */ - ed_t *ed_bulktail; /* last endpoint of bulk list */ - ed_t *ed_controltail; /* last endpoint of control list */ - int intrstatus; - __u32 hc_control; /* copy of the hc control reg */ - struct usb_device *dev[32]; - struct virt_root_hub rh; - - const char *slot_name; -} ohci_t; - -#define NUM_EDS 8 /* num of preallocated endpoint descriptors */ - -struct ohci_device { - ed_t ed[NUM_EDS]; - int ed_cnt; -}; - -/* hcd */ -/* endpoint */ -static int ep_link(ohci_t * ohci, ed_t * ed); -static int ep_unlink(ohci_t * ohci, ed_t * ed); -static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe); - -/*-------------------------------------------------------------------------*/ - -/* we need more TDs than EDs */ -#define NUM_TD 64 - -/* +1 so we can align the storage */ -td_t gtd[NUM_TD+1]; -/* pointers to aligned storage */ -td_t *ptd; - -/* TDs ... */ -static inline struct td * -td_alloc (struct usb_device *usb_dev) -{ - int i; - struct td *td; - - td = NULL; - for (i = 0; i < NUM_TD; i++) - { - if (ptd[i].usb_dev == NULL) - { - td = &ptd[i]; - td->usb_dev = usb_dev; - break; - } - } - - return td; -} - -static inline void -ed_free (struct ed *ed) -{ - ed->usb_dev = NULL; -} diff --git a/cpu/arm920t/s3c24x0/Makefile b/cpu/arm920t/s3c24x0/Makefile index 3a7c4b3..0ff36c5 100644 --- a/cpu/arm920t/s3c24x0/Makefile +++ b/cpu/arm920t/s3c24x0/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(SOC).a COBJS = i2c.o interrupts.o serial.o speed.o \ - usb_ohci.o + usb.o SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/arm920t/s3c24x0/usb.c b/cpu/arm920t/s3c24x0/usb.c new file mode 100644 index 0000000..ef5d5bf --- /dev/null +++ b/cpu/arm920t/s3c24x0/usb.c @@ -0,0 +1,72 @@ +/* + * (C) Copyright 2006 + * DENX Software Engineering <mk@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) +# if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) + +#if defined(CONFIG_S3C2400) +# include <s3c2400.h> +#elif defined(CONFIG_S3C2410) +# include <s3c2410.h> +#endif + +int usb_cpu_init (void) +{ + + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); + + /* + * Set the 48 MHz UPLL clocking. Values are taken from + * "PLL value selection guide", 6-23, s3c2400_UM.pdf. + */ + clk_power->UPLLCON = ((40 << 12) + (1 << 4) + 2); + gpio->MISCCR |= 0x8; /* 1 = use pads related USB for USB host */ + + /* + * Enable USB host clock. + */ + clk_power->CLKCON |= (1 << 4); + + return 0; +} + +int usb_cpu_stop (void) +{ + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + /* may not want to do this */ + clk_power->CLKCON &= ~(1 << 4); + return 0; +} + +int usb_cpu_init_fail (void) +{ + S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER(); + clk_power->CLKCON &= ~(1 << 4); + return 0; +} + +# endif /* defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/arm920t/start.S b/cpu/arm920t/start.S index 346f0d0..b9c364b 100644 --- a/cpu/arm920t/start.S +++ b/cpu/arm920t/start.S @@ -27,7 +27,9 @@ #include <config.h> #include <version.h> - +#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF) +#include <led.h> +#endif /* ************************************************************************* @@ -116,6 +118,69 @@ reset: orr r0,r0,#0xd3 msr cpsr,r0 +#if CONFIG_AT91RM9200 +#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF) + bl LED_init + bl red_LED_on +#endif + +#ifdef CONFIG_BOOTBINFUNC +/* code based on entry.S from ATMEL */ +#define AT91C_BASE_CKGR 0xFFFFFC20 +#define CKGR_MOR 0 + /* Get the CKGR Base Address */ + ldr r1, =AT91C_BASE_CKGR + +/* Main oscillator Enable register APMC_MOR : Enable main oscillator , OSCOUNT = 0xFF */ +/* ldr r0, = AT91C_CKGR_MOSCEN:OR:AT91C_CKGR_OSCOUNT */ + ldr r0, =0x0000FF01 + str r0, [r1, #CKGR_MOR] + /* Add loop to compensate Main Oscillator startup time */ + ldr r0, =0x00000010 +LoopOsc: + subs r0, r0, #1 + bhi LoopOsc + /* scratch stack */ + ldr r1, =0x00204000 + /* Insure word alignment */ + bic r1, r1, #3 + /* Init stack SYS */ + mov sp, r1 + /* + * This does a lot more than just set up the memory, which + * is why it's called lowlevelinit + */ + bl lowlevelinit /* in memsetup.S */ + bl icache_enable; + /* ------------------------------------ + * Read/modify/write CP15 control register + * ------------------------------------- + * read cp15 control register (cp15 r1) in r0 + * ------------------------------------ + */ + mrc p15, 0, r0, c1, c0, 0 + /* Reset bit :Little Endian end fast bus mode */ + ldr r3, =0xC0000080 + /* Set bit :Asynchronous clock mode, Not Fast Bus */ + ldr r4, =0xC0000000 + bic r0, r0, r3 + orr r0, r0, r4 + /* write r0 in cp15 control register (cp15 r1) */ + mcr p15, 0, r0, c1, c0, 0 +#endif /* CONFIG_BOOTBINFUNC */ + /* + * relocate exeception table + */ + ldr r0, =_start + ldr r1, =0x0 + mov r2, #16 +copyex: + subs r2, r2, #1 + ldr r3, [r0], #4 + str r3, [r1], #4 + bne copyex +#endif + /* turn off the watchdog */ #if defined(CONFIG_S3C2400) # define pWTCON 0x15300000 @@ -160,6 +225,26 @@ reset: bl cpu_init_crit #endif +#ifdef CONFIG_AT91RM9200 +#ifdef CONFIG_BOOTBINFUNC +relocate: /* relocate U-Boot to RAM */ + adr r0, _start /* r0 <- current position of code */ + ldr r1, _TEXT_BASE /* test if we run from flash or RAM */ + cmp r0, r1 /* don't reloc during debug */ + beq stack_setup + + ldr r2, _armboot_start + ldr r3, _bss_start + sub r2, r3, r2 /* r2 <- size of armboot */ + add r2, r0, r2 /* r2 <- source end address */ + +copy_loop: + ldmia r0!, {r3-r10} /* copy from source address [r0] */ + stmia r1!, {r3-r10} /* copy to target address [r1] */ + cmp r0, r2 /* until source end addreee [r2] */ + ble copy_loop +#endif /* CONFIG_BOOTBINFUNC */ +#else #ifndef CONFIG_SKIP_RELOCATE_UBOOT relocate: /* relocate U-Boot to RAM */ adr r0, _start /* r0 <- current position of code */ @@ -178,7 +263,7 @@ copy_loop: cmp r0, r2 /* until source end addreee [r2] */ ble copy_loop #endif /* CONFIG_SKIP_RELOCATE_UBOOT */ - +#endif /* Set up the stack */ stack_setup: ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */ @@ -262,7 +347,11 @@ cpu_init_crit: * find a lowlevel_init.S in your board directory. */ mov ip, lr +#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK) || defined(CONFIG_AT91RM9200DF) + +#else bl lowlevel_init +#endif mov lr, ip mov pc, lr #endif /* CONFIG_SKIP_LOWLEVEL_INIT */ diff --git a/cpu/arm926ejs/davinci/Makefile b/cpu/arm926ejs/davinci/Makefile new file mode 100644 index 0000000..0f77f40 --- /dev/null +++ b/cpu/arm926ejs/davinci/Makefile @@ -0,0 +1,49 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(SOC).a + +COBJS = timer.o ether.o lxt972.o dp83848.o i2c.o nand.o +SOBJS = lowlevel_init.o reset.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/arm926ejs/davinci/dp83848.c b/cpu/arm926ejs/davinci/dp83848.c new file mode 100644 index 0000000..5719845 --- /dev/null +++ b/cpu/arm926ejs/davinci/dp83848.c @@ -0,0 +1,156 @@ +/* + * National Semiconductor DP83848 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <net.h> +#include <dp83848.h> +#include <asm/arch/emac_defs.h> + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int dp83848_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID1_REG, &id1)) + return(0); + if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID2_REG, &id2)) + return(0); + + if ((id1 == DP83848_PHYID1_OUI) && (id2 == DP83848_PHYID2_OUI)) + return(1); + + return(0); +} + +int dp83848_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_LINK_STATUS)) /* link up? */ + return(0); + + if (!dm644x_eth_phy_read(phy_addr, DP83848_PHY_STAT_REG, &tmp)) + return(0); + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (tmp & DP83848_SPEED) { + if (tmp & DP83848_DUPLEX) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } else { + if (tmp & DP83848_DUPLEX) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } + + return(0); +} + + +int dp83848_init_phy(int phy_addr) +{ + int ret = 1; + + if (!dp83848_get_link_speed(phy_addr)) { + /* Try another time */ + udelay(100000); + ret = dp83848_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + dm644x_eth_phy_write(phy_addr, DP83848_PHY_INTR_CTRL_REG, 0); + + return(ret); +} + + +int dp83848_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + + if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp &= ~DP83848_AUTONEG; /* remove autonegotiation enable */ + tmp |= DP83848_ISOLATE; /* Electrically isolate PHY */ + dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Set the Auto_negotiation Advertisement Register + * MII advertising for Next page, 100BaseTxFD and HD, + * 10BaseTFD and HD, IEEE 802.3 + */ + tmp = DP83848_NP | DP83848_TX_FDX | DP83848_TX_HDX | + DP83848_10_FDX | DP83848_10_HDX | DP83848_AN_IEEE_802_3; + dm644x_eth_phy_write(phy_addr, DP83848_ANA_REG, tmp); + + + /* Read Control Register */ + if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp)) + return(0); + + tmp |= DP83848_SPEED_SELECT | DP83848_AUTONEG | DP83848_DUPLEX_MODE; + dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /* Restart Auto_negotiation */ + tmp |= DP83848_RESTART_AUTONEG; + dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp); + + /*check AutoNegotiate complete */ + udelay(10000); + if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp)) + return(0); + + if (!(tmp & DP83848_AUTONEG_COMP)) + return(0); + + return (dp83848_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm926ejs/davinci/ether.c b/cpu/arm926ejs/davinci/ether.c new file mode 100644 index 0000000..766bc7d --- /dev/null +++ b/cpu/arm926ejs/davinci/ether.c @@ -0,0 +1,650 @@ +/* + * Ethernet driver for TI TMS320DM644x (DaVinci) chips. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright + * follows: + * + * ---------------------------------------------------------------------------- + * + * dm644x_emac.c + * + * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM + * + * Copyright (C) 2005 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + + * Modifications: + * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot. + * ver 1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors + * + */ +#include <common.h> +#include <command.h> +#include <net.h> +#include <miiphy.h> +#include <asm/arch/emac_defs.h> + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +unsigned int emac_dbg = 0; +#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args) + +/* Internal static functions */ +static int dm644x_eth_hw_init (void); +static int dm644x_eth_open (void); +static int dm644x_eth_close (void); +static int dm644x_eth_send_packet (volatile void *packet, int length); +static int dm644x_eth_rcv_packet (void); +static void dm644x_eth_mdio_enable(void); + +static int gen_init_phy(int phy_addr); +static int gen_is_phy_connected(int phy_addr); +static int gen_get_link_speed(int phy_addr); +static int gen_auto_negotiate(int phy_addr); + +/* Wrappers exported to the U-Boot proper */ +int eth_hw_init(void) +{ + return(dm644x_eth_hw_init()); +} + +int eth_init(bd_t * bd) +{ + return(dm644x_eth_open()); +} + +void eth_halt(void) +{ + dm644x_eth_close(); +} + +int eth_send(volatile void *packet, int length) +{ + return(dm644x_eth_send_packet(packet, length)); +} + +int eth_rx(void) +{ + return(dm644x_eth_rcv_packet()); +} + +void eth_mdio_enable(void) +{ + dm644x_eth_mdio_enable(); +} +/* End of wrappers */ + + +static u_int8_t dm644x_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + +/* + * This function must be called before emac_open() if you want to override + * the default mac address. + */ +void dm644x_eth_set_mac_addr(const u_int8_t *addr) +{ + int i; + + for (i = 0; i < sizeof (dm644x_eth_mac_addr); i++) { + dm644x_eth_mac_addr[i] = addr[i]; + } +} + +/* EMAC Addresses */ +static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR; +static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; +static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR; + +/* EMAC descriptors */ +static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); +static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); +static volatile emac_desc *emac_rx_active_head = 0; +static volatile emac_desc *emac_rx_active_tail = 0; +static int emac_rx_queue_active = 0; + +/* Receive packet buffers */ +static unsigned char emac_rx_buffers[EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + +/* PHY address for a discovered PHY (0xff - not found) */ +static volatile u_int8_t active_phy_addr = 0xff; + +phy_t phy; + +static void dm644x_eth_mdio_enable(void) +{ + u_int32_t clkdiv; + + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + + adap_mdio->CONTROL = (clkdiv & 0xff) | + MDIO_CONTROL_ENABLE | + MDIO_CONTROL_FAULT | + MDIO_CONTROL_FAULT_ENABLE; + + while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;} +} + +/* + * Tries to find an active connected PHY. Returns 1 if address if found. + * If no active PHY (or more than one PHY) found returns 0. + * Sets active_phy_addr variable. + */ +static int dm644x_eth_phy_detect(void) +{ + u_int32_t phy_act_state; + int i; + + active_phy_addr = 0xff; + + if ((phy_act_state = adap_mdio->ALIVE) == 0) + return(0); /* No active PHYs */ + + debug_emac("dm644x_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state); + + for (i = 0; i < 32; i++) { + if (phy_act_state & (1 << i)) { + if (phy_act_state & ~(1 << i)) + return(0); /* More than one PHY */ + else { + active_phy_addr = i; + return(1); + } + } + } + + return(0); /* Just to make GCC happy */ +} + + +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */ +int dm644x_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data) +{ + int tmp; + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_READ | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16); + + /* Wait for command to complete */ + while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;} + + if (tmp & MDIO_USERACCESS0_ACK) { + *data = tmp & 0xffff; + return(1); + } + + *data = -1; + return(0); +} + +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */ +int dm644x_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data) +{ + + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO | + MDIO_USERACCESS0_WRITE_WRITE | + ((reg_num & 0x1f) << 21) | + ((phy_addr & 0x1f) << 16) | + (data & 0xffff); + + /* Wait for command to complete */ + while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;} + + return(1); +} + +/* PHY functions for a generic PHY */ +static int gen_init_phy(int phy_addr) +{ + int ret = 1; + + if (gen_get_link_speed(phy_addr)) { + /* Try another time */ + ret = gen_get_link_speed(phy_addr); + } + + return(ret); +} + +static int gen_is_phy_connected(int phy_addr) +{ + u_int16_t dummy; + + return(dm644x_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy)); +} + +static int gen_get_link_speed(int phy_addr) +{ + u_int16_t tmp; + + if (dm644x_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04)) + return(1); + + return(0); +} + +static int gen_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + if (!dm644x_eth_phy_read(phy_addr, PHY_BMCR, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= PHY_BMCR_AUTON; + dm644x_eth_phy_write(phy_addr, PHY_BMCR, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!dm644x_eth_phy_read(phy_addr, PHY_BMSR, &tmp)) + return(0); + + if (!(tmp & PHY_BMSR_AUTN_COMP)) + return(0); + + return(gen_get_link_speed(phy_addr)); +} +/* End of generic PHY functions */ + + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +static int dm644x_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value) +{ + return(dm644x_eth_phy_read(addr, reg, value) ? 0 : 1); +} + +static int dm644x_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value) +{ + return(dm644x_eth_phy_write(addr, reg, value) ? 0 : 1); +} + +int dm644x_eth_miiphy_initialize(bd_t *bis) +{ + miiphy_register(phy.name, dm644x_mii_phy_read, dm644x_mii_phy_write); + + return(1); +} +#endif + +/* + * This function initializes the emac hardware. It does NOT initialize + * EMAC modules power or pin multiplexors, that is done by board_init() + * much earlier in bootup process. Returns 1 on success, 0 otherwise. + */ +static int dm644x_eth_hw_init(void) +{ + u_int32_t phy_id; + u_int16_t tmp; + int i; + + dm644x_eth_mdio_enable(); + + for (i = 0; i < 256; i++) { + if (adap_mdio->ALIVE) + break; + udelay(10); + } + + if (i >= 256) { + printf("No ETH PHY detected!!!\n"); + return(0); + } + + /* Find if a PHY is connected and get it's address */ + if (!dm644x_eth_phy_detect()) + return(0); + + /* Get PHY ID and initialize phy_ops for a detected PHY */ + if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id = (tmp << 16) & 0xffff0000; + + if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) { + active_phy_addr = 0xff; + return(0); + } + + phy_id |= tmp & 0x0000ffff; + + switch (phy_id) { + case PHY_LXT972: + sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr); + phy.init = lxt972_init_phy; + phy.is_phy_connected = lxt972_is_phy_connected; + phy.get_link_speed = lxt972_get_link_speed; + phy.auto_negotiate = lxt972_auto_negotiate; + break; + case PHY_DP83848: + sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr); + phy.init = dp83848_init_phy; + phy.is_phy_connected = dp83848_is_phy_connected; + phy.get_link_speed = dp83848_get_link_speed; + phy.auto_negotiate = dp83848_auto_negotiate; + break; + default: + sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr); + phy.init = gen_init_phy; + phy.is_phy_connected = gen_is_phy_connected; + phy.get_link_speed = gen_get_link_speed; + phy.auto_negotiate = gen_auto_negotiate; + } + + return(1); +} + + +/* Eth device open */ +static int dm644x_eth_open(void) +{ + dv_reg_p addr; + u_int32_t clkdiv, cnt; + volatile emac_desc *rx_desc; + + debug_emac("+ emac_open\n"); + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + while (adap_emac->SOFTRESET != 0) {;} + adap_ewrap->EWCTL = 0; + for (cnt = 0; cnt < 5; cnt++) { + clkdiv = adap_ewrap->EWCTL; + } + + rx_desc = emac_rx_desc; + + adap_emac->TXCONTROL = 0x01; + adap_emac->RXCONTROL = 0x01; + + /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */ + /* Using channel 0 only - other channels are disabled */ + adap_emac->MACINDEX = 0; + adap_emac->MACADDRHI = + (dm644x_eth_mac_addr[3] << 24) | + (dm644x_eth_mac_addr[2] << 16) | + (dm644x_eth_mac_addr[1] << 8) | + (dm644x_eth_mac_addr[0]); + adap_emac->MACADDRLO = + (dm644x_eth_mac_addr[5] << 8) | + (dm644x_eth_mac_addr[4]); + + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Set source MAC address - REQUIRED */ + adap_emac->MACSRCADDRHI = + (dm644x_eth_mac_addr[3] << 24) | + (dm644x_eth_mac_addr[2] << 16) | + (dm644x_eth_mac_addr[1] << 8) | + (dm644x_eth_mac_addr[0]); + adap_emac->MACSRCADDRLO = + (dm644x_eth_mac_addr[4] << 8) | + (dm644x_eth_mac_addr[5]); + + /* Set DMA 8 TX / 8 RX Head pointers to 0 */ + addr = &adap_emac->TX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + addr = &adap_emac->RX0HDP; + for(cnt = 0; cnt < 16; cnt++) + *addr++ = 0; + + /* Clear Statistics (do this before setting MacControl register) */ + addr = &adap_emac->RXGOODFRAMES; + for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++) + *addr++ = 0; + + /* No multicast addressing */ + adap_emac->MACHASH1 = 0; + adap_emac->MACHASH2 = 0; + + /* Create RX queue and set receive process in place */ + emac_rx_active_head = emac_rx_desc; + for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) { + rx_desc->next = (u_int32_t)(rx_desc + 1); + rx_desc->buffer = &emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; + rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_desc++; + } + + /* Set the last descriptor's "next" parameter to 0 to end the RX desc list */ + rx_desc--; + rx_desc->next = 0; + emac_rx_active_tail = rx_desc; + emac_rx_queue_active = 1; + + /* Enable TX/RX */ + adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE; + adap_emac->RXBUFFEROFFSET = 0; + + /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */ + adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN; + + /* Enable ch 0 only */ + adap_emac->RXUNICASTSET = 0x01; + + /* Enable MII interface and Full duplex mode */ + adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE); + + /* Init MDIO & get link state */ + clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1; + adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT); + + if (!phy.get_link_speed(active_phy_addr)) + return(0); + + /* Start receive process */ + adap_emac->RX0HDP = (u_int32_t)emac_rx_desc; + + debug_emac("- emac_open\n"); + + return(1); +} + +/* EMAC Channel Teardown */ +static void dm644x_eth_ch_teardown(int ch) +{ + dv_reg dly = 0xff; + dv_reg cnt; + + debug_emac("+ emac_ch_teardown\n"); + + if (ch == EMAC_CH_TX) { + /* Init TX channel teardown */ + adap_emac->TXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->TX0CP) { + /* Wait here for Tx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->TX0CP = cnt; + adap_emac->TX0HDP = 0; + } else { + /* Init RX channel teardown */ + adap_emac->RXTEARDOWN = 1; + for(cnt = 0; cnt != 0xfffffffc; cnt = adap_emac->RX0CP) { + /* Wait here for Rx teardown completion interrupt to occur + * Note: A task delay can be called here to pend rather than + * occupying CPU cycles - anyway it has been found that teardown + * takes very few cpu cycles and does not affect functionality */ + dly--; + udelay(1); + if (dly == 0) + break; + } + adap_emac->RX0CP = cnt; + adap_emac->RX0HDP = 0; + } + + debug_emac("- emac_ch_teardown\n"); +} + +/* Eth device close */ +static int dm644x_eth_close(void) +{ + debug_emac("+ emac_close\n"); + + dm644x_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */ + dm644x_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */ + + /* Reset EMAC module and disable interrupts in wrapper */ + adap_emac->SOFTRESET = 1; + adap_ewrap->EWCTL = 0; + + debug_emac("- emac_close\n"); + return(1); +} + +static int tx_send_loop = 0; + +/* + * This function sends a single packet on the network and returns + * positive number (number of bytes transmitted) or negative for error + */ +static int dm644x_eth_send_packet(volatile void *packet, int length) +{ + int ret_status = -1; + tx_send_loop = 0; + + /* Return error if no link */ + if (!phy.get_link_speed(active_phy_addr)) + { + printf("WARN: emac_send_packet: No link\n"); + return (ret_status); + } + + /* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */ + if (length < EMAC_MIN_ETHERNET_PKT_SIZE) + { + length = EMAC_MIN_ETHERNET_PKT_SIZE; + } + + /* Populate the TX descriptor */ + emac_tx_desc->next = 0; + emac_tx_desc->buffer = (u_int8_t *)packet; + emac_tx_desc->buff_off_len = (length & 0xffff); + emac_tx_desc->pkt_flag_len = ((length & 0xffff) | + EMAC_CPPI_SOP_BIT | + EMAC_CPPI_OWNERSHIP_BIT | + EMAC_CPPI_EOP_BIT); + /* Send the packet */ + adap_emac->TX0HDP = (unsigned int)emac_tx_desc; + + /* Wait for packet to complete or link down */ + while (1) { + if (!phy.get_link_speed(active_phy_addr)) { + dm644x_eth_ch_teardown(EMAC_CH_TX); + return (ret_status); + } + if (adap_emac->TXINTSTATRAW & 0x01) { + ret_status = length; + break; + } + tx_send_loop++; + } + + return(ret_status); +} + +/* + * This function handles receipt of a packet from the network + */ +static int dm644x_eth_rcv_packet(void) +{ + volatile emac_desc *rx_curr_desc; + volatile emac_desc *curr_desc; + volatile emac_desc *tail_desc; + int status, ret = -1; + + rx_curr_desc = emac_rx_active_head; + status = rx_curr_desc->pkt_flag_len; + if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) { + if (status & EMAC_CPPI_RX_ERROR_FRAME) { + /* Error in packet - discard it and requeue desc */ + printf("WARN: emac_rcv_pkt: Error in packet\n"); + } else { + NetReceive(rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff)); + ret = rx_curr_desc->buff_off_len & 0xffff; + } + + /* Ack received packet descriptor */ + adap_emac->RX0CP = (unsigned int)rx_curr_desc; + curr_desc = rx_curr_desc; + emac_rx_active_head = (volatile emac_desc *)rx_curr_desc->next; + + if (status & EMAC_CPPI_EOQ_BIT) { + if (emac_rx_active_head) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + } else { + emac_rx_queue_active = 0; + printf("INFO:emac_rcv_packet: RX Queue not active\n"); + } + } + + /* Recycle RX descriptor */ + rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE; + rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT; + rx_curr_desc->next = 0; + + if (emac_rx_active_head == 0) { + printf("INFO: emac_rcv_pkt: active queue head = 0\n"); + emac_rx_active_head = curr_desc; + emac_rx_active_tail = curr_desc; + if (emac_rx_queue_active != 0) { + adap_emac->RX0HDP = (unsigned int)emac_rx_active_head; + printf("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n"); + emac_rx_queue_active = 1; + } + } else { + tail_desc = emac_rx_active_tail; + emac_rx_active_tail = curr_desc; + tail_desc->next = (unsigned int)curr_desc; + status = tail_desc->pkt_flag_len; + if (status & EMAC_CPPI_EOQ_BIT) { + adap_emac->RX0HDP = (unsigned int)curr_desc; + status &= ~EMAC_CPPI_EOQ_BIT; + tail_desc->pkt_flag_len = status; + } + } + return(ret); + } + return(0); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_TI_EMAC */ diff --git a/cpu/arm926ejs/davinci/i2c.c b/cpu/arm926ejs/davinci/i2c.c new file mode 100644 index 0000000..af9dc03 --- /dev/null +++ b/cpu/arm926ejs/davinci/i2c.c @@ -0,0 +1,351 @@ +/* + * TI DaVinci (TMS320DM644x) I2C driver. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#ifdef CONFIG_DRIVER_DAVINCI_I2C + +#include <i2c.h> +#include <asm/arch/hardware.h> +#include <asm/arch/i2c_defs.h> + +#define CHECK_NACK() \ + do {\ + if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\ + REG(I2C_CON) = 0;\ + return(1);\ + }\ + } while (0) + + +static int wait_for_bus(void) +{ + int stat, timeout; + + REG(I2C_STAT) = 0xffff; + + for (timeout = 0; timeout < 10; timeout++) { + if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) { + REG(I2C_STAT) = 0xffff; + return(0); + } + + REG(I2C_STAT) = stat; + udelay(50000); + } + + REG(I2C_STAT) = 0xffff; + return(1); +} + + +static int poll_i2c_irq(int mask) +{ + int stat, timeout; + + for (timeout = 0; timeout < 10; timeout++) { + udelay(1000); + stat = REG(I2C_STAT); + if (stat & mask) { + return(stat); + } + } + + REG(I2C_STAT) = 0xffff; + return(stat | I2C_TIMEOUT); +} + + +void flush_rx(void) +{ + int dummy; + + while (1) { + if (!(REG(I2C_STAT) & I2C_STAT_RRDY)) + break; + + dummy = REG(I2C_DRR); + REG(I2C_STAT) = I2C_STAT_RRDY; + udelay(1000); + } +} + + +void i2c_init(int speed, int slaveadd) +{ + u_int32_t div, psc; + + if (REG(I2C_CON) & I2C_CON_EN) { + REG(I2C_CON) = 0; + udelay (50000); + } + + psc = 2; + div = (CFG_HZ_CLOCK / ((psc + 1) * speed)) - 10; /* SCLL + SCLH */ + REG(I2C_PSC) = psc; /* 27MHz / (2 + 1) = 9MHz */ + REG(I2C_SCLL) = (div * 50) / 100; /* 50% Duty */ + REG(I2C_SCLH) = div - REG(I2C_SCLL); + + REG(I2C_OA) = slaveadd; + REG(I2C_CNT) = 0; + + /* Interrupts must be enabled or I2C module won't work */ + REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE | + I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE; + + /* Now enable I2C controller (get it out of reset) */ + REG(I2C_CON) = I2C_CON_EN; + + udelay(1000); +} + + +int i2c_probe(u_int8_t chip) +{ + int rc = 1; + + if (chip == REG(I2C_OA)) { + return(rc); + } + + REG(I2C_CON) = 0; + if (wait_for_bus()) {return(1);} + + /* try to read one byte from current (or only) address */ + REG(I2C_CNT) = 1; + REG(I2C_SA) = chip; + REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP); + udelay (50000); + + if (!(REG(I2C_STAT) & I2C_STAT_NACK)) { + rc = 0; + flush_rx(); + REG(I2C_STAT) = 0xffff; + } else { + REG(I2C_STAT) = 0xffff; + REG(I2C_CON) |= I2C_CON_STP; + udelay(20000); + if (wait_for_bus()) {return(1);} + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + return(rc); +} + + +int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) +{ + u_int32_t tmp; + int i; + + if ((alen < 0) || (alen > 2)) { + printf("%s(): bogus address length %x\n", __FUNCTION__, alen); + return(1); + } + + if (wait_for_bus()) {return(1);} + + if (alen != 0) { + /* Start address phase */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX; + REG(I2C_CNT) = alen; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + switch (alen) { + case 2: + /* Send address MSByte */ + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = (addr >> 8) & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + /* No break, fall through */ + case 1: + /* Send address LSByte */ + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = addr & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_ARDY)) { + REG(I2C_CON) = 0; + return(1); + } + } + } + + /* Address phase is over, now read 'len' bytes and stop */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP; + REG(I2C_CNT) = len & 0xffff; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + for (i = 0; i < len; i++) { + tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR); + + CHECK_NACK(); + + if (tmp & I2C_STAT_RRDY) { + buf[i] = REG(I2C_DRR); + } else { + REG(I2C_CON) = 0; + return(1); + } + } + + tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_SCD)) { + REG(I2C_CON) = 0; + return(1); + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + REG(I2C_CON) = 0; + + return(0); +} + + +int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len) +{ + u_int32_t tmp; + int i; + + if ((alen < 0) || (alen > 2)) { + printf("%s(): bogus address length %x\n", __FUNCTION__, alen); + return(1); + } + if (len < 0) { + printf("%s(): bogus length %x\n", __FUNCTION__, len); + return(1); + } + + if (wait_for_bus()) {return(1);} + + /* Start address phase */ + tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP; + REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen; + REG(I2C_SA) = chip; + REG(I2C_CON) = tmp; + + switch (alen) { + case 2: + /* Send address MSByte */ + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = (addr >> 8) & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + /* No break, fall through */ + case 1: + /* Send address LSByte */ + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = addr & 0xff; + } else { + REG(I2C_CON) = 0; + return(1); + } + } + + for (i = 0; i < len; i++) { + tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK); + + CHECK_NACK(); + + if (tmp & I2C_STAT_XRDY) { + REG(I2C_DXR) = buf[i]; + } else { + return(1); + } + } + + tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK); + + CHECK_NACK(); + + if (!(tmp & I2C_STAT_SCD)) { + REG(I2C_CON) = 0; + return(1); + } + + flush_rx(); + REG(I2C_STAT) = 0xffff; + REG(I2C_CNT) = 0; + REG(I2C_CON) = 0; + + return(0); +} + + +u_int8_t i2c_reg_read(u_int8_t chip, u_int8_t reg) +{ + u_int8_t tmp; + + i2c_read(chip, reg, 1, &tmp, 1); + return(tmp); +} + + +void i2c_reg_write(u_int8_t chip, u_int8_t reg, u_int8_t val) +{ + u_int8_t tmp; + + i2c_write(chip, reg, 1, &tmp, 1); +} + +#endif /* CONFIG_DRIVER_DAVINCI_I2C */ diff --git a/cpu/arm926ejs/davinci/lowlevel_init.S b/cpu/arm926ejs/davinci/lowlevel_init.S new file mode 100644 index 0000000..a87c112 --- /dev/null +++ b/cpu/arm926ejs/davinci/lowlevel_init.S @@ -0,0 +1,707 @@ +/* + * Low-level board setup code for TI DaVinci SoC based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Partially based on TI sources, original copyrights follow: + */ + +/* + * Board specific setup info + * + * (C) Copyright 2003 + * Texas Instruments, <www.ti.com> + * Kshitij Gupta <Kshitij@ti.com> + * + * Modified for OMAP 1610 H2 board by Nishant Kamat, Jan 2004 + * + * Modified for OMAP 5912 OSK board by Rishi Bhattacharya, Apr 2004 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Rishi Bhattacharya, Apr 2005 + * See file CREDITS for list of people who contributed to this + * project. + * + * Modified for DV-EVM board by Swaminathan S, Nov 2005 + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> + +.globl lowlevel_init +lowlevel_init: + + /*-------------------------------------------------------* + * Mask all IRQs by setting all bits in the EINT default * + *-------------------------------------------------------*/ + mov r1, $0 + ldr r0, =EINT_ENABLE0 + str r1, [r0] + ldr r0, =EINT_ENABLE1 + str r1, [r0] + + /*------------------------------------------------------* + * Put the GEM in reset * + *------------------------------------------------------*/ + + /* Put the GEM in reset */ + ldr r8, PSC_GEM_FLAG_CLEAR + ldr r6, MDCTL_GEM + ldr r7, [r6] + and r7, r7, r8 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x02 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStopGem: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x02 + bne checkStatClkStopGem + + /* Check for GEM Reset Completion */ +checkGemStatClkStop: + ldr r6, MDSTAT_GEM + ldr r7, [r6] + ands r7, r7, $0x100 + bne checkGemStatClkStop + + /* Do this for enabling a WDT initiated reset this is a workaround + for a chip bug. Not required under normal situations */ + ldr r6, P1394 + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * Enable L1 & L2 Memories in Fast mode * + *------------------------------------------------------*/ + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, MMARG_BRF0 + ldr r10, MMARG_BRF0_VAL + str r10, [r6] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /*------------------------------------------------------* + * DDR2 PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r10, $0 + ldr r6, PLL2_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r10, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 +WaitPPL2Loop: + subs r10, r10, $1 + bne WaitPPL2Loop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL2_PLLM + mov r2, $0x17 /* 162 MHz */ + str r2, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV2 + mov r3, $0x01 + str r3, [r6] + + /* Program the PLL2 Divisor Value */ + ldr r6, PLL2_DIV1 + mov r4, $0x0b /* 54 MHz */ + str r4, [r6] + + /* PLL2 DIV2 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV2 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop_0: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop_0 + + /* PLL2 DIV1 MMR */ + ldr r8, PLL2_DIV_MASK + ldr r6, PLL2_DIV1 + ldr r9, [r6] + and r8, r8, r9 + mov r9, $0x01 + mov r9, r9, lsl $15 + orr r8, r8, r9 + str r8, [r6] + + /* Program the GOSET bit to take new divider values */ + ldr r6, PLL2_PLLCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Wait for Done */ + ldr r6, PLL2_PLLSTAT +doneLoop: + ldr r7, [r6] + ands r7, r7, $0x01 + bne doneLoop + + /* Wait for PLL to Reset Properly */ + mov r10, $0x218 +ResetPPL2Loop: + subs r10, r10, $1 + bne ResetPPL2Loop + + /* Bring PLL out of Reset */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT +PLL2Lock: + subs r10, r10, $1 + bne PLL2Lock + + /* Enable the PLL */ + ldr r6, PLL2_CTL + ldr r8, [r6] + orr r8, r8, $0x01 + str r8, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $0x1f + cmp r7, $0x03 + bne checkDDRStatClkStop + + /*------------------------------------------------------* + * Program DDR2 MMRs for 162MHz Setting * + *------------------------------------------------------*/ + + /* Program PHY Control Register */ + ldr r6, DDRCTL + ldr r7, DDRCTL_VAL + str r7, [r6] + + /* Program SDRAM Bank Config Register */ + ldr r6, SDCFG + ldr r7, SDCFG_VAL + str r7, [r6] + + /* Program SDRAM TIM-0 Config Register */ + ldr r6, SDTIM0 + ldr r7, SDTIM0_VAL_162MHz + str r7, [r6] + + /* Program SDRAM TIM-1 Config Register */ + ldr r6, SDTIM1 + ldr r7, SDTIM1_VAL_162MHz + str r7, [r6] + + /* Program the SDRAM Bank Config Control Register */ + ldr r10, MASK_VAL + ldr r8, SDCFG + ldr r9, SDCFG_VAL + and r9, r9, r10 + str r9, [r8] + + /* Program SDRAM SDREF Config Register */ + ldr r6, SDREF + ldr r7, SDREF_VAL + str r7, [r6] + + /*------------------------------------------------------* + * Issue Soft Reset to DDR Module * + *------------------------------------------------------*/ + + /* Issue a Dummy DDR2 read/write */ + ldr r8, DDR2_START_ADDR + ldr r7, DUMMY_VAL + str r7, [r8] + ldr r7, [r8] + + /* Shut down the DDR2 LPSC Module */ + ldr r8, PSC_FLAG_CLEAR + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + and r7, r7, r8 + orr r7, r7, $0x01 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkStop2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkStop2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkStop2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $0x1f + cmp r7, $0x01 + bne checkDDRStatClkStop2 + + /*------------------------------------------------------* + * Turn DDR2 Controller Clocks On * + *------------------------------------------------------*/ + + /* Enable the DDR2 LPSC Module */ + ldr r6, MDCTL_DDR2 + ldr r7, [r6] + orr r7, r7, $0x03 + str r7, [r6] + + /* Enable the Power Domain Transition Command */ + ldr r6, PTCMD + ldr r7, [r6] + orr r7, r7, $0x01 + str r7, [r6] + + /* Check for Transition Complete(PTSTAT) */ +checkStatClkEn2: + ldr r6, PTSTAT + ldr r7, [r6] + ands r7, r7, $0x01 + bne checkStatClkEn2 + + /* Check for DDR2 Controller Enable Completion */ +checkDDRStatClkEn2: + ldr r6, MDSTAT_DDR2 + ldr r7, [r6] + and r7, r7, $0x1f + cmp r7, $0x03 + bne checkDDRStatClkEn2 + + /* DDR Writes and Reads */ + ldr r6, CFGTEST + mov r3, $0x01 + str r3, [r6] + + /*------------------------------------------------------* + * System PLL Initialization * + *------------------------------------------------------*/ + + /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */ + mov r2, $0 + ldr r6, PLL1_CTL + ldr r7, PLL_CLKSRC_MASK + ldr r8, [r6] + and r8, r8, r7 + mov r9, r2, lsl $8 + orr r8, r8, r9 + str r8, [r6] + + /* Select the PLLEN source */ + ldr r7, PLL_ENSRC_MASK + and r8, r8, r7 + str r8, [r6] + + /* Bypass the PLL */ + ldr r7, PLL_BYPASS_MASK + and r8, r8, r7 + str r8, [r6] + + /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */ + mov r10, $0x20 + +WaitLoop: + subs r10, r10, $1 + bne WaitLoop + + /* Reset the PLL */ + ldr r7, PLL_RESET_MASK + and r8, r8, r7 + str r8, [r6] + + /* Disable the PLL */ + orr r8, r8, $0x10 + str r8, [r6] + + /* Power up the PLL */ + ldr r7, PLL_PWRUP_MASK + and r8, r8, r7 + str r8, [r6] + + /* Enable the PLL from Disable Mode */ + ldr r7, PLL_DISABLE_ENABLE_MASK + and r8, r8, r7 + str r8, [r6] + + /* Program the PLL Multiplier */ + ldr r6, PLL1_PLLM + mov r3, $0x15 /* For 594MHz */ + str r3, [r6] + + /* Wait for PLL to Reset Properly */ + mov r10, $0xff + +ResetLoop: + subs r10, r10, $1 + bne ResetLoop + + /* Bring PLL out of Reset */ + ldr r6, PLL1_CTL + orr r8, r8, $0x08 + str r8, [r6] + + /* Wait for PLL to Lock */ + ldr r10, PLL_LOCK_COUNT + +PLL1Lock: + subs r10, r10, $1 + bne PLL1Lock + + /* Enable the PLL */ + orr r8, r8, $0x01 + str r8, [r6] + + nop + nop + nop + nop + + /*------------------------------------------------------* + * AEMIF configuration for NOR Flash (double check) * + *------------------------------------------------------*/ + ldr r0, _PINMUX0 + ldr r1, _DEV_SETTING + str r1, [r0] + + ldr r0, WAITCFG + ldr r1, WAITCFG_VAL + ldr r2, [r0] + orr r2, r2, r1 + str r2, [r0] + + ldr r0, ACFG3 + ldr r1, ACFG3_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG4 + ldr r1, ACFG4_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + ldr r0, ACFG5 + ldr r1, ACFG5_VAL + ldr r2, [r0] + and r1, r2, r1 + str r1, [r0] + + /*--------------------------------------* + * VTP manual Calibration * + *--------------------------------------*/ + ldr r0, VTPIOCR + ldr r1, VTP_MMR0 + str r1, [r0] + + ldr r0, VTPIOCR + ldr r1, VTP_MMR1 + str r1, [r0] + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTPLock: + subs r10, r10, $1 + bne VTPLock + + ldr r6, DFT_ENABLE + mov r10, $0x01 + str r10, [r6] + + ldr r6, DDRVTPR + ldr r7, [r6] + and r7, r7, $0x1f + and r8, r7, $0x3e0 + orr r8, r7, r8 + ldr r7, VTP_RECAL + orr r8, r7, r8 + ldr r7, VTP_EN + orr r8, r7, r8 + str r8, [r0] + + + /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */ + ldr r10, VTP_LOCK_COUNT +VTP1Lock: + subs r10, r10, $1 + bne VTP1Lock + + ldr r1, [r0] + ldr r2, VTP_MASK + and r2, r1, r2 + str r2, [r0] + + ldr r6, DFT_ENABLE + mov r10, $0 + str r10, [r6] + + /* + * Call board-specific lowlevel init. + * That MUST be present and THAT returns + * back to arch calling code with "mov pc, lr." + */ + b dv_board_init + +.ltorg + +_PINMUX0: + .word 0x01c40000 /* Device Configuration Registers */ +_PINMUX1: + .word 0x01c40004 /* Device Configuration Registers */ + +_DEV_SETTING: + .word 0x00000c1f + +WAITCFG: + .word 0x01e00004 +WAITCFG_VAL: + .word 0 +ACFG3: + .word 0x01e00014 +ACFG3_VAL: + .word 0x3ffffffd +ACFG4: + .word 0x01e00018 +ACFG4_VAL: + .word 0x3ffffffd +ACFG5: + .word 0x01e0001c +ACFG5_VAL: + .word 0x3ffffffd + +MDCTL_DDR2: + .word 0x01c41a34 +MDSTAT_DDR2: + .word 0x01c41834 + +PTCMD: + .word 0x01c41120 +PTSTAT: + .word 0x01c41128 + +EINT_ENABLE0: + .word 0x01c48018 +EINT_ENABLE1: + .word 0x01c4801c + +PSC_FLAG_CLEAR: + .word 0xffffffe0 +PSC_GEM_FLAG_CLEAR: + .word 0xfffffeff + +/* DDR2 MMR & CONFIGURATION VALUES, 162 MHZ clock */ +DDRCTL: + .word 0x200000e4 +DDRCTL_VAL: + .word 0x50006405 +SDREF: + .word 0x2000000c +SDREF_VAL: + .word 0x000005c3 +SDCFG: + .word 0x20000008 +SDCFG_VAL: +#ifdef DDR_4BANKS + .word 0x00178622 +#elif defined DDR_8BANKS + .word 0x00178632 +#else +#error "Unknown DDR configuration!!!" +#endif +SDTIM0: + .word 0x20000010 +SDTIM0_VAL_162MHz: + .word 0x28923211 +SDTIM1: + .word 0x20000014 +SDTIM1_VAL_162MHz: + .word 0x0016c722 +VTPIOCR: + .word 0x200000f0 /* VTP IO Control register */ +DDRVTPR: + .word 0x01c42030 /* DDR VPTR MMR */ +VTP_MMR0: + .word 0x201f +VTP_MMR1: + .word 0xa01f +DFT_ENABLE: + .word 0x01c4004c +VTP_LOCK_COUNT: + .word 0x5b0 +VTP_MASK: + .word 0xffffdfff +VTP_RECAL: + .word 0x40000 +VTP_EN: + .word 0x02000 +CFGTEST: + .word 0x80010000 +MASK_VAL: + .word 0x00000fff + +/* GEM Power Up & LPSC Control Register */ +MDCTL_GEM: + .word 0x01c41a9c +MDSTAT_GEM: + .word 0x01c4189c + +/* For WDT reset chip bug */ +P1394: + .word 0x01c41a20 + +PLL_CLKSRC_MASK: + .word 0xfffffeff /* Mask the Clock Mode bit */ +PLL_ENSRC_MASK: + .word 0xffffffdf /* Select the PLLEN source */ +PLL_BYPASS_MASK: + .word 0xfffffffe /* Put the PLL in BYPASS */ +PLL_RESET_MASK: + .word 0xfffffff7 /* Put the PLL in Reset Mode */ +PLL_PWRUP_MASK: + .word 0xfffffffd /* PLL Power up Mask Bit */ +PLL_DISABLE_ENABLE_MASK: + .word 0xffffffef /* Enable the PLL from Disable */ +PLL_LOCK_COUNT: + .word 0x2000 + +/* PLL1-SYSTEM PLL MMRs */ +PLL1_CTL: + .word 0x01c40900 +PLL1_PLLM: + .word 0x01c40910 + +/* PLL2-SYSTEM PLL MMRs */ +PLL2_CTL: + .word 0x01c40d00 +PLL2_PLLM: + .word 0x01c40d10 +PLL2_DIV1: + .word 0x01c40d18 +PLL2_DIV2: + .word 0x01c40d1c +PLL2_PLLCMD: + .word 0x01c40d38 +PLL2_PLLSTAT: + .word 0x01c40d3c +PLL2_DIV_MASK: + .word 0xffff7fff + +MMARG_BRF0: + .word 0x01c42010 /* BRF margin mode 0 (R/W)*/ +MMARG_BRF0_VAL: + .word 0x00444400 + +DDR2_START_ADDR: + .word 0x80000000 +DUMMY_VAL: + .word 0xa55aa55a diff --git a/cpu/arm926ejs/davinci/lxt972.c b/cpu/arm926ejs/davinci/lxt972.c new file mode 100644 index 0000000..6eeb6e5 --- /dev/null +++ b/cpu/arm926ejs/davinci/lxt972.c @@ -0,0 +1,142 @@ +/* + * Intel LXT971/LXT972 PHY Driver for TI DaVinci + * (TMS320DM644x) based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * -------------------------------------------------------- + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <net.h> +#include <lxt971a.h> +#include <asm/arch/emac_defs.h> + +#ifdef CONFIG_DRIVER_TI_EMAC + +#ifdef CONFIG_CMD_NET + +int lxt972_is_phy_connected(int phy_addr) +{ + u_int16_t id1, id2; + + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID1, &id1)) + return(0); + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID2, &id2)) + return(0); + + if ((id1 == (0x0013)) && ((id2 & 0xfff0) == 0x78e0)) + return(1); + + return(0); +} + +int lxt972_get_link_speed(int phy_addr) +{ + u_int16_t stat1, tmp; + volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR; + + if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_STAT2, &stat1)) + return(0); + + if (!(stat1 & PHY_LXT971_STAT2_LINK)) /* link up? */ + return(0); + + if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + tmp |= PHY_LXT971_DIG_CFG_MII_DRIVE; + + dm644x_eth_phy_write(phy_addr, PHY_LXT971_DIG_CFG, tmp); + /* Read back */ + if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp)) + return(0); + + + /* Speed doesn't matter, there is no setting for it in EMAC... */ + if (stat1 & PHY_LXT971_STAT2_100BTX) { + if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } else { + if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) { + /* set DM644x EMAC for Full Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE; + } else { + /*set DM644x EMAC for Half Duplex */ + emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE; + } + + return(1); + } + + return(0); +} + + +int lxt972_init_phy(int phy_addr) +{ + int ret = 1; + + if (!lxt972_get_link_speed(phy_addr)) { + /* Try another time */ + ret = lxt972_get_link_speed(phy_addr); + } + + /* Disable PHY Interrupts */ + dm644x_eth_phy_write(phy_addr, PHY_LXT971_INT_ENABLE, 0); + + return(ret); +} + + +int lxt972_auto_negotiate(int phy_addr) +{ + u_int16_t tmp; + + + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_CTRL, &tmp)) + return(0); + + /* Restart Auto_negotiation */ + tmp |= PHY_COMMON_CTRL_RES_AUTO; + dm644x_eth_phy_write(phy_addr, PHY_COMMON_CTRL, tmp); + + /*check AutoNegotiate complete */ + udelay (10000); + if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_STAT, &tmp)) + return(0); + + if (!(tmp & PHY_COMMON_STAT_AN_COMP)) + return(0); + + return (lxt972_get_link_speed(phy_addr)); +} + +#endif /* CONFIG_CMD_NET */ + +#endif /* CONFIG_DRIVER_ETHER */ diff --git a/cpu/arm926ejs/davinci/nand.c b/cpu/arm926ejs/davinci/nand.c new file mode 100644 index 0000000..127be9f --- /dev/null +++ b/cpu/arm926ejs/davinci/nand.c @@ -0,0 +1,389 @@ +/* + * NAND driver for TI DaVinci based boards. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * Based on Linux DaVinci NAND driver by TI. Original copyright follows: + */ + +/* + * + * linux/drivers/mtd/nand/nand_davinci.c + * + * NAND Flash Driver + * + * Copyright (C) 2006 Texas Instruments. + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + * + * Overview: + * This is a device driver for the NAND flash device found on the + * DaVinci board which utilizes the Samsung k9k2g08 part. + * + Modifications: + ver. 1.0: Feb 2005, Vinod/Sudhakar + - + * + */ + +#include <common.h> + +#ifdef CFG_USE_NAND +#if !defined(CFG_NAND_LEGACY) + +#include <nand.h> +#include <asm/arch/nand_defs.h> +#include <asm/arch/emif_defs.h> + +extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE]; + +static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd) +{ + struct nand_chip *this = mtd->priv; + u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W; + + IO_ADDR_W &= ~(MASK_ALE|MASK_CLE); + + switch (cmd) { + case NAND_CTL_SETCLE: + IO_ADDR_W |= MASK_CLE; + break; + case NAND_CTL_SETALE: + IO_ADDR_W |= MASK_ALE; + break; + } + + this->IO_ADDR_W = (void *)IO_ADDR_W; +} + +/* Set WP on deselect, write enable on select */ +static void nand_davinci_select_chip(struct mtd_info *mtd, int chip) +{ +#define GPIO_SET_DATA01 0x01c67018 +#define GPIO_CLR_DATA01 0x01c6701c +#define GPIO_NAND_WP (1 << 4) +#ifdef SONATA_BOARD_GPIOWP + if (chip < 0) { + REG(GPIO_CLR_DATA01) |= GPIO_NAND_WP; + } else { + REG(GPIO_SET_DATA01) |= GPIO_NAND_WP; + } +#endif +} + +#ifdef CFG_NAND_HW_ECC +#ifdef CFG_NAND_LARGEPAGE +static struct nand_oobinfo davinci_nand_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 12, + .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58}, + .oobfree = { {2, 6}, {12, 12}, {28, 12}, {44, 12}, {60, 4} } +}; +#elif defined(CFG_NAND_SMALLPAGE) +static struct nand_oobinfo davinci_nand_oobinfo = { + .useecc = MTD_NANDECC_AUTOPLACE, + .eccbytes = 3, + .eccpos = {0, 1, 2}, + .oobfree = { {6, 2}, {8, 8} } +}; +#else +#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" +#endif + +static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode) +{ + emifregs emif_addr; + int dummy; + + emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + dummy = emif_addr->NANDF1ECC; + dummy = emif_addr->NANDF2ECC; + dummy = emif_addr->NANDF3ECC; + dummy = emif_addr->NANDF4ECC; + + emif_addr->NANDFCR |= (1 << 8); +} + +static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region) +{ + u_int32_t ecc = 0; + emifregs emif_base_addr; + + emif_base_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + if (region == 1) + ecc = emif_base_addr->NANDF1ECC; + else if (region == 2) + ecc = emif_base_addr->NANDF2ECC; + else if (region == 3) + ecc = emif_base_addr->NANDF3ECC; + else if (region == 4) + ecc = emif_base_addr->NANDF4ECC; + + return(ecc); +} + +static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) +{ + u_int32_t tmp; + int region, n; + struct nand_chip *this = mtd->priv; + + n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; + + region = 1; + while (n--) { + tmp = nand_davinci_readecc(mtd, region); + *ecc_code++ = tmp; + *ecc_code++ = tmp >> 16; + *ecc_code++ = ((tmp >> 8) & 0x0f) | ((tmp >> 20) & 0xf0); + region++; + } + return(0); +} + +static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf) +{ + u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8); + + ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp)); + ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp)); + ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp)); +} + +static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t *ecc_calc, u_int8_t *page_data) +{ + u_int32_t i; + u_int8_t tmp0_bit[8], tmp1_bit[8], tmp2_bit[8]; + u_int8_t comp0_bit[8], comp1_bit[8], comp2_bit[8]; + u_int8_t ecc_bit[24]; + u_int8_t ecc_sum = 0; + u_int8_t find_bit = 0; + u_int32_t find_byte = 0; + int is_ecc_ff; + + is_ecc_ff = ((*ecc_nand == 0xff) && (*(ecc_nand + 1) == 0xff) && (*(ecc_nand + 2) == 0xff)); + + nand_davinci_gen_true_ecc(ecc_nand); + nand_davinci_gen_true_ecc(ecc_calc); + + for (i = 0; i <= 2; i++) { + *(ecc_nand + i) = ~(*(ecc_nand + i)); + *(ecc_calc + i) = ~(*(ecc_calc + i)); + } + + for (i = 0; i < 8; i++) { + tmp0_bit[i] = *ecc_nand % 2; + *ecc_nand = *ecc_nand / 2; + } + + for (i = 0; i < 8; i++) { + tmp1_bit[i] = *(ecc_nand + 1) % 2; + *(ecc_nand + 1) = *(ecc_nand + 1) / 2; + } + + for (i = 0; i < 8; i++) { + tmp2_bit[i] = *(ecc_nand + 2) % 2; + *(ecc_nand + 2) = *(ecc_nand + 2) / 2; + } + + for (i = 0; i < 8; i++) { + comp0_bit[i] = *ecc_calc % 2; + *ecc_calc = *ecc_calc / 2; + } + + for (i = 0; i < 8; i++) { + comp1_bit[i] = *(ecc_calc + 1) % 2; + *(ecc_calc + 1) = *(ecc_calc + 1) / 2; + } + + for (i = 0; i < 8; i++) { + comp2_bit[i] = *(ecc_calc + 2) % 2; + *(ecc_calc + 2) = *(ecc_calc + 2) / 2; + } + + for (i = 0; i< 6; i++) + ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i]; + + for (i = 0; i < 8; i++) + ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i]; + + ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0]; + ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1]; + + for (i = 0; i < 24; i++) + ecc_sum += ecc_bit[i]; + + switch (ecc_sum) { + case 0: + /* Not reached because this function is not called if + ECC values are equal */ + return 0; + case 1: + /* Uncorrectable error */ + DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n"); + return(-1); + case 12: + /* Correctable error */ + find_byte = (ecc_bit[23] << 8) + + (ecc_bit[21] << 7) + + (ecc_bit[19] << 6) + + (ecc_bit[17] << 5) + + (ecc_bit[15] << 4) + + (ecc_bit[13] << 3) + + (ecc_bit[11] << 2) + + (ecc_bit[9] << 1) + + ecc_bit[7]; + + find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1]; + + DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit); + + page_data[find_byte] ^= (1 << find_bit); + + return(0); + default: + if (is_ecc_ff) { + if (ecc_calc[0] == 0 && ecc_calc[1] == 0 && ecc_calc[2] == 0) + return(0); + } + DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n"); + return(-1); + } +} + +static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) +{ + struct nand_chip *this; + int block_count = 0, i, rc; + + this = mtd->priv; + block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1; + for (i = 0; i < block_count; i++) { + if (memcmp(read_ecc, calc_ecc, 3) != 0) { + rc = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat); + if (rc < 0) { + return(rc); + } + } + read_ecc += 3; + calc_ecc += 3; + dat += 512; + } + return(0); +} +#endif + +static int nand_davinci_dev_ready(struct mtd_info *mtd) +{ + emifregs emif_addr; + + emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + return(emif_addr->NANDFSR & 0x1); +} + +static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state) +{ + while(!nand_davinci_dev_ready(mtd)) {;} + *NAND_CE0CLE = NAND_STATUS; + return(*NAND_CE0DATA); +} + +static void nand_flash_init(void) +{ + u_int32_t acfg1 = 0x3ffffffc; + u_int32_t acfg2 = 0x3ffffffc; + u_int32_t acfg3 = 0x3ffffffc; + u_int32_t acfg4 = 0x3ffffffc; + emifregs emif_regs; + + /*------------------------------------------------------------------* + * NAND FLASH CHIP TIMEOUT @ 459 MHz * + * * + * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz * + * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns * + * * + *------------------------------------------------------------------*/ + acfg1 = 0 + | (0 << 31 ) /* selectStrobe */ + | (0 << 30 ) /* extWait */ + | (1 << 26 ) /* writeSetup 10 ns */ + | (3 << 20 ) /* writeStrobe 40 ns */ + | (1 << 17 ) /* writeHold 10 ns */ + | (1 << 13 ) /* readSetup 10 ns */ + | (5 << 7 ) /* readStrobe 60 ns */ + | (1 << 4 ) /* readHold 10 ns */ + | (3 << 2 ) /* turnAround ?? ns */ + | (0 << 0 ) /* asyncSize 8-bit bus */ + ; + + emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE; + + emif_regs->AWCCR |= 0x10000000; + emif_regs->AB1CR = acfg1; /* 0x08244128 */; + emif_regs->AB2CR = acfg2; + emif_regs->AB3CR = acfg3; + emif_regs->AB4CR = acfg4; + emif_regs->NANDFCR = 0x00000101; +} + +int board_nand_init(struct nand_chip *nand) +{ + nand->IO_ADDR_R = (void __iomem *)NAND_CE0DATA; + nand->IO_ADDR_W = (void __iomem *)NAND_CE0DATA; + nand->chip_delay = 0; + nand->select_chip = nand_davinci_select_chip; +#ifdef CFG_NAND_USE_FLASH_BBT + nand->options = NAND_USE_FLASH_BBT; +#endif +#ifdef CFG_NAND_HW_ECC +#ifdef CFG_NAND_LARGEPAGE + nand->eccmode = NAND_ECC_HW12_2048; +#elif defined(CFG_NAND_SMALLPAGE) + nand->eccmode = NAND_ECC_HW3_512; +#else +#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!" +#endif + nand->autooob = &davinci_nand_oobinfo; + nand->calculate_ecc = nand_davinci_calculate_ecc; + nand->correct_data = nand_davinci_correct_data; + nand->enable_hwecc = nand_davinci_enable_hwecc; +#else + nand->eccmode = NAND_ECC_SOFT; +#endif + + /* Set address of hardware control function */ + nand->hwcontrol = nand_davinci_hwcontrol; + + nand->dev_ready = nand_davinci_dev_ready; + nand->waitfunc = nand_davinci_waitfunc; + + nand_flash_init(); + + return(0); +} + +#else +#error "U-Boot legacy NAND support not available for DaVinci chips" +#endif +#endif /* CFG_USE_NAND */ diff --git a/cpu/arm926ejs/davinci/reset.S b/cpu/arm926ejs/davinci/reset.S new file mode 100644 index 0000000..a687d44 --- /dev/null +++ b/cpu/arm926ejs/davinci/reset.S @@ -0,0 +1,77 @@ +/* + * Processor reset using WDT for TI TMS320DM644x SoC. + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * ----------------------------------------------------- + * + * 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 + */ + +.globl reset_cpu +reset_cpu: + ldr r0, WDT_TGCR + mov r1, $0x08 + str r1, [r0] + ldr r1, [r0] + orr r1, r1, $0x03 + str r1, [r0] + mov r1, $0 + ldr r0, WDT_TIM12 + str r1, [r0] + ldr r0, WDT_TIM34 + str r1, [r0] + ldr r0, WDT_PRD12 + str r1, [r0] + ldr r0, WDT_PRD34 + str r1, [r0] + ldr r0, WDT_TCR + ldr r1, [r0] + orr r1, r1, $0x40 + str r1, [r0] + ldr r0, WDT_WDTCR + ldr r1, [r0] + orr r1, r1, $0x4000 + str r1, [r0] + ldr r1, WDTCR_VAL1 + str r1, [r0] + ldr r1, WDTCR_VAL2 + str r1, [r0] + nop + nop + nop + nop +reset_cpu_loop: + b reset_cpu_loop + +WDT_TGCR: + .word 0x01c21c24 +WDT_TIM12: + .word 0x01c21c10 +WDT_TIM34: + .word 0x01c21c14 +WDT_PRD12: + .word 0x01c21c18 +WDT_PRD34: + .word 0x01c21c1c +WDT_TCR: + .word 0x01c21c20 +WDT_WDTCR: + .word 0x01c21c28 +WDTCR_VAL1: + .word 0xa5c64000 +WDTCR_VAL2: + .word 0xda7e4000 diff --git a/cpu/arm926ejs/davinci/timer.c b/cpu/arm926ejs/davinci/timer.c new file mode 100644 index 0000000..c6b1dda --- /dev/null +++ b/cpu/arm926ejs/davinci/timer.c @@ -0,0 +1,165 @@ +/* + * (C) Copyright 2003 + * Texas Instruments <www.ti.com> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Marius Groeger <mgroeger@sysgo.de> + * + * (C) Copyright 2002 + * Sysgo Real-Time Solutions, GmbH <www.elinos.com> + * Alex Zuepke <azu@sysgo.de> + * + * (C) Copyright 2002-2004 + * Gary Jennejohn, DENX Software Engineering, <gj@denx.de> + * + * (C) Copyright 2004 + * Philippe Robin, ARM Ltd. <philippe.robin@arm.com> + * + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <arm926ejs.h> + +typedef volatile struct { + u_int32_t pid12; + u_int32_t emumgt_clksped; + u_int32_t gpint_en; + u_int32_t gpdir_dat; + u_int32_t tim12; + u_int32_t tim34; + u_int32_t prd12; + u_int32_t prd34; + u_int32_t tcr; + u_int32_t tgcr; + u_int32_t wdtcr; + u_int32_t tlgc; + u_int32_t tlmr; +} davinci_timer; + +davinci_timer *timer = (davinci_timer *)CFG_TIMERBASE; + +#define TIMER_LOAD_VAL (CFG_HZ_CLOCK / CFG_HZ) +#define READ_TIMER timer->tim34 + +static ulong timestamp; +static ulong lastinc; + +int timer_init(void) +{ + /* We are using timer34 in unchained 32-bit mode, full speed */ + timer->tcr = 0x0; + timer->tgcr = 0x0; + timer->tgcr = 0x06; + timer->tim34 = 0x0; + timer->prd34 = TIMER_LOAD_VAL; + lastinc = 0; + timer->tcr = 0x80 << 16; + timestamp = 0; + + return(0); +} + +void reset_timer(void) +{ + reset_timer_masked(); +} + +ulong get_timer(ulong base) +{ + return(get_timer_masked() - base); +} + +void set_timer(ulong t) +{ + timestamp = t; +} + +void udelay(unsigned long usec) +{ + udelay_masked(usec); +} + +void reset_timer_masked(void) +{ + lastinc = READ_TIMER; + timestamp = 0; +} + +ulong get_timer_raw(void) +{ + ulong now = READ_TIMER; + + if (now >= lastinc) { + /* normal mode */ + timestamp += now - lastinc; + } else { + /* overflow ... */ + timestamp += now + TIMER_LOAD_VAL - lastinc; + } + lastinc = now; + return timestamp; +} + +ulong get_timer_masked(void) +{ + return(get_timer_raw() / TIMER_LOAD_VAL); +} + +void udelay_masked(unsigned long usec) +{ + ulong tmo; + ulong endtime; + signed long diff; + + tmo = CFG_HZ_CLOCK / 1000; + tmo *= usec; + tmo /= 1000; + + endtime = get_timer_raw() + tmo; + + do { + ulong now = get_timer_raw(); + diff = endtime - now; + } while (diff >= 0); +} + +/* + * This function is derived from PowerPC code (read timebase as long long). + * On ARM it just returns the timer value. + */ +unsigned long long get_ticks(void) +{ + return(get_timer(0)); +} + +/* + * This function is derived from PowerPC code (timebase clock frequency). + * On ARM it returns the number of timer ticks per second. + */ +ulong get_tbclk(void) +{ + ulong tbclk; + + tbclk = CFG_HZ; + return(tbclk); +} diff --git a/cpu/at32ap/atmel_mci.c b/cpu/at32ap/atmel_mci.c index 9f62c0f..cf48be1 100644 --- a/cpu/at32ap/atmel_mci.c +++ b/cpu/at32ap/atmel_mci.c @@ -56,6 +56,7 @@ #define MMC_DEFAULT_RCA 1 static unsigned int mmc_rca; +static int mmc_card_is_sd; static block_dev_desc_t mmc_blkdev; block_dev_desc_t *mmc_get_dev(int dev) @@ -82,7 +83,9 @@ static void mci_set_mode(unsigned long hz, unsigned long blklen) blklen &= 0xfffc; mmci_writel(MR, (MMCI_BF(CLKDIV, clkdiv) - | MMCI_BF(BLKLEN, blklen))); + | MMCI_BF(BLKLEN, blklen) + | MMCI_BIT(RDPROOF) + | MMCI_BIT(WRPROOF))); } #define RESP_NO_CRC 1 @@ -225,7 +228,7 @@ mmc_bread(int dev, unsigned long start, lbaint_t blkcnt, *buffer++ = data; wordcount++; } - } while(wordcount < (512 / 4)); + } while(wordcount < (mmc_blkdev.blksz / 4)); pr_debug("mmc: read %u words, waiting for BLKE\n", wordcount); @@ -243,7 +246,7 @@ out: fail: mmc_cmd(MMC_CMD_SEND_STATUS, mmc_rca << 16, &card_status, R1 | NCR); - printf("mmc: bread failed, card status = ", card_status); + printf("mmc: bread failed, card status = %08x\n", card_status); goto out; } @@ -371,6 +374,7 @@ static int sd_init_card(struct mmc_cid *cid, int verbose) mmc_rca = resp[0] >> 16; if (verbose) printf("SD Card detected (RCA %u)\n", mmc_rca); + mmc_card_is_sd = 1; return 0; } @@ -405,10 +409,64 @@ static int mmc_init_card(struct mmc_cid *cid, int verbose) return ret; } +static void mci_set_data_timeout(struct mmc_csd *csd) +{ + static const unsigned int dtomul_to_shift[] = { + 0, 4, 7, 8, 10, 12, 16, 20, + }; + static const unsigned int taac_exp[] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, + }; + static const unsigned int taac_mant[] = { + 0, 10, 12, 13, 15, 60, 25, 30, + 35, 40, 45, 50, 55, 60, 70, 80, + }; + unsigned int timeout_ns, timeout_clks; + unsigned int e, m; + unsigned int dtocyc, dtomul; + unsigned int shift; + u32 dtor; + + e = csd->taac & 0x07; + m = (csd->taac >> 3) & 0x0f; + + timeout_ns = (taac_exp[e] * taac_mant[m] + 9) / 10; + timeout_clks = csd->nsac * 100; + + timeout_clks += (((timeout_ns + 9) / 10) + * ((CFG_MMC_CLK_PP + 99999) / 100000) + 9999) / 10000; + if (!mmc_card_is_sd) + timeout_clks *= 10; + else + timeout_clks *= 100; + + dtocyc = timeout_clks; + dtomul = 0; + while (dtocyc > 15 && dtomul < 8) { + dtomul++; + shift = dtomul_to_shift[dtomul]; + dtocyc = (timeout_clks + (1 << shift) - 1) >> shift; + } + + if (dtomul >= 8) { + dtomul = 7; + dtocyc = 15; + puts("Warning: Using maximum data timeout\n"); + } + + dtor = (MMCI_BF(DTOMUL, dtomul) + | MMCI_BF(DTOCYC, dtocyc)); + mmci_writel(DTOR, dtor); + + printf("mmc: Using %u cycles data timeout (DTOR=0x%x)\n", + dtocyc << shift, dtor); +} + int mmc_init(int verbose) { struct mmc_cid cid; struct mmc_csd csd; + unsigned int max_blksz; int ret; /* Initialize controller */ @@ -418,6 +476,8 @@ int mmc_init(int verbose) mmci_writel(IDR, ~0UL); mci_set_mode(CFG_MMC_CLK_OD, MMC_DEFAULT_BLKLEN); + mmc_card_is_sd = 0; + ret = sd_init_card(&cid, verbose); if (ret) { mmc_rca = MMC_DEFAULT_RCA; @@ -433,6 +493,8 @@ int mmc_init(int verbose) if (verbose) mmc_dump_csd(&csd); + mci_set_data_timeout(&csd); + /* Initialize the blockdev structure */ mmc_blkdev.if_type = IF_TYPE_MMC; mmc_blkdev.part_type = PART_TYPE_DOS; @@ -444,7 +506,17 @@ int mmc_init(int verbose) sizeof(mmc_blkdev.product)); sprintf((char *)mmc_blkdev.revision, "%x %x", cid.prv >> 4, cid.prv & 0x0f); - mmc_blkdev.blksz = 1 << csd.read_bl_len; + + /* + * If we can't use 512 byte blocks, refuse to deal with the + * card. Tons of code elsewhere seems to depend on this. + */ + max_blksz = 1 << csd.read_bl_len; + if (max_blksz < 512 || (max_blksz > 512 && !csd.read_bl_partial)) { + printf("Card does not support 512 byte reads, aborting.\n"); + return -ENODEV; + } + mmc_blkdev.blksz = 512; mmc_blkdev.lba = (csd.c_size + 1) * (1 << (csd.c_size_mult + 2)); mci_set_mode(CFG_MMC_CLK_PP, mmc_blkdev.blksz); diff --git a/cpu/at32ap/atmel_mci.h b/cpu/at32ap/atmel_mci.h index 0ffbc4f..5b4f5c9 100644 --- a/cpu/at32ap/atmel_mci.h +++ b/cpu/at32ap/atmel_mci.h @@ -57,6 +57,10 @@ #define MMCI_CLKDIV_SIZE 8 #define MMCI_PWSDIV_OFFSET 8 #define MMCI_PWSDIV_SIZE 3 +#define MMCI_RDPROOF_OFFSET 11 +#define MMCI_RDPROOF_SIZE 1 +#define MMCI_WRPROOF_OFFSET 12 +#define MMCI_WRPROOF_SIZE 1 #define MMCI_PDCPADV_OFFSET 14 #define MMCI_PDCPADV_SIZE 1 #define MMCI_PDCMODE_OFFSET 15 diff --git a/cpu/at32ap/interrupts.c b/cpu/at32ap/interrupts.c index c9e0499..bef1f30 100644 --- a/cpu/at32ap/interrupts.c +++ b/cpu/at32ap/interrupts.c @@ -20,8 +20,8 @@ * MA 02111-1307 USA */ #include <common.h> +#include <div64.h> -#include <asm/div64.h> #include <asm/errno.h> #include <asm/io.h> #include <asm/processor.h> diff --git a/cpu/i386/serial.c b/cpu/i386/serial.c index e7299a7..baf35e5 100644 --- a/cpu/i386/serial.c +++ b/cpu/i386/serial.c @@ -394,7 +394,7 @@ int serial_buffered_tstc(void) #endif /* CONFIG_SERIAL_SOFTWARE_FIFO */ -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) /* AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port number 0 or number 1 @@ -500,4 +500,4 @@ void kgdb_interruptible(int yes) return; } #endif /* (CONFIG_KGDB_SER_INDEX & 2) */ -#endif /* CFG_CMD_KGDB */ +#endif diff --git a/cpu/ixp/cpu.c b/cpu/ixp/cpu.c index 7f9f334..2c7d5a0 100644 --- a/cpu/ixp/cpu.c +++ b/cpu/ixp/cpu.c @@ -85,7 +85,7 @@ int cpu_init (void) FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ; #endif -#if (CONFIG_COMMANDS & CFG_CMD_PCI) || defined (CONFIG_PCI) +#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI) pci_init(); #endif return 0; diff --git a/cpu/ixp/npe/npe.c b/cpu/ixp/npe/npe.c index ab7ca8b..7e4af44 100644 --- a/cpu/ixp/npe/npe.c +++ b/cpu/ixp/npe/npe.c @@ -682,7 +682,7 @@ int npe_initialize(bd_t * bis) eth_register(dev); -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register(dev->name, npe_miiphy_read, npe_miiphy_write); #endif diff --git a/cpu/mcf52x2/fec.c b/cpu/mcf52x2/fec.c index b6540b5..ef9c798 100644 --- a/cpu/mcf52x2/fec.c +++ b/cpu/mcf52x2/fec.c @@ -53,7 +53,7 @@ #undef ET_DEBUG #undef MII_DEBUG -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET) +#if defined(CONFIG_CMD_NET) && defined(FEC_ENET) #ifdef CFG_DISCOVER_PHY #include <miiphy.h> @@ -363,7 +363,7 @@ void eth_halt (void) } -#if defined(CFG_DISCOVER_PHY) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_CMD_MII) static int phyaddr = -1; /* didn't find a PHY yet */ static uint phytype; @@ -419,7 +419,7 @@ static uint mii_send (uint mii_cmd) #endif return (mii_reply & 0xffff); /* data read from phy */ } -#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CFG_CMD_MII) */ +#endif #if defined(CFG_DISCOVER_PHY) static void mii_discover_phy (void) @@ -485,7 +485,7 @@ static void mii_discover_phy (void) } #endif /* CFG_DISCOVER_PHY */ -#if (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII) +#if defined(CONFIG_CMD_MII) && !defined(CONFIG_BITBANGMII) static int mii_init_done = 0; @@ -591,13 +591,13 @@ int mcf52x2_miiphy_write (char *devname, unsigned char addr, return 0; } -#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII) */ -#endif /* CFG_CMD_NET, FEC_ENET */ +#endif +#endif int mcf52x2_miiphy_initialize(bd_t *bis) { -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(FEC_ENET) -#if (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII) +#if defined(CONFIG_CMD_NET) && defined(FEC_ENET) +#if defined(CONFIG_CMD_MII) && !defined(CONFIG_BITBANGMII) miiphy_register("mcf52x2phy", mcf52x2_miiphy_read, mcf52x2_miiphy_write); #endif #endif diff --git a/cpu/microblaze/cache.c b/cpu/microblaze/cache.c index 4f36a84..6ce0b55 100755..100644 --- a/cpu/microblaze/cache.c +++ b/cpu/microblaze/cache.c @@ -25,7 +25,7 @@ #include <common.h> #include <asm/asm.h> -#if (CONFIG_COMMANDS & CFG_CMD_CACHE) +#if defined(CONFIG_CMD_CACHE) int dcache_status (void) { diff --git a/cpu/microblaze/interrupts.c b/cpu/microblaze/interrupts.c index b61153f..3f04b29 100755..100644 --- a/cpu/microblaze/interrupts.c +++ b/cpu/microblaze/interrupts.c @@ -190,7 +190,7 @@ void interrupt_handler (void) } #endif -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) #ifdef CFG_INTC_0 int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { @@ -217,4 +217,4 @@ int do_irqinfo (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) puts ("Undefined interrupt controller\n"); } #endif -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/microblaze/irq.S b/cpu/microblaze/irq.S index e1fc190..e1fc190 100755..100644 --- a/cpu/microblaze/irq.S +++ b/cpu/microblaze/irq.S diff --git a/cpu/mips/au1x00_eth.c b/cpu/mips/au1x00_eth.c index 078e832..b69741a 100644 --- a/cpu/mips/au1x00_eth.c +++ b/cpu/mips/au1x00_eth.c @@ -63,7 +63,7 @@ #include <asm/io.h> #include <asm/au1x00.h> -#if (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_CMD_MII) #include <miiphy.h> #endif @@ -241,7 +241,7 @@ int au1x00_enet_initialize(bd_t *bis){ eth_register(dev); -#if (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_CMD_MII) miiphy_register(dev->name, au1x00_miiphy_read, au1x00_miiphy_write); #endif @@ -249,7 +249,7 @@ int au1x00_enet_initialize(bd_t *bis){ return 1; } -#if (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_CMD_MII) int au1x00_miiphy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short * value) { @@ -306,6 +306,6 @@ int au1x00_miiphy_write(char *devname, unsigned char addr, *mii_control_reg = mii_control; return 0; } -#endif /* CONFIG_COMMANDS & CFG_CMD_MII */ +#endif #endif /* CONFIG_AU1X00 */ diff --git a/cpu/mpc512x/Makefile b/cpu/mpc512x/Makefile new file mode 100644 index 0000000..2be35b2 --- /dev/null +++ b/cpu/mpc512x/Makefile @@ -0,0 +1,46 @@ +# +# (C) Copyright 2007 DENX Software Engineering +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB = $(obj)lib$(CPU).a + +START = start.o +COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o serial.o fec.o i2c.o + +SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) +OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) +START := $(addprefix $(obj),$(START)) + +all: $(obj).depend $(START) $(LIB) + +$(LIB): $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +# defines $(obj).depend target +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/cpu/mpc512x/config.mk b/cpu/mpc512x/config.mk new file mode 100644 index 0000000..8a07c5a --- /dev/null +++ b/cpu/mpc512x/config.mk @@ -0,0 +1,25 @@ +# +# (C) Copyright 2007 DENX Software Engineering +# +# 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 +# +PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi + +PLATFORM_CPPFLAGS += -DCONFIG_MPC512X -DCONFIG_E300 \ + -ffixed-r2 -ffixed-r29 -msoft-float -mcpu=603e diff --git a/cpu/mpc512x/cpu.c b/cpu/mpc512x/cpu.c new file mode 100644 index 0000000..accae6e --- /dev/null +++ b/cpu/mpc512x/cpu.c @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. + * (C) Copyright 2007 DENX Software Engineering + * + * 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 + */ + +/* + * CPU specific code for the MPC512x family. + * + * Derived from the MPC83xx code. + */ + +#include <common.h> +#include <command.h> +#include <mpc512x.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +int checkcpu (void) +{ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + ulong clock = gd->cpu_clk; + u32 pvr = get_pvr (); + u32 spridr = immr->sysconf.spridr; + char buf[32]; + + puts ("CPU: "); + + switch (spridr & 0xffff0000) { + case SPR_5121E: + puts ("MPC5121e "); + break; + default: + printf ("Unknown part ID %08x ", spridr & 0xffff0000); + } + printf ("rev. %d.%d, Core ", SVR_MJREV (spridr), SVR_MNREV (spridr)); + + switch (pvr & 0xffff0000) { + case PVR_E300C4: + puts ("e300c4 "); + break; + default: + puts ("unknown "); + } + printf ("at %s MHz, CSB at %3d MHz\n", strmhz(buf, clock), + gd->csb_clk / 1000000); + return 0; +} + + +int +do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + ulong msr; + volatile immap_t *immap = (immap_t *) CFG_IMMR; + + /* Interrupts and MMU off */ + __asm__ __volatile__ ("mfmsr %0":"=r" (msr):); + + msr &= ~( MSR_EE | MSR_IR | MSR_DR); + __asm__ __volatile__ ("mtmsr %0"::"r" (msr)); + + /* + * Enable Reset Control Reg - "RSTE" is the magic word that let us go + */ + immap->reset.rpr = 0x52535445; + + /* Verify Reset Control Reg is enabled */ + while (!((immap->reset.rcer) & RCER_CRE)) + ; + + printf ("Resetting the board.\n"); + udelay(200); + + /* Perform reset */ + immap->reset.rcr = RCR_SWHR; + + /* Unreached... */ + return 1; +} + + +/* + * Get timebase clock frequency (like cpu_clk in Hz) + */ +unsigned long get_tbclk (void) +{ + ulong tbclk; + + tbclk = (gd->bus_clk + 3L) / 4L; + + return tbclk; +} + + +#if defined(CONFIG_WATCHDOG) +void watchdog_reset (void) +{ + int re_enable = disable_interrupts (); + + /* Reset watchdog */ + volatile immap_t *immr = (immap_t *) CFG_IMMR; + immr->wdt.swsrr = 0x556c; + immr->wdt.swsrr = 0xaa39; + + if (re_enable) + enable_interrupts (); +} +#endif diff --git a/cpu/mpc512x/cpu_init.c b/cpu/mpc512x/cpu_init.c new file mode 100644 index 0000000..d6949f6 --- /dev/null +++ b/cpu/mpc512x/cpu_init.c @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc. + * (C) Copyright 2007 DENX Software Engineering + * + * 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 + * + * Derived from the MPC83xx code. + * + */ + +#include <common.h> +#include <mpc512x.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Set up the memory map, initialize registers, + */ +void cpu_init_f (volatile immap_t * im) +{ + u32 ips_div; + + /* Pointer is writable since we allocated a register for it */ + gd = (gd_t *) (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET); + + /* Clear initial global data */ + memset ((void *) gd, 0, sizeof (gd_t)); + + /* system performance tweaking */ + +#ifdef CFG_ACR_PIPE_DEP + /* Arbiter pipeline depth */ + im->arbiter.acr = (im->arbiter.acr & ~ACR_PIPE_DEP) | + (CFG_ACR_PIPE_DEP << ACR_PIPE_DEP_SHIFT); +#endif + +#ifdef CFG_ACR_RPTCNT + /* Arbiter repeat count */ + im->arbiter.acr = ((im->arbiter.acr & ~(ACR_RPTCNT)) | + (CFG_ACR_RPTCNT << ACR_RPTCNT_SHIFT)); +#endif + + /* RSR - Reset Status Register - clear all status */ + gd->reset_status = im->reset.rsr; + im->reset.rsr = ~(RSR_RES); + + /* + * RMR - Reset Mode Register - enable checkstop reset + */ + im->reset.rmr = (RMR_CSRE & (1 << RMR_CSRE_SHIFT)); + + /* Set IPS-CSB divider: IPS = 1/2 CSB */ + ips_div = im->clk.scfr[0]; + ips_div &= ~(SCFR1_IPS_DIV_MASK); + ips_div |= SCFR1_IPS_DIV << SCFR1_IPS_DIV_SHIFT; + im->clk.scfr[0] = ips_div; + + /* + * Enable Time Base/Decrementer + * + * NOTICE: TB needs to be enabled as early as possible in order to + * have udelay() working; if not enabled, usually leads to a hang, like + * during FLASH chip identification etc. + */ + im->sysconf.spcr |= SPCR_TBEN; +} + +int cpu_init_r (void) +{ + return 0; +} diff --git a/cpu/mpc512x/fec.c b/cpu/mpc512x/fec.c new file mode 100644 index 0000000..3c142a9 --- /dev/null +++ b/cpu/mpc512x/fec.c @@ -0,0 +1,801 @@ +/* + * (C) Copyright 2003-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Derived from the MPC8xx FEC driver. + * Adapted for MPC512x by Grzegorz Bernacki <gjb@semihalf.com> + */ + +#include <common.h> +#include <mpc512x.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> +#include "fec.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define DEBUG 0 + +#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ + defined(CONFIG_MPC512x_FEC) + +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) +#error "CONFIG_MII has to be defined!" +#endif + +#if (DEBUG & 0x40) +static uint32 local_crc32(char *string, unsigned int crc_value, int len); +#endif + +int fec512x_miiphy_read(char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal); +int fec512x_miiphy_write(char *devname, uint8 phyAddr, uint8 regAddr, uint16 data); +int mpc512x_fec_init_phy(struct eth_device *dev, bd_t * bis); + +/********************************************************************/ +#if (DEBUG & 0x2) +static void mpc512x_fec_phydump (char *devname) +{ + uint16 phyStatus, i; + uint8 phyAddr = CONFIG_PHY_ADDR; + uint8 reg_mask[] = { + /* regs to print: 0...8, 21,27,31 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, + }; + + for (i = 0; i < 32; i++) { + if (reg_mask[i]) { + miiphy_read (devname, phyAddr, i, &phyStatus); + printf ("Mii reg %d: 0x%04x\n", i, phyStatus); + } + } +} +#endif + +/********************************************************************/ +static int mpc512x_fec_bd_init (mpc512x_fec_priv *fec) +{ + int ix; + + /* + * Receive BDs init + */ + for (ix = 0; ix < FEC_RBD_NUM; ix++) { + fec->bdBase->rbd[ix].dataPointer = (uint32)&fec->bdBase->recv_frames[ix]; + fec->bdBase->rbd[ix].status = FEC_RBD_EMPTY; + fec->bdBase->rbd[ix].dataLength = 0; + } + + /* + * have the last RBD to close the ring + */ + fec->bdBase->rbd[ix - 1].status |= FEC_RBD_WRAP; + fec->rbdIndex = 0; + + /* + * Trasmit BDs init + */ + for (ix = 0; ix < FEC_TBD_NUM; ix++) { + fec->bdBase->tbd[ix].status = 0; + } + + /* + * Have the last TBD to close the ring + */ + fec->bdBase->tbd[ix - 1].status |= FEC_TBD_WRAP; + + /* + * Initialize some indices + */ + fec->tbdIndex = 0; + fec->usedTbdIndex = 0; + fec->cleanTbdNum = FEC_TBD_NUM; + + return 0; +} + +/********************************************************************/ +static void mpc512x_fec_rbd_clean (mpc512x_fec_priv *fec, volatile FEC_RBD * pRbd) +{ + /* + * Reset buffer descriptor as empty + */ + if ((fec->rbdIndex) == (FEC_RBD_NUM - 1)) + pRbd->status = (FEC_RBD_WRAP | FEC_RBD_EMPTY); + else + pRbd->status = FEC_RBD_EMPTY; + + pRbd->dataLength = 0; + + /* + * Increment BD count + */ + fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM; + + /* + * Now, we have an empty RxBD, notify FEC + */ + fec->eth->r_des_active = 0x01000000; /* Descriptor polling active */ +} + +/********************************************************************/ +static void mpc512x_fec_tbd_scrub (mpc512x_fec_priv *fec) +{ + volatile FEC_TBD *pUsedTbd; + +#if (DEBUG & 0x1) + printf ("tbd_scrub: fec->cleanTbdNum = %d, fec->usedTbdIndex = %d\n", + fec->cleanTbdNum, fec->usedTbdIndex); +#endif + + /* + * process all the consumed TBDs + */ + while (fec->cleanTbdNum < FEC_TBD_NUM) { + pUsedTbd = &fec->bdBase->tbd[fec->usedTbdIndex]; + if (pUsedTbd->status & FEC_TBD_READY) { +#if (DEBUG & 0x20) + printf ("Cannot clean TBD %d, in use\n", fec->usedTbdIndex); +#endif + return; + } + + /* + * clean this buffer descriptor + */ + if (fec->usedTbdIndex == (FEC_TBD_NUM - 1)) + pUsedTbd->status = FEC_TBD_WRAP; + else + pUsedTbd->status = 0; + + /* + * update some indeces for a correct handling of the TBD ring + */ + fec->cleanTbdNum++; + fec->usedTbdIndex = (fec->usedTbdIndex + 1) % FEC_TBD_NUM; + } +} + +/********************************************************************/ +static void mpc512x_fec_set_hwaddr (mpc512x_fec_priv *fec, char *mac) +{ + uint8 currByte; /* byte for which to compute the CRC */ + int byte; /* loop - counter */ + int bit; /* loop - counter */ + uint32 crc = 0xffffffff; /* initial value */ + + /* + * The algorithm used is the following: + * we loop on each of the six bytes of the provided address, + * and we compute the CRC by left-shifting the previous + * value by one position, so that each bit in the current + * byte of the address may contribute the calculation. If + * the latter and the MSB in the CRC are different, then + * the CRC value so computed is also ex-ored with the + * "polynomium generator". The current byte of the address + * is also shifted right by one bit at each iteration. + * This is because the CRC generatore in hardware is implemented + * as a shift-register with as many ex-ores as the radixes + * in the polynomium. This suggests that we represent the + * polynomiumm itself as a 32-bit constant. + */ + for (byte = 0; byte < 6; byte++) { + currByte = mac[byte]; + for (bit = 0; bit < 8; bit++) { + if ((currByte & 0x01) ^ (crc & 0x01)) { + crc >>= 1; + crc = crc ^ 0xedb88320; + } else { + crc >>= 1; + } + currByte >>= 1; + } + } + + crc = crc >> 26; + + /* + * Set individual hash table register + */ + if (crc >= 32) { + fec->eth->iaddr1 = (1 << (crc - 32)); + fec->eth->iaddr2 = 0; + } else { + fec->eth->iaddr1 = 0; + fec->eth->iaddr2 = (1 << crc); + } + + /* + * Set physical address + */ + fec->eth->paddr1 = (mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3]; + fec->eth->paddr2 = (mac[4] << 24) + (mac[5] << 16) + 0x8808; +} + +/********************************************************************/ +static int mpc512x_fec_init (struct eth_device *dev, bd_t * bis) +{ + mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; + +#if (DEBUG & 0x1) + printf ("mpc512x_fec_init... Begin\n"); +#endif + + /* Set interrupt mask register */ + fec->eth->imask = 0x00000000; + + /* Clear FEC-Lite interrupt event register(IEVENT) */ + fec->eth->ievent = 0xffffffff; + + /* Set transmit fifo watermark register(X_WMRK), default = 64 */ + fec->eth->x_wmrk = 0x0; + + /* Set Opcode/Pause Duration Register */ + fec->eth->op_pause = 0x00010020; + + /* Frame length=1518; MII mode */ + fec->eth->r_cntrl = 0x05ee000c; + + /* Half-duplex, heartbeat disabled */ + fec->eth->x_cntrl = 0x00000000; + + /* Enable MIB counters */ + fec->eth->mib_control = 0x0; + + /* Setup recv fifo start and buff size */ + fec->eth->r_fstart = 0x500; + fec->eth->r_buff_size = 0x5e0; + + /* Setup BD base addresses */ + fec->eth->r_des_start = (uint32)fec->bdBase->rbd; + fec->eth->x_des_start = (uint32)fec->bdBase->tbd; + + /* DMA Control */ + fec->eth->dma_control = 0xc0000000; + + /* Enable FEC */ + fec->eth->ecntrl |= 0x00000006; + + /* Initilize addresses and status words of BDs */ + mpc512x_fec_bd_init (fec); + + /* Descriptor polling active */ + fec->eth->r_des_active = 0x01000000; + +#if (DEBUG & 0x1) + printf("mpc512x_fec_init... Done \n"); +#endif + return 1; +} + +/********************************************************************/ +int mpc512x_fec_init_phy (struct eth_device *dev, bd_t * bis) +{ + mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; + const uint8 phyAddr = CONFIG_PHY_ADDR; /* Only one PHY */ + int timeout = 1; + uint16 phyStatus; + +#if (DEBUG & 0x1) + printf ("mpc512x_fec_init_phy... Begin\n"); +#endif + + /* + * Clear FEC-Lite interrupt event register(IEVENT) + */ + fec->eth->ievent = 0xffffffff; + + /* + * Set interrupt mask register + */ + fec->eth->imask = 0x00000000; + + if (fec->xcv_type != SEVENWIRE) { + /* + * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock + * and do not drop the Preamble. + */ + fec->eth->mii_speed = (((gd->ipb_clk / 1000000) / 5) + 1) << 1; + + /* + * Reset PHY, then delay 300ns + */ + miiphy_write (dev->name, phyAddr, 0x0, 0x8000); + udelay (1000); + + if (fec->xcv_type == MII10) { + /* + * Force 10Base-T, FDX operation + */ +#if (DEBUG & 0x2) + printf ("Forcing 10 Mbps ethernet link... "); +#endif + miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); + + miiphy_write (dev->name, phyAddr, 0x0, 0x0180); + + timeout = 20; + do { /* wait for link status to go down */ + udelay (10000); + if ((timeout--) == 0) { +#if (DEBUG & 0x2) + printf ("hmmm, should not have waited..."); +#endif + break; + } + miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); +#if (DEBUG & 0x2) + printf ("="); +#endif + } while ((phyStatus & 0x0004)); /* !link up */ + + timeout = 1000; + do { /* wait for link status to come back up */ + udelay (10000); + if ((timeout--) == 0) { + printf ("failed. Link is down.\n"); + break; + } + miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); +#if (DEBUG & 0x2) + printf ("+"); +#endif + } while (!(phyStatus & 0x0004)); /* !link up */ + +#if (DEBUG & 0x2) + printf ("done.\n"); +#endif + } else { /* MII100 */ + /* + * Set the auto-negotiation advertisement register bits + */ + miiphy_write (dev->name, phyAddr, 0x4, 0x01e1); + + /* + * Set MDIO bit 0.12 = 1(&& bit 0.9=1?) to enable auto-negotiation + */ + miiphy_write (dev->name, phyAddr, 0x0, 0x1200); + + /* + * Wait for AN completion + */ + timeout = 50000; + do { + udelay (1000); + + if ((timeout--) == 0) { +#if (DEBUG & 0x2) + printf ("PHY auto neg 0 failed...\n"); +#endif + return -1; + } + + if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) != 0) { +#if (DEBUG & 0x2) + printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus); +#endif + return -1; + } + } while (!(phyStatus & 0x0004)); + +#if (DEBUG & 0x2) + printf ("PHY auto neg complete! \n"); +#endif + } + } + +#if (DEBUG & 0x2) + if (fec->xcv_type != SEVENWIRE) + mpc512x_fec_phydump (dev->name); +#endif + +#if (DEBUG & 0x1) + printf ("mpc512x_fec_init_phy... Done \n"); +#endif + return 1; +} + +/********************************************************************/ +static void mpc512x_fec_halt (struct eth_device *dev) +{ + mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; + int counter = 0xffff; + +#if (DEBUG & 0x2) + if (fec->xcv_type != SEVENWIRE) + mpc512x_fec_phydump (dev->name); +#endif + + /* + * mask FEC chip interrupts + */ + fec->eth->imask = 0; + + /* + * issue graceful stop command to the FEC transmitter if necessary + */ + fec->eth->x_cntrl |= 0x00000001; + + /* + * wait for graceful stop to register + */ + while ((counter--) && (!(fec->eth->ievent & 0x10000000))) ; + + /* + * Disable the Ethernet Controller + */ + fec->eth->ecntrl &= 0xfffffffd; + + /* + * Issue a reset command to the FEC chip + */ + fec->eth->ecntrl |= 0x1; + + /* + * wait at least 16 clock cycles + */ + udelay (10); +#if (DEBUG & 0x3) + printf ("Ethernet task stopped\n"); +#endif +} + +/********************************************************************/ + +static int mpc512x_fec_send (struct eth_device *dev, volatile void *eth_data, + int data_length) +{ + /* + * This routine transmits one frame. This routine only accepts + * 6-byte Ethernet addresses. + */ + mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; + volatile FEC_TBD *pTbd; + +#if (DEBUG & 0x20) + printf("tbd status: 0x%04x\n", fec->tbdBase[fec->tbdIndex].status); +#endif + + /* + * Clear Tx BD ring at first + */ + mpc512x_fec_tbd_scrub (fec); + + /* + * Check for valid length of data. + */ + if ((data_length > 1500) || (data_length <= 0)) { + return -1; + } + + /* + * Check the number of vacant TxBDs. + */ + if (fec->cleanTbdNum < 1) { +#if (DEBUG & 0x20) + printf ("No available TxBDs ...\n"); +#endif + return -1; + } + + /* + * Get the first TxBD to send the mac header + */ + pTbd = &fec->bdBase->tbd[fec->tbdIndex]; + pTbd->dataLength = data_length; + pTbd->dataPointer = (uint32)eth_data; + pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY; + fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM; + + /* Activate transmit Buffer Descriptor polling */ + fec->eth->x_des_active = 0x01000000; /* Descriptor polling active */ + +#if (DEBUG & 0x8) + printf ( "+" ); +#endif + + fec->cleanTbdNum -= 1; + + /* + * wait until frame is sent . + */ + while (pTbd->status & FEC_TBD_READY) { + udelay (10); +#if (DEBUG & 0x8) + printf ("TDB status = %04x\n", pTbd->status); +#endif + } + + return 0; +} + + +/********************************************************************/ +static int mpc512x_fec_recv (struct eth_device *dev) +{ + /* + * This command pulls one frame from the card + */ + mpc512x_fec_priv *fec = (mpc512x_fec_priv *)dev->priv; + volatile FEC_RBD *pRbd = &fec->bdBase->rbd[fec->rbdIndex]; + unsigned long ievent; + int frame_length, len = 0; + uchar buff[FEC_MAX_PKT_SIZE]; + +#if (DEBUG & 0x1) + printf ("mpc512x_fec_recv %d Start...\n", fec->rbdIndex); +#endif +#if (DEBUG & 0x8) + printf( "-" ); +#endif + + /* + * Check if any critical events have happened + */ + ievent = fec->eth->ievent; + fec->eth->ievent = ievent; + if (ievent & 0x20060000) { + /* BABT, Rx/Tx FIFO errors */ + mpc512x_fec_halt (dev); + mpc512x_fec_init (dev, NULL); + return 0; + } + if (ievent & 0x80000000) { + /* Heartbeat error */ + fec->eth->x_cntrl |= 0x00000001; + } + if (ievent & 0x10000000) { + /* Graceful stop complete */ + if (fec->eth->x_cntrl & 0x00000001) { + mpc512x_fec_halt (dev); + fec->eth->x_cntrl &= ~0x00000001; + mpc512x_fec_init (dev, NULL); + } + } + + if (!(pRbd->status & FEC_RBD_EMPTY)) { + if ((pRbd->status & FEC_RBD_LAST) && + !(pRbd->status & FEC_RBD_ERR) && + ((pRbd->dataLength - 4) > 14)) { + + /* + * Get buffer size + */ + frame_length = pRbd->dataLength - 4; + +#if (DEBUG & 0x20) + { + int i; + printf ("recv data hdr:"); + for (i = 0; i < 14; i++) + printf ("%x ", *((uint8*)pRbd->dataPointer + i)); + printf("\n"); + } +#endif + + /* + * Fill the buffer and pass it to upper layers + */ + memcpy (buff, (void*)pRbd->dataPointer, frame_length); + NetReceive ((uchar*)buff, frame_length); + len = frame_length; + } + + /* + * Reset buffer descriptor as empty + */ + mpc512x_fec_rbd_clean (fec, pRbd); + } + + /* Try to fill Buffer Descriptors */ + fec->eth->r_des_active = 0x01000000; /* Descriptor polling active */ + return len; +} + +/********************************************************************/ +int mpc512x_fec_initialize (bd_t * bis) +{ + + immap_t *im = (immap_t*) CFG_IMMR; + mpc512x_fec_priv *fec; + struct eth_device *dev; + int i; + char *tmp, *end, env_enetaddr[6]; + uint32 *reg; + void * bd; + + fec = (mpc512x_fec_priv *) malloc (sizeof(*fec)); + dev = (struct eth_device *) malloc (sizeof(*dev)); + memset (dev, 0, sizeof *dev); + + fec->eth = (ethernet_regs *) MPC512X_FEC; + +# ifndef CONFIG_FEC_10MBIT + fec->xcv_type = MII100; +# else + fec->xcv_type = MII10; +# endif + dev->priv = (void *)fec; + dev->iobase = MPC512X_FEC; + dev->init = mpc512x_fec_init; + dev->halt = mpc512x_fec_halt; + dev->send = mpc512x_fec_send; + dev->recv = mpc512x_fec_recv; + + sprintf (dev->name, "FEC ETHERNET"); + eth_register (dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) + miiphy_register (dev->name, + fec512x_miiphy_read, fec512x_miiphy_write); +#endif + + /* + * Initialize I\O pins + */ + reg = (uint32 *) &(im->io_ctrl.regs[PSC0_0_IDX]); + + for (i = 0; i < 15; i++) + reg[i] = IOCTRL_MUX_FEC | 0x00000001; + + im->io_ctrl.regs[SPDIF_TXCLOCK_IDX] = IOCTRL_MUX_FEC | 0x00000001; + im->io_ctrl.regs[SPDIF_TX_IDX] = IOCTRL_MUX_FEC | 0x00000001; + im->io_ctrl.regs[SPDIF_RX_IDX] = IOCTRL_MUX_FEC | 0x00000001; + + /* Clean up space FEC's MIB and FIFO RAM ...*/ + memset ((void *) MPC512X_FEC + 0x200, 0x00, 0x400); + + /* + * Malloc space for BDs (must be quad word-aligned) + * this pointer is lost, so cannot be freed + */ + bd = malloc (sizeof(mpc512x_buff_descs) + 0x1f); + fec->bdBase = (mpc512x_buff_descs*)((uint32)bd & 0xfffffff0); + memset ((void *) bd, 0x00, sizeof(mpc512x_buff_descs) + 0x1f); + + /* + * Set interrupt mask register + */ + fec->eth->imask = 0x00000000; + + /* + * Clear FEC-Lite interrupt event register(IEVENT) + */ + fec->eth->ievent = 0xffffffff; + + /* + * Try to set the mac address now. The fec mac address is + * a garbage after reset. When not using fec for booting + * the Linux fec driver will try to work with this garbage. + */ + tmp = getenv ("ethaddr"); + if (tmp) { + for (i=0; i<6; i++) { + env_enetaddr[i] = tmp ? simple_strtoul (tmp, &end, 16) : 0; + if (tmp) + tmp = (*end) ? end+1 : end; + } + mpc512x_fec_set_hwaddr (fec, env_enetaddr); + fec->eth->gaddr1 = 0x00000000; + fec->eth->gaddr2 = 0x00000000; + } + + mpc512x_fec_init_phy (dev, bis); + + return 1; +} + +/* MII-interface related functions */ +/********************************************************************/ +int fec512x_miiphy_read (char *devname, uint8 phyAddr, uint8 regAddr, uint16 * retVal) +{ + ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC; + uint32 reg; /* convenient holder for the PHY register */ + uint32 phy; /* convenient holder for the PHY */ + int timeout = 0xffff; + + /* + * reading from any PHY's register is done by properly + * programming the FEC's MII data register. + */ + reg = regAddr << FEC_MII_DATA_RA_SHIFT; + phy = phyAddr << FEC_MII_DATA_PA_SHIFT; + + eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg); + + /* + * wait for the related interrupt + */ + while ((timeout--) && (!(eth->ievent & 0x00800000))) ; + + if (timeout == 0) { +#if (DEBUG & 0x2) + printf ("Read MDIO failed...\n"); +#endif + return -1; + } + + /* + * clear mii interrupt bit + */ + eth->ievent = 0x00800000; + + /* + * it's now safe to read the PHY's register + */ + *retVal = (uint16) eth->mii_data; + + return 0; +} + +/********************************************************************/ +int fec512x_miiphy_write (char *devname, uint8 phyAddr, uint8 regAddr, uint16 data) +{ + ethernet_regs *eth = (ethernet_regs *) MPC512X_FEC; + uint32 reg; /* convenient holder for the PHY register */ + uint32 phy; /* convenient holder for the PHY */ + int timeout = 0xffff; + + reg = regAddr << FEC_MII_DATA_RA_SHIFT; + phy = phyAddr << FEC_MII_DATA_PA_SHIFT; + + eth->mii_data = (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | + FEC_MII_DATA_TA | phy | reg | data); + + /* + * wait for the MII interrupt + */ + while ((timeout--) && (!(eth->ievent & 0x00800000))) ; + + if (timeout == 0) { +#if (DEBUG & 0x2) + printf ("Write MDIO failed...\n"); +#endif + return -1; + } + + /* + * clear MII interrupt bit + */ + eth->ievent = 0x00800000; + + return 0; +} + +#if (DEBUG & 0x40) +static uint32 local_crc32 (char *string, unsigned int crc_value, int len) +{ + int i; + char c; + unsigned int crc, count; + + /* + * crc32 algorithm + */ + /* + * crc = 0xffffffff; * The initialized value should be 0xffffffff + */ + crc = crc_value; + + for (i = len; --i >= 0;) { + c = *string++; + for (count = 0; count < 8; count++) { + if ((c & 0x01) ^ (crc & 0x01)) { + crc >>= 1; + crc = crc ^ 0xedb88320; + } else { + crc >>= 1; + } + c >>= 1; + } + } + + /* + * In big endian system, do byte swaping for crc value + */ + /**/ return crc; +} +#endif /* DEBUG */ + +#endif /* CONFIG_MPC512x_FEC */ diff --git a/cpu/mpc512x/fec.h b/cpu/mpc512x/fec.h new file mode 100644 index 0000000..d2d877a --- /dev/null +++ b/cpu/mpc512x/fec.h @@ -0,0 +1,224 @@ +/* + * (C) Copyright 2003 - 2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Derived from the MPC8xx driver's header file. + */ + +#ifndef __MPC512X_FEC_H +#define __MPC512X_FEC_H + +#include <common.h> +#include <mpc512x.h> + +typedef unsigned long uint32; +typedef unsigned short uint16; +typedef unsigned char uint8; + +typedef struct ethernet_register_set { + +/* [10:2]addr = 00 */ + +/* Control and status Registers (offset 000-1FF) */ + + volatile uint32 fec_id; /* MBAR_ETH + 0x000 */ + volatile uint32 ievent; /* MBAR_ETH + 0x004 */ + volatile uint32 imask; /* MBAR_ETH + 0x008 */ + + volatile uint32 RES0[1]; /* MBAR_ETH + 0x00C */ + volatile uint32 r_des_active; /* MBAR_ETH + 0x010 */ + volatile uint32 x_des_active; /* MBAR_ETH + 0x014 */ + + volatile uint32 RES1[3]; /* MBAR_ETH + 0x018-020 */ + volatile uint32 ecntrl; /* MBAR_ETH + 0x024 */ + + volatile uint32 RES2[6]; /* MBAR_ETH + 0x028-03C */ + volatile uint32 mii_data; /* MBAR_ETH + 0x040 */ + volatile uint32 mii_speed; /* MBAR_ETH + 0x044 */ + + volatile uint32 RES3[7]; /* MBAR_ETH + 0x048-060 */ + volatile uint32 mib_control; /* MBAR_ETH + 0x064 */ + + volatile uint32 RES4[7]; /* MBAR_ETH + 0x068-80 */ + volatile uint32 r_cntrl; /* MBAR_ETH + 0x084 */ + volatile uint32 r_hash; /* MBAR_ETH + 0x088 */ + + volatile uint32 RES5[14]; /* MBAR_ETH + 0x08c-0C0 */ + volatile uint32 x_cntrl; /* MBAR_ETH + 0x0C4 */ + + volatile uint32 RES6[7]; /* MBAR_ETH + 0x0C8-0E0 */ + volatile uint32 paddr1; /* MBAR_ETH + 0x0E4 */ + volatile uint32 paddr2; /* MBAR_ETH + 0x0E8 */ + volatile uint32 op_pause; /* MBAR_ETH + 0x0EC */ + + volatile uint32 RES7[10]; /* MBAR_ETH + 0x0F0-114 */ + volatile uint32 iaddr1; /* MBAR_ETH + 0x118 */ + volatile uint32 iaddr2; /* MBAR_ETH + 0x11C */ + volatile uint32 gaddr1; /* MBAR_ETH + 0x120 */ + volatile uint32 gaddr2; /* MBAR_ETH + 0x124 */ + + volatile uint32 RES8[6]; /* MBAR_ETH + 0x128-13C */ + volatile uint32 fifo_id; /* MBAR_ETH + 0x140 */ + volatile uint32 x_wmrk; /* MBAR_ETH + 0x144 */ + volatile uint32 RES9[1]; /* MBAR_ETH + 0x148 */ + volatile uint32 r_bound; /* MBAR_ETH + 0x14C */ + volatile uint32 r_fstart; /* MBAR_ETH + 0x150 */ + + volatile uint32 RES10[11]; /* MBAR_ETH + 0x154-17C */ + volatile uint32 r_des_start; /* MBAR_ETH + 0x180 */ + volatile uint32 x_des_start; /* MBAR_ETH + 0x184 */ + volatile uint32 r_buff_size; /* MBAR_ETH + 0x188 */ + volatile uint32 RES11[26]; /* MBAR_ETH + 0x18C-1F0 */ + volatile uint32 dma_control; /* MBAR_ETH + 0x1F4 */ + volatile uint32 RES12[2]; /* MBAR_ETH + 0x1F8-1FC */ + +/* MIB COUNTERS (Offset 200-2FF) */ + + volatile uint32 rmon_t_drop; /* MBAR_ETH + 0x200 */ + volatile uint32 rmon_t_packets; /* MBAR_ETH + 0x204 */ + volatile uint32 rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */ + volatile uint32 rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */ + volatile uint32 rmon_t_crc_align; /* MBAR_ETH + 0x210 */ + volatile uint32 rmon_t_undersize; /* MBAR_ETH + 0x214 */ + volatile uint32 rmon_t_oversize; /* MBAR_ETH + 0x218 */ + volatile uint32 rmon_t_frag; /* MBAR_ETH + 0x21C */ + volatile uint32 rmon_t_jab; /* MBAR_ETH + 0x220 */ + volatile uint32 rmon_t_col; /* MBAR_ETH + 0x224 */ + volatile uint32 rmon_t_p64; /* MBAR_ETH + 0x228 */ + volatile uint32 rmon_t_p65to127; /* MBAR_ETH + 0x22C */ + volatile uint32 rmon_t_p128to255; /* MBAR_ETH + 0x230 */ + volatile uint32 rmon_t_p256to511; /* MBAR_ETH + 0x234 */ + volatile uint32 rmon_t_p512to1023; /* MBAR_ETH + 0x238 */ + volatile uint32 rmon_t_p1024to2047; /* MBAR_ETH + 0x23C */ + volatile uint32 rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */ + volatile uint32 rmon_t_octets; /* MBAR_ETH + 0x244 */ + volatile uint32 ieee_t_drop; /* MBAR_ETH + 0x248 */ + volatile uint32 ieee_t_frame_ok; /* MBAR_ETH + 0x24C */ + volatile uint32 ieee_t_1col; /* MBAR_ETH + 0x250 */ + volatile uint32 ieee_t_mcol; /* MBAR_ETH + 0x254 */ + volatile uint32 ieee_t_def; /* MBAR_ETH + 0x258 */ + volatile uint32 ieee_t_lcol; /* MBAR_ETH + 0x25C */ + volatile uint32 ieee_t_excol; /* MBAR_ETH + 0x260 */ + volatile uint32 ieee_t_macerr; /* MBAR_ETH + 0x264 */ + volatile uint32 ieee_t_cserr; /* MBAR_ETH + 0x268 */ + volatile uint32 ieee_t_sqe; /* MBAR_ETH + 0x26C */ + volatile uint32 t_fdxfc; /* MBAR_ETH + 0x270 */ + volatile uint32 ieee_t_octets_ok; /* MBAR_ETH + 0x274 */ + + volatile uint32 RES13[2]; /* MBAR_ETH + 0x278-27C */ + volatile uint32 rmon_r_drop; /* MBAR_ETH + 0x280 */ + volatile uint32 rmon_r_packets; /* MBAR_ETH + 0x284 */ + volatile uint32 rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */ + volatile uint32 rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */ + volatile uint32 rmon_r_crc_align; /* MBAR_ETH + 0x290 */ + volatile uint32 rmon_r_undersize; /* MBAR_ETH + 0x294 */ + volatile uint32 rmon_r_oversize; /* MBAR_ETH + 0x298 */ + volatile uint32 rmon_r_frag; /* MBAR_ETH + 0x29C */ + volatile uint32 rmon_r_jab; /* MBAR_ETH + 0x2A0 */ + + volatile uint32 rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */ + + volatile uint32 rmon_r_p64; /* MBAR_ETH + 0x2A8 */ + volatile uint32 rmon_r_p65to127; /* MBAR_ETH + 0x2AC */ + volatile uint32 rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */ + volatile uint32 rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */ + volatile uint32 rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */ + volatile uint32 rmon_r_p1024to2047; /* MBAR_ETH + 0x2BC */ + volatile uint32 rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */ + volatile uint32 rmon_r_octets; /* MBAR_ETH + 0x2C4 */ + volatile uint32 ieee_r_drop; /* MBAR_ETH + 0x2C8 */ + volatile uint32 ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */ + volatile uint32 ieee_r_crc; /* MBAR_ETH + 0x2D0 */ + volatile uint32 ieee_r_align; /* MBAR_ETH + 0x2D4 */ + volatile uint32 r_macerr; /* MBAR_ETH + 0x2D8 */ + volatile uint32 r_fdxfc; /* MBAR_ETH + 0x2DC */ + volatile uint32 ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */ + + volatile uint32 RES14[6]; /* MBAR_ETH + 0x2E4-2FC */ + + volatile uint32 RES15[64]; /* MBAR_ETH + 0x300-3FF */ +} ethernet_regs; + +/* Receive & Transmit Buffer Descriptor definitions */ +typedef struct BufferDescriptor { + uint16 status; + uint16 dataLength; + uint32 dataPointer; +} FEC_RBD; + +typedef struct { + uint16 status; + uint16 dataLength; + uint32 dataPointer; +} FEC_TBD; + +/* private structure */ +typedef enum { + SEVENWIRE, /* 7-wire */ + MII10, /* MII 10Mbps */ + MII100 /* MII 100Mbps */ +} xceiver_type; + +/* BD Numer definitions */ +#define FEC_TBD_NUM 48 /* The user can adjust this value */ +#define FEC_RBD_NUM 32 /* The user can adjust this value */ + +/* packet size limit */ +#define FEC_MAX_PKT_SIZE 1536 + +typedef struct { + uint8 frame[FEC_MAX_PKT_SIZE]; +} mpc512x_frame; + +typedef struct { + FEC_RBD rbd[FEC_RBD_NUM]; /* RBD ring */ + FEC_TBD tbd[FEC_TBD_NUM]; /* TBD ring */ + mpc512x_frame recv_frames[FEC_RBD_NUM]; /* receive buff */ +} mpc512x_buff_descs; + +typedef struct { + ethernet_regs *eth; + xceiver_type xcv_type; /* transceiver type */ + mpc512x_buff_descs *bdBase; /* BD rings and recv buffer */ + uint16 rbdIndex; /* next receive BD to read */ + uint16 tbdIndex; /* next transmit BD to send */ + uint16 usedTbdIndex; /* next transmit BD to clean */ + uint16 cleanTbdNum; /* the number of available transmit BDs */ +} mpc512x_fec_priv; + +/* RBD bits definitions */ +#define FEC_RBD_EMPTY 0x8000 /* Buffer is empty */ +#define FEC_RBD_WRAP 0x2000 /* Last BD in ring */ +#define FEC_RBD_LAST 0x0800 /* Buffer is last in frame(useless) */ +#define FEC_RBD_MISS 0x0100 /* Miss bit for prom mode */ +#define FEC_RBD_BC 0x0080 /* The received frame is broadcast frame */ +#define FEC_RBD_MC 0x0040 /* The received frame is multicast frame */ +#define FEC_RBD_LG 0x0020 /* Frame length violation */ +#define FEC_RBD_NO 0x0010 /* Nonoctet align frame */ +#define FEC_RBD_SH 0x0008 /* Short frame */ +#define FEC_RBD_CR 0x0004 /* CRC error */ +#define FEC_RBD_OV 0x0002 /* Receive FIFO overrun */ +#define FEC_RBD_TR 0x0001 /* Frame is truncated */ +#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \ + FEC_RBD_OV | FEC_RBD_TR) + +/* TBD bits definitions */ +#define FEC_TBD_READY 0x8000 /* Buffer is ready */ +#define FEC_TBD_WRAP 0x2000 /* Last BD in ring */ +#define FEC_TBD_LAST 0x0800 /* Buffer is last in frame */ +#define FEC_TBD_TC 0x0400 /* Transmit the CRC */ +#define FEC_TBD_ABC 0x0200 /* Append bad CRC */ + +/* MII-related definitios */ +#define FEC_MII_DATA_ST 0x40000000 /* Start of frame delimiter */ +#define FEC_MII_DATA_OP_RD 0x20000000 /* Perform a read operation */ +#define FEC_MII_DATA_OP_WR 0x10000000 /* Perform a write operation */ +#define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address field mask */ +#define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register field mask */ +#define FEC_MII_DATA_TA 0x00020000 /* Turnaround */ +#define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data field */ + +#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */ +#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */ + +#endif /* __MPC512X_FEC_H */ diff --git a/cpu/mpc512x/i2c.c b/cpu/mpc512x/i2c.c new file mode 100644 index 0000000..00e28d6 --- /dev/null +++ b/cpu/mpc512x/i2c.c @@ -0,0 +1,431 @@ +/* + * (C) Copyright 2003 - 2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Based on the MPC5xxx code. + */ + +#include <common.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_HARD_I2C + +#include <mpc512x.h> +#include <i2c.h> + +#define immr ((immap_t *)CFG_IMMR) + +/* by default set I2C bus 0 active */ +static unsigned int bus_num = 0; + +#define I2C_TIMEOUT 100 +#define I2C_RETRIES 3 + +struct mpc512x_i2c_tap { + int scl2tap; + int tap2tap; +}; + +static int mpc_reg_in(volatile u32 *reg); +static void mpc_reg_out(volatile u32 *reg, int val, int mask); +static int wait_for_bb(void); +static int wait_for_pin(int *status); +static int do_address(uchar chip, char rdwr_flag); +static int send_bytes(uchar chip, char *buf, int len); +static int receive_bytes(uchar chip, char *buf, int len); +static int mpc_get_fdr(int); + +static int mpc_reg_in (volatile u32 *reg) +{ + int ret = *reg >> 24; + __asm__ __volatile__ ("eieio"); + return ret; +} + +static void mpc_reg_out (volatile u32 *reg, int val, int mask) +{ + int tmp; + + if (!mask) { + *reg = val << 24; + } else { + tmp = mpc_reg_in (reg); + *reg = ((tmp & ~mask) | (val & mask)) << 24; + } + __asm__ __volatile__ ("eieio"); + + return; +} + +static int wait_for_bb (void) +{ + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int timeout = I2C_TIMEOUT; + int status; + + status = mpc_reg_in (®s->msr); + + while (timeout-- && (status & I2C_BB)) { + volatile int temp; + mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); + temp = mpc_reg_in (®s->mdr); + mpc_reg_out (®s->mcr, 0, I2C_STA); + mpc_reg_out (®s->mcr, 0, 0); + mpc_reg_out (®s->mcr, I2C_EN, 0); + + udelay (1000); + status = mpc_reg_in (®s->msr); + } + + return (status & I2C_BB); +} + +static int wait_for_pin (int *status) +{ + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int timeout = I2C_TIMEOUT; + + *status = mpc_reg_in (®s->msr); + + while (timeout-- && !(*status & I2C_IF)) { + udelay (1000); + *status = mpc_reg_in (®s->msr); + } + + if (!(*status & I2C_IF)) { + return -1; + } + + mpc_reg_out (®s->msr, 0, I2C_IF); + + return 0; +} + +static int do_address (uchar chip, char rdwr_flag) +{ + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int status; + + chip <<= 1; + + if (rdwr_flag) { + chip |= 1; + } + + mpc_reg_out (®s->mcr, I2C_TX, I2C_TX); + mpc_reg_out (®s->mdr, chip, 0); + + if (wait_for_pin (&status)) { + return -2; + } + + if (status & I2C_RXAK) { + return -3; + } + + return 0; +} + +static int send_bytes (uchar chip, char *buf, int len) +{ + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int wrcount; + int status; + + for (wrcount = 0; wrcount < len; ++wrcount) { + + mpc_reg_out (®s->mdr, buf[wrcount], 0); + + if (wait_for_pin (&status)) { + break; + } + + if (status & I2C_RXAK) { + break; + } + + } + + return !(wrcount == len); +} + +static int receive_bytes (uchar chip, char *buf, int len) +{ + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int dummy = 1; + int rdcount = 0; + int status; + int i; + + mpc_reg_out (®s->mcr, 0, I2C_TX); + + for (i = 0; i < len; ++i) { + buf[rdcount] = mpc_reg_in (®s->mdr); + + if (dummy) { + dummy = 0; + } else { + rdcount++; + } + + if (wait_for_pin (&status)) { + return -4; + } + } + + mpc_reg_out (®s->mcr, I2C_TXAK, I2C_TXAK); + buf[rdcount++] = mpc_reg_in (®s->mdr); + + if (wait_for_pin (&status)) { + return -5; + } + + mpc_reg_out (®s->mcr, 0, I2C_TXAK); + + return 0; +} + +/**************** I2C API ****************/ + +void i2c_init (int speed, int saddr) +{ + int i; + for(i = 0; i < I2C_BUS_CNT; i++){ + i2c512x_dev_t *regs = &immr->i2c.dev[i]; + mpc_reg_out (®s->mcr, 0, 0); + + /* Set clock */ + mpc_reg_out (®s->mfdr, mpc_get_fdr (speed), 0); + mpc_reg_out (®s->madr, saddr << 1, 0); + + /* Enable module */ + mpc_reg_out (®s->mcr, I2C_EN, I2C_INIT_MASK); + mpc_reg_out (®s->msr, 0, I2C_IF); + } + + /* Disable interrupts */ + immr->i2c.icr = 0; + /* Turn off filters */ + immr->i2c.mifr = 0; + return; +} + +static int mpc_get_fdr (int speed) +{ + static int fdr = -1; + + if (fdr == -1) { + ulong best_speed = 0; + ulong divider; + ulong ipb, scl; + ulong bestmatch = 0xffffffffUL; + int best_i = 0, best_j = 0, i, j; + int SCL_Tap[] = { 9, 10, 12, 15, 5, 6, 7, 8}; + struct mpc512x_i2c_tap scltap[] = { + {4, 1}, + {4, 2}, + {6, 4}, + {6, 8}, + {14, 16}, + {30, 32}, + {62, 64}, + {126, 128} + }; + + ipb = gd->ipb_clk; + for (i = 7; i >= 0; i--) { + for (j = 7; j >= 0; j--) { + scl = 2 * (scltap[j].scl2tap + + (SCL_Tap[i] - 1) * scltap[j].tap2tap + + 2); + if (ipb <= speed*scl) { + if ((speed*scl - ipb) < bestmatch) { + bestmatch = speed*scl - ipb; + best_i = i; + best_j = j; + best_speed = ipb/scl; + } + } + } + } + divider = (best_i & 3) | ((best_i & 4) << 3) | (best_j << 2); + if (gd->flags & GD_FLG_RELOC) { + fdr = divider; + } else { + debug("%ld kHz, \n", best_speed / 1000); + return divider; + } + } + + return fdr; +} + +int i2c_probe (uchar chip) +{ + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int i; + + for (i = 0; i < I2C_RETRIES; i++) { + mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); + + if (! do_address (chip, 0)) { + mpc_reg_out (®s->mcr, 0, I2C_STA); + udelay (500); + break; + } + + mpc_reg_out (®s->mcr, 0, I2C_STA); + udelay (500); + } + + return (i == I2C_RETRIES); +} + +int i2c_read (uchar chip, uint addr, int alen, uchar *buf, int len) +{ + char xaddr[4]; + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int ret = -1; + + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + + if (wait_for_bb ()) { + printf ("i2c_read: bus is busy\n"); + goto Done; + } + + mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); + if (do_address (chip, 0)) { + printf ("i2c_read: failed to address chip\n"); + goto Done; + } + + if (send_bytes (chip, &xaddr[4-alen], alen)) { + printf ("i2c_read: send_bytes failed\n"); + goto Done; + } + + mpc_reg_out (®s->mcr, I2C_RSTA, I2C_RSTA); + if (do_address (chip, 1)) { + printf ("i2c_read: failed to address chip\n"); + goto Done; + } + + if (receive_bytes (chip, (char *)buf, len)) { + printf ("i2c_read: receive_bytes failed\n"); + goto Done; + } + + ret = 0; +Done: + mpc_reg_out (®s->mcr, 0, I2C_STA); + return ret; +} + +int i2c_write (uchar chip, uint addr, int alen, uchar *buf, int len) +{ + char xaddr[4]; + i2c512x_dev_t *regs = &immr->i2c.dev[bus_num]; + int ret = -1; + + xaddr[0] = (addr >> 24) & 0xFF; + xaddr[1] = (addr >> 16) & 0xFF; + xaddr[2] = (addr >> 8) & 0xFF; + xaddr[3] = addr & 0xFF; + + if (wait_for_bb ()) { + printf ("i2c_write: bus is busy\n"); + goto Done; + } + + mpc_reg_out (®s->mcr, I2C_STA, I2C_STA); + if (do_address (chip, 0)) { + printf ("i2c_write: failed to address chip\n"); + goto Done; + } + + if (send_bytes (chip, &xaddr[4-alen], alen)) { + printf ("i2c_write: send_bytes failed\n"); + goto Done; + } + + if (send_bytes (chip, (char *)buf, len)) { + printf ("i2c_write: send_bytes failed\n"); + goto Done; + } + + ret = 0; +Done: + mpc_reg_out (®s->mcr, 0, I2C_STA); + return ret; +} + +uchar i2c_reg_read (uchar chip, uchar reg) +{ + uchar buf; + + i2c_read (chip, reg, 1, &buf, 1); + + return buf; +} + +void i2c_reg_write (uchar chip, uchar reg, uchar val) +{ + i2c_write (chip, reg, 1, &val, 1); + + return; +} + + +int i2c_set_bus_num (unsigned int bus) +{ + if (bus >= I2C_BUS_CNT) { + return -1; + } + bus_num = bus; + + return 0; +} + +unsigned int i2c_get_bus_num (void) +{ + return bus_num; +} + +/* TODO */ +unsigned int i2c_get_bus_speed (void) +{ + return -1; +} + +int i2c_set_bus_speed (unsigned int speed) +{ + if (speed != CFG_I2C_SPEED) + return -1; + + return 0; +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/cpu/mpc512x/interrupts.c b/cpu/mpc512x/interrupts.c new file mode 100644 index 0000000..8cc241c --- /dev/null +++ b/cpu/mpc512x/interrupts.c @@ -0,0 +1,61 @@ +/* + * (C) Copyright 2000-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright 2004 Freescale Semiconductor, 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 + * + * Derived from the MPC83xx code. + */ + +#include <common.h> + +DECLARE_GLOBAL_DATA_PTR; + +struct irq_action { + interrupt_handler_t *handler; + void *arg; + ulong count; +}; + +int interrupt_init_cpu (unsigned *decrementer_count) +{ + *decrementer_count = get_tbclk () / CFG_HZ; + + return 0; +} + +/* + * Install and free an interrupt handler. + */ +void +irq_install_handler (int irq, interrupt_handler_t * handler, void *arg) +{ +} + +void irq_free_handler (int irq) +{ +} + +void timer_interrupt_cpu (struct pt_regs *regs) +{ + /* nothing to do here */ + return; +} diff --git a/cpu/mpc512x/serial.c b/cpu/mpc512x/serial.c new file mode 100644 index 0000000..200ff2c --- /dev/null +++ b/cpu/mpc512x/serial.c @@ -0,0 +1,197 @@ +/* + * (C) Copyright 2000 - 2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + * + * Based ont the MPC5200 PSC driver. + * Adapted for MPC512x by Jan Wrobel <wrr@semihalf.com> + */ + +/* + * Minimal serial functions needed to use one of the PSC ports + * as serial console interface. + */ + +#include <common.h> + +DECLARE_GLOBAL_DATA_PTR; + +#if defined(CONFIG_PSC_CONSOLE) + +static void fifo_init (volatile psc512x_t *psc) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + + /* reset Rx & Tx fifo slice */ + psc->rfcmd = PSC_FIFO_RESET_SLICE; + psc->tfcmd = PSC_FIFO_RESET_SLICE; + + /* disable Tx & Rx FIFO interrupts */ + psc->rfintmask = 0; + psc->tfintmask = 0; + + psc->tfsize = CONSOLE_FIFO_TX_SIZE | (CONSOLE_FIFO_TX_ADDR << 16); + psc->rfsize = CONSOLE_FIFO_RX_SIZE | (CONSOLE_FIFO_RX_ADDR << 16); + + /* enable Tx & Rx FIFO slice */ + psc->rfcmd = PSC_FIFO_ENABLE_SLICE; + psc->tfcmd = PSC_FIFO_ENABLE_SLICE; + + im->fifoc.fifoc_cmd = FIFOC_DISABLE_CLOCK_GATE; + __asm__ volatile ("sync"); +} + +int serial_init(void) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + unsigned long baseclk; + int div; + + fifo_init (psc); + + /* set MR register to point to MR1 */ + psc->command = PSC_SEL_MODE_REG_1; + + /* disable Tx/Rx */ + psc->command = PSC_TX_DISABLE | PSC_RX_DISABLE; + + /* choose the prescaler by 16 for the Tx/Rx clock generation */ + psc->psc_clock_select = 0xdd00; + + /* switch to UART mode */ + psc->sicr = 0; + + /* mode register points to mr1 */ + /* configure parity, bit length and so on in mode register 1*/ + psc->mode = PSC_MODE_8_BITS | PSC_MODE_PARNONE; + /* now, mode register points to mr2 */ + psc->mode = PSC_MODE_1_STOPBIT; + + /* calculate dividor for setting PSC CTUR and CTLR registers */ + baseclk = (gd->ipb_clk + 8) / 16; + div = (baseclk + (gd->baudrate / 2)) / gd->baudrate; + + psc->ctur = (div >> 8) & 0xff; + /* set baudrate */ + psc->ctlr = div & 0xff; + + /* disable all interrupts */ + psc->psc_imr = 0; + + /* reset and enable Rx/Tx */ + psc->command = PSC_RST_RX; + psc->command = PSC_RST_TX; + psc->command = PSC_RX_ENABLE | PSC_TX_ENABLE; + + return 0; +} + +void serial_putc (const char c) +{ + volatile immap_t *im = (immap_t *)CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + + if (c == '\n') + serial_putc ('\r'); + + /* Wait for last character to go. */ + while (!(psc->psc_status & PSC_SR_TXEMP)) + ; + + psc->tfdata_8 = c; +} + +void serial_putc_raw (const char c) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + + /* Wait for last character to go. */ + while (!(psc->psc_status & PSC_SR_TXEMP)) + ; + + psc->tfdata_8 = c; +} + + +void serial_puts (const char *s) +{ + while (*s) { + serial_putc (*s++); + } +} + +int serial_getc (void) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + + /* Wait for a character to arrive. */ + while (psc->rfstat & PSC_FIFO_EMPTY) + ; + + return psc->rfdata_8; +} + +int serial_tstc (void) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + + return !(psc->rfstat & PSC_FIFO_EMPTY); +} + +void serial_setbrg (void) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + unsigned long baseclk, div; + + baseclk = (gd->csb_clk + 8) / 16; + div = (baseclk + (gd->baudrate / 2)) / gd->baudrate; + + psc->ctur = (div >> 8) & 0xFF; + psc->ctlr = div & 0xff; /* set baudrate */ +} + +void serial_setrts(int s) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + + if (s) { + /* Assert RTS (become LOW) */ + psc->op1 = 0x1; + } + else { + /* Negate RTS (become HIGH) */ + psc->op0 = 0x1; + } +} + +int serial_getcts(void) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + volatile psc512x_t *psc = (psc512x_t *) &im->psc[CONFIG_PSC_CONSOLE]; + + return (psc->ip & 0x1) ? 0 : 1; +} +#endif /* CONFIG_PSC_CONSOLE */ diff --git a/cpu/mpc512x/speed.c b/cpu/mpc512x/speed.c new file mode 100644 index 0000000..a609827 --- /dev/null +++ b/cpu/mpc512x/speed.c @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2000-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 2004-2006 Freescale Semiconductor, 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 + * + * Based on the MPC83xx code. + */ + +#include <common.h> +#include <mpc512x.h> +#include <command.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int spmf_mult[] = { + 68, 1, 12, 16, + 20, 24, 28, 32, + 36, 40, 44, 48, + 52, 56, 60, 64 +}; + +static int cpmf_mult[][2] = { + {0, 1}, {0, 1}, /* 0 and 1 are not valid */ + {1, 1}, {3, 2}, + {2, 1}, {5, 2}, + {3, 1}, {7, 2}, + {0, 1}, {0, 1}, /* and all above 7 are not valid too */ + {0, 1}, {0, 1}, + {0, 1}, {0, 1}, + {0, 1}, {0, 1} +}; + +static int sys_dividors[][2] = { + {2, 1}, {5, 2}, {3, 1}, {7, 2}, {4, 1}, + {9, 2}, {5, 1}, {7, 1}, {6, 1}, {8, 1}, + {9, 1}, {11, 1}, {10, 1}, {12, 1}, {13, 1}, + {15, 1}, {14, 1}, {16, 1}, {17, 1}, {19, 1}, + {18, 1}, {20, 1}, {21, 1}, {23, 1}, {22, 1}, + {24, 1}, {25, 1}, {27, 1}, {26, 1}, {28, 1}, + {29, 1}, {31, 1}, {30, 1}, {32, 1}, {33, 1} +}; + +int get_clocks (void) +{ + volatile immap_t *im = (immap_t *) CFG_IMMR; + u8 spmf; + u8 cpmf; + u8 sys_div; + u8 ips_div; + u32 ref_clk = CFG_MPC512X_CLKIN; + u32 spll; + u32 sys_clk; + u32 core_clk; + u32 csb_clk; + u32 ips_clk; + + if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32) im) + return -1; + + spmf = (im->clk.spmr & SPMR_SPMF) >> SPMR_SPMF_SHIFT; + spll = ref_clk * spmf_mult[spmf]; + + sys_div = (im->clk.scfr[1] & SCFR2_SYS_DIV) >> SCFR2_SYS_DIV_SHIFT; + sys_clk = (spll * sys_dividors[sys_div][1]) / sys_dividors[sys_div][0]; + + csb_clk = sys_clk / 2; + + cpmf = (im->clk.spmr & SPMR_CPMF) >> SPMR_CPMF_SHIFT; + core_clk = (csb_clk * cpmf_mult[cpmf][0]) / cpmf_mult[cpmf][1]; + + ips_div = (im->clk.scfr[0] & SCFR1_IPS_DIV_MASK) >> SCFR1_IPS_DIV_SHIFT; + if (ips_div != 0) { + ips_clk = csb_clk / ips_div; + } else { + /* in case we cannot get a sane IPS divisor, fail gracefully */ + ips_clk = 0; + } + + gd->ipb_clk = ips_clk; + gd->csb_clk = csb_clk; + gd->cpu_clk = core_clk; + gd->bus_clk = csb_clk; + return 0; + +} + +/******************************************** + * get_bus_freq + * return system bus freq in Hz + *********************************************/ +ulong get_bus_freq (ulong dummy) +{ + return gd->csb_clk; +} + +int do_clocks (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + printf ("Clock configuration:\n"); + printf (" CPU: %4d MHz\n", gd->cpu_clk / 1000000); + printf (" Coherent System Bus: %4d MHz\n", gd->csb_clk / 1000000); + printf (" IPS Bus: %4d MHz\n", gd->ipb_clk / 1000000); + printf (" DDR: %4d MHz\n", 2 * gd->csb_clk / 1000000); + return 0; +} + +U_BOOT_CMD(clocks, 1, 0, do_clocks, + "clocks - print clock configuration\n", + " clocks\n" +); + +int prt_mpc512x_clks (void) +{ + do_clocks (NULL, 0, 0, NULL); + return (0); +} diff --git a/cpu/mpc512x/start.S b/cpu/mpc512x/start.S new file mode 100644 index 0000000..244c69b --- /dev/null +++ b/cpu/mpc512x/start.S @@ -0,0 +1,780 @@ +/* + * Copyright (C) 1998 Dan Malek <dmalek@jlc.net> + * Copyright (C) 1999 Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> + * Copyright (C) 2000, 2001, 2002, 2007 Wolfgang Denk <wd@denx.de> + * Copyright Freescale Semiconductor, Inc. 2004, 2006. All rights reserved. + * + * 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 + * + * Based on the MPC83xx code. + */ + +/* + * U-Boot - Startup Code for MPC512x based Embedded Boards + */ + +#include <config.h> +#include <mpc512x.h> +#include <version.h> + +#define CONFIG_521X 1 /* needed for Linux kernel header files*/ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#ifndef CONFIG_IDENT_STRING +#define CONFIG_IDENT_STRING "MPC512X" +#endif + +/* + * Floating Point enable, Machine Check and Recoverable Interr. + */ +#undef MSR_KERNEL +#ifdef DEBUG +#define MSR_KERNEL (MSR_FP|MSR_RI) +#else +#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI) +#endif + +/* Macros for manipulating CSx_START/STOP */ +#define START_REG(start) ((start) >> 16) +#define STOP_REG(start, size) (((start) + (size) - 1) >> 16) + +/* + * Set up GOT: Global Offset Table + * + * Use r14 to access the GOT + */ + START_GOT + GOT_ENTRY(_GOT2_TABLE_) + GOT_ENTRY(_FIXUP_TABLE_) + + GOT_ENTRY(_start) + GOT_ENTRY(_start_of_vectors) + GOT_ENTRY(_end_of_vectors) + GOT_ENTRY(transfer_to_handler) + + GOT_ENTRY(__init_end) + GOT_ENTRY(_end) + GOT_ENTRY(__bss_start) + END_GOT + +/* + * Magic number and version string + */ + .long 0x27051956 /* U-Boot Magic Number */ + .globl version_string +version_string: + .ascii U_BOOT_VERSION + .ascii " (", __DATE__, " - ", __TIME__, ")" + .ascii " ", CONFIG_IDENT_STRING, "\0" + +/* + * Vector Table + */ + .text + . = EXC_OFF_SYS_RESET + + .globl _start + /* Start from here after reset/power on */ +_start: + li r21, BOOTFLAG_COLD /* Normal Power-On: Boot from FLASH */ + b boot_cold + + .globl _start_of_vectors +_start_of_vectors: + +/* Machine check */ + STD_EXCEPTION(0x200, MachineCheck, MachineCheckException) + +/* Data Storage exception. */ + STD_EXCEPTION(0x300, DataStorage, UnknownException) + +/* Instruction Storage exception. */ + STD_EXCEPTION(0x400, InstStorage, UnknownException) + +/* External Interrupt exception. */ + STD_EXCEPTION(0x500, ExtInterrupt, UnknownException) + +/* Alignment exception. */ + . = 0x600 +Alignment: + EXCEPTION_PROLOG(SRR0, SRR1) + mfspr r4,DAR + stw r4,_DAR(r21) + mfspr r5,DSISR + stw r5,_DSISR(r21) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + rlwimi r20,r23,0,25,25 /* copy IP bit from saved MSR */ + lwz r6,GOT(transfer_to_handler) + mtlr r6 + blrl +.L_Alignment: + .long AlignmentException - _start + EXC_OFF_SYS_RESET + .long int_return - _start + EXC_OFF_SYS_RESET + +/* Program check exception */ + . = 0x700 +ProgramCheck: + EXCEPTION_PROLOG(SRR0, SRR1) + addi r3,r1,STACK_FRAME_OVERHEAD + li r20,MSR_KERNEL + rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ + rlwimi r20,r23,0,25,25 /* copy IP bit from saved MSR */ + lwz r6,GOT(transfer_to_handler) + mtlr r6 + blrl +.L_ProgramCheck: + .long ProgramCheckException - _start + EXC_OFF_SYS_RESET + .long int_return - _start + EXC_OFF_SYS_RESET + +/* Floating Point Unit unavailable exception */ + STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + +/* Decrementer */ + STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + +/* Critical interrupt */ + STD_EXCEPTION(0xa00, Critical, UnknownException) + +/* System Call */ + STD_EXCEPTION(0xc00, SystemCall, UnknownException) + +/* Trace interrupt */ + STD_EXCEPTION(0xd00, Trace, UnknownException) + +/* Performance Monitor interrupt */ + STD_EXCEPTION(0xf00, PerfMon, UnknownException) + +/* Intruction Translation Miss */ + STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException) + +/* Data Load Translation Miss */ + STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException) + +/* Data Store Translation Miss */ + STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException) + +/* Instruction Address Breakpoint */ + STD_EXCEPTION(0x1300, InstructionAddrBreakpoint, DebugException) + +/* System Management interrupt */ + STD_EXCEPTION(0x1400, SystemMgmtInterrupt, UnknownException) + + .globl _end_of_vectors +_end_of_vectors: + + . = 0x3000 +boot_cold: + /* Save msr contents */ + mfmsr r5 + + /* Set IMMR area to our preferred location */ + lis r4, CONFIG_DEFAULT_IMMR@h + lis r3, CFG_IMMR@h + ori r3, r3, CFG_IMMR@l + stw r3, IMMRBAR(r4) + mtspr MBAR, r3 /* IMMRBAR is mirrored into the MBAR SPR (311) */ + + /* Initialise the machine */ + bl cpu_early_init + + /* + * Set up Local Access Windows: + * + * 1) Boot/CS0 (boot FLASH) + * 2) On-chip SRAM (initial stack purposes) + */ + + /* Boot CS/CS0 window range */ + lis r3, CFG_IMMR@h + ori r3, r3, CFG_IMMR@l + + lis r4, START_REG(CFG_FLASH_BASE) + ori r4, r4, STOP_REG(CFG_FLASH_BASE, CFG_FLASH_SIZE) + stw r4, LPCS0AW(r3) + + /* + * The SRAM window has a fixed size (256K), so only the start address + * is necessary + */ + lis r4, START_REG(CFG_SRAM_BASE) & 0xff00 + stw r4, SRAMBAR(r3) + + /* + * According to MPC5121e RM, configuring local access windows should + * be followed by a dummy read of the config register that was + * modified last and an isync + */ + lwz r4, SRAMBAR(r3) + isync + + /* + * Set configuration of the Boot/CS0, the SRAM window does not have a + * config register so no params can be set for it + */ + lis r3, (CFG_IMMR + LPC_OFFSET)@h + ori r3, r3, (CFG_IMMR + LPC_OFFSET)@l + + lis r4, CFG_CS0_CFG@h + ori r4, r4, CFG_CS0_CFG@l + stw r4, CS0_CONFIG(r3) + + /* Master enable all CS's */ + lis r4, CS_CTRL_ME@h + ori r4, r4, CS_CTRL_ME@l + stw r4, CS_CTRL(r3) + + lis r4, (CFG_MONITOR_BASE)@h + ori r4, r4, (CFG_MONITOR_BASE)@l + addi r5, r4, in_flash - _start + EXC_OFF_SYS_RESET + mtlr r5 + blr + +in_flash: + lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h + ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l + + li r0, 0 /* Make room for stack frame header and */ + stwu r0, -4(r1) /* clear final stack frame so that */ + stwu r0, -4(r1) /* stack backtraces terminate cleanly */ + + /* let the C-code set up the rest */ + /* */ + /* Be careful to keep code relocatable & stack humble */ + /*------------------------------------------------------*/ + + GET_GOT /* initialize GOT access */ + + /* r3: IMMR */ + lis r3, CFG_IMMR@h + /* run low-level CPU init code (in Flash) */ + bl cpu_init_f + + /* r3: BOOTFLAG */ + mr r3, r21 + /* run 1st part of board init code (in Flash) */ + bl board_init_f + + /* NOTREACHED - board_init_f() does not return */ + +/* + * This code finishes saving the registers to the exception frame + * and jumps to the appropriate handler for the exception. + * Register r21 is pointer into trap frame, r1 has new stack pointer. + */ + .globl transfer_to_handler +transfer_to_handler: + stw r22,_NIP(r21) + lis r22,MSR_POW@h + andc r23,r23,r22 + stw r23,_MSR(r21) + SAVE_GPR(7, r21) + SAVE_4GPRS(8, r21) + SAVE_8GPRS(12, r21) + SAVE_8GPRS(24, r21) + mflr r23 + andi. r24,r23,0x3f00 /* get vector offset */ + stw r24,TRAP(r21) + li r22,0 + stw r22,RESULT(r21) + lwz r24,0(r23) /* virtual address of handler */ + lwz r23,4(r23) /* where to go when done */ + mtspr SRR0,r24 + mtspr SRR1,r20 + mtlr r23 + SYNC + rfi /* jump to handler, enable MMU */ + +int_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SRR0,r2 + mtspr SRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfi + +/* + * This code initialises the machine, it expects original MSR contents to be in r5. + */ +cpu_early_init: + /* Initialize machine status; enable machine check interrupt */ + /*-----------------------------------------------------------*/ + + li r3, MSR_KERNEL /* Set ME and RI flags */ + rlwimi r3, r5, 0, 25, 25 /* preserve IP bit */ +#ifdef DEBUG + rlwimi r3, r5, 0, 21, 22 /* debugger might set SE, BE bits */ +#endif + mtmsr r3 + SYNC + mtspr SRR1, r3 /* Mirror current MSR state in SRR1 */ + + lis r3, CFG_IMMR@h + +#if defined(CONFIG_WATCHDOG) + /* Initialise the watchdog and reset it */ + /*--------------------------------------*/ + lis r4, CFG_WATCHDOG_VALUE + ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR) + stw r4, SWCRR(r3) + + /* reset */ + li r4, 0x556C + sth r4, SWSRR@l(r3) + li r4, 0x0 + ori r4, r4, 0xAA39 + sth r4, SWSRR@l(r3) +#else + /* Disable the watchdog */ + /*----------------------*/ + lwz r4, SWCRR(r3) + /* + * Check to see if it's enabled for disabling: once disabled by s/w + * it's not possible to re-enable it + */ + andi. r4, r4, 0x4 + beq 1f + xor r4, r4, r4 + stw r4, SWCRR(r3) +1: +#endif /* CONFIG_WATCHDOG */ + + /* Initialize the Hardware Implementation-dependent Registers */ + /* HID0 also contains cache control */ + /*------------------------------------------------------*/ + lis r3, CFG_HID0_INIT@h + ori r3, r3, CFG_HID0_INIT@l + SYNC + mtspr HID0, r3 + + lis r3, CFG_HID0_FINAL@h + ori r3, r3, CFG_HID0_FINAL@l + SYNC + mtspr HID0, r3 + + lis r3, CFG_HID2@h + ori r3, r3, CFG_HID2@l + SYNC + mtspr HID2, r3 + sync + blr + + +/* Cache functions. + * + * Note: requires that all cache bits in + * HID0 are in the low half word. + */ + .globl icache_enable +icache_enable: + mfspr r3, HID0 + ori r3, r3, HID0_ICE + lis r4, 0 + ori r4, r4, HID0_ILOCK + andc r3, r3, r4 + ori r4, r3, HID0_ICFI + isync + mtspr HID0, r4 /* sets enable and invalidate, clears lock */ + isync + mtspr HID0, r3 /* clears invalidate */ + blr + + .globl icache_disable +icache_disable: + mfspr r3, HID0 + lis r4, 0 + ori r4, r4, HID0_ICE|HID0_ILOCK + andc r3, r3, r4 + ori r4, r3, HID0_ICFI + isync + mtspr HID0, r4 /* sets invalidate, clears enable and lock*/ + isync + mtspr HID0, r3 /* clears invalidate */ + blr + + .globl icache_status +icache_status: + mfspr r3, HID0 + rlwinm r3, r3, (31 - HID0_ICE_SHIFT + 1), 31, 31 + blr + + .globl dcache_enable +dcache_enable: + mfspr r3, HID0 + li r5, HID0_DCFI|HID0_DLOCK + andc r3, r3, r5 + mtspr HID0, r3 /* no invalidate, unlock */ + ori r3, r3, HID0_DCE + ori r5, r3, HID0_DCFI + mtspr HID0, r5 /* enable + invalidate */ + mtspr HID0, r3 /* enable */ + sync + blr + + .globl dcache_disable +dcache_disable: + mfspr r3, HID0 + lis r4, 0 + ori r4, r4, HID0_DCE|HID0_DLOCK + andc r3, r3, r4 + ori r4, r3, HID0_DCI + sync + mtspr HID0, r4 /* sets invalidate, clears enable and lock */ + sync + mtspr HID0, r3 /* clears invalidate */ + blr + + .globl dcache_status +dcache_status: + mfspr r3, HID0 + rlwinm r3, r3, (31 - HID0_DCE_SHIFT + 1), 31, 31 + blr + + .globl get_pvr +get_pvr: + mfspr r3, PVR + blr + +/*------------------------------------------------------------------------------- */ +/* Function: ppcDcbf */ +/* Description: Data Cache block flush */ +/* Input: r3 = effective address */ +/* Output: none. */ +/*------------------------------------------------------------------------------- */ + .globl ppcDcbf +ppcDcbf: + dcbf r0,r3 + blr + +/*------------------------------------------------------------------------------- */ +/* Function: ppcDcbi */ +/* Description: Data Cache block Invalidate */ +/* Input: r3 = effective address */ +/* Output: none. */ +/*------------------------------------------------------------------------------- */ + .globl ppcDcbi +ppcDcbi: + dcbi r0,r3 + blr + +/*-------------------------------------------------------------------------- + * Function: ppcDcbz + * Description: Data Cache block zero. + * Input: r3 = effective address + * Output: none. + *-------------------------------------------------------------------------- */ + + .globl ppcDcbz +ppcDcbz: + dcbz r0,r3 + blr + + .globl ppcDWstore +ppcDWstore: + lfd 1, 0(r4) + stfd 1, 0(r3) + blr + + .globl ppcDWload +ppcDWload: + lfd 1, 0(r3) + stfd 1, 0(r4) + blr + +/*-------------------------------------------------------------------*/ + +/* + * void relocate_code (addr_sp, gd, addr_moni) + * + * This "function" does not return, instead it continues in RAM + * after relocating the monitor code. + * + * r3 = dest + * r4 = src + * r5 = length in bytes + * r6 = cachelinesize + */ + .globl relocate_code +relocate_code: + mr r1, r3 /* Set new stack pointer */ + mr r9, r4 /* Save copy of Global Data pointer */ + mr r10, r5 /* Save copy of Destination Address */ + + mr r3, r5 /* Destination Address */ + lis r4, CFG_MONITOR_BASE@h /* Source Address */ + ori r4, r4, CFG_MONITOR_BASE@l + lwz r5, GOT(__init_end) + sub r5, r5, r4 + li r6, CFG_CACHELINE_SIZE /* Cache Line Size */ + + /* + * Fix GOT pointer: + * + * New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + * + Destination Address + * + * Offset: + */ + sub r15, r10, r4 + + /* First our own GOT */ + add r14, r14, r15 + /* then the one used by the C code */ + add r30, r30, r15 + + /* + * Now relocate code + */ + cmplw cr1,r3,r4 + addi r0,r5,3 + srwi. r0,r0,2 + beq cr1,4f /* In place copy is not necessary */ + beq 7f /* Protect against 0 count */ + mtctr r0 + bge cr1,2f + la r8,-4(r4) + la r7,-4(r3) + + /* copy */ +1: lwzu r0,4(r8) + stwu r0,4(r7) + bdnz 1b + + addi r0,r5,3 + srwi. r0,r0,2 + mtctr r0 + la r8,-4(r4) + la r7,-4(r3) + + /* and compare */ +20: lwzu r20,4(r8) + lwzu r21,4(r7) + xor. r22, r20, r21 + bne 30f + bdnz 20b + b 4f + + /* compare failed */ +30: li r3, 0 + blr + +2: slwi r0,r0,2 /* re copy in reverse order ... y do we needed it? */ + add r8,r4,r0 + add r7,r3,r0 +3: lwzu r0,-4(r8) + stwu r0,-4(r7) + bdnz 3b + +/* + * Now flush the cache: note that we must start from a cache aligned + * address. Otherwise we might miss one cache line. + */ +4: cmpwi r6,0 + add r5,r3,r5 + beq 7f /* Always flush prefetch queue in any case */ + subi r0,r6,1 + andc r3,r3,r0 + mr r4,r3 +5: dcbst 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 5b + sync /* Wait for all dcbst to complete on bus */ + mr r4,r3 +6: icbi 0,r4 + add r4,r4,r6 + cmplw r4,r5 + blt 6b +7: sync /* Wait for all icbi to complete on bus */ + isync + +/* + * We are done. Do not return, instead branch to second part of board + * initialization, now running from RAM. + */ + addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET + mtlr r0 + blr + +in_ram: + /* + * Relocation Function, r14 point to got2+0x8000 + * + * Adjust got2 pointers, no need to check for 0, this code + * already puts a few entries in the table. + */ + li r0,__got2_entries@sectoff@l + la r3,GOT(_GOT2_TABLE_) + lwz r11,GOT(_GOT2_TABLE_) + mtctr r0 + sub r11,r3,r11 + addi r3,r3,-4 +1: lwzu r0,4(r3) + add r0,r0,r11 + stw r0,0(r3) + bdnz 1b + + /* + * Now adjust the fixups and the pointers to the fixups + * in case we need to move ourselves again. + */ +2: li r0,__fixup_entries@sectoff@l + lwz r3,GOT(_FIXUP_TABLE_) + cmpwi r0,0 + mtctr r0 + addi r3,r3,-4 + beq 4f +3: lwzu r4,4(r3) + lwzux r0,r4,r11 + add r0,r0,r11 + stw r10,0(r3) + stw r0,0(r4) + bdnz 3b +4: +clear_bss: + /* + * Now clear BSS segment + */ + lwz r3,GOT(__bss_start) + lwz r4,GOT(_end) + + cmplw 0, r3, r4 + beq 6f + + li r0, 0 +5: + stw r0, 0(r3) + addi r3, r3, 4 + cmplw 0, r3, r4 + bne 5b +6: + mr r3, r9 /* Global Data pointer */ + mr r4, r10 /* Destination Address */ + bl board_init_r + + /* + * Copy exception vector code to low memory + * + * r3: dest_addr + * r7: source address, r8: end address, r9: target address + */ + .globl trap_init +trap_init: + lwz r7, GOT(_start) + lwz r8, GOT(_end_of_vectors) + + li r9, 0x100 /* reset vector at 0x100 */ + + cmplw 0, r7, r8 + bgelr /* return if r7>=r8 - just in case */ + + mflr r4 /* save link register */ +1: + lwz r0, 0(r7) + stw r0, 0(r9) + addi r7, r7, 4 + addi r9, r9, 4 + cmplw 0, r7, r8 + bne 1b + + /* + * relocate `hdlr' and `int_return' entries + */ + li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET + li r8, Alignment - _start + EXC_OFF_SYS_RESET +2: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 2b + + li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET + bl trap_reloc + + li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET + li r8, SystemCall - _start + EXC_OFF_SYS_RESET +3: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 3b + + li r7, .L_Trace - _start + EXC_OFF_SYS_RESET + li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET +4: + bl trap_reloc + addi r7, r7, 0x100 /* next exception vector */ + cmplw 0, r7, r8 + blt 4b + + mfmsr r3 /* now that the vectors have */ + lis r7, MSR_IP@h /* relocated into low memory */ + ori r7, r7, MSR_IP@l /* MSR[IP] can be turned off */ + andc r3, r3, r7 /* (if it was on) */ + SYNC /* Some chip revs need this... */ + mtmsr r3 + SYNC + + mtlr r4 /* restore link register */ + blr + + /* + * Function: relocate entries for one exception vector + */ +trap_reloc: + lwz r0, 0(r7) /* hdlr ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 0(r7) + + lwz r0, 4(r7) /* int_return ... */ + add r0, r0, r3 /* ... += dest_addr */ + stw r0, 4(r7) + + blr diff --git a/cpu/mpc512x/traps.c b/cpu/mpc512x/traps.c new file mode 100644 index 0000000..8455c92 --- /dev/null +++ b/cpu/mpc512x/traps.c @@ -0,0 +1,205 @@ +/* + * (C) Copyright 2000 - 2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) + * + * 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 + * + * Derived from the MPC83xx code. + */ + +/* + * This file handles the architecture-dependent parts of hardware + * exceptions + */ + +#include <common.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +extern unsigned long search_exception_table(unsigned long); + +#define END_OF_MEM (gd->bd->bi_memstart + gd->bd->bi_memsize) + +/* + * Trap & Exception support + */ + +void +print_backtrace (unsigned long *sp) +{ + int cnt = 0; + unsigned long i; + + puts ("Call backtrace: "); + while (sp) { + if ((uint)sp > END_OF_MEM) + break; + + i = sp[1]; + if (cnt++ % 7 == 0) + putc ('\n'); + printf ("%08lX ", i); + if (cnt > 32) break; + sp = (unsigned long *) *sp; + } + putc ('\n'); +} + +void show_regs (struct pt_regs * regs) +{ + int i; + + printf ("NIP: %08lX XER: %08lX LR: %08lX REGS: %p TRAP: %04lx DAR: %08lX\n", + regs->nip, regs->xer, regs->link, regs, regs->trap, regs->dar); + printf ("MSR: %08lx EE: %01x PR: %01x FP: %01x ME: %01x IR/DR: %01x%01x\n", + regs->msr, regs->msr & MSR_EE ? 1 : 0, regs->msr & MSR_PR ? 1 : 0, + regs->msr & MSR_FP ? 1 : 0,regs->msr & MSR_ME ? 1 : 0, + regs->msr & MSR_IR ? 1 : 0, + regs->msr & MSR_DR ? 1 : 0); + + putc ('\n'); + for (i = 0; i < 32; i++) { + if ((i % 8) == 0) { + printf ("GPR%02d: ", i); + } + + printf ("%08lX ", regs->gpr[i]); + if ((i % 8) == 7) { + putc ('\n'); + } + } +} + + +void +_exception (int signr, struct pt_regs *regs) +{ + show_regs (regs); + print_backtrace ((unsigned long *)regs->gpr[1]); + panic ("Exception at pc %lx signal %d", regs->nip,signr); +} + + +void +MachineCheckException (struct pt_regs *regs) +{ + unsigned long fixup; + + if ((fixup = search_exception_table (regs->nip)) != 0) { + regs->nip = fixup; + return; + } + +#ifdef CONFIG_CMD_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + puts ("Machine check.\nCaused by (from msr): "); + printf ("regs %p ",regs); + switch (regs->msr & 0x00FF0000) { + case (0x80000000 >> 10): + puts ("Instruction cache parity signal\n"); + break; + case (0x80000000 >> 11): + puts ("Data cache parity signal\n"); + break; + case (0x80000000 >> 12): + puts ("Machine check signal\n"); + break; + case (0x80000000 >> 13): + puts ("Transfer error ack signal\n"); + break; + case (0x80000000 >> 14): + puts ("Data parity signal\n"); + break; + case (0x80000000 >> 15): + puts ("Address parity signal\n"); + break; + default: + puts ("Unknown values in msr\n"); + } + show_regs (regs); + print_backtrace ((unsigned long *)regs->gpr[1]); + + panic ("machine check"); +} + +void +AlignmentException (struct pt_regs *regs) +{ +#ifdef CONFIG_CMD_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs (regs); + print_backtrace ((unsigned long *)regs->gpr[1]); + panic ("Alignment Exception"); +} + +void +ProgramCheckException (struct pt_regs *regs) +{ +#ifdef CONFIG_CMD_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs (regs); + print_backtrace ((unsigned long *)regs->gpr[1]); + panic ("Program Check Exception"); +} + +void +SoftEmuException (struct pt_regs *regs) +{ +#ifdef CONFIG_CMD_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + show_regs (regs); + print_backtrace ((unsigned long *)regs->gpr[1]); + panic ("Software Emulation Exception"); +} + + +void +UnknownException (struct pt_regs *regs) +{ +#ifdef CONFIG_CMD_KGDB + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + printf ("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", + regs->nip, regs->msr, regs->trap); + _exception (0, regs); +} + +#ifdef CONFIG_CMD_BEDBUG +extern void do_bedbug_breakpoint (struct pt_regs *); +#endif + +void +DebugException (struct pt_regs *regs) +{ + printf ("Debugger trap at @ %lx\n", regs->nip ); + show_regs (regs); +#ifdef CONFIG_CMD_BEDBUG + do_bedbug_breakpoint (regs); +#endif +} diff --git a/cpu/mpc5xx/config.mk b/cpu/mpc5xx/config.mk index 5b26a76..e95b8a1 100644 --- a/cpu/mpc5xx/config.mk +++ b/cpu/mpc5xx/config.mk @@ -28,6 +28,9 @@ # -PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi +PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -mrelocatable PLATFORM_CPPFLAGS += -DCONFIG_5xx -ffixed-r2 -ffixed-r29 -mpowerpc -msoft-float + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/cpu/mpc5xx/u-boot.lds diff --git a/cpu/mpc5xx/interrupts.c b/cpu/mpc5xx/interrupts.c index 7f6e136..a4f47c7 100644 --- a/cpu/mpc5xx/interrupts.c +++ b/cpu/mpc5xx/interrupts.c @@ -178,7 +178,7 @@ void timer_interrupt_cpu (struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) /******************************************************************************* * * irqinfo - print information about IRQs @@ -204,4 +204,4 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) } -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/mpc5xx/traps.c b/cpu/mpc5xx/traps.c index 14fd59e..d22b89a 100644 --- a/cpu/mpc5xx/traps.c +++ b/cpu/mpc5xx/traps.c @@ -36,11 +36,11 @@ #include <command.h> #include <asm/processor.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -131,7 +131,7 @@ void MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -165,7 +165,7 @@ void MachineCheckException(struct pt_regs *regs) */ void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -179,7 +179,7 @@ void AlignmentException(struct pt_regs *regs) */ void ProgramCheckException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -193,7 +193,7 @@ void ProgramCheckException(struct pt_regs *regs) */ void SoftEmuException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -208,7 +208,7 @@ void SoftEmuException(struct pt_regs *regs) */ void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -224,7 +224,7 @@ void DebugException(struct pt_regs *regs) { printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/mpc5xx/u-boot.lds b/cpu/mpc5xx/u-boot.lds new file mode 100644 index 0000000..10001b1 --- /dev/null +++ b/cpu/mpc5xx/u-boot.lds @@ -0,0 +1,139 @@ +/* + * (C) Copyright 2001 Wolfgang Denk, DENX Software Engineering, wd@denx.de + * (C) Copyright 2003 Martin Winistoerfer, martinwinistoerfer@gmx.ch + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + /* WARNING - the following is hand-optimized to fit within */ + /* the sector layout of our flash chips! XXX FIXME XXX */ + + cpu/mpc5xx/start.o (.text) + + *(.text) + *(.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 = .); +/* . = env_start; + .ppcenv : + { + common/environment.o (.ppcenv) + } +*/ +} diff --git a/cpu/mpc5xxx/Makefile b/cpu/mpc5xxx/Makefile index 235adb7..312b0bf 100644 --- a/cpu/mpc5xxx/Makefile +++ b/cpu/mpc5xxx/Makefile @@ -28,7 +28,7 @@ LIB = $(obj)lib$(CPU).a START = start.o SOBJS = io.o firmware_sc_task_bestcomm.impl.o firmware_sc_task.impl.o COBJS = i2c.o traps.o cpu.o cpu_init.o fec.o ide.o interrupts.o \ - loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o + loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o usb.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mpc5xxx/config.mk b/cpu/mpc5xxx/config.mk index ecd94e9..0e861c4 100644 --- a/cpu/mpc5xxx/config.mk +++ b/cpu/mpc5xxx/config.mk @@ -21,7 +21,10 @@ # MA 02111-1307 USA # -PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi +PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -mrelocatable PLATFORM_CPPFLAGS += -DCONFIG_MPC5xxx -ffixed-r2 -ffixed-r29 \ -mstring -mcpu=603e -mmultiple + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/cpu/mpc5xxx/u-boot.lds diff --git a/cpu/mpc5xxx/cpu_init.c b/cpu/mpc5xxx/cpu_init.c index d744030..bc6201e 100644 --- a/cpu/mpc5xxx/cpu_init.c +++ b/cpu/mpc5xxx/cpu_init.c @@ -198,7 +198,7 @@ int cpu_init_r (void) /* route critical ints to normal ints */ *(vu_long *)MPC5XXX_ICTL_EXT |= 0x00000001; -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_MPC5xxx_FEC) +#if defined(CONFIG_CMD_NET) && defined(CONFIG_MPC5xxx_FEC) /* load FEC microcode */ loadtask(0, 2); #endif diff --git a/cpu/mpc5xxx/fec.c b/cpu/mpc5xxx/fec.c index 3d99d5c..1d3da77 100644 --- a/cpu/mpc5xxx/fec.c +++ b/cpu/mpc5xxx/fec.c @@ -18,10 +18,10 @@ DECLARE_GLOBAL_DATA_PTR; /* #define DEBUG 0x28 */ -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ +#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ defined(CONFIG_MPC5xxx_FEC) -#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) #error "CONFIG_MII has to be defined!" #endif @@ -890,7 +890,7 @@ int mpc5xxx_fec_initialize(bd_t * bis) fec->tbdBase = (FEC_TBD *)FEC_BD_BASE; fec->rbdBase = (FEC_RBD *)(FEC_BD_BASE + FEC_TBD_NUM * sizeof(FEC_TBD)); #if defined(CONFIG_CANMB) || \ - defined(CONFIG_CM1_QP1) || \ + defined(CONFIG_CM5200) || \ defined(CONFIG_HMI1001) || \ defined(CONFIG_ICECUBE) || \ defined(CONFIG_INKA4X0) || \ @@ -924,7 +924,7 @@ int mpc5xxx_fec_initialize(bd_t * bis) sprintf(dev->name, "FEC ETHERNET"); eth_register(dev); -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register (dev->name, fec5xxx_miiphy_read, fec5xxx_miiphy_write); #endif diff --git a/cpu/mpc5xxx/ide.c b/cpu/mpc5xxx/ide.c index 29b99f6..087ddac 100644 --- a/cpu/mpc5xxx/ide.c +++ b/cpu/mpc5xxx/ide.c @@ -24,7 +24,7 @@ */ #include <common.h> -#ifdef CFG_CMD_IDE +#if defined(CONFIG_CMD_IDE) #include <mpc5xxx.h> DECLARE_GLOBAL_DATA_PTR; @@ -85,4 +85,4 @@ int ide_preinit (void) return (0); } -#endif /* CFG_CMD_IDE */ +#endif diff --git a/cpu/mpc5xxx/interrupts.c b/cpu/mpc5xxx/interrupts.c index beeb222..8816dd1 100644 --- a/cpu/mpc5xxx/interrupts.c +++ b/cpu/mpc5xxx/interrupts.c @@ -310,7 +310,7 @@ void irq_free_handler(int irq) /****************************************************************************/ -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) void do_irqinfo(cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[]) { int irq, re_enable; diff --git a/cpu/mpc5xxx/traps.c b/cpu/mpc5xxx/traps.c index 2ee782b..daa1ec6 100644 --- a/cpu/mpc5xxx/traps.c +++ b/cpu/mpc5xxx/traps.c @@ -37,7 +37,7 @@ #include <command.h> #include <asm/processor.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif @@ -123,7 +123,7 @@ MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -158,7 +158,7 @@ MachineCheckException(struct pt_regs *regs) void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -170,7 +170,7 @@ AlignmentException(struct pt_regs *regs) void ProgramCheckException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -182,7 +182,7 @@ ProgramCheckException(struct pt_regs *regs) void SoftEmuException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -195,7 +195,7 @@ SoftEmuException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -204,7 +204,7 @@ UnknownException(struct pt_regs *regs) _exception(0, regs); } -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -214,7 +214,7 @@ DebugException(struct pt_regs *regs) printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/mpc5xxx/u-boot-customlayout.lds b/cpu/mpc5xxx/u-boot-customlayout.lds new file mode 100644 index 0000000..1107943 --- /dev/null +++ b/cpu/mpc5xxx/u-boot-customlayout.lds @@ -0,0 +1,135 @@ +/* + * (C) Copyright 2003-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +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 : + { + /* WARNING - the following is hand-optimized to fit within */ + /* the sector layout of our flash chips! XXX FIXME XXX */ + + cpu/mpc5xxx/start.o (.text) + cpu/mpc5xxx/traps.o (.text) + lib_generic/crc32.o (.text) + lib_ppc/cache.o (.text) + lib_ppc/time.o (.text) + + . = DEFINED(env_offset) ? env_offset : .; + common/environment.o (.ppcenv) + + *(.text) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/cpu/mpc5xxx/u-boot.lds b/cpu/mpc5xxx/u-boot.lds new file mode 100644 index 0000000..a28a3af --- /dev/null +++ b/cpu/mpc5xxx/u-boot.lds @@ -0,0 +1,124 @@ +/* + * (C) Copyright 2003-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); +/* Do we need any of these for elf? + __DYNAMIC = 0; */ +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + . = + SIZEOF_HEADERS; + .interp : { *(.interp) } + .hash : { *(.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .rel.text : { *(.rel.text) } + .rela.text : { *(.rela.text) } + .rel.data : { *(.rel.data) } + .rela.data : { *(.rela.data) } + .rel.rodata : { *(.rel.rodata) } + .rela.rodata : { *(.rela.rodata) } + .rel.got : { *(.rel.got) } + .rela.got : { *(.rela.got) } + .rel.ctors : { *(.rel.ctors) } + .rela.ctors : { *(.rela.ctors) } + .rel.dtors : { *(.rel.dtors) } + .rela.dtors : { *(.rela.dtors) } + .rel.bss : { *(.rel.bss) } + .rela.bss : { *(.rela.bss) } + .rel.plt : { *(.rel.plt) } + .rela.plt : { *(.rela.plt) } + .init : { *(.init) } + .plt : { *(.plt) } + .text : + { + cpu/mpc5xxx/start.o (.text) + *(.text) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/cpu/mpc5xxx/usb.c b/cpu/mpc5xxx/usb.c new file mode 100644 index 0000000..ce709fc --- /dev/null +++ b/cpu/mpc5xxx/usb.c @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2007 + * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) + +#include <mpc5xxx.h> + +int usb_cpu_init() +{ + /* Set the USB Clock */ + *(vu_long *)MPC5XXX_CDM_48_FDC = CONFIG_USB_CLOCK; + + /* remove all USB bits first before ORing in ours */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00807000; + + /* Activate USB port */ + *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= CONFIG_USB_CONFIG; + + return 0; +} + +int usb_cpu_stop() +{ + return 0; +} + +int usb_cpu_init_fail() +{ + return 0; +} + +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/mpc8220/config.mk b/cpu/mpc8220/config.mk index 6fec5df..c41cafe 100644 --- a/cpu/mpc8220/config.mk +++ b/cpu/mpc8220/config.mk @@ -21,7 +21,10 @@ # MA 02111-1307 USA # -PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi +PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -mrelocatable PLATFORM_CPPFLAGS += -DCONFIG_MPC8220 -ffixed-r2 -ffixed-r29 \ -mstring -mcpu=603e -mmultiple + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/cpu/mpc8220/u-boot.lds diff --git a/cpu/mpc8220/cpu_init.c b/cpu/mpc8220/cpu_init.c index 3cf5f66..0daac5b 100644 --- a/cpu/mpc8220/cpu_init.c +++ b/cpu/mpc8220/cpu_init.c @@ -128,7 +128,7 @@ int cpu_init_r (void) /* route critical ints to normal ints */ *(vu_long *) 0xf0000710 |= 0x00000001; -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_MPC8220_FEC) +#if defined(CONFIG_CMD_NET) && defined(CONFIG_MPC8220_FEC) /* load FEC microcode */ loadtask (0, 2); #endif diff --git a/cpu/mpc8220/fec.c b/cpu/mpc8220/fec.c index 1201e79..992e0ff 100644 --- a/cpu/mpc8220/fec.c +++ b/cpu/mpc8220/fec.c @@ -15,10 +15,10 @@ #include "fec.h" #undef DEBUG -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ +#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ defined(CONFIG_MPC8220_FEC) -#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) #error "CONFIG_MII has to be defined!" #endif @@ -847,7 +847,7 @@ int mpc8220_fec_initialize (bd_t * bis) sprintf (dev->name, "FEC ETHERNET"); eth_register (dev); -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register (dev->name, fec8220_miiphy_read, fec8220_miiphy_write); #endif diff --git a/cpu/mpc8220/traps.c b/cpu/mpc8220/traps.c index cdee2be..89cca1d 100644 --- a/cpu/mpc8220/traps.c +++ b/cpu/mpc8220/traps.c @@ -37,7 +37,7 @@ #include <command.h> #include <asm/processor.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler) (struct pt_regs *) = 0; #endif @@ -118,7 +118,7 @@ void MachineCheckException (struct pt_regs *regs) regs->nip = fixup; return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; @@ -152,7 +152,7 @@ void MachineCheckException (struct pt_regs *regs) void AlignmentException (struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; @@ -164,7 +164,7 @@ void AlignmentException (struct pt_regs *regs) void ProgramCheckException (struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; @@ -176,7 +176,7 @@ void ProgramCheckException (struct pt_regs *regs) void SoftEmuException (struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; @@ -189,7 +189,7 @@ void SoftEmuException (struct pt_regs *regs) void UnknownException (struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; @@ -199,7 +199,7 @@ void UnknownException (struct pt_regs *regs) _exception (0, regs); } -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint (struct pt_regs *); #endif @@ -208,7 +208,7 @@ void DebugException (struct pt_regs *regs) printf ("Debugger trap at @ %lx\n", regs->nip); show_regs (regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint (regs); #endif } diff --git a/cpu/mpc8220/u-boot.lds b/cpu/mpc8220/u-boot.lds new file mode 100644 index 0000000..a199a64 --- /dev/null +++ b/cpu/mpc8220/u-boot.lds @@ -0,0 +1,124 @@ +/* + * (C) Copyright 2003-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +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/mpc8220/start.o (.text) + *(.text) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/cpu/mpc824x/config.mk b/cpu/mpc824x/config.mk index dac61d8..17fdb21 100644 --- a/cpu/mpc824x/config.mk +++ b/cpu/mpc824x/config.mk @@ -21,6 +21,9 @@ # MA 02111-1307 USA # -PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -fno-strict-aliasing +PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -fno-strict-aliasing -mrelocatable PLATFORM_CPPFLAGS += -DCONFIG_MPC824X -ffixed-r2 -ffixed-r29 -mstring -mcpu=603e -msoft-float + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/cpu/mpc824x/u-boot.lds diff --git a/cpu/mpc824x/traps.c b/cpu/mpc824x/traps.c index 071d003..0a72430 100644 --- a/cpu/mpc824x/traps.c +++ b/cpu/mpc824x/traps.c @@ -175,7 +175,7 @@ UnknownException(struct pt_regs *regs) _exception(0, regs); } -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -185,7 +185,7 @@ DebugException(struct pt_regs *regs) printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/mpc824x/u-boot.lds b/cpu/mpc824x/u-boot.lds new file mode 100644 index 0000000..8cbef4a --- /dev/null +++ b/cpu/mpc824x/u-boot.lds @@ -0,0 +1,124 @@ +/* + * (C) Copyright 2001-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +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/mpc824x/start.o (.text) + *(.text) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/cpu/mpc8260/bedbug_603e.c b/cpu/mpc8260/bedbug_603e.c index be09cfb..f1be485 100644 --- a/cpu/mpc8260/bedbug_603e.c +++ b/cpu/mpc8260/bedbug_603e.c @@ -10,7 +10,8 @@ #include <bedbug/regs.h> #include <bedbug/ppc.h> -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) && (defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260)) +#if defined(CONFIG_CMD_BEDBUG) \ + && (defined(CONFIG_MPC824X) || defined(CONFIG_MPC8260)) #define MAX_BREAK_POINTS 1 diff --git a/cpu/mpc8260/config.mk b/cpu/mpc8260/config.mk index dd7a71f..d401e4c 100644 --- a/cpu/mpc8260/config.mk +++ b/cpu/mpc8260/config.mk @@ -21,7 +21,10 @@ # MA 02111-1307 USA # -PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi +PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -mrelocatable PLATFORM_CPPFLAGS += -DCONFIG_8260 -DCONFIG_CPM2 -ffixed-r2 -ffixed-r29 \ -mstring -mcpu=603e -mmultiple + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/cpu/mpc8260/u-boot.lds diff --git a/cpu/mpc8260/cpu_init.c b/cpu/mpc8260/cpu_init.c index 380d7af..36fc1eb 100644 --- a/cpu/mpc8260/cpu_init.c +++ b/cpu/mpc8260/cpu_init.c @@ -182,7 +182,7 @@ void cpu_init_f (volatile immap_t * immr) #endif /* now restrict to preliminary range */ - /* the PS came from the HRCW, don´t change it */ + /* the PS came from the HRCW, don´t change it */ memctl->memc_br0 = SET_VAL_MASK(memctl->memc_br0 , CFG_BR0_PRELIM, BRx_PS_MSK); memctl->memc_or0 = CFG_OR0_PRELIM; diff --git a/cpu/mpc8260/ether_fcc.c b/cpu/mpc8260/ether_fcc.c index 584c40f..37bf445 100644 --- a/cpu/mpc8260/ether_fcc.c +++ b/cpu/mpc8260/ether_fcc.c @@ -47,13 +47,13 @@ #include <config.h> #include <net.h> -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) #include <miiphy.h> #endif DECLARE_GLOBAL_DATA_PTR; -#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET) && \ +#if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET) && \ defined(CONFIG_NET_MULTI) static struct ether_fcc_info_s @@ -393,7 +393,7 @@ int fec_initialize(bd_t *bis) eth_register(dev); -#if (defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) \ +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \ && defined(CONFIG_BITBANGMII) miiphy_register(dev->name, bb_miiphy_read, bb_miiphy_write); @@ -1187,4 +1187,4 @@ eth_loopback_test (void) #endif /* CONFIG_ETHER_LOOPBACK_TEST */ -#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET && CONFIG_NET_MULTI */ +#endif diff --git a/cpu/mpc8260/ether_scc.c b/cpu/mpc8260/ether_scc.c index a733b45..e56839d 100644 --- a/cpu/mpc8260/ether_scc.c +++ b/cpu/mpc8260/ether_scc.c @@ -36,7 +36,7 @@ #include <command.h> #include <config.h> -#if defined(CONFIG_ETHER_ON_SCC) && (CONFIG_COMMANDS & CFG_CMD_NET) +#if defined(CONFIG_ETHER_ON_SCC) && defined(CONFIG_CMD_NET) #if (CONFIG_ETHER_INDEX == 1) # define PROFF_ENET PROFF_SCC1 @@ -353,4 +353,4 @@ void restart(void) } #endif -#endif /* CONFIG_ETHER_ON_SCC && CFG_CMD_NET */ +#endif diff --git a/cpu/mpc8260/interrupts.c b/cpu/mpc8260/interrupts.c index 56e9a72..bf0d4d0 100644 --- a/cpu/mpc8260/interrupts.c +++ b/cpu/mpc8260/interrupts.c @@ -246,7 +246,7 @@ void timer_interrupt_cpu (struct pt_regs *regs) /****************************************************************************/ -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) /* ripped this out of ppc4xx/interrupts.c */ @@ -276,4 +276,4 @@ do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[]) enable_interrupts (); } -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/mpc8260/kgdb.S b/cpu/mpc8260/kgdb.S index 2a25024..dae87bb 100644 --- a/cpu/mpc8260/kgdb.S +++ b/cpu/mpc8260/kgdb.S @@ -34,7 +34,7 @@ #include <asm/cache.h> #include <asm/mmu.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) /* * cache flushing routines for kgdb @@ -69,4 +69,4 @@ kgdb_flush_cache_range: SYNC blr -#endif /* CFG_CMD_KGDB */ +#endif diff --git a/cpu/mpc8260/traps.c b/cpu/mpc8260/traps.c index 0c39e43..b5d416c 100644 --- a/cpu/mpc8260/traps.c +++ b/cpu/mpc8260/traps.c @@ -37,7 +37,7 @@ #include <asm/processor.h> #include <asm/m8260_pci.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif @@ -150,7 +150,7 @@ MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -186,7 +186,7 @@ MachineCheckException(struct pt_regs *regs) void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -198,7 +198,7 @@ AlignmentException(struct pt_regs *regs) void ProgramCheckException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -210,7 +210,7 @@ ProgramCheckException(struct pt_regs *regs) void SoftEmuException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -223,7 +223,7 @@ SoftEmuException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -232,7 +232,7 @@ UnknownException(struct pt_regs *regs) _exception(0, regs); } -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -242,7 +242,7 @@ DebugException(struct pt_regs *regs) printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/mpc8260/u-boot.lds b/cpu/mpc8260/u-boot.lds new file mode 100644 index 0000000..b8abc17 --- /dev/null +++ b/cpu/mpc8260/u-boot.lds @@ -0,0 +1,124 @@ +/* + * (C) Copyright 2001-2007 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +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/mpc8260/start.o (.text) + *(.text) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile index bb96f77..2329970 100644 --- a/cpu/mpc83xx/Makefile +++ b/cpu/mpc83xx/Makefile @@ -29,7 +29,7 @@ LIB = $(obj)lib$(CPU).a START = start.o COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \ - spd_sdram.o qe_io.o pci.o + spd_sdram.o ecc.o qe_io.o pci.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mpc83xx/config.mk b/cpu/mpc83xx/config.mk index 8b4ff92..2ec395d 100644 --- a/cpu/mpc83xx/config.mk +++ b/cpu/mpc83xx/config.mk @@ -20,7 +20,10 @@ # MA 02111-1307 USA # -PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi +PLATFORM_RELFLAGS += -fPIC -ffixed-r14 -meabi -mrelocatable PLATFORM_CPPFLAGS += -DCONFIG_MPC83XX -DCONFIG_E300 \ -ffixed-r2 -ffixed-r29 -msoft-float + +# Use default linker script. Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/cpu/mpc83xx/u-boot.lds diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c index 841fe82..adf8083 100644 --- a/cpu/mpc83xx/cpu.c +++ b/cpu/mpc83xx/cpu.c @@ -33,8 +33,7 @@ #include <asm/processor.h> #if defined(CONFIG_OF_FLAT_TREE) #include <ft_build.h> -#endif -#if defined(CONFIG_OF_LIBFDT) +#elif defined(CONFIG_OF_LIBFDT) #include <libfdt.h> #include <libfdt_env.h> #endif @@ -113,12 +112,14 @@ int checkcpu(void) case SPR_8360E_REV11: case SPR_8360E_REV12: case SPR_8360E_REV20: + case SPR_8360E_REV21: puts("MPC8360E, "); break; case SPR_8360_REV10: case SPR_8360_REV11: case SPR_8360_REV12: case SPR_8360_REV20: + case SPR_8360_REV21: puts("MPC8360, "); break; case SPR_8323E_REV10: @@ -150,7 +151,8 @@ int checkcpu(void) puts("MPC8313E, "); break; default: - puts("Rev: Unknown revision number.\nWarning: Unsupported cpu revision!\n"); + printf("Rev: Unknown revision number:%08x\n" + "Warning: Unsupported cpu revision!\n",spridr); return 0; } @@ -329,154 +331,167 @@ void watchdog_reset (void) /* * "Setter" functions used to add/modify FDT entries. */ -static int fdt_set_eth0(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth0(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enetaddr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enetaddr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #ifdef CONFIG_HAS_ETH1 /* second onboard ethernet port */ -static int fdt_set_eth1(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth1(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet1addr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enet1addr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #endif #ifdef CONFIG_HAS_ETH2 /* third onboard ethernet port */ -static int fdt_set_eth2(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth2(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet2addr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enet2addr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #endif #ifdef CONFIG_HAS_ETH3 /* fourth onboard ethernet port */ -static int fdt_set_eth3(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_eth3(void *blob, int nodeoffset, const char *name, bd_t *bd) { /* * Fix it up if it exists, don't create it if it doesn't exist. */ - if (fdt_get_property(fdt, nodeoffset, name, 0)) { - return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet3addr, 6); + if (fdt_get_property(blob, nodeoffset, name, 0)) { + return fdt_setprop(blob, nodeoffset, name, bd->bi_enet3addr, 6); } - return -FDT_ERR_NOTFOUND; + return 0; } #endif -static int fdt_set_busfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd) +static int fdt_set_busfreq(void *blob, int nodeoffset, const char *name, bd_t *bd) { u32 tmp; /* * Create or update the property. */ tmp = cpu_to_be32(bd->bi_busfreq); - return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); + return fdt_setprop(blob, nodeoffset, name, &tmp, sizeof(tmp)); +} + +static int fdt_set_tbfreq(void *blob, int nodeoffset, const char *name, bd_t *bd) +{ + u32 tmp; + /* + * Create or update the property. + */ + tmp = cpu_to_be32(OF_TBCLK); + return fdt_setprop(blob, nodeoffset, name, &tmp, sizeof(tmp)); } + /* - * Fixups to the fdt. If "create" is TRUE, the node is created - * unconditionally. If "create" is FALSE, the node is updated - * only if it already exists. + * Fixups to the fdt. */ static const struct { char *node; char *prop; - int (*set_fn)(void *fdt, int nodeoffset, const char *name, bd_t *bd); + int (*set_fn)(void *blob, int nodeoffset, const char *name, bd_t *bd); } fixup_props[] = { { "/cpus/" OF_CPU, - "bus-frequency", - fdt_set_busfreq + "timebase-frequency", + fdt_set_tbfreq }, - { "/cpus/" OF_SOC, + { "/cpus/" OF_CPU, "bus-frequency", fdt_set_busfreq }, - { "/" OF_SOC "/serial@4500/", + { "/cpus/" OF_CPU, + "clock-frequency", + fdt_set_busfreq + }, + { "/" OF_SOC "/serial@4500", "clock-frequency", fdt_set_busfreq }, - { "/" OF_SOC "/serial@4600/", + { "/" OF_SOC "/serial@4600", "clock-frequency", fdt_set_busfreq }, #ifdef CONFIG_TSEC1 - { "/" OF_SOC "/ethernet@24000, + { "/" OF_SOC "/ethernet@24000", "mac-address", fdt_set_eth0 }, - { "/" OF_SOC "/ethernet@24000, + { "/" OF_SOC "/ethernet@24000", "local-mac-address", fdt_set_eth0 }, #endif #ifdef CONFIG_TSEC2 - { "/" OF_SOC "/ethernet@25000, + { "/" OF_SOC "/ethernet@25000", "mac-address", fdt_set_eth1 }, - { "/" OF_SOC "/ethernet@25000, + { "/" OF_SOC "/ethernet@25000", "local-mac-address", fdt_set_eth1 }, #endif #ifdef CONFIG_UEC_ETH1 #if CFG_UEC1_UCC_NUM == 0 /* UCC1 */ - { "/" OF_QE "/ucc@2000/mac-address", + { "/" OF_QE "/ucc@2000", "mac-address", fdt_set_eth0 }, - { "/" OF_QE "/ucc@2000/mac-address", + { "/" OF_QE "/ucc@2000", "local-mac-address", fdt_set_eth0 }, #elif CFG_UEC1_UCC_NUM == 2 /* UCC3 */ - { "/" OF_QE "/ucc@2200/mac-address", + { "/" OF_QE "/ucc@2200", "mac-address", fdt_set_eth0 }, - { "/" OF_QE "/ucc@2200/mac-address", + { "/" OF_QE "/ucc@2200", "local-mac-address", fdt_set_eth0 }, #endif -#endif +#endif /* CONFIG_UEC_ETH1 */ #ifdef CONFIG_UEC_ETH2 #if CFG_UEC2_UCC_NUM == 1 /* UCC2 */ - { "/" OF_QE "/ucc@3000/mac-address", + { "/" OF_QE "/ucc@3000", "mac-address", fdt_set_eth1 }, - { "/" OF_QE "/ucc@3000/mac-address", + { "/" OF_QE "/ucc@3000", "local-mac-address", fdt_set_eth1 }, #elif CFG_UEC1_UCC_NUM == 3 /* UCC4 */ - { "/" OF_QE "/ucc@3200/mac-address", + { "/" OF_QE "/ucc@3200", "mac-address", fdt_set_eth1 }, - { "/" OF_QE "/ucc@3200/mac-address", + { "/" OF_QE "/ucc@3200", "local-mac-address", fdt_set_eth1 }, #endif -#endif +#endif /* CONFIG_UEC_ETH2 */ }; void @@ -487,20 +502,23 @@ ft_cpu_setup(void *blob, bd_t *bd) int j; for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) { - nodeoffset = fdt_path_offset(fdt, fixup_props[j].node); + nodeoffset = fdt_find_node_by_path(blob, fixup_props[j].node); if (nodeoffset >= 0) { - err = (*fixup_props[j].set_fn)(blob, nodeoffset, fixup_props[j].prop, bd); + err = fixup_props[j].set_fn(blob, nodeoffset, + fixup_props[j].prop, bd); if (err < 0) - printf("set_fn/libfdt: %s %s returned %s\n", + debug("Problem setting %s = %s: %s\n", fixup_props[j].node, fixup_props[j].prop, fdt_strerror(err)); + } else { + debug("Couldn't find %s: %s\n", + fixup_props[j].node, + fdt_strerror(nodeoffset)); } } } -#endif - -#if defined(CONFIG_OF_FLAT_TREE) +#elif defined(CONFIG_OF_FLAT_TREE) void ft_cpu_setup(void *blob, bd_t *bd) { diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c index 3ac9161..7224979 100644 --- a/cpu/mpc83xx/cpu_init.c +++ b/cpu/mpc83xx/cpu_init.c @@ -83,20 +83,30 @@ void cpu_init_f (volatile immap_t * im) im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_TSEC2EP) | (CFG_SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT); #endif -#ifdef CONFIG_MPC834X #ifdef CFG_SCCR_TSEC1CM /* TSEC1 clock mode */ im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC1CM) | (CFG_SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT); #endif + #ifdef CFG_SCCR_TSEC2CM /* TSEC2 & I2C1 clock mode */ im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC2CM) | (CFG_SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT); #endif + +#ifdef CFG_SCCR_TSEC1ON + /* TSEC1 clock switch */ + im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC1ON) | (CFG_SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT); +#endif + +#ifdef CFG_SCCR_TSEC2ON + /* TSEC2 clock switch */ + im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC2ON) | (CFG_SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT); +#endif + #ifdef CFG_SCCR_USBMPHCM /* USB MPH clock mode */ im->clk.sccr = (im->clk.sccr & ~SCCR_USBMPHCM) | (CFG_SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT); #endif -#endif /* CONFIG_MPC834X */ #ifdef CFG_SCCR_PCICM /* PCI & DMA clock mode */ @@ -247,3 +257,39 @@ int cpu_init_r (void) #endif return 0; } + +/* + * Figure out the cause of the reset + */ +int prt_83xx_rsr(void) +{ + static struct { + ulong mask; + char *desc; + } bits[] = { + { + RSR_SWSR, "Software Soft"}, { + RSR_SWHR, "Software Hard"}, { + RSR_JSRS, "JTAG Soft"}, { + RSR_CSHR, "Check Stop"}, { + RSR_SWRS, "Software Watchdog"}, { + RSR_BMRS, "Bus Monitor"}, { + RSR_SRS, "External/Internal Soft"}, { + RSR_HRS, "External/Internal Hard"} + }; + static int n = sizeof bits / sizeof bits[0]; + ulong rsr = gd->reset_status; + int i; + char *sep; + + puts("Reset Status:"); + + sep = " "; + for (i = 0; i < n; i++) + if (rsr & bits[i].mask) { + printf("%s%s", sep, bits[i].desc); + sep = ", "; + } + puts("\n\n"); + return 0; +} diff --git a/cpu/mpc83xx/ecc.c b/cpu/mpc83xx/ecc.c new file mode 100644 index 0000000..6f13094 --- /dev/null +++ b/cpu/mpc83xx/ecc.c @@ -0,0 +1,390 @@ +/* + * Copyright (C) 2007 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on the contribution of Marian Balakowicz <m8@semihalf.com> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <common.h> +#include <mpc83xx.h> +#include <command.h> + +#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD) +void ecc_print_status(void) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + volatile ddr83xx_t *ddr = &immap->ddr; + + printf("\nECC mode: %s\n\n", + (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF"); + + /* Interrupts */ + printf("Memory Error Interrupt Enable:\n"); + printf(" Multiple-Bit Error Interrupt Enable: %d\n", + (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0); + printf(" Single-Bit Error Interrupt Enable: %d\n", + (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0); + printf(" Memory Select Error Interrupt Enable: %d\n\n", + (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0); + + /* Error disable */ + printf("Memory Error Disable:\n"); + printf(" Multiple-Bit Error Disable: %d\n", + (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0); + printf(" Sinle-Bit Error Disable: %d\n", + (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0); + printf(" Memory Select Error Disable: %d\n\n", + (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0); + + /* Error injection */ + printf("Memory Data Path Error Injection Mask High/Low: %08lx %08lx\n", + ddr->data_err_inject_hi, ddr->data_err_inject_lo); + + printf("Memory Data Path Error Injection Mask ECC:\n"); + printf(" ECC Mirror Byte: %d\n", + (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0); + printf(" ECC Injection Enable: %d\n", + (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0); + printf(" ECC Error Injection Mask: 0x%02x\n\n", + ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM); + + /* SBE counter/threshold */ + printf("Memory Single-Bit Error Management (0..255):\n"); + printf(" Single-Bit Error Threshold: %d\n", + (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT); + printf(" Single-Bit Error Counter: %d\n\n", + (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT); + + /* Error detect */ + printf("Memory Error Detect:\n"); + printf(" Multiple Memory Errors: %d\n", + (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0); + printf(" Multiple-Bit Error: %d\n", + (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0); + printf(" Single-Bit Error: %d\n", + (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0); + printf(" Memory Select Error: %d\n\n", + (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0); + + /* Capture data */ + printf("Memory Error Address Capture: 0x%08lx\n", ddr->capture_address); + printf("Memory Data Path Read Capture High/Low: %08lx %08lx\n", + ddr->capture_data_hi, ddr->capture_data_lo); + printf("Memory Data Path Read Capture ECC: 0x%02x\n\n", + ddr->capture_ecc & CAPTURE_ECC_ECE); + + printf("Memory Error Attributes Capture:\n"); + printf(" Data Beat Number: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >> + ECC_CAPT_ATTR_BNUM_SHIFT); + printf(" Transaction Size: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >> + ECC_CAPT_ATTR_TSIZ_SHIFT); + printf(" Transaction Source: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >> + ECC_CAPT_ATTR_TSRC_SHIFT); + printf(" Transaction Type: %d\n", + (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >> + ECC_CAPT_ATTR_TTYP_SHIFT); + printf(" Error Information Valid: %d\n\n", + ddr->capture_attributes & ECC_CAPT_ATTR_VLD); +} + +int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ + volatile immap_t *immap = (immap_t *) CFG_IMMR; + volatile ddr83xx_t *ddr = &immap->ddr; + volatile u32 val; + u64 *addr; + u32 count; + register u64 *i; + u32 ret[2]; + u32 pattern[2]; + u32 writeback[2]; + + /* The pattern is written into memory to generate error */ + pattern[0] = 0xfedcba98UL; + pattern[1] = 0x76543210UL; + + /* After injecting error, re-initialize the memory with the value */ + writeback[0] = 0x01234567UL; + writeback[1] = 0x89abcdefUL; + + if (argc > 4) { + printf("Usage:\n%s\n", cmdtp->usage); + return 1; + } + + if (argc == 2) { + if (strcmp(argv[1], "status") == 0) { + ecc_print_status(); + return 0; + } else if (strcmp(argv[1], "captureclear") == 0) { + ddr->capture_address = 0; + ddr->capture_data_hi = 0; + ddr->capture_data_lo = 0; + ddr->capture_ecc = 0; + ddr->capture_attributes = 0; + return 0; + } + } + if (argc == 3) { + if (strcmp(argv[1], "sbecnt") == 0) { + val = simple_strtoul(argv[2], NULL, 10); + if (val > 255) { + printf("Incorrect Counter value, " + "should be 0..255\n"); + return 1; + } + + val = (val << ECC_ERROR_MAN_SBEC_SHIFT); + val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET); + + ddr->err_sbe = val; + return 0; + } else if (strcmp(argv[1], "sbethr") == 0) { + val = simple_strtoul(argv[2], NULL, 10); + if (val > 255) { + printf("Incorrect Counter value, " + "should be 0..255\n"); + return 1; + } + + val = (val << ECC_ERROR_MAN_SBET_SHIFT); + val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC); + + ddr->err_sbe = val; + return 0; + } else if (strcmp(argv[1], "errdisable") == 0) { + val = ddr->err_disable; + + if (strcmp(argv[2], "+sbe") == 0) { + val |= ECC_ERROR_DISABLE_SBED; + } else if (strcmp(argv[2], "+mbe") == 0) { + val |= ECC_ERROR_DISABLE_MBED; + } else if (strcmp(argv[2], "+mse") == 0) { + val |= ECC_ERROR_DISABLE_MSED; + } else if (strcmp(argv[2], "+all") == 0) { + val |= (ECC_ERROR_DISABLE_SBED | + ECC_ERROR_DISABLE_MBED | + ECC_ERROR_DISABLE_MSED); + } else if (strcmp(argv[2], "-sbe") == 0) { + val &= ~ECC_ERROR_DISABLE_SBED; + } else if (strcmp(argv[2], "-mbe") == 0) { + val &= ~ECC_ERROR_DISABLE_MBED; + } else if (strcmp(argv[2], "-mse") == 0) { + val &= ~ECC_ERROR_DISABLE_MSED; + } else if (strcmp(argv[2], "-all") == 0) { + val &= ~(ECC_ERROR_DISABLE_SBED | + ECC_ERROR_DISABLE_MBED | + ECC_ERROR_DISABLE_MSED); + } else { + printf("Incorrect err_disable field\n"); + return 1; + } + + ddr->err_disable = val; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + return 0; + } else if (strcmp(argv[1], "errdetectclr") == 0) { + val = ddr->err_detect; + + if (strcmp(argv[2], "mme") == 0) { + val |= ECC_ERROR_DETECT_MME; + } else if (strcmp(argv[2], "sbe") == 0) { + val |= ECC_ERROR_DETECT_SBE; + } else if (strcmp(argv[2], "mbe") == 0) { + val |= ECC_ERROR_DETECT_MBE; + } else if (strcmp(argv[2], "mse") == 0) { + val |= ECC_ERROR_DETECT_MSE; + } else if (strcmp(argv[2], "all") == 0) { + val |= (ECC_ERROR_DETECT_MME | + ECC_ERROR_DETECT_MBE | + ECC_ERROR_DETECT_SBE | + ECC_ERROR_DETECT_MSE); + } else { + printf("Incorrect err_detect field\n"); + return 1; + } + + ddr->err_detect = val; + return 0; + } else if (strcmp(argv[1], "injectdatahi") == 0) { + val = simple_strtoul(argv[2], NULL, 16); + + ddr->data_err_inject_hi = val; + return 0; + } else if (strcmp(argv[1], "injectdatalo") == 0) { + val = simple_strtoul(argv[2], NULL, 16); + + ddr->data_err_inject_lo = val; + return 0; + } else if (strcmp(argv[1], "injectecc") == 0) { + val = simple_strtoul(argv[2], NULL, 16); + if (val > 0xff) { + printf("Incorrect ECC inject mask, " + "should be 0x00..0xff\n"); + return 1; + } + val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM); + + ddr->ecc_err_inject = val; + return 0; + } else if (strcmp(argv[1], "inject") == 0) { + val = ddr->ecc_err_inject; + + if (strcmp(argv[2], "en") == 0) + val |= ECC_ERR_INJECT_EIEN; + else if (strcmp(argv[2], "dis") == 0) + val &= ~ECC_ERR_INJECT_EIEN; + else + printf("Incorrect command\n"); + + ddr->ecc_err_inject = val; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + return 0; + } else if (strcmp(argv[1], "mirror") == 0) { + val = ddr->ecc_err_inject; + + if (strcmp(argv[2], "en") == 0) + val |= ECC_ERR_INJECT_EMB; + else if (strcmp(argv[2], "dis") == 0) + val &= ~ECC_ERR_INJECT_EMB; + else + printf("Incorrect command\n"); + + ddr->ecc_err_inject = val; + return 0; + } + } + if (argc == 4) { + if (strcmp(argv[1], "testdw") == 0) { + addr = (u64 *) simple_strtoul(argv[2], NULL, 16); + count = simple_strtoul(argv[3], NULL, 16); + + if ((u32) addr % 8) { + printf("Address not alligned on " + "double word boundary\n"); + return 1; + } + disable_interrupts(); + + for (i = addr; i < addr + count; i++) { + + /* enable injects */ + ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* write memory location injecting errors */ + ppcDWstore((u32 *) i, pattern); + __asm__ __volatile__("sync"); + + /* disable injects */ + ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* read data, this generates ECC error */ + ppcDWload((u32 *) i, ret); + __asm__ __volatile__("sync"); + + /* re-initialize memory, double word write the location again, + * generates new ECC code this time */ + ppcDWstore((u32 *) i, writeback); + __asm__ __volatile__("sync"); + } + enable_interrupts(); + return 0; + } + if (strcmp(argv[1], "testword") == 0) { + addr = (u64 *) simple_strtoul(argv[2], NULL, 16); + count = simple_strtoul(argv[3], NULL, 16); + + if ((u32) addr % 8) { + printf("Address not alligned on " + "double word boundary\n"); + return 1; + } + disable_interrupts(); + + for (i = addr; i < addr + count; i++) { + + /* enable injects */ + ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* write memory location injecting errors */ + *(u32 *) i = 0xfedcba98UL; + __asm__ __volatile__("sync"); + + /* sub double word write, + * bus will read-modify-write, + * generates ECC error */ + *((u32 *) i + 1) = 0x76543210UL; + __asm__ __volatile__("sync"); + + /* disable injects */ + ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN; + __asm__ __volatile__("sync"); + __asm__ __volatile__("isync"); + + /* re-initialize memory, + * double word write the location again, + * generates new ECC code this time */ + ppcDWstore((u32 *) i, writeback); + __asm__ __volatile__("sync"); + } + enable_interrupts(); + return 0; + } + } + printf("Usage:\n%s\n", cmdtp->usage); + return 1; +} + +U_BOOT_CMD(ecc, 4, 0, do_ecc, + "ecc - support for DDR ECC features\n", + "status - print out status info\n" + "ecc captureclear - clear capture regs data\n" + "ecc sbecnt <val> - set Single-Bit Error counter\n" + "ecc sbethr <val> - set Single-Bit Threshold\n" + "ecc errdisable <flag> - clear/set disable Memory Error Disable, flag:\n" + " [-|+]sbe - Single-Bit Error\n" + " [-|+]mbe - Multiple-Bit Error\n" + " [-|+]mse - Memory Select Error\n" + " [-|+]all - all errors\n" + "ecc errdetectclr <flag> - clear Memory Error Detect, flag:\n" + " mme - Multiple Memory Errors\n" + " sbe - Single-Bit Error\n" + " mbe - Multiple-Bit Error\n" + " mse - Memory Select Error\n" + " all - all errors\n" + "ecc injectdatahi <hi> - set Memory Data Path Error Injection Mask High\n" + "ecc injectdatalo <lo> - set Memory Data Path Error Injection Mask Low\n" + "ecc injectecc <ecc> - set ECC Error Injection Mask\n" + "ecc inject <en|dis> - enable/disable error injection\n" + "ecc mirror <en|dis> - enable/disable mirror byte\n" + "ecc testdw <addr> <cnt> - test mem region with double word access:\n" + " - enables injects\n" + " - writes pattern injecting errors with double word access\n" + " - disables injects\n" + " - reads pattern back with double word access, generates error\n" + " - re-inits memory\n" + "ecc testword <addr> <cnt> - test mem region with word access:\n" + " - enables injects\n" + " - writes pattern injecting errors with word access\n" + " - writes pattern with word access, generates error\n" + " - disables injects\n" " - re-inits memory"); +#endif diff --git a/cpu/mpc83xx/interrupts.c b/cpu/mpc83xx/interrupts.c index bb1fe1a..98ed21c 100644 --- a/cpu/mpc83xx/interrupts.c +++ b/cpu/mpc83xx/interrupts.c @@ -81,7 +81,7 @@ void timer_interrupt_cpu (struct pt_regs *regs) } -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) /* ripped this out of ppc4xx/interrupts.c */ @@ -94,4 +94,4 @@ do_irqinfo(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[]) { } -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/mpc83xx/pci.c b/cpu/mpc83xx/pci.c index 785d612..2298218 100644 --- a/cpu/mpc83xx/pci.c +++ b/cpu/mpc83xx/pci.c @@ -25,7 +25,14 @@ #include <common.h> #include <pci.h> + +#if defined(CONFIG_OF_LIBFDT) +#include <libfdt.h> +#include <libfdt_env.h> +#elif defined(CONFIG_OF_FLAT_TREE) #include <ft_build.h> +#endif + #include <asm/mpc8349_pci.h> #ifdef CONFIG_83XX_GENERIC_PCI @@ -163,7 +170,34 @@ void mpc83xx_pci_init(int num_buses, struct pci_region **reg, int warmboot) pci_init_bus(i, reg[i]); } -#ifdef CONFIG_OF_FLAT_TREE +#if defined(CONFIG_OF_LIBFDT) +void ft_pci_setup(void *blob, bd_t *bd) +{ + int nodeoffset; + int err; + int tmp[2]; + + if (pci_num_buses < 1) + return; + + nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500"); + if (nodeoffset >= 0) { + tmp[0] = cpu_to_be32(pci_hose[0].first_busno); + tmp[1] = cpu_to_be32(pci_hose[0].last_busno); + err = fdt_setprop(blob, nodeoffset, "bus-range", tmp, sizeof(tmp)); + } + + if (pci_num_buses < 2) + return; + + nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8600"); + if (nodeoffset >= 0) { + tmp[0] = cpu_to_be32(pci_hose[0].first_busno); + tmp[1] = cpu_to_be32(pci_hose[0].last_busno); + err = fdt_setprop(blob, nodeoffset, "bus-range", tmp, sizeof(tmp)); + } +} +#elif CONFIG_OF_FLAT_TREE void ft_pci_setup(void *blob, bd_t *bd) { u32 *p; diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c index 647813f..54f0c83 100644 --- a/cpu/mpc83xx/spd_sdram.c +++ b/cpu/mpc83xx/spd_sdram.c @@ -574,7 +574,10 @@ long int spd_sdram() /* Check DIMM data bus width */ if (spd.dataw_lsb == 0x20) { - burstlen = 0x03; /* 32 bit data bus, burst len is 8 */ + if (spd.mem_type == SPD_MEMTYPE_DDR) + burstlen = 0x03; /* 32 bit data bus, burst len is 8 */ + else + burstlen = 0x02; /* 32 bit data bus, burst len is 4 */ printf("\n DDR DIMM: data bus width is 32 bit"); } else { burstlen = 0x02; /* Others act as 64 bit bus, burst len is 4 */ @@ -730,8 +733,12 @@ long int spd_sdram() sdram_cfg |= 0x10000000; /* The DIMM is 32bit width */ - if (spd.dataw_lsb == 0x20) - sdram_cfg |= 0x000C0000; + if (spd.dataw_lsb == 0x20) { + if (spd.mem_type == SPD_MEMTYPE_DDR) + sdram_cfg |= 0x000C0000; + if (spd.mem_type == SPD_MEMTYPE_DDR2) + sdram_cfg |= 0x00080000; + } ddrc_ecc_enable = 0; diff --git a/cpu/mpc83xx/traps.c b/cpu/mpc83xx/traps.c index 152fa73..dfd6c03 100644 --- a/cpu/mpc83xx/traps.c +++ b/cpu/mpc83xx/traps.c @@ -140,7 +140,7 @@ MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -176,7 +176,7 @@ MachineCheckException(struct pt_regs *regs) void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -188,7 +188,7 @@ AlignmentException(struct pt_regs *regs) void ProgramCheckException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -200,7 +200,7 @@ ProgramCheckException(struct pt_regs *regs) void SoftEmuException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -213,7 +213,7 @@ SoftEmuException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -222,7 +222,7 @@ UnknownException(struct pt_regs *regs) _exception(0, regs); } -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -231,7 +231,7 @@ DebugException(struct pt_regs *regs) { printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/mpc83xx/u-boot.lds b/cpu/mpc83xx/u-boot.lds new file mode 100644 index 0000000..ca663bc --- /dev/null +++ b/cpu/mpc83xx/u-boot.lds @@ -0,0 +1,122 @@ +/* + * (C) Copyright 2006 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +OUTPUT_ARCH(powerpc) +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/mpc83xx/start.o (.text) + *(.text) + *(.got1) + . = ALIGN(16); + *(.rodata) + *(.rodata1) + *(.rodata.str1.4) + *(.eh_frame) + } + .fini : { *(.fini) } =0 + .ctors : { *(.ctors) } + .dtors : { *(.dtors) } + + /* Read-write section, merged into data segment: */ + . = (. + 0x0FFF) & 0xFFFFF000; + _erotext = .; + PROVIDE (erotext = .); + .reloc : + { + *(.got) + _GOT2_TABLE_ = .; + *(.got2) + _FIXUP_TABLE_ = .; + *(.fixup) + } + __got2_entries = (_FIXUP_TABLE_ - _GOT2_TABLE_) >> 2; + __fixup_entries = (. - _FIXUP_TABLE_) >> 2; + + .data : + { + *(.data) + *(.data1) + *(.sdata) + *(.sdata2) + *(.dynamic) + CONSTRUCTORS + } + _edata = .; + PROVIDE (edata = .); + + . = .; + __u_boot_cmd_start = .; + .u_boot_cmd : { *(.u_boot_cmd) } + __u_boot_cmd_end = .; + + + . = .; + __start___ex_table = .; + __ex_table : { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + __init_begin = .; + .text.init : { *(.text.init) } + .data.init : { *(.data.init) } + . = ALIGN(4096); + __init_end = .; + + __bss_start = .; + .bss : + { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + *(COMMON) + } + _end = . ; + PROVIDE (end = .); +} +ENTRY(_start) diff --git a/cpu/mpc85xx/Makefile b/cpu/mpc85xx/Makefile index ff67dcd..32091fa 100644 --- a/cpu/mpc85xx/Makefile +++ b/cpu/mpc85xx/Makefile @@ -30,7 +30,7 @@ LIB = $(obj)lib$(CPU).a START = start.o resetvec.o COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \ - pci.o serial_scc.o commproc.o ether_fcc.o spd_sdram.o + pci.o serial_scc.o commproc.o ether_fcc.o spd_sdram.o qe_io.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mpc85xx/cpu.c b/cpu/mpc85xx/cpu.c index 1d791c9..08e0468 100644 --- a/cpu/mpc85xx/cpu.c +++ b/cpu/mpc85xx/cpu.c @@ -280,7 +280,7 @@ ft_cpu_setup(void *blob, bd_t *bd) if (p != NULL) *p = cpu_to_be32(clock); -#if defined(CONFIG_TSEC1) +#if defined(CONFIG_HAS_ETH0) p = ft_get_prop(blob, "/" OF_SOC "/ethernet@24000/mac-address", &len); if (p) memcpy(p, bd->bi_enetaddr, 6); @@ -308,6 +308,17 @@ ft_cpu_setup(void *blob, bd_t *bd) p = ft_get_prop(blob, "/" OF_SOC "/ethernet@26000/local-mac-address", &len); if (p) memcpy(p, bd->bi_enet2addr, 6); + +#ifdef CONFIG_UEC_ETH + p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/mac-address", &len); + if (p) + memcpy(p, bd->bi_enet2addr, 6); + + p = ft_get_prop(blob, "/" OF_QE "/ucc@2000/local-mac-address", &len); + if (p) + memcpy(p, bd->bi_enet2addr, 6); + +#endif #endif #if defined(CONFIG_HAS_ETH3) @@ -318,6 +329,17 @@ ft_cpu_setup(void *blob, bd_t *bd) p = ft_get_prop(blob, "/" OF_SOC "/ethernet@27000/local-mac-address", &len); if (p) memcpy(p, bd->bi_enet3addr, 6); + +#ifdef CONFIG_UEC_ETH + p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/mac-address", &len); + if (p) + memcpy(p, bd->bi_enet3addr, 6); + + p = ft_get_prop(blob, "/" OF_QE "/ucc@3000/local-mac-address", &len); + if (p) + memcpy(p, bd->bi_enet3addr, 6); + +#endif #endif } diff --git a/cpu/mpc85xx/cpu_init.c b/cpu/mpc85xx/cpu_init.c index 9517146..7b99610 100644 --- a/cpu/mpc85xx/cpu_init.c +++ b/cpu/mpc85xx/cpu_init.c @@ -1,4 +1,6 @@ /* + * Copyright 2007 Freescale Semiconductor. + * * (C) Copyright 2003 Motorola Inc. * Modified by Xianghua Xiao, X.Xiao@motorola.com * @@ -32,6 +34,29 @@ DECLARE_GLOBAL_DATA_PTR; +#ifdef CONFIG_QE +extern qe_iop_conf_t qe_iop_conf_tab[]; +extern void qe_config_iopin(u8 port, u8 pin, int dir, + int open_drain, int assign); +extern void qe_init(uint qe_base); +extern void qe_reset(void); + +static void config_qe_ioports(void) +{ + u8 port, pin; + int dir, open_drain, assign; + int i; + + for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) { + port = qe_iop_conf_tab[i].port; + pin = qe_iop_conf_tab[i].pin; + dir = qe_iop_conf_tab[i].dir; + open_drain = qe_iop_conf_tab[i].open_drain; + assign = qe_iop_conf_tab[i].assign; + qe_config_iopin(port, pin, dir, open_drain, assign); + } +} +#endif #ifdef CONFIG_CPM2 static void config_8560_ioports (volatile immap_t * immr) @@ -133,15 +158,18 @@ void cpu_init_f (void) #endif /* now restrict to preliminary range */ + /* if cs1 is already set via debugger, leave cs0/cs1 alone */ + if (! memctl->br1 & 1) { #if defined(CFG_BR0_PRELIM) && defined(CFG_OR0_PRELIM) - memctl->br0 = CFG_BR0_PRELIM; - memctl->or0 = CFG_OR0_PRELIM; + memctl->br0 = CFG_BR0_PRELIM; + memctl->or0 = CFG_OR0_PRELIM; #endif #if defined(CFG_BR1_PRELIM) && defined(CFG_OR1_PRELIM) - memctl->or1 = CFG_OR1_PRELIM; - memctl->br1 = CFG_BR1_PRELIM; + memctl->or1 = CFG_OR1_PRELIM; + memctl->br1 = CFG_BR1_PRELIM; #endif + } #if defined(CFG_BR2_PRELIM) && defined(CFG_OR2_PRELIM) memctl->or2 = CFG_OR2_PRELIM; @@ -176,6 +204,11 @@ void cpu_init_f (void) #if defined(CONFIG_CPM2) m8560_cpm_reset(); #endif +#ifdef CONFIG_QE + /* Config QE ioports */ + config_qe_ioports(); +#endif + } @@ -185,16 +218,25 @@ void cpu_init_f (void) * The newer 8548, etc, parts have twice as much cache, but * use the same bit-encoding as the older 8555, etc, parts. * - * FIXME: Use PVR_VER(pvr) == 1 test here instead of SVR_VER()? */ int cpu_init_r(void) { +#if defined(CONFIG_CLEAR_LAW0) || defined(CONFIG_L2_CACHE) + volatile immap_t *immap = (immap_t *)CFG_IMMR; +#endif +#ifdef CONFIG_CLEAR_LAW0 + volatile ccsr_local_ecm_t *ecm = &immap->im_local_ecm; + + /* clear alternate boot location LAW (used for sdram, or ddr bank) */ + ecm->lawar0 = 0; +#endif + #if defined(CONFIG_L2_CACHE) - volatile immap_t *immap = (immap_t *)CFG_IMMR; volatile ccsr_l2cache_t *l2cache = &immap->im_l2cache; volatile uint cache_ctl; uint svr, ver; + uint l2srbar; svr = get_svr(); ver = SVR_VER(svr); @@ -204,33 +246,55 @@ int cpu_init_r(void) switch (cache_ctl & 0x30000000) { case 0x20000000: - if (ver == SVR_8548 || ver == SVR_8548_E) { + if (ver == SVR_8548 || ver == SVR_8548_E || + ver == SVR_8544) { printf ("L2 cache 512KB:"); + /* set L2E=1, L2I=1, & L2SRAM=0 */ + cache_ctl = 0xc0000000; } else { printf ("L2 cache 256KB:"); + /* set L2E=1, L2I=1, & L2BLKSZ=2 (256 Kbyte) */ + cache_ctl = 0xc8000000; } break; - case 0x00000000: case 0x10000000: + printf ("L2 cache 256KB:"); + if (ver == SVR_8544 || ver == SVR_8544_E) { + cache_ctl = 0xc0000000; /* set L2E=1, L2I=1, & L2SRAM=0 */ + } + break; case 0x30000000: + case 0x00000000: default: printf ("L2 cache unknown size (0x%08x)\n", cache_ctl); return -1; } - asm("msync;isync"); - l2cache->l2ctl = 0x68000000; /* invalidate */ - cache_ctl = l2cache->l2ctl; - asm("msync;isync"); - - l2cache->l2ctl = 0xa8000000; /* enable 256KB L2 cache */ - cache_ctl = l2cache->l2ctl; - asm("msync;isync"); - - printf(" enabled\n"); + if (l2cache->l2ctl & 0x80000000) { + printf(" already enabled."); + l2srbar = l2cache->l2srbar0; +#ifdef CFG_INIT_L2_ADDR + if (l2cache->l2ctl & 0x00010000 && l2srbar >= CFG_FLASH_BASE) { + l2srbar = CFG_INIT_L2_ADDR; + l2cache->l2srbar0 = l2srbar; + printf(" Moving to 0x%08x", CFG_INIT_L2_ADDR); + } +#endif /* CFG_INIT_L2_ADDR */ + puts("\n"); + } else { + asm("msync;isync"); + l2cache->l2ctl = cache_ctl; /* invalidate & enable */ + asm("msync;isync"); + printf(" enabled\n"); + } #else printf("L2 cache: disabled\n"); #endif +#ifdef CONFIG_QE + uint qe_base = CFG_IMMR + 0x00080000; /* QE immr base */ + qe_init(qe_base); + qe_reset(); +#endif return 0; } diff --git a/cpu/mpc85xx/ether_fcc.c b/cpu/mpc85xx/ether_fcc.c index d15d242..5b23a80 100644 --- a/cpu/mpc85xx/ether_fcc.c +++ b/cpu/mpc85xx/ether_fcc.c @@ -48,13 +48,13 @@ #include <config.h> #include <net.h> -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) #include <miiphy.h> #endif #if defined(CONFIG_CPM2) -#if defined(CONFIG_ETHER_ON_FCC) && (CONFIG_COMMANDS & CFG_CMD_NET) && \ +#if defined(CONFIG_ETHER_ON_FCC) && defined(CONFIG_CMD_NET) && \ defined(CONFIG_NET_MULTI) static struct ether_fcc_info_s @@ -458,7 +458,7 @@ int fec_initialize(bd_t *bis) eth_register(dev); -#if (defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) \ +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) \ && defined(CONFIG_BITBANGMII) miiphy_register(dev->name, bb_miiphy_read, bb_miiphy_write); @@ -468,6 +468,6 @@ int fec_initialize(bd_t *bis) return 1; } -#endif /* CONFIG_ETHER_ON_FCC && CFG_CMD_NET && CONFIG_NET_MULTI */ +#endif #endif /* CONFIG_CPM2 */ diff --git a/cpu/mpc85xx/interrupts.c b/cpu/mpc85xx/interrupts.c index 832781b..bf737d6 100644 --- a/cpu/mpc85xx/interrupts.c +++ b/cpu/mpc85xx/interrupts.c @@ -89,6 +89,39 @@ int interrupt_init (void) mtspr(SPRN_TCR, TCR_PIE); set_dec (decrementer_count); set_msr (get_msr () | MSR_EE); + +#ifdef CONFIG_INTERRUPTS + volatile ccsr_pic_t *pic = &immr->im_pic; + + pic->iivpr1 = 0x810002; /* 50220 enable ecm interrupts */ + debug("iivpr1@%x = %x\n",&pic->iivpr1, pic->iivpr1); + + pic->iivpr2 = 0x810002; /* 50240 enable ddr interrupts */ + debug("iivpr2@%x = %x\n",&pic->iivpr2, pic->iivpr2); + + pic->iivpr3 = 0x810003; /* 50260 enable lbc interrupts */ + debug("iivpr3@%x = %x\n",&pic->iivpr3, pic->iivpr3); + +#ifdef CONFIG_PCI1 + pic->iivpr8 = 0x810008; /* enable pci1 interrupts */ + debug("iivpr8@%x = %x\n",&pic->iivpr8, pic->iivpr8); +#endif +#if defined(CONFIG_PCI2) || defined(CONFIG_PCIE2) + pic->iivpr9 = 0x810009; /* enable pci1 interrupts */ + debug("iivpr9@%x = %x\n",&pic->iivpr9, pic->iivpr9); +#endif +#ifdef CONFIG_PCIE1 + pic->iivpr10 = 0x81000a; /* enable pcie1 interrupts */ + debug("iivpr10@%x = %x\n",&pic->iivpr10, pic->iivpr10); +#endif +#ifdef CONFIG_PCIE3 + pic->iivpr11 = 0x81000b; /* enable pcie3 interrupts */ + debug("iivpr11@%x = %x\n",&pic->iivpr11, pic->iivpr11); +#endif + + pic->ctpr=0; /* 40080 clear current task priority register */ +#endif + return (0); } @@ -144,7 +177,7 @@ void set_timer (ulong t) timestamp = t; } -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) /******************************************************************************* * @@ -159,4 +192,4 @@ do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/mpc85xx/pci.c b/cpu/mpc85xx/pci.c index 3c1a323..db09e45 100644 --- a/cpu/mpc85xx/pci.c +++ b/cpu/mpc85xx/pci.c @@ -142,7 +142,7 @@ pci_mpc85xx_init(struct pci_controller *board_hose) u8 header_type; pci_hose_read_config_byte(hose, - PCI_BDF(0,17,0), + PCI_BDF(0,BRIDGE_ID,0), PCI_HEADER_TYPE, &header_type); } diff --git a/cpu/mpc85xx/qe_io.c b/cpu/mpc85xx/qe_io.c new file mode 100644 index 0000000..8878bc5 --- /dev/null +++ b/cpu/mpc85xx/qe_io.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "common.h" +#include "asm/errno.h" +#include "asm/io.h" +#include "asm/immap_85xx.h" + +#if defined(CONFIG_QE) +#define NUM_OF_PINS 32 +void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) +{ + u32 pin_2bit_mask; + u32 pin_2bit_dir; + u32 pin_2bit_assign; + u32 pin_1bit_mask; + u32 tmp_val; + volatile immap_t *im = (volatile immap_t *)CFG_IMMR; + volatile par_io_t *par_io = (volatile par_io_t *) + &(im->im_gur.qe_par_io); + + /* Caculate pin location and 2bit mask and dir */ + pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); + pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); + + /* Setup the direction */ + tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \ + in_be32(&par_io[port].cpdir2) : + in_be32(&par_io[port].cpdir1); + + if (pin > (NUM_OF_PINS/2) -1) { + out_be32(&par_io[port].cpdir2, ~pin_2bit_mask & tmp_val); + out_be32(&par_io[port].cpdir2, pin_2bit_dir | tmp_val); + } else { + out_be32(&par_io[port].cpdir1, ~pin_2bit_mask & tmp_val); + out_be32(&par_io[port].cpdir1, pin_2bit_dir | tmp_val); + } + + /* Calculate pin location for 1bit mask */ + pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1))); + + /* Setup the open drain */ + tmp_val = in_be32(&par_io[port].cpodr); + if (open_drain) + out_be32(&par_io[port].cpodr, pin_1bit_mask | tmp_val); + else + out_be32(&par_io[port].cpodr, ~pin_1bit_mask & tmp_val); + + /* Setup the assignment */ + tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? + in_be32(&par_io[port].cppar2): + in_be32(&par_io[port].cppar1); + pin_2bit_assign = (u32)(assign + << (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2)); + + /* Clear and set 2 bits mask */ + if (pin > (NUM_OF_PINS/2) - 1) { + out_be32(&par_io[port].cppar2, ~pin_2bit_mask & tmp_val); + out_be32(&par_io[port].cppar2, pin_2bit_assign | tmp_val); + } else { + out_be32(&par_io[port].cppar1, ~pin_2bit_mask & tmp_val); + out_be32(&par_io[port].cppar1, pin_2bit_assign | tmp_val); + } +} + +#endif /* CONFIG_QE */ diff --git a/cpu/mpc85xx/spd_sdram.c b/cpu/mpc85xx/spd_sdram.c index 3777f49..5dc223a 100644 --- a/cpu/mpc85xx/spd_sdram.c +++ b/cpu/mpc85xx/spd_sdram.c @@ -1,5 +1,5 @@ /* - * Copyright 2004 Freescale Semiconductor. + * Copyright 2004, 2007 Freescale Semiconductor. * (C) Copyright 2003 Motorola Inc. * Xianghua Xiao (X.Xiao@motorola.com) * @@ -173,11 +173,10 @@ spd_sdram(void) { volatile immap_t *immap = (immap_t *)CFG_IMMR; volatile ccsr_ddr_t *ddr = &immap->im_ddr; - volatile ccsr_gur_t *gur = &immap->im_gur; spd_eeprom_t spd; unsigned int n_ranks; unsigned int rank_density; - unsigned int odt_rd_cfg, odt_wr_cfg; + unsigned int odt_rd_cfg, odt_wr_cfg, ba_bits; unsigned int odt_cfg, mode_odt_enable; unsigned int refresh_clk; #ifdef MPC85xx_DDR_SDRAM_CLK_CNTL @@ -189,7 +188,7 @@ spd_sdram(void) unsigned int max_data_rate, effective_data_rate; unsigned int busfreq; unsigned sdram_cfg; - unsigned int memsize; + unsigned int memsize = 0; unsigned char caslat, caslat_ctrl; unsigned int trfc, trfc_clk, trfc_low, trfc_high; unsigned int trcd_clk; @@ -204,6 +203,46 @@ spd_sdram(void) unsigned int mode_caslat; unsigned char sdram_type; unsigned char d_init; + unsigned int bnds; + + /* + * Skip configuration if already configured. + * memsize is determined from last configured chip select. + */ + if (ddr->cs0_config & 0x80000000) { + debug(" cs0 already configured, bnds=%x\n",ddr->cs0_bnds); + bnds = 0xfff & ddr->cs0_bnds; + if (bnds < 0xff) { /* do not add if at top of 4G */ + memsize = (bnds + 1) << 4; + } + } + if (ddr->cs1_config & 0x80000000) { + debug(" cs1 already configured, bnds=%x\n",ddr->cs1_bnds); + bnds = 0xfff & ddr->cs1_bnds; + if (bnds < 0xff) { /* do not add if at top of 4G */ + memsize = (bnds + 1) << 4; /* assume ordered bnds */ + } + } + if (ddr->cs2_config & 0x80000000) { + debug(" cs2 already configured, bnds=%x\n",ddr->cs2_bnds); + bnds = 0xfff & ddr->cs2_bnds; + if (bnds < 0xff) { /* do not add if at top of 4G */ + memsize = (bnds + 1) << 4; + } + } + if (ddr->cs3_config & 0x80000000) { + debug(" cs3 already configured, bnds=%x\n",ddr->cs3_bnds); + bnds = 0xfff & ddr->cs3_bnds; + if (bnds < 0xff) { /* do not add if at top of 4G */ + memsize = (bnds + 1) << 4; + } + } + + if (memsize) { + printf(" Reusing current %dMB configuration\n",memsize); + memsize = setup_laws_and_tlbs(memsize); + return memsize << 20; + } /* * Read SPD information. @@ -262,6 +301,7 @@ spd_sdram(void) return 0; } +#ifdef CONFIG_MPC8548 /* * Adjust DDR II IO voltage biasing. * Only 8548 rev 1 needs the fix @@ -269,9 +309,11 @@ spd_sdram(void) if ((SVR_VER(get_svr()) == SVR_8548_E) && (SVR_MJREV(get_svr()) == 1) && (spd.mem_type == SPD_MEMTYPE_DDR2)) { + volatile ccsr_gur_t *gur = &immap->im_gur; gur->ddrioovcr = (0x80000000 /* Enable */ | 0x10000000);/* VSEL to 1.8V */ } +#endif /* * Determine the size of each Rank in bytes. @@ -299,9 +341,14 @@ spd_sdram(void) #endif } + ba_bits = 0; + if (spd.nbanks == 0x8) + ba_bits = 1; + ddr->cs0_config = ( 1 << 31 | (odt_rd_cfg << 20) | (odt_wr_cfg << 16) + | (ba_bits << 14) | (spd.nrow_addr - 12) << 8 | (spd.ncol_addr - 8) ); debug("\n"); @@ -645,13 +692,10 @@ spd_sdram(void) */ cpo = 0; if (spd.mem_type == SPD_MEMTYPE_DDR2) { - if (effective_data_rate == 266 || effective_data_rate == 333) { + if (effective_data_rate <= 333) { cpo = 0x7; /* READ_LAT + 5/4 */ - } else if (effective_data_rate == 400) { - cpo = 0x9; /* READ_LAT + 7/4 */ } else { - /* Pure speculation */ - cpo = 0xb; + cpo = 0x9; /* READ_LAT + 7/4 */ } } @@ -858,7 +902,12 @@ spd_sdram(void) if (spd.mem_type == SPD_MEMTYPE_DDR) clk_adjust = 0x6; else +#ifdef CONFIG_MPC8568 + /* Empirally setting clk_adjust */ + clk_adjust = 0x6; +#else clk_adjust = 0x7; +#endif ddr->sdram_clk_cntl = (0 | 0x80000000 diff --git a/cpu/mpc85xx/start.S b/cpu/mpc85xx/start.S index 77c155c..2c98c2a 100644 --- a/cpu/mpc85xx/start.S +++ b/cpu/mpc85xx/start.S @@ -1,7 +1,6 @@ /* - * Copyright 2004 Freescale Semiconductor. + * Copyright 2004, 2007 Freescale Semiconductor. * Copyright (C) 2003 Motorola,Inc. - * Xianghua Xiao<X.Xiao@motorola.com> * * See file CREDITS for list of people who contributed to this * project. @@ -46,7 +45,7 @@ #endif #undef MSR_KERNEL -#define MSR_KERNEL ( MSR_ME ) /* Machine Check */ +#define MSR_KERNEL ( MSR_ME ) /* Machine Check */ /* * Set up GOT: Global Offset Table @@ -80,110 +79,37 @@ * */ - .section .bootpg,"ax" - .globl _start_e500 + .section .bootpg,"ax" + .globl _start_e500 _start_e500: - mfspr r0, PVR - lis r1, PVR_85xx_REV1@h - ori r1, r1, PVR_85xx_REV1@l - cmpw r0, r1 - bne 1f - /* Semi-bogus errata fixup for Rev 1 */ - li r0,0x2000 - mtspr 977,r0 +/* clear registers/arrays not reset by hardware */ - /* - * Before invalidating MMU L1/L2, read TLB1 Entry 0 and then - * write it back immediately to fixup a Rev 1 bug (Errata CPU4) - * for this initial TLB1 entry 0, otherwise the TLB1 entry 0 - * will be invalidated (incorrectly). - */ - lis r2,0x1000 - mtspr MAS0,r2 - tlbre - tlbwe - isync - -1: - /* - * Clear and set up some registers. - * Note: Some registers need strict synchronization by - * sync/mbar/msync/isync when being "mtspr". - * BookE: isync before PID,tlbivax,tlbwe - * BookE: isync after MSR,PID; msync_isync after tlbivax & tlbwe - * E500: msync,isync before L1CSR0 - * E500: isync after BBEAR,BBTAR,BUCSR,DBCR0,DBCR1,HID0,HID1, - * L1CSR0, L1CSR1, MAS[0,1,2,3,4,6],MMUCSR0, PID[0,1,2], - * SPEFCSR - */ - - /* invalidate d-cache */ - mfspr r0,L1CSR0 - ori r0,r0,0x0002 - msync - isync - mtspr L1CSR0,r0 - isync - - /* disable d-cache */ - li r0,0x0 - mtspr L1CSR0,r0 - - /* invalidate i-cache */ - mfspr r0,L1CSR1 - ori r0,r0,0x0002 - mtspr L1CSR1,r0 - isync - - /* disable i-cache */ - li r0,0x0 - mtspr L1CSR1,r0 - isync - - /* clear registers */ - li r0,0 - mtspr SRR0,r0 - mtspr SRR1,r0 - mtspr CSRR0,r0 - mtspr CSRR1,r0 - mtspr MCSRR0,r0 - mtspr MCSRR1,r0 - - mtspr ESR,r0 - mtspr MCSR,r0 - mtspr DEAR,r0 - - /* not needed and conflicts with some debuggers */ - /* mtspr DBCR0,r0 */ - mtspr DBCR1,r0 - mtspr DBCR2,r0 - /* not needed and conflicts with some debuggers */ - /* mtspr IAC1,r0 */ - /* mtspr IAC2,r0 */ - mtspr DAC1,r0 - mtspr DAC2,r0 + /* L1 */ + li r0,2 + mtspr L1CSR0,r0 /* invalidate d-cache */ + mtspr L1CSR1,r0 /* invalidate i-cache */ mfspr r1,DBSR mtspr DBSR,r1 /* Clear all valid bits */ - mtspr PID0,r0 - mtspr PID1,r0 - mtspr PID2,r0 - mtspr TCR,r0 + /* + * Enable L1 Caches early + * + */ - mtspr BUCSR,r0 /* disable branch prediction */ - mtspr MAS4,r0 - mtspr MAS6,r0 -#if defined(CONFIG_ENABLE_36BIT_PHYS) - mtspr MAS7,r0 -#endif + lis r2,L1CSR0_CPE@H /* enable parity */ + ori r2,r2,L1CSR0_DCE + mtspr L1CSR0,r2 /* enable L1 Dcache */ isync + mtspr L1CSR1,r2 /* enable L1 Icache */ + isync + msync /* Setup interrupt vectors */ lis r1,TEXT_BASE@h - mtspr IVPR, r1 + mtspr IVPR,r1 li r1,0x0100 mtspr IVOR0,r1 /* 0: Critical input */ @@ -217,26 +143,6 @@ _start_e500: li r1,0x0f00 mtspr IVOR15,r1 /* 15: Debug */ - /* - * Invalidate MMU L1/L2 - * - * Note: There is a fixup earlier for Errata CPU4 on - * Rev 1 parts that must precede this MMU invalidation. - */ - li r2, 0x001e - mtspr MMUCSR0, r2 - isync - - /* - * Invalidate all TLB0 entries. - */ - li r3,4 - li r4,0 - tlbivax r4,r3 - /* - * To avoid REV1 Errata CPU6 issues, make sure - * the instruction following tlbivax is not a store. - */ /* * After reset, CCSRBAR is located at CFG_CCSRBAR_DEFAULT, i.e. @@ -254,14 +160,14 @@ _start_e500: lwzu r4,0(r5) /* how many TLB1 entries we actually use */ mtctr r4 -0: lwzu r0,4(r5) - lwzu r1,4(r5) - lwzu r2,4(r5) - lwzu r3,4(r5) - mtspr MAS0,r0 - mtspr MAS1,r1 - mtspr MAS2,r2 - mtspr MAS3,r3 +0: lwzu r6,4(r5) + lwzu r7,4(r5) + lwzu r8,4(r5) + lwzu r9,4(r5) + mtspr MAS0,r6 + mtspr MAS1,r7 + mtspr MAS2,r8 + mtspr MAS3,r9 isync msync tlbwe @@ -271,22 +177,22 @@ _start_e500: 1: #if (CFG_CCSRBAR_DEFAULT != CFG_CCSRBAR) /* Special sequence needed to update CCSRBAR itself */ - lis r4, CFG_CCSRBAR_DEFAULT@h - ori r4, r4, CFG_CCSRBAR_DEFAULT@l + lis r4,CFG_CCSRBAR_DEFAULT@h + ori r4,r4,CFG_CCSRBAR_DEFAULT@l - lis r5, CFG_CCSRBAR@h - ori r5, r5, CFG_CCSRBAR@l + lis r5,CFG_CCSRBAR@h + ori r5,r5,CFG_CCSRBAR@l srwi r6,r5,12 - stw r6, 0(r4) + stw r6,0(r4) isync - lis r5, 0xffff + lis r5,0xffff ori r5,r5,0xf000 - lwz r5, 0(r5) + lwz r5,0(r5) isync - lis r3, CFG_CCSRBAR@h - lwz r5, CFG_CCSRBAR@l(r3) + lis r3,CFG_CCSRBAR@h + lwz r5,CFG_CCSRBAR@l(r3) isync #endif @@ -300,8 +206,8 @@ _start_e500: lwzu r5,0(r6) /* how many windows we actually use */ mtctr r5 - li r2,0x0c28 /* the first pair is reserved for boot-over-rio-or-pci */ - li r1,0x0c30 + li r2,0x0c28 /* the first pair is reserved for */ + li r1,0x0c30 /* boot-over-rio-or-pci */ 0: lwzu r4,4(r6) lwzu r3,4(r6) @@ -311,31 +217,6 @@ _start_e500: addi r1,r1,0x0020 bdnz 0b - /* Jump out the last 4K page and continue to 'normal' start */ -1: bl 3f - b _start - -3: li r0,0 - mtspr SRR1,r0 /* Keep things disabled for now */ - mflr r1 - mtspr SRR0,r1 - rfi - -/* - * r3 - 1st arg to board_init(): IMMP pointer - * r4 - 2nd arg to board_init(): boot flag - */ - .text - .long 0x27051956 /* U-BOOT Magic Number */ - .globl version_string -version_string: - .ascii U_BOOT_VERSION - .ascii " (", __DATE__, " - ", __TIME__, ")" - .ascii CONFIG_IDENT_STRING, "\0" - - . = EXC_OFF_SYS_RESET - .globl _start -_start: /* Clear and set up some registers. */ li r0,0x0000 lis r1,0xffff @@ -354,17 +235,14 @@ _start: /* Enable Time Base and Select Time Base Clock */ lis r0,HID0_EMCP@h /* Enable machine check */ - ori r0,r0,0x4000 /* time base is processor clock */ #if defined(CONFIG_ENABLE_36BIT_PHYS) - ori r0,r0,0x0080 /* enable MAS7 updates */ + ori r0,r0,(HID0_TBEN|HID0_ENMAS7)@l /* Enable Timebase & MAS7 */ +#else + ori r0,r0,HID0_TBEN@l /* enable Timebase */ #endif mtspr HID0,r0 -#if defined(CONFIG_ADDR_STREAMING) - li r0,0x3000 -#else - li r0,0x1000 -#endif + li r0,(HID1_ASTME|HID1_ABE)@l /* Addr streaming & broadcast */ mtspr HID1,r0 /* Enable Branch Prediction */ @@ -383,37 +261,53 @@ _start: #endif /* L1 DCache is used for initial RAM */ - mfspr r2, L1CSR0 - ori r2, r2, 0x0003 - oris r2, r2, 0x0001 - mtspr L1CSR0, r2 /* enable/invalidate L1 Dcache */ - isync /* Allocate Initial RAM in data cache. */ - lis r3, CFG_INIT_RAM_ADDR@h - ori r3, r3, CFG_INIT_RAM_ADDR@l - li r2, 512 /* 512*32=16K */ + lis r3,CFG_INIT_RAM_ADDR@h + ori r3,r3,CFG_INIT_RAM_ADDR@l + li r2,512 /* 512*32=16K */ mtctr r2 - li r0, 0 + li r0,0 1: - dcbz r0, r3 - dcbtls 0,r0, r3 - addi r3, r3, 32 + dcbz r0,r3 + dcbtls 0,r0,r3 + addi r3,r3,32 bdnz 1b -#ifndef CFG_RAMBOOT + /* Jump out the last 4K page and continue to 'normal' start */ +#ifdef CFG_RAMBOOT + bl 3f + b _start_cont +#else /* Calculate absolute address in FLASH and jump there */ /*--------------------------------------------------------------*/ - lis r3, CFG_MONITOR_BASE@h - ori r3, r3, CFG_MONITOR_BASE@l - addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET + lis r3,CFG_MONITOR_BASE@h + ori r3,r3,CFG_MONITOR_BASE@l + addi r3,r3,_start_cont - _start + _START_OFFSET mtlr r3 - blr +#endif -in_flash: -#endif /* CFG_RAMBOOT */ +3: li r0,0 + mtspr SRR1,r0 /* Keep things disabled for now */ + mflr r1 + mtspr SRR0,r1 + rfi + isync + .text + .globl _start +_start: + .long 0x27051956 /* U-BOOT Magic Number */ + .globl version_string +version_string: + .ascii U_BOOT_VERSION + .ascii " (", __DATE__, " - ", __TIME__, ")" + .ascii CONFIG_IDENT_STRING, "\0" + + .align 4 + .globl _start_cont +_start_cont: /* Setup the stack in initial RAM,could be L2-as-SRAM or L1 dcache*/ lis r1,CFG_INIT_RAM_ADDR@h ori r1,r1,CFG_INIT_SP_OFFSET@l @@ -424,26 +318,24 @@ in_flash: stwu r1,-8(r1) /* Save back chain and move SP */ lis r0,RESET_VECTOR@h /* Address of reset vector */ - ori r0,r0, RESET_VECTOR@l + ori r0,r0,RESET_VECTOR@l stwu r1,-8(r1) /* Save back chain and move SP */ stw r0,+12(r1) /* Save return addr (underflow vect) */ GET_GOT bl cpu_init_f - bl icache_enable bl board_init_f isync -/* --FIXME-- machine check with MCSRRn and rfmci */ - + . = EXC_OFF_SYS_RESET .globl _start_of_vectors _start_of_vectors: -#if 0 + /* Critical input. */ - CRIT_EXCEPTION(0x0100, CritcalInput, CritcalInputException) -#endif -/* Machine check --FIXME-- Should be MACH_EXCEPTION */ - CRIT_EXCEPTION(0x0200, MachineCheck, MachineCheckException) + CRIT_EXCEPTION(0x0100, CriticalInput, CritcalInputException) + +/* Machine check */ + MCK_EXCEPTION(0x200, MachineCheck, MachineCheckException) /* Data Storage exception. */ STD_EXCEPTION(0x0300, DataStorage, UnknownException) @@ -452,7 +344,7 @@ _start_of_vectors: STD_EXCEPTION(0x0400, InstStorage, UnknownException) /* External Interrupt exception. */ - STD_EXCEPTION(0x0500, ExtInterrupt, UnknownException) + STD_EXCEPTION(0x0500, ExtInterrupt, ExtIntException) /* Alignment exception. */ . = 0x0600 @@ -469,8 +361,8 @@ Alignment: mtlr r6 blrl .L_Alignment: - .long AlignmentException - _start + EXC_OFF_SYS_RESET - .long int_return - _start + EXC_OFF_SYS_RESET + .long AlignmentException - _start + _START_OFFSET + .long int_return - _start + _START_OFFSET /* Program check exception */ . = 0x0700 @@ -483,8 +375,8 @@ ProgramCheck: mtlr r6 blrl .L_ProgramCheck: - .long ProgramCheckException - _start + EXC_OFF_SYS_RESET - .long int_return - _start + EXC_OFF_SYS_RESET + .long ProgramCheckException - _start + _START_OFFSET + .long int_return - _start + _START_OFFSET /* No FPU on MPC85xx. This exception is not supposed to happen. */ @@ -496,23 +388,23 @@ ProgramCheck: * r3-... arguments */ SystemCall: - addis r11,r0,0 /* get functions table addr */ - ori r11,r11,0 /* Note: this code is patched in trap_init */ - addis r12,r0,0 /* get number of functions */ + addis r11,r0,0 /* get functions table addr */ + ori r11,r11,0 /* Note: this code is patched in trap_init */ + addis r12,r0,0 /* get number of functions */ ori r12,r12,0 - cmplw 0, r0, r12 + cmplw 0,r0,r12 bge 1f - rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */ + rlwinm r0,r0,2,0,31 /* fn_addr = fn_tbl[r0] */ add r11,r11,r0 lwz r11,0(r11) - li r20,0xd00-4 /* Get stack pointer */ + li r20,0xd00-4 /* Get stack pointer */ lwz r12,0(r20) - subi r12,r12,12 /* Adjust stack pointer */ + subi r12,r12,12 /* Adjust stack pointer */ li r0,0xc00+_end_back-SystemCall - cmplw 0, r0, r12 /* Check stack overflow */ + cmplw 0,r0,r12 /* Check stack overflow */ bgt 1f stw r12,0(r20) @@ -570,7 +462,7 @@ _end_back: _end_of_vectors: - . = 0x2100 + . = . + (0x100 - ( . & 0xff )) /* align for debug */ /* * This code finishes saving the registers to the exception frame @@ -655,26 +547,58 @@ crit_return: REST_GPR(31, r1) lwz r2,_NIP(r1) /* Restore environment */ lwz r0,_MSR(r1) - mtspr 990,r2 /* SRR2 */ - mtspr 991,r0 /* SRR3 */ + mtspr SPRN_CSRR0,r2 + mtspr SPRN_CSRR1,r0 lwz r0,GPR0(r1) lwz r2,GPR2(r1) lwz r1,GPR1(r1) SYNC rfci +mck_return: + mfmsr r28 /* Disable interrupts */ + li r4,0 + ori r4,r4,MSR_EE + andc r28,r28,r4 + SYNC /* Some chip revs need this... */ + mtmsr r28 + SYNC + lwz r2,_CTR(r1) + lwz r0,_LINK(r1) + mtctr r2 + mtlr r0 + lwz r2,_XER(r1) + lwz r0,_CCR(r1) + mtspr XER,r2 + mtcrf 0xFF,r0 + REST_10GPRS(3, r1) + REST_10GPRS(13, r1) + REST_8GPRS(23, r1) + REST_GPR(31, r1) + lwz r2,_NIP(r1) /* Restore environment */ + lwz r0,_MSR(r1) + mtspr SPRN_MCSRR0,r2 + mtspr SPRN_MCSRR1,r0 + lwz r0,GPR0(r1) + lwz r2,GPR2(r1) + lwz r1,GPR1(r1) + SYNC + rfmci + /* Cache functions. */ invalidate_icache: mfspr r0,L1CSR1 - ori r0,r0,0x0002 + ori r0,r0,L1CSR1_ICFI + msync + isync mtspr L1CSR1,r0 isync - blr /* entire I cache */ + blr /* entire I cache */ invalidate_dcache: mfspr r0,L1CSR0 - ori r0,r0,0x0002 + ori r0,r0,L1CSR0_DCFI msync isync mtspr L1CSR0,r0 @@ -697,9 +621,9 @@ icache_enable: .globl icache_disable icache_disable: mfspr r0,L1CSR1 - lis r1,0xfffffffe@h - ori r1,r1,0xfffffffe@l - and r0,r0,r1 + lis r3,0 + ori r3,r3,L1CSR1_ICE + andc r0,r0,r3 mtspr L1CSR1,r0 isync blr @@ -707,7 +631,7 @@ icache_disable: .globl icache_status icache_status: mfspr r3,L1CSR1 - andi. r3,r3,1 + andi. r3,r3,L1CSR1_ICE blr .globl dcache_enable @@ -727,12 +651,10 @@ dcache_enable: .globl dcache_disable dcache_disable: - mfspr r0,L1CSR0 - lis r1,0xfffffffe@h - ori r1,r1,0xfffffffe@l - and r0,r0,r1 - msync - isync + mfspr r3,L1CSR0 + lis r4,0 + ori r4,r4,L1CSR0_DCE + andc r3,r3,r4 mtspr L1CSR0,r0 isync blr @@ -740,27 +662,27 @@ dcache_disable: .globl dcache_status dcache_status: mfspr r3,L1CSR0 - andi. r3,r3,1 + andi. r3,r3,L1CSR0_DCE blr .globl get_pir get_pir: - mfspr r3, PIR + mfspr r3,PIR blr .globl get_pvr get_pvr: - mfspr r3, PVR + mfspr r3,PVR blr .globl get_svr get_svr: - mfspr r3, SVR + mfspr r3,SVR blr .globl wr_tcr wr_tcr: - mtspr TCR, r3 + mtspr TCR,r3 blr /*------------------------------------------------------------------------------- */ @@ -913,16 +835,16 @@ ppcSync: */ .globl relocate_code relocate_code: - mr r1, r3 /* Set new stack pointer */ - mr r9, r4 /* Save copy of Init Data pointer */ - mr r10, r5 /* Save copy of Destination Address */ + mr r1,r3 /* Set new stack pointer */ + mr r9,r4 /* Save copy of Init Data pointer */ + mr r10,r5 /* Save copy of Destination Address */ - mr r3, r5 /* Destination Address */ - lis r4, CFG_MONITOR_BASE@h /* Source Address */ - ori r4, r4, CFG_MONITOR_BASE@l + mr r3,r5 /* Destination Address */ + lis r4,CFG_MONITOR_BASE@h /* Source Address */ + ori r4,r4,CFG_MONITOR_BASE@l lwz r5,GOT(__init_end) sub r5,r5,r4 - li r6, CFG_CACHELINE_SIZE /* Cache Line Size */ + li r6,CFG_CACHELINE_SIZE /* Cache Line Size */ /* * Fix GOT pointer: @@ -931,12 +853,12 @@ relocate_code: * * Offset: */ - sub r15, r10, r4 + sub r15,r10,r4 /* First our own GOT */ - add r14, r14, r15 + add r14,r14,r15 /* the the one used by the C code */ - add r30, r30, r15 + add r30,r30,r15 /* * Now relocate code @@ -997,10 +919,10 @@ relocate_code: * initialization, now running from RAM. */ - addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET + addi r0,r10,in_ram - _start + _START_OFFSET mtlr r0 blr /* NEVER RETURNS! */ - + .globl in_ram in_ram: /* @@ -1044,19 +966,19 @@ clear_bss: lwz r3,GOT(__bss_start) lwz r4,GOT(_end) - cmplw 0, r3, r4 + cmplw 0,r3,r4 beq 6f - li r0, 0 + li r0,0 5: - stw r0, 0(r3) - addi r3, r3, 4 - cmplw 0, r3, r4 + stw r0,0(r3) + addi r3,r3,4 + cmplw 0,r3,r4 bne 5b 6: - mr r3, r9 /* Init Data pointer */ - mr r4, r10 /* Destination Address */ + mr r3,r9 /* Init Data pointer */ + mr r4,r10 /* Destination Address */ bl board_init_r /* @@ -1067,52 +989,54 @@ clear_bss: */ .globl trap_init trap_init: - lwz r7, GOT(_start) - lwz r8, GOT(_end_of_vectors) + lwz r7,GOT(_start_of_vectors) + lwz r8,GOT(_end_of_vectors) - li r9, 0x100 /* reset vector always at 0x100 */ + li r9,0x100 /* reset vector always at 0x100 */ - cmplw 0, r7, r8 + cmplw 0,r7,r8 bgelr /* return if r7>=r8 - just in case */ mflr r4 /* save link register */ 1: - lwz r0, 0(r7) - stw r0, 0(r9) - addi r7, r7, 4 - addi r9, r9, 4 - cmplw 0, r7, r8 + lwz r0,0(r7) + stw r0,0(r9) + addi r7,r7,4 + addi r9,r9,4 + cmplw 0,r7,r8 bne 1b /* * relocate `hdlr' and `int_return' entries */ - li r7, .L_MachineCheck - _start + EXC_OFF_SYS_RESET + li r7,.L_CriticalInput - _start + _START_OFFSET bl trap_reloc - li r7, .L_DataStorage - _start + EXC_OFF_SYS_RESET + li r7,.L_MachineCheck - _start + _START_OFFSET bl trap_reloc - li r7, .L_InstStorage - _start + EXC_OFF_SYS_RESET + li r7,.L_DataStorage - _start + _START_OFFSET bl trap_reloc - li r7, .L_ExtInterrupt - _start + EXC_OFF_SYS_RESET + li r7,.L_InstStorage - _start + _START_OFFSET bl trap_reloc - li r7, .L_Alignment - _start + EXC_OFF_SYS_RESET + li r7,.L_ExtInterrupt - _start + _START_OFFSET bl trap_reloc - li r7, .L_ProgramCheck - _start + EXC_OFF_SYS_RESET + li r7,.L_Alignment - _start + _START_OFFSET bl trap_reloc - li r7, .L_FPUnavailable - _start + EXC_OFF_SYS_RESET + li r7,.L_ProgramCheck - _start + _START_OFFSET bl trap_reloc - li r7, .L_Decrementer - _start + EXC_OFF_SYS_RESET + li r7,.L_FPUnavailable - _start + _START_OFFSET bl trap_reloc - li r7, .L_IntervalTimer - _start + EXC_OFF_SYS_RESET - li r8, _end_of_vectors - _start + EXC_OFF_SYS_RESET + li r7,.L_Decrementer - _start + _START_OFFSET + bl trap_reloc + li r7,.L_IntervalTimer - _start + _START_OFFSET + li r8,_end_of_vectors - _start + _START_OFFSET 2: bl trap_reloc - addi r7, r7, 0x100 /* next exception vector */ - cmplw 0, r7, r8 + addi r7,r7,0x100 /* next exception vector */ + cmplw 0,r7,r8 blt 2b lis r7,0x0 - mtspr IVPR, r7 + mtspr IVPR,r7 mtlr r4 /* restore link register */ blr @@ -1121,13 +1045,13 @@ trap_init: * Function: relocate entries for one exception vector */ trap_reloc: - lwz r0, 0(r7) /* hdlr ... */ - add r0, r0, r3 /* ... += dest_addr */ - stw r0, 0(r7) + lwz r0,0(r7) /* hdlr ... */ + add r0,r0,r3 /* ... += dest_addr */ + stw r0,0(r7) - lwz r0, 4(r7) /* int_return ... */ - add r0, r0, r3 /* ... += dest_addr */ - stw r0, 4(r7) + lwz r0,4(r7) /* int_return ... */ + add r0,r0,r3 /* ... += dest_addr */ + stw r0,4(r7) blr @@ -1135,13 +1059,13 @@ trap_reloc: .globl unlock_ram_in_cache unlock_ram_in_cache: /* invalidate the INIT_RAM section */ - lis r3, (CFG_INIT_RAM_ADDR & ~31)@h - ori r3, r3, (CFG_INIT_RAM_ADDR & ~31)@l - li r2,512 - mtctr r2 -1: icbi r0, r3 - dcbi r0, r3 - addi r3, r3, 32 + lis r3,(CFG_INIT_RAM_ADDR & ~31)@h + ori r3,r3,(CFG_INIT_RAM_ADDR & ~31)@l + li r4,512 + mtctr r4 +1: icbi r0,r3 + dcbi r0,r3 + addi r3,r3,32 bdnz 1b sync /* Wait for all icbi to complete on bus */ isync diff --git a/cpu/mpc85xx/traps.c b/cpu/mpc85xx/traps.c index 904f052..efc80c7 100644 --- a/cpu/mpc85xx/traps.c +++ b/cpu/mpc85xx/traps.c @@ -1,6 +1,7 @@ /* * linux/arch/ppc/kernel/traps.c * + * Copyright 2007 Freescale Semiconductor. * Copyright (C) 2003 Motorola * Modified by Xianghua Xiao(x.xiao@motorola.com) * @@ -41,7 +42,7 @@ DECLARE_GLOBAL_DATA_PTR; -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif @@ -74,7 +75,7 @@ static __inline__ unsigned long get_esr(void) #define ESR_DIZ 0x00400000 #define ESR_U0F 0x00008000 -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -145,10 +146,13 @@ CritcalInputException(struct pt_regs *regs) panic("Critical Input Exception"); } +int machinecheck_count = 0; +int machinecheck_error = 0; void MachineCheckException(struct pt_regs *regs) { unsigned long fixup; + unsigned int mcsr, mcsrr0, mcsrr1, mcar; /* Probing PCI using config cycles cause this exception * when a device is not present. Catch it and return to @@ -159,40 +163,68 @@ MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) + mcsrr0 = mfspr(SPRN_MCSRR0); + mcsrr1 = mfspr(SPRN_MCSRR1); + mcsr = mfspr(SPRN_MCSR); + mcar = mfspr(SPRN_MCAR); + + machinecheck_count++; + machinecheck_error=1; + +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif printf("Machine check in kernel mode.\n"); - printf("Caused by (from msr): "); - printf("regs %p ",regs); - switch( regs->msr & 0x000F0000) { - case (0x80000000>>12): - printf("Machine check signal - probably due to mm fault\n" - "with mmu off\n"); - break; - case (0x80000000>>13): - printf("Transfer error ack signal\n"); - break; - case (0x80000000>>14): - printf("Data parity signal\n"); - break; - case (0x80000000>>15): - printf("Address parity signal\n"); - break; - default: - printf("Unknown values in msr\n"); - } + printf("Caused by (from mcsr): "); + printf("mcsr = 0x%08x\n", mcsr); + if (mcsr & 0x80000000) + printf("Machine check input pin\n"); + if (mcsr & 0x40000000) + printf("Instruction cache parity error\n"); + if (mcsr & 0x20000000) + printf("Data cache push parity error\n"); + if (mcsr & 0x10000000) + printf("Data cache parity error\n"); + if (mcsr & 0x00000080) + printf("Bus instruction address error\n"); + if (mcsr & 0x00000040) + printf("Bus Read address error\n"); + if (mcsr & 0x00000020) + printf("Bus Write address error\n"); + if (mcsr & 0x00000010) + printf("Bus Instruction data bus error\n"); + if (mcsr & 0x00000008) + printf("Bus Read data bus error\n"); + if (mcsr & 0x00000004) + printf("Bus Write bus error\n"); + if (mcsr & 0x00000002) + printf("Bus Instruction parity error\n"); + if (mcsr & 0x00000001) + printf("Bus Read parity error\n"); + show_regs(regs); + printf("MCSR=0x%08x \tMCSRR0=0x%08x \nMCSRR1=0x%08x \tMCAR=0x%08x\n", + mcsr, mcsrr0, mcsrr1, mcar); print_backtrace((unsigned long *)regs->gpr[1]); - panic("machine check"); + if (machinecheck_count > 10) { + panic("machine check count too high\n"); + } + + if (machinecheck_count > 1) { + regs->nip += 4; /* skip offending instruction */ + printf("Skipping current instr, Returning to 0x%08x\n", + regs->nip); + } else { + printf("Returning back to 0x%08x\n",regs->nip); + } } void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -207,7 +239,7 @@ ProgramCheckException(struct pt_regs *regs) { long esr_val; -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -244,7 +276,7 @@ PITException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -253,13 +285,40 @@ UnknownException(struct pt_regs *regs) regs->nip, regs->msr, regs->trap); _exception(0, regs); } +void +ExtIntException(struct pt_regs *regs) +{ + volatile immap_t *immap = (immap_t *)CFG_IMMR; + volatile ccsr_pic_t *pic = &immap->im_pic; + uint vect; + +#if defined(CONFIG_CMD_KGDB) + if (debugger_exception_handler && (*debugger_exception_handler)(regs)) + return; +#endif + + printf("External Interrupt Exception at PC: %lx, SR: %lx, vector=%lx", + regs->nip, regs->msr, regs->trap); + vect = pic->iack0; + printf(" irq IACK0@%05x=%d\n",&pic->iack0,vect); + show_regs(regs); + print_backtrace((unsigned long *)regs->gpr[1]); + machinecheck_count++; +#ifdef EXTINT_NOSKIP + printf("Returning back to 0x%08x\n",regs->nip); +#else + regs->nip += 4; /* skip offending instruction */ + printf("Skipping current instr, Returning to 0x%08x\n",regs->nip); +#endif + +} void DebugException(struct pt_regs *regs) { printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/mpc86xx/Makefile b/cpu/mpc86xx/Makefile index fffcfd2..6d9300e 100644 --- a/cpu/mpc86xx/Makefile +++ b/cpu/mpc86xx/Makefile @@ -1,4 +1,5 @@ # +# Copyright 2007 Freescale Semiconductor, Inc. # (C) Copyright 2002,2003 Motorola Inc. # Xianghua Xiao,X.Xiao@motorola.com # @@ -30,7 +31,7 @@ LIB = $(obj)lib$(CPU).a START = start.o #resetvec.o SOBJS = cache.o COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \ - pci.o pcie_indirect.o spd_sdram.o + spd_sdram.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mpc86xx/cpu_init.c b/cpu/mpc86xx/cpu_init.c index 4673d05..c8e4666 100644 --- a/cpu/mpc86xx/cpu_init.c +++ b/cpu/mpc86xx/cpu_init.c @@ -104,8 +104,8 @@ void cpu_init_f(void) /* enable the timebase bit in HID0 */ set_hid0(get_hid0() | 0x4000000); - /* enable SYNCBE | ABE bits in HID1 */ - set_hid1(get_hid1() | 0x00000C00); + /* enable EMCP, SYNCBE | ABE bits in HID1 */ + set_hid1(get_hid1() | 0x80000C00); } /* diff --git a/cpu/mpc86xx/interrupts.c b/cpu/mpc86xx/interrupts.c index 49820bb..d9f634f 100644 --- a/cpu/mpc86xx/interrupts.c +++ b/cpu/mpc86xx/interrupts.c @@ -8,7 +8,7 @@ * (C) Copyright 2003 Motorola Inc. (MPC85xx port) * Xianghua Xiao (X.Xiao@motorola.com) * - * (C) Copyright 2004 Freescale Semiconductor. (MPC86xx Port) + * (C) Copyright 2004, 2007 Freescale Semiconductor. (MPC86xx Port) * Jeff Brown * Srikanth Srinivasan (srikanth.srinivasan@freescale.com) * @@ -71,7 +71,7 @@ static __inline__ void set_dec(unsigned long val) } /* interrupt is not supported yet */ -int interrupt_init_cpu(unsigned *decrementer_count) +int interrupt_init_cpu(unsigned long *decrementer_count) { return 0; } @@ -80,25 +80,10 @@ int interrupt_init(void) { int ret; - /* - * The IRQ0 on Rev 2 is pulled high (low in Rev 1.x) to - * implement PEX10 errata. As INT is active high, it - * will cause core to take 0x500 interrupt. - * - * Due to the PIC's default pass through mode, as soon - * as interrupts are enabled (MSR[EE] = 1), an interrupt - * will be taken and u-boot will hang. This is due to a - * hardware change (per an errata fix) on new revisions - * of the board with Rev 2.x parts. - * - * Setting the PIC to mixed mode prevents the hang. - */ - if ((get_svr() & 0xf0) == 0x20) { - volatile immap_t *immr = (immap_t *)CFG_IMMR; - immr->im_pic.gcr = MPC86xx_PICGCR_RST; - while (immr->im_pic.gcr & MPC86xx_PICGCR_RST); - immr->im_pic.gcr = MPC86xx_PICGCR_MODE; - } + volatile immap_t *immr = (immap_t *)CFG_IMMR; + immr->im_pic.gcr = MPC86xx_PICGCR_RST; + while (immr->im_pic.gcr & MPC86xx_PICGCR_RST); + immr->im_pic.gcr = MPC86xx_PICGCR_MODE; /* call cpu specific function from $(CPU)/interrupts.c */ ret = interrupt_init_cpu(&decrementer_count); @@ -107,7 +92,7 @@ int interrupt_init(void) return ret; decrementer_count = get_tbclk() / CFG_HZ; - debug("interrupt init: tbclk() = %d MHz, decrementer_count = %d\n", + debug("interrupt init: tbclk() = %d MHz, decrementer_count = %ld\n", (get_tbclk() / 1000000), decrementer_count); @@ -119,6 +104,30 @@ int interrupt_init(void) get_msr(), get_dec()); +#ifdef CONFIG_INTERRUPTS + volatile ccsr_pic_t *pic = &immr->im_pic; + + pic->iivpr1 = 0x810001; /* 50220 enable mcm interrupts */ + debug("iivpr1@%x = %x\n", &pic->iivpr1, pic->iivpr1); + + pic->iivpr2 = 0x810002; /* 50240 enable ddr interrupts */ + debug("iivpr2@%x = %x\n", &pic->iivpr2, pic->iivpr2); + + pic->iivpr3 = 0x810003; /* 50260 enable lbc interrupts */ + debug("iivpr3@%x = %x\n", &pic->iivpr3, pic->iivpr3); + +#if defined(CONFIG_PCI1) || defined(CONFIG_PCIE1) + pic->iivpr8 = 0x810008; /* enable pcie1 interrupts */ + debug("iivpr8@%x = %x\n", &pic->iivpr8, pic->iivpr8); +#endif +#if defined(CONFIG_PCI2) || defined(CONFIG_PCIE2) + pic->iivpr9 = 0x810009; /* enable pcie2 interrupts */ + debug("iivpr9@%x = %x\n", &pic->iivpr9, pic->iivpr9); +#endif + + pic->ctpr = 0; /* 40080 clear current task priority register */ +#endif + return 0; } @@ -158,8 +167,6 @@ void timer_interrupt(struct pt_regs *regs) timestamp++; - ppcDcbf(×tamp); - /* Restore Decrementer Count */ set_dec(decrementer_count); diff --git a/cpu/mpc86xx/pci.c b/cpu/mpc86xx/pci.c deleted file mode 100644 index b86548d..0000000 --- a/cpu/mpc86xx/pci.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) Freescale Semiconductor,Inc. - * 2005, 2006. All rights reserved. - * - * Ed Swarthout (ed.swarthout@freescale.com) - * Jason Jin (Jason.jin@freescale.com) - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -/* - * PCIE Configuration space access support for PCIE Bridge - */ -#include <common.h> -#include <pci.h> - -#if defined(CONFIG_PCI) -void -pci_mpc86xx_init(struct pci_controller *hose) -{ - volatile immap_t *immap = (immap_t *) CFG_CCSRBAR; - volatile ccsr_pex_t *pcie1 = &immap->im_pex1; - u16 temp16; - u32 temp32; - - volatile ccsr_gur_t *gur = &immap->im_gur; - uint host1_agent = (gur->porbmsr & MPC86xx_PORBMSR_HA) >> 17; - uint pcie1_host = (host1_agent == 2) || (host1_agent == 3); - uint pcie1_agent = (host1_agent == 0) || (host1_agent == 1); - uint devdisr = gur->devdisr; - uint io_sel = (gur->pordevsr & MPC86xx_PORDEVSR_IO_SEL) >> 16; - - if ((io_sel == 2 || io_sel == 3 || io_sel == 5 || io_sel == 6 || - io_sel == 7 || io_sel == 0xf) - && !(devdisr & MPC86xx_DEVDISR_PCIEX1)) { - printf("PCI-EXPRESS 1: Configured as %s \n", - pcie1_agent ? "Agent" : "Host"); - if (pcie1_agent) - return; /*Don't scan bus when configured as agent */ - printf(" Scanning PCIE bus"); - debug("0x%08x=0x%08x ", - &pcie1->pme_msg_det, - pcie1->pme_msg_det); - if (pcie1->pme_msg_det) { - pcie1->pme_msg_det = 0xffffffff; - debug(" with errors. Clearing. Now 0x%08x", - pcie1->pme_msg_det); - } - debug("\n"); - } else { - printf("PCI-EXPRESS 1 disabled!\n"); - return; - } - - /* - * Set first_bus=0 only skipped B0:D0:F0 which is - * a reserved device in M1575, but make it easy for - * most of the scan process. - */ - hose->first_busno = 0x00; - hose->last_busno = 0xfe; - - pcie_setup_indirect(hose, (CFG_IMMR + 0x8000), (CFG_IMMR + 0x8004)); - - pci_hose_read_config_word(hose, - PCI_BDF(0, 0, 0), PCI_COMMAND, &temp16); - temp16 |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | - PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - pci_hose_write_config_word(hose, - PCI_BDF(0, 0, 0), PCI_COMMAND, temp16); - - pci_hose_write_config_word(hose, PCI_BDF(0, 0, 0), PCI_STATUS, 0xffff); - pci_hose_write_config_byte(hose, - PCI_BDF(0, 0, 0), PCI_LATENCY_TIMER, 0x80); - - pci_hose_read_config_dword(hose, PCI_BDF(0, 0, 0), PCI_PRIMARY_BUS, - &temp32); - temp32 = (temp32 & 0xff000000) | (0xff) | (0x0 << 8) | (0xfe << 16); - pci_hose_write_config_dword(hose, PCI_BDF(0, 0, 0), PCI_PRIMARY_BUS, - temp32); - - pcie1->powar1 = 0; - pcie1->powar2 = 0; - pcie1->piwar1 = 0; - pcie1->piwar1 = 0; - - pcie1->powbar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff; - pcie1->powar1 = 0x8004401c; /* 512M MEM space */ - pcie1->potar1 = (CFG_PCI1_MEM_BASE >> 12) & 0x000fffff; - pcie1->potear1 = 0x00000000; - - pcie1->powbar2 = (CFG_PCI1_IO_BASE >> 12) & 0x000fffff; - pcie1->powar2 = 0x80088017; /* 16M IO space */ - pcie1->potar2 = 0x00000000; - pcie1->potear2 = 0x00000000; - - pcie1->pitar1 = 0x00000000; - pcie1->piwbar1 = 0x00000000; - /* Enable, Prefetch, Local Mem, * Snoop R/W, 2G */ - pcie1->piwar1 = 0xa0f5501e; - - pci_set_region(hose->regions + 0, - CFG_PCI_MEMORY_BUS, - CFG_PCI_MEMORY_PHYS, - CFG_PCI_MEMORY_SIZE, - PCI_REGION_MEM | PCI_REGION_MEMORY); - - pci_set_region(hose->regions + 1, - CFG_PCI1_MEM_BASE, - CFG_PCI1_MEM_PHYS, - CFG_PCI1_MEM_SIZE, - PCI_REGION_MEM); - - pci_set_region(hose->regions + 2, - CFG_PCI1_IO_BASE, - CFG_PCI1_IO_PHYS, - CFG_PCI1_IO_SIZE, - PCI_REGION_IO); - - hose->region_count = 3; - - pci_register_hose(hose); - - hose->last_busno = pci_hose_scan(hose); - debug("pcie_mpc86xx_init: last_busno %x\n", hose->last_busno); - debug("pcie_mpc86xx init: current_busno %x\n ", hose->current_busno); - - printf("....PCIE1 scan & enumeration done\n"); -} -#endif /* CONFIG_PCI */ diff --git a/cpu/mpc86xx/pcie_indirect.c b/cpu/mpc86xx/pcie_indirect.c deleted file mode 100644 index b00ad76..0000000 --- a/cpu/mpc86xx/pcie_indirect.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Support for indirect PCI bridges. - * - * Copyright (c) Freescale Semiconductor, Inc. - * 2006. All rights reserved. - * - * Jason Jin <Jason.jin@freescale.com> - * - * 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. - * - * partly derived from - * arch/powerpc/platforms/86xx/mpc86xx_pcie.c - */ - -#include <common.h> - -#ifdef CONFIG_PCI - -#include <asm/processor.h> -#include <asm/io.h> -#include <pci.h> - -#define PCI_CFG_OUT out_be32 -#define PEX_FIX out_be32(hose->cfg_addr+0x4, 0x0400ffff) - -static int -indirect_read_config_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - int len, - u32 *val) -{ - int bus = PCI_BUS(dev); - - volatile unsigned char *cfg_data; - u32 temp; - - PEX_FIX; - if (bus == 0xff) { - PCI_CFG_OUT(hose->cfg_addr, - dev | (offset & 0xfc) | 0x80000001); - } else { - PCI_CFG_OUT(hose->cfg_addr, - dev | (offset & 0xfc) | 0x80000000); - } - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ - cfg_data = hose->cfg_data; - PEX_FIX; - temp = in_le32((u32 *) cfg_data); - switch (len) { - case 1: - *val = (temp >> (((offset & 3)) * 8)) & 0xff; - break; - case 2: - *val = (temp >> (((offset & 3)) * 8)) & 0xffff; - break; - default: - *val = temp; - break; - } - - return 0; -} - -static int -indirect_write_config_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - int len, - u32 val) -{ - int bus = PCI_BUS(dev); - volatile unsigned char *cfg_data; - u32 temp; - - PEX_FIX; - if (bus == 0xff) { - PCI_CFG_OUT(hose->cfg_addr, - dev | (offset & 0xfc) | 0x80000001); - } else { - PCI_CFG_OUT(hose->cfg_addr, - dev | (offset & 0xfc) | 0x80000000); - } - - /* - * Note: the caller has already checked that offset is - * suitably aligned and that len is 1, 2 or 4. - */ - /* ERRATA PCI-Ex 12 - Configuration Address/Data Alignment */ - cfg_data = hose->cfg_data; - switch (len) { - case 1: - PEX_FIX; - temp = in_le32((u32 *) cfg_data); - temp = (temp & ~(0xff << ((offset & 3) * 8))) | - (val << ((offset & 3) * 8)); - PEX_FIX; - out_le32((u32 *) cfg_data, temp); - break; - case 2: - PEX_FIX; - temp = in_le32((u32 *) cfg_data); - temp = (temp & ~(0xffff << ((offset & 3) * 8))); - temp |= (val << ((offset & 3) * 8)); - PEX_FIX; - out_le32((u32 *) cfg_data, temp); - break; - default: - PEX_FIX; - out_le32((u32 *) cfg_data, val); - break; - } - PEX_FIX; - return 0; -} - -static int -indirect_read_config_byte_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - u8 *val) -{ - u32 val32; - indirect_read_config_pcie(hose, dev, offset, 1, &val32); - *val = (u8) val32; - return 0; -} - -static int -indirect_read_config_word_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - u16 *val) -{ - u32 val32; - indirect_read_config_pcie(hose, dev, offset, 2, &val32); - *val = (u16) val32; - return 0; -} - -static int -indirect_read_config_dword_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - u32 *val) -{ - return indirect_read_config_pcie(hose, dev, offset, 4, val); -} - -static int -indirect_write_config_byte_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - u8 val) -{ - return indirect_write_config_pcie(hose, dev, offset, 1, (u32) val); -} - -static int -indirect_write_config_word_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - unsigned short val) -{ - return indirect_write_config_pcie(hose, dev, offset, 2, (u32) val); -} - -static int -indirect_write_config_dword_pcie(struct pci_controller *hose, - pci_dev_t dev, - int offset, - u32 val) -{ - return indirect_write_config_pcie(hose, dev, offset, 4, val); -} - -void -pcie_setup_indirect(struct pci_controller *hose, u32 cfg_addr, u32 cfg_data) -{ - pci_set_ops(hose, - indirect_read_config_byte_pcie, - indirect_read_config_word_pcie, - indirect_read_config_dword_pcie, - indirect_write_config_byte_pcie, - indirect_write_config_word_pcie, - indirect_write_config_dword_pcie); - - hose->cfg_addr = (unsigned int *)cfg_addr; - hose->cfg_data = (unsigned char *)cfg_data; -} - -#endif /* CONFIG_PCI */ diff --git a/cpu/mpc86xx/start.S b/cpu/mpc86xx/start.S index 412745b..c83310a 100644 --- a/cpu/mpc86xx/start.S +++ b/cpu/mpc86xx/start.S @@ -1,5 +1,5 @@ /* - * Copyright 2004 Freescale Semiconductor. + * Copyright 2004, 2007 Freescale Semiconductor. * Srikanth Srinivasan <srikanth.srinivaan@freescale.com> * * See file CREDITS for list of people who contributed to this @@ -44,11 +44,9 @@ #define CONFIG_IDENT_STRING "" #endif -/* We don't want the MMU yet. -*/ -#undef MSR_KERNEL -/* Machine Check and Recoverable Interr. */ -#define MSR_KERNEL ( MSR_ME | MSR_RI ) +/* + * Need MSR_DR | MSR_IR enabled to access I/O (printf) in exceptions + */ /* * Set up GOT: Global Offset Table @@ -195,17 +193,21 @@ boot_warm: bl secondary_cpu_setup #endif +1: +#ifdef CFG_RAMBOOT /* disable everything */ -1: li r0, 0 + li r0, 0 mtspr HID0, r0 sync mtmsr 0 +#endif + bl invalidate_bats sync #ifdef CFG_L2 /* init the L2 cache */ - addis r3, r0, L2_INIT@h + lis r3, L2_INIT@h ori r3, r3, L2_INIT@l mtspr l2cr, r3 /* invalidate the L2 cache */ @@ -241,69 +243,9 @@ in_flash: bl setup_ccsrbar #endif - - /* -- MPC8641 Rev 1.0 MCM Errata fixups -- */ - - /* skip fixups if not Rev 1.0 */ - mfspr r4, SVR - rlwinm r4,r4,0,24,31 - cmpwi r4,0x10 - bne 1f - - lis r3,MCM_ABCR@ha - lwz r4,MCM_ABCR@l(r3) /* ABCR -> r4 */ - - /* set ABCR[A_STRM_CNT] = 0 */ - rlwinm r4,r4,0,0,29 - - /* set ABCR[ARB_POLICY] to 0x1 (round-robin) */ - addi r0,r0,1 - rlwimi r4,r0,12,18,19 - - stw r4,MCM_ABCR@l(r3) /* r4 -> ABCR */ - sync - - /* Set DBCR[ERD_DIS] */ - lis r3,MCM_DBCR@ha - lwz r4,MCM_DBCR@l(r3) - oris r4, r4, 0x4000 - stw r4,MCM_DBCR@l(r3) - sync -1: /* setup the law entries */ bl law_entry sync - - -#if (EMULATOR_RUN == 1) - /* On the emulator we want to adjust these ASAP */ - /* otherwise things are sloooow */ - /* Setup OR0 (LALE FIX)*/ - lis r3, CFG_CCSRBAR@h - ori r3, r3, 0x5004 - li r4, 0x0FF3 - stw r4, 0(r3) - sync - - /* Setup LCRR */ - lis r3, CFG_CCSRBAR@h - ori r3, r3, 0x50D4 - lis r4, 0x8000 - ori r4, r4, 0x0002 - stw r4, 0(r3) - sync -#endif -#if 1 - /* make sure timer enabled in guts register too */ - lis r3, CFG_CCSRBAR@h - oris r3,r3, 0xE - ori r3,r3,0x0070 - lwz r4, 0(r3) - lis r5,0xFFFC - ori r5,r5,0x5FFF - and r4,r4,r5 - stw r4,0(r3) -#endif /* * Cache must be enabled here for stack-in-cache trick. * This means we need to enable the BATS. @@ -346,8 +288,6 @@ in_flash: #ifdef RUN_DIAG - /* Sri: Code to run the diagnostic automatically */ - /* Load PX_AUX register address in r4 */ lis r4, 0xf810 ori r4, r4, 0x6 @@ -392,6 +332,7 @@ diag_done: .globl invalidate_bats invalidate_bats: + li r0, 0 /* invalidate BATs */ mtspr IBAT0U, r0 mtspr IBAT1U, r0 @@ -1040,6 +981,7 @@ trap_init: mfmsr r7 li r8,MSR_IP andc r7,r7,r8 + ori r7,r7,MSR_ME /* Enable Machine Check */ mtmsr r7 mtlr r4 /* restore link register */ @@ -1224,8 +1166,9 @@ secondary_cpu_setup: sync isync - /*SYNCBE|ABE in HID1*/ + /* MCP|SYNCBE|ABE in HID1 */ mfspr r4, HID1 + oris r4, r4, 0x8000 ori r4, r4, 0x0C00 mtspr HID1, r4 sync diff --git a/cpu/mpc86xx/traps.c b/cpu/mpc86xx/traps.c index 8ea14e5..c84bfbf 100644 --- a/cpu/mpc86xx/traps.c +++ b/cpu/mpc86xx/traps.c @@ -34,7 +34,7 @@ #include <command.h> #include <asm/processor.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif @@ -122,7 +122,7 @@ MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; #endif @@ -130,8 +130,11 @@ MachineCheckException(struct pt_regs *regs) printf("Machine check in kernel mode.\n"); printf("Caused by (from msr): "); printf("regs %p ", regs); - switch (regs->msr & 0x000F0000) { - case (0x80000000 >> 12): + switch ( regs->msr & 0x001F0000) { + case (0x80000000>>11): + printf("MSS error. MSSSR0: %08x\n", mfspr(SPRN_MSSSR0)); + break; + case (0x80000000>>12): printf("Machine check signal - probably due to mm fault\n" "with mmu off\n"); break; @@ -155,7 +158,7 @@ MachineCheckException(struct pt_regs *regs) void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; #endif @@ -170,7 +173,7 @@ ProgramCheckException(struct pt_regs *regs) unsigned char *p = regs ? (unsigned char *)(regs->nip) : NULL; int i, j; -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; #endif @@ -193,7 +196,7 @@ ProgramCheckException(struct pt_regs *regs) void SoftEmuException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; #endif @@ -205,10 +208,11 @@ SoftEmuException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler) (regs)) return; #endif + printf("UnknownException regs@%x\n", regs); printf("Bad trap at PC: %lx, SR: %lx, vector=%lx\n", regs->nip, regs->msr, regs->trap); _exception(0, regs); diff --git a/cpu/mpc8xx/bedbug_860.c b/cpu/mpc8xx/bedbug_860.c index e91a100..5d52366 100644 --- a/cpu/mpc8xx/bedbug_860.c +++ b/cpu/mpc8xx/bedbug_860.c @@ -10,7 +10,7 @@ #include <bedbug/ppc.h> #include <bedbug/type.h> -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) && defined(CONFIG_8xx) +#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_8xx) #define MAX_BREAK_POINTS 2 diff --git a/cpu/mpc8xx/fec.c b/cpu/mpc8xx/fec.c index 6d2755e..08a3715 100644 --- a/cpu/mpc8xx/fec.c +++ b/cpu/mpc8xx/fec.c @@ -31,7 +31,7 @@ DECLARE_GLOBAL_DATA_PTR; #undef ET_DEBUG -#if (CONFIG_COMMANDS & CFG_CMD_NET) && \ +#if defined(CONFIG_CMD_NET) && \ (defined(FEC_ENET) || defined(CONFIG_ETHER_ON_FEC1) || defined(CONFIG_ETHER_ON_FEC2)) /* compatibility test, if only FEC_ENET defined assume ETHER on FEC1 */ @@ -49,7 +49,7 @@ DECLARE_GLOBAL_DATA_PTR; #if defined(WANT_MII) #include <miiphy.h> -#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) #error "CONFIG_MII has to be defined!" #endif @@ -182,7 +182,7 @@ int fec_initialize(bd_t *bis) eth_register(dev); -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register(dev->name, fec8xx_miiphy_read, fec8xx_miiphy_write); #endif @@ -268,7 +268,7 @@ static int fec_recv (struct eth_device *dev) length -= 4; -#if (CONFIG_COMMANDS & CFG_CMD_CDP) +#if defined(CONFIG_CMD_CDP) if ((rx[0] & 1) != 0 && memcmp ((uchar *) rx, NetBcastAddr, 6) != 0 && memcmp ((uchar *) rx, NetCDPAddr, 6) != 0) @@ -608,7 +608,7 @@ static int fec_init (struct eth_device *dev, bd_t * bd) fecp->fec_addr_high = (ea[4] << 8) | (ea[5]); #undef ea -#if (CONFIG_COMMANDS & CFG_CMD_CDP) +#if defined(CONFIG_CMD_CDP) /* * Turn on multicast address hash table */ @@ -787,7 +787,7 @@ static void fec_halt(struct eth_device* dev) efis->initialized = 0; } -#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CFG_DISCOVER_PHY) || defined(CONFIG_MII) || defined(CONFIG_CMD_MII) /* Make MII read/write commands for the FEC. */ @@ -852,7 +852,7 @@ mii_send(uint mii_cmd) #endif return (mii_reply & 0xffff); /* data read from phy */ } -#endif /* CFG_DISCOVER_PHY || (CONFIG_COMMANDS & CFG_CMD_MII) */ +#endif #if defined(CFG_DISCOVER_PHY) static int mii_discover_phy(struct eth_device *dev) @@ -926,7 +926,7 @@ static int mii_discover_phy(struct eth_device *dev) } #endif /* CFG_DISCOVER_PHY */ -#if (defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) && !defined(CONFIG_BITBANGMII) +#if (defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) && !defined(CONFIG_BITBANGMII) /**************************************************************************** * mii_init -- Initialize the MII for MII command without ethernet @@ -1020,6 +1020,6 @@ int fec8xx_miiphy_write(char *devname, unsigned char addr, #endif return 0; } -#endif /* (CONFIG_COMMANDS & CFG_CMD_MII) && !defined(CONFIG_BITBANGMII)*/ +#endif -#endif /* CFG_CMD_NET, FEC_ENET */ +#endif diff --git a/cpu/mpc8xx/kgdb.S b/cpu/mpc8xx/kgdb.S index 11c3c69..812baa3 100644 --- a/cpu/mpc8xx/kgdb.S +++ b/cpu/mpc8xx/kgdb.S @@ -34,7 +34,7 @@ #include <asm/cache.h> #include <asm/mmu.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) /* * cache flushing routines for kgdb @@ -71,4 +71,4 @@ kgdb_flush_cache_range: SYNC blr -#endif /* CFG_CMD_KGDB */ +#endif diff --git a/cpu/mpc8xx/scc.c b/cpu/mpc8xx/scc.c index 6b9110f..744dcdd 100644 --- a/cpu/mpc8xx/scc.c +++ b/cpu/mpc8xx/scc.c @@ -38,7 +38,7 @@ #include <net.h> #include <command.h> -#if (CONFIG_COMMANDS & CFG_CMD_NET) && defined(SCC_ENET) +#if defined(CONFIG_CMD_NET) && defined(SCC_ENET) /* Ethernet Transmit and Receive Buffers */ #define DBUF_LENGTH 1520 @@ -567,4 +567,4 @@ void restart (void) (SCC_GSMRL_ENR | SCC_GSMRL_ENT); } #endif -#endif /* CFG_CMD_NET, SCC_ENET */ +#endif diff --git a/cpu/mpc8xx/serial.c b/cpu/mpc8xx/serial.c index ffc898c..68804cc 100644 --- a/cpu/mpc8xx/serial.c +++ b/cpu/mpc8xx/serial.c @@ -666,7 +666,7 @@ void enable_putc(void) } #endif -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) void kgdb_serial_init(void) @@ -723,6 +723,6 @@ kgdb_interruptible (int yes) { return; } -#endif /* CFG_CMD_KGDB */ +#endif #endif /* CONFIG_8xx_CONS_NONE */ diff --git a/cpu/mpc8xx/traps.c b/cpu/mpc8xx/traps.c index 67b75cc..e1ec889 100644 --- a/cpu/mpc8xx/traps.c +++ b/cpu/mpc8xx/traps.c @@ -36,11 +36,11 @@ #include <command.h> #include <asm/processor.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -126,7 +126,7 @@ MachineCheckException(struct pt_regs *regs) return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -159,7 +159,7 @@ MachineCheckException(struct pt_regs *regs) void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -171,7 +171,7 @@ AlignmentException(struct pt_regs *regs) void ProgramCheckException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -183,7 +183,7 @@ ProgramCheckException(struct pt_regs *regs) void SoftEmuException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -196,7 +196,7 @@ SoftEmuException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -210,7 +210,7 @@ DebugException(struct pt_regs *regs) { printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/nios/cpu.c b/cpu/nios/cpu.c index d2bb2c0..5519e82 100644 --- a/cpu/nios/cpu.c +++ b/cpu/nios/cpu.c @@ -34,7 +34,7 @@ int checkcpu (void) /* Get cpu version info */ val = rdctl (CTL_CPU_ID); - printf ("CPU: "); + puts ("CPU: "); printf ("%s", (val & 0x00008000) ? "Nios-16 " : "Nios-32 "); rev_major = (val>>12) & 0x07; rev_minor = (val>>4) & 0x0ff; diff --git a/cpu/nios/interrupts.c b/cpu/nios/interrupts.c index 48fc81e..75e491d 100644 --- a/cpu/nios/interrupts.c +++ b/cpu/nios/interrupts.c @@ -173,7 +173,7 @@ void irq_install_handler (int vec, interrupt_handler_t *handler, void *arg) } /*************************************************************************/ -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int vec; @@ -193,4 +193,4 @@ int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return (0); } -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/nios2/interrupts.c b/cpu/nios2/interrupts.c index 4685161..aeb5b65 100644 --- a/cpu/nios2/interrupts.c +++ b/cpu/nios2/interrupts.c @@ -204,7 +204,7 @@ int interrupt_init (void) /*************************************************************************/ -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { int i; @@ -228,4 +228,4 @@ int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return (0); } -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/ppc4xx/440spe_pcie.c b/cpu/ppc4xx/440spe_pcie.c index d6c4be5..bf68cc1 100644 --- a/cpu/ppc4xx/440spe_pcie.c +++ b/cpu/ppc4xx/440spe_pcie.c @@ -1,5 +1,5 @@ /* - * (C) Copyright 2006 + * (C) Copyright 2006 - 2007 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. * * Copyright (c) 2005 Cisco Systems. All rights reserved. @@ -40,6 +40,34 @@ enum { LNKW_X8 = 0x8 }; +static inline int pcie_in_8(const volatile unsigned char __iomem *addr) +{ + int ret; + + PCIE_IN(lbzx, ret, addr); + + return ret; +} + +static inline int pcie_in_le16(const volatile unsigned short __iomem *addr) +{ + int ret; + + PCIE_IN(lhbrx, ret, addr) + + return ret; +} + +static inline unsigned pcie_in_le32(const volatile unsigned __iomem *addr) +{ + unsigned ret; + + PCIE_IN(lwbrx, ret, addr); + + return ret; +} + + static int pcie_read_config(struct pci_controller *hose, unsigned int devfn, int offset, int len, u32 *val) { @@ -55,13 +83,13 @@ static int pcie_read_config(struct pci_controller *hose, unsigned int devfn, switch (len) { case 1: - *val = in_8(hose->cfg_data + offset); + *val = pcie_in_8(hose->cfg_data + offset); break; case 2: - *val = in_le16((u16 *)(hose->cfg_data + offset)); + *val = pcie_in_le16((u16 *)(hose->cfg_data + offset)); break; default: - *val = in_le32((u32 *)(hose->cfg_data + offset)); + *val = pcie_in_le32((u32*)(hose->cfg_data + offset)); break; } return 0; @@ -783,9 +811,14 @@ void ppc440spe_setup_pcie_rootpoint(struct pci_controller *hose, int port) /* * Set bus numbers on our root port */ - out_8((u8 *)mbase + PCI_PRIMARY_BUS, 0); - out_8((u8 *)mbase + PCI_SECONDARY_BUS, 1); - out_8((u8 *)mbase + PCI_SUBORDINATE_BUS, 1); + if (ppc440spe_revB()) { + out_8((u8 *)mbase + PCI_PRIMARY_BUS, 0); + out_8((u8 *)mbase + PCI_SECONDARY_BUS, 1); + out_8((u8 *)mbase + PCI_SUBORDINATE_BUS, 1); + } else { + out_8((u8 *)mbase + PCI_PRIMARY_BUS, 0); + out_8((u8 *)mbase + PCI_SECONDARY_BUS, 0); + } /* * Set up outbound translation to hose->mem_space from PLB diff --git a/cpu/ppc4xx/440spe_pcie.h b/cpu/ppc4xx/440spe_pcie.h index 2becc77..eb7cecf 100644 --- a/cpu/ppc4xx/440spe_pcie.h +++ b/cpu/ppc4xx/440spe_pcie.h @@ -145,8 +145,8 @@ #define PECFG_PIMEN 0x33c #define PECFG_PIM0LAL 0x340 #define PECFG_PIM0LAH 0x344 -#define PECFG_PIM1LAL 0x348 -#define PECFG_PIM1LAH 0x34c +#define PECFG_PIM1LAL 0x348 +#define PECFG_PIM1LAH 0x34c #define PECFG_PIM01SAL 0x350 #define PECFG_PIM01SAH 0x354 @@ -161,6 +161,21 @@ mtdcr(DCRN_SDR0_CFGADDR, offset); \ mtdcr(DCRN_SDR0_CFGDATA,data);}) +#define PCIE_IN(opcode, ret, addr) \ + __asm__ __volatile__( \ + "sync\n" \ + #opcode " %0,0,%1\n" \ + "1: twi 0,%0,0\n" \ + "isync\n" \ + "b 3f\n" \ + "2: li %0,-1\n" \ + "3:\n" \ + ".section __ex_table,\"a\"\n" \ + ".balign 4\n" \ + ".long 1b,2b\n" \ + ".previous\n" \ + : "=r" (ret) : "r" (addr), "m" (*addr)); + int ppc440spe_init_pcie(void); int ppc440spe_init_pcie_rootport(int port); void yucca_setup_pcie_fpga_rootpoint(int port); diff --git a/cpu/ppc4xx/44x_spd_ddr.c b/cpu/ppc4xx/44x_spd_ddr.c index 6d6fba1..4a4c6f2 100644 --- a/cpu/ppc4xx/44x_spd_ddr.c +++ b/cpu/ppc4xx/44x_spd_ddr.c @@ -269,9 +269,8 @@ struct bank_param { typedef struct bank_param BANKPARMS; #ifdef CFG_SIMULATE_SPD_EEPROM -extern unsigned char cfg_simulate_spd_eeprom[128]; +extern const unsigned char cfg_simulate_spd_eeprom[128]; #endif -void program_tlb(u32 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value); static unsigned char spd_read(uchar chip, uint addr); static void get_spd_info(unsigned long *dimm_populated, diff --git a/cpu/ppc4xx/44x_spd_ddr2.c b/cpu/ppc4xx/44x_spd_ddr2.c index 5fef27b..18b90ba 100644 --- a/cpu/ppc4xx/44x_spd_ddr2.c +++ b/cpu/ppc4xx/44x_spd_ddr2.c @@ -109,7 +109,7 @@ /* Defines for the Read Cycle Delay test */ #define NUMMEMTESTS 8 #define NUMMEMWORDS 8 -#define NUMLOOPS 256 /* memory test loops */ +#define NUMLOOPS 64 /* memory test loops */ #undef CONFIG_ECC_ERROR_RESET /* test-only: see description below, at check_ecc() */ @@ -138,6 +138,26 @@ void __spd_ddr_init_hang (void) } void spd_ddr_init_hang (void) __attribute__((weak, alias("__spd_ddr_init_hang"))); +/* + * To provide an interface for board specific config values in this common + * DDR setup code, we implement he "weak" default functions here. They return + * the default value back to the caller. + * + * Please see include/configs/yucca.h for an example fora board specific + * implementation. + */ +u32 __ddr_wrdtr(u32 default_val) +{ + return default_val; +} +u32 ddr_wrdtr(u32) __attribute__((weak, alias("__ddr_wrdtr"))); + +u32 __ddr_clktr(u32 default_val) +{ + return default_val; +} +u32 ddr_clktr(u32) __attribute__((weak, alias("__ddr_clktr"))); + /* Private Structure Definitions */ @@ -154,7 +174,6 @@ typedef enum ddr_cas_id { * Prototypes *-----------------------------------------------------------------------------*/ static unsigned long sdram_memsize(void); -void program_tlb(u32 phys_addr, u32 virt_addr, u32 size, u32 tlb_word2_i_value); static void get_spd_info(unsigned long *dimm_populated, unsigned char *iic0_dimm_addr, unsigned long num_dimm_banks); @@ -216,9 +235,7 @@ static void test(void); #else static void DQS_calibration_process(void); #endif -#if defined(DEBUG) static void ppc440sp_sdram_register_dump(void); -#endif int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); void dcbz_area(u32 start_address, u32 num_bytes); void dflush(void); @@ -469,17 +486,14 @@ long int initdram(int board_type) *-----------------------------------------------------------------*/ mfsdram(SDRAM_WRDTR, val); mtsdram(SDRAM_WRDTR, (val & ~(SDRAM_WRDTR_LLWP_MASK | SDRAM_WRDTR_WTR_MASK)) | - (SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV)); + ddr_wrdtr(SDRAM_WRDTR_LLWP_1_CYC | SDRAM_WRDTR_WTR_90_DEG_ADV)); /*------------------------------------------------------------------ * Set the SDRAM Clock Timing Register *-----------------------------------------------------------------*/ mfsdram(SDRAM_CLKTR, val); -#ifdef CFG_44x_DDR2_CKTR_180 - mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | SDRAM_CLKTR_CLKP_180_DEG_ADV); -#else - mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | SDRAM_CLKTR_CLKP_0_DEG); -#endif + mtsdram(SDRAM_CLKTR, (val & ~SDRAM_CLKTR_CLKP_MASK) | + ddr_clktr(SDRAM_CLKTR_CLKP_0_DEG)); /*------------------------------------------------------------------ * Program the BxCF registers. @@ -538,7 +552,12 @@ long int initdram(int board_type) dram_size = sdram_memsize(); /* and program tlb entries for this size (dynamic) */ - program_tlb(0, 0, dram_size, MY_TLB_WORD2_I_ENABLE); + + /* + * Program TLB entries with caches enabled, for best performace + * while auto-calibrating and ECC generation + */ + program_tlb(0, 0, dram_size, 0); /*------------------------------------------------------------------ * DQS calibration. @@ -549,12 +568,18 @@ long int initdram(int board_type) /*------------------------------------------------------------------ * If ecc is enabled, initialize the parity bits. *-----------------------------------------------------------------*/ - program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, MY_TLB_WORD2_I_ENABLE); + program_ecc(dimm_populated, iic0_dimm_addr, num_dimm_banks, 0); #endif -#ifdef DEBUG + /* + * Now after initialization (auto-calibration and ECC generation) + * remove the TLB entries with caches enabled and program again with + * desired cache functionality + */ + remove_tlb(0, dram_size); + program_tlb(0, 0, dram_size, MY_TLB_WORD2_I_ENABLE); + ppc440sp_sdram_register_dump(); -#endif return dram_size; } @@ -2703,6 +2728,7 @@ calibration_loop: printf("\nERROR: Cannot determine a common read delay for the " "DIMM(s) installed.\n"); debug("%s[%d] ERROR : \n", __FUNCTION__,__LINE__); + ppc440sp_sdram_register_dump(); spd_ddr_init_hang (); } @@ -3028,5 +3054,9 @@ static void ppc440sp_sdram_register_dump(void) dcr_data = mfdcr(SDRAM_R3BAS); printf(" MQ3_B0BAS = 0x%08X\n", dcr_data); } +#else +static void ppc440sp_sdram_register_dump(void) +{ +} #endif #endif /* CONFIG_SPD_EEPROM */ diff --git a/cpu/ppc4xx/4xx_enet.c b/cpu/ppc4xx/4xx_enet.c index 1200d02..cc8e734 100644 --- a/cpu/ppc4xx/4xx_enet.c +++ b/cpu/ppc4xx/4xx_enet.c @@ -94,9 +94,9 @@ * network support enabled. * Remark: CONFIG_405 describes Xilinx PPC405 FPGA without EMAC controller! */ -#if (CONFIG_COMMANDS & CFG_CMD_NET) && !defined(CONFIG_405) && !defined(CONFIG_IOP480) +#if defined(CONFIG_CMD_NET) && !defined(CONFIG_405) && !defined(CONFIG_IOP480) -#if !(defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)) +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) #error "CONFIG_MII has to be defined!" #endif @@ -1415,10 +1415,8 @@ static void enet_rcv (struct eth_device *dev, unsigned long malisr) if ((MAL_RX_CTRL_EMPTY & hw_p->rx[i].ctrl) || (loop_count >= NUM_RX_BUFF)) break; + loop_count++; - hw_p->rx_slot++; - if (NUM_RX_BUFF == hw_p->rx_slot) - hw_p->rx_slot = 0; handled++; data_len = (unsigned long) hw_p->rx[i].data_len; /* Get len */ if (data_len) { @@ -1468,6 +1466,10 @@ static void enet_rcv (struct eth_device *dev, unsigned long malisr) if (NUM_RX_BUFF == hw_p->rx_i_index) hw_p->rx_i_index = 0; + hw_p->rx_slot++; + if (NUM_RX_BUFF == hw_p->rx_slot) + hw_p->rx_slot = 0; + /* AS.HARNOIS * free receive buffer only when * buffer has been handled (eth_rx) @@ -1683,7 +1685,7 @@ int ppc_4xx_eth_initialize (bd_t * bis) #endif #if defined(CONFIG_NET_MULTI) -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register (dev->name, emac4xx_miiphy_read, emac4xx_miiphy_write); #endif @@ -1724,7 +1726,7 @@ int eth_rx(void) int emac4xx_miiphy_initialize (bd_t * bis) { -#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII) +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) miiphy_register ("ppc_4xx_eth0", emac4xx_miiphy_read, emac4xx_miiphy_write); #endif @@ -1733,4 +1735,4 @@ int emac4xx_miiphy_initialize (bd_t * bis) } #endif /* !defined(CONFIG_NET_MULTI) */ -#endif /* #if (CONFIG_COMMANDS & CFG_CMD_NET) */ +#endif diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile index 4068b53..af9da5b 100644 --- a/cpu/ppc4xx/Makefile +++ b/cpu/ppc4xx/Makefile @@ -27,12 +27,12 @@ LIB = $(obj)lib$(CPU).a START = start.o resetvec.o kgdb.o SOBJS = dcr.o -COBJS = 405gp_pci.o 4xx_enet.o \ +COBJS = 405gp_pci.o 440spe_pcie.o 4xx_enet.o \ bedbug_405.o commproc.o \ cpu.o cpu_init.o gpio.o i2c.o interrupts.o \ miiphy.o ndfc.o sdram.o serial.o \ 40x_spd_sdram.o 44x_spd_ddr.o 44x_spd_ddr2.o speed.o \ - tlb.o traps.o usb_ohci.o usbdev.o \ + tlb.o traps.o usb_ohci.o usb.o usbdev.o \ 440spe_pcie.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) diff --git a/cpu/ppc4xx/bedbug_405.c b/cpu/ppc4xx/bedbug_405.c index a3c2119..5ef5607 100644 --- a/cpu/ppc4xx/bedbug_405.c +++ b/cpu/ppc4xx/bedbug_405.c @@ -10,7 +10,7 @@ #include <bedbug/regs.h> #include <bedbug/ppc.h> -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) && defined(CONFIG_4xx) +#if defined(CONFIG_CMD_BEDBUG) && defined(CONFIG_4xx) #define MAX_BREAK_POINTS 4 diff --git a/cpu/ppc4xx/dcr.S b/cpu/ppc4xx/dcr.S index 7102364..93465a3 100644 --- a/cpu/ppc4xx/dcr.S +++ b/cpu/ppc4xx/dcr.S @@ -22,7 +22,7 @@ */ #include <config.h> -#if defined(CONFIG_4xx) && defined(CFG_CMD_SETGETDCR) +#if defined(CONFIG_4xx) && defined(CONFIG_CMD_SETGETDCR) #include <ppc4xx.h> @@ -195,4 +195,4 @@ set_dcr: blr /* Return to calling function */ .Lfe4: .size set_dcr,.Lfe4-set_dcr /* end set_dcr() */ -#endif /* CONFIG_4xx & CFG_CMD_SETGETDCR */ +#endif diff --git a/cpu/ppc4xx/gpio.c b/cpu/ppc4xx/gpio.c index 5235203..50f2fdf 100644 --- a/cpu/ppc4xx/gpio.c +++ b/cpu/ppc4xx/gpio.c @@ -186,6 +186,7 @@ void gpio_set_chip_configuration(void) out32(GPIO0_TCR, reg); } +#ifdef GPIO1 if (gpio_core == GPIO1) { /* * Setup output value @@ -193,16 +194,17 @@ void gpio_set_chip_configuration(void) * 0 -> low level * else -> don't touch */ - reg = in32(GPIO0_OR); + reg = in32(GPIO1_OR); if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_1) reg |= (0x80000000 >> (i)); else if (gpio_tab[gpio_core][i].out_val == GPIO_OUT_0) reg &= ~(0x80000000 >> (i)); - out32(GPIO0_OR, reg); + out32(GPIO1_OR, reg); reg = in32(GPIO1_TCR) | (0x80000000 >> (i)); out32(GPIO1_TCR, reg); } +#endif /* GPIO1 */ reg = in32(GPIO_OS(core_add+offs)) & ~(GPIO_MASK >> (j*2)); diff --git a/cpu/ppc4xx/interrupts.c b/cpu/ppc4xx/interrupts.c index c5a9f02..ca565cc 100644 --- a/cpu/ppc4xx/interrupts.c +++ b/cpu/ppc4xx/interrupts.c @@ -628,7 +628,7 @@ void timer_interrupt_cpu (struct pt_regs *regs) /****************************************************************************/ -#if (CONFIG_COMMANDS & CFG_CMD_IRQ) +#if defined(CONFIG_CMD_IRQ) /******************************************************************************* * @@ -698,4 +698,4 @@ do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) return 0; } -#endif /* CONFIG_COMMANDS & CFG_CMD_IRQ */ +#endif diff --git a/cpu/ppc4xx/kgdb.S b/cpu/ppc4xx/kgdb.S index be28340..8c4bbf2 100644 --- a/cpu/ppc4xx/kgdb.S +++ b/cpu/ppc4xx/kgdb.S @@ -34,7 +34,7 @@ #include <asm/cache.h> #include <asm/mmu.h> -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) /* * cache flushing routines for kgdb */ @@ -75,4 +75,4 @@ kgdb_flush_cache_range: SYNC blr -#endif /* CFG_CMD_KGDB */ +#endif diff --git a/cpu/ppc4xx/ndfc.c b/cpu/ppc4xx/ndfc.c index f63fc79..3984577 100644 --- a/cpu/ppc4xx/ndfc.c +++ b/cpu/ppc4xx/ndfc.c @@ -31,7 +31,7 @@ #include <common.h> -#if (CONFIG_COMMANDS & CFG_CMD_NAND) && !defined(CFG_NAND_LEGACY) && \ +#if defined(CONFIG_CMD_NAND) && !defined(CFG_NAND_LEGACY) && \ (defined(CONFIG_440EP) || defined(CONFIG_440GR) || \ defined(CONFIG_440EPX) || defined(CONFIG_440GRX) || \ defined(CONFIG_405EZ)) diff --git a/cpu/ppc4xx/sdram.c b/cpu/ppc4xx/sdram.c index d520cd3..2724d91 100644 --- a/cpu/ppc4xx/sdram.c +++ b/cpu/ppc4xx/sdram.c @@ -187,14 +187,14 @@ void sdram_init(void) /* * Disable memory controller. */ - mtsdram0(mem_mcopt1, 0x00000000); + mtsdram(mem_mcopt1, 0x00000000); /* * Set MB0CF for bank 0. */ - mtsdram0(mem_mb0cf, mb0cf[i].reg); - mtsdram0(mem_sdtr1, sdtr1); - mtsdram0(mem_rtr, compute_rtr(speed, mb0cf[i].rows, 64)); + mtsdram(mem_mb0cf, mb0cf[i].reg); + mtsdram(mem_sdtr1, sdtr1); + mtsdram(mem_rtr, compute_rtr(speed, mb0cf[i].rows, 64)); udelay(200); @@ -203,14 +203,34 @@ void sdram_init(void) * Set DC_EN to '1' and BRD_PRF to '01' for 16 byte PLB Burst * read/prefetch. */ - mtsdram0(mem_mcopt1, 0x80800000); + mtsdram(mem_mcopt1, 0x80800000); udelay(10000); if (get_ram_size(0, mb0cf[i].size) == mb0cf[i].size) { /* - * OK, size detected -> all done + * OK, size detected. Enable second bank if + * defined (assumes same type as bank 0) */ +#ifdef CONFIG_SDRAM_BANK1 + u32 b1cr = mb0cf[i].size | mb0cf[i].reg; + + mtsdram(mem_mcopt1, 0x00000000); + mtsdram(mem_mb1cf, b1cr); /* SDRAM0_B1CR */ + mtsdram(mem_mcopt1, 0x80800000); + udelay(10000); + + /* + * Check if 2nd bank is really available. + * If the size not equal to the size of the first + * bank, then disable the 2nd bank completely. + */ + if (get_ram_size((long *)mb0cf[i].size, mb0cf[i].size) != + mb0cf[i].size) { + mtsdram(mem_mb1cf, 0); + mtsdram(mem_mcopt1, 0); + } +#endif return; } } diff --git a/cpu/ppc4xx/sdram.h b/cpu/ppc4xx/sdram.h index 62b5442..4fb9b1a 100644 --- a/cpu/ppc4xx/sdram.h +++ b/cpu/ppc4xx/sdram.h @@ -29,8 +29,6 @@ #include <config.h> -#define mtsdram0(reg, data) mtdcr(memcfga,reg);mtdcr(memcfgd,data) - #define ONE_BILLION 1000000000 struct sdram_conf_s { diff --git a/cpu/ppc4xx/serial.c b/cpu/ppc4xx/serial.c index e62dd9d..60712b1 100644 --- a/cpu/ppc4xx/serial.c +++ b/cpu/ppc4xx/serial.c @@ -448,12 +448,17 @@ static void serial_divs (int baudrate, unsigned long *pudiv, unsigned long i; unsigned long est; /* current estimate */ unsigned long plloutb; + unsigned long cpr_pllc; u32 reg; + /* check the pll feedback source */ + mfcpr(cprpllc, cpr_pllc); + get_sys_info(&sysinfo); - plloutb = ((CONFIG_SYS_CLK_FREQ * sysinfo.pllFwdDiv * sysinfo.pllFbkDiv) - / sysinfo.pllFwdDivB); + plloutb = ((CONFIG_SYS_CLK_FREQ * ((cpr_pllc & PLLC_SRC_MASK) ? + sysinfo.pllFwdDivB : sysinfo.pllFwdDiv) * sysinfo.pllFbkDiv) / + sysinfo.pllFwdDivB); udiv = 256; /* Assume lowest possible serial clk */ div = plloutb / (16 * baudrate); /* total divisor */ umin = (plloutb / get_OPB_freq()) << 1; /* 2 x OPB divisor */ @@ -843,7 +848,7 @@ int serial_buffered_tstc (void) #endif /* CONFIG_SERIAL_SOFTWARE_FIFO */ -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) /* AS HARNOIS : according to CONFIG_KGDB_SER_INDEX kgdb uses serial port number 0 or number 1 @@ -949,7 +954,7 @@ void kgdb_interruptible (int yes) return; } #endif /* (CONFIG_KGDB_SER_INDEX & 2) */ -#endif /* CFG_CMD_KGDB */ +#endif #if defined(CONFIG_SERIAL_MULTI) diff --git a/cpu/ppc4xx/speed.c b/cpu/ppc4xx/speed.c index 028b11a..da5330a 100644 --- a/cpu/ppc4xx/speed.c +++ b/cpu/ppc4xx/speed.c @@ -771,6 +771,7 @@ ulong get_PCI_freq (void) void get_sys_info (PPC405_SYS_INFO * sysInfo) { unsigned long cpr_plld; + unsigned long cpr_pllc; unsigned long cpr_primad; unsigned long sysClkPeriodPs = ONE_BILLION / (CONFIG_SYS_CLK_FREQ/1000); unsigned long primad_cpudv; @@ -780,6 +781,7 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo) * Read PLL Mode registers */ mfcpr(cprplld, cpr_plld); + mfcpr(cprpllc, cpr_pllc); /* * Determine forward divider A @@ -787,20 +789,18 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo) sysInfo->pllFwdDiv = ((cpr_plld & PLLD_FWDVA_MASK) >> 16); /* - * Determine forward divider B (should be equal to A) + * Determine forward divider B */ sysInfo->pllFwdDivB = ((cpr_plld & PLLD_FWDVB_MASK) >> 8); - if (sysInfo->pllFwdDivB == 0) { + if (sysInfo->pllFwdDivB == 0) sysInfo->pllFwdDivB = 8; - } /* * Determine FBK_DIV. */ sysInfo->pllFbkDiv = ((cpr_plld & PLLD_FBDV_MASK) >> 24); - if (sysInfo->pllFbkDiv == 0) { + if (sysInfo->pllFbkDiv == 0) sysInfo->pllFbkDiv = 256; - } /* * Read CPR_PRIMAD register @@ -810,30 +810,30 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo) * Determine PLB_DIV. */ sysInfo->pllPlbDiv = ((cpr_primad & PRIMAD_PLBDV_MASK) >> 16); - if (sysInfo->pllPlbDiv == 0) { + if (sysInfo->pllPlbDiv == 0) sysInfo->pllPlbDiv = 16; - } /* * Determine EXTBUS_DIV. */ sysInfo->pllExtBusDiv = (cpr_primad & PRIMAD_EBCDV_MASK); - if (sysInfo->pllExtBusDiv == 0) { + if (sysInfo->pllExtBusDiv == 0) sysInfo->pllExtBusDiv = 16; - } /* * Determine OPB_DIV. */ sysInfo->pllOpbDiv = ((cpr_primad & PRIMAD_OPBDV_MASK) >> 8); - if (sysInfo->pllOpbDiv == 0) { + if (sysInfo->pllOpbDiv == 0) sysInfo->pllOpbDiv = 16; - } /* * Determine the M factor */ - m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB; + if (cpr_pllc & PLLC_SRC_MASK) + m = sysInfo->pllFbkDiv * sysInfo->pllFwdDivB; + else + m = sysInfo->pllFbkDiv * sysInfo->pllFwdDiv; /* * Determine VCO clock frequency @@ -845,16 +845,17 @@ void get_sys_info (PPC405_SYS_INFO * sysInfo) * Determine CPU clock frequency */ primad_cpudv = ((cpr_primad & PRIMAD_CPUDV_MASK) >> 24); - if (primad_cpudv == 0) { + if (primad_cpudv == 0) primad_cpudv = 16; - } - sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / primad_cpudv; + sysInfo->freqProcessor = (CONFIG_SYS_CLK_FREQ * m) / + sysInfo->pllFwdDiv / primad_cpudv; /* * Determine PLB clock frequency */ - sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * sysInfo->pllFbkDiv) / sysInfo->pllPlbDiv; + sysInfo->freqPLB = (CONFIG_SYS_CLK_FREQ * m) / + sysInfo->pllFwdDiv / sysInfo->pllPlbDiv; } /******************************************** diff --git a/cpu/ppc4xx/start.S b/cpu/ppc4xx/start.S index 8ecaaea..9626b65 100644 --- a/cpu/ppc4xx/start.S +++ b/cpu/ppc4xx/start.S @@ -1870,28 +1870,6 @@ ppc405ep_init: mtdcr ebccfgd,r3 #endif -#ifndef CFG_CPC0_PCI - li r3,CPC0_PCI_HOST_CFG_EN -#ifdef CONFIG_BUBINGA - /* - !----------------------------------------------------------------------- - ! Check FPGA for PCI internal/external arbitration - ! If board is set to internal arbitration, update cpc0_pci - !----------------------------------------------------------------------- - */ - addis r5,r0,FPGA_REG1@h /* set offset for FPGA_REG1 */ - ori r5,r5,FPGA_REG1@l - lbz r5,0x0(r5) /* read to get PCI arb selection */ - andi. r6,r5,FPGA_REG1_PCI_INT_ARB /* using internal arbiter ?*/ - beq ..pci_cfg_set /* if not set, then bypass reg write*/ -#endif - ori r3,r3,CPC0_PCI_ARBIT_EN -#else /* CFG_CPC0_PCI */ - li r3,CFG_CPC0_PCI -#endif /* CFG_CPC0_PCI */ -..pci_cfg_set: - mtdcr CPC0_PCI, r3 /* Enable internal arbiter*/ - /* !----------------------------------------------------------------------- ! Check to see if chip is in bypass mode. @@ -1947,11 +1925,50 @@ ppc405ep_init: ..no_pllset: #endif /* CONFIG_BUBINGA */ +#ifdef CONFIG_TAIHU + mfdcr r4, CPC0_BOOT + andi. r5, r4, CPC0_BOOT_SEP@l + bne strap_1 /* serial eeprom present */ + addis r5,0,CPLD_REG0_ADDR@h + ori r5,r5,CPLD_REG0_ADDR@l + andi. r5, r5, 0x10 + bne _pci_66mhz +#endif /* CONFIG_TAIHU */ + +#if defined(CONFIG_ZEUS) + mfdcr r4, CPC0_BOOT + andi. r5, r4, CPC0_BOOT_SEP@l + bne strap_1 /* serial eeprom present */ + lis r3,0x0000 + addi r3,r3,0x3030 + lis r4,0x8042 + addi r4,r4,0x223e + b 1f +strap_1: + mfdcr r3, CPC0_PLLMR0 + mfdcr r4, CPC0_PLLMR1 + b 1f +#endif + addis r3,0,PLLMR0_DEFAULT@h /* PLLMR0 default value */ ori r3,r3,PLLMR0_DEFAULT@l /* */ addis r4,0,PLLMR1_DEFAULT@h /* PLLMR1 default value */ ori r4,r4,PLLMR1_DEFAULT@l /* */ +#ifdef CONFIG_TAIHU + b 1f +_pci_66mhz: + addis r3,0,PLLMR0_DEFAULT_PCI66@h + ori r3,r3,PLLMR0_DEFAULT_PCI66@l + addis r4,0,PLLMR1_DEFAULT_PCI66@h + ori r4,r4,PLLMR1_DEFAULT_PCI66@l + b 1f +strap_1: + mfdcr r3, CPC0_PLLMR0 + mfdcr r4, CPC0_PLLMR1 +#endif /* CONFIG_TAIHU */ + +1: b pll_write /* Write the CPC0_PLLMR with new value */ pll_done: diff --git a/cpu/ppc4xx/tlb.c b/cpu/ppc4xx/tlb.c index 049a785..098694c 100644 --- a/cpu/ppc4xx/tlb.c +++ b/cpu/ppc4xx/tlb.c @@ -25,7 +25,6 @@ #if defined(CONFIG_440) -#include <ppc4xx.h> #include <ppc440.h> #include <asm/io.h> #include <asm/mmu.h> @@ -36,6 +35,67 @@ typedef struct region { unsigned long tlb_word2_i_value; } region_t; +void remove_tlb(u32 vaddr, u32 size) +{ + int i; + u32 tlb_word0_value; + u32 tlb_vaddr; + u32 tlb_size = 0; + + /* First, find the index of a TLB entry not being used */ + for (i=0; i<PPC4XX_TLB_SIZE; i++) { + tlb_word0_value = mftlb1(i); + tlb_vaddr = TLB_WORD0_EPN_DECODE(tlb_word0_value); + if (((tlb_word0_value & TLB_WORD0_V_MASK) == TLB_WORD0_V_ENABLE) && + (tlb_vaddr >= vaddr)) { + /* + * TLB is enabled and start address is lower or equal + * than the area we are looking for. Now we only have + * to check the size/end address for a match. + */ + switch (tlb_word0_value & TLB_WORD0_SIZE_MASK) { + case TLB_WORD0_SIZE_1KB: + tlb_size = 1 << 10; + break; + case TLB_WORD0_SIZE_4KB: + tlb_size = 4 << 10; + break; + case TLB_WORD0_SIZE_16KB: + tlb_size = 16 << 10; + break; + case TLB_WORD0_SIZE_64KB: + tlb_size = 64 << 10; + break; + case TLB_WORD0_SIZE_256KB: + tlb_size = 256 << 10; + break; + case TLB_WORD0_SIZE_1MB: + tlb_size = 1 << 20; + break; + case TLB_WORD0_SIZE_16MB: + tlb_size = 16 << 20; + break; + case TLB_WORD0_SIZE_256MB: + tlb_size = 256 << 20; + break; + } + + /* + * Now check the end-address if it's in the range + */ + if ((tlb_vaddr + tlb_size - 1) <= (vaddr + size - 1)) + /* + * Found a TLB in the range. + * Disable it by writing 0 to tlb0 word. + */ + mttlb1(i, 0); + } + } + + /* Execute an ISYNC instruction so that the new TLB entry takes effect */ + asm("isync"); +} + static int add_tlb_entry(unsigned long phys_addr, unsigned long virt_addr, unsigned long tlb_word0_size_value, diff --git a/cpu/ppc4xx/traps.c b/cpu/ppc4xx/traps.c index eb9420e..f5365cb 100755..100644 --- a/cpu/ppc4xx/traps.c +++ b/cpu/ppc4xx/traps.c @@ -38,7 +38,7 @@ DECLARE_GLOBAL_DATA_PTR; -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) int (*debugger_exception_handler)(struct pt_regs *) = 0; #endif @@ -78,7 +78,7 @@ static __inline__ unsigned long get_esr(void) #define ESR_DIZ 0x00400000 #define ESR_U0F 0x00008000 -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) extern void do_bedbug_breakpoint(struct pt_regs *); #endif @@ -147,18 +147,25 @@ MachineCheckException(struct pt_regs *regs) unsigned long fixup, val; #if defined(CONFIG_440EPX) || defined(CONFIG_440GRX) u32 value2; + int corr_ecc = 0; + int uncorr_ecc = 0; #endif - /* Probing PCI using config cycles cause this exception - * when a device is not present. Catch it and return to - * the PCI exception handler. + /* Probing PCI(E) using config cycles may cause this exception + * when a device is not present. To gracefully recover in such + * scenarios config read/write routines need to be instrumented in + * order to return via fixup handler. For examples refer to + * pcie_in_8(), pcie_in_le16() and pcie_in_le32() */ if ((fixup = search_exception_table(regs->nip)) != 0) { regs->nip = fixup; + val = mfspr(MCSR); + /* Clear MCSR */ + mtspr(SPRN_MCSR, val); return; } -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -214,14 +221,22 @@ MachineCheckException(struct pt_regs *regs) printf("DDR0: At least one interrupt active\n"); if (val & 0x40) printf("DDR0: DRAM initialization complete.\n"); - if (val & 0x20) + if (val & 0x20) { printf("DDR0: Multiple uncorrectable ECC events.\n"); - if (val & 0x10) + uncorr_ecc = 1; + } + if (val & 0x10) { printf("DDR0: Single uncorrectable ECC event.\n"); - if (val & 0x08) + uncorr_ecc = 1; + } + if (val & 0x08) { printf("DDR0: Multiple correctable ECC events.\n"); - if (val & 0x04) + corr_ecc = 1; + } + if (val & 0x04) { printf("DDR0: Single correctable ECC event.\n"); + corr_ecc = 1; + } if (val & 0x02) printf("Multiple accesses outside the defined" " physical memory space detected\n"); @@ -252,11 +267,11 @@ MachineCheckException(struct pt_regs *regs) printf("DDR0: No DDR0 error know 0x%x %p\n", val, value2); } mfsdram(DDR0_23, val); - if ( (val >> 16) & 0xff) + if (((val >> 16) & 0xff) && corr_ecc) printf("DDR0: Syndrome for correctable ECC event 0x%x\n", (val >> 16) & 0xff); mfsdram(DDR0_23, val); - if ( (val >> 8) & 0xff) + if (((val >> 8) & 0xff) && uncorr_ecc) printf("DDR0: Syndrome for uncorrectable ECC event 0x%x\n", (val >> 8) & 0xff); mfsdram(DDR0_33, val); @@ -264,28 +279,28 @@ MachineCheckException(struct pt_regs *regs) printf("DDR0: Address of command that caused an " "Out-of-Range interrupt %p\n", val); mfsdram(DDR0_34, val); - if (val) + if (val && uncorr_ecc) printf("DDR0: Address of uncorrectable ECC event %p\n", val); mfsdram(DDR0_35, val); - if (val) + if (val && uncorr_ecc) printf("DDR0: Address of uncorrectable ECC event %p\n", val); mfsdram(DDR0_36, val); - if (val) + if (val && uncorr_ecc) printf("DDR0: Data of uncorrectable ECC event 0x%08x\n", val); mfsdram(DDR0_37, val); - if (val) + if (val && uncorr_ecc) printf("DDR0: Data of uncorrectable ECC event 0x%08x\n", val); mfsdram(DDR0_38, val); - if (val) + if (val && corr_ecc) printf("DDR0: Address of correctable ECC event %p\n", val); mfsdram(DDR0_39, val); - if (val) + if (val && corr_ecc) printf("DDR0: Address of correctable ECC event %p\n", val); mfsdram(DDR0_40, val); - if (val) + if (val && corr_ecc) printf("DDR0: Data of correctable ECC event 0x%08x\n", val); mfsdram(DDR0_41, val); - if (val) + if (val && corr_ecc) printf("DDR0: Data of correctable ECC event 0x%08x\n", val); #endif /* CONFIG_440EPX */ #endif /* CONFIG_440 */ @@ -297,7 +312,7 @@ MachineCheckException(struct pt_regs *regs) void AlignmentException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -312,7 +327,7 @@ ProgramCheckException(struct pt_regs *regs) { long esr_val; -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -349,7 +364,7 @@ DecrementerPITException(struct pt_regs *regs) void UnknownException(struct pt_regs *regs) { -#if (CONFIG_COMMANDS & CFG_CMD_KGDB) +#if defined(CONFIG_CMD_KGDB) if (debugger_exception_handler && (*debugger_exception_handler)(regs)) return; #endif @@ -364,7 +379,7 @@ DebugException(struct pt_regs *regs) { printf("Debugger trap at @ %lx\n", regs->nip ); show_regs(regs); -#if (CONFIG_COMMANDS & CFG_CMD_BEDBUG) +#if defined(CONFIG_CMD_BEDBUG) do_bedbug_breakpoint( regs ); #endif } diff --git a/cpu/ppc4xx/usb.c b/cpu/ppc4xx/usb.c new file mode 100644 index 0000000..272ed8c --- /dev/null +++ b/cpu/ppc4xx/usb.c @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2007 + * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) + +#include "usbdev.h" + +int usb_cpu_init(void) +{ + +#if defined(CONFIG_440EP) || defined(CONFIG_440EPX) + usb_dev_init(); +#endif + + return 0; +} + +int usb_cpu_stop(void) +{ + return 0; +} + +int usb_cpu_init_fail(void) +{ + return 0; +} + +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ diff --git a/cpu/ppc4xx/usbdev.c b/cpu/ppc4xx/usbdev.c index 6140d2a..5924a6c 100644 --- a/cpu/ppc4xx/usbdev.c +++ b/cpu/ppc4xx/usbdev.c @@ -3,7 +3,7 @@ #include <common.h> #include <asm/processor.h> -#if (defined(CONFIG_440EP) || defined(CONFIG_440EPX)) && (CONFIG_COMMANDS & CFG_CMD_USB) +#if (defined(CONFIG_440EP) || defined(CONFIG_440EPX)) && defined(CONFIG_CMD_USB) #include <usb.h> #include "usbdev.h" diff --git a/cpu/pxa/Makefile b/cpu/pxa/Makefile index cded7ff..8b4367e 100644 --- a/cpu/pxa/Makefile +++ b/cpu/pxa/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(CPU).a START = start.o -COBJS = serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o +COBJS = serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o usb.o SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c new file mode 100644 index 0000000..65f457f --- /dev/null +++ b/cpu/pxa/usb.c @@ -0,0 +1,79 @@ +/* + * (C) Copyright 2006 + * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> + +#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT) +# if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X) + +#include <asm/arch/pxa-regs.h> + +int usb_cpu_init() +{ +#if defined(CONFIG_CPU_MONAHANS) + /* Enable USB host clock. */ + CKENA |= (CKENA_2_USBHOST | CKENA_20_UDC); + udelay(100); +#endif +#if defined(CONFIG_PXA27X) + /* Enable USB host clock. */ + CKEN |= CKEN10_USBHOST; +#endif + +#if defined(CONFIG_CPU_MONAHANS) + /* Configure Port 2 for Host (USB Client Registers) */ + UP2OCR = 0x3000c; +#endif + + UHCHR |= UHCHR_FHR; + wait_ms(11); + UHCHR &= ~UHCHR_FHR; + + UHCHR |= UHCHR_FSBIR; + while (UHCHR & UHCHR_FSBIR) + udelay(1); + +#if defined(CONFIG_CPU_MONAHANS) + UHCHR &= ~UHCHR_SSEP0; +#endif +#if defined(CONFIG_PXA27X) + UHCHR &= ~UHCHR_SSEP2; +#endif + UHCHR &= ~UHCHR_SSEP1; + UHCHR &= ~UHCHR_SSE; + + return 0; +} + +int usb_cpu_stop() +{ + return 0; +} + +int usb_cpu_init_fail() +{ + return 0; +} + +# endif /* defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X) */ +#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */ |