本文轉(zhuǎn)自公眾號(hào),歡迎關(guān)注
基于DWC2的USB驅(qū)動(dòng)開(kāi)發(fā)-0x0D PHY寄存器讀寫(xiě)代碼編寫(xiě)與測(cè)試 (qq.com)
PHY寄存器讀寫(xiě)
1.1前言
我們前面重點(diǎn)介紹了ULPI接口和PHY的寄存器,這一篇來(lái)進(jìn)行PHY寄存器讀寫(xiě)的代碼編寫(xiě)與測(cè)試。從這一篇開(kāi)始就正真進(jìn)入了驅(qū)動(dòng)編寫(xiě)的過(guò)程了。
1.2 GPVNDCTL寄存器介紹
DWC2提供了讀寫(xiě)PHY寄存器的機(jī)制,對(duì)于應(yīng)用來(lái)說(shuō)就是操作一個(gè)寄存器GPVNDCTL:PHY供應(yīng)商控制寄存器。能夠讀寫(xiě)PHY寄存器這在有些底層問(wèn)題分析時(shí)很重要。
《DesignWare Cores USB 2.0 Hi-Speed On-TheGo (OTG) Databook》的P391 5.4.14 GPVNDCTL 有該寄存器的介紹。
IP必須配置OTG_VENDOR_CTL_INTERFACE = 1 才支持該功能。
GHWCFG3寄存器的b9查看該配置值。


對(duì)于UTMI+PHY,DWC_otg核心使用UTMI+供應(yīng)商控制接口進(jìn)行PHY寄存器訪問(wèn)。對(duì)于ULPI PHY,核心使用ULPI接口進(jìn)行PHY寄存器訪問(wèn)。應(yīng)用程序設(shè)置GPVNDCTL來(lái)訪問(wèn)PHY寄存器,并對(duì)PHY寄存器的訪問(wèn)進(jìn)行計(jì)時(shí),應(yīng)用程序輪詢此寄存器中的VStatus Done位來(lái)確認(rèn)是否完成PHY寄存器的訪問(wèn)。
該寄存器的描述如下
偏移0x34 訪問(wèn)大小32位




我們重點(diǎn)關(guān)注和PHY讀寫(xiě)有關(guān)的位域,其他的位暫時(shí)用不到,先不管。
NewRegReq: 軟件寫(xiě)1觸發(fā)一次操作。
VStsDone: 當(dāng)應(yīng)用程序設(shè)置NewRegReq為1時(shí),硬件清除該位,操作完成后硬件再置位該位。軟件查詢?cè)撐灰耘袛嗍欠裢瓿桑⒁獯a中需要考慮查詢超時(shí)機(jī)制。
VStsBsy: 忙標(biāo)志,正在進(jìn)行操作時(shí)硬件置位該位,操作完成時(shí)硬件清零,可以認(rèn)為是和VStsDone相反的標(biāo)志。
RegWr: 0表示讀PHY寄存器,1表示寫(xiě)PHY寄存器
RegAddr: PHY寄存器地址,PHY立即寄存器的6位地址。設(shè)置為6'h2F用于擴(kuò)展PHY寄存器集訪問(wèn)。
VCtrl:UTMI+供應(yīng)商控制寄存器地址(VCtrl)供應(yīng)商定義的4位并行輸出總線的4位寄存器地址。該字段的位11:8被置于utmi_vontrol[3:0]上。ULPI擴(kuò)展寄存器地址(ExtRegAddr)PHY擴(kuò)展寄存器地址。
RegData: 寫(xiě)寄存器時(shí)寫(xiě)入寄存器的數(shù)據(jù)。讀寄存器時(shí)讀到的寄存器內(nèi)容,設(shè)置VStatus Done時(shí)有效。
DisUlpiDrvr:讀寫(xiě)PHY寄存器無(wú)關(guān),
應(yīng)用程序在完成ULPI Carkit中斷(GINTSTS.ULPICKINT)處理后設(shè)置此位。設(shè)置后,控制器將禁用輸出信號(hào)的驅(qū)動(dòng)器,并屏蔽ULPI接口的輸入信號(hào)??刂破髟趩⒂肬LPI接口之前清除該位。
1.3 代碼編寫(xiě)
讀PHY寄存器
- RegWr設(shè)置為0
 - RegAddr設(shè)置為立即寄存器的6位地址,如果是擴(kuò)展寄存器則設(shè)置為0x2F且設(shè)置VCtrl為擴(kuò)展寄存器的值。
 - NewRegReq置1啟動(dòng)操作
 - 等待VStsDone變?yōu)?
 - 讀出RegData
 
寫(xiě)PHY寄存器
- RegWr設(shè)置為1
 - RegAddr設(shè)置為立即寄存器的6位地址,如果是擴(kuò)展寄存器則設(shè)置為0x2F且設(shè)置VCtrl為擴(kuò)展寄存器的值。
 - RegData設(shè)置為待寫(xiě)入寄存器的值
 - NewRegReq置1啟動(dòng)操作
 - 等待VStsDone變?yōu)?
 
代碼如下
/**
 * \\fn static uint8_t hw_dwc2_is_vndctlsupt(void)
 * 判斷是否支持供應(yīng)商控制接口(VndctlSupt)
 * \\retval 0 不支持 供應(yīng)商控制接口(VndctlSupt)
 * \\retval 1 支持
*/
static uint8_t hw_dwc2_is_vndctlsupt(void)
{
    return ((USB_OTG_READ_REG(CFG_GHWCFG3_ADDR) & VNDCTLSUPT_MASK) > > VNDCTLSUPT_OFFSET) & 0x01;
    //return (uint8_t)(s_dwc2_reg_t- >ghwcfg3._b.vndctlsupt);
}
/**
 * \\fn  int hw_dwc2_read_phyreg(uint8_t regaddr, uint8_t* regval, uint32_t timeout)
 * \\param[in] regaddr PHY寄存器,立即寄存器和擴(kuò)展寄存器統(tǒng)一編碼,高2位為0表示立即寄存器,
 * 高兩位不為0表示擴(kuò)展寄存器。
 * \\param[out] regval 存儲(chǔ)讀出的寄存器值
 * \\param[in] timeout 查詢是否完成的次數(shù)
 * \\retval -1 不支持供應(yīng)商控制接口(VndctlSupt)
 * \\retval -2 讀超時(shí)
 * \\retval 0  讀成功
*/
int hw_dwc2_read_phyreg(uint8_t regaddr, uint8_t* regval, uint32_t timeout)
{
    /* 判斷是否支持供應(yīng)商控制接口(VndctlSupt) */
    if(hw_dwc2_is_vndctlsupt() == 0)
    {
        return -1;
    }
#if 0
    s_dwc2_reg_t- >gpvndctl._b.regwr = 0; /* 讀模式 */
    if((regaddr & 0xC0) != 0)
    {
        /* 擴(kuò)展寄存器 */
        s_dwc2_reg_t- >gpvndctl._b.regaddr = 0x2F;
        s_dwc2_reg_t- >gpvndctl._b.vctrl = regaddr;
    }
    else
    {
        /* 立即寄存器 */
        s_dwc2_reg_t- >gpvndctl._b.regaddr = regaddr;
        s_dwc2_reg_t- >gpvndctl._b.vctrl = 0;    
    }
    s_dwc2_reg_t- >gpvndctl._b.newregreq = 1;  /* 啟動(dòng)操作 */
    while ((s_dwc2_reg_t- >gpvndctl._b.vstsdone == 0) && (timeout-- > 0));  /* 等待完成 */
    /* 根據(jù)標(biāo)志返回值或者錯(cuò)誤 */
    if(s_dwc2_reg_t- >gpvndctl._b.vstsdone != 0)
    {
        *regval = s_dwc2_reg_t- >gpvndctl._b.regdata;
        //s_dwc2_reg_t- >gpvndctl._b.vstsdone = 1;  /* newregreq =1時(shí)硬件清0,沒(méi)必要手動(dòng)清零 */
        return 0;
    }
    else
    {
        return -2;
    }
#else
    uint32_t tmp = 0;
    tmp &= ~REGWR_MASK; /* 讀模式 */
    if((regaddr & 0xC0) != 0)
    {
        /* 擴(kuò)展寄存器 */
        tmp |= ((uint32_t)0x2F < < REGADDR_OFFSET);
        tmp |= ((uint32_t)regaddr < < VCTRL_OFFSET);
    }
    else
    {
        /* 立即寄存器 */
        tmp |= ((uint32_t)regaddr < < REGADDR_OFFSET);
        tmp |= ((uint32_t)0 < < VCTRL_OFFSET);  
    }   
    tmp |= NEWREGREQ_MASK;                       /* 啟動(dòng)操作 */
    USB_OTG_WRITE_REG(CFG_GPVNDCTL_ADDR,tmp);
    while(((USB_OTG_READ_REG(CFG_GPVNDCTL_ADDR)&VSTSDONE_MASK) == 0) && (timeout-- > 0));  /* 等待完成 */
    if(((USB_OTG_READ_REG(CFG_GPVNDCTL_ADDR)&VSTSDONE_MASK) != 0))
    {
        *regval = (USB_OTG_READ_REG(CFG_GPVNDCTL_ADDR) > > REGDATA_OFFSET) & 0xFF; /* 讀出寄存器的值 */
        USB_OTG_WRITE_REG(CFG_GPVNDCTL_ADDR,USB_OTG_READ_REG(CFG_GPVNDCTL_ADDR) | VSTSDONE_MASK);
        /* newregreq =1時(shí)硬件清0,沒(méi)必要手動(dòng)清零 */
        return 0;
    }
    else
    {
        return -2;
    }
#endif
}
/**
 * \\fn  int hw_dwc2_write_phyreg(uint8_t regaddr, uint8_t regval, uint32_t timeout)
 * \\param[in] regaddr PHY寄存器,立即寄存器和擴(kuò)展寄存器統(tǒng)一編碼,高2位為0表示立即寄存器,
 * 高兩位不為0表示擴(kuò)展寄存器。
 * \\param[out] regval 寫(xiě)入寄存器的值
 * \\param[in] timeout 查詢是否完成的次數(shù)
 * \\retval -1 不支持供應(yīng)商控制接口(VndctlSupt)
 * \\retval -2 讀超時(shí)
 * \\retval 0  讀成功
*/
int hw_dwc2_write_phyreg(uint8_t regaddr, uint8_t regval, uint32_t timeout)
{
    /* 判斷是否支持供應(yīng)商控制接口(VndctlSupt) */
    if(hw_dwc2_is_vndctlsupt() == 0)
    {
        return -1;
    }
#if 0
    /* 不能使用結(jié)構(gòu)體單位域操作,因?yàn)閞egdata需要vstsdone=1才能訪問(wèn)
     * 且vstsdone是W1C,所以單位域讀-修改-寫(xiě)時(shí)vstsdone寫(xiě)入1導(dǎo)致清0,導(dǎo)致后面regdata不能寫(xiě)入
    */
    s_dwc2_reg_t- >gpvndctl._b.regwr = 1; /* 寫(xiě)模式 */
    if((regaddr & 0xC0) != 0
          
        
        
基于DWC2的USB驅(qū)動(dòng)開(kāi)發(fā)-0x0D PHY寄存器讀寫(xiě)代碼編寫(xiě)與測(cè)試