| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- /*
- * Copyright : (C) 2022 Phytium Information Technology, Inc.
- * All Rights Reserved.
- *
- * This program is OPEN SOURCE software: you can redistribute it and/or modify it
- * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
- * either version 1.0 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the Phytium Public License for more details.
- *
- *
- * FilePath: fgmac_phy.c
- * Date: 2022-04-06 14:46:52
- * LastEditTime: 2022-04-06 14:46:53
- * Description: This file is for
- *
- * Modify History:
- * Ver Who Date Changes
- * ----- ------ -------- --------------------------------------
- */
- /***************************** Include Files *********************************/
- #include "fassert.h"
- #include "fio.h"
- #include "ferror_code.h"
- #include "ftypes.h"
- #include "fdebug.h"
- #include "fparameters.h"
- #include "fgmac_hw.h"
- #include "fgmac_phy.h"
- #include "fgmac.h"
- #ifdef CONFIG_FGMAC_PHY_AR803X
- #include "fgmac_ar803x.h"
- #endif
- #include "fsleep.h"
- /************************** Constant Definitions *****************************/
- /**************************** Type Definitions *******************************/
- /***************** Macros (Inline Functions) Definitions *********************/
- #define FGMAC_DEBUG_TAG "FGMAC-PHY"
- #define FGMAC_ERROR(format, ...) FT_DEBUG_PRINT_E(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FGMAC_WARN(format, ...) FT_DEBUG_PRINT_W(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FGMAC_INFO(format, ...) FT_DEBUG_PRINT_I(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
- #define FGMAC_DEBUG(format, ...) FT_DEBUG_PRINT_D(FGMAC_DEBUG_TAG, format, ##__VA_ARGS__)
- /************************** Function Prototypes ******************************/
- /************************** Variable Definitions *****************************/
- /*****************************************************************************/
- /* 此文件主要为了完成用户对外接口,用户可以使用这些接口直接开始工作 */
- /* - 包括用户API的定义和实现
- - 同时包含必要的OPTION方法,方便用户进行配置
- - 如果驱动可以直接进行I/O操作,在此源文件下可以将API 进行实现 */
- /* - 包括用户API的定义和实现
- - 同时包含必要的OPTION方法,方便用户进行配置
- - 如果驱动可以直接进行I/O操作,在此源文件下可以将API 进行实现 */
- /**
- * @name: FGmacWaitPhyAutoNegotiationEnd
- * @msg: wait fgmac phy auto negotiation complete
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @param {u32} phy_address, phy address connect to fgmac
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- static FError FGmacWaitPhyAutoNegotiationEnd(FGmac *instance_p, u32 phy_address)
- {
- u16 reg_val;
- FError ret = FGMAC_SUCCESS;
- int timeout = FGMAC_RETRY_TIMES;
- do
- {
- reg_val = 0;
- ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_STATUS_REG, ®_val);
- if (FGMAC_SUCCESS != ret)
- break;
- fsleep_millisec(20);
- }
- while ((FGMAC_PHY_MII_SR_AUTO_NEGOT_COMPLETE != (FGMAC_PHY_MII_SR_AUTO_NEGOT_COMPLETE & reg_val)) &&
- (0 < --timeout));
- if (FGMAC_SUCCESS != ret)
- return ret;
- if (0 >= timeout)
- {
- FGMAC_ERROR("auto negotiation timeout, reg_val: %#x", reg_val);
- ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, ®_val);
- FGMAC_ERROR("auto negotiation timeout, FGMAC_PHY_MII_CTRL_REG reg_val: %#x", reg_val);
- ret = FGMAC_ERR_TIMEOUT;
- }
- return ret;
- }
- /**
- * @name: FGmacPhyAutoNegotiation
- * @msg: fgmac phy auto negotiation configuration
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @param {u32} phy_address, phy address connect to fgmac
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- static FError FGmacPhyAutoNegotiation(FGmac *instance_p, u32 phy_address)
- {
- FASSERT(instance_p);
- u16 reg_val;
- FError ret = FGMAC_SUCCESS;
- int timeout = FGMAC_RETRY_TIMES;
- /* check link state */
- do
- {
- reg_val = 0;
- ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_STATUS_REG, ®_val);
- if (FGMAC_SUCCESS != ret)
- break;
- fsleep_millisec(20);
- }
- while (!(reg_val & FGMAC_PHY_MII_SR_LSTATUS) && (0 <= --timeout));
- if (0 >= timeout)
- {
- FGMAC_ERROR("timeout when wait phy auto negotiation ");
- return FGMAC_ERR_TIMEOUT;
- }
- if (FGMAC_SUCCESS != ret)
- return ret;
- ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, ®_val);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("auto negotiation failed");
- return ret;
- }
- reg_val |= FGMAC_PHY_MII_CR_AUTO_NEGOT;
- ret = FGmacWritePhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, reg_val);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("auto negotiation failed");
- return ret;
- }
- ret = FGmacWaitPhyAutoNegotiationEnd(instance_p, phy_address);
- if (FGMAC_SUCCESS != ret)
- return ret;
- return ret;
- }
- /**
- * @name: FGmacPhyNoneNegotiation
- * @msg: fgmac phy not negotiation configuration
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @param {u32} phy_address, phy address connect to fgmac
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- static FError FGmacPhyNoneNegotiation(FGmac *instance_p, u32 phy_address)
- {
- FASSERT(instance_p);
- u16 control_reg = 0;
- FError ret = FGMAC_SUCCESS;
- /* read phy control register */
- ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, &control_reg);
- if (FGMAC_SUCCESS != ret)
- return ret;
- /* 设置半双工模式 */
- if (FGMAC_PHY_MODE_FULLDUPLEX == instance_p->config.duplex_mode)
- control_reg |= FGMAC_PHY_MII_CR_DUPLEX_MODE;
- else
- control_reg &= ~(FGMAC_PHY_MII_CR_DUPLEX_MODE);
- /* 设置速度bit6|bit13, 10b-1000M, 01b-100M, 00b-10M */
- switch (instance_p->config.speed)
- {
- case FGMAC_PHY_SPEED_1000:
- control_reg |= FGMAC_PHY_MII_CR_SPEED_SEL_MSB;
- control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_LSB);
- break;
- case FGMAC_PHY_SPEED_100:
- control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_MSB);
- control_reg |= FGMAC_PHY_MII_CR_SPEED_SEL_LSB;
- break;
- case FGMAC_PHY_SPEED_10:
- control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_MSB);
- control_reg &= ~(FGMAC_PHY_MII_CR_SPEED_SEL_LSB);
- break;
- default:
- FASSERT(0);
- break;
- }
- /* disable auto-negotiation */
- control_reg &= ~(FGMAC_PHY_MII_CR_AUTO_NEGOT);
- control_reg &= ~(FGMAC_PHY_MII_CR_RESTART_AUTO_NEGO);
- /* write phy control register */
- ret = FGmacWritePhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, control_reg);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("disable auto-negotiation failed");
- return ret;
- }
- return ret;
- }
- /**
- * @name: FGmacWritePhyReg
- * @msg: write phy register value
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @param {u32} phy_address, phy address connect to fgmac
- * @param {u16} phy_reg, phy register offset to write
- * @param {u16} phy_reg_val, value write to phy register
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- FError FGmacWritePhyReg(FGmac *instance_p, u32 phy_address, u16 phy_reg, u16 phy_reg_val)
- {
- FASSERT(instance_p);
- u32 cmd_reg_val;
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FGMAC_SUCCESS;
- cmd_reg_val = FGMAC_MII_ADDR_CR(instance_p->config.mdc_clk_hz);
- cmd_reg_val |= FGMAC_MII_ADDR_PA(phy_address);
- cmd_reg_val |= FGMAC_MII_ADDR_GR(phy_reg);
- cmd_reg_val |= FGMAC_MII_ADDR_GW;
- cmd_reg_val |= FGMAC_MII_ADDR_GB;
- FGMAC_WRITE_REG32(base_addr, FGMAC_GMII_DATA_OFFSET, phy_reg_val);
- FGMAC_WRITE_REG32(base_addr, FGMAC_GMII_ADDR_OFFSET, cmd_reg_val);
- ret = FGmacPhyWaitBusBusy(base_addr, FGMAC_RETRY_TIMES);
- return ret;
- }
- /**
- * @name: FGmacReadPhyReg
- * @msg: read phy register value
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @param {u32} phy_address, phy address connect to fgmac
- * @param {u16} phy_reg, phy register offset to read
- * @param {u16} *phy_reg_val_p, phy register value pointer
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- FError FGmacReadPhyReg(FGmac *instance_p, u32 phy_address, u16 phy_reg, u16 *phy_reg_val_p)
- {
- FASSERT(instance_p && phy_reg_val_p);
- u32 cmd_reg_val;
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FGMAC_SUCCESS;
- cmd_reg_val = FGMAC_MII_ADDR_CR(instance_p->config.mdc_clk_hz);
- cmd_reg_val |= FGMAC_MII_ADDR_PA(phy_address);
- cmd_reg_val |= FGMAC_MII_ADDR_GR(phy_reg);
- cmd_reg_val &= ~FGMAC_MII_ADDR_GW;
- cmd_reg_val |= FGMAC_MII_ADDR_GB;
- ret = FGmacPhyWaitBusBusy(base_addr, FGMAC_RETRY_TIMES);
- if (FGMAC_SUCCESS != ret)
- return ret;
- FGMAC_WRITE_REG32(base_addr, FGMAC_GMII_ADDR_OFFSET, cmd_reg_val);
- ret = FGmacPhyWaitBusBusy(base_addr, FGMAC_RETRY_TIMES);
- if (FGMAC_SUCCESS != ret)
- return ret;
- *phy_reg_val_p = FGMAC_MII_DATA_GD_MASK & FGMAC_READ_REG32(base_addr, FGMAC_GMII_DATA_OFFSET);
- return ret;
- }
- /**
- * @name: FGmacPhyDetect
- * @msg: detect fgmac phy, and get phy addr
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- FError FGmacPhyDetect(FGmac *instance_p)
- {
- u32 phy_addr = 0;
- u16 phy_reg = 0, phy_id1_reg, phy_id2_reg;
- FError ret = FGMAC_SUCCESS;
- u32 invalid_count = 0;
- for (phy_addr = 0; phy_addr < FGMAC_PHY_MAX_NUM; phy_addr++)
- {
- ret = FGmacReadPhyReg(instance_p, phy_addr, FGMAC_PHY_MII_STATUS_REG, &phy_reg);
- if (ret != FGMAC_SUCCESS)
- {
- FGMAC_ERROR("%s, PHY operation is busy", __func__);
- return ret;
- }
- if (phy_reg != 0xffff)
- {
- ret = FGmacReadPhyReg(instance_p, phy_addr, FGMAC_PHY_MII_PHYSID1_REG, &phy_id1_reg);
- ret |= FGmacReadPhyReg(instance_p, phy_addr, FGMAC_PHY_MII_PHYSID2_REG, &phy_id2_reg);
- if ((ret == FGMAC_SUCCESS) && (phy_id1_reg != 0xffff) && (phy_id2_reg != 0xffff))
- {
- /* assign the max valid phy address to instance_p->phy_addr */
- instance_p->phy_addr = phy_addr;
- instance_p->phy_valid_mask |= (1 << phy_addr);
- instance_p->phy_id1 = phy_id1_reg;
- FGMAC_INFO("phy_addr: [%d], phy_valid_mask: 0x%x, phy id: [0x%08x][0x%08x], phy_reg:0x%x",
- phy_addr, instance_p->phy_valid_mask, phy_id1_reg, phy_id2_reg, phy_reg);
- return ret;
- }
- }
- else
- {
- invalid_count++;
- }
- }
- if (invalid_count == FGMAC_PHY_MAX_NUM)
- {
- FGMAC_ERROR("phy detect failed, phy address is not found!");
- return FGMAC_ERR_PHY_IS_NOT_FOUND;
- }
- return FGMAC_SUCCESS;
- }
- /**
- * @name: FGmacPhyReset
- * @msg: detect fgmac phy, and get phy addr
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @param {u32} phy_address, phy address connect to fgmac
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- FError FGmacPhyReset(FGmac *instance_p, u32 phy_address)
- {
- FError ret = FGMAC_ERR_PHY_NOT_SUPPORT;
- uintptr base_addr = instance_p->config.base_addr;
- ret = FGmacWritePhyReg(instance_p, phy_address, FGMAC_PHY_MII_CTRL_REG, FGMAC_PHY_MII_CR_RESET);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("reset phy failed");
- return ret;
- }
- return FGMAC_SUCCESS;
- }
- /**
- * @name: FGmacGetPhySpecialStatus
- * @msg: read phy special status register to get speed and duplex mode
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @param {u32} phy_address, phy address connect to fgmac
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- static FError FGmacGetPhySpecialStatus(FGmac *instance_p, u32 phy_address)
- {
- u16 phy_special_status = 0;
- u32 ret = FGMAC_SUCCESS;
- ret = FGmacReadPhyReg(instance_p, phy_address, FGMAC_PHY_MII_PHY_SPECIAL_REG, &phy_special_status);
- if (FGMAC_SUCCESS != ret)
- {
- return ret;
- }
- switch (phy_special_status & FGMAC_PHY_SPECIFIC_STATUS_SPEED_MASK)
- {
- case FGMAC_PHY_SPECIFIC_STATUS_SPEED_1000M:
- instance_p->config.speed = FGMAC_PHY_SPEED_1000;
- break;
- case FGMAC_PHY_SPECIFIC_STATUS_SPEED_100M:
- instance_p->config.speed = FGMAC_PHY_SPEED_100;
- break;
- case FGMAC_PHY_SPECIFIC_STATUS_SPEED_10M:
- instance_p->config.speed = FGMAC_PHY_SPEED_10;
- break;
- default:
- break;
- }
- if (phy_special_status & FGMAC_PHY_SPECIFIC_STATUS_DUPLEX_MASK)
- instance_p->config.duplex_mode = FGMAC_PHY_MODE_FULLDUPLEX;
- else
- instance_p->config.duplex_mode = FGMAC_PHY_MODE_HALFDUPLEX;
- return ret;
- }
- /**
- * @name: FGmacPhyCfgInitialize
- * @msg: fgmac phy configuration
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- FError FGmacPhyCfgInitialize(FGmac *instance_p)
- {
- FASSERT(instance_p);
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FGMAC_SUCCESS;
- u32 phy_addr;
- /* detect phy address, and assigned the minimum valid address to phy_addr */
- ret = FGmacPhyDetect(instance_p);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("phy detect failed!");
- return ret;
- }
- for (phy_addr = 0; phy_addr <= instance_p->phy_addr; phy_addr++)
- {
- /* 计算出当前位置 */
- if (instance_p->phy_valid_mask & (1 << phy_addr))
- {
- /* set phy power down and set phy Normal operation */
- FGmacPhyReset(instance_p, phy_addr);
- /* auto negotiation */
- if (instance_p->config.en_auto_negtiation)
- {
- ret = FGmacPhyAutoNegotiation(instance_p, phy_addr);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("auto negotiation phy failed");
- return ret;
- }
- }
- else
- {
- /* if gmac is disable auto negotiation, we need set speed */
- ret = FGmacPhyNoneNegotiation(instance_p, phy_addr);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("negotiation phy failed");
- return ret;
- }
- }
- /* read phy special status register to get speed and duplex mode */
- ret = FGmacGetPhySpecialStatus(instance_p, phy_addr);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("get phy special status failed");
- return ret;
- }
- FGMAC_DEBUG("instance_p->config.speed: %d", instance_p->config.speed);
- FGMAC_DEBUG("instance_p->config.duplex_mode: 0x%x", instance_p->config.duplex_mode);
- /* update mac controller speed setting */
- FGmacControllerSpeedConfig(instance_p, instance_p->config.speed);
- /* update mac controller duplex mode setting */
- FGmacControllerDuplexConfig(instance_p, instance_p->config.duplex_mode);
- }
- }
- return ret;
- }
- FError FGmacPhyCfgDeInitialize(FGmac *instance_p)
- {
- FASSERT(instance_p);
- uintptr base_addr = instance_p->config.base_addr;
- FError ret = FGMAC_SUCCESS;
- u32 phy_addr;
- for (phy_addr = 0; phy_addr <= instance_p->phy_addr; phy_addr++)
- {
- /* 计算出当前位置 */
- if (instance_p->phy_valid_mask & (1 << phy_addr))
- {
- /* set phy power down and set phy Normal operation */
- FGmacPhyReset(instance_p, phy_addr);
- }
- }
- return ret;
- }
- /**
- * @name: FGmacPhyAwaken
- * @msg: fgmac phy awaken
- * @param {FGmac} *instance_p, instance of FGmac controller
- * @return err code information, FGMAC_SUCCESS indicates success,others indicates failed
- */
- FError FGmacPhyAwaken(FGmac *instance_p)
- {
- FError ret = FGMAC_SUCCESS;
- #ifdef CONFIG_FGMAC_PHY_AR803X
- ret = FGmacPhyDetect(instance_p);
- if (FGMAC_SUCCESS != ret)
- {
- FGMAC_ERROR("phy detect failed!");
- return ret;
- }
- u16 phy_id1;
- phy_id1 = instance_p->phy_id1;
- if (phy_id1 == FGMAC_AR803X_PHY_ID1)
- {
- ret = FGmacAr803xDisableHibernate(instance_p);
- }
- #endif
- return ret;
- }
|