U-Boot
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2000 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
August 2006
- 279 discussions
I need to calculate CRC for the data (jffs2) on NAND flash. (u-boot is
on separate NOR flash, btw.) What do you all think is the best way to
do so? I'm guessing that I need to do the nand read.jffs2 and then
perform CRC on that data where its read.
Can anyone suggest a better/faster way?
2
3
What is the best way to use a value in a memory location in a hush
shell scritpt that gets run with autoscript?
For example, say a CRC value for area 20000000 -- 20001000 is stored
in a flash, at location 12345678. If I wanted to verify a crc against
this value, I'd like to pass the value at address 12345678 as a last
argument.
crc32 -v 20000000 1000 (data @ 12345678)
or is it better to just read the value from flash, store it in a local
variable and use it?
2
2

17 Aug '06
Dear Mr. U. Boot,
thank you for your contribution to the U-Boot project.
Your e-mail was registered at our system under the ticket
number [DNX#2006081742000132].
Please keep this ticked ID string in the subject line of
any e-mail replies!!!
Your U-Boot support team
Powered by OTRS (http://otrs.org/)
1
0

17 Aug '06
Subject: [PATCH] Consolidate mpc83xx cpu for mpc8360e
---
cpu/mpc83xx/cpu.c | 39 ++++--
cpu/mpc83xx/cpu_init.c | 26 +++-
cpu/mpc83xx/i2c.c | 10 +
cpu/mpc83xx/spd_sdram.c | 333
+++++++++++++++++++++++++++++------------------
cpu/mpc83xx/speed.c | 226 ++++++++++++++++++--------------
cpu/mpc83xx/start.S | 39 ++++--
6 files changed, 414 insertions(+), 259 deletions(-)
2ec049fdc52d6133a335b1073bf6f749048d1817
diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c
index 20bba6c..16c4ee4 100644
--- a/cpu/mpc83xx/cpu.c
+++ b/cpu/mpc83xx/cpu.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.
@@ -23,6 +23,8 @@
*
* 20050101: Eran Liberty (liberty(a)freescale.com)
* Initial file creating (porting from 85XX & 8260)
+ * 20060520: Dave Liu (Daveliu(a)freescale.com)
+ * Add support for mpc8360e
*/
/*
@@ -43,28 +45,43 @@ DECLARE_GLOBAL_DATA_PTR;
int checkcpu(void)
{
+ volatile immap_t *immr;
+ u32 spridr;
ulong clock = gd->cpu_clk;
u32 pvr = get_pvr();
char buf[32];
+ immr = (immap_t *)CFG_IMMRBAR;
+
if ((pvr & 0xFFFF0000) != PVR_83xx) {
puts("Not MPC83xx Family!!!\n");
return -1;
}
- puts("CPU: MPC83xx, ");
- switch(pvr) {
- case PVR_8349_REV10:
+ spridr = immr->sysconf.spridr;
+ puts("CPU: ");
+ switch(spridr) {
+ case SPR_8349E_REV10:
+ case SPR_8349E_REV11:
+ puts("MPC8349E, ");
break;
- case PVR_8349_REV11:
+ case SPR_8360E_REV10:
+ case SPR_8360E_REV11:
+ case SPR_8360E_REV12:
+ puts("MPC8360E, ");
break;
default:
puts("Rev: Unknown\n");
return -1; /* Not sure what this is */
}
- printf("Rev: %d.%d at %s MHz\n", (pvr & 0xf0) >> 4,
- (pvr & 0x0f), strmhz(buf, clock));
-
+#if defined(CONFIG_MPC8349)
+ printf("Rev: %02x at %s MHz\n",
+ (spridr & 0x0000FFFF)>>4 |(spridr & 0x0000000F),
+ strmhz(buf, clock));
+#elif defined(CONFIG_MPC8360)
+ printf("Rev: %02x at %s MHz\n",
+ spridr & 0x0000FFFF, strmhz(buf, clock));
+#endif
return 0;
}
@@ -195,7 +212,7 @@ #if defined(CONFIG_DDR_ECC)
void dma_init(void)
{
volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
- volatile dma8349_t *dma = &immap->dma;
+ volatile dma83xx_t *dma = &immap->dma;
volatile u32 status = swab32(dma->dmasr0);
volatile u32 dmamr0 = swab32(dma->dmamr0);
@@ -226,7 +243,7 @@ void dma_init(void)
uint dma_check(void)
{
volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
- volatile dma8349_t *dma = &immap->dma;
+ volatile dma83xx_t *dma = &immap->dma;
volatile u32 status = swab32(dma->dmasr0);
volatile u32 byte_count = swab32(dma->dmabcr0);
@@ -245,7 +262,7 @@ uint dma_check(void)
int dma_xfer(void *dest, u32 count, void *src)
{
volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
- volatile dma8349_t *dma = &immap->dma;
+ volatile dma83xx_t *dma = &immap->dma;
volatile u32 dmamr0;
/* initialize DMASARn, DMADAR and DMAABCRn */
diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c
index 6ed0992..429fe9a 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.
@@ -23,6 +23,8 @@
*
* 20050101: Eran Liberty (liberty(a)freescale.com)
* Initial file creating (porting from 85XX & 8260)
+ * 20060520: Dave Liu (Daveliu(a)freescale.com)
+ * Add support for mpc8360e
*/
#include <common.h>
@@ -59,17 +61,27 @@ void cpu_init_f (volatile immap_t * im)
/* LCRR - Clock Ratio Register (10.3.1.16) */
im->lbus.lcrr = CFG_LCRR;
+#if defined (CONFIG_MPC8349)
+ im->clk.sccr = CFG_SCCR_VAL;
+#endif
/* Enable Time Base & Decrimenter ( so we will have udelay() )*/
im->sysconf.spcr |= SPCR_TBEN;
- /* System General Purpose Register */
-#ifdef CFG_SICRH
- im->sysconf.sicrh = CFG_SICRH;
-#endif
-#ifdef CFG_SICRL
- im->sysconf.sicrl = CFG_SICRL;
+ /* System General Purpose Register */
+#if defined (CONFIG_MPC8360)
+ im->sysconf.sicrh = CFG_SICRH_VAL;
+ im->sysconf.sicrl = CFG_SICRL_VAL;
+#elif defined(CONFIG_MPC8349)
+ im->sysconf.sicrh = SICRH_TSOBI1;
+ im->sysconf.sicrl = SICRL_LDP_A;
+#else
+#error sicrl no stuff!
#endif
+ /* DDR control driver register */
+#if defined (CONFIG_DDR_II)
+ im->sysconf.ddrcdr = CFG_DDRCDR_VALUE;
+#endif
/*
* Memory Controller:
*/
diff --git a/cpu/mpc83xx/i2c.c b/cpu/mpc83xx/i2c.c
index 70450f9..08d2c93 100644
--- a/cpu/mpc83xx/i2c.c
+++ b/cpu/mpc83xx/i2c.c
@@ -1,4 +1,6 @@
/*
+ * (C) Copyright 2006 Freescale Semiconductor, Inc.
+ *
* (C) Copyright 2003,Motorola Inc.
* Xianghua Xiao <x.xiao(a)motorola.com>
* Adapted for Motorola 85xx chip.
@@ -31,6 +33,8 @@
*
* 20050101: Eran Liberty (liberty(a)freescale.com)
* Initial file creating (porting from 85XX & 8260)
+ * 20060601: Dave Liu (daveliu(a)freescale.com)
+ * Unified variable names for mpc83xx
*/
#include <common.h>
@@ -41,8 +45,8 @@ #ifdef CONFIG_HARD_I2C
#include <i2c.h>
#include <asm/i2c.h>
-#if defined(CONFIG_MPC8349EMDS) || defined(CONFIG_TQM834X)
-i2c_t * mpc8349_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET);
+#if defined(CONFIG_MPC8349EMDS) || defined(CONFIG_TQM834X) ||
defined(CONFIG_MPC8360EPB)
+i2c_t * mpc83xx_i2c = (i2c_t*)(CFG_IMMRBAR + CFG_I2C_OFFSET);
#endif
void
@@ -52,7 +56,7 @@ i2c_init(int speed, int slaveadd)
writeb(0x00 , &I2C->cr);
/* set clock */
- writeb(0x3f, &I2C->fdr);
+ writeb(speed, &I2C->fdr);
/* set default filter */
writeb(0x10,&I2C->dfsrr);
diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c
index 48624fe..3b5ee33 100644
--- a/cpu/mpc83xx/spd_sdram.c
+++ b/cpu/mpc83xx/spd_sdram.c
@@ -1,4 +1,6 @@
/*
+ * (C) Copyright 2006 Freescale Semiconductor, Inc.
+ *
* (C) Copyright 2006
* Wolfgang Denk, DENX Software Engineering, wd(a)denx.de.
*
@@ -28,6 +30,10 @@
*
* 20050101: Eran Liberty (liberty(a)freescale.com)
* Initial file creating (porting from 85XX & 8260)
+ * 20060601: Dave Liu (daveliu(a)freescale.com)
+ * mpc8360 support and DDR ECC support
+ * unify variable names for 83xx
+ * code cleanup
*/
#include <common.h>
@@ -39,7 +45,7 @@ #include <spd_sdram.h>
#ifdef CONFIG_SPD_EEPROM
-#if defined(CONFIG_DDR_ECC)
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRC)
extern void dma_init(void);
extern uint dma_check(void);
extern int dma_xfer(void *dest, uint count, void *src);
@@ -52,15 +58,18 @@ #endif
/*
* Convert picoseconds into clock cycles (rounding up if needed).
*/
+extern ulong get_ddr_clk(ulong dummy);
int
picos_to_clk(int picos)
{
+ unsigned int ddr_bus_clk;
int clks;
- clks = picos / (2000000000 / (get_bus_freq(0) / 1000));
- if (picos % (2000000000 / (get_bus_freq(0) / 1000)) != 0) {
- clks++;
+ ddr_bus_clk = get_ddr_clk(0) >> 1;
+ clks = picos / ((1000000000 / ddr_bus_clk) * 1000);
+ if (picos % ((1000000000 / ddr_bus_clk) * 1000) !=0) {
+ clks++;
}
return clks;
@@ -104,32 +113,71 @@ #endif /* SPD_DEBUG */
long int spd_sdram()
{
volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
- volatile ddr8349_t *ddr = &immap->ddr;
- volatile law8349_t *ecm = &immap->sysconf.ddrlaw[0];
+ volatile ddr83xx_t *ddr = &immap->ddr;
+ volatile law83xx_t *ecm = &immap->sysconf.ddrlaw[0];
spd_eeprom_t spd;
- unsigned tmp, tmp1;
+ unsigned tmp;
unsigned int memsize;
unsigned int law_size;
- unsigned char caslat;
- unsigned int trfc, trfc_clk, trfc_low;
+ unsigned char caslat, caslat_ctrl;
+ unsigned char burstlen;
+ unsigned int max_bus_clk;
+ unsigned int max_data_rate, effective_data_rate;
+ unsigned int ddrc_clk;
+ unsigned sdram_cfg;
+ unsigned int ddrc_ecc_enable;
+
+ /* Read SPD parameters with I2C */
CFG_READ_SPD(SPD_EEPROM_ADDRESS, 0, 1, (uchar *) & spd, sizeof
(spd));
#ifdef SPD_DEBUG
spd_debug(&spd);
#endif
- if (spd.nrows > 2) {
- puts("DDR:Only two chip selects are supported on
ADS.\n");
+ /* Check the memory type */
+ if (spd.mem_type != SPD_MEMTYPE_DDR) {
+ printf("DDR: Module mem type is %02X\n", spd.mem_type);
return 0;
}
- if (spd.nrow_addr < 12
- || spd.nrow_addr > 14
- || spd.ncol_addr < 8
- || spd.ncol_addr > 11) {
- puts("DDR:Row or Col number unsupported.\n");
+ /* Check the number of physical bank */
+ if (spd.nrows > 2) {
+ printf("DDR: The number of physical bank is %02X\n",
spd.nrows);
return 0;
}
+ /* Check if the number of row of the module is in the range of
DDRC */
+ if (spd.nrow_addr < 12 || spd.nrow_addr > 14) {
+ printf("DDR: Row number is out of range of DDRC,
row=%02X\n",
+ spd.nrow_addr);
+ return 0;
+ }
+
+ /* Check if the number of col of the module is in the range of
DDRC */
+ if (spd.ncol_addr < 8 || spd.ncol_addr > 11) {
+ printf("DDR: Col number is out of range of DDRC,
col=%02X\n",
+ spd.ncol_addr);
+ return 0;
+ }
+ /* Setup DDR chip select register */
+#ifdef CONFIG_MPC8360EPB
+ ddr->csbnds[0].csbnds = (banksize(spd.row_dens) >> 24) - 1;
+ ddr->cs_config[0] = ( 1 << 31
+ | (spd.nrow_addr - 12) << 8
+ | (spd.ncol_addr - 8) );
+ debug("\n");
+ debug("cs0_bnds = 0x%08x\n",ddr->csbnds[0].csbnds);
+ debug("cs0_config = 0x%08x\n",ddr->cs_config[0]);
+
+ if (spd.nrows == 2) {
+ ddr->csbnds[1].csbnds = ( (banksize(spd.row_dens) >> 8)
+ | ((banksize(spd.row_dens) >> 23) - 1)
);
+ ddr->cs_config[1] = ( 1<<31
+ | (spd.nrow_addr-12) << 8
+ | (spd.ncol_addr-8) );
+ debug("cs1_bnds = 0x%08x\n",ddr->csbnds[1].csbnds);
+ debug("cs1_config = 0x%08x\n",ddr->cs_config[1]);
+ }
+#else
ddr->csbnds[2].csbnds = (banksize(spd.row_dens) >> 24) - 1;
ddr->cs_config[2] = ( 1 << 31
| (spd.nrow_addr - 12) << 8
@@ -147,6 +195,7 @@ #endif
debug("cs3_bnds = 0x%08x\n",ddr->csbnds[3].csbnds);
debug("cs3_config = 0x%08x\n",ddr->cs_config[3]);
}
+#endif
if (spd.mem_type != 0x07) {
puts("No DDR module found!\n");
@@ -172,54 +221,84 @@ #endif
debug("DDR:ar=0x%08x\n", ecm->ar);
/*
- * find the largest CAS
+ * Find the largest CAS by locating the highest 1 bit
+ * in the spd.cas_lat field. Translate it to a DDR
+ * controller field value:
+ *
+ * CAS Lat DDR I Ctrl
+ * Clocks SPD Bit Value
+ * -------+--------+---------
+ * 1.0 0 001
+ * 1.5 1 010
+ * 2.0 2 011
+ * 2.5 3 100
+ * 3.0 4 101
+ * 3.5 5 110
+ * 4.0 6 111
*/
- if(spd.cas_lat & 0x40) {
- caslat = 7;
- } else if (spd.cas_lat & 0x20) {
- caslat = 6;
- } else if (spd.cas_lat & 0x10) {
- caslat = 5;
- } else if (spd.cas_lat & 0x08) {
- caslat = 4;
- } else if (spd.cas_lat & 0x04) {
- caslat = 3;
- } else if (spd.cas_lat & 0x02) {
- caslat = 2;
- } else if (spd.cas_lat & 0x01) {
- caslat = 1;
- } else {
- puts("DDR:no valid CAS Latency information.\n");
+ caslat = __ilog2(spd.cas_lat);
+
+ if (caslat > 4 ) {
+ printf("DDR: Invalid SPD CAS Latency, caslat=%02X\n",
caslat);
return 0;
}
+ max_bus_clk = 1000 *10 / (((spd.clk_cycle & 0xF0) >> 4) * 10
+ + (spd.clk_cycle & 0x0f));
+ max_data_rate = max_bus_clk * 2;
+
+ debug("DDR:Module maximum data rate is: %dMhz\n",
max_data_rate);
- tmp = 20000 / (((spd.clk_cycle & 0xF0) >> 4) * 10
- + (spd.clk_cycle & 0x0f));
- debug("DDR:Module maximum data rate is: %dMhz\n", tmp);
-
- tmp1 = get_bus_freq(0) / 1000000;
- if (tmp1 < 230 && tmp1 >= 90 && tmp >= 230) {
- /* 90~230 range, treated as DDR 200 */
- if (spd.clk_cycle3 == 0xa0)
- caslat -= 2;
- else if(spd.clk_cycle2 == 0xa0)
- caslat--;
- } else if (tmp1 < 280 && tmp1 >= 230 && tmp >= 280) {
- /* 230-280 range, treated as DDR 266 */
- if (spd.clk_cycle3 == 0x75)
- caslat -= 2;
- else if (spd.clk_cycle2 == 0x75)
- caslat--;
- } else if (tmp1 < 350 && tmp1 >= 280 && tmp >= 350) {
- /* 280~350 range, treated as DDR 333 */
- if (spd.clk_cycle3 == 0x60)
- caslat -= 2;
- else if (spd.clk_cycle2 == 0x60)
- caslat--;
- } else if (tmp1 < 90 || tmp1 >= 350) {
- /* DDR rate out-of-range */
- puts("DDR:platform frequency is not fit for DDR
rate\n");
+ ddrc_clk = get_ddr_clk(0) / 1000000;
+
+ if (max_data_rate >= 390) { /* it is DDR 400 */
+ printf("DDR: platform not support DDR 400\n");
return 0;
+ } else if (max_data_rate >= 323) { /* it is DDR 333 */
+ if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDRC clk at 280~350 */
+ effective_data_rate = 333; /* 6ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDRC clk at 230~280 */
+ if (spd.clk_cycle2 == 0x75) {
+ effective_data_rate = 266; /* 7.5ns */
+ caslat = caslat - 1;
+ }
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDRC clk at 90~230 */
+ if (spd.clk_cycle3 == 0xa0) {
+ effective_data_rate = 200; /* 10ns */
+ caslat = caslat - 2;
+ }
+ }
+ } else if (max_data_rate >= 256) { /* it is DDR 266 */
+ if (ddrc_clk <= 350 && ddrc_clk > 280) {
+ /* DDRC clk at 280~350 */
+ printf("DDR: DDR controller freq is more than "
+ "max data rate of the module\n");
+ return 0;
+ } else if (ddrc_clk <= 280 && ddrc_clk > 230) {
+ /* DDRC clk at 230~280 */
+ effective_data_rate = 266; /* 7.5ns */
+ caslat = caslat;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDRC clk at 90~230 */
+ if (spd.clk_cycle2 == 0xa0) {
+ effective_data_rate = 200; /* 10ns */
+ caslat = caslat - 1;
+ }
+ }
+ } else if (max_data_rate >= 190) { /* it is DDR 200 */
+ if (ddrc_clk <= 350 && ddrc_clk > 230) {
+ /* DDRC clk at 230~350 */
+ printf("DDR: DDR controller freq is more than "
+ "max data rate of the module\n");
+ return 0;
+ } else if (ddrc_clk <= 230 && ddrc_clk > 90) {
+ /* DDRC clk at 90~230 */
+ effective_data_rate = 200; /* 10ns */
+ caslat = caslat;
+ }
}
/*
@@ -229,16 +308,14 @@ #endif
* note: WRREC(Twr) and WRTORD(Twtr) are not in SPD,
* use conservative value here.
*/
- trfc = spd.trfc * 1000; /* up to ps */
- trfc_clk = picos_to_clk(trfc);
- trfc_low = (trfc_clk - 8) & 0xf;
+ caslat_ctrl = (caslat + 1) & 0x07; /* see as above */
ddr->timing_cfg_1 =
(((picos_to_clk(spd.trp * 250) & 0x07) << 28 ) |
((picos_to_clk(spd.tras * 1000) & 0x0f ) << 24 ) |
((picos_to_clk(spd.trcd * 250) & 0x07) << 20 ) |
- ((caslat & 0x07) << 16 ) |
- (trfc_low << 12 ) |
+ ((caslat_ctrl & 0x07) << 16 ) |
+ (((picos_to_clk(spd.trfc * 1000) - 8) & 0x0f) << 12 ) |
( 0x300 ) |
((picos_to_clk(spd.trrd * 250) & 0x07) << 4) | 1);
@@ -246,36 +323,48 @@ #endif
debug("DDR:timing_cfg_1=0x%08x\n", ddr->timing_cfg_1);
debug("DDR:timing_cfg_2=0x%08x\n", ddr->timing_cfg_2);
+ /* Setup init value, but not enable */
+ ddr->sdram_cfg = 0x42000000;
+
+ /* Check DIMM data bus width */
+ if (spd.dataw_lsb == 0x20)
+ {
+ burstlen = 0x03; /* 32 bit data bus, burst len is 8 */
+ printf("\n DDR DIMM: data bus width is 32 bit");
+ }
+ else
+ {
+ burstlen = 0x02; /* Others act as 64 bit bus, burst len
is 4 */
+ printf("\n DDR DIMM: data bus width is 64 bit");
+ }
- /*
- * Only DDR I is supported
- * DDR I and II have different mode-register-set definition
+ /* Is this an ECC DDR chip? */
+ if (spd.config == 0x02) {
+ printf(" with ECC\n");
+ }
+ else
+ printf(" without ECC\n");
+
+ /* Burst length is always 4 for 64 bit data bus, 8 for 32 bit
data bus,
+ Burst type is sequential
*/
switch(caslat) {
+ case 1:
+ ddr->sdram_mode = 0x50 | burstlen; /* CL=1.5 */
+ break;
case 2:
- tmp = 0x50; /* 1.5 */
+ ddr->sdram_mode = 0x20 | burstlen; /* CL=2.0 */
break;
case 3:
- tmp = 0x20; /* 2.0 */
+ ddr->sdram_mode = 0x60 | burstlen; /* CL=2.5 */
break;
case 4:
- tmp = 0x60; /* 2.5 */
- break;
- case 5:
- tmp = 0x30; /* 3.0 */
+ ddr->sdram_mode = 0x30 | burstlen; /* CL=3.0 */
break;
default:
- puts("DDR:only CAS Latency 1.5, 2.0, 2.5, 3.0 is
supported.\n");
+ printf("DDR:only CAS Latency 1.5, 2.0, 2.5, 3.0 is
supported.\n");
return 0;
}
-#if defined (CONFIG_DDR_32BIT)
- /* set burst length to 8 for 32-bit data path */
- tmp |= 0x03;
-#else
- /* set burst length to 4 - default for 64-bit data path */
- tmp |= 0x02;
-#endif
- ddr->sdram_mode = tmp;
debug("DDR:sdram_mode=0x%08x\n", ddr->sdram_mode);
switch(spd.refresh) {
@@ -315,33 +404,15 @@ #endif
ddr->sdram_interval = ((tmp & 0x3fff) << 16) | 0x100;
debug("DDR:sdram_interval=0x%08x\n", ddr->sdram_interval);
- /*
- * Is this an ECC DDR chip?
- */
-#if defined(CONFIG_DDR_ECC)
- if (spd.config == 0x02) {
- /* disable error detection */
- ddr->err_disable = ~ECC_ERROR_ENABLE;
+ /* SS_EN = 0, source synchronous disable
+ * CLK_ADJST = 0, MCK/MCK# is launched aligned with addr/cmd
+ */
+ ddr->sdram_clk_cntl = 0x00000000;
+ debug("DDR:sdram_clk_cntl=0x%08x\n", ddr->sdram_clk_cntl);
- /* set single bit error threshold to maximum value,
- * reset counter to zero */
- ddr->err_sbe = (255 << ECC_ERROR_MAN_SBET_SHIFT) |
- (0 << ECC_ERROR_MAN_SBEC_SHIFT);
- }
- debug("DDR:err_disable=0x%08x\n", ddr->err_disable);
- debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe);
-#endif
asm("sync;isync");
- udelay(500);
-
- /*
- * SS_EN=1,
- * CLK_ADJST = 2-MCK/MCK_B, is lauched 1/2 of one SDRAM
- * clock cycle after address/command
- */
- /*ddr->sdram_clk_cntl = 0x82000000;*/
- ddr->sdram_clk_cntl =
(DDR_SDRAM_CLK_CNTL_SS_EN|DDR_SDRAM_CLK_CNTL_CLK_ADJUST_05);
+ udelay(600);
/*
* Figure out the settings for the sdram_cfg register. Build up
@@ -352,38 +423,48 @@ #endif
* sdram_cfg[0] = 1 (ddr sdram logic enable)
* sdram_cfg[1] = 1 (self-refresh-enable)
* sdram_cfg[6:7] = 2 (SDRAM type = DDR SDRAM)
+ * sdram_cfg[12] = 0 (32_BE =0 , 64 bit bus mode)
+ * sdram_cfg[13] = 0 (8_BE =0, 4-beat bursts)
*/
- tmp = 0xc2000000;
+ sdram_cfg = 0xC2000000;
-#if defined (CONFIG_DDR_32BIT)
- /* in 32-Bit mode burst len is 8 beats */
- tmp |= (SDRAM_CFG_32_BE | SDRAM_CFG_8_BE);
-#endif
- /*
- * sdram_cfg[3] = RD_EN - registered DIMM enable
- * A value of 0x26 indicates micron registered DIMMS
(micron.com)
- */
- if (spd.mod_attr == 0x26) {
- tmp |= 0x10000000;
+ /* sdram_cfg[3] = RD_EN - registered DIMM enable */
+ if (spd.mod_attr & 0x02) {
+ sdram_cfg |= 0x10000000;
+ }
+
+ /* The DIMM is 32bit width */
+ if (spd.dataw_lsb == 0x20) {
+ sdram_cfg |= 0x000C0000;
}
+ ddrc_ecc_enable = 0;
#if defined(CONFIG_DDR_ECC)
- /*
- * If the user wanted ECC (enabled via sdram_cfg[2])
- */
+ /* Enable ECC with sdram_cfg[2] */
if (spd.config == 0x02) {
- tmp |= SDRAM_CFG_ECC_EN;
+ sdram_cfg |= 0x20000000;
+ ddrc_ecc_enable = 1;
+ /* disable error detection */
+ ddr->err_disable = ~ECC_ERROR_ENABLE;
+ /* set single bit error threshold to maximum value,
+ * reset counter to zero */
+ ddr->err_sbe = (255 << ECC_ERROR_MAN_SBET_SHIFT) |
+ (0 << ECC_ERROR_MAN_SBEC_SHIFT);
}
+
+ debug("DDR:err_disable=0x%08x\n", ddr->err_disable);
+ debug("DDR:err_sbe=0x%08x\n", ddr->err_sbe);
#endif
+ printf(" DDRC ECC mode: %s", ddrc_ecc_enable ? "ON":"OFF");
#if defined(CONFIG_DDR_2T_TIMING)
/*
* Enable 2T timing by setting sdram_cfg[16].
*/
- tmp |= SDRAM_CFG_2T_EN;
+ sdram_cfg |= SDRAM_CFG_2T_EN;
#endif
-
- ddr->sdram_cfg = tmp;
+ /* Enable controller, and GO! */
+ ddr->sdram_cfg = sdram_cfg;
asm("sync;isync");
udelay(500);
@@ -393,7 +474,7 @@ #endif
#endif /* CONFIG_SPD_EEPROM */
-#if defined(CONFIG_DDR_ECC)
+#if defined(CONFIG_DDR_ECC) && !defined(CONFIG_ECC_INIT_VIA_DDRC)
/*
* Use timebase counter, get_timer() is not availabe
* at this point of initialization yet.
@@ -431,7 +512,7 @@ void ddr_enable_ecc(unsigned int dram_si
{
uint *p;
volatile immap_t *immap = (immap_t *)CFG_IMMRBAR;
- volatile ddr8349_t *ddr = &immap->ddr;
+ volatile ddr83xx_t *ddr= &immap->ddr;
unsigned long t_start, t_end;
#if defined(CONFIG_DDR_ECC_INIT_VIA_DMA)
uint i;
diff --git a/cpu/mpc83xx/speed.c b/cpu/mpc83xx/speed.c
index ad6b3f6..f3f3a9a 100644
--- a/cpu/mpc83xx/speed.c
+++ b/cpu/mpc83xx/speed.c
@@ -2,7 +2,7 @@
* (C) Copyright 2000-2002
* Wolfgang Denk, DENX Software Engineering, wd(a)denx.de.
*
- * Copyright 2004 Freescale Semiconductor, Inc.
+ * (C) Copyright 2006 Freescale Semiconductor, Inc.
*
* See file CREDITS for list of people who contributed to this
* project.
@@ -26,6 +26,10 @@
*
* 20050101: Eran Liberty (liberty(a)freescale.com)
* Initial file creating (porting from 85XX & 8260)
+ * 200506: Daveliu (daveliu(a)freescale.com)
+ * add mpc8360e support
+ * Code cleanup
+ *
*/
#include <common.h>
@@ -104,79 +108,53 @@ int get_clocks (void)
u32 lcrr;
u32 csb_clk;
+#if defined(CONFIG_MPC8349)
u32 tsec1_clk;
u32 tsec2_clk;
- u32 core_clk;
u32 usbmph_clk;
u32 usbdr_clk;
- u32 i2c_clk;
+#endif
+ u32 core_clk;
+ u32 i2c1_clk;
+ u32 i2c2_clk;
u32 enc_clk;
u32 lbiu_clk;
u32 lclk_clk;
u32 ddr_clk;
+#if defined (CONFIG_MPC8360)
+ u32 qepmf;
+ u32 qepdf;
+ u32 ddr_sec_clk;
+ u32 qe_clk;
+ u32 brg_clk;
+#endif
if ((im->sysconf.immrbar & IMMRBAR_BASE_ADDR) != (u32)im)
return -1;
-
-#ifndef CFG_HRCW_HIGH
-# error "CFG_HRCW_HIGH must be defined in board config file"
-#endif /* CFG_HCWD_HIGH */
-
-#if (CFG_HRCW_HIGH & HRCWH_PCI_HOST)
-
-# ifndef CONFIG_83XX_CLKIN
-# error "In PCI Host Mode, CONFIG_83XX_CLKIN must be defined in board
config file"
-# endif /* CONFIG_83XX_CLKIN */
-# ifdef CONFIG_83XX_PCICLK
-# warning "In PCI Host Mode, CONFIG_83XX_PCICLK in board config file
is igonred"
-# endif /* CONFIG_83XX_PCICLK */
-
- /* PCI Host Mode */
- if (!(im->reset.rcwh & RCWH_PCIHOST)) {
- /* though RCWH_PCIHOST is defined in CFG_HRCW_HIGH
- * the im->reset.rcwhr PCI Host Mode is disabled
- * FIXME: findout if there is a way to issue some
warning */
- return -2;
- }
- if (im->clk.spmr & SPMR_CKID) {
- /* PCI Clock is half CONFIG_83XX_CLKIN */
- pci_sync_in = CONFIG_83XX_CLKIN / 2;
- }
- else {
- pci_sync_in = CONFIG_83XX_CLKIN;
- }
-
-#else /* (CFG_HRCW_HIGH & HRCWH_PCI_HOST) */
-
-# ifdef CONFIG_83XX_CLKIN
-# warning "In PCI Agent Mode, CONFIG_83XX_CLKIN in board config file
is igonred"
-# endif /* CONFIG_83XX_CLKIN */
-# ifndef CONFIG_83XX_PCICLK
-# error "In PCI Agent Mode, CONFIG_83XX_PCICLK must be defined in
board config file"
-# endif /* CONFIG_83XX_PCICLK */
-
- /* PCI Agent Mode */
- if (im->reset.rcwh & RCWH_PCIHOST) {
- /* though RCWH_PCIHOST is not defined in CFG_HRCW_HIGH
- * the im->reset.rcwhr PCI Host Mode is enabled */
- return -3;
- }
- pci_sync_in = CONFIG_83XX_PCICLK;
-
-#endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST) */
-
- /* we have up to date pci_sync_in */
- spmf = ((im->reset.rcwl & RCWL_SPMF) >> RCWL_SPMF_SHIFT);
+
clkin_div = ((im->clk.spmr & SPMR_CKID) >> SPMR_CKID_SHIFT);
-
- if ((im->reset.rcwl & RCWL_LBIUCM) || (im->reset.rcwl &
RCWL_DDRCM)) {
- csb_clk = (pci_sync_in * spmf * (1 + clkin_div)) / 2;
+
+ if (im->reset.rcwh & HRCWH_PCI_HOST) {
+#if defined(CONFIG_83XX_CLKIN)
+ pci_sync_in = CONFIG_83XX_CLKIN / (1 + clkin_div);
+#else
+ pci_sync_in = 0xDEADBEEF;
+#endif
}
else {
- csb_clk = pci_sync_in * spmf * (1 + clkin_div);
+#if defined(CONFIG_83XX_PCICLK)
+ pci_sync_in = CONFIG_83XX_PCICLK;
+#else
+ pci_sync_in = 0xDEADBEEF;
+#endif
}
-
+
+ spmf = ((im->reset.rcwl & RCWL_SPMF) >> RCWL_SPMF_SHIFT);
+ csb_clk = pci_sync_in * (1 + clkin_div) * spmf;
+
sccr = im->clk.sccr;
+
+#if defined(CONFIG_MPC8349)
switch ((sccr & SCCR_TSEC1CM) >> SCCR_TSEC1CM_SHIFT) {
case 0:
tsec1_clk = 0;
@@ -212,26 +190,9 @@ #endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST)
/* unkown SCCR_TSEC2CM value */
return -5;
}
- i2c_clk = tsec2_clk;
-
- switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) {
- case 0:
- enc_clk = 0;
- break;
- case 1:
- enc_clk = csb_clk;
- break;
- case 2:
- enc_clk = csb_clk / 2;
- break;
- case 3:
- enc_clk = csb_clk / 3;
- break;
- default:
- /* unkown SCCR_ENCCM value */
- return -6;
- }
+ i2c1_clk = tsec2_clk;
+
switch ((sccr & SCCR_USBMPHCM) >> SCCR_USBMPHCM_SHIFT) {
case 0:
usbmph_clk = 0;
@@ -274,8 +235,34 @@ #endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST)
/* if USB MPH clock is not disabled and USB DR clock is
not disabled than USB MPH & USB DR must have the same rate */
return -9;
}
+#endif
+#if defined (CONFIG_MPC8360)
+ i2c1_clk = csb_clk;
+#endif
+ i2c2_clk = csb_clk; /* i2c-2 clk is equal to csb clk */
+ switch ((sccr & SCCR_ENCCM) >> SCCR_ENCCM_SHIFT) {
+ case 0:
+ enc_clk = 0;
+ break;
+ case 1:
+ enc_clk = csb_clk;
+ break;
+ case 2:
+ enc_clk = csb_clk / 2;
+ break;
+ case 3:
+ enc_clk = csb_clk / 3;
+ break;
+ default:
+ /* unkown SCCR_ENCCM value */
+ return -6;
+ }
+#if defined(CONFIG_MPC8349) || defined(CONFIG_MPC8360)
lbiu_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_LBIUCM) >>
RCWL_LBIUCM_SHIFT));
+#else
+#error Unknown MPC83xx chip
+#endif
lcrr = (im->lbus.lcrr & LCRR_CLKDIV) >> LCRR_CLKDIV_SHIFT;
switch (lcrr) {
case 2:
@@ -287,10 +274,16 @@ #endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST)
/* unknown lcrr */
return -10;
}
-
+#if defined(CONFIG_MPC8349) || defined(CONFIG_MPC8360)
ddr_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_DDRCM) >>
RCWL_DDRCM_SHIFT));
-
corepll = (im->reset.rcwl & RCWL_COREPLL) >> RCWL_COREPLL_SHIFT;
+#if defined (CONFIG_MPC8360)
+ ddr_sec_clk = csb_clk * (1 + ((im->reset.rcwl & RCWL_LBIUCM) >>
RCWL_LBIUCM_SHIFT));
+#endif
+#else
+#error Unknown MPC83xx chip
+#endif
+
corecnf_tab_index = ((corepll & 0x1F) << 2) | ((corepll & 0x60)
>> 5);
if (corecnf_tab_index > (sizeof(corecnf_tab)/sizeof(corecnf_t))
) {
/* corecnf_tab_index is too high, possibly worng value
*/
@@ -318,25 +311,45 @@ #endif /* (CFG_HRCW_HIGH | RCWH_PCIHOST)
/* unkown core to csb ratio */
return -12;
}
+
+#if defined (CONFIG_MPC8360)
+ qepmf = (im->reset.rcwl & RCWL_CEPMF) >> RCWL_CEPMF_SHIFT;
+ qepdf = (im->reset.rcwl & RCWL_CEPDF) >> RCWL_CEPDF_SHIFT;
+ qe_clk = (pci_sync_in * qepmf)/(1+qepdf);
+ brg_clk = 0;
+#endif
+
+ gd->csb_clk = csb_clk;
+#if defined(CONFIG_MPC8349)
+ gd->tsec1_clk = tsec1_clk;
+ gd->tsec2_clk = tsec2_clk;
+ gd->usbmph_clk = usbmph_clk;
+ gd->usbdr_clk = usbdr_clk;
+#endif
+ gd->core_clk = core_clk;
+ gd->i2c1_clk = i2c1_clk;
+ gd->i2c2_clk = i2c2_clk;
+ gd->enc_clk = enc_clk;
+ gd->lbiu_clk = lbiu_clk;
+ gd->lclk_clk = lclk_clk;
+ gd->ddr_clk = ddr_clk;
+#if defined (CONFIG_MPC8360)
+ gd->ddr_sec_clk = ddr_sec_clk;
+ gd->qe_clk = qe_clk;
+ gd->brg_clk = brg_clk;
+#endif
+ gd->cpu_clk = gd->core_clk;
+ gd->bus_clk = gd->csb_clk;
+ return 0;
- gd->csb_clk = csb_clk ;
- gd->tsec1_clk = tsec1_clk ;
- gd->tsec2_clk = tsec2_clk ;
- gd->core_clk = core_clk ;
- gd->usbmph_clk = usbmph_clk;
- gd->usbdr_clk = usbdr_clk ;
- gd->i2c_clk = i2c_clk ;
- gd->enc_clk = enc_clk ;
- gd->lbiu_clk = lbiu_clk ;
- gd->lclk_clk = lclk_clk ;
- gd->ddr_clk = ddr_clk ;
- gd->pci_clk = pci_sync_in;
+}
- gd->cpu_clk = gd->core_clk;
- gd->bus_clk = gd->lbiu_clk;
- return 0;
+ulong get_ddr_clk(ulong dummy)
+{
+ return gd->ddr_clk;
}
+
/********************************************
* get_bus_freq
* return system bus freq in Hz
@@ -351,14 +364,23 @@ int print_clock_conf (void)
printf("Clock configuration:\n");
printf(" Coherent System Bus: %4d MHz\n",gd->csb_clk/1000000);
printf(" Core: %4d MHz\n",gd->core_clk/1000000);
- debug(" Local Bus Controller:%4d MHz\n",gd->lbiu_clk/1000000);
+#if defined (CONFIG_MPC8360)
+ printf(" QE: %4d MHz\n",gd->qe_clk/1000000);
+#endif
+ printf(" Local Bus Controller:%4d MHz\n",gd->lbiu_clk/1000000);
printf(" Local Bus: %4d MHz\n",gd->lclk_clk/1000000);
- debug(" DDR: %4d MHz\n",gd->ddr_clk/1000000);
- debug(" I2C: %4d MHz\n",gd->i2c_clk/1000000);
- debug(" TSEC1: %4d MHz\n",gd->tsec1_clk/1000000);
- debug(" TSEC2: %4d MHz\n",gd->tsec2_clk/1000000);
- debug(" USB MPH: %4d
MHz\n",gd->usbmph_clk/1000000);
- debug(" USB DR: %4d MHz\n",gd->usbdr_clk/1000000);
-
+ printf(" DDR: %4d MHz\n",gd->ddr_clk/1000000);
+#if defined (CONFIG_MPC8360)
+ printf(" DDR Secondary: %4d
MHz\n",gd->ddr_sec_clk/1000000);
+#endif
+ printf(" SEC: %4d MHz\n",gd->enc_clk/1000000);
+ printf(" I2C1: %4d MHz\n",gd->i2c1_clk/1000000);
+ printf(" I2C2: %4d MHz\n",gd->i2c2_clk/1000000);
+#if defined(CONFIG_MPC8349)
+ printf(" TSEC1: %4d
MHz\n",gd->tsec1_clk/1000000);
+ printf(" TSEC2: %4d
MHz\n",gd->tsec2_clk/1000000);
+ printf(" USB MPH: %4d
MHz\n",gd->usbmph_clk/1000000);
+ printf(" USB DR: %4d
MHz\n",gd->usbdr_clk/1000000);
+#endif
return 0;
}
diff --git a/cpu/mpc83xx/start.S b/cpu/mpc83xx/start.S
index 6e02cce..8ecab88 100644
--- a/cpu/mpc83xx/start.S
+++ b/cpu/mpc83xx/start.S
@@ -174,9 +174,9 @@ #ifndef CFG_RAMBOOT
mtlr r5
blr
in_flash:
-#if 1 /* Remapping flash with LAW0. */
+ /* Change BR0 to CFG_FLASH_BASE, and remapping ROM flash with
LAW0 */
bl remap_flash_by_law0
-#endif
+ /* Change ROM flash base address and LAW0 is done! */
#endif /* CFG_RAMBOOT */
/* setup the bats */
@@ -870,6 +870,25 @@ ppcDcbz:
dcbz r0,r3
blr
+ .globl ppcDWstore
+ppcDWstore:
+ lfd 1, 0(r4)
+ stfd 1, 0(r3)
+ sync
+ blr
+
+ .globl ppcDWload
+ppcDWload:
+ lfd 1, 0(r3)
+ stfd 1, 0(r4)
+ sync
+ blr
+
+ .globl ppcDcbst
+ppcDcbst:
+ dcbst r0, r3
+ blr
+
/*-------------------------------------------------------------------*/
/*
@@ -1214,9 +1233,9 @@ map_flash_by_law1:
lis r4, (CFG_FLASH_BASE)@h
ori r4, r4, (CFG_FLASH_BASE)@l
stw r4, LBLAWBAR1(r3) /* LBLAWBAR1 <= CFG_FLASH_BASE */
- lis r4, (0x80000016)@h
- ori r4, r4, (0x80000016)@l
- stw r4, LBLAWAR1(r3) /* LBLAWAR1 <= 8MB Flash Size */
+ lis r4, (0x80000018)@h
+ ori r4, r4, (0x80000018)@l
+ stw r4, LBLAWAR1(r3) /* LBLAWAR1 <= 32MB Flash Size */
blr
/* Though all the LBIU Local Access Windows and LBC Banks will
be
@@ -1234,17 +1253,17 @@ remap_flash_by_law0:
stw r5, BR0(r3) /* r5 <= (CFG_FLASH_BASE & 0xFFFF8000) | (BR0 &
0x00007FFF) */
lwz r4, OR0(r3)
- lis r5, 0xFF80 /* 8M */
+ lis r5, 0xFE00 /* 32M */
or r4, r4, r5
- stw r4, OR0(r3) /* OR0 <= OR0 | 0xFF800000 */
+ stw r4, OR0(r3) /* OR0 <= OR0 | 0xFE000000 */
lis r4, (CFG_FLASH_BASE)@h
ori r4, r4, (CFG_FLASH_BASE)@l
stw r4, LBLAWBAR0(r3) /* LBLAWBAR0 <= CFG_FLASH_BASE */
- lis r4, (0x80000016)@h
- ori r4, r4, (0x80000016)@l
- stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= 8MB Flash Size */
+ lis r4, (0x80000018)@h
+ ori r4, r4, (0x80000018)@l
+ stw r4, LBLAWAR0(r3) /* LBLAWAR0 <= 32MB Flash Size */
xor r4, r4, r4
stw r4, LBLAWBAR1(r3)
--
1.3.GIT
2
1

[U-Boot-Users] [PATCH 6/6 ] Unified variable names and consolidated macro for TQM834x
by Jiang Bo-r61859 17 Aug '06
by Jiang Bo-r61859 17 Aug '06
17 Aug '06
Subject: [PATCH] Unified variable names and consolidated macro for
TQM834x
---
board/tqm834x/pci.c | 12 ++++++------
include/configs/TQM834x.h | 12 ++++++++++++
2 files changed, 18 insertions(+), 6 deletions(-)
205d48a033f0f2118845d26119416888f7e7c2f8
diff --git a/board/tqm834x/pci.c b/board/tqm834x/pci.c
index 5a23e6c..d01277f 100644
--- a/board/tqm834x/pci.c
+++ b/board/tqm834x/pci.c
@@ -69,17 +69,17 @@ void
pci_init_board(void)
{
volatile immap_t * immr;
- volatile clk8349_t * clk;
- volatile law8349_t * pci_law;
- volatile pot8349_t * pci_pot;
- volatile pcictrl8349_t * pci_ctrl;
- volatile pciconf8349_t * pci_conf;
+ volatile clk83xx_t * clk;
+ volatile law83xx_t * pci_law;
+ volatile pot83xx_t * pci_pot;
+ volatile pcictrl83xx_t * pci_ctrl;
+ volatile pciconf83xx_t * pci_conf;
u16 reg16;
u32 reg32;
struct pci_controller * hose;
immr = (immap_t *)CFG_IMMRBAR;
- clk = (clk8349_t *)&immr->clk;
+ clk = (clk83xx_t *)&immr->clk;
pci_law = immr->sysconf.pcilaw;
pci_pot = immr->ios.pot;
pci_ctrl = immr->pci_ctrl;
diff --git a/include/configs/TQM834x.h b/include/configs/TQM834x.h
index cec7e3e..5c469bf 100644
--- a/include/configs/TQM834x.h
+++ b/include/configs/TQM834x.h
@@ -36,6 +36,7 @@ #undef DEBUG
*/
#define CONFIG_E300 1 /* E300 Family */
#define CONFIG_MPC83XX 1 /* MPC83XX family */
+#define CONFIG_MPC8349 1 /* MPC8349 specific */
#define CONFIG_MPC834X 1 /* MPC834X specific */
#define CONFIG_TQM834X 1 /* TQM834X board specific */
@@ -56,6 +57,17 @@ #define CONFIG_83XX_CLKIN 66666000 /* 66
*/
#define CFG_LCRR (LCRR_DBYP | LCRR_CLKDIV_8)
+#define CFG_SCCR_INIT (SCCR_DEFAULT & (~SCCR_CLK_MASK))
+#define CFG_SCCR_TSEC1CM SCCR_TSEC1CM_1 /* TSEC1 clock setting
*/
+#define CFG_SCCR_TSEC2CM SCCR_TSEC2CM_1 /* TSEC2 clock setting
*/
+#define CFG_SCCR_ENCCM SCCR_ENCCM_3 /* ENC clock setting */
+#define CFG_SCCR_USBCM SCCR_USBCM_3 /* USB clock setting */
+#define CFG_SCCR_VAL ( CFG_SCCR_INIT \
+ | CFG_SCCR_TSEC1CM \
+ | CFG_SCCR_TSEC2CM \
+ | CFG_SCCR_ENCCM \
+ | CFG_SCCR_USBCM )
+
/* board pre init: do not call, nothing to do */
#undef CONFIG_BOARD_EARLY_INIT_F
--
1.3.GIT
2
1
I want to know the step to port u-boot on my custom board and required tools
--
View this message in context: http://www.nabble.com/step-to-port-u-boot-on-custom-board-tf2120824.html#a5…
Sent from the Uboot - Users forum at Nabble.com.
3
2
Subject: [PATCH] PHY support for QE
---
drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c | 568
++++++++++++++++++++++++++++++
drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h | 262 ++++++++++++++
2 files changed, 830 insertions(+), 0 deletions(-)
create mode 100644 drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
create mode 100644 drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
e066a4f092e8a4812983e0ff5fde933c4727e354
diff --git a/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
new file mode 100644
index 0000000..7cf725b
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
@@ -0,0 +1,568 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc_geth_phy.c
+ *
+ * UCC GETH Driver -- PHY handling
+ * Driver for UEC on QE
+ * Based on 8260_io/fcc_enet.c
+ *
+ * Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
+ * Author: Shlomi Gridish
+ * Maintainer: Kumar Gala (kumar.gala(a)freescale.com)
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 "list.h"
+#include "asm/errno.h"
+#include "immap_qe.h"
+#include "qe.h"
+#include "asm/io.h"
+#include "ucc.h"
+#include "ucc_fast.h"
+#include "ucc_geth.h"
+#include "ucc_geth_phy.h"
+
+#include "miiphy.h"
+
+#define UGETH_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 UGETH_VERBOSE_DEBUG
+#define ugphy_vdbg ugphy_dbg
+#else
+#define ugphy_vdbg(ugeth, fmt, args...) do { } while (0)
+#endif /* UGETH_VERBOSE_DEBUG */
+
+static void config_genmii_advert(struct ugeth_mii_info *mii_info);
+static void genmii_setup_forced(struct ugeth_mii_info *mii_info);
+static void genmii_restart_aneg(struct ugeth_mii_info *mii_info);
+static int gbit_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_config_aneg(struct ugeth_mii_info *mii_info);
+static int genmii_update_link(struct ugeth_mii_info *mii_info);
+static int genmii_read_status(struct ugeth_mii_info *mii_info);
+u16 phy_read(struct ugeth_mii_info *mii_info, u16 regnum);
+void phy_write(struct ugeth_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)
+{
+ ucc_geth_private_t *ugeth = (ucc_geth_private_t *) dev->priv;
+ ucc_geth_t *ug_regs;
+ enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+ u32 tmp_reg;
+
+ ug_regs = ugeth->ug_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)
+{
+ ucc_geth_private_t *ugeth = (ucc_geth_private_t *) dev->priv;
+ ucc_geth_t *ug_regs;
+ enet_tbi_mii_reg_e mii_reg = (enet_tbi_mii_reg_e) regnum;
+ u32 tmp_reg;
+ u16 value;
+
+ ug_regs = ugeth->ug_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 ugeth_mii_info *mii_info)
+{
+ if (mii_info->phyinfo->ack_interrupt)
+ mii_info->phyinfo->ack_interrupt(mii_info);
+}
+
+void mii_configure_phy_interrupt(struct ugeth_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 ugeth_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 ugeth_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 ugeth_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 ugeth_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 ugeth_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 ugeth_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 ugeth_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 ugeth_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 ugeth_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);
+
+#if 0
+ /* If speed and duplex aren't resolved,
+ * return an error. Isn't this handled
+ * by checking aneg?
+ */
+ if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
+ return -EAGAIN;
+#endif
+
+ /* 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 ugeth_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 ugeth_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 ugeth_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);
+#if CONFIG_RMII_MODE == 1
+ 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);
+
+ udelay(3000000);
+
+ return 0;
+}
+
+static int dm9161_config_aneg(struct ugeth_mii_info *mii_info)
+{
+ return 0;
+}
+
+static int dm9161_read_status(struct ugeth_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 ugeth_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 ugeth_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 ugeth_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 ugeth_mii_info *mii_info, u16 regnum)
+{
+ return mii_info->mdio_read(mii_info->dev, mii_info->mii_id,
regnum);
+}
+
+void phy_write(struct ugeth_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 ugeth_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("geth: PHY id %x is not supported!", phy_ID);
+ return NULL;
+ } else {
+ ugphy_info("geth: PHY is %s (%x)", theInfo->name,
phy_ID);
+ }
+
+ return theInfo;
+}
diff --git a/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
new file mode 100644
index 0000000..a711116
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
@@ -0,0 +1,262 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc_geth_phy.h
+ *
+ * UCC GETH Driver Header File
+ *
+ * Copyright (c) 2002-2006 Freescale Semiconductor, Inc.
+ * Author: Shlomi Gridish
+ * Maintainer: Kumar Gala (kumar.gala(a)freescale.com)
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 __UCC_GETH_PHY_H__
+#define __UCC_GETH_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 ugeth_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 ugeth_mii_info * mii_info);
+
+ /* Called to suspend the PHY for power */
+ int (*suspend) (struct ugeth_mii_info * mii_info);
+
+ /* Reconfigures autonegotiation (or disables it) */
+ int (*config_aneg) (struct ugeth_mii_info * mii_info);
+
+ /* Determines the negotiated speed and duplex */
+ int (*read_status) (struct ugeth_mii_info * mii_info);
+
+ /* Clears any pending interrupts */
+ int (*ack_interrupt) (struct ugeth_mii_info * mii_info);
+
+ /* Enables or disables interrupts */
+ int (*config_intr) (struct ugeth_mii_info * mii_info);
+
+ /* Clears up any memory if needed */
+ void (*close) (struct ugeth_mii_info * mii_info);
+};
+
+struct phy_info *get_phy_info(struct ugeth_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 ugeth_mii_info *mii_info);
+void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info,
+ u32 interrupts);
+
+#endif /* __UCC_GETH_PHY_H__ */
--
1.3.GIT
1
0

[U-Boot-Users] [PATCH 4/6 part 4] UCC fast mode support in QUICC Engine
by Jiang Bo-r61859 17 Aug '06
by Jiang Bo-r61859 17 Aug '06
17 Aug '06
Subject: [PATCH] UCC fast mode support in QUICC Engine
---
drivers/sysdev/qe_lib/ucc/ucc_fast.c | 399
++++++++++++++++++++++++++++++++++
drivers/sysdev/qe_lib/ucc/ucc_fast.h | 274 +++++++++++++++++++++++
2 files changed, 673 insertions(+), 0 deletions(-)
create mode 100644 drivers/sysdev/qe_lib/ucc/ucc_fast.c
create mode 100644 drivers/sysdev/qe_lib/ucc/ucc_fast.h
70d5c3232e44ede21d30f53f6522f49d7a9b81f4
diff --git a/drivers/sysdev/qe_lib/ucc/ucc_fast.c
b/drivers/sysdev/qe_lib/ucc/ucc_fast.c
new file mode 100644
index 0000000..f0d5d9d
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc_fast.c
@@ -0,0 +1,399 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc_fast.c
+ *
+ * QE UCC Fast API Set - UCC Fast specific routines implementations.
+ *
+ * (C) Copyright 2006 Freescale Semiconductor, Inc
+ * Author: Shlomi Gridish <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 "malloc.h"
+#include "asm/errno.h"
+#include "immap_qe.h"
+#include "qe.h"
+#include "asm/io.h"
+#include "ucc.h"
+#include "ucc_fast.h"
+
+#define uccf_printk(format, arg...) \
+ printf(format "\n", ## arg)
+
+#define uccf_dbg(format, arg...) \
+ uccf_printk(format , ## arg)
+#define uccf_err(format, arg...) \
+ uccf_printk(format , ## arg)
+#define uccf_info(format, arg...) \
+ uccf_printk(format , ## arg)
+#define uccf_warn(format, arg...) \
+ uccf_printk(format , ## arg)
+
+#ifdef UCCF_VERBOSE_DEBUG
+#define uccf_vdbg uccf_dbg
+#else
+#define uccf_vdbg(ugeth, fmt, args...) do { } while (0)
+#endif /* UCCF_VERBOSE_DEBUG */
+
+void ucc_fast_dump_regs(ucc_fast_private_t * uccf)
+{
+ uccf_info("UCC%d Fast registers:", uccf->uf_info->ucc_num);
+ uccf_info("Base address: 0x%08x", (u32) uccf->uf_regs);
+
+ uccf_info("gumr : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->gumr,
in_be32(&uccf->uf_regs->gumr));
+ uccf_info("upsmr : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->upsmr,
in_be32(&uccf->uf_regs->upsmr));
+ uccf_info("utodr : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utodr,
in_be16(&uccf->uf_regs->utodr));
+ uccf_info("udsr : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->udsr,
in_be16(&uccf->uf_regs->udsr));
+ uccf_info("ucce : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->ucce,
in_be32(&uccf->uf_regs->ucce));
+ uccf_info("uccm : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->uccm,
in_be32(&uccf->uf_regs->uccm));
+ uccf_info("uccs : addr - 0x%08x, val - 0x%02x",
+ (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs);
+ uccf_info("urfb : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->urfb,
in_be32(&uccf->uf_regs->urfb));
+ uccf_info("urfs : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->urfs,
in_be16(&uccf->uf_regs->urfs));
+ uccf_info("urfet : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->urfet,
in_be16(&uccf->uf_regs->urfet));
+ uccf_info("urfset: addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->urfset,
+ in_be16(&uccf->uf_regs->urfset));
+ uccf_info("utfb : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->utfb,
in_be32(&uccf->uf_regs->utfb));
+ uccf_info("utfs : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utfs,
in_be16(&uccf->uf_regs->utfs));
+ uccf_info("utfet : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utfet,
in_be16(&uccf->uf_regs->utfet));
+ uccf_info("utftt : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utftt,
in_be16(&uccf->uf_regs->utftt));
+ uccf_info("utpt : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utpt,
in_be16(&uccf->uf_regs->utpt));
+ uccf_info("urtry : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->urtry,
in_be32(&uccf->uf_regs->urtry));
+ uccf_info("guemr : addr - 0x%08x, val - 0x%02x",
+ (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr);
+}
+
+u32 ucc_fast_get_qe_cr_subblock(int uccf_num)
+{
+ switch (uccf_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;
+ }
+}
+
+void ucc_fast_transmit_on_demand(ucc_fast_private_t * uccf)
+{
+ out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
+}
+
+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;
+ u32 gumr = 0;
+ int ret;
+
+ uccf_vdbg("%s: IN", __FUNCTION__);
+
+ if (!uf_info)
+ return -EINVAL;
+
+ /* check if the UCC port number is in range. */
+ if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM -
1)) {
+ uccf_err("ucc_fast_init: Illagal UCC number!");
+ return -EINVAL;
+ }
+
+ /* Check that 'max_rx_buf_length' is properly aligned (4). */
+ if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1))
{
+ uccf_err("ucc_fast_init: max_rx_buf_length not
aligned.");
+ return -EINVAL;
+ }
+
+ /* Validate Virtual Fifo register values */
+ if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) {
+ uccf_err("ucc_fast_init: Virtual Fifo "
+ "register urfs too small.");
+ return -EINVAL;
+ }
+
+ if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err ("ucc_fast_init: Virtual Fifo "
+ "register urfs not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err("ucc_fast_init: Virtual Fifo "
+ "register urfet not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err("ucc_fast_init: Virtual Fifo "
+ "register urfset not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err("ucc_fast_init: Virtual Fifo "
+ "register utfs not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err("ucc_fast_init: Virtual Fifo "
+ "register utfet not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err("ucc_fast_init: Virtual Fifo "
+ "register utftt not aligned.");
+ return -EINVAL;
+ }
+
+ uccf = (ucc_fast_private_t *)
malloc(sizeof(ucc_fast_private_t));
+ if (!uccf) {
+ uccf_err("ucc_fast_init: No memory for "
+ "UCC slow data structure!");
+ return -ENOMEM;
+ }
+ memset(uccf, 0, sizeof(ucc_fast_private_t));
+
+ /* Fill fast UCC structure */
+ uccf->uf_info = uf_info;
+ /* Set the PHY base address */
+ uccf->uf_regs = (ucc_fast_t *) uf_info->regs;
+ if (uccf->uf_regs == NULL) {
+ uccf_err("ucc_fast_init: No memory map "
+ "for UCC slow controller!");
+ return -ENOMEM;
+ }
+
+ uccf->enabled_tx = 0;
+ uccf->enabled_rx = 0;
+ uccf->stopped_tx = 0;
+ uccf->stopped_rx = 0;
+ uf_regs = uccf->uf_regs;
+ uccf->p_ucce = (u32 *) & (uf_regs->ucce);
+ uccf->p_uccm = (u32 *) & (uf_regs->uccm);
+#ifdef STATISTICS
+ uccf->tx_frames = 0;
+ uccf->rx_frames = 0;
+ uccf->rx_discarded = 0;
+#endif /* STATISTICS */
+
+ /* Init Guemr register */
+ if ((ret = ucc_init_guemr((ucc_common_t *) (uf_regs)))) {
+ uccf_err("ucc_fast_init: Could not init the guemr
register.");
+ ucc_fast_free(uccf);
+ return ret;
+ }
+
+ /* Set UCC to fast type */
+ if ((ret = ucc_set_type(uf_info->ucc_num,
+ (ucc_common_t *) (uf_regs),
+ UCC_SPEED_TYPE_FAST))) {
+ uccf_err("ucc_fast_init: Could not set type to fast.");
+ ucc_fast_free(uccf);
+ return ret;
+ }
+
+ uccf->mrblr = uf_info->max_rx_buf_length;
+
+ /* Set GUMR. */
+ /* For more details see the hardware spec. */
+ /* gumr starts as zero. */
+ if (uf_info->tci)
+ gumr |= UCC_FAST_GUMR_TCI;
+ gumr |= uf_info->ttx_trx;
+ if (uf_info->cdp)
+ gumr |= UCC_FAST_GUMR_CDP;
+ if (uf_info->ctsp)
+ gumr |= UCC_FAST_GUMR_CTSP;
+ if (uf_info->cds)
+ gumr |= UCC_FAST_GUMR_CDS;
+ if (uf_info->ctss)
+ gumr |= UCC_FAST_GUMR_CTSS;
+ if (uf_info->txsy)
+ gumr |= UCC_FAST_GUMR_TXSY;
+ if (uf_info->rsyn)
+ gumr |= UCC_FAST_GUMR_RSYN;
+ gumr |= uf_info->synl;
+ if (uf_info->rtsm)
+ gumr |= UCC_FAST_GUMR_RTSM;
+ gumr |= uf_info->renc;
+ if (uf_info->revd)
+ gumr |= UCC_FAST_GUMR_REVD;
+ gumr |= uf_info->tenc;
+ gumr |= uf_info->tcrc;
+ gumr |= uf_info->mode;
+ out_be32(&uf_regs->gumr, gumr);
+
+ /* Allocate memory for Tx Virtual Fifo */
+ uccf->ucc_fast_tx_virtual_fifo_base_offset =
+ qe_muram_alloc(uf_info->utfs,
UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+ if (IS_MURAM_ERR(uccf->ucc_fast_tx_virtual_fifo_base_offset)) {
+ uccf_err("ucc_fast_init: Can not allocate MURAM memory "
+ "for ucc_fast_tx_virtual_fifo_base_offset.");
+ uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
+ ucc_fast_free(uccf);
+ return -ENOMEM;
+ }
+
+ /* Allocate memory for Rx Virtual Fifo */
+ uccf->ucc_fast_rx_virtual_fifo_base_offset =
+ qe_muram_alloc(uf_info->urfs +
+ (u32)UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR,
+ UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT);
+ if (IS_MURAM_ERR(uccf->ucc_fast_rx_virtual_fifo_base_offset)) {
+ uccf_err("ucc_fast_init: Can not allocate MURAM memory "
+ "for ucc_fast_rx_virtual_fifo_base_offset.");
+ uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
+ ucc_fast_free(uccf);
+ return -ENOMEM;
+ }
+
+ /* Set Virtual Fifo registers */
+ out_be16(&uf_regs->urfs, uf_info->urfs);
+ out_be16(&uf_regs->urfet, uf_info->urfet);
+ out_be16(&uf_regs->urfset, uf_info->urfset);
+ out_be16(&uf_regs->utfs, uf_info->utfs);
+ out_be16(&uf_regs->utfet, uf_info->utfet);
+ out_be16(&uf_regs->utftt, uf_info->utftt);
+ /* 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);
+
+ /* Mux clocking */
+ /* Grant Support */
+ ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support);
+ /* Breakpoint Support */
+ ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support);
+ /* Set Tsa or NMSI mode. */
+ ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa);
+ /* If NMSI (not Tsa), set Tx and Rx clock. */
+ if (!uf_info->tsa) {
+ /* Rx clock routing */
+ if (uf_info->rx_clock != QE_CLK_NONE) {
+ if (ucc_set_qe_mux_rxtx(uf_info->ucc_num,
+ uf_info->rx_clock, COMM_DIR_RX)) {
+ uccf_err("ucc_fast_init: Illegal value "
+ "for parameter 'RxClock'.");
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+ }
+ /* Tx clock routing */
+ if (uf_info->tx_clock != QE_CLK_NONE) {
+ if (ucc_set_qe_mux_rxtx(uf_info->ucc_num,
+ uf_info->tx_clock, COMM_DIR_TX)) {
+ uccf_err("ucc_fast_init: Illegal value "
+ "for parameter 'TxClock'.");
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+ }
+ }
+
+ /*
+ * INTERRUPTS
+ */
+ /* Set interrupt mask register at UCC level. */
+ out_be32(&uf_regs->uccm, uf_info->uccm_mask);
+
+ /* First, clear anything pending at UCC level, */
+ /* otherwise, old garbage may come through */
+ /* as soon as the dam is opened. */
+
+ /* Writing '1' clears */
+ out_be32(&uf_regs->ucce, 0xffffffff);
+
+ *uccf_ret = uccf;
+ return 0;
+}
+
+void ucc_fast_free(ucc_fast_private_t * uccf)
+{
+ if (!uccf)
+ return;
+
+ if (uccf->ucc_fast_tx_virtual_fifo_base_offset)
+
qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset);
+
+ if (uccf->ucc_fast_rx_virtual_fifo_base_offset)
+
qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset);
+
+ free(uccf);
+}
diff --git a/drivers/sysdev/qe_lib/ucc/ucc_fast.h
b/drivers/sysdev/qe_lib/ucc/ucc_fast.h
new file mode 100644
index 0000000..b2bd900
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc_fast.h
@@ -0,0 +1,274 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc_fast.h
+ *
+ * Internal header file for UCC FAST unit routines.
+ *
+ * (C) Copyright 2006 Freescale Semiconductor, Inc
+ * Author: Shlomi Gridish <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 __UCC_FAST_H__
+#define __UCC_FAST_H__
+
+#include "immap_qe.h"
+#include "qe.h"
+#include "ucc.h"
+
+#define DEFAULT_bd_mem_part MEM_PART_SYSTEM
+#define DEFAULT_initTx 1
+#define DEFAULT_initRx 1
+#define DEFAULT_brkptSupport 0
+#define DEFAULT_grantSupport 0
+#define DEFAULT_tsa 0
+#define DEFAULT_cdp 0
+#define DEFAULT_cds 0
+#define DEFAULT_ctsp 0
+#define DEFAULT_ctss 0
+#define DEFAULT_tci 0
+#define DEFAULT_txsy 0
+#define DEFAULT_rtsm UCC_FAST_SEND_IDLES_BETWEEN_FRAMES
+#define DEFAULT_revd 0
+#define DEFAULT_rsyn 0
+#define DEFAULT_syn1 0x7E /* hdlc flag */
+#define DEFAULT_syn2 0x7E /* hdlc flag */
+#define DEFAULT_utftt 0x40 /* recommended */
+#define DEFAULT_ufpt 256 /* recommended */
+#define DEFAULT_ttx_trx
UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL
+#define DEFAULT_tenc UCC_FAST_TX_ENCODING_NRZ
+#define DEFAULT_renc UCC_FAST_RX_ENCODING_NRZ
+#define DEFAULT_diag UCC_FAST_DIAGNOSTIC_NORMAL
+#define DEFAULT_tcrc UCC_FAST_16_BIT_CRC
+#define DEFAULT_synl UCC_FAST_SYNC_LEN_NOT_USED
+
+/* Receive BD's status.
+*/
+#define R_E 0x80000000 /* buffer empty
*/
+#define R_W 0x20000000 /* wrap bit
*/
+#define R_I 0x10000000 /* interrupt on reception
*/
+#define R_L 0x08000000 /* last
*/
+#define R_F 0x04000000 /* first
*/
+
+/* transmit BD's status.
+*/
+#define T_R 0x80000000 /* ready bit */
+#define T_W 0x20000000 /* wrap bit */
+#define T_I 0x10000000 /* interrupt on completion */
+#define T_L 0x08000000 /* last */
+
+/* Rx Data buffer must be 4 bytes aligned in most cases.*/
+#define UCC_FAST_RX_ALIGN 4
+#define UCC_FAST_MRBLR_ALIGNMENT 4
+#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8
+
+/* Sizes
+*/
+#define UCC_FAST_URFS_MIN_VAL 0x88
+#define UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR 8
+
+/* ucc_fast_channel_protocol_mode - UCC FAST mode.
+*/
+typedef enum ucc_fast_channel_protocol_mode {
+ UCC_FAST_PROTOCOL_MODE_HDLC = 0x00000000,
+ UCC_FAST_PROTOCOL_MODE_RESERVED01 = 0x00000001,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_QMC = 0x00000002,
+ UCC_FAST_PROTOCOL_MODE_RESERVED02 = 0x00000003,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_UART = 0x00000004,
+ UCC_FAST_PROTOCOL_MODE_RESERVED03 = 0x00000005,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_1 = 0x00000006,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_2 = 0x00000007,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_BISYNC = 0x00000008,
+ UCC_FAST_PROTOCOL_MODE_RESERVED04 = 0x00000009,
+ UCC_FAST_PROTOCOL_MODE_ATM = 0x0000000A,
+ UCC_FAST_PROTOCOL_MODE_RESERVED05 = 0x0000000B,
+ UCC_FAST_PROTOCOL_MODE_ETHERNET = 0x0000000C,
+ UCC_FAST_PROTOCOL_MODE_RESERVED06 = 0x0000000D,
+ UCC_FAST_PROTOCOL_MODE_POS = 0x0000000E,
+ UCC_FAST_PROTOCOL_MODE_RESERVED07 = 0x0000000F
+} ucc_fast_channel_protocol_mode_e;
+
+/* ucc_fast_transparent_txrx - UCC Fast Transparent TX & RX
+*/
+typedef enum ucc_fast_transparent_txrx {
+ UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL = 0x00000000,
+ UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_TRANSPARENT = 0x18000000
+} ucc_fast_transparent_txrx_e;
+
+/* UCC fast diagnostic mode
+*/
+typedef enum ucc_fast_diag_mode {
+ UCC_FAST_DIAGNOSTIC_NORMAL = 0x0,
+ UCC_FAST_DIAGNOSTIC_LOCAL_LOOP_BACK = 0x40000000,
+ UCC_FAST_DIAGNOSTIC_AUTO_ECHO = 0x80000000,
+ UCC_FAST_DIAGNOSTIC_LOOP_BACK_AND_ECHO = 0xC0000000
+} ucc_fast_diag_mode_e;
+
+/* UCC fast Sync length (transparent mode only)
+*/
+typedef enum ucc_fast_sync_len {
+ UCC_FAST_SYNC_LEN_NOT_USED = 0x0,
+ UCC_FAST_SYNC_LEN_AUTOMATIC = 0x00004000,
+ UCC_FAST_SYNC_LEN_8_BIT = 0x00008000,
+ UCC_FAST_SYNC_LEN_16_BIT = 0x0000C000
+} ucc_fast_sync_len_e;
+
+/* UCC fast RTS mode
+*/
+typedef enum ucc_fast_ready_to_send {
+ UCC_FAST_SEND_IDLES_BETWEEN_FRAMES = 0x00000000,
+ UCC_FAST_SEND_FLAGS_BETWEEN_FRAMES = 0x00002000
+} ucc_fast_ready_to_send_e;
+
+/* UCC fast receiver decoding mode
+*/
+typedef enum ucc_fast_rx_decoding_method {
+ UCC_FAST_RX_ENCODING_NRZ = 0x00000000,
+ UCC_FAST_RX_ENCODING_NRZI = 0x00000800,
+ UCC_FAST_RX_ENCODING_RESERVED0 = 0x00001000,
+ UCC_FAST_RX_ENCODING_RESERVED1 = 0x00001800
+} ucc_fast_rx_decoding_method_e;
+
+/* UCC fast transmitter encoding mode
+*/
+typedef enum ucc_fast_tx_encoding_method {
+ UCC_FAST_TX_ENCODING_NRZ = 0x00000000,
+ UCC_FAST_TX_ENCODING_NRZI = 0x00000100,
+ UCC_FAST_TX_ENCODING_RESERVED0 = 0x00000200,
+ UCC_FAST_TX_ENCODING_RESERVED1 = 0x00000300
+} ucc_fast_tx_encoding_method_e;
+
+/* UCC fast CRC length
+*/
+typedef enum ucc_fast_transparent_tcrc {
+ UCC_FAST_16_BIT_CRC = 0x00000000,
+ UCC_FAST_CRC_RESERVED0 = 0x00000040,
+ UCC_FAST_32_BIT_CRC = 0x00000080,
+ UCC_FAST_CRC_RESERVED1 = 0x000000C0
+} ucc_fast_transparent_tcrc_e;
+
+/* Fast UCC initialization structure.
+*/
+typedef struct ucc_fast_info {
+ int ucc_num;
+ qe_clock_e rx_clock;
+ qe_clock_e tx_clock;
+ u32 regs;
+ int irq;
+ u32 uccm_mask;
+ int bd_mem_part;
+ int brkpt_support;
+ int grant_support;
+ int tsa;
+ int cdp;
+ int cds;
+ int ctsp;
+ int ctss;
+ int tci;
+ int txsy;
+ int rtsm;
+ int revd;
+ int rsyn;
+ u16 max_rx_buf_length;
+ u16 urfs;
+ u16 urfet;
+ u16 urfset;
+ u16 utfs;
+ u16 utfet;
+ u16 utftt;
+ u16 ufpt;
+ ucc_fast_channel_protocol_mode_e mode;
+ ucc_fast_transparent_txrx_e ttx_trx;
+ ucc_fast_tx_encoding_method_e tenc;
+ ucc_fast_rx_decoding_method_e renc;
+ ucc_fast_transparent_tcrc_e tcrc;
+ ucc_fast_sync_len_e synl;
+} 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 in
memory.*/
+ u32 *p_uccm; /* a pointer to the mask register in
memory. */
+ int enabled_tx; /* Whether channel is enabled for Tx
(ENT) */
+ int enabled_rx; /* Whether channel is enabled for Rx
(ENR) */
+ int stopped_tx; /* Whether channel has been stopped for
Tx */
+ int stopped_rx; /* Whether channel has been stopped for
Rx */
+ u32 ucc_fast_tx_virtual_fifo_base_offset; /* pointer to
base of
+ * Tx virtual
fifo */
+ u32 ucc_fast_rx_virtual_fifo_base_offset; /* pointer to
base of
+ * Rx virtual
fifo */
+#ifdef STATISTICS
+ u32 tx_frames; /* Transmitted frames counter.*/
+ u32 rx_frames; /* Received frames counter
+ * (only frames passed to
application).*/
+ u32 tx_discarded; /* Discarded tx frames counter
+ * (frames that were discarded
+ * by the driver due to errors).*/
+ u32 rx_discarded; /* Discarded rx frames counter
+ * (frames that were discarded
+ * by the driver due to errors).*/
+#endif /* STATISTICS */
+ u16 mrblr; /* maximum receive buffer length */
+} ucc_fast_private_t;
+
+/* ucc_fast_init
+ * Initializes Fast UCC according to user provided parameters.
+ * uf_info - (In) pointer to the fast UCC info structure.
+ * uccf_ret - (Out) pointer to the fast UCC structure.
+ */
+int ucc_fast_init(ucc_fast_info_t * uf_info, ucc_fast_private_t **
uccf_ret);
+
+/* ucc_fast_free
+ * Frees all resources for fast UCC.
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_free(ucc_fast_private_t * uccf);
+
+/* ucc_fast_enable
+ * Enables a fast UCC port.
+ * This routine enables Tx and/or Rx through the General UCC Mode
Register.
+ * uccf - (In) pointer to the fast UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_fast_enable(ucc_fast_private_t * uccf, comm_dir_e mode);
+
+/* ucc_fast_disable
+ * Disables a fast UCC port.
+ * This routine disables Tx and/or Rx through the General UCC Mode
Register.
+ * uccf - (In) pointer to the fast UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_fast_disable(ucc_fast_private_t * uccf, comm_dir_e mode);
+
+/* ucc_fast_irq
+ * Handles interrupts on fast UCC.
+ * Called from the general interrupt routine to handle interrupts on
fast UCC.
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_irq(ucc_fast_private_t * uccf);
+
+/* ucc_fast_transmit_on_demand
+ * Immediately forces a poll of the transmitter for data to be sent.
+ * Typically, the hardware performs a periodic poll for data that the
+ * transmit routine has set up to be transmitted. In cases where
+ * this polling cycle is not soon enough, this optional routine can
+ * be invoked to force a poll right away, instead. Proper use for
+ * each transmission for which this functionality is desired is to
+ * call the transmit routine and then this routine right after.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_transmit_on_demand(ucc_fast_private_t * uccf);
+
+u32 ucc_fast_get_qe_cr_subblock(int uccf_num);
+
+void ucc_fast_dump_regs(ucc_fast_private_t * uccf);
+
+#endif /* __UCC_FAST_H__ */
--
1.3.GIT
1
0

17 Aug '06
Subject: [PATCH] UCC lib support in QUICC Engine
---
drivers/sysdev/qe_lib/ucc/Makefile | 36 ++
drivers/sysdev/qe_lib/ucc/list.h | 728
++++++++++++++++++++++++++++++++++++
drivers/sysdev/qe_lib/ucc/ucc.c | 332 ++++++++++++++++
drivers/sysdev/qe_lib/ucc/ucc.h | 98 +++++
4 files changed, 1194 insertions(+), 0 deletions(-)
create mode 100644 drivers/sysdev/qe_lib/ucc/Makefile
create mode 100644 drivers/sysdev/qe_lib/ucc/list.h
create mode 100644 drivers/sysdev/qe_lib/ucc/ucc.c
create mode 100644 drivers/sysdev/qe_lib/ucc/ucc.h
289a211d534f06211b566ad164238cad3e76e8ca
diff --git a/drivers/sysdev/qe_lib/ucc/Makefile
b/drivers/sysdev/qe_lib/ucc/Makefile
new file mode 100644
index 0000000..85de266
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2004 Freescale Semiconductor, Inc.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = libucc.a
+
+OBJS := ucc.o ucc_fast.o ucc_geth.o ucc_geth_phy.o
+
+CFLAGS += -I..
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $(OBJS)
+
+clean:
+ rm -f $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak .depend *.flc
+
+#######################################################################
##
+
+.depend: Makefile $(OBJS:.o=.c)
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(OBJS:.o=.c) > $@
+
+-include .depend
+#######################################################################
##
diff --git a/drivers/sysdev/qe_lib/ucc/list.h
b/drivers/sysdev/qe_lib/ucc/list.h
new file mode 100644
index 0000000..9217cc6
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/list.h
@@ -0,0 +1,728 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/list.h
+ * General List Operations from Linux Kernel
(linux/include/linux/list.h)
+ *
+ * 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 _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#ifdef __KERNEL__
+
+#include "common.h"
+
+#define barrier() __asm__ __volatile__("": : :"memory")
+#define smp_wmb barrier
+
+/**
+ * container_of - cast a member of a structure out to the containing
structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev, struct list_head
*next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head
*head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct
list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add_rcu(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ new->next = next;
+ new->prev = prev;
+ smp_wmb();
+ next->prev = new;
+ prev->next = new;
+}
+
+/**
+ * list_add_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_rcu(struct list_head *new, struct list_head
*head)
+{
+ __list_add_rcu(new, head, head->next);
+}
+
+/**
+ * list_add_tail_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_tail_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_tail_rcu(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add_rcu(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head *prev, struct list_head
*next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry
is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_rcu - deletes entry from list without re-initialization
+ * @entry: the element to delete from the list.
+ *
+ * Note: list_empty on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_del_rcu()
+ * or list_add_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ *
+ * Note that the caller is not permitted to immediately free
+ * the newly deleted entry. Instead, either synchronize_kernel()
+ * or call_rcu() must be used to defer freeing until an RCU
+ * grace period has elapsed.
+ */
+static inline void list_del_rcu(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->prev = LIST_POISON2;
+}
+
+/*
+ * list_replace_rcu - replace old entry by new one
+ * @old : the element to be replaced
+ * @new : the new element to insert
+ *
+ * The old entry will be replaced with the new entry atomically.
+ */
+static inline void list_replace_rcu(struct list_head *old,
+ struct list_head *new)
+{
+ new->next = old->next;
+ new->prev = old->prev;
+ smp_wmb();
+ new->next->prev = new;
+ new->prev->next = new;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head
*head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list, struct
list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head
*head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+ pos = pos->next)
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
+ pos = pos->prev)
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal
of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member)
\
+ for (pos = list_entry((head)->next, typeof(*pos), member);
\
+ prefetch(pos->member.next), &pos->member != (head);
\
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given
type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member)
\
+ for (pos = list_entry((head)->prev, typeof(*pos), member);
\
+ prefetch(pos->member.prev), &pos->member != (head);
\
+ pos = list_entry(pos->member.prev, typeof(*pos), member))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ * list_for_each_entry_continue
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - iterate over list of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member)
\
+ for (pos = list_entry(pos->member.next, typeof(*pos), member);
\
+ prefetch(pos->member.next), &pos->member != (head);
\
+ pos = list_entry(pos->member.next, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe
against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)
\
+ for (pos = list_entry((head)->next, typeof(*pos), member),
\
+ n = list_entry(pos->member.next, typeof(*pos), member);
\
+ &pos->member != (head);
\
+ pos = n, n = list_entry(n->member.next, typeof(*n),
member))
+
+/**
+ * list_for_each_rcu - iterate over an rcu-protected list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; prefetch(pos->next), pos != (head); \
+ pos = rcu_dereference(pos->next))
+
+#define __list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = rcu_dereference(pos->next))
+
+/**
+ * list_for_each_safe_rcu - iterate over an rcu-protected
list safe
+ * against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_safe_rcu(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = rcu_dereference(n), n = pos->next)
+
+/**
+ * list_for_each_entry_rcu - iterate over rcu list of given
type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_entry_rcu(pos, head, member)
\
+ for (pos = list_entry((head)->next, typeof(*pos), member);
\
+ prefetch(pos->member.next), &pos->member != (head);
\
+ pos = rcu_dereference(list_entry(pos->member.next,
\
+ typeof(*pos), member)))
+
+/**
+ * list_for_each_continue_rcu - iterate over an rcu-protected
list
+ * continuing after existing point.
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_continue_rcu(pos, head) \
+ for ((pos) = (pos)->next; prefetch((pos)->next), (pos) !=
(head); \
+ (pos) = rcu_dereference((pos)->next))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_del_rcu - deletes entry from hash list without
re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: list_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry().
+ */
+static inline void hlist_del_rcu(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (n->pprev) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+static inline void hlist_add_head(struct hlist_node *n, struct
hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+/**
+ * hlist_add_head_rcu - adds the specified element to the specified
hlist,
+ * while permitting racing traversals.
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_rcu(), used to prevent memory-consistency
+ * problems on Alpha CPUs. Regardless of the type of CPU, the
+ * list-traversal primitive must be guarded by rcu_read_lock().
+ */
+static inline void hlist_add_head_rcu(struct hlist_node *n,
+ struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ n->pprev = &h->first;
+ smp_wmb();
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if (next->next)
+ next->next->pprev = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; });
\
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+#define hlist_for_each_rcu(pos, head) \
+ for ((pos) = (head)->first; pos && ({ prefetch((pos)->next); 1;
}); \
+ (pos) = rcu_dereference((pos)->next))
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member)
\
+ for (pos = (head)->first;
\
+ pos && ({ prefetch(pos->next); 1;}) &&
\
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
\
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing
after existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member)
\
+ for (pos = (pos)->next;
\
+ pos && ({ prefetch(pos->next); 1;}) &&
\
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
\
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from
existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member)
\
+ for (; pos && ({ prefetch(pos->next); 1;}) &&
\
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
\
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe
against removal of list entry
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member)
\
+ for (pos = (head)->first;
\
+ pos && ({ n = pos->next; 1; }) &&
\
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
\
+ pos = n)
+
+/**
+ * hlist_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as hlist_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define hlist_for_each_entry_rcu(tpos, pos, head, member)
\
+ for (pos = (head)->first;
\
+ pos && ({ prefetch(pos->next); 1;}) &&
\
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;});
\
+ pos = rcu_dereference(pos->next))
+
+#else
+#warning "don't include kernel headers in userspace"
+#endif /* __KERNEL__ */
+#endif
diff --git a/drivers/sysdev/qe_lib/ucc/ucc.c
b/drivers/sysdev/qe_lib/ucc/ucc.c
new file mode 100644
index 0000000..59b4495
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc.c
@@ -0,0 +1,332 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc.c
+ *
+ * QE UCC API Set - UCC specific routines implementations.
+ *
+ * (C) Copyright 2006 Freescale Semiconductor, Inc
+ * Author: Shlomi Gridish <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 "asm/errno.h"
+#include "immap_qe.h"
+#include "qe.h"
+#include "asm/io.h"
+#include "ucc.h"
+
+int ucc_set_type(int ucc_num, struct ucc_common *regs,
+ enum ucc_speed_type speed)
+{
+ u8 guemr = 0;
+
+ /* check if the UCC number is in range. */
+ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+ return -EINVAL;
+
+ guemr = regs->guemr;
+ guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX);
+ switch (speed) {
+ case UCC_SPEED_TYPE_SLOW:
+ guemr |= (UCC_GUEMR_MODE_SLOW_RX |
UCC_GUEMR_MODE_SLOW_TX);
+ break;
+ case UCC_SPEED_TYPE_FAST:
+ guemr |= (UCC_GUEMR_MODE_FAST_RX |
UCC_GUEMR_MODE_FAST_TX);
+ break;
+ default:
+ return -EINVAL;
+ }
+ regs->guemr = guemr;
+
+ return 0;
+}
+
+int ucc_init_guemr(struct ucc_common *regs)
+{
+ u8 guemr = 0;
+
+ if (!regs)
+ return -EINVAL;
+
+ /* Set bit 3 (which is reserved in the GUEMR register) to 1 */
+ guemr = UCC_GUEMR_SET_RESERVED3;
+
+ regs->guemr = guemr;
+
+ return 0;
+}
+
+static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 *
reg_num,
+ u8 * shift)
+{
+ switch (ucc_num) {
+ case (0):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr1);
+ *reg_num = 1;
+ *shift = 16;
+ break;
+ case (2):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr1);
+ *reg_num = 1;
+ *shift = 0;
+ break;
+ case (4):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr2);
+ *reg_num = 2;
+ *shift = 16;
+ break;
+ case (6):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr2);
+ *reg_num = 2;
+ *shift = 0;
+ break;
+ case (1):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr3);
+ *reg_num = 3;
+ *shift = 16;
+ break;
+ case (3):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr3);
+ *reg_num = 3;
+ *shift = 0;
+ break;
+ case (5):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr4);
+ *reg_num = 4;
+ *shift = 16;
+ break;
+ case (7):
+ *p_cmxucr = &(qe_immr->qmx.cmxucr4);
+ *reg_num = 4;
+ *shift = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask)
+{
+ volatile u32 *p_cmxucr;
+ u8 reg_num;
+ u8 shift;
+
+ /* check if the UCC number is in range. */
+ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+ return -EINVAL;
+
+ get_cmxucr_reg(ucc_num, &p_cmxucr, ®_num, &shift);
+
+ if (set)
+ out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift));
+ else
+ out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask <<
shift));
+
+ return 0;
+}
+
+int ucc_set_qe_mux_rxtx(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("ucc_set_qe_mux_rxtx: bad comm mode type
passed.");
+ return -EINVAL;
+ }
+
+ 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("ucc_set_qe_mux_rxtx: Bad combination of clock
and UCC.");
+ 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;
+}
diff --git a/drivers/sysdev/qe_lib/ucc/ucc.h
b/drivers/sysdev/qe_lib/ucc/ucc.h
new file mode 100644
index 0000000..5d92594
--- /dev/null
+++ b/drivers/sysdev/qe_lib/ucc/ucc.h
@@ -0,0 +1,98 @@
+/*
+ * drivers/sysdev/qe_lib/ucc/ucc.h
+ *
+ * Internal header file for UCC unit routines.
+ *
+ * (C) Copyright 2006 Freescale Semiconductor, Inc
+ * Author: Shlomi Gridish <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 __UCC_H__
+#define __UCC_H__
+
+#include "immap_qe.h"
+#include "qe.h"
+
+#define STATISTICS
+
+#define UCC_MAX_NUM 8
+
+typedef enum _enet_interface_e {
+ 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;
+
+/* Slow or fast type for UCCs.
+*/
+typedef enum ucc_speed_type {
+ UCC_SPEED_TYPE_FAST, UCC_SPEED_TYPE_SLOW
+} ucc_speed_type_e;
+
+/* Initial UCCs Parameter RAM address relative to: MEM_MAP_BASE (IMMR).
+*/
+typedef enum ucc_pram_initial_offset {
+ UCC_PRAM_OFFSET_UCC1 = 0x8400,
+ UCC_PRAM_OFFSET_UCC2 = 0x8500,
+ UCC_PRAM_OFFSET_UCC3 = 0x8600,
+ UCC_PRAM_OFFSET_UCC4 = 0x9000,
+ UCC_PRAM_OFFSET_UCC5 = 0x8000,
+ UCC_PRAM_OFFSET_UCC6 = 0x8100,
+ UCC_PRAM_OFFSET_UCC7 = 0x8200,
+ UCC_PRAM_OFFSET_UCC8 = 0x8300
+} ucc_pram_initial_offset_e;
+
+/* ucc_set_type
+ * Sets UCC to slow or fast mode.
+ *
+ * ucc_num - (In) number of UCC (0-7).
+ * regs - (In) pointer to registers base for the UCC.
+ * speed - (In) slow or fast mode for UCC.
+ */
+int ucc_set_type(int ucc_num, struct ucc_common *regs,
+ enum ucc_speed_type speed);
+
+/* ucc_init_guemr
+ * Init the Guemr register.
+ *
+ * regs - (In) pointer to registers base for the UCC.
+ */
+int ucc_init_guemr(struct ucc_common *regs);
+
+int ucc_set_qe_mux_rxtx(int ucc_num, qe_clock_e clock, comm_dir_e
mode);
+
+int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask);
+
+/* QE MUX clock routing for UCC
+*/
+static inline int ucc_set_qe_mux_grant(int ucc_num, int set)
+{
+ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set,
QE_CMXUCR_GRANT);
+}
+
+static inline int ucc_set_qe_mux_tsa(int ucc_num, int set)
+{
+ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_TSA);
+}
+
+static inline int ucc_set_qe_mux_bkpt(int ucc_num, int set)
+{
+ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_BKPT);
+}
+
+#endif /* __UCC_H__ */
--
1.3.GIT
1
0
Subject: [PATCH] QUICC Engine lib
---
drivers/sysdev/qe_lib/Makefile | 36 ++
drivers/sysdev/qe_lib/board.c | 230 ++++++++++++
drivers/sysdev/qe_lib/mm.c | 728
+++++++++++++++++++++++++++++++++++++
drivers/sysdev/qe_lib/mm.h | 33 ++
drivers/sysdev/qe_lib/qe_common.c | 252 +++++++++++++
5 files changed, 1279 insertions(+), 0 deletions(-)
create mode 100644 drivers/sysdev/qe_lib/Makefile
create mode 100644 drivers/sysdev/qe_lib/board.c
create mode 100644 drivers/sysdev/qe_lib/mm.c
create mode 100644 drivers/sysdev/qe_lib/mm.h
create mode 100644 drivers/sysdev/qe_lib/qe_common.c
3278ada1f08a1f31954537269503ccf845cc3e08
diff --git a/drivers/sysdev/qe_lib/Makefile
b/drivers/sysdev/qe_lib/Makefile
new file mode 100644
index 0000000..d0bf511
--- /dev/null
+++ b/drivers/sysdev/qe_lib/Makefile
@@ -0,0 +1,36 @@
+#
+# 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.
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = libqe.a
+
+OBJS := qe_common.o mm.o board.o
+
+#CFLAGS +=
+
+$(LIB): $(OBJS)
+ $(AR) crv $@ $(OBJS)
+
+clean:
+ rm -f $(OBJS)
+
+distclean: clean
+ rm -f $(LIB) core *.bak .depend *.flc
+
+#######################################################################
##
+
+.depend: Makefile $(OBJS:.o=.c)
+ $(CC) -M $(CPPFLAGS) $(CFLAGS) $(OBJS:.o=.c) > $@
+
+-include .depend
+#######################################################################
##
diff --git a/drivers/sysdev/qe_lib/board.c
b/drivers/sysdev/qe_lib/board.c
new file mode 100644
index 0000000..a9dad32
--- /dev/null
+++ b/drivers/sysdev/qe_lib/board.c
@@ -0,0 +1,230 @@
+/*
+ * drivers/sysdev/qe_lib/board.c
+ * GETH io map function at here for MPC83XX QE
+ *
+ * (C) Copyright 2006 Freescale Semiconductor, Inc
+ * Author: Shlomi Gridih <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 "asm/io.h"
+#include "asm/errno.h"
+
+extern void qe_reset(void);
+
+#define NUM_OF_PINS 32
+#if defined(CONFIG_MPC8360)
+#define NUM_OF_PAR_IOS 7
+#endif
+
+typedef struct par_io {
+ struct {
+ u32 cpodr; /* Open drain register */
+ u32 cpdata; /* Data register */
+ u32 cpdir1; /* Direction register */
+ u32 cpdir2; /* Direction register */
+ u32 cppar1; /* Pin assignment register */
+ u32 cppar2; /* Pin assignment register */
+ } io_regs[NUM_OF_PAR_IOS];
+} par_io_t;
+
+typedef struct qe_par_io {
+ u8 res[0xc];
+ u32 cepier; /* QE ports interrupt event register */
+ u32 cepimr; /* QE ports mask event register */
+ u32 cepicr; /* QE ports control event register */
+} qe_par_io_t;
+
+static int qe_irq_ports[NUM_OF_PAR_IOS][NUM_OF_PINS] = {
+ /* 0-7 */ /* 8-15 */ /* 16 - 23 */ /* 24 -
31 */
+ {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,1, 1,0,0,0,0,0,0,0,
0,0,0,0,0,1,1,0},
+ {0,0,0,1,0,1,0,0, 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0,
0,0,1,1,0,0,0,0},
+ {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,1,1,1,0,0},
+ {0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0, 1,1,0,0,0,0,0,0,
0,0,1,1,0,0,0,0},
+#if defined (CONFIG_MPC8360)
+ {0,0,0,0,0,0,0,0, 0,0,0,0,1,1,0,0, 0,0,0,0,0,0,0,0,
1,1,1,1,0,0,0,1},
+ {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,0,
0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,1}
+#endif
+};
+
+static u8 get_irq_num(u8 port, u8 pin)
+{
+ int i, j;
+ u8 num = 0;
+
+ for (j = 0; j <= port; j++)
+ for (i = 0; i < pin; i++)
+ if (qe_irq_ports[j][i])
+ num++;
+ return num;
+}
+
+static par_io_t *par_io = NULL;
+static qe_par_io_t *qe_par_io = NULL;
+
+static int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
+ int assignment, int has_irq)
+{
+ u32 pinMask1bit, pinMask2bits, newMask2bits, tmp_val;
+
+ if (!par_io) {
+ par_io = (par_io_t *) (CFG_IMMRBAR + 0x1400);
+ qe_par_io = (qe_par_io_t *) (CFG_IMMRBAR + 0xC00);
+
+ /* clear event bits in the event register of the QE
ports */
+ out_be32(&qe_par_io->cepier, 0xFFFFFFFF);
+ }
+
+ /* calculate pin location for single and 2 bits information */
+ pinMask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
+
+ /* Set open drain, if required */
+ tmp_val = in_be32(&par_io->io_regs[port].cpodr);
+ if (open_drain)
+ out_be32(&par_io->io_regs[port].cpodr,
+ pinMask1bit | tmp_val);
+ else
+ out_be32(&par_io->io_regs[port].cpodr,
+ ~pinMask1bit & tmp_val);
+
+ /* define direction */
+ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+ in_be32(&par_io->io_regs[port].cpdir2):
+ in_be32(&par_io->io_regs[port].cpdir1);
+
+ /* get all bits mask for 2 bit per port */
+ pinMask2bits =
+ (u32) (0x3 <<
+ (NUM_OF_PINS - (pin % (NUM_OF_PINS/2) + 1) *
2));
+
+ /* Get the final mask we need for the right definition */
+ newMask2bits =
+ (u32) (dir <<
+ (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->io_regs[port].cpdir2,
+ ~pinMask2bits & tmp_val);
+ out_be32(&par_io->io_regs[port].cpdir2,
+ newMask2bits | tmp_val);
+ } else {
+ out_be32(&par_io->io_regs[port].cpdir1,
+ ~pinMask2bits & tmp_val);
+ out_be32(&par_io->io_regs[port].cpdir1,
+ newMask2bits | tmp_val);
+ }
+ /* define pin assignment */
+ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+ in_be32(&par_io->io_regs[port].cppar2):
+ in_be32(&par_io->io_regs[port].cppar1);
+
+ newMask2bits = (u32) (assignment <<
+ (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->io_regs[port].cppar2,
+ ~pinMask2bits & tmp_val);
+ out_be32(&par_io->io_regs[port].cppar2,
+ newMask2bits | tmp_val);
+ } else {
+ out_be32(&par_io->io_regs[port].cppar1,
+ ~pinMask2bits & tmp_val);
+ out_be32(&par_io->io_regs[port].cppar1,
+ newMask2bits | tmp_val);
+ }
+
+ /* If this pin should not generate interrupt clear event mask
bit */
+ if (has_irq) {
+ int i, j, k = 0;
+ int irq = get_irq_num(port, pin);
+ u32 mask = 0;
+
+ for (j = 0; j < NUM_OF_PAR_IOS; j++)
+ for (i = 0; i < NUM_OF_PINS; i++) {
+ if (qe_irq_ports[j][i]) {
+ if (k == irq) {
+ mask = 0x80000000 >> k;
+ break;
+ }
+ k++;
+ }
+ }
+
+ if (!mask)
+ return -EINVAL;
+
+ tmp_val = in_be32(&qe_par_io->cepimr);
+ out_be32(&qe_par_io->cepimr, ~mask & tmp_val);
+ }
+ return 0;
+}
+
+#if defined (CONFIG_MPC8360EPB)
+void board_init(int rgmii)
+{
+ qe_reset();
+
+ par_io_config_pin(0, 1, 3, 0, 2, 0); /* MDIO */
+ par_io_config_pin(0, 2, 1, 0, 1, 0); /* MDC */
+
+ if (rgmii) {
+ /* There's a bug in initial chip rev(s) in the RGMII ac
timing. */
+ /* The following compensates by writing to the reserved
*/
+ /* QE Port Output Hold Registers (CPOH1?).
*/
+ u32 *tmp_reg = (u32 *) (CFG_IMMRBAR + 0x14A8);
+ u32 tmp_val = in_be32(tmp_reg);
+
+ out_be32(tmp_reg, tmp_val | 0x00003000);
+
+ par_io_config_pin(0, 3, 1, 0, 1, 0); /* TxD0orTxD4 */
+ par_io_config_pin(0, 4, 1, 0, 1, 0); /* TxD1orTxD5 */
+ par_io_config_pin(0, 5, 1, 0, 1, 0); /* TxD2orTxD6 */
+ par_io_config_pin(0, 6, 1, 0, 1, 0); /* TxD2orTxD7 */
+ par_io_config_pin(0, 7, 1, 0, 1, 0); /* TX_ENorTX_ER
*/
+ par_io_config_pin(0, 9, 2, 0, 1, 0); /* RxD0orRxD4 */
+ par_io_config_pin(0, 10, 2, 0, 1, 0); /* RxD1orRxD5 */
+ par_io_config_pin(0, 11, 2, 0, 1, 0); /* RxD2orRxD6 */
+ par_io_config_pin(0, 12, 2, 0, 1, 0); /* RxD3orRxD7 */
+ par_io_config_pin(0, 15, 2, 0, 1, 0); /* RX_DVorRX_ER
*/
+ par_io_config_pin(0, 0, 2, 0, 1, 0); /* RX_CLK */
+ par_io_config_pin(2, 9, 1, 0, 3, 0); /* GTX_CLK -
CLK10 */
+ par_io_config_pin(2, 8, 2, 0, 1, 0); /* GTX125 - CLK9
*/
+ } else {
+ par_io_config_pin(0, 3, 1, 0, 1, 0); /* TxD0 */
+ par_io_config_pin(0, 4, 1, 0, 1, 0); /* TxD1 */
+ par_io_config_pin(0, 5, 1, 0, 1, 0); /* TxD2 */
+ par_io_config_pin(0, 6, 1, 0, 1, 0); /* TxD3 */
+ par_io_config_pin(1, 6, 1, 0, 3, 0); /* TxD4 */
+ par_io_config_pin(1, 7, 1, 0, 1, 0); /* TxD5 */
+ par_io_config_pin(1, 9, 1, 0, 2, 0); /* TxD6 */
+ par_io_config_pin(1, 10, 1, 0, 2, 0); /* TxD7 */
+ par_io_config_pin(0, 9, 2, 0, 1, 0); /* RxD0 */
+ par_io_config_pin(0, 10, 2, 0, 1, 0); /* RxD1 */
+ par_io_config_pin(0, 11, 2, 0, 1, 0); /* RxD2 */
+ par_io_config_pin(0, 12, 2, 0, 1, 0); /* RxD3 */
+ par_io_config_pin(0, 13, 2, 0, 1, 0); /* RxD4 */
+ par_io_config_pin(1, 1, 2, 0, 2, 0); /* RxD5 */
+ par_io_config_pin(1, 0, 2, 0, 2, 0); /* RxD6 */
+ par_io_config_pin(1, 4, 2, 0, 2, 0); /* RxD7 */
+ par_io_config_pin(0, 7, 1, 0, 1, 0); /* TX_EN */
+ par_io_config_pin(0, 8, 1, 0, 1, 0); /* TX_ER */
+ par_io_config_pin(0, 15, 2, 0, 1, 0); /* RX_DV */
+ par_io_config_pin(0, 16, 2, 0, 1, 0); /* RX_ER */
+ par_io_config_pin(0, 0, 2, 0, 1, 0); /* RX_CLK */
+ par_io_config_pin(2, 9, 1, 0, 3, 0); /* GTX_CLK -
CLK10 */
+ par_io_config_pin(2, 8, 2, 0, 1, 0); /* GTX125 - CLK9
*/
+ }
+}
+#else
+#error need ucc io for geth!
+#endif
diff --git a/drivers/sysdev/qe_lib/mm.c b/drivers/sysdev/qe_lib/mm.c
new file mode 100644
index 0000000..aaf3aba
--- /dev/null
+++ b/drivers/sysdev/qe_lib/mm.c
@@ -0,0 +1,728 @@
+/*
+ * drivers/sysdev/qe_lib/mm.c
+ * Memory Manager.
+ *
+ * (C) Copyright 2006 Freescale Semiconductor, Inc
+ * Author: Shlomi Gridish <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 "asm/errno.h"
+#include "linux/string.h"
+#include "malloc.h"
+#include "mm.h"
+
+#define MAX_ALIGNMENT 20
+#define MAX_NAME_LEN 50
+
+#define MAKE_ALIGNED(adr, align) (((u32)adr + (align - 1)) & (~(align -
1)))
+
+/* mem_block_t data stucutre defines parameters of the Memory Block */
+typedef struct mem_block {
+ struct mem_block *next; /* Pointer to the next memory block */
+ u32 base; /* base address of the memory block */
+ u32 end; /* end address of the memory block */
+} mem_block_t;
+
+/* free_block_t data stucutre defines parameters of the Free Block */
+typedef struct free_block {
+ struct free_block *next;/* Pointer to the next free block */
+ u32 base; /* base address of the block */
+ u32 end; /* end address of the block */
+} free_block_t;
+
+/* busy_block_t data stucutre defines parameters of the Busy Block */
+typedef struct busy_block {
+ struct busy_block *next;/* Pointer to the next free block */
+ u32 base; /* base address of the block */
+ u32 end; /* end address of the block */
+ char name[MAX_NAME_LEN];
+} busy_block_t;
+
+/* mm_t data structure defines parameters of the MM object */
+typedef struct mm {
+ mem_block_t *mem_blocks;
+ /* List of memory blocks (Memory list) */
+ busy_block_t *busy_blocks;
+ /* List of busy blocks (Busy list) */
+ free_block_t *free_blocks[MAX_ALIGNMENT + 1];
+ /* align lists of free blocks (Free lists) */
+} mm_t;
+
+/**********************************************************************
+ * MM internal routines set *
+
**********************************************************************/
+
+/****************************************************************
+ * Routine: mem_block_init
+ *
+ * Description:
+ * Initializes a new memory block of "size" bytes and started
+ * from "base" address.
+ *
+ * Arguments:
+ * mem_blk- handle to the mem_blk object
+ * base - base address of the memory block
+ * size - size of the memory block
+ *
+ * Return value:
+ * 0 is returned on success. E_NOMEMORY is returned
+ * if can't allocate memory for mem_blk object.
+ ****************************************************************/
+static int mem_block_init(void **mem_blk, u32 base, u32 size)
+{
+ mem_block_t *p_mem_blk;
+
+ p_mem_blk = (mem_block_t *) malloc(sizeof(mem_block_t));
+ if (!p_mem_blk)
+ return -ENOMEM;
+
+ p_mem_blk->base = base;
+ p_mem_blk->end = base + size;
+ p_mem_blk->next = 0;
+
+ *mem_blk = p_mem_blk;
+
+ return (0);
+}
+
+/****************************************************************
+ * Routine: free_block_init
+ *
+ * Description:
+ * Initializes a new free block of of "size" bytes and
+ * started from "base" address.
+ *
+ * Arguments:
+ * FreeBlock - handle to the FreeBlock object
+ * base - base address of the free block
+ * size - size of the free block
+ *
+ * Return value:
+ * 0 is returned on success. E_NOMEMORY is returned
+ * if can't allocate memory for a free block.
+ ****************************************************************/
+static int free_block_init(void **FreeBlock, u32 base, u32 size)
+{
+ free_block_t *p_free_blk;
+
+ p_free_blk = (free_block_t *) malloc(sizeof(free_block_t));
+ if (!p_free_blk)
+ return -ENOMEM;
+
+ p_free_blk->base = base;
+ p_free_blk->end = base + size;
+ p_free_blk->next = 0;
+
+ *FreeBlock = p_free_blk;
+
+ return (0);
+}
+
+/****************************************************************
+ * Routine: busy_block_init
+ *
+ * Description:
+ * Initializes a new busy block of "size" bytes and started
+ * rom "base" address. Each busy block has a name that
+ * specified the purpose of the memory allocation.
+ *
+ * Arguments:
+ * BusyBlock - handle to the BusyBlock object
+ * base - base address of the busy block
+ * size - size of the busy block
+ * name - name that specified the busy block
+ *
+ * Return value:
+ * 0 is returned on success. E_NOMEMORY is returned
+ * if can't allocate memory for busy block.
+ ****************************************************************/
+static int busy_block_init(void **BusyBlock, u32 base, u32 size, char
*name)
+{
+ busy_block_t *p_busy_blk;
+ int n, NameLen;
+
+ p_busy_blk = (busy_block_t *) malloc(sizeof(busy_block_t));
+ if (!p_busy_blk)
+ return -ENOMEM;
+
+ p_busy_blk->base = base;
+ p_busy_blk->end = base + size;
+ NameLen = (int)strlen(name);
+ n = (NameLen > MAX_NAME_LEN - 1) ? MAX_NAME_LEN - 1 : NameLen;
+ strncpy(p_busy_blk->name, name, (u32) n);
+ p_busy_blk->name[n] = '\0';
+ p_busy_blk->next = 0;
+
+ *BusyBlock = p_busy_blk;
+
+ return (0);
+}
+
+/****************************************************************
+ * Routine: add_free
+ *
+ * Description:
+ * Adds a new free block to the free lists. It updates each
+ * free list to include a new free block.
+ * Note, that all free block in each free list are ordered
+ * by their base address.
+ *
+ * Arguments:
+ * p_mm - pointer to the MM object
+ * base - base address of a given free block
+ * end - end address of a given free block
+ *
+ * Return value:
+ *
+ *
+ ****************************************************************/
+static int add_free(mm_t * p_mm, u32 base, u32 end)
+{
+ free_block_t *p_prev_blk, *p_curr_blk, *p_new_blk;
+ u32 align;
+ int i;
+ u32 align_base;
+
+ /* Updates free lists to include a just released block */
+ for (i = 0; i <= MAX_ALIGNMENT; i++) {
+ p_prev_blk = p_new_blk = 0;
+ p_curr_blk = p_mm->free_blocks[i];
+
+ align = (u32) (0x1 << i);
+ align_base = MAKE_ALIGNED(base, align);
+
+ /* Goes to the next free list if there is no block to
free */
+ if (align_base >= end)
+ continue;
+
+ /* Looks for a free block that should be updated */
+ while (p_curr_blk) {
+ if (align_base <= p_curr_blk->end) {
+ if (end > p_curr_blk->end) {
+ free_block_t *p_NextB;
+ while (p_curr_blk->next
+ && end >
p_curr_blk->next->end) {
+ p_NextB =
p_curr_blk->next;
+ p_curr_blk->next =
+
p_curr_blk->next->next;
+ free(p_NextB);
+ }
+
+ p_NextB = p_curr_blk->next;
+ if (!p_NextB || (p_NextB && end
< p_NextB->base)) {
+ p_curr_blk->end = end;
+ } else {
+ p_curr_blk->end =
p_NextB->end;
+ p_curr_blk->next =
p_NextB->next;
+ free(p_NextB);
+ }
+ } else if (end < p_curr_blk->base
+ && ((end - align_base) >=
align)) {
+ if (free_block_init((void
*)&p_new_blk, align_base,
+ end - align_base) != 0)
+ return -ENOMEM;
+ p_new_blk->next = p_curr_blk;
+ if (p_prev_blk)
+ p_prev_blk->next =
p_new_blk;
+ else
+ p_mm->free_blocks[i] =
p_new_blk;
+ break;
+ }
+
+ if (align_base < p_curr_blk->base
+ && end >= p_curr_blk->base)
+ p_curr_blk->base = align_base;
+
+ /* if size of the free block is less
then alignment
+ * deletes that free block from the free
list.
+ */
+ if ((p_curr_blk->end - p_curr_blk->base)
< align) {
+ if (p_prev_blk)
+ p_prev_blk->next =
p_curr_blk->next;
+ else
+ p_mm->free_blocks[i] =
p_curr_blk->next;
+ free(p_curr_blk);
+ }
+ break;
+ } else {
+ p_prev_blk = p_curr_blk;
+ p_curr_blk = p_curr_blk->next;
+ }
+ }
+
+ /* If no free block found to be updated, insert a new
free block
+ * to the end of the free list.
+ */
+ if (!p_curr_blk && ((end - base) % align == 0)) {
+ if (free_block_init ((void *)&p_new_blk,
+ align_base, end - base) != 0)
+ return -ENOMEM;
+ if (p_prev_blk)
+ p_prev_blk->next = p_new_blk;
+ else
+ p_mm->free_blocks[i] = p_new_blk;
+ }
+
+ /* Update boundaries of the new free block */
+ if (align == 1 && !p_new_blk) {
+ if (p_curr_blk && base > p_curr_blk->base)
+ base = p_curr_blk->base;
+ if (p_curr_blk && end < p_curr_blk->end)
+ end = p_curr_blk->end;
+ }
+ }
+
+ return (0);
+}
+
+/****************************************************************
+ * Routine: cut_free
+ *
+ * Description:
+ * Cuts a free block from hold_base to hold_end from the free
lists.
+ * That is, it updates all free lists of the MM object do
+ * not include a block of memory from hold_base to hold_end.
+ * For each free lists it seek for a free block that holds
+ * either hold_base or hold_end. If such block is found it updates
it.
+ *
+ * Arguments:
+ * p_mm - pointer to the MM object
+ * hold_base - base address of the allocated block
+ * hold_end - end address of the allocated block
+ *
+ * Return value:
+ * 0 is returned on success,
+ * otherwise returns an error code.
+ *
+ ****************************************************************/
+static int cut_free(mm_t * p_mm, u32 hold_base, u32 hold_end)
+{
+ free_block_t *p_prev_blk, *p_curr_blk, *p_new_blk;
+ u32 align_base, base, end, align;
+ int i;
+
+ for (i = 0; i <= MAX_ALIGNMENT; i++) {
+ p_prev_blk = p_new_blk = 0;
+ p_curr_blk = p_mm->free_blocks[i];
+
+ align = (u32) 0x1 << i;
+ align_base = MAKE_ALIGNED(hold_end, align);
+
+ while (p_curr_blk) {
+ base = p_curr_blk->base;
+ end = p_curr_blk->end;
+
+ if (hold_base <= base && hold_end <= end
+ && hold_end > base) {
+ if (align_base >= end
+ || (align_base < end
+ && (end - align_base) < align))
{
+ if (p_prev_blk)
+ p_prev_blk->next =
p_curr_blk->next;
+ else
+ p_mm->free_blocks[i] =
p_curr_blk->next;
+ free(p_curr_blk);
+ } else {
+ p_curr_blk->base = align_base;
+ }
+ break;
+ } else if (hold_base > base && hold_end <= end)
{
+ if ((hold_base - base) >= align) {
+ if (align_base < end
+ && (end - align_base) >=
align) {
+ if (free_block_init
((void *)&p_new_blk,
+ align_base, (end -
align_base)) != 0)
+ return -ENOMEM;
+ p_new_blk->next =
p_curr_blk->next;
+ p_curr_blk->next =
p_new_blk;
+ }
+ p_curr_blk->end = hold_base;
+ } else if (align_base < end
+ && (end - align_base) >=
align) {
+ p_curr_blk->base = align_base;
+ } else {
+ if (p_prev_blk)
+ p_prev_blk->next =
p_curr_blk->next;
+ else
+ p_mm->free_blocks[i] =
p_curr_blk->next;
+ free(p_curr_blk);
+ }
+ break;
+ } else {
+ p_prev_blk = p_curr_blk;
+ p_curr_blk = p_curr_blk->next;
+ }
+ }
+ }
+
+ return (0);
+}
+
+/****************************************************************
+ * Routine: add_busy
+ *
+ * Description:
+ * Adds a new busy block to the list of busy blocks. Note,
+ * that all busy blocks are ordered by their base address in
+ * the busy list.
+ *
+ * Arguments:
+ * MM - handler to the MM object
+ * p_new_busy_blk - pointer to the a busy block
+ *
+ * Return value:
+ * None.
+ *
+ ****************************************************************/
+static void add_busy(mm_t * p_mm, busy_block_t * p_new_busy_blk)
+{
+ busy_block_t *p_cur_busy_blk, *p_prev_busy_blk;
+
+ /* finds a place of a new busy block in the list of busy blocks
*/
+ p_prev_busy_blk = 0;
+ p_cur_busy_blk = p_mm->busy_blocks;
+
+ while (p_cur_busy_blk && p_new_busy_blk->base
+ > p_cur_busy_blk->base) {
+ p_prev_busy_blk = p_cur_busy_blk;
+ p_cur_busy_blk = p_cur_busy_blk->next;
+ }
+
+ /* insert the new busy block into the list of busy blocks */
+ if (p_cur_busy_blk)
+ p_new_busy_blk->next = p_cur_busy_blk;
+ if (p_prev_busy_blk)
+ p_prev_busy_blk->next = p_new_busy_blk;
+ else
+ p_mm->busy_blocks = p_new_busy_blk;
+
+}
+
+/****************************************************************
+ * Routine: get_greater_align
+ *
+ * Description:
+ * Allocates a block of memory according to the given size
+ * and the alignment. That routine is called from the mm_get
+ * routine if the required alignment is grater then MAX_ALIGNMENT.
+ * In that case, it goes over free blocks of 64 byte align list
+ * and checks if it has the required size of bytes of the required
+ * alignment. If no blocks found returns ILLEGAL_BASE.
+ * After the block is found and data is allocated, it calls
+ * the internal cut_free routine to update all free lists
+ * do not include a just allocated block. Of course, each
+ * free list contains a free blocks with the same alignment.
+ * It is also creates a busy block that holds
+ * information about an allocated block.
+ *
+ * Arguments:
+ * MM - handle to the MM object
+ * size - size of the MM
+ * align - index as a power of two defines
+ * a required alignment that is grater then 64.
+ * name - the name that specifies an allocated block.
+ *
+ * Return value:
+ * base address of an allocated block.
+ * ILLEGAL_BASE if can't allocate a block
+ *
+ ****************************************************************/
+static int get_greater_align(void *MM, u32 size, int align, char *name)
+{
+ mm_t *p_mm = (mm_t *) MM;
+ free_block_t *p_free_blk;
+ busy_block_t *p_new_busy_blk;
+ u32 hold_base, hold_end, align_base = 0;
+ u32 ret;
+
+ /* goes over free blocks of the 64 byte alignment list
+ * and look for a block of the suitable size and
+ * base address according to the alignment.
+ */
+ p_free_blk = p_mm->free_blocks[MAX_ALIGNMENT];
+
+ while (p_free_blk) {
+ align_base = MAKE_ALIGNED(p_free_blk->base, align);
+
+ /* the block is found if the aligned base inside the
block
+ * and has the anough size.
+ */
+ if (align_base >= p_free_blk->base &&
+ align_base < p_free_blk->end &&
+ size <= (p_free_blk->end - align_base))
+ break;
+ else
+ p_free_blk = p_free_blk->next;
+ }
+
+ /* If such block isn't found */
+ if (!p_free_blk)
+ return -EBUSY;
+
+ hold_base = align_base;
+ hold_end = align_base + size;
+
+ /* init a new busy block */
+ if ((ret = busy_block_init((void *)&p_new_busy_blk,
+ hold_base, size, name)) != 0)
+ return ret;
+
+ /* calls Update routine to update a lists of free blocks */
+ if ((ret = cut_free(MM, hold_base, hold_end)) != 0)
+ return ret;
+
+ /* insert the new busy block into the list of busy blocks */
+ add_busy(p_mm, p_new_busy_blk);
+
+ return (hold_base);
+}
+
+/**********************************************************************
+ * MM API routines set *
+
**********************************************************************/
+int mm_init(void **MM, u32 base, u32 size)
+{
+ mm_t *p_mm;
+ int i;
+ u32 new_base, new_size;
+
+ /* Initializes a new MM object */
+ p_mm = (mm_t *) malloc(sizeof(mm_t));
+ if (p_mm == 0)
+ return -ENOMEM;
+
+ /* initializes a new memory block */
+ if (mem_block_init((void *)&p_mm->mem_blocks, base, size) != 0)
+ return -ENOMEM;
+
+ /* A busy list is empty */
+ p_mm->busy_blocks = 0;
+
+ /*Initializes a new free block for each free list */
+ for (i = 0; i <= MAX_ALIGNMENT; i++) {
+ new_base = MAKE_ALIGNED(base, (0x1 << i));
+ new_size = size - (new_base - base);
+ if (free_block_init((void *)&p_mm->free_blocks[i],
+ new_base, new_size) != 0)
+ return -ENOMEM;
+ }
+ *MM = p_mm;
+ return (0);
+}
+
+void mm_free(void *MM)
+{
+ mm_t *p_mm = (mm_t *) MM;
+ mem_block_t *p_mem_blk;
+ busy_block_t *p_busy_blk;
+ free_block_t *p_free_blk;
+ void *p_blk;
+ int i;
+
+ if (!p_mm)
+ return;
+
+ /* release memory allocated for busy blocks */
+ p_busy_blk = p_mm->busy_blocks;
+ while (p_busy_blk) {
+ p_blk = p_busy_blk;
+ p_busy_blk = p_busy_blk->next;
+ free(p_blk);
+ }
+
+ /* release memory allocated for free blocks */
+ for (i = 0; i <= MAX_ALIGNMENT; i++) {
+ p_free_blk = p_mm->free_blocks[i];
+ while (p_free_blk) {
+ p_blk = p_free_blk;
+ p_free_blk = p_free_blk->next;
+ free(p_blk);
+ }
+ }
+
+ /* release memory allocated for memory blocks */
+ p_mem_blk = p_mm->mem_blocks;
+ while (p_mem_blk) {
+ p_blk = p_mem_blk;
+ p_mem_blk = p_mem_blk->next;
+ free(p_blk);
+ }
+
+ /* release memory allocated for MM object itself */
+ free(p_mm);
+}
+
+void *mm_get(void *MM, u32 size, int align, char *name)
+{
+ mm_t *p_mm = (mm_t *) MM;
+ free_block_t *p_free_blk;
+ busy_block_t *p_new_busy_blk;
+ u32 hold_base, hold_end;
+ u32 i = 0, j = (u32) align;
+ u32 ret;
+
+ if (!p_mm)
+ return ERR_PTR(-EINVAL);
+
+ /* checks that align value is grater then zero */
+ if (align == 0)
+ return ERR_PTR(-EINVAL);
+
+ /* checks if alignment is a power of two,
+ * if it correct and if the required size
+ * is multiple of the given alignment.
+ */
+ while ((j & 0x1) == 0) {
+ i++;
+ j = j >> 1;
+ }
+
+ /* if the given alignment isn't power of two, returns an error
*/
+ if (j != 1)
+ return ERR_PTR(-EINVAL);
+
+ if (i > MAX_ALIGNMENT)
+ return ERR_PTR(get_greater_align(MM, size, align,
name));
+
+ /* look for a block of the size grater or equal to the
+ * required size.
+ */
+ p_free_blk = p_mm->free_blocks[i];
+ while (p_free_blk && (p_free_blk->end - p_free_blk->base) <
size)
+ p_free_blk = p_free_blk->next;
+
+ /* If such block is found */
+ if (!p_free_blk)
+ return ERR_PTR(-ENOMEM);
+
+ hold_base = p_free_blk->base;
+ hold_end = hold_base + size;
+
+ /* init a new busy block */
+ if ((ret = busy_block_init((void *)&p_new_busy_blk,
+ hold_base, size, name)) != 0)
+ return ERR_PTR(ret);
+
+ /* calls Update routine to update a lists of free blocks */
+ if ((ret = cut_free(MM, hold_base, hold_end)) != 0)
+ return ERR_PTR(ret);
+
+ /* insert the new busy block into the list of busy blocks */
+ add_busy(p_mm, p_new_busy_blk);
+
+ return (void *)(hold_base);
+}
+
+void *mm_get_force(void *MM, u32 base, u32 size, char *name)
+{
+ mm_t *p_mm = (mm_t *) MM;
+ free_block_t *p_free_blk;
+ busy_block_t *p_new_busy_blk;
+ int blk_is_free = 0;
+ u32 ret;
+
+ p_free_blk = p_mm->free_blocks[0]; /* The biggest free blocks
are in the
+ free list with alignment 1 */
+ while (p_free_blk) {
+ if (base >= p_free_blk->base
+ && (base + size) <= p_free_blk->end) {
+ blk_is_free = 1;
+ break;
+ } else
+ p_free_blk = p_free_blk->next;
+ }
+
+ if (!blk_is_free)
+ return ERR_PTR(-ENOMEM);
+
+ /* init a new busy block */
+ if ((ret = busy_block_init((void *)&p_new_busy_blk,
+ base, size, name)) != 0)
+ return ERR_PTR(ret);
+
+ /* calls Update routine to update a lists of free blocks */
+ if ((ret = cut_free(MM, base, base + size)) != 0)
+ return ERR_PTR(ret);
+
+ /* insert the new busy block into the list of busy blocks */
+ add_busy(p_mm, p_new_busy_blk);
+ return (void *)(base);
+}
+
+int mm_put(void *MM, u32 base)
+{
+ mm_t *p_mm = (mm_t *) MM;
+ busy_block_t *p_busy_blk, *p_prev_busy_blk;
+ u32 size;
+ u32 ret;
+
+ if (!p_mm)
+ return -EINVAL;
+
+ /* Look for a busy block that have the given base value.
+ * That block will be returned back to the memory.
+ */
+ p_prev_busy_blk = 0;
+ p_busy_blk = p_mm->busy_blocks;
+ while (p_busy_blk && base != p_busy_blk->base) {
+ p_prev_busy_blk = p_busy_blk;
+ p_busy_blk = p_busy_blk->next;
+ }
+
+ if (!p_busy_blk)
+ return -EINVAL;
+
+ if ((ret = add_free(p_mm, p_busy_blk->base, p_busy_blk->end)) !=
0)
+ return ret;
+
+ /* removes a busy block form the list of busy blocks */
+ if (p_prev_busy_blk)
+ p_prev_busy_blk->next = p_busy_blk->next;
+ else
+ p_mm->busy_blocks = p_busy_blk->next;
+
+ size = p_busy_blk->end - p_busy_blk->base;
+
+ free(p_busy_blk);
+
+ return (0);
+}
+
+void mm_dump(void *MM)
+{
+ mm_t *p_mm = (mm_t *) MM;
+ free_block_t *p_free_blk;
+ busy_block_t *p_busy_blk;
+ int i;
+
+ p_busy_blk = p_mm->busy_blocks;
+ printf("List of busy blocks:\n");
+ while (p_busy_blk) {
+ printf("\t0x%08x: (%s: b=0x%08x, e=0x%08x)\n",
+ (u32) p_busy_blk, p_busy_blk->name,
+ p_busy_blk->base, p_busy_blk->end);
+ p_busy_blk = p_busy_blk->next;
+ }
+
+ printf("\nLists of free blocks according to alignment:\n");
+ for (i = 0; i <= MAX_ALIGNMENT; i++) {
+ printf("%d alignment:\n", (0x1 << i));
+ p_free_blk = p_mm->free_blocks[i];
+ while (p_free_blk) {
+ printf("\t0x%08x: (b=0x%08x, e=0x%08x)\n",
+ (u32) p_free_blk, p_free_blk->base,
+ p_free_blk->end);
+ p_free_blk = p_free_blk->next;
+ }
+ printf("\n");
+ }
+}
diff --git a/drivers/sysdev/qe_lib/mm.h b/drivers/sysdev/qe_lib/mm.h
new file mode 100644
index 0000000..0dca3a0
--- /dev/null
+++ b/drivers/sysdev/qe_lib/mm.h
@@ -0,0 +1,33 @@
+/*
+ * drivers/sysdev/qe_lib/mm.h
+ * MURAM operation.
+ *
+ * Copyright (C) 2006 Freescale Semiconductor, Inc
+ *
+ * Author: Shlomi Gridish <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 __MM_H__
+#define __MM_H__
+
+int mm_init(void **MM, u32 base, u32 size);
+void mm_free(void *MM);
+void *mm_get(void *MM, u32 size, int align, char *name);
+void *mm_get_force(void *MM, u32 base, u32 size, char *name);
+int mm_put(void *MM, u32 base);
+void mm_dump(void *MM);
+
+static inline void *ERR_PTR(long error)
+{
+ return (void *)error;
+}
+
+#endif /* __MM_H__ */
diff --git a/drivers/sysdev/qe_lib/qe_common.c
b/drivers/sysdev/qe_lib/qe_common.c
new file mode 100644
index 0000000..94abe24
--- /dev/null
+++ b/drivers/sysdev/qe_lib/qe_common.c
@@ -0,0 +1,252 @@
+/*
+ * drivers/sysdev/qe_lib/qe_common.c
+ *
+ * General Purpose functions for the global management of the
+ * QUICC Engine (QE).
+ *
+ * (C) Copyright 2006 Freescale Semiconductor, Inc
+ * Author: Shlomi Gridish <gridish(a)freescale.com>
+ *
+ * History:
+ * 20060601 tanya jiang (tanya.jiang(a)freescale.com)
+ * Code style fixed; move from cpu/mpc83xx to drivers/sysdev
+ *
+ * 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 "asm/errno.h"
+#include "asm/io.h"
+
+#include "immap_qe.h"
+#include "qe.h"
+#include "mm.h"
+#include "qe_common.h"
+
+#define QE_MAP_SIZE (0x100000) /* 1MB */
+
+/* QE snum state
+*/
+typedef enum qe_snum_state {
+ QE_SNUM_STATE_USED, /* used */
+ QE_SNUM_STATE_FREE /* free */
+} qe_snum_state_e;
+
+/* QE snum
+*/
+typedef struct qe_snum {
+ u8 num; /* snum */
+ qe_snum_state_e state; /* state */
+} qe_snum_t;
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+qe_map_t *qe_immr;
+static qe_snum_t snums[QE_NUM_OF_SNUM]; /* Dynamically allocated
SNUMs */
+
+static void qe_snums_init(void);
+static void qe_muram_init(void);
+
+void qe_reset(void)
+{
+ qe_immr = (qe_map_t *) (CFG_IMMRBAR + 0x00100000);
+
+ qe_snums_init();
+
+ qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
+ (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ /* Reclaim the MURAM memory for our use. */
+ qe_muram_init();
+
+ qe_muram_alloc(sizeof(qe_timer_tables_t), 1);
+}
+
+int qe_issue_cmd(uint cmd, uint device, u8 TypeId, u32 cmd_input)
+{
+ u32 cecr;
+ u8 shift;
+
+ if (cmd == QE_RESET) {
+ out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
+ } else {
+ if (device == QE_CR_SUBBLOCK_USB)
+ shift = 4;
+ else
+ shift = 6;
+ out_be32(&qe_immr->cp.cecdr, cmd_input);
+ out_be32(&qe_immr->cp.cecr,
+ (cmd | QE_CR_FLG | device | (u32) TypeId <<
shift));
+ }
+
+ /* wait for the QE_CR_FLG to clear */
+ do {
+ cecr = in_be32(&qe_immr->cp.cecr);
+ } while (cecr & QE_CR_FLG);
+
+ return 0;
+}
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * 16 BRGs, which can be connected to the QE channels or output
+ * as clocks. The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers). Documentation uses 1-based numbering.
+ */
+#define BRG_CLK (gd->bd->bi_brgfreq)
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void qe_setbrg(uint brg, uint rate)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ volatile uint *bp;
+ u32 divisor;
+ int div16 = 0;
+
+ 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;
+ if (div16)
+ *bp |= QE_BRGC_DIV16;
+}
+
+static void qe_snums_init(void)
+{
+ int i;
+
+ /* Initialize the SNUMs array. */
+ for (i = 0; i < QE_NUM_OF_SNUM; i++)
+ snums[i].state = QE_SNUM_STATE_FREE;
+
+ /* Initialize SNUMs (thread serial numbers)
+ * according to QE spec chapter 4, SNUM table
+ */
+ i = 0;
+ snums[i++].num = 0x04;
+ snums[i++].num = 0x05;
+ snums[i++].num = 0x0C;
+ snums[i++].num = 0x0D;
+ snums[i++].num = 0x14;
+ snums[i++].num = 0x15;
+ snums[i++].num = 0x1C;
+ snums[i++].num = 0x1D;
+ snums[i++].num = 0x24;
+ snums[i++].num = 0x25;
+ snums[i++].num = 0x2C;
+ snums[i++].num = 0x2D;
+ snums[i++].num = 0x34;
+ snums[i++].num = 0x35;
+ snums[i++].num = 0x88;
+ snums[i++].num = 0x89;
+ snums[i++].num = 0x98;
+ snums[i++].num = 0x99;
+ snums[i++].num = 0xA8;
+ snums[i++].num = 0xA9;
+ snums[i++].num = 0xB8;
+ snums[i++].num = 0xB9;
+ snums[i++].num = 0xC8;
+ snums[i++].num = 0xC9;
+ snums[i++].num = 0xD8;
+ snums[i++].num = 0xD9;
+ snums[i++].num = 0xE8;
+ snums[i++].num = 0xE9;
+}
+
+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;
+ }
+ }
+}
+
+/*
+ * muram_alloc / muram_free bits.
+ */
+static void *mm = NULL;
+
+static void qe_muram_init(void)
+{
+ mm_init(&mm, (u32) qe_muram_addr(QE_MURAM_DATAONLY_BASE),
+ QE_MURAM_DATAONLY_SIZE);
+}
+
+/* This function returns an index into the MURAM area.
+ */
+uint qe_muram_alloc(uint size, uint align)
+{
+ void *start;
+
+ start = mm_get(mm, (u32) size, (int)align, "QE");
+ if (!IS_MURAM_ERR((u32) start))
+ start = (void *)((u32) start - (u32) qe_immr->muram);
+
+ return (uint) start;
+}
+
+int qe_muram_free(uint offset)
+{
+ int ret;
+
+ ret = mm_put(mm, (u32) qe_muram_addr(offset));
+
+ return ret;
+}
+
+/* not sure if this is ever needed */
+uint qe_muram_alloc_fixed(uint offset, uint size, uint align)
+{
+ void *start;
+
+ start = mm_get_force(mm, (u32) offset, (u32) size, "QE");
+ if (!IS_MURAM_ERR((u32) start))
+ start = (void *)((u32) start - (u32) qe_immr->muram);
+
+ return (uint) start;
+}
+
+void qe_muram_dump(void)
+{
+ mm_dump(mm);
+}
+
+void *qe_muram_addr(uint offset)
+{
+ return (void *)&qe_immr->muram[offset];
+}
--
1.3.GIT
1
0