1. 程式人生 > >基於335X平臺的UBOOT中交換芯片驅動移植

基於335X平臺的UBOOT中交換芯片驅動移植

-m 驅動移植 暫時 time 函數 down appears avi 使用

基於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*******\n");

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\n");

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\n",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\n",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\n",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\n",mac_control); */

printf("!phy\n ");

return;

}

基於335X平臺的UBOOT中交換芯片驅動移植