?? smc9118.c
字號:
/*------------------------------------------------------------------------ . smc9118.c . This is a driver for SMSC's LAN9118 single-chip Ethernet device. . . (C) Copyright 2006 ARM Ltd. <www.arm.com> . . 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 . . Device information contained in this file was obtained from the LAN9118 . manual from SMC <www.smsc.com>. . . author: . Peter Pearse ( peter.pearse@arm.com) . . Sources: . o SMSC LAN9118 databook (www.smsc.com) . o drivers/smc91111.c . . History: . 2006.10.24 Peter Pearse Initial version based on drivers/smc91111.c . - Dropped board specific code . - Dropped #if 0 code, . it's in smc91111.c if you want it . - Made all but interface functions static . - Add in ARM smc9118 code ----------------------------------------------------------------------------*/#include <common.h>#include <command.h>#include <config.h>#include "smc9118.h"#include <net.h>#ifdef CONFIG_DRIVER_SMC9118#define SMC9118_DEV_NAME "SMC9118"#ifndef CONFIG_SMC9118_BASE include/configs/<board>.h must define the base address of the device registers#endif#define SMC9118_DBG 0#if SMC9118_DBG > 1static const char version[] = "smc9118.c:v1.0 06/10/24 by Peter Pearse <peter.pearse@arm.com>\n";#endif#if (SMC9118_DBG > 2 )# define PRINTK3(args...) printf(args)#else# define PRINTK3(args...)#endif#if SMC9118_DBG > 1# define PRINTK2(args...) printf(args)#else# define PRINTK2(args...)#endif#ifdef SMC9118_DBG# define PRINTK(args...) printf(args)#else# define PRINTK(args...)#endif#if SMC9118_DBG > 0static void smsc9118_print_mac_registers(void){ unsigned int read; int i; i = 0; read = 0; for(i = 1; i <= 0xC; i++) { smsc9118_mac_regread(i, &read); debug("MAC Register %02d: 0x%08x\n",i,read); } debug("\n"); return;}static void smsc9118_print_registers(void){ volatile unsigned int *i; for (i = (volatile unsigned int *)CONFIG_SMC9118_BASE; (int)i < (int)SMSC9118_RESERVED3; i++){ debug("Register @%p 0x%08x\n",i, *i); }} static void smsc9118_print_phy_registers(void){ unsigned short read; unsigned int i; i = 0; read = 0; for(i = 0; i <= 6; i++) { smsc9118_phy_regread(i, &read); debug("PHY Register %02d: 0x%08x\n",i,read); } smsc9118_phy_regread(i = 17, &read); debug("Phy Register %02d: 0x%08x\n", i, read); smsc9118_phy_regread(i = 18, &read); debug("Phy Register %02d: 0x%08x\n", i, read); smsc9118_phy_regread(i = 27, &read); debug("Phy Register %02d: 0x%08x\n", i, read); smsc9118_phy_regread(i = 29, &read); debug("Phy Register %02d: 0x%08x\n", i, read); smsc9118_phy_regread(i = 30, &read); debug("Phy Register %02d: 0x%08x\n", i, read); smsc9118_phy_regread(i = 31, &read); debug("Phy Register %02d: 0x%08x\n", i, read); debug("\n"); return;}#endif /* SMC9118_DBG > 0 *//*----------------------------------------------------------------- . . The driver can be entered at any of the following entry points. . .------------------------------------------------------------------ */int eth_init(bd_t *bd);void eth_halt(void);int eth_rx(void);int eth_send(volatile void *packet, int length);#ifdef SHARED_RESOURCES/* * Resource swapper */void swap_to(int device_id);#endif/* * ---------------------------------------------------------- * * Chip register access routines * * ---------------------------------------------------------- */static int smsc9118_mac_regread(unsigned char regoffset, unsigned int *data){ unsigned int val, maccmd; int timedout; int error; ulong start; error = 0; val = *SMSC9118_MAC_CSR_CMD; if(!(val & ((unsigned int)1 << 31))) { // Make sure there's no pending operation maccmd = 0; maccmd |= regoffset; maccmd |= ((unsigned int)1 << 30); // Indicates read maccmd |= ((unsigned int)1 << 31); // Start bit *SMSC9118_MAC_CSR_CMD = maccmd; // Start operation start = get_timer (0); do { timedout = get_timer(start) > MS50 ? 1 : 0; val = *SMSC9118_BYTE_TEST; // A no-op read. } while(!timedout && (*SMSC9118_MAC_CSR_CMD & ((unsigned int)1 << 31))); if(timedout) { printf("Error: SMSC9118 MAC CSR read operation timed out.\n"); error = 1; return error; } *data = *SMSC9118_MAC_CSR_DATA; } else { printf("Warning: SMSC9118 MAC CSR is busy. No data read.\n"); *data = 0; } return 0;}static int smsc9118_mac_regwrite(unsigned char regoffset, unsigned int val){ unsigned int read, maccmd; int timedout; int error; ulong start; debug("MAC[%02d] write 0x%08x \n", regoffset, val); error = 0; read = *SMSC9118_MAC_CSR_CMD; if(!(read & ((unsigned int)1 << 31))) { // Make sure there's no pending operation *SMSC9118_MAC_CSR_DATA = val; // Load data. maccmd = 0; maccmd |= regoffset; maccmd &= ~((unsigned int)1 << 30); // Clear indicates write maccmd |= ((unsigned int)1 << 31); // Indicate start of operation *SMSC9118_MAC_CSR_CMD = maccmd; start = get_timer (0); do { timedout = get_timer(start) > MS50 ? 1 : 0; read = *SMSC9118_BYTE_TEST; // A no-op read. } while(!timedout && (*SMSC9118_MAC_CSR_CMD & ((unsigned int)1 << 31))); if(timedout) { printf("Error: SMSC9118 MAC CSR write operation timed out.\n"); error = 1; return error; } } else { printf("Warning: SMSC9118 MAC CSR is busy. No data written.\n"); } return 0;}static int smsc9118_phy_regread(unsigned char regoffset, unsigned short *data){ unsigned int val, phycmd; int error; int timedout; ulong start; error = 0; smsc9118_mac_regread(SMSC9118_MAC_MII_ACC, &val); if(!(val & 1)) { // Not busy phycmd = 0; phycmd |= (1 << 11); // 1 to [15:11] phycmd |= ((regoffset & 0x1F) << 6); // Put regoffset to [10:6] phycmd &= ~(1 << 1); // Clear [1] indicates read. phycmd |= (1 << 0); // Set [0] indicates operation start smsc9118_mac_regwrite(SMSC9118_MAC_MII_ACC, phycmd); val = 0; timedout = 0; start = get_timer (0); do { timedout = get_timer(start) > MS50 ? 1 : 0; smsc9118_mac_regread(SMSC9118_MAC_MII_ACC,&val); } while(!timedout && (val & ((unsigned int)1 << 0))); if(timedout) { printf("Error: SMSC9118 MAC MII read operation timed out.\n"); error = 1; return error; } smsc9118_mac_regread(SMSC9118_MAC_MII_DATA, &val); } else { printf("Warning: SMSC9118 MAC MII is busy. No data read.\n"); val = 0; } *data = (unsigned short)(val & 0xFFFF); return 0;}static int smsc9118_phy_regwrite(unsigned char regoffset, unsigned short data){ unsigned int val, phycmd, u32data; int error; int timedout; ulong start; u32data = (unsigned int)data; debug("PHY[%02d] write 0x%08x \n", regoffset, u32data); smsc9118_mac_regread(SMSC9118_MAC_MII_ACC, &val); if(!(val & 1)) { // Not busy smsc9118_mac_regwrite(SMSC9118_MAC_MII_DATA, u32data); // Load the data phycmd = 0; phycmd |= (1 << 11); // 1 to [15:11] phycmd |= ((regoffset & 0x1F) << 6); // Put regoffset to [10:6] phycmd |= (1 << 1); // Set [1] indicates write. phycmd |= (1 << 0); // Set [0] indicates operation start smsc9118_mac_regwrite(SMSC9118_MAC_MII_ACC, phycmd); // Start operation phycmd = 0; timedout = 0; start = get_timer (0); do { timedout = get_timer(start) > MS50 ? 1 : 0; smsc9118_mac_regread(SMSC9118_MAC_MII_ACC, &phycmd); } while(!timedout && (phycmd & (1 << 0))); if(timedout) { printf("Error: SMSC9118 MAC MII write operation timed out.\n"); error = 1; return error; } } else { printf("Warning: SMSC9118 MAC MII is busy. No data written.\n"); } return 0;}/* ------------------------------------------------------------ . . Internal routines . ------------------------------------------------------------*//* * Functions left as in/outu16, even for ARM where ARM WORD == 32 bits == (2* Other Architecture Word) * until we decide we can't use the common functions..... */#ifdef CONFIG_SMC_USE_IOFUNCS/* * input and output functions * - the access macros defined in smc9118.h may not * work for other boards - they have only been tested on * ARM RealViewEB Revision D boards * * This code is copied from smc91111.c (functions & types renamed), * however 16 bit access may be different for SMC9118 * - see the datasheet & test well before use * */# if defined(CONFIG_SMC_USE_32_BIT) 32 bit access functions not yet provided# elsestatic inline u16 SMC9118_inu16(u32 offset);static inline void SMC9118_outu16(u16 value, u32 offset);static inline u8 SMC9118_inu8(u32 offset);static inline void SMC9118_outu8(u8 value, u32 offset);static inline void SMC9118_ins16(u32 offset, volatile uchar* buf, u32 len);static inline void SMC9118_outs16(u32 offset, uchar* buf, u32 len);#define barrier() __asm__ __volatile__("": : :"memory")#define SMC9118_BASE_ADDRESS CONFIG_SMC9118_BASEstatic inline u16 SMC9118_inu16(u32 offset){ u16 v; v = *((volatile u16*)(SMC9118_BASE_ADDRESS+offset)); barrier(); *(volatile u32*)(0xc0000000); return v;}static inline void SMC9118_outu16(u16 value, u32 offset){ *((volatile u16*)(SMC9118_BASE_ADDRESS+offset)) = value; barrier(); *(volatile u32*)(0xc0000000);}static inline u8 SMC9118_inu8(u32 offset){ u16 _w; _w = SMC9118_inu16(offset & ~((u32)1)); return (offset & 1) ? (u8)(_w >> 8) : (u8)(_w);}static inline void SMC9118_outu8(u8 value, u32 offset){ u16 _w; _w = SMC9118_inu16(offset & ~((u32)1)); if (offset & 1) *((volatile u16*)(SMC9118_BASE_ADDRESS+(offset & ~((u32)1)))) = (value<<8) | (_w & 0x00ff); else *((volatile u16*)(SMC9118_BASE_ADDRESS+offset)) = value | (_w & 0xff00);}static inline void SMC9118_ins16(u32 offset, volatile uchar* buf, u32 len){ volatile u16 *p = (volatile u16 *)buf; while (len-- > 0) { *p++ = SMC9118_inu16(offset); barrier(); *((volatile u32*)(0xc0000000)); }}static inline void SMC9118_outs16(u32 offset, uchar* buf, u32 len){ volatile u16 *p = (volatile u16 *)buf; while (len-- > 0) { SMC9118_outu16(*p++, offset); barrier(); *(volatile u32*)(0xc0000000); }}# endif#endif /* CONFIG_SMC_USE_IOFUNCS */// Returns smsc9118 id.static unsigned int smsc9118_read_id(void){ return *SMSC9118_ID_REV;}static int smsc9118_check_id(void){ int error; unsigned int id; error = 0; id = smsc9118_read_id(); switch(((id >> 16) & 0xFFFF)) { case 0x118: // If bottom and top halves of the words are the same if(((id >> 16) & 0xFFFF) == (id & 0xFFFF)) { printf("Error: The SMSC9118 bus is in 16-bit mode. 32-bit mode was expected.\n"); error = 1; return error; } else { printf("SMSC9118 is identified successfully.\n"); break; } default: printf("Error: SMSC9118 id reads: 0x%08x, either an unknown chip, or error.\n",id); error = 1; break; } if((id & 0xFFFF) == 0) { printf("Error: This test is not intended for this chip revision.\n"); error = 1; } return error;}// Initiates a soft reset, returns failure or success.static __inline int smsc9118_soft_reset(void){ int timedout = 0; ulong start; // Soft reset *SMSC9118_HW_CFG |= 1; // Wait start = get_timer(0); while (!timedout && (*SMSC9118_HW_CFG & 1)){ timedout = get_timer(start) < MS10 ? 0 : 1; } return timedout;}static __inline void smsc9118_set_txfifo(unsigned int val){ // 2kb minimum, 14kb maximum if(val < 2 || val > 14) return; *SMSC9118_HW_CFG = val << 16;}static int smsc9118_wait_eeprom(void){ int timedout = 0; // Wait ulong start = get_timer(0); while (!timedout && (*SMSC9118_E2P_CMD & ((unsigned int) 1 << 31))){ timedout = get_timer(start) < MS50 ? 0 : 1; } return timedout;}static
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -