diff options
| author | Dave Liu <daveliu@freescale.com> | 2006-11-03 12:11:15 -0600 | 
|---|---|---|
| committer | Kim Phillips <kim.phillips@freescale.com> | 2006-11-03 19:42:21 -0600 | 
| commit | 7737d5c658c606f999dfbe3e86b0fed49e5c50ef (patch) | |
| tree | d1bf347ba7f4292def53870ecfcba0a1dd4c6231 | |
| parent | 5f8204394e39bbe8cd9f08b8f8d145b6c01f7c73 (diff) | |
| download | olio-uboot-2014.01-7737d5c658c606f999dfbe3e86b0fed49e5c50ef.tar.xz olio-uboot-2014.01-7737d5c658c606f999dfbe3e86b0fed49e5c50ef.zip | |
mpc83xx: add QE ethernet support
this patch adds support for the QUICC Engine based UCC gigabit ethernet device.
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | board/mpc8360emds/mpc8360emds.c | 56 | ||||
| -rw-r--r-- | cpu/mpc83xx/Makefile | 2 | ||||
| -rw-r--r-- | cpu/mpc83xx/cpu_init.c | 40 | ||||
| -rw-r--r-- | cpu/mpc83xx/qe_io.c | 85 | ||||
| -rw-r--r-- | drivers/qe/Makefile | 43 | ||||
| -rw-r--r-- | drivers/qe/qe.c | 254 | ||||
| -rw-r--r-- | drivers/qe/qe.h | 237 | ||||
| -rw-r--r-- | drivers/qe/uccf.c | 404 | ||||
| -rw-r--r-- | drivers/qe/uccf.h | 130 | ||||
| -rw-r--r-- | drivers/qe/uec.c | 1266 | ||||
| -rw-r--r-- | drivers/qe/uec.h | 716 | ||||
| -rw-r--r-- | drivers/qe/uec_phy.c | 604 | ||||
| -rw-r--r-- | drivers/qe/uec_phy.h | 256 | ||||
| -rw-r--r-- | include/asm-ppc/global_data.h | 2 | ||||
| -rw-r--r-- | include/configs/MPC8360EMDS.h | 29 | ||||
| -rw-r--r-- | include/ioports.h | 11 | ||||
| -rw-r--r-- | net/eth.c | 7 | 
18 files changed, 4138 insertions, 7 deletions
| @@ -203,6 +203,9 @@ LIBS += dtt/libdtt.a  LIBS += drivers/libdrivers.a  LIBS += drivers/nand/libnand.a  LIBS += drivers/nand_legacy/libnand_legacy.a +ifeq ($(CPU),mpc83xx) +LIBS += drivers/qe/qe.a +endif  LIBS += drivers/sk98lin/libsk98lin.a  LIBS += post/libpost.a post/cpu/libcpu.a  LIBS += common/libcommon.a diff --git a/board/mpc8360emds/mpc8360emds.c b/board/mpc8360emds/mpc8360emds.c index d70a4c3cb..5eadcd39e 100644 --- a/board/mpc8360emds/mpc8360emds.c +++ b/board/mpc8360emds/mpc8360emds.c @@ -29,6 +29,62 @@  #include <asm/mmu.h>  #endif +const qe_iop_conf_t qe_iop_conf_tab[] = { +	/* GETH1 */ +	{0,  3, 1, 0, 1}, /* TxD0 */ +	{0,  4, 1, 0, 1}, /* TxD1 */ +	{0,  5, 1, 0, 1}, /* TxD2 */ +	{0,  6, 1, 0, 1}, /* TxD3 */ +	{1,  6, 1, 0, 3}, /* TxD4 */ +	{1,  7, 1, 0, 1}, /* TxD5 */ +	{1,  9, 1, 0, 2}, /* TxD6 */ +	{1, 10, 1, 0, 2}, /* TxD7 */ +	{0,  9, 2, 0, 1}, /* RxD0 */ +	{0, 10, 2, 0, 1}, /* RxD1 */ +	{0, 11, 2, 0, 1}, /* RxD2 */ +	{0, 12, 2, 0, 1}, /* RxD3 */ +	{0, 13, 2, 0, 1}, /* RxD4 */ +	{1,  1, 2, 0, 2}, /* RxD5 */ +	{1,  0, 2, 0, 2}, /* RxD6 */ +	{1,  4, 2, 0, 2}, /* RxD7 */ +	{0,  7, 1, 0, 1}, /* TX_EN */ +	{0,  8, 1, 0, 1}, /* TX_ER */ +	{0, 15, 2, 0, 1}, /* RX_DV */ +	{0, 16, 2, 0, 1}, /* RX_ER */ +	{0,  0, 2, 0, 1}, /* RX_CLK */ +	{2,  9, 1, 0, 3}, /* GTX_CLK - CLK10 */ +	{2,  8, 2, 0, 1}, /* GTX125 - CLK9 */ +	/* GETH2 */ +	{0, 17, 1, 0, 1}, /* TxD0 */ +	{0, 18, 1, 0, 1}, /* TxD1 */ +	{0, 19, 1, 0, 1}, /* TxD2 */ +	{0, 20, 1, 0, 1}, /* TxD3 */ +	{1,  2, 1, 0, 1}, /* TxD4 */ +	{1,  3, 1, 0, 2}, /* TxD5 */ +	{1,  5, 1, 0, 3}, /* TxD6 */ +	{1,  8, 1, 0, 3}, /* TxD7 */ +	{0, 23, 2, 0, 1}, /* RxD0 */ +	{0, 24, 2, 0, 1}, /* RxD1 */ +	{0, 25, 2, 0, 1}, /* RxD2 */ +	{0, 26, 2, 0, 1}, /* RxD3 */ +	{0, 27, 2, 0, 1}, /* RxD4 */ +	{1, 12, 2, 0, 2}, /* RxD5 */ +	{1, 13, 2, 0, 3}, /* RxD6 */ +	{1, 11, 2, 0, 2}, /* RxD7 */ +	{0, 21, 1, 0, 1}, /* TX_EN */ +	{0, 22, 1, 0, 1}, /* TX_ER */ +	{0, 29, 2, 0, 1}, /* RX_DV */ +	{0, 30, 2, 0, 1}, /* RX_ER */ +	{0, 31, 2, 0, 1}, /* RX_CLK */ +	{2,  2, 1, 0, 2}, /* GTX_CLK = CLK10 */ +	{2,  3, 2, 0, 1}, /* GTX125 - CLK4 */ + +	{0,  1, 3, 0, 2}, /* MDIO */ +	{0,  2, 1, 0, 1}, /* MDC */ + +	{0,  0, 0, 0, QE_IOP_TAB_END}, /* END of table */ +}; +  int board_early_init_f(void)  {  	volatile u8 *bcsr = (volatile u8 *)CFG_BCSR; diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile index 1aa0005d4..e254ef98f 100644 --- a/cpu/mpc83xx/Makefile +++ b/cpu/mpc83xx/Makefile @@ -29,7 +29,7 @@ LIB	= $(obj)lib$(CPU).a  START	= start.o  COBJS	= traps.o cpu.o cpu_init.o speed.o interrupts.o \ -	  i2c.o spd_sdram.o +	  i2c.o spd_sdram.o qe_io.o  SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)  OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS)) diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c index 999fe7196..eb8f8c042 100644 --- a/cpu/mpc83xx/cpu_init.c +++ b/cpu/mpc83xx/cpu_init.c @@ -1,5 +1,5 @@  /* - * Copyright 2004 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2006 Freescale Semiconductor, Inc.   *   * See file CREDITS for list of people who contributed to this   * project. @@ -31,6 +31,30 @@  DECLARE_GLOBAL_DATA_PTR; +#ifdef CONFIG_QE +extern qe_iop_conf_t qe_iop_conf_tab[]; +extern void qe_config_iopin(u8 port, u8 pin, int dir, +			 int open_drain, int assign); +extern void qe_init(uint qe_base); +extern void qe_reset(void); + +static void config_qe_ioports(void) +{ +	u8	port, pin; +	int	dir, open_drain, assign; +	int	i; + +	for (i = 0; qe_iop_conf_tab[i].assign != QE_IOP_TAB_END; i++) { +		port		= qe_iop_conf_tab[i].port; +		pin		= qe_iop_conf_tab[i].pin; +		dir		= qe_iop_conf_tab[i].dir; +		open_drain	= qe_iop_conf_tab[i].open_drain; +		assign		= qe_iop_conf_tab[i].assign; +		qe_config_iopin(port, pin, dir, open_drain, assign); +	} +} +#endif +  /*   * Breathe some life into the CPU...   * @@ -100,6 +124,10 @@ void cpu_init_f (volatile immap_t * im)  #ifdef CFG_SICRL  	im->sysconf.sicrl = CFG_SICRL;  #endif +#ifdef CONFIG_QE +	/* Config QE ioports */ +	config_qe_ioports(); +#endif  	/*  	 * Memory Controller: @@ -188,12 +216,12 @@ void cpu_init_f (volatile immap_t * im)  #endif  } - -/* - * Initialize higher level parts of CPU like time base and timers. - */ -  int cpu_init_r (void)  { +#ifdef CONFIG_QE +	uint qe_base = CFG_IMMRBAR + 0x00100000; /* QE immr base */ +	qe_init(qe_base); +	qe_reset(); +#endif  	return 0;  } diff --git a/cpu/mpc83xx/qe_io.c b/cpu/mpc83xx/qe_io.c new file mode 100644 index 000000000..11cf3722b --- /dev/null +++ b/cpu/mpc83xx/qe_io.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "common.h" +#include "asm/errno.h" +#include "asm/io.h" +#include "asm/immap_83xx.h" + +#if defined(CONFIG_QE) +#define	NUM_OF_PINS	32 +void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign) +{ +	u32			pin_2bit_mask; +	u32			pin_2bit_dir; +	u32			pin_2bit_assign; +	u32			pin_1bit_mask; +	u32			tmp_val; +	volatile immap_t	*im = (volatile immap_t *)CFG_IMMRBAR; +	volatile gpio83xx_t	*par_io =(volatile gpio83xx_t *)&im->gpio; + +	/* Caculate pin location and 2bit mask and dir */ +	pin_2bit_mask = (u32)(0x3 << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); +	pin_2bit_dir = (u32)(dir << (NUM_OF_PINS-(pin%(NUM_OF_PINS/2)+1)*2)); + +	/* Setup the direction */ +	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? \ +		in_be32(&par_io->ioport[port].dir2) : +		in_be32(&par_io->ioport[port].dir1); + +	if (pin > (NUM_OF_PINS/2) -1) { +		out_be32(&par_io->ioport[port].dir2, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io->ioport[port].dir2, pin_2bit_dir | tmp_val); +	} else { +		out_be32(&par_io->ioport[port].dir1, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io->ioport[port].dir1, pin_2bit_dir | tmp_val); +	} + +	/* Calculate pin location for 1bit mask */ +	pin_1bit_mask = (u32)(1 << (NUM_OF_PINS - (pin+1))); + +	/* Setup the open drain */ +	tmp_val = in_be32(&par_io->ioport[port].podr); +	if (open_drain) { +		out_be32(&par_io->ioport[port].podr, pin_1bit_mask | tmp_val); +	} else { +		out_be32(&par_io->ioport[port].podr, ~pin_1bit_mask & tmp_val); +	} + +	/* Setup the assignment */ +	tmp_val = (pin > (NUM_OF_PINS/2) - 1) ? +		in_be32(&par_io->ioport[port].ppar2): +		in_be32(&par_io->ioport[port].ppar1); +	pin_2bit_assign = (u32)(assign +				<< (NUM_OF_PINS - (pin%(NUM_OF_PINS/2)+1)*2)); + +	/* Clear and set 2 bits mask */ +	if (pin > (NUM_OF_PINS/2) - 1) { +		out_be32(&par_io->ioport[port].ppar2, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io->ioport[port].ppar2, pin_2bit_assign | tmp_val); +	} else { +		out_be32(&par_io->ioport[port].ppar1, ~pin_2bit_mask & tmp_val); +		out_be32(&par_io->ioport[port].ppar1, pin_2bit_assign | tmp_val); +	} +} + +#endif /* CONFIG_QE */ diff --git a/drivers/qe/Makefile b/drivers/qe/Makefile new file mode 100644 index 000000000..4844181b8 --- /dev/null +++ b/drivers/qe/Makefile @@ -0,0 +1,43 @@ +# +# Copyright (C) 2006 Freescale Semiconductor, Inc. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +include $(TOPDIR)/config.mk + +LIB 	:= $(obj)qe.a + +COBJS 	:= qe.o uccf.o uec.o uec_phy.o + +SRCS 	:= $(COBJS:.o=.c) +OBJS 	:= $(addprefix $(obj),$(COBJS)) + +all:	$(LIB) + +$(LIB):	$(obj).depend $(OBJS) +	$(AR) $(ARFLAGS) $@ $(OBJS) + +######################################################################### + +include $(SRCTREE)/rules.mk + +sinclude $(obj).depend + +######################################################################### diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c new file mode 100644 index 000000000..5f209629f --- /dev/null +++ b/drivers/qe/qe.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "common.h" +#include "asm/errno.h" +#include "asm/io.h" +#include "asm/immap_qe.h" +#include "qe.h" + +#if defined(CONFIG_QE) +qe_map_t		*qe_immr = NULL; +static qe_snum_t	snums[QE_NUM_OF_SNUM]; + +void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data) +{ +	u32           cecr; + +	if (cmd == QE_RESET) { +		out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG)); +	} else { +		out_be32(&qe_immr->cp.cecdr, cmd_data); +		out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG | +			 ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd)); +	} +	/* Wait for the QE_CR_FLG to clear */ +	do { +		cecr = in_be32(&qe_immr->cp.cecr); +	} while (cecr & QE_CR_FLG); + +	return; +} + +uint qe_muram_alloc(uint size, uint align) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	uint	retloc; +	uint	align_mask, off; +	uint	savebase; + +	align_mask = align - 1; +	savebase = gd->mp_alloc_base; + +	if ((off = (gd->mp_alloc_base & align_mask)) != 0) +		gd->mp_alloc_base += (align - off); + +	if ((off = size & align_mask) != 0) +		size += (align - off); + +	if ((gd->mp_alloc_base + size) >= gd->mp_alloc_top) { +		gd->mp_alloc_base = savebase; +		printf("%s: ran out of ram.\n",  __FUNCTION__); +	} + +	retloc = gd->mp_alloc_base; +	gd->mp_alloc_base += size; + +	memset((void *)&qe_immr->muram[retloc], 0, size); + +	__asm__ __volatile__("sync"); + +	return retloc; +} + +void *qe_muram_addr(uint offset) +{ +	return (void *)&qe_immr->muram[offset]; +} + +static void qe_sdma_init(void) +{ +	volatile sdma_t	*p; +	uint		sdma_buffer_base; + +	p = (volatile sdma_t *)&qe_immr->sdma; + +	/* All of DMA transaction in bus 1 */ +	out_be32(&p->sdaqr, 0); +	out_be32(&p->sdaqmr, 0); + +	/* Allocate 2KB temporary buffer for sdma */ +	sdma_buffer_base = qe_muram_alloc(2048, 64); +	out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK); + +	/* Clear sdma status */ +	out_be32(&p->sdsr, 0x03000000); + +	/* Enable global mode on bus 1, and 2KB buffer size */ +	out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT)); +} + +static u8 thread_snum[QE_NUM_OF_SNUM] = { +	0x04, 0x05, 0x0c, 0x0d, +	0x14, 0x15, 0x1c, 0x1d, +	0x24, 0x25, 0x2c, 0x2d, +	0x34, 0x35, 0x88, 0x89, +	0x98, 0x99, 0xa8, 0xa9, +	0xb8, 0xb9, 0xc8, 0xc9, +	0xd8, 0xd9, 0xe8, 0xe9 +}; + +static void qe_snums_init(void) +{ +	int	i; + +	for (i = 0; i < QE_NUM_OF_SNUM; i++) { +		snums[i].state = QE_SNUM_STATE_FREE; +		snums[i].num   = thread_snum[i]; +	} +} + +int qe_get_snum(void) +{ +	int	snum = -EBUSY; +	int	i; + +	for (i = 0; i < QE_NUM_OF_SNUM; i++) { +		if (snums[i].state == QE_SNUM_STATE_FREE) { +			snums[i].state = QE_SNUM_STATE_USED; +			snum = snums[i].num; +			break; +		} +	} + +	return snum; +} + +void qe_put_snum(u8 snum) +{ +	int	i; + +	for (i = 0; i < QE_NUM_OF_SNUM; i++) { +		if (snums[i].num == snum) { +			snums[i].state = QE_SNUM_STATE_FREE; +			break; +		} +	} +} + +void qe_init(uint qe_base) +{ +	DECLARE_GLOBAL_DATA_PTR; + +	/* Init the QE IMMR base */ +	qe_immr = (qe_map_t *)qe_base; + +	gd->mp_alloc_base = QE_DATAONLY_BASE; +	gd->mp_alloc_top = gd->mp_alloc_base + QE_DATAONLY_SIZE; + +	qe_sdma_init(); +	qe_snums_init(); +} + +void qe_reset(void) +{ +	qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID, +			 (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0); +} + +void qe_assign_page(uint snum, uint para_ram_base) +{ +	u32	cecr; + +	out_be32(&qe_immr->cp.cecdr, para_ram_base); +	out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT) +					 | QE_CR_FLG | QE_ASSIGN_PAGE); + +	/* Wait for the QE_CR_FLG to clear */ +	do { +		cecr = in_be32(&qe_immr->cp.cecr); +	} while (cecr & QE_CR_FLG ); + +	return; +} + +/* + * brg: 0~15 as BRG1~BRG16 +   rate: baud rate + * BRG input clock comes from the BRGCLK (internal clock generated from +   the QE clock, it is one-half of the QE clock), If need the clock source +   from CLKn pin, we have te change the function. + */ + +#define BRG_CLK		(gd->brg_clk) + +int qe_set_brg(uint brg, uint rate) +{ +	DECLARE_GLOBAL_DATA_PTR; +	volatile uint	*bp; +	u32		divisor; +	int		div16 = 0; + +	if (brg >= QE_NUM_OF_BRGS) +		return -EINVAL; +	bp = (uint *)&qe_immr->brg.brgc1; +	bp += brg; + +	divisor = (BRG_CLK / rate); +	if (divisor > QE_BRGC_DIVISOR_MAX + 1) { +		div16 = 1; +		divisor /= 16; +	} + +	*bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE; +	__asm__ __volatile__("sync"); + +	if (div16) { +		*bp |= QE_BRGC_DIV16; +		__asm__ __volatile__("sync"); +	} + +	return 0; +} + +/* Set ethernet MII clock master +*/ +int qe_set_mii_clk_src(int ucc_num) +{ +	u32	cmxgcr; + +	/* check if the UCC number is in range. */ +	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { +		printf("%s: ucc num not in ranges\n", __FUNCTION__); +		return -EINVAL; +	} + +	cmxgcr = in_be32(&qe_immr->qmx.cmxgcr); +	cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK; +	cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT); +	out_be32(&qe_immr->qmx.cmxgcr, cmxgcr); + +	return 0; +} + +#endif /* CONFIG_QE */ diff --git a/drivers/qe/qe.h b/drivers/qe/qe.h new file mode 100644 index 000000000..f7f8ed0a7 --- /dev/null +++ b/drivers/qe/qe.h @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __QE_H__ +#define __QE_H__ + +#include "common.h" + +#define QE_NUM_OF_SNUM	28 +#define QE_NUM_OF_BRGS	16 +#define UCC_MAX_NUM	8 + +#define QE_DATAONLY_BASE	(uint)(128) +#define QE_DATAONLY_SIZE	((uint)(0xc000) - QE_DATAONLY_BASE) + +/* QE threads SNUM +*/ +typedef enum qe_snum_state { +	QE_SNUM_STATE_USED,   /* used */ +	QE_SNUM_STATE_FREE    /* free */ +} qe_snum_state_e; + +typedef struct qe_snum { +	u8		num;   /* snum  */ +	qe_snum_state_e	state; /* state */ +} qe_snum_t; + +/* QE RISC allocation +*/ +typedef enum qe_risc_allocation { +	QE_RISC_ALLOCATION_RISC1		= 1,  /* RISC 1 */ +	QE_RISC_ALLOCATION_RISC2		= 2,  /* RISC 2 */ +	QE_RISC_ALLOCATION_RISC1_AND_RISC2	= 3   /* RISC 1 or RISC 2 */ +} qe_risc_allocation_e; + +/* QE CECR commands for UCC fast. +*/ +#define QE_CR_FLG			0x00010000 +#define QE_RESET			0x80000000 +#define QE_INIT_TX_RX			0x00000000 +#define QE_INIT_RX			0x00000001 +#define QE_INIT_TX			0x00000002 +#define QE_ENTER_HUNT_MODE		0x00000003 +#define QE_STOP_TX			0x00000004 +#define QE_GRACEFUL_STOP_TX		0x00000005 +#define QE_RESTART_TX			0x00000006 +#define QE_SWITCH_COMMAND		0x00000007 +#define QE_SET_GROUP_ADDRESS		0x00000008 +#define QE_INSERT_CELL			0x00000009 +#define QE_ATM_TRANSMIT			0x0000000a +#define QE_CELL_POOL_GET		0x0000000b +#define QE_CELL_POOL_PUT		0x0000000c +#define QE_IMA_HOST_CMD			0x0000000d +#define QE_ATM_MULTI_THREAD_INIT	0x00000011 +#define QE_ASSIGN_PAGE			0x00000012 +#define QE_START_FLOW_CONTROL		0x00000014 +#define QE_STOP_FLOW_CONTROL		0x00000015 +#define QE_ASSIGN_PAGE_TO_DEVICE	0x00000016 +#define QE_GRACEFUL_STOP_RX		0x0000001a +#define QE_RESTART_RX			0x0000001b + +/* QE CECR Sub Block Code - sub block code of QE command. +*/ +#define QE_CR_SUBBLOCK_INVALID		0x00000000 +#define QE_CR_SUBBLOCK_USB		0x03200000 +#define QE_CR_SUBBLOCK_UCCFAST1		0x02000000 +#define QE_CR_SUBBLOCK_UCCFAST2		0x02200000 +#define QE_CR_SUBBLOCK_UCCFAST3		0x02400000 +#define QE_CR_SUBBLOCK_UCCFAST4		0x02600000 +#define QE_CR_SUBBLOCK_UCCFAST5		0x02800000 +#define QE_CR_SUBBLOCK_UCCFAST6		0x02a00000 +#define QE_CR_SUBBLOCK_UCCFAST7		0x02c00000 +#define QE_CR_SUBBLOCK_UCCFAST8		0x02e00000 +#define QE_CR_SUBBLOCK_UCCSLOW1		0x00000000 +#define QE_CR_SUBBLOCK_UCCSLOW2		0x00200000 +#define QE_CR_SUBBLOCK_UCCSLOW3		0x00400000 +#define QE_CR_SUBBLOCK_UCCSLOW4		0x00600000 +#define QE_CR_SUBBLOCK_UCCSLOW5		0x00800000 +#define QE_CR_SUBBLOCK_UCCSLOW6		0x00a00000 +#define QE_CR_SUBBLOCK_UCCSLOW7		0x00c00000 +#define QE_CR_SUBBLOCK_UCCSLOW8		0x00e00000 +#define QE_CR_SUBBLOCK_MCC1		0x03800000 +#define QE_CR_SUBBLOCK_MCC2		0x03a00000 +#define QE_CR_SUBBLOCK_MCC3		0x03000000 +#define QE_CR_SUBBLOCK_IDMA1		0x02800000 +#define QE_CR_SUBBLOCK_IDMA2		0x02a00000 +#define QE_CR_SUBBLOCK_IDMA3		0x02c00000 +#define QE_CR_SUBBLOCK_IDMA4		0x02e00000 +#define QE_CR_SUBBLOCK_HPAC		0x01e00000 +#define QE_CR_SUBBLOCK_SPI1		0x01400000 +#define QE_CR_SUBBLOCK_SPI2		0x01600000 +#define QE_CR_SUBBLOCK_RAND		0x01c00000 +#define QE_CR_SUBBLOCK_TIMER		0x01e00000 +#define QE_CR_SUBBLOCK_GENERAL		0x03c00000 + +/* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command. +*/ +#define QE_CR_PROTOCOL_UNSPECIFIED	0x00 /* For all other protocols */ +#define QE_CR_PROTOCOL_HDLC_TRANSPARENT	0x00 +#define QE_CR_PROTOCOL_ATM_POS		0x0A +#define QE_CR_PROTOCOL_ETHERNET		0x0C +#define QE_CR_PROTOCOL_L2_SWITCH	0x0D +#define QE_CR_PROTOCOL_SHIFT		6 + +/* QE ASSIGN PAGE command +*/ +#define QE_CR_ASSIGN_PAGE_SNUM_SHIFT	17 + +/* Communication Direction. +*/ +typedef enum comm_dir { +	COMM_DIR_NONE		= 0, +	COMM_DIR_RX		= 1, +	COMM_DIR_TX		= 2, +	COMM_DIR_RX_AND_TX	= 3 +} comm_dir_e; + +/* Clocks and BRG's +*/ +typedef enum qe_clock { +	QE_CLK_NONE = 0, +	QE_BRG1,     /* Baud Rate Generator  1 */ +	QE_BRG2,     /* Baud Rate Generator  2 */ +	QE_BRG3,     /* Baud Rate Generator  3 */ +	QE_BRG4,     /* Baud Rate Generator  4 */ +	QE_BRG5,     /* Baud Rate Generator  5 */ +	QE_BRG6,     /* Baud Rate Generator  6 */ +	QE_BRG7,     /* Baud Rate Generator  7 */ +	QE_BRG8,     /* Baud Rate Generator  8 */ +	QE_BRG9,     /* Baud Rate Generator  9 */ +	QE_BRG10,    /* Baud Rate Generator 10 */ +	QE_BRG11,    /* Baud Rate Generator 11 */ +	QE_BRG12,    /* Baud Rate Generator 12 */ +	QE_BRG13,    /* Baud Rate Generator 13 */ +	QE_BRG14,    /* Baud Rate Generator 14 */ +	QE_BRG15,    /* Baud Rate Generator 15 */ +	QE_BRG16,    /* Baud Rate Generator 16 */ +	QE_CLK1,     /* Clock  1               */ +	QE_CLK2,     /* Clock  2               */ +	QE_CLK3,     /* Clock  3               */ +	QE_CLK4,     /* Clock  4               */ +	QE_CLK5,     /* Clock  5               */ +	QE_CLK6,     /* Clock  6               */ +	QE_CLK7,     /* Clock  7               */ +	QE_CLK8,     /* Clock  8               */ +	QE_CLK9,     /* Clock  9               */ +	QE_CLK10,    /* Clock 10               */ +	QE_CLK11,    /* Clock 11               */ +	QE_CLK12,    /* Clock 12               */ +	QE_CLK13,    /* Clock 13               */ +	QE_CLK14,    /* Clock 14               */ +	QE_CLK15,    /* Clock 15               */ +	QE_CLK16,    /* Clock 16               */ +	QE_CLK17,    /* Clock 17               */ +	QE_CLK18,    /* Clock 18               */ +	QE_CLK19,    /* Clock 19               */ +	QE_CLK20,    /* Clock 20               */ +	QE_CLK21,    /* Clock 21               */ +	QE_CLK22,    /* Clock 22               */ +	QE_CLK23,    /* Clock 23               */ +	QE_CLK24,    /* Clock 24               */ +	QE_CLK_DUMMY +} qe_clock_e; + +/* QE CMXGCR register +*/ +#define QE_CMXGCR_MII_ENET_MNG_MASK	0x00007000 +#define QE_CMXGCR_MII_ENET_MNG_SHIFT	12 + +/* QE CMXUCR registers + */ +#define QE_CMXUCR_TX_CLK_SRC_MASK	0x0000000F + +/* QE BRG configuration register +*/ +#define QE_BRGC_ENABLE			0x00010000 +#define QE_BRGC_DIVISOR_SHIFT		1 +#define QE_BRGC_DIVISOR_MAX		0xFFF +#define QE_BRGC_DIV16			1 + +/* QE SDMA registers +*/ +#define QE_SDSR_BER1			0x02000000 +#define QE_SDSR_BER2			0x01000000 + +#define QE_SDMR_GLB_1_MSK		0x80000000 +#define QE_SDMR_ADR_SEL			0x20000000 +#define QE_SDMR_BER1_MSK		0x02000000 +#define QE_SDMR_BER2_MSK		0x01000000 +#define QE_SDMR_EB1_MSK			0x00800000 +#define QE_SDMR_ER1_MSK			0x00080000 +#define QE_SDMR_ER2_MSK			0x00040000 +#define QE_SDMR_CEN_MASK		0x0000E000 +#define QE_SDMR_SBER_1			0x00000200 +#define QE_SDMR_SBER_2			0x00000200 +#define QE_SDMR_EB1_PR_MASK		0x000000C0 +#define QE_SDMR_ER1_PR			0x00000008 + +#define QE_SDMR_CEN_SHIFT		13 +#define QE_SDMR_EB1_PR_SHIFT		6 + +#define QE_SDTM_MSNUM_SHIFT		24 + +#define QE_SDEBCR_BA_MASK		0x01FFFFFF + +void qe_config_iopin(u8 port, u8 pin, int dir, int open_drain, int assign); +void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data); +uint qe_muram_alloc(uint size, uint align); +void *qe_muram_addr(uint offset); +int qe_get_snum(void); +void qe_put_snum(u8 snum); +void qe_init(uint qe_base); +void qe_reset(void); +void qe_assign_page(uint snum, uint para_ram_base); +int qe_set_brg(uint brg, uint rate); +int qe_set_mii_clk_src(int ucc_num); + +#endif /* __QE_H__ */ diff --git a/drivers/qe/uccf.c b/drivers/qe/uccf.c new file mode 100644 index 000000000..25f74826c --- /dev/null +++ b/drivers/qe/uccf.c @@ -0,0 +1,404 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "common.h" +#include "malloc.h" +#include "asm/errno.h" +#include "asm/io.h" +#include "asm/immap_qe.h" +#include "qe.h" +#include "uccf.h" + +#if defined(CONFIG_QE) +void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf) +{ +	out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD); +} + +u32 ucc_fast_get_qe_cr_subblock(int ucc_num) +{ +	switch (ucc_num) { +		case 0:	return QE_CR_SUBBLOCK_UCCFAST1; +		case 1:	return QE_CR_SUBBLOCK_UCCFAST2; +		case 2:	return QE_CR_SUBBLOCK_UCCFAST3; +		case 3:	return QE_CR_SUBBLOCK_UCCFAST4; +		case 4:	return QE_CR_SUBBLOCK_UCCFAST5; +		case 5:	return QE_CR_SUBBLOCK_UCCFAST6; +		case 6:	return QE_CR_SUBBLOCK_UCCFAST7; +		case 7:	return QE_CR_SUBBLOCK_UCCFAST8; +		default:	return QE_CR_SUBBLOCK_INVALID; +    } +} + +static void ucc_get_cmxucr_reg(int ucc_num, volatile u32 **p_cmxucr, +				 u8 *reg_num, u8 *shift) +{ +	switch (ucc_num) { +		case 0:	/* UCC1 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr1); +			*reg_num = 1; +			*shift  = 16; +			break; +		case 2:	/* UCC3 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr1); +			*reg_num = 1; +			*shift  = 0; +			break; +		case 4:	/* UCC5 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr2); +			*reg_num = 2; +			*shift  = 16; +			break; +		case 6:	/* UCC7 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr2); +			*reg_num = 2; +			*shift  = 0; +			break; +		case 1:	/* UCC2 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr3); +			*reg_num = 3; +			*shift  = 16; +			break; +		case 3:	/* UCC4 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr3); +			*reg_num = 3; +			*shift  = 0; +			break; +		case 5:	/* UCC6 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr4); +			*reg_num = 4; +			*shift  = 16; +			break; +		case 7:	/* UCC8 */ +			*p_cmxucr  = &(qe_immr->qmx.cmxucr4); +			*reg_num = 4; +			*shift  = 0; +			break; +		default: +			break; +	} +} + +static int ucc_set_clk_src(int ucc_num, qe_clock_e clock, comm_dir_e mode) +{ +	volatile u32	*p_cmxucr; +	u8		reg_num; +	u8		shift; +	u32		clockBits; +	u32		clockMask; +	int		source = -1; + +	/* check if the UCC number is in range. */ +	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) +		return -EINVAL; + +	if (! ((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) { +		printf("%s: bad comm mode type passed\n", __FUNCTION__); +		return -EINVAL; +	} + +	ucc_get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift); + +	switch (reg_num) { +		case 1: +			switch (clock) { +				case QE_BRG1:	source = 1; break; +				case QE_BRG2:	source = 2; break; +				case QE_BRG7:	source = 3; break; +				case QE_BRG8:	source = 4; break; +				case QE_CLK9:	source = 5; break; +				case QE_CLK10:	source = 6; break; +				case QE_CLK11:	source = 7; break; +				case QE_CLK12:	source = 8; break; +				case QE_CLK15:	source = 9; break; +				case QE_CLK16:	source = 10; break; +				default:	source = -1; break; +			} +			break; +		case 2: +			switch (clock) { +				case QE_BRG5:	source = 1; break; +				case QE_BRG6:	source = 2; break; +				case QE_BRG7:	source = 3; break; +				case QE_BRG8:	source = 4; break; +				case QE_CLK13:	source = 5; break; +				case QE_CLK14:	source = 6; break; +				case QE_CLK19:	source = 7; break; +				case QE_CLK20:	source = 8; break; +				case QE_CLK15:	source = 9; break; +				case QE_CLK16:	source = 10; break; +				default:	source = -1; break; +			} +			break; +		case 3: +			switch (clock) { +				case QE_BRG9:	source = 1; break; +				case QE_BRG10:	source = 2; break; +				case QE_BRG15:	source = 3; break; +				case QE_BRG16:	source = 4; break; +				case QE_CLK3:	source = 5; break; +				case QE_CLK4:	source = 6; break; +				case QE_CLK17:	source = 7; break; +				case QE_CLK18:	source = 8; break; +				case QE_CLK7:	source = 9; break; +				case QE_CLK8:	source = 10; break; +				case QE_CLK16:	source = 11; break; +				default:	source = -1; break; +			} +			break; +		case 4: +			switch (clock) { +				case QE_BRG13:	source = 1; break; +				case QE_BRG14:	source = 2; break; +				case QE_BRG15:	source = 3; break; +				case QE_BRG16:	source = 4; break; +				case QE_CLK5:	source = 5; break; +				case QE_CLK6:	source = 6; break; +				case QE_CLK21:	source = 7; break; +				case QE_CLK22:	source = 8; break; +				case QE_CLK7:	source = 9; break; +				case QE_CLK8:	source = 10; break; +				case QE_CLK16:	source = 11; break; +				default:	source = -1; break; +			} +			break; +		default: +			source = -1; +			break; +	} + +	if (source == -1) { +		printf("%s: Bad combination of clock and UCC\n", __FUNCTION__); +		return -ENOENT; +	} + +	clockBits = (u32) source; +	clockMask = QE_CMXUCR_TX_CLK_SRC_MASK; +	if (mode == COMM_DIR_RX) { +		clockBits <<= 4; /* Rx field is 4 bits to left of Tx field */ +		clockMask <<= 4; /* Rx field is 4 bits to left of Tx field */ +	} +	clockBits <<= shift; +	clockMask <<= shift; + +	out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clockMask) | clockBits); + +	return 0; +} + +static uint ucc_get_reg_baseaddr(int ucc_num) +{ +	uint base = 0; + +	/* check if the UCC number is in range */ +	if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) { +		printf("%s: the UCC num not in ranges\n", __FUNCTION__); +		return 0; +	} + +	switch (ucc_num) { +		case 0:	base = 0x00002000; break; +		case 1:	base = 0x00003000; break; +		case 2:	base = 0x00002200; break; +		case 3:	base = 0x00003200; break; +		case 4:	base = 0x00002400; break; +		case 5:	base = 0x00003400; break; +		case 6:	base = 0x00002600; break; +		case 7:	base = 0x00003600; break; +		default: break; +	} + +	base = (uint)qe_immr + base; +	return base; +} + +void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode) +{ +	ucc_fast_t	*uf_regs; +	u32		gumr; + +	uf_regs = uccf->uf_regs; + +	/* Enable reception and/or transmission on this UCC. */ +	gumr = in_be32(&uf_regs->gumr); +	if (mode & COMM_DIR_TX) { +		gumr |= UCC_FAST_GUMR_ENT; +		uccf->enabled_tx = 1; +	} +	if (mode & COMM_DIR_RX) { +		gumr |= UCC_FAST_GUMR_ENR; +		uccf->enabled_rx = 1; +	} +	out_be32(&uf_regs->gumr, gumr); +} + +void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode) +{ +	ucc_fast_t	*uf_regs; +	u32		gumr; + +	uf_regs = uccf->uf_regs; + +	/* Disable reception and/or transmission on this UCC. */ +	gumr = in_be32(&uf_regs->gumr); +	if (mode & COMM_DIR_TX) { +		gumr &= ~UCC_FAST_GUMR_ENT; +		uccf->enabled_tx = 0; +	} +	if (mode & COMM_DIR_RX) { +		gumr &= ~UCC_FAST_GUMR_ENR; +		uccf->enabled_rx = 0; +	} +	out_be32(&uf_regs->gumr, gumr); +} + +int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t  **uccf_ret) +{ +	ucc_fast_private_t	*uccf; +	ucc_fast_t		*uf_regs; + +	if (!uf_info) +		return -EINVAL; + +	if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) { +		printf("%s: Illagal UCC number!\n", __FUNCTION__); +		return -EINVAL; +	} + +	uccf = (ucc_fast_private_t *)malloc(sizeof(ucc_fast_private_t)); +	if (!uccf) { +		printf("%s: No memory for UCC fast data structure!\n", +			 __FUNCTION__); +		return -ENOMEM; +	} +	memset(uccf, 0, sizeof(ucc_fast_private_t)); + +	/* Save fast UCC structure */ +	uccf->uf_info	= uf_info; +	uccf->uf_regs	= (ucc_fast_t *)ucc_get_reg_baseaddr(uf_info->ucc_num); + +	if (uccf->uf_regs == NULL) { +		printf("%s: No memory map for UCC fast controller!\n", +			 __FUNCTION__); +		return -ENOMEM; +	} + +	uccf->enabled_tx	= 0; +	uccf->enabled_rx	= 0; + +	uf_regs			= uccf->uf_regs; +	uccf->p_ucce		= (u32 *) &(uf_regs->ucce); +	uccf->p_uccm		= (u32 *) &(uf_regs->uccm); + +	/* Init GUEMR register, UCC both Rx and Tx is Fast protocol */ +	out_8(&uf_regs->guemr, UCC_GUEMR_SET_RESERVED3 | UCC_GUEMR_MODE_FAST_RX +				 | UCC_GUEMR_MODE_FAST_TX); + +	/* Set GUMR, disable UCC both Rx and Tx, Ethernet protocol */ +	out_be32(&uf_regs->gumr, UCC_FAST_GUMR_ETH); + +	/* Set the Giga ethernet VFIFO stuff */ +	if (uf_info->eth_type == GIGA_ETH) { +		/* Allocate memory for Tx Virtual Fifo */ +		uccf->ucc_fast_tx_virtual_fifo_base_offset = +		qe_muram_alloc(UCC_GETH_UTFS_GIGA_INIT, +				 UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + +		/* Allocate memory for Rx Virtual Fifo */ +		uccf->ucc_fast_rx_virtual_fifo_base_offset = +		qe_muram_alloc(UCC_GETH_URFS_GIGA_INIT + +				 UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD, +				UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + +		/* utfb, urfb are offsets from MURAM base */ +		out_be32(&uf_regs->utfb, +			 uccf->ucc_fast_tx_virtual_fifo_base_offset); +		out_be32(&uf_regs->urfb, +			 uccf->ucc_fast_rx_virtual_fifo_base_offset); + +		/* Set Virtual Fifo registers */ +		out_be16(&uf_regs->urfs, UCC_GETH_URFS_GIGA_INIT); +		out_be16(&uf_regs->urfet, UCC_GETH_URFET_GIGA_INIT); +		out_be16(&uf_regs->urfset, UCC_GETH_URFSET_GIGA_INIT); +		out_be16(&uf_regs->utfs, UCC_GETH_UTFS_GIGA_INIT); +		out_be16(&uf_regs->utfet, UCC_GETH_UTFET_GIGA_INIT); +		out_be16(&uf_regs->utftt, UCC_GETH_UTFTT_GIGA_INIT); +	} + +	/* Set the Fast ethernet VFIFO stuff */ +	if (uf_info->eth_type == FAST_ETH) { +		/* Allocate memory for Tx Virtual Fifo */ +		uccf->ucc_fast_tx_virtual_fifo_base_offset = +		qe_muram_alloc(UCC_GETH_UTFS_INIT, +				 UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + +		/* Allocate memory for Rx Virtual Fifo */ +		uccf->ucc_fast_rx_virtual_fifo_base_offset = +		qe_muram_alloc(UCC_GETH_URFS_INIT + +				 UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD, +				UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT); + +		/* utfb, urfb are offsets from MURAM base */ +		out_be32(&uf_regs->utfb, +			 uccf->ucc_fast_tx_virtual_fifo_base_offset); +		out_be32(&uf_regs->urfb, +			 uccf->ucc_fast_rx_virtual_fifo_base_offset); + +		/* Set Virtual Fifo registers */ +		out_be16(&uf_regs->urfs, UCC_GETH_URFS_INIT); +		out_be16(&uf_regs->urfet, UCC_GETH_URFET_INIT); +		out_be16(&uf_regs->urfset, UCC_GETH_URFSET_INIT); +		out_be16(&uf_regs->utfs, UCC_GETH_UTFS_INIT); +		out_be16(&uf_regs->utfet, UCC_GETH_UTFET_INIT); + 		out_be16(&uf_regs->utftt, UCC_GETH_UTFTT_INIT); +	} + +	/* Rx clock routing */ +	if (uf_info->rx_clock != QE_CLK_NONE) { +		if (ucc_set_clk_src(uf_info->ucc_num, +			 uf_info->rx_clock, COMM_DIR_RX)) { +			printf("%s: Illegal value for parameter 'RxClock'.\n", +				 __FUNCTION__); +			return -EINVAL; +		} +	} + +	/* Tx clock routing */ +	if (uf_info->tx_clock != QE_CLK_NONE) { +		if (ucc_set_clk_src(uf_info->ucc_num, +			 uf_info->tx_clock, COMM_DIR_TX)) { +			printf("%s: Illegal value for parameter 'TxClock'.\n", +				 __FUNCTION__); +			return -EINVAL; +		} +	} + +	/* Clear interrupt mask register to disable all of interrupts */ +	out_be32(&uf_regs->uccm, 0x0); + +	/* Writing '1' to clear all of envents */ +	out_be32(&uf_regs->ucce, 0xffffffff); + +	*uccf_ret = uccf; +	return 0; +} +#endif /* CONFIG_QE */ diff --git a/drivers/qe/uccf.h b/drivers/qe/uccf.h new file mode 100644 index 000000000..1ff9e1daf --- /dev/null +++ b/drivers/qe/uccf.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __UCCF_H__ +#define __UCCF_H__ + +#include "common.h" +#include "qe.h" + +/* Fast or Giga ethernet +*/ +typedef enum enet_type { +	FAST_ETH, +	GIGA_ETH, +} enet_type_e; + +/* General UCC Extended Mode Register +*/ +#define UCC_GUEMR_MODE_MASK_RX		0x02 +#define UCC_GUEMR_MODE_MASK_TX		0x01 +#define UCC_GUEMR_MODE_FAST_RX		0x02 +#define UCC_GUEMR_MODE_FAST_TX		0x01 +#define UCC_GUEMR_MODE_SLOW_RX		0x00 +#define UCC_GUEMR_MODE_SLOW_TX		0x00 +#define UCC_GUEMR_SET_RESERVED3		0x10 /* Bit 3 must be set 1 */ + +/* General UCC FAST Mode Register +*/ +#define UCC_FAST_GUMR_TCI		0x20000000 +#define UCC_FAST_GUMR_TRX		0x10000000 +#define UCC_FAST_GUMR_TTX		0x08000000 +#define UCC_FAST_GUMR_CDP		0x04000000 +#define UCC_FAST_GUMR_CTSP		0x02000000 +#define UCC_FAST_GUMR_CDS		0x01000000 +#define UCC_FAST_GUMR_CTSS		0x00800000 +#define UCC_FAST_GUMR_TXSY		0x00020000 +#define UCC_FAST_GUMR_RSYN		0x00010000 +#define UCC_FAST_GUMR_RTSM		0x00002000 +#define UCC_FAST_GUMR_REVD		0x00000400 +#define UCC_FAST_GUMR_ENR		0x00000020 +#define UCC_FAST_GUMR_ENT		0x00000010 + +/* GUMR [MODE] bit maps +*/ +#define UCC_FAST_GUMR_HDLC		0x00000000 +#define UCC_FAST_GUMR_QMC		0x00000002 +#define UCC_FAST_GUMR_UART		0x00000004 +#define UCC_FAST_GUMR_BISYNC		0x00000008 +#define UCC_FAST_GUMR_ATM		0x0000000a +#define UCC_FAST_GUMR_ETH		0x0000000c + +/* Transmit On Demand (UTORD) +*/ +#define UCC_SLOW_TOD			0x8000 +#define UCC_FAST_TOD			0x8000 + +/* Fast Ethernet (10/100 Mbps) +*/ +#define UCC_GETH_URFS_INIT		512        /* Rx virtual FIFO size */ +#define UCC_GETH_URFET_INIT		256        /* 1/2 urfs */ +#define UCC_GETH_URFSET_INIT		384        /* 3/4 urfs */ +#define UCC_GETH_UTFS_INIT		512        /* Tx virtual FIFO size */ +#define UCC_GETH_UTFET_INIT		256        /* 1/2 utfs */ +#define UCC_GETH_UTFTT_INIT		128 + +/* Gigabit Ethernet (1000 Mbps) +*/ +#define UCC_GETH_URFS_GIGA_INIT		4096/*2048*/    /* Rx virtual FIFO size */ +#define UCC_GETH_URFET_GIGA_INIT	2048/*1024*/    /* 1/2 urfs */ +#define UCC_GETH_URFSET_GIGA_INIT	3072/*1536*/    /* 3/4 urfs */ +#define UCC_GETH_UTFS_GIGA_INIT		8192/*2048*/    /* Tx virtual FIFO size */ +#define UCC_GETH_UTFET_GIGA_INIT	4096/*1024*/    /* 1/2 utfs */ +#define UCC_GETH_UTFTT_GIGA_INIT	0x400/*0x40*/   /*  */ + +/* UCC fast alignment +*/ +#define UCC_FAST_RX_ALIGN			4 +#define UCC_FAST_MRBLR_ALIGNMENT		4 +#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT	8 + +/* Sizes +*/ +#define UCC_FAST_RX_VIRTUAL_FIFO_SIZE_PAD	8 + +/* UCC fast structure. +*/ +typedef struct ucc_fast_info { +	int		ucc_num; +	qe_clock_e	rx_clock; +	qe_clock_e	tx_clock; +	enet_type_e	eth_type; +} ucc_fast_info_t; + +typedef struct ucc_fast_private { +	ucc_fast_info_t	*uf_info; +	ucc_fast_t	*uf_regs; /* a pointer to memory map of UCC regs */ +	u32		*p_ucce; /* a pointer to the event register */ +	u32		*p_uccm; /* a pointer to the mask register */ +	int		enabled_tx; /* whether UCC is enabled for Tx (ENT) */ +	int		enabled_rx; /* whether UCC is enabled for Rx (ENR) */ +	u32		ucc_fast_tx_virtual_fifo_base_offset; +	u32		ucc_fast_rx_virtual_fifo_base_offset; +} ucc_fast_private_t; + +void ucc_fast_transmit_on_demand(ucc_fast_private_t *uccf); +u32 ucc_fast_get_qe_cr_subblock(int ucc_num); +void ucc_fast_enable(ucc_fast_private_t *uccf, comm_dir_e mode); +void ucc_fast_disable(ucc_fast_private_t *uccf, comm_dir_e mode); +int ucc_fast_init(ucc_fast_info_t *uf_info, ucc_fast_private_t **uccf_ret); + +#endif /* __UCCF_H__ */ diff --git a/drivers/qe/uec.c b/drivers/qe/uec.c new file mode 100644 index 000000000..f640c8191 --- /dev/null +++ b/drivers/qe/uec.c @@ -0,0 +1,1266 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include "common.h" +#include "net.h" +#include "malloc.h" +#include "asm/errno.h" +#include "asm/io.h" +#include "asm/immap_qe.h" +#include "qe.h" +#include "uccf.h" +#include "uec.h" +#include "uec_phy.h" + +#if defined(CONFIG_QE) + +#ifdef CONFIG_UEC_ETH1 +static uec_info_t eth1_uec_info = { +	.uf_info		= { +		.ucc_num	= CFG_UEC1_UCC_NUM, +		.rx_clock	= CFG_UEC1_RX_CLK, +		.tx_clock	= CFG_UEC1_TX_CLK, +		.eth_type	= CFG_UEC1_ETH_TYPE, +	}, +	.num_threads_tx		= UEC_NUM_OF_THREADS_4, +	.num_threads_rx		= UEC_NUM_OF_THREADS_4, +	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2, +	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2, +	.tx_bd_ring_len		= 16, +	.rx_bd_ring_len		= 16, +	.phy_address		= CFG_UEC1_PHY_ADDR, +	.enet_interface		= CFG_UEC1_INTERFACE_MODE, +}; +#endif +#ifdef CONFIG_UEC_ETH2 +static uec_info_t eth2_uec_info = { +	.uf_info		= { +		.ucc_num	= CFG_UEC2_UCC_NUM, +		.rx_clock	= CFG_UEC2_RX_CLK, +		.tx_clock	= CFG_UEC2_TX_CLK, +		.eth_type	= CFG_UEC2_ETH_TYPE, +	}, +	.num_threads_tx		= UEC_NUM_OF_THREADS_4, +	.num_threads_rx		= UEC_NUM_OF_THREADS_4, +	.riscTx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2, +	.riscRx			= QE_RISC_ALLOCATION_RISC1_AND_RISC2, +	.tx_bd_ring_len		= 16, +	.rx_bd_ring_len		= 16, +	.phy_address		= CFG_UEC2_PHY_ADDR, +	.enet_interface		= CFG_UEC2_INTERFACE_MODE, +}; +#endif + +static int uec_mac_enable(uec_private_t *uec, comm_dir_e mode) +{ +	uec_t		*uec_regs; +	u32		maccfg1; + +	if (!uec) { +		printf("%s: uec not initial\n", __FUNCTION__); +		return -EINVAL; +	} +	uec_regs = uec->uec_regs; + +	maccfg1 = in_be32(&uec_regs->maccfg1); + +	if (mode & COMM_DIR_TX)	{ +		maccfg1 |= MACCFG1_ENABLE_TX; +		out_be32(&uec_regs->maccfg1, maccfg1); +		uec->mac_tx_enabled = 1; +	} + +	if (mode & COMM_DIR_RX)	{ +		maccfg1 |= MACCFG1_ENABLE_RX; +		out_be32(&uec_regs->maccfg1, maccfg1); +		uec->mac_rx_enabled = 1; +	} + +	return 0; +} + +static int uec_mac_disable(uec_private_t *uec, comm_dir_e mode) +{ +	uec_t		*uec_regs; +	u32		maccfg1; + +	if (!uec) { +		printf("%s: uec not initial\n", __FUNCTION__); +		return -EINVAL; +	} +	uec_regs = uec->uec_regs; + +	maccfg1 = in_be32(&uec_regs->maccfg1); + +	if (mode & COMM_DIR_TX)	{ +		maccfg1 &= ~MACCFG1_ENABLE_TX; +		out_be32(&uec_regs->maccfg1, maccfg1); +		uec->mac_tx_enabled = 0; +	} + +	if (mode & COMM_DIR_RX)	{ +		maccfg1 &= ~MACCFG1_ENABLE_RX; +		out_be32(&uec_regs->maccfg1, maccfg1); +		uec->mac_rx_enabled = 0; +	} + +	return 0; +} + +static int uec_graceful_stop_tx(uec_private_t *uec) +{ +	ucc_fast_t		*uf_regs; +	u32			cecr_subblock; +	u32			ucce; + +	if (!uec || !uec->uccf) { +		printf("%s: No handle passed.\n", __FUNCTION__); +		return -EINVAL; +	} + +	uf_regs = uec->uccf->uf_regs; + +	/* Clear the grace stop event */ +	out_be32(&uf_regs->ucce, UCCE_GRA); + +	/* Issue host command */ +	cecr_subblock = +		 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); +	qe_issue_cmd(QE_GRACEFUL_STOP_TX, cecr_subblock, +			 (u8)QE_CR_PROTOCOL_ETHERNET, 0); + +	/* Wait for command to complete */ +	do { +		ucce = in_be32(&uf_regs->ucce); +	} while (! (ucce & UCCE_GRA)); + +	uec->grace_stopped_tx = 1; + +	return 0; +} + +static int uec_graceful_stop_rx(uec_private_t *uec) +{ +	u32		cecr_subblock; +	u8		ack; + +	if (!uec) { +		printf("%s: No handle passed.\n", __FUNCTION__); +		return -EINVAL; +	} + +	if (!uec->p_rx_glbl_pram) { +		printf("%s: No init rx global parameter\n", __FUNCTION__); +		return -EINVAL; +	} + +	/* Clear acknowledge bit */ +	ack = uec->p_rx_glbl_pram->rxgstpack; +	ack &= ~GRACEFUL_STOP_ACKNOWLEDGE_RX; +	uec->p_rx_glbl_pram->rxgstpack = ack; + +	/* Keep issuing cmd and checking ack bit until it is asserted */ +	do { +		/* Issue host command */ +		cecr_subblock = +		 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); +		qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, +				 (u8)QE_CR_PROTOCOL_ETHERNET, 0); +		ack = uec->p_rx_glbl_pram->rxgstpack; +	} while (! (ack & GRACEFUL_STOP_ACKNOWLEDGE_RX )); + +	uec->grace_stopped_rx = 1; + +	return 0; +} + +static int uec_restart_tx(uec_private_t *uec) +{ +	u32		cecr_subblock; + +	if (!uec || !uec->uec_info) { +		printf("%s: No handle passed.\n", __FUNCTION__); +		return -EINVAL; +	} + +	cecr_subblock = +	 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); +	qe_issue_cmd(QE_RESTART_TX, cecr_subblock, +			 (u8)QE_CR_PROTOCOL_ETHERNET, 0); + +	uec->grace_stopped_tx = 0; + +	return 0; +} + +static int uec_restart_rx(uec_private_t *uec) +{ +	u32		cecr_subblock; + +	if (!uec || !uec->uec_info) { +		printf("%s: No handle passed.\n", __FUNCTION__); +		return -EINVAL; +	} + +	cecr_subblock = +	 ucc_fast_get_qe_cr_subblock(uec->uec_info->uf_info.ucc_num); +	qe_issue_cmd(QE_RESTART_RX, cecr_subblock, +			 (u8)QE_CR_PROTOCOL_ETHERNET, 0); + +	uec->grace_stopped_rx = 0; + +	return 0; +} + +static int uec_open(uec_private_t *uec, comm_dir_e mode) +{ +	ucc_fast_private_t	*uccf; + +	if (!uec || !uec->uccf) { +		printf("%s: No handle passed.\n", __FUNCTION__); +		return -EINVAL; +	} +	uccf = uec->uccf; + +	/* check if the UCC number is in range. */ +	if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) { +		printf("%s: ucc_num out of range.\n", __FUNCTION__); +		return -EINVAL; +	} + +	/* Enable MAC */ +	uec_mac_enable(uec, mode); + +	/* Enable UCC fast */ +	ucc_fast_enable(uccf, mode); + +	/* RISC microcode start */ +	if ((mode & COMM_DIR_TX) && uec->grace_stopped_tx) { +		uec_restart_tx(uec); +	} +	if ((mode & COMM_DIR_RX) && uec->grace_stopped_rx) { +		uec_restart_rx(uec); +	} + +	return 0; +} + +static int uec_stop(uec_private_t *uec, comm_dir_e mode) +{ +	ucc_fast_private_t	*uccf; + +	if (!uec || !uec->uccf) { +		printf("%s: No handle passed.\n", __FUNCTION__); +		return -EINVAL; +	} +	uccf = uec->uccf; + +	/* check if the UCC number is in range. */ +	if (uec->uec_info->uf_info.ucc_num >= UCC_MAX_NUM) { +		printf("%s: ucc_num out of range.\n", __FUNCTION__); +		return -EINVAL; +	} +	/* Stop any transmissions */ +	if ((mode & COMM_DIR_TX) && !uec->grace_stopped_tx) { +		uec_graceful_stop_tx(uec); +	} +	/* Stop any receptions */ +	if ((mode & COMM_DIR_RX) && !uec->grace_stopped_rx) { +		uec_graceful_stop_rx(uec); +	} + +	/* Disable the UCC fast */ +	ucc_fast_disable(uec->uccf, mode); + +	/* Disable the MAC */ +	uec_mac_disable(uec, mode); + +	return 0; +} + +static int uec_set_mac_duplex(uec_private_t *uec, int duplex) +{ +	uec_t		*uec_regs; +	u32		maccfg2; + +	if (!uec) { +		printf("%s: uec not initial\n", __FUNCTION__); +		return -EINVAL; +	} +	uec_regs = uec->uec_regs; + +	if (duplex == DUPLEX_HALF) { +		maccfg2 = in_be32(&uec_regs->maccfg2); +		maccfg2 &= ~MACCFG2_FDX; +		out_be32(&uec_regs->maccfg2, maccfg2); +	} + +	if (duplex == DUPLEX_FULL) { +		maccfg2 = in_be32(&uec_regs->maccfg2); +		maccfg2 |= MACCFG2_FDX; +		out_be32(&uec_regs->maccfg2, maccfg2); +	} + +	return 0; +} + +static int uec_set_mac_if_mode(uec_private_t *uec, enet_interface_e if_mode) +{ +	enet_interface_e	enet_if_mode; +	uec_info_t 		*uec_info; +	uec_t			*uec_regs; +	u32			upsmr; +	u32			maccfg2; + +	if (!uec) { +		printf("%s: uec not initial\n", __FUNCTION__); +		return -EINVAL; +	} + +	uec_info = uec->uec_info; +	uec_regs = uec->uec_regs; +	enet_if_mode = if_mode; + +	maccfg2 = in_be32(&uec_regs->maccfg2); +	maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; + +	upsmr = in_be32(&uec->uccf->uf_regs->upsmr); +	upsmr &= ~(UPSMR_RPM | UPSMR_TBIM | UPSMR_R10M | UPSMR_RMM); + +	switch (enet_if_mode) { +		case ENET_100_MII: +		case ENET_10_MII: +			maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; +			break; +		case ENET_1000_GMII: +			maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; +			break; +		case ENET_1000_TBI: +			maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; +			upsmr |= UPSMR_TBIM; +			break; +		case ENET_1000_RTBI: +			maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; +			upsmr |= (UPSMR_RPM | UPSMR_TBIM); +			break; +		case ENET_1000_RGMII: +			maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; +			upsmr |= UPSMR_RPM; +			break; +		case ENET_100_RGMII: +			maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; +			upsmr |= UPSMR_RPM; +			break; +		case ENET_10_RGMII: +			maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; +			upsmr |= (UPSMR_RPM | UPSMR_R10M); +			break; +		case ENET_100_RMII: +			maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; +			upsmr |= UPSMR_RMM; +			break; +		case ENET_10_RMII: +			maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; +			upsmr |= (UPSMR_R10M | UPSMR_RMM); +			break; +		default: +			return -EINVAL; +			break; +	} +	out_be32(&uec_regs->maccfg2, maccfg2); +	out_be32(&uec->uccf->uf_regs->upsmr, upsmr); + +	return 0; +} + +static int init_mii_management_configuration(uec_t *uec_regs) +{ +	uint		timeout = 0x1000; +	u32		miimcfg = 0; + +	miimcfg = in_be32(&uec_regs->miimcfg); +	miimcfg |= MIIMCFG_MNGMNT_CLC_DIV_INIT_VALUE; +	out_be32(&uec_regs->miimcfg, miimcfg); + +	/* Wait until the bus is free */ +	while ((in_be32(&uec_regs->miimcfg) & MIIMIND_BUSY) && timeout--); +	if (timeout <= 0) { +		printf("%s: The MII Bus is stuck!", __FUNCTION__); +		return -ETIMEDOUT; +	} + +	return 0; +} + +static int init_phy(struct eth_device *dev) +{ +	uec_private_t		*uec; +	uec_t			*uec_regs; +	struct uec_mii_info	*mii_info; +	struct phy_info		*curphy; +	int			err; + +	uec = (uec_private_t *)dev->priv; +	uec_regs = uec->uec_regs; + +	uec->oldlink = 0; +	uec->oldspeed = 0; +	uec->oldduplex = -1; + +	mii_info = malloc(sizeof(*mii_info)); +	if (!mii_info) { +		printf("%s: Could not allocate mii_info", dev->name); +		return -ENOMEM; +	} +	memset(mii_info, 0, sizeof(*mii_info)); + +	mii_info->speed = SPEED_1000; +	mii_info->duplex = DUPLEX_FULL; +	mii_info->pause = 0; +	mii_info->link = 1; + +	mii_info->advertising = (ADVERTISED_10baseT_Half | +				ADVERTISED_10baseT_Full | +				ADVERTISED_100baseT_Half | +				ADVERTISED_100baseT_Full | +				ADVERTISED_1000baseT_Full); +	mii_info->autoneg = 1; +	mii_info->mii_id = uec->uec_info->phy_address; +	mii_info->dev = dev; + +	mii_info->mdio_read = &read_phy_reg; +	mii_info->mdio_write = &write_phy_reg; + +	uec->mii_info = mii_info; + +	if (init_mii_management_configuration(uec_regs)) { +		printf("%s: The MII Bus is stuck!", dev->name); +		err = -1; +		goto bus_fail; +	} + +	/* get info for this PHY */ +	curphy = get_phy_info(uec->mii_info); +	if (!curphy) { +		printf("%s: No PHY found", dev->name); +		err = -1; +		goto no_phy; +	} + +	mii_info->phyinfo = curphy; + +	/* Run the commands which initialize the PHY */ +	if (curphy->init) { +		err = curphy->init(uec->mii_info); +		if (err) +			goto phy_init_fail; +	} + +	return 0; + +phy_init_fail: +no_phy: +bus_fail: +	free(mii_info); +	return err; +} + +static void adjust_link(struct eth_device *dev) +{ +	uec_private_t		*uec = (uec_private_t *)dev->priv; +	uec_t			*uec_regs; +	struct uec_mii_info	*mii_info = uec->mii_info; + +	extern void change_phy_interface_mode(struct eth_device *dev, +					 enet_interface_e mode); +	uec_regs = uec->uec_regs; + +	if (mii_info->link) { +		/* Now we make sure that we can be in full duplex mode. +		* If not, we operate in half-duplex mode. */ +		if (mii_info->duplex != uec->oldduplex) { +			if (!(mii_info->duplex)) { +				uec_set_mac_duplex(uec, DUPLEX_HALF); +				printf("%s: Half Duplex\n", dev->name); +			} else { +				uec_set_mac_duplex(uec, DUPLEX_FULL); +				printf("%s: Full Duplex\n", dev->name); +			} +			uec->oldduplex = mii_info->duplex; +		} + +		if (mii_info->speed != uec->oldspeed) { +			switch (mii_info->speed) { +				case 1000: +					break; +				case 100: +					printf ("switching to rgmii 100\n"); +					/* change phy to rgmii 100 */ +					change_phy_interface_mode(dev, +								ENET_100_RGMII); +					/* change the MAC interface mode */ +					uec_set_mac_if_mode(uec,ENET_100_RGMII); +					break; +				case 10: +					printf ("switching to rgmii 10\n"); +					/* change phy to rgmii 10 */ +					change_phy_interface_mode(dev, +								ENET_10_RGMII); +					/* change the MAC interface mode */ +					uec_set_mac_if_mode(uec,ENET_10_RGMII); +					break; +				default: +					printf("%s: Ack,Speed(%d)is illegal\n", +						dev->name, mii_info->speed); +					break; +			} + +			printf("%s: Speed %dBT\n", dev->name, mii_info->speed); +			uec->oldspeed = mii_info->speed; +		} + +		if (!uec->oldlink) { +			printf("%s: Link is up\n", dev->name); +			uec->oldlink = 1; +		} + +	} else { /* if (mii_info->link) */ +		if (uec->oldlink) { +			printf("%s: Link is down\n", dev->name); +			uec->oldlink = 0; +			uec->oldspeed = 0; +			uec->oldduplex = -1; +		} +	} +} + +static void phy_change(struct eth_device *dev) +{ +	uec_private_t	*uec = (uec_private_t *)dev->priv; +	uec_t		*uec_regs; +	int		result = 0; + +	uec_regs = uec->uec_regs; + +	/* Delay 5s to give the PHY a chance to change the register state */ +	udelay(5000000); + +	/* Update the link, speed, duplex */ +	result = uec->mii_info->phyinfo->read_status(uec->mii_info); + +	/* Adjust the interface according to speed */ +	if ((0 == result) || (uec->mii_info->link == 0)) { +		adjust_link(dev); +	} +} + +static int uec_set_mac_address(uec_private_t *uec, u8 *mac_addr) +{ +	uec_t		*uec_regs; +	u32		mac_addr1; +	u32		mac_addr2; + +	if (!uec) { +		printf("%s: uec not initial\n", __FUNCTION__); +		return -EINVAL; +	} + +	uec_regs = uec->uec_regs; + +	/* if a station address of 0x12345678ABCD, perform a write to +	MACSTNADDR1 of 0xCDAB7856, +	MACSTNADDR2 of 0x34120000 */ + +	mac_addr1 = (mac_addr[5] << 24) | (mac_addr[4] << 16) | \ +			(mac_addr[3] << 8)  | (mac_addr[2]); +	out_be32(&uec_regs->macstnaddr1, mac_addr1); + +	mac_addr2 = ((mac_addr[1] << 24) | (mac_addr[0] << 16)) & 0xffff0000; +	out_be32(&uec_regs->macstnaddr2, mac_addr2); + +	return 0; +} + +static int uec_convert_threads_num(uec_num_of_threads_e threads_num, +					 int *threads_num_ret) +{ +	int	num_threads_numerica; + +	switch (threads_num) { +		case UEC_NUM_OF_THREADS_1: +			num_threads_numerica = 1; +			break; +		case UEC_NUM_OF_THREADS_2: +			num_threads_numerica = 2; +			break; +		case UEC_NUM_OF_THREADS_4: +			num_threads_numerica = 4; +			break; +		case UEC_NUM_OF_THREADS_6: +			num_threads_numerica = 6; +			break; +		case UEC_NUM_OF_THREADS_8: +			num_threads_numerica = 8; +			break; +		default: +			printf("%s: Bad number of threads value.", +				 __FUNCTION__); +			return -EINVAL; +	} + +	*threads_num_ret = num_threads_numerica; + +	return 0; +} + +static void uec_init_tx_parameter(uec_private_t *uec, int num_threads_tx) +{ +	uec_info_t	*uec_info; +	u32		end_bd; +	u8		bmrx = 0; +	int		i; + +	uec_info = uec->uec_info; + +	/* Alloc global Tx parameter RAM page */ +	uec->tx_glbl_pram_offset = qe_muram_alloc( +				sizeof(uec_tx_global_pram_t), +				 UEC_TX_GLOBAL_PRAM_ALIGNMENT); +	uec->p_tx_glbl_pram = (uec_tx_global_pram_t *) +				qe_muram_addr(uec->tx_glbl_pram_offset); + +	/* Zero the global Tx prameter RAM */ +	memset(uec->p_tx_glbl_pram, 0, sizeof(uec_tx_global_pram_t)); + +	/* Init global Tx parameter RAM */ + +	/* TEMODER, RMON statistics disable, one Tx queue */ +	out_be16(&uec->p_tx_glbl_pram->temoder, TEMODER_INIT_VALUE); + +	/* SQPTR */ +	uec->send_q_mem_reg_offset = qe_muram_alloc( +				sizeof(uec_send_queue_qd_t), +				 UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT); +	uec->p_send_q_mem_reg = (uec_send_queue_mem_region_t *) +				qe_muram_addr(uec->send_q_mem_reg_offset); +	out_be32(&uec->p_tx_glbl_pram->sqptr, uec->send_q_mem_reg_offset); + +	/* Setup the table with TxBDs ring */ +	end_bd = (u32)uec->p_tx_bd_ring + (uec_info->tx_bd_ring_len - 1) +					 * SIZEOFBD; +	out_be32(&uec->p_send_q_mem_reg->sqqd[0].bd_ring_base, +				 (u32)(uec->p_tx_bd_ring)); +	out_be32(&uec->p_send_q_mem_reg->sqqd[0].last_bd_completed_address, +						 end_bd); + +	/* Scheduler Base Pointer, we have only one Tx queue, no need it */ +	out_be32(&uec->p_tx_glbl_pram->schedulerbasepointer, 0); + +	/* TxRMON Base Pointer, TxRMON disable, we don't need it */ +	out_be32(&uec->p_tx_glbl_pram->txrmonbaseptr, 0); + +	/* TSTATE, global snooping, big endian, the CSB bus selected */ +	bmrx = BMR_INIT_VALUE; +	out_be32(&uec->p_tx_glbl_pram->tstate, ((u32)(bmrx) << BMR_SHIFT)); + +	/* IPH_Offset */ +	for (i = 0; i < MAX_IPH_OFFSET_ENTRY; i++) { +		out_8(&uec->p_tx_glbl_pram->iphoffset[i], 0); +	} + +	/* VTAG table */ +	for (i = 0; i < UEC_TX_VTAG_TABLE_ENTRY_MAX; i++) { +		out_be32(&uec->p_tx_glbl_pram->vtagtable[i], 0); +	} + +	/* TQPTR */ +	uec->thread_dat_tx_offset = qe_muram_alloc( +		num_threads_tx * sizeof(uec_thread_data_tx_t) + +		 32 *(num_threads_tx == 1), UEC_THREAD_DATA_ALIGNMENT); + +	uec->p_thread_data_tx = (uec_thread_data_tx_t *) +				qe_muram_addr(uec->thread_dat_tx_offset); +	out_be32(&uec->p_tx_glbl_pram->tqptr, uec->thread_dat_tx_offset); +} + +static void uec_init_rx_parameter(uec_private_t *uec, int num_threads_rx) +{ +	u8	bmrx = 0; +	int	i; +	uec_82xx_address_filtering_pram_t	*p_af_pram; + +	/* Allocate global Rx parameter RAM page */ +	uec->rx_glbl_pram_offset = qe_muram_alloc( +		sizeof(uec_rx_global_pram_t), UEC_RX_GLOBAL_PRAM_ALIGNMENT); +	uec->p_rx_glbl_pram = (uec_rx_global_pram_t *) +				qe_muram_addr(uec->rx_glbl_pram_offset); + +	/* Zero Global Rx parameter RAM */ +	memset(uec->p_rx_glbl_pram, 0, sizeof(uec_rx_global_pram_t)); + +	/* Init global Rx parameter RAM */ +	/* REMODER, Extended feature mode disable, VLAN disable, +	 LossLess flow control disable, Receive firmware statisic disable, +	 Extended address parsing mode disable, One Rx queues, +	 Dynamic maximum/minimum frame length disable, IP checksum check +	 disable, IP address alignment disable +	*/ +	out_be32(&uec->p_rx_glbl_pram->remoder, REMODER_INIT_VALUE); + +	/* RQPTR */ +	uec->thread_dat_rx_offset = qe_muram_alloc( +			num_threads_rx * sizeof(uec_thread_data_rx_t), +			 UEC_THREAD_DATA_ALIGNMENT); +	uec->p_thread_data_rx = (uec_thread_data_rx_t *) +				qe_muram_addr(uec->thread_dat_rx_offset); +	out_be32(&uec->p_rx_glbl_pram->rqptr, uec->thread_dat_rx_offset); + +	/* Type_or_Len */ +	out_be16(&uec->p_rx_glbl_pram->typeorlen, 3072); + +	/* RxRMON base pointer, we don't need it */ +	out_be32(&uec->p_rx_glbl_pram->rxrmonbaseptr, 0); + +	/* IntCoalescingPTR, we don't need it, no interrupt */ +	out_be32(&uec->p_rx_glbl_pram->intcoalescingptr, 0); + +	/* RSTATE, global snooping, big endian, the CSB bus selected */ +	bmrx = BMR_INIT_VALUE; +	out_8(&uec->p_rx_glbl_pram->rstate, bmrx); + +	/* MRBLR */ +	out_be16(&uec->p_rx_glbl_pram->mrblr, MAX_RXBUF_LEN); + +	/* RBDQPTR */ +	uec->rx_bd_qs_tbl_offset = qe_muram_alloc( +				sizeof(uec_rx_bd_queues_entry_t) + \ +				sizeof(uec_rx_prefetched_bds_t), +				 UEC_RX_BD_QUEUES_ALIGNMENT); +	uec->p_rx_bd_qs_tbl = (uec_rx_bd_queues_entry_t *) +				qe_muram_addr(uec->rx_bd_qs_tbl_offset); + +	/* Zero it */ +	memset(uec->p_rx_bd_qs_tbl, 0, sizeof(uec_rx_bd_queues_entry_t) + \ +					sizeof(uec_rx_prefetched_bds_t)); +	out_be32(&uec->p_rx_glbl_pram->rbdqptr, uec->rx_bd_qs_tbl_offset); +	out_be32(&uec->p_rx_bd_qs_tbl->externalbdbaseptr, +		 (u32)uec->p_rx_bd_ring); + +	/* MFLR */ +	out_be16(&uec->p_rx_glbl_pram->mflr, MAX_FRAME_LEN); +	/* MINFLR */ +	out_be16(&uec->p_rx_glbl_pram->minflr, MIN_FRAME_LEN); +	/* MAXD1 */ +	out_be16(&uec->p_rx_glbl_pram->maxd1, MAX_DMA1_LEN); +	/* MAXD2 */ +	out_be16(&uec->p_rx_glbl_pram->maxd2, MAX_DMA2_LEN); +	/* ECAM_PTR */ +	out_be32(&uec->p_rx_glbl_pram->ecamptr, 0); +	/* L2QT */ +	out_be32(&uec->p_rx_glbl_pram->l2qt, 0); +	/* L3QT */ +	for (i = 0; i < 8; i++)	{ +		out_be32(&uec->p_rx_glbl_pram->l3qt[i], 0); +	} + +	/* VLAN_TYPE */ +	out_be16(&uec->p_rx_glbl_pram->vlantype, 0x8100); +	/* TCI */ +	out_be16(&uec->p_rx_glbl_pram->vlantci, 0); + +	/* Clear PQ2 style address filtering hash table */ +	p_af_pram = (uec_82xx_address_filtering_pram_t *) \ +			uec->p_rx_glbl_pram->addressfiltering; + +	p_af_pram->iaddr_h = 0; +	p_af_pram->iaddr_l = 0; +	p_af_pram->gaddr_h = 0; +	p_af_pram->gaddr_l = 0; +} + +static int uec_issue_init_enet_rxtx_cmd(uec_private_t *uec, +					 int thread_tx, int thread_rx) +{ +	uec_init_cmd_pram_t		*p_init_enet_param; +	u32				init_enet_param_offset; +	uec_info_t			*uec_info; +	int				i; +	int				snum; +	u32				init_enet_offset; +	u32				entry_val; +	u32				command; +	u32				cecr_subblock; + +	uec_info = uec->uec_info; + +	/* Allocate init enet command parameter */ +	uec->init_enet_param_offset = qe_muram_alloc( +					sizeof(uec_init_cmd_pram_t), 4); +	init_enet_param_offset = uec->init_enet_param_offset; +	uec->p_init_enet_param = (uec_init_cmd_pram_t *) +				qe_muram_addr(uec->init_enet_param_offset); + +	/* Zero init enet command struct */ +	memset((void *)uec->p_init_enet_param, 0, sizeof(uec_init_cmd_pram_t)); + +	/* Init the command struct */ +	p_init_enet_param = uec->p_init_enet_param; +	p_init_enet_param->resinit0 = ENET_INIT_PARAM_MAGIC_RES_INIT0; +	p_init_enet_param->resinit1 = ENET_INIT_PARAM_MAGIC_RES_INIT1; +	p_init_enet_param->resinit2 = ENET_INIT_PARAM_MAGIC_RES_INIT2; +	p_init_enet_param->resinit3 = ENET_INIT_PARAM_MAGIC_RES_INIT3; +	p_init_enet_param->resinit4 = ENET_INIT_PARAM_MAGIC_RES_INIT4; +	p_init_enet_param->largestexternallookupkeysize = 0; + +	p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_rx) +					 << ENET_INIT_PARAM_RGF_SHIFT; +	p_init_enet_param->rgftgfrxglobal |= ((u32)uec_info->num_threads_tx) +					 << ENET_INIT_PARAM_TGF_SHIFT; + +	/* Init Rx global parameter pointer */ +	p_init_enet_param->rgftgfrxglobal |= uec->rx_glbl_pram_offset | +						 (u32)uec_info->riscRx; + +	/* Init Rx threads */ +	for (i = 0; i < (thread_rx + 1); i++) { +		if ((snum = qe_get_snum()) < 0) { +			printf("%s can not get snum\n", __FUNCTION__); +			return -ENOMEM; +		} + +		if (i==0) { +			init_enet_offset = 0; +		} else { +			init_enet_offset = qe_muram_alloc( +					sizeof(uec_thread_rx_pram_t), +					 UEC_THREAD_RX_PRAM_ALIGNMENT); +		} + +		entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) | +				 init_enet_offset | (u32)uec_info->riscRx; +		p_init_enet_param->rxthread[i] = entry_val; +	} + +	/* Init Tx global parameter pointer */ +	p_init_enet_param->txglobal = uec->tx_glbl_pram_offset | +					 (u32)uec_info->riscTx; + +	/* Init Tx threads */ +	for (i = 0; i < thread_tx; i++) { +		if ((snum = qe_get_snum()) < 0)	{ +			printf("%s can not get snum\n", __FUNCTION__); +			return -ENOMEM; +		} + +		init_enet_offset = qe_muram_alloc(sizeof(uec_thread_tx_pram_t), +						 UEC_THREAD_TX_PRAM_ALIGNMENT); + +		entry_val = ((u32)snum << ENET_INIT_PARAM_SNUM_SHIFT) | +				 init_enet_offset | (u32)uec_info->riscTx; +		p_init_enet_param->txthread[i] = entry_val; +	} + +	__asm__ __volatile__("sync"); + +	/* Issue QE command */ +	command = QE_INIT_TX_RX; +	cecr_subblock =	ucc_fast_get_qe_cr_subblock( +				uec->uec_info->uf_info.ucc_num); +	qe_issue_cmd(command, cecr_subblock, (u8) QE_CR_PROTOCOL_ETHERNET, +						 init_enet_param_offset); + +	return 0; +} + +static int uec_startup(uec_private_t *uec) +{ +	uec_info_t			*uec_info; +	ucc_fast_info_t			*uf_info; +	ucc_fast_private_t		*uccf; +	ucc_fast_t			*uf_regs; +	uec_t				*uec_regs; +	int				num_threads_tx; +	int				num_threads_rx; +	u32				utbipar; +	enet_interface_e		enet_interface; +	u32				length; +	u32				align; +	qe_bd_t				*bd; +	u8				*buf; +	int				i; + +	if (!uec || !uec->uec_info) { +		printf("%s: uec or uec_info not initial\n", __FUNCTION__); +		return -EINVAL; +	} + +	uec_info = uec->uec_info; +	uf_info = &(uec_info->uf_info); + +	/* Check if Rx BD ring len is illegal */ +	if ((uec_info->rx_bd_ring_len < UEC_RX_BD_RING_SIZE_MIN) || \ +		(uec_info->rx_bd_ring_len % UEC_RX_BD_RING_SIZE_ALIGNMENT)) { +		printf("%s: Rx BD ring len must be multiple of 4, and > 8.\n", +			 __FUNCTION__); +		return -EINVAL; +	} + +	/* Check if Tx BD ring len is illegal */ +	if (uec_info->tx_bd_ring_len < UEC_TX_BD_RING_SIZE_MIN) { +		printf("%s: Tx BD ring length must not be smaller than 2.\n", +			 __FUNCTION__); +		return -EINVAL; +	} + +	/* Check if MRBLR is illegal */ +	if ((MAX_RXBUF_LEN == 0) || (MAX_RXBUF_LEN  % UEC_MRBLR_ALIGNMENT)) { +		printf("%s: max rx buffer length must be mutliple of 128.\n", +			 __FUNCTION__); +		return -EINVAL; +	} + +	/* Both Rx and Tx are stopped */ +	uec->grace_stopped_rx = 1; +	uec->grace_stopped_tx = 1; + +	/* Init UCC fast */ +	if (ucc_fast_init(uf_info, &uccf)) { +		printf("%s: failed to init ucc fast\n", __FUNCTION__); +		return -ENOMEM; +	} + +	/* Save uccf */ +	uec->uccf = uccf; + +	/* Convert the Tx threads number */ +	if (uec_convert_threads_num(uec_info->num_threads_tx, +					 &num_threads_tx)) { +		return -EINVAL; +	} + +	/* Convert the Rx threads number */ +	if (uec_convert_threads_num(uec_info->num_threads_rx, +					 &num_threads_rx)) { +		return -EINVAL; +	} + +	uf_regs = uccf->uf_regs; + +	/* UEC register is following UCC fast registers */ +	uec_regs = (uec_t *)(&uf_regs->ucc_eth); + +	/* Save the UEC register pointer to UEC private struct */ +	uec->uec_regs = uec_regs; + +	/* Init UPSMR, enable hardware statistics (UCC) */ +	out_be32(&uec->uccf->uf_regs->upsmr, UPSMR_INIT_VALUE); + +	/* Init MACCFG1, flow control disable, disable Tx and Rx */ +	out_be32(&uec_regs->maccfg1, MACCFG1_INIT_VALUE); + +	/* Init MACCFG2, length check, MAC PAD and CRC enable */ +	out_be32(&uec_regs->maccfg2, MACCFG2_INIT_VALUE); + +	/* Setup MAC interface mode */ +	uec_set_mac_if_mode(uec, uec_info->enet_interface); + +	/* Setup MII master clock source */ +	qe_set_mii_clk_src(uec_info->uf_info.ucc_num); + +	/* Setup UTBIPAR */ +	utbipar = in_be32(&uec_regs->utbipar); +	utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; +	enet_interface = uec->uec_info->enet_interface; +	if (enet_interface == ENET_1000_TBI || +		 enet_interface == ENET_1000_RTBI) { +		utbipar |=  (uec_info->phy_address + uec_info->uf_info.ucc_num) +						 << UTBIPAR_PHY_ADDRESS_SHIFT; +	} else { +		utbipar |=  (0x10 + uec_info->uf_info.ucc_num) +						 << UTBIPAR_PHY_ADDRESS_SHIFT; +	} + +	out_be32(&uec_regs->utbipar, utbipar); + +	/* Allocate Tx BDs */ +	length = ((uec_info->tx_bd_ring_len * SIZEOFBD) / +		 UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) * +		 UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; +	if ((uec_info->tx_bd_ring_len * SIZEOFBD) % +		 UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT) { +		length += UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT; +	} + +	align = UEC_TX_BD_RING_ALIGNMENT; +	uec->tx_bd_ring_offset = (u32)malloc((u32)(length + align)); +	if (uec->tx_bd_ring_offset != 0) { +		uec->p_tx_bd_ring = (u8 *)((uec->tx_bd_ring_offset + align) +						 & ~(align - 1)); +	} + +	/* Zero all of Tx BDs */ +	memset((void *)(uec->tx_bd_ring_offset), 0, length + align); + +	/* Allocate Rx BDs */ +	length = uec_info->rx_bd_ring_len * SIZEOFBD; +	align = UEC_RX_BD_RING_ALIGNMENT; +	uec->rx_bd_ring_offset = (u32)(malloc((u32)(length + align))); +	if (uec->rx_bd_ring_offset != 0) { +		uec->p_rx_bd_ring = (u8 *)((uec->rx_bd_ring_offset + align) +							 & ~(align - 1)); +	} + +	/* Zero all of Rx BDs */ +	memset((void *)(uec->rx_bd_ring_offset), 0, length + align); + +	/* Allocate Rx buffer */ +	length = uec_info->rx_bd_ring_len * MAX_RXBUF_LEN; +	align = UEC_RX_DATA_BUF_ALIGNMENT; +	uec->rx_buf_offset = (u32)malloc(length + align); +	if (uec->rx_buf_offset != 0) { +		uec->p_rx_buf = (u8 *)((uec->rx_buf_offset + align) +						 & ~(align - 1)); +	} + +	/* Zero all of the Rx buffer */ +	memset((void *)(uec->rx_buf_offset), 0, length + align); + +	/* Init TxBD ring */ +	bd = (qe_bd_t *)uec->p_tx_bd_ring; +	uec->txBd = bd; + +	for (i = 0; i < uec_info->tx_bd_ring_len; i++) { +		BD_DATA_CLEAR(bd); +		BD_STATUS_SET(bd, 0); +		BD_LENGTH_SET(bd, 0); +		bd ++; +	} +	BD_STATUS_SET((--bd), TxBD_WRAP); + +	/* Init RxBD ring */ +	bd = (qe_bd_t *)uec->p_rx_bd_ring; +	uec->rxBd = bd; +	buf = uec->p_rx_buf; +	for (i = 0; i < uec_info->rx_bd_ring_len; i++) { +		BD_DATA_SET(bd, buf); +		BD_LENGTH_SET(bd, 0); +		BD_STATUS_SET(bd, RxBD_EMPTY); +		buf += MAX_RXBUF_LEN; +		bd ++; +	} +	BD_STATUS_SET((--bd), RxBD_WRAP | RxBD_EMPTY); + +	/* Init global Tx parameter RAM */ +	uec_init_tx_parameter(uec, num_threads_tx); + +	/* Init global Rx parameter RAM */ +	uec_init_rx_parameter(uec, num_threads_rx); + +	/* Init ethernet Tx and Rx parameter command */ +	if (uec_issue_init_enet_rxtx_cmd(uec, num_threads_tx, +					 num_threads_rx)) { +		printf("%s issue init enet cmd failed\n", __FUNCTION__); +		return -ENOMEM; +	} + +	return 0; +} + +static int uec_init(struct eth_device* dev, bd_t *bd) +{ +	uec_private_t		*uec; +	int			err; + +	uec = (uec_private_t *)dev->priv; + +	if (uec->the_first_run == 0) { +		/* Set up the MAC address */ +		if (dev->enetaddr[0] & 0x01) { +			printf("%s: MacAddress is multcast address\n", +				 __FUNCTION__); +			return -EINVAL; +		} +		uec_set_mac_address(uec, dev->enetaddr); +		uec->the_first_run = 1; +	} + +	err = uec_open(uec, COMM_DIR_RX_AND_TX); +	if (err) { +		printf("%s: cannot enable UEC device\n", dev->name); +		return err; +	} + +	return 0; +} + +static void uec_halt(struct eth_device* dev) +{ +	uec_private_t	*uec = (uec_private_t *)dev->priv; +	uec_stop(uec, COMM_DIR_RX_AND_TX); +} + +static int uec_send(struct eth_device* dev, volatile void *buf, int len) +{ +	uec_private_t		*uec; +	ucc_fast_private_t	*uccf; +	volatile qe_bd_t	*bd; +	volatile u16		status; +	int			i; +	int			result = 0; + +	uec = (uec_private_t *)dev->priv; +	uccf = uec->uccf; +	bd = uec->txBd; + +	/* Find an empty TxBD */ +	for (i = 0; BD_STATUS(bd) & TxBD_READY; i++) { +		if (i > 0x100000) { +			printf("%s: tx buffer not ready\n", dev->name); +			return result; +		} +	} + +	/* Init TxBD */ +	BD_DATA_SET(bd, buf); +	BD_LENGTH_SET(bd, len); +	status = BD_STATUS(bd); +	status &= BD_WRAP; +	status |= (TxBD_READY | TxBD_LAST); +	BD_STATUS_SET(bd, status); + +	/* Tell UCC to transmit the buffer */ +	ucc_fast_transmit_on_demand(uccf); + +	/* Wait for buffer to be transmitted */ +	status = BD_STATUS(bd); +	for (i = 0; status & TxBD_READY; i++) { +		if (i > 0x100000) { +			printf("%s: tx error\n", dev->name); +			return result; +		} +		status = BD_STATUS(bd); +	} + +	/* Ok, the buffer be transimitted */ +	BD_ADVANCE(bd, status, uec->p_tx_bd_ring); +	uec->txBd = bd; +	result = 1; + +	return result; +} + +static int uec_recv(struct eth_device* dev) +{ +	uec_private_t		*uec = dev->priv; +	volatile qe_bd_t	*bd; +	volatile u16		status; +	u16			len; +	u8			*data; + +	bd = uec->rxBd; +	status = BD_STATUS(bd); + +	while (!(status & RxBD_EMPTY)) { +		if (!(status & RxBD_ERROR)) { +			data = BD_DATA(bd); +			len = BD_LENGTH(bd); +			NetReceive(data, len); +		} else { +			printf("%s: Rx error\n", dev->name); +		} +		status &= BD_CLEAN; +		BD_LENGTH_SET(bd, 0); +		BD_STATUS_SET(bd, status | RxBD_EMPTY); +		BD_ADVANCE(bd, status, uec->p_rx_bd_ring); +		status = BD_STATUS(bd); +	} +	uec->rxBd = bd; + +	return 1; +} + +int uec_initialize(int index) +{ +	struct eth_device	*dev; +	int			i; +	uec_private_t		*uec; +	uec_info_t		*uec_info; +	int			err; + +	dev = (struct eth_device *)malloc(sizeof(struct eth_device)); +	if (!dev) +		return 0; +	memset(dev, 0, sizeof(struct eth_device)); + +	/* Allocate the UEC private struct */ +	uec = (uec_private_t *)malloc(sizeof(uec_private_t)); +	if (!uec) { +		return -ENOMEM; +	} +	memset(uec, 0, sizeof(uec_private_t)); + +	/* Init UEC private struct, they come from board.h */ +	if (index == 0) { +#ifdef CONFIG_UEC_ETH1 +		uec_info = ð1_uec_info; +#endif +	} else if (index == 1) { +#ifdef CONFIG_UEC_ETH2 +		uec_info = ð2_uec_info; +#endif +	} else { +		printf("%s: index is illegal.\n", __FUNCTION__); +		return -EINVAL; +	} + +	uec->uec_info = uec_info; + +	sprintf(dev->name, "FSL UEC%d", index); +	dev->iobase = 0; +	dev->priv = (void *)uec; +	dev->init = uec_init; +	dev->halt = uec_halt; +	dev->send = uec_send; +	dev->recv = uec_recv; + +	/* Clear the ethnet address */ +	for (i = 0; i < 6; i++) +		dev->enetaddr[i] = 0; + +	eth_register(dev); + +	err = uec_startup(uec); +	if (err) { +		printf("%s: Cannot configure net device, aborting.",dev->name); +		return err; +	} + +	err = init_phy(dev); +	if (err) { +		printf("%s: Cannot initialize PHY, aborting.\n", dev->name); +		return err; +	} + +	phy_change(dev); + +	return 1; +} +#endif /* CONFIG_QE */ diff --git a/drivers/qe/uec.h b/drivers/qe/uec.h new file mode 100644 index 000000000..04950264b --- /dev/null +++ b/drivers/qe/uec.h @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2006 Freescale Semiconductor, Inc. + * + * Dave Liu <daveliu@freescale.com> + * based on source code of Shlomi Gridish + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#ifndef __UEC_H__ +#define __UEC_H__ + +#define MAX_TX_THREADS				8 +#define MAX_RX_THREADS				8 +#define MAX_TX_QUEUES				8 +#define MAX_RX_QUEUES				8 +#define MAX_PREFETCHED_BDS			4 +#define MAX_IPH_OFFSET_ENTRY			8 +#define MAX_ENET_INIT_PARAM_ENTRIES_RX		9 +#define MAX_ENET_INIT_PARAM_ENTRIES_TX		8 + +/* UEC UPSMR (Protocol Specific Mode Register) + */ +#define UPSMR_ECM	0x04000000 /* Enable CAM Miss               */ +#define UPSMR_HSE	0x02000000 /* Hardware Statistics Enable    */ +#define UPSMR_PRO	0x00400000 /* Promiscuous                   */ +#define UPSMR_CAP	0x00200000 /* CAM polarity                  */ +#define UPSMR_RSH	0x00100000 /* Receive Short Frames          */ +#define UPSMR_RPM	0x00080000 /* Reduced Pin Mode interfaces   */ +#define UPSMR_R10M	0x00040000 /* RGMII/RMII 10 Mode            */ +#define UPSMR_RLPB	0x00020000 /* RMII Loopback Mode            */ +#define UPSMR_TBIM	0x00010000 /* Ten-bit Interface Mode        */ +#define UPSMR_RMM	0x00001000 /* RMII/RGMII Mode               */ +#define UPSMR_CAM	0x00000400 /* CAM Address Matching          */ +#define UPSMR_BRO	0x00000200 /* Broadcast Address             */ +#define UPSMR_RES1	0x00002000 /* Reserved feild - must be 1    */ + +#define UPSMR_INIT_VALUE	(UPSMR_HSE | UPSMR_RES1) + +/* UEC MACCFG1 (MAC Configuration 1 Register) + */ +#define MACCFG1_FLOW_RX			0x00000020 /* Flow Control Rx */ +#define MACCFG1_FLOW_TX			0x00000010 /* Flow Control Tx */ +#define MACCFG1_ENABLE_SYNCHED_RX	0x00000008 /* Enable Rx Sync  */ +#define MACCFG1_ENABLE_RX		0x00000004 /* Enable Rx       */ +#define MACCFG1_ENABLE_SYNCHED_TX	0x00000002 /* Enable Tx Sync  */ +#define MACCFG1_ENABLE_TX		0x00000001 /* Enable Tx       */ + +#define MACCFG1_INIT_VALUE		(0) + +/* UEC MACCFG2 (MAC Configuration 2 Register) + */ +#define MACCFG2_PREL				0x00007000 +#define MACCFG2_PREL_SHIFT			(31 - 19) +#define MACCFG2_PREL_MASK			0x0000f000 +#define MACCFG2_SRP				0x00000080 +#define MACCFG2_STP				0x00000040 +#define MACCFG2_RESERVED_1			0x00000020 /* must be set  */ +#define MACCFG2_LC				0x00000010 /* Length Check */ +#define MACCFG2_MPE				0x00000008 +#define MACCFG2_FDX				0x00000001 /* Full Duplex  */ +#define MACCFG2_FDX_MASK			0x00000001 +#define MACCFG2_PAD_CRC				0x00000004 +#define MACCFG2_CRC_EN				0x00000002 +#define MACCFG2_PAD_AND_CRC_MODE_NONE		0x00000000 +#define MACCFG2_PAD_AND_CRC_MODE_CRC_ONLY	0x00000002 +#define MACCFG2_PAD_AND_CRC_MODE_PAD_AND_CRC	0x00000004 +#define MACCFG2_INTERFACE_MODE_NIBBLE		0x00000100 +#define MACCFG2_INTERFACE_MODE_BYTE		0x00000200 +#define MACCFG2_INTERFACE_MODE_MASK		0x00000300 + +#define MACCFG2_INIT_VALUE	(MACCFG2_PREL | MACCFG2_RESERVED_1 | \ +				 MACCFG2_LC | MACCFG2_PAD_CRC | MACCFG2_FDX) + +/* UEC Event Register +*/ +#define UCCE_MPD				0x80000000 +#define UCCE_SCAR				0x40000000 +#define UCCE_GRA				0x20000000 +#define UCCE_CBPR				0x10000000 +#define UCCE_BSY				0x08000000 +#define UCCE_RXC				0x04000000 +#define UCCE_TXC				0x02000000 +#define UCCE_TXE				0x01000000 +#define UCCE_TXB7				0x00800000 +#define UCCE_TXB6				0x00400000 +#define UCCE_TXB5				0x00200000 +#define UCCE_TXB4				0x00100000 +#define UCCE_TXB3				0x00080000 +#define UCCE_TXB2				0x00040000 +#define UCCE_TXB1				0x00020000 +#define UCCE_TXB0				0x00010000 +#define UCCE_RXB7				0x00008000 +#define UCCE_RXB6				0x00004000 +#define UCCE_RXB5				0x00002000 +#define UCCE_RXB4				0x00001000 +#define UCCE_RXB3				0x00000800 +#define UCCE_RXB2				0x00000400 +#define UCCE_RXB1				0x00000200 +#define UCCE_RXB0				0x00000100 +#define UCCE_RXF7				0x00000080 +#define UCCE_RXF6				0x00000040 +#define UCCE_RXF5				0x00000020 +#define UCCE_RXF4				0x00000010 +#define UCCE_RXF3				0x00000008 +#define UCCE_RXF2				0x00000004 +#define UCCE_RXF1				0x00000002 +#define UCCE_RXF0				0x00000001 + +#define UCCE_TXB	(UCCE_TXB7 | UCCE_TXB6 | UCCE_TXB5 | UCCE_TXB4 | \ +			 UCCE_TXB3 | UCCE_TXB2 | UCCE_TXB1 | UCCE_TXB0) +#define UCCE_RXB	(UCCE_RXB7 | UCCE_RXB6 | UCCE_RXB5 | UCCE_RXB4 | \ +			 UCCE_RXB3 | UCCE_RXB2 | UCCE_RXB1 | UCCE_RXB0) +#define UCCE_RXF	(UCCE_RXF7 | UCCE_RXF6 | UCCE_RXF5 | UCCE_RXF4 | \ +			 UCCE_RXF3 | UCCE_RXF2 | UCCE_RXF1 | UCCE_RXF0) +#define UCCE_OTHER	(UCCE_SCAR | UCCE_GRA  | UCCE_CBPR | UCCE_BSY  | \ +			 UCCE_RXC  | UCCE_TXC  | UCCE_TXE) + +/* UEC TEMODR Register +*/ +#define TEMODER_SCHEDULER_ENABLE		0x2000 +#define TEMODER_IP_CHECKSUM_GENERATE		0x0400 +#define TEMODER_PERFORMANCE_OPTIMIZATION_MODE1	0x0200 +#define TEMODER_RMON_STATISTICS			0x0100 +#define TEMODER_NUM_OF_QUEUES_SHIFT		(15-15) + +#define TEMODER_INIT_VALUE			0xc000 + +/* UEC REMODR Register +*/ +#define REMODER_RX_RMON_STATISTICS_ENABLE	0x00001000 +#define REMODER_RX_EXTENDED_FEATURES		0x80000000 +#define REMODER_VLAN_OPERATION_TAGGED_SHIFT	(31-9 ) +#define REMODER_VLAN_OPERATION_NON_TAGGED_SHIFT	(31-10) +#define REMODER_RX_QOS_MODE_SHIFT		(31-15) +#define REMODER_RMON_STATISTICS			0x00001000 +#define REMODER_RX_EXTENDED_FILTERING		0x00000800 +#define REMODER_NUM_OF_QUEUES_SHIFT		(31-23) +#define REMODER_DYNAMIC_MAX_FRAME_LENGTH	0x00000008 +#define REMODER_DYNAMIC_MIN_FRAME_LENGTH	0x00000004 +#define REMODER_IP_CHECKSUM_CHECK		0x00000002 +#define REMODER_IP_ADDRESS_ALIGNMENT		0x00000001 + +#define REMODER_INIT_VALUE			0 + +/* BMRx - Bus Mode Register */ +#define BMR_GLB					0x20 +#define BMR_BO_BE				0x10 +#define BMR_DTB_SECONDARY_BUS			0x02 +#define BMR_BDB_SECONDARY_BUS			0x01 + +#define BMR_SHIFT				24 +#define BMR_INIT_VALUE				(BMR_GLB | BMR_BO_BE) + +/* UEC UCCS (Ethernet Status Register) + */ +#define UCCS_BPR				0x02 +#define UCCS_PAU				0x02 +#define UCCS_MPD				0x01 + +/* UEC MIIMCFG (MII Management Configuration Register) + */ +#define MIIMCFG_RESET_MANAGEMENT		0x80000000 +#define MIIMCFG_NO_PREAMBLE			0x00000010 +#define MIIMCFG_CLOCK_DIVIDE_SHIFT		(31 - 31) +#define MIIMCFG_CLOCK_DIVIDE_MASK		0x0000000f +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4	0x00000001 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6	0x00000002 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8	0x00000003 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10	0x00000004 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14	0x00000005 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20	0x00000006 +#define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28	0x00000007 + +#define MIIMCFG_MNGMNT_CLC_DIV_INIT_VALUE	\ +	MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 + +/* UEC MIIMCOM (MII Management Command Register) + */ +#define MIIMCOM_SCAN_CYCLE			0x00000002 /* Scan cycle */ +#define MIIMCOM_READ_CYCLE			0x00000001 /* Read cycle */ + +/* UEC MIIMADD (MII Management Address Register) + */ +#define MIIMADD_PHY_ADDRESS_SHIFT		(31 - 23) +#define MIIMADD_PHY_REGISTER_SHIFT		(31 - 31) + +/* UEC MIIMCON (MII Management Control Register) + */ +#define MIIMCON_PHY_CONTROL_SHIFT		(31 - 31) +#define MIIMCON_PHY_STATUS_SHIFT		(31 - 31) + +/* UEC MIIMIND (MII Management Indicator Register) + */ +#define MIIMIND_NOT_VALID			0x00000004 +#define MIIMIND_SCAN				0x00000002 +#define MIIMIND_BUSY				0x00000001 + +/* UEC UTBIPAR (Ten Bit Interface Physical Address Register) + */ +#define UTBIPAR_PHY_ADDRESS_SHIFT		(31 - 31) +#define UTBIPAR_PHY_ADDRESS_MASK		0x0000001f + +/* UEC UESCR (Ethernet Statistics Control Register) + */ +#define UESCR_AUTOZ				0x8000 +#define UESCR_CLRCNT				0x4000 +#define UESCR_MAXCOV_SHIFT			(15 -  7) +#define UESCR_SCOV_SHIFT			(15 - 15) + +/****** Tx data struct collection ******/ +/* Tx thread data, each Tx thread has one this struct. +*/ +typedef struct uec_thread_data_tx { +	u8   res0[136]; +} __attribute__ ((packed)) uec_thread_data_tx_t; + +/* Tx thread parameter, each Tx thread has one this struct. +*/ +typedef struct uec_thread_tx_pram { +	u8   res0[64]; +} __attribute__ ((packed)) uec_thread_tx_pram_t; + +/* Send queue queue-descriptor, each Tx queue has one this QD +*/ +typedef struct uec_send_queue_qd { +	u32    bd_ring_base; /* pointer to BD ring base address */ +	u8     res0[0x8]; +	u32    last_bd_completed_address; /* last entry in BD ring */ +	u8     res1[0x30]; +} __attribute__ ((packed)) uec_send_queue_qd_t; + +/* Send queue memory region */ +typedef struct uec_send_queue_mem_region { +	uec_send_queue_qd_t   sqqd[MAX_TX_QUEUES]; +} __attribute__ ((packed)) uec_send_queue_mem_region_t; + +/* Scheduler struct +*/ +typedef struct uec_scheduler { +	u16  cpucount0;        /* CPU packet counter */ +	u16  cpucount1;        /* CPU packet counter */ +	u16  cecount0;         /* QE  packet counter */ +	u16  cecount1;         /* QE  packet counter */ +	u16  cpucount2;        /* CPU packet counter */ +	u16  cpucount3;        /* CPU packet counter */ +	u16  cecount2;         /* QE  packet counter */ +	u16  cecount3;         /* QE  packet counter */ +	u16  cpucount4;        /* CPU packet counter */ +	u16  cpucount5;        /* CPU packet counter */ +	u16  cecount4;         /* QE  packet counter */ +	u16  cecount5;         /* QE  packet counter */ +	u16  cpucount6;        /* CPU packet counter */ +	u16  cpucount7;        /* CPU packet counter */ +	u16  cecount6;         /* QE  packet counter */ +	u16  cecount7;         /* QE  packet counter */ +	u32  weightstatus[MAX_TX_QUEUES]; /* accumulated weight factor */ +	u32  rtsrshadow;       /* temporary variable handled by QE */ +	u32  time;             /* temporary variable handled by QE */ +	u32  ttl;              /* temporary variable handled by QE */ +	u32  mblinterval;      /* max burst length interval        */ +	u16  nortsrbytetime;   /* normalized value of byte time in tsr units */ +	u8   fracsiz; +	u8   res0[1]; +	u8   strictpriorityq;  /* Strict Priority Mask register */ +	u8   txasap;           /* Transmit ASAP register        */ +	u8   extrabw;          /* Extra BandWidth register      */ +	u8   oldwfqmask;       /* temporary variable handled by QE */ +	u8   weightfactor[MAX_TX_QUEUES]; /**< weight factor for queues */ +	u32  minw;             /* temporary variable handled by QE */ +	u8   res1[0x70-0x64]; +} __attribute__ ((packed)) uec_scheduler_t; + +/* Tx firmware counters +*/ +typedef struct uec_tx_firmware_statistics_pram { +	u32  sicoltx;            /* single collision */ +	u32  mulcoltx;           /* multiple collision */ +	u32  latecoltxfr;        /* late collision */ +	u32  frabortduecol;      /* frames aborted due to tx collision */ +	u32  frlostinmactxer;    /* frames lost due to internal MAC error tx */ +	u32  carriersenseertx;   /* carrier sense error */ +	u32  frtxok;             /* frames transmitted OK */ +	u32  txfrexcessivedefer; +	u32  txpkts256;          /* total packets(including bad) 256~511 B */ +	u32  txpkts512;          /* total packets(including bad) 512~1023B */ +	u32  txpkts1024;         /* total packets(including bad) 1024~1518B */ +	u32  txpktsjumbo;        /* total packets(including bad)  >1024 */ +} __attribute__ ((packed)) uec_tx_firmware_statistics_pram_t; + +/* Tx global parameter table +*/ +typedef struct uec_tx_global_pram { +	u16  temoder; +	u8   res0[0x38-0x02]; +	u32  sqptr; +	u32  schedulerbasepointer; +	u32  txrmonbaseptr; +	u32  tstate; +	u8   iphoffset[MAX_IPH_OFFSET_ENTRY]; +	u32  vtagtable[0x8]; +	u32  tqptr; +	u8   res2[0x80-0x74]; +} __attribute__ ((packed)) uec_tx_global_pram_t; + + +/****** Rx data struct collection ******/ +/* Rx thread data, each Rx thread has one this struct. +*/ +typedef struct uec_thread_data_rx { +	u8   res0[40]; +} __attribute__ ((packed)) uec_thread_data_rx_t; + +/* Rx thread parameter, each Rx thread has one this struct. +*/ +typedef struct uec_thread_rx_pram { +	u8   res0[128]; +} __attribute__ ((packed)) uec_thread_rx_pram_t; + +/* Rx firmware counters +*/ +typedef struct uec_rx_firmware_statistics_pram { +	u32   frrxfcser;         /* frames with crc error */ +	u32   fraligner;         /* frames with alignment error */ +	u32   inrangelenrxer;    /* in range length error */ +	u32   outrangelenrxer;   /* out of range length error */ +	u32   frtoolong;         /* frame too long */ +	u32   runt;              /* runt */ +	u32   verylongevent;     /* very long event */ +	u32   symbolerror;       /* symbol error */ +	u32   dropbsy;           /* drop because of BD not ready */ +	u8    res0[0x8]; +	u32   mismatchdrop;      /* drop because of MAC filtering */ +	u32   underpkts;         /* total frames less than 64 octets */ +	u32   pkts256;           /* total frames(including bad)256~511 B */ +	u32   pkts512;           /* total frames(including bad)512~1023 B */ +	u32   pkts1024;          /* total frames(including bad)1024~1518 B */ +	u32   pktsjumbo;         /* total frames(including bad) >1024 B */ +	u32   frlossinmacer; +	u32   pausefr;           /* pause frames */ +	u8    res1[0x4]; +	u32   removevlan; +	u32   replacevlan; +	u32   insertvlan; +} __attribute__ ((packed)) uec_rx_firmware_statistics_pram_t; + +/* Rx interrupt coalescing entry, each Rx queue has one this entry. +*/ +typedef struct uec_rx_interrupt_coalescing_entry { +	u32   maxvalue; +	u32   counter; +} __attribute__ ((packed)) uec_rx_interrupt_coalescing_entry_t; + +typedef struct uec_rx_interrupt_coalescing_table { +	uec_rx_interrupt_coalescing_entry_t   entry[MAX_RX_QUEUES]; +} __attribute__ ((packed)) uec_rx_interrupt_coalescing_table_t; + +/* RxBD queue entry, each Rx queue has one this entry. +*/ +typedef struct uec_rx_bd_queues_entry { +	u32   bdbaseptr;         /* BD base pointer          */ +	u32   bdptr;             /* BD pointer               */ +	u32   externalbdbaseptr; /* external BD base pointer */ +	u32   externalbdptr;     /* external BD pointer      */ +} __attribute__ ((packed)) uec_rx_bd_queues_entry_t; + +/* Rx global paramter table +*/ +typedef struct uec_rx_global_pram { +	u32  remoder;             /* ethernet mode reg. */ +	u32  rqptr;               /* base pointer to the Rx Queues */ +	u32  res0[0x1]; +	u8   res1[0x20-0xC]; +	u16  typeorlen; +	u8   res2[0x1]; +	u8   rxgstpack;           /* ack on GRACEFUL STOP RX command */ +	u32  rxrmonbaseptr;       /* Rx RMON statistics base */ +	u8   res3[0x30-0x28]; +	u32  intcoalescingptr;    /* Interrupt coalescing table pointer */ +	u8   res4[0x36-0x34]; +	u8   rstate; +	u8   res5[0x46-0x37]; +	u16  mrblr;               /* max receive buffer length reg. */ +	u32  rbdqptr;             /* RxBD parameter table description */ +	u16  mflr;                /* max frame length reg. */ +	u16  minflr;              /* min frame length reg. */ +	u16  maxd1;               /* max dma1 length reg. */ +	u16  maxd2;               /* max dma2 length reg. */ +	u32  ecamptr;             /* external CAM address */ +	u32  l2qt;                /* VLAN priority mapping table. */ +	u32  l3qt[0x8];           /* IP   priority mapping table. */ +	u16  vlantype;            /* vlan type */ +	u16  vlantci;             /* default vlan tci */ +	u8   addressfiltering[64];/* address filtering data structure */ +	u32  exfGlobalParam;      /* extended filtering global parameters */ +	u8   res6[0x100-0xC4];    /* Initialize to zero */ +} __attribute__ ((packed)) uec_rx_global_pram_t; + +#define GRACEFUL_STOP_ACKNOWLEDGE_RX            0x01 + + +/****** UEC common ******/ +/* UCC statistics - hardware counters +*/ +typedef struct uec_hardware_statistics { +	u32 tx64; +	u32 tx127; +	u32 tx255; +	u32 rx64; +	u32 rx127; +	u32 rx255; +	u32 txok; +	u16 txcf; +	u32 tmca; +	u32 tbca; +	u32 rxfok; +	u32 rxbok; +	u32 rbyt; +	u32 rmca; +	u32 rbca; +} __attribute__ ((packed)) uec_hardware_statistics_t; + +/* InitEnet command parameter +*/ +typedef struct uec_init_cmd_pram { +	u8   resinit0; +	u8   resinit1; +	u8   resinit2; +	u8   resinit3; +	u16  resinit4; +	u8   res1[0x1]; +	u8   largestexternallookupkeysize; +	u32  rgftgfrxglobal; +	u32  rxthread[MAX_ENET_INIT_PARAM_ENTRIES_RX]; /* rx threads */ +	u8   res2[0x38 - 0x30]; +	u32  txglobal;				   /* tx global  */ +	u32  txthread[MAX_ENET_INIT_PARAM_ENTRIES_TX]; /* tx threads */ +	u8   res3[0x1]; +} __attribute__ ((packed)) uec_init_cmd_pram_t; + +#define ENET_INIT_PARAM_RGF_SHIFT		(32 - 4) +#define ENET_INIT_PARAM_TGF_SHIFT		(32 - 8) + +#define ENET_INIT_PARAM_RISC_MASK		0x0000003f +#define ENET_INIT_PARAM_PTR_MASK		0x00ffffc0 +#define ENET_INIT_PARAM_SNUM_MASK		0xff000000 +#define ENET_INIT_PARAM_SNUM_SHIFT		24 + +#define ENET_INIT_PARAM_MAGIC_RES_INIT0		0x06 +#define ENET_INIT_PARAM_MAGIC_RES_INIT1		0x30 +#define ENET_INIT_PARAM_MAGIC_RES_INIT2		0xff +#define ENET_INIT_PARAM_MAGIC_RES_INIT3		0x00 +#define ENET_INIT_PARAM_MAGIC_RES_INIT4		0x0400 + +/* structure representing 82xx Address Filtering Enet Address in PRAM +*/ +typedef struct uec_82xx_enet_address { +	u8   res1[0x2]; +	u16  h;       /* address (MSB) */ +	u16  m;       /* address       */ +	u16  l;       /* address (LSB) */ +} __attribute__ ((packed)) uec_82xx_enet_address_t; + +/* structure representing 82xx Address Filtering PRAM +*/ +typedef struct uec_82xx_address_filtering_pram { +	u32  iaddr_h;        /* individual address filter, high */ +	u32  iaddr_l;        /* individual address filter, low  */ +	u32  gaddr_h;        /* group address filter, high      */ +	u32  gaddr_l;        /* group address filter, low       */ +	uec_82xx_enet_address_t    taddr; +	uec_82xx_enet_address_t    paddr[4]; +	u8                         res0[0x40-0x38]; +} __attribute__ ((packed)) uec_82xx_address_filtering_pram_t; + +/* Buffer Descriptor +*/ +typedef struct buffer_descriptor { +	u16 status; +	u16 len; +	u32 data; +} __attribute__ ((packed)) qe_bd_t, *p_bd_t; + +#define	SIZEOFBD		sizeof(qe_bd_t) + +/* Common BD flags +*/ +#define BD_WRAP			0x2000 +#define BD_INT			0x1000 +#define BD_LAST			0x0800 +#define BD_CLEAN		0x3000 + +/* TxBD status flags +*/ +#define TxBD_READY		0x8000 +#define TxBD_PADCRC		0x4000 +#define TxBD_WRAP		BD_WRAP +#define TxBD_INT		BD_INT +#define TxBD_LAST		BD_LAST +#define TxBD_TXCRC		0x0400 +#define TxBD_DEF		0x0200 +#define TxBD_PP			0x0100 +#define TxBD_LC			0x0080 +#define TxBD_RL			0x0040 +#define TxBD_RC			0x003C +#define TxBD_UNDERRUN		0x0002 +#define TxBD_TRUNC		0x0001 + +#define TxBD_ERROR		(TxBD_UNDERRUN | TxBD_TRUNC) + +/* RxBD status flags +*/ +#define RxBD_EMPTY		0x8000 +#define RxBD_OWNER		0x4000 +#define RxBD_WRAP		BD_WRAP +#define RxBD_INT		BD_INT +#define RxBD_LAST		BD_LAST +#define RxBD_FIRST		0x0400 +#define RxBD_CMR		0x0200 +#define RxBD_MISS		0x0100 +#define RxBD_BCAST		0x0080 +#define RxBD_MCAST		0x0040 +#define RxBD_LG			0x0020 +#define RxBD_NO			0x0010 +#define RxBD_SHORT		0x0008 +#define RxBD_CRCERR		0x0004 +#define RxBD_OVERRUN		0x0002 +#define RxBD_IPCH		0x0001 + +#define RxBD_ERROR		(RxBD_LG | RxBD_NO | RxBD_SHORT | \ +				 RxBD_CRCERR | RxBD_OVERRUN) + +/* BD access macros +*/ +#define BD_STATUS(_bd)			(((p_bd_t)(_bd))->status) +#define BD_STATUS_SET(_bd, _val)	(((p_bd_t)(_bd))->status = _val) +#define BD_LENGTH(_bd)			(((p_bd_t)(_bd))->len) +#define BD_LENGTH_SET(_bd, _val)	(((p_bd_t)(_bd))->len = _val) +#define BD_DATA_CLEAR(_bd)		(((p_bd_t)(_bd))->data = 0) +#define BD_IS_DATA(_bd)			(((p_bd_t)(_bd))->data) +#define BD_DATA(_bd)			((u8 *)(((p_bd_t)(_bd))->data)) +#define BD_DATA_SET(_bd, _data)		(((p_bd_t)(_bd))->data = (u32)(_data)) +#define BD_ADVANCE(_bd,_status,_base)	\ +	(((_status) & BD_WRAP) ? (_bd) = ((p_bd_t)(_base)) : ++(_bd)) + +/* Rx Prefetched BDs +*/ +typedef struct uec_rx_prefetched_bds { +    qe_bd_t   bd[MAX_PREFETCHED_BDS]; /* prefetched bd */ +} __attribute__ ((packed)) uec_rx_prefetched_bds_t; + +/* Alignments + */ +#define UEC_RX_GLOBAL_PRAM_ALIGNMENT				64 +#define UEC_TX_GLOBAL_PRAM_ALIGNMENT				64 +#define UEC_THREAD_RX_PRAM_ALIGNMENT				128 +#define UEC_THREAD_TX_PRAM_ALIGNMENT				64 +#define UEC_THREAD_DATA_ALIGNMENT				256 +#define UEC_SEND_QUEUE_QUEUE_DESCRIPTOR_ALIGNMENT		32 +#define UEC_SCHEDULER_ALIGNMENT					4 +#define UEC_TX_STATISTICS_ALIGNMENT				4 +#define UEC_RX_STATISTICS_ALIGNMENT				4 +#define UEC_RX_INTERRUPT_COALESCING_ALIGNMENT			4 +#define UEC_RX_BD_QUEUES_ALIGNMENT				8 +#define UEC_RX_PREFETCHED_BDS_ALIGNMENT				128 +#define UEC_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT	4 +#define UEC_RX_BD_RING_ALIGNMENT				32 +#define UEC_TX_BD_RING_ALIGNMENT				32 +#define UEC_MRBLR_ALIGNMENT					128 +#define UEC_RX_BD_RING_SIZE_ALIGNMENT				4 +#define UEC_TX_BD_RING_SIZE_MEMORY_ALIGNMENT			32 +#define UEC_RX_DATA_BUF_ALIGNMENT				64 + +#define UEC_VLAN_PRIORITY_MAX					8 +#define UEC_IP_PRIORITY_MAX					64 +#define UEC_TX_VTAG_TABLE_ENTRY_MAX				8 +#define UEC_RX_BD_RING_SIZE_MIN					8 +#define UEC_TX_BD_RING_SIZE_MIN					2 + +/* Ethernet speed +*/ +typedef enum enet_speed { +	ENET_SPEED_10BT,   /* 10 Base T */ +	ENET_SPEED_100BT,  /* 100 Base T */ +	ENET_SPEED_1000BT  /* 1000 Base T */ +} enet_speed_e; + +/* Ethernet Address Type. +*/ +typedef enum enet_addr_type { +	ENET_ADDR_TYPE_INDIVIDUAL, +	ENET_ADDR_TYPE_GROUP, +	ENET_ADDR_TYPE_BROADCAST +} enet_addr_type_e; + +/* TBI / MII Set Register +*/ +typedef enum enet_tbi_mii_reg { +	ENET_TBI_MII_CR        = 0x00, +	ENET_TBI_MII_SR        = 0x01, +	ENET_TBI_MII_ANA       = 0x04, +	ENET_TBI_MII_ANLPBPA   = 0x05, +	ENET_TBI_MII_ANEX      = 0x06, +	ENET_TBI_MII_ANNPT     = 0x07, +	ENET_TBI_MII_ANLPANP   = 0x08, +	ENET_TBI_MII_EXST      = 0x0F, +	ENET_TBI_MII_JD        = 0x10, +	ENET_TBI_MII_TBICON    = 0x11 +} enet_tbi_mii_reg_e; + +/* UEC number of threads +*/ +typedef enum uec_num_of_threads { +	UEC_NUM_OF_THREADS_1  = 0x1,  /* 1 */ +	UEC_NUM_OF_THREADS_2  = 0x2,  /* 2 */ +	UEC_NUM_OF_THREADS_4  = 0x0,  /* 4 */ +	UEC_NUM_OF_THREADS_6  = 0x3,  /* 6 */ +	UEC_NUM_OF_THREADS_8  = 0x4   /* 8 */ +} uec_num_of_threads_e; + +/* UEC ethernet interface type +*/ +typedef enum enet_interface { +	ENET_10_MII, +	ENET_10_RMII, +	ENET_10_RGMII, +	ENET_100_MII, +	ENET_100_RMII, +	ENET_100_RGMII, +	ENET_1000_GMII, +	ENET_1000_RGMII, +	ENET_1000_TBI, +	ENET_1000_RTBI +} enet_interface_e; + +/* UEC initialization info struct +*/ +typedef struct uec_info { +	ucc_fast_info_t			uf_info; +	uec_num_of_threads_e		num_threads_tx; +	uec_num_of_threads_e		num_threads_rx; +	qe_risc_allocation_e		riscTx; +	qe_risc_allocation_e		riscRx; +	u16				rx_bd_ring_len; +	u16				tx_bd_ring_len; +	u8				phy_address; +	enet_interface_e		enet_interface; +} uec_info_t; + +/* UEC driver initialized info +*/ +#define MAX_RXBUF_LEN			1536 +#define MAX_FRAME_LEN			1518 +#define MIN_FRAME_LEN			64 +#define MAX_DMA1_LEN			1520 +#define MAX_DMA2_LEN			1520 + +/* UEC driver private struct +*/ +typedef struct uec_private { +	uec_info_t			*uec_info; +	ucc_fast_private_t		*uccf; +	struct eth_device		*dev; +	uec_t				*uec_regs; +	/* enet init command parameter */ +	uec_init_cmd_pram_t		*p_init_enet_param; +	u32				init_enet_param_offset; +	/* Rx and Tx paramter */ +	uec_rx_global_pram_t		*p_rx_glbl_pram; +	u32				rx_glbl_pram_offset; +	uec_tx_global_pram_t		*p_tx_glbl_pram; +	u32				tx_glbl_pram_offset; +	uec_send_queue_mem_region_t	*p_send_q_mem_reg; +	u32				send_q_mem_reg_offset; +	uec_thread_data_tx_t		*p_thread_data_tx; +	u32				thread_dat_tx_offset; +	uec_thread_data_rx_t		*p_thread_data_rx; +	u32				thread_dat_rx_offset; +	uec_rx_bd_queues_entry_t	*p_rx_bd_qs_tbl; +	u32				rx_bd_qs_tbl_offset; +	/* BDs specific */ +	u8				*p_tx_bd_ring; +	u32				tx_bd_ring_offset; +	u8				*p_rx_bd_ring; +	u32				rx_bd_ring_offset; +	u8				*p_rx_buf; +	u32				rx_buf_offset; +	volatile qe_bd_t		*txBd; +	volatile qe_bd_t		*rxBd; +	/* Status */ +	int				mac_tx_enabled; +	int				mac_rx_enabled; +	int				grace_stopped_tx; +	int				grace_stopped_rx; +	int				the_first_run; +	/* PHY specific */ +	struct uec_mii_info 		*mii_info; +	int				oldspeed; +	int				oldduplex; +	int				oldlink; +} uec_private_t; + +#endif /* __UEC_H__ */ diff --git a/drivers/qe/uec_phy.c b/drivers/qe/uec_phy.c new file mode 100644 index 000000000..fedf6361c --- /dev/null +++ b/drivers/qe/uec_phy.c @@ -0,0 +1,604 @@ +/* + * Copyright (C) 2005 Freescale Semiconductor, Inc. + * + * Author: Shlomi Gridish + * + * Description: UCC GETH Driver -- PHY handling + * 		Driver for UEC on QE + * 		Based on 8260_io/fcc_enet.c + * + * This program is free software; you can redistribute  it and/or modify it + * under  the terms of  the GNU General  Public License as published by the + * Free Software Foundation;  either version 2 of the  License, or (at your + * option) any later version. + * + */ + +#include "common.h" +#include "net.h" +#include "malloc.h" +#include "asm/errno.h" +#include "asm/immap_qe.h" +#include "asm/io.h" +#include "qe.h" +#include "uccf.h" +#include "uec.h" +#include "uec_phy.h" +#include "miiphy.h" + +#if defined(CONFIG_QE) + +#define UEC_VERBOSE_DEBUG +#define ugphy_printk(format, arg...)  \ +        printf(format "\n", ## arg) + +#define ugphy_dbg(format, arg...)            \ +        ugphy_printk(format , ## arg) +#define ugphy_err(format, arg...)            \ +        ugphy_printk(format , ## arg) +#define ugphy_info(format, arg...)           \ +        ugphy_printk(format , ## arg) +#define ugphy_warn(format, arg...)           \ +        ugphy_printk(format , ## arg) + +#ifdef UEC_VERBOSE_DEBUG +#define ugphy_vdbg ugphy_dbg +#else +#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0) +#endif /* UEC_VERBOSE_DEBUG */ + +static void config_genmii_advert(struct uec_mii_info *mii_info); +static void genmii_setup_forced(struct uec_mii_info *mii_info); +static void genmii_restart_aneg(struct uec_mii_info *mii_info); +static int gbit_config_aneg(struct uec_mii_info *mii_info); +static int genmii_config_aneg(struct uec_mii_info *mii_info); +static int genmii_update_link(struct uec_mii_info *mii_info); +static int genmii_read_status(struct uec_mii_info *mii_info); +u16 phy_read(struct uec_mii_info *mii_info, u16 regnum); +void phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val); + +/* Write value to the PHY for this device to the register at regnum, */ +/* waiting until the write is done before it returns.  All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +void write_phy_reg(struct eth_device *dev, int mii_id, int regnum, int value) +{ +    uec_private_t      *ugeth = (uec_private_t *)dev->priv; +    uec_t             *ug_regs; +    enet_tbi_mii_reg_e     mii_reg = (enet_tbi_mii_reg_e)regnum; +    u32                    tmp_reg; + +    ug_regs = ugeth->uec_regs; + +    /* Stop the MII management read cycle */ +    out_be32(&ug_regs->miimcom, 0); +    /* Setting up the MII Mangement Address Register */ +    tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; +    out_be32(&ug_regs->miimadd, tmp_reg); + +    /* Setting up the MII Mangement Control Register with the value */ +    out_be32(&ug_regs->miimcon, (u32)value); + +    /* Wait till MII management write is complete */ +    while((in_be32(&ug_regs->miimind)) & MIIMIND_BUSY); + +    udelay(100000); +} + +/* Reads from register regnum in the PHY for device dev, */ +/* returning the value.  Clears miimcom first.  All PHY */ +/* configuration has to be done through the TSEC1 MIIM regs */ +int read_phy_reg(struct eth_device *dev, int mii_id, int regnum) +{ +    uec_private_t      *ugeth = (uec_private_t *)dev->priv; +    uec_t             *ug_regs; +    enet_tbi_mii_reg_e     mii_reg = (enet_tbi_mii_reg_e)regnum; +    u32                    tmp_reg; +    u16                    value; + +    ug_regs = ugeth->uec_regs; + +    /* Setting up the MII Mangement Address Register */ +    tmp_reg = ((u32)mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg ; +    out_be32(&ug_regs->miimadd, tmp_reg); + +    /* Perform an MII management read cycle */ +    out_be32(&ug_regs->miimcom, 0); +    out_be32(&ug_regs->miimcom, MIIMCOM_READ_CYCLE); + +    /* Wait till MII management write is complete */ +    while((in_be32(&ug_regs->miimind)) & (MIIMIND_NOT_VALID | MIIMIND_BUSY)); + +    udelay(100000); + +    /* Read MII management status  */ +    value = (u16)in_be32(&ug_regs->miimstat); +    if(value == 0xffff) +        ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", +                   mii_id, mii_reg, (u32) &(ug_regs->miimcfg)); + +    return (value); +} + +void mii_clear_phy_interrupt(struct uec_mii_info *mii_info) +{ +    if(mii_info->phyinfo->ack_interrupt) +        mii_info->phyinfo->ack_interrupt(mii_info); +} + +void mii_configure_phy_interrupt(struct uec_mii_info *mii_info, u32 interrupts) +{ +    mii_info->interrupts = interrupts; +    if(mii_info->phyinfo->config_intr) +        mii_info->phyinfo->config_intr(mii_info); +} + +/* Writes MII_ADVERTISE with the appropriate values, after + * sanitizing advertise to make sure only supported features + * are advertised + */ +static void config_genmii_advert(struct uec_mii_info *mii_info) +{ +    u32 advertise; +    u16 adv; + +    /* Only allow advertising what this PHY supports */ +    mii_info->advertising &= mii_info->phyinfo->features; +    advertise = mii_info->advertising; + +    /* Setup standard advertisement */ +    adv = phy_read(mii_info, PHY_ANAR); +    adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); +    if (advertise & ADVERTISED_10baseT_Half) +        adv |= ADVERTISE_10HALF; +    if (advertise & ADVERTISED_10baseT_Full) +        adv |= ADVERTISE_10FULL; +    if (advertise & ADVERTISED_100baseT_Half) +        adv |= ADVERTISE_100HALF; +    if (advertise & ADVERTISED_100baseT_Full) +        adv |= ADVERTISE_100FULL; +    phy_write(mii_info, PHY_ANAR, adv); +} + +static void genmii_setup_forced(struct uec_mii_info *mii_info) +{ +    u16 ctrl; +    u32 features = mii_info->phyinfo->features; + +    ctrl = phy_read(mii_info, PHY_BMCR); + +    ctrl &= ~(PHY_BMCR_DPLX|PHY_BMCR_100_MBPS| +		PHY_BMCR_1000_MBPS|PHY_BMCR_AUTON); +    ctrl |= PHY_BMCR_RESET; + +    switch(mii_info->speed) { +        case SPEED_1000: +            if(features & (SUPPORTED_1000baseT_Half +                        | SUPPORTED_1000baseT_Full)) { +                ctrl |= PHY_BMCR_1000_MBPS; +                break; +            } +            mii_info->speed = SPEED_100; +        case SPEED_100: +            if (features & (SUPPORTED_100baseT_Half +                        | SUPPORTED_100baseT_Full)) { +                ctrl |= PHY_BMCR_100_MBPS; +                break; +            } +            mii_info->speed = SPEED_10; +        case SPEED_10: +            if (features & (SUPPORTED_10baseT_Half +                        | SUPPORTED_10baseT_Full)) +                break; +        default: /* Unsupported speed! */ +            ugphy_err("%s: Bad speed!", mii_info->dev->name); +            break; +    } + +    phy_write(mii_info, PHY_BMCR, ctrl); +} + +/* Enable and Restart Autonegotiation */ +static void genmii_restart_aneg(struct uec_mii_info *mii_info) +{ +    u16 ctl; + +    ctl = phy_read(mii_info, PHY_BMCR); +    ctl |= (PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); +    phy_write(mii_info, PHY_BMCR, ctl); +} + +static int gbit_config_aneg(struct uec_mii_info *mii_info) +{ +    u16 adv; +    u32 advertise; + +    if(mii_info->autoneg) { +        /* Configure the ADVERTISE register */ +        config_genmii_advert(mii_info); +        advertise = mii_info->advertising; + +        adv = phy_read(mii_info, MII_1000BASETCONTROL); +        adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | +                MII_1000BASETCONTROL_HALFDUPLEXCAP); +        if (advertise & SUPPORTED_1000baseT_Half) +            adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; +        if (advertise & SUPPORTED_1000baseT_Full) +            adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; +        phy_write(mii_info, MII_1000BASETCONTROL, adv); + +        /* Start/Restart aneg */ +        genmii_restart_aneg(mii_info); +    } else +        genmii_setup_forced(mii_info); + +    return 0; +} + +static int marvell_config_aneg(struct uec_mii_info *mii_info) +{ +    /* The Marvell PHY has an errata which requires +     * that certain registers get written in order +     * to restart autonegotiation */ +    phy_write(mii_info, PHY_BMCR, PHY_BMCR_RESET); + +    phy_write(mii_info, 0x1d, 0x1f); +    phy_write(mii_info, 0x1e, 0x200c); +    phy_write(mii_info, 0x1d, 0x5); +    phy_write(mii_info, 0x1e, 0); +    phy_write(mii_info, 0x1e, 0x100); + +    gbit_config_aneg(mii_info); + +    return 0; +} + +static int genmii_config_aneg(struct uec_mii_info *mii_info) +{ +    if (mii_info->autoneg) { +        config_genmii_advert(mii_info); +        genmii_restart_aneg(mii_info); +    } else +        genmii_setup_forced(mii_info); + +    return 0; +} + +static int genmii_update_link(struct uec_mii_info *mii_info) +{ +    u16 status; + +    /* Do a fake read */ +    phy_read(mii_info, PHY_BMSR); + +    /* Read link and autonegotiation status */ +    status = phy_read(mii_info, PHY_BMSR); +    if ((status & PHY_BMSR_LS) == 0) +        mii_info->link = 0; +    else +        mii_info->link = 1; + +    /* If we are autonegotiating, and not done, +     * return an error */ +    if (mii_info->autoneg && !(status & PHY_BMSR_AUTN_COMP)) +        return -EAGAIN; + +    return 0; +} + +static int genmii_read_status(struct uec_mii_info *mii_info) +{ +    u16 status; +    int err; + +    /* Update the link, but return if there +     * was an error */ +    err = genmii_update_link(mii_info); +    if (err) +        return err; + +    if (mii_info->autoneg) { +        status = phy_read(mii_info, PHY_ANLPAR); + +        if (status & (PHY_ANLPAR_10FD | PHY_ANLPAR_TXFD)) +            mii_info->duplex = DUPLEX_FULL; +        else +            mii_info->duplex = DUPLEX_HALF; +        if (status & (PHY_ANLPAR_TXFD | PHY_ANLPAR_TX)) +            mii_info->speed = SPEED_100; +        else +            mii_info->speed = SPEED_10; +        mii_info->pause = 0; +    } +    /* On non-aneg, we assume what we put in BMCR is the speed, +     * though magic-aneg shouldn't prevent this case from occurring +     */ + +    return 0; +} + +static int marvell_read_status(struct uec_mii_info *mii_info) +{ +    u16 status; +    int err; + +    /* Update the link, but return if there +     * was an error */ +    err = genmii_update_link(mii_info); +    if (err) +        return err; + +    /* If the link is up, read the speed and duplex */ +    /* If we aren't autonegotiating, assume speeds +     * are as set */ +    if (mii_info->autoneg && mii_info->link) { +        int speed; +        status = phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); + +        /* Get the duplexity */ +        if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) +            mii_info->duplex = DUPLEX_FULL; +        else +            mii_info->duplex = DUPLEX_HALF; + +        /* Get the speed */ +        speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; +        switch(speed) { +            case MII_M1011_PHY_SPEC_STATUS_1000: +                mii_info->speed = SPEED_1000; +                break; +            case MII_M1011_PHY_SPEC_STATUS_100: +                mii_info->speed = SPEED_100; +                break; +            default: +                mii_info->speed = SPEED_10; +                break; +        } +        mii_info->pause = 0; +    } + +    return 0; +} + +static int marvell_ack_interrupt(struct uec_mii_info *mii_info) +{ +    /* Clear the interrupts by reading the reg */ +    phy_read(mii_info, MII_M1011_IEVENT); + +    return 0; +} + +static int marvell_config_intr(struct uec_mii_info *mii_info) +{ +    if(mii_info->interrupts == MII_INTERRUPT_ENABLED) +        phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); +    else +        phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); + +    return 0; +} + +static int dm9161_init(struct uec_mii_info *mii_info) +{ +    /* Reset the PHY */ +    phy_write(mii_info, PHY_BMCR, phy_read(mii_info, PHY_BMCR) | +						 PHY_BMCR_RESET); +    /* PHY and MAC connect*/ +    phy_write(mii_info, PHY_BMCR, phy_read(mii_info, PHY_BMCR) & +						 ~PHY_BMCR_ISO); +#ifdef CONFIG_RMII_MODE +    phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_RMII_INIT); +#else +    phy_write(mii_info, MII_DM9161_SCR, MII_DM9161_SCR_INIT); +#endif +    config_genmii_advert(mii_info); +    /* Start/restart aneg */ +    genmii_config_aneg(mii_info); +    /* Delay to wait the aneg compeleted */ +    udelay(3000000); + +    return 0; +} + +static int dm9161_config_aneg(struct uec_mii_info *mii_info) +{ +   return 0; +} + +static int dm9161_read_status(struct uec_mii_info *mii_info) +{ +    u16 status; +    int err; + +    /* Update the link, but return if there was an error*/ +    err = genmii_update_link(mii_info); +    if (err) +        return err; +    /* If the link is up, read the speed and duplex +       If we aren't autonegotiating assume speeds are as set */ +    if (mii_info->autoneg && mii_info->link) { +        status = phy_read(mii_info, MII_DM9161_SCSR); +        if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) +            mii_info->speed = SPEED_100; +        else +            mii_info->speed = SPEED_10; + +        if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) +            mii_info->duplex = DUPLEX_FULL; +        else +            mii_info->duplex = DUPLEX_HALF; +    } + +    return 0; +} + +static int dm9161_ack_interrupt(struct uec_mii_info *mii_info) +{ +    /* Clear the interrupt by reading the reg */ +    phy_read(mii_info, MII_DM9161_INTR); + +    return 0; +} + +static int dm9161_config_intr(struct uec_mii_info *mii_info) +{ +    if (mii_info->interrupts == MII_INTERRUPT_ENABLED) +        phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); +    else +        phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); + +    return 0; +} + +static void dm9161_close(struct uec_mii_info *mii_info) +{ +} + +static struct phy_info phy_info_dm9161 = { +    .phy_id         = 0x0181b880, +    .phy_id_mask    = 0x0ffffff0, +    .name           = "Davicom DM9161E", +    .init           = dm9161_init, +    .config_aneg    = dm9161_config_aneg, +    .read_status    = dm9161_read_status, +    .close          = dm9161_close, +}; + +static struct phy_info phy_info_dm9161a = { +    .phy_id         = 0x0181b8a0, +    .phy_id_mask    = 0x0ffffff0, +    .name           = "Davicom DM9161A", +    .features       = MII_BASIC_FEATURES, +    .init           = dm9161_init, +    .config_aneg    = dm9161_config_aneg, +    .read_status    = dm9161_read_status, +    .ack_interrupt  = dm9161_ack_interrupt, +    .config_intr    = dm9161_config_intr, +    .close          = dm9161_close, +}; + +static struct phy_info phy_info_marvell = { +    .phy_id         = 0x01410c00, +    .phy_id_mask    = 0xffffff00, +    .name           = "Marvell 88E11x1", +    .features       = MII_GBIT_FEATURES, +    .config_aneg    = &marvell_config_aneg, +    .read_status    = &marvell_read_status, +    .ack_interrupt  = &marvell_ack_interrupt, +    .config_intr    = &marvell_config_intr, +}; + +static struct phy_info phy_info_genmii= { +    .phy_id         = 0x00000000, +    .phy_id_mask    = 0x00000000, +    .name           = "Generic MII", +    .features       = MII_BASIC_FEATURES, +    .config_aneg    = genmii_config_aneg, +    .read_status    = genmii_read_status, +}; + +static struct phy_info *phy_info[] = { +    &phy_info_dm9161, +    &phy_info_dm9161a, +    &phy_info_marvell, +    &phy_info_genmii, +    NULL +}; + +u16 phy_read(struct uec_mii_info *mii_info, u16 regnum) +{ +    return mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); +} + +void phy_write(struct uec_mii_info *mii_info, u16 regnum, u16 val) +{ +    mii_info->mdio_write(mii_info->dev, +            mii_info->mii_id, +            regnum, val); +} + +/* Use the PHY ID registers to determine what type of PHY is attached + * to device dev.  return a struct phy_info structure describing that PHY + */ +struct phy_info * get_phy_info(struct uec_mii_info *mii_info) +{ +    u16 phy_reg; +    u32 phy_ID; +    int i; +    struct phy_info *theInfo = NULL; + +    /* Grab the bits from PHYIR1, and put them in the upper half */ +    phy_reg = phy_read(mii_info, PHY_PHYIDR1); +    phy_ID = (phy_reg & 0xffff) << 16; + +    /* Grab the bits from PHYIR2, and put them in the lower half */ +    phy_reg = phy_read(mii_info, PHY_PHYIDR2); +    phy_ID |= (phy_reg & 0xffff); + +    /* loop through all the known PHY types, and find one that */ +    /* matches the ID we read from the PHY. */ +    for (i = 0; phy_info[i]; i++) +        if (phy_info[i]->phy_id == +                (phy_ID & phy_info[i]->phy_id_mask)) { +            theInfo = phy_info[i]; +            break; +        } + +    /* This shouldn't happen, as we have generic PHY support */ +    if (theInfo == NULL) { +        ugphy_info("UEC: PHY id %x is not supported!", phy_ID); +	return NULL; +    } else { +        ugphy_info("UEC: PHY is %s (%x)", theInfo->name, phy_ID); +    } + +    return theInfo; +} + +void marvell_phy_interface_mode(struct eth_device *dev, enet_interface_e mode) +{ +	uec_private_t		*uec = (uec_private_t *)dev->priv; +	struct uec_mii_info	*mii_info; + +	if (!uec->mii_info) { +		printf("%s: the PHY not intialized\n", __FUNCTION__); +		return; +	} +	mii_info = uec->mii_info; + +	if (mode == ENET_100_RGMII) { +		phy_write(mii_info, 0x00, 0x9140); +		phy_write(mii_info, 0x1d, 0x001f); +		phy_write(mii_info, 0x1e, 0x200c); +		phy_write(mii_info, 0x1d, 0x0005); +		phy_write(mii_info, 0x1e, 0x0000); +		phy_write(mii_info, 0x1e, 0x0100); +		phy_write(mii_info, 0x09, 0x0e00); +		phy_write(mii_info, 0x04, 0x01e1); +		phy_write(mii_info, 0x00, 0x9140); +		phy_write(mii_info, 0x00, 0x1000); +		udelay(100000); +		phy_write(mii_info, 0x00, 0x2900); +		phy_write(mii_info, 0x14, 0x0cd2); +		phy_write(mii_info, 0x00, 0xa100); +		phy_write(mii_info, 0x09, 0x0000); +		phy_write(mii_info, 0x1b, 0x800b); +		phy_write(mii_info, 0x04, 0x05e1); +		phy_write(mii_info, 0x00, 0xa100); +		phy_write(mii_info, 0x00, 0x2100); +		udelay(1000000); +	} else if (mode == ENET_10_RGMII) { +		phy_write(mii_info, 0x14, 0x8e40); +		phy_write(mii_info, 0x1b, 0x800b); +		phy_write(mii_info, 0x14, 0x0c82); +		phy_write(mii_info, 0x00, 0x8100); +		udelay(1000000); +	} +} + +void change_phy_interface_mode(struct eth_device *dev, enet_interface_e mode) +{ +#ifdef CONFIG_PHY_MODE_NEED_CHANGE +	marvell_phy_interface_mode(dev, mode); +#endif +} +#endif /* CONFIG_QE */ diff --git a/drivers/qe/uec_phy.h b/drivers/qe/uec_phy.h new file mode 100644 index 000000000..a82f1f589 --- /dev/null +++ b/drivers/qe/uec_phy.h @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2005 Freescale Semiconductor, Inc. + * + * Author: Shlomi Gridish <gridish@freescale.com> + * + * Description: UCC ethernet driver -- PHY handling + * 		Driver for UEC on QE + * 		Based on 8260_io/fcc_enet.c + * + * 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. + * + */ +#ifndef __UEC_PHY_H__ +#define __UEC_PHY_H__ + +#define MII_end ((u32)-2) +#define MII_read ((u32)-1) + +#define MIIMIND_BUSY            0x00000001 +#define MIIMIND_NOTVALID        0x00000004 + +#define UGETH_AN_TIMEOUT        2000 + +/* 1000BT control (Marvell & BCM54xx at least) */ +#define MII_1000BASETCONTROL                  0x09 +#define MII_1000BASETCONTROL_FULLDUPLEXCAP    0x0200 +#define MII_1000BASETCONTROL_HALFDUPLEXCAP    0x0100 + +/* Cicada Extended Control Register 1 */ +#define MII_CIS8201_EXT_CON1        0x17 +#define MII_CIS8201_EXTCON1_INIT    0x0000 + +/* Cicada Interrupt Mask Register */ +#define MII_CIS8201_IMASK           0x19 +#define MII_CIS8201_IMASK_IEN       0x8000 +#define MII_CIS8201_IMASK_SPEED     0x4000 +#define MII_CIS8201_IMASK_LINK      0x2000 +#define MII_CIS8201_IMASK_DUPLEX    0x1000 +#define MII_CIS8201_IMASK_MASK      0xf000 + +/* Cicada Interrupt Status Register */ +#define MII_CIS8201_ISTAT           0x1a +#define MII_CIS8201_ISTAT_STATUS    0x8000 +#define MII_CIS8201_ISTAT_SPEED     0x4000 +#define MII_CIS8201_ISTAT_LINK      0x2000 +#define MII_CIS8201_ISTAT_DUPLEX    0x1000 + +/* Cicada Auxiliary Control/Status Register */ +#define MII_CIS8201_AUX_CONSTAT        0x1c +#define MII_CIS8201_AUXCONSTAT_INIT    0x0004 +#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x0020 +#define MII_CIS8201_AUXCONSTAT_SPEED   0x0018 +#define MII_CIS8201_AUXCONSTAT_GBIT    0x0010 +#define MII_CIS8201_AUXCONSTAT_100     0x0008 + +/* 88E1011 PHY Status Register */ +#define MII_M1011_PHY_SPEC_STATUS               0x11 +#define MII_M1011_PHY_SPEC_STATUS_1000          0x8000 +#define MII_M1011_PHY_SPEC_STATUS_100           0x4000 +#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK      0xc000 +#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX    0x2000 +#define MII_M1011_PHY_SPEC_STATUS_RESOLVED      0x0800 +#define MII_M1011_PHY_SPEC_STATUS_LINK          0x0400 + +#define MII_M1011_IEVENT                0x13 +#define MII_M1011_IEVENT_CLEAR          0x0000 + +#define MII_M1011_IMASK                 0x12 +#define MII_M1011_IMASK_INIT            0x6400 +#define MII_M1011_IMASK_CLEAR           0x0000 + +#define MII_DM9161_SCR                  0x10 +#define MII_DM9161_SCR_INIT             0x0610 +#define MII_DM9161_SCR_RMII_INIT	0x0710 + +/* DM9161 Specified Configuration and Status Register */ +#define MII_DM9161_SCSR                 0x11 +#define MII_DM9161_SCSR_100F            0x8000 +#define MII_DM9161_SCSR_100H            0x4000 +#define MII_DM9161_SCSR_10F             0x2000 +#define MII_DM9161_SCSR_10H             0x1000 + +/* DM9161 Interrupt Register */ +#define MII_DM9161_INTR                 0x15 +#define MII_DM9161_INTR_PEND            0x8000 +#define MII_DM9161_INTR_DPLX_MASK       0x0800 +#define MII_DM9161_INTR_SPD_MASK        0x0400 +#define MII_DM9161_INTR_LINK_MASK       0x0200 +#define MII_DM9161_INTR_MASK            0x0100 +#define MII_DM9161_INTR_DPLX_CHANGE     0x0010 +#define MII_DM9161_INTR_SPD_CHANGE      0x0008 +#define MII_DM9161_INTR_LINK_CHANGE     0x0004 +#define MII_DM9161_INTR_INIT            0x0000 +#define MII_DM9161_INTR_STOP    \ +(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ + | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) + +/* DM9161 10BT Configuration/Status */ +#define MII_DM9161_10BTCSR              0x12 +#define MII_DM9161_10BTCSR_INIT         0x7800 + +#define MII_BASIC_FEATURES    (SUPPORTED_10baseT_Half | \ +                 SUPPORTED_10baseT_Full | \ +                 SUPPORTED_100baseT_Half | \ +                 SUPPORTED_100baseT_Full | \ +                 SUPPORTED_Autoneg | \ +                 SUPPORTED_TP | \ +                 SUPPORTED_MII) + +#define MII_GBIT_FEATURES    (MII_BASIC_FEATURES | \ +                 SUPPORTED_1000baseT_Half | \ +                 SUPPORTED_1000baseT_Full) + +#define MII_READ_COMMAND                0x00000001 + +#define MII_INTERRUPT_DISABLED          0x0 +#define MII_INTERRUPT_ENABLED           0x1 + +#define SPEED_10    10 +#define SPEED_100   100 +#define SPEED_1000  1000 + +/* Duplex, half or full. */ +#define DUPLEX_HALF             0x00 +#define DUPLEX_FULL             0x01 + +/* Indicates what features are supported by the interface. */ +#define SUPPORTED_10baseT_Half          (1 << 0) +#define SUPPORTED_10baseT_Full          (1 << 1) +#define SUPPORTED_100baseT_Half         (1 << 2) +#define SUPPORTED_100baseT_Full         (1 << 3) +#define SUPPORTED_1000baseT_Half        (1 << 4) +#define SUPPORTED_1000baseT_Full        (1 << 5) +#define SUPPORTED_Autoneg               (1 << 6) +#define SUPPORTED_TP                    (1 << 7) +#define SUPPORTED_AUI                   (1 << 8) +#define SUPPORTED_MII                   (1 << 9) +#define SUPPORTED_FIBRE                 (1 << 10) +#define SUPPORTED_BNC                   (1 << 11) +#define SUPPORTED_10000baseT_Full       (1 << 12) + +#define ADVERTISED_10baseT_Half         (1 << 0) +#define ADVERTISED_10baseT_Full         (1 << 1) +#define ADVERTISED_100baseT_Half        (1 << 2) +#define ADVERTISED_100baseT_Full        (1 << 3) +#define ADVERTISED_1000baseT_Half       (1 << 4) +#define ADVERTISED_1000baseT_Full       (1 << 5) +#define ADVERTISED_Autoneg              (1 << 6) +#define ADVERTISED_TP                   (1 << 7) +#define ADVERTISED_AUI                  (1 << 8) +#define ADVERTISED_MII                  (1 << 9) +#define ADVERTISED_FIBRE                (1 << 10) +#define ADVERTISED_BNC                  (1 << 11) +#define ADVERTISED_10000baseT_Full      (1 << 12) + +/* Advertisement control register. */ +#define ADVERTISE_SLCT          0x001f  /* Selector bits               */ +#define ADVERTISE_CSMA          0x0001  /* Only selector supported     */ +#define ADVERTISE_10HALF        0x0020  /* Try for 10mbps half-duplex  */ +#define ADVERTISE_10FULL        0x0040  /* Try for 10mbps full-duplex  */ +#define ADVERTISE_100HALF       0x0080  /* Try for 100mbps half-duplex */ +#define ADVERTISE_100FULL       0x0100  /* Try for 100mbps full-duplex */ +#define ADVERTISE_100BASE4      0x0200  /* Try for 100mbps 4k packets  */ +#define ADVERTISE_RESV          0x1c00  /* Unused...                   */ +#define ADVERTISE_RFAULT        0x2000  /* Say we can detect faults    */ +#define ADVERTISE_LPACK         0x4000  /* Ack link partners response  */ +#define ADVERTISE_NPAGE         0x8000  /* Next page bit               */ + +#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ +                        ADVERTISE_CSMA) +#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ +                       ADVERTISE_100HALF | ADVERTISE_100FULL) + +/* Taken from mii_if_info and sungem_phy.h */ +struct uec_mii_info { +    /* Information about the PHY type */ +    /* And management functions */ +    struct phy_info *phyinfo; + +    struct eth_device *dev; + +    /* forced speed & duplex (no autoneg) +     * partner speed & duplex & pause (autoneg) +     */ +    int speed; +    int duplex; +    int pause; + +    /* The most recently read link state */ +    int link; + +    /* Enabled Interrupts */ +    u32 interrupts; + +    u32 advertising; +    int autoneg; +    int mii_id; + +    /* private data pointer */ +    /* For use by PHYs to maintain extra state */ +    void *priv; + +    /* Provided by ethernet driver */ +    int (*mdio_read) (struct eth_device *dev, int mii_id, int reg); +    void (*mdio_write) (struct eth_device *dev, int mii_id, int reg, int val); +}; + +/* struct phy_info: a structure which defines attributes for a PHY + * + * id will contain a number which represents the PHY.  During + * startup, the driver will poll the PHY to find out what its + * UID--as defined by registers 2 and 3--is.  The 32-bit result + * gotten from the PHY will be ANDed with phy_id_mask to + * discard any bits which may change based on revision numbers + * unimportant to functionality + * + * There are 6 commands which take a ugeth_mii_info structure. + * Each PHY must declare config_aneg, and read_status. + */ +struct phy_info { +    u32 phy_id; +    char *name; +    unsigned int phy_id_mask; +    u32 features; + +    /* Called to initialize the PHY */ +    int (*init)(struct uec_mii_info *mii_info); + +    /* Called to suspend the PHY for power */ +    int (*suspend)(struct uec_mii_info *mii_info); + +    /* Reconfigures autonegotiation (or disables it) */ +    int (*config_aneg)(struct uec_mii_info *mii_info); + +    /* Determines the negotiated speed and duplex */ +    int (*read_status)(struct uec_mii_info *mii_info); + +    /* Clears any pending interrupts */ +    int (*ack_interrupt)(struct uec_mii_info *mii_info); + +    /* Enables or disables interrupts */ +    int (*config_intr)(struct uec_mii_info *mii_info); + +    /* Clears up any memory if needed */ +    void (*close)(struct uec_mii_info *mii_info); +}; + +struct phy_info *get_phy_info(struct uec_mii_info *mii_info); +void write_phy_reg(struct eth_device *dev, int mii_id, int regnum, int value); +int read_phy_reg(struct eth_device *dev, int mii_id, int regnum); +void mii_clear_phy_interrupt(struct uec_mii_info *mii_info); +void mii_configure_phy_interrupt(struct uec_mii_info *mii_info, u32 interrupts); +#endif /* __UEC_PHY_H__ */ diff --git a/include/asm-ppc/global_data.h b/include/asm-ppc/global_data.h index 418315bef..8bc61b63a 100644 --- a/include/asm-ppc/global_data.h +++ b/include/asm-ppc/global_data.h @@ -69,6 +69,8 @@ typedef	struct	global_data {  #if defined(CONFIG_QE)  	u32 qe_clk;  	u32 brg_clk; +	uint mp_alloc_base; +	uint mp_alloc_top;  #endif /* CONFIG_QE */  #if defined (CONFIG_MPC8360)  	u32  ddr_sec_clk; diff --git a/include/configs/MPC8360EMDS.h b/include/configs/MPC8360EMDS.h index 0ae60618e..330c3073d 100644 --- a/include/configs/MPC8360EMDS.h +++ b/include/configs/MPC8360EMDS.h @@ -364,6 +364,35 @@  #endif  /* + * QE UEC ethernet configuration + */ +#define CONFIG_UEC_ETH +#define CONFIG_ETHPRIME		"Freescale GETH" +#define CONFIG_PHY_MODE_NEED_CHANGE + +#define CONFIG_UEC_ETH1		/* GETH1 */ + +#ifdef CONFIG_UEC_ETH1 +#define CFG_UEC1_UCC_NUM	0	/* UCC1 */ +#define CFG_UEC1_RX_CLK		QE_CLK_NONE +#define CFG_UEC1_TX_CLK		QE_CLK9 +#define CFG_UEC1_ETH_TYPE	GIGA_ETH +#define CFG_UEC1_PHY_ADDR	0 +#define CFG_UEC1_INTERFACE_MODE	ENET_1000_GMII +#endif + +#define CONFIG_UEC_ETH2		/* GETH2 */ + +#ifdef CONFIG_UEC_ETH2 +#define CFG_UEC2_UCC_NUM	1	/* UCC2 */ +#define CFG_UEC2_RX_CLK		QE_CLK_NONE +#define CFG_UEC2_TX_CLK		QE_CLK4 +#define CFG_UEC2_ETH_TYPE	GIGA_ETH +#define CFG_UEC2_PHY_ADDR	1 +#define CFG_UEC2_INTERFACE_MODE	ENET_1000_GMII +#endif + +/*   * Environment   */ diff --git a/include/ioports.h b/include/ioports.h index d7e19e195..91ca6fb48 100644 --- a/include/ioports.h +++ b/include/ioports.h @@ -53,3 +53,14 @@ typedef struct {   * like the table in the 8260UM (and in the hymod manuals).   */  extern const iop_conf_t iop_conf_tab[4][32]; + +typedef struct { +	unsigned char	port; +	unsigned char	pin; +	int		dir; +	int		open_drain; +	int		assign; +} qe_iop_conf_t; + +#define QE_IOP_TAB_END	(-1) + @@ -54,6 +54,7 @@ extern int scc_initialize(bd_t*);  extern int skge_initialize(bd_t*);  extern int tsec_initialize(bd_t*, int, char *);  extern int npe_initialize(bd_t *); +extern int uec_initialize(int);  static struct eth_device *eth_devices, *eth_current; @@ -196,6 +197,12 @@ int eth_initialize(bd_t *bis)  	tsec_initialize(bis, 3, CONFIG_MPC83XX_TSEC4_NAME);  #    endif  #endif +#if defined(CONFIG_UEC_ETH1) +	uec_initialize(0); +#endif +#if defined(CONFIG_UEC_ETH2) +	uec_initialize(1); +#endif  #if defined(CONFIG_MPC86XX_TSEC1)         tsec_initialize(bis, 0, CONFIG_MPC86XX_TSEC1_NAME);  #endif |