易百纳论坛

 找回密码
 注册
搜索
热搜: 海思 四轴 linux
查看: 8270|回复: 34

[源码] 雄迈板子,3535芯片,网络芯片是AR8035,kernel驱动怎么弄

  [复制链接]
发表于 2016-5-9 19:53:56 | 显示全部楼层 |阅读模式
本帖最后由 ngswfx 于 2016-5-23 18:25 编辑

越搞越糊涂了,对PHY硬件连接百思不得其姐。


不是内部已经集成了网络了吗,怎么又搞个8035,通常这种情况下,怎么弄驱动呀。

主要是这个3535是BGA,想测量连接的哪条腿都没法量。不像3520,万用表就搞定了。


是不是在kernel里面,开启MII PHY方式,调试驱动呀? 哪位大侠指点一下,我感觉我在走弯路。




//////////////////////////////////////////////////////////////////最新的动作是,直接将U-boot里面所有网络东西都禁用,仅仅在kernel里面配置网络相关的参数。
//初步计划是彻底放弃Uboot网络支持,使其能支持u盘自动升级即可。但3535 kernel网络AR8035一定要搞过去,因为自我感觉已经到了关键结点了。就差2\3个参数了。流程基本都走通了。



2016_5_11
//////////////////终于搞定了,主要是牵扯的调节项太多,没搞过驱动这种东西,一上来就搞,网上资料没有能照着模仿的,研究了3天,编译刷了1500多次kernel ,没有相关文档,自己摸索,任何一个有用的log信息,都对这次编程解决问题过程,提供很大帮助。

最后主要卡在menuconfig中,那个STMMAC    (0x7) STMMAC MDIO INTERFACE ,设置成6不行,必须7才行。不知道啥意思,这个是今天黔驴技穷了,估计是配置寄存器没对,想想干脆用雄迈Uboot,然后进入kernel后,啥寄存器我都不动,尝试。

突然发现雄迈uboot,log中,有一个PHY mode=7的信息。


然后这个板子,最开始估计连接的是MAC1端口,其实连接的是MAC0。主要在menuconfig中,将PHY ID配置成2即可。

另外AT303X.c文件中的,#define AT803X_DEVICE_ADDR                      0x03,不用管,保持3即可。开始总觉得这个是不是应该为2,其实不是,就是3。

////////////////////////////////////////////////////////////////////////////////////////////////////////////

附件当中,是at303x.c文件,以及Kconfig,Makefile文件,可以使-*-   PHY Device support and infrastructure  ---> 中出现 ar3035选择项。

注意:at303x.c文件被我改的很乱,需要自己清空printk ,有些代码还需要整理。

/////////////////////////////
home/ngs/Hi3535_SDK_V1.0.2.0/osdrv/kernel/linux-3.4.y/drivers/net/ethernet/stmmac,这里面的东西应该无需调整,可以直接使用。

/home/ngs/Hi3535_SDK_V1.0.2.0/osdrv/kernel/linux-3.4.y/drivers/net/phy              ,目录里面就是用那3个文件,覆盖就行了。

然后就是配置menuconfig。我选定了PHY DMA 等选项,是在3535的小型化配置文件基础上修改的。
#cp arch/arm/configs/hi3535_mini_defconfig .config

////////////////////////////////////////////我的百纳币太少太丢人,只能挣些小钱了,呵呵。


顺便吐槽一下,又爱又恨的海丝。

static int stmmac_syscfg_init(struct platform_device *pdev)  函数里面有一句代码,差点让我吐血。

pr_info("Set system config register 0x200300ec with value 0x003f003f\n");

//这次搞驱动过程中,打印出了这个log信息,这个很明显,已经写入寄存器值,我还挺高兴,结果一看源代码,无语了.......这种信息能随便打印吗

我又掉进坑里了。  而且这个地址寄存器值到底啥意思,我现在也没搞懂,只知道,如果writl直接写这个寄存器,系统就崩溃。代码中得到的寄存器地址,和这个0x200300ec完全不是一回事,差得老远了。不知所谓。


//////////////////////////////////////////////////2016_5_21 调整修改phy.c中void phy_state_machine(struct work_struct *work),使断线检测以及换交换机100M 1000M正常
case PHY_RUNNING:
                       
                        printk("HY_RUNNING phydev->irq:%d\n",phydev->irq);
                        ///////////////////////////////////////////////////////////ngs add for 8035
                        err = genphy_update_link(phydev);
                        if (err)
                                break;
                        if (!phydev->link) {
                                phydev->state = PHY_NOLINK;
                                printk("HY_RUNNING found link off\n");
                                netif_carrier_off(phydev->attached_dev);
                                phydev->adjust_link(phydev->attached_dev);
                        }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2016-5-9 20:21:49 | 显示全部楼层
8035 是千兆的phy吧
 楼主| 发表于 2016-5-9 21:13:38 | 显示全部楼层
本帖最后由 ngswfx 于 2016-5-9 21:18 编辑

对,这个板子就是要用千兆,所以采用8035的,我搞这个板子做解码

现在就是不知道,这个8035和3535怎么连接的,还是用的那2个端口其中一个吧?

我在kernel里面强制开启STMMAC,系统可以找到eth1(eth0找不到),也可以配置IP,(由于没有实际连接,当然无法访问)


我只能猜测,eth0那个端口连接了8035。这种方式怎么搞驱动。

我从3536的SDK里面,已经找到了at803X.c,也就是基于PHY方式的驱动。接着就不知道该怎么搞了。在kernel menu config中,启用PHY,kernel启动找不到。
发表于 2016-5-10 08:22:51 | 显示全部楼层
海思网络部分物理上看一般是MAC连接PHY(就是8035)再连接网络变压器再到RJ45

从数据通路上看, MAC是海思芯片内部的模块,通过MDIO来设置PHY(读写PHY的寄存器), 通过MII/RMII/RGMII接口(3535都支持)来和PHY交换网络数据

通常情况下, 海思的linux网络驱动基本都是好的,要修改的一般就是PHY地址和使用MII/RMII/RGMII接口中的哪一种,这个在linux config时应该都可以选

另外, 要注意一下管脚复用, 一般uboot配网络时应该都把复用关系改好了,只要后面不要再改变就好了

3535有两个MAC, 两套PHY接口, 一套MDIO接口(有点像I2C, 可以读写多个PHY)
 楼主| 发表于 2016-5-10 09:55:53 | 显示全部楼层
本帖最后由 ngswfx 于 2016-5-10 10:45 编辑
zhuangweiye 发表于 2016-5-10 08:22
海思网络部分物理上看一般是MAC连接PHY(就是8035)再连接网络变压器再到RJ45

从数据通路上看, MAC是海思 ...


多谢解答,我昨晚上搞了很久,尝试修改menuconfig一些地方,基本上的思路是摸清了一些,和您说的基本吻合了。

目前我将menuconfig中ethernet 中STMMAC,驱动开启,进入系统后,已经可以搜索到AT803X的PHY设备,显示的设备PHY ID和8035驱动中的一致,都是004dd072

0x000000000000-0x000000040000 : "boot"
0x000000040000-0x0000004e0000 : "kernel"
0x0000004e0000-0x000000fe0000 : "rootfs"
Fixed MDIO Bus: probed
atheros_init in
phy_driver_register ok
tun: Universal TUN/TAP device driver, 1.6
tun: (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
STMMAC driver:
        platform registration...
        done!
Set system config register 0x200300ec with value 0x003f003f            //这应该也是一个关键动作。
        done!
        DWMAC1000 - user ID: 0x10, Synopsys ID: 0x36
        Enhanced descriptor structure
MACADDR in get is 0:0:0:0:0:0
        no valid MAC address for MAC 0;please, use ifconfig or nwhwconfig!
stmmac_external_phy_reset in
stmmac_rst_phy_use_gpio in                 //这里好像没对,怎么配置起GPIO了
        eth0 - (dev. name: stmmaceth - id: 0, IRQ #59
        IO base addr: 0xfe0a0000)        //由于硬件连接很可能是第二个MAC口,所以我在Menuconfig里面直接将MAC0的ID号,改成2了,这里的IObase还不太对。应该再+0x4000.


//////////////////////////////////////////////////////////////////下面面我在各个相关函数进入时加入了printk
mdio_clk_init in
STMMAC MII Bus: probed
eth0: PHY ID 004dd072 at 2 IRQ -6 (1:02) active                      //这里的active很关键,但看了源代码才发现IRQ -6中的-,可不是分隔符号,就是-6,这里就错了。
stmmac_reset: RESET COMPLETE!

**************************************************
*  TNK driver built on May 10 2016 at 06:34:36
*  TNK driver mode is BYPASS
**************************************************
stmmac: Rx Checksum Offload Engine supported
TCP: cubic registered
Initializing XFRM netlink socket
NET: Registered protocol family 17
NET: Registered protocol family 15
registered taskstats version 1
VFS: Mounted root (jffs2 filesystem) on device 31:2.
Freeing init memory: 156K

            _ _ _ _ _ _ _ _ _ _ _ _
            \  _  _   _  _ _ ___
            / /__/ \ |_/
           / __   /  -  _ ___
          / /  / /  / /
  _ _ _ _/ /  /  \_/  \_ ______
___________\___\__________________

/////////////////////////////////////////////////////////////////////////进入系统后 IPconfig配置网络
# ifconfig eth0 hw ether 20:30:40:00:02:32
# ifconfig eth0 192.168.2.18 netmask 255.255.0.0
at803x_config_init in
at803x_config_init 100M
at803x_config_init 1000M
at803x_set_wol_mac_addr in
at803x_set_wol_mac_addr 30:2000        //仅仅确认MAC信息是否一致,仅仅显示了部分
phy_start_machine
MACADDR in set is 20:30:40:0:2:32
PHY_start
# PHY_UP
phy_start_aneg
PHY_AN
PHY_NOLINK
reset_mac_interface_dual in
ngs PHY: 1:02 - Link is Up - 100/Full
route add default gw 192.168.2.1
#
//////////////////////////////////////////////////////////////////////////问题就来了,网络表面成功了,其实PHY连接没对
//正常网络不停修改MAC,不会出错了,这个不行,也就是硬件PHY部分数据交互部分还是异常
//比较确信用的是MAC第二个口的依据是:目前这种配置,如果IPConfig开启网络,能够自动侦测到网络开启,显示PHY: 1:02 - Link is Up - 100/Full。但是断网不行,无任何状态显示。
//下面的MAC地址修改,只有将ipconfig eth0 down,再次UP,才能正确配置一次


# ifconfig eth0 hw ether 20:30:40:00:02:32
ifconfig: SIOCSIFHWADDR: Device or resource busy
# ifconfig eth0 hw ether 20:30:40:00:02:33
ifconfig: SIOCSIFHWADDR: Device or resource busy

/////////////////////////////////////////////////////////////////////////使用ping命令阻塞在那里,不动,其他设备也无法ping通这个设备。

# ifconfig                                
eth0      Link encap:Ethernet  HWaddr 20:30:40:00:02:32  
          inet addr:192.168.2.18  Bcast:192.168.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:547 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:81540 (79.6 KiB)  TX bytes:0 (0.0 B)
          Interrupt:59
///////////////////////////////////////////////////////////           

我现在主要怀疑几个关键点: 不确定。仅仅猜测

1、 IO base addr: 0xfe0a0000)  问题,需要强制使用第二个MAC口的地址,再加上0x4000
2、#define AT803X_DEVICE_ADDR                        0x03               //这个是在AT803X里面的定义,这个值可能需要修改,感觉这个值应该和硬件某些脚上拉下拉有关(还没搞懂)。
3、怀疑MAC没有正确写入PHY芯片。
4、MDIO配置等命令错误


//////目前我仿照3536的处理方法,在tnk_hi3535.c添加了void stmmac_external_phy_reset(int port_id, void *syscfg_addr);函数实现。并在stmmac_main中,加入这个函数。log流程显示,已经进入去配置了(日志里面的 stmmac_external_phy_reset in)。
#define SYSCTL_BASE                0x20030000
#define TOE_CLK_SRST                0x000000c8
#define TOE_MAC_INTERFACE        0x000000ec

#define TOE_CLK_DEF_100M        0x00000800

#define TOE_MAX_CON_NUM                0x000000ff
#define TOE_DEFAULT_CLK_100M        100000000
#define TOE_DEFAULT_CLK_150M        150000000
#define TOE_DEFAULT_CLK_250M        250000000

//////////////////////////////////////////////////////////////////////////////////////////下面这几个还没有参考文档确认,抄的3536的,stmmac_external_phy_reset流程中要用到。
#define MUXCTL_BASE                IO_ADDRESS(0x120f0000)
#define MUXCTL_REG16_OFFSET        (0x040)
#define MUXCTL_REG34_OFFSET        (0x088)
#define MUXCTL_PHY_MASK                0x3

#define TOE_CLK_EXT_PHY0_RST_BIT                13
#define TOE_CLK_EXT_PHY1_RST_BIT                14
///////////////////////////////////////////////////////////////////////////////////////////////////

 楼主| 发表于 2016-5-10 10:22:26 | 显示全部楼层
本帖最后由 ngswfx 于 2016-5-10 10:25 编辑

//////////////////////////////////////////////////AT803X.c代码,为了方便流程检查,也放上来
////////////////////////////////////////////////配合上面的启动log,可以看出ifconfig执行开启网络时,已经进入了at803x_config_init以及at803x_set_wol_mac_addr

#include <linux/phy.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>

#define AT803X_INTR_ENABLE                        0x12
#define AT803X_INTR_STATUS                        0x13
#define AT803X_WOL_ENABLE                        0x01
#define AT803X_DEVICE_ADDR                        0x03
//#define AT803X_DEVICE_ADDR                        0x00   //ngs

#define AT803X_LOC_MAC_ADDR_0_15_OFFSET                0x804C
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET        0x804B
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET        0x804A
#define AT803X_MMD_ACCESS_CONTROL                0x0D
#define AT803X_MMD_ACCESS_CONTROL_DATA                0x0E
#define AT803X_FUNC_DATA                        0x4003

MODULE_DESCRIPTION("Atheros 803x PHY driver");
MODULE_AUTHOR("Matus Ujhelyi");
MODULE_LICENSE("GPL");

static void at803x_set_wol_mac_addr(struct phy_device *phydev)
{
        printk(" at803x_set_wol_mac_addr in\n");
        struct net_device *ndev = phydev->attached_dev;
        const u8 *mac;
        unsigned int i, offsets[] = {
                AT803X_LOC_MAC_ADDR_32_47_OFFSET,
                AT803X_LOC_MAC_ADDR_16_31_OFFSET,
                AT803X_LOC_MAC_ADDR_0_15_OFFSET,
        };

        if (!ndev){
                printk(" at803x_set_wol_mac_addr ndev error \n");
                return;
        }

        mac = (const u8 *) ndev->dev_addr;
        printk("at803x_set_wol_mac_addr %x:%x \n", mac[1],(mac[0] << 8));
       
        if (!is_valid_ether_addr(mac)){
                printk(" at803x_set_wol_mac_addr mac error \n");
                return;
        }
        unsigned int j;
        //for(j=0;j<16;j++)
        {
                for (i = 0; i < 3; i++) {
                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,AT803X_DEVICE_ADDR);
                        //phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,j);
                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,offsets);
                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,AT803X_FUNC_DATA);
                        phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
                }
        }
}

static int at803x_config_init(struct phy_device *phydev)
{
        printk(" at803x_config_init in\n");
        int val;
        u32 features;
        int status;

        features = SUPPORTED_TP | SUPPORTED_MII | SUPPORTED_AUI |
                   SUPPORTED_FIBRE | SUPPORTED_BNC;

        val = phy_read(phydev, MII_BMSR);
        if (val < 0){
                printk(" at803x_config_init error val<0\n");
                return val;
        }

        if (val & BMSR_ANEGCAPABLE)
                features |= SUPPORTED_Autoneg;
        if (val & BMSR_100FULL){
                features |= SUPPORTED_100baseT_Full;
                printk(" at803x_config_init 100M\n");
        }
        if (val & BMSR_100HALF)
                features |= SUPPORTED_100baseT_Half;
        if (val & BMSR_10FULL)
                features |= SUPPORTED_10baseT_Full;
        if (val & BMSR_10HALF)
                features |= SUPPORTED_10baseT_Half;

        if (val & BMSR_ESTATEN) {
                val = phy_read(phydev, MII_ESTATUS);
                if (val < 0){
                        printk(" at803x_config_init error 2 val<0\n");
                        return val;
                }

                if (val & ESTATUS_1000_TFULL){
                        features |= SUPPORTED_1000baseT_Full;
                        printk(" at803x_config_init 1000M\n");
                }
                if (val & ESTATUS_1000_THALF)
                        features |= SUPPORTED_1000baseT_Half;
        }


        features |= SUPPORTED_10baseT_Full;

        phydev->supported = features;
        phydev->advertising = features;

        /* enable WOL */
        at803x_set_wol_mac_addr(phydev);
        status = phy_write(phydev, AT803X_INTR_ENABLE, AT803X_WOL_ENABLE);
        status = phy_read(phydev, AT803X_INTR_STATUS);

        return 0;
}

/* ATHEROS 8035 */
static struct phy_driver at8035_driver = {
        .phy_id                = 0x004dd072,
        .name                = "Atheros 8035 ethernet",
        .phy_id_mask        = 0xffffffef,
        .config_init        = at803x_config_init,
        .features        = PHY_GBIT_FEATURES,
        .flags                = PHY_HAS_INTERRUPT,
        .config_aneg        = &genphy_config_aneg,
        .read_status        = &genphy_read_status,
        .driver                = {
                .owner = THIS_MODULE,
        },
};

/* ATHEROS 8030 */
static struct phy_driver at8030_driver = {
        .phy_id                = 0x004dd076,
        .name                = "Atheros 8030 ethernet",
        .phy_id_mask        = 0xffffffef,
        .config_init        = at803x_config_init,
        .features        = PHY_GBIT_FEATURES,
        .flags                = PHY_HAS_INTERRUPT,
        .config_aneg        = &genphy_config_aneg,
        .read_status        = &genphy_read_status,
        .driver                = {
                .owner = THIS_MODULE,
        },
};

static int __init atheros_init(void)
{
printk(" atheros_init in\n");
        int ret;

        ret = phy_driver_register(&at8035_driver);
        if (ret){
                printk("phy_driver_register error\n");
                goto err1;
        }

        ret = phy_driver_register(&at8030_driver);
        if (ret)
         goto err2;
        printk("phy_driver_register ok\n");
        return 0;

err2:
        phy_driver_unregister(&at8035_driver);
err1:
        return ret;
}

static void __exit atheros_exit(void)
{
        printk(" atheros_exit in\n");
        phy_driver_unregister(&at8035_driver);
        phy_driver_unregister(&at8030_driver);
}

module_init(atheros_init);
module_exit(atheros_exit);

static struct mdio_device_id __maybe_unused atheros_tbl[] = {
        { 0x004dd076, 0xffffffef },
        { 0x004dd072, 0xffffffef },
        { }
};
 楼主| 发表于 2016-5-10 10:32:10 | 显示全部楼层
本帖最后由 ngswfx 于 2016-5-11 19:00 编辑
zhuangweiye 发表于 2016-5-10 08:22
海思网络部分物理上看一般是MAC连接PHY(就是8035)再连接网络变压器再到RJ45

从数据通路上看, MAC是海思 ...


现在能基本预估的结论是:
1、这个雄迈板子应该连接的第2个MAC口,因为在2个都开启情况下,第二个口能配置IP,并且能侦测出网线插入动作(ifconfig开启前都不插网线,开启后等很久,没有任何提示(其实内部持续提示PHY_NOLINK),只要一插入,提示PHY: 1:02 - Link is Up - 100/Full)。
2、既然是千兆,应该用的RGMII连接方式。模式应为为6,代码帮助解释,也说默认为6。其实这就是最大的问题,后来成成功后,证明必须为7,而且端口也不是第二个MAC,仅仅因为第二个MAC设置的PHY ID=2,所以有反应.

///////////////////////////////////////////////////////最新的动作是,直接将U-boot里面所有网络东西都禁用,仅仅在kernel里面配置网络相关的参数。
发表于 2016-5-10 11:22:29 | 显示全部楼层
本帖最后由 zhuangweiye 于 2016-5-10 11:27 编辑

来个网络通的log

[10:58:59:206] STMMAC driver:
[10:58:59:417]         platform registration...
[10:58:59:418]         done!
[10:58:59:418]         done!
[10:58:59:418]         DWMAC1000 - user ID: 0x10, Synopsys ID: 0x36
[10:58:59:419] MACADDR in get is 0:32:ff:ff:ff:ff
[10:58:59:420] stmmac_associate_phy: phy 0 mode=6
[10:58:59:420]         eth0 - (dev. name: stmmaceth - id: 0, IRQ #59
[10:58:59:421]         IO base addr: 0xfe0a0000)
[10:58:59:421] STMMAC MII Bus: probed
[10:58:59:421] eth0: PHY ID 004dd072 at 2 IRQ -6 (0:02) active        //004dd072这个ID是不是和楼主的一样  这个2表示的是PHY地址, 好像也和楼主的一样
[10:58:59:422]         DWMAC1000 - user ID: 0x10, Synopsys ID: 0x36



楼主看样子是PHY地址没设对

关于PHY地址的问题

就是AR8035支持有3个管脚来设PHY地址,可以量一下就知道了,当然也可以偷懒,反正linux起来的时候会去扫描所有的PHY地址,并把符合的PHY找出来(上面有下划线的部分),里面有PHY ID和PHY地址


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
 楼主| 发表于 2016-5-10 12:02:08 | 显示全部楼层
看来IRQ -6不是问题

有了你这个log我就不用瞎怀疑很多东西了
发表于 2016-5-10 15:37:51 | 显示全部楼层
ngswfx 发表于 2016-5-10 12:02
看来IRQ -6不是问题

有了你这个log我就不用瞎怀疑很多东西了

目录下有这个么?
Linux/drivers/net/phy/at803x.c
我下面没有

  1.   1 /*
  2.   2  * drivers/net/phy/at803x.c
  3.   3  *
  4.   4  * Driver for Atheros 803x PHY
  5.   5  *
  6.   6  * Author: Matus Ujhelyi <ujhelyi.m@gmail.com>
  7.   7  *
  8.   8  * This program is free software; you can redistribute  it and/or modify it
  9.   9  * under  the terms of  the GNU General  Public License as published by the
  10. 10  * Free Software Foundation;  either version 2 of the  License, or (at your
  11. 11  * option) any later version.
  12. 12  */
  13. 13
  14. 14 #include <linux/phy.h>
  15. 15 #include <linux/module.h>
  16. 16 #include <linux/string.h>
  17. 17 #include <linux/netdevice.h>
  18. 18 #include <linux/etherdevice.h>
  19. 19 #include <linux/of_gpio.h>
  20. 20 #include <linux/gpio/consumer.h>
  21. 21
  22. 22 #define AT803X_INTR_ENABLE                      0x12
  23. 23 #define AT803X_INTR_ENABLE_AUTONEG_ERR          BIT(15)
  24. 24 #define AT803X_INTR_ENABLE_SPEED_CHANGED        BIT(14)
  25. 25 #define AT803X_INTR_ENABLE_DUPLEX_CHANGED       BIT(13)
  26. 26 #define AT803X_INTR_ENABLE_PAGE_RECEIVED        BIT(12)
  27. 27 #define AT803X_INTR_ENABLE_LINK_FAIL            BIT(11)
  28. 28 #define AT803X_INTR_ENABLE_LINK_SUCCESS         BIT(10)
  29. 29 #define AT803X_INTR_ENABLE_WIRESPEED_DOWNGRADE  BIT(5)
  30. 30 #define AT803X_INTR_ENABLE_POLARITY_CHANGED     BIT(1)
  31. 31 #define AT803X_INTR_ENABLE_WOL                  BIT(0)
  32. 32
  33. 33 #define AT803X_INTR_STATUS                      0x13
  34. 34
  35. 35 #define AT803X_SMART_SPEED                      0x14
  36. 36 #define AT803X_LED_CONTROL                      0x18
  37. 37
  38. 38 #define AT803X_DEVICE_ADDR                      0x03
  39. 39 #define AT803X_LOC_MAC_ADDR_0_15_OFFSET         0x804C
  40. 40 #define AT803X_LOC_MAC_ADDR_16_31_OFFSET        0x804B
  41. 41 #define AT803X_LOC_MAC_ADDR_32_47_OFFSET        0x804A
  42. 42 #define AT803X_MMD_ACCESS_CONTROL               0x0D
  43. 43 #define AT803X_MMD_ACCESS_CONTROL_DATA          0x0E
  44. 44 #define AT803X_FUNC_DATA                        0x4003
  45. 45
  46. 46 #define AT803X_DEBUG_ADDR                       0x1D
  47. 47 #define AT803X_DEBUG_DATA                       0x1E
  48. 48
  49. 49 #define AT803X_DEBUG_REG_0                      0x00
  50. 50 #define AT803X_DEBUG_RX_CLK_DLY_EN              BIT(15)
  51. 51
  52. 52 #define AT803X_DEBUG_REG_5                      0x05
  53. 53 #define AT803X_DEBUG_TX_CLK_DLY_EN              BIT(8)
  54. 54
  55. 55 #define ATH8030_PHY_ID 0x004dd076
  56. 56 #define ATH8031_PHY_ID 0x004dd074
  57. 57 #define ATH8035_PHY_ID 0x004dd072
  58. 58
  59. 59 MODULE_DESCRIPTION("Atheros 803x PHY driver");
  60. 60 MODULE_AUTHOR("Matus Ujhelyi");
  61. 61 MODULE_LICENSE("GPL");
  62. 62
  63. 63 struct at803x_priv {
  64. 64         bool phy_reset:1;
  65. 65         struct gpio_desc *gpiod_reset;
  66. 66 };
  67. 67
  68. 68 struct at803x_context {
  69. 69         u16 bmcr;
  70. 70         u16 advertise;
  71. 71         u16 control1000;
  72. 72         u16 int_enable;
  73. 73         u16 smart_speed;
  74. 74         u16 led_control;
  75. 75 };
  76. 76
  77. 77 static int at803x_debug_reg_read(struct phy_device *phydev, u16 reg)
  78. 78 {
  79. 79         int ret;
  80. 80
  81. 81         ret = phy_write(phydev, AT803X_DEBUG_ADDR, reg);
  82. 82         if (ret < 0)
  83. 83                 return ret;
  84. 84
  85. 85         return phy_read(phydev, AT803X_DEBUG_DATA);
  86. 86 }
  87. 87
  88. 88 static int at803x_debug_reg_mask(struct phy_device *phydev, u16 reg,
  89. 89                                  u16 clear, u16 set)
  90. 90 {
  91. 91         u16 val;
  92. 92         int ret;
  93. 93
  94. 94         ret = at803x_debug_reg_read(phydev, reg);
  95. 95         if (ret < 0)
  96. 96                 return ret;
  97. 97
  98. 98         val = ret & 0xffff;
  99. 99         val &= ~clear;
  100. 100         val |= set;
  101. 101
  102. 102         return phy_write(phydev, AT803X_DEBUG_DATA, val);
  103. 103 }
  104. 104
  105. 105 static inline int at803x_enable_rx_delay(struct phy_device *phydev)
  106. 106 {
  107. 107         return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
  108. 108                                         AT803X_DEBUG_RX_CLK_DLY_EN);
  109. 109 }
  110. 110
  111. 111 static inline int at803x_enable_tx_delay(struct phy_device *phydev)
  112. 112 {
  113. 113         return at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
  114. 114                                         AT803X_DEBUG_TX_CLK_DLY_EN);
  115. 115 }
  116. 116
  117. 117 /* save relevant PHY registers to private copy */
  118. 118 static void at803x_context_save(struct phy_device *phydev,
  119. 119                                 struct at803x_context *context)
  120. 120 {
  121. 121         context->bmcr = phy_read(phydev, MII_BMCR);
  122. 122         context->advertise = phy_read(phydev, MII_ADVERTISE);
  123. 123         context->control1000 = phy_read(phydev, MII_CTRL1000);
  124. 124         context->int_enable = phy_read(phydev, AT803X_INTR_ENABLE);
  125. 125         context->smart_speed = phy_read(phydev, AT803X_SMART_SPEED);
  126. 126         context->led_control = phy_read(phydev, AT803X_LED_CONTROL);
  127. 127 }
  128. 128
  129. 129 /* restore relevant PHY registers from private copy */
  130. 130 static void at803x_context_restore(struct phy_device *phydev,
  131. 131                                    const struct at803x_context *context)
  132. 132 {
  133. 133         phy_write(phydev, MII_BMCR, context->bmcr);
  134. 134         phy_write(phydev, MII_ADVERTISE, context->advertise);
  135. 135         phy_write(phydev, MII_CTRL1000, context->control1000);
  136. 136         phy_write(phydev, AT803X_INTR_ENABLE, context->int_enable);
  137. 137         phy_write(phydev, AT803X_SMART_SPEED, context->smart_speed);
  138. 138         phy_write(phydev, AT803X_LED_CONTROL, context->led_control);
  139. 139 }
  140. 140
  141. 141 static int at803x_set_wol(struct phy_device *phydev,
  142. 142                           struct ethtool_wolinfo *wol)
  143. 143 {
  144. 144         struct net_device *ndev = phydev->attached_dev;
  145. 145         const u8 *mac;
  146. 146         int ret;
  147. 147         u32 value;
  148. 148         unsigned int i, offsets[] = {
  149. 149                 AT803X_LOC_MAC_ADDR_32_47_OFFSET,
  150. 150                 AT803X_LOC_MAC_ADDR_16_31_OFFSET,
  151. 151                 AT803X_LOC_MAC_ADDR_0_15_OFFSET,
  152. 152         };
  153. 153
  154. 154         if (!ndev)
  155. 155                 return -ENODEV;
  156. 156
  157. 157         if (wol->wolopts & WAKE_MAGIC) {
  158. 158                 mac = (const u8 *) ndev->dev_addr;
  159. 159
  160. 160                 if (!is_valid_ether_addr(mac))
  161. 161                         return -EFAULT;
  162. 162
  163. 163                 for (i = 0; i < 3; i++) {
  164. 164                         phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
  165. 165                                   AT803X_DEVICE_ADDR);
  166. 166                         phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
  167. 167                                   offsets[i]);
  168. 168                         phy_write(phydev, AT803X_MMD_ACCESS_CONTROL,
  169. 169                                   AT803X_FUNC_DATA);
  170. 170                         phy_write(phydev, AT803X_MMD_ACCESS_CONTROL_DATA,
  171. 171                                   mac[(i * 2) + 1] | (mac[(i * 2)] << 8));
  172. 172                 }
  173. 173
  174. 174                 value = phy_read(phydev, AT803X_INTR_ENABLE);
  175. 175                 value |= AT803X_INTR_ENABLE_WOL;
  176. 176                 ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
  177. 177                 if (ret)
  178. 178                         return ret;
  179. 179                 value = phy_read(phydev, AT803X_INTR_STATUS);
  180. 180         } else {
  181. 181                 value = phy_read(phydev, AT803X_INTR_ENABLE);
  182. 182                 value &= (~AT803X_INTR_ENABLE_WOL);
  183. 183                 ret = phy_write(phydev, AT803X_INTR_ENABLE, value);
  184. 184                 if (ret)
  185. 185                         return ret;
  186. 186                 value = phy_read(phydev, AT803X_INTR_STATUS);
  187. 187         }
  188. 188
  189. 189         return ret;
  190. 190 }
  191. 191
  192. 192 static void at803x_get_wol(struct phy_device *phydev,
  193. 193                            struct ethtool_wolinfo *wol)
  194. 194 {
  195. 195         u32 value;
  196. 196
  197. 197         wol->supported = WAKE_MAGIC;
  198. 198         wol->wolopts = 0;
  199. 199
  200. 200         value = phy_read(phydev, AT803X_INTR_ENABLE);
  201. 201         if (value & AT803X_INTR_ENABLE_WOL)
  202. 202                 wol->wolopts |= WAKE_MAGIC;
  203. 203 }
  204. 204
  205. 205 static int at803x_suspend(struct phy_device *phydev)
  206. 206 {
  207. 207         int value;
  208. 208         int wol_enabled;
  209. 209
  210. 210         mutex_lock(&phydev->lock);
  211. 211
  212. 212         value = phy_read(phydev, AT803X_INTR_ENABLE);
  213. 213         wol_enabled = value & AT803X_INTR_ENABLE_WOL;
  214. 214
  215. 215         value = phy_read(phydev, MII_BMCR);
  216. 216
  217. 217         if (wol_enabled)
  218. 218                 value |= BMCR_ISOLATE;
  219. 219         else
  220. 220                 value |= BMCR_PDOWN;
  221. 221
  222. 222         phy_write(phydev, MII_BMCR, value);
  223. 223
  224. 224         mutex_unlock(&phydev->lock);
  225. 225
  226. 226         return 0;
  227. 227 }
  228. 228
  229. 229 static int at803x_resume(struct phy_device *phydev)
  230. 230 {
  231. 231         int value;
  232. 232
  233. 233         mutex_lock(&phydev->lock);
  234. 234
  235. 235         value = phy_read(phydev, MII_BMCR);
  236. 236         value &= ~(BMCR_PDOWN | BMCR_ISOLATE);
  237. 237         phy_write(phydev, MII_BMCR, value);
  238. 238
  239. 239         mutex_unlock(&phydev->lock);
  240. 240
  241. 241         return 0;
  242. 242 }
  243. 243
  244. 244 static int at803x_probe(struct phy_device *phydev)
  245. 245 {
  246. 246         struct device *dev = &phydev->mdio.dev;
  247. 247         struct at803x_priv *priv;
  248. 248         struct gpio_desc *gpiod_reset;
  249. 249
  250. 250         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  251. 251         if (!priv)
  252. 252                 return -ENOMEM;
  253. 253
  254. 254         gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
  255. 255         if (IS_ERR(gpiod_reset))
  256. 256                 return PTR_ERR(gpiod_reset);
  257. 257
  258. 258         priv->gpiod_reset = gpiod_reset;
  259. 259
  260. 260         phydev->priv = priv;
  261. 261
  262. 262         return 0;
  263. 263 }
  264. 264
  265. 265 static int at803x_config_init(struct phy_device *phydev)
  266. 266 {
  267. 267         int ret;
  268. 268
  269. 269         ret = genphy_config_init(phydev);
  270. 270         if (ret < 0)
  271. 271                 return ret;
  272. 272
  273. 273         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||
  274. 274                         phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
  275. 275                 ret = at803x_enable_rx_delay(phydev);
  276. 276                 if (ret < 0)
  277. 277                         return ret;
  278. 278         }
  279. 279
  280. 280         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
  281. 281                         phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
  282. 282                 ret = at803x_enable_tx_delay(phydev);
  283. 283                 if (ret < 0)
  284. 284                         return ret;
  285. 285         }
  286. 286
  287. 287         return 0;
  288. 288 }
  289. 289
  290. 290 static int at803x_ack_interrupt(struct phy_device *phydev)
  291. 291 {
  292. 292         int err;
  293. 293
  294. 294         err = phy_read(phydev, AT803X_INTR_STATUS);
  295. 295
  296. 296         return (err < 0) ? err : 0;
  297. 297 }
  298. 298
  299. 299 static int at803x_config_intr(struct phy_device *phydev)
  300. 300 {
  301. 301         int err;
  302. 302         int value;
  303. 303
  304. 304         value = phy_read(phydev, AT803X_INTR_ENABLE);
  305. 305
  306. 306         if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
  307. 307                 value |= AT803X_INTR_ENABLE_AUTONEG_ERR;
  308. 308                 value |= AT803X_INTR_ENABLE_SPEED_CHANGED;
  309. 309                 value |= AT803X_INTR_ENABLE_DUPLEX_CHANGED;
  310. 310                 value |= AT803X_INTR_ENABLE_LINK_FAIL;
  311. 311                 value |= AT803X_INTR_ENABLE_LINK_SUCCESS;
  312. 312
  313. 313                 err = phy_write(phydev, AT803X_INTR_ENABLE, value);
  314. 314         }
  315. 315         else
  316. 316                 err = phy_write(phydev, AT803X_INTR_ENABLE, 0);
  317. 317
  318. 318         return err;
  319. 319 }
  320. 320
  321. 321 static void at803x_link_change_notify(struct phy_device *phydev)
  322. 322 {
  323. 323         struct at803x_priv *priv = phydev->priv;
  324. 324
  325. 325         /*
  326. 326          * Conduct a hardware reset for AT8030 every time a link loss is
  327. 327          * signalled. This is necessary to circumvent a hardware bug that
  328. 328          * occurs when the cable is unplugged while TX packets are pending
  329. 329          * in the FIFO. In such cases, the FIFO enters an error mode it
  330. 330          * cannot recover from by software.
  331. 331          */
  332. 332         if (phydev->drv->phy_id == ATH8030_PHY_ID) {
  333. 333                 if (phydev->state == PHY_NOLINK) {
  334. 334                         if (priv->gpiod_reset && !priv->phy_reset) {
  335. 335                                 struct at803x_context context;
  336. 336
  337. 337                                 at803x_context_save(phydev, &context);
  338. 338
  339. 339                                 gpiod_set_value(priv->gpiod_reset, 0);
  340. 340                                 msleep(1);
  341. 341                                 gpiod_set_value(priv->gpiod_reset, 1);
  342. 342                                 msleep(1);
  343. 343
  344. 344                                 at803x_context_restore(phydev, &context);
  345. 345
  346. 346                                 phydev_dbg(phydev, "%s(): phy was reset\n",
  347. 347                                            __func__);
  348. 348                                 priv->phy_reset = true;
  349. 349                         }
  350. 350                 } else {
  351. 351                         priv->phy_reset = false;
  352. 352                 }
  353. 353         }
  354. 354 }
  355. 355
  356. 356 static struct phy_driver at803x_driver[] = {
  357. 357 {
  358. 358         /* ATHEROS 8035 */
  359. 359         .phy_id                 = ATH8035_PHY_ID,
  360. 360         .name                   = "Atheros 8035 ethernet",
  361. 361         .phy_id_mask            = 0xffffffef,
  362. 362         .probe                  = at803x_probe,
  363. 363         .config_init            = at803x_config_init,
  364. 364         .link_change_notify     = at803x_link_change_notify,
  365. 365         .set_wol                = at803x_set_wol,
  366. 366         .get_wol                = at803x_get_wol,
  367. 367         .suspend                = at803x_suspend,
  368. 368         .resume                 = at803x_resume,
  369. 369         .features               = PHY_GBIT_FEATURES,
  370. 370         .flags                  = PHY_HAS_INTERRUPT,
  371. 371         .config_aneg            = genphy_config_aneg,
  372. 372         .read_status            = genphy_read_status,
  373. 373         .ack_interrupt          = at803x_ack_interrupt,
  374. 374         .config_intr            = at803x_config_intr,
  375. 375 }, {
  376. 376         /* ATHEROS 8030 */
  377. 377         .phy_id                 = ATH8030_PHY_ID,
  378. 378         .name                   = "Atheros 8030 ethernet",
  379. 379         .phy_id_mask            = 0xffffffef,
  380. 380         .probe                  = at803x_probe,
  381. 381         .config_init            = at803x_config_init,
  382. 382         .link_change_notify     = at803x_link_change_notify,
  383. 383         .set_wol                = at803x_set_wol,
  384. 384         .get_wol                = at803x_get_wol,
  385. 385         .suspend                = at803x_suspend,
  386. 386         .resume                 = at803x_resume,
  387. 387         .features               = PHY_BASIC_FEATURES,
  388. 388         .flags                  = PHY_HAS_INTERRUPT,
  389. 389         .config_aneg            = genphy_config_aneg,
  390. 390         .read_status            = genphy_read_status,
  391. 391         .ack_interrupt          = at803x_ack_interrupt,
  392. 392         .config_intr            = at803x_config_intr,
  393. 393 }, {
  394. 394         /* ATHEROS 8031 */
  395. 395         .phy_id                 = ATH8031_PHY_ID,
  396. 396         .name                   = "Atheros 8031 ethernet",
  397. 397         .phy_id_mask            = 0xffffffef,
  398. 398         .probe                  = at803x_probe,
  399. 399         .config_init            = at803x_config_init,
  400. 400         .link_change_notify     = at803x_link_change_notify,
  401. 401         .set_wol                = at803x_set_wol,
  402. 402         .get_wol                = at803x_get_wol,
  403. 403         .suspend                = at803x_suspend,
  404. 404         .resume                 = at803x_resume,
  405. 405         .features               = PHY_GBIT_FEATURES,
  406. 406         .flags                  = PHY_HAS_INTERRUPT,
  407. 407         .config_aneg            = genphy_config_aneg,
  408. 408         .read_status            = genphy_read_status,
  409. 409         .ack_interrupt          = &at803x_ack_interrupt,
  410. 410         .config_intr            = &at803x_config_intr,
  411. 411 } };
  412. 412
  413. 413 module_phy_driver(at803x_driver);
  414. 414
  415. 415 static struct mdio_device_id __maybe_unused atheros_tbl[] = {
  416. 416         { ATH8030_PHY_ID, 0xffffffef },
  417. 417         { ATH8031_PHY_ID, 0xffffffef },
  418. 418         { ATH8035_PHY_ID, 0xffffffef },
  419. 419         { }
  420. 420 };
  421. 421
  422. 422 MODULE_DEVICE_TABLE(mdio, atheros_tbl);
复制代码
 楼主| 发表于 2016-5-10 17:29:22 | 显示全部楼层
rafael_wl 发表于 2016-5-10 15:37
目录下有这个么?
Linux/drivers/net/phy/at803x.c
我下面没有

你的这个文件版本太高了,要用3536里面的改吧,你这个是linxu 4.5里面的,牵扯修改的地方太多。

3535默认SDK没有这个at303x.c文件。
发表于 2016-6-17 17:55:02 | 显示全部楼层
楼主,我想请教下,我也是网卡似乎可以用了,就是ping不通,请问最后楼主怎么解决的
 楼主| 发表于 2016-6-17 18:22:08 | 显示全部楼层
根据我调试8035的经验,已经做了3535以及3536,现在都基本正常。
//////一定找2个交换机,1个百兆一个千兆,ping的时候,都试一下。

///主要就是PHY的地址,这个只要对了,就是驱动代码了,3536里面的代码还需要改一下,才能用。

注意这2句:
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID ||                       
  phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
                ret = at803x_enable_rx_delay(phydev);
                 if (ret < 0)
                        return ret;
         }     
   if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID ||
                         phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
                ret = at803x_enable_tx_delay(phydev);
                if (ret < 0)
                        return ret;
         }
////你可以直接开启deley 不去判断phydev->interface  ,上面代码好像要求interface 为6或者7才执行。
//我发现这2行,如果在3535上不执行,ping不通。3536我做的时候,强制都执行了。如下:
ret = at803x_enable_rx_delay(phydev);
ret = at803x_enable_tx_delay(phydev);
发表于 2016-6-18 10:50:03 | 显示全部楼层
目前很多phy在linux都有驱动代码了,其实最主要的还是phy地址,mii通了基本就能用了
发表于 2016-6-20 08:58:13 | 显示全部楼层
我是3521A做主控芯片,也是AR8035,直接用它的内核源码,只是修改内核配置就修改了PHY地址,然而现在PING不通同网段的,看来还得再纠结下了
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|手机版|小黑屋|易百纳 ( 苏ICP备14036084 )

GMT+8, 2017-10-21 14:31 , Processed in 0.107435 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表