⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 athrs26_phy.c

📁 linux下atheros的ag7100驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This file is subject to the terms and conditions of the GNU General Public * License.  See the file "COPYING" in the main directory of this archive * for more details. * * Copyright © 2007 Atheros Communications, Inc.,  All Rights Reserved. *//* * Manage the atheros ethernet PHY. * * All definitions in this file are operating system independent! */#include <linux/config.h>#include <linux/types.h>#include <linux/netdevice.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include "ag7100_phy.h"#include "ag7100.h"/* PHY selections and access functions */typedef enum {    PHY_SRCPORT_INFO,     PHY_PORTINFO_SIZE,} PHY_CAP_TYPE;typedef enum {    PHY_SRCPORT_NONE,    PHY_SRCPORT_VLANTAG,     PHY_SRCPORT_TRAILER,} PHY_SRCPORT_TYPE;#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)#define DRV_MSG(x,a,b,c,d,e,f)#define DRV_PRINT(DBG_SW,X)#define ATHR_LAN_PORT_VLAN          1#define ATHR_WAN_PORT_VLAN          2#define ENET_UNIT_LAN 0#define TRUE    1#define FALSE   0#define ATHR_PHY0_ADDR   0x0#define ATHR_PHY1_ADDR   0x1#define ATHR_PHY2_ADDR   0x2#define ATHR_PHY3_ADDR   0x3#define ATHR_PHY4_ADDR   0x4#define MODULE_NAME "ATHRS26"/* * Track per-PHY port information. */typedef struct {    BOOL   isEnetPort;       /* normal enet port */    BOOL   isPhyAlive;       /* last known state of link */    int    ethUnit;          /* MAC associated with this phy port */    uint32_t phyBase;    uint32_t phyAddr;          /* PHY registers associated with this phy port */    uint32_t VLANTableSetting; /* Value to be written to VLAN table */} athrPhyInfo_t;/* * Per-PHY information, indexed by PHY unit number. */static athrPhyInfo_t athrPhyInfo[] = {    {TRUE,   /* phy port 0 -- LAN port 0 */     FALSE,     ENET_UNIT_LAN,     0,     ATHR_PHY0_ADDR,     ATHR_LAN_PORT_VLAN    },    {TRUE,   /* phy port 1 -- LAN port 1 */     FALSE,     ENET_UNIT_LAN,     0,     ATHR_PHY1_ADDR,     ATHR_LAN_PORT_VLAN    },    {TRUE,   /* phy port 2 -- LAN port 2 */     FALSE,     ENET_UNIT_LAN,     0,     ATHR_PHY2_ADDR,      ATHR_LAN_PORT_VLAN    },    {TRUE,   /* phy port 3 -- LAN port 3 */     FALSE,     ENET_UNIT_LAN,     0,     ATHR_PHY3_ADDR,      ATHR_LAN_PORT_VLAN    },    {TRUE,   /* phy port 4 -- WAN port or LAN port 4 */     FALSE,     1,     0,     ATHR_PHY4_ADDR,      ATHR_LAN_PORT_VLAN   /* Send to all ports */    },        {FALSE,  /* phy port 5 -- CPU port (no RJ45 connector) */     TRUE,     ENET_UNIT_LAN,     0,     0x00,      ATHR_LAN_PORT_VLAN    /* Send to all ports */    },};static uint8_t athr26_init_flag = 0;static cmd_resp_t cmd_resp;static DECLARE_WAIT_QUEUE_HEAD (hd_conf_wait);static int wait_flag = 0;static ag7100_mac_t *ag7100_macs[2];static atomic_t seqcnt = ATOMIC_INIT(0);#define ATHR_GLOBALREGBASE    0//#define ATHR_PHY_MAX (sizeof(ipPhyInfo) / sizeof(ipPhyInfo[0]))#define ATHR_PHY_MAX 5/* Range of valid PHY IDs is [MIN..MAX] */#define ATHR_ID_MIN 0#define ATHR_ID_MAX (ATHR_PHY_MAX-1)/* Convenience macros to access myPhyInfo */#define ATHR_IS_ENET_PORT(phyUnit) (athrPhyInfo[phyUnit].isEnetPort)#define ATHR_IS_PHY_ALIVE(phyUnit) (athrPhyInfo[phyUnit].isPhyAlive)#define ATHR_ETHUNIT(phyUnit) (athrPhyInfo[phyUnit].ethUnit)#define ATHR_PHYBASE(phyUnit) (athrPhyInfo[phyUnit].phyBase)#define ATHR_PHYADDR(phyUnit) (athrPhyInfo[phyUnit].phyAddr)#define ATHR_VLAN_TABLE_SETTING(phyUnit) (athrPhyInfo[phyUnit].VLANTableSetting)#define ATHR_IS_ETHUNIT(phyUnit, ethUnit) \            (ATHR_IS_ENET_PORT(phyUnit) &&        \            ATHR_ETHUNIT(phyUnit) == (ethUnit))#define ATHR_IS_WAN_PORT(phyUnit) (!(ATHR_ETHUNIT(phyUnit)==ENET_UNIT_LAN))            /* Forward references */BOOL athrs26_phy_is_link_alive(int phyUnit);static uint32_t athrs26_reg_read(uint32_t reg_addr);static void athrs26_reg_write(uint32_t reg_addr, uint32_t reg_val);#if !defined(HEADER_REG_CONF) && !defined(CONFIG_AR9100) #define get_field_val(_reg, _mask, _shift, _res_reg)     \    do { \        unsigned int temp;	\        temp = ar7100_reg_rd(_reg); \        temp &= (unsigned int)_mask;\        _res_reg  = temp >> _shift; \    } while (0)#define set_field_val(_reg, _mask, _shift, _val)                \    do { \        unsigned int temp; \        temp = ar7100_reg_rd(_reg); \        temp &= ~_mask;  \        temp |= _val << _shift;  \        ar7100_reg_wr(_reg, temp);\    } while (0)static unsigned int old_ahb_div = 0;void ag7100_ahb_feq_adjust(void){    unsigned int pll_fb = 0, ahb_div = 0, cpu_div = 0, mask = 0;     mask = PLL_DIV_MASK << PLL_DIV_SHIFT;    get_field_val(AR7100_PLL_CONFIG, mask, PLL_DIV_SHIFT, pll_fb);    mask = AHB_DIV_MASK << AHB_DIV_SHIFT;    get_field_val(AR7100_PLL_CONFIG, mask, AHB_DIV_SHIFT, old_ahb_div);    mask = CPU_DIV_MASK << CPU_DIV_SHIFT;    get_field_val(AR7100_PLL_CONFIG, mask, CPU_DIV_SHIFT, cpu_div);        //ahb_div = ((((pll_fb + 1) * 40)*2/(200*(cpu_div + 1))) + 1)/2 - 1;    ahb_div = ( (2*pll_fb + 2)/(5*cpu_div + 5) + 1)/2 - 1;    mask = AHB_DIV_MASK << AHB_DIV_SHIFT;    set_field_val(AR7100_PLL_CONFIG, mask, AHB_DIV_SHIFT, ahb_div);}void ag7100_ahb_feq_restore(void){    unsigned int mask = 0;    mask = AHB_DIV_MASK << AHB_DIV_SHIFT;    set_field_val(AR7100_PLL_CONFIG, mask, AHB_DIV_SHIFT, old_ahb_div); }#endif#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)static uint16_t port_def_vid[5] = {1, 1, 1, 1, 1};static uint8_t cpu_egress_tagged_flag = 0;inline uint8_t is_cpu_egress_tagged(void){    return cpu_egress_tagged_flag;}void set_cpu_egress_tagged(uint8_t is_tagged){    cpu_egress_tagged_flag = is_tagged;   }inline uint16_t athrs26_defvid_get(uint32_t port_id){    if ((port_id == 0) || (port_id > 5))        return 0;    return port_def_vid[port_id - 1];}BOOL athrs26_defvid_set(uint32_t port_id, uint16_t def_vid){    if ((def_vid == 0) || (def_vid > 4094))        return FALSE;    if ((port_id == 0) || (port_id > 5))        return FALSE;          port_def_vid[port_id - 1] = def_vid;    return TRUE;}#endifvoid athrs26_reg_init(){    int i = 20;        /* if using header for register configuration, we have to     */    /* configure s26 register after frame transmission is enabled */    if (athr26_init_flag)        return;    #if (!defined(CONFIG_AR9100)) && (!defined(HEADER_REG_CONF))    ag7100_ahb_feq_adjust();  #endif      /* reset switch */    printk(MODULE_NAME ": resetting s26\n");    athrs26_reg_write(0x0, athrs26_reg_read(0x0)|0x80000000);    while(i--) {    	mdelay(100);    	if(!(athrs26_reg_read(0x0)&0x80000000))    		break;	}    mdelay(3000);    printk(MODULE_NAME ": s26 reset done\n");            phy_reg_write(0, ATHR_PHY4_ADDR, 0, 0x0800);    athrs26_reg_write(0x200, 0x200);    athrs26_reg_write(0x300, 0x200);    athrs26_reg_write(0x400, 0x200);    athrs26_reg_write(0x500, 0x200);    athrs26_reg_write(0x600, 0x7d);    athrs26_reg_write(0x38, 0xc000050e);#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)        #ifdef HEADER_EN            athrs26_reg_write(0x104, 0x6804);#else    athrs26_reg_write(0x104, 0x6004);#endif    athrs26_reg_write(0x204, 0x6004);    athrs26_reg_write(0x304, 0x6004);    athrs26_reg_write(0x404, 0x6004);    athrs26_reg_write(0x504, 0x6004);        athrs26_reg_write(0x604, 0x6004);    #else#ifdef HEADER_EN            athrs26_reg_write(0x104, 0x4804);#else    athrs26_reg_write(0x104, 0x4004);#endif#endif           athrs26_reg_write(0x60, 0xffffffff);    athrs26_reg_write(0x64, 0xaaaaaaaa);    athrs26_reg_write(0x68, 0x55555555);        athrs26_reg_write(0x6c, 0x0);        athrs26_reg_write(0x70, 0x41af);#if (!defined(CONFIG_AR9100)) && (!defined(HEADER_REG_CONF))        ag7100_ahb_feq_restore(); #endif#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)    set_cpu_egress_tagged(0); /* use set_cpu_egress_tagged(1) to let s26 forward frame to cpu always tagged */                              /* some applications need to know the vlan information, but please make sure  */                              /* define HEADER_EN in this case */ #endif#ifdef FULL_FEATURE    athena_init(0, 2);#endif    athr26_init_flag = 1;}static unsigned int phy_val_saved = 0;/******************************************************************************** athrs26_phy_off - power off the phy to change its speed** Power off the phy*/void athrs26_phy_off(ag7100_mac_t *mac){    struct net_device  *dev = mac->mac_dev;        if (mac->mac_unit == ENET_UNIT_LAN)        return;            netif_carrier_off(dev);    netif_stop_queue(dev);    phy_val_saved = phy_reg_read(0, ATHR_PHY4_ADDR, ATHR_PHY_CONTROL);    phy_reg_write(0, ATHR_PHY4_ADDR, ATHR_PHY_CONTROL, phy_val_saved | 0x800);}/******************************************************************************** athrs26_phy_on - power on the phy after speed changed** Power on the phy*/void athrs26_phy_on(ag7100_mac_t *mac){    if ((mac->mac_unit == ENET_UNIT_LAN) || (phy_val_saved == 0))        return;            phy_reg_write(0, ATHR_PHY4_ADDR, ATHR_PHY_CONTROL, phy_val_saved & 0xf7ff);    mdelay(2000);}/******************************************************************************** athrs26_mac_speed_set - set mac in s26 speed mode (actually RMII mode)** Set mac speed mode*/void athrs26_mac_speed_set(ag7100_mac_t *mac, ag7100_phy_speed_t speed){    if ((mac->mac_unit == ENET_UNIT_LAN))        return;        switch (speed) {        case AG7100_PHY_SPEED_100TX:            athrs26_reg_write (0x600, 0x7d);            break;                   case AG7100_PHY_SPEED_10T:            athrs26_reg_write (0x600, 0x7c);            break;                 default:            break;      }}/******************************************************************************** athrs26_phy_is_link_alive - test to see if the specified link is alive** RETURNS:*    TRUE  --> link is alive*    FALSE --> link is down*/BOOLathrs26_phy_is_link_alive(int phyUnit){    uint16_t phyHwStatus;    uint32_t phyBase;    uint32_t phyAddr;    phyBase = ATHR_PHYBASE(phyUnit);    phyAddr = ATHR_PHYADDR(phyUnit);    phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_SPEC_STATUS);    if (phyHwStatus & ATHR_STATUS_LINK_PASS)        return TRUE;    return FALSE;}/******************************************************************************** athrs26_phy_setup - reset and setup the PHY associated with* the specified MAC unit number.** Resets the associated PHY port.** RETURNS:*    TRUE  --> associated PHY is alive*    FALSE --> no LINKs on this ethernet unit*/BOOLathrs26_phy_setup(int ethUnit){    int       phyUnit;    uint16_t  phyHwStatus;    uint16_t  timeout;    int       liveLinks = 0;    uint32_t  phyBase = 0;    BOOL      foundPhy = FALSE;    uint32_t  phyAddr = 0;        /* See if there's any configuration data for this enet */    /* start auto negogiation on each phy */    for (phyUnit=0; phyUnit < ATHR_PHY_MAX; phyUnit++) {        if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {            continue;        }        foundPhy = TRUE;        phyBase = ATHR_PHYBASE(phyUnit);        phyAddr = ATHR_PHYADDR(phyUnit);                phy_reg_write(phyBase, phyAddr, ATHR_AUTONEG_ADVERT,                      ATHR_ADVERTISE_ALL);        /* Reset PHYs*/        phy_reg_write(phyBase, phyAddr, ATHR_PHY_CONTROL,                      ATHR_CTRL_AUTONEGOTIATION_ENABLE                       | ATHR_CTRL_SOFTWARE_RESET);    }    if (!foundPhy) {        return FALSE; /* No PHY's configured for this ethUnit */    }        /*     * After the phy is reset, it takes a little while before     * it can respond properly.     */     if (ethUnit == ENET_UNIT_LAN)        mdelay(1000);     else        mdelay(3000);        /*     * Wait up to 3 seconds for ALL associated PHYs to finish     * autonegotiation.  The only way we get out of here sooner is     * if ALL PHYs are connected AND finish autonegotiation.     */    for (phyUnit=0; (phyUnit < ATHR_PHY_MAX) /*&& (timeout > 0) */; phyUnit++) {        if (!ATHR_IS_ETHUNIT(phyUnit, ethUnit)) {            continue;        }        timeout=20;        for (;;) {            phyHwStatus = phy_reg_read(phyBase, phyAddr, ATHR_PHY_CONTROL);            if (ATHR_RESET_DONE(phyHwStatus)) {                DRV_PRINT(DRV_DEBUG_PHYSETUP,                          ("Port %d, Neg Success\n", phyUnit));                break;            }            if (timeout == 0) {                DRV_PRINT(DRV_DEBUG_PHYSETUP,                          ("Port %d, Negogiation timeout\n", phyUnit));                break;            }            if (--timeout == 0) {                DRV_PRINT(DRV_DEBUG_PHYSETUP,                          ("Port %d, Negogiation timeout\n", phyUnit));                break;            }            mdelay(150);        }        #ifdef S26_VER_1_0        //turn off power saving        phy_reg_write(0, phyUnit, 29, 41);        phy_reg_write(0, phyUnit, 30, 0);       	printk("def_ S26_VER_1_0\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -