zoukankan      html  css  js  c++  java
  • 基于335X平台的UBOOT中交换芯片驱动移植

    基于335X平台的UBOOT中交换芯片驱动移植

     

    一、软硬件平台资料

     

    1、开发板:创龙AM3359核心板,网口采用RMII形式。

    2、UBOOT版本:U-Boot-2016.05,采用FDT和DM。

    3、交换芯片MARVELL的88E6321.

    4、参考文章:本博客基于335X的UBOOT网口驱动分析。

    二、移植主要步骤

    1、准备工作:

    (1)、必须熟悉U-Boot-2016.05中的网口驱动构架,熟悉其中各个网口设备结构体的意义,网口初始化流程。重点详细分析常规基于phydev的驱动初始化的过程。大多数switch的访问和PHY类似,但是寄存器功能较PHY更为复杂,也是两类设备,我们这里只是基于UBOOT中原有MII-PHY的方式,基于现有PHY架构的驱动模型,添加SW的相关驱动.

    (2)、熟悉switch的相关内容,参见相关datasheet,主要熟悉寄存器的寻址方式。

     2、主要需要实现的步骤:

    (1)、在 /driver/net/phy/目录下,添加mv88e6321.c和mv88e6321.h文件,构造一个类PHY的SW设备,及所需所有驱动接口。

    (2)/driver/net/phy/目录下,修改Makefile,增加obj-$(CONFIG_MV88E6321_SWITCH) += mv88e6321.o

    (3)、在 /driver/net/phy/目录下的phy.c文件中的create_phy_by_mask函数中添加相关内容。实现查询到相关SW驱动及设备的功能。

    三、具体代码分析

    3.1.新建文件

    根据/driver/net/phy/目录下的mv88e61xx以及mv88e6352的相关内容,建立我们需要的mv88e6321.c和mv88e6321.h文件。

    3.2 mv88e6321.h文件内容

    3.2.1.寄存器定义

        主要为相关PORT寄存器,PHY寄存器,以及PORT寄存器中的状态寄存器中的MODE定义。主要定义如下:

    #define MV88E6321_CPU_PORT      0x12

    #define MV88E6321_PHY_TIMEOUT      100000

    /* port dev-addr (= port + 0x10) */

    #define MV88E6321_PRT_OFST      0x10

    /* port registers */

    #define MV88E6321_Port_Status_REG      0x0

    #define MV88E6321_Physical_Control_REG    0x1

    #define MV88E6321_Jamming_Control_REG     0x2

    #define MV88E6321_Product_Identifier_REG      0x3

    #define MV88E6321_Port_Control_REG     0x4

    #define MV88E6321_Port_Control_1_REG      0x5

    #define MV88E6321_Port_Based_VLAN_REG     0x6

    #define MV88E6321_Port_VLAN_ID_REG     0x7

    #define MV88E6321_LED_Control_REG      0x16

    #define MV88E6321_internal_phy3_addr      0x03

    #define MV88E6321_internal_phy4_addr  0x04

    #define MV88E6321_internal_serdes0_addr   0x0c

    #define MV88E6321_internal_serdes1_addr  0x0d

    #define MV88E6321_internal_phyid1_REG     0x02

    #define MV88E6321_internal_phyid2_REG     0x03

    /* global 1 registers dev-addr */

    #define MV88E6321_GLBREG_DEVADR 0x1B

    /* global registers */

    #define MV88E6321_SGSR          0x00

    #define MV88E6321_SGCR          0x04

    /* global 2 registers dev-addr */

    #define MV88E6321_GLB2REG_DEVADR   0x1C

    /* global 2 registers */

    #define MV88E6321_PHY_CMD       0x18

    #define MV88E6321_PHY_DATA      0x19

    /* global 2 phy commands */

    #define MV88E6321_PHY_WRITE_CMD    0x9400

    #define MV88E6321_PHY_READ_CMD     0x9800

    #define MV88E6321_BUSY_OFST     15

    #define MV88E6321_MODE_OFST     12

    #define MV88E6321_OP_OFST       10

    #define MV88E6321_ADDR_OFST     5

    /* Basic mode PortStatus REG. */

    #define mv88e6321_LINK_STA     0x0800

    #define mv88e6321_FULL_DPX  0x0400

    #define mv88e6321_SPEED_100M    0x0100

    #define mv88e6321_C_Mode_RMII    0x0004

    3.2.2.寄存器读写函数定义

    #ifdef CONFIG_MV88E6321_MULTICHIP_ADRMODE

    static int mv88e6321_busychk_multic(char *name, u32 devaddr);

    static void mv88e6321_switch_write(char *name, u32 phy_adr,

        u32 reg_ofs, u16 data);

    static void mv88e6321_switch_read(char *name, u32 phy_adr,

        u32 reg_ofs, u16 *data);

    #define wr_switch_reg mv88e6321_switch_write

    #define rd_switch_reg mv88e6321_switch_read

    #else

    /* switch appears a s simple PHY and can thus use miiphy */

    #define wr_switch_reg miiphy_write

    #define rd_switch_reg miiphy_read

    #endif /* CONFIG_MV88E6321_MULTICHIP_ADRMODE */

    #endif /* _MV88E6321_H */

    根据88E6321的 datasheet描述,寄存器访问有单芯片和多芯片两种方式,这里采用单芯片方式。

    3.3 mv88e6321.c文件内容

    mv88e6321.c文件中的内容为主要需要实现的驱动接口,主要分为:

    3.3.1建立M88E6321_driver结构体

          参考其它phydev驱动模型,建立一个M88E6321驱动结构体如下:

    static struct phy_driver M88E6321_driver = {

        .name = "Marvell 88E6321",

        .uid = 0x00003100,

        .mask = 0xffffff0,

        .features  = PHY_GBIT_FEATURES | SUPPORTED_MII |

                 SUPPORTED_AUI | SUPPORTED_FIBRE |

                 SUPPORTED_BNC,

        .config = &m88e6321_config,

        .startup = &m88e6321_startup,

        .shutdown = &genphy_shutdown,

    };

    并且完成M88E6321驱动的注册函数.

    int phy_marvell_sw_init(void)

    {

        phy_register(&M88E6321_driver);

        return 0;

    }

    此函数会在phy_init中被调用,进行M88E6321_driver的注册。主要是将M88E6321_driver添加至drv->list链表中,在create_phy_by_mask创建phydev时,根据MDIO读取的phyid进行查找,与相关 phy_driver中的uid以及mask进行比较,找到相应的phydev。

    3.3.2完成驱动结构体中的函数

        static int m88e6321_config(struct phy_device *phydev)

    {

          u32 features;

        

         //   u32 features;

            /*******

                可以添加一些m88e6321的初始化配置

            ********/

            

            #ifdef DEBUG

                  

                  

                m88e6321_port_reg_test(phydev);

                m88e6321_phy_reg_test(phydev);

             

            #endif

            

                features = (SUPPORTED_TP | SUPPORTED_MII

              | SUPPORTED_AUI | SUPPORTED_FIBRE |

               SUPPORTED_BNC|SUPPORTED_100baseT_Full|SUPPORTED_Autoneg|SUPPORTED_10baseT_Full);

            phydev->supported &= features;

            phydev->advertising &= features;

            phydev->autoneg == AUTONEG_DISABLE;

            

                return 0;

       }

    m88e6321_config这个函数暂时没有太多实际的作用,主要是关闭自动协商,这里暂时不需要自动协商功能,对phydev设备进行一些相关网卡能力的赋值(也是常规默认设置,暂无实际意义,后期可调整)。其中还可以添加一些寄存器读测试。

    static int m88e6321_startup(struct phy_device *phydev)

    {

       printf("********m88e6321_startup******* ");

       m88e6321_update_link(phydev);

       m88e6321_parse_link(phydev);

       return  0;

    }

    m88e6321_startup函数中包含m88e6321_update_link和m88e6321_parse_link,m88e6321_update_link在这里的主要作用是进行link状态的更新,m88e6321_parse_link中则是根据CPU_PORT端口Status_REG中的相关BIT进行网卡工作模式的设置。具体代码如下:

    static int m88e6321_update_link(struct phy_device *phydev)

       {

           unsigned short mii_reg;

      

          

           if (phydev->link)

              return 0;

      

       /* 由于是交换芯片,所以去掉了有关自动协商的判断*/

              /* Read the link a second time to clear the latched state */

                    RD_SWITCH_REG(phydev->dev->name, MV88E6321_CPU_PORT, MV88E6321_Port_Status_REG, &mii_reg);

              if ((mii_reg &mv88e6321_LINK_STA)&&(mii_reg &mv88e6321_C_Mode_RMII)) //RMII   linked

                  phydev->link = 1;

              else

                  phydev->link = 0;

          

           return 0;

       }

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

    static int m88e6321_parse_link(struct phy_device *phydev)

    {

              unsigned short mii_reg;

            

          

      

           /* We're using autonegotiation */

        

              RD_SWITCH_REG(phydev->dev->name, MV88E6321_CPU_PORT, MV88E6321_Port_Status_REG, &mii_reg);

              phydev->speed = SPEED_10;

              phydev->duplex = DUPLEX_HALF;

             

              if (mii_reg & mv88e6321_FULL_DPX)

                  phydev->duplex = DUPLEX_FULL;

      

               if (mii_reg & mv88e6321_SPEED_100M)

                  phydev->speed = SPEED_100;

          

      

           return 0;

       }

    上述已经完成了mv88e6321相关驱动接口函数的添加。

    3.4添加编译设置

    在/include/configs/目录下的am335x_evm.h文件中,添加相关宏定义:

    /* Network. */

    #define CONFIG_PHY_GIGE

    #define CONFIG_PHYLIB

    #define  CONFIG_PHY_SMSC

    #define CONFIG_MV88E6321_SWITCH(new added)

    在/driver/net/phy/目录下的makefile 中添加相关编译设置:

    obj-$(CONFIG_BITBANGMII) += miiphybb.o

    obj-$(CONFIG_MV88E61XX_SWITCH) += mv88e61xx.o

    obj-$(CONFIG_MV88E6352_SWITCH) += mv88e6352.o

    obj-$(CONFIG_MV88E6321_SWITCH) += mv88e6321.o(new added)

    3.5 phy.c文件中的相关补充

    因为335X平台的UBOOT有关网口驱动的结构都是按照CPSW->MII->phy这个层次来进行相关结构和设备驱动的定义,我们添加的SWITCH驱动也是类PHY驱动的模型,并没有舍弃PHY设备驱动的这部分结构。

    所以,这里我们需要在phy.c中添加或修改相关部分,完成MV88E6321设备的查找以及相关驱动调用。

    3.5.1添加相关初始化内容

    在int phy_init(void)中,添加:

    #ifdef CONFIG_MV88E6321_SWITCH

       printf("CONFIG_MV88E6321_SWITCH now ");

       phy_marvell_sw_init();

    #endif

    在这里进行了MV88E6321_SWITCH驱动的添加

    3.5.2 添加 get_sw_id函数

        仿照get_phy_id函数的内容,添加get_sw_id函数,主要是读取SWITCH的PORT2口(CPU_PORT)中Product_Identifier寄存器的值。

        int  get_sw_id(struct mii_dev *bus, int addr, int devad, u32 *phy_id)//add to connect SW

        {

           int phy_reg,Product_Id;

            Product_Id=0x3;  //MV88E6321_Port_Product_Identifier

           /* Grab the bits from sw id reg, and put them

            * in the upper half */

            printf("phy_addr=0x%08X ",addr); 

           phy_reg = bus->read(bus, addr, devad, Product_Id);

       

           if (phy_reg < 0)

               return -EIO;

       

           *phy_id = (phy_reg & 0xffff);

           return 0;

        }

    3.5.3修改create_phy_by_mask函数

        create_phy_by_mask函数中主要是根据phy_id读取的值进行相关phydev的创建,这里我们主要用get_sw_id函数,代替get_phy_id函数。主要部分为:

    {

         u32 phy_id = 0xffffffff;

         int i,port_reg[32];

         printf("phy_mask=0x%08X ",phy_mask);  

         int addr = ffs(phy_mask) - 1;

         int r = get_sw_id(bus, addr, devad, &phy_id);

           /* If the PHY ID is mostly f's, we didn't find anything */

         printf("phy_id=0x%08X ",phy_id); 

                     

         if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff)

                 return phy_device_create(bus, addr, phy_id, interface);////

            else

           return NULL;     

      }

    这里需要注意的是phy_mask是根据设备树中的相关phy_id = <&davinci_mdio>, <0x12>来定义,这里的<0x12>为addr,类似phyaddr.这里0x12为SWITH的PORT2的地址,我们的CPU连接SWITH的PORT2,可参考下图:

    综上,完成了 phy.c中相关部分的修改

    四、驱动的调用

    4.1..config函数的调用

    cpsw_phy_init函数中,进行完phy_connect后,就会找到我们创建的类PHY设备及驱动,接下来会有如下赋值:

    priv->phydev = phydev;

    此后就将次phydev与priv结构相关联了。之后会调用phy_config(phydev)函数,进一步调用m88e6321_config函数。

    4.2 .startup函数的调用

    在完成cpsw_eth_probe函数的调用后,就激活了m88e6321的驱动,后期在UBOOT命令行中使用PING命令时,会发生如下调用:

    ping 192.168.1.10

    |-eth_init

      |- _cpsw_init

        |- cpsw_update_link

           |- cpsw_slave_update_link

             |- phy_startup(phy)

                |-m88e6321_startup

    分析可知,主要是通过m88e6321_startup函数中返回的LINK状态下的相关MODE,在cpsw_slave_update_link中对cpsw_slave->sliver->mac_control寄存器进行设置。正确的配置了cpsw_slave模式及功能。

    综上总结,类似网卡设备的移植中,主要是完成PHY驱动结构体额添加,完整其中相关函数的内容。最终是在cpsw_slave_update_link函数中根据网卡的状态设置cpsw的相关寄存器。只有cpsw_slave->sliver->mac_control寄存器被正确设置,才能启动网络数据的传输。

    备注:若暂时没有完成PHY设备的驱动,也可在cpsw_slave_update_link

    函数中作如下修改,自行设置mac_control寄存器的值。也可以实现网络数据传输。

    if (!phy)

          {

          /* mac_control=0x00008021;//test no phy, write mac_control in slave->sliver->mac_control by self

          __raw_writel(mac_control, &slave->sliver->mac_control);

             slave->mac_control = mac_control;

             printf("mac_control :0x%08lX ",mac_control);      */

            printf("!phy ");

            return;

          }

  • 相关阅读:
    linux同一客户端多个git账号的配置
    linux同一台机子上用多个git 账号
    执行ssh-add时出现Could not open a connection to your authentication agent
    国内常用NTP服务器地址及IP
    PHP双引号的隐患
    mysql 累加求和
    php实现Facebook风格的 time ago函数
    Mysql之数据库设计规范
    搭建Git服务器
    win7下如何根据端口号杀掉进程
  • 原文地址:https://www.cnblogs.com/lh03061238/p/10541670.html
Copyright © 2011-2022 走看看