Commit 7737d5c6 authored by Dave Liu's avatar Dave Liu Committed by Kim Phillips
Browse files

mpc83xx: add QE ethernet support

this patch adds support for the QUICC Engine based UCC gigabit ethernet device.
parent 5f820439
......@@ -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
......
......@@ -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;
......
......@@ -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))
......
/*
* 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;
}
/*
* 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 */
#
# 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
#########################################################################
/*
* 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 */
/*
* 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