我們先來了解一下88E15xx官方文檔的寄存器類型,該類型決定我們要做什麼操作
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIyVGduV2YfNWawNCM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2csITRE9Ee4wmYohnMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1MDO3QzM1AjMwETNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
圖中可以看到如果寄存器中有Retain或者Update都不在軟體重新開機之前生效。這就意味着你在設定寄存時看到這兩個辨別需要額外進行PHY的軟體複位。那麼什麼寄存器在哪裡寫複位資訊呢?那就看下圖:
上面這張圖告訴你,你要想哪個寄存器設定生效,那麼你就需要在對應的複位寄存器中的對應bit寫1,寫完後PHY會自動重新開機。重新開機後你設定的值就會生效。可能有讀者會不明白0_0.15、0_0.15、20_18.15是什麼意思。下面我就來解析一下。
拿20_18.15來說,這段數字描述的意思是18頁的第20個寄存器的第15位,那麼可以推廣一下0_0.15就是0頁的第0個寄存器的第15位。我們可以使用Register_Page.Bit來表示。至于為什麼會有頁,這是由于IEEE802.3中定義了标準的寄存器隻有0到15。廠家為了拓展就使用了分頁分寄存器來管理PHY和把PHY的狀态通過寄存器的方式對外暴露。
說完了上面的圖,現在就舉個例子來說明一下88E15xx寄存器的配置。這裡以配置20_18.2:0為例,第一步需要切換到第18頁,怎麼切換呢?來看圖
圖中紅色的框框表示切換頁面的寄存,你要切換到哪一頁,那麼就往這個寄存器寫對應的頁數就行了。
我們要切換到18頁,那麼就往第22個寄存器寫18,那麼就可以切換過去第18頁了,接着再往第20個寄存器的低3位寫對應模式資料。看圖
下面展示核心代碼中路徑為drivers/net/phy/marvell.c實作配置寄存器的代碼
static int marvell_of_reg_init(struct phy_device *phydev)
{
const __be32 *paddr;
int len, i, saved_page, current_page, page_changed, ret;
if (!phydev->dev.of_node)
return 0;
paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len); //從裝置樹中查找marvell,reg-init的屬性,一般裝置樹中會有 marvell,reg-init = <page reg mask bit>字樣
if (!paddr || len < (4 * sizeof(*paddr)))
return 0;
saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE); //該宏就是22,頁轉換寄存器,先讀原來的頁,後面會切換回去
if (saved_page < 0)
return saved_page;
page_changed = 0;
current_page = saved_page;
ret = 0;
len /= sizeof(*paddr);
for (i = 0; i < len - 3; i += 4) {
u16 reg_page = be32_to_cpup(paddr + i); //擷取頁值
u16 reg = be32_to_cpup(paddr + i + 1); //擷取寄存器值
u16 mask = be32_to_cpup(paddr + i + 2); //你要哪些内容不變
u16 val_bits = be32_to_cpup(paddr + i + 3); //你要設定的參數
int val;
if (reg_page != current_page) {
current_page = reg_page;
page_changed = 1;
ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
if (ret < 0)
goto err;
}
val = 0;
if (mask) {
val = phy_read(phydev, reg);
if (val < 0) {
ret = val;
goto err;
}
val &= mask;
}
val |= val_bits;
ret = phy_write(phydev, reg, val);
if (ret < 0)
goto err;
}
err:
if (page_changed) {
i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page); //配置完切換回去原來的頁
if (ret == 0)
ret = i;
}
return ret;
}
還是用上面的20_18.2:0為例子,我需要設定RGMII to 1000BASE-X模式,那麼就在裝置樹中配置如下:
marvell,reg-init = <0x12 0x14 0xFFF7 0x2> //第18頁 第20頁 你隻需要改低3位,其他不變 1000BASE-X對應2
上面的設定了沒有生效,因為有Update字樣。是以還要添加如下
marvell,reg-init = <0x12 0x14 0xFFF7 0x2> //第18頁 第20頁 你隻需要改低3位,其他不變 1000BASE-X對應2
<0x12 0x14 0x7FFF 0x8000> //第18頁 第20頁 你隻需要改最高位,其他不變 最高位職位對應0x8000,也就是重新開機PHY
最後介紹一下phytool的使用,phytool read ethx/add/reg可以從網卡号為ethx、MDIO位址為add、寄存器位址為reg讀取資料。phytool write ethx/add/reg value把value寫進網卡為ethx、MDIO位址為add、寄存器位址為reg的地方。
如果部落格中有什麼錯誤,歡迎指出~~~