[Armadeus-commitlog] SF.net SVN: armadeus:[1083] trunk/buildroot/target/u-boot
Brought to you by:
sszy
|
From: <ar...@us...> - 2009-02-23 15:47:13
|
Revision: 1083
http://armadeus.svn.sourceforge.net/armadeus/?rev=1083&view=rev
Author: artemys
Date: 2009-02-23 15:47:08 +0000 (Mon, 23 Feb 2009)
Log Message:
-----------
[U-BOOT] Add missing APF27 patches
Added Paths:
-----------
trunk/buildroot/target/u-boot/u-boot-1.3.4-140-ds1374.patch
trunk/buildroot/target/u-boot/u-boot-1.3.4-300-imx27.patch
trunk/buildroot/target/u-boot/u-boot-1.3.4-301-nand.patch
trunk/buildroot/target/u-boot/u-boot-1.3.4-310-apf27.patch
Added: trunk/buildroot/target/u-boot/u-boot-1.3.4-140-ds1374.patch
===================================================================
--- trunk/buildroot/target/u-boot/u-boot-1.3.4-140-ds1374.patch (rev 0)
+++ trunk/buildroot/target/u-boot/u-boot-1.3.4-140-ds1374.patch 2009-02-23 15:47:08 UTC (rev 1083)
@@ -0,0 +1,68 @@
+--- ref/u-boot-1.3.4/drivers/rtc/ds1374.c 2008-08-12 16:08:38.000000000 +0200
++++ u-boot-1.3.4/drivers/rtc/ds1374.c 2008-12-17 01:16:05.000000000 +0100
+@@ -113,6 +113,11 @@ int rtc_get (struct rtc_time *tm){
+ unsigned int limit;
+ unsigned char tmp;
+ unsigned int i;
++ int old_bus;
++
++ /* switch to correct I2C bus */
++ old_bus = I2C_GET_BUS();
++ I2C_SET_BUS(CFG_RTC_BUS_NUM);
+
+ /*
+ * Since the reads are being performed one byte at a time,
+@@ -154,6 +159,9 @@ int rtc_get (struct rtc_time *tm){
+ tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
++ /* switch back to original I2C bus */
++ I2C_SET_BUS(old_bus);
++
+ return rel;
+ }
+
+@@ -164,6 +172,11 @@ void rtc_set (struct rtc_time *tmp){
+
+ unsigned long time;
+ unsigned i;
++ int old_bus;
++
++ /* switch to correct I2C bus */
++ old_bus = I2C_GET_BUS();
++ I2C_SET_BUS(CFG_RTC_BUS_NUM);
+
+ DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
+ tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
+@@ -186,6 +199,9 @@ void rtc_set (struct rtc_time *tmp){
+
+ /* Start clock */
+ rtc_write(RTC_CTL_ADDR, RTC_CTL_BIT_EN_OSC, FALSE);
++
++ /* switch back to original I2C bus */
++ I2C_SET_BUS(old_bus);
+ }
+
+ /*
+@@ -198,6 +214,11 @@ void rtc_set (struct rtc_time *tmp){
+ void rtc_reset (void){
+
+ struct rtc_time tmp;
++ int old_bus;
++
++ /* switch to correct I2C bus */
++ old_bus = I2C_GET_BUS();
++ I2C_SET_BUS(CFG_RTC_BUS_NUM);
+
+ /* clear status flags */
+ rtc_write (RTC_SR_ADDR, (RTC_SR_BIT_AF|RTC_SR_BIT_OSF), FALSE); /* clearing OSF and AF */
+@@ -230,6 +251,9 @@ void rtc_reset (void){
+ rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR,0xAC, TRUE);
+ rtc_write(RTC_WD_ALM_CNT_BYTE1_ADDR,0xDE, TRUE);
+ rtc_write(RTC_WD_ALM_CNT_BYTE2_ADDR,0xAD, TRUE);
++
++ /* switch back to original I2C bus */
++ I2C_SET_BUS(old_bus);
+ }
+
+ /*
Added: trunk/buildroot/target/u-boot/u-boot-1.3.4-300-imx27.patch
===================================================================
--- trunk/buildroot/target/u-boot/u-boot-1.3.4-300-imx27.patch (rev 0)
+++ trunk/buildroot/target/u-boot/u-boot-1.3.4-300-imx27.patch 2009-02-23 15:47:08 UTC (rev 1083)
@@ -0,0 +1,4796 @@
+--- ref/u-boot-1.3.4/cpu/arm926ejs/config.mk 2008-08-12 16:08:38.000000000 +0200
++++ u-boot-1.3.4/cpu/arm926ejs/config.mk 2008-12-29 16:27:49.000000000 +0100
+@@ -24,7 +24,7 @@
+ PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \
+ -msoft-float
+
+-PLATFORM_CPPFLAGS += -march=armv4
++PLATFORM_CPPFLAGS += -march=armv5te
+ # =========================================================================
+ #
+ # Supply options according to compiler version
+--- ref/u-boot-1.3.4/cpu/arm926ejs/imx27/cmd_imxfuse.c 1970-01-01 01:00:00.000000000 +0100
++++ u-boot-1.3.4/cpu/arm926ejs/imx27/cmd_imxfuse.c 2009-01-07 18:20:21.000000000 +0100
+@@ -0,0 +1,328 @@
++/*
++ * cmd_imxfuse-c Interface to iMX IC Identification Module
++ * Based on Freescale iMX27 Board Support Package
++ *
++ * (C) Copyright 2008,2009 Eric Jarrige <eri...@ar...>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <config.h>
++#include <common.h>
++#include <command.h>
++
++#ifdef CONFIG_CMD_IMX_FUSE
++
++#include <asm/arch/imx-regs.h>
++#include <asm/io.h>
++
++#define IIM_ERR_SHIFT 8
++#define POLL_FUSE_PRGD (IIM_STAT_PRGD | (IIM_ERR_PRGE << IIM_ERR_SHIFT))
++#define POLL_FUSE_SNSD (IIM_STAT_SNSD | (IIM_ERR_SNSE << IIM_ERR_SHIFT))
++
++static void imx_fuse_op_start(void)
++{
++ /* Do not generate interrupt */
++ writel(0x00, &IIM_STATM);
++ // clear the status bits and error bits
++ writel(0x03, &IIM_STAT);
++ writel(0xFE, &IIM_ERR);
++}
++
++/*
++ * The action should be either:
++ * POLL_FUSE_PRGD
++ * or:
++ * POLL_FUSE_SNSD
++ */
++static int imx_poll_fuse_op_done(int action)
++{
++
++ u32 status, error;
++
++ if (action != POLL_FUSE_PRGD && action != POLL_FUSE_SNSD) {
++ printf("%s(%d) invalid operation\n", __FUNCTION__, action);
++ return -1;
++ }
++
++ /* Poll busy bit till it is NOT set */
++ while ((readl(&IIM_STAT) & IIM_STAT_BUSY) != 0 ) {
++ }
++
++ /* Test for successful write */
++ status = readl(&IIM_STAT);
++ error = readl(&IIM_ERR);
++
++ if ((status & action) != 0 && (error & (action >> IIM_ERR_SHIFT)) == 0) {
++ if (error) {
++ printf("Even though the operation seems successful...\n");
++ printf("There are some error(s) at addr=0x%x: 0x%x\n",
++ readl(&IIM_ERR), error);
++ }
++ return 0;
++ }
++ printf("%s(0x%x) failed\n", __FUNCTION__, action);
++ printf("status address=0x%x, value=0x%x\n",
++ readl(&IIM_STAT), status);
++ printf("There are some error(s) at addr=0x%x: 0x%x\n",
++ readl(&IIM_ERR), error);
++ return -1;
++}
++
++static int imx_read_shadow_fuse(int bank, int row, int bit)
++{
++ printf("Shadow fuses at (bank:%d, row:%d) = 0x%x\n",
++ bank, row, readl(&IIM_BANK_REG(bank,row)));
++ return 0;
++}
++
++static int imx_sense_fuse(int bank, int row, int bit)
++{
++ int addr, addr_l, addr_h;
++
++ imx_fuse_op_start();
++
++ /* Enable IIM Program Protect */
++ writel(0x0, &IIM_PROG_P);
++
++ addr = ((bank << 11) | (row << 3) | (bit & 0x7));
++ /* Set IIM Program Upper Address */
++ addr_h = (addr >> 8) & 0x000000FF;
++ /* Set IIM Program Lower Address */
++ addr_l = (addr & 0x000000FF);
++
++#ifdef IIM_FUSE_DEBUG
++ printf("%s: addr_h=0x%x, addr_l=0x%x\n",
++ __FUNCTION__, addr_h, addr_l);
++#endif
++ writel(addr_h, &IIM_UA);
++ writel(addr_l, &IIM_LA);
++
++ /* Start sensing */
++ writel(0x08, &IIM_FCTL);
++ if (imx_poll_fuse_op_done(POLL_FUSE_SNSD) != 0) {
++ printf("%s(bank: %d, row: %d, bit: %d failed\n",
++ __FUNCTION__, bank, row, bit);
++ }
++
++ printf("fuses at (bank:%d, row:%d) = 0x%x\n",
++ bank, row, readl(&IIM_SDAT));
++ return 0;
++}
++
++/* Blow fuses based on the bank, row and bit positions (all 0-based)
++*/
++static int imx_fuse_blow(int bank,int row,int bit)
++{
++ int addr, addr_l, addr_h, ret = 1;
++
++ imx_fuse_op_start();
++
++ /* Disable IIM Program Protect */
++ writel(0xAA, &IIM_PROG_P);
++
++ addr = ((bank << 11) | (row << 3) | (bit & 0x7));
++ /* Set IIM Program Upper Address */
++ addr_h = (addr >> 8) & 0x000000FF;
++ /* Set IIM Program Lower Address */
++ addr_l = (addr & 0x000000FF);
++
++#ifdef IIM_FUSE_DEBUG
++ printf("blowing addr_h=0x%x, addr_l=0x%x\n", addr_h, addr_l);
++#endif
++
++ writel(addr_h, &IIM_UA);
++ writel(addr_l, &IIM_LA);
++ /* Start Programming */
++ writel(0x31, &IIM_FCTL);
++ if (imx_poll_fuse_op_done(POLL_FUSE_PRGD) == 0) {
++ ret = 0;
++ }
++
++ /* Enable IIM Program Protect */
++ writel(0x0, &IIM_PROG_P);
++ return ret;
++}
++
++/* Blow byte fuses based on the bank and row positions (all 0-based)
++*/
++static int imx_fuse_blow_byte(int bank,int row,unsigned char value)
++{
++ int i, ret = 0;
++
++ for (i = 0; i < 8; i++) {
++ if (((value >> i) & 0x1) == 0) {
++ continue;
++ }
++ ret |= imx_fuse_blow(bank, row, i);
++ }
++
++ return ret;
++}
++
++static int imx_mac_read(unsigned char pmac[6])
++{
++ int i;
++ int uninitialized = 0;
++
++ for (i=0;i<6;i++) {
++ pmac[6-1-i] = readl(&IIM_BANK_REG(0,(IIM0_MAC+i)));
++ }
++
++ /* uninitialized if all 00 */
++ if ((pmac[0] == 0) && (pmac[1] == 0) && (pmac[2] == 0) &&
++ (pmac[3] == 0) && (pmac[4] == 0) && (pmac[5] == 0))
++ uninitialized = 1;
++
++ /* uninitialized if all FF (could be safe) */
++ if ((pmac[0] == 0xff) && (pmac[1] == 0xff) && (pmac[2] == 0xff) &&
++ (pmac[3] == 0xff) && (pmac[4] == 0xff) && (pmac[5] == 0xff))
++ uninitialized = 1;
++
++ return uninitialized;
++}
++
++static int imx_mac_blow(unsigned char pmac[6])
++{
++ int i, ret = 1;
++ unsigned char mac[6];
++ int uninitialized = 0;
++
++ uninitialized = imx_mac_read(mac);
++
++ if (uninitialized) {
++ ret = 0;
++ for(i=0;i<6;i++) {
++ ret |= imx_fuse_blow_byte(0, (IIM0_MAC+i), pmac[6 - 1 -i]);
++ }
++ }
++
++ return ret;
++}
++
++
++int do_imx_fuse(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
++{
++ uint32_t bank, row, value, i;
++ int ret = 1;
++
++ if (argc < 2) {
++ printf("It is too dangeous for you to use this command.\n");
++ printf("Usage:\n%s\n", cmdtp->usage);
++ return ret;
++ }
++
++ if ((!strcmp(argv[1], "sense"))&&((argc == 4))) {
++ bank = simple_strtoul(argv[2], NULL, 16);
++ row = simple_strtoul(argv[3], NULL, 16);
++
++ printf("Sense read fuse at bank:%d row:%d\n", bank, row);
++ ret = imx_sense_fuse(bank, row, 0);
++ }else if ((!strcmp(argv[1], "read"))&&((argc == 4))) {
++ bank = simple_strtoul(argv[2], NULL, 16);
++ row = simple_strtoul(argv[3], NULL, 16);
++
++ printf("Shadow read fuse at bank:%d row:%d\n", bank, row);
++ ret = imx_read_shadow_fuse(bank, row, 0);
++ }else if ((!strcmp(argv[1], "blow"))&&(argc == 5)) {
++ bank = simple_strtoul(argv[2], NULL, 16);
++ row = simple_strtoul(argv[3], NULL, 16);
++ value = simple_strtoul(argv[4], NULL, 16);
++
++ printf("Blowing fuse at bank:%d row:%d value:%d\n",
++ bank, row, value);
++ for (i = 0; i < 8; i++) {
++ if (((value >> i) & 0x1) == 0) {
++ continue;
++ }
++ if (imx_fuse_blow(bank, row, i) != 0) {
++ printf("fuse_blow(bank: %d, row: %d, bit:"
++ " %d failed\n", bank, row, i);
++ } else {
++ printf("fuse_blow(bank: %d, row: %d, bit:"
++ " %d successful\n", bank, row, i);
++ ret = 0;
++ }
++ }
++
++ /* read back fuse by shadow register if applicable */
++ ret |= imx_read_shadow_fuse(bank, row, 0);
++
++ }else if ((!strcmp(argv[1], "mac"))&&(argc == 2)) {
++ unsigned char mac[6];
++ ret = imx_mac_read(mac);
++
++ printf("%siMX mac_addr in fuse: %02X:%02X:%02X:%02X:%02X:%02X\n",
++ ret?"No ":"",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ }else if ((!strcmp(argv[1], "mac"))&&(argc == 3)) {
++ unsigned char mac[6];
++ char *tmp, *end;
++
++ tmp = argv[2];
++ /* convert MAC from string to int */
++ for (i=0; i<6; i++) {
++ mac[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
++ if (tmp)
++ tmp = (*end) ? end+1 : end;
++ }
++
++ ret = imx_mac_blow(mac);
++ if (ret) {
++ printf("Failed to blow mac_addr in fuse: "
++ "%02X:%02X:%02X:%02X:%02X:%02X\n",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ } else {
++ imx_mac_read(mac);
++ printf("Mac_addr blowed in fuse: "
++ "%02X:%02X:%02X:%02X:%02X:%02X\n",
++ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++ }
++ }else if ((!strcmp(argv[1], "suid"))&&(argc == 2)) {
++
++ printf("iMX SUID: ");
++ for (i=0;i<6;i++) {
++ printf("%02x", readl(&IIM_BANK_REG(1,(IIM1_SUID+i))));
++ }
++ printf("\n");
++ ret = 0;
++ }else if ((!strcmp(argv[1], "scc_key"))&&(argc == 2)) {
++
++ printf("iMX SCC_KEY: ");
++ for (i=0;i<21;i++) {
++ printf("%02x", readl(&IIM_BANK_REG(0,(IIM0_SCC_KEY+i))));
++ }
++ printf("\n");
++ ret = 0;
++ } else { printf("arc:%d\n", argc);
++ printf("Usage:\n%s\n", cmdtp->usage);
++ return 1;
++ }
++
++ return ret;
++}
++
++U_BOOT_CMD(imxfuse, 5, 0, do_imx_fuse,
++ "imxfuse - Read/Blow some iMX fuses\n",\
++ "sense <bank> <row> - sense read iMX fuses at <bank>/<row>\n" \
++ "imxfuse read <bank> <row> - shadow read iMX fuses at <bank>/<row>\n" \
++ "imxfuse blow <bank> <row> <value> - blow <value> at <bank>/<row>\n"\
++ " - Read/Blow 8 bits <Value> for some iMX fuses at <bank>/<row>\n"\
++ "imxfuse mac [<mac_addr>] - read/blow <mac_addr> in iMX fuses\n"\
++ "imxfuse suid - read iMX SUID\n"\
++ "imxfuse scc_key - read iMX SCC_KEY\n");
++
++#endif /* CONFIG_CMD_IMX_FUSE */
+--- ref/u-boot-1.3.4/cpu/arm926ejs/imx27/fec_imx27.c 1970-01-01 01:00:00.000000000 +0100
++++ u-boot-1.3.4/cpu/arm926ejs/imx27/fec_imx27.c 2009-01-07 18:20:45.000000000 +0100
+@@ -0,0 +1,797 @@
++/*
++ * (C) Copyright 2008,2009 Eric Jarrige <eri...@ar...>
++ * (C) Copyright 2008 Armadeus Systems nc
++ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s....@pe...>
++ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.b...@pe...>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++/************************** TODO eth_register + cleanup gfec !! *****/
++
++
++#include <common.h>
++#include <malloc.h>
++#include <net.h>
++#include "miiphy.h"
++#include "fec_imx27.h"
++
++#include <asm/arch/clock.h>
++#include <asm/arch/imx-regs.h>
++#include <asm/io.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++#ifdef CONFIG_DRIVER_FEC_IMX27
++
++#if !(defined(CONFIG_MII) || defined(CONFIG_CMD_MII))
++#error "CONFIG_MII has to be defined!"
++#endif
++
++//#undef CONFIG_FEC_IMX27_DEBUG
++#ifdef CONFIG_FEC_IMX27_DEBUG
++#define PRINTF(fmt,args...) printf (fmt ,##args)
++#else
++#define PRINTF(fmt,args...)
++#endif
++
++static int fec_miiphy_read(struct miiphy_device *mdev, uint8_t phyAddr,
++ uint8_t regAddr, uint16_t * retVal);
++static int fec_miiphy_write(struct miiphy_device *mdev, uint8_t phyAddr,
++ uint8_t regAddr, uint16_t data);
++
++typedef struct {
++ uint8_t data[1500]; /**< actual data */
++ int length; /**< actual length */
++ int used; /**< buffer in use or not */
++ uint8_t head[16]; /**< MAC header(6 + 6 + 2) + 2(aligned) */
++} NBUF;
++
++fec_priv gfec=
++{
++ .eth = (ethernet_regs *)IMX_FEC_BASE,
++ .xcv_type = MII100,
++ .rbd_base = NULL,
++ .rbd_index = 0,
++ .tbd_base = NULL,
++ .tbd_index = 0,
++ .miiphy =
++ {
++ CONFIG_PHY_ADDR,
++ fec_miiphy_read,
++ fec_miiphy_write,
++ 0,
++ NULL
++ },
++ .bd = NULL,
++};
++
++/*
++ * MII-interface related functions
++ */
++static int fec_miiphy_read(struct miiphy_device *mdev, uint8_t phyAddr,
++ uint8_t regAddr, uint16_t * retVal)
++{
++ struct eth_device *edev = mdev->edev;
++ fec_priv *fec = (fec_priv *)edev->priv;
++
++ uint32_t reg; /* convenient holder for the PHY register */
++ uint32_t phy; /* convenient holder for the PHY */
++ uint32_t start;
++
++ /*
++ * reading from any PHY's register is done by properly
++ * programming the FEC's MII data register.
++ */
++ writel(FEC_IEVENT_MII, &fec->eth->ievent);
++ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
++ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
++
++ writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA | phy | reg, &fec->eth->mii_data);
++
++ /*
++ * wait for the related interrupt
++ */
++ start = get_timer_masked(); /* get_time_ns(); */
++ while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
++ if (get_timer (start) > (CFG_HZ /1000) /* is_timeout(start, MSECOND)*/) {
++ printf("Read MDIO failed...\n");
++ return -1;
++ }
++ }
++
++ /*
++ * clear mii interrupt bit
++ */
++ writel(FEC_IEVENT_MII, &fec->eth->ievent);
++
++ /*
++ * it's now safe to read the PHY's register
++ */
++ *retVal = readl(&fec->eth->mii_data);
++ PRINTF("fec_miiphy_read: phy: %02x reg:%02x val:%#x\n", phyAddr, regAddr, *retVal);
++ return 0;
++}
++
++static int fec_miiphy_write(struct miiphy_device *mdev, uint8_t phyAddr,
++ uint8_t regAddr, uint16_t data)
++{
++ struct eth_device *edev = mdev->edev;
++ fec_priv *fec = (fec_priv *)edev->priv;
++
++ uint32_t reg; /* convenient holder for the PHY register */
++ uint32_t phy; /* convenient holder for the PHY */
++ uint32_t start;
++
++ reg = regAddr << FEC_MII_DATA_RA_SHIFT;
++ phy = phyAddr << FEC_MII_DATA_PA_SHIFT;
++
++ writel(FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR |
++ FEC_MII_DATA_TA | phy | reg | data, &fec->eth->mii_data);
++
++ /*
++ * wait for the MII interrupt
++ */
++ start = get_timer_masked(); /* get_time_ns(); */
++ while (!(readl(&fec->eth->ievent) & FEC_IEVENT_MII)) {
++ if (get_timer (start) > (CFG_HZ /1000) /* is_timeout(start, MSECOND)*/) {
++ printf("Write MDIO failed...\n");
++ return -1;
++ }
++ }
++
++ /*
++ * clear MII interrupt bit
++ */
++ writel(FEC_IEVENT_MII, &fec->eth->ievent);
++ PRINTF("fec_miiphy_write: phy: %02x reg:%02x val:%#x\n", phyAddr, regAddr, data);
++
++ return 0;
++}
++
++static int fec_rx_task_enable(fec_priv *fec)
++{
++ writel(1 << 24, &fec->eth->r_des_active);
++ return 0;
++}
++
++static int fec_rx_task_disable(fec_priv *fec)
++{
++ return 0;
++}
++
++static int fec_tx_task_enable(fec_priv *fec)
++{
++ writel(1 << 24, &fec->eth->x_des_active);
++ return 0;
++}
++
++static int fec_tx_task_disable(fec_priv *fec)
++{
++ return 0;
++}
++
++/**
++ * Initialize receive task's buffer descriptors
++ * @param[in] fec all we know about the device yet
++ * @param[in] count receive buffer count to be allocated
++ * @param[in] size size of each receive buffer
++ * @return 0 on success
++ *
++ * For this task we need additional memory for the data buffers. And each
++ * data buffer requires some alignment. Thy must be aligned to a specific
++ * boundary each (DB_DATA_ALIGNMENT).
++ */
++static int fec_rbd_init(fec_priv *fec, int count, int size, int once)
++{
++ int ix;
++ uint32_t p=0;
++
++ if (!once) {
++ /* reserve data memory and consider alignment */
++ p = (uint32_t)malloc(size * count + DB_DATA_ALIGNMENT);
++ memset((void *)p, 0, size * count + DB_DATA_ALIGNMENT);
++ p += DB_DATA_ALIGNMENT-1;
++ p &= ~(DB_DATA_ALIGNMENT-1);
++ }
++
++ for (ix = 0; ix < count; ix++) {
++ if (!once) {
++ writel(p, &fec->rbd_base[ix].data_pointer);
++ p += size;
++ }
++ writew(FEC_RBD_EMPTY, &fec->rbd_base[ix].status);
++ writew(0, &fec->rbd_base[ix].data_length);
++ }
++ /*
++ * mark the last RBD to close the ring
++ */
++ writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &fec->rbd_base[ix - 1].status);
++ fec->rbd_index = 0;
++
++ return 0;
++}
++
++/**
++ * Initialize transmit task's buffer descriptors
++ * @param[in] fec all we know about the device yet
++ *
++ * Transmit buffers are created externally. We only have to init the BDs here.\n
++ * Note: There is a race condition in the hardware. When only one BD is in
++ * use it must be marked with the WRAP bit to use it for every transmitt.
++ * This bit in combination with the READY bit results into double transmit
++ * of each data buffer. It seems the state machine checks READY earlier then
++ * resetting it after the first transfer.
++ * Using two BDs solves this issue.
++ */
++static void fec_tbd_init(fec_priv *fec)
++{
++ writew(0x0000, &fec->tbd_base[0].status);
++ writew(FEC_TBD_WRAP, &fec->tbd_base[1].status);
++ fec->tbd_index = 0;
++}
++
++/**
++ * Mark the given read buffer descriptor as free
++ * @param[in] last 1 if this is the last buffer descriptor in the chain, else 0
++ * @param[in] pRbd buffer descriptor to mark free again
++ */
++static void fec_rbd_clean(int last, FEC_BD *pRbd)
++{
++ /*
++ * Reset buffer descriptor as empty
++ */
++ if (last)
++ writew(FEC_RBD_WRAP | FEC_RBD_EMPTY, &pRbd->status);
++ else
++ writew(FEC_RBD_EMPTY, &pRbd->status);
++ /*
++ * no data in it
++ */
++ writew(0, &pRbd->data_length);
++}
++
++static int fec_get_hwaddr(struct eth_device *dev, unsigned char *mac)
++{
++ int i;
++ int uninitialized = 0;
++
++ for (i=0;i<6;i++) {
++ mac[6-1-i] = readl(&IIM_BANK_REG(0,(IIM0_MAC+i)));
++ }
++
++ /* uninitialized if all 00 */
++ if ((mac[0] == 0) && (mac[1] == 0) && (mac[2] == 0) &&
++ (mac[3] == 0) && (mac[4] == 0) && (mac[5] == 0))
++ uninitialized = 1;
++
++ /* uninitialized if all FF (could be safe) */
++ if ((mac[0] == 0xff) && (mac[1] == 0xff) && (mac[2] == 0xff) &&
++ (mac[3] == 0xff) && (mac[4] == 0xff) && (mac[5] == 0xff))
++ uninitialized = 1;
++
++ return uninitialized;
++}
++
++static int fec_set_hwaddr(struct eth_device *dev, unsigned char *mac)
++{
++ fec_priv *fec = (fec_priv *)dev->priv;
++//#define WTF_IS_THIS
++#ifdef WTF_IS_THIS
++ uint32_t crc = 0xffffffff; /* initial value */
++ uint8_t currByte; /* byte for which to compute the CRC */
++ int byte; /* loop - counter */
++ int bit; /* loop - counter */
++
++ /*
++ * The algorithm used is the following:
++ * we loop on each of the six bytes of the provided address,
++ * and we compute the CRC by left-shifting the previous
++ * value by one position, so that each bit in the current
++ * byte of the address may contribute the calculation. If
++ * the latter and the MSB in the CRC are different, then
++ * the CRC value so computed is also ex-ored with the
++ * "polynomium generator". The current byte of the address
++ * is also shifted right by one bit at each iteration.
++ * This is because the CRC generatore in hardware is implemented
++ * as a shift-register with as many ex-ores as the radixes
++ * in the polynomium. This suggests that we represent the
++ * polynomiumm itself as a 32-bit constant.
++ */
++ for (byte = 0; byte < 6; byte++) {
++ currByte = mac[byte];
++ for (bit = 0; bit < 8; bit++) {
++ if ((currByte & 0x01) ^ (crc & 0x01)) {
++ crc >>= 1;
++ crc = crc ^ 0xedb88320;
++ } else {
++ crc >>= 1;
++ }
++ currByte >>= 1;
++ }
++ }
++
++ crc = crc >> 26;
++
++ /*
++ * Set individual hash table register
++ */
++ if (crc >= 32) {
++ fec->eth->iaddr1 = (1 << (crc - 32));
++ fec->eth->iaddr2 = 0;
++ } else {
++ fec->eth->iaddr1 = 0;
++ fec->eth->iaddr2 = (1 << crc);
++ }
++#else
++ writel(0, &fec->eth->iaddr1);
++ writel(0, &fec->eth->iaddr2);
++ writel(0, &fec->eth->gaddr1);
++ writel(0, &fec->eth->gaddr2);
++#endif
++ /*
++ * Set physical address
++ */
++ writel((mac[0] << 24) + (mac[1] << 16) + (mac[2] << 8) + mac[3], &fec->eth->paddr1);
++ writel((mac[4] << 24) + (mac[5] << 16) + 0x8808, &fec->eth->paddr2);
++
++ return 0;
++}
++
++/**
++ * Start the FEC engine
++ * @param[in] dev Our device to handle
++ */
++static int fec_open(struct eth_device *edev)
++{
++ fec_priv *fec = (fec_priv *)edev->priv;
++
++ PRINTF("fec_open: fec_open(dev)\n");
++ writel(1 << 2, &fec->eth->x_cntrl); /* full-duplex, heartbeat disabled */
++ fec->rbd_index = 0;
++
++ /*
++ * Enable FEC-Lite controller
++ */
++ writel(FEC_ECNTRL_ETHER_EN, &fec->eth->ecntrl);
++
++ if (fec->xcv_type != SEVENWIRE) {
++ miiphy_wait_aneg(&fec->miiphy);
++ miiphy_print_status(&fec->miiphy);
++ }
++
++ /*
++ * Enable SmartDMA receive task
++ */
++ fec_rx_task_enable(fec);
++
++ udelay(100000);
++ return 0;
++}
++
++static int fec_init(struct eth_device *dev, bd_t* bd)
++{
++ static int once = 0;
++ uint32_t base;
++ fec_priv *fec = (fec_priv *)dev->priv;
++
++ if( !once )
++ {
++ /*
++ * reserve memory for both buffer descriptor chains at once
++ * Datasheet forces the startaddress of each chain is 16 byte aligned
++ */
++ base = (uint32_t)malloc( (2 + FEC_RBD_NUM) * sizeof(FEC_BD) + DB_ALIGNMENT );
++ memset((void *)base, 0, (2 + FEC_RBD_NUM) * sizeof(FEC_BD) + DB_ALIGNMENT);
++ base += (DB_ALIGNMENT-1);
++ base &= ~(DB_ALIGNMENT-1);
++
++ fec->rbd_base = (FEC_BD*)base;
++
++ base += FEC_RBD_NUM * sizeof(FEC_BD);
++
++ fec->tbd_base = (FEC_BD*)base;
++ }
++
++ /*
++ * Set interrupt mask register
++ */
++ writel(0x00000000, &fec->eth->imask);
++
++ /*
++ * Clear FEC-Lite interrupt event register(IEVENT)
++ */
++ writel(0xffffffff, &fec->eth->ievent);
++
++
++ /*
++ * Set FEC-Lite receive control register(R_CNTRL):
++ */
++ if (fec->xcv_type == SEVENWIRE) {
++ /*
++ * Frame length=1518; 7-wire mode
++ */
++ writel(0x05ee0020, &fec->eth->r_cntrl); /* FIXME 0x05ee0000 */
++ } else {
++ /*
++ * Frame length=1518; MII mode;
++ */
++ writel(0x05ee0024, &fec->eth->r_cntrl); /* FIXME 0x05ee0004 */
++ /*
++ * Set MII_SPEED = (1/(mii_speed * 2)) * System Clock
++ * and do not drop the Preamble.
++ */
++ writel((((imx_get_ahbclk() /1000000)+2) / 5) << 1, &fec->eth->mii_speed); /* No MII for 7-wire mode */
++ PRINTF("fec_init: mii_speed %#lx\n", (((imx_get_ahbclk() /1000000)+2) / 5) << 1);
++ }
++ /*
++ * Set Opcode/Pause Duration Register
++ */
++ writel(0x00010020, &fec->eth->op_pause); /* FIXME 0xffff0020; */
++ writel(0x2, &fec->eth->x_wmrk);
++ /*
++ * Set multicast address filter
++ */
++ writel(0x00000000, &fec->eth->gaddr1);
++ writel(0x00000000, &fec->eth->gaddr2);
++
++
++ /* clear MIB RAM */
++ long* mib_ptr = (long*)(IMX_FEC_BASE + 0x200);
++ while (mib_ptr <= (long*)(IMX_FEC_BASE + 0x2FC)) {
++ *mib_ptr++ = 0;
++ }
++
++ /* FIFO receive start register */
++ writel(0x520, &fec->eth->r_fstart);
++
++ /* size and address of each buffer */
++ writel(FEC_MAX_PKT_SIZE, &fec->eth->emrbr);
++ writel((uint32_t)fec->tbd_base, &fec->eth->etdsr);
++ writel((uint32_t)fec->rbd_base, &fec->eth->erdsr);
++
++ /*
++ * Initialize RxBD/TxBD rings
++ */
++ fec_rbd_init(fec, FEC_RBD_NUM, FEC_MAX_PKT_SIZE, once);
++ fec_tbd_init(fec);
++
++
++ if (fec->xcv_type != SEVENWIRE)
++ miiphy_restart_aneg(&fec->miiphy);
++
++ once = 1; /* malloc done now (and once) */
++
++ fec_open(dev);
++ return 0;
++}
++
++/**
++ * Halt the FEC engine
++ * @param[in] dev Our device to handle
++ */
++static void fec_halt(struct eth_device *dev)
++{
++ fec_priv *fec = &gfec;
++ int counter = 0xffff;
++
++ /*
++ * issue graceful stop command to the FEC transmitter if necessary
++ */
++ writel(FEC_ECNTRL_RESET | readl(&fec->eth->x_cntrl), &fec->eth->x_cntrl);
++
++ PRINTF("eth_halt: wait for stop regs\n");
++ /*
++ * wait for graceful stop to register
++ */
++ while ((counter--) && (!(readl(&fec->eth->ievent) & FEC_IEVENT_GRA)))
++ ; /* FIXME ensure time */
++
++ /*
++ * Disable SmartDMA tasks
++ */
++ fec_tx_task_disable(fec);
++ fec_rx_task_disable(fec);
++
++ /*
++ * Disable the Ethernet Controller
++ * Note: this will also reset the BD index counter!
++ */
++ writel(0, &fec->eth->ecntrl);
++ fec->rbd_index = 0;
++ fec->tbd_index = 0;
++ PRINTF("eth_halt: done\n");
++}
++
++/**
++ * Transmit one frame
++ * @param[in] dev Our ethernet device to handle
++ * @param[in] packet Pointer to the data to be transmitted
++ * @param[in] length Data count in bytes
++ * @return 0 on success
++ */
++static int fec_send(struct eth_device *dev, volatile void* packet, int length)
++{
++ unsigned int status;
++
++ /*
++ * This routine transmits one frame. This routine only accepts
++ * 6-byte Ethernet addresses.
++ */
++ fec_priv *fec = (fec_priv *)dev->priv;
++
++ /*
++ * Check for valid length of data.
++ */
++ if ((length > 1500) || (length <= 0)) {
++ printf("Payload (%d) to large!\n", length);
++ return -1;
++ }
++
++ /*
++ * Setup the transmitt buffer
++ * Note: We are always using the first buffer for transmission,
++ * the second will be empty and only used to stop the DMA engine
++ */
++/* {
++ int i;
++ PRINTF("fec_send %d bytes:", length);
++ for (i=0;i<length;i++)
++ PRINTF(" %02x", ((char*)packet)[i]);
++ PRINTF("\n");
++ }
++*/ writew(length, &fec->tbd_base[fec->tbd_index].data_length);
++ writel((uint32_t)packet, &fec->tbd_base[fec->tbd_index].data_pointer);
++ /*
++ * update BD's status now
++ * This block:
++ * - is always the last in a chain (means no chain)
++ * - should transmitt the CRC
++ * - might be the last BD in the list, so the address counter should
++ * wrap (-> keep the WRAP flag)
++ */
++ status = readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_WRAP;
++ status |= FEC_TBD_LAST | FEC_TBD_TC | FEC_TBD_READY;
++ writew(status, &fec->tbd_base[fec->tbd_index].status);
++
++ /*
++ * Enable SmartDMA transmit task
++ */
++ fec_tx_task_enable(fec);
++
++ /*
++ * wait until frame is sent .
++ */
++ while (readw(&fec->tbd_base[fec->tbd_index].status) & FEC_TBD_READY) {
++ /* FIXME: Timeout */
++ }
++ PRINTF("fec_send: status 0x%x index %d\n", readw(&fec->tbd_base[fec->tbd_index].status), fec->tbd_index);
++ /* for next transmission use the other buffer */
++ if (fec->tbd_index)
++ fec->tbd_index = 0;
++ else
++ fec->tbd_index = 1;
++
++ return 0;
++}
++
++/**
++ * Pull one frame from the card
++ * @param[in] dev Our ethernet device to handle
++ * @return Length of packet read
++ */
++static int fec_recv(struct eth_device *dev)
++{
++ fec_priv *fec = (fec_priv *)dev->priv;
++ FEC_BD *rbd = &fec->rbd_base[fec->rbd_index];
++ unsigned long ievent;
++ int frame_length, len = 0;
++ NBUF *frame;
++ uint16_t bd_status;
++ uchar buff[FEC_MAX_PKT_SIZE];
++
++ /*
++ * Check if any critical events have happened
++ */
++ ievent = readl(&fec->eth->ievent);
++ writel(ievent, &fec->eth->ievent);
++ PRINTF("fec_recv: ievent 0x%x\n", ievent );
++ if (ievent & FEC_IEVENT_BABR) {
++ fec_halt(dev);
++ fec_init(dev, fec->bd);
++ printf("some error: 0x%08lx\n", ievent);
++ return 0;
++ }
++ if (ievent & FEC_IEVENT_HBERR) {
++ /* Heartbeat error */
++ writel(0x00000001 | readl(&fec->eth->x_cntrl), &fec->eth->x_cntrl);
++ }
++ if (ievent & FEC_IEVENT_GRA) {
++ /* Graceful stop complete */
++ if (readl(&fec->eth->x_cntrl) & 0x00000001) {
++ fec_halt(dev);
++ writel(~0x00000001 & readl(&fec->eth->x_cntrl), &fec->eth->x_cntrl);
++ fec_init(dev, fec->bd);
++ }
++ }
++
++ /*
++ * ensure reading the right buffer status
++ */
++ bd_status = readw(&rbd->status);
++ PRINTF("fec_recv: status 0x%x\n", bd_status );
++
++ if (!(bd_status & FEC_RBD_EMPTY)) {
++ if ((bd_status & FEC_RBD_LAST) && !(bd_status & FEC_RBD_ERR) &&
++ ((readw(&rbd->data_length) - 4) > 14)) {
++ /*
++ * Get buffer address and size
++ */
++ frame = (NBUF *)readl(&rbd->data_pointer);
++ frame_length = readw(&rbd->data_length) - 4;
++ /*
++ * Fill the buffer and pass it to upper layers
++ */
++ memcpy(buff, frame->data, frame_length);
++/* PRINTF("fec_recv %d bytes:", frame_length);
++ for (len=0;len<frame_length;len++)
++ PRINTF(" %02x", buff[len]);
++ PRINTF("\n");
++*/ NetReceive(buff, frame_length);
++ len = frame_length;
++ } else {
++ if (bd_status & FEC_RBD_ERR) {
++ printf("error frame: 0x%08lx 0x%08x\n", (ulong)rbd->data_pointer, bd_status);
++ }
++ }
++ /*
++ * free the current buffer, restart the engine
++ * and move forward to the next buffer
++ */
++ fec_rbd_clean(fec->rbd_index == (FEC_RBD_NUM - 1) ? 1 : 0, rbd);
++ fec_rx_task_enable(fec);
++ fec->rbd_index = (fec->rbd_index + 1) % FEC_RBD_NUM;
++ }
++ PRINTF("fec_recv: stop\n");
++
++ return len;
++}
++
++static int fec_probe(bd_t * bd)
++{
++ /*struct fec_platform_data *pdata = (struct fec_platform_data *)dev->platform_data;*/
++ struct eth_device *edev;
++ fec_priv *fec = &gfec;
++ unsigned char ethaddr_str[20];
++ unsigned char ethaddr[6];
++ char *tmp = getenv ("ethaddr");
++ char *end;
++
++ /* enable FEC clock */
++ PCCR1 |= PCCR1_HCLK_FEC;
++ PCCR0 |= PCCR0_FEC_EN;
++
++ /*create and fill edev struct*/
++ edev = (struct eth_device *)malloc(sizeof(struct eth_device));
++ edev->priv = fec;
++ edev->init = fec_init;
++ edev->send = fec_send;
++ edev->recv = fec_recv;
++ edev->halt = fec_halt;
++
++ fec->eth = (ethernet_regs *)IMX_FEC_BASE;
++ fec->bd = bd;
++
++ /* Reset chip. */
++ writel(FEC_ECNTRL_RESET, &fec->eth->ecntrl);
++ while(readl(&fec->eth->ecntrl) & 1) {
++ udelay(10);
++ }
++
++ fec->xcv_type = MII100; /*pdata->xcv_type;*/
++
++ sprintf(edev->name, "FEC ETHERNET");
++
++ if (fec->xcv_type != SEVENWIRE) {
++ fec->miiphy.read = fec_miiphy_read;
++ fec->miiphy.write = fec_miiphy_write;
++ fec->miiphy.address = CONFIG_PHY_ADDR;
++ fec->miiphy.flags = fec->xcv_type == MII10 ? MIIPHY_FORCE_10 : 0;
++ fec->miiphy.edev = edev;
++
++ /* if multiple PHY have to be supported */
++ /*miiphy_register (edev_>name, fec_miiphy_read, fec_miiphy_write);*/
++ }
++
++ //eth_register(edev);
++
++ if (( NULL != tmp ) && (12 <= strlen(tmp))) {
++ int i;
++ /* convert MAC from string to int */
++ for (i=0; i<6; i++) {
++ ethaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
++ if (tmp)
++ tmp = (*end) ? end+1 : end;
++ }
++ }
++ else if (fec_get_hwaddr(edev, ethaddr) == 0) {
++ sprintf ((char*)ethaddr_str, "%02X:%02X:%02X:%02X:%02X:%02X",
++ ethaddr[0], ethaddr[1], ethaddr[2], ethaddr[3],
++ ethaddr[4], ethaddr[5]);
++ printf("got MAC address from EEPROM: %s\n",ethaddr_str);
++ setenv ("ethaddr", (char*)ethaddr_str);
++ }
++ memcpy(edev->enetaddr, ethaddr, 6);
++ fec_set_hwaddr(edev, ethaddr);
++
++ return 0;
++}
++
++static int once = 0;
++
++int eth_init(bd_t * bd)
++{
++
++ if (!once)
++ {
++ PRINTF("eth_init: fec_probe(bd)\n");
++ fec_probe(bd);
++ once = 1;
++ }
++ PRINTF("eth_init: fec_init(gfec.miiphy.edev, bd)\n");
++ return fec_init(gfec.miiphy.edev, bd);
++};
++
++int fec_eth_initialize(bd_t *bd)
++{
++int lout=1;
++
++ if (!once)
++ {
++ PRINTF("eth_init: fec_probe(bd)\n");
++ lout = fec_probe(bd);
++ once = 1;
++ }
++ return lout;
++}
++
++int eth_send(volatile void *packet, int length)
++{
++ PRINTF("eth_send: fec_send(gfec.miiphy.edev, packet 0x%08lx, length)\n", packet);
++ return fec_send(gfec.miiphy.edev, packet, length);
++};
++
++int eth_rx(void){
++ PRINTF("eth_rcv: fec_rcv(gfec.miiphy.edev)\n");
++ return fec_recv(gfec.miiphy.edev);
++};
++
++
++void eth_halt(void)
++{
++ PRINTF("eth_halt: fec_halt(gfec)\n");
++ fec_halt(NULL);
++ return;
++};
++
++/**
++ * @file
++ * @brief Network driver for FreeScale's FEC implementation.
++ * This type of hardware can be found on i.MX27 CPUs
++ */
++
++#endif /* CONFIG_DRIVER_FEC_IMX27 */
++
+--- ref/u-boot-1.3.4/cpu/arm926ejs/imx27/fec_imx27.h 1970-01-01 01:00:00.000000000 +0100
++++ u-boot-1.3.4/cpu/arm926ejs/imx27/fec_imx27.h 2008-12-29 16:27:49.000000000 +0100
+@@ -0,0 +1,306 @@
++/*
++ * (C) Copyright 2008 Armadeus Systems, nc
++ * (C) Copyright 2008 Eric Jarrige <eri...@ar...>
++ * (C) Copyright 2007 Pengutronix, Sascha Hauer <s....@pe...>
++ * (C) Copyright 2007 Pengutronix, Juergen Beisert <j.b...@pe...>
++ *
++ * (C) Copyright 2003
++ * Wolfgang Denk, DENX Software Engineering, wd...@de....
++ *
++ * This file is based on mpc4200fec.h
++ * (C) Copyright Motorola, Inc., 2000
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ *
++ */
++
++#ifdef CONFIG_DRIVER_FEC_IMX27
++
++#ifndef __IMX27_FEC_H
++#define __IMX27_FEC_H
++
++/**
++ * Layout description of the FEC
++ */
++typedef struct ethernet_register_set {
++
++/* [10:2]addr = 00 */
++
++/* Control and status Registers (offset 000-1FF) */
++
++ uint32_t RES0[1]; /* MBAR_ETH + 0x000 */
++ uint32_t ievent; /* MBAR_ETH + 0x004 */
++ uint32_t imask; /* MBAR_ETH + 0x008 */
++
++ uint32_t RES1[1]; /* MBAR_ETH + 0x00C */
++ uint32_t r_des_active; /* MBAR_ETH + 0x010 */
++ uint32_t x_des_active; /* MBAR_ETH + 0x014 */
++ uint32_t RES2[3]; /* MBAR_ETH + 0x018-20 */
++ uint32_t ecntrl; /* MBAR_ETH + 0x024 */
++
++ uint32_t RES3[6]; /* MBAR_ETH + 0x028-03C */
++ uint32_t mii_data; /* MBAR_ETH + 0x040 */
++ uint32_t mii_speed; /* MBAR_ETH + 0x044 */
++ uint32_t RES4[7]; /* MBAR_ETH + 0x048-60 */
++ uint32_t mib_control; /* MBAR_ETH + 0x064 */
++
++ uint32_t RES5[7]; /* MBAR_ETH + 0x068-80 */
++ uint32_t r_cntrl; /* MBAR_ETH + 0x084 */
++ uint32_t RES6[15]; /* MBAR_ETH + 0x088-C0 */
++ uint32_t x_cntrl; /* MBAR_ETH + 0x0C4 */
++ uint32_t RES7[7]; /* MBAR_ETH + 0x0C8-E0 */
++ uint32_t paddr1; /* MBAR_ETH + 0x0E4 */
++ uint32_t paddr2; /* MBAR_ETH + 0x0E8 */
++ uint32_t op_pause; /* MBAR_ETH + 0x0EC */
++
++ uint32_t RES8[10]; /* MBAR_ETH + 0x0F0-114 */
++ uint32_t iaddr1; /* MBAR_ETH + 0x118 */
++ uint32_t iaddr2; /* MBAR_ETH + 0x11C */
++ uint32_t gaddr1; /* MBAR_ETH + 0x120 */
++ uint32_t gaddr2; /* MBAR_ETH + 0x124 */
++ uint32_t RES9[7]; /* MBAR_ETH + 0x128-140 */
++
++ uint32_t x_wmrk; /* MBAR_ETH + 0x144 */
++ uint32_t RES10[1]; /* MBAR_ETH + 0x148 */
++ uint32_t r_bound; /* MBAR_ETH + 0x14C */
++ uint32_t r_fstart; /* MBAR_ETH + 0x150 */
++ uint32_t RES11[11]; /* MBAR_ETH + 0x154-17C */
++ uint32_t erdsr; /* MBAR_ETH + 0x180 */
++ uint32_t etdsr; /* MBAR_ETH + 0x184 */
++ uint32_t emrbr; /* MBAR_ETH + 0x188 */
++ uint32_t RES12[29]; /* MBAR_ETH + 0x18C-1FC */
++
++/* MIB COUNTERS (Offset 200-2FF) */
++
++ uint32_t rmon_t_drop; /* MBAR_ETH + 0x200 */
++ uint32_t rmon_t_packets; /* MBAR_ETH + 0x204 */
++ uint32_t rmon_t_bc_pkt; /* MBAR_ETH + 0x208 */
++ uint32_t rmon_t_mc_pkt; /* MBAR_ETH + 0x20C */
++ uint32_t rmon_t_crc_align; /* MBAR_ETH + 0x210 */
++ uint32_t rmon_t_undersize; /* MBAR_ETH + 0x214 */
++ uint32_t rmon_t_oversize; /* MBAR_ETH + 0x218 */
++ uint32_t rmon_t_frag; /* MBAR_ETH + 0x21C */
++ uint32_t rmon_t_jab; /* MBAR_ETH + 0x220 */
++ uint32_t rmon_t_col; /* MBAR_ETH + 0x224 */
++ uint32_t rmon_t_p64; /* MBAR_ETH + 0x228 */
++ uint32_t rmon_t_p65to127; /* MBAR_ETH + 0x22C */
++ uint32_t rmon_t_p128to255; /* MBAR_ETH + 0x230 */
++ uint32_t rmon_t_p256to511; /* MBAR_ETH + 0x234 */
++ uint32_t rmon_t_p512to1023; /* MBAR_ETH + 0x238 */
++ uint32_t rmon_t_p1024to2047; /* MBAR_ETH + 0x23C */
++ uint32_t rmon_t_p_gte2048; /* MBAR_ETH + 0x240 */
++ uint32_t rmon_t_octets; /* MBAR_ETH + 0x244 */
++ uint32_t ieee_t_drop; /* MBAR_ETH + 0x248 */
++ uint32_t ieee_t_frame_ok; /* MBAR_ETH + 0x24C */
++ uint32_t ieee_t_1col; /* MBAR_ETH + 0x250 */
++ uint32_t ieee_t_mcol; /* MBAR_ETH + 0x254 */
++ uint32_t ieee_t_def; /* MBAR_ETH + 0x258 */
++ uint32_t ieee_t_lcol; /* MBAR_ETH + 0x25C */
++ uint32_t ieee_t_excol; /* MBAR_ETH + 0x260 */
++ uint32_t ieee_t_macerr; /* MBAR_ETH + 0x264 */
++ uint32_t ieee_t_cserr; /* MBAR_ETH + 0x268 */
++ uint32_t ieee_t_sqe; /* MBAR_ETH + 0x26C */
++ uint32_t t_fdxfc; /* MBAR_ETH + 0x270 */
++ uint32_t ieee_t_octets_ok; /* MBAR_ETH + 0x274 */
++
++ uint32_t RES13[2]; /* MBAR_ETH + 0x278-27C */
++ uint32_t rmon_r_drop; /* MBAR_ETH + 0x280 */
++ uint32_t rmon_r_packets; /* MBAR_ETH + 0x284 */
++ uint32_t rmon_r_bc_pkt; /* MBAR_ETH + 0x288 */
++ uint32_t rmon_r_mc_pkt; /* MBAR_ETH + 0x28C */
++ uint32_t rmon_r_crc_align; /* MBAR_ETH + 0x290 */
++ uint32_t rmon_r_undersize; /* MBAR_ETH + 0x294 */
++ uint32_t rmon_r_oversize; /* MBAR_ETH + 0x298 */
++ uint32_t rmon_r_frag; /* MBAR_ETH + 0x29C */
++ uint32_t rmon_r_jab; /* MBAR_ETH + 0x2A0 */
++
++ uint32_t rmon_r_resvd_0; /* MBAR_ETH + 0x2A4 */
++
++ uint32_t rmon_r_p64; /* MBAR_ETH + 0x2A8 */
++ uint32_t rmon_r_p65to127; /* MBAR_ETH + 0x2AC */
++ uint32_t rmon_r_p128to255; /* MBAR_ETH + 0x2B0 */
++ uint32_t rmon_r_p256to511; /* MBAR_ETH + 0x2B4 */
++ uint32_t rmon_r_p512to1023; /* MBAR_ETH + 0x2B8 */
++ uint32_t rmon_r_p1024to2047; /* MBAR_ETH + 0x2BC */
++ uint32_t rmon_r_p_gte2048; /* MBAR_ETH + 0x2C0 */
++ uint32_t rmon_r_octets; /* MBAR_ETH + 0x2C4 */
++ uint32_t ieee_r_drop; /* MBAR_ETH + 0x2C8 */
++ uint32_t ieee_r_frame_ok; /* MBAR_ETH + 0x2CC */
++ uint32_t ieee_r_crc; /* MBAR_ETH + 0x2D0 */
++ uint32_t ieee_r_align; /* MBAR_ETH + 0x2D4 */
++ uint32_t r_macerr; /* MBAR_ETH + 0x2D8 */
++ uint32_t r_fdxfc; /* MBAR_ETH + 0x2DC */
++ uint32_t ieee_r_octets_ok; /* MBAR_ETH + 0x2E0 */
++
++ uint32_t RES14[6]; /* MBAR_ETH + 0x2E4-2FC */
++
++ uint32_t RES15[64]; /* MBAR_ETH + 0x300-3FF */
++} ethernet_regs;
++
++#define FEC_IEVENT_HBERR 0x80000000
++#define FEC_IEVENT_BABR 0x40000000
++#define FEC_IEVENT_BABT 0x20000000
++#define FEC_IEVENT_GRA 0x10000000
++#define FEC_IEVENT_TXF 0x08000000
++#define FEC_IEVENT_TXB 0x04000000
++#define FEC_IEVENT_RXF 0x02000000
++#define FEC_IEVENT_RXB 0x01000000
++#define FEC_IEVENT_MII 0x00800000
++#define FEC_IEVENT_EBERR 0x00400000
++#define FEC_IEVENT_LC 0x00200000
++#define FEC_IEVENT_RL 0x00100000
++#define FEC_IEVENT_UN 0x00080000
++
++#define FEC_IMASK_HBERR 0x80000000
++#define FEC_IMASK_BABR 0x40000000
++#define FEC_IMASKT_BABT 0x20000000
++#define FEC_IMASK_GRA 0x10000000
++#define FEC_IMASKT_TXF 0x08000000
++#define FEC_IMASK_TXB 0x04000000
++#define FEC_IMASKT_RXF 0x02000000
++#define FEC_IMASK_RXB 0x01000000
++#define FEC_IMASK_MII 0x00800000
++#define FEC_IMASK_EBERR 0x00400000
++#define FEC_IMASK_LC 0x00200000
++#define FEC_IMASKT_RL 0x00100000
++#define FEC_IMASK_UN 0x00080000
++
++
++#define FEC_RCNTRL_MAX_FL_SHIFT 16
++#define FEC_RCNTRL_LOOP 0x00000001
++#define FEC_RCNTRL_DRT 0x00000002
++#define FEC_RCNTRL_MII_MODE 0x00000004
++#define FEC_RCNTRL_PROM 0x00000008
++#define FEC_RCNTRL_BC_REJ 0x00000010
++#define FEC_RCNTRL_FCE 0x00000020
++
++#define FEC_TCNTRL_GTS 0x00000001
++#define FEC_TCNTRL_HBC 0x00000002
++#define FEC_TCNTRL_FDEN 0x00000004
++#define FEC_TCNTRL_TFC_PAUSE 0x00000008
++#define FEC_TCNTRL_RFC_PAUSE 0x00000010
++
++#define FEC_ECNTRL_RESET 0x00000001 /**< reset the FEC */
++#define FEC_ECNTRL_ETHER_EN 0x00000002 /**< enable the FEC */
++
++/**
++ * @brief Descriptor buffer alignment
++ *
++ * i.MX27 requires a 16 byte alignment (but for the first element only)
++ */
++#define DB_ALIGNMENT 16
++
++/**
++ * @brief Data buffer alignment
++ *
++ * i.MX27 requires a four byte alignment for transmit and 16 bits
++ * alignment for receive so take 16
++ * Note: Valid for member data_pointer in struct buffer_descriptor
++ */
++#define DB_DATA_ALIGNMENT 16
++
++/**
++ * @brief Receive & Transmit Buffer Descriptor definitions
++ *
++ * Note: The first BD must be aligned (see DB_ALIGNMENT)
++ */
++typedef struct buffer_descriptor {
++ uint16_t data_length; /**< payload's length in bytes */
++ uint16_t status; /**< BD's staus (see datasheet) */
++ uint32_t data_pointer; /**< payload's buffer address */
++} FEC_BD;
++
++/**
++ * Supported phy types on this platform
++ */
++typedef enum {
++ SEVENWIRE, /**< 7-wire */
++ MII10, /**< MII 10Mbps */
++ MII100 /**< MII 100Mbps */
++} xceiver_type;
++
++/**
++ * @brief i.MX27-FEC private structure
++ */
++typedef struct {
++ ethernet_regs *eth; /**< pointer to register'S base */
++ xceiver_type xcv_type; /**< transceiver type */
++ FEC_BD *rbd_base; /**< RBD ring */
++ int rbd_index; /**< next receive BD to read */
++ FEC_BD *tbd_base; /**< TBD ring */
++ int tbd_index; /**< next transmit BD to write */
++ struct miiphy_device miiphy;
++ bd_t * bd;
++} fec_priv;
++
++/**
++ * @brief Numbers of buffer descriptors for receiving
++ *
++ * The number defines the stocked memory buffers for the receiving task.
++ * Larger values makes no sense in this limited environment.
++ */
++#define FEC_RBD_NUM 64
++
++/**
++ * @brief Define the ethernet packet size limit in memory
++ *
++ * Note: Do not shrink this number. This will force the FEC to spread larger
++ * frames in more than one BD. This is nothing to worry about, but the current
++ * driver can't handle it.
++ */
++#define FEC_MAX_PKT_SIZE 1536
++
++/* Receive BD status bits */
++#define FEC_RBD_EMPTY 0x8000 /**< Receive BD status: Buffer is empty */
++#define FEC_RBD_WRAP 0x2000 /**< Receive BD status: Last BD in ring */
++#define FEC_RBD_LAST 0x0800 /**< Receive BD status: Buffer is last in frame (useless here!) */
++#define FEC_RBD_MISS 0x0100 /**< Receive BD status: Miss bit for prom mode */
++#define FEC_RBD_BC 0x0080 /**< Receive BD status: The received frame is broadcast frame */
++#define FEC_RBD_MC 0x0040 /**< Receive BD status: The received frame is multicast frame */
++#define FEC_RBD_LG 0x0020 /**< Receive BD status: Frame length violation */
++#define FEC_RBD_NO 0x0010 /**< Receive BD status: Nonoctet align frame */
++#define FEC_RBD_CR 0x0004 /**< Receive BD status: CRC error */
++#define FEC_RBD_OV 0x0002 /**< Receive BD status: Receive FIFO overrun */
++#define FEC_RBD_TR 0x0001 /**< Receive BD status: Frame is truncated */
++#define FEC_RBD_ERR (FEC_RBD_LG | FEC_RBD_NO | FEC_RBD_CR | \
++ FEC_RBD_OV | FEC_RBD_TR)
++
++/* Transmit BD status bits */
++#define FEC_TBD_READY 0x8000 /**< Tansmit BD status: Buffer is ready */
++#define FEC_TBD_WRAP 0x2000 /**< Tansmit BD status: Mark as last BD in ring */
++#define FEC_TBD_LAST 0x0800 /**< Tansmit BD status: Buffer is last in frame */
++#define FEC_TBD_TC 0x0400 /**< Tansmit BD status: Transmit the CRC */
++#define FEC_TBD_ABC 0x0200 /**< Tansmit BD status: Append bad CRC */
++
++/* MII-related definitios */
++#define FEC_MII_DATA_ST 0x40000000 /**< Start of frame delimiter */
++#define FEC_MII_DATA_OP_RD 0x20000000 /**< Perform a read operation */
++#define FEC_MII_DATA_OP_WR 0x10000000 /**< Perform a write operation */
++#define FEC_MII_DATA_PA_MSK 0x0f800000 /**< PHY Address field mask */
++#define FEC_MII_DATA_RA_MSK 0x007c0000 /**< PHY Register field mask */
++#define FEC_MII_DATA_TA 0x00020000 /**< Turnaround */
++#define FEC_MII_DATA_DATAMSK 0x0000ffff /**< PHY data field */
++
++#define FEC_MII_DATA_RA_SHIFT 18 /* MII Register address bits */
++#define FEC_MII_DATA_PA_SHIFT 23 /* MII PHY address bits */
++
++#endif /* __IMX27_FEC_H */
++
++#endif /* CONFIG_DRIVER_FEC_IMX27 */
++/**
++ * @file
++ * @brief Definitions for the FEC driver (i.MX27)
++ */
+--- ref/u-boot-1.3.4/cpu/arm926ejs/imx27/generic.c 1970-01-01 01:00:00.000000000 +0100
++++ u-boot-1.3.4/cpu/arm926ejs/imx27/generic.c 2008-12-29 16:27:49.000000000 +0100
+@@ -0,0 +1,289 @@
++/*
++ * Copyright (c) 2008 Eric Jarrige <eri...@ar...>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <common.h>
++#include <asm/arch/imx-regs.h>
++/*#include <asm/arch/clock.h>
++#include <asm-generic/div64.h>
++#include <init.h>
++*/
++/*
++ * get the system pll clock in Hz
++ *
++ * mfi + mfn / (mfd +1)
++ * f = 2 * f_ref * --------------------
++ * pd + 1
++ */
++unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref)
++{
++/* unsigned long long ll;
++ unsigned int quot;
++*/
++ unsigned int mfi = (pll >> 10) & 0xf;
++ unsigned int mfn = pll & 0x3ff;
++ unsigned int mfd = (pll >> 16) & 0x3ff;
++ unsigned int pd = (pll >> 26) & 0xf;
++
++ mfi = mfi <= 5 ? 5 : mfi;
++
++/* ll = 2 * (unsigned long long)f_ref * ( (mfi << 16) + (mfn << 16) / (mfd + 1));
++ quot = (pd + 1) * (1 << 16);
++ ll += quot / 2;
++ do_div(ll, quot);
++ return (unsigned int) ll;*/
++ return (2*(u64)f_ref* (mfi*(mfd+1) + mfn))/((mfd+1)*(pd+1));
++}
++
++static ulong clk_in_32k(void)
++{
++ return 1024 * CFG_OSC32;
++}
++
++static ulong clk_in_26m(void)
++{
++ if (CSCR & CSCR_OSC26M_DIV1P5) {
++ /* divide by 1.5 */
++ return 26000000 / 1.5;
++ } else {
++ /* divide by 1 */
++ return 26000000;
++ }
++}
++
++ulong imx_get_mpllclk(void)
++{
++ ulong cscr = CSCR;
++ ulong fref;
++
++ if (cscr & CSCR_MCU_SEL)
++ fref = clk_in_26m();
++ else
++ fref = clk_in_32k();
++
++ return imx_decode_pll(MPCTL0, fref);
++}
++
++ulong imx_get_armclk(void)
++{
++ ulong cscr = CSCR;
++ ulong fref = imx_get_mpllclk();
++ ulong div;
++
++ if (!(cscr & CSCR_ARM_SRC_MPLL))
++ fref = (fref * 2) / 3;
++
++ div = ((cscr >> 12) & 0x3) + 1;
++
++ return fref / div;
++}
++
++ulong imx_get_ahbclk(void)
++{
++ ulong cscr = CSCR;
++ ulong fref = imx_get_mpllclk();
++ ulong div;
++
++ div = ((cscr >> 8) & 0x3) + 1;
++
++ return fref * 2 / 3 / div;
++
++}
++
++ulong imx_get_spllclk(void)
++{
++ ulong cscr = CSCR;
++ ulong fref;
++
++ if (cscr & CSCR_SP_SEL)
++ fref = clk_in_26m();
++ else
++ fref = clk_in_32k();
++
++ return imx_decode_pll(SPCTL0, fref);
++}
++
++static ulong imx_get_usbclk(void)
++{
++ return (imx_get_spllclk() / (((CSCR >> 28) & 0x07) + 1));
++}
++
++static ulong imx_get_nfcclk(void)
++{
++ return (imx_get_ahbclk() / (((PCDR0 >> 6) & 0x0f) + 1));
++}
++
++static ulong imx_get_mshcclk(void)
++{
++ return (imx_get_mpllclk() * 2 / (((PCDR0 >> 0) & 0x3f) + 1) / 3);
++}
++
++static ulong imx_get_h264clk(void)
++{
++ return ((imx_get_mpllclk() * 4 ) / (((PCDR0 >> 10) & 0x3f) + 4) / 3);
++}
++
++static ulong imx_get_ssi1clk(void)
++{
++ return ((imx_get_mpllclk() * 4 ) / (((PCDR0 >> 16) & 0x3f) + 4) / 3);
++}
++
++static ulong imx_get_ssi2clk(void)
++{
++ return ((imx_get_mpllclk() * 4) / (((PCDR0 >> 26) & 0x3f) + 4) / 3);
++}
++
++static ulong imx_decode_perclk(ulong div)
++{
++ return (imx_get_mpllclk() * 2) / (div * 3);
++}
++
++ulong imx_get_perclk1(void)
++{
++ return imx_decode_perclk((PCDR1 & 0x3f) + 1);
++}
++
++ulong imx_get_perclk2(void)
++{
++ return imx_decode_perclk(((PCDR1 >> 8) & 0x3f) + 1);
++}
++
++ulong imx_get_perclk3(void)
++{
++ return imx_decode_perclk(((PCDR1 >> 16) & 0x3f) + 1);
++}
++
++ulong imx_get_perclk4(void)
++{
++ return imx_decode_perclk(((PCDR1 >> 24) & 0x3f) + 1);
++}
++
++int imx_dump_clocks(void)
++{
++ printf("mpll : %10ld Hz\n", imx_get_mpllclk());
++ printf("spll : %10ld Hz\n", imx_get_spllclk());
++ printf("arm : %10ld Hz\n", imx_get_armclk());
++ printf("hclk : %10ld Hz\n", imx_get_ahbclk());
++ printf("perclk1: %10ld Hz\n", imx_get_perclk1());
++ printf("perclk2: %10ld Hz\n", imx_get_perclk2());
++ printf("perclk3: %10ld Hz\n", imx_get_perclk3());
++ printf("perclk4: %10ld Hz\n", imx_get_perclk4());
++ printf("usbclk : %10ld Hz\n", imx_get_usbclk());
++ printf("nfcclk : %10ld Hz\n", imx_get_nfcclk());
++ printf("mshcclk: %10ld Hz\n", imx_get_mshcclk());
++ printf("h264clk: %10ld Hz\n", imx_get_h264clk());
++ printf("ssi1clk: %10ld Hz\n", imx_get_ssi1clk());
++ printf("ssi2clk: %10ld Hz\n", imx_get_ssi2clk());
++ printf("clkin26: %10ld Hz\n", clk_in_26m());
++ printf("clkin32: %10d Hz\n", CFG_OSC32);
++ printf("ESDCTL0: %#x ESDCTL1: %#x\n", ESDCTL0, ESDCTL1);
++ printf("ESDCFG0: %#x ESDCFG1: %#x\n", ESDCFG0,ESDCFG1);
++ printf("SDmdreg: %#x\n", CFG_SDRAM_1_BASE+CFG_SDRAM_MODE_REGISTER_VAL);
++ printf("SDemdreg: %#x\n", CFG_SDRAM_1_BASE+CFG_SDRAM_EXT_MODE_REGISTER_VAL);
++ printf("SDprech: %#x\n", CFG_SDRAM_PRECHARGE_ALL_VAL);
++ printf("SPL Saved boot: %#lx\n", *((long*)(0xa0200004)));
++ printf("uboot Saved boot: %#lx\n", *((long*)(0xa0200008)));
++
++ return 0;
++}
++
++
++/*void imx_gpio_mux(unsigned long mode)
++{
++ unsigned long reg, shift, tmp;
++
++ reg = IOMUXC_BASE + (mode & 0xfc);
++ shift = (~mode & 0x3) * 8;
++
++ tmp = __REG(reg);
++ tmp &= ~(0xff << shift);
++ tmp |= ((mode >> 8) & 0xff) << shift;
++ __REG(reg) = tmp;
++}
++*/
++#if defined(CONFIG_DISPLAY_CPUINFO)
++int print_cpuinfo (void)
++{
++ printf("CPU: Freescale i.MX27 at %ld MHz\n",
++ imx_get_mpllclk() / 1000000);
++ imx_dump_clocks();
++ printf("\n");
++ return 0;
++}
++#endif
++
++void imx_gpio_mode(int gpio_mode)
++{
++ unsigned int pin = gpio_mode & GPIO_PIN_MASK;
++ unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
++ unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT;
++ unsigned int aout = (gpio_mode & GPIO_AOUT_MASK) >> GPIO_AOUT_SHIFT;
++ unsigned int bout = (gpio_mode & GPIO_BOUT_MASK) >> GPIO_BOUT_SHIFT;
++ unsigned int tmp;
++
++ /* Pullup enable */
++ if(gpio_mode & GPIO_PUEN)
++ PUEN(port) |= (1 << pin);
++ else
++ PUEN(port) &= ~(1 << pin);
++
++ /* Data direction */
++ if(gpio_mode & GPIO_OUT)
++ DDIR(port) |= 1 << pin;
++ else
++ DDIR(port) &= ~(1 << pin);
++
++ /* Primary / alternate function */
++ if(gpio_mode & GPIO_AF)
++ GPR(port) |= (1 << pin);
++ else
++ GPR(port) &= ~(1 << pin);
++
++ /* use as gpio? */
++ if(!(gpio_mode & (GPIO_PF | GPIO_AF)))
++ GIUS(port) |= (1 << pin);
++ else
++ GIUS(port) &= ~(1 << pin);
++
++ /* Output / input configuration */
++ if (pin < 16) {
++ tmp = OCR1(port);
++ tmp &= ~(3 << (pin * 2));
++ tmp |= (ocr << (pin * 2));
++ OCR1(port) = tmp;
++
++ ICONFA1(port) &= ~(3 << (pin * 2));
++ ICONFA1(port) |= aout << (pin * 2);
++ ICONFB1(port) &= ~(3 << (pin * 2));
++ ICONFB1(port) |= bout << (pin * 2);
++ } else {
++ pin -= 16;
++
++ tmp = OCR2(port);
++ tmp &= ~(3 << (pin * 2));
++ tmp |= (ocr << (pin * 2));
++ OCR2(port) = tmp;
++
++ ICONFA2(port) &= ~(3 << (pin * 2));
++ ICONFA2(port) |= aout << (pin * 2);
++ ICONFB2(port) &= ~(3 << (pin * 2));
++ ICONFB2(port) |= bout << (pin * 2);
++ }
++
++}
++
+--- ref/u-boot-1.3.4/cpu/arm926ejs/imx27/i2c.c 1970-01-01 01:00:00.000000000 +0100
++++ u-boot-1.3.4/cpu/arm926ejs/imx27/i2c.c 2008-12-29 16:27:49.000000000 +0100
+@@ -0,0 +1,407 @@
++/*
++ * Eric Jarrige <jo...@us...>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ *
++ *
++ */
++
++#include <common.h>
++
++#ifdef CONFIG_HARD_I2C
++
++#include <asm/io.h>
++#include <asm/arch/clock.h>
++#include <asm/arch/imx-regs.h>
++#include <i2c.h>
++#include "i2c.h"
++
++/*#define DEBUG_I2C*/
++
++/* current active I2C bus */
++static unsigned int bus_num = 0;
++
++static int hclk_dividers[] = {
++ 30, 32, 36, 42, 48, 52, 60, 72,
++ 80, 88, 104, 128, 144, 160, 192, 240,
++ 288, 320, 384, 480, 576, 640, 768, 960,
++ 1152, 1280, 1536, 1920, 2304, 2560, 3072, 3840,
++ 22, 24, 26, 26, 32, 36, 40, 44,
++ 48, 56, 64, 72, 80, 96, 112, 128,
++ 160, 192, 224, 256, 320, 384, 448, 512,
++ 640, 768, 896, 1024, 1280, 1536, 1792, 2048
++};
++
++unsigned long i2c_bases[] = {IMX_I2C1_BASE, IMX_I2C2_BASE};
++
++extern void imx_gpio_mode (int gpio_mode);
++
++/*-----------------------------------------------------------------------
++ * Definitions
++ */
++
++#define I2C_ACK 0 /* level to ack a byte */
++#define I2C_NOACK 1 /* level to noack a byte */
++
++
++#ifdef DEBUG_I2C
++#define PRINTD(fmt,args...) do { \
++ DECLARE_GLOBAL_DATA_PTR; \
++ if (gd->have_console) \
++ printf (fmt ,##args); \
++ } while (0)
++#else
++#define PRINTD(fmt,args...)
++#endif
++
++/*-----------------------------------------------------------------------
++ * Local functions
++ */
++
++/*-----------------------------------------------------------------------
++ * START: High -> Low on SDA while SCL is High
++ * after check for a bus free
++ */
++static void
++imxi2c_send_start (void)
++{
++ while ((I2SR(bus_num) & I2SR_IBB)) ;
++ I2CR(bus_num) |= I2CR_MSTA;
++ I2SR(bus_num) &= ~I2SR_IIF;
++}
++
++/*-----------------------------------------------------------------------
++ * STOP: Low -> High on SDA while SCL is High
++ * after the end of previous transfer
++ */
++static void
++imxi2c_send_stop (void)
++{
++ while (!(I2SR(bus_num) & I2SR_ICF)) ;
++ I2CR(bus_num) &= ~I2CR_MSTA;
++}
++
++/*-----------------------------------------------------------------------
++ * Send 8 bits and look for an acknowledgement.
++ */
++static int
++imxi2c_write_byte (uchar data)
++{
++ while (!(I2SR(bus_num) & I2SR_ICF)) ; /* Wait end of transfer */
++
++ I2CR(bus_num) |= I2CR_MTX;
++ I2SR(bus_num) &= ~I2SR_IIF;
++ I2DR(bus_num) = data;
++
++ while (!(I2SR(bus_num) & I2SR_IIF)) ; /* checking IIF before ICF seems required */
++
++ I2SR(bus_num) &= ~I2SR_IIF;
++
++ while (!(I2SR(bus_num) & I2SR_ICF)) ; /* Wait end of transfer */
++
++ return (I2SR(bus_num) & I2SR_RXAK); /* not a nack is an ack */
++}
++
++/*-----------------------------------------------------------------------
++ * if ack == I2C_ACK, ACK the byte so can continue reading, else
++ * send I2C_NOACK to end the read.
++ */
++static uchar
++imxi2c_read_byte (int ack)
++{
++ int data;
++
++ while (!(I2SR(bus_num) & I2SR_ICF)) ;
++ I2CR(bus_num) &= ~I2CR_MTX;
++
++ if (ack)
++ {
++ I2CR(bus_num) |= I2CR_TXAK;
++ }
++ else
++ {
++ I2CR(bus_num) &= ~I2CR_TXAK;
++ }
++
++ data = I2DR(bus_num);
++ return (data);
++}
++
++/* ------------------------------------------------------------------------
++ * API Functions
++ * ------------------------------------------------------------------------
++ */
++
++/*-----------------------------------------------------------------------
++ * i2c_init compute the i2c divider to reach the requested speed
++ * see mxl reference manual
++ */
++void
++i2c_init (int speed, int slaveaddr)
++{
++ int i;
++
++#ifdef CONFIG_I2C_MULTI_BUS
++ imx_gpio_mode (PC5_PF_I2C2_DATA);
++ imx_gpio_mode (PC6_PF_I2C2_CLK);
++ PCCR0 |= PCCR0_I2C2_EN; /*enable I2C2 clock*/
++#endif
++ imx_gpio_mode (PD17_PF_I2C_DATA);
++ imx_gpio_mode (PD18_PF_I2C_CLK);
++ PCCR0 |= PCCR0_I2C1_EN; /*enable I2C2 clock*/
++
++
++ for(i = 0; i < CONFIG_I2C_MULTI_BUS; i++){
++
++ i2c_set_bus_num(i);
++ I2CR(bus_num) = 0;
++
++ i2c_set_bus_speed(speed);
++
...
[truncated message content] |