/*
* 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
* Target board. Anything with a CL-PS7111 or ep7211 shocould 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
* 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
* Merchantability or fitness for a special purpose. See
* GNU General Public License for more details.
*
* You shoshould have written ed 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 2010*) (dm9000_io)
# Define dm9000_pdata * (volatile 2010*) (dm9000_data)
# Define mdelay (n) udelay (n) * 1000)
Static unsigned char ior (INT );
Static void Iow (INT, u8 );
Static void phy_write (INT, 2010 );
Static void move8 (unsigned char *, Int, INT );
Static void move16 (unsigned char *, Int, INT );
Static void move32 (unsigned char *, Int, INT );
Static 2010read_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, 2010value)
{
/* 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 = (2010*) data_ptr) [I];
Else
For (I = 0; I <tmpleng; I ++)
(*) 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 2010read_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 20 ms */
Iow (dm9ks_gpr, upl_phyup );
Mdelay (20);/* Wait for phy power-on ready */
Iow (dm9ks_gpr, upl_phydown);/* power-down PHY */
Mdelay( 1000);/* compatible with rtl8305s */
Iow (dm9ks_gpr, upl_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_ctl, 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, upl_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;
+ + +;
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_mr1_x );
Rxread = ior (dm9ks_isr );
Rxread = ior (dm9ks_mr1_x) & 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 \ 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_ctl, tcr_tx_request );
While (1)/* Wait For TX complete */
{
If (IOR (dm9ks_nsr) & (ns_tx2end | ns_tx1end ))
Break;
}
Return 0;
}
# Endif/* config_driver_dm9000 */