diff options
Diffstat (limited to 'arch/powerpc/cpu/mpc8220')
22 files changed, 5848 insertions, 0 deletions
| diff --git a/arch/powerpc/cpu/mpc8220/Makefile b/arch/powerpc/cpu/mpc8220/Makefile new file mode 100644 index 000000000..b4fad286d --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/Makefile @@ -0,0 +1,50 @@ +# +# (C) Copyright 2003-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB	= $(obj)lib$(CPU).a + +START	= start.o +SOBJS	= io.o fec_dma_tasks.o +COBJS	= cpu.o cpu_init.o dramSetup.o fec.o i2c.o \ +	  interrupts.o loadtask.o speed.o \ +	  traps.o uart.o pci.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/arch/powerpc/cpu/mpc8220/config.mk b/arch/powerpc/cpu/mpc8220/config.mk new file mode 100644 index 000000000..e70688393 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/config.mk @@ -0,0 +1,30 @@ +# +# (C) Copyright 2003 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +PLATFORM_RELFLAGS += -fPIC -meabi + +PLATFORM_CPPFLAGS += -DCONFIG_MPC8220 -ffixed-r2 \ +		     -mstring -mcpu=603e -mmultiple + +# Use default linker script.  Board port can override in board/*/config.mk +LDSCRIPT := $(SRCTREE)/arch/powerpc/cpu/mpc8220/u-boot.lds diff --git a/arch/powerpc/cpu/mpc8220/cpu.c b/arch/powerpc/cpu/mpc8220/cpu.c new file mode 100644 index 000000000..563cfe053 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/cpu.c @@ -0,0 +1,104 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * CPU specific code for the MPC8220 CPUs + */ + +#include <common.h> +#include <watchdog.h> +#include <command.h> +#include <mpc8220.h> +#include <netdev.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +int checkcpu (void) +{ +	ulong clock = gd->cpu_clk; +	char buf[32]; + +	puts ("CPU:   "); + +	printf (CPU_ID_STR); + +	printf (" (JTAG ID %08lx)", *(vu_long *) (CONFIG_SYS_MBAR + 0x50)); + +	printf (" at %s MHz\n", strmhz (buf, clock)); + +	return 0; +} + +/* ------------------------------------------------------------------------- */ + +int do_reset (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) +{ +	volatile gptmr8220_t *gptmr = (volatile gptmr8220_t *) MMAP_GPTMR; +	ulong msr; + +	/* Interrupts and MMU off */ +	__asm__ __volatile__ ("mfmsr    %0":"=r" (msr):); + +	msr &= ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR); +	__asm__ __volatile__ ("mtmsr    %0"::"r" (msr)); + +	/* Charge the watchdog timer */ +	gptmr->Prescl = 10; +	gptmr->Count = 1; + +	gptmr->Mode = GPT_TMS_SGPIO; + +	gptmr->Control = GPT_CTRL_WDEN | GPT_CTRL_CE; + +	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); +} + +/* ------------------------------------------------------------------------- */ + +/* + * Initializes on-chip ethernet controllers. + * to override, implement board_eth_init() + */ +int cpu_eth_init(bd_t *bis) +{ +#if defined(CONFIG_MPC8220_FEC) +	mpc8220_fec_initialize(bis); +#endif +	return 0; +} diff --git a/arch/powerpc/cpu/mpc8220/cpu_init.c b/arch/powerpc/cpu/mpc8220/cpu_init.c new file mode 100644 index 000000000..8f52c7dd0 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/cpu_init.c @@ -0,0 +1,136 @@ +/* + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <common.h> +#include <mpc8220.h> + +DECLARE_GLOBAL_DATA_PTR; + +/* + * Breath some life into the CPU... + * + * Set up the memory map, + * initialize a bunch of registers. + */ +void cpu_init_f (void) +{ +	volatile flexbus8220_t *flexbus = (volatile flexbus8220_t *) MMAP_FB; +	volatile pcfg8220_t *portcfg = (volatile pcfg8220_t *) MMAP_PCFG; +	volatile xlbarb8220_t *xlbarb = (volatile xlbarb8220_t *) MMAP_XLBARB; + +	/* Pointer is writable since we allocated a register for it */ +	gd = (gd_t *) (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_GBL_DATA_OFFSET); + +	/* Clear initial global data */ +	memset ((void *) gd, 0, sizeof (gd_t)); + +	/* Clear all port configuration */ +	portcfg->pcfg0 = 0; +	portcfg->pcfg1 = 0; +	portcfg->pcfg2 = 0; +	portcfg->pcfg3 = 0; +	portcfg->pcfg2 = CONFIG_SYS_GP1_PORT2_CONFIG; +	portcfg->pcfg3 = CONFIG_SYS_PCI_PORT3_CONFIG | CONFIG_SYS_GP2_PORT3_CONFIG; + +	/* +	 * Flexbus Controller: configure chip selects and enable them +	 */ +#if defined (CONFIG_SYS_CS0_BASE) +	flexbus->csar0 = CONFIG_SYS_CS0_BASE; + +/* Sorcery-C can hang-up after CTRL reg initialization */ +#if defined (CONFIG_SYS_CS0_CTRL) +	flexbus->cscr0 = CONFIG_SYS_CS0_CTRL; +#endif +	flexbus->csmr0 = ((CONFIG_SYS_CS0_MASK - 1) & 0xffff0000) | 1; +	__asm__ volatile ("sync"); +#endif +#if defined (CONFIG_SYS_CS1_BASE) +	flexbus->csar1 = CONFIG_SYS_CS1_BASE; +	flexbus->cscr1 = CONFIG_SYS_CS1_CTRL; +	flexbus->csmr1 = ((CONFIG_SYS_CS1_MASK - 1) & 0xffff0000) | 1; +	__asm__ volatile ("sync"); +#endif +#if defined (CONFIG_SYS_CS2_BASE) +	flexbus->csar2 = CONFIG_SYS_CS2_BASE; +	flexbus->cscr2 = CONFIG_SYS_CS2_CTRL; +	flexbus->csmr2 = ((CONFIG_SYS_CS2_MASK - 1) & 0xffff0000) | 1; +	portcfg->pcfg3 |= CONFIG_SYS_CS2_PORT3_CONFIG; +	__asm__ volatile ("sync"); +#endif +#if defined (CONFIG_SYS_CS3_BASE) +	flexbus->csar3 = CONFIG_SYS_CS3_BASE; +	flexbus->cscr3 = CONFIG_SYS_CS3_CTRL; +	flexbus->csmr3 = ((CONFIG_SYS_CS3_MASK - 1) & 0xffff0000) | 1; +	portcfg->pcfg3 |= CONFIG_SYS_CS3_PORT3_CONFIG; +	__asm__ volatile ("sync"); +#endif +#if defined (CONFIG_SYS_CS4_BASE) +	flexbus->csar4 = CONFIG_SYS_CS4_BASE; +	flexbus->cscr4 = CONFIG_SYS_CS4_CTRL; +	flexbus->csmr4 = ((CONFIG_SYS_CS4_MASK - 1) & 0xffff0000) | 1; +	portcfg->pcfg3 |= CONFIG_SYS_CS4_PORT3_CONFIG; +	__asm__ volatile ("sync"); +#endif +#if defined (CONFIG_SYS_CS5_BASE) +	flexbus->csar5 = CONFIG_SYS_CS5_BASE; +	flexbus->cscr5 = CONFIG_SYS_CS5_CTRL; +	flexbus->csmr5 = ((CONFIG_SYS_CS5_MASK - 1) & 0xffff0000) | 1; +	portcfg->pcfg3 |= CONFIG_SYS_CS5_PORT3_CONFIG; +	__asm__ volatile ("sync"); +#endif + +	/* This section of the code cannot place in cpu_init_r(), +	   it will cause the system to hang */ +	/* enable timebase */ +	xlbarb->addrTenTimeOut = 0x1000; +	xlbarb->dataTenTimeOut = 0x1000; +	xlbarb->busActTimeOut = 0x2000; + +	xlbarb->config = 0x00002000; + +	/* Master Priority Enable */ +	xlbarb->mastPriority = 0; +	xlbarb->mastPriEn = 0xff; +} + +/* + * initialize higher level parts of CPU like time base and timers + */ +int cpu_init_r (void) +{ +	/* this may belongs to disable interrupt section */ +	/* mask all interrupts */ +	*(vu_long *) 0xf0000700 = 0xfffffc00; +	*(vu_long *) 0xf0000714 |= 0x0001ffff; +	*(vu_long *) 0xf0000710 &= ~0x00000f00; + +	/* route critical ints to normal ints */ +	*(vu_long *) 0xf0000710 |= 0x00000001; + +#if defined(CONFIG_CMD_NET) && defined(CONFIG_MPC8220_FEC) +	/* load FEC microcode */ +	loadtask (0, 2); +#endif +	return (0); +} diff --git a/arch/powerpc/cpu/mpc8220/dma.h b/arch/powerpc/cpu/mpc8220/dma.h new file mode 100644 index 000000000..d06ee6313 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/dma.h @@ -0,0 +1,68 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on code + * (C) Copyright Motorola, Inc., 2000 + * + * MPC8220 dma header file + */ + +#ifndef __MPC8220_DMA_H +#define __MPC8220_DMA_H + +#include <common.h> +#include <mpc8220.h> + +/* Task number assignment */ +#define FEC_RECV_TASK_NO            0 +#define FEC_XMIT_TASK_NO            1 + +/*--------------------------------------------------------------------- + * Stuff for Ethernet Tx/Rx tasks + *--------------------------------------------------------------------- + */ + +/* Layout of Ethernet controller Parameter SRAM area: + * ---------------------------------------------------------------- + * 0x00: TBD_BASE, base address of TX BD ring + * 0x04: TBD_NEXT, address of next TX BD to be processed + * 0x08: RBD_BASE, base address of RX BD ring + * 0x0C: RBD_NEXT, address of next RX BD to be processed + * --------------------------------------------------------------- + * ALL PARAMETERS ARE ALL LONGWORDS (FOUR BYTES EACH). + */ + +/* base address of SRAM area to store parameters used by Ethernet tasks */ +#define FEC_PARAM_BASE  (MMAP_SRAM + 0x5b00) + +/* base address of SRAM area for buffer descriptors */ +#define FEC_BD_BASE     (MMAP_SRAM + 0x5b20) + +/*--------------------------------------------------------------------- + * common shortcuts  used  by driver C code + *--------------------------------------------------------------------- + */ + +/* Disable SmartDMA task */ +#define DMA_TASK_DISABLE(tasknum)						\ +{										\ +	volatile ushort *tcr = (ushort *)(MMAP_DMA + 0x0000001c + 2 * tasknum); \ +	*tcr = (*tcr) & (~0x8000);						\ +} + +/* Enable SmartDMA task */ +#define DMA_TASK_ENABLE(tasknum)						\ +{										\ +	volatile ushort *tcr = (ushort *) (MMAP_DMA + 0x0000001c + 2 * tasknum);\ +	*tcr = (*tcr)  | 0x8000;						\ +} + +/* Clear interrupt pending bits */ +#define DMA_CLEAR_IEVENT(tasknum)						\ +{										\ +	struct mpc8220_dma *dma = (struct mpc8220_dma *)MMAP_DMA;		\ +	dma->IntPend = (1 << tasknum);						\ +} + +#endif  /* __MPC8220_DMA_H */ diff --git a/arch/powerpc/cpu/mpc8220/dramSetup.c b/arch/powerpc/cpu/mpc8220/dramSetup.c new file mode 100644 index 000000000..52cf1333f --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/dramSetup.c @@ -0,0 +1,752 @@ +/* + * (C) Copyright 2004, Freescale, Inc + * TsiChung Liew, Tsi-Chung.Liew@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 + */ + +/* +DESCRIPTION +Read Dram spd and base on its information to calculate the memory size, +characteristics to initialize the dram on MPC8220 +*/ + +#include <common.h> +#include <mpc8220.h> +#include "i2cCore.h" +#include "dramSetup.h" + +DECLARE_GLOBAL_DATA_PTR; + +#define SPD_SIZE	CONFIG_SYS_SDRAM_SPD_SIZE +#define DRAM_SPD	(CONFIG_SYS_SDRAM_SPD_I2C_ADDR)<<1	/* on Board SPD eeprom */ +#define TOTAL_BANK	CONFIG_SYS_SDRAM_TOTAL_BANKS + +int spd_status (volatile i2c8220_t * pi2c, u8 sta_bit, u8 truefalse) +{ +	int i; + +	for (i = 0; i < I2C_POLL_COUNT; i++) { +		if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0)) +			return (OK); +	} + +	return (ERROR); +} + +int spd_clear (volatile i2c8220_t * pi2c) +{ +	pi2c->adr = 0; +	pi2c->fdr = 0; +	pi2c->cr = 0; +	pi2c->sr = 0; + +	return (OK); +} + +int spd_stop (volatile i2c8220_t * pi2c) +{ +	pi2c->cr &= ~I2C_CTL_STA;	/* Generate stop signal         */ +	if (spd_status (pi2c, I2C_STA_BB, 0) != OK) +		return ERROR; + +	return (OK); +} + +int spd_readbyte (volatile i2c8220_t * pi2c, u8 * readb, int *index) +{ +	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt Bit          */ +	*readb = pi2c->dr;	/* Read a byte                  */ + +	/* +	   Set I2C_CTRL_TXAK will cause Transfer pending and +	   set I2C_CTRL_STA will cause Interrupt pending +	 */ +	if (*index != 2) { +		if (spd_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?       */ +			return ERROR; +	} + +	if (*index != 1) { +		if (spd_status (pi2c, I2C_STA_IF, 1) != OK) +			return ERROR; +	} + +	return (OK); +} + +int readSpdData (u8 * spdData) +{ +	volatile i2c8220_t *pi2cReg; +	volatile pcfg8220_t *pcfg; +	u8 slvAdr = DRAM_SPD; +	u8 Tmp; +	int Length = SPD_SIZE; +	int i = 0; + +	/* Enable Port Configuration for SDA and SDL signals */ +	pcfg = (volatile pcfg8220_t *) (MMAP_PCFG); +	__asm__ ("sync"); +	pcfg->pcfg3 &= ~CONFIG_SYS_I2C_PORT3_CONFIG; +	__asm__ ("sync"); + +	/* Points the structure to I2c mbar memory offset */ +	pi2cReg = (volatile i2c8220_t *) (MMAP_I2C); + + +	/* Clear FDR, ADR, SR and CR reg */ +	pi2cReg->adr = 0; +	pi2cReg->fdr = 0; +	pi2cReg->cr = 0; +	pi2cReg->sr = 0; + +	/* Set for fix XLB Bus Frequency */ +	switch (gd->bus_clk) { +	case 60000000: +		pi2cReg->fdr = 0x15; +		break; +	case 70000000: +		pi2cReg->fdr = 0x16; +		break; +	case 80000000: +		pi2cReg->fdr = 0x3a; +		break; +	case 90000000: +		pi2cReg->fdr = 0x17; +		break; +	case 100000000: +		pi2cReg->fdr = 0x3b; +		break; +	case 110000000: +		pi2cReg->fdr = 0x18; +		break; +	case 120000000: +		pi2cReg->fdr = 0x19; +		break; +	case 130000000: +		pi2cReg->fdr = 0x1a; +		break; +	} + +	pi2cReg->adr = CONFIG_SYS_I2C_SLAVE<<1; + +	pi2cReg->cr = I2C_CTL_EN;	/* Set Enable         */ + +	/* +	   The I2C bus should be in Idle state. If the bus is busy, +	   clear the STA bit in control register +	 */ +	if (spd_status (pi2cReg, I2C_STA_BB, 0) != OK) { +		if ((pi2cReg->cr & I2C_CTL_STA) == I2C_CTL_STA) +			pi2cReg->cr &= ~I2C_CTL_STA; + +		/* Check again if it is still busy, return error if found */ +		if (spd_status (pi2cReg, I2C_STA_BB, 1) == OK) +			return ERROR; +	} + +	pi2cReg->cr |= I2C_CTL_TX;	/* Enable the I2c for TX, Ack   */ +	pi2cReg->cr |= I2C_CTL_STA;	/* Generate start signal        */ + +	if (spd_status (pi2cReg, I2C_STA_BB, 1) != OK) +		return ERROR; + + +	/* Write slave address */ +	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */ +	pi2cReg->dr = slvAdr;	/* Write a byte                 */ + +	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */ +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + + +	/* Issue the offset to start */ +	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */ +	pi2cReg->dr = 0;	/* Write a byte                 */ + +	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */ +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + + +	/* Set repeat start */ +	pi2cReg->cr |= I2C_CTL_RSTA;	/* Repeat Start                 */ + +	pi2cReg->sr &= ~I2C_STA_IF;	/* Clear Interrupt              */ +	pi2cReg->dr = slvAdr | 1;	/* Write a byte                 */ + +	if (spd_status (pi2cReg, I2C_STA_CF, 1) != OK) {	/* Transfer not complete?       */ +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (spd_status (pi2cReg, I2C_STA_IF, 1) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + +	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01)) +		return ERROR; + +	pi2cReg->cr &= ~I2C_CTL_TX;	/* Set receive mode             */ + +	if (((pi2cReg->sr & 0x07) == 0x07) || (pi2cReg->sr & 0x01)) +		return ERROR; + +	/* Dummy Read */ +	if (spd_readbyte (pi2cReg, &Tmp, &i) != OK) { +		spd_stop (pi2cReg); +		return ERROR; +	} + +	i = 0; +	while (Length) { +		if (Length == 2) +			pi2cReg->cr |= I2C_CTL_TXAK; + +		if (Length == 1) +			pi2cReg->cr &= ~I2C_CTL_STA; + +		if (spd_readbyte (pi2cReg, spdData, &Length) != OK) { +			return spd_stop (pi2cReg); +		} +		i++; +		Length--; +		spdData++; +	} + +	/* Stop the service */ +	spd_stop (pi2cReg); + +	return OK; +} + +int getBankInfo (int bank, draminfo_t * pBank) +{ +	int status; +	int checksum; +	int count; +	u8 spdData[SPD_SIZE]; + + +	if (bank > 2 || pBank == 0) { +		/* illegal values */ +		return (-42); +	} + +	status = readSpdData (&spdData[0]); +	if (status < 0) +		return (-1); + +	/* check the checksum */ +	for (count = 0, checksum = 0; count < LOC_CHECKSUM; count++) +		checksum += spdData[count]; + +	checksum = checksum - ((checksum / 256) * 256); + +	if (checksum != spdData[LOC_CHECKSUM]) +		return (-2); + +	/* Get the memory type */ +	if (! +	    ((spdData[LOC_TYPE] == TYPE_DDR) +	     || (spdData[LOC_TYPE] == TYPE_SDR))) +		/* not one of the types we support */ +		return (-3); + +	pBank->type = spdData[LOC_TYPE]; + +	/* Set logical banks */ +	pBank->banks = spdData[LOC_LOGICAL_BANKS]; + +	/* Check that we have enough physical banks to cover the bank we are +	 * figuring out.  Odd-numbered banks correspond to the second bank +	 * on the device. +	 */ +	if (bank & 1) { +		/* Second bank of a "device" */ +		if (spdData[LOC_PHYS_BANKS] < 2) +			/* this bank doesn't exist on the "device" */ +			return (-4); + +		if (spdData[LOC_ROWS] & 0xf0) +			/* Two asymmetric banks */ +			pBank->rows = spdData[LOC_ROWS] >> 4; +		else +			pBank->rows = spdData[LOC_ROWS]; + +		if (spdData[LOC_COLS] & 0xf0) +			/* Two asymmetric banks */ +			pBank->cols = spdData[LOC_COLS] >> 4; +		else +			pBank->cols = spdData[LOC_COLS]; +	} else { +		/* First bank of a "device" */ +		pBank->rows = spdData[LOC_ROWS]; +		pBank->cols = spdData[LOC_COLS]; +	} + +	pBank->width = spdData[LOC_WIDTH_HIGH] << 8 | spdData[LOC_WIDTH_LOW]; +	pBank->bursts = spdData[LOC_BURSTS]; +	pBank->CAS = spdData[LOC_CAS]; +	pBank->CS = spdData[LOC_CS]; +	pBank->WE = spdData[LOC_WE]; +	pBank->Trp = spdData[LOC_Trp]; +	pBank->Trcd = spdData[LOC_Trcd]; +	pBank->buffered = spdData[LOC_Buffered] & 1; +	pBank->refresh = spdData[LOC_REFRESH]; + +	return (0); +} + + +/* checkMuxSetting -- given a row/column device geometry, return a mask + *                    of the valid DRAM controller addr_mux settings for + *                    that geometry. + * + *  Arguments:        u8 rows:     number of row addresses in this device + *                    u8 columns:  number of column addresses in this device + * + *  Returns:          a mask of the allowed addr_mux settings for this + *                    geometry.  Each bit in the mask represents a + *                    possible addr_mux settings (for example, the + *                    (1<<2) bit in the mask represents the 0b10 setting)/ + * + */ +u8 checkMuxSetting (u8 rows, u8 columns) +{ +	muxdesc_t *pIdx, *pMux; +	u8 mask; +	int lrows, lcolumns; +	u32 mux[4] = { 0x00080c04, 0x01080d03, 0x02080e02, 0xffffffff }; + +	/* Setup MuxDescriptor in SRAM space */ +	/* MUXDESC AddressRuns [] = { +	   { 0, 8, 12, 4 },         / setting, columns, rows, extra columns / +	   { 1, 8, 13, 3 },         / setting, columns, rows, extra columns / +	   { 2, 8, 14, 2 },         / setting, columns, rows, extra columns / +	   { 0xff }                 / list terminator / +	   }; */ + +	pIdx = (muxdesc_t *) & mux[0]; + +	/* Check rows x columns against each possible address mux setting */ +	for (pMux = pIdx, mask = 0;; pMux++) { +		lrows = rows; +		lcolumns = columns; + +		if (pMux->MuxValue == 0xff) +			break;	/* end of list */ + +		/* For a given mux setting, since we want all the memory in a +		 * device to be contiguous, we want the device "use up" the +		 * address lines such that there are no extra column or row +		 * address lines on the device. +		 */ + +		lcolumns -= pMux->Columns; +		if (lcolumns < 0) +			/* Not enough columns to get to the rows */ +			continue; + +		lrows -= pMux->Rows; +		if (lrows > 0) +			/* we have extra rows left -- can't do that! */ +			continue; + +		/* At this point, we either have to have used up all the +		 * rows or we have to have no columns left. +		 */ + +		if (lcolumns != 0 && lrows != 0) +			/* rows AND columns are left.  Bad! */ +			continue; + +		lcolumns -= pMux->MoreColumns; + +		if (lcolumns <= 0) +			mask |= (1 << pMux->MuxValue); +	} + +	return (mask); +} + + +u32 dramSetup (void) +{ +	draminfo_t DramInfo[TOTAL_BANK]; +	draminfo_t *pDramInfo; +	u32 size, temp, cfg_value, mode_value, refresh; +	u8 *ptr; +	u8 bursts, Trp, Trcd, type, buffered; +	u8 muxmask, rows, columns; +	int count, banknum; +	u32 *prefresh, *pIdx; +	u32 refrate[8] = { 15625, 3900, 7800, 31300, +		62500, 125000, 0xffffffff, 0xffffffff +	}; +	volatile sysconf8220_t *sysconf; +	volatile memctl8220_t *memctl; + +	sysconf = (volatile sysconf8220_t *) MMAP_MBAR; +	memctl = (volatile memctl8220_t *) MMAP_MEMCTL; + +	/* Set everything in the descriptions to zero */ +	ptr = (u8 *) & DramInfo[0]; +	for (count = 0; count < sizeof (DramInfo); count++) +		*ptr++ = 0; + +	for (banknum = 0; banknum < TOTAL_BANK; banknum++) +		sysconf->cscfg[banknum]; + +	/* Descriptions of row/column address muxing for various +	 * addr_mux settings. +	 */ + +	pIdx = prefresh = (u32 *) & refrate[0]; + +	/* Get all the info for all three logical banks */ +	bursts = 0xff; +	Trp = 0; +	Trcd = 0; +	type = 0; +	buffered = 0xff; +	refresh = 0xffffffff; +	muxmask = 0xff; + +	/* Two bank, CS0 and CS1 */ +	for (banknum = 0, pDramInfo = &DramInfo[0]; +	     banknum < TOTAL_BANK; banknum++, pDramInfo++) { +		pDramInfo->ordinal = banknum;	/* initial sorting */ +		if (getBankInfo (banknum, pDramInfo) < 0) +			continue; + +		/* get cumulative parameters of all three banks */ +		if (type && pDramInfo->type != type) +			return 0; + +		type = pDramInfo->type; +		rows = pDramInfo->rows; +		columns = pDramInfo->cols; + +		/* This chip only supports 13 DRAM memory lines, but some devices +		 * have 14 rows.  To deal with this, ignore the 14th address line +		 * by limiting the number of rows (and columns) to 13.  This will +		 * mean that for 14-row devices we will only be able to use +		 * half of the memory, but it's better than nothing. +		 */ +		if (rows > 13) +			rows = 13; +		if (columns > 13) +			columns = 13; + +		pDramInfo->size = +			((1 << (rows + columns)) * pDramInfo->width); +		pDramInfo->size *= pDramInfo->banks; +		pDramInfo->size >>= 3; + +		/* figure out which addr_mux configurations will support this device */ +		muxmask &= checkMuxSetting (rows, columns); +		if (muxmask == 0) +			return 0; + +		buffered = pDramInfo->buffered; +		bursts &= pDramInfo->bursts;	/* union of all bursts */ +		if (pDramInfo->Trp > Trp)	/* worst case (longest) Trp */ +			Trp = pDramInfo->Trp; + +		if (pDramInfo->Trcd > Trcd)	/* worst case (longest) Trcd */ +			Trcd = pDramInfo->Trcd; + +		prefresh = pIdx; +		/* worst case (shortest) Refresh period */ +		if (refresh > prefresh[pDramInfo->refresh & 7]) +			refresh = prefresh[pDramInfo->refresh & 7]; + +	}			/* for loop */ + + +	/* We only allow a burst length of 8! */ +	if (!(bursts & 8)) +		bursts = 8; + +	/* Sort the devices.  In order to get each chip select region +	 * aligned properly, put the biggest device at the lowest address. +	 * A simple bubble sort will do the trick. +	 */ +	for (banknum = 0, pDramInfo = &DramInfo[0]; +	     banknum < TOTAL_BANK; banknum++, pDramInfo++) { +		int i; + +		for (i = 0; i < TOTAL_BANK; i++) { +			if (pDramInfo->size < DramInfo[i].size && +			    pDramInfo->ordinal < DramInfo[i].ordinal) { +				/* If the current bank is smaller, but if the ordinal is also +				 * smaller, swap the ordinals +				 */ +				u8 temp8; + +				temp8 = DramInfo[i].ordinal; +				DramInfo[i].ordinal = pDramInfo->ordinal; +				pDramInfo->ordinal = temp8; +			} +		} +	} + + +	/* Now figure out the base address for each bank.  While +	 * we're at it, figure out how much memory there is. +	 * +	 */ +	size = 0; +	for (banknum = 0; banknum < TOTAL_BANK; banknum++) { +		int i; + +		for (i = 0; i < TOTAL_BANK; i++) { +			if (DramInfo[i].ordinal == banknum +			    && DramInfo[i].size != 0) { +				DramInfo[i].base = size; +				size += DramInfo[i].size; +			} +		} +	} + +	/* Set up the Drive Strength register */ +	sysconf->sdramds = CONFIG_SYS_SDRAM_DRIVE_STRENGTH; + +	/* ********************** Cfg 1 ************************* */ + +	/* Set the single read to read/write/precharge delay */ +	cfg_value = CFG1_SRD2RWP ((type == TYPE_DDR) ? 7 : 0xb); + +	/* Set the single write to read/write/precharge delay. +	 * This may or may not be correct.  The controller spec +	 * says "tWR", but "tWR" does not appear in the SPD.  It +	 * always seems to be 15nsec for the class of device we're +	 * using, which turns out to be 2 clock cycles at 133MHz, +	 * so that's what we're going to use. +	 * +	 * HOWEVER, because of a bug in the controller, for DDR +	 * we need to set this to be the same as the value +	 * calculated for bwt2rwp. +	 */ +	cfg_value |= CFG1_SWT2RWP ((type == TYPE_DDR) ? 7 : 2); + +	/* Set the Read CAS latency.  We're going to use a CL of +	 * 2.5 for DDR and 2 SDR. +	 */ +	cfg_value |= CFG1_RLATENCY ((type == TYPE_DDR) ? 7 : 2); + + +	/* Set the Active to Read/Write delay.  This depends +	 * on Trcd which is reported as nanoseconds times 4. +	 * We want to calculate Trcd (in nanoseconds) times XLB clock (in Hz) +	 * which gives us a dimensionless quantity.  Play games with +	 * the divisions so we don't run out of dynamic ranges. +	 */ +	/* account for megaherz and the times 4 */ +	temp = (Trcd * (gd->bus_clk / 1000000)) / 4; + +	/* account for nanoseconds and round up, with a minimum value of 2 */ +	temp = ((temp + 999) / 1000) - 1; +	if (temp < 2) +		temp = 2; + +	cfg_value |= CFG1_ACT2WR (temp); + +	/* Set the precharge to active delay.  This depends +	 * on Trp which is reported as nanoseconds times 4. +	 * We want to calculate Trp (in nanoseconds) times XLB clock (in Hz) +	 * which gives us a dimensionless quantity.  Play games with +	 * the divisions so we don't run out of dynamic ranges. +	 */ +	/* account for megaherz and the times 4 */ +	temp = (Trp * (gd->bus_clk / 1000000)) / 4; + +	/* account for nanoseconds and round up, then subtract 1, with a +	 * minumum value of 1 and a maximum value of 7. +	 */ +	temp = (((temp + 999) / 1000) - 1) & 7; +	if (temp < 1) +		temp = 1; + +	cfg_value |= CFG1_PRE2ACT (temp); + +	/* Set refresh to active delay.  This depends +	 * on Trfc which is not reported in the SPD. +	 * We'll use a nominal value of 75nsec which is +	 * what the controller spec uses. +	 */ +	temp = (75 * (gd->bus_clk / 1000000)); +	/* account for nanoseconds and round up, then subtract 1 */ +	cfg_value |= CFG1_REF2ACT (((temp + 999) / 1000) - 1); + +	/* Set the write latency, using the values given in the controller spec */ +	cfg_value |= CFG1_WLATENCY ((type == TYPE_DDR) ? 3 : 0); +	memctl->cfg1 = cfg_value;	/* cfg 1 */ +	asm volatile ("sync"); + + +	/* ********************** Cfg 2 ************************* */ + +	/* Set the burst read to read/precharge delay */ +	cfg_value = CFG2_BRD2RP ((type == TYPE_DDR) ? 5 : 8); + +	/* Set the burst write to read/precharge delay.  Semi-magic numbers +	 * based on the controller spec recommendations, assuming tWR is +	 * two clock cycles. +	 */ +	cfg_value |= CFG2_BWT2RWP ((type == TYPE_DDR) ? 7 : 10); + +	/* Set the Burst read to write delay.  Semi-magic numbers +	 * based on the DRAM controller documentation. +	 */ +	cfg_value |= CFG2_BRD2WT ((type == TYPE_DDR) ? 7 : 0xb); + +	/* Set the burst length -- must be 8!! Well, 7, actually, becuase +	 * it's burst lenght minus 1. +	 */ +	cfg_value |= CFG2_BURSTLEN (7); +	memctl->cfg2 = cfg_value;	/* cfg 2 */ +	asm volatile ("sync"); + + +	/* ********************** mode ************************* */ + +	/* Set enable bit, CKE high/low bits, and the DDR/SDR mode bit, +	 * disable automatic refresh. +	 */ +	cfg_value = CTL_MODE_ENABLE | CTL_CKE_HIGH | +		((type == TYPE_DDR) ? CTL_DDR_MODE : 0); + +	/* Set the address mux based on whichever setting(s) is/are common +	 * to all the devices we have.  If there is more than one, choose +	 * one arbitrarily. +	 */ +	if (muxmask & 0x4) +		cfg_value |= CTL_ADDRMUX (2); +	else if (muxmask & 0x2) +		cfg_value |= CTL_ADDRMUX (1); +	else +		cfg_value |= CTL_ADDRMUX (0); + +	/* Set the refresh interval. */ +	temp = ((refresh * (gd->bus_clk / 1000000)) / (1000 * 64)) - 1; +	cfg_value |= CTL_REFRESH_INTERVAL (temp); + +	/* Set buffered/non-buffered memory */ +	if (buffered) +		cfg_value |= CTL_BUFFERED; + +	memctl->ctrl = cfg_value;	/* ctrl */ +	asm volatile ("sync"); + +	if (type == TYPE_DDR) { +		/* issue precharge all */ +		temp = cfg_value | CTL_PRECHARGE_CMD; +		memctl->ctrl = temp;	/* ctrl */ +		asm volatile ("sync"); +	} + + +	/* Set up mode value for CAS latency */ +#if (CONFIG_SYS_SDRAM_CAS_LATENCY==5) /* CL=2.5 */ +	mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) | +		MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2p5) | MODE_CMD); +#else +	mode_value = (MODE_MODE | MODE_BURSTLEN (MODE_BURSTLEN_8) | +		      MODE_BT_SEQUENTIAL | MODE_CL (MODE_CL_2) | MODE_CMD); +#endif +	asm volatile ("sync"); + +	/* Write Extended Mode  - enable DLL */ +	if (type == TYPE_DDR) { +		temp = MODE_EXTENDED | MODE_X_DLL_ENABLE | +			MODE_X_DS_NORMAL | MODE_CMD; +		memctl->mode = (temp >> 16);	/* mode */ +		asm volatile ("sync"); + +		/* Write Mode - reset DLL, set CAS latency */ +		temp = mode_value | MODE_OPMODE (MODE_OPMODE_RESETDLL); +		memctl->mode = (temp >> 16);	/* mode */ +		asm volatile ("sync"); +	} + +	/* Program the chip selects. */ +	for (banknum = 0; banknum < TOTAL_BANK; banknum++) { +		if (DramInfo[banknum].size != 0) { +			u32 mask; +			int i; + +			for (i = 0, mask = 1; i < 32; mask <<= 1, i++) { +				if (DramInfo[banknum].size & mask) +					break; +			} +			temp = (DramInfo[banknum].base & 0xfff00000) | (i - +									1); + +			sysconf->cscfg[banknum] = temp; +			asm volatile ("sync"); +		} +	} + +	/* Wait for DLL lock */ +	udelay (200); + +	temp = cfg_value | CTL_PRECHARGE_CMD;	/* issue precharge all */ +	memctl->ctrl = temp;	/* ctrl */ +	asm volatile ("sync"); + +	temp = cfg_value | CTL_REFRESH_CMD;	/* issue precharge all */ +	memctl->ctrl = temp;	/* ctrl */ +	asm volatile ("sync"); + +	memctl->ctrl = temp;	/* ctrl */ +	asm volatile ("sync"); + +	/* Write Mode - DLL normal */ +	temp = mode_value | MODE_OPMODE (MODE_OPMODE_NORMAL); +	memctl->mode = (temp >> 16);	/* mode */ +	asm volatile ("sync"); + +	/* Enable refresh, enable DQS's (if DDR), and lock the control register */ +	cfg_value &= ~CTL_MODE_ENABLE;	/* lock register */ +	cfg_value |= CTL_REFRESH_ENABLE;	/* enable refresh */ + +	if (type == TYPE_DDR) +		cfg_value |= CTL_DQSOEN (0xf);	/* enable DQS's for DDR */ + +	memctl->ctrl = cfg_value;	/* ctrl */ +	asm volatile ("sync"); + +	return size; +} diff --git a/arch/powerpc/cpu/mpc8220/dramSetup.h b/arch/powerpc/cpu/mpc8220/dramSetup.h new file mode 100644 index 000000000..3b64e088c --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/dramSetup.h @@ -0,0 +1,108 @@ +/* + * dramSetup.h + * + * Prototypes, etc. for the Motorola MPC8220 + * embedded cpu chips + * + * 2004 (c) Freescale, Inc. + * Author: TsiChung Liew <Tsi-Chung.Liew@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 + */ +#ifndef __INCdramsetuph +#define __INCdramsetuph +#ifndef __ASSEMBLY__ +/* Where various things are in the SPD */ +#define LOC_TYPE                    2 +#define LOC_CHECKSUM                63 +#define LOC_PHYS_BANKS              5 +#define LOC_LOGICAL_BANKS           17 +#define LOC_ROWS                    3 +#define LOC_COLS                    4 +#define LOC_WIDTH_HIGH              7 +#define LOC_WIDTH_LOW               6 +#define LOC_REFRESH                 12 +#define LOC_BURSTS                  16 +#define LOC_CAS                     18 +#define LOC_CS                      19 +#define LOC_WE                      20 +#define LOC_Tcyc                    9 +#define LOC_Tac                     10 +#define LOC_Trp                     27 +#define LOC_Trrd                    28 +#define LOC_Trcd                    29 +#define LOC_Tras                    30 +#define LOC_Buffered                21 +/* Types of memory the SPD can tell us about. + * We can actually only use SDRAM and DDR. + */ +#define TYPE_DRAM                   1	/* plain old dram */ +#define TYPE_EDO                    2	/* EDO dram */ +#define TYPE_Nibble                 3	/* serial nibble memory */ +#define TYPE_SDR                    4	/* SDRAM */ +#define TYPE_ROM                    5	/*  */ +#define TYPE_SGRRAM                 6	/* graphics memory */ +#define TYPE_DDR                    7	/* DDR sdram */ +#define SDRAMDS_MASK        0x3	/* each field is 2 bits wide */ +#define SDRAMDS_SBE_SHIFT     8	/* Clock enable drive strength */ +#define SDRAMDS_SBC_SHIFT     6	/* Clocks drive strength */ +#define SDRAMDS_SBA_SHIFT     4	/* Address drive strength */ +#define SDRAMDS_SBS_SHIFT     2	/* SDR DQS drive strength */ +#define SDRAMDS_SBD_SHIFT     0	/* Data and DQS drive strength */ +#define  DRIVE_STRENGTH_HIGH 0 +#define  DRIVE_STRENGTH_MED  1 +#define  DRIVE_STRENGTH_LOW  2 +#define  DRIVE_STRENGTH_OFF  3 + +#define OK      0 +#define ERROR   -1 +/* Structure to hold information about address muxing. */ +	typedef struct tagMuxDescriptor { +	u8 MuxValue; +	u8 Columns; +	u8 Rows; +	u8 MoreColumns; +} muxdesc_t; + +/* Structure to define one physical bank of + * memory.  Note that dram size in bytes is + * (2^^(rows+columns)) * width * banks / 8 +*/ +typedef struct tagDramInfo { +	u32 size;		/* size in bytes */ +	u32 base;		/* base address */ +	u8 ordinal;		/* where in the memory map will we put this */ +	u8 type; +	u8 rows; +	u8 cols; +	u16 width;		/* width of each chip in bits */ +	u8 banks;		/* number of chips, aka logical banks */ +	u8 bursts;		/* bit-encoded allowable burst length */ +	u8 CAS;			/* bit-encoded CAS latency values */ +	u8 CS;			/* bit-encoded CS latency values */ +	u8 WE;			/* bit-encoded WE latency values */ +	u8 Trp;			/* bit-encoded row precharge time */ +	u8 Trcd;		/* bit-encoded RAS to CAS delay */ +	u8 buffered;		/* buffered or not */ +	u8 refresh;		/* encoded refresh rate */ +} draminfo_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* __INCdramsetuph */ diff --git a/arch/powerpc/cpu/mpc8220/fec.c b/arch/powerpc/cpu/mpc8220/fec.c new file mode 100644 index 000000000..992e0ffbc --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/fec.c @@ -0,0 +1,1000 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on mpc4200fec.c, + * (C) Copyright Motorola, Inc., 2000 + */ + +#include <common.h> +#include <mpc8220.h> +#include <malloc.h> +#include <net.h> +#include <miiphy.h> +#include "dma.h" +#include "fec.h" + +#undef  DEBUG +#if defined(CONFIG_CMD_NET) && defined(CONFIG_NET_MULTI) && \ +    defined(CONFIG_MPC8220_FEC) + +#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII)) +#error "CONFIG_MII has to be defined!" +#endif + +#ifdef DEBUG +static void tfifo_print (char *devname, mpc8220_fec_priv * fec); +static void rfifo_print (char *devname, mpc8220_fec_priv * fec); +#endif /* DEBUG */ + +#ifdef DEBUG +static u32 local_crc32 (char *string, unsigned int crc_value, int len); +#endif + +typedef struct { +	u8 data[1500];		/* actual data */ +	int length;		/* actual length */ +	int used;		/* buffer in use or not */ +	u8 head[16];		/* MAC header(6 + 6 + 2) + 2(aligned) */ +} NBUF; + +int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal); +int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data); + +/********************************************************************/ +#ifdef DEBUG +static void mpc8220_fec_phydump (char *devname) +{ +	u16 phyStatus, i; +	u8 phyAddr = CONFIG_PHY_ADDR; +	u8 reg_mask[] = { +#if CONFIG_PHY_TYPE == 0x79c874 /* AMD Am79C874 */ +		/* regs to print: 0...7, 16...19, 21, 23, 24 */ +		1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, +		1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, +#else +		/* regs to print: 0...8, 16...20 */ +		1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, +		1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#endif +	}; + +	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 mpc8220_fec_rbd_init (mpc8220_fec_priv * fec) +{ +	int ix; +	char *data; +	static int once = 0; + +	for (ix = 0; ix < FEC_RBD_NUM; ix++) { +		if (!once) { +			data = (char *) malloc (FEC_MAX_PKT_SIZE); +			if (data == NULL) { +				printf ("RBD INIT FAILED\n"); +				return -1; +			} +			fec->rbdBase[ix].dataPointer = (u32) data; +		} +		fec->rbdBase[ix].status = FEC_RBD_EMPTY; +		fec->rbdBase[ix].dataLength = 0; +	} +	once++; + +	/* +	 * have the last RBD to close the ring +	 */ +	fec->rbdBase[ix - 1].status |= FEC_RBD_WRAP; +	fec->rbdIndex = 0; + +	return 0; +} + +/********************************************************************/ +static void mpc8220_fec_tbd_init (mpc8220_fec_priv * fec) +{ +	int ix; + +	for (ix = 0; ix < FEC_TBD_NUM; ix++) { +		fec->tbdBase[ix].status = 0; +	} + +	/* +	 * Have the last TBD to close the ring +	 */ +	fec->tbdBase[ix - 1].status |= FEC_TBD_WRAP; + +	/* +	 * Initialize some indices +	 */ +	fec->tbdIndex = 0; +	fec->usedTbdIndex = 0; +	fec->cleanTbdNum = FEC_TBD_NUM; +} + +/********************************************************************/ +static void mpc8220_fec_rbd_clean (mpc8220_fec_priv * fec, 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; + +	/* +	 * Now, we have an empty RxBD, restart the SmartDMA receive task +	 */ +	DMA_TASK_ENABLE (FEC_RECV_TASK_NO); + +	/* +	 * Increment BD count +	 */ +	fec->rbdIndex = (fec->rbdIndex + 1) % FEC_RBD_NUM; +} + +/********************************************************************/ +static void mpc8220_fec_tbd_scrub (mpc8220_fec_priv * fec) +{ +	FEC_TBD *pUsedTbd; + +#ifdef DEBUG +	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->tbdBase[fec->usedTbdIndex]; +		if (pUsedTbd->status & FEC_TBD_READY) { +#ifdef DEBUG +			printf ("Cannot clean TBD %d, in use\n", +				fec->cleanTbdNum); +#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 mpc8220_fec_set_hwaddr (mpc8220_fec_priv * fec, char *mac) +{ +	u8 currByte;		/* byte for which to compute the CRC */ +	int byte;		/* loop - counter */ +	int bit;		/* loop - counter */ +	u32 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 mpc8220_fec_init (struct eth_device *dev, bd_t * bis) +{ +	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; +	struct mpc8220_dma *dma = (struct mpc8220_dma *) MMAP_DMA; +	const u8 phyAddr = CONFIG_PHY_ADDR;	/* Only one PHY */ + +#ifdef DEBUG +	printf ("mpc8220_fec_init... Begin\n"); +#endif + +	/* +	 * Initialize RxBD/TxBD rings +	 */ +	mpc8220_fec_rbd_init (fec); +	mpc8220_fec_tbd_init (fec); + +	/* +	 * Set up Pin Muxing for FEC 1 +	 */ +	*(vu_long *) MMAP_PCFG = 0; +	*(vu_long *) (MMAP_PCFG + 4) = 0; +	/* +	 * Clear FEC-Lite interrupt event register(IEVENT) +	 */ +	fec->eth->ievent = 0xffffffff; + +	/* +	 * Set interrupt mask register +	 */ +	fec->eth->imask = 0x00000000; + +	/* +	 * Set FEC-Lite receive control register(R_CNTRL): +	 */ +	if (fec->xcv_type == SEVENWIRE) { +		/* +		 * Frame length=1518; 7-wire mode +		 */ +		fec->eth->r_cntrl = 0x05ee0020; /*0x05ee0000;FIXME */ +	} else { +		/* +		 * Frame length=1518; MII mode; +		 */ +		fec->eth->r_cntrl = 0x05ee0024; /*0x05ee0004;FIXME */ +	} + +	fec->eth->x_cntrl = 0x00000000; /* half-duplex, heartbeat disabled */ +	if (fec->xcv_type != SEVENWIRE) { +		/* +		 * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock +		 * and do not drop the Preamble. +		 */ +		/* tbd - rtm */ +		/*fec->eth->mii_speed = (((gd->ipb_clk >> 20) / 5) << 1); */ +		/* No MII for 7-wire mode */ +		fec->eth->mii_speed = 0x00000030; +	} + +	/* +	 * Set Opcode/Pause Duration Register +	 */ +	fec->eth->op_pause = 0x00010020;	/*FIXME0xffff0020; */ + +	/* +	 * Set Rx FIFO alarm and granularity value +	 */ +	fec->eth->rfifo_cntrl = 0x0c000000; +	fec->eth->rfifo_alarm = 0x0000030c; +#ifdef DEBUG +	if (fec->eth->rfifo_status & 0x00700000) { +		printf ("mpc8220_fec_init() RFIFO error\n"); +	} +#endif + +	/* +	 * Set Tx FIFO granularity value +	 */ +	/*fec->eth->tfifo_cntrl = 0x0c000000; */ /*tbd - rtm */ +	fec->eth->tfifo_cntrl = 0x0e000000; +#ifdef DEBUG +	printf ("tfifo_status: 0x%08x\n", fec->eth->tfifo_status); +	printf ("tfifo_alarm: 0x%08x\n", fec->eth->tfifo_alarm); +#endif + +	/* +	 * Set transmit fifo watermark register(X_WMRK), default = 64 +	 */ +	fec->eth->tfifo_alarm = 0x00000080; +	fec->eth->x_wmrk = 0x2; + +	/* +	 * Set individual address filter for unicast address +	 * and set physical address registers. +	 */ +	mpc8220_fec_set_hwaddr (fec, (char *)(dev->enetaddr)); + +	/* +	 * Set multicast address filter +	 */ +	fec->eth->gaddr1 = 0x00000000; +	fec->eth->gaddr2 = 0x00000000; + +	/* +	 * Turn ON cheater FSM: ???? +	 */ +	fec->eth->xmit_fsm = 0x03000000; + +#if 1 +/*#if defined(CONFIG_MPC5200)*/ +	/* +	 * Turn off COMM bus prefetch in the MGT5200 BestComm. It doesn't +	 * work w/ the current receive task. +	 */ +	dma->PtdCntrl |= 0x00000001; +#endif + +	/* +	 * Set priority of different initiators +	 */ +	dma->IPR0 = 7;		/* always */ +	dma->IPR3 = 6;		/* Eth RX */ +	dma->IPR4 = 5;		/* Eth Tx */ + +	/* +	 * Clear SmartDMA task interrupt pending bits +	 */ +	DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO); + +	/* +	 * Initialize SmartDMA parameters stored in SRAM +	 */ +	*(int *) FEC_TBD_BASE = (int) fec->tbdBase; +	*(int *) FEC_RBD_BASE = (int) fec->rbdBase; +	*(int *) FEC_TBD_NEXT = (int) fec->tbdBase; +	*(int *) FEC_RBD_NEXT = (int) fec->rbdBase; + +	if (fec->xcv_type != SEVENWIRE) { +		/* +		 * Initialize PHY(LXT971A): +		 * +		 *   Generally, on power up, the LXT971A reads its configuration +		 *   pins to check for forced operation, If not cofigured for +		 *   forced operation, it uses auto-negotiation/parallel detection +		 *   to automatically determine line operating conditions. +		 *   If the PHY device on the other side of the link supports +		 *   auto-negotiation, the LXT971A auto-negotiates with it +		 *   using Fast Link Pulse(FLP) Bursts. If the PHY partner does not +		 *   support auto-negotiation, the LXT971A automatically detects +		 *   the presence of either link pulses(10Mbps PHY) or Idle +		 *   symbols(100Mbps) and sets its operating conditions accordingly. +		 * +		 *   When auto-negotiation is controlled by software, the following +		 *   steps are recommended. +		 * +		 * Note: +		 *   The physical address is dependent on hardware configuration. +		 * +		 */ +		int timeout = 1; +		u16 phyStatus; + +		/* +		 * Reset PHY, then delay 300ns +		 */ +		miiphy_write (dev->name, phyAddr, 0x0, 0x8000); +		udelay (1000); + +		if (fec->xcv_type == MII10) { +			/* +			 * Force 10Base-T, FDX operation +			 */ +#ifdef DEBUG +			printf ("Forcing 10 Mbps ethernet link... "); +#endif +			miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); +			/* +			   miiphy_write(fec, phyAddr, 0x0, 0x0100); +			 */ +			miiphy_write (dev->name, phyAddr, 0x0, 0x0180); + +			timeout = 20; +			do {	/* wait for link status to go down */ +				udelay (10000); +				if ((timeout--) == 0) { +#ifdef DEBUG +					printf ("hmmm, should not have waited..."); +#endif +					break; +				} +				miiphy_read (dev->name, phyAddr, 0x1, &phyStatus); +#ifdef DEBUG +				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); +#ifdef DEBUG +				printf ("+"); +#endif +			} while (!(phyStatus & 0x0004));	/* !link up */ + +#ifdef DEBUG +			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 = 5000; +			do { +				udelay (1000); + +				if ((timeout--) == 0) { +#ifdef DEBUG +					printf ("PHY auto neg 0 failed...\n"); +#endif +					return -1; +				} + +				if (miiphy_read (dev->name, phyAddr, 0x1, &phyStatus) != +				    0) { +#ifdef DEBUG +					printf ("PHY auto neg 1 failed 0x%04x...\n", phyStatus); +#endif +					return -1; +				} +			} while (!(phyStatus & 0x0004)); + +#ifdef DEBUG +			printf ("PHY auto neg complete! \n"); +#endif +		} + +	} + +	/* +	 * Enable FEC-Lite controller +	 */ +	fec->eth->ecntrl |= 0x00000006; + +#ifdef DEBUG +	if (fec->xcv_type != SEVENWIRE) +		mpc8220_fec_phydump (dev->name); +#endif + +	/* +	 * Enable SmartDMA receive task +	 */ +	DMA_TASK_ENABLE (FEC_RECV_TASK_NO); + +#ifdef DEBUG +	printf ("mpc8220_fec_init... Done \n"); +#endif + +	return 1; +} + +/********************************************************************/ +static void mpc8220_fec_halt (struct eth_device *dev) +{ +	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; +	int counter = 0xffff; + +#ifdef DEBUG +	if (fec->xcv_type != SEVENWIRE) +		mpc8220_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 SmartDMA tasks +	 */ +	DMA_TASK_DISABLE (FEC_XMIT_TASK_NO); +	DMA_TASK_DISABLE (FEC_RECV_TASK_NO); + +	/* +	 * Disable the Ethernet Controller +	 */ +	fec->eth->ecntrl &= 0xfffffffd; + +	/* +	 * Clear FIFO status registers +	 */ +	fec->eth->rfifo_status &= 0x00700000; +	fec->eth->tfifo_status &= 0x00700000; + +	fec->eth->reset_cntrl = 0x01000000; + +	/* +	 * Issue a reset command to the FEC chip +	 */ +	fec->eth->ecntrl |= 0x1; + +	/* +	 * wait at least 16 clock cycles +	 */ +	udelay (10); + +#ifdef DEBUG +	printf ("Ethernet task stopped\n"); +#endif +} + +#ifdef DEBUG +/********************************************************************/ + +static void tfifo_print (char *devname, mpc8220_fec_priv * fec) +{ +	u16 phyAddr = CONFIG_PHY_ADDR; +	u16 phyStatus; + +	if ((fec->eth->tfifo_lrf_ptr != fec->eth->tfifo_lwf_ptr) +	    || (fec->eth->tfifo_rdptr != fec->eth->tfifo_wrptr)) { + +		miiphy_read (devname, phyAddr, 0x1, &phyStatus); +		printf ("\nphyStatus: 0x%04x\n", phyStatus); +		printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl); +		printf ("ievent:   0x%08x\n", fec->eth->ievent); +		printf ("x_status: 0x%08x\n", fec->eth->x_status); +		printf ("tfifo: status	0x%08x\n", fec->eth->tfifo_status); + +		printf ("	control 0x%08x\n", fec->eth->tfifo_cntrl); +		printf ("	lrfp	0x%08x\n", fec->eth->tfifo_lrf_ptr); +		printf ("	lwfp	0x%08x\n", fec->eth->tfifo_lwf_ptr); +		printf ("	alarm	0x%08x\n", fec->eth->tfifo_alarm); +		printf ("	readptr 0x%08x\n", fec->eth->tfifo_rdptr); +		printf ("	writptr 0x%08x\n", fec->eth->tfifo_wrptr); +	} +} + +static void rfifo_print (char *devname, mpc8220_fec_priv * fec) +{ +	u16 phyAddr = CONFIG_PHY_ADDR; +	u16 phyStatus; + +	if ((fec->eth->rfifo_lrf_ptr != fec->eth->rfifo_lwf_ptr) +	    || (fec->eth->rfifo_rdptr != fec->eth->rfifo_wrptr)) { + +		miiphy_read (devname, phyAddr, 0x1, &phyStatus); +		printf ("\nphyStatus: 0x%04x\n", phyStatus); +		printf ("ecntrl:   0x%08x\n", fec->eth->ecntrl); +		printf ("ievent:   0x%08x\n", fec->eth->ievent); +		printf ("x_status: 0x%08x\n", fec->eth->x_status); +		printf ("rfifo: status	0x%08x\n", fec->eth->rfifo_status); + +		printf ("	control 0x%08x\n", fec->eth->rfifo_cntrl); +		printf ("	lrfp	0x%08x\n", fec->eth->rfifo_lrf_ptr); +		printf ("	lwfp	0x%08x\n", fec->eth->rfifo_lwf_ptr); +		printf ("	alarm	0x%08x\n", fec->eth->rfifo_alarm); +		printf ("	readptr 0x%08x\n", fec->eth->rfifo_rdptr); +		printf ("	writptr 0x%08x\n", fec->eth->rfifo_wrptr); +	} +} +#endif /* DEBUG */ + +/********************************************************************/ + +static int mpc8220_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. +	 */ +	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; +	FEC_TBD *pTbd; + +#ifdef DEBUG +	printf ("tbd status: 0x%04x\n", fec->tbdBase[0].status); +	tfifo_print (dev->name, fec); +#endif + +	/* +	 * Clear Tx BD ring at first +	 */ +	mpc8220_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) { +#ifdef DEBUG +		printf ("No available TxBDs ...\n"); +#endif +		return -1; +	} + +	/* +	 * Get the first TxBD to send the mac header +	 */ +	pTbd = &fec->tbdBase[fec->tbdIndex]; +	pTbd->dataLength = data_length; +	pTbd->dataPointer = (u32) eth_data; +	pTbd->status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY; +	fec->tbdIndex = (fec->tbdIndex + 1) % FEC_TBD_NUM; + +#ifdef DEBUG +	printf ("DMA_TASK_ENABLE, fec->tbdIndex = %d \n", fec->tbdIndex); +#endif + +	/* +	 * Kick the MII i/f +	 */ +	if (fec->xcv_type != SEVENWIRE) { +		u16 phyStatus; + +		miiphy_read (dev->name, 0, 0x1, &phyStatus); +	} + +	/* +	 * Enable SmartDMA transmit task +	 */ + +#ifdef DEBUG +	tfifo_print (dev->name, fec); +#endif + +	DMA_TASK_ENABLE (FEC_XMIT_TASK_NO); + +#ifdef DEBUG +	tfifo_print (dev->name, fec); +#endif + +#ifdef DEBUG +	printf ("+"); +#endif + +	fec->cleanTbdNum -= 1; + +#ifdef DEBUG +	printf ("smartDMA ethernet Tx task enabled\n"); +#endif +	/* +	 * wait until frame is sent . +	 */ +	while (pTbd->status & FEC_TBD_READY) { +		udelay (10); +#ifdef DEBUG +		printf ("TDB status = %04x\n", pTbd->status); +#endif +	} + +	return 0; +} + + +/********************************************************************/ +static int mpc8220_fec_recv (struct eth_device *dev) +{ +	/* +	 * This command pulls one frame from the card +	 */ +	mpc8220_fec_priv *fec = (mpc8220_fec_priv *) dev->priv; +	FEC_RBD *pRbd = &fec->rbdBase[fec->rbdIndex]; +	unsigned long ievent; +	int frame_length, len = 0; +	NBUF *frame; + +#ifdef DEBUG +	printf ("mpc8220_fec_recv %d Start...\n", fec->rbdIndex); +	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 */ +		mpc8220_fec_halt (dev); +		mpc8220_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) { +			mpc8220_fec_halt (dev); +			fec->eth->x_cntrl &= ~0x00000001; +			mpc8220_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 address and size +			 */ +			frame = (NBUF *) pRbd->dataPointer; +			frame_length = pRbd->dataLength - 4; + +#if (0) +			{ +				int i; + +				printf ("recv data hdr:"); +				for (i = 0; i < 14; i++) +					printf ("%x ", *(frame->head + i)); +				printf ("\n"); +			} +#endif +			/* +			 *  Fill the buffer and pass it to upper layers +			 */ +/*			memcpy(buff, frame->head, 14); +			memcpy(buff + 14, frame->data, frame_length);*/ +			NetReceive ((volatile uchar *) pRbd->dataPointer, +				    frame_length); +			len = frame_length; +		} +		/* +		 * Reset buffer descriptor as empty +		 */ +		mpc8220_fec_rbd_clean (fec, pRbd); +	} +	DMA_CLEAR_IEVENT (FEC_RECV_TASK_NO); +	return len; +} + + +/********************************************************************/ +int mpc8220_fec_initialize (bd_t * bis) +{ +	mpc8220_fec_priv *fec; + +#ifdef CONFIG_HAS_ETH1 +	mpc8220_fec_priv *fec2; +#endif +	struct eth_device *dev; +	char *tmp, *end; +	char env_enetaddr[6]; + +#ifdef CONFIG_HAS_ETH1 +	char env_enet1addr[6]; +#endif +	int i; + +	fec = (mpc8220_fec_priv *) malloc (sizeof (*fec)); +	dev = (struct eth_device *) malloc (sizeof (*dev)); +	memset (dev, 0, sizeof *dev); + +	fec->eth = (ethernet_regs *) MMAP_FEC1; +#ifdef CONFIG_HAS_ETH1 +	fec2 = (mpc8220_fec_priv *) malloc (sizeof (*fec)); +	fec2->eth = (ethernet_regs *) MMAP_FEC2; +#endif +	fec->tbdBase = (FEC_TBD *) FEC_BD_BASE; +	fec->rbdBase = +		(FEC_RBD *) (FEC_BD_BASE + FEC_TBD_NUM * sizeof (FEC_TBD)); +	fec->xcv_type = MII100; + +	dev->priv = (void *) fec; +	dev->iobase = MMAP_FEC1; +	dev->init = mpc8220_fec_init; +	dev->halt = mpc8220_fec_halt; +	dev->send = mpc8220_fec_send; +	dev->recv = mpc8220_fec_recv; + +	sprintf (dev->name, "FEC ETHERNET"); +	eth_register (dev); + +#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) +	miiphy_register (dev->name, +			fec8220_miiphy_read, fec8220_miiphy_write); +#endif + +	/* +	 * 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; +		} +		mpc8220_fec_set_hwaddr (fec, env_enetaddr); +	} +#ifdef CONFIG_HAS_ETH1 +	tmp = getenv ("eth1addr"); +	if (tmp) { +		for (i = 0; i < 6; i++) { +			env_enet1addr[i] = +				tmp ? simple_strtoul (tmp, &end, 16) : 0; +			if (tmp) +				tmp = (*end) ? end + 1 : end; +		} +		mpc8220_fec_set_hwaddr (fec2, env_enet1addr); +	} +#endif + +	return 1; +} + +/* MII-interface related functions */ +/********************************************************************/ +int fec8220_miiphy_read (char *devname, u8 phyAddr, u8 regAddr, u16 * retVal) +{ +	ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1; +	u32 reg;		/* convenient holder for the PHY register */ +	u32 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) { +#ifdef DEBUG +		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 = (u16) eth->mii_data; + +	return 0; +} + +/********************************************************************/ +int fec8220_miiphy_write (char *devname, u8 phyAddr, u8 regAddr, u16 data) +{ +	ethernet_regs *eth = (ethernet_regs *) MMAP_FEC1; +	u32 reg;		/* convenient holder for the PHY register */ +	u32 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) { +#ifdef DEBUG +		printf ("Write MDIO failed...\n"); +#endif +		return -1; +	} + +	/* +	 * clear MII interrupt bit +	 */ +	eth->ievent = 0x00800000; + +	return 0; +} + +#ifdef DEBUG +static u32 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_MPC8220_FEC */ diff --git a/arch/powerpc/cpu/mpc8220/fec.h b/arch/powerpc/cpu/mpc8220/fec.h new file mode 100644 index 000000000..a8927fcdb --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/fec.h @@ -0,0 +1,283 @@ +/* + * (C) Copyright 2003-2004 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on mpc4200fec.h + * (C) Copyright Motorola, Inc., 2000 + * + * odin ethernet header file + */ + +#ifndef __MPC8220_FEC_H +#define __MPC8220_FEC_H + +#include <common.h> +#include <mpc8220.h> +#include "dma.h" + +typedef struct ethernet_register_set { + +/* [10:2]addr = 00 */ + +/*  Control and status Registers (offset 000-1FF) */ + +	volatile u32 fec_id;		/* MBAR_ETH + 0x000 */ +	volatile u32 ievent;		/* MBAR_ETH + 0x004 */ +	volatile u32 imask;		/* MBAR_ETH + 0x008 */ + +	volatile u32 RES0[1];		/* MBAR_ETH + 0x00C */ +	volatile u32 r_des_active;	/* MBAR_ETH + 0x010 */ +	volatile u32 x_des_active;	/* MBAR_ETH + 0x014 */ +	volatile u32 r_des_active_cl;	/* MBAR_ETH + 0x018 */ +	volatile u32 x_des_active_cl;	/* MBAR_ETH + 0x01C */ +	volatile u32 ivent_set;		/* MBAR_ETH + 0x020 */ +	volatile u32 ecntrl;		/* MBAR_ETH + 0x024 */ + +	volatile u32 RES1[6];		/* MBAR_ETH + 0x028-03C */ +	volatile u32 mii_data;		/* MBAR_ETH + 0x040 */ +	volatile u32 mii_speed;		/* MBAR_ETH + 0x044 */ +	volatile u32 mii_status;	/* MBAR_ETH + 0x048 */ + +	volatile u32 RES2[5];		/* MBAR_ETH + 0x04C-05C */ +	volatile u32 mib_data;		/* MBAR_ETH + 0x060 */ +	volatile u32 mib_control;	/* MBAR_ETH + 0x064 */ + +	volatile u32 RES3[6];		/* MBAR_ETH + 0x068-7C */ +	volatile u32 r_activate;	/* MBAR_ETH + 0x080 */ +	volatile u32 r_cntrl;		/* MBAR_ETH + 0x084 */ +	volatile u32 r_hash;		/* MBAR_ETH + 0x088 */ +	volatile u32 r_data;		/* MBAR_ETH + 0x08C */ +	volatile u32 ar_done;		/* MBAR_ETH + 0x090 */ +	volatile u32 r_test;		/* MBAR_ETH + 0x094 */ +	volatile u32 r_mib;		/* MBAR_ETH + 0x098 */ +	volatile u32 r_da_low;		/* MBAR_ETH + 0x09C */ +	volatile u32 r_da_high;		/* MBAR_ETH + 0x0A0 */ + +	volatile u32 RES4[7];		/* MBAR_ETH + 0x0A4-0BC */ +	volatile u32 x_activate;	/* MBAR_ETH + 0x0C0 */ +	volatile u32 x_cntrl;		/* MBAR_ETH + 0x0C4 */ +	volatile u32 backoff;		/* MBAR_ETH + 0x0C8 */ +	volatile u32 x_data;		/* MBAR_ETH + 0x0CC */ +	volatile u32 x_status;		/* MBAR_ETH + 0x0D0 */ +	volatile u32 x_mib;		/* MBAR_ETH + 0x0D4 */ +	volatile u32 x_test;		/* MBAR_ETH + 0x0D8 */ +	volatile u32 fdxfc_da1;		/* MBAR_ETH + 0x0DC */ +	volatile u32 fdxfc_da2;		/* MBAR_ETH + 0x0E0 */ +	volatile u32 paddr1;		/* MBAR_ETH + 0x0E4 */ +	volatile u32 paddr2;		/* MBAR_ETH + 0x0E8 */ +	volatile u32 op_pause;		/* MBAR_ETH + 0x0EC */ + +	volatile u32 RES5[4];		/* MBAR_ETH + 0x0F0-0FC */ +	volatile u32 instr_reg;		/* MBAR_ETH + 0x100 */ +	volatile u32 context_reg;	/* MBAR_ETH + 0x104 */ +	volatile u32 test_cntrl;	/* MBAR_ETH + 0x108 */ +	volatile u32 acc_reg;		/* MBAR_ETH + 0x10C */ +	volatile u32 ones;		/* MBAR_ETH + 0x110 */ +	volatile u32 zeros;		/* MBAR_ETH + 0x114 */ +	volatile u32 iaddr1;		/* MBAR_ETH + 0x118 */ +	volatile u32 iaddr2;		/* MBAR_ETH + 0x11C */ +	volatile u32 gaddr1;		/* MBAR_ETH + 0x120 */ +	volatile u32 gaddr2;		/* MBAR_ETH + 0x124 */ +	volatile u32 random;		/* MBAR_ETH + 0x128 */ +	volatile u32 rand1;		/* MBAR_ETH + 0x12C */ +	volatile u32 tmp;		/* MBAR_ETH + 0x130 */ + +	volatile u32 RES6[3];		/* MBAR_ETH + 0x134-13C */ +	volatile u32 fifo_id;		/* MBAR_ETH + 0x140 */ +	volatile u32 x_wmrk;		/* MBAR_ETH + 0x144 */ +	volatile u32 fcntrl;		/* MBAR_ETH + 0x148 */ +	volatile u32 r_bound;		/* MBAR_ETH + 0x14C */ +	volatile u32 r_fstart;		/* MBAR_ETH + 0x150 */ +	volatile u32 r_count;		/* MBAR_ETH + 0x154 */ +	volatile u32 r_lag;		/* MBAR_ETH + 0x158 */ +	volatile u32 r_read;		/* MBAR_ETH + 0x15C */ +	volatile u32 r_write;		/* MBAR_ETH + 0x160 */ +	volatile u32 x_count;		/* MBAR_ETH + 0x164 */ +	volatile u32 x_lag;		/* MBAR_ETH + 0x168 */ +	volatile u32 x_retry;		/* MBAR_ETH + 0x16C */ +	volatile u32 x_write;		/* MBAR_ETH + 0x170 */ +	volatile u32 x_read;		/* MBAR_ETH + 0x174 */ + +	volatile u32 RES7[2];		/* MBAR_ETH + 0x178-17C */ +	volatile u32 fm_cntrl;		/* MBAR_ETH + 0x180 */ +	volatile u32 rfifo_data;	/* MBAR_ETH + 0x184 */ +	volatile u32 rfifo_status;	/* MBAR_ETH + 0x188 */ +	volatile u32 rfifo_cntrl;	/* MBAR_ETH + 0x18C */ +	volatile u32 rfifo_lrf_ptr;	/* MBAR_ETH + 0x190 */ +	volatile u32 rfifo_lwf_ptr;	/* MBAR_ETH + 0x194 */ +	volatile u32 rfifo_alarm;	/* MBAR_ETH + 0x198 */ +	volatile u32 rfifo_rdptr;	/* MBAR_ETH + 0x19C */ +	volatile u32 rfifo_wrptr;	/* MBAR_ETH + 0x1A0 */ +	volatile u32 tfifo_data;	/* MBAR_ETH + 0x1A4 */ +	volatile u32 tfifo_status;	/* MBAR_ETH + 0x1A8 */ +	volatile u32 tfifo_cntrl;	/* MBAR_ETH + 0x1AC */ +	volatile u32 tfifo_lrf_ptr;	/* MBAR_ETH + 0x1B0 */ +	volatile u32 tfifo_lwf_ptr;	/* MBAR_ETH + 0x1B4 */ +	volatile u32 tfifo_alarm;	/* MBAR_ETH + 0x1B8 */ +	volatile u32 tfifo_rdptr;	/* MBAR_ETH + 0x1BC */ +	volatile u32 tfifo_wrptr;	/* MBAR_ETH + 0x1C0 */ + +	volatile u32 reset_cntrl;	/* MBAR_ETH + 0x1C4 */ +	volatile u32 xmit_fsm;		/* MBAR_ETH + 0x1C8 */ + +	volatile u32 RES8[3];		/* MBAR_ETH + 0x1CC-1D4 */ +	volatile u32 rdes_data0;	/* MBAR_ETH + 0x1D8 */ +	volatile u32 rdes_data1;	/* MBAR_ETH + 0x1DC */ +	volatile u32 r_length;		/* MBAR_ETH + 0x1E0 */ +	volatile u32 x_length;		/* MBAR_ETH + 0x1E4 */ +	volatile u32 x_addr;		/* MBAR_ETH + 0x1E8 */ +	volatile u32 cdes_data;		/* MBAR_ETH + 0x1EC */ +	volatile u32 status;		/* MBAR_ETH + 0x1F0 */ +	volatile u32 dma_control;	/* MBAR_ETH + 0x1F4 */ +	volatile u32 des_cmnd;		/* MBAR_ETH + 0x1F8 */ +	volatile u32 data;		/* MBAR_ETH + 0x1FC */ + +	/*  MIB COUNTERS (Offset 200-2FF) */ + +	volatile u32 rmon_t_drop;	/* MBAR_ETH + 0x200 */ +	volatile u32 rmon_t_packets;	/* MBAR_ETH + 0x204 */ +	volatile u32 rmon_t_bc_pkt;	/* MBAR_ETH + 0x208 */ +	volatile u32 rmon_t_mc_pkt;	/* MBAR_ETH + 0x20C */ +	volatile u32 rmon_t_crc_align;	/* MBAR_ETH + 0x210 */ +	volatile u32 rmon_t_undersize;	/* MBAR_ETH + 0x214 */ +	volatile u32 rmon_t_oversize;	/* MBAR_ETH + 0x218 */ +	volatile u32 rmon_t_frag;	/* MBAR_ETH + 0x21C */ +	volatile u32 rmon_t_jab;	/* MBAR_ETH + 0x220 */ +	volatile u32 rmon_t_col;	/* MBAR_ETH + 0x224 */ +	volatile u32 rmon_t_p64;	/* MBAR_ETH + 0x228 */ +	volatile u32 rmon_t_p65to127;	/* MBAR_ETH + 0x22C */ +	volatile u32 rmon_t_p128to255;	/* MBAR_ETH + 0x230 */ +	volatile u32 rmon_t_p256to511;	/* MBAR_ETH + 0x234 */ +	volatile u32 rmon_t_p512to1023;	/* MBAR_ETH + 0x238 */ +	volatile u32 rmon_t_p1024to2047;/* MBAR_ETH + 0x23C */ +	volatile u32 rmon_t_p_gte2048;	/* MBAR_ETH + 0x240 */ +	volatile u32 rmon_t_octets;	/* MBAR_ETH + 0x244 */ +	volatile u32 ieee_t_drop;	/* MBAR_ETH + 0x248 */ +	volatile u32 ieee_t_frame_ok;	/* MBAR_ETH + 0x24C */ +	volatile u32 ieee_t_1col;	/* MBAR_ETH + 0x250 */ +	volatile u32 ieee_t_mcol;	/* MBAR_ETH + 0x254 */ +	volatile u32 ieee_t_def;	/* MBAR_ETH + 0x258 */ +	volatile u32 ieee_t_lcol;	/* MBAR_ETH + 0x25C */ +	volatile u32 ieee_t_excol;	/* MBAR_ETH + 0x260 */ +	volatile u32 ieee_t_macerr;	/* MBAR_ETH + 0x264 */ +	volatile u32 ieee_t_cserr;	/* MBAR_ETH + 0x268 */ +	volatile u32 ieee_t_sqe;	/* MBAR_ETH + 0x26C */ +	volatile u32 t_fdxfc;		/* MBAR_ETH + 0x270 */ +	volatile u32 ieee_t_octets_ok;	/* MBAR_ETH + 0x274 */ + +	volatile u32 RES9[2];		/* MBAR_ETH + 0x278-27C */ +	volatile u32 rmon_r_drop;	/* MBAR_ETH + 0x280 */ +	volatile u32 rmon_r_packets;	/* MBAR_ETH + 0x284 */ +	volatile u32 rmon_r_bc_pkt;	/* MBAR_ETH + 0x288 */ +	volatile u32 rmon_r_mc_pkt;	/* MBAR_ETH + 0x28C */ +	volatile u32 rmon_r_crc_align;	/* MBAR_ETH + 0x290 */ +	volatile u32 rmon_r_undersize;	/* MBAR_ETH + 0x294 */ +	volatile u32 rmon_r_oversize;	/* MBAR_ETH + 0x298 */ +	volatile u32 rmon_r_frag;	/* MBAR_ETH + 0x29C */ +	volatile u32 rmon_r_jab;	/* MBAR_ETH + 0x2A0 */ + +	volatile u32 rmon_r_resvd_0;	/* MBAR_ETH + 0x2A4 */ + +	volatile u32 rmon_r_p64;	/* MBAR_ETH + 0x2A8 */ +	volatile u32 rmon_r_p65to127;	/* MBAR_ETH + 0x2AC */ +	volatile u32 rmon_r_p128to255;	/* MBAR_ETH + 0x2B0 */ +	volatile u32 rmon_r_p256to511;	/* MBAR_ETH + 0x2B4 */ +	volatile u32 rmon_r_p512to1023;	/* MBAR_ETH + 0x2B8 */ +	volatile u32 rmon_r_p1024to2047;/* MBAR_ETH + 0x2BC */ +	volatile u32 rmon_r_p_gte2048;	/* MBAR_ETH + 0x2C0 */ +	volatile u32 rmon_r_octets;	/* MBAR_ETH + 0x2C4 */ +	volatile u32 ieee_r_drop;	/* MBAR_ETH + 0x2C8 */ +	volatile u32 ieee_r_frame_ok;	/* MBAR_ETH + 0x2CC */ +	volatile u32 ieee_r_crc;	/* MBAR_ETH + 0x2D0 */ +	volatile u32 ieee_r_align;	/* MBAR_ETH + 0x2D4 */ +	volatile u32 r_macerr;		/* MBAR_ETH + 0x2D8 */ +	volatile u32 r_fdxfc;		/* MBAR_ETH + 0x2DC */ +	volatile u32 ieee_r_octets_ok;	/* MBAR_ETH + 0x2E0 */ + +	volatile u32 RES10[6];		/* MBAR_ETH + 0x2E4-2FC */ + +	volatile u32 RES11[64];		/* MBAR_ETH + 0x300-3FF */ +} ethernet_regs; + +/* Receive & Transmit Buffer Descriptor definitions */ +typedef struct BufferDescriptor { +	u16 status; +	u16 dataLength; +	u32 dataPointer; +} FEC_RBD; + +typedef struct { +	u16 status; +	u16 dataLength; +	u32 dataPointer; +} FEC_TBD; + +/* private structure */ +typedef enum { +	SEVENWIRE,		/* 7-wire       */ +	MII10,			/* MII 10Mbps   */ +	MII100			/* MII 100Mbps  */ +} xceiver_type; + +typedef struct { +	ethernet_regs *eth; +	xceiver_type xcv_type;	/* transceiver type */ +	FEC_RBD *rbdBase;	/* RBD ring */ +	FEC_TBD *tbdBase;	/* TBD ring */ +	u16 rbdIndex;		/* next receive BD to read */ +	u16 tbdIndex;		/* next transmit BD to send */ +	u16 usedTbdIndex;	/* next transmit BD to clean */ +	u16 cleanTbdNum;	/* the number of available transmit BDs */ +} mpc8220_fec_priv; + +/* Ethernet parameter area */ +#define FEC_TBD_BASE	    (FEC_PARAM_BASE + 0x00) +#define FEC_TBD_NEXT	    (FEC_PARAM_BASE + 0x04) +#define FEC_RBD_BASE	    (FEC_PARAM_BASE + 0x08) +#define FEC_RBD_NEXT	    (FEC_PARAM_BASE + 0x0c) + +/* 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 + +/* RBD bits definitions */ +#define FEC_RBD_EMPTY	0x8000	/* Buffer is empty */ +#define FEC_RBD_WRAP	0x2000	/* Last BD in ring */ +#define FEC_RBD_INT	0x1000	/* Interrupt */ +#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_INT	0x1000	/* Interrupt */ +#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 /* __MPC8220_FEC_H */ diff --git a/arch/powerpc/cpu/mpc8220/fec_dma_tasks.S b/arch/powerpc/cpu/mpc8220/fec_dma_tasks.S new file mode 100644 index 000000000..3f8a03bf1 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/fec_dma_tasks.S @@ -0,0 +1,363 @@ +/* + * Copyright (C) 2004, Freescale Semiconductor, Inc. + * + * This file contains microcode for the FEC controller of the MPC8220. + */ + +#include <config.h> + +#if defined(CONFIG_MPC8220) + +/* sas/sccg, gas target */ +.section        smartdmaInitData,"aw",@progbits	/* Initialized data for task variables */ +.section        smartdmaTaskTable,"aw",@progbits	/* Task tables */ +.align  9 +.globl taskTable +taskTable: +.globl scEthernetRecv_Entry +scEthernetRecv_Entry:		/* Task 0 */ +.long   scEthernetRecv_TDT - taskTable	/* Task 0 Descriptor Table */ +.long   scEthernetRecv_TDT - taskTable + 0x00000094 +.long   scEthernetRecv_VarTab - taskTable	/* Task 0 Variable Table */ +.long   scEthernetRecv_FDT - taskTable + 0x03	/* Task 0 Function Descriptor Table & Flags */ +.long   0x00000000 +.long   0x00000000 +.long   scEthernetRecv_CSave - taskTable	/* Task 0 context save space */ +.long   0xf0000000 +.globl scEthernetXmit_Entry +scEthernetXmit_Entry:		/* Task 1 */ +.long   scEthernetXmit_TDT - taskTable	/* Task 1 Descriptor Table */ +.long   scEthernetXmit_TDT - taskTable + 0x000000e0 +.long   scEthernetXmit_VarTab - taskTable	/* Task 1 Variable Table */ +.long   scEthernetXmit_FDT - taskTable + 0x03	/* Task 1 Function Descriptor Table & Flags */ +.long   0x00000000 +.long   0x00000000 +.long   scEthernetXmit_CSave - taskTable	/* Task 1 context save space */ +.long   0xf0000000 + + +.globl scEthernetRecv_TDT +scEthernetRecv_TDT:	/* Task 0 Descriptor Table */ +.long   0xc4c50000	/* 0000(153):  LCDEXT: idx0 = var9 + var10; idx0 once var0; idx0 += inc0 */ +.long   0x84c5e000	/* 0004(153):  LCD: idx1 = var9 + var11; ; idx1 += inc0 */ +.long   0x10001f08	/* 0008(156):    DRD1A: var7 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x10000380	/* 000C(157):    DRD1A: var0 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x00000f88	/* 0010(158):    DRD1A: var3 = *idx1; FN=0 init=0 WS=0 RS=0 */ +.long   0x81980000	/* 0014(162):  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */ +.long   0x10000780	/* 0018(164):    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x60000000	/* 001C(165):    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long   0x010cf04c	/* 0020(165):    DRD2B1: var4 = EU3(); EU3(var1,var12)  */ +.long   0x82180349	/* 0024(169):  LCD: idx0 = var4; idx0 != var13; idx0 += inc1 */ +.long   0x81c68004	/* 0028(172):    LCD: idx1 = var3 + var13 + 4; idx1 once var0; idx1 += inc0 */ +.long   0x70000000	/* 002C(174):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long   0x018cf04e	/* 0030(174):      DRD2B1: var6 = EU3(); EU3(var1,var14)  */ +.long   0x70000000	/* 0034(175):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long   0x020cf04f	/* 0038(175):      DRD2B1: var8 = EU3(); EU3(var1,var15)  */ +.long   0x00000b88	/* 003C(176):      DRD1A: var2 = *idx1; FN=0 init=0 WS=0 RS=0 */ +.long   0x80025184	/* 0040(205):    LCDEXT: idx1 = 0xf0009184; ; */ +.long   0x86810412	/* 0044(205):    LCD: idx2 = var13, idx3 = var2; idx2 < var16; idx2 += inc2, idx3 += inc2 */ +.long   0x0200cf88	/* 0048(209):      DRD1A: *idx3 = *idx1; FN=0 init=16 WS=0 RS=0 */ +.long   0x80025184	/* 004C(217):    LCDEXT: idx1 = 0xf0009184; ; */ +.long   0x8681845b	/* 0050(217):    LCD: idx2 = var13, idx3 = var3; idx2 < var17; idx2 += inc3, idx3 += inc3 */ +.long   0x0000cf88	/* 0054(221):      DRD1A: *idx3 = *idx1; FN=0 init=0 WS=0 RS=0 */ +.long   0xc31883a4	/* 0058(225):    LCDEXT: idx1 = var6; idx1 == var14; idx1 += inc4 */ +.long   0x80190000	/* 005C(225):    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */ +.long   0x04008468	/* 0060(227):      DRD1A: idx1 = var13; FN=0 INT init=0 WS=0 RS=0 */ +.long   0xc4038360	/* 0064(232):    LCDEXT: idx1 = var8, idx2 = var7; idx1 == var13; idx1 += inc4, idx2 += inc0 */ +.long   0x81c50000	/* 0068(233):    LCD: idx3 = var3 + var10; idx3 once var0; idx3 += inc0 */ +.long   0x1000cb18	/* 006C(235):      DRD1A: *idx2 = idx3; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x00000f18	/* 0070(236):      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */ +.long   0xc418836d	/* 0074(238):    LCDEXT: idx1 = var8; idx1 > var13; idx1 += inc5 */ +.long   0x83990000	/* 0078(238):    LCD: idx2 = var7; idx2 once var0; idx2 += inc0 */ +.long   0x10000c00	/* 007C(240):      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x0000c800	/* 0080(241):      DRD1A: *idx2 = var0; FN=0 init=0 WS=0 RS=0 */ +.long   0x81988000	/* 0084(245):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ +.long   0x10000788	/* 0088(247):      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x60000000	/* 008C(248):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long   0x080cf04c	/* 0090(248):      DRD2B1: idx0 = EU3(); EU3(var1,var12)  */ +.long   0x000001f8	/* 0094(:0):    NOP */ + + +.globl scEthernetXmit_TDT +scEthernetXmit_TDT:	/* Task 1 Descriptor Table */ +.long   0x80095b00	/* 0000(280):  LCDEXT: idx0 = 0xf0025b00; ; */ +.long   0x85c60004	/* 0004(280):  LCD: idx1 = var11 + var12 + 4; idx1 once var0; idx1 += inc0 */ +.long   0x10002308	/* 0008(283):    DRD1A: var8 = idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x10000f88	/* 000C(284):    DRD1A: var3 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x00000380	/* 0010(285):    DRD1A: var0 = *idx0; FN=0 init=0 WS=0 RS=0 */ +.long   0x81980000	/* 0014(288):  LCD: idx0 = var3; idx0 once var0; idx0 += inc0 */ +.long   0x10000780	/* 0018(290):    DRD1A: var1 = *idx0; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x60000000	/* 001C(291):    DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long   0x024cf04d	/* 0020(291):    DRD2B1: var9 = EU3(); EU3(var1,var13)  */ +.long   0x84980309	/* 0024(294):  LCD: idx0 = var9; idx0 != var12; idx0 += inc1 */ +.long   0xc0004003	/* 0028(297):    LCDEXT: idx1 = 0x00000003; ; */ +.long   0x81c60004	/* 002C(297):    LCD: idx2 = var3 + var12 + 4; idx2 once var0; idx2 += inc0 */ +.long   0x70000000	/* 0030(299):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long   0x010cf04e	/* 0034(299):      DRD2B1: var4 = EU3(); EU3(var1,var14)  */ +.long   0x70000000	/* 0038(300):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long   0x014cf04f	/* 003C(300):      DRD2B1: var5 = EU3(); EU3(var1,var15)  */ +.long   0x70000000	/* 0040(301):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long   0x028cf050	/* 0044(301):      DRD2B1: var10 = EU3(); EU3(var1,var16)  */ +.long   0x70000000	/* 0048(302):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT MORE init=0 WS=0 RS=0 */ +.long   0x018cf051	/* 004C(302):      DRD2B1: var6 = EU3(); EU3(var1,var17)  */ +.long   0x10000b90	/* 0050(303):      DRD1A: var2 = *idx2; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x60000000	/* 0054(304):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long   0x01ccf0a1	/* 0058(304):      DRD2B1: var7 = EU3(); EU3(var2,idx1)  */ +.long   0xc2988312	/* 005C(308):    LCDEXT: idx1 = var5; idx1 > var12; idx1 += inc2 */ +.long   0x83490000	/* 0060(308):    LCD: idx2 = var6 + var18; idx2 once var0; idx2 += inc0 */ +.long   0x00001b10	/* 0064(310):      DRD1A: var6 = idx2; FN=0 init=0 WS=0 RS=0 */ +.long   0x800251a4	/* 0068(315):    LCDEXT: idx1 = 0xf00091a4; ; */ +.long   0xc30104dc	/* 006C(315):    LCDEXT: idx2 = var6, idx3 = var2; idx2 >= var19; idx2 += inc3, idx3 += inc4 */ +.long   0x839a032d	/* 0070(316):    LCD: idx4 = var7; idx4 == var12; idx4 += inc5 */ +.long   0x0220c798	/* 0074(321):      DRD1A: *idx1 = *idx3; FN=0 init=17 WS=0 RS=0 */ +.long   0x800251a4	/* 0078(329):    LCDEXT: idx1 = 0xf00091a4; ; */ +.long   0x99198337	/* 007C(329):    LCD: idx2 = idx2, idx3 = idx3; idx2 > var12; idx2 += inc6, idx3 += inc7 */ +.long   0x022ac798	/* 0080(333):      DRD1A: *idx1 = *idx3; FN=0 init=17 WS=1 RS=1 */ +.long   0x800251a4	/* 0084(350):    LCDEXT: idx1 = 0xf00091a4; ; */ +.long   0xc1430000	/* 0088(350):    LCDEXT: idx2 = var2 + var6; idx2 once var0; idx2 += inc0 */ +.long   0x82998312	/* 008C(351):    LCD: idx3 = var5; idx3 > var12; idx3 += inc2 */ +.long   0x0a2ac790	/* 0090(354):      DRD1A: *idx1 = *idx2; FN=0 TFD init=17 WS=1 RS=1 */ +.long   0x81988000	/* 0094(359):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ +.long   0x60000002	/* 0098(361):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=0 RS=0 */ +.long   0x0c4cfc4d	/* 009C(361):      DRD2B1: *idx1 = EU3(); EU3(*idx1,var13)  */ +.long   0xc21883ad	/* 00A0(365):    LCDEXT: idx1 = var4; idx1 == var14; idx1 += inc5 */ +.long   0x80190000	/* 00A4(365):    LCD: idx2 = var0; idx2 once var0; idx2 += inc0 */ +.long   0x04008460	/* 00A8(367):      DRD1A: idx1 = var12; FN=0 INT init=0 WS=0 RS=0 */ +.long   0xc4052305	/* 00AC(371):    LCDEXT: idx1 = var8, idx2 = var10; idx2 == var12; idx1 += inc0, idx2 += inc5 */ +.long   0x81ca0000	/* 00B0(372):    LCD: idx3 = var3 + var20; idx3 once var0; idx3 += inc0 */ +.long   0x1000c718	/* 00B4(374):      DRD1A: *idx1 = idx3; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x00000f18	/* 00B8(375):      DRD1A: var3 = idx3; FN=0 init=0 WS=0 RS=0 */ +.long   0xc4188000	/* 00BC(378):    LCDEXT: idx1 = var8; idx1 once var0; idx1 += inc0 */ +.long   0x85190312	/* 00C0(378):    LCD: idx2 = var10; idx2 > var12; idx2 += inc2 */ +.long   0x10000c00	/* 00C4(380):      DRD1A: var3 = var0; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x1000c400	/* 00C8(381):      DRD1A: *idx1 = var0; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x00008860	/* 00CC(382):      DRD1A: idx2 = var12; FN=0 init=0 WS=0 RS=0 */ +.long   0x81988000	/* 00D0(386):    LCD: idx1 = var3; idx1 once var0; idx1 += inc0 */ +.long   0x10000788	/* 00D4(388):      DRD1A: var1 = *idx1; FN=0 MORE init=0 WS=0 RS=0 */ +.long   0x60000000	/* 00D8(389):      DRD2A: EU0=0 EU1=0 EU2=0 EU3=0 EXT init=0 WS=0 RS=0 */ +.long   0x080cf04d	/* 00DC(389):      DRD2B1: idx0 = EU3(); EU3(var1,var13)  */ +.long   0x000001f8	/* 00E0(:0):    NOP */ + +.align 8 + +.globl scEthernetRecv_VarTab +scEthernetRecv_VarTab:	/* Task 0 Variable Table */ +.long   0x00000000	/* var[0] */ +.long   0x00000000	/* var[1] */ +.long   0x00000000	/* var[2] */ +.long   0x00000000	/* var[3] */ +.long   0x00000000	/* var[4] */ +.long   0x00000000	/* var[5] */ +.long   0x00000000	/* var[6] */ +.long   0x00000000	/* var[7] */ +.long   0x00000000	/* var[8] */ +.long   0xf0025b00	/* var[9] */ +.long   0x00000008	/* var[10] */ +.long   0x0000000c	/* var[11] */ +.long   0x80000000	/* var[12] */ +.long   0x00000000	/* var[13] */ +.long   0x10000000	/* var[14] */ +.long   0x20000000	/* var[15] */ +.long   0x00000800	/* var[16] */ +.long   0x00000001	/* var[17] */ +.long   0x00000000	/* var[18] */ +.long   0x00000000	/* var[19] */ +.long   0x00000000	/* var[20] */ +.long   0x00000000	/* var[21] */ +.long   0x00000000	/* var[22] */ +.long   0x00000000	/* var[23] */ +.long   0x00000000	/* inc[0] */ +.long   0x60000000	/* inc[1] */ +.long   0x20000004	/* inc[2] */ +.long   0x20000001	/* inc[3] */ +.long   0x80000000	/* inc[4] */ +.long   0x40000000	/* inc[5] */ +.long   0x00000000	/* inc[6] */ +.long   0x00000000	/* inc[7] */ + +.align  8 + +.globl scEthernetXmit_VarTab +scEthernetXmit_VarTab:	/* Task 1 Variable Table */ +.long   0x00000000	/* var[0] */ +.long   0x00000000	/* var[1] */ +.long   0x00000000	/* var[2] */ +.long   0x00000000	/* var[3] */ +.long   0x00000000	/* var[4] */ +.long   0x00000000	/* var[5] */ +.long   0x00000000	/* var[6] */ +.long   0x00000000	/* var[7] */ +.long   0x00000000	/* var[8] */ +.long   0x00000000	/* var[9] */ +.long   0x00000000	/* var[10] */ +.long   0xf0025b00	/* var[11] */ +.long   0x00000000	/* var[12] */ +.long   0x80000000	/* var[13] */ +.long   0x10000000	/* var[14] */ +.long   0x08000000	/* var[15] */ +.long   0x20000000	/* var[16] */ +.long   0x0000ffff	/* var[17] */ +.long   0xffffffff	/* var[18] */ +.long   0x00000004	/* var[19] */ +.long   0x00000008	/* var[20] */ +.long   0x00000000	/* var[21] */ +.long   0x00000000	/* var[22] */ +.long   0x00000000	/* var[23] */ +.long   0x00000000	/* inc[0] */ +.long   0x60000000	/* inc[1] */ +.long   0x40000000	/* inc[2] */ +.long   0xc000fffc	/* inc[3] */ +.long   0xe0000004	/* inc[4] */ +.long   0x80000000	/* inc[5] */ +.long   0x4000ffff	/* inc[6] */ +.long   0xe0000001	/* inc[7] */ + +.align 8 + +.globl scEthernetRecv_FDT +scEthernetRecv_FDT:	/* Task 0 Function Descriptor Table */ +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x21800000	/* and(), EU# 3 */ +.long   0x21e00000	/* or(), EU# 3 */ +.long   0x21400000	/* andn(), EU# 3 */ +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 + +.align 8 + +.globl scEthernetXmit_FDT +scEthernetXmit_FDT:	/* Task 1 Function Descriptor Table */ +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x21800000	/* and(), EU# 3 */ +.long   0x21e00000	/* or(), EU# 3 */ +.long   0x21400000	/* andn(), EU# 3 */ +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 +.long   0x00000000 + + +.globl scEthernetRecv_CSave +scEthernetRecv_CSave:	/* Task 0 context save space */ +.space  128, 0x0 + + +.globl scEthernetXmit_CSave +scEthernetXmit_CSave:	/* Task 1 context save space */ +.space  128, 0x0 + +#endif diff --git a/arch/powerpc/cpu/mpc8220/i2c.c b/arch/powerpc/cpu/mpc8220/i2c.c new file mode 100644 index 000000000..76ecdf11e --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/i2c.c @@ -0,0 +1,390 @@ +/* + * (C) Copyright 2004, Freescale, Inc + * TsiChung Liew, Tsi-Chung.Liew@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 + */ + +#include <common.h> + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_HARD_I2C + +#include <mpc8220.h> +#include <i2c.h> + +typedef struct mpc8220_i2c { +	volatile u32 adr;	/* I2Cn + 0x00 */ +	volatile u32 fdr;	/* I2Cn + 0x04 */ +	volatile u32 cr;	/* I2Cn + 0x08 */ +	volatile u32 sr;	/* I2Cn + 0x0C */ +	volatile u32 dr;	/* I2Cn + 0x10 */ +} i2c_t; + +/* I2Cn control register bits */ +#define I2C_EN      0x80 +#define I2C_IEN     0x40 +#define I2C_STA     0x20 +#define I2C_TX      0x10 +#define I2C_TXAK    0x08 +#define I2C_RSTA    0x04 +#define I2C_INIT_MASK   (I2C_EN | I2C_STA | I2C_TX | I2C_RSTA) + +/* I2Cn status register bits */ +#define I2C_CF      0x80 +#define I2C_AAS     0x40 +#define I2C_BB      0x20 +#define I2C_AL      0x10 +#define I2C_SRW     0x04 +#define I2C_IF      0x02 +#define I2C_RXAK    0x01 + +#define I2C_TIMEOUT 100 +#define I2C_RETRIES 1 + +struct mpc8220_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; +	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) +{ +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	int timeout = I2C_TIMEOUT; +	int status; + +	status = mpc_reg_in (®s->sr); + +	while (timeout-- && (status & I2C_BB)) { +#if 1 +		volatile int temp; + +		mpc_reg_out (®s->cr, I2C_STA, I2C_STA); +		temp = mpc_reg_in (®s->dr); +		mpc_reg_out (®s->cr, 0, I2C_STA); +		mpc_reg_out (®s->cr, 0, 0); +		mpc_reg_out (®s->cr, I2C_EN, 0); +#endif +		udelay (1000); +		status = mpc_reg_in (®s->sr); +	} + +	return (status & I2C_BB); +} + +static int wait_for_pin (int *status) +{ +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	int timeout = I2C_TIMEOUT; + +	*status = mpc_reg_in (®s->sr); + +	while (timeout-- && !(*status & I2C_IF)) { +		udelay (1000); +		*status = mpc_reg_in (®s->sr); +	} + +	if (!(*status & I2C_IF)) { +		return -1; +	} + +	mpc_reg_out (®s->sr, 0, I2C_IF); +	return 0; +} + +static int do_address (uchar chip, char rdwr_flag) +{ +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	int status; + +	chip <<= 1; + +	if (rdwr_flag) +		chip |= 1; + +	mpc_reg_out (®s->cr, I2C_TX, I2C_TX); +	mpc_reg_out (®s->dr, 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) +{ +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	int wrcount; +	int status; + +	for (wrcount = 0; wrcount < len; ++wrcount) { + +		mpc_reg_out (®s->dr, buf[wrcount], 0); + +		if (wait_for_pin (&status)) +			break; + +		if (status & I2C_RXAK) +			break; + +	} + +	return !(wrcount == len); +	return 0; +} + +static int receive_bytes (uchar chip, char *buf, int len) +{ +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	int dummy = 1; +	int rdcount = 0; +	int status; +	int i; + +	mpc_reg_out (®s->cr, 0, I2C_TX); + +	for (i = 0; i < len; ++i) { +		buf[rdcount] = mpc_reg_in (®s->dr); + +		if (dummy) +			dummy = 0; +		else +			rdcount++; + +		if (wait_for_pin (&status)) +			return -4; +	} + +	mpc_reg_out (®s->cr, I2C_TXAK, I2C_TXAK); +	buf[rdcount++] = mpc_reg_in (®s->dr); + +	if (wait_for_pin (&status)) +		return -5; + +	mpc_reg_out (®s->cr, 0, I2C_TXAK); +	return 0; +} + +/**************** I2C API ****************/ + +void i2c_init (int speed, int saddr) +{ +	i2c_t *regs = (i2c_t *) MMAP_I2C; + +	mpc_reg_out (®s->cr, 0, 0); +	mpc_reg_out (®s->adr, saddr << 1, 0); + +	/* Set clock +	 */ +	mpc_reg_out (®s->fdr, mpc_get_fdr (speed), 0); + +	/* Enable module +	 */ +	mpc_reg_out (®s->cr, I2C_EN, I2C_INIT_MASK); +	mpc_reg_out (®s->sr, 0, I2C_IF); +	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 mpc8220_i2c_tap scltap[] = { +			{4, 1}, +			{4, 2}, +			{6, 4}, +			{6, 8}, +			{14, 16}, +			{30, 32}, +			{62, 64}, +			{126, 128} +		}; + +		ipb = gd->bus_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 { +			printf ("%ld kHz, ", best_speed / 1000); +			return divider; +		} +	} + +	return fdr; +} + +int i2c_probe (uchar chip) +{ +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	int i; + +	for (i = 0; i < I2C_RETRIES; i++) { +		mpc_reg_out (®s->cr, I2C_STA, I2C_STA); + +		if (!do_address (chip, 0)) { +			mpc_reg_out (®s->cr, 0, I2C_STA); +			break; +		} + +		mpc_reg_out (®s->cr, 0, I2C_STA); +		udelay (50); +	} + +	return (i == I2C_RETRIES); +} + +int i2c_read (uchar chip, uint addr, int alen, uchar * buf, int len) +{ +	uchar xaddr[4]; +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	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->cr, I2C_STA, I2C_STA); +	if (do_address (chip, 0)) { +		printf ("i2c_read: failed to address chip\n"); +		goto Done; +	} + +	if (send_bytes (chip, (char *)&xaddr[4 - alen], alen)) { +		printf ("i2c_read: send_bytes failed\n"); +		goto Done; +	} + +	mpc_reg_out (®s->cr, 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->cr, 0, I2C_STA); +	return ret; +} + +int i2c_write (uchar chip, uint addr, int alen, uchar * buf, int len) +{ +	uchar xaddr[4]; +	i2c_t *regs = (i2c_t *) MMAP_I2C; +	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->cr, I2C_STA, I2C_STA); +	if (do_address (chip, 0)) { +		printf ("i2c_write: failed to address chip\n"); +		goto Done; +	} + +	if (send_bytes (chip, (char *)&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->cr, 0, I2C_STA); +	return ret; +} + +#endif /* CONFIG_HARD_I2C */ diff --git a/arch/powerpc/cpu/mpc8220/i2cCore.c b/arch/powerpc/cpu/mpc8220/i2cCore.c new file mode 100644 index 000000000..b89ad034f --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/i2cCore.c @@ -0,0 +1,627 @@ +/* I2cCore.c - MPC8220 PPC I2C Library */ + +/* Copyright 2004      Freescale Semiconductor, Inc. */ + +/* +modification history +-------------------- +01c,29jun04,tcl	 1.3	removed CR. Added two bytes offset support. +01b,19jan04,tcl	 1.2	removed i2cMsDelay and sysDecGet. renamed i2cMsDelay +			back to sysMsDelay +01a,19jan04,tcl	 1.1	created and seperated from i2c.c +*/ + +/* +DESCRIPTION +This file contain I2C low level handling library functions +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <vxWorks.h> +#include <sysLib.h> +#include <iosLib.h> +#include <logLib.h> +#include <tickLib.h> + +/* BSP Includes */ +#include "config.h" +#include "mpc8220.h" +#include "i2cCore.h" + +#ifdef DEBUG_I2CCORE +int I2CCDbg = 0; +#endif + +#define ABS(x)	((x < 0)? -x : x) + +char *I2CERR[16] = { +	"Transfer in Progress\n",	/* 0 */ +	"Transfer complete\n", +	"Not Addressed\n",		/* 2 */ +	"Addressed as a slave\n", +	"Bus is Idle\n",		/* 4 */ +	"Bus is busy\n", +	"Arbitration Lost\n",		/* 6 */ +	"Arbitration on Track\n", +	"Slave receive, master writing to slave\n",	/* 8 */ +	"Slave transmit, master reading from slave\n", +	"Interrupt is pending\n",	/* 10 */ +	"Interrupt complete\n", +	"Acknowledge received\n",	/* 12 */ +	"No acknowledge received\n", +	"Unknown status\n",		/* 14 */ +	"\n" +}; + +/****************************************************************************** + * + * chk_status - Check I2C status bit + * + * RETURNS: OK, or ERROR if the bit encounter + * + */ + +STATUS chk_status (PSI2C pi2c, UINT8 sta_bit, UINT8 truefalse) +{ +	int i, status = 0; + +	for (i = 0; i < I2C_POLL_COUNT; i++) { +		if ((pi2c->sr & sta_bit) == (truefalse ? sta_bit : 0)) +			return (OK); +	} + +	I2CCDBG (L2, ("--- sr %x stabit %x truefalse %d\n", +		      pi2c->sr, sta_bit, truefalse, 0, 0, 0)); + +	if (i == I2C_POLL_COUNT) { +		switch (sta_bit) { +		case I2C_STA_CF: +			status = 0; +			break; +		case I2C_STA_AAS: +			status = 2; +			break; +		case I2C_STA_BB: +			status = 4; +			break; +		case I2C_STA_AL: +			status = 6; +			break; +		case I2C_STA_SRW: +			status = 8; +			break; +		case I2C_STA_IF: +			status = 10; +			break; +		case I2C_STA_RXAK: +			status = 12; +			break; +		default: +			status = 14; +			break; +		} + +		if (!truefalse) +			status++; + +		I2CCDBG (NO, ("--- status %d\n", status, 0, 0, 0, 0, 0)); +		I2CCDBG (NO, (I2CERR[status], 0, 0, 0, 0, 0, 0)); +	} + +	return (ERROR); +} + +/****************************************************************************** + * + * I2C Enable - Enable the I2C Controller + * + */ +STATUS i2c_enable (SI2C * pi2c, PI2CSET pi2cSet) +{ +	int fdr = pi2cSet->bit_rate; +	UINT8 adr = pi2cSet->i2c_adr; + +	I2CCDBG (L2, ("i2c_enable fdr %d adr %x\n", fdr, adr, 0, 0, 0, 0)); + +	i2c_clear (pi2c);	/* Clear FDR, ADR, SR and CR reg */ + +	SetI2cFDR (pi2c, fdr);	/* Frequency			*/ +	pi2c->adr = adr; + +	pi2c->cr = I2C_CTL_EN;	/* Set Enable			*/ + +	/* +	   The I2C bus should be in Idle state. If the bus is busy, +	   clear the STA bit in control register +	 */ +	if (chk_status (pi2c, I2C_STA_BB, 0) != OK) { +		if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA) +			pi2c->cr &= ~I2C_CTL_STA; + +		/* Check again if it is still busy, return error if found */ +		if (chk_status (pi2c, I2C_STA_BB, 1) == OK) +			return ERROR; +	} + +	return (OK); +} + +/****************************************************************************** + * + * I2C Disable - Disable the I2C Controller + * + */ +STATUS i2c_disable (PSI2C pi2c) +{ +	i2c_clear (pi2c); + +	pi2c->cr &= I2C_CTL_EN; /* Disable I2c			*/ + +	if ((pi2c->cr & I2C_CTL_STA) == I2C_CTL_STA) +		pi2c->cr &= ~I2C_CTL_STA; + +	if (chk_status (pi2c, I2C_STA_BB, 0) != OK) +		return ERROR; + +	return (OK); +} + +/****************************************************************************** + * + * I2C Clear - Clear the I2C Controller + * + */ +STATUS i2c_clear (PSI2C pi2c) +{ +	pi2c->adr = 0; +	pi2c->fdr = 0; +	pi2c->cr = 0; +	pi2c->sr = 0; + +	return (OK); +} + + +STATUS i2c_start (PSI2C pi2c, PI2CSET pi2cSet) +{ +#ifdef TWOBYTES +	UINT16 ByteOffset = pi2cSet->str_adr; +#else +	UINT8 ByteOffset = pi2cSet->str_adr; +#endif +#if 1 +	UINT8 tmp = 0; +#endif +	UINT8 Addr = pi2cSet->slv_adr; + +	pi2c->cr |= I2C_CTL_STA;	/* Generate start signal	*/ + +	if (chk_status (pi2c, I2C_STA_BB, 1) != OK) +		return ERROR; + +	/* Write slave address */ +	if (i2c_writebyte (pi2c, &Addr) != OK) { +		i2c_stop (pi2c);	/* Disable I2c			*/ +		return ERROR; +	} +#ifdef TWOBYTES +#   if 0 +	/* Issue the offset to start */ +	if (i2c_write2byte (pi2c, &ByteOffset) != OK) { +		i2c_stop (pi2c);	/* Disable I2c			*/ +		return ERROR; +	} +#endif +	tmp = (ByteOffset >> 8) & 0xff; +	if (i2c_writebyte (pi2c, &tmp) != OK) { +		i2c_stop (pi2c);	/* Disable I2c			*/ +		return ERROR; +	} +	tmp = ByteOffset & 0xff; +	if (i2c_writebyte (pi2c, &tmp) != OK) { +		i2c_stop (pi2c);	/* Disable I2c			*/ +		return ERROR; +	} +#else +	if (i2c_writebyte (pi2c, &ByteOffset) != OK) { +		i2c_stop (pi2c);	/* Disable I2c			*/ +		return ERROR; +	} +#endif + +	return (OK); +} + +STATUS i2c_stop (PSI2C pi2c) +{ +	pi2c->cr &= ~I2C_CTL_STA;	/* Generate stop signal		*/ +	if (chk_status (pi2c, I2C_STA_BB, 0) != OK) +		return ERROR; + +	return (OK); +} + +/****************************************************************************** + * + * Read Len bytes to the location pointed to by *Data from the device + * with address Addr. + */ +int i2c_readblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data) +{ +	int i = 0; +	UINT8 Tmp; + +/*    UINT8 ByteOffset = pi2cSet->str_adr; not used? */ +	UINT8 Addr = pi2cSet->slv_adr; +	int Length = pi2cSet->xfer_size; + +	I2CCDBG (L1, ("i2c_readblock addr %x data 0x%08x len %d offset %d\n", +		      Addr, (int) Data, Length, ByteOffset, 0, 0)); + +	if (pi2c->sr & I2C_STA_AL) {	/* Check if Arbitration lost	*/ +		I2CCDBG (FN, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0)); +		pi2c->sr &= ~I2C_STA_AL;	/* Clear Arbitration status bit */ +		return ERROR; +	} + +	pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack	*/ + +	if (i2c_start (pi2c, pi2cSet) == ERROR) +		return ERROR; + +	pi2c->cr |= I2C_CTL_RSTA;	/* Repeat Start */ + +	Tmp = Addr | 1; + +	if (i2c_writebyte (pi2c, &Tmp) != OK) { +		i2c_stop (pi2c);	/* Disable I2c	*/ +		return ERROR; +	} + +	if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01)) +		return ERROR; + +	pi2c->cr &= ~I2C_CTL_TX;	/* Set receive mode	*/ + +	if (((pi2c->sr & 0x07) == 0x07) || (pi2c->sr & 0x01)) +		return ERROR; + +	/* Dummy Read */ +	if (i2c_readbyte (pi2c, &Tmp, &i) != OK) { +		i2c_stop (pi2c);	/* Disable I2c	*/ +		return ERROR; +	} + +	i = 0; +	while (Length) { +		if (Length == 2) +			pi2c->cr |= I2C_CTL_TXAK; + +		if (Length == 1) +			pi2c->cr &= ~I2C_CTL_STA; + +		if (i2c_readbyte (pi2c, Data, &Length) != OK) { +			return i2c_stop (pi2c); +		} +		i++; +		Length--; +		Data++; +	} + +	if (i2c_stop (pi2c) == ERROR) +		return ERROR; + +	return i; +} + +STATUS i2c_writeblock (SI2C * pi2c, PI2CSET pi2cSet, UINT8 * Data) +{ +	int Length = pi2cSet->xfer_size; + +#ifdef TWOBYTES +	UINT16 ByteOffset = pi2cSet->str_adr; +#else +	UINT8 ByteOffset = pi2cSet->str_adr; +#endif +	int j, k; + +	I2CCDBG (L2, ("i2c_writeblock\n", 0, 0, 0, 0, 0, 0)); + +	if (pi2c->sr & I2C_STA_AL) { +		/* Check if arbitration lost */ +		I2CCDBG (L2, ("Arbitration lost\n", 0, 0, 0, 0, 0, 0)); +		pi2c->sr &= ~I2C_STA_AL;	/* Clear the condition	*/ +		return ERROR; +	} + +	pi2c->cr |= I2C_CTL_TX; /* Enable the I2c for TX, Ack	*/ + +	/* Do the not even offset first */ +	if ((ByteOffset % 8) != 0) { +		int remain; + +		if (Length > 8) { +			remain = 8 - (ByteOffset % 8); +			Length -= remain; + +			pi2cSet->str_adr = ByteOffset; + +			if (i2c_start (pi2c, pi2cSet) == ERROR) +				return ERROR; + +			for (j = ByteOffset; j < remain; j++) { +				if (i2c_writebyte (pi2c, Data++) != OK) +					return ERROR; +			} + +			if (i2c_stop (pi2c) == ERROR) +				return ERROR; + +			sysMsDelay (32); + +			/* Update the new ByteOffset */ +			ByteOffset += remain; +		} +	} + +	for (j = ByteOffset, k = 0; j < (Length + ByteOffset); j++) { +		if ((j % 8) == 0) { +			pi2cSet->str_adr = j; +			if (i2c_start (pi2c, pi2cSet) == ERROR) +				return ERROR; +		} + +		k++; + +		if (i2c_writebyte (pi2c, Data++) != OK) +			return ERROR; + +		if ((j == (Length - 1)) || ((k % 8) == 0)) { +			if (i2c_stop (pi2c) == ERROR) +				return ERROR; + +			sysMsDelay (50); +		} + +	} + +	return k; +} + +STATUS i2c_readbyte (SI2C * pi2c, UINT8 * readb, int *index) +{ +	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt Bit	*/ +	*readb = pi2c->dr;		/* Read a byte		*/ + +	/* +	   Set I2C_CTRL_TXAK will cause Transfer pending and +	   set I2C_CTRL_STA will cause Interrupt pending +	 */ +	if (*index != 2) { +		if (chk_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?	*/ +			return ERROR; +	} + +	if (*index != 1) { +		if (chk_status (pi2c, I2C_STA_IF, 1) != OK) +			return ERROR; +	} + +	return (OK); +} + + +STATUS i2c_writebyte (SI2C * pi2c, UINT8 * writeb) +{ +	pi2c->sr &= ~I2C_STA_IF;	/* Clear Interrupt	*/ +	pi2c->dr = *writeb;		/* Write a byte		*/ + +	if (chk_status (pi2c, I2C_STA_CF, 1) != OK)	/* Transfer not complete?	*/ +		return ERROR; + +	if (chk_status (pi2c, I2C_STA_IF, 1) != OK) +		return ERROR; + +	return OK; +} + +STATUS i2c_write2byte (SI2C * pi2c, UINT16 * writeb) +{ +	UINT8 data; + +	data = (UINT8) ((*writeb >> 8) & 0xff); +	if (i2c_writebyte (pi2c, &data) != OK) +		return ERROR; +	data = (UINT8) (*writeb & 0xff); +	if (i2c_writebyte (pi2c, &data) != OK) +		return ERROR; +	return OK; +} + +/* FDR table base on 33MHz - more detail please refer to Odini2c_dividers.xls +FDR FDR scl sda scl2tap2 +510 432 tap tap tap tap scl_per	    sda_hold	I2C Freq    0	1   2	3   4	5 +000 000 9   3	4   1	28 Clocks   9 Clocks	1190 KHz    0	0   0	0   0	0 +000 001 9   3	4   2	44 Clocks   11 Clocks	758 KHz	    0	0   1	0   0	0 +000 010 9   3	6   4	80 Clocks   17 Clocks	417 KHz	    0	0   0	1   0	0 +000 011 9   3	6   8	144 Clocks  25 Clocks	231 KHz	    0	0   1	1   0	0 +000 100 9   3	14  16	288 Clocks  49 Clocks	116 KHz	    0	0   0	0   1	0 +000 101 9   3	30  32	576 Clocks  97 Clocks	58 KHz	    0	0   1	0   1	0 +000 110 9   3	62  64	1152 Clocks 193 Clocks	29 KHz	    0	0   0	1   1	0 +000 111 9   3	126 128 2304 Clocks 385 Clocks	14 KHz	    0	0   1	1   1	0 +001 000 10  3	4   1	30 Clocks   9 Clocks	1111 KHz1   0	0   0	0   0 +001 001 10  3	4   2	48 Clocks   11 Clocks	694 KHz	    1	0   1	0   0	0 +001 010 10  3	6   4	88 Clocks   17 Clocks	379 KHz	    1	0   0	1   0	0 +001 011 10  3	6   8	160 Clocks  25 Clocks	208 KHz	    1	0   1	1   0	0 +001 100 10  3	14  16	320 Clocks  49 Clocks	104 KHz	    1	0   0	0   1	0 +001 101 10  3	30  32	640 Clocks  97 Clocks	52 KHz	    1	0   1	0   1	0 +001 110 10  3	62  64	1280 Clocks 193 Clocks	26 KHz	    1	0   0	1   1	0 +001 111 10  3	126 128 2560 Clocks 385 Clocks	13 KHz	    1	0   1	1   1	0 +010 000 12  4	4   1	34 Clocks   10 Clocks	980 KHz	    0	1   0	0   0	0 +010 001 12  4	4   2	56 Clocks   13 Clocks	595 KHz	    0	1   1	0   0	0 +010 010 12  4	6   4	104 Clocks  21 Clocks	321 KHz	    0	1   0	1   0	0 +010 011 12  4	6   8	192 Clocks  33 Clocks	174 KHz	    0	1   1	1   0	0 +010 100 12  4	14  16	384 Clocks  65 Clocks	87 KHz	    0	1   0	0   1	0 +010 101 12  4	30  32	768 Clocks  129 Clocks	43 KHz	    0	1   1	0   1	0 +010 110 12  4	62  64	1536 Clocks 257 Clocks	22 KHz	    0	1   0	1   1	0 +010 111 12  4	126 128 3072 Clocks 513 Clocks	11 KHz	    0	1   1	1   1	0 +011 000 15  4	4   1	40 Clocks   10 Clocks	833 KHz	    1	1   0	0   0	0 +011 001 15  4	4   2	68 Clocks   13 Clocks	490 KHz	    1	1   1	0   0	0 +011 010 15  4	6   4	128 Clocks  21 Clocks	260 KHz	    1	1   0	1   0	0 +011 011 15  4	6   8	240 Clocks  33 Clocks	139 KHz	    1	1   1	1   0	0 +011 100 15  4	14  16	480 Clocks  65 Clocks	69 KHz	    1	1   0	0   1	0 +011 101 15  4	30  32	960 Clocks  129 Clocks	35 KHz	    1	1   1	0   1	0 +011 110 15  4	62  64	1920 Clocks 257 Clocks	17 KHz	    1	1   0	1   1	0 +011 111 15  4	126 128 3840 Clocks 513 Clocks	9 KHz	    1	1   1	1   1	0 +100 000 5   1	4   1	20 Clocks   7 Clocks	1667 KHz    0	0   0	0   0	1 +100 001 5   1	4   2	28 Clocks   7 Clocks	1190 KHz    0	0   1	0   0	1 +100 010 5   1	6   4	48 Clocks   9 Clocks	694 KHz	    0	0   0	1   0	1 +100 011 5   1	6   8	80 Clocks   9 Clocks	417 KHz	    0	0   1	1   0	1 +100 100 5   1	14  16	160 Clocks  17 Clocks	208 KHz	    0	0   0	0   1	1 +100 101 5   1	30  32	320 Clocks  33 Clocks	104 KHz	    0	0   1	0   1	1 +100 110 5   1	62  64	640 Clocks  65 Clocks	52 KHz	    0	0   0	1   1	1 +100 111 5   1	126 128 1280 Clocks 129 Clocks	26 KHz	    0	0   1	1   1	1 +101 000 6   1	4   1	22 Clocks   7 Clocks	1515 KHz    1	0   0	0   0	1 +101 001 6   1	4   2	32 Clocks   7 Clocks	1042 KHz    1	0   1	0   0	1 +101 010 6   1	6   4	56 Clocks   9 Clocks	595 KHz	    1	0   0	1   0	1 +101 011 6   1	6   8	96 Clocks   9 Clocks	347 KHz	    1	0   1	1   0	1 +101 100 6   1	14  16	192 Clocks  17 Clocks	174 KHz	    1	0   0	0   1	1 +101 101 6   1	30  32	384 Clocks  33 Clocks	87 KHz	    1	0   1	0   1	1 +101 110 6   1	62  64	768 Clocks  65 Clocks	43 KHz	    1	0   0	1   1	1 +101 111 6   1	126 128 1536 Clocks 129 Clocks	22 KHz	    1	0   1	1   1	1 +110 000 7   2	4   1	24 Clocks   8 Clocks	1389 KHz    0	1   0	0   0	1 +110 001 7   2	4   2	36 Clocks   9 Clocks	926 KHz	    0	1   1	0   0	1 +110 010 7   2	6   4	64 Clocks   13 Clocks	521 KHz	    0	1   0	1   0	1 +110 011 7   2	6   8	112 Clocks  17 Clocks	298 KHz	    0	1   1	1   0	1 +110 100 7   2	14  16	224 Clocks  33 Clocks	149 KHz	    0	1   0	0   1	1 +110 101 7   2	30  32	448 Clocks  65 Clocks	74 KHz	    0	1   1	0   1	1 +110 110 7   2	62  64	896 Clocks  129 Clocks	37 KHz	    0	1   0	1   1	1 +110 111 7   2	126 128 1792 Clocks 257 Clocks	19 KHz	    0	1   1	1   1	1 +111 000 8   2	4   1	26 Clocks   8 Clocks	1282 KHz    1	1   0	0   0	1 +111 001 8   2	4   2	40 Clocks   9 Clocks	833 KHz	    1	1   1	0   0	1 +111 010 8   2	6   4	72 Clocks   13 Clocks	463 KHz	    1	1   0	1   0	1 +111 011 8   2	6   8	128 Clocks  17 Clocks	260 KHz	    1	1   1	1   0	1 +111 100 8   2	14  16	256 Clocks  33 Clocks	130 KHz	    1	1   0	0   1	1 +111 101 8   2	30  32	512 Clocks  65 Clocks	65 KHz	    1	1   1	0   1	1 +111 110 8   2	62  64	1024 Clocks 129 Clocks	33 KHz	    1	1   0	1   1	1 +111 111 8   2	126 128 2048 Clocks 257 Clocks	16 KHz	    1	1   1	1   1	1 +*/ +STATUS SetI2cFDR (PSI2C pi2cRegs, int bitrate) +{ +/* Constants */ +	const UINT8 div_hold[8][3] = { {9, 3}, {10, 3}, +	{12, 4}, {15, 4}, +	{5, 1}, {6, 1}, +	{7, 2}, {8, 2} +	}; + +	const UINT8 scl_tap[8][2] = { {4, 1}, {4, 2}, +	{6, 4}, {6, 8}, +	{14, 16}, {30, 32}, +	{62, 64}, {126, 128} +	}; + +	UINT8 mfdr_bits; + +	int i = 0; +	int j = 0; + +	int Diff, min; +	int WhichFreq, iRec, jRec; +	int SCL_Period; +	int SCL_Hold; +	int I2C_Freq; + +	I2CCDBG (L2, ("Entering getBitRate: bitrate %d pi2cRegs 0x%08x\n", +		      bitrate, (int) pi2cRegs, 0, 0, 0, 0)); + +	if (bitrate < 0) { +		I2CCDBG (NO, ("Invalid bitrate\n", 0, 0, 0, 0, 0, 0)); +		return ERROR; +	} + +	/* Initialize */ +	mfdr_bits = 0; +	min = 0x7fffffff; +	WhichFreq = iRec = jRec = 0; + +	for (i = 0; i < 8; i++) { +		for (j = 0; j < 8; j++) { +			/* SCL Period = 2 * (scl2tap + [(SCL_Tap - 1) * tap2tap] + 2) +			 * SCL Hold   = scl2tap + ((SDA_Tap - 1) * tap2tap) + 3 +			 * Bit Rate (I2C Freq) = System Freq / SCL Period +			 */ +			SCL_Period = +				2 * (scl_tap[i][0] + +				     ((div_hold[j][0] - 1) * scl_tap[i][1]) + +				     2); + +			/* Now get the I2C Freq */ +			I2C_Freq = DEV_CLOCK_FREQ / SCL_Period; + +			/* Take equal or slower */ +			if (I2C_Freq > bitrate) +				continue; + +			/* Take the differences */ +			Diff = I2C_Freq - bitrate; + +			Diff = ABS (Diff); + +			/* Find the closer value */ +			if (Diff < min) { +				min = Diff; +				WhichFreq = I2C_Freq; +				iRec = i; +				jRec = j; +			} + +			I2CCDBG (L2, +				 ("--- (%d,%d) I2C_Freq %d minDiff %d min %d\n", +				  i, j, I2C_Freq, Diff, min, 0)); +		} +	} + +	SCL_Period = +		2 * (scl_tap[iRec][0] + +		     ((div_hold[jRec][0] - 1) * scl_tap[iRec][1]) + 2); + +	I2CCDBG (L2, ("\nmin %d WhichFreq %d iRec %d jRec %d\n", +		      min, WhichFreq, iRec, jRec, 0, 0)); +	I2CCDBG (L2, ("--- scl2tap %d SCL_Tap %d tap2tap %d\n", +		      scl_tap[iRec][0], div_hold[jRec][0], scl_tap[iRec][1], +		      0, 0, 0)); + +	/* This may no require */ +	SCL_Hold = +		scl_tap[iRec][0] + +		((div_hold[jRec][1] - 1) * scl_tap[iRec][1]) + 3; +	I2CCDBG (L2, +		 ("--- SCL_Period %d SCL_Hold %d\n", SCL_Period, SCL_Hold, 0, +		  0, 0, 0)); + +	I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0)); + +	/* FDR 4,3,2 */ +	if ((iRec & 1) == 1) +		mfdr_bits |= 0x04;	/* FDR 2 */ +	if ((iRec & 2) == 2) +		mfdr_bits |= 0x08;	/* FDR 3 */ +	if ((iRec & 4) == 4) +		mfdr_bits |= 0x10;	/* FDR 4 */ +	/* FDR 5,1,0 */ +	if ((jRec & 1) == 1) +		mfdr_bits |= 0x01;	/* FDR 0 */ +	if ((jRec & 2) == 2) +		mfdr_bits |= 0x02;	/* FDR 1 */ +	if ((jRec & 4) == 4) +		mfdr_bits |= 0x20;	/* FDR 5 */ + +	I2CCDBG (L2, ("--- mfdr_bits %x\n", mfdr_bits, 0, 0, 0, 0, 0)); + +	pi2cRegs->fdr = mfdr_bits; + +	return OK; +} diff --git a/arch/powerpc/cpu/mpc8220/i2cCore.h b/arch/powerpc/cpu/mpc8220/i2cCore.h new file mode 100644 index 000000000..72783fd48 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/i2cCore.h @@ -0,0 +1,103 @@ +/* + * i2cCore.h + * + * Prototypes, etc. for the Motorola MPC8220 + * embedded cpu chips + * + * 2004 (c) Freescale, Inc. + * Author: TsiChung Liew <Tsi-Chung.Liew@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 + */ +#ifndef __INCi2ccoreh +#define __INCi2ccoreh +#ifndef __ASSEMBLY__ +/* device types */ +#define I2C_DEVICE_TYPE_EEPROM 0 +#define I2C_EEPROM_ADRS 0xa0 +#define I2C_CTRL_ADRS   I2C_EEPROM_ADRS +#define EEPROM_ADDR0    0xA2	/* on Dimm SPD eeprom */ +#define EEPROM_ADDR1    0xA4	/* on Board SPD eeprom */ +#define EEPROM_ADDR2    0xD2	/* non-standard eeprom - clock generator */ +/* Control Register */ +#define I2C_CTL_EN      0x80	/* I2C Enable                   */ +#define I2C_CTL_IEN     0x40	/* I2C Interrupt Enable         */ +#define I2C_CTL_STA     0x20	/* Master/Slave Mode select     */ +#define I2C_CTL_TX      0x10	/* Transmit/Receive Mode Select */ +#define I2C_CTL_TXAK    0x08	/* Transmit Acknowledge Enable  */ +#define I2C_CTL_RSTA    0x04	/* Repeat Start                 */ +/* Status Register */ +#define I2C_STA_CF      0x80	/* Data Transfer       */ +#define I2C_STA_AAS     0x40	/* Adressed As Slave   */ +#define I2C_STA_BB      0x20	/* Bus Busy            */ +#define I2C_STA_AL      0x10	/* Arbitration Lost    */ +#define I2C_STA_SRW     0x04	/* Slave Read/Write    */ +#define I2C_STA_IF      0x02	/* I2C Interrupt       */ +#define I2C_STA_RXAK    0x01	/* Receive Acknowledge */ +/* Interrupt Contol Register */ +#define I2C_INT_BNBE2   0x80	/* Bus Not Busy Enable 2 */ +#define I2C_INT_TE2     0x40	/* Transmit Enable 2     */ +#define I2C_INT_RE2     0x20	/* Receive Enable 2      */ +#define I2C_INT_IE2     0x10	/* Interrupt Enable 2    */ +#define I2C_INT_BNBE1   0x08	/* Bus Not Busy Enable 1 */ +#define I2C_INT_TE1     0x04	/* Transmit Enable 1     */ +#define I2C_INT_RE1     0x02	/* Receive Enable 1      */ +#define I2C_INT_IE1     0x01	/* Interrupt Enable 1    */ +#define I2C_POLL_COUNT 0x100000 +#define I2C_ENABLE      0x00000001 +#define I2C_DISABLE     0x00000002 +#define I2C_START       0x00000004 +#define I2C_REPSTART    0x00000008 +#define I2C_STOP        0x00000010 +#define I2C_BITRATE     0x00000020 +#define I2C_SLAVEADR    0x00000040 +#define I2C_STARTADR    0x00000080 +#undef TWOBYTES +typedef struct i2c_settings { +	/* Device settings */ +	int bit_rate;		/* Device bit rate */ +	u8 i2c_adr;		/* I2C address */ +	u8 slv_adr;		/* Slave address */ +#ifdef TWOBYTES +	u16 str_adr;		/* Start address */ +#else +	u8 str_adr;		/* Start address */ +#endif +	int xfer_size;		/* Transfer Size */ + +	int bI2c_en;		/* Enable or Disable */ +	int cmdFlag;		/* I2c Command Flags */ +} i2cset_t; + +/* +int check_status(PSI2C pi2c, u8 sta_bit, u8 truefalse); +int i2c_enable(PSI2C pi2c, PI2CSET pi2cSet); +int i2c_disable(PSI2C pi2c); +int i2c_start(PSI2C pi2c, PI2CSET pi2cSet); +int i2c_stop(PSI2C pi2c); +int i2c_clear(PSI2C pi2c); +int i2c_readblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data); +int i2c_writeblock (PSI2C pi2c, PI2CSET pi2cSet, u8 *Data); +int i2c_readbyte(PSI2C pi2c, u8 *readb, int *index); +int i2c_writebyte(PSI2C pi2c, u8 *writeb); +int SetI2cFDR( PSI2C pi2cRegs, int bitrate ); +*/ +#endif /* __ASSEMBLY__ */ + +#endif /* __INCi2ccoreh */ diff --git a/arch/powerpc/cpu/mpc8220/interrupts.c b/arch/powerpc/cpu/mpc8220/interrupts.c new file mode 100644 index 000000000..78e99179c --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/interrupts.c @@ -0,0 +1,80 @@ +/* + * (C) Copyright -2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * (C) Copyright 2001 + * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * interrupts.c - just enough support for the decrementer/timer + */ + +#include <common.h> +#include <asm/processor.h> +#include <command.h> + +int interrupt_init_cpu (ulong * decrementer_count) +{ +	*decrementer_count = get_tbclk () / CONFIG_SYS_HZ; + +	return (0); +} + +/****************************************************************************/ + +/* + * Handle external interrupts + */ +void external_interrupt (struct pt_regs *regs) +{ +	puts ("external_interrupt (oops!)\n"); +} + +void timer_interrupt_cpu (struct pt_regs *regs) +{ +	/* nothing to do here */ +	return; +} + +/****************************************************************************/ + +/* + * Install and free a interrupt handler. + */ + +void irq_install_handler (int vec, interrupt_handler_t * handler, void *arg) +{ + +} + +void irq_free_handler (int vec) +{ + +} + +/****************************************************************************/ + +void +do_irqinfo (cmd_tbl_t * cmdtp, bd_t * bd, int flag, int argc, char *argv[]) +{ +	puts ("IRQ related functions are unimplemented currently.\n"); +} diff --git a/arch/powerpc/cpu/mpc8220/io.S b/arch/powerpc/cpu/mpc8220/io.S new file mode 100644 index 000000000..5ecdf550a --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/io.S @@ -0,0 +1,128 @@ +/* + *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net> + *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> + *  Copyright (C) 2001	Sysgo Real-Time Solutions, GmbH <www.elinos.com> + *			Andreas Heppel <aheppel@sysgo.de> + *  Copyright (C) 2003	Wolfgang Denk <wd@denx.de> + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <config.h> +#include <ppc_asm.tmpl> + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  in8 */ +/*  Description:  Input 8 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	in8 +in8: +	lbz	r3,0(r3) +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  in16 */ +/*  Description:  Input 16 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	in16 +in16: +	lhz	r3,0(r3) +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  in16r */ +/*  Description:  Input 16 bits and byte reverse */ +/* ------------------------------------------------------------------------------- */ +	.globl	in16r +in16r: +	lhbrx	r3,0,r3 +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  in32 */ +/*  Description:  Input 32 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	in32 +in32: +	lwz	3,0(3) +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  in32r */ +/*  Description:  Input 32 bits and byte reverse */ +/* ------------------------------------------------------------------------------- */ +	.globl	in32r +in32r: +	lwbrx	r3,0,r3 +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  out8 */ +/*  Description:  Output 8 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	out8 +out8: +	stb	r4,0(r3) +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  out16 */ +/*  Description:  Output 16 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	out16 +out16: +	sth	r4,0(r3) +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  out16r */ +/*  Description:  Byte reverse and output 16 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	out16r +out16r: +	sthbrx	r4,0,r3 +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  out32 */ +/*  Description:  Output 32 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	out32 +out32: +	stw	r4,0(r3) +	sync +	blr + +/* ------------------------------------------------------------------------------- */ +/*  Function:	  out32r */ +/*  Description:  Byte reverse and output 32 bits */ +/* ------------------------------------------------------------------------------- */ +	.globl	out32r +out32r: +	stwbrx	r4,0,r3 +	sync +	blr diff --git a/arch/powerpc/cpu/mpc8220/loadtask.c b/arch/powerpc/cpu/mpc8220/loadtask.c new file mode 100644 index 000000000..6d8b627e8 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/loadtask.c @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * This file is based on code + * (C) Copyright Motorola, Inc., 2000 + */ + +#include <common.h> +#include <mpc8220.h> + +/* Multichannel DMA microcode */ +extern int taskTable; + +void loadtask (int basetask, int tasks) +{ +	int *sram = (int *) (MMAP_SRAM + 512); +	int *task_org = &taskTable; +	unsigned int start, offset, end; +	int i; + +#ifdef DEBUG +	printf ("basetask = %d, tasks = %d\n", basetask, tasks); +	printf ("task_org = 0x%08x\n", (unsigned int) task_org); +#endif + +	/* setup TaskBAR register */ +	*(vu_long *) MMAP_DMA = (MMAP_SRAM + 512); + +	/* relocate task table entries */ +	offset = (unsigned int) sram; +	for (i = basetask; i < basetask + tasks; i++) { +		sram[i * 8 + 0] = task_org[i * 8 + 0] + offset; +		sram[i * 8 + 1] = task_org[i * 8 + 1] + offset; +		sram[i * 8 + 2] = task_org[i * 8 + 2] + offset; +		sram[i * 8 + 3] = task_org[i * 8 + 3] + offset; +		sram[i * 8 + 4] = task_org[i * 8 + 4]; +		sram[i * 8 + 5] = task_org[i * 8 + 5]; +		sram[i * 8 + 6] = task_org[i * 8 + 6] + offset; +		sram[i * 8 + 7] = task_org[i * 8 + 7]; +	} + +	/* relocate task descriptors */ +	start = (sram[basetask * 8] - (unsigned int) sram); +	end = (sram[(basetask + tasks - 1) * 8 + 1] - (unsigned int) sram); + +#ifdef DEBUG +	printf ("TDT start = 0x%08x, end = 0x%08x\n", start, end); +#endif + +	start /= 4; +	end /= 4; +	for (i = start; i <= end; i++) { +		sram[i] = task_org[i]; +	} + +	/* relocate variables */ +	start = (sram[basetask * 8 + 2] - (unsigned int) sram); +	end = (sram[(basetask + tasks - 1) * 8 + 2] + 256 - +	       (unsigned int) sram); +	start /= 4; +	end /= 4; +	for (i = start; i < end; i++) { +		sram[i] = task_org[i]; +	} + +	/* relocate function decriptors */ +	start = ((sram[basetask * 8 + 3] & 0xfffffffc) - (unsigned int) sram); +	end = ((sram[(basetask + tasks - 1) * 8 + 3] & 0xfffffffc) + 256 - +	       (unsigned int) sram); +	start /= 4; +	end /= 4; +	for (i = start; i < end; i++) { +		sram[i] = task_org[i]; +	} + +	asm volatile ("sync"); +} diff --git a/arch/powerpc/cpu/mpc8220/pci.c b/arch/powerpc/cpu/mpc8220/pci.c new file mode 100644 index 000000000..7ef43b72c --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/pci.c @@ -0,0 +1,191 @@ +/* + * Copyright 2004 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. + * + * 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 + */ + +/* + * PCI Configuration space access support for MPC8220 PCI Bridge + */ +#include <common.h> +#include <mpc8220.h> +#include <pci.h> +#include <asm/io.h> + +#if defined(CONFIG_PCI) + +/* System RAM mapped over PCI */ +#define CONFIG_PCI_SYS_MEM_BUS	 CONFIG_SYS_SDRAM_BASE +#define CONFIG_PCI_SYS_MEM_PHYS	 CONFIG_SYS_SDRAM_BASE +#define CONFIG_PCI_SYS_MEM_SIZE	 (1024 * 1024 * 1024) + +#define cfg_read(val, addr, type, op)		*val = op((type)(addr)); +#define cfg_write(val, addr, type, op)		op((type *)(addr), (val)); + +#define PCI_OP(rw, size, type, op, mask)				\ +int mpc8220_pci_##rw##_config_##size(struct pci_controller *hose,	\ +	pci_dev_t dev, int offset, type val)				\ +{									\ +	u32 addr = 0;							\ +	u16 cfg_type = 0;						\ +	addr = ((offset & 0xfc) | cfg_type | (dev)  | 0x80000000);	\ +	out_be32(hose->cfg_addr, addr);					\ +	__asm__ __volatile__("sync");					\ +	cfg_##rw(val, hose->cfg_data + (offset & mask), type, op);	\ +	out_be32(hose->cfg_addr, addr & 0x7fffffff);			\ +	__asm__ __volatile__("sync");					\ +	return 0;							\ +} + +PCI_OP(read, byte, u8 *, in_8, 3) +PCI_OP(read, word, u16 *, in_le16, 2) +PCI_OP(write, byte, u8, out_8, 3) +PCI_OP(write, word, u16, out_le16, 2) +PCI_OP(write, dword, u32, out_le32, 0) + +int mpc8220_pci_read_config_dword(struct pci_controller *hose, pci_dev_t dev, +	int offset, u32 *val) +{ +	u32 addr; +	u32 tmpv; +	u32 mask = 2;	 /* word access */ +	/* Read lower 16 bits */ +	addr = ((offset & 0xfc) | (dev) | 0x80000000); +	out_be32(hose->cfg_addr, addr); +	__asm__ __volatile__("sync"); +	*val = (u32) in_le16((u16 *) (hose->cfg_data + (offset & mask))); +	out_be32(hose->cfg_addr, addr & 0x7fffffff); +	__asm__ __volatile__("sync"); + +	/* Read upper 16 bits */ +	offset += 2; +	addr = ((offset & 0xfc) | 1 | (dev) | 0x80000000); +	out_be32(hose->cfg_addr, addr); +	__asm__ __volatile__("sync"); +	tmpv = (u32) in_le16((u16 *) (hose->cfg_data + (offset & mask))); +	out_be32(hose->cfg_addr, addr & 0x7fffffff); +	__asm__ __volatile__("sync"); + +	/* combine results into dword value */ +	*val = (tmpv << 16) | *val; + +	return 0; +} + +void +pci_mpc8220_init(struct pci_controller *hose) +{ +	u32 win0, win1, win2; +	volatile mpc8220_xcpci_t *xcpci = +		(volatile mpc8220_xcpci_t *) MMAP_XCPCI; + +	volatile pcfg8220_t *portcfg = (volatile pcfg8220_t *) MMAP_PCFG; + +	win0 = (u32) CONFIG_PCI_MEM_PHYS; +	win1 = (u32) CONFIG_PCI_IO_PHYS; +	win2 = (u32) CONFIG_PCI_CFG_PHYS; + +	/* Assert PCI reset */ +	out_be32 (&xcpci->glb_stat_ctl, PCI_GLB_STAT_CTRL_PR); + +	/* Disable prefetching but read-multiples will still prefetch */ +	out_be32 (&xcpci->target_ctrl, 0x00000000); + +	/* Initiator windows */ +	out_be32 (&xcpci->init_win0,  (win0 >> 16) | win0 | 0x003f0000); +	out_be32 (&xcpci->init_win1, ((win1 >> 16) | win1 )); +	out_be32 (&xcpci->init_win2, ((win2 >> 16) | win2 )); + +	out_be32 (&xcpci->init_win_cfg, +		PCI_INIT_WIN_CFG_WIN0_CTRL_EN | +		PCI_INIT_WIN_CFG_WIN1_CTRL_EN | PCI_INIT_WIN_CFG_WIN1_CTRL_IO | +		PCI_INIT_WIN_CFG_WIN2_CTRL_EN | PCI_INIT_WIN_CFG_WIN2_CTRL_IO); + +	out_be32 (&xcpci->init_ctrl, 0x00000000); + +	/* Enable bus master and mem access */ +	out_be32 (&xcpci->stat_cmd_reg, PCI_STAT_CMD_B | PCI_STAT_CMD_M); + +	/* Cache line size and master latency */ +	out_be32 (&xcpci->bist_htyp_lat_cshl, (0xf8 << PCI_CFG1_LT_SHIFT)); + +	out_be32 (&xcpci->base0, PCI_BASE_ADDR_REG0); /* 256MB - MBAR space */ +	out_be32 (&xcpci->base1, PCI_BASE_ADDR_REG1); /* 1GB - SDRAM space */ + +	out_be32 (&xcpci->target_bar0, +		PCI_TARGET_BASE_ADDR_REG0 | PCI_TARGET_BASE_ADDR_EN); +	out_be32 (&xcpci->target_bar1, +		PCI_TARGET_BASE_ADDR_REG1 | PCI_TARGET_BASE_ADDR_EN); + +	/* Deassert reset bit */ +	out_be32 (&xcpci->glb_stat_ctl, 0x00000000); + +	/* Enable PCI bus master support */ +	/* Set PCIGNT1, PCIREQ1, PCIREQ0/PCIGNTIN, PCIGNT0/PCIREQOUT, +	       PCIREQ2, PCIGNT2 */ +	out_be32((volatile u32 *)&portcfg->pcfg3, +		(in_be32((volatile u32 *)&portcfg->pcfg3) & 0xFC3FCE7F)); +	out_be32((volatile u32 *)&portcfg->pcfg3, +		(in_be32((volatile u32 *)&portcfg->pcfg3) | 0x01400180)); + +	hose->first_busno = 0; +	hose->last_busno = 0xff; + +	pci_set_region(hose->regions + 0, +		CONFIG_PCI_MEM_BUS, +		CONFIG_PCI_MEM_PHYS, +		CONFIG_PCI_MEM_SIZE, +		PCI_REGION_MEM); + +	pci_set_region(hose->regions + 1, +		CONFIG_PCI_IO_BUS, +		CONFIG_PCI_IO_PHYS, +		CONFIG_PCI_IO_SIZE, +		PCI_REGION_IO); + +	pci_set_region(hose->regions + 2, +		CONFIG_PCI_SYS_MEM_BUS, +		CONFIG_PCI_SYS_MEM_PHYS, +		CONFIG_PCI_SYS_MEM_SIZE, +		PCI_REGION_MEM | PCI_REGION_SYS_MEMORY); + +	hose->region_count = 3; + +	hose->cfg_addr = &(xcpci->cfg_adr); +	hose->cfg_data = (volatile unsigned char *)CONFIG_PCI_CFG_BUS; + +	pci_set_ops(hose, +		mpc8220_pci_read_config_byte, +		mpc8220_pci_read_config_word, +		mpc8220_pci_read_config_dword, +		mpc8220_pci_write_config_byte, +		mpc8220_pci_write_config_word, +		mpc8220_pci_write_config_dword); + +	/* Hose scan */ +	pci_register_hose(hose); +	hose->last_busno = pci_hose_scan(hose); + +	out_be32 (&xcpci->base0, PCI_BASE_ADDR_REG0); /* 256MB - MBAR space */ +	out_be32 (&xcpci->base1, PCI_BASE_ADDR_REG1); /* 1GB - SDRAM space */ +} + +#endif /* CONFIG_PCI */ diff --git a/arch/powerpc/cpu/mpc8220/speed.c b/arch/powerpc/cpu/mpc8220/speed.c new file mode 100644 index 000000000..62ac845b7 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/speed.c @@ -0,0 +1,123 @@ +/* + * (C) Copyright 2004, Freescale, Inc + * TsiChung Liew, Tsi-Chung.Liew@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 + */ + +#include <common.h> +#include <mpc8220.h> +#include <asm/processor.h> + +DECLARE_GLOBAL_DATA_PTR; + +typedef struct pllmultiplier { +	u8 hid1; +	int multi; +	int vco_div; +} pllcfg_t; + +/* ------------------------------------------------------------------------- */ + +/* + * + */ + +int get_clocks (void) +{ +	pllcfg_t bus2core[] = { +		{0x02, 2, 8},	/* 1 */ +		{0x01, 2, 4}, +		{0x0C, 3, 8},	/* 1.5 */ +		{0x00, 3, 4}, +		{0x18, 3, 2}, +		{0x05, 4, 4},	/* 2 */ +		{0x04, 4, 2}, +		{0x11, 5, 4},	/* 2.5 */ +		{0x06, 5, 2}, +		{0x10, 6, 4},	/* 3 */ +		{0x08, 6, 2}, +		{0x0E, 7, 2},	/* 3.5 */ +		{0x0A, 8, 2},	/* 4 */ +		{0x07, 9, 2},	/* 4.5 */ +		{0x0B, 10, 2},	/* 5 */ +		{0x09, 11, 2},	/* 5.5 */ +		{0x0D, 12, 2},	/* 6 */ +		{0x12, 13, 2},	/* 6.5 */ +		{0x14, 14, 2},	/* 7 */ +		{0x16, 15, 2},	/* 7.5 */ +		{0x1C, 16, 2}	/* 8 */ +	}; +	u32 hid1; +	int i, size, pci2bus; + +#if !defined(CONFIG_SYS_MPC8220_CLKIN) +#error clock measuring not implemented yet - define CONFIG_SYS_MPC8220_CLKIN +#endif + +	gd->inp_clk = CONFIG_SYS_MPC8220_CLKIN; + +	/* Read XLB to PCI(INP) clock multiplier */ +	pci2bus = (*((volatile u32 *)PCI_REG_PCIGSCR) & +		PCI_REG_PCIGSCR_PCI2XLB_CLK_MASK)>>PCI_REG_PCIGSCR_PCI2XLB_CLK_BIT; + +	/* XLB bus clock */ +	gd->bus_clk = CONFIG_SYS_MPC8220_CLKIN * pci2bus; + +	/* PCI clock is same as input clock */ +	gd->pci_clk = CONFIG_SYS_MPC8220_CLKIN; + +	/* FlexBus is temporary set as the same as input clock */ +	/* will do dynamic in the future */ +	gd->flb_clk = CONFIG_SYS_MPC8220_CLKIN; + +	/* CPU Clock - Read HID1 */ +	asm volatile ("mfspr %0, 1009":"=r" (hid1):); + +	size = sizeof (bus2core) / sizeof (pllcfg_t); + +	hid1 >>= 27; + +	for (i = 0; i < size; i++) +		if (hid1 == bus2core[i].hid1) { +			gd->cpu_clk = (bus2core[i].multi * gd->bus_clk) >> 1; +			gd->vco_clk = CONFIG_SYS_MPC8220_SYSPLL_VCO_MULTIPLIER * (gd->pci_clk * bus2core[i].vco_div)/2; +			break; +		} + +	/* hardcoded 81MHz for now */ +	gd->pev_clk = 81000000; + +	return (0); +} + +int prt_mpc8220_clks (void) +{ +	char buf1[32], buf2[32], buf3[32], buf4[32]; + +	printf ("       Bus %s MHz, CPU %s MHz, PCI %s MHz, VCO %s MHz\n", +		strmhz(buf1, gd->bus_clk), +		strmhz(buf2, gd->cpu_clk), +		strmhz(buf3, gd->pci_clk), +		strmhz(buf4, gd->vco_clk) +	); +	return (0); +} + +/* ------------------------------------------------------------------------- */ diff --git a/arch/powerpc/cpu/mpc8220/start.S b/arch/powerpc/cpu/mpc8220/start.S new file mode 100644 index 000000000..3d79d8ec0 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/start.S @@ -0,0 +1,750 @@ +/* + *  Copyright (C) 1998	Dan Malek <dmalek@jlc.net> + *  Copyright (C) 1999	Magnus Damm <kieraypc01.p.y.kie.era.ericsson.se> + *  Copyright (C) 2000 - 2003 Wolfgang Denk <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 + */ + +/* + *  U-Boot - Startup Code for MPC8220 CPUs + */ +#include <config.h> +#include <mpc8220.h> +#include <timestamp.h> +#include <version.h> + +#define _LINUX_CONFIG_H 1   /* avoid reading Linux autoconf.h file  */ + +#include <ppc_asm.tmpl> +#include <ppc_defs.h> + +#include <asm/cache.h> +#include <asm/mmu.h> + +#ifndef	 CONFIG_IDENT_STRING +#define	 CONFIG_IDENT_STRING "" +#endif + +/* We don't want the  MMU yet. +*/ +#undef	MSR_KERNEL +/* Floating Point enable, Machine Check and Recoverable Interr. */ +#ifdef DEBUG +#define MSR_KERNEL (MSR_FP|MSR_RI) +#else +#define MSR_KERNEL (MSR_FP|MSR_ME|MSR_RI) +#endif + +/* + * Set up GOT: Global Offset Table + * + * Use r12 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 + +/* + * Version string + */ +	.data +	.globl	version_string +version_string: +	.ascii U_BOOT_VERSION +	.ascii " (", U_BOOT_DATE, " - ", U_BOOT_TIME, ")" +	.ascii CONFIG_IDENT_STRING, "\0" + +/* + * Exception vectors + */ +	.text +	. = EXC_OFF_SYS_RESET +	.globl	_start +_start: +	li	r21, BOOTFLAG_COLD  /* Normal Power-On	    */ +	nop +	b	boot_cold + +	. = EXC_OFF_SYS_RESET + 0x10 + +	.globl	_start_warm +_start_warm: +	li	r21, BOOTFLAG_WARM  /* Software reboot	    */ +	b	boot_warm + +boot_cold: +boot_warm: +	mfmsr	r5		    /* save msr contents    */ + +	/* replace default MBAR base address from 0x80000000 +	    to 0xf0000000 */ + +#if defined(CONFIG_SYS_DEFAULT_MBAR) && !defined(CONFIG_SYS_RAMBOOT) +	lis	r3, CONFIG_SYS_MBAR@h +	ori	r3, r3, CONFIG_SYS_MBAR@l + +	/* MBAR is mirrored into the MBAR SPR */ +	mtspr	MBAR,r3 +	mtspr	SPRN_SPRG7W,r3 +	lis	r4, CONFIG_SYS_DEFAULT_MBAR@h +	stw	r3, 0(r4) +#endif /* CONFIG_SYS_DEFAULT_MBAR */ + +	/* Initialise the MPC8220 processor core			*/ +	/*--------------------------------------------------------------*/ + +	bl  init_8220_core + +	/* initialize some things that are hard to access from C	*/ +	/*--------------------------------------------------------------*/ + +	/* set up stack in on-chip SRAM */ +	lis	r3, CONFIG_SYS_INIT_RAM_ADDR@h +	ori	r3, r3, CONFIG_SYS_INIT_RAM_ADDR@l +	ori	r1, r3, CONFIG_SYS_INIT_SP_OFFSET + +	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 !			*/ +	/*--------------------------------------------------------------*/ + +	GET_GOT			/* initialize GOT access		*/ + +	/* r3: IMMR */ +	bl	cpu_init_f	/* run low-level CPU init code (in Flash)*/ + +	mr	r3, r21 +	/* r3: BOOTFLAG */ +	bl	board_init_f	/* run 1st part of board init code (in Flash)*/ + +/* + * Vector Table + */ + +	.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, external_interrupt) + +/* 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 +	EXC_XFER_TEMPLATE(Alignment, AlignmentException, MSR_KERNEL, COPY_EE) + +/* Program check exception */ +	. = 0x700 +ProgramCheck: +	EXCEPTION_PROLOG(SRR0, SRR1) +	addi	r3,r1,STACK_FRAME_OVERHEAD +	EXC_XFER_TEMPLATE(ProgramCheck, ProgramCheckException, +		MSR_KERNEL, COPY_EE) + +	STD_EXCEPTION(0x800, FPUnavailable, UnknownException) + +	/* I guess we could implement decrementer, and may have +	 * to someday for timekeeping. +	 */ +	STD_EXCEPTION(0x900, Decrementer, timer_interrupt) + +	STD_EXCEPTION(0xa00, Trap_0a, UnknownException) +	STD_EXCEPTION(0xb00, Trap_0b, UnknownException) +	STD_EXCEPTION(0xc00, SystemCall, UnknownException) +	STD_EXCEPTION(0xd00, SingleStep, UnknownException) + +	STD_EXCEPTION(0xe00, Trap_0e, UnknownException) +	STD_EXCEPTION(0xf00, Trap_0f, UnknownException) + +	STD_EXCEPTION(0x1000, InstructionTLBMiss, UnknownException) +	STD_EXCEPTION(0x1100, DataLoadTLBMiss, UnknownException) +	STD_EXCEPTION(0x1200, DataStoreTLBMiss, UnknownException) +#ifdef DEBUG +	. = 0x1300 +	/* +	 * This exception occurs when the program counter matches the +	 * Instruction Address Breakpoint Register (IABR). +	 * +	 * I want the cpu to halt if this occurs so I can hunt around +	 * with the debugger and look at things. +	 * +	 * When DEBUG is defined, both machine check enable (in the MSR) +	 * and checkstop reset enable (in the reset mode register) are +	 * turned off and so a checkstop condition will result in the cpu +	 * halting. +	 * +	 * I force the cpu into a checkstop condition by putting an illegal +	 * instruction here (at least this is the theory). +	 * +	 * well - that didnt work, so just do an infinite loop! +	 */ +1:	b	1b +#else +	STD_EXCEPTION(0x1300, InstructionBreakpoint, DebugException) +#endif +	STD_EXCEPTION(0x1400, SMI, UnknownException) + +	STD_EXCEPTION(0x1500, Trap_15, UnknownException) +	STD_EXCEPTION(0x1600, Trap_16, UnknownException) +	STD_EXCEPTION(0x1700, Trap_17, UnknownException) +	STD_EXCEPTION(0x1800, Trap_18, UnknownException) +	STD_EXCEPTION(0x1900, Trap_19, UnknownException) +	STD_EXCEPTION(0x1a00, Trap_1a, UnknownException) +	STD_EXCEPTION(0x1b00, Trap_1b, UnknownException) +	STD_EXCEPTION(0x1c00, Trap_1c, UnknownException) +	STD_EXCEPTION(0x1d00, Trap_1d, UnknownException) +	STD_EXCEPTION(0x1e00, Trap_1e, UnknownException) +	STD_EXCEPTION(0x1f00, Trap_1f, UnknownException) +	STD_EXCEPTION(0x2000, Trap_20, UnknownException) +	STD_EXCEPTION(0x2100, Trap_21, UnknownException) +	STD_EXCEPTION(0x2200, Trap_22, UnknownException) +	STD_EXCEPTION(0x2300, Trap_23, UnknownException) +	STD_EXCEPTION(0x2400, Trap_24, UnknownException) +	STD_EXCEPTION(0x2500, Trap_25, UnknownException) +	STD_EXCEPTION(0x2600, Trap_26, UnknownException) +	STD_EXCEPTION(0x2700, Trap_27, UnknownException) +	STD_EXCEPTION(0x2800, Trap_28, UnknownException) +	STD_EXCEPTION(0x2900, Trap_29, UnknownException) +	STD_EXCEPTION(0x2a00, Trap_2a, UnknownException) +	STD_EXCEPTION(0x2b00, Trap_2b, UnknownException) +	STD_EXCEPTION(0x2c00, Trap_2c, UnknownException) +	STD_EXCEPTION(0x2d00, Trap_2d, UnknownException) +	STD_EXCEPTION(0x2e00, Trap_2e, UnknownException) +	STD_EXCEPTION(0x2f00, Trap_2f, UnknownException) + + +	.globl	_end_of_vectors +_end_of_vectors: + +	. = 0x3000 + +/* + * 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 MPC8220 processor core + * (conforms to PowerPC 603e spec) + * Note: expects original MSR contents to be in r5. + */ + +	.globl	init_8220_core +init_8220_core: + +	/* 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 set by HRCW	*/ +#ifdef DEBUG +	rlwimi	r3, r5, 0, 21, 22   /* debugger might set SE & BE bits	*/ +#endif +	SYNC			    /* Some chip revs need this...	*/ +	mtmsr	r3 +	SYNC +	mtspr	SRR1, r3	    /* Make SRR1 match MSR		*/ + +	/* Initialize the Hardware Implementation-dependent Registers	*/ +	/* HID0 also contains cache control				*/ +	/*--------------------------------------------------------------*/ + +	lis	r3, CONFIG_SYS_HID0_INIT@h +	ori	r3, r3, CONFIG_SYS_HID0_INIT@l +	SYNC +	mtspr	HID0, r3 + +	lis	r3, CONFIG_SYS_HID0_FINAL@h +	ori	r3, r3, CONFIG_SYS_HID0_FINAL@l +	SYNC +	mtspr	HID0, r3 + +	/* Enable Extra BATs */ +	mfspr	r3, 1011    /* HID2 */ +	lis	r4, 0x0004 +	ori	r4, r4, 0x0000 +	or	r4, r4, r3 +	mtspr	1011, r4 +	sync + +	/* clear all BAT's						*/ +	/*--------------------------------------------------------------*/ + +	li	r0, 0 +	mtspr	DBAT0U, r0 +	mtspr	DBAT0L, r0 +	mtspr	DBAT1U, r0 +	mtspr	DBAT1L, r0 +	mtspr	DBAT2U, r0 +	mtspr	DBAT2L, r0 +	mtspr	DBAT3U, r0 +	mtspr	DBAT3L, r0 +	mtspr	DBAT4U, r0 +	mtspr	DBAT4L, r0 +	mtspr	DBAT5U, r0 +	mtspr	DBAT5L, r0 +	mtspr	DBAT6U, r0 +	mtspr	DBAT6L, r0 +	mtspr	DBAT7U, r0 +	mtspr	DBAT7L, r0 +	mtspr	IBAT0U, r0 +	mtspr	IBAT0L, r0 +	mtspr	IBAT1U, r0 +	mtspr	IBAT1L, r0 +	mtspr	IBAT2U, r0 +	mtspr	IBAT2L, r0 +	mtspr	IBAT3U, r0 +	mtspr	IBAT3L, r0 +	mtspr	IBAT4U, r0 +	mtspr	IBAT4L, r0 +	mtspr	IBAT5U, r0 +	mtspr	IBAT5L, r0 +	mtspr	IBAT6U, r0 +	mtspr	IBAT6L, r0 +	mtspr	IBAT7U, r0 +	mtspr	IBAT7L, r0 +	SYNC + +	/* invalidate all tlb's						*/ +	/*								*/ +	/* From the 603e User Manual: "The 603e provides the ability to */ +	/* invalidate a TLB entry. The TLB Invalidate Entry (tlbie)	*/ +	/* instruction invalidates the TLB entry indexed by the EA, and */ +	/* operates on both the instruction and data TLBs simultaneously*/ +	/* invalidating four TLB entries (both sets in each TLB). The	*/ +	/* index corresponds to bits 15-19 of the EA. To invalidate all */ +	/* entries within both TLBs, 32 tlbie instructions should be	*/ +	/* issued, incrementing this field by one each time."		*/ +	/*								*/ +	/* "Note that the tlbia instruction is not implemented on the	*/ +	/* 603e."							*/ +	/*								*/ +	/* bits 15-19 correspond to addresses 0x00000000 to 0x0001F000	*/ +	/* incrementing by 0x1000 each time. The code below is sort of	*/ +	/* based on code in "flush_tlbs" from arch/powerpc/kernel/head.S	*/ +	/*								*/ +	/*--------------------------------------------------------------*/ + +	li	r3, 32 +	mtctr	r3 +	li	r3, 0 +1:	tlbie	r3 +	addi	r3, r3, 0x1000 +	bdnz	1b +	SYNC + +	/* Done!							*/ +	/*--------------------------------------------------------------*/ + +	blr + +/* Cache functions. + * + * Note: requires that all cache bits in + * HID0 are in the low half word. + */ +	.globl	icache_enable +icache_enable: +	lis	r4, 0 +	ori	r4, r4, CONFIG_SYS_HID0_INIT /* set ICE & ICFI bit		*/ +	rlwinm	r3, r4, 0, 21, 19     /* clear the ICFI bit		*/ + +	/* +	 * The setting of the instruction cache enable (ICE) bit must be +	 * preceded by an isync instruction to prevent the cache from being +	 * enabled or disabled while an instruction access is in progress. +	 */ +	isync +	mtspr	HID0, r4	      /* Enable Instr Cache & Inval cache */ +	mtspr	HID0, r3	      /* using 2 consec instructions	*/ +	isync +	blr + +	.globl	icache_disable +icache_disable: +	mfspr	r3, HID0 +	rlwinm	r3, r3, 0, 17, 15     /* clear the ICE bit		*/ +	mtspr	HID0, r3 +	isync +	blr + +	.globl	icache_status +icache_status: +	mfspr	r3, HID0 +	rlwinm	r3, r3, HID0_ICE_BITPOS + 1, 31, 31 +	blr + +	.globl	dcache_enable +dcache_enable: +	lis	r4, 0 +	ori	r4, r4, HID0_DCE|HID0_DCFI /* set DCE & DCFI bit	*/ +	rlwinm	r3, r4, 0, 22, 20     /* clear the DCFI bit		*/ + +	/* Enable address translation in MSR bit */ +	mfmsr	r5 +	ori	r5, r5, 0x + + +	/* +	 * The setting of the instruction cache enable (ICE) bit must be +	 * preceded by an isync instruction to prevent the cache from being +	 * enabled or disabled while an instruction access is in progress. +	 */ +	isync +	mtspr	HID0, r4	      /* Enable Data Cache & Inval cache*/ +	mtspr	HID0, r3	      /* using 2 consec instructions	*/ +	isync +	blr + +	.globl	dcache_disable +dcache_disable: +	mfspr	r3, HID0 +	rlwinm	r3, r3, 0, 18, 16     /* clear the DCE bit */ +	mtspr	HID0, r3 +	isync +	blr + +	.globl	dcache_status +dcache_status: +	mfspr	r3, HID0 +	rlwinm	r3, r3, HID0_DCE_BITPOS + 1, 31, 31 +	blr + +	.globl	get_pvr +get_pvr: +	mfspr	r3, PVR +	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 */ + +	GET_GOT +	mr	r3,  r5	    /* Destination Address		*/ +	lis	r4, CONFIG_SYS_MONITOR_BASE@h	/* Source Address	*/ +	ori	r4, r4, CONFIG_SYS_MONITOR_BASE@l +	lwz	r5, GOT(__init_end) +	sub	r5, r5, r4 +	li	r6, CONFIG_SYS_CACHELINE_SIZE	/* Cache Line Size	*/ + +	/* +	 * Fix GOT pointer: +	 * +	 * New GOT-PTR = (old GOT-PTR - CONFIG_SYS_MONITOR_BASE) + Destination Address +	 * +	 * Offset: +	 */ +	sub	r15, r10, r4 + +	/* First our own GOT */ +	add	r12, r12, 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) +1:	lwzu	r0,4(r8) +	stwu	r0,4(r7) +	bdnz	1b +	b	4f + +2:	slwi	r0,r0,2 +	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 +	mfspr	r7,HID0	    /* don't do dcbst if dcache is disabled	*/ +	rlwinm	r7,r7,HID0_DCE_BITPOS+1,31,31 +	cmpwi	r7,0 +	beq	9f +	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	*/ +9:	mfspr	r7,HID0	    /* don't do icbi if icache is disabled	*/ +	rlwinm	r7,r7,HID0_ICE_BITPOS+1,31,31 +	cmpwi	r7,0 +	beq	7f +	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, r12 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) +	cmpwi	r0,0 +	beq-	2f +	add	r0,r0,r11 +	stw	r0,0(r3) +2:	bdnz	1b + +	/* +	 * Now adjust the fixups and the pointers to the fixups +	 * in case we need to move ourselves again. +	 */ +	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: +	mflr	r4	    /* save link register		*/ +	GET_GOT +	lwz	r7, GOT(_start) +	lwz	r8, GOT(_end_of_vectors) + +	li	r9, 0x100   /* reset vector always at 0x100	*/ + +	cmplw	0, r7, r8 +	bgelr		    /* return if r7>=r8 - just in case	*/ +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_SingleStep - _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 diff --git a/arch/powerpc/cpu/mpc8220/traps.c b/arch/powerpc/cpu/mpc8220/traps.c new file mode 100644 index 000000000..13894c905 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/traps.c @@ -0,0 +1,236 @@ +/* + * linux/arch/powerpc/kernel/traps.c + * + * Copyright (C) 1995-1996  Gary Thomas (gdt@linuxppc.org) + * + * Modified by Cort Dougan (cort@cs.nmt.edu) + * and Paul Mackerras (paulus@cs.anu.edu.au) + * fixed Machine Check Reasons by Reinhard Meyer (r.meyer@emk-elektronik.de) + * + * (C) Copyright 2000-2003 + * Wolfgang Denk, DENX Software Engineering, wd@denx.de. + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +/* + * This file handles the architecture-dependent parts of hardware exceptions + */ + +#include <common.h> +#include <command.h> +#include <kgdb.h> +#include <asm/processor.h> + +/* Returns 0 if exception not found and fixup otherwise.  */ +extern unsigned long search_exception_table (unsigned long); + +/* THIS NEEDS CHANGING to use the board info structure. +*/ +#define END_OF_MEM      0x02000000 + +/* + * Trap & Exception support + */ + +void print_backtrace (unsigned long *sp) +{ +	int cnt = 0; +	unsigned long i; + +	printf ("Call backtrace: "); +	while (sp) { +		if ((uint) sp > END_OF_MEM) +			break; + +		i = sp[1]; +		if (cnt++ % 7 == 0) +			printf ("\n"); +		printf ("%08lX ", i); +		if (cnt > 32) +			break; +		sp = (unsigned long *) *sp; +	} +	printf ("\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); + +	printf ("\n"); +	for (i = 0; i < 32; i++) { +		if ((i % 8) == 0) { +			printf ("GPR%02d: ", i); +		} + +		printf ("%08lX ", regs->gpr[i]); +		if ((i % 8) == 7) { +			printf ("\n"); +		} +	} +} + + +void _exception (int signr, struct pt_regs *regs) +{ +	show_regs (regs); +	print_backtrace ((unsigned long *) regs->gpr[1]); +	panic ("Exception in kernel pc %lx signal %d", regs->nip, signr); +} + +void MachineCheckException (struct pt_regs *regs) +{ +	unsigned long fixup; + +	/* Probing PCI using config cycles cause this exception +	 * when a device is not present.  Catch it and return to +	 * the PCI exception handler. +	 */ +	if ((fixup = search_exception_table (regs->nip)) != 0) { +		regs->nip = fixup; +		return; +	} +#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); +	/* refer to 603e Manual (MPC603EUM/AD), chapter 4.5.2.1 */ +	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"); +	} +	show_regs (regs); +	print_backtrace ((unsigned long *) regs->gpr[1]); +	panic ("machine check"); +} + +void AlignmentException (struct pt_regs *regs) +{ +#if defined(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) +{ +#if defined(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) +{ +#if defined(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) +{ +#if defined(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); +} + +#if defined(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); +#if defined(CONFIG_CMD_BEDBUG) +	do_bedbug_breakpoint (regs); +#endif +} + +/* Probe an address by reading.  If not present, return -1, otherwise + * return 0. + */ +int addr_probe (uint * addr) +{ +#if 0 +	int retval; + +	__asm__ __volatile__ ("1: lwz %0,0(%1)\n" +			      "   eieio\n" +			      "   li %0,0\n" +			      "2:\n" +			      ".section .fixup,\"ax\"\n" +			      "3: li %0,-1\n" +			      "   b 2b\n" +			      ".section __ex_table,\"a\"\n" +			      "   .align 2\n" +			      "   .long 1b,3b\n" +			      ".text":"=r" (retval):"r" (addr)); + +	return (retval); +#endif +	return 0; +} diff --git a/arch/powerpc/cpu/mpc8220/u-boot.lds b/arch/powerpc/cpu/mpc8220/u-boot.lds new file mode 100644 index 000000000..31a7a0e4e --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/u-boot.lds @@ -0,0 +1,122 @@ +/* + * (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) +/* 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      : +  { +    arch/powerpc/cpu/mpc8220/start.o	(.text) +    *(.text) +    *(.got1) +    . = ALIGN(16); +    *(.eh_frame) +    *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) +  } +  .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 (NOLOAD)       : +  { +   *(.sbss) *(.scommon) +   *(.dynbss) +   *(.bss) +   *(COMMON) +   . = ALIGN(4); +  } +  _end = . ; +  PROVIDE (end = .); +} diff --git a/arch/powerpc/cpu/mpc8220/uart.c b/arch/powerpc/cpu/mpc8220/uart.c new file mode 100644 index 000000000..0c4b536b4 --- /dev/null +++ b/arch/powerpc/cpu/mpc8220/uart.c @@ -0,0 +1,126 @@ +/* + * (C) Copyright 2004, Freescale, Inc + * TsiChung Liew, Tsi-Chung.Liew@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 + * + */ + +/* + * Minimal serial functions needed to use one of the PSC ports + * as serial console interface. + */ + +#include <common.h> +#include <mpc8220.h> + +DECLARE_GLOBAL_DATA_PTR; + +#define PSC_BASE   MMAP_PSC1 + +#if defined(CONFIG_PSC_CONSOLE) +int serial_init (void) +{ +	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE; +	u32 counter; + +	/* write to SICR: SIM2 = uart mode,dcd does not affect rx */ +	psc->cr = 0; +	psc->ipcr_acr = 0; +	psc->isr_imr = 0; + +	/* write to CSR: RX/TX baud rate from timers */ +	psc->sr_csr = 0xdd000000; + +	psc->mr1_2 = PSC_MR1_BITS_CHAR_8 | PSC_MR1_NO_PARITY | PSC_MR2_STOP_BITS_1; + +	/* Setting up BaudRate */ +	counter = ((gd->bus_clk / gd->baudrate)) >> 5; +	counter++; + +	/* write to CTUR: divide counter upper byte */ +	psc->ctur = ((counter & 0xff00) << 16); +	/* write to CTLR: divide counter lower byte */ +	psc->ctlr = ((counter & 0x00ff) << 24); + +	psc->cr = PSC_CR_RST_RX_CMD; +	psc->cr = PSC_CR_RST_TX_CMD; +	psc->cr = PSC_CR_RST_ERR_STS_CMD; +	psc->cr = PSC_CR_RST_BRK_INT_CMD; +	psc->cr = PSC_CR_RST_MR_PTR_CMD; + +	psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE; +	return (0); +} + +void serial_putc (const char c) +{ +	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE; + +	if (c == '\n') +		serial_putc ('\r'); + +	/* Wait for last character to go. */ +	while (!(psc->sr_csr & PSC_SR_TXRDY)); + +	psc->xmitbuf[0] = c; +} + +void serial_puts (const char *s) +{ +	while (*s) { +		serial_putc (*s++); +	} +} + +int serial_getc (void) +{ +	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE; + +	/* Wait for a character to arrive. */ +	while (!(psc->sr_csr & PSC_SR_RXRDY)); +	return psc->xmitbuf[2]; +} + +int serial_tstc (void) +{ +	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE; + +	return (psc->sr_csr & PSC_SR_RXRDY); +} + +void serial_setbrg (void) +{ +	volatile psc8220_t *psc = (psc8220_t *) PSC_BASE; +	u32 counter; + +	counter = ((gd->bus_clk / gd->baudrate)) >> 5; +	counter++; + +	/* write to CTUR: divide counter upper byte */ +	psc->ctur = ((counter & 0xff00) << 16); +	/* write to CTLR: divide counter lower byte */ +	psc->ctlr = ((counter & 0x00ff) << 24); + +	psc->cr = PSC_CR_RST_RX_CMD; +	psc->cr = PSC_CR_RST_TX_CMD; + +	psc->cr = PSC_CR_RX_ENABLE | PSC_CR_TX_ENABLE; +} +#endif /* CONFIG_PSC_CONSOLE */ |