dm9000x.c

/*
 *             U-BOOT DM9000A DRIVER
 *              www.davicom.com.tw
 *
 * This program is loaded into SRAM in bootstrap mode, where it waits
 * for commands on UART1 to read and write memory, jump to code etc.
 * A design goal for this program is to be entirely independent of the
 * target board.  Anything with a CL-PS7111 or EP7211 should be able to run
 * this code in bootstrap mode.  All the board specifics can be handled on
 * the host.
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *V1.01 -load MAC address from EEPROM
 */

#include <common.h>
#include <command.h>
#include <net.h>

#ifdef CONFIG_DRIVER_DM9000
#include "dm9000x.h"



#define DM9000_ID        0x90000A46
#define DM9010_ID        0x90100A46
#define DM9KS_REG05        (RXCR_Discard_LongPkt|RXCR_Discard_CRCPkt)
#define DM9KS_DISINTR        IMR_SRAM_antoReturn
/*
 * If your bus is 8-bit or 32-bit, you must modify below.
 * Ex. your bus is 8 bit
 *    DM9000_PPTR *(volatile u8 *)(DM9000_BASE)
 */

#define DM9000_BASE        CONFIG_DM9000_BASE

#define DM9000_PPTR        *(volatile u16 *)(DM9000_IO)
#define DM9000_PDATA        *(volatile u16 *)(DM9000_DATA)


#define mdelay(n)       udelay((n)*1000)

static unsigned char ior(int);
static void iow(int, u8);
static void phy_write(int, u16);
static void move8(unsigned char *, int, int);
static void move16(unsigned char *, int, int);
static void move32(unsigned char *, int, int);
static u16 read_srom_word(int);
static void dmfe_init_dm9000(void);
static u32 GetDM9000ID(void);
void DM9000_get_enetaddr (uchar *);
static void eth_reset (void);
void eth_halt(void);
int eth_init(bd_t *);
void (*MoveData)(unsigned char *, int , int);

static void iow(int reg, u8 value)
{
        DM9000_PPTR = reg;
        DM9000_PDATA  =  value & 0xff;
}

static unsigned char ior(int reg)
{
        DM9000_PPTR = reg;
        return DM9000_PDATA & 0xff;
}

static void phy_write(int reg, u16 value)
{
        /* Fill the phyxcer register into REG_0C */
        iow(DM9KS_EPAR, DM9KS_PHY | reg);

        /* Fill the written data into REG_0D & REG_0E */
        iow(DM9KS_EPDRL, (value & 0xff));
        iow(DM9KS_EPDRH, ( (value >> 8) & 0xff));

        iow(DM9KS_EPCR, EPCR_PHY_Sele|EPCR_Write);    /* Issue phyxcer write command */
        udelay(500);            /* Wait write complete */
        iow(DM9KS_EPCR, 0x0);    /* Clear phyxcer write command */
}

/*
        leng: unit BYTE
        selec 0:input(RX)    1:output(TX)
        if selec=0, move data from FIFO to data_ptr
        if selec=1, move data from data_ptr to FIFO
*/
static void move8(unsigned char *data_ptr, int leng, int selec)
{
        int i;
        if (selec)
                for (i=0; i<leng; i++)
                        DM9000_PDATA =(data_ptr[i] & 0xff);
        else
                for (i=0; i<leng; i++)
                        data_ptr[i] = DM9000_PDATA;
}    

static void move16(unsigned char *data_ptr, int leng, int selec)
{
        int i, tmpleng;
        tmpleng = (leng + 1) >> 1;
        if (selec)
                for (i=0; i<tmpleng; i++)
                        DM9000_PDATA =((u16 *)data_ptr)[i];
        else
                for (i=0; i<tmpleng; i++)
                        ((u16 *)data_ptr)[i] = DM9000_PDATA;
}    

static void move32(unsigned char *data_ptr, int leng, int selec)
{
        int i, tmpleng;
        tmpleng = (leng + 3) >> 2;
        if (selec)
                for (i=0; i<tmpleng; i++)
                        DM9000_PDATA = ((u32 *)data_ptr)[i];
        else
                for (i=0; i<tmpleng; i++)
                        ((u32 *)data_ptr)[i]=DM9000_PDATA;
}    

/*
 * Read a word data from EEPROM
 */
static u16 read_srom_word(int offset)
{
        iow(DM9KS_EPAR, offset);
        iow(DM9KS_EPCR, 0x4);
        udelay(200);
        iow(DM9KS_EPCR, 0x0);
        return (ior(DM9KS_EPDRL) + (ior(DM9KS_EPDRH) << 8) );
}
/*
 *    Initilize dm9000 board
 */
static void dmfe_init_dm9000(void)
{
        int io_mode;
        
        /* set the internal PHY power-on, GPIOs normal, and wait 20ms */
        iow(DM9KS_GPR, GPR_PHYUp);
        mdelay(20); /* wait for PHY power-on ready */
        iow(DM9KS_GPR, GPR_PHYDown);/* Power-Down PHY */
        mdelay(1000);    /* compatible with rtl8305s */
        iow(DM9KS_GPR, GPR_PHYUp);    
        mdelay(20);/* wait for PHY power-on ready */

        iow(DM9KS_NCR, NCR_MAC_loopback|NCR_Reset);
        udelay(20);/* wait 20us at least for software reset ok */
        iow(DM9KS_NCR, NCR_MAC_loopback|NCR_Reset);
        udelay(20);/* wait 20us at least for software reset ok */

        /* I/O mode */
        io_mode = ior(DM9KS_ISR) >> 6; /* ISR bit7:6 keeps I/O mode */
        switch (io_mode)
        {
                case DM9KS_BYTE_MODE:
                        printf("DM9000 work in 8 bus width\n");
                        MoveData = move8;
                        break;
                case DM9KS_WORD_MODE:
                        printf("DM9000 work in 16 bus width\n");
                        MoveData = move16;
                        break;
                case DM9KS_DWORD_MODE:
                        printf("DM9000 work in 32 bus width\n");
                        MoveData = move32;
                        break;
                default:
                        printf("DM9000 work in wrong bus width, error\n");
                        break;
        }
        
        /* Set PHY */
        phy_write(4, 0x01e1);
        phy_write(0, 0x1200); /* N-way */

        /* Program operating register */
        iow(DM9KS_NCR, 0);
        iow(DM9KS_TCR, 0);/* TX Polling clear */
        iow(DM9KS_BPTR, 0x30|JPT_600us);/* Less 3kb, 600us */
        iow(DM9KS_SMCR, 0);/* Special Mode */
        iow(DM9KS_NSR, 0x2c);/* clear TX status */
        iow(DM9KS_ISR, 0x0f);/* Clear interrupt status */
        iow(DM9KS_TCR2, TCR2_LedMode1);/* Set LED mode 1 */
#if 0
        /* Data bus current driving/sinking capability  */
        iow(DM9KS_PBCR, 0x60);    /* default: 8mA */
#endif
 
        iow(0x1d, 0x80);/* receive broadcast packet */

        /* Activate DM9000A/DM9010 */
        iow(DM9KS_RXCR, DM9KS_REG05 | RXCR_RxEnable);    
        iow(DM9KS_IMR, DM9KS_DISINTR);
}

/* packet page register access functions */
static u32 GetDM9000ID(void)
{
        u32    id_val;

        DM9000_PPTR = DM9KS_PID_H;
        id_val = (DM9000_PDATA & 0xff) << 8;
        DM9000_PPTR = DM9KS_PID_L;
        id_val+= (DM9000_PDATA & 0xff);
        id_val = id_val << 16;
        
        DM9000_PPTR = DM9KS_VID_H;
        id_val += (DM9000_PDATA & 0xff) << 8;
        DM9000_PPTR = DM9KS_VID_L;
        id_val += (DM9000_PDATA & 0xff);
        

        return id_val;
}


void DM9000_get_enetaddr (uchar * addr)
{
        int i;
        u8 temp;
        eth_reset ();    
        printf ("MAC: ");
        for (i = 0x10; i <= 0x15; i++) {
                temp = ior (i);
                *addr++ = temp;
                printf ("%x:", temp);
        }

        return;
}

static void eth_reset (void)
{
        u32 ID;
        
        ID = GetDM9000ID();
        if ( ID != DM9000_ID)
        {
                printf("not found the dm9000 ID:%x\n",ID);
                return ;
        }else
                printf("found DM9000 ID:%x\n",ID);
        eth_halt();
        dmfe_init_dm9000();
}

void eth_halt (void)
{
        /* RESET devie */
        phy_write(0x00, 0x8000);    /* PHY RESET */
        iow(DM9KS_GPR, GPR_PHYDown);     /* Power-Down PHY */
        iow(DM9KS_IMR, DM9KS_DISINTR);    /* Disable all interrupt */
        iow(DM9KS_RXCR, 0x00);        /* Disable RX */
}

int eth_init (bd_t * bd)
{
        u32 ID;
        int i,j;
        u16 * mac =(u16 *) bd->bi_enetaddr;

        ID = GetDM9000ID();
        if ( ID != DM9000_ID)
        {
                printf("not found the dm9000 ID:%x\n",ID);
                return 1;
        }
        printf("Found DM9000 ID:%x at address %x !\n", ID,  DM9000_BASE);
        dmfe_init_dm9000();

        {
          int env_size;
          char *s = NULL, *e = NULL;
          unsigned char env_mac[20];
          env_size = getenv_r("ethaddr", env_mac, sizeof(env_mac));
          if(env_size != 18)
            {
              printf("\n***ERROR: ethaddr is not set properly!!\n");
#if 0
              for (i=0; i<3; i++) /* read MAC from EEPROM */
                mac[i]= read_srom_word(i);
#else
              mac[0]=0x1100;
              mac[1]=0x3322;
              mac[2]=0x5544;
#endif
            }
          else
            {
              s = env_mac;
              for(i = 0; i < 6; ++i)
                {
                  (bd->bi_enetaddr)[i] = s ? simple_strtoul(s, &e, 16) : 0;
                  if(s)  s = (*e) ? e + 1 : e;
                }
              printf("bd->bi_entaddr: %02x:%02x:%02x:%02x:%02x:%02x\n", bd->bi_enetaddr[0],
                     bd->bi_enetaddr[1], bd->bi_enetaddr[2], bd->bi_enetaddr[3],
                     bd->bi_enetaddr[4], bd->bi_enetaddr[5]);
            }
        }
        printf("[eth_init]MAC:");
        for(i=0,j=0x10; i<6; i++,j++)
          {    
            iow(j,bd->bi_enetaddr[i]);
            printf("%x:",bd->bi_enetaddr[i]);
          }
        printf("\n");

        return 0;
}

/* Get a data block via Ethernet */
extern int eth_rx (void)
{
        unsigned short rxlen;
        unsigned char *addr = NULL;
        u8 RxRead;
        rx_t rx;
        u8 * ptr = (u8*)&rx;
        

        RxRead = ior(DM9KS_MRCMDX);
        RxRead = ior(DM9KS_ISR);
        RxRead = ior(DM9KS_MRCMDX) & 0xff;

        if (RxRead != 1)  /* no data */
                return 0;

        DM9000_PPTR = DM9KS_MRCMD; /* set read ptr ++ */

        /* Read packet status & length */
        MoveData(ptr, 4, 0);

        rxlen = rx.desc.length;        /* get len */

        if(rx.desc.status & (RX_RuntFrame | RX_PhyErr | RX_AlignErr | RX_CRCErr))
                printf ("[dm9ks]RX error %x\n", rx.desc.status);    

        if (rxlen > PKTSIZE_ALIGN + PKTALIGN)
                printf ("packet too big! %d %d\n", rxlen, PKTSIZE_ALIGN + PKTALIGN);

        addr = (unsigned char *)NetRxPackets[0];
        MoveData(addr, rxlen, 0);

        /* Pass the packet up to the protocol layers. */
        NetReceive (NetRxPackets[0], rxlen);

        return rxlen;
}

/* Send a data block via Ethernet. */
extern int eth_send (volatile void *packet, int length)
{
        volatile unsigned char *addr;
        int    length1 = length;

        DM9000_PPTR = DM9KS_MWCMD;/* data copy ready set */

        /* copy data */
        addr = packet;
        MoveData(addr,length,1);

        /* set packet length  */
        iow(DM9KS_TXPLH, (length1 >> 8) & 0xff);  
        iow(DM9KS_TXPLL, length1 & 0xff);

        /* start transmit */
        iow(DM9KS_TCR, TCR_TX_Request);

        while (1)/* wait for tx complete */
        {
                if (ior(DM9KS_NSR)& (NSR_TX2END|NSR_TX1END))    
                        break;
        }
        return 0;
}

#endif                /* CONFIG_DRIVER_DM9000 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值